Skip to content

Commit

Permalink
add operation - AND
Browse files Browse the repository at this point in the history
  • Loading branch information
marcantoineg committed Apr 4, 2024
1 parent e543045 commit a843fa3
Show file tree
Hide file tree
Showing 2 changed files with 335 additions and 10 deletions.
33 changes: 23 additions & 10 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down Expand Up @@ -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"),
}
Expand All @@ -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);
Expand All @@ -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);
Expand Down
312 changes: 312 additions & 0 deletions tests/and_tests.rs
Original file line number Diff line number Diff line change
@@ -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]);
}

0 comments on commit a843fa3

Please sign in to comment.