From b2fad73cc546752258b6e0e5b5f56542e66b11c7 Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Fri, 27 Dec 2019 11:10:43 +0100 Subject: [PATCH] restructed --- src/nes/cpu.rs | 114 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 36 deletions(-) diff --git a/src/nes/cpu.rs b/src/nes/cpu.rs index 5f3dbe2..0d39ebd 100644 --- a/src/nes/cpu.rs +++ b/src/nes/cpu.rs @@ -37,15 +37,17 @@ impl Debug for Registers { } pub const STACK_BASE_ADDR: Addr = 0x0100; +pub const LO: Addr = 0x00FF; +pub const HI: Addr = 0xFFFF; -pub const CARRY: Byte = 1 << 0; -pub const ZERO: Byte = 1 << 1; -pub const IRQ: Byte = 1 << 2; -pub const DECIMAL: Byte = 1 << 3; -pub const BREAK: Byte = 1 << 4; -pub const UNUSED: Byte = 1 << 5; -pub const OVERFLOW: Byte = 1 << 6; -pub const NEGATIVE: Byte = 1 << 7; +pub const CARRY: Byte = 1 << 0; // 0000 0001 0x01 +pub const ZERO: Byte = 1 << 1; // 0000 0010 0x02 +pub const IRQ: Byte = 1 << 2; // 0000 0100 0x04 +pub const DECIMAL: Byte = 1 << 3; // 0000 1000 0x08 +pub const BREAK: Byte = 1 << 4; // 0001 0000 0x10 +pub const UNUSED: Byte = 1 << 5; // 0010 0000 0x20 +pub const OVERFLOW: Byte = 1 << 6; // 0100 0000 0x40 +pub const NEGATIVE: Byte = 1 << 7; // 1000 0000 0x80 pub struct CPU { pub regs: Registers, @@ -130,6 +132,36 @@ impl CPU { val } + // Pop a byte from the SP + fn popb_sp(&mut self, bus: &T) -> Byte { + self.regs.sp += 1; + let val = self.readb(bus, STACK_BASE_ADDR + self.regs.sp as Word); + val + } + + // Pop a word from the stack + fn popw_sp(&mut self, bus: &T) -> Word { + let hi = self.popb_sp(bus); + let lo = self.popb_sp(bus); + (hi << 8) as Word & lo as Word + } + + // Push a byte to the SP. + fn pushb_sp(&mut self, bus: &mut T, val: Byte) { + self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, val); + self.regs.sp -= 1; + } + + // push a word to the stack, lo first, hi second + fn pushw_sp(&mut self, bus: &mut T, val: Word) { + let lo = ((val >> 8) & LO) as Byte; + let hi = (val & LO) as Byte; + self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, lo); + self.regs.sp -= 1; + self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, hi); + self.regs.sp -= 1; + } + // Set the flag with the corresponding mask fn set_flag(&mut self, flag: Byte, val: bool) { if val { @@ -154,7 +186,6 @@ impl CPU { // Jump to address fn jump(&mut self, addr: Addr) { - let old_addr = self.regs.pc; self.regs.pc = addr; } @@ -256,19 +287,19 @@ impl CPU { // Absolute address on zero page fn am_ZP0(&mut self, bus: &T) -> (Word, bool) { let addr = self.readb_pc(bus); - (0x00ff & addr as Word, false) + (LO & addr as Word, false) } // Absolute address on zero page with x offset fn am_ZPX(&mut self, bus: &T) -> (Word, bool) { let addr = self.readb_pc(bus) + self.regs.x; - (0x00ff & addr as Word , false) + (LO & addr as Word , false) } // Absolute address on zero page with y offset fn am_ZPY(&mut self, bus: &T) -> (Word, bool) { let addr = self.readb_pc(bus) + self.regs.y; - (0x00ff & addr as Word, false) + (LO & addr as Word, false) } // Absolute address. Next 2 bytes of pc are the address @@ -283,7 +314,8 @@ impl CPU { let tmp_addr = self.readw_pc(bus); let addr = tmp_addr + self.regs.x as Word; - (addr, addr & 0xFF00 != tmp_addr & 0xF00) + let page_cross = addr & HI != tmp_addr & HI; + (addr, page_cross) } // Absolute address with offset. Next 2 bytes of pc are the address @@ -292,18 +324,23 @@ impl CPU { let tmp_addr = self.readw_pc(bus); let addr = tmp_addr + self.regs.y as Word; - (addr, addr & 0xFF00 != tmp_addr & 0xF00) + let page_cross = addr & HI != tmp_addr & HI; + (addr, page_cross) } // Relative addressing. Only used for branching. The next byte on the // pc is a signed offset from the current pc location fn am_REL(&mut self, bus: &T) -> (Word, bool) { let rel_addr = self.readb_pc(bus) as Word; - if rel_addr < 0x80 { - (self.regs.pc + rel_addr, false) + let base_addr = self.regs.pc; + + // If rel_addr > 0x8000, we substract 256 to make a negative jump + let addr = if rel_addr < 128 { + base_addr + rel_addr } else { - (self.regs.pc + rel_addr - 256, false) - } + base_addr + rel_addr - 256 + }; + (addr, false) } // the next 16 bits are an address. This address stores the real address @@ -312,29 +349,32 @@ impl CPU { // must be read from the next page. Instead it wraps around and reads from // the same page! fn am_IND(&mut self, bus: &T) -> (Word, bool) { - let mut ind_addr = self.readw_pc(bus); + let ind_addr = self.readw_pc(bus); - // page boundary bug - let lo = ind_addr & 0b00001111; - if lo == 0x00FF { - ind_addr -= 0x00FF; - } + // page boundary bug: If LO is 0x00FF, we are at the page border + // and need to wrap around. So hi is fetched from 0x0000 instead of + // 0x0100 + let addr = if ind_addr & LO == 0x00FF { + let lo = self.readb(bus, ind_addr); + let hi_addr = ind_addr - 0x00FF; + let hi = self.readb(bus, hi_addr); + ((hi << 8) as Word | lo as Word) + } else { // normal behaviour + self.readw(bus, ind_addr) + }; - let addr = bus.readw(ind_addr); (addr, false) } - // the next 8 bits + x are an address. This address stores the real address + // the next 8 bits + x are an address on the zero page. 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_IZX(&mut self, bus: &T) -> (Word, bool) { - let mut ind_addr = self.readb_pc(bus) as Word; - ind_addr += self.regs.x as Word; + let ind_addr = self.readb_pc(bus); - let addr = bus.readw(ind_addr & 0x00FF); - (addr, false) + // 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) } // the next 8 bits + y are an address. This address stores the real address @@ -343,10 +383,12 @@ 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 tmp_addr = self.readb_pc(bus) as Word; - let addr = self.readw(bus, tmp_addr & 0x00FF); + let ind_addr = self.readb_pc(bus); - (addr, addr & 0xFF00 != tmp_addr & 0xF00) + // since its a zero page addr, we are only interested in low + let addr = ind_addr.wrapping_add(self.regs.y); + + (addr as Word, false) } // Operations