diff --git a/src/processor/memory.rs b/src/processor/memory.rs index 7acc887..d16fc42 100644 --- a/src/processor/memory.rs +++ b/src/processor/memory.rs @@ -1,4 +1,4 @@ -use self::mmio::Joypad; +use self::mmio::{Apu, Joypad}; pub use self::rom::Rom; use crate::{processor::SplitRegister, verbose_println}; use gilrs::ConnectedGamepadsIterator; @@ -26,7 +26,7 @@ pub struct Memory { io: [u8; 76], pub(super) user_mode: bool, joypad: Joypad, - pub(super) apu_enabled: bool, + apu: Apu, } impl Memory { @@ -46,7 +46,7 @@ impl Memory { io: [0xFF; 76], user_mode: false, joypad: Joypad::default(), - apu_enabled: true, + apu: Apu::default(), } } @@ -119,10 +119,11 @@ impl Memory { } fn get_io(&self, address: Address) -> u8 { - if address == 0xFF00 { - return self.joypad.as_register(); + match address { + 0xFF00 => self.joypad.as_register(), + 0xFF10..0xFF40 => self.apu.get_register(address), + _ => self.io[(address - 0xFF00) as usize], } - self.io[(address - 0xFF00) as usize] } fn set_io(&mut self, address: Address, data: u8) { @@ -144,19 +145,7 @@ impl Memory { 0xFF04 => self.io[addr_l] = 0, 0xFF07 => self.masked_io(addr_l, data, 0b111), 0xFF0F => self.masked_io(addr_l, data, 0b11111), - 0xFF10 => self.masked_io(addr_l, data, 0b01111111), - 0xFF1A => self.masked_io(addr_l, data, 0b10000000), - 0xFF1C => self.masked_io(addr_l, data, 0b1100000), - 0xFF20 => self.masked_io(addr_l, data, 0b111111), - 0xFF23 => self.io[addr_l] = (self.io[addr_l] & 0b10111111) | (data & 0b01000000), - 0xFF26 => { - self.io[addr_l] = (self.io[addr_l] & 0b1111111) | (data & 0b10000000); - self.apu_enabled = self.io[addr_l] & 0b10000000 == 0b10000000 - } - 0xFF11 | 0xFF14 | 0xFF16 | 0xFF19 | 0xFF1E => { - // sound - self.io[addr_l] = data; - } + 0xFF10..0xFF40 => self.apu.mmio_write(address, data), 0xFF41 => { // mixed read/write self.masked_io(addr_l, data, 0b01111000); @@ -165,16 +154,7 @@ impl Memory { // cgb only self.io[addr_l] = data; } - 0xFF03 - | 0xFF08..0xFF0F - | 0xFF15 - | 0xFF1F - | 0xFF27 - | 0xFF28 - | 0xFF29 - | 0xFF44 - | 0xFF76 - | 0xFF77 => { + 0xFF03 | 0xFF08..0xFF0F | 0xFF44 | 0xFF76 | 0xFF77 => { // read-only addresses println!("BANNED write: {data:#X} to {address:#X}"); } @@ -198,7 +178,7 @@ impl Memory { } fn masked_io(&mut self, addr_l: usize, data: u8, mask: u8) { - self.io[addr_l] = (self.io[addr_l] & (!mask)) | (data & mask); + self.io[addr_l] = masked_update(self.io[addr_l], data, mask); } pub fn update_pressed_keys( @@ -235,3 +215,7 @@ impl Memory { } } } + +pub fn masked_update(current: u8, data: u8, mask: u8) -> u8 { + (current & (!mask)) | (data & mask) +} diff --git a/src/processor/memory/mmio/apu.rs b/src/processor/memory/mmio/apu.rs index 6c057ce..e7f8950 100644 --- a/src/processor/memory/mmio/apu.rs +++ b/src/processor/memory/mmio/apu.rs @@ -1,7 +1,61 @@ -pub struct Apu {} +use crate::{ + processor::memory::{masked_update, Address}, + util::get_bit, +}; -impl Apu { - fn init() -> Self { - Self {} +const MEM_START: usize = 0xFF10; +const MEM_SIZE: usize = 0xFF40 - MEM_START; + +const fn reg(a: Address) -> usize { + (a as usize) - MEM_START +} + +pub struct Apu { + mem: [u8; MEM_SIZE], +} + +impl Default for Apu { + fn default() -> Self { + Self { + mem: [0x0; MEM_SIZE], + } + } +} + +impl Apu { + pub fn get_register(&self, addr: Address) -> u8 { + if addr == 0xFF26 + || addr == 0xFF11 + || addr == 0xFF16 + || addr == 0xFF1B + || addr == 0xFF20 + || get_bit(self.mem[reg(0xFF26)], 7) + { + self.mem[reg(addr)] + } else { + 0xFF + } + } + + pub fn mmio_write(&mut self, addr: Address, data: u8) { + match addr { + 0xFF10 => self.masked_io(reg(addr), data, 0b01111111), + 0xFF1A => self.masked_io(reg(addr), data, 0b10000000), + 0xFF1C => self.masked_io(reg(addr), data, 0b1100000), + 0xFF20 => self.masked_io(reg(addr), data, 0b111111), + 0xFF23 => { + self.mem[reg(addr)] = (self.mem[reg(addr)] & 0b10111111) | (data & 0b01000000) + } + 0xFF26 => self.mem[reg(addr)] = (self.mem[reg(addr)] & 0b1111111) | (data & 0b10000000), + 0xFF11 | 0xFF14 | 0xFF16 | 0xFF19 | 0xFF1E => self.mem[reg(addr)] = data, + 0xFF15 | 0xFF1F | 0xFF27 | 0xFF28 | 0xFF29 => { + println!("BANNED write in APU: {data:#X} to {addr:#X}") + } + _ => panic!("non-apu addr in apu"), + } + } + + fn masked_io(&mut self, addr_el: usize, data: u8, mask: u8) { + self.mem[addr_el] = masked_update(self.mem[addr_el], data, mask); } }