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

229 lines
7.4 KiB
Rust

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) type VramDmaAddress = BoundedAddress<0xFF51, 0xFF56>;
pub(crate) type CgbPaletteAddress = BoundedAddress<0xFF68, 0xFF6C>;
#[derive(Clone, Copy)]
pub(crate) enum RomAddress {
Bank0(Bank0Address),
MappedBank(MappedBankAddress),
}
#[derive(Clone, Copy)]
pub(crate) enum IoAddress {
Joypad,
Serial(SerialAddress),
Timer(TimerAddress),
InterruptFlag,
Audio(AudioAddress),
WaveRam(WaveRamAddress),
Video(VideoAddress),
Cgb(CgbIoAddress),
Unused(u16),
}
#[derive(Clone, Copy)]
pub(crate) enum CgbIoAddress {
CompatMode,
PrepareSpeed,
VramBank,
VramDma(VramDmaAddress),
Infrared,
Palette(CgbPaletteAddress),
ObjPriority,
WramBank,
Pcm12,
Pcm34,
Unused(u16),
}
#[derive(Clone, Copy)]
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<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 From<Address> for u16 {
fn from(value: Address) -> Self {
value.inner()
}
}
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 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())),
0xFF4C..0xFF78 => Ok(IoAddress::Cgb(self.try_into().unwrap())),
0x0..0xFF00 | 0xFFFF => Err(AddressError::OutOfBounds),
_ => Ok(IoAddress::Unused(self)),
}
}
}
impl TryInto<CgbIoAddress> for u16 {
type Error = AddressError;
fn try_into(self) -> Result<CgbIoAddress, Self::Error> {
match self {
0xFF4C => Ok(CgbIoAddress::CompatMode),
0xFF4D => Ok(CgbIoAddress::PrepareSpeed),
0xFF4F => Ok(CgbIoAddress::VramBank),
0xFF51..0xFF56 => Ok(CgbIoAddress::VramDma(self.try_into().unwrap())),
0xFF56 => Ok(CgbIoAddress::Infrared),
0xFF68..0xFF6C => Ok(CgbIoAddress::Palette(self.try_into().unwrap())),
0xFF6C => Ok(CgbIoAddress::ObjPriority),
0xFF70 => Ok(CgbIoAddress::WramBank),
0xFF76 => Ok(CgbIoAddress::Pcm12),
0xFF77 => Ok(CgbIoAddress::Pcm34),
0x0..0xFF4C | 0xFF78..=0xFFFF => Err(AddressError::OutOfBounds),
_ => Ok(CgbIoAddress::Unused(self)),
}
}
}
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 {
match self {
CgbIoAddress::CompatMode => 0xFF4C,
CgbIoAddress::PrepareSpeed => 0xFF4D,
CgbIoAddress::VramBank => 0xFF4F,
CgbIoAddress::VramDma(v) => v.inner(),
CgbIoAddress::Infrared => 0xFF56,
CgbIoAddress::Palette(v) => v.inner(),
CgbIoAddress::ObjPriority => 0xFF6C,
CgbIoAddress::WramBank => 0xFF70,
CgbIoAddress::Pcm12 => 0xFF76,
CgbIoAddress::Pcm34 => 0xFF77,
CgbIoAddress::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 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()
}
}