diff --git a/src/apu.rs b/src/apu.rs index aec71d3..075a05f 100644 --- a/src/apu.rs +++ b/src/apu.rs @@ -4,7 +4,7 @@ bitfield::bitfield! { pub struct DutyVol(u8); impl Debug; duty, set_duty: 7, 6; - r#loop, set_loop: 5; + length_counter_halt, set_length_counter_halt: 5; const_vol, set_const_vol: 4; volume, set_volume: 3, 0; } @@ -27,6 +27,62 @@ bitfield::bitfield! { struct PulseChannel { enabled: bool, + duty_vol: DutyVol, + sweep: Sweep, + timer_low: u8, + length_timer_high: LengthTimerHigh, + + cur_time: u16, + cur_length: u8, +} + +impl PulseChannel { + pub fn new() -> Self { + Self { + enabled: false, + duty_vol: DutyVol(0), + sweep: Sweep(0), + timer_low: 0, + length_timer_high: LengthTimerHigh(0), + cur_time: 0, + cur_length: 0, + } + } + fn use_envelope(&self) -> bool { + !self.duty_vol.const_vol() + } + fn volume(&self) -> u8 { + self.duty_vol.volume() + } + fn timer(&self) -> u16 { + self.timer_low as u16 | ((self.length_timer_high.timer_high() as u16) << 8) + } + fn length(&self) -> u8 { + self.length_timer_high.length() + } + + pub fn reset(&mut self) { + // TODO + self.cur_time = self.timer(); + } + pub fn clock(&mut self) { + if self.cur_time == 0 { + self.cur_time = self.timer(); + } else { + self.cur_time -= 1; + } + // TODO + } + pub fn q_frame_clock(&mut self) { + if !self.duty_vol.length_counter_halt() && self.cur_length > 0 { + self.cur_length -= 1; + } + } + pub fn h_frame_clock(&mut self) { + if !self.duty_vol.length_counter_halt() && self.cur_length > 0 { + self.cur_length -= 1; + } + } } bitfield::bitfield! { @@ -46,6 +102,12 @@ struct DeltaChannel { enabled: bool, } +impl DeltaChannel { + pub fn int(&self) -> bool { + false + } +} + struct FrameCounter { count: usize, mode_5_step: bool, @@ -76,8 +138,8 @@ impl std::fmt::Debug for APU { impl APU { pub fn init() -> Self { Self { - pulse_1: PulseChannel { enabled: false }, - pulse_2: PulseChannel { enabled: false }, + pulse_1: PulseChannel::new(), + pulse_2: PulseChannel::new(), triangle: TriangleChannel { enabled: false }, noise: NoiseChannel { enabled: false }, dmc: DeltaChannel { enabled: false }, @@ -90,18 +152,38 @@ impl APU { } } pub fn read_reg(&mut self, offset: u16) -> u8 { + // println!("APU read: {offset:02X}"); match offset { + 0x15 => { + let val = (u8::from(self.dmc.int()) << 7) + | (u8::from(self.frame_counter.irq) << 6) + | (u8::from(self.dmc.enabled) << 4) + | (u8::from(self.noise.enabled) << 3) + | (u8::from(self.triangle.enabled) << 2) + | (u8::from(self.pulse_2.enabled) << 1) + | (u8::from(self.pulse_1.enabled) << 0); + self.frame_counter.irq = false; + val + } _ => panic!("No register at {:X}", offset), } } pub fn write_reg(&mut self, offset: u16, val: u8) { + // println!("APU write: {offset:02X} <= {val:02X}"); match offset { - 0x15 => { - self.dmc.enabled = val & 0b0001_0000 != 0; - self.noise.enabled = val & 0b0000_1000 != 0; - self.triangle.enabled = val & 0b0000_0100 != 0; - self.pulse_2.enabled = val & 0b0000_0010 != 0; - self.pulse_1.enabled = val & 0b0000_0001 != 0; + 0x00 => self.pulse_1.duty_vol.0 = val, + 0x01 => self.pulse_1.sweep.0 = val, + 0x02 => self.pulse_1.timer_low = val, + 0x03 => { + self.pulse_1.length_timer_high.0 = val; + self.pulse_1.reset(); + } + 0x04 => self.pulse_2.duty_vol.0 = val, + 0x05 => self.pulse_2.sweep.0 = val, + 0x06 => self.pulse_2.timer_low = val, + 0x07 => { + self.pulse_2.length_timer_high.0 = val; + self.pulse_2.reset(); } 0x10 => { assert_eq!(val, 0x00); @@ -110,27 +192,60 @@ impl APU { 0x11 => { // TODO: load dmc counter with (val & 7F) } - _ => (), - // _ => panic!("No register at {:X}", offset), + 0x15 => { + self.dmc.enabled = val & 0b0001_0000 != 0; + self.noise.enabled = val & 0b0000_1000 != 0; + self.triangle.enabled = val & 0b0000_0100 != 0; + self.pulse_2.enabled = val & 0b0000_0010 != 0; + self.pulse_1.enabled = val & 0b0000_0001 != 0; + } + 0x17 => { + self.frame_counter.mode_5_step = val & 0b1000_0000 == 0; + self.frame_counter.interrupt_enabled = val & 0b0100_0000 == 0; + if !self.frame_counter.interrupt_enabled { + self.frame_counter.irq = false; + } + } + // _ => (), + _ => panic!("No register at {:X}", offset), } } + fn q_frame_clock(&mut self) { + self.pulse_1.q_frame_clock(); + self.pulse_2.q_frame_clock(); // TODO: clock all + } + fn h_frame_clock(&mut self) { + self.pulse_1.q_frame_clock(); + self.pulse_1.h_frame_clock(); + self.pulse_2.q_frame_clock(); + self.pulse_2.h_frame_clock(); + } + pub fn run_one_clock_cycle(&mut self, ppu_cycle: usize) -> bool { if ppu_cycle % 6 == 1 { // APU Frame Counter clock cycle - if !self.frame_counter.mode_5_step - && self.frame_counter.interrupt_enabled - && self.frame_counter.count == 14914 - { - self.frame_counter.irq = true; - } else if !self.frame_counter.mode_5_step - && self.frame_counter.interrupt_enabled - && self.frame_counter.count == 14915 - { - self.frame_counter.irq = true; - self.frame_counter.count = 0; + if self.frame_counter.mode_5_step { + todo!() + } else { + if self.frame_counter.count == 3728 { + self.q_frame_clock(); + } else if self.frame_counter.count == 7456 { + self.h_frame_clock(); + } else if self.frame_counter.count == 11185 { + self.q_frame_clock(); + } else if self.frame_counter.count == 14914 { + self.frame_counter.irq = self.frame_counter.interrupt_enabled; + self.h_frame_clock(); + } else if self.frame_counter.count == 14915 { + self.frame_counter.count = 0; + self.frame_counter.irq = self.frame_counter.interrupt_enabled; + } } self.frame_counter.count += 1; + + self.pulse_1.clock(); + self.pulse_2.clock(); } false } @@ -144,8 +259,6 @@ impl APU { self.frame_counter.irq } pub fn irq_waiting(&mut self) -> bool { - let res = self.frame_counter.irq; - self.frame_counter.irq = false; - res + self.frame_counter.irq } } diff --git a/src/ppu.rs b/src/ppu.rs index 19240ae..ba48ebb 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -467,7 +467,7 @@ impl Palette { pub struct PPU { // registers: PPURegisters, - frame_count: usize, + pub frame_count: usize, nmi_enabled: bool, // nmi_waiting: bool, pub even: bool,