address handling

This commit is contained in:
Alex Janka 2023-04-18 18:09:21 +10:00
parent 7448d18424
commit 828da3e01f
17 changed files with 506 additions and 259 deletions

View file

@ -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 crate::{processor::memory::Memory, util::pause};
use connect::{ use connect::{

View file

@ -1,5 +1,6 @@
pub use self::rom::Rom; pub use self::rom::Rom;
use self::{ use self::{
addresses::{Address, AddressMarker, IoAddress},
mmio::{ mmio::{
apu::ApuSaveState, apu::ApuSaveState,
gpu::{Colour, GpuSaveState}, gpu::{Colour, GpuSaveState},
@ -11,17 +12,16 @@ use self::{
use crate::{ use crate::{
connect::{AudioOutput, CameraWrapperRef, JoypadState, PocketCamera, Renderer, SerialTarget}, connect::{AudioOutput, CameraWrapperRef, JoypadState, PocketCamera, Renderer, SerialTarget},
processor::SplitRegister, processor::SplitRegister,
verbose_println, Cpu, Cpu,
}; };
mod interrupts; mod interrupts;
pub use interrupts::{Interrupt, Interrupts}; pub use interrupts::{Interrupt, Interrupts};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub(crate) mod addresses;
pub mod mmio; pub mod mmio;
pub(crate) mod rom; pub(crate) mod rom;
pub(crate) type Address = u16;
pub struct Memory<ColourFormat, R, C> pub struct Memory<ColourFormat, R, C>
where where
ColourFormat: From<Colour> + Clone, ColourFormat: From<Colour> + Clone,
@ -124,132 +124,148 @@ where
} }
} }
pub fn get(&self, address: Address) -> u8 { pub(crate) fn get<T>(&self, address: T) -> u8
where
T: Into<Address>,
{
let address: Address = address.into();
match address { match address {
0x0..0x8000 => { Address::Rom(address) => {
// rom access // rom access
// todo - switchable rom banks // todo - switchable rom banks
if let Some(bootrom) = &self.bootrom && (address as usize) < bootrom.len() { if let Some(bootrom) = &self.bootrom && (address.inner() as usize) < bootrom.len() {
bootrom[address as usize] bootrom[address.inner() as usize]
} else { } else {
self.rom.get(address) self.rom.get(address)
} }
} }
0x8000..0xA000 => self.gpu.vram.get(address), Address::Vram(address) => self.gpu.vram.get(address),
0xA000..0xC000 => { Address::CartRam(address) => self.rom.get_ram(address),
// cart ram Address::WorkRam(address) => self.ram[address.get_local() as usize],
self.rom.get_ram(address) Address::BankedWorkRam(address) => self.ram[(address.get_local() + 0x1000) as usize],
} Address::MirroredRam(address) => self.ram[address.get_local() as usize],
0xC000..0xE000 => self.ram[(address - 0xC000) as usize], Address::Oam(address) => self.gpu.oam.get(address),
0xE000..0xFE00 => self.ram[(address - 0xE000) as usize], Address::Prohibited(_) => 0xFF,
0xFE00..0xFEA0 => self.gpu.oam.get(address), Address::Io(address) => self.get_io(address),
0xFEA0..0xFF00 => 0xFF, Address::Hram(address) => self.cpu_ram[address.get_local() as usize],
0xFF00..0xFF4C => self.get_io(address), Address::InterruptEnable(_) => self.interrupts.get_enable_register(),
0xFF4C..0xFF80 => 0xFF,
0xFF80..0xFFFF => self.cpu_ram[(address - 0xFF80) as usize],
0xFFFF => self.interrupts.get_enable_register(),
} }
} }
pub fn set(&mut self, address: Address, data: u8) { pub(crate) fn set<T>(&mut self, address: T, data: u8)
where
T: Into<Address>,
{
let address: Address = address.into();
match address { match address {
0x0..0x8000 => { Address::Rom(address) => {
// change this with MBC code...
self.rom.set(address, data); self.rom.set(address, data);
if self.rom.can_rumble() { if self.rom.can_rumble() {
// rumble // rumble
self.gpu.window.set_rumble(self.rom.is_rumbling()) self.gpu.window.set_rumble(self.rom.is_rumbling())
} }
} }
0x8000..0xA000 => self.gpu.vram.set(address, data), Address::Vram(address) => self.gpu.vram.set(address, data),
0xA000..0xC000 => self.rom.set_ram(address, data), Address::CartRam(address) => self.rom.set_ram(address, data),
0xC000..0xE000 => self.ram[(address - 0xC000) as usize] = data, Address::WorkRam(address) => self.ram[address.get_local() as usize] = data,
0xE000..0xFE00 => self.ram[(address - 0xE000) as usize] = data, Address::BankedWorkRam(address) => {
0xFE00..0xFEA0 => self.gpu.oam.set(address, data), self.ram[(address.get_local() + 0x1000) as usize] = 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::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 { fn get_io(&self, address: IoAddress) -> u8 {
// range: 0xFF00 - 0xFF4B inclusive
match address { match address {
0xFF00 => self.joypad.as_register(), IoAddress::Joypad => self.joypad.as_register(),
0xFF01 => self.serial.get_queued(), IoAddress::Serial(address) => match address.inner() {
0xFF02 => self.serial.get_control(), 0xFF01 => self.serial.get_queued(),
0xFF04 => self.timers.get_div(), 0xFF02 => self.serial.get_control(),
0xFF05 => self.timers.get_tima(), _ => unreachable!(),
0xFF06 => self.timers.get_tma(), },
0xFF07 => self.timers.get_timer_control(), IoAddress::Timer(address) => match address.inner() {
0xFF0F => self.interrupts.get_flag_register(), 0xFF04 => self.timers.get_div(),
0xFF10..0xFF40 => self.apu.get_register(address), 0xFF05 => self.timers.get_tima(),
0xFF40 => self.gpu.get_lcdc(), 0xFF06 => self.timers.get_tma(),
0xFF41 => self.gpu.get_lcd_status(), 0xFF07 => self.timers.get_timer_control(),
0xFF42 => self.gpu.get_scy(), _ => unreachable!(),
0xFF43 => self.gpu.get_scx(), },
0xFF44 => self.gpu.get_ly(), IoAddress::InterruptFlag => self.interrupts.get_flag_register(),
0xFF45 => self.gpu.get_lyc(), IoAddress::Audio(address) => self.apu.get_register(address),
0xFF46 => self.dma_addr, IoAddress::WaveRam(address) => self.apu.get_wave_ram_register(address),
0xFF47 => self.gpu.get_bg_palette(), IoAddress::Video(address) => match address.inner() {
0xFF48 => self.gpu.get_obj_palette_0(), 0xFF40 => self.gpu.get_lcdc(),
0xFF49 => self.gpu.get_obj_palette_1(), 0xFF41 => self.gpu.get_lcd_status(),
0xFF4A => self.gpu.get_wy(), 0xFF42 => self.gpu.get_scy(),
0xFF4B => self.gpu.get_wx(), 0xFF43 => self.gpu.get_scx(),
0xFF03 | 0xFF08..0xFF0F => 0xFF, 0xFF44 => self.gpu.get_ly(),
0x0..0xFF00 | 0xFF4C..=0xFFFF => panic!("passed wrong address to get_io"), 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) { fn set_io(&mut self, address: IoAddress, data: u8) {
// range: 0xFF00 - 0xFF4B inclusive
match address { match address {
0xFF00 => { IoAddress::Joypad => self.joypad.mmio_write(data),
// joypad IoAddress::Serial(address) => match address.inner() {
self.joypad.mmio_write(data); 0xFF01 => self.serial.update_queued(data),
} 0xFF02 => self.serial.update_control(data),
0xFF01 => self.serial.update_queued(data), _ => unreachable!(),
0xFF02 => self.serial.update_control(data), },
0xFF04 => self.timers.update_div(), IoAddress::Timer(address) => match address.inner() {
0xFF05 => self.timers.update_tima(data), 0xFF04 => self.timers.update_div(),
0xFF06 => self.timers.update_tma(data), 0xFF05 => self.timers.update_tima(data),
0xFF07 => self.timers.update_timer_control(data), 0xFF06 => self.timers.update_tma(data),
0xFF0F => self.interrupts.set_flag_register(data), 0xFF07 => self.timers.update_timer_control(data),
0xFF10..0xFF40 => self.apu.mmio_write(address, data), _ => unreachable!(),
0xFF40 => self.gpu.update_lcdc(data), },
0xFF41 => self.gpu.update_lcd_status(data), IoAddress::InterruptFlag => self.interrupts.set_flag_register(data),
0xFF42 => self.gpu.update_scy(data), IoAddress::Audio(address) => self.apu.mmio_write(address, data),
0xFF43 => self.gpu.update_scx(data), IoAddress::WaveRam(address) => self.apu.mmio_write_wave_ram(address, data),
0xFF45 => self.gpu.update_lyc(data), IoAddress::Video(address) => match address.inner() {
0xFF46 => { 0xFF40 => self.gpu.update_lcdc(data),
if data > 0xDF { 0xFF41 => self.gpu.update_lcd_status(data),
panic!("dma transfer out of bounds: {data:#X}"); 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; 0xFF47 => self.gpu.update_bg_palette(data),
let mut addr: u16 = 0x0; 0xFF48 => self.gpu.update_obj_palette_0(data),
addr.set_high(data); 0xFF49 => self.gpu.update_obj_palette_1(data),
for l in 0x0..0xA0 { 0xFF4A => self.gpu.update_wy(data),
addr.set_low(l); 0xFF4B => self.gpu.update_wx(data),
self.gpu.oam.data[l as usize] = self.get(addr); _ => unreachable!(),
} },
} IoAddress::Unused(_) => {}
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"),
} }
} }

View file

@ -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<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()
}
}

View file

@ -0,0 +1,65 @@
use std::ops::{Add, Sub};
#[derive(Debug)]
pub(crate) enum AddressError {
OutOfBounds,
}
#[derive(Copy, Clone)]
pub(crate) struct BoundedAddress<const MIN: u16, const MAX: u16>(u16);
impl<const MIN: u16, const MAX: u16> Add<u16> for BoundedAddress<MIN, MAX> {
type Output = Option<BoundedAddress<MIN, MAX>>;
fn add(self, rhs: u16) -> Self::Output {
(self.0 + rhs).try_into().ok()
}
}
impl<const MIN: u16, const MAX: u16> Sub<u16> for BoundedAddress<MIN, MAX> {
type Output = Option<BoundedAddress<MIN, MAX>>;
fn sub(self, rhs: u16) -> Self::Output {
(self.0 - rhs).try_into().ok()
}
}
impl<const MIN: u16, const MAX: u16> TryInto<BoundedAddress<MIN, MAX>> for u16 {
type Error = AddressError;
fn try_into(self) -> Result<BoundedAddress<MIN, MAX>, Self::Error> {
if self >= MIN && self < MAX {
Ok(BoundedAddress(self))
} else {
Err(AddressError::OutOfBounds)
}
}
}
impl<const MIN: u16, const MAX: u16> BoundedAddress<MIN, MAX> {
pub(crate) fn get_local(&self) -> u16 {
self.0 - MIN
}
}
impl<const MIN: u16, const MAX: u16> PartialEq for BoundedAddress<MIN, MAX> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<const MIN: u16, const MAX: u16> PartialOrd for BoundedAddress<MIN, MAX> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
pub(crate) trait AddressMarker {
fn inner(&self) -> u16;
}
impl<const MIN: u16, const MAX: u16> AddressMarker for BoundedAddress<MIN, MAX> {
fn inner(&self) -> u16 {
self.0
}
}

View file

@ -4,7 +4,7 @@ use self::{
}; };
use crate::{ use crate::{
connect::AudioOutput, connect::AudioOutput,
processor::memory::Address, processor::memory::addresses::{AddressMarker, AudioAddress, WaveRamAddress},
util::{get_bit, set_or_clear_bit}, util::{get_bit, set_or_clear_bit},
}; };
use futures::executor; use futures::executor;
@ -185,11 +185,11 @@ impl Apu {
self.output.send_rb.is_full() 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 { if self.apu_enable {
self.make_register(addr) self.make_register(addr)
} else { } else {
match addr { match addr.inner() {
0xFF26 | 0xFF11 | 0xFF16 | 0xFF1B | 0xFF20 | 0xFF30..0xFF40 => { 0xFF26 | 0xFF11 | 0xFF16 | 0xFF1B | 0xFF20 | 0xFF30..0xFF40 => {
self.make_register(addr) self.make_register(addr)
} }
@ -198,8 +198,12 @@ impl Apu {
} }
} }
fn make_register(&self, addr: Address) -> u8 { pub(crate) fn get_wave_ram_register(&self, addr: WaveRamAddress) -> u8 {
match addr { 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(), 0xFF10 => self.channels.one.get_sweep_register(),
0xFF11 => self.channels.one.get_length_timer_and_duty_cycle(), 0xFF11 => self.channels.one.get_length_timer_and_duty_cycle(),
0xFF12 => self.channels.one.get_volume_and_envelope(), 0xFF12 => self.channels.one.get_volume_and_envelope(),
@ -250,15 +254,13 @@ impl Apu {
// write-only registers // write-only registers
0xFF13 | 0xFF18 | 0xFF1B | 0xFF1D | 0xFF20 => 0xFF, 0xFF13 | 0xFF18 | 0xFF1B | 0xFF1D | 0xFF20 => 0xFF,
// not registers // not registers
0xFF15 | 0xFF1F | 0xFF27..0xFF30 => 0xFF, 0xFF15 | 0xFF1F => 0xFF,
// wave ram _ => unreachable!(),
0xFF30..0xFF40 => self.channels.three.wave_ram.data[(addr - 0xFF30) as usize],
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
} }
} }
pub fn mmio_write(&mut self, addr: Address, data: u8) { pub(crate) fn mmio_write(&mut self, addr: AudioAddress, data: u8) {
match addr { match addr.inner() {
0xFF10 => self.channels.one.update_sweep(data), 0xFF10 => self.channels.one.update_sweep(data),
0xFF11 => self.channels.one.update_length_timer_and_duty_cycle(data), 0xFF11 => self.channels.one.update_length_timer_and_duty_cycle(data),
0xFF12 => self.channels.one.update_volume_and_envelope(data), 0xFF12 => self.channels.one.update_volume_and_envelope(data),
@ -296,17 +298,19 @@ impl Apu {
0xFF26 => { 0xFF26 => {
if !self.apu_enable { if !self.apu_enable {
for i in 0xFF10..0xFF20 { for i in 0xFF10..0xFF20 {
self.mmio_write(i, 0x0); self.mmio_write(i.try_into().unwrap(), 0x0);
} }
for i in 0xFF21..0xFF25 { 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); self.apu_enable = (1 << 7) == (data & 0b10000000);
} }
0xFF30..0xFF40 => self.channels.three.update_wave_ram(addr, data), _ => unreachable!(),
0xFF15 | 0xFF1F | 0xFF27..0xFF30 => {}
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
} }
} }
pub(crate) fn mmio_write_wave_ram(&mut self, addr: WaveRamAddress, data: u8) {
self.channels.three.update_wave_ram(addr, data);
}
} }

View file

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
processor::memory::Address, processor::memory::addresses::WaveRamAddress,
util::{get_bit, set_or_clear_bit, Nibbles}, util::{get_bit, set_or_clear_bit, Nibbles},
}; };
@ -461,8 +461,8 @@ impl WaveChannel {
set_or_clear_bit(0xFF, 6, self.length_enable) set_or_clear_bit(0xFF, 6, self.length_enable)
} }
pub(super) fn update_wave_ram(&mut self, addr: Address, data: u8) { pub(super) fn update_wave_ram(&mut self, addr: WaveRamAddress, data: u8) {
let real_addr = (addr - 0xFF30) as usize; let real_addr = addr.get_local() as usize;
if real_addr >= self.wave_ram.data.len() { if real_addr >= self.wave_ram.data.len() {
panic!("sent the wrong address to update_wave_ram"); panic!("sent the wrong address to update_wave_ram");
} }

View file

@ -332,17 +332,17 @@ where
let mut objs = vec![]; let mut objs = vec![];
let effective_scanline = scanline + 16; let effective_scanline = scanline + 16;
for i in (0xFE00..0xFE9F).step_by(4) { 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 if y_pos <= effective_scanline
&& (y_pos + self.lcdc.obj_size.get_height()) > effective_scanline && (y_pos + self.lcdc.obj_size.get_height()) > effective_scanline
{ {
// sprite is on line // sprite is on line
let x_pos = self.oam.get(i + 1); let x_pos = self.oam.get((i + 1).try_into().unwrap());
let mut tile_index = self.oam.get(i + 2); let mut tile_index = self.oam.get((i + 2).try_into().unwrap());
if self.lcdc.obj_size == ObjSize::S8x16 { if self.lcdc.obj_size == ObjSize::S8x16 {
tile_index = clear_bit(tile_index, 0); 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 { objs.push(Object {
x: x_pos, x: x_pos,
y: y_pos, y: y_pos,
@ -380,11 +380,12 @@ where
object_row = self.lcdc.obj_size.get_height() - (object_row + 1); object_row = self.lcdc.obj_size.get_height() - (object_row + 1);
} }
let tile_row = object_row % 8; 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 }) .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 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 { for px_x in 0..8 {
let x_addr = if object.flags.x_flip { px_x } else { 7 - px_x }; let x_addr = if object.flags.x_flip { px_x } else { 7 - px_x };
let lsb = get_bit(lsbs, x_addr); let lsb = get_bit(lsbs, x_addr);
@ -437,14 +438,15 @@ where
let tilemap_column = (tile_line_x / 8) as u16; let tilemap_column = (tile_line_x / 8) as u16;
let tile_px_x = tile_line_x % 8; let tile_px_x = tile_line_x % 8;
let tile_addr = self let tile_addr = (self
.lcdc .lcdc
.tile_area .tile_area
.get_addr(self.vram.get(tilemap.get_addr(row_addr + (tilemap_column)))) .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 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 lsb = get_bit(lsbs, 7 - tile_px_x);
let msb = get_bit(msbs, 7 - tile_px_x); let msb = get_bit(msbs, 7 - tile_px_x);
let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb); let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb);

View file

@ -61,9 +61,9 @@ where
for tile_x in 0..16 { for tile_x in 0..16 {
let tile_num = (tile_y * 16) + tile_x; let tile_num = (tile_y * 16) + tile_x;
let data_begin = area.get_addr(tile_num); let data_begin = area.get_addr(tile_num);
for px_y in 0..8 { for px_y in 0..8_u16 {
let lsbs = memory.get((px_y * 2) + data_begin); let lsbs = memory.get((data_begin + (px_y * 2)).unwrap());
let msbs = memory.get((px_y * 2) + data_begin + 1); let msbs = memory.get((data_begin + (1 + (px_y * 2))).unwrap());
for px_x in 0..8 { for px_x in 0..8 {
let real_px_y = (display_y * 8) + px_y as usize; let real_px_y = (display_y * 8) + px_y as usize;
let real_px_x = (tile_x as usize * 8) + px_x as usize; let real_px_x = (tile_x as usize * 8) + px_x as usize;

View file

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
processor::memory::Address, processor::memory::addresses::{OamAddress, VramAddress},
util::{as_signed, get_bit}, util::{as_signed, get_bit},
}; };
@ -20,10 +20,10 @@ pub(super) enum TilemapArea {
} }
impl TilemapArea { impl TilemapArea {
pub(super) fn get_addr(&self, addr: u16) -> u16 { pub(super) fn get_addr(&self, addr: u16) -> VramAddress {
match self { match self {
TilemapArea::T9800 => 0x9800 + addr, TilemapArea::T9800 => (0x9800 + addr).try_into().unwrap(),
TilemapArea::T9C00 => 0x9C00 + addr, TilemapArea::T9C00 => (0x9C00 + addr).try_into().unwrap(),
} }
} }
} }
@ -35,10 +35,13 @@ pub(super) enum TiledataArea {
} }
impl TiledataArea { impl TiledataArea {
pub(super) fn get_addr(&self, addr: u8) -> u16 { pub(super) fn get_addr(&self, addr: u8) -> VramAddress {
match self { match self {
TiledataArea::D8000 => 0x8000 + ((addr as u16) * 16), TiledataArea::D8000 => (0x8000 + ((addr as u16) * 16)).try_into().unwrap(),
TiledataArea::D9000 => 0x9000_u16.wrapping_add_signed((as_signed(addr) as i16) * 16), 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 { impl Vram {
pub fn get(&self, address: Address) -> u8 { pub(crate) fn get(&self, address: VramAddress) -> u8 {
self.data[(address - 0x8000) as usize] self.data[address.get_local() as usize]
} }
pub fn set(&mut self, address: Address, data: u8) { pub(crate) fn set(&mut self, address: VramAddress, data: u8) {
self.data[(address - 0x8000) as usize] = data; self.data[address.get_local() as usize] = data;
} }
} }
@ -247,12 +250,12 @@ pub struct Oam {
} }
impl Oam { impl Oam {
pub fn get(&self, address: Address) -> u8 { pub(crate) fn get(&self, address: OamAddress) -> u8 {
self.data[(address - 0xFE00) as usize] self.data[address.get_local() as usize]
} }
pub fn set(&mut self, address: Address, data: u8) { pub(crate) fn set(&mut self, address: OamAddress, data: u8) {
self.data[(address - 0xFE00) as usize] = data; self.data[address.get_local() as usize] = data;
} }
} }

View file

@ -1,9 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait};
connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait},
processor::memory::Address,
};
use std::{ use std::{
fs::{File, OpenOptions}, fs::{File, OpenOptions},
io::{Read, Seek, SeekFrom, Write}, io::{Read, Seek, SeekFrom, Write},
@ -17,6 +14,8 @@ use self::mbcs::{
PocketCamera, PocketCameraSaveState, PocketCamera, PocketCameraSaveState,
}; };
use super::addresses::{CartRamAddress, RomAddress};
mod mbcs; mod mbcs;
struct MaybeBufferedSram { struct MaybeBufferedSram {
@ -249,19 +248,19 @@ where
&self.title &self.title
} }
pub(super) fn get(&self, address: Address) -> u8 { pub(super) fn get(&self, address: RomAddress) -> u8 {
self.mbc.get(address) 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) 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); 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); self.mbc.set_ram(address, data);
} }

View file

@ -1,4 +1,4 @@
use crate::processor::memory::Address; use crate::processor::memory::addresses::{CartRamAddress, RomAddress};
mod mbc1; mod mbc1;
mod mbc2; mod mbc2;
@ -21,11 +21,11 @@ const RAM_BANK_SIZE: usize = 8 * KB;
pub(super) trait Mbc: Send { pub(super) trait Mbc: Send {
// addresses 0x0000 - 0x7FFF // addresses 0x0000 - 0x7FFF
fn get(&self, address: Address) -> u8; fn get(&self, address: RomAddress) -> u8;
// addresses 0xA000 - 0xBFFF // addresses 0xA000 - 0xBFFF
fn get_ram(&self, address: Address) -> u8; fn get_ram(&self, address: CartRamAddress) -> u8;
fn set(&mut self, address: Address, data: u8); fn set(&mut self, address: RomAddress, data: u8);
fn set_ram(&mut self, address: Address, data: u8); fn set_ram(&mut self, address: CartRamAddress, data: u8);
fn mbc_type(&self) -> String; fn mbc_type(&self) -> String;
fn get_save_state(&self) -> MbcSaveState; fn get_save_state(&self) -> MbcSaveState;
fn is_rumbling(&self) -> bool { fn is_rumbling(&self) -> bool {

View file

@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
use crate::processor::memory::{ use crate::processor::memory::{
addresses::{AddressMarker, CartRamAddress, RomAddress},
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
Address,
}; };
#[derive(Clone, Copy, Serialize, Deserialize)] #[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 { (match address {
0x0..0x4000 => match self.bank_mode { RomAddress::Bank0(address) => match self.bank_mode {
BankingMode::Simple => address as usize, BankingMode::Simple => address.inner() as usize,
BankingMode::Advanced => { 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 => { RomAddress::MappedBank(address) => {
(address - 0x4000) as usize (address.get_local() as usize)
+ (ROM_BANK_SIZE * self.rom_bank as usize) + (ROM_BANK_SIZE * self.rom_bank as usize)
+ (self.upper_banks as usize * 512 * KB) + (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) } % self.rom_len)
} }
fn get_ram_addr(&self, address: Address) -> usize { fn get_ram_addr(&self, address: CartRamAddress) -> usize {
match address { match self.bank_mode {
0x0..0x8000 => panic!("passed rom address to ram address function"), BankingMode::Simple => {
0xA000..0xC000 => match self.bank_mode { (address.get_local() as usize) + (RAM_BANK_SIZE * self.ram_bank as usize)
BankingMode::Simple => { }
(address - 0xA000) as usize + (RAM_BANK_SIZE * self.ram_bank as usize) BankingMode::Advanced => {
} (address.get_local() as usize)
BankingMode::Advanced => { + (RAM_BANK_SIZE * self.ram_bank as usize)
(address - 0xA000) as usize + (self.upper_banks as usize * 16 * KB)
+ (RAM_BANK_SIZE * self.ram_bank as usize) }
+ (self.upper_banks as usize * 16 * KB)
}
},
_ => panic!("address {address} incompatible with MBC"),
} }
} }
@ -104,11 +97,11 @@ impl Mbc1 {
} }
impl Mbc for Mbc1 { impl Mbc for Mbc1 {
fn get(&self, address: Address) -> u8 { fn get(&self, address: RomAddress) -> u8 {
self.data[self.get_rom_addr(address)] 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 { if self.ram_enabled && let Some(ram) = &self.ram {
let addr = self.get_ram_addr(address) % ram.len(); let addr = self.get_ram_addr(address) % ram.len();
return ram.get(addr); return ram.get(addr);
@ -116,7 +109,7 @@ impl Mbc for Mbc1 {
0xFF 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); let mut addr = self.get_ram_addr(address);
if self.ram_enabled && let Some(ram) = &mut self.ram { if self.ram_enabled && let Some(ram) = &mut self.ram {
addr %= ram.len(); addr %= ram.len();
@ -124,8 +117,8 @@ impl Mbc for Mbc1 {
} }
} }
fn set(&mut self, address: Address, data: u8) { fn set(&mut self, address: RomAddress, data: u8) {
match address { match address.inner() {
0x0..0x2000 => { 0x0..0x2000 => {
// enable/disable ram // enable/disable ram
self.ram_enabled = (data & 0x0F) == 0xA; self.ram_enabled = (data & 0x0F) == 0xA;

View file

@ -3,8 +3,8 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::processor::memory::{ use crate::processor::memory::{
addresses::{AddressMarker, CartRamAddress, RomAddress},
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
Address,
}; };
use super::{rom_banks, Mbc, ROM_BANK_SIZE}; use super::{rom_banks, Mbc, ROM_BANK_SIZE};
@ -51,28 +51,27 @@ impl Mbc2 {
} }
impl Mbc for Mbc2 { impl Mbc for Mbc2 {
fn get(&self, address: Address) -> u8 { fn get(&self, address: RomAddress) -> u8 {
match address { match address {
0x0..0x4000 => self.data[address as usize], RomAddress::Bank0(address) => self.data[address.inner() as usize],
0x4000..0x8000 => { RomAddress::MappedBank(address) => {
self.data[((address as usize - 0x4000) + (0x4000 * self.rom_bank as usize)) self.data[((address.get_local() as usize) + (0x4000 * self.rom_bank as usize))
% self.rom_len] % 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 { 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 { } else {
0xFF 0xFF
} }
} }
fn set(&mut self, address: Address, data: u8) { fn set(&mut self, address: RomAddress, data: u8) {
if address < 0x4000 { if let RomAddress::Bank0(_) = address {
if address & (1 << 8) == (1 << 8) { if address.inner() & (1 << 8) == (1 << 8) {
// bit 8 is set - rom bank // bit 8 is set - rom bank
self.rom_bank = data & 0xF; self.rom_bank = data & 0xF;
if self.rom_bank == 0 { 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 { if self.ram_enabled {
self.ram.set((address - 0xA000) as usize % 512, data); self.ram.set((address.get_local() as usize) % 512, data);
} }
} }

View file

@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize};
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
use crate::{ use crate::{
processor::memory::{ processor::memory::{
addresses::{AddressMarker, CartRamAddress, RomAddress},
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
Address,
}, },
util::set_or_clear_bit, 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 { (match address {
0x0..0x4000 => address as usize, RomAddress::Bank0(address) => address.inner() as usize,
0x4000..0x8000 => { RomAddress::MappedBank(address) => {
let internal_addr = address as usize - 0x4000; let internal_addr = address.get_local() as usize;
internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize) internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize)
} }
_ => panic!("address {address} incompatible with MBC"),
} % self.rom_size) } % self.rom_size)
} }
fn get_ram_addr(&self, address: Address, ram_bank: usize) -> usize { fn get_ram_addr(&self, address: CartRamAddress, ram_bank: usize) -> usize {
((address as usize - 0xA000) + (RAM_BANK_SIZE * ram_bank)) % self.ram_size ((address.get_local() as usize) + (RAM_BANK_SIZE * ram_bank)) % self.ram_size
} }
pub fn from_save_state(state: Mbc3SaveState, data: Vec<u8>) -> Self { pub fn from_save_state(state: Mbc3SaveState, data: Vec<u8>) -> Self {
@ -158,11 +157,11 @@ impl Mbc3 {
} }
impl Mbc for Mbc3 { impl Mbc for Mbc3 {
fn get(&self, address: Address) -> u8 { fn get(&self, address: RomAddress) -> u8 {
self.data[self.get_rom_addr(address)] 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 { if self.ram_enabled {
match &self.ram_bank { match &self.ram_bank {
RamBank::Ram(ram_bank) => { RamBank::Ram(ram_bank) => {
@ -180,8 +179,8 @@ impl Mbc for Mbc3 {
0xFF 0xFF
} }
fn set(&mut self, address: Address, data: u8) { fn set(&mut self, address: RomAddress, data: u8) {
match address { match address.inner() {
0x0..0x2000 => { 0x0..0x2000 => {
if data & 0xF == 0xA { if data & 0xF == 0xA {
self.ram_enabled = true; self.ram_enabled = true;
@ -218,12 +217,11 @@ impl Mbc for Mbc3 {
} }
} }
} }
_ => panic!("unsupported addr"), _ => 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 { if self.ram_enabled {
match &self.ram_bank { match &self.ram_bank {
RamBank::Ram(ram_bank) => { RamBank::Ram(ram_bank) => {

View file

@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
processor::memory::{ processor::memory::{
addresses::{AddressMarker, CartRamAddress, RomAddress},
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState}, rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
Address,
}, },
util::get_bit, 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 { (match address {
0x0..0x4000 => address as usize, RomAddress::Bank0(address) => address.inner() as usize,
0x4000..0x8000 => { RomAddress::MappedBank(address) => {
let internal_addr = address as usize - 0x4000; let internal_addr = address.get_local() as usize;
internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize) internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize)
} }
_ => panic!("address {address} incompatible with MBC"),
} % self.rom_size) } % self.rom_size)
} }
fn get_ram_addr(&self, address: Address) -> usize { fn get_ram_addr(&self, address: CartRamAddress) -> usize {
((address as usize - 0xA000) + (RAM_BANK_SIZE * self.ram_bank as usize)) % self.ram_size ((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<u8>) -> Self { pub fn from_save_state(state: Mbc5SaveState, data: Vec<u8>) -> Self {
@ -89,11 +88,11 @@ impl Mbc5 {
} }
impl Mbc for Mbc5 { impl Mbc for Mbc5 {
fn get(&self, address: Address) -> u8 { fn get(&self, address: RomAddress) -> u8 {
self.data[self.get_rom_addr(address)] 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 { if self.ram_enabled && let Some(ram) = &self.ram {
ram.get(self.get_ram_addr(address)) ram.get(self.get_ram_addr(address))
} else { } else {
@ -101,8 +100,8 @@ impl Mbc for Mbc5 {
} }
} }
fn set(&mut self, address: Address, data: u8) { fn set(&mut self, address: RomAddress, data: u8) {
match address { match address.inner() {
0x0..0x2000 => { 0x0..0x2000 => {
if (data & 0xF) == 0xA { if (data & 0xF) == 0xA {
self.ram_enabled = true self.ram_enabled = true
@ -121,11 +120,11 @@ impl Mbc for Mbc5 {
} }
} }
0x6000..0x8000 => {} 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); let real_addr = self.get_ram_addr(address);
if self.ram_enabled && let Some(ram) = &mut self.ram { if self.ram_enabled && let Some(ram) = &mut self.ram {
ram.set(real_addr, data); ram.set(real_addr, data);

View file

@ -1,5 +1,8 @@
use super::Mbc; use super::Mbc;
use crate::processor::memory::{rom::MbcSaveState, Address}; use crate::processor::memory::{
addresses::{AddressMarker, CartRamAddress, RomAddress},
rom::MbcSaveState,
};
pub struct None { pub struct None {
data: Vec<u8>, data: Vec<u8>,
@ -12,17 +15,17 @@ impl None {
} }
impl Mbc for None { impl Mbc for None {
fn get(&self, address: Address) -> u8 { fn get(&self, address: RomAddress) -> u8 {
self.data[address as usize] self.data[address.inner() as usize]
} }
fn get_ram(&self, _address: Address) -> u8 { fn get_ram(&self, _address: CartRamAddress) -> u8 {
0xFF 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 { fn mbc_type(&self) -> String {
String::from("None") String::from("None")

View file

@ -2,8 +2,8 @@ use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
use crate::{ use crate::{
connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait}, connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait},
processor::memory::{ processor::memory::{
addresses::{AddressMarker, CartRamAddress, RomAddress},
rom::{MaybeBufferedSram, MbcSaveState}, rom::{MaybeBufferedSram, MbcSaveState},
Address,
}, },
}; };
use serde::{Deserialize, Serialize}; 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 { (match address {
0x0..0x4000 => address as usize, RomAddress::Bank0(address) => address.inner() as usize,
0x4000..0x8000 => { RomAddress::MappedBank(address) => {
let internal_addr = address as usize - 0x4000; let internal_addr = address.get_local() as usize;
internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize) internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize)
} }
_ => panic!("address {address} incompatible with MBC"),
} % self.rom_size) } % self.rom_size)
} }
fn get_ram_addr(&self, address: Address, bank: u8) -> usize { fn get_ram_addr(&self, address: CartRamAddress, bank: u8) -> usize {
((address as usize - 0xA000) + (RAM_BANK_SIZE * bank as usize)) % self.ram_size ((address.get_local() as usize) + (RAM_BANK_SIZE * bank as usize)) % self.ram_size
} }
pub(crate) fn from_save_state( pub(crate) fn from_save_state(
@ -83,8 +82,8 @@ where
todo!(); todo!();
} }
fn get_cam_reg(&self, address: Address) -> u8 { fn get_cam_reg(&self, address: CartRamAddress) -> u8 {
match address { match address.inner() {
0xA000 => { 0xA000 => {
(if self.camera.lock().unwrap().is_capturing() { (if self.camera.lock().unwrap().is_capturing() {
0x1 0x1
@ -92,13 +91,13 @@ where
0x0 0x0
}) | self.extra_bits_a000 }) | self.extra_bits_a000
} }
0xA001..=0xA035 => self.camera_ram[(address - 0xA001) as usize], 0xA001..=0xA035 => self.camera_ram[(address.inner() - 0xA001) as usize],
_ => 0x00, _ => 0x00,
} }
} }
fn set_cam_reg(&mut self, address: Address, data: u8) { fn set_cam_reg(&mut self, address: CartRamAddress, data: u8) {
match address { match address.inner() {
0xA000 => { 0xA000 => {
if data & 0x1 == 0x1 { if data & 0x1 == 0x1 {
self.camera.lock().unwrap().begin_capture(); self.camera.lock().unwrap().begin_capture();
@ -106,7 +105,7 @@ where
self.extra_bits_a000 = data & 0b110; self.extra_bits_a000 = data & 0b110;
} }
0xA001..=0xA035 => { 0xA001..=0xA035 => {
self.camera_ram[(address - 0xA001) as usize] = data; self.camera_ram[(address.inner() - 0xA001) as usize] = data;
} }
_ => {} _ => {}
} }
@ -127,11 +126,11 @@ impl<C> Mbc for PocketCamera<C>
where where
C: PocketCameraTrait + Send, C: PocketCameraTrait + Send,
{ {
fn get(&self, address: Address) -> u8 { fn get(&self, address: RomAddress) -> u8 {
self.data[self.get_rom_addr(address)] 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 { match self.ram_bank {
RamBank::Ram(bank) => { RamBank::Ram(bank) => {
if let Some(ram) = &self.ram { 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(); self.check_for_new_image();
match address { match address.inner() {
0x0..0x2000 => { 0x0..0x2000 => {
if (data & 0xF) == 0xA { if (data & 0xF) == 0xA {
self.ram_enabled = true self.ram_enabled = true
@ -167,11 +166,11 @@ where
} }
} }
0x6000..0x8000 => {} 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(); self.check_for_new_image();
match self.ram_bank { match self.ram_bank {
RamBank::Ram(bank) => { RamBank::Ram(bank) => {