From c36761e01b465966768891d375523c02163b2e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Antoine=20Gigu=C3=A8re?= Date: Tue, 11 Jun 2024 21:49:21 +0000 Subject: [PATCH] implement operation - LSR --- src/cpu.rs | 20 +++++ tests/lsr_tests.rs | 206 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 tests/lsr_tests.rs diff --git a/src/cpu.rs b/src/cpu.rs index 7d51541..8924735 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -159,6 +159,12 @@ impl CPU { (0xAC, Operation::new(LDY, Absolute, 3)), (0xBC, Operation::new(LDY, AbsoluteX, 3)), + (0x4A, Operation::new(LSR, Implied, 1)), + (0x46, Operation::new(LSR, ZeroPage, 2)), + (0x56, Operation::new(LSR, ZeroPageX, 2)), + (0x4E, Operation::new(LSR, Absolute, 3)), + (0x5E, Operation::new(LSR, AbsoluteX, 3)), + (0xAA, Operation::new(TAX, Implied, 1)), (0xA8, Operation::new(TAY, Implied, 1)), ]); @@ -293,6 +299,7 @@ impl CPU { LDA => self.lda(op.addressing_mode), LDX => self.ldx(op.addressing_mode), LDY => self.ldy(op.addressing_mode), + LSR => self.lsr(op.addressing_mode), TAX => self.tax(), TAY => self.tay(), @@ -525,6 +532,19 @@ impl CPU { self.program_counter = subroutine_addr; } + fn lsr(&mut self, mode: AddressingMode) { + if mode == AddressingMode::Implied { + self.set_carry_flag((self.register_a & 0b0000_0001) != 0); + self.set_register_a(self.register_a >> 1); + } else { + let addr = self.get_op_target_addr(mode); + let mem_value = self.memory.read(addr); + + self.set_carry_flag((mem_value & 0b0000_0001) != 0); + self.set_memory(addr, mem_value >> 1); + } + } + fn set_register_a(&mut self, value: u8) { self.register_a = value; self.set_zero_flag(self.register_a); diff --git a/tests/lsr_tests.rs b/tests/lsr_tests.rs new file mode 100644 index 0000000..1de6a85 --- /dev/null +++ b/tests/lsr_tests.rs @@ -0,0 +1,206 @@ +use common::assert_flag; +use nes_emulator::cpu::{Flags, CPU}; + +mod common; +use crate::common::assert_no_flags; + +#[test] +fn test_0x4a_lsr_implied_shifts_right_without_carry_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1010_1010; + + cpu.load_and_run_without_reset(vec![ + 0x4A, 0x00 + ]); + + assert_eq!(cpu.register_a, 0b0101_0101); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x4a_lsr_implied_shifts_right_with_carry_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0b1010_1011; + + cpu.load_and_run_without_reset(vec![ + 0x4A, 0x00 + ]); + + assert_eq!(cpu.register_a, 0b0101_0101); + assert_flag(&cpu, Flags::Carry); +} + +#[test] +fn test_0x4a_lsr_implied_shifts_right_with_zero_correctly() { + let mut cpu = CPU::new(); + cpu.register_a = 0x00; + + cpu.load_and_run_without_reset(vec![ + 0x4A, 0x00 + ]); + + assert_eq!(cpu.register_a, 0x00); + assert_flag(&cpu, Flags::Zero); +} + +#[test] +fn test_0x46_lsr_zero_page_shifts_right_without_carry_correctly() { + let mut cpu = CPU::new(); + cpu.memory.write(0x0010, 0b1000_1110); + + cpu.load_and_run_without_reset(vec![ + 0x46, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x0010), 0b0100_0111); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x46_lsr_zero_page_shifts_right_with_carry_correctly() { + let mut cpu = CPU::new(); + cpu.memory.write(0x0010, 0b1000_1111); + + cpu.load_and_run_without_reset(vec![ + 0x46, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x0010), 0b0100_0111); + assert_flag(&cpu, Flags::Carry) +} + +#[test] +fn test_0x46_lsr_zero_page_shifts_right_with_zero_correctly() { + let mut cpu = CPU::new(); + cpu.memory.write(0x0010, 0x00); + + cpu.load_and_run_without_reset(vec![ + 0x46, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x0010), 0x00); + assert_flag(&cpu, Flags::Zero) +} + +#[test] +fn test_0x56_lsr_zero_page_x_shifts_right_without_carry_correctly() { + let mut cpu = CPU::new(); + cpu.register_x = 0x01; + cpu.memory.write(0x0011, 0b1000_1110); + + cpu.load_and_run_without_reset(vec![ + 0x56, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x0011), 0b0100_0111); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x56_lsr_zero_page_x_shifts_right_with_carry_correctly() { + let mut cpu = CPU::new(); + cpu.register_x = 0x01; + cpu.memory.write(0x0011, 0b1000_1111); + + cpu.load_and_run_without_reset(vec![ + 0x56, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x0011), 0b0100_0111); + assert_flag(&cpu, Flags::Carry); +} + +#[test] +fn test_0x56_lsr_zero_page_x_shifts_right_with_zero_correctly() { + let mut cpu = CPU::new(); + cpu.register_x = 0x01; + cpu.memory.write(0x0011, 0x00); + + cpu.load_and_run_without_reset(vec![ + 0x56, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x0011), 0x00); + assert_flag(&cpu, Flags::Zero); +} + +#[test] +fn test_0x4e_lsr_absolute_shifts_right_without_carry_correctly() { + let mut cpu = CPU::new(); + cpu.memory.write(0x1011, 0b0100_0110); + + cpu.load_and_run_without_reset(vec![ + 0x4E, 0x11, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x1011), 0b0010_0011); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x4e_lsr_absolute_shifts_right_with_carry_correctly() { + let mut cpu = CPU::new(); + cpu.memory.write(0x1011, 0b0011_1111); + + cpu.load_and_run_without_reset(vec![ + 0x4E, 0x11, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x1011), 0b0001_1111); + assert_flag(&cpu, Flags::Carry); +} + +#[test] +fn test_0x4e_lsr_absolute_shifts_right_with_zero_correctly() { + let mut cpu = CPU::new(); + cpu.memory.write(0x1011, 0x00); + + cpu.load_and_run_without_reset(vec![ + 0x4E, 0x11, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x1011), 0x00); + assert_flag(&cpu, Flags::Zero); +} + +#[test] +fn test_0x5e_lsr_absolute_x_shifts_right_without_carry_correctly() { + let mut cpu = CPU::new(); + cpu.register_x = 0x01; + cpu.memory.write(0x1012, 0b1010_1010); + + cpu.load_and_run_without_reset(vec![ + 0x5E, 0x11, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x1012), 0b0101_0101); + assert_no_flags(&cpu); +} + +#[test] +fn test_0x5e_lsr_absolute_x_shifts_right_with_carry_correctly() { + let mut cpu = CPU::new(); + cpu.register_x = 0x01; + cpu.memory.write(0x1012, 0b1010_1011); + + cpu.load_and_run_without_reset(vec![ + 0x5E, 0x11, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x1012), 0b0101_0101); + assert_flag(&cpu, Flags::Carry); +} + +#[test] +fn test_0x5e_lsr_absolute_x_shifts_right_with_zero_correctly() { + let mut cpu = CPU::new(); + cpu.register_x = 0x01; + cpu.memory.write(0x1012, 0x00); + + cpu.load_and_run_without_reset(vec![ + 0x5E, 0x11, 0x10, 0x00 + ]); + + assert_eq!(cpu.memory.read(0x1012), 0x00); + assert_flag(&cpu, Flags::Zero); +}