use std::ops::{Add, Sub}; pub(crate) use self::types::*; mod types; pub(crate) type VramAddress = BoundedAddress<0x8000, 0xA000>; pub(crate) type CartRamAddress = BoundedAddress<0xA000, 0xC000>; pub(crate) type WorkRamAddress = BoundedAddress<0xC000, 0xD000>; pub(crate) type BankedWorkRamAddress = BoundedAddress<0xD000, 0xE000>; pub(crate) type MirroredRamAddress = BoundedAddress<0xE000, 0xFE00>; pub(crate) type OamAddress = BoundedAddress<0xFE00, 0xFEA0>; pub(crate) type ProhibitedAddress = BoundedAddress<0xFEA0, 0xFF00>; pub(crate) type HramAddress = BoundedAddress<0xFF80, 0xFFFF>; pub(crate) type InterruptEnable = (); pub(crate) type Bank0Address = BoundedAddress<0x0, 0x4000>; pub(crate) type MappedBankAddress = BoundedAddress<0x4000, 0x8000>; pub(crate) type SerialAddress = BoundedAddress<0xFF01, 0xFF03>; pub(crate) type TimerAddress = BoundedAddress<0xFF04, 0xFF08>; pub(crate) type AudioAddress = BoundedAddress<0xFF10, 0xFF27>; pub(crate) type WaveRamAddress = BoundedAddress<0xFF30, 0xFF40>; pub(crate) type VideoAddress = BoundedAddress<0xFF40, 0xFF4C>; pub(crate) enum RomAddress { Bank0(Bank0Address), MappedBank(MappedBankAddress), } pub(crate) enum IoAddress { Joypad, Serial(SerialAddress), Timer(TimerAddress), InterruptFlag, Audio(AudioAddress), WaveRam(WaveRamAddress), Video(VideoAddress), Cgb(CgbIoAddress), Unused(u16), } pub(crate) enum CgbIoAddress {} pub(crate) enum Address { Rom(RomAddress), Vram(VramAddress), CartRam(CartRamAddress), WorkRam(WorkRamAddress), BankedWorkRam(BankedWorkRamAddress), MirroredRam(MirroredRamAddress), Oam(OamAddress), Prohibited(ProhibitedAddress), Io(IoAddress), Hram(HramAddress), InterruptEnable(InterruptEnable), } impl From for Address { fn from(value: u16) -> Self { match value { 0x0..0x8000 => Address::Rom(value.try_into().unwrap()), 0x8000..0xA000 => Address::Vram(value.try_into().unwrap()), 0xA000..0xC000 => Address::CartRam(value.try_into().unwrap()), 0xC000..0xD000 => Address::WorkRam(value.try_into().unwrap()), 0xD000..0xE000 => Address::BankedWorkRam(value.try_into().unwrap()), 0xE000..0xFE00 => Address::MirroredRam(value.try_into().unwrap()), 0xFE00..0xFEA0 => Address::Oam(value.try_into().unwrap()), 0xFEA0..0xFF00 => Address::Prohibited(value.try_into().unwrap()), 0xFF00..0xFF80 => Address::Io(value.try_into().unwrap()), 0xFF80..0xFFFF => Address::Hram(value.try_into().unwrap()), 0xFFFF => Address::InterruptEnable(()), } } } impl From
for u16 { fn from(value: Address) -> Self { value.inner() } } impl TryInto for u16 { type Error = AddressError; fn try_into(self) -> Result { match self { 0x0..0x4000 => Ok(RomAddress::Bank0(self.try_into().unwrap())), 0x4000..0x8000 => Ok(RomAddress::MappedBank(self.try_into().unwrap())), _ => Err(AddressError::OutOfBounds), } } } impl TryInto for u16 { type Error = AddressError; fn try_into(self) -> Result { match self { 0xFF00 => Ok(IoAddress::Joypad), 0xFF01..0xFF03 => Ok(IoAddress::Serial(self.try_into().unwrap())), 0xFF04..0xFF08 => Ok(IoAddress::Timer(self.try_into().unwrap())), 0xFF0F => Ok(IoAddress::InterruptFlag), 0xFF10..0xFF27 => Ok(IoAddress::Audio(self.try_into().unwrap())), 0xFF30..0xFF40 => Ok(IoAddress::WaveRam(self.try_into().unwrap())), 0xFF40..0xFF4C => Ok(IoAddress::Video(self.try_into().unwrap())), 0xFF4D..0xFF78 => Ok(IoAddress::Cgb(self.try_into().unwrap())), 0x0..0xFF00 => Err(AddressError::OutOfBounds), 0xFFFF => Err(AddressError::OutOfBounds), _ => Ok(IoAddress::Unused(self)), } } } impl TryInto for u16 { type Error = AddressError; fn try_into(self) -> Result { todo!() } } impl AddressMarker for RomAddress { fn inner(&self) -> u16 { match self { RomAddress::Bank0(v) => v.inner(), RomAddress::MappedBank(v) => v.inner(), } } } impl AddressMarker for IoAddress { fn inner(&self) -> u16 { match self { IoAddress::Joypad => 0xFF00, IoAddress::Serial(v) => v.inner(), IoAddress::Timer(v) => v.inner(), IoAddress::InterruptFlag => 0xFF0F, IoAddress::Audio(v) => v.inner(), IoAddress::WaveRam(v) => v.inner(), IoAddress::Video(v) => v.inner(), IoAddress::Unused(v) => *v, IoAddress::Cgb(v) => v.inner(), } } } impl AddressMarker for CgbIoAddress { fn inner(&self) -> u16 { todo!() } } impl AddressMarker for Address { fn inner(&self) -> u16 { match self { Address::Rom(v) => v.inner(), Address::Vram(v) => v.inner(), Address::CartRam(v) => v.inner(), Address::WorkRam(v) => v.inner(), Address::BankedWorkRam(v) => v.inner(), Address::MirroredRam(v) => v.inner(), Address::Oam(v) => v.inner(), Address::Prohibited(v) => v.inner(), Address::Io(v) => v.inner(), Address::Hram(v) => v.inner(), Address::InterruptEnable(_) => 0xFFFF, } } } impl Add for Address { type Output = Address; fn add(self, rhs: Self) -> Self::Output { self.inner().wrapping_add(rhs.inner()).into() } } impl Sub for Address { type Output = Address; fn sub(self, rhs: Self) -> Self::Output { self.inner().wrapping_sub(rhs.inner()).into() } }