From 828da3e01f93ae70856d05dd330a288e133180a7 Mon Sep 17 00:00:00 2001 From: Alex Janka Date: Tue, 18 Apr 2023 18:09:21 +1000 Subject: [PATCH] address handling --- lib/src/lib.rs | 2 +- lib/src/processor/memory.rs | 220 ++++++++++-------- lib/src/processor/memory/addresses.rs | 167 +++++++++++++ lib/src/processor/memory/addresses/types.rs | 65 ++++++ lib/src/processor/memory/mmio/apu.rs | 36 +-- lib/src/processor/memory/mmio/apu/channels.rs | 6 +- lib/src/processor/memory/mmio/gpu.rs | 22 +- .../processor/memory/mmio/gpu/tile_window.rs | 6 +- lib/src/processor/memory/mmio/gpu/types.rs | 33 +-- lib/src/processor/memory/rom.rs | 15 +- lib/src/processor/memory/rom/mbcs.rs | 10 +- lib/src/processor/memory/rom/mbcs/mbc1.rs | 51 ++-- lib/src/processor/memory/rom/mbcs/mbc2.rs | 25 +- lib/src/processor/memory/rom/mbcs/mbc3.rs | 26 +-- lib/src/processor/memory/rom/mbcs/mbc5.rs | 27 ++- lib/src/processor/memory/rom/mbcs/none.rs | 15 +- .../processor/memory/rom/mbcs/pocketcamera.rs | 39 ++-- 17 files changed, 506 insertions(+), 259 deletions(-) create mode 100644 lib/src/processor/memory/addresses.rs create mode 100644 lib/src/processor/memory/addresses/types.rs diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 82d9656..318f5a2 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(exclusive_range_pattern, let_chains, bigint_helper_methods)] +#![feature(exclusive_range_pattern, let_chains, bigint_helper_methods, step_trait)] use crate::{processor::memory::Memory, util::pause}; use connect::{ diff --git a/lib/src/processor/memory.rs b/lib/src/processor/memory.rs index 803e3a0..e7a3315 100644 --- a/lib/src/processor/memory.rs +++ b/lib/src/processor/memory.rs @@ -1,5 +1,6 @@ pub use self::rom::Rom; use self::{ + addresses::{Address, AddressMarker, IoAddress}, mmio::{ apu::ApuSaveState, gpu::{Colour, GpuSaveState}, @@ -11,17 +12,16 @@ use self::{ use crate::{ connect::{AudioOutput, CameraWrapperRef, JoypadState, PocketCamera, Renderer, SerialTarget}, processor::SplitRegister, - verbose_println, Cpu, + Cpu, }; mod interrupts; pub use interrupts::{Interrupt, Interrupts}; use serde::{Deserialize, Serialize}; +pub(crate) mod addresses; pub mod mmio; pub(crate) mod rom; -pub(crate) type Address = u16; - pub struct Memory where ColourFormat: From + Clone, @@ -124,132 +124,148 @@ where } } - pub fn get(&self, address: Address) -> u8 { + pub(crate) fn get(&self, address: T) -> u8 + where + T: Into
, + { + let address: Address = address.into(); match address { - 0x0..0x8000 => { + Address::Rom(address) => { // rom access // todo - switchable rom banks - if let Some(bootrom) = &self.bootrom && (address as usize) < bootrom.len() { - bootrom[address as usize] + if let Some(bootrom) = &self.bootrom && (address.inner() as usize) < bootrom.len() { + bootrom[address.inner() as usize] } else { self.rom.get(address) } } - 0x8000..0xA000 => self.gpu.vram.get(address), - 0xA000..0xC000 => { - // cart ram - self.rom.get_ram(address) - } - 0xC000..0xE000 => self.ram[(address - 0xC000) as usize], - 0xE000..0xFE00 => self.ram[(address - 0xE000) as usize], - 0xFE00..0xFEA0 => self.gpu.oam.get(address), - 0xFEA0..0xFF00 => 0xFF, - 0xFF00..0xFF4C => self.get_io(address), - 0xFF4C..0xFF80 => 0xFF, - 0xFF80..0xFFFF => self.cpu_ram[(address - 0xFF80) as usize], - 0xFFFF => self.interrupts.get_enable_register(), + Address::Vram(address) => self.gpu.vram.get(address), + Address::CartRam(address) => self.rom.get_ram(address), + Address::WorkRam(address) => self.ram[address.get_local() as usize], + Address::BankedWorkRam(address) => self.ram[(address.get_local() + 0x1000) as usize], + Address::MirroredRam(address) => self.ram[address.get_local() as usize], + Address::Oam(address) => self.gpu.oam.get(address), + Address::Prohibited(_) => 0xFF, + Address::Io(address) => self.get_io(address), + Address::Hram(address) => self.cpu_ram[address.get_local() as usize], + Address::InterruptEnable(_) => self.interrupts.get_enable_register(), } } - pub fn set(&mut self, address: Address, data: u8) { + pub(crate) fn set(&mut self, address: T, data: u8) + where + T: Into
, + { + let address: Address = address.into(); match address { - 0x0..0x8000 => { - // change this with MBC code... + Address::Rom(address) => { self.rom.set(address, data); if self.rom.can_rumble() { // rumble self.gpu.window.set_rumble(self.rom.is_rumbling()) } } - 0x8000..0xA000 => self.gpu.vram.set(address, data), - 0xA000..0xC000 => self.rom.set_ram(address, data), - 0xC000..0xE000 => self.ram[(address - 0xC000) as usize] = data, - 0xE000..0xFE00 => self.ram[(address - 0xE000) as usize] = data, - 0xFE00..0xFEA0 => self.gpu.oam.set(address, data), - 0xFEA0..0xFF00 => {} - 0xFF00..0xFF4C => self.set_io(address, data), - 0xFF50 => self.bootrom = None, - 0xFF4C..0xFF50 | 0xFF51..0xFF80 => {} - 0xFF80..0xFFFF => self.cpu_ram[(address - 0xFF80) as usize] = data, - 0xFFFF => { - verbose_println!("interrupts set to {:#b}", data); - verbose_println!(" / {:#X}", data); - self.interrupts.set_enable_register(data); + Address::Vram(address) => self.gpu.vram.set(address, data), + Address::CartRam(address) => self.rom.set_ram(address, data), + Address::WorkRam(address) => self.ram[address.get_local() as usize] = data, + Address::BankedWorkRam(address) => { + self.ram[(address.get_local() + 0x1000) as usize] = data } + Address::MirroredRam(address) => self.ram[address.get_local() as usize] = data, + Address::Oam(address) => self.gpu.oam.set(address, data), + Address::Prohibited(_) => {} + Address::Io(address) => { + if address.inner() == 0xFF50 { + self.bootrom = None + } + self.set_io(address, data) + } + Address::Hram(address) => self.cpu_ram[address.get_local() as usize] = data, + Address::InterruptEnable(_) => self.interrupts.set_enable_register(data), } } - fn get_io(&self, address: Address) -> u8 { - // range: 0xFF00 - 0xFF4B inclusive + fn get_io(&self, address: IoAddress) -> u8 { match address { - 0xFF00 => self.joypad.as_register(), - 0xFF01 => self.serial.get_queued(), - 0xFF02 => self.serial.get_control(), - 0xFF04 => self.timers.get_div(), - 0xFF05 => self.timers.get_tima(), - 0xFF06 => self.timers.get_tma(), - 0xFF07 => self.timers.get_timer_control(), - 0xFF0F => self.interrupts.get_flag_register(), - 0xFF10..0xFF40 => self.apu.get_register(address), - 0xFF40 => self.gpu.get_lcdc(), - 0xFF41 => self.gpu.get_lcd_status(), - 0xFF42 => self.gpu.get_scy(), - 0xFF43 => self.gpu.get_scx(), - 0xFF44 => self.gpu.get_ly(), - 0xFF45 => self.gpu.get_lyc(), - 0xFF46 => self.dma_addr, - 0xFF47 => self.gpu.get_bg_palette(), - 0xFF48 => self.gpu.get_obj_palette_0(), - 0xFF49 => self.gpu.get_obj_palette_1(), - 0xFF4A => self.gpu.get_wy(), - 0xFF4B => self.gpu.get_wx(), - 0xFF03 | 0xFF08..0xFF0F => 0xFF, - 0x0..0xFF00 | 0xFF4C..=0xFFFF => panic!("passed wrong address to get_io"), + IoAddress::Joypad => self.joypad.as_register(), + IoAddress::Serial(address) => match address.inner() { + 0xFF01 => self.serial.get_queued(), + 0xFF02 => self.serial.get_control(), + _ => unreachable!(), + }, + IoAddress::Timer(address) => match address.inner() { + 0xFF04 => self.timers.get_div(), + 0xFF05 => self.timers.get_tima(), + 0xFF06 => self.timers.get_tma(), + 0xFF07 => self.timers.get_timer_control(), + _ => unreachable!(), + }, + IoAddress::InterruptFlag => self.interrupts.get_flag_register(), + IoAddress::Audio(address) => self.apu.get_register(address), + IoAddress::WaveRam(address) => self.apu.get_wave_ram_register(address), + IoAddress::Video(address) => match address.inner() { + 0xFF40 => self.gpu.get_lcdc(), + 0xFF41 => self.gpu.get_lcd_status(), + 0xFF42 => self.gpu.get_scy(), + 0xFF43 => self.gpu.get_scx(), + 0xFF44 => self.gpu.get_ly(), + 0xFF45 => self.gpu.get_lyc(), + 0xFF46 => self.dma_addr, + 0xFF47 => self.gpu.get_bg_palette(), + 0xFF48 => self.gpu.get_obj_palette_0(), + 0xFF49 => self.gpu.get_obj_palette_1(), + 0xFF4A => self.gpu.get_wy(), + 0xFF4B => self.gpu.get_wx(), + _ => unreachable!(), + }, + IoAddress::Unused(_) => 0xFF, } } - fn set_io(&mut self, address: Address, data: u8) { - // range: 0xFF00 - 0xFF4B inclusive + fn set_io(&mut self, address: IoAddress, data: u8) { match address { - 0xFF00 => { - // joypad - self.joypad.mmio_write(data); - } - 0xFF01 => self.serial.update_queued(data), - 0xFF02 => self.serial.update_control(data), - 0xFF04 => self.timers.update_div(), - 0xFF05 => self.timers.update_tima(data), - 0xFF06 => self.timers.update_tma(data), - 0xFF07 => self.timers.update_timer_control(data), - 0xFF0F => self.interrupts.set_flag_register(data), - 0xFF10..0xFF40 => self.apu.mmio_write(address, data), - 0xFF40 => self.gpu.update_lcdc(data), - 0xFF41 => self.gpu.update_lcd_status(data), - 0xFF42 => self.gpu.update_scy(data), - 0xFF43 => self.gpu.update_scx(data), - 0xFF45 => self.gpu.update_lyc(data), - 0xFF46 => { - if data > 0xDF { - panic!("dma transfer out of bounds: {data:#X}"); + IoAddress::Joypad => self.joypad.mmio_write(data), + IoAddress::Serial(address) => match address.inner() { + 0xFF01 => self.serial.update_queued(data), + 0xFF02 => self.serial.update_control(data), + _ => unreachable!(), + }, + IoAddress::Timer(address) => match address.inner() { + 0xFF04 => self.timers.update_div(), + 0xFF05 => self.timers.update_tima(data), + 0xFF06 => self.timers.update_tma(data), + 0xFF07 => self.timers.update_timer_control(data), + _ => unreachable!(), + }, + IoAddress::InterruptFlag => self.interrupts.set_flag_register(data), + IoAddress::Audio(address) => self.apu.mmio_write(address, data), + IoAddress::WaveRam(address) => self.apu.mmio_write_wave_ram(address, data), + IoAddress::Video(address) => match address.inner() { + 0xFF40 => self.gpu.update_lcdc(data), + 0xFF41 => self.gpu.update_lcd_status(data), + 0xFF42 => self.gpu.update_scy(data), + 0xFF43 => self.gpu.update_scx(data), + 0xFF45 => self.gpu.update_lyc(data), + 0xFF46 => { + if data > 0xDF { + panic!("dma transfer out of bounds: {data:#X}"); + } + self.dma_addr = data; + let mut addr: u16 = 0x0; + addr.set_high(data); + for l in 0x0..0xA0 { + addr.set_low(l); + self.gpu.oam.data[l as usize] = self.get(addr); + } } - self.dma_addr = data; - let mut addr: u16 = 0x0; - addr.set_high(data); - for l in 0x0..0xA0 { - addr.set_low(l); - self.gpu.oam.data[l as usize] = self.get(addr); - } - } - 0xFF47 => self.gpu.update_bg_palette(data), - 0xFF48 => self.gpu.update_obj_palette_0(data), - 0xFF49 => self.gpu.update_obj_palette_1(data), - 0xFF4A => self.gpu.update_wy(data), - 0xFF4B => self.gpu.update_wx(data), - 0xFF03 | 0xFF08..0xFF0F | 0xFF44 => { - // read-only addresses - verbose_println!("BANNED write: {data:#X} to {address:#X}"); - } - 0x0..0xFF00 | 0xFF4C..=u16::MAX => panic!("passed wrong address to set_io"), + 0xFF47 => self.gpu.update_bg_palette(data), + 0xFF48 => self.gpu.update_obj_palette_0(data), + 0xFF49 => self.gpu.update_obj_palette_1(data), + 0xFF4A => self.gpu.update_wy(data), + 0xFF4B => self.gpu.update_wx(data), + _ => unreachable!(), + }, + IoAddress::Unused(_) => {} } } diff --git a/lib/src/processor/memory/addresses.rs b/lib/src/processor/memory/addresses.rs new file mode 100644 index 0000000..0da8ea7 --- /dev/null +++ b/lib/src/processor/memory/addresses.rs @@ -0,0 +1,167 @@ +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 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 AddressMarker for RomAddress { + fn inner(&self) -> u16 { + match self { + RomAddress::Bank0(v) => v.inner(), + RomAddress::MappedBank(v) => v.inner(), + } + } +} + +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 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())), + 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
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() + } +} diff --git a/lib/src/processor/memory/addresses/types.rs b/lib/src/processor/memory/addresses/types.rs new file mode 100644 index 0000000..0a72287 --- /dev/null +++ b/lib/src/processor/memory/addresses/types.rs @@ -0,0 +1,65 @@ +use std::ops::{Add, Sub}; + +#[derive(Debug)] +pub(crate) enum AddressError { + OutOfBounds, +} + +#[derive(Copy, Clone)] +pub(crate) struct BoundedAddress(u16); + +impl Add for BoundedAddress { + type Output = Option>; + + fn add(self, rhs: u16) -> Self::Output { + (self.0 + rhs).try_into().ok() + } +} + +impl Sub for BoundedAddress { + type Output = Option>; + + fn sub(self, rhs: u16) -> Self::Output { + (self.0 - rhs).try_into().ok() + } +} + +impl TryInto> for u16 { + type Error = AddressError; + + fn try_into(self) -> Result, Self::Error> { + if self >= MIN && self < MAX { + Ok(BoundedAddress(self)) + } else { + Err(AddressError::OutOfBounds) + } + } +} + +impl BoundedAddress { + pub(crate) fn get_local(&self) -> u16 { + self.0 - MIN + } +} + +impl PartialEq for BoundedAddress { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl PartialOrd for BoundedAddress { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +pub(crate) trait AddressMarker { + fn inner(&self) -> u16; +} + +impl AddressMarker for BoundedAddress { + fn inner(&self) -> u16 { + self.0 + } +} diff --git a/lib/src/processor/memory/mmio/apu.rs b/lib/src/processor/memory/mmio/apu.rs index 35aee38..d52505d 100644 --- a/lib/src/processor/memory/mmio/apu.rs +++ b/lib/src/processor/memory/mmio/apu.rs @@ -4,7 +4,7 @@ use self::{ }; use crate::{ connect::AudioOutput, - processor::memory::Address, + processor::memory::addresses::{AddressMarker, AudioAddress, WaveRamAddress}, util::{get_bit, set_or_clear_bit}, }; use futures::executor; @@ -185,11 +185,11 @@ impl Apu { self.output.send_rb.is_full() } - pub fn get_register(&self, addr: Address) -> u8 { + pub(crate) fn get_register(&self, addr: AudioAddress) -> u8 { if self.apu_enable { self.make_register(addr) } else { - match addr { + match addr.inner() { 0xFF26 | 0xFF11 | 0xFF16 | 0xFF1B | 0xFF20 | 0xFF30..0xFF40 => { self.make_register(addr) } @@ -198,8 +198,12 @@ impl Apu { } } - fn make_register(&self, addr: Address) -> u8 { - match addr { + pub(crate) fn get_wave_ram_register(&self, addr: WaveRamAddress) -> u8 { + self.channels.three.wave_ram.data[addr.get_local() as usize] + } + + fn make_register(&self, addr: AudioAddress) -> u8 { + match addr.inner() { 0xFF10 => self.channels.one.get_sweep_register(), 0xFF11 => self.channels.one.get_length_timer_and_duty_cycle(), 0xFF12 => self.channels.one.get_volume_and_envelope(), @@ -250,15 +254,13 @@ impl Apu { // write-only registers 0xFF13 | 0xFF18 | 0xFF1B | 0xFF1D | 0xFF20 => 0xFF, // not registers - 0xFF15 | 0xFF1F | 0xFF27..0xFF30 => 0xFF, - // wave ram - 0xFF30..0xFF40 => self.channels.three.wave_ram.data[(addr - 0xFF30) as usize], - 0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"), + 0xFF15 | 0xFF1F => 0xFF, + _ => unreachable!(), } } - pub fn mmio_write(&mut self, addr: Address, data: u8) { - match addr { + pub(crate) fn mmio_write(&mut self, addr: AudioAddress, data: u8) { + match addr.inner() { 0xFF10 => self.channels.one.update_sweep(data), 0xFF11 => self.channels.one.update_length_timer_and_duty_cycle(data), 0xFF12 => self.channels.one.update_volume_and_envelope(data), @@ -296,17 +298,19 @@ impl Apu { 0xFF26 => { if !self.apu_enable { for i in 0xFF10..0xFF20 { - self.mmio_write(i, 0x0); + self.mmio_write(i.try_into().unwrap(), 0x0); } for i in 0xFF21..0xFF25 { - self.mmio_write(i, 0x0); + self.mmio_write(i.try_into().unwrap(), 0x0); } } self.apu_enable = (1 << 7) == (data & 0b10000000); } - 0xFF30..0xFF40 => self.channels.three.update_wave_ram(addr, data), - 0xFF15 | 0xFF1F | 0xFF27..0xFF30 => {} - 0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"), + _ => unreachable!(), } } + + pub(crate) fn mmio_write_wave_ram(&mut self, addr: WaveRamAddress, data: u8) { + self.channels.three.update_wave_ram(addr, data); + } } diff --git a/lib/src/processor/memory/mmio/apu/channels.rs b/lib/src/processor/memory/mmio/apu/channels.rs index 7d2ecd3..c4d7b6c 100644 --- a/lib/src/processor/memory/mmio/apu/channels.rs +++ b/lib/src/processor/memory/mmio/apu/channels.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::{ - processor::memory::Address, + processor::memory::addresses::WaveRamAddress, util::{get_bit, set_or_clear_bit, Nibbles}, }; @@ -461,8 +461,8 @@ impl WaveChannel { set_or_clear_bit(0xFF, 6, self.length_enable) } - pub(super) fn update_wave_ram(&mut self, addr: Address, data: u8) { - let real_addr = (addr - 0xFF30) as usize; + pub(super) fn update_wave_ram(&mut self, addr: WaveRamAddress, data: u8) { + let real_addr = addr.get_local() as usize; if real_addr >= self.wave_ram.data.len() { panic!("sent the wrong address to update_wave_ram"); } diff --git a/lib/src/processor/memory/mmio/gpu.rs b/lib/src/processor/memory/mmio/gpu.rs index be64f2c..ba0eb3b 100644 --- a/lib/src/processor/memory/mmio/gpu.rs +++ b/lib/src/processor/memory/mmio/gpu.rs @@ -332,17 +332,17 @@ where let mut objs = vec![]; let effective_scanline = scanline + 16; for i in (0xFE00..0xFE9F).step_by(4) { - let y_pos = self.oam.get(i); + let y_pos = self.oam.get(i.try_into().unwrap()); if y_pos <= effective_scanline && (y_pos + self.lcdc.obj_size.get_height()) > effective_scanline { // sprite is on line - let x_pos = self.oam.get(i + 1); - let mut tile_index = self.oam.get(i + 2); + let x_pos = self.oam.get((i + 1).try_into().unwrap()); + let mut tile_index = self.oam.get((i + 2).try_into().unwrap()); if self.lcdc.obj_size == ObjSize::S8x16 { tile_index = clear_bit(tile_index, 0); } - let flags = self.oam.get(i + 3); + let flags = self.oam.get((i + 3).try_into().unwrap()); objs.push(Object { x: x_pos, y: y_pos, @@ -380,11 +380,12 @@ where object_row = self.lcdc.obj_size.get_height() - (object_row + 1); } let tile_row = object_row % 8; - let tile_addr = TiledataArea::D8000 + let tile_addr = (TiledataArea::D8000 .get_addr(object.tile_index + if object_row >= 8 { 1 } else { 0 }) - + (tile_row as u16 * 2); + + (tile_row as u16 * 2)) + .unwrap(); let lsbs = self.vram.get(tile_addr); - let msbs = self.vram.get(tile_addr + 1); + let msbs = self.vram.get((tile_addr + 1).unwrap()); for px_x in 0..8 { let x_addr = if object.flags.x_flip { px_x } else { 7 - px_x }; let lsb = get_bit(lsbs, x_addr); @@ -437,14 +438,15 @@ where let tilemap_column = (tile_line_x / 8) as u16; let tile_px_x = tile_line_x % 8; - let tile_addr = self + let tile_addr = (self .lcdc .tile_area .get_addr(self.vram.get(tilemap.get_addr(row_addr + (tilemap_column)))) - + tiledata_offset as u16; + + tiledata_offset as u16) + .unwrap(); let lsbs = self.vram.get(tile_addr); - let msbs = self.vram.get(tile_addr + 1); + let msbs = self.vram.get((tile_addr + 1).unwrap()); let lsb = get_bit(lsbs, 7 - tile_px_x); let msb = get_bit(msbs, 7 - tile_px_x); let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb); diff --git a/lib/src/processor/memory/mmio/gpu/tile_window.rs b/lib/src/processor/memory/mmio/gpu/tile_window.rs index 03cdbdc..eac80cd 100644 --- a/lib/src/processor/memory/mmio/gpu/tile_window.rs +++ b/lib/src/processor/memory/mmio/gpu/tile_window.rs @@ -61,9 +61,9 @@ where for tile_x in 0..16 { let tile_num = (tile_y * 16) + tile_x; let data_begin = area.get_addr(tile_num); - for px_y in 0..8 { - let lsbs = memory.get((px_y * 2) + data_begin); - let msbs = memory.get((px_y * 2) + data_begin + 1); + for px_y in 0..8_u16 { + let lsbs = memory.get((data_begin + (px_y * 2)).unwrap()); + let msbs = memory.get((data_begin + (1 + (px_y * 2))).unwrap()); for px_x in 0..8 { let real_px_y = (display_y * 8) + px_y as usize; let real_px_x = (tile_x as usize * 8) + px_x as usize; diff --git a/lib/src/processor/memory/mmio/gpu/types.rs b/lib/src/processor/memory/mmio/gpu/types.rs index ae22c94..877c3cb 100644 --- a/lib/src/processor/memory/mmio/gpu/types.rs +++ b/lib/src/processor/memory/mmio/gpu/types.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::{ - processor::memory::Address, + processor::memory::addresses::{OamAddress, VramAddress}, util::{as_signed, get_bit}, }; @@ -20,10 +20,10 @@ pub(super) enum TilemapArea { } impl TilemapArea { - pub(super) fn get_addr(&self, addr: u16) -> u16 { + pub(super) fn get_addr(&self, addr: u16) -> VramAddress { match self { - TilemapArea::T9800 => 0x9800 + addr, - TilemapArea::T9C00 => 0x9C00 + addr, + TilemapArea::T9800 => (0x9800 + addr).try_into().unwrap(), + TilemapArea::T9C00 => (0x9C00 + addr).try_into().unwrap(), } } } @@ -35,10 +35,13 @@ pub(super) enum TiledataArea { } impl TiledataArea { - pub(super) fn get_addr(&self, addr: u8) -> u16 { + pub(super) fn get_addr(&self, addr: u8) -> VramAddress { match self { - TiledataArea::D8000 => 0x8000 + ((addr as u16) * 16), - TiledataArea::D9000 => 0x9000_u16.wrapping_add_signed((as_signed(addr) as i16) * 16), + TiledataArea::D8000 => (0x8000 + ((addr as u16) * 16)).try_into().unwrap(), + TiledataArea::D9000 => 0x9000_u16 + .wrapping_add_signed((as_signed(addr) as i16) * 16) + .try_into() + .unwrap(), } } } @@ -224,12 +227,12 @@ pub struct Vram { } impl Vram { - pub fn get(&self, address: Address) -> u8 { - self.data[(address - 0x8000) as usize] + pub(crate) fn get(&self, address: VramAddress) -> u8 { + self.data[address.get_local() as usize] } - pub fn set(&mut self, address: Address, data: u8) { - self.data[(address - 0x8000) as usize] = data; + pub(crate) fn set(&mut self, address: VramAddress, data: u8) { + self.data[address.get_local() as usize] = data; } } @@ -247,12 +250,12 @@ pub struct Oam { } impl Oam { - pub fn get(&self, address: Address) -> u8 { - self.data[(address - 0xFE00) as usize] + pub(crate) fn get(&self, address: OamAddress) -> u8 { + self.data[address.get_local() as usize] } - pub fn set(&mut self, address: Address, data: u8) { - self.data[(address - 0xFE00) as usize] = data; + pub(crate) fn set(&mut self, address: OamAddress, data: u8) { + self.data[address.get_local() as usize] = data; } } diff --git a/lib/src/processor/memory/rom.rs b/lib/src/processor/memory/rom.rs index 197aac0..922a490 100644 --- a/lib/src/processor/memory/rom.rs +++ b/lib/src/processor/memory/rom.rs @@ -1,9 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::{ - connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait}, - processor::memory::Address, -}; +use crate::connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait}; use std::{ fs::{File, OpenOptions}, io::{Read, Seek, SeekFrom, Write}, @@ -17,6 +14,8 @@ use self::mbcs::{ PocketCamera, PocketCameraSaveState, }; +use super::addresses::{CartRamAddress, RomAddress}; + mod mbcs; struct MaybeBufferedSram { @@ -249,19 +248,19 @@ where &self.title } - pub(super) fn get(&self, address: Address) -> u8 { + pub(super) fn get(&self, address: RomAddress) -> u8 { self.mbc.get(address) } - pub(super) fn get_ram(&self, address: Address) -> u8 { + pub(super) fn get_ram(&self, address: CartRamAddress) -> u8 { self.mbc.get_ram(address) } - pub(super) fn set(&mut self, address: Address, data: u8) { + pub(super) fn set(&mut self, address: RomAddress, data: u8) { self.mbc.set(address, data); } - pub(super) fn set_ram(&mut self, address: Address, data: u8) { + pub(super) fn set_ram(&mut self, address: CartRamAddress, data: u8) { self.mbc.set_ram(address, data); } diff --git a/lib/src/processor/memory/rom/mbcs.rs b/lib/src/processor/memory/rom/mbcs.rs index 60cf897..bd2fd1d 100644 --- a/lib/src/processor/memory/rom/mbcs.rs +++ b/lib/src/processor/memory/rom/mbcs.rs @@ -1,4 +1,4 @@ -use crate::processor::memory::Address; +use crate::processor::memory::addresses::{CartRamAddress, RomAddress}; mod mbc1; mod mbc2; @@ -21,11 +21,11 @@ const RAM_BANK_SIZE: usize = 8 * KB; pub(super) trait Mbc: Send { // addresses 0x0000 - 0x7FFF - fn get(&self, address: Address) -> u8; + fn get(&self, address: RomAddress) -> u8; // addresses 0xA000 - 0xBFFF - fn get_ram(&self, address: Address) -> u8; - fn set(&mut self, address: Address, data: u8); - fn set_ram(&mut self, address: Address, data: u8); + fn get_ram(&self, address: CartRamAddress) -> u8; + fn set(&mut self, address: RomAddress, data: u8); + fn set_ram(&mut self, address: CartRamAddress, data: u8); fn mbc_type(&self) -> String; fn get_save_state(&self) -> MbcSaveState; fn is_rumbling(&self) -> bool { diff --git a/lib/src/processor/memory/rom/mbcs/mbc1.rs b/lib/src/processor/memory/rom/mbcs/mbc1.rs index a8b57e3..5dbae92 100644 --- a/lib/src/processor/memory/rom/mbcs/mbc1.rs +++ b/lib/src/processor/memory/rom/mbcs/mbc1.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; use crate::processor::memory::{ + addresses::{AddressMarker, CartRamAddress, RomAddress}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, - Address, }; #[derive(Clone, Copy, Serialize, Deserialize)] @@ -53,39 +53,32 @@ impl Mbc1 { } } - fn get_rom_addr(&self, address: Address) -> usize { + fn get_rom_addr(&self, address: RomAddress) -> usize { (match address { - 0x0..0x4000 => match self.bank_mode { - BankingMode::Simple => address as usize, + RomAddress::Bank0(address) => match self.bank_mode { + BankingMode::Simple => address.inner() as usize, BankingMode::Advanced => { - (address as usize) + (self.upper_banks as usize * 512 * KB) + (address.inner() as usize) + (self.upper_banks as usize * 512 * KB) } }, - 0x4000..0x8000 => { - (address - 0x4000) as usize + RomAddress::MappedBank(address) => { + (address.get_local() as usize) + (ROM_BANK_SIZE * self.rom_bank as usize) + (self.upper_banks as usize * 512 * KB) } - - 0xA000..0xC000 => panic!("passed ram address to rom address function"), - _ => panic!("address {address} incompatible with MBC"), } % self.rom_len) } - fn get_ram_addr(&self, address: Address) -> usize { - match address { - 0x0..0x8000 => panic!("passed rom address to ram address function"), - 0xA000..0xC000 => match self.bank_mode { - BankingMode::Simple => { - (address - 0xA000) as usize + (RAM_BANK_SIZE * self.ram_bank as usize) - } - BankingMode::Advanced => { - (address - 0xA000) as usize - + (RAM_BANK_SIZE * self.ram_bank as usize) - + (self.upper_banks as usize * 16 * KB) - } - }, - _ => panic!("address {address} incompatible with MBC"), + fn get_ram_addr(&self, address: CartRamAddress) -> usize { + match self.bank_mode { + BankingMode::Simple => { + (address.get_local() as usize) + (RAM_BANK_SIZE * self.ram_bank as usize) + } + BankingMode::Advanced => { + (address.get_local() as usize) + + (RAM_BANK_SIZE * self.ram_bank as usize) + + (self.upper_banks as usize * 16 * KB) + } } } @@ -104,11 +97,11 @@ impl Mbc1 { } impl Mbc for Mbc1 { - fn get(&self, address: Address) -> u8 { + fn get(&self, address: RomAddress) -> u8 { self.data[self.get_rom_addr(address)] } - fn get_ram(&self, address: Address) -> u8 { + fn get_ram(&self, address: CartRamAddress) -> u8 { if self.ram_enabled && let Some(ram) = &self.ram { let addr = self.get_ram_addr(address) % ram.len(); return ram.get(addr); @@ -116,7 +109,7 @@ impl Mbc for Mbc1 { 0xFF } - fn set_ram(&mut self, address: Address, data: u8) { + fn set_ram(&mut self, address: CartRamAddress, data: u8) { let mut addr = self.get_ram_addr(address); if self.ram_enabled && let Some(ram) = &mut self.ram { addr %= ram.len(); @@ -124,8 +117,8 @@ impl Mbc for Mbc1 { } } - fn set(&mut self, address: Address, data: u8) { - match address { + fn set(&mut self, address: RomAddress, data: u8) { + match address.inner() { 0x0..0x2000 => { // enable/disable ram self.ram_enabled = (data & 0x0F) == 0xA; diff --git a/lib/src/processor/memory/rom/mbcs/mbc2.rs b/lib/src/processor/memory/rom/mbcs/mbc2.rs index 84279c6..a8f0435 100644 --- a/lib/src/processor/memory/rom/mbcs/mbc2.rs +++ b/lib/src/processor/memory/rom/mbcs/mbc2.rs @@ -3,8 +3,8 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; use crate::processor::memory::{ + addresses::{AddressMarker, CartRamAddress, RomAddress}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, - Address, }; use super::{rom_banks, Mbc, ROM_BANK_SIZE}; @@ -51,28 +51,27 @@ impl Mbc2 { } impl Mbc for Mbc2 { - fn get(&self, address: Address) -> u8 { + fn get(&self, address: RomAddress) -> u8 { match address { - 0x0..0x4000 => self.data[address as usize], - 0x4000..0x8000 => { - self.data[((address as usize - 0x4000) + (0x4000 * self.rom_bank as usize)) + RomAddress::Bank0(address) => self.data[address.inner() as usize], + RomAddress::MappedBank(address) => { + self.data[((address.get_local() as usize) + (0x4000 * self.rom_bank as usize)) % self.rom_len] } - _ => panic!("passed wrong address to mbc"), } } - fn get_ram(&self, address: Address) -> u8 { + fn get_ram(&self, address: CartRamAddress) -> u8 { if self.ram_enabled { - 0xF0 | (0x0F & self.ram.get((address - 0xA000) as usize % 512)) + 0xF0 | (0x0F & self.ram.get((address.get_local() as usize) % 512)) } else { 0xFF } } - fn set(&mut self, address: Address, data: u8) { - if address < 0x4000 { - if address & (1 << 8) == (1 << 8) { + fn set(&mut self, address: RomAddress, data: u8) { + if let RomAddress::Bank0(_) = address { + if address.inner() & (1 << 8) == (1 << 8) { // bit 8 is set - rom bank self.rom_bank = data & 0xF; if self.rom_bank == 0 { @@ -85,9 +84,9 @@ impl Mbc for Mbc2 { } } - fn set_ram(&mut self, address: Address, data: u8) { + fn set_ram(&mut self, address: CartRamAddress, data: u8) { if self.ram_enabled { - self.ram.set((address - 0xA000) as usize % 512, data); + self.ram.set((address.get_local() as usize) % 512, data); } } diff --git a/lib/src/processor/memory/rom/mbcs/mbc3.rs b/lib/src/processor/memory/rom/mbcs/mbc3.rs index 92b1022..7a6ddb9 100644 --- a/lib/src/processor/memory/rom/mbcs/mbc3.rs +++ b/lib/src/processor/memory/rom/mbcs/mbc3.rs @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize}; use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; use crate::{ processor::memory::{ + addresses::{AddressMarker, CartRamAddress, RomAddress}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, - Address, }, util::set_or_clear_bit, }; @@ -127,19 +127,18 @@ impl Mbc3 { } } - fn get_rom_addr(&self, address: Address) -> usize { + fn get_rom_addr(&self, address: RomAddress) -> usize { (match address { - 0x0..0x4000 => address as usize, - 0x4000..0x8000 => { - let internal_addr = address as usize - 0x4000; + RomAddress::Bank0(address) => address.inner() as usize, + RomAddress::MappedBank(address) => { + let internal_addr = address.get_local() as usize; internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize) } - _ => panic!("address {address} incompatible with MBC"), } % self.rom_size) } - fn get_ram_addr(&self, address: Address, ram_bank: usize) -> usize { - ((address as usize - 0xA000) + (RAM_BANK_SIZE * ram_bank)) % self.ram_size + fn get_ram_addr(&self, address: CartRamAddress, ram_bank: usize) -> usize { + ((address.get_local() as usize) + (RAM_BANK_SIZE * ram_bank)) % self.ram_size } pub fn from_save_state(state: Mbc3SaveState, data: Vec) -> Self { @@ -158,11 +157,11 @@ impl Mbc3 { } impl Mbc for Mbc3 { - fn get(&self, address: Address) -> u8 { + fn get(&self, address: RomAddress) -> u8 { self.data[self.get_rom_addr(address)] } - fn get_ram(&self, address: Address) -> u8 { + fn get_ram(&self, address: CartRamAddress) -> u8 { if self.ram_enabled { match &self.ram_bank { RamBank::Ram(ram_bank) => { @@ -180,8 +179,8 @@ impl Mbc for Mbc3 { 0xFF } - fn set(&mut self, address: Address, data: u8) { - match address { + fn set(&mut self, address: RomAddress, data: u8) { + match address.inner() { 0x0..0x2000 => { if data & 0xF == 0xA { self.ram_enabled = true; @@ -218,12 +217,11 @@ impl Mbc for Mbc3 { } } } - _ => panic!("unsupported addr"), } } - fn set_ram(&mut self, address: Address, data: u8) { + fn set_ram(&mut self, address: CartRamAddress, data: u8) { if self.ram_enabled { match &self.ram_bank { RamBank::Ram(ram_bank) => { diff --git a/lib/src/processor/memory/rom/mbcs/mbc5.rs b/lib/src/processor/memory/rom/mbcs/mbc5.rs index 7feb182..f421fbf 100644 --- a/lib/src/processor/memory/rom/mbcs/mbc5.rs +++ b/lib/src/processor/memory/rom/mbcs/mbc5.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; use crate::{ processor::memory::{ + addresses::{AddressMarker, CartRamAddress, RomAddress}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, - Address, }, util::get_bit, }; @@ -58,19 +58,18 @@ impl Mbc5 { } } - fn get_rom_addr(&self, address: Address) -> usize { + fn get_rom_addr(&self, address: RomAddress) -> usize { (match address { - 0x0..0x4000 => address as usize, - 0x4000..0x8000 => { - let internal_addr = address as usize - 0x4000; + RomAddress::Bank0(address) => address.inner() as usize, + RomAddress::MappedBank(address) => { + let internal_addr = address.get_local() as usize; internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize) } - _ => panic!("address {address} incompatible with MBC"), } % self.rom_size) } - fn get_ram_addr(&self, address: Address) -> usize { - ((address as usize - 0xA000) + (RAM_BANK_SIZE * self.ram_bank as usize)) % self.ram_size + fn get_ram_addr(&self, address: CartRamAddress) -> usize { + ((address.get_local() as usize) + (RAM_BANK_SIZE * self.ram_bank as usize)) % self.ram_size } pub fn from_save_state(state: Mbc5SaveState, data: Vec) -> Self { @@ -89,11 +88,11 @@ impl Mbc5 { } impl Mbc for Mbc5 { - fn get(&self, address: Address) -> u8 { + fn get(&self, address: RomAddress) -> u8 { self.data[self.get_rom_addr(address)] } - fn get_ram(&self, address: Address) -> u8 { + fn get_ram(&self, address: CartRamAddress) -> u8 { if self.ram_enabled && let Some(ram) = &self.ram { ram.get(self.get_ram_addr(address)) } else { @@ -101,8 +100,8 @@ impl Mbc for Mbc5 { } } - fn set(&mut self, address: Address, data: u8) { - match address { + fn set(&mut self, address: RomAddress, data: u8) { + match address.inner() { 0x0..0x2000 => { if (data & 0xF) == 0xA { self.ram_enabled = true @@ -121,11 +120,11 @@ impl Mbc for Mbc5 { } } 0x6000..0x8000 => {} - _ => panic!("address {address} incompatible with MBC"), + _ => panic!(), } } - fn set_ram(&mut self, address: Address, data: u8) { + fn set_ram(&mut self, address: CartRamAddress, data: u8) { let real_addr = self.get_ram_addr(address); if self.ram_enabled && let Some(ram) = &mut self.ram { ram.set(real_addr, data); diff --git a/lib/src/processor/memory/rom/mbcs/none.rs b/lib/src/processor/memory/rom/mbcs/none.rs index ba7ca79..f79dfe9 100644 --- a/lib/src/processor/memory/rom/mbcs/none.rs +++ b/lib/src/processor/memory/rom/mbcs/none.rs @@ -1,5 +1,8 @@ use super::Mbc; -use crate::processor::memory::{rom::MbcSaveState, Address}; +use crate::processor::memory::{ + addresses::{AddressMarker, CartRamAddress, RomAddress}, + rom::MbcSaveState, +}; pub struct None { data: Vec, @@ -12,17 +15,17 @@ impl None { } impl Mbc for None { - fn get(&self, address: Address) -> u8 { - self.data[address as usize] + fn get(&self, address: RomAddress) -> u8 { + self.data[address.inner() as usize] } - fn get_ram(&self, _address: Address) -> u8 { + fn get_ram(&self, _address: CartRamAddress) -> u8 { 0xFF } - fn set_ram(&mut self, _address: Address, _data: u8) {} + fn set_ram(&mut self, _address: CartRamAddress, _data: u8) {} - fn set(&mut self, _address: Address, _data: u8) {} + fn set(&mut self, _address: RomAddress, _data: u8) {} fn mbc_type(&self) -> String { String::from("None") diff --git a/lib/src/processor/memory/rom/mbcs/pocketcamera.rs b/lib/src/processor/memory/rom/mbcs/pocketcamera.rs index 0c9cc13..3299b19 100644 --- a/lib/src/processor/memory/rom/mbcs/pocketcamera.rs +++ b/lib/src/processor/memory/rom/mbcs/pocketcamera.rs @@ -2,8 +2,8 @@ use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; use crate::{ connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait}, processor::memory::{ + addresses::{AddressMarker, CartRamAddress, RomAddress}, rom::{MaybeBufferedSram, MbcSaveState}, - Address, }, }; use serde::{Deserialize, Serialize}; @@ -60,19 +60,18 @@ where } } - fn get_rom_addr(&self, address: Address) -> usize { + fn get_rom_addr(&self, address: RomAddress) -> usize { (match address { - 0x0..0x4000 => address as usize, - 0x4000..0x8000 => { - let internal_addr = address as usize - 0x4000; + RomAddress::Bank0(address) => address.inner() as usize, + RomAddress::MappedBank(address) => { + let internal_addr = address.get_local() as usize; internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize) } - _ => panic!("address {address} incompatible with MBC"), } % self.rom_size) } - fn get_ram_addr(&self, address: Address, bank: u8) -> usize { - ((address as usize - 0xA000) + (RAM_BANK_SIZE * bank as usize)) % self.ram_size + fn get_ram_addr(&self, address: CartRamAddress, bank: u8) -> usize { + ((address.get_local() as usize) + (RAM_BANK_SIZE * bank as usize)) % self.ram_size } pub(crate) fn from_save_state( @@ -83,8 +82,8 @@ where todo!(); } - fn get_cam_reg(&self, address: Address) -> u8 { - match address { + fn get_cam_reg(&self, address: CartRamAddress) -> u8 { + match address.inner() { 0xA000 => { (if self.camera.lock().unwrap().is_capturing() { 0x1 @@ -92,13 +91,13 @@ where 0x0 }) | self.extra_bits_a000 } - 0xA001..=0xA035 => self.camera_ram[(address - 0xA001) as usize], + 0xA001..=0xA035 => self.camera_ram[(address.inner() - 0xA001) as usize], _ => 0x00, } } - fn set_cam_reg(&mut self, address: Address, data: u8) { - match address { + fn set_cam_reg(&mut self, address: CartRamAddress, data: u8) { + match address.inner() { 0xA000 => { if data & 0x1 == 0x1 { self.camera.lock().unwrap().begin_capture(); @@ -106,7 +105,7 @@ where self.extra_bits_a000 = data & 0b110; } 0xA001..=0xA035 => { - self.camera_ram[(address - 0xA001) as usize] = data; + self.camera_ram[(address.inner() - 0xA001) as usize] = data; } _ => {} } @@ -127,11 +126,11 @@ impl Mbc for PocketCamera where C: PocketCameraTrait + Send, { - fn get(&self, address: Address) -> u8 { + fn get(&self, address: RomAddress) -> u8 { self.data[self.get_rom_addr(address)] } - fn get_ram(&self, address: Address) -> u8 { + fn get_ram(&self, address: CartRamAddress) -> u8 { match self.ram_bank { RamBank::Ram(bank) => { if let Some(ram) = &self.ram { @@ -144,9 +143,9 @@ where } } - fn set(&mut self, address: Address, data: u8) { + fn set(&mut self, address: RomAddress, data: u8) { self.check_for_new_image(); - match address { + match address.inner() { 0x0..0x2000 => { if (data & 0xF) == 0xA { self.ram_enabled = true @@ -167,11 +166,11 @@ where } } 0x6000..0x8000 => {} - _ => panic!("address {address} incompatible with MBC"), + _ => panic!(), } } - fn set_ram(&mut self, address: Address, data: u8) { + fn set_ram(&mut self, address: CartRamAddress, data: u8) { self.check_for_new_image(); match self.ram_bank { RamBank::Ram(bank) => {