From c9e74e00f47edf1e01523cda1cd97f67be11081c Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Thu, 26 Dec 2019 21:16:25 +0100 Subject: [PATCH] some bug fixes --- src/main.rs | 27 +++++++++---- src/nes/bus.rs | 12 +++--- src/nes/cartridge.rs | 2 + src/nes/cpu.rs | 91 +++++++++++++++++++++++++++----------------- src/nes/disasm.rs | 16 ++++++-- src/nes/mappers.rs | 23 +++++++---- 6 files changed, 112 insertions(+), 59 deletions(-) diff --git a/src/main.rs b/src/main.rs index e66ab07..9f7a790 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use nes::cartridge::*; use nes::disasm::*; use opengl_graphics::OpenGL; use log::Level; +use failure::Error; use gfx_glyph::{Section, GlyphBrushBuilder,GlyphBrush, Scale}; use gfx_device_gl::{Resources,Factory}; @@ -25,19 +26,19 @@ const BG_COLOR: [f32; 4] = [0.0, 0.0, 252.0/256.0, 1.0]; // font options const FT_SIZE_PX: f32 = 11.0; const FT_COLOR_WHITE: [f32; 4] = [1.0; 4]; -const FT_COLOR_RED: [f32; 4] = [168.0/256.0, 0.0, 32.0/256.0, 1.0]; +const FT_COLOR_RED: [f32; 4] = [168.0/256.0, 32.0/256.0, 0.0, 1.0]; const FT_COLOR_GREEN: [f32; 4] = [0.0, 168.0/256.0, 0.0, 1.0]; const FT_LINE_DISTANCE: f32 = FT_SIZE_PX * 0.5; lazy_static! { static ref FT_SCALE: Scale = Scale::uniform(FT_SIZE_PX); } -fn main() { - simple_logger::init_with_level(Level::Error).unwrap(); +fn main() -> Result<(), Error> { + simple_logger::init_with_level(Level::Debug).unwrap(); let mut bus = MemoryBus::new(); - let cartridge = Path::new("test_roms/registers.nes"); - let cartridge = Cartridge::new(cartridge).unwrap(); + let cartridge = Path::new("test_roms/nestest.nes"); + let cartridge = Cartridge::new(cartridge)?; bus.insert_cartrige(cartridge); // Load little test program into ram @@ -55,7 +56,7 @@ fn main() { // bus.writew(0xfffc, offset); // disassemble instructions - let disasm = Disasm::disassemble(&bus, 0xe1ff, 0xffff-2).unwrap(); + let disasm = Disasm::disassemble(&bus, 0xC000, 0xFFFF).unwrap(); // println!("{:?}", disasm.instructions); // return; // let disasm = Disasm::disassemble(&[], 0x000).unwrap(); @@ -63,6 +64,8 @@ fn main() { // Create and reset CPU let mut cpu: CPU = CPU::new(); cpu.find_pc_addr(&bus); + cpu.regs.pc = 0xC000; + // return Ok(()); // cpu.reset(&bus); // Prepare window and drawing resources @@ -115,6 +118,7 @@ fn main() { } } } + Ok(()) } fn render(window: &mut PistonWindow, event: &Event, @@ -220,6 +224,15 @@ fn render_cpu(glyphs: &mut GlyphBrush, cpu: &CPU, offset: [f color: color, ..Section::default() }); + position.0 += 16.0; + let color = FT_COLOR_WHITE; + glyphs.queue(Section { + text: &format!("{:#06x}", cpu.regs.flags), + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); let cpu_register_texts = [ &format!("A: {0:#x} ({0})", cpu.regs.a), @@ -296,7 +309,7 @@ fn render_memory(glyphs: &mut GlyphBrush, bus: &MemoryBus, o } position_y.1 += FT_LINE_DISTANCE+FT_SIZE_PX * 1.5; - for page in (0x6000..0x60FF).step_by(16) { + for page in (0x2000..0x20FF).step_by(16) { position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX; let mut line = format!("{:#06x}:", page); (0u16..16u16).map(|offset| offset + page) diff --git a/src/nes/bus.rs b/src/nes/bus.rs index c0133d6..3cc22aa 100644 --- a/src/nes/bus.rs +++ b/src/nes/bus.rs @@ -44,14 +44,14 @@ pub trait Clockable { // A simple bus giving access to a chunk of memory // and the cartrige pub struct MemoryBus { - ram: [Byte; 0x07ff], // 2kb + ram: [Byte; 0x0800], // 2kb cartrige: Option } impl MemoryBus { pub fn new() -> MemoryBus { MemoryBus { - ram: [0; 0x07ff], + ram: [0; 0x0800], cartrige: None, } } @@ -65,12 +65,12 @@ impl Memory for MemoryBus { fn readb(&self, addr: Addr) -> Byte { if let Some(cartrige) = &self.cartrige { - if CART_ADDR_RANGE[0] <= addr && addr < CART_ADDR_RANGE[1] { + if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { return cartrige.readb(addr) } } - if RAM_ADDR_RANGE[0] <= addr && addr < RAM_ADDR_RANGE[1] { + if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { // Ram is 3x mirrored after 07ff return self.ram[(addr & 0x07ff) as usize] } @@ -79,12 +79,12 @@ impl Memory for MemoryBus { fn writeb(&mut self, addr: Addr, data: Byte) { if let Some(cartrige) = &mut self.cartrige { - if CART_ADDR_RANGE[0] <= addr && addr < CART_ADDR_RANGE[1] { + if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { cartrige.writeb(addr, data) } } - if RAM_ADDR_RANGE[0] <= addr && addr < RAM_ADDR_RANGE[1] { + if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { // Ram is 3x mirrored after 07ff self.ram[(addr & 0x07ff) as usize] = data } diff --git a/src/nes/cartridge.rs b/src/nes/cartridge.rs index 03ddf44..30524bb 100644 --- a/src/nes/cartridge.rs +++ b/src/nes/cartridge.rs @@ -86,6 +86,8 @@ impl Cartridge { id => bail!("Mapper {:04} not supported", id) }; + + debug!("Cartrige loaded. mapper: {:?}", &mapper); Ok(Cartridge { prg_rom: prg_rom, chr_rom: chr_rom, diff --git a/src/nes/cpu.rs b/src/nes/cpu.rs index bd34154..aec592c 100644 --- a/src/nes/cpu.rs +++ b/src/nes/cpu.rs @@ -136,6 +136,11 @@ impl CPU { } } + fn set_flag_nz(&mut self, val: Byte) { + self.set_flag(ZERO, val == 0); + self.set_flag(NEGATIVE, (val & 0x80) == 0); + } + pub fn get_flag(&self, flag: Byte) -> Byte { if self.regs.flags & flag > 0 { 1 @@ -340,9 +345,8 @@ impl CPU { let val = tmp2.0; let overflow = tmp1.1 || tmp2.1; self.set_flag(CARRY, (val & 0xFF) > 255); - self.set_flag(ZERO, val == 0); - self.set_flag(NEGATIVE, (val & 0x80) == 1); self.set_flag(OVERFLOW, overflow); + self.set_flag_nz(val as Byte); self.regs.a = val as Byte; } @@ -366,25 +370,44 @@ impl CPU { unimplemented!() } - fn op_BIT(&mut self, bus: &T, val: Word) { - unimplemented!() + // bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V); + // the zeroflag is set to the result of operand AND accumulator. + fn op_BIT(&mut self, bus: &T, addr: Word) { + let val = self.readb(bus, addr); + self.set_flag(OVERFLOW, (val & OVERFLOW) == 1); + self.set_flag(NEGATIVE, (val & NEGATIVE) == 1); + println!("{:#06x}: {}", addr, val); + println!("{}", (val & self.regs.a)); + self.set_flag(ZERO, (val & self.regs.a) == 0); } - fn op_BMI(&mut self, bus: &T, val: Word) { - unimplemented!() + // Jump to address + fn jump(&mut self, addr: Addr) { + let old_addr = self.regs.pc; + self.regs.pc = addr; + println!("Jumping from {:#x} to {:#x}", old_addr, addr); } - // Branch if 0 flag is set - fn op_BNE(&mut self, addr: Word) { - if self.get_flag(ZERO) == 0 { - let old_addr = self.regs.pc; - self.regs.pc = addr; - println!("Jumping from {:#x} to {:#x}", old_addr, addr); + + // Branch if negative flag is set + fn op_BMI(&mut self, bus: &T, addr: Addr) { + if self.get_flag(NEGATIVE) == 1 { + self.jump(addr); } } - fn op_BPL(&mut self, bus: &T, val: Word) { - unimplemented!() + // Branch if 0 flag is set + fn op_BNE(&mut self, addr: Addr) { + if self.get_flag(ZERO) == 0 { + self.jump(addr); + } + } + + // Branch if negative flag is unset + fn op_BPL(&mut self, bus: &T, addr: Addr) { + if self.get_flag(NEGATIVE) == 0 { + self.jump(addr); + } } fn op_BRK(&mut self, bus: &T, val: Word) { @@ -439,15 +462,13 @@ impl CPU { // Decrement X fn op_DEX(&mut self) { self.regs.x = self.regs.x.wrapping_sub(1); - self.set_flag(ZERO, self.regs.x == 0); - self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0) + self.set_flag_nz(self.regs.x); } // Decrement Y fn op_DEY(&mut self) { self.regs.y = self.regs.y.wrapping_sub(1); - self.set_flag(ZERO, self.regs.y == 0); - self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0) + self.set_flag_nz(self.regs.y); } fn op_EOR(&mut self, bus: &T, val: Word) { @@ -458,25 +479,22 @@ impl CPU { let val = self.readb(bus, addr); let val = val.wrapping_add(1); self.writeb(bus, addr, val); - self.set_flag(ZERO, val == 0); - self.set_flag(NEGATIVE, (val & 0x80) != 0) + self.set_flag_nz(val); } fn op_INX(&mut self, bus: &T) { self.regs.x = self.regs.x.wrapping_add(1); - self.set_flag(ZERO, self.regs.x == 0); - self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0) + self.set_flag_nz(self.regs.x); } fn op_INY(&mut self, bus: &T) { self.regs.y = self.regs.y.wrapping_add(1); - self.set_flag(ZERO, self.regs.y == 0); - self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0) + self.set_flag_nz(self.regs.y); } // Jump to address (set pc) fn op_JMP(&mut self, bus: &T, addr: Word) { - self.regs.pc = addr; + self.jump(addr); } // Jump to subroutine (leaves trace on the stack) @@ -486,31 +504,28 @@ impl CPU { self.regs.sp -= 1; bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte); self.regs.sp -= 1; - self.regs.pc = addr; + self.jump(addr); } // Read value from addr into A fn op_LDA(&mut self, bus: &T, addr: Word) { let val = bus.readb(addr); self.regs.a = val; - self.set_flag(ZERO, val == 0); - self.set_flag(NEGATIVE, (val & 0x80) != 0); + self.set_flag_nz(val); } // Read value from addr into X fn op_LDX(&mut self, bus: &T, addr: Word) { let val = bus.readb(addr); self.regs.x = val; - self.set_flag(ZERO, val == 0); - self.set_flag(NEGATIVE, (val & 0x80) != 0); + self.set_flag_nz(val); } // Read value from addr into Y fn op_LDY(&mut self, bus: &T, addr: Word) { let val = bus.readb(addr); self.regs.y = val; - self.set_flag(ZERO, val == 0); - self.set_flag(NEGATIVE, (val & 0x80) != 0); + self.set_flag_nz(val); } fn op_LSR(&mut self, bus: &T, val: Word) { @@ -521,8 +536,9 @@ impl CPU { // does nothing } - fn op_ORA(&mut self, bus: &T, val: Word) { - unimplemented!() + fn op_ORA(&mut self, bus: &T, addr: Addr) { + self.regs.a |= self.readb(bus, addr); + self.set_flag_nz(self.regs.a); } fn op_PHA(&mut self, bus: &T, val: Word) { @@ -564,7 +580,12 @@ impl CPU { } fn op_RTS(&mut self, bus: &T, val: Word) { - unimplemented!() + self.regs.sp += 1; + let lo = bus.readb(0x0100 + self.regs.sp as Addr); + self.regs.sp += 1; + let hi = bus.readb(0x0100 + self.regs.sp as Addr); + let addr = (hi as Addr) << 8 | lo as Addr; + self.regs.pc = addr + 1; } fn op_SBC(&mut self, bus: &T, val: Word) { diff --git a/src/nes/disasm.rs b/src/nes/disasm.rs index e9dd7ac..83a7cdf 100644 --- a/src/nes/disasm.rs +++ b/src/nes/disasm.rs @@ -20,16 +20,22 @@ impl Disasm { pub fn disassemble(mem: &MemoryBus, start: Addr, stop: Addr) -> Result { let mut instructions = Vec::new(); let mut addresses = Vec::new(); - let mut mem_iter = ((start as usize) .. (stop as usize)+1).map({|a| a as Addr}); + let mut mem_iter = ((start as usize) .. (stop as usize)).map({|a| a as Addr}); while let Some(addr) = mem_iter.next() { + let opcode = mem.readb(addr); + // Decode opcode, default to NOP/IMP to "skip" the byte let i = Instruction::decode_op(opcode) .unwrap_or(Instruction::decode_op(0xeau8).unwrap()); + // debug!("{:?}", i); let args = match i.addr_mode { - AddrMode::IMM => format!("#{0:02x} ({0})", mem.readb(mem_iter.next().unwrap())), + AddrMode::IMM => { + let val = mem.readb(mem_iter.next().unwrap()); + format!("#{0:02x} ({0})", val) + }, AddrMode::ZP0 | AddrMode::ZPX | AddrMode::ZPY => { let rel_addr = mem.readb(mem_iter.next().unwrap()); format!("{:#04x}", rel_addr) @@ -58,9 +64,13 @@ impl Disasm { }; let s = format!("{:#06x}: {} {} ({})", addr, i.operation, args, i.addr_mode); - // debug!("{:#06x} {}", addr, &s); + // println!("opcode: {:#04x} {:?}", opcode, i); + // println!("{}", &s); + instructions.push(s); addresses.push(addr); + + } Ok(Disasm { start, stop, instructions, addresses }) } diff --git a/src/nes/mappers.rs b/src/nes/mappers.rs index 87bffc5..316101d 100644 --- a/src/nes/mappers.rs +++ b/src/nes/mappers.rs @@ -16,6 +16,7 @@ pub trait Mapper { // Cartrige: // 0x4000-0xffff -> first 16K // 0xc000-0xffff -> last 16K or mirror or 0x8000-0xbfff +#[derive(Debug)] pub struct Mapper0 { prg_banks: Byte, chr_banks: Byte, @@ -29,17 +30,23 @@ impl Mapper0 { impl Mapper for Mapper0 { fn map_read_addr(&self, addr: Addr) -> Addr { - if self.prg_banks > 1 { - addr & 0x7fff - } else { - addr & 0x3fff + if 0x8000 <= addr && addr <= 0xFFFF { + if self.prg_banks > 1 { + return addr & 0x7fff; + } else { + return addr & 0x3fff; + } } + 0x0000 } fn map_write_addr(&self, addr: Addr) -> Addr { - if self.prg_banks > 1 { - addr & 0x7fff - } else { - addr & 0x3fff + if 0x8000 <= addr && addr <= 0xFFFF { + if self.prg_banks > 1 { + return addr & 0x7fff; + } else { + return addr & 0x3fff; + } } + 0x0000 } }