diff --git a/src/processor/memory/mmio/apu.rs b/src/processor/memory/mmio/apu.rs index b02a2f5..c9a9319 100644 --- a/src/processor/memory/mmio/apu.rs +++ b/src/processor/memory/mmio/apu.rs @@ -1,6 +1,6 @@ use crate::{ processor::memory::{masked_update, Address}, - util::get_bit, + util::{get_bit, set_or_clear_bit}, }; const MEM_START: usize = 0xFF10; @@ -10,14 +10,46 @@ const fn reg(a: Address) -> usize { (a as usize) - MEM_START } +struct Channel { + enabled: bool, +} + +impl Channel { + fn new(enabled: bool) -> Self { + Self { enabled } + } +} + +struct Channels { + one: Channel, + two: Channel, + three: Channel, + four: Channel, +} + +impl Default for Channels { + fn default() -> Self { + Self { + one: Channel::new(true), + two: Channel::new(false), + three: Channel::new(false), + four: Channel::new(false), + } + } +} + pub struct Apu { mem: [u8; MEM_SIZE], + apu_enable: bool, + channels: Channels, } impl Default for Apu { fn default() -> Self { Self { mem: [0x0; MEM_SIZE], + apu_enable: true, + channels: Channels::default(), } } } @@ -31,12 +63,27 @@ impl Apu { || addr == 0xFF20 || get_bit(self.mem[reg(0xFF26)], 7) { - self.mem[reg(addr)] + self.make_register(addr) } else { 0xFF } } + fn make_register(&self, addr: Address) -> u8 { + match addr { + 0xFF26 => { + // NR52 - Sound on/off + let mut v = if self.apu_enable { 1 << 7 } else { 0 }; + v = set_or_clear_bit(v, 0, self.channels.one.enabled); + v = set_or_clear_bit(v, 1, self.channels.two.enabled); + v = set_or_clear_bit(v, 2, self.channels.three.enabled); + v = set_or_clear_bit(v, 3, self.channels.four.enabled); + v + } + _ => self.mem[reg(addr)], + } + } + pub fn mmio_write(&mut self, addr: Address, data: u8) { match addr { 0xFF10 => self.masked_io(reg(addr), data, 0b01111111), @@ -46,7 +93,7 @@ impl Apu { 0xFF23 => { self.mem[reg(addr)] = (self.mem[reg(addr)] & 0b10111111) | (data & 0b01000000) } - 0xFF26 => self.mem[reg(addr)] = (self.mem[reg(addr)] & 0b1111111) | (data & 0b10000000), + 0xFF26 => self.apu_enable = (1 << 7) == (data & 0b10000000), 0xFF11..0xFF1A | 0xFF1B | 0xFF1D..0xFF23 | 0xFF24..0xFF40 => { println!("BANNED write in APU: {data:#X} to {addr:#X}") }