use crate::{CpuDetails, M68000};
use crate::addressing_modes::{EffectiveAddress, AddressingMode};
use crate::exception::{ACCESS_ERROR, ADDRESS_ERROR};
use crate::instruction::Size;
use crate::utils::IsEven;
type GetResult<T> = Result<T, u8>;
type SetResult = Result<(), u8>;
pub trait MemoryAccess {
#[must_use]
fn get_byte(&mut self, addr: u32) -> Option<u8>;
#[must_use]
fn get_word(&mut self, addr: u32) -> Option<u16>;
#[must_use]
fn get_long(&mut self, addr: u32) -> Option<u32> {
Some((self.get_word(addr)? as u32) << 16 | self.get_word(addr.wrapping_add(2))? as u32)
}
#[must_use]
fn set_byte(&mut self, addr: u32, value: u8) -> Option<()>;
#[must_use]
fn set_word(&mut self, addr: u32, value: u16) -> Option<()>;
#[must_use]
fn set_long(&mut self, addr: u32, value: u32) -> Option<()> {
self.set_word(addr, (value >> 16) as u16)?;
self.set_word(addr.wrapping_add(2), value as u16)
}
#[must_use]
fn iter_u16(&mut self, addr: u32) -> MemoryIter<Self> {
MemoryIter { memory: self, next_addr: addr }
}
fn reset_instruction(&mut self);
}
pub struct MemoryIter<'a, M: MemoryAccess + ?Sized> {
pub memory: &'a mut M,
pub next_addr: u32,
}
impl<M: MemoryAccess + ?Sized> Iterator for MemoryIter<'_, M> {
type Item = GetResult<u16>;
fn next(&mut self) -> Option<Self::Item> {
if self.next_addr.is_even() {
let data = self.memory.get_word(self.next_addr);
self.next_addr = self.next_addr.wrapping_add(2);
Some(data.ok_or(ACCESS_ERROR))
} else {
Some(Err(ADDRESS_ERROR))
}
}
}
impl<CPU: CpuDetails> M68000<CPU> {
pub(super) fn get_byte<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize) -> GetResult<u8> {
match ea.mode {
AddressingMode::Drd(reg) => Ok(self.regs.d[reg as usize].0 as u8),
AddressingMode::Immediate(imm) => {
*exec_time += CPU::EA_IMMEDIATE;
Ok(imm as u8)
},
_ => memory.get_byte(self.get_effective_address(ea, exec_time)).ok_or(ACCESS_ERROR),
}
}
pub(super) fn get_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize) -> GetResult<u16> {
match ea.mode {
AddressingMode::Drd(reg) => Ok(self.regs.d[reg as usize].0 as u16),
AddressingMode::Ard(reg) => Ok(self.regs.a(reg) as u16),
AddressingMode::Immediate(imm) => {
*exec_time += CPU::EA_IMMEDIATE;
Ok(imm as u16)
},
_ => {
let addr = self.get_effective_address(ea, exec_time).even()?;
memory.get_word(addr).ok_or(ACCESS_ERROR)
},
}
}
pub(super) fn get_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize) -> GetResult<u32> {
match ea.mode {
AddressingMode::Drd(reg) => Ok(self.regs.d[reg as usize].0),
AddressingMode::Ard(reg) => Ok(self.regs.a(reg)),
AddressingMode::Immediate(imm) => {
*exec_time += CPU::EA_IMMEDIATE + 4;
Ok(imm)
},
_ => {
let addr = self.get_effective_address(ea, exec_time).even()?;
let r = memory.get_long(addr).ok_or(ACCESS_ERROR);
*exec_time += 4;
r
},
}
}
pub(super) fn set_byte<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize, value: u8) -> SetResult {
match ea.mode {
AddressingMode::Drd(reg) => { self.regs.d_byte(reg, value); Ok(()) },
_ => memory.set_byte(self.get_effective_address(ea, exec_time), value).ok_or(ACCESS_ERROR),
}
}
pub(super) fn set_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize, value: u16) -> SetResult {
match ea.mode {
AddressingMode::Drd(reg) => { self.regs.d_word(reg, value); Ok(()) },
AddressingMode::Ard(reg) => { self.regs.a_mut(reg).0 = value as i16 as u32; Ok(()) },
_ => {
let addr = self.get_effective_address(ea, exec_time).even()?;
memory.set_word(addr, value).ok_or(ACCESS_ERROR)
},
}
}
pub(super) fn set_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize, value: u32) -> SetResult {
match ea.mode {
AddressingMode::Drd(reg) => { self.regs.d[reg as usize].0 = value; Ok(()) },
AddressingMode::Ard(reg) => { self.regs.a_mut(reg).0 = value; Ok(()) },
_ => {
let addr = self.get_effective_address(ea, exec_time).even()?;
let r = memory.set_long(addr, value).ok_or(ACCESS_ERROR);
*exec_time += 4;
r
},
}
}
pub fn get_next_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u16> {
let data = memory.get_word(self.regs.pc.even()?.0).ok_or(ACCESS_ERROR);
self.regs.pc += 2;
data
}
pub fn get_next_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u32> {
let data = memory.get_long(self.regs.pc.even()?.0).ok_or(ACCESS_ERROR);
self.regs.pc += 4;
data
}
pub fn peek_next_word<M: MemoryAccess + ?Sized>(&self, memory: &mut M) -> GetResult<u16> {
memory.get_word(self.regs.pc.even()?.0).ok_or(ACCESS_ERROR)
}
pub(super) fn pop_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u16> {
let addr = self.ariwpo(7, Size::Word);
memory.get_word(addr.even()?).ok_or(ACCESS_ERROR)
}
pub(super) fn pop_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u32> {
let addr = self.ariwpo(7, Size::Long);
memory.get_long(addr.even()?).ok_or(ACCESS_ERROR)
}
pub(super) fn push_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, value: u16) -> SetResult {
let addr = self.ariwpr(7, Size::Word);
memory.set_word(addr.even()?, value).ok_or(ACCESS_ERROR)
}
pub(super) fn push_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, value: u32) -> SetResult {
let addr = self.ariwpr(7, Size::Long);
memory.set_long(addr.even()?, value).ok_or(ACCESS_ERROR)
}
pub(super) fn iter_from_pc<'a, M: MemoryAccess + ?Sized>(&self, memory: &'a mut M) -> MemoryIter<'a, M> {
memory.iter_u16(self.regs.pc.0)
}
}
impl MemoryAccess for [u8] {
fn get_byte(&mut self, addr: u32) -> Option<u8> {
let addr = addr as usize;
if addr < self.len() {
Some(self[addr])
} else {
None
}
}
fn get_word(&mut self, addr: u32) -> Option<u16> {
let addr = addr as usize;
if addr < self.len() {
Some((self[addr] as u16) << 8 | self[addr.wrapping_add(1)] as u16)
} else {
None
}
}
fn set_byte(&mut self, addr: u32, data: u8) -> Option<()> {
let addr = addr as usize;
if addr < self.len() {
self[addr] = data;
Some(())
} else {
None
}
}
fn set_word(&mut self, addr: u32, data: u16) -> Option<()> {
let addr = addr as usize;
if addr < self.len() {
self[addr] = (data >> 8) as u8;
self[addr.wrapping_add(1)] = data as u8;
Some(())
} else {
None
}
}
fn reset_instruction(&mut self) {}
}
impl MemoryAccess for &[u8] {
fn get_byte(&mut self, addr: u32) -> Option<u8> {
let addr = addr as usize;
if addr < self.len() {
Some(self[addr])
} else {
None
}
}
fn get_word(&mut self, addr: u32) -> Option<u16> {
let addr = addr as usize;
if addr < self.len() {
Some((self[addr] as u16) << 8 | self[addr.wrapping_add(1)] as u16)
} else {
None
}
}
fn set_byte(&mut self, _: u32, _: u8) -> Option<()> {
panic!("Can't write in non-mutable buffer");
}
fn set_word(&mut self, _: u32, _: u16) -> Option<()> {
panic!("Can't write in non-mutable buffer");
}
fn reset_instruction(&mut self) {}
}
impl MemoryAccess for [u16] {
fn get_byte(&mut self, addr: u32) -> Option<u8> {
let a = addr as usize >> 1;
if a < self.len() {
if addr.is_even() {
Some((self[a] >> 8) as u8)
} else {
Some(self[a] as u8)
}
} else {
None
}
}
fn get_word(&mut self, addr: u32) -> Option<u16> {
let addr = addr as usize >> 1;
if addr < self.len() {
Some(self[addr])
} else {
None
}
}
fn set_byte(&mut self, addr: u32, data: u8) -> Option<()> {
let a = addr as usize >> 1;
if a < self.len() {
if addr.is_even() {
self[a] &= 0x00FF;
self[a] |= (data as u16) << 8;
} else {
self[a] &= 0xFF00;
self[a] |= data as u16;
}
Some(())
} else {
None
}
}
fn set_word(&mut self, addr: u32, data: u16) -> Option<()> {
let addr = addr as usize >> 1;
if addr < self.len() {
self[addr] = data;
Some(())
} else {
None
}
}
fn reset_instruction(&mut self) {}
}
impl MemoryAccess for &[u16] {
fn get_byte(&mut self, addr: u32) -> Option<u8> {
let a = addr as usize >> 1;
if a < self.len() {
if addr.is_even() {
Some((self[a] >> 8) as u8)
} else {
Some(self[a] as u8)
}
} else {
None
}
}
fn get_word(&mut self, addr: u32) -> Option<u16> {
let addr = addr as usize >> 1;
if addr < self.len() {
Some(self[addr])
} else {
None
}
}
fn set_byte(&mut self, _: u32, _: u8) -> Option<()> {
panic!("Can't write in non-mutable buffer");
}
fn set_word(&mut self, _: u32, _: u16) -> Option<()> {
panic!("Can't write in non-mutable buffer");
}
fn reset_instruction(&mut self) {}
}