cleanup, notes
This commit is contained in:
parent
d4b1a8389b
commit
8b4eba15a4
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 = <usize>::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::<u8>::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::<u8>::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
|
||||
}
|
||||
|
|
16
src/main.rs
16
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.
|
||||
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue