gb-emu/lib/src/processor/memory/addresses.rs

168 lines
5.4 KiB
Rust
Raw Normal View History

2023-04-18 18:09:21 +10:00
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),
Unused(u16),
}
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 TryInto<RomAddress> for u16 {
type Error = AddressError;
fn try_into(self) -> Result<RomAddress, Self::Error> {
match self {
0x0..0x4000 => Ok(RomAddress::Bank0(self.try_into().unwrap())),
0x4000..0x8000 => Ok(RomAddress::MappedBank(self.try_into().unwrap())),
_ => Err(AddressError::OutOfBounds),
}
}
}
impl AddressMarker for RomAddress {
fn inner(&self) -> u16 {
match self {
RomAddress::Bank0(v) => v.inner(),
RomAddress::MappedBank(v) => v.inner(),
}
}
}
impl From<u16> 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 TryInto<IoAddress> for u16 {
type Error = AddressError;
fn try_into(self) -> Result<IoAddress, Self::Error> {
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())),
0x0..0xFF00 => Err(AddressError::OutOfBounds),
0xFFFF => Err(AddressError::OutOfBounds),
_ => Ok(IoAddress::Unused(self)),
}
}
}
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,
}
}
}
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 From<Address> for u16 {
fn from(value: Address) -> Self {
value.inner()
}
}
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()
}
}