From 504cc9db9b2a6033013024739fbf807de1d1184c Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Sat, 18 Jan 2020 13:32:57 +0100 Subject: [PATCH] ppu read/write --- src/main.rs | 2 +- src/nes/cpu.rs | 12 ++--- src/nes/memory.rs | 2 +- src/nes/ppu.rs | 110 +++++++++++++++++++++++++++++----------------- 4 files changed, 77 insertions(+), 49 deletions(-) diff --git a/src/main.rs b/src/main.rs index 48c9104..80a6bb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,7 +37,7 @@ lazy_static! { } fn main() -> Result<(), Error> { - simple_logger::init_with_level(Level::Debug).unwrap(); + simple_logger::init_with_level(Level::Info).unwrap(); let args: Vec = env::args().collect(); if args.len() < 2 { bail!("No cartridge supplied. Usage: ./jane cartridge.nes"); diff --git a/src/nes/cpu.rs b/src/nes/cpu.rs index f8e9192..0b762a4 100644 --- a/src/nes/cpu.rs +++ b/src/nes/cpu.rs @@ -53,7 +53,7 @@ impl Registers { impl Debug for Registers { fn fmt(&self, f: &mut Formatter) -> Result { write!(f, "{{ a: {:#x}, x: {:#x}, y: {:#x}, sp: {:#x}, pc: {:#x}, flags: {:#010b} }}", - self.a, self.x, self.y, self.sp, self.pc, self.flags.bits) + self.a, self.x, self.y, self.sp, self.pc, self.flags.bits()) } } @@ -169,7 +169,7 @@ impl CPU { fn set_flag_nz(&mut self, val: Byte) { self.set_flag(Flags::ZERO, val == 0); - self.set_flag(Flags::NEGATIVE, (val & Flags::NEGATIVE.bits) > 0); + self.set_flag(Flags::NEGATIVE, (val & Flags::NEGATIVE.bits()) > 0); } pub fn get_flag(&self, flag: Flags) -> Byte { @@ -522,8 +522,8 @@ impl CPU { // the zeroflag is set to the result of operand AND accumulator. fn op_BIT(&mut self, mem: &T, addr: Word) -> bool { let val = self.readb(mem, addr); - self.set_flag(Flags::OVERFLOW, (val & Flags::OVERFLOW.bits) > 1); - self.set_flag(Flags::NEGATIVE, (val & Flags::NEGATIVE.bits) > 1); + self.set_flag(Flags::OVERFLOW, (val & Flags::OVERFLOW.bits()) > 1); + self.set_flag(Flags::NEGATIVE, (val & Flags::NEGATIVE.bits()) > 1); self.set_flag(Flags::ZERO, (val & self.regs.a) == 0); false } @@ -579,7 +579,7 @@ impl CPU { // Push flags to stack self.set_flag(Flags::BREAK, true); - self.pushb_sp(mem, self.regs.flags.bits); + self.pushb_sp(mem, self.regs.flags.bits()); self.set_flag(Flags::BREAK, false); // set PC to IRQ vector @@ -875,7 +875,7 @@ impl CPU { // Pushes a copy of the status flags on to the stack. fn op_PHP(&mut self, mem: &mut T) -> bool { let tmp = self.regs.flags | Flags::BREAK; - self.pushb_sp(mem, tmp.bits); + self.pushb_sp(mem, tmp.bits()); self.set_flag(Flags::BREAK, false); false } diff --git a/src/nes/memory.rs b/src/nes/memory.rs index f33b5cf..c92acbc 100644 --- a/src/nes/memory.rs +++ b/src/nes/memory.rs @@ -58,7 +58,7 @@ impl Memory for NESMemory { return self.ram[(addr & RAM_PHYS_RANGE[1]) as usize] } if PPU_ADDR_RANGE[0] <= addr && addr <= PPU_ADDR_RANGE[1] { - let ppu = self.ppu.borrow(); + let mut ppu = self.ppu.borrow_mut(); return ppu.readb(addr & PPU_PHYS_RANGE[1]); } 0x0000 // generic response diff --git a/src/nes/ppu.rs b/src/nes/ppu.rs index 66c7253..7da43e9 100644 --- a/src/nes/ppu.rs +++ b/src/nes/ppu.rs @@ -102,6 +102,7 @@ pub struct PPU { pattern_table: [Sprite; 2], pub frame_ready: bool, addr_latch_set: bool, + data_buffer: Byte, } // impl PPUMemoryReader for PPU {} @@ -116,6 +117,7 @@ impl PPU { pattern_table: [ImageBuffer::new(128, 128), ImageBuffer::new(128, 128)], frame_ready: false, addr_latch_set: false, + data_buffer: 0 } } @@ -183,19 +185,39 @@ impl PPU { } // CPU can write certain registers of the PPU through the bus - pub fn readb(&self, addr: Addr) -> Byte { + pub fn readb(&mut self, addr: Addr) -> Byte { // Only certain registers of the PPU can actually by read // remaining registers and read attemps will return garbage match addr { // status - 0x2002 => { self.regs.status.bits }, + 0x2002 => { + let status = self.regs.status.bits(); + // Reading the status register also clears VBLANK and the + // address latch + self.set_status(Status::VERTICAL_BLANK, false); + self.addr_latch_set = false; + status + }, // oam data - 0x2004 => { unimplemented!() }, + 0x2004 => { /* TODO */ 0x00 }, // ppu data - 0x2007 => { unimplemented!() }, - _ => 0x00, // unmapped reads + 0x2007 => { + // ppu reads are delayed by one clock. Therefore, this uses + // a buffer variable to return the data from the previous + // read, and then set the new data to the buffer. However, + // because the PPU is weird, this does not apply for the + // palette memory + let data = self.data_buffer; + self.data_buffer = self.readb_ppu(addr); + + if addr > 0x3F00 { // everything above 0x3F00 is palette + self.data_buffer + } else { + data + } + }, + _ => 0x00, // unmapped reads } - } // CPU can write certain registers of the PPU through the bus @@ -203,19 +225,25 @@ impl PPU { // Only some of the PPU regs can be written to match addr { // Control - 0x2000 => { self.regs.ctrl = Control::from_bits(data).unwrap() }, + 0x2000 => { + self.regs.ctrl = Control::from_bits(data).unwrap() + }, // Mask - 0x2001 => { self.regs.mask = Mask::from_bits(data).unwrap() }, + 0x2001 => { + self.regs.mask = Mask::from_bits(data).unwrap() + }, // OAM address - 0x2003 => { unreachable!() }, + 0x2003 => { /* TODO */ }, // OAM data - 0x2004 => { unreachable!() }, + 0x2004 => { /* TODO */ }, // Scroll - 0x2005 => { unimplemented!() }, + 0x2005 => { /* TODO */ }, // Addr - // To write a 16bit addr to the ppu, two consecutive writes are - // required to set the hi and lo byte, respectively - 0x2006 => { + 0x2006 => { + // To write a 16bit addr to the ppu, two consecutive writes are + // required to set the hi and lo byte of the address. + // addr_latch_set indicates wether the hi byte is already + // set or not if !self.addr_latch_set { self.regs.addr = self.regs.addr & 0x00FF | (data as Word) << 8; } else { @@ -226,13 +254,13 @@ impl PPU { // write data to the ppu addr bus 0x2007 => { self.writeb_ppu(self.regs.addr, data); - // after write, increment vram addr for further writes. + // after write, increment vram addr for next write. // The increment value is determined by the vertical mode // flag of the status reg 0: +1, 1: +32 - if self.get_control(Control::INCREMENT_MODE) { - self.regs.addr += 32; + self.regs.addr += if self.get_control(Control::INCREMENT_MODE) { + 32 } else { - self.regs.addr += 1; + 1 } }, _ => { } // unwriteable addr, do nothing @@ -305,40 +333,40 @@ mod tests { let mut ppu = PPU::new(); // set unset flag - assert_eq!(ppu.regs.status.bits, 0b00000000); - ppu.set_status(VERTICAL_BLANK, true); - assert_eq!(ppu.regs.status.bits, 0b10000000, - "register={:#010b}; should be 0b10000000", ppu.regs.status.bits); - ppu.set_status(VERTICAL_BLANK, false); - assert_eq!(ppu.regs.status.bits, 0b00000000, - "register={:#010b}; should be 0b00000000", ppu.regs.status.bits); + assert_eq!(ppu.regs.status.bits(), 0b00000000); + ppu.set_status(Status::VERTICAL_BLANK, true); + assert_eq!(ppu.regs.status.bits(), 0b10000000, + "register={:#010b}; should be 0b10000000", ppu.regs.status.bits()); + ppu.set_status(Status::VERTICAL_BLANK, false); + assert_eq!(ppu.regs.status.bits(), 0b00000000, + "register={:#010b}; should be 0b00000000", ppu.regs.status.bits()); // set same flag twice - ppu.set_status(VERTICAL_BLANK, true); - assert_eq!(ppu.regs.status.bits, 0b10000000, - "register={:#010b}; should be 0b10000000", ppu.regs.status.bits); - ppu.set_status(VERTICAL_BLANK, true); - assert_eq!(ppu.regs.status.bits, 0b10000000, - "register={:#010b}; should be 0b10000000", ppu.regs.status.bits); + ppu.set_status(Status::VERTICAL_BLANK, true); + assert_eq!(ppu.regs.status.bits(), 0b10000000, + "register={:#010b}; should be 0b10000000", ppu.regs.status.bits()); + ppu.set_status(Status::VERTICAL_BLANK, true); + assert_eq!(ppu.regs.status.bits(), 0b10000000, + "register={:#010b}; should be 0b10000000", ppu.regs.status.bits()); // set other flag - ppu.set_status(SPRITE_ZERO_HIT, true); - assert_eq!(ppu.regs.status.bits, 0b11000000, - "register={:#010b}; should be 0b11000000", ppu.regs.status.bits); + ppu.set_status(Status::SPRITE_ZERO_HIT, true); + assert_eq!(ppu.regs.status.bits(), 0b11000000, + "register={:#010b}; should be 0b11000000", ppu.regs.status.bits()); - ppu.set_status(SPRITE_ZERO_HIT, false); - assert_eq!(ppu.regs.status.bits, 0b10000000, - "register={:#010b}; should be 0b10000000", ppu.regs.status.bits); + ppu.set_status(Status::SPRITE_ZERO_HIT, false); + assert_eq!(ppu.regs.status.bits(), 0b10000000, + "register={:#010b}; should be 0b10000000", ppu.regs.status.bits()); // set other register ppu.set_control(Control::INCREMENT_MODE, true); - assert_eq!(ppu.regs.status.bits, 0b10000000, - "register={:#010b}; should be 0b10000000", ppu.regs.status.bits); - assert_eq!(ppu.regs.control.bits, 0b0000100, - "register={:#010b}; should be 0b0000001", ppu.regs.control.bits); + assert_eq!(ppu.regs.status.bits(), 0b10000000, + "register={:#010b}; should be 0b10000000", ppu.regs.status.bits()); + assert_eq!(ppu.regs.ctrl.bits(), 0b0000100, + "register={:#010b}; should be 0b0000001", ppu.regs.ctrl.bits()); } #[test]