From a843fa3d77814b322dc8f33f5a633a21508c51a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Antoine=20Gigu=C3=A8re?= Date: Thu, 4 Apr 2024 01:40:23 +0000 Subject: [PATCH] add operation - AND --- src/cpu.rs | 33 +++-- tests/and_tests.rs | 312 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 335 insertions(+), 10 deletions(-) create mode 100644 tests/and_tests.rs diff --git a/src/cpu.rs b/src/cpu.rs index 4dc48a9..012938a 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -54,6 +54,15 @@ impl CPU { (0x61, Operation::new(ADC, IndirectX, 2)), (0x71, Operation::new(ADC, IndirectY, 2)), + (0x29, Operation::new(AND, Immediate, 2)), + (0x25, Operation::new(AND, ZeroPage, 2)), + (0x35, Operation::new(AND, ZeroPageX, 2)), + (0x2D, Operation::new(AND, Absolute, 3)), + (0x3D, Operation::new(AND, AbsoluteX, 3)), + (0x39, Operation::new(AND, AbsoluteY, 3)), + (0x21, Operation::new(AND, IndirectX, 2)), + (0x31, Operation::new(AND, IndirectY, 2)), + (0x00, Operation::new(BRK, Implied, 1)), (0xA9, Operation::new(LDA, Immediate, 2)), @@ -177,21 +186,14 @@ impl CPU { match op.mnemonic_name { ADC => self.adc(op.addressing_mode), - + AND => self.and(op.addressing_mode), + BRK => return, LDA => self.lda(op.addressing_mode), LDX => self.ldx(op.addressing_mode), LDY => self.ldy(op.addressing_mode), - TAX => self.tax(), TAY => self.tay(), - - INX => { - let v = self.register_x.wrapping_add(1); - self.set_register_x(v); - } - - // BRK - BRK => return, + INX => self.inx(), _ => todo!("op not implemented"), } @@ -216,6 +218,12 @@ impl CPU { self.set_register_a(wrapped_sum); } + fn and(&mut self, mode: AddressingMode) { + let addr = self.get_op_target_addr(mode); + let mem_value = self.memory.read(addr); + self.set_register_a(self.register_a & mem_value) + } + fn lda(&mut self, mode: AddressingMode) { let addr = self.get_op_target_addr(mode); let mem_value = self.memory.read(addr); @@ -242,6 +250,11 @@ impl CPU { self.set_register_y(self.register_a); } + fn inx(&mut self) { + let v = self.register_x.wrapping_add(1); + self.set_register_x(v); + } + fn set_register_a(&mut self, value: u8) { self.register_a = value; self.set_zero_flag(self.register_a); diff --git a/tests/and_tests.rs b/tests/and_tests.rs new file mode 100644 index 0000000..1c40d77 --- /dev/null +++ b/tests/and_tests.rs @@ -0,0 +1,312 @@ +use nes_emulator::cpu::{CPU, Flags}; + +mod common; +use common::{assert_no_flags, assert_flags}; + +#[test] +fn test_0x29_and_immediate_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_1111; + + cpu.load_and_run_without_reset(vec![0x29, 0b0111_0000, 0x00]); + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x29_and_immediate_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1111_1111; + + cpu.load_and_run_without_reset(vec![0x29, 0b0000_0000, 0x00]); + + assert_eq!(cpu.register_a, 0); + assert_flags(&cpu, vec![Flags::Zero]); +} + +#[test] +fn test_0x29_and_immediate_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1000_0000; + + cpu.load_and_run_without_reset(vec![0x29, 0b1000_0000, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +} + +#[test] +fn test_0x25_and_zero_page_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.memory.write(0x0024, 0b0111_0000); + + cpu.load_and_run_without_reset(vec![0x25, 0x24, 0x00]); + + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x25_and_zero_page_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.memory.write(0x0024, 0b0000_0000); + + cpu.load_and_run_without_reset(vec![0x25, 0x24, 0x00]); + + + assert_eq!(cpu.register_a, 0b0000_0000); + assert_flags(&cpu, vec![Flags::Zero]); +} + +#[test] +fn test_0x25_and_zero_page_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1000_0000; + cpu.memory.write(0x0024, 0b1000_0000); + + cpu.load_and_run_without_reset(vec![0x25, 0x24, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +} + +#[test] +fn test_0x35_and_zero_page_x_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_x = 0x01; + cpu.memory.write(0x0025, 0b0111_0000); + + cpu.load_and_run_without_reset(vec![0x35, 0x24, 0x00]); + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x35_and_zero_page_x_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_x = 0x01; + cpu.memory.write(0x0025, 0b0000_0000); + + cpu.load_and_run_without_reset(vec![0x35, 0x24, 0x00]); + + assert_eq!(cpu.register_a, 0b0000_0000); + assert_flags(&cpu, vec![Flags::Zero]); +} + +#[test] +fn test_0x35_and_zero_page_x_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1000_0000; + cpu.register_x = 0x01; + cpu.memory.write(0x0025, 0b1000_0000); + + cpu.load_and_run_without_reset(vec![0x35, 0x24, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +} + +#[test] +fn test_0x2d_and_absolute_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.memory.write(0x1010, 0b0111_0000); + + cpu.load_and_run_without_reset(vec![0x2D, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x2d_and_absolute_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.memory.write(0x1010, 0b0000_0000); + + cpu.load_and_run_without_reset(vec![0x2D, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b0000_0000); + assert_flags(&cpu, vec![Flags::Zero]); +} + +#[test] +fn test_0x2d_and_absolute_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1000_0000; + cpu.memory.write(0x1010, 0b1000_0000); + + cpu.load_and_run_without_reset(vec![0x2D, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +} + +#[test] +fn test_0x3d_and_absolute_x_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_x = 0x01; + cpu.memory.write(0x1011, 0b0111_0000); + + cpu.load_and_run_without_reset(vec![0x3D, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x3d_and_absolute_x_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_x = 0x01; + cpu.memory.write(0x1011, 0b0000_0000); + + cpu.load_and_run_without_reset(vec![0x3D, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b0000_0000); + assert_flags(&cpu, vec![Flags::Zero]); +} + +#[test] +fn test_0x3d_and_absolute_x_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1000_0000; + cpu.register_x = 0x01; + cpu.memory.write(0x1011, 0b1000_0000); + + cpu.load_and_run_without_reset(vec![0x3D, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +} + +#[test] +fn test_0x39_and_absolute_y_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_y = 0x01; + cpu.memory.write(0x1011, 0b0111_0000); + + cpu.load_and_run_without_reset(vec![0x39, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x39_and_absolute_y_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_y = 0x01; + cpu.memory.write(0x1011, 0b0000_0000); + + cpu.load_and_run_without_reset(vec![0x39, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b0000_0000); + assert_flags(&cpu, vec![Flags::Zero]) +} + +#[test] +fn test_0x39_and_absolute_y_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1000_0000; + cpu.register_y = 0x01; + cpu.memory.write(0x1011, 0b1000_0000); + + cpu.load_and_run_without_reset(vec![0x39, 0x10, 0x10, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +} + +#[test] +fn test_0x21_and_indirect_x_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_x = 0x01; + cpu.memory.write_u16(0x02, 0x1010); + cpu.memory.write_u16(0x1010, 0b0111_0000); + + cpu.load_and_run_without_reset(vec![0x21, 0x01, 0x00]); + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x21_and_indirect_x_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_x = 0x01; + cpu.memory.write_u16(0x02, 0x1010); + cpu.memory.write_u16(0x1010, 0b0000_0000); + + cpu.load_and_run_without_reset(vec![0x21, 0x01, 0x00]); + + assert_eq!(cpu.register_a, 0b0000_0000); + assert_flags(&cpu, vec![Flags::Zero]); +} + +#[test] +fn test_0x21_and_indirect_x_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1000_0000; + cpu.register_x = 0x01; + cpu.memory.write_u16(0x02, 0x1010); + cpu.memory.write_u16(0x1010, 0b1000_0000); + + cpu.load_and_run_without_reset(vec![0x21, 0x01, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +} + +#[test] +fn test_0x31_and_indirect_y_calculates_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_y = 0x01; + cpu.memory.write_u16(0x02, 0x1010); + cpu.memory.write(0x1011, 0b0111_0000); + + cpu.load_and_run_without_reset(vec![0x31, 0x02, 0x00]); + + assert_eq!(cpu.register_a, 0b0111_0000); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x31_and_indirect_y_zero_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b0111_0000; + cpu.register_y = 0x01; + cpu.memory.write_u16(0x02, 0x1010); + cpu.memory.write(0x1011, 0b0000_0000); + + cpu.load_and_run_without_reset(vec![0x31, 0x02, 0x00]); + + assert_eq!(cpu.register_a, 0b0000_0000); + assert_flags(&cpu, vec![Flags::Zero]); +} + +#[test] +fn test_0x31_and_indirect_y_negative_flag() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1111_0000; + cpu.register_y = 0x01; + cpu.memory.write_u16(0x02, 0x1010); + cpu.memory.write(0x1011, 0b1000_0000); + + cpu.load_and_run_without_reset(vec![0x31, 0x02, 0x00]); + + assert_eq!(cpu.register_a, 0b1000_0000); + assert_flags(&cpu, vec![Flags::Negative]); +}