From 0388a6ba24643b9d73eb509aeebf09fd12c1e613 Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Fri, 27 Dec 2019 00:06:57 +0100 Subject: [PATCH] more opcodes implemented --- src/main.rs | 2 - src/nes/cpu.rs | 449 ++++++++++++++++++++++++++---------- src/nes/cpu/instructions.rs | 2 +- 3 files changed, 322 insertions(+), 131 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9f7a790..80fc3c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,8 +65,6 @@ fn main() -> Result<(), Error> { 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 let mut window: PistonWindow = WindowSettings::new("NESemu", [256*3, 240*2]) diff --git a/src/nes/cpu.rs b/src/nes/cpu.rs index aec592c..5f3dbe2 100644 --- a/src/nes/cpu.rs +++ b/src/nes/cpu.rs @@ -50,7 +50,8 @@ pub const NEGATIVE: Byte = 1 << 7; pub struct CPU { pub regs: Registers, curr_op: Byte, // current operation - cycles: u8, // number of clock clycles the CPU is ahead of global clock + cycles: u64, // number of clock clycles the CPU is ahead of global clock + cycles_ahead: u8, } // Default implementation to read/write from bus @@ -59,15 +60,17 @@ impl BusDevice for CPU { } // A cpu is clockable impl Clockable for CPU { fn clock(&mut self, bus: &mut T) { - if self.cycles == 0 { + if self.cycles_ahead == 0 { let opcode = self.readb_pc(bus); self.curr_op = opcode; let instruction = Instruction::decode_op(opcode).unwrap(); // TODO error handling - self.cycles = self.run_instruction(bus, instruction); + info!("{:#06X} {:02X} {} A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X} CYC:{}", + self.regs.pc-1, opcode, instruction.operation, + self.regs.a, self.regs.x, self.regs.y, self.regs.flags, self.regs.sp, self.cycles); + self.cycles_ahead = self.run_instruction(bus, instruction); } - debug!("{:?}", self); - self.cycles -= 1; - + self.cycles_ahead -= 1; + self.cycles += 1 } } @@ -75,8 +78,9 @@ impl CPU { pub fn new() -> Self { CPU { regs: Registers::new(), - cycles: 0, curr_op: 0x00, + cycles: 0, + cycles_ahead: 0, } } @@ -109,7 +113,7 @@ impl CPU { // True if the operation is not finished yet pub fn is_ahead(&self) -> bool { - return self.cycles > 0; + return self.cycles_ahead > 0; } // read the next opcode and increment pc @@ -128,7 +132,6 @@ impl CPU { // Set the flag with the corresponding mask fn set_flag(&mut self, flag: Byte, val: bool) { - debug!("{}set flag: {:08b}", if val { "" } else {"un"}, flag); if val { self.regs.flags |= flag; } else { @@ -149,6 +152,12 @@ impl CPU { } } + // Jump to address + fn jump(&mut self, addr: Addr) { + let old_addr = self.regs.pc; + self.regs.pc = addr; + } + fn run_instruction(&mut self, bus: &mut T, i: &Instruction) -> u8 { let (value, page_cross) = match &i.addr_mode { AddrMode::IMP => self.am_IMP(), @@ -164,9 +173,8 @@ impl CPU { AddrMode::IZX => self.am_IZX(bus), AddrMode::IZY => self.am_IZY(bus), }; - debug!("{:?}, Operand: {:#x}", i, value); - match i.operation { + let extra_cycle_on_page_cross = match i.operation { Operation::ADC => self.op_ADC(bus, value), Operation::AND => self.op_AND(bus, value), Operation::ASL => self.op_ASL(bus, value), @@ -177,9 +185,9 @@ impl CPU { Operation::BMI => self.op_BMI(bus, value), Operation::BNE => self.op_BNE(value), Operation::BPL => self.op_BPL(bus, value), - Operation::BRK => self.op_BRK(bus, value), - Operation::BVC => self.op_BVC(bus, value), - Operation::BVS => self.op_BVS(bus, value), + Operation::BRK => self.op_BRK(bus), + Operation::BVC => self.op_BVC(value), + Operation::BVS => self.op_BVS(value), Operation::CLC => self.op_CLC(), Operation::CLD => self.op_CLD(), Operation::CLI => self.op_CLI(), @@ -223,21 +231,22 @@ impl CPU { Operation::TXA => self.op_TXA(bus, value), Operation::TXS => self.op_TXS(bus, value), Operation::TYA => self.op_TYA(bus, value), - } + }; - if page_cross { + if page_cross && extra_cycle_on_page_cross { i.cycles[0] + i.cycles[1] } else { i.cycles[0] } } - // Implied aka no target + // Implied aka no target fn am_IMP(&mut self) -> (Word, bool) { (0, false) } - // Immediate, next byte comes from pc + // Immediate, next byte of pc as addr for read (value is stores after + // opcode) fn am_IMM(&mut self) -> (Word, bool) { let addr = self.regs.pc; self.regs.pc += 1; @@ -247,35 +256,28 @@ impl CPU { // Absolute address on zero page fn am_ZP0(&mut self, bus: &T) -> (Word, bool) { let addr = self.readb_pc(bus); - (addr as Word & 0x0ff, false) + (0x00ff & 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; - (addr as Word & 0x0ff, false) + (0x00ff & 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; - (addr as Word & 0x0ff, false) - } - - 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) - } else { - (self.regs.pc + rel_addr - 256, false) - } + (0x00ff & addr as Word, false) } + // Absolute address. Next 2 bytes of pc are the address fn am_ABS(&mut self, bus: &T) -> (Word, bool) { let addr = self.readw_pc(bus); (addr, false) } + // Absolute address with offset. Next 2 bytes of pc are the address // additional cycle on page wrap fn am_ABX(&mut self, bus: &T) -> (Word, bool) { let tmp_addr = self.readw_pc(bus); @@ -284,6 +286,7 @@ impl CPU { (addr, addr & 0xFF00 != tmp_addr & 0xF00) } + // Absolute address with offset. Next 2 bytes of pc are the address // additional cycle on page wrap fn am_ABY(&mut self, bus: &T) -> (Word, bool) { let tmp_addr = self.readw_pc(bus); @@ -292,6 +295,17 @@ impl CPU { (addr, addr & 0xFF00 != tmp_addr & 0xF00) } + // 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) + } else { + (self.regs.pc + rel_addr - 256, false) + } + } + // the next 16 bits 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 @@ -337,8 +351,14 @@ impl CPU { // Operations - // Add to A - fn op_ADC(&mut self, bus: &T, addr: Word) { + // ADC - Add with Carry + // A,Z,C,N = A+M+C + // This instruction adds the contents of a memory location to the + // accumulator together with the carry bit. If overflow occurs the + // carry bit is set, this enables multiple byte addition to be performed. + // If the result is 0, Zero bit is set. If the result if negative, + // 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 tmp2 = tmp1.0.overflowing_add(self.get_flag(CARRY) as Word); @@ -348,316 +368,489 @@ impl CPU { self.set_flag(OVERFLOW, overflow); self.set_flag_nz(val as Byte); self.regs.a = val as Byte; + true } - fn op_AND(&mut self, bus: &T, val: Word) { - unimplemented!() + // AND - Logical AND + // A,Z,N = A&M + // A logical AND is performed, bit by bit, on the accumulator contents + // using the contents of a byte of memory. + // If the result is 0, Zero bit is set. If the result if negative, + // Negative bit is set + 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); + true } - fn op_ASL(&mut self, bus: &T, val: Word) { - unimplemented!() + // ASL - Arithmetic Shift Left + // A,Z,C,N = M*2 or M,Z,C,N = M*2 + // This operation shifts all the bits of the accumulator or memory + // contents one bit left. Bit 0 is set to 0 and bit 7 is placed in the + // carry flag. The effect of this operation is to multiply the memory + // contents by 2 (ignoring 2's complement considerations), setting the + // carry if the result will not fit in 8 bits. + // 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); + let shifted = val << 1; + self.set_flag(CARRY, (val & 0b1000000) != 0); + self.set_flag_nz(shifted); + if Instruction::decode_op(self.curr_op).unwrap().addr_mode == AddrMode::IMP { + self.regs.a = (shifted & 0x0FF) as Byte + } else { + self.writeb(bus, addr, (shifted & 0x0FF) as Byte) + } + false } - fn op_BCC(&mut self, bus: &T, val: Word) { - unimplemented!() + + // BCC - Branch if Carry Clear + // If the carry flag is clear then add the relative displacement to + // the program counter to cause a branch to a new location. + fn op_BCC(&mut self, bus: &T, addr: Addr) -> bool { + if self.get_flag(CARRY) == 0 { + self.jump(addr); + } + false } - fn op_BCS(&mut self, bus: &T, val: Word) { - unimplemented!() + // BCC - Branch if Carry Set + // If the carry flag is set then add the relative displacement to the + // program counter to cause a branch to a new location. + fn op_BCS(&mut self, bus: &T, addr: Addr) -> bool { + if self.get_flag(CARRY) == 1 { + self.jump(addr); + } + false } - fn op_BEQ(&mut self, bus: &T, val: Word) { - unimplemented!() + // BEQ - Branch if Equal + // If the zero flag is set then add the relative displacement to + // the program counter to cause a branch to a new location. + fn op_BEQ(&mut self, bus: &T, addr: Addr) -> bool { + if self.get_flag(ZERO) == 1 { + self.jump(addr); + } + false } + // BIT - Bit Test + // A & M, N = M7, V = M6 // 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) { + fn op_BIT(&mut self, bus: &T, addr: Word) -> bool { 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); + false } - // 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 negative flag is set - fn op_BMI(&mut self, bus: &T, addr: Addr) { + // BMI - Branch if Minus + // If the negative flag is set then add the relative displacement to the + // program counter to cause a branch to a new location. + fn op_BMI(&mut self, bus: &T, addr: Addr) -> bool { if self.get_flag(NEGATIVE) == 1 { self.jump(addr); } + false } - // Branch if 0 flag is set - fn op_BNE(&mut self, addr: Addr) { + // BNE - Branch if Not Equal + // If the zero flag is clear then add the relative displacement to the + // program counter to cause a branch to a new location. + fn op_BNE(&mut self, addr: Addr) -> bool { if self.get_flag(ZERO) == 0 { self.jump(addr); } + false } - // Branch if negative flag is unset - fn op_BPL(&mut self, bus: &T, addr: Addr) { + // BPL - Branch if Positive + // If the negative flag is clear then add the relative displacement to + // the program counter to cause a branch to a new location. + fn op_BPL(&mut self, bus: &T, addr: Addr) -> bool { if self.get_flag(NEGATIVE) == 0 { self.jump(addr); } + false } - fn op_BRK(&mut self, bus: &T, val: Word) { - unimplemented!() + // BRK - Force Interrupt + // The BRK instruction forces the generation of an interrupt request. + // The program counter and processor status are pushed on the stack + // then the IRQ interrupt vector at $FFFE/F is loaded into the PC and + // the break flag in the status set to one. + fn op_BRK(&mut self, bus: &mut T) -> bool { + self.regs.pc += 1; + self.set_flag(IRQ, true); + self.writeb(bus, 0x0100 + self.regs.sp as Word, (self.regs.pc >> 8) as Byte); + self.regs.sp -= 1; + self.writeb(bus, 0x0100 + self.regs.sp as Word, self.regs.pc as Byte); + self.regs.sp -= 1; + + self.set_flag(BREAK, true); + self.writeb(bus, 0x0100 + self.regs.sp as Word, self.regs.flags); + self.regs.sp -= 1; + self.set_flag(BREAK, false); + + self.regs.pc = self.readw(bus, 0xFFFE); + false } - fn op_BVC(&mut self, bus: &T, val: Word) { - unimplemented!() + // BVC - Branch if Overflow Clear + // If the overflow flag is clear then add the relative displacement to + // the program counter to cause a branch to a new location. + fn op_BVC(&mut self, addr: Addr) -> bool { + if self.get_flag(OVERFLOW) == 0 { + self.jump(addr); + } + false } - fn op_BVS(&mut self, bus: &T, val: Word) { - unimplemented!() + // BVS - Branch if Overflow Set + // If the overflow flag is set then add the relative displacement to the + // program counter to cause a branch to a new location. + fn op_BVS(&mut self, addr: Addr) -> bool { + if self.get_flag(OVERFLOW) == 1 { + self.jump(addr); + } + false } // Clear carry flag - fn op_CLC(&mut self) { + fn op_CLC(&mut self) -> bool { self.set_flag(CARRY, false); + false } // clear decimal flag - fn op_CLD(&mut self) { + fn op_CLD(&mut self) -> bool { self.set_flag(DECIMAL, false); + false } // clear IRQ - fn op_CLI(&mut self) { + fn op_CLI(&mut self) -> bool { self.set_flag(IRQ, false); + false } // clear Overflow - fn op_CLV(&mut self) { + fn op_CLV(&mut self) -> bool { self.set_flag(OVERFLOW, false); + false } - fn op_CMP(&mut self, bus: &T, val: Word) { - unimplemented!() + // CMP - Compare + // Z,C,N = A-M + // This instruction compares the contents of the accumulator with another + // memory held value and sets the zero and carry flags as appropriate. + fn op_CMP(&mut self, bus: &mut T, addr: Addr) -> bool { + let val = self.readb(bus, addr); + let tmp = self.regs.a as Word - val as Word; + self.set_flag(CARRY, self.regs.a >= val); + self.set_flag_nz(tmp as Byte); + true } - fn op_CPX(&mut self, bus: &T, val: Word) { - unimplemented!() + // Compare X + fn op_CPX(&mut self, bus: &T, addr: Addr) -> bool { + let val = self.readb(bus, addr); + let tmp = self.regs.x as Word - val as Word; + self.set_flag(CARRY, self.regs.x >= val); + self.set_flag_nz(tmp as Byte); + true } - fn op_CPY(&mut self, bus: &T, val: Word) { - unimplemented!() + // Compare Y + fn op_CPY(&mut self, bus: &T, addr: Addr) -> bool { + let val = self.readb(bus, addr); + let tmp = self.regs.y as Word - val as Word; + self.set_flag(CARRY, self.regs.y >= val); + self.set_flag_nz(tmp as Byte); + true } - fn op_DEC(&mut self, bus: &T, val: Word) { - unimplemented!() + // DEC - Decrement Memory + // M,Z,N = M-1 + // Subtracts one from the value held at a specified memory location + // setting the zero and negative flags as appropriate. + fn op_DEC(&mut self, bus: &mut T, addr: Word) -> bool { + let val = self.readb(bus, addr); + let val = val.wrapping_sub(1); + self.writeb(bus, addr, val); + self.set_flag_nz(val); + false } - // Decrement X - fn op_DEX(&mut self) { + // DEX - Decrement X Register + // X,Z,N = X-1 + // Subtracts one from the X register setting the zero and negative + // flags as appropriate. + fn op_DEX(&mut self) -> bool { self.regs.x = self.regs.x.wrapping_sub(1); self.set_flag_nz(self.regs.x); + false } - // Decrement Y - fn op_DEY(&mut self) { + // DEY - Decrement X Register + // X,Z,N = Y-1 + // Subtracts one from the Y register setting the zero and negative + // flags as appropriate. + fn op_DEY(&mut self) -> bool { self.regs.y = self.regs.y.wrapping_sub(1); self.set_flag_nz(self.regs.y); + false } - fn op_EOR(&mut self, bus: &T, val: Word) { + // EOR - Exclusive OR + // A,Z,N = A^M + // An exclusive OR is performed, bit by bit, on the accumulator contents + // using the contents of a byte of memory. + fn op_EOR(&mut self, bus: &T, val: Word) -> bool { unimplemented!() } - fn op_INC(&mut self, bus: &mut T, addr: Word) { + // INC - Increment Memory + // M,Z,N = M+1 + // Adds one to the value held at a specified memory location setting the + // zero and negative flags as appropriate. + fn op_INC(&mut self, bus: &mut T, addr: Word) -> bool { let val = self.readb(bus, addr); let val = val.wrapping_add(1); self.writeb(bus, addr, val); self.set_flag_nz(val); + false } - fn op_INX(&mut self, bus: &T) { + // INX - Increment X Register + // X,Z,N = X+1 + // Adds one to the X register setting the zero and negative flags + // as appropriate. + fn op_INX(&mut self, bus: &T) -> bool { self.regs.x = self.regs.x.wrapping_add(1); self.set_flag_nz(self.regs.x); + false } - fn op_INY(&mut self, bus: &T) { + // INY - Increment Y Register + // Y,Z,N = Y+1 + // Adds one to the Y register setting the zero and negative flags as appropriate. + fn op_INY(&mut self, bus: &T) -> bool { self.regs.y = self.regs.y.wrapping_add(1); self.set_flag_nz(self.regs.y); + false } // Jump to address (set pc) - fn op_JMP(&mut self, bus: &T, addr: Word) { + fn op_JMP(&mut self, bus: &T, addr: Word) -> bool { self.jump(addr); + false } // Jump to subroutine (leaves trace on the stack) - fn op_JSR(&mut self, bus: &mut T, addr: Word) { + fn op_JSR(&mut self, bus: &mut T, addr: Word) -> bool { self.regs.pc -= 1; bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, ((self.regs.pc >> 8) & 0x00ff) as Byte); 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.jump(addr); + false } // Read value from addr into A - fn op_LDA(&mut self, bus: &T, addr: Word) { + fn op_LDA(&mut self, bus: &T, addr: Word) -> bool { let val = bus.readb(addr); self.regs.a = val; self.set_flag_nz(val); + true } // Read value from addr into X - fn op_LDX(&mut self, bus: &T, addr: Word) { + fn op_LDX(&mut self, bus: &T, addr: Word) -> bool { let val = bus.readb(addr); self.regs.x = val; self.set_flag_nz(val); + true } // Read value from addr into Y - fn op_LDY(&mut self, bus: &T, addr: Word) { + fn op_LDY(&mut self, bus: &T, addr: Word) -> bool { let val = bus.readb(addr); self.regs.y = val; self.set_flag_nz(val); + true } - fn op_LSR(&mut self, bus: &T, val: Word) { + fn op_LSR(&mut self, bus: &T, val: Word) -> bool { unimplemented!() } - fn op_NOP(&mut self, bus: &T, val: Word) { + fn op_NOP(&mut self, bus: &T, val: Word) -> bool { // does nothing + false } - fn op_ORA(&mut self, bus: &T, addr: Addr) { + // ORA - Logical Inclusive OR + // A,Z,N = A|M + // An inclusive OR is performed, bit by bit, on the accumulator contents + // using the contents of a byte of memory. + fn op_ORA(&mut self, bus: &T, addr: Addr) -> bool { self.regs.a |= self.readb(bus, addr); self.set_flag_nz(self.regs.a); + true } - fn op_PHA(&mut self, bus: &T, val: Word) { - unimplemented!() + // PHA - Push Accumulator + // Pushes a copy of the accumulator on to the stack. + fn op_PHA(&mut self, bus: &mut T, val: Word) -> bool { + self.writeb(bus, 0x0100 + self.regs.sp as Word, self.regs.a); + self.regs.sp -= 1; + false } - // Write flags to stack - fn op_PHP(&mut self, bus: &mut T) { + // 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; 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"); + false } // Read from stack into A - fn op_PLA(&mut self, bus: &T, val: Word) { + fn op_PLA(&mut self, bus: &T, val: Word) -> bool { self.regs.sp += 1; 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) + self.set_flag(NEGATIVE, (self.regs.a & 0x80) == 1); + false } - fn op_PLP(&mut self, bus: &T, val: Word) { + fn op_PLP(&mut self, bus: &T, val: Word) -> bool { unimplemented!() } - fn op_ROL(&mut self, bus: &T, val: Word) { + fn op_ROL(&mut self, bus: &T, val: Word) -> bool { unimplemented!() } - fn op_ROR(&mut self, bus: &T, val: Word) { + fn op_ROR(&mut self, bus: &T, val: Word) -> bool { unimplemented!() } - fn op_RTI(&mut self, bus: &T, val: Word) { + fn op_RTI(&mut self, bus: &T, val: Word) -> bool { unimplemented!() } - fn op_RTS(&mut self, bus: &T, val: Word) { + // RTS - Return from Subroutine + // The RTS instruction is used at the end of a subroutine to return to the + // calling routine. It pulls the program counter (minus one) from the stack. + fn op_RTS(&mut self, bus: &T, val: Word) -> bool { 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; + false } - fn op_SBC(&mut self, bus: &T, val: Word) { + // subtract with carry + fn op_SBC(&mut self, bus: &T, val: Word) -> bool { unimplemented!() } - fn op_SEC(&mut self, bus: &T, val: Word) { - unimplemented!() + // set carry + fn op_SEC(&mut self, bus: &T, val: Word) -> bool { + self.set_flag(CARRY, true); + false } - fn op_SED(&mut self, bus: &T, val: Word) { - unimplemented!() + // SED - Set Decimal Flag + // D = 1 + // Set the decimal mode flag to one. + fn op_SED(&mut self, bus: &T, val: Word) -> bool { + self.set_flag(DECIMAL, true); + false } // set irq flag - fn op_SEI(&mut self) { + fn op_SEI(&mut self) -> bool { self.set_flag(IRQ, true); + false } // Push A reg to memory - fn op_STA(&mut self, bus: &mut T, addr: Word) { - self.writeb(bus, addr, self.regs.a) + fn op_STA(&mut self, bus: &mut T, addr: Word) -> bool { + self.writeb(bus, addr, self.regs.a); + false } // Push X reg to memory - fn op_STX(&mut self, bus: &mut T, addr: Word) { - self.writeb(bus, addr, self.regs.x) + fn op_STX(&mut self, bus: &mut T, addr: Word) -> bool { + self.writeb(bus, addr, self.regs.x); + false } // Push Y reg to memory - fn op_STY(&mut self, bus: &mut T, addr: Word) { - self.writeb(bus, addr, self.regs.y) + fn op_STY(&mut self, bus: &mut T, addr: Word) -> bool { + self.writeb(bus, addr, self.regs.y); + false } // a to x - fn op_TAX(&mut self, bus: &T, val: Word) { + fn op_TAX(&mut self, bus: &T, val: Word) -> 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(NEGATIVE, (self.regs.x & 0x80) == 1); + false } // a to y - fn op_TAY(&mut self, bus: &T, val: Word) { + fn op_TAY(&mut self, bus: &T, val: Word) -> 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(NEGATIVE, (self.regs.y & 0x80) == 1); + false } // stack pointer to x - fn op_TSX(&mut self, bus: &T) { + fn op_TSX(&mut self, bus: &T) -> 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(NEGATIVE, (self.regs.x & 0x80) == 1); + false } // transfer x to a - fn op_TXA(&mut self, bus: &T, val: Word) { + fn op_TXA(&mut self, bus: &T, val: Word) -> 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(NEGATIVE, (self.regs.a & 0x80) == 1); + false } // transfer y to a - fn op_TYA(&mut self, bus: &T, val: Word) { + fn op_TYA(&mut self, bus: &T, val: Word) -> 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(NEGATIVE, (self.regs.a & 0x80) == 1); + false } // transfer x to stack - fn op_TXS(&mut self, bus: &T, val: Word) { + fn op_TXS(&mut self, bus: &T, val: Word) -> bool { self.regs.sp = self.regs.x; + false } } diff --git a/src/nes/cpu/instructions.rs b/src/nes/cpu/instructions.rs index b1f8f5d..acb7ae3 100644 --- a/src/nes/cpu/instructions.rs +++ b/src/nes/cpu/instructions.rs @@ -4,7 +4,7 @@ use failure::{Error}; use std::fmt; use std::fmt::{Debug,Display}; -#[derive(Debug)] +#[derive(Debug,PartialEq)] pub enum AddrMode { IMP, IMM,