From f56fc055799245ca71eaf6e9036a5fe27c122652 Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Wed, 25 Dec 2019 19:21:30 +0100 Subject: [PATCH] more operations, better debugging --- src/main.rs | 26 ++++++++++++----- src/nes/cpu.rs | 72 ++++++++++++++++++++++++++--------------------- src/nes/disasm.rs | 7 +++-- 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/src/main.rs b/src/main.rs index ab23599..b51de21 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,7 +62,9 @@ fn main() { // Create and reset CPU let mut cpu: CPU = CPU::new(); - cpu.reset(&bus); + cpu.find_pc_addr(&bus); + + // cpu.reset(&bus); // Prepare window and drawing resources let mut window: PistonWindow = WindowSettings::new("NESemu", [256*3, 240*2]) @@ -192,12 +194,22 @@ fn render_cpu(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, offset: transform, g ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = FT_COLOR_WHITE; + Text::new_color(color, FT_SIZE_PT).draw( + &format!("({:#4x})", cpu.regs.flags), + glyphs, + &c.draw_state, + transform, + g + ).unwrap(); + let cpu_register_texts = [ - &format!("A: {:#x} ({})", cpu.regs.a, cpu.regs.a), - &format!("X: {:#x} ({})", cpu.regs.x, cpu.regs.y), - &format!("Y: {:#x} ({})", cpu.regs.y, cpu.regs.x), - &format!("Stack P: {:#x} ({})", cpu.regs.sp, cpu.regs.sp), + &format!("A: {0:#x} ({0})", cpu.regs.a), + &format!("X: {0:#x} ({0})", cpu.regs.x), + &format!("Y: {0:#x} ({0})", cpu.regs.y), + &format!("Stack P: {0:#x} ({0})", cpu.regs.sp), &format!("Program P: {:#x}", cpu.regs.pc), ]; @@ -253,7 +265,7 @@ fn render_disasm(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, disasm: &Disasm, fn render_memory(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, bus: &MemoryBus, offset: [f64; 2]) { let mut transform_y = c.transform.trans(offset[0], offset[1]); - for page in (0x0000..0x00F0).step_by(16) { + for page in (0x0000..0x01FF).step_by(16) { transform_y = transform_y.trans(0.0, FT_LINE_DISTANCE+FT_SIZE_PX); Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw( &format!("{:#06x}:", page), @@ -277,7 +289,7 @@ fn render_memory(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, bus: &MemoryBus, } transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX) * 1.5); - for page in (0x8000..0x80F0).step_by(16) { + for page in (0x6000..0x6030).step_by(16) { transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX)); Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw( &format!("{:#06x}:", page), diff --git a/src/nes/cpu.rs b/src/nes/cpu.rs index 8b1e407..e3c096d 100644 --- a/src/nes/cpu.rs +++ b/src/nes/cpu.rs @@ -22,9 +22,9 @@ impl Registers { a: 0, x: 0, y: 0, - sp: 0, - pc: 0, - flags: 0, + sp: 0x00FD, + pc: 0x0000, + flags: 0x0034, } } } @@ -36,6 +36,7 @@ impl Debug for Registers { } } +pub const STACK_BASE_ADDR: Addr = 0x0100; pub const CARRY: Byte = 1 << 0; pub const ZERO: Byte = 1 << 1; @@ -79,24 +80,25 @@ impl CPU { } } - // Brings the CPU to a known state. Resets all registers and flags - // Read location of pc from 0xfffc - pub fn reset(&mut self, bus: &T) { - // reset registers - self.regs.a = 0; - self.regs.x = 0; - self.regs.y = 0; - self.regs.sp = 0xfd; - self.regs.pc = 0x00; - self.regs.flags = 0x00 | UNUSED; - + // sets PC + pub fn find_pc_addr(&mut self, bus: &T) { // 0xfffc and 0xfffc+1 stores the location of the first op code (where // the program starts). Read it and set pc accordingly. let addr: u16 = 0xfffc; let lo = bus.readb(addr); let hi = bus.readb(addr + 1); self.regs.pc = (hi as u16) << 8 | lo as u16; - debug!("PC after reset: {:#06x}", self.regs.pc); + debug!("PC set to: {:#06x}", self.regs.pc); + } + + // Brings the CPU to a known state. Resets all registers and flags + // Read location of pc from 0xfffc + pub fn reset(&mut self, bus: &T) { + // reset registers + self.regs.sp = self.regs.sp - 3; + self.set_flag(IRQ, true); + + self.find_pc_addr(bus); // A reset takes 8 CPU clocks self.cycles = 8; @@ -185,8 +187,8 @@ impl CPU { Operation::DEY => self.op_DEY(), Operation::EOR => self.op_EOR(bus, value), Operation::INC => self.op_INC(bus, value), - Operation::INX => self.op_INX(bus, value), - Operation::INY => self.op_INY(bus, value), + Operation::INX => self.op_INX(bus), + Operation::INY => self.op_INY(bus), Operation::JMP => self.op_JMP(bus, value), Operation::JSR => self.op_JSR(bus, value), Operation::LDA => self.op_LDA(bus, value), @@ -196,7 +198,7 @@ impl CPU { Operation::NOP => self.op_NOP(bus, value), Operation::ORA => self.op_ORA(bus, value), Operation::PHA => self.op_PHA(bus, value), - Operation::PHP => self.op_PHP(bus, value), + Operation::PHP => self.op_PHP(bus), Operation::PLA => self.op_PLA(bus, value), Operation::PLP => self.op_PLP(bus, value), Operation::ROL => self.op_ROL(bus, value), @@ -212,7 +214,7 @@ impl CPU { Operation::STY => self.op_STY(bus, value), Operation::TAX => self.op_TAX(bus, value), Operation::TAY => self.op_TAY(bus, value), - Operation::TSX => self.op_TSX(bus, value), + Operation::TSX => self.op_TSX(bus), Operation::TXA => self.op_TXA(bus, value), Operation::TXS => self.op_TXS(bus, value), Operation::TYA => self.op_TYA(bus, value), @@ -303,7 +305,7 @@ impl CPU { // must be read from the next page. Instead it wraps around and reads from // the same page! fn am_IZX(&mut self, bus: &T) -> (Word, bool) { - let mut ind_addr = self.readw_pc(bus); + let mut ind_addr = self.readb_pc(bus) as Word; ind_addr += self.regs.x as Word; let lo = ind_addr & 0b00001111; @@ -322,7 +324,7 @@ impl CPU { // must be read from the next page. Instead it wraps around and reads from // the same page! fn am_IZY(&mut self, bus: &T) -> (Word, bool) { - let mut ind_addr = self.readw_pc(bus); + let mut ind_addr = self.readb_pc(bus) as Word; ind_addr += self.regs.y as Word; let lo = ind_addr & 0b00001111; @@ -460,12 +462,16 @@ impl CPU { unimplemented!() } - fn op_INX(&mut self, bus: &T, val: Word) { - unimplemented!() + fn op_INX(&mut self, bus: &T) { + self.regs.x += 1; + self.set_flag(ZERO, self.regs.x == 0); + self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0) } - fn op_INY(&mut self, bus: &T, val: Word) { - unimplemented!() + fn op_INY(&mut self, bus: &T) { + self.regs.y += 1; + self.set_flag(ZERO, self.regs.y == 0); + self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0) } // Jump to address (set pc) @@ -476,9 +482,9 @@ impl CPU { // Jump to subroutine (leaves trace on the stack) fn op_JSR(&mut self, bus: &mut T, addr: Word) { self.regs.pc -= 1; - bus.writeb(0x0100 + self.regs.sp as Word, ((self.regs.pc >> 8) & 0x00ff) as Byte); + bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, ((self.regs.pc >> 8) & 0x00ff) as Byte); self.regs.sp -= 1; - bus.writeb(0x0100 + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte); + bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte); self.regs.sp -= 1; self.regs.pc = addr; } @@ -524,18 +530,19 @@ impl CPU { } // Write flags to stack - fn op_PHP(&mut self, bus: &mut T, val: Word) { + fn op_PHP(&mut self, bus: &mut T) { let tmp = self.regs.flags | BREAK | UNUSED; - bus.writeb(0x0100 + self.regs.sp as Word, tmp); + bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, tmp); self.set_flag(BREAK, false); self.set_flag(UNUSED, false); self.regs.sp -= 1; + println!("PHP executed"); } // Read from stack into A fn op_PLA(&mut self, bus: &T, val: Word) { self.regs.sp += 1; - self.regs.a = bus.readb(0x0100 + self.regs.sp as Word); + self.regs.a = bus.readb(STACK_BASE_ADDR + self.regs.sp as Word); self.set_flag(ZERO, self.regs.a == 0); self.set_flag(NEGATIVE, (self.regs.a & 0x80) == 1) } @@ -606,8 +613,9 @@ impl CPU { self.set_flag(NEGATIVE, (self.regs.y & 0x80) == 1) } - fn op_TSX(&mut self, bus: &T, val: Word) { - self.regs.x = bus.readb(0x0100 + self.regs.sp as Word); + // stack pointer to x + fn op_TSX(&mut self, bus: &T) { + self.regs.x = self.regs.sp; self.set_flag(ZERO, self.regs.x == 0); self.set_flag(NEGATIVE, (self.regs.x & 0x80) == 1) } diff --git a/src/nes/disasm.rs b/src/nes/disasm.rs index d4f58f9..e9dd7ac 100644 --- a/src/nes/disasm.rs +++ b/src/nes/disasm.rs @@ -44,11 +44,14 @@ impl Disasm { let jmp_addr = Disasm::get_rel_addr(rel_addr, addr+2); format!("#{:02x} => {:#06x}", rel_addr, jmp_addr) }, - - AddrMode::IND | AddrMode::IZX | AddrMode::IZY=> { + AddrMode::IND => { let addr = mem.readw(mem_iter.next().unwrap()); mem_iter.next().unwrap(); format!("{:#06x}", addr) + }, + AddrMode::IZX | AddrMode::IZY => { + let addr = mem.readb(mem_iter.next().unwrap()); + format!("{:#06x}", addr) } AddrMode::IMP => String::from(""), _ => bail!("Disassembly of {} not implemented", i.addr_mode),