diff --git a/src/cartridge/mappers.rs b/src/cartridge/mappers.rs index 78ee5ef..a924f9b 100644 --- a/src/cartridge/mappers.rs +++ b/src/cartridge/mappers.rs @@ -7,8 +7,8 @@ pub fn nrom_cpu(cpu: &mut crate::cpu::Cpu, address: usize, writing: bool) -> Opt // CPU $C000-$FFFF: Last 16 KB of ROM (NROM-256) or mirror of $8000-$BFFF (NROM-128). let l = cpu.prg_rom.len(); match address { - 0x8000...0xBFFF => Some(&mut cpu.prg_rom[0][address % 0x4000]), - 0xC000...0xFFFF => Some(&mut cpu.prg_rom[l - 1][address % 0x4000]), + 0x8000..=0xBFFF => Some(&mut cpu.prg_rom[0][address % 0x4000]), + 0xC000..=0xFFFF => Some(&mut cpu.prg_rom[l - 1][address % 0x4000]), _ => panic!("bad cpu address passed to nrom mapper"), } } @@ -18,7 +18,7 @@ pub fn nrom_ppu(ppu: &mut crate::ppu::Ppu, address: usize, writing: bool) -> Opt // NROM/mapper 0 doesn't allow writes to CHR-ROM if writing || l == 0 { return None }; match address { - 0x0000...0x1FFF => Some(&mut ppu.pattern_tables[l-1][address]), + 0x0000..=0x1FFF => Some(&mut ppu.pattern_tables[l-1][address]), _ => panic!("bad ppu address passed to nrom mapper: 0x{:04x}", address), } } diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index 7112226..4a6f1cd 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -17,7 +17,7 @@ const DECIMAL_FLAG: u8 = 1 << 3; const OVERFLOW_FLAG: u8 = 1 << 6; const NEGATIVE_FLAG: u8 = 1 << 7; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum Mode { ABS, ABX, ABY, ACC, IMM, IMP, IDX, IND, @@ -83,6 +83,8 @@ pub struct Cpu { pub strobe: u8, pub button_states: u8, // Player 1 controller button_number: u8, + + more: usize, } impl Cpu { @@ -102,6 +104,7 @@ impl Cpu { strobe: 0, button_states: 0, button_number: 0, + more: 0, opcode_table: vec![ // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F /*00*/ Cpu::brk, Cpu::ora, Cpu::bad, Cpu::slo, Cpu::nop, Cpu::ora, Cpu::asl, Cpu::slo, Cpu::php, Cpu::ora, Cpu::asl, Cpu::nop, Cpu::nop, Cpu::ora, Cpu::asl, Cpu::slo, /*00*/ @@ -167,26 +170,37 @@ impl Cpu { let clock = self.clock; let opcode = ::from(self.read(self.PC)); - // debugging - // let pc = self.PC; - // print!("{:04X} {:02X} [{:02x} {:02x}] A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X}", - // pc, self.read(pc), self.read(pc + 1), self.read(pc+2), - // self.A, self.X, self.Y, self.P, self.S, - // ); - // let mut zpg = Vec::::new(); - // for i in 0..32 { - // zpg.push(self.read(i)); - // } - // print!(" zpg: {:x?}", zpg); - // print!("\n"); - // get addressing mode let mode = self.mode_table[opcode].clone(); let address = mode.get()(self); + + // debugging + let pc = self.PC; + if address == 0x06d6 { // if we're doing something with the WarpZoneControl global + println!("===========================\n0x{:04x} {:?}", address, mode); + if self.more == 0 { + self.more += 10; + } + } + if self.more > 0 { + print!("{:04X} {:02X} [{:02x} {:02x}] A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X}", + pc, self.read(pc), self.read(pc + 1), self.read(pc+2), + self.A, self.X, self.Y, self.P, self.S, + ); + let mut zpg = Vec::::new(); + for i in 0..32 { + zpg.push(self.read(i)); + } + print!(" zpg: {:x?}", zpg); + print!("\n"); + self.more -= 1; + } + // advance program counter according to how many bytes that instruction operated on self.advance_pc(mode); // look up instruction in table and execute self.opcode_table[opcode](self, address, mode); + // return how many cycles it took self.clock - clock } diff --git a/src/main.rs b/src/main.rs index 9397bf5..7fc3f1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,6 @@ use apu::Apu; use cartridge::Cartridge; use input::poll_buttons; use screen::{init_window, draw_pixel, draw_to_window}; -use audio::initialize; use sdl2::keyboard::Keycode; use sdl2::event::Event; @@ -35,7 +34,7 @@ fn main() -> Result<(), String> { let mut screen_buffer = vec![0; byte_width * byte_height]; // contains raw RGB data for the screen // Set up audio - let mut audio_device = audio::initialize(&sdl_context).expect("Could not create audio device"); + let audio_device = audio::initialize(&sdl_context).expect("Could not create audio device"); let mut half_cycle = false; audio_device.resume(); @@ -109,11 +108,11 @@ fn main() -> Result<(), String> { // calculate fps let now = Instant::now(); if now > fps_timer + Duration::from_secs(1) { - println!("fps: {}", fps); + // println!("fps: {}", fps); fps = 0; fps_timer = now; - println!("samples per second: {}", sps); + // println!("samples per second: {}", sps); sps = 0; } @@ -139,4 +138,13 @@ The PPU is throttled to 60Hz by sleeping in the main loop. This locks the CPU to The SDL audio device samples/outputs at 44,100Hz, so as long as the APU queues up 44,100 samples per second, it works. But it's not doing so evenly. If PPU runs faster than 60Hz, audio will get skipped, and if slower, audio will pop/have gaps. Need to probably lock everything to the APU but worried about checking time that often. Can do for some division of 44_100. + +Nowhere room debugging: +Do we want to detect every time WarpZoneControl is accessed and log a buffer before and after it? +Or is the problem not with loading WZC but writing it? Good and bad logs match when entering the pipe. +The subroutine that accesses $06D6 is HandlePipeEntry. That's only called by ChkFootMTile->DoFootCheck->ChkCollSize->PlayerBGCollision->PlayerCtrlRoutine. +PlayerCtrlRoutine is called by PlayerInjuryBlink and PlayerDeath, and all three of those are called by GameRoutines engine. +So the normal physics loop checks for pipe entry every so often. So need to find out how HandlePipeEntry determines where to send you, +and what puts you in the room. + */ diff --git a/src/ppu/cpu_registers.rs b/src/ppu/cpu_registers.rs index efec963..5be045a 100644 --- a/src/ppu/cpu_registers.rs +++ b/src/ppu/cpu_registers.rs @@ -159,11 +159,11 @@ impl super::Ppu { let mem_val = self.read(self.v as usize); let ret_val; match self.v % 0x4000 { - 0x0000...0x3EFF => { + 0x0000..=0x3EFF => { ret_val = self.read_buffer; self.read_buffer = mem_val; }, - 0x3F00...0x3FFF => { + 0x3F00..=0x3FFF => { ret_val = mem_val; self.read_buffer = self.read(self.v as usize - 0x1000); }, diff --git a/src/ppu/memory.rs b/src/ppu/memory.rs index f44f35b..68b8b19 100644 --- a/src/ppu/memory.rs +++ b/src/ppu/memory.rs @@ -3,15 +3,15 @@ impl super::Ppu { pub fn read(&mut self, addr: usize) -> u8 { let address = addr % 0x4000; match addr { - 0x0000...0x1FFF => { + 0x0000..=0x1FFF => { if self.pattern_tables.len() > 0 { *(self.mapper_func)(self, address, false).unwrap() // unwrapping because mapper funcs won't return None for reads } else { 0 } }, - 0x2000...0x3EFF => self.read_nametable(address), - 0x3F00...0x3FFF => { + 0x2000..=0x3EFF => self.read_nametable(address), + 0x3F00..=0x3FFF => { let a = address % 0x0020; let value = self.palette_ram[a]; value @@ -23,14 +23,14 @@ impl super::Ppu { pub fn write(&mut self, addr: usize, value: u8) { let address = addr % 0x4000; match addr { - 0x0000...0x1FFF => { + 0x0000..=0x1FFF => { match (self.mapper_func)(self, address, true) { Some(loc) => *loc = value, None => (), } }, - 0x2000...0x3EFF => self.write_nametable(address, value), - 0x3F00...0x3FFF => { + 0x2000..=0x3EFF => self.write_nametable(address, value), + 0x3F00..=0x3FFF => { // I did not read this closely enough for a long time. // Addresses $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C. // Note that this goes for writing as well as reading. @@ -65,20 +65,20 @@ impl super::Ppu { let offset = base % 0x0400; if self.mirroring == 0 { // horizontal match base { - 0x0000...0x07FF => { + 0x0000..=0x07FF => { self.nametable_0[offset] }, - 0x0800...0x0FFF => { + 0x0800..=0x0FFF => { self.nametable_2[offset] }, _ => panic!("panicked writing nametable base: {}", base), } } else { // vertical match base { - 0x0000...0x03FF | 0x0800...0x0BFF => { + 0x0000..=0x03FF | 0x0800..=0x0BFF => { self.nametable_0[offset] }, - 0x0400...0x07FF | 0x0C00...0x0FFF => { + 0x0400..=0x07FF | 0x0C00..=0x0FFF => { self.nametable_1[offset] }, _ => panic!("panicked writing nametable base: {}", base), @@ -91,11 +91,11 @@ impl super::Ppu { let offset = base % 0x0400; if self.mirroring == 0 { // horizontal match base { - 0x0000...0x07FF => { + 0x0000..=0x07FF => { self.nametable_0[offset] = value; self.nametable_1[offset] = value; }, - 0x0800...0x0FFF => { + 0x0800..=0x0FFF => { self.nametable_2[offset] = value; self.nametable_3[offset] = value; }, @@ -103,11 +103,11 @@ impl super::Ppu { } } else { // vertical match base { - 0x0000...0x03FF | 0x0800...0x0BFF => { + 0x0000..=0x03FF | 0x0800..=0x0BFF => { self.nametable_0[offset] = value; self.nametable_2[offset] = value; }, - 0x0400...0x07FF | 0x0C00...0x0FFF => { + 0x0400..=0x07FF | 0x0C00..=0x0FFF => { self.nametable_1[offset] = value; self.nametable_3[offset] = value; }, diff --git a/src/ppu/mod.rs b/src/ppu/mod.rs index db7dc86..ca428c3 100644 --- a/src/ppu/mod.rs +++ b/src/ppu/mod.rs @@ -159,7 +159,7 @@ impl Ppu { // background-related things match self.line_cycle { 0 => (), // This is an idle cycle. - 1...256 => { + 1..=256 => { if self.scanline != 261 { pixel = Some(self.render_pixel()); } @@ -168,7 +168,7 @@ impl Ppu { self.perform_memory_fetch(); }, 257 => self.copy_horizontal(), // At dot 257 of each scanline, if rendering is enabled, the PPU copies all bits related to horizontal position from t to v - 321...336 => { + 321..=336 => { self.load_data_into_registers(); self.shift_registers(); self.perform_memory_fetch(); @@ -186,7 +186,7 @@ impl Ppu { self.evaluate_sprites(); // ignoring all timing details self.fetch_sprites(); }, - 321...340 => (), // Read the first byte in secondary OAM (while the PPU fetches the first two background tiles for the next scanline) + 321..=340 => (), // Read the first byte in secondary OAM (while the PPU fetches the first two background tiles for the next scanline) _ => (), } }