use crate::{
cpu::Flag,
sfr::{SFR_BASE, SFR_P2},
};
pub trait CpuView {
fn read_xdata(&self, addr: u16) -> u8;
fn read_code(&self, addr: u32) -> u8;
fn pc(&self) -> u16;
fn pc_ext(&self) -> u32;
fn a(&self) -> u8;
fn b(&self) -> u8;
fn dptr(&self) -> u16;
fn dpl(&self) -> u8;
fn dph(&self) -> u8;
fn psw(&self, flag: Flag) -> bool;
fn sp(&self) -> u8;
fn r(&self, x: u8) -> u8;
fn sfr(&self, addr: u8) -> u8;
}
pub trait CpuContext {
type Ports: PortMapper;
type Xdata: MemoryMapper;
type Code: ReadOnlyMemoryMapper;
fn ports(&self) -> &Self::Ports;
fn xdata(&self) -> &Self::Xdata;
fn code(&self) -> &Self::Code;
fn ports_mut(&mut self) -> &mut Self::Ports;
fn xdata_mut(&mut self) -> &mut Self::Xdata;
fn code_mut(&mut self) -> &mut Self::Code;
}
#[allow(clippy::len_without_is_empty)]
pub trait MemoryMapper {
type WriteValue;
fn len(&self) -> u32;
fn read<C: CpuView>(&self, cpu: &C, addr: u32) -> u8;
fn prepare_write<C: CpuView>(&self, cpu: &C, addr: u32, value: u8) -> Self::WriteValue;
fn write(&mut self, value: Self::WriteValue);
}
#[allow(clippy::len_without_is_empty)]
pub trait ReadOnlyMemoryMapper {
fn len(&self) -> u32;
fn read<C: CpuView>(&self, cpu: &C, addr: u32) -> u8;
}
pub trait PortMapper {
type WriteValue;
fn interest<C: CpuView>(&self, cpu: &C, addr: u8) -> bool;
fn extend_short_read<C: CpuView>(&self, cpu: &C, addr: u8) -> u16 {
addr as u16 | (cpu.sfr(SFR_P2) as u16) << 8
}
fn pc_extension<C: CpuView>(&self, _cpu: &C) -> u16 {
0
}
fn read<C: CpuView>(&self, cpu: &C, addr: u8) -> u8;
fn read_latch<C: CpuView>(&self, _cpu: &C, #[expect(unused)] addr: u8) -> u8 {
unreachable!()
}
fn prepare_write<C: CpuView>(&self, cpu: &C, addr: u8, value: u8) -> Self::WriteValue;
fn write(&mut self, value: Self::WriteValue);
}
impl<P: PortMapper> PortMapper for &mut P {
type WriteValue = P::WriteValue;
fn interest<C: CpuView>(&self, cpu: &C, addr: u8) -> bool {
(**self).interest(cpu, addr)
}
fn read<C: CpuView>(&self, cpu: &C, addr: u8) -> u8 {
(**self).read(cpu, addr)
}
fn prepare_write<C: CpuView>(&self, cpu: &C, addr: u8, value: u8) -> Self::WriteValue {
(**self).prepare_write(cpu, addr, value)
}
fn write(&mut self, value: Self::WriteValue) {
(**self).write(value)
}
fn extend_short_read<C: CpuView>(&self, cpu: &C, addr: u8) -> u16 {
(**self).extend_short_read(cpu, addr)
}
fn pc_extension<C: CpuView>(&self, cpu: &C) -> u16 {
(**self).pc_extension(cpu)
}
fn read_latch<C: CpuView>(&self, cpu: &C, addr: u8) -> u8 {
(**self).read_latch(cpu, addr)
}
}
impl<P: PortMapper> PortMapper for &P {
type WriteValue = P::WriteValue;
fn interest<C: CpuView>(&self, cpu: &C, addr: u8) -> bool {
(**self).interest(cpu, addr)
}
fn read<C: CpuView>(&self, cpu: &C, addr: u8) -> u8 {
(**self).read(cpu, addr)
}
fn prepare_write<C: CpuView>(&self, cpu: &C, addr: u8, value: u8) -> Self::WriteValue {
(**self).prepare_write(cpu, addr, value)
}
fn write(&mut self, _value: Self::WriteValue) {
unreachable!()
}
fn extend_short_read<C: CpuView>(&self, cpu: &C, addr: u8) -> u16 {
(**self).extend_short_read(cpu, addr)
}
fn pc_extension<C: CpuView>(&self, cpu: &C) -> u16 {
(**self).pc_extension(cpu)
}
fn read_latch<C: CpuView>(&self, cpu: &C, addr: u8) -> u8 {
(**self).read_latch(cpu, addr)
}
}
impl MemoryMapper for () {
type WriteValue = ();
fn len(&self) -> u32 {
0
}
fn read<C: CpuView>(&self, _cpu: &C, _addr: u32) -> u8 {
0
}
fn prepare_write<C: CpuView>(&self, _cpu: &C, _addr: u32, _value: u8) -> Self::WriteValue {}
fn write(&mut self, _value: Self::WriteValue) {}
}
impl ReadOnlyMemoryMapper for () {
fn len(&self) -> u32 {
0
}
fn read<C: CpuView>(&self, _cpu: &C, _addr: u32) -> u8 {
0
}
}
pub struct DefaultPortMapper {
sfr: [u8; 128],
}
impl Default for DefaultPortMapper {
fn default() -> Self {
Self { sfr: [0; 128] }
}
}
impl PortMapper for DefaultPortMapper {
type WriteValue = (u8, u8);
fn interest<C: CpuView>(&self, _cpu: &C, _addr: u8) -> bool {
true
}
fn extend_short_read<C: CpuView>(&self, _cpu: &C, addr: u8) -> u16 {
addr as u16
}
fn read<C: CpuView>(&self, _cpu: &C, addr: u8) -> u8 {
self.sfr[addr.wrapping_sub(SFR_BASE) as usize]
}
fn read_latch<C: CpuView>(&self, _cpu: &C, addr: u8) -> u8 {
self.sfr[addr.wrapping_sub(SFR_BASE) as usize]
}
fn prepare_write<C: CpuView>(&self, _cpu: &C, addr: u8, value: u8) -> Self::WriteValue {
(addr, value)
}
fn write(&mut self, (addr, value): Self::WriteValue) {
self.sfr[addr.wrapping_sub(SFR_BASE) as usize] = value;
}
}
impl PortMapper for () {
type WriteValue = ();
fn interest<C: CpuView>(&self, _cpu: &C, _addr: u8) -> bool {
false
}
fn extend_short_read<C: CpuView>(&self, _cpu: &C, addr: u8) -> u16 {
addr as u16
}
fn read<C: CpuView>(&self, _cpu: &C, _addr: u8) -> u8 {
unreachable!()
}
fn prepare_write<C: CpuView>(&self, _cpu: &C, _addr: u8, _value: u8) -> Self::WriteValue {
unreachable!()
}
fn write(&mut self, _value: Self::WriteValue) {
unreachable!()
}
}
pub enum WriteChoice<A, B> {
A(A),
B(B),
}
impl<A, B> PortMapper for (A, B)
where
A: PortMapper,
B: PortMapper,
{
type WriteValue = WriteChoice<A::WriteValue, B::WriteValue>;
fn interest<C: CpuView>(&self, cpu: &C, addr: u8) -> bool {
self.0.interest(cpu, addr) || self.1.interest(cpu, addr)
}
fn extend_short_read<C: CpuView>(&self, cpu: &C, addr: u8) -> u16 {
self.0.extend_short_read(cpu, addr)
}
fn pc_extension<C: CpuView>(&self, cpu: &C) -> u16 {
self.0.pc_extension(cpu)
}
fn read<C: CpuView>(&self, cpu: &C, addr: u8) -> u8 {
if self.0.interest(cpu, addr) {
self.0.read(cpu, addr)
} else if self.1.interest(cpu, addr) {
self.1.read(cpu, addr)
} else {
unreachable!()
}
}
fn read_latch<C: CpuView>(&self, cpu: &C, addr: u8) -> u8 {
if self.0.interest(cpu, addr) {
self.0.read_latch(cpu, addr)
} else if self.1.interest(cpu, addr) {
self.1.read_latch(cpu, addr)
} else {
unreachable!()
}
}
fn prepare_write<C: CpuView>(&self, cpu: &C, addr: u8, value: u8) -> Self::WriteValue {
if self.0.interest(cpu, addr) {
WriteChoice::A(self.0.prepare_write(cpu, addr, value))
} else if self.1.interest(cpu, addr) {
WriteChoice::B(self.1.prepare_write(cpu, addr, value))
} else {
unreachable!()
}
}
fn write(&mut self, value: Self::WriteValue) {
match value {
WriteChoice::A(value) => self.0.write(value),
WriteChoice::B(value) => self.1.write(value),
}
}
}
impl CpuContext for () {
type Ports = ();
type Xdata = ();
type Code = ();
fn ports(&self) -> &Self::Ports {
&()
}
fn xdata(&self) -> &Self::Xdata {
&()
}
fn code(&self) -> &Self::Code {
&()
}
fn ports_mut(&mut self) -> &mut Self::Ports {
self
}
fn xdata_mut(&mut self) -> &mut Self::Xdata {
self
}
fn code_mut(&mut self) -> &mut Self::Code {
self
}
}
impl<A: PortMapper, X: MemoryMapper, C: ReadOnlyMemoryMapper> CpuContext for (A, X, C) {
type Ports = A;
type Xdata = X;
type Code = C;
fn ports(&self) -> &Self::Ports {
&self.0
}
fn ports_mut(&mut self) -> &mut Self::Ports {
&mut self.0
}
fn xdata(&self) -> &Self::Xdata {
&self.1
}
fn xdata_mut(&mut self) -> &mut Self::Xdata {
&mut self.1
}
fn code(&self) -> &Self::Code {
&self.2
}
fn code_mut(&mut self) -> &mut Self::Code {
&mut self.2
}
}