diff --git a/src/main.rs b/src/main.rs index 693d1eb..143042a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,6 +86,7 @@ fn main() -> Result<(), Error> { let mut run = false; while let Some(event) = events.next(&mut window) { if let Some(_) = event.update_args() { + // if cpu.regs.pc == 0xD031 || cpu.regs.pc == 0xD01A { run = false } if run { cpu.clock(&mut bus); } @@ -292,7 +293,7 @@ fn render_disasm(glyphs: &mut GlyphBrush, fn render_memory(glyphs: &mut GlyphBrush, bus: &MemoryBus, offset: [f32; 2]) { let mut position_y = (offset[0], offset[1]); - for page in (0x0100..0x01FF).step_by(16) { + for page in (0x0000..0x00FF).step_by(16) { position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX; let mut line = format!("{:#06x}:", page); (0u16..16u16).map(|offset| offset + page) @@ -309,7 +310,7 @@ fn render_memory(glyphs: &mut GlyphBrush, bus: &MemoryBus, o } position_y.1 += FT_LINE_DISTANCE+FT_SIZE_PX * 1.5; - for page in (0x2000..0x20FF).step_by(16) { + for page in (0x0400..0x06FF).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 3cc22aa..8ba6a08 100644 --- a/src/nes/bus.rs +++ b/src/nes/bus.rs @@ -62,7 +62,7 @@ impl MemoryBus { } 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] { diff --git a/src/nes/cpu.rs b/src/nes/cpu.rs index 8715ceb..b62fb0b 100644 --- a/src/nes/cpu.rs +++ b/src/nes/cpu.rs @@ -24,7 +24,7 @@ impl Registers { y: 0, sp: 0x00FD, pc: 0x0000, - flags: 0b00100100, + flags: 0x24, } } } @@ -371,24 +371,27 @@ impl CPU { fn am_IZX(&mut self, bus: &T) -> (Word, bool) { let ind_addr = self.readb_pc(bus); - // since its a zero page addr, we are only interested in low - let addr = ind_addr.wrapping_add(self.regs.x); - - (addr as Word, false) + let lo_addr = ind_addr.wrapping_add(self.regs.x); + let hi_addr = ind_addr.wrapping_add(self.regs.x).wrapping_add(1); + let lo = self.readb(bus, lo_addr as Word); + let hi = self.readb(bus, hi_addr as Word); + ((hi as Word) << 8 | lo as Word, false) } - // the next 8 bits + y are an address. This address stores the real address - // that is used for the operation. - // Hardware bug: Normally, if lo of the supplied address is 0xFF, high byte - // 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 ind_addr = self.readb_pc(bus); - // since its a zero page addr, we are only interested in low - let addr = ind_addr.wrapping_add(self.regs.y); + let lo = self.readb(bus, ind_addr as Word); + let hi = self.readb(bus, ind_addr.wrapping_add(1) as Word); - (addr as Word, false) + let addr = (hi as Word) << 8 | lo as Word; + let addr = addr.wrapping_add(self.regs.y as Word); + + if addr & HI != (hi as Word) << 8 { + (addr, true) + } else { + (addr, false) + } } // Operations @@ -402,15 +405,19 @@ impl CPU { // Negative bit is set fn op_ADC(&mut self, bus: &T, addr: Word) -> bool { let val = self.readb(bus, addr) as Word; - let tmp1 = (self.regs.a as Word).overflowing_add(val); - let result = tmp1.0.overflowing_add(self.get_flag(CARRY) as Word); + let tmp = self.regs.a as Word + val + self.get_flag(CARRY) as Word; + + self.set_flag(CARRY, tmp > 255); + self.set_flag_nz(tmp as Byte); - self.regs.a = result.0 as Byte; - let is_overflown = tmp1.1 || result.1; - - self.set_flag(CARRY, (result.0 & LO) > 255); + // There are two cases where the overflow bit should be set. if we look + // at the last bit of val and A: a) 0 + 0 = 1 b) 1 + 1 = 0. This + // expression selects for both of them + let is_overflown = (!(self.regs.a as Word ^ val) & + (self.regs.a as Word ^ tmp)) & 0x0080 != 0; self.set_flag(OVERFLOW, is_overflown); - self.set_flag_nz(self.regs.a); + + self.regs.a = tmp as Byte; true } @@ -423,7 +430,7 @@ impl CPU { fn op_AND(&mut self, bus: &T, addr: Addr) -> bool { let val = self.readb(bus, addr); self.regs.a &= val; - self.set_flag_nz(val as Byte); + self.set_flag_nz(self.regs.a); true } @@ -437,16 +444,22 @@ impl CPU { // If the result is 0, Zero bit is set. If the result if negative, // Negative bit is set fn op_ASL(&mut self, bus: &mut T, addr: Addr) -> bool { - let val = self.readb(bus, addr); + // LSR works on memory or A. We can differenciate by the addr mode + let addr_mode = &Instruction::decode_op(self.curr_op).unwrap().addr_mode; + let val = if *addr_mode == AddrMode::IMP { + self.regs.a + } else { + self.readb(bus, addr) + }; let shifted = (val << 1) as Byte; + self.set_flag(CARRY, (val & 0b1000000) == 0); - if Instruction::decode_op(self.curr_op).unwrap().addr_mode == AddrMode::IMP { + if *addr_mode == AddrMode::IMP { self.regs.a = shifted; } else { self.writeb(bus, addr, shifted); } - self.set_flag(CARRY, (val & 0b1000000) != 0); self.set_flag_nz(shifted); false } @@ -618,7 +631,7 @@ impl CPU { // Compare Y fn op_CPY(&mut self, bus: &T, addr: Addr) -> bool { let val = self.readb(bus, addr); - let tmp = (self.regs.a as Word).wrapping_sub(val as Word); + let tmp = (self.regs.y as Word).wrapping_sub(val as Word); self.set_flag(CARRY, self.regs.y >= val); self.set_flag_nz(tmp as Byte); @@ -749,12 +762,19 @@ impl CPU { // Each of the bits in A or M is shift one place to the right. The bit // that was in bit 0 is shifted into the carry flag. Bit 7 is set to zero. fn op_LSR(&mut self, bus: &mut T, addr: Addr) -> bool { - let val = self.readb(bus, addr) as Word; - self.set_flag(CARRY, (val & 0b00000001) == 1); + // LSR works on memory or A. We can differenciate by the addr mode + let addr_mode = &Instruction::decode_op(self.curr_op).unwrap().addr_mode; + let val = if *addr_mode == AddrMode::IMP { + self.regs.a as Word + } else { + self.readb(bus, addr) as Word + }; + + self.set_flag(CARRY, (val & 0b00000001) != 0); let shifted = (val >> 1) as Byte; self.set_flag_nz(shifted); - if Instruction::decode_op(self.curr_op).unwrap().addr_mode == AddrMode::IMP { + if *addr_mode == AddrMode::IMP { self.regs.a = shifted; } else { self.writeb(bus, addr, shifted); @@ -787,18 +807,16 @@ impl CPU { // PHP - Push Processor Status // Pushes a copy of the status flags on to the stack. fn op_PHP(&mut self, bus: &mut T) -> bool { - let tmp = self.regs.flags | BREAK | UNUSED; + let tmp = self.regs.flags | BREAK; self.pushb_sp(bus, tmp); self.set_flag(BREAK, false); - self.set_flag(UNUSED, false); false } // Read from stack into A fn op_PLA(&mut self, bus: &T) -> bool { self.regs.a = self.popb_sp(bus); - self.set_flag(ZERO, self.regs.a == 0); - self.set_flag(NEGATIVE, (self.regs.a & 0x80) == 1); + self.set_flag_nz(self.regs.a); false } @@ -807,7 +825,10 @@ impl CPU { // flags will take on new states as determined by the value pulled. fn op_PLP(&mut self, bus: &T) -> bool { self.regs.flags = self.popb_sp(bus); - self.set_flag(UNUSED, true); // Just to be sure this keeps set. + + // Im not sure why this is set to false and stack value is not used + // but that's how the nestest.log shows it.. + self.set_flag(BREAK, false); false } @@ -816,13 +837,18 @@ impl CPU { // filled with the current value of the carry flag whilst the old bit 7 // becomes the new carry flag value. fn op_ROL(&mut self, bus: &mut T, addr: Addr) -> bool { - let val = self.readb(bus, addr) as Word; + let addr_mode = &Instruction::decode_op(self.curr_op).unwrap().addr_mode; + let val = if *addr_mode == AddrMode::IMP { + self.regs.a as Word + } else { + self.readb(bus, addr) as Word + }; let shifted = (val << 1) as Byte | self.get_flag(CARRY); - self.set_flag(CARRY, (val & 0b1000000) > 0); + self.set_flag(CARRY, (val & 0b1000000) == 0); self.set_flag_nz(shifted); - if Instruction::decode_op(self.curr_op).unwrap().addr_mode == AddrMode::IMP { + if *addr_mode == AddrMode::IMP { self.regs.a = shifted as Byte; } else { self.writeb(bus, addr, shifted); @@ -835,13 +861,19 @@ impl CPU { // filled with the current value of the carry flag whilst the old bit 0 // becomes the new carry flag value. fn op_ROR(&mut self, bus: &mut T, addr: Addr) -> bool { - let val = self.readb(bus, addr) as Word; + let addr_mode = &Instruction::decode_op(self.curr_op).unwrap().addr_mode; + let val = if *addr_mode == AddrMode::IMP { + self.regs.a as Word + } else { + self.readb(bus, addr) as Word + }; + let shifted = (val >> 1) as Byte | (self.get_flag(CARRY) << 7); self.set_flag(CARRY, (val & 0b00000001) > 0); self.set_flag_nz(shifted); - if Instruction::decode_op(self.curr_op).unwrap().addr_mode == AddrMode::IMP { + if *addr_mode == AddrMode::IMP { self.regs.a = shifted; } else { self.writeb(bus, addr, shifted); @@ -856,7 +888,6 @@ impl CPU { fn op_RTI(&mut self, bus: &T) -> bool { self.regs.flags = self.popb_sp(bus); self.regs.flags &= !BREAK; - self.regs.flags &= !UNUSED; let pc_lo = self.popb_sp(bus) as Word; let pc_hi = self.popb_sp(bus) as Word; @@ -889,16 +920,20 @@ impl CPU { // invert buttom 8 bits let val = val ^ LO; - // Now its a simple addition - let tmp1 = (self.regs.a as Word).overflowing_add(val); - let result = tmp1.0.overflowing_add(self.get_flag(CARRY) as Word); + // Now it's similar to ADC + let tmp = self.regs.a as Word + val + self.get_flag(CARRY) as Word; + + self.set_flag(CARRY, tmp > 255); + self.set_flag_nz(tmp as Byte); - self.regs.a = result.0 as Byte; - let is_overflown = tmp1.1 || result.1; - - self.set_flag(CARRY, (result.0 & LO) > 255); + // There are two cases where the overflow bit should be set. if we look + // at the last bit of val and A: a) 0 + 0 = 1 b) 1 + 1 = 0. This + // expression selects for both of them + let is_overflown = (!(self.regs.a as Word ^ val) & + (self.regs.a as Word ^ tmp)) & 0x0080 != 0; self.set_flag(OVERFLOW, is_overflown); - self.set_flag_nz(self.regs.a); + + self.regs.a = tmp as Byte; true } @@ -943,40 +978,35 @@ impl CPU { // a to x fn op_TAX(&mut self) -> bool { self.regs.x = self.regs.a; - self.set_flag(ZERO, self.regs.x == 0); - self.set_flag(NEGATIVE, (self.regs.x & 0x80) == 1); + self.set_flag_nz(self.regs.x); false } // a to y fn op_TAY(&mut self) -> bool { self.regs.y = self.regs.a; - self.set_flag(ZERO, self.regs.y == 0); - self.set_flag(NEGATIVE, (self.regs.y & 0x80) == 1); + self.set_flag_nz(self.regs.y); false } // stack pointer to x fn op_TSX(&mut self) -> bool { self.regs.x = self.regs.sp; - self.set_flag(ZERO, self.regs.x == 0); - self.set_flag(NEGATIVE, (self.regs.x & 0x80) == 1); + self.set_flag_nz(self.regs.x); false } // transfer x to a fn op_TXA(&mut self) -> bool { self.regs.a = self.regs.x; - self.set_flag(ZERO, self.regs.a == 0); - self.set_flag(NEGATIVE, (self.regs.a & 0x80) == 1); + self.set_flag_nz(self.regs.x); false } // transfer y to a fn op_TYA(&mut self) -> bool { self.regs.a = self.regs.y; - self.set_flag(ZERO, self.regs.a == 0); - self.set_flag(NEGATIVE, (self.regs.a & 0x80) == 1); + self.set_flag_nz(self.regs.a); false } diff --git a/src/nes/cpu/instructions.rs b/src/nes/cpu/instructions.rs index acb7ae3..91e5f22 100644 --- a/src/nes/cpu/instructions.rs +++ b/src/nes/cpu/instructions.rs @@ -6,18 +6,18 @@ use std::fmt::{Debug,Display}; #[derive(Debug,PartialEq)] pub enum AddrMode { - IMP, - IMM, - ZP0, - ZPX, - ZPY, - REL, - ABS, - ABX, - ABY, - IND, - IZX, - IZY, + IMP, // Implied + IMM, // Immediate + ZP0, // Zero page + ZPX, // Zero Page with X (ZPX and ZPY are the same at nesdev) + ZPY, // Zero Page with Y (ZPX and ZPY are the same at nesdev) + REL, // Relatvive (Only for branching) + ABS, // Absolute address + ABX, // Absolute with X offset + ABY, // Absolute with Y offset + IND, // Indirect addressing + IZX, // Pre Indexed + IZY, // Post Indexed } impl fmt::Display for AddrMode { @@ -27,7 +27,7 @@ impl fmt::Display for AddrMode { } -#[derive(Debug)] +#[derive(Debug,PartialEq)] pub enum Operation { ADC, AND,