ferris-boi/tests/cpu/arith8.rs

638 lines
31 KiB
Rust

use ferris_boi::{
cpu::{instructions::RunnableInstruction, Processor},
register,
};
use crate::testutil;
use test_case::test_case;
struct AdditionOperationFlags {
zero: u8,
half_carry: u8,
carry: u8,
}
#[test]
fn test_add_a_to_itself() {
let mut processor = Processor::default();
processor.registers.a = 10;
let data = [0x87, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
assert_eq!(20, processor.registers.a);
}
#[test_case(0x80, register::SingleEightBit::B)]
#[test_case(0x81, register::SingleEightBit::C)]
#[test_case(0x82, register::SingleEightBit::D)]
#[test_case(0x83, register::SingleEightBit::E)]
#[test_case(0x84, register::SingleEightBit::H)]
#[test_case(0x85, register::SingleEightBit::L)]
fn test_add_to_a_value(opcode: u8, src: register::SingleEightBit) {
let mut processor = Processor::default();
processor.registers.a = 10;
processor.registers.set_single_8bit_register(src, 20);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
assert_eq!(30, processor.registers.a);
}
#[test_case(0x80, register::SingleEightBit::B, 0x00, 0x00, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "zero flag for zero value")]
#[test_case(0x80, register::SingleEightBit::B, 0x00, 0x01, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no zero flag for non-zero value")]
#[test_case(0x81, register::SingleEightBit::C, 0x0F, 0x01, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "half carry flag")]
#[test_case(0x81, register::SingleEightBit::C, 0x80, 0x80, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 1}; "full carry flag")]
#[test_case(0x81, register::SingleEightBit::C, 0xFF, 0x01, AdditionOperationFlags{zero: 1, half_carry: 1, carry: 1}; "all flags")]
// 0000 1111
fn test_add_register_to_a_flags(
opcode: u8,
src: register::SingleEightBit,
a_value: u8,
src_value: u8,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor.registers.a = a_value;
// Set all the register to the opposite we expect to ensure they all get set
testutil::set_opposite_of_expected_flags(
&mut processor,
(
expected_flags.zero,
0,
expected_flags.half_carry,
expected_flags.carry,
),
);
processor.registers.set_single_8bit_register(src, src_value);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test]
fn test_add_hl_addr_to_a_value() {
let mut processor = Processor::default();
processor
.memory
.set(0xFF00, 0x34)
.expect("expected to be able to set 0xFF00");
processor
.registers
.set_combined_register(register::Combined::HL, 0xFF00);
processor.registers.a = 0x12;
let data = [0x86, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
assert_eq!(0x46, processor.registers.a);
}
#[test_case(0x00, 0x00, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "zero flag for zero value")]
#[test_case(0x00, 0x01, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no zero flag for non-zero value")]
#[test_case(0x0F, 0x01, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "half carry flag")]
#[test_case(0x80, 0x80, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 1}; "full carry flag")]
#[test_case(0xFF, 0x01, AdditionOperationFlags{zero: 1, half_carry: 1, carry: 1}; "all flags")]
fn test_add_hl_addr_to_a_flags(
a_value: u8,
hl_addr_value: u8,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor.registers.a = a_value;
processor
.registers
.set_combined_register(register::Combined::HL, 0xFF00);
processor
.memory
.set(0xFF00, hl_addr_value)
.expect("expected to set address 0xFF00 but could not");
// Set all the register to the opposite we expect to ensure they all get set
testutil::set_opposite_of_expected_flags(
&mut processor,
(
expected_flags.zero,
0,
expected_flags.half_carry,
expected_flags.carry,
),
);
let data = [0x86, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test]
fn test_add_immediate_to_a_value() {
let mut processor = Processor::default();
processor.registers.a = 50;
let data = [0xC6, 0x13, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
assert_eq!(69, processor.registers.a);
}
#[test_case(0x00, 0x00, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "zero flag for zero value")]
#[test_case(0x00, 0x01, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no zero flag for non-zero value")]
#[test_case(0x0F, 0x01, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "half carry flag")]
#[test_case(0x80, 0x80, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 1}; "full carry flag")]
#[test_case(0xFF, 0x01, AdditionOperationFlags{zero: 1, half_carry: 1, carry: 1}; "all flags")]
fn test_add_immediate_to_a_flags(a_value: u8, n: u8, expected_flags: AdditionOperationFlags) {
let mut processor = Processor::default();
processor.registers.a = a_value;
// Set all the register to the opposite we expect to ensure they all get set
testutil::set_opposite_of_expected_flags(
&mut processor,
(
expected_flags.zero,
0,
expected_flags.half_carry,
expected_flags.carry,
),
);
let data = [0xC6, n, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test_case(0x88, 0x12, 0, register::SingleEightBit::B, 0x5, 0x17; "no carry to register b")]
#[test_case(0x88, 0x12, 1, register::SingleEightBit::B, 0x5, 0x18; "carry to register b")]
#[test_case(0x89, 0x12, 0, register::SingleEightBit::C, 0x5, 0x17; "no carry to register c")]
#[test_case(0x89, 0x12, 1, register::SingleEightBit::C, 0x5, 0x18; "carry to register c")]
#[test_case(0x8A, 0x12, 0, register::SingleEightBit::D, 0x5, 0x17; "no carry to register d")]
#[test_case(0x8A, 0x12, 1, register::SingleEightBit::D, 0x5, 0x18; "carry to register d")]
#[test_case(0x8B, 0x12, 0, register::SingleEightBit::E, 0x5, 0x17; "no carry to register e")]
#[test_case(0x8B, 0x12, 1, register::SingleEightBit::E, 0x5, 0x18; "carry to register e")]
#[test_case(0x8C, 0x12, 0, register::SingleEightBit::H, 0x5, 0x17; "no carry to register h")]
#[test_case(0x8C, 0x12, 1, register::SingleEightBit::H, 0x5, 0x18; "carry to register h")]
#[test_case(0x8D, 0x12, 0, register::SingleEightBit::L, 0x5, 0x17; "no carry to register l")]
#[test_case(0x8D, 0x12, 1, register::SingleEightBit::L, 0x5, 0x18; "carry to register l")]
fn test_add_register_with_carry_to_a_value(
opcode: u8,
initial_value: u8,
carry_bit: u8,
operand_register: register::SingleEightBit,
operand: u8,
expected_value: u8,
) {
let mut processor = Processor::default();
processor.registers.a = initial_value;
processor
.registers
.set_single_8bit_register(operand_register, operand);
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
assert_eq!(expected_value, processor.registers.a);
}
// these parameters are like impossible to read but I can't think of a nicer way to do this right now
// B register
#[test_case(0x88, 0x12, 0, register::SingleEightBit::B, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register b")]
#[test_case(0x88, 0x12, 1, register::SingleEightBit::B, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register b")]
#[test_case(0x88, 0x00, 0, register::SingleEightBit::B, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register b")]
#[test_case(0x88, 0x00, 1, register::SingleEightBit::B, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register b")]
#[test_case(0x88, 0x0F, 0, register::SingleEightBit::B, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register b")]
#[test_case(0x88, 0x0F, 1, register::SingleEightBit::B, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register b")]
#[test_case(0x88, 0x0F, 0, register::SingleEightBit::B, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register b")]
#[test_case(0x88, 0x0F, 1, register::SingleEightBit::B, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register b")]
#[test_case(0x88, 0xFF, 1, register::SingleEightBit::B, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register b")]
// C register
#[test_case(0x89, 0x12, 0, register::SingleEightBit::C, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register c")]
#[test_case(0x89, 0x12, 1, register::SingleEightBit::C, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register c")]
#[test_case(0x89, 0x00, 0, register::SingleEightBit::C, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register c")]
#[test_case(0x89, 0x00, 1, register::SingleEightBit::C, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register c")]
#[test_case(0x89, 0x0F, 0, register::SingleEightBit::C, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register c")]
#[test_case(0x89, 0x0F, 1, register::SingleEightBit::C, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register c")]
#[test_case(0x89, 0x0F, 0, register::SingleEightBit::C, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register c")]
#[test_case(0x89, 0x0F, 1, register::SingleEightBit::C, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register c")]
#[test_case(0x89, 0xFF, 1, register::SingleEightBit::C, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register c")]
// D register
#[test_case(0x8A, 0x12, 0, register::SingleEightBit::D, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register d")]
#[test_case(0x8A, 0x12, 1, register::SingleEightBit::D, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register d")]
#[test_case(0x8A, 0x00, 0, register::SingleEightBit::D, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register d")]
#[test_case(0x8A, 0x00, 1, register::SingleEightBit::D, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register d")]
#[test_case(0x8A, 0x0F, 0, register::SingleEightBit::D, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register d")]
#[test_case(0x8A, 0x0F, 1, register::SingleEightBit::D, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register d")]
#[test_case(0x8A, 0x0F, 0, register::SingleEightBit::D, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register d")]
#[test_case(0x8A, 0x0F, 1, register::SingleEightBit::D, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register d")]
#[test_case(0x8A, 0xFF, 1, register::SingleEightBit::D, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register d")]
// E register
#[test_case(0x8B, 0x12, 0, register::SingleEightBit::E, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register e")]
#[test_case(0x8B, 0x12, 1, register::SingleEightBit::E, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register e")]
#[test_case(0x8B, 0x00, 0, register::SingleEightBit::E, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register e")]
#[test_case(0x8B, 0x00, 1, register::SingleEightBit::E, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register e")]
#[test_case(0x8B, 0x0F, 0, register::SingleEightBit::E, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register e")]
#[test_case(0x8B, 0x0F, 1, register::SingleEightBit::E, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register e")]
#[test_case(0x8B, 0x0F, 0, register::SingleEightBit::E, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register e")]
#[test_case(0x8B, 0x0F, 1, register::SingleEightBit::E, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register e")]
#[test_case(0x8B, 0xFF, 1, register::SingleEightBit::E, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register e")]
// H register
#[test_case(0x8C, 0x12, 0, register::SingleEightBit::H, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register h")]
#[test_case(0x8C, 0x12, 1, register::SingleEightBit::H, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register h")]
#[test_case(0x8C, 0x00, 0, register::SingleEightBit::H, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register h")]
#[test_case(0x8C, 0x00, 1, register::SingleEightBit::H, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register h")]
#[test_case(0x8C, 0x0F, 0, register::SingleEightBit::H, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register h")]
#[test_case(0x8C, 0x0F, 1, register::SingleEightBit::H, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register h")]
#[test_case(0x8C, 0x0F, 0, register::SingleEightBit::H, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register h")]
#[test_case(0x8C, 0x0F, 1, register::SingleEightBit::H, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register h")]
#[test_case(0x8C, 0xFF, 1, register::SingleEightBit::H, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register h")]
// L register
#[test_case(0x8D, 0x12, 0, register::SingleEightBit::L, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register l")]
#[test_case(0x8D, 0x12, 1, register::SingleEightBit::L, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register l")]
#[test_case(0x8D, 0x00, 0, register::SingleEightBit::L, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register l")]
#[test_case(0x8D, 0x00, 1, register::SingleEightBit::L, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register l")]
#[test_case(0x8D, 0x0F, 0, register::SingleEightBit::L, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register l")]
#[test_case(0x8D, 0x0F, 1, register::SingleEightBit::L, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register l")]
#[test_case(0x8D, 0x0F, 0, register::SingleEightBit::L, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register l")]
#[test_case(0x8D, 0x0F, 1, register::SingleEightBit::L, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register l")]
#[test_case(0x8D, 0xFF, 1, register::SingleEightBit::L, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register l")]
fn test_add_register_with_carry_to_a_flags(
opcode: u8,
initial_value: u8,
carry_bit: u8,
operand_register: register::SingleEightBit,
operand: u8,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor.registers.a = initial_value;
processor
.registers
.set_single_8bit_register(operand_register, operand);
// Set all the register to the opposite we expect to ensure they all get set
testutil::set_opposite_of_expected_flags(
&mut processor,
(
expected_flags.zero,
0,
expected_flags.half_carry,
expected_flags.carry,
),
);
// ...except for the carry bit, which we must set for the test
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test_case(0xF0, 0, 0xE0; "no carry bit")]
#[test_case(0xF0, 1, 0xE1; "carry bit")]
fn test_add_a_to_itself_with_carry_value(initial_value: u8, carry_bit: u8, expected_value: u8) {
let mut processor = Processor::default();
processor.registers.a = initial_value;
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0x8F, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
assert_eq!(processor.registers.a, expected_value);
}
#[test_case(0xF0, 0, AdditionOperationFlags{zero: 0, carry: 1, half_carry: 0}; "carry bit")]
#[test_case(0x0F, 0, AdditionOperationFlags{zero: 0, carry: 0, half_carry: 1}; "half carry bit")]
#[test_case(0x0E, 1, AdditionOperationFlags{zero: 0, carry: 0, half_carry: 1}; "half carry bit with input carry bit")]
fn test_add_a_to_itself_with_carry_flags(
initial_value: u8,
carry_bit: u8,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor.registers.a = initial_value;
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0x8F, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test_case(0x01, 0x00, 0x02, 0x03; "no carry")]
#[test_case(0x01, 0x01, 0x02, 0x04; "carry")]
fn test_add_immediate_with_carry_to_a_value(
initial_value: u8,
carry_bit: u8,
operand: u8,
expected_value: u8,
) {
let mut processor = Processor::default();
processor.registers.a = initial_value;
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0xCE, operand, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
assert_eq!(processor.registers.a, expected_value);
}
#[test_case(0x01, 0, 0x02, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry")]
#[test_case(0xFF, 1, 0x00, AdditionOperationFlags{zero: 1, half_carry: 1, carry: 1}; "all flags")]
#[test_case(0x0F, 1, 0x80, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "half carry flag")]
#[test_case(0xF0, 1, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "full carry flag")]
fn test_add_immediate_with_carry_to_a_flags(
initial_value: u8,
carry_bit: u8,
operand: u8,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor.registers.a = initial_value;
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0xCE, operand, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test_case(0, 0xFE; "no carry bit")]
#[test_case(1, 0xFF; "carry bit")]
fn test_add_hl_addr_to_a_with_carry_value(carry_flag: u8, expected: u8) {
let mut processor = Processor::default();
processor
.memory
.set(0xFFFE, 0xF0)
.expect("expected to be able to set 0xFF00");
processor
.registers
.set_combined_register(register::Combined::HL, 0xFFFE);
processor.registers.a = 0x0E;
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_flag);
let data = [0x8E, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
assert_eq!(expected, processor.registers.a);
}
#[test_case(0x01, 0, 0x02, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry")]
#[test_case(0xFF, 1, 0x00, AdditionOperationFlags{zero: 1, half_carry: 1, carry: 1}; "all flags")]
#[test_case(0x0F, 1, 0x80, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "half carry flag")]
#[test_case(0xF0, 1, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "full carry flag")]
fn test_add_hl_addr_to_a_with_carry_flags(
initial_value: u8,
carry_bit: u8,
operand: u8,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor
.memory
.set(0xFFFE, operand)
.expect("expected to be able to set 0xFF00");
processor
.registers
.set_combined_register(register::Combined::HL, 0xFFFE);
processor.registers.a = initial_value;
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0x8E, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test_case(0x90, 0xFF, 0x0F, register::SingleEightBit::B, 0xF0; "subtract B")]
#[test_case(0x91, 0xFF, 0x0F, register::SingleEightBit::C, 0xF0; "subtract C")]
#[test_case(0x92, 0xFF, 0x0F, register::SingleEightBit::D, 0xF0; "subtract D")]
#[test_case(0x93, 0xFF, 0x0F, register::SingleEightBit::E, 0xF0; "subtract E")]
#[test_case(0x94, 0xFF, 0x0F, register::SingleEightBit::H, 0xF0; "subtract H")]
#[test_case(0x95, 0xFF, 0x0F, register::SingleEightBit::L, 0xF0; "subtract L")]
fn test_sub_register_from_a_value(
opcode: u8,
a_value: u8,
operand: u8,
operand_register: register::SingleEightBit,
expected: u8,
) {
let mut processor = Processor::default();
processor.registers.a = a_value;
processor
.registers
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
assert_eq!(processor.registers.a, expected);
}
#[test_case(0x90, 0xFF, 0x0F, register::SingleEightBit::B, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags from B")]
#[test_case(0x90, 0xF0, 0x0F, register::SingleEightBit::B, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry from B")]
#[test_case(0x90, 0x0F, 0xF0, register::SingleEightBit::B, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry from B")]
#[test_case(0x90, 0x01, 0x01, register::SingleEightBit::B, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero from B")]
#[test_case(0x91, 0xFF, 0x0F, register::SingleEightBit::C, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags from C")]
#[test_case(0x91, 0xF0, 0x0F, register::SingleEightBit::C, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry from C")]
#[test_case(0x91, 0x0F, 0xF0, register::SingleEightBit::C, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry from C")]
#[test_case(0x91, 0x01, 0x01, register::SingleEightBit::C, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero from C")]
#[test_case(0x92, 0xFF, 0x0F, register::SingleEightBit::D, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags from D")]
#[test_case(0x92, 0xF0, 0x0F, register::SingleEightBit::D, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry from D")]
#[test_case(0x92, 0x0F, 0xF0, register::SingleEightBit::D, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry from D")]
#[test_case(0x92, 0x01, 0x01, register::SingleEightBit::D, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero from D")]
#[test_case(0x93, 0xFF, 0x0F, register::SingleEightBit::E, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags from E")]
#[test_case(0x93, 0xF0, 0x0F, register::SingleEightBit::E, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry from E")]
#[test_case(0x93, 0x0F, 0xF0, register::SingleEightBit::E, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry from E")]
#[test_case(0x93, 0x01, 0x01, register::SingleEightBit::E, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero from E")]
#[test_case(0x94, 0xFF, 0x0F, register::SingleEightBit::H, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags from H")]
#[test_case(0x94, 0xF0, 0x0F, register::SingleEightBit::H, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry from H")]
#[test_case(0x94, 0x0F, 0xF0, register::SingleEightBit::H, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry from H")]
#[test_case(0x94, 0x01, 0x01, register::SingleEightBit::H, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero from H")]
#[test_case(0x95, 0xFF, 0x0F, register::SingleEightBit::L, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags from L")]
#[test_case(0x95, 0xF0, 0x0F, register::SingleEightBit::L, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry from L")]
#[test_case(0x95, 0x0F, 0xF0, register::SingleEightBit::L, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry from L")]
#[test_case(0x95, 0x01, 0x01, register::SingleEightBit::L, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero from L")]
fn test_sub_register_from_a_flags(
opcode: u8,
a_value: u8,
operand: u8,
operand_register: register::SingleEightBit,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor.registers.a = a_value;
processor
.registers
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 1),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
#[test]
fn test_sub_a_from_itself() {
let mut processor = Processor::default();
processor.registers.a = 0xFF;
let data = [0x97, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, 1),
(register::Flag::Subtract, 1),
(register::Flag::HalfCarry, 0),
(register::Flag::Carry, 0),
);
}