1353 lines
63 KiB
Rust
1353 lines
63 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();
|
|
// 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.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();
|
|
// 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.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);
|
|
|
|
// 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.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);
|
|
|
|
// 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,
|
|
1,
|
|
expected_flags.half_carry,
|
|
expected_flags.carry,
|
|
),
|
|
);
|
|
|
|
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]);
|
|
|
|
// Set all the register to the opposite we expect to ensure they all get set
|
|
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 1, 1));
|
|
|
|
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),
|
|
);
|
|
}
|
|
|
|
#[test_case(0x98, 0xFF, 0x0F, 0, register::SingleEightBit::B, 0xF0; "subtract B with no carry")]
|
|
#[test_case(0x98, 0xFF, 0x0F, 1, register::SingleEightBit::B, 0xEF; "subtract B with carry")]
|
|
#[test_case(0x99, 0xFF, 0x0F, 0, register::SingleEightBit::C, 0xF0; "subtract C with no carry")]
|
|
#[test_case(0x99, 0xFF, 0x0F, 1, register::SingleEightBit::C, 0xEF; "subtract C with carry")]
|
|
#[test_case(0x9A, 0xFF, 0x0F, 0, register::SingleEightBit::D, 0xF0; "subtract D with no carry")]
|
|
#[test_case(0x9A, 0xFF, 0x0F, 1, register::SingleEightBit::D, 0xEF; "subtract D with carry")]
|
|
#[test_case(0x9B, 0xFF, 0x0F, 0, register::SingleEightBit::E, 0xF0; "subtract E with no carry")]
|
|
#[test_case(0x9B, 0xFF, 0x0F, 1, register::SingleEightBit::E, 0xEF; "subtract E with carry")]
|
|
#[test_case(0x9C, 0xFF, 0x0F, 0, register::SingleEightBit::H, 0xF0; "subtract H with no carry")]
|
|
#[test_case(0x9C, 0xFF, 0x0F, 1, register::SingleEightBit::H, 0xEF; "subtract H with carry")]
|
|
#[test_case(0x9D, 0xFF, 0x0F, 0, register::SingleEightBit::L, 0xF0; "subtract L with no carry")]
|
|
#[test_case(0x9D, 0xFF, 0x0F, 1, register::SingleEightBit::L, 0xEF; "subtract L with carry")]
|
|
fn test_sub_register_with_carry_from_a_value(
|
|
opcode: u8,
|
|
a_value: u8,
|
|
operand: u8,
|
|
carry_bit: 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);
|
|
processor
|
|
.registers
|
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
|
|
|
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);
|
|
}
|
|
|
|
// Register B
|
|
#[test_case(0x98, 0xFE, 0, register::SingleEightBit::B, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register b")]
|
|
#[test_case(0x98, 0xFE, 1, register::SingleEightBit::B, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register b")]
|
|
#[test_case(0x98, 0x00, 0, register::SingleEightBit::B, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "all zero operands give zero flag, register b")]
|
|
#[test_case(0x98, 0x01, 1, register::SingleEightBit::B, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 1 gives zero flag with carry bit, register b")]
|
|
#[test_case(0x98, 0x02, 0, register::SingleEightBit::B, 0x2, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 2 gives zero flag with no, register b")]
|
|
#[test_case(0x98, 0xF0, 0, register::SingleEightBit::B, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit set, half carry bit, register b")]
|
|
#[test_case(0x98, 0x0F, 0, register::SingleEightBit::B, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "no carry bit set, full carry bit, register b")]
|
|
#[test_case(0x98, 0xF0, 1, register::SingleEightBit::B, 0x0E, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit set, half carry bit, register b")]
|
|
#[test_case(0x98, 0x0F, 1, register::SingleEightBit::B, 0xEE, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "carry bit set, full carry bit, register b")]
|
|
// Register C
|
|
#[test_case(0x99, 0xFE, 0, register::SingleEightBit::C, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register c")]
|
|
#[test_case(0x99, 0xFE, 1, register::SingleEightBit::C, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register c")]
|
|
#[test_case(0x99, 0x00, 0, register::SingleEightBit::C, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "all zero operands give zero flag, register c")]
|
|
#[test_case(0x99, 0x01, 1, register::SingleEightBit::C, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 1 gives zero flag with carry bit, register c")]
|
|
#[test_case(0x99, 0x02, 0, register::SingleEightBit::C, 0x2, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 2 gives zero flag with no, register c")]
|
|
#[test_case(0x99, 0xF0, 0, register::SingleEightBit::C, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit set, half carry bit, register c")]
|
|
#[test_case(0x99, 0x0F, 0, register::SingleEightBit::C, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "no carry bit set, full carry bit, register c")]
|
|
#[test_case(0x99, 0xF0, 1, register::SingleEightBit::C, 0x0E, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit set, half carry bit, register c")]
|
|
#[test_case(0x99, 0x0F, 1, register::SingleEightBit::C, 0xEE, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "carry bit set, full carry bit, register c")]
|
|
// Register D
|
|
#[test_case(0x9A, 0xFE, 0, register::SingleEightBit::D, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register d")]
|
|
#[test_case(0x9A, 0xFE, 1, register::SingleEightBit::D, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register d")]
|
|
#[test_case(0x9A, 0x00, 0, register::SingleEightBit::D, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "all zero operands give zero flag, register d")]
|
|
#[test_case(0x9A, 0x01, 1, register::SingleEightBit::D, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 1 gives zero flag with carry bit, register d")]
|
|
#[test_case(0x9A, 0x02, 0, register::SingleEightBit::D, 0x2, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 2 gives zero flag with no, register d")]
|
|
#[test_case(0x9A, 0xF0, 0, register::SingleEightBit::D, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit set, half carry bit, register d")]
|
|
#[test_case(0x9A, 0x0F, 0, register::SingleEightBit::D, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "no carry bit set, full carry bit, register d")]
|
|
#[test_case(0x9A, 0xF0, 1, register::SingleEightBit::D, 0x0E, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit set, half carry bit, register d")]
|
|
#[test_case(0x9A, 0x0F, 1, register::SingleEightBit::D, 0xEE, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "carry bit set, full carry bit, register d")]
|
|
// Register E
|
|
#[test_case(0x9B, 0xFE, 0, register::SingleEightBit::E, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register e")]
|
|
#[test_case(0x9B, 0xFE, 1, register::SingleEightBit::E, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register e")]
|
|
#[test_case(0x9B, 0x00, 0, register::SingleEightBit::E, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "all zero operands give zero flag, register e")]
|
|
#[test_case(0x9B, 0x01, 1, register::SingleEightBit::E, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 1 gives zero flag with carry bit, register e")]
|
|
#[test_case(0x9B, 0x02, 0, register::SingleEightBit::E, 0x2, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 2 gives zero flag with no, register e")]
|
|
#[test_case(0x9B, 0xF0, 0, register::SingleEightBit::E, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit set, half carry bit, register e")]
|
|
#[test_case(0x9B, 0x0F, 0, register::SingleEightBit::E, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "no carry bit set, full carry bit, register e")]
|
|
#[test_case(0x9B, 0xF0, 1, register::SingleEightBit::E, 0x0E, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit set, half carry bit, register e")]
|
|
#[test_case(0x9B, 0x0F, 1, register::SingleEightBit::E, 0xEE, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "carry bit set, full carry bit, register e")]
|
|
// Register H
|
|
#[test_case(0x9C, 0xFE, 0, register::SingleEightBit::H, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register h")]
|
|
#[test_case(0x9C, 0xFE, 1, register::SingleEightBit::H, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register h")]
|
|
#[test_case(0x9C, 0x00, 0, register::SingleEightBit::H, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "all zero operands give zero flag, register h")]
|
|
#[test_case(0x9C, 0x01, 1, register::SingleEightBit::H, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 1 gives zero flag with carry bit, register h")]
|
|
#[test_case(0x9C, 0x02, 0, register::SingleEightBit::H, 0x2, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 2 gives zero flag with no, register h")]
|
|
#[test_case(0x9C, 0xF0, 0, register::SingleEightBit::H, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit set, half carry bit, register h")]
|
|
#[test_case(0x9C, 0x0F, 0, register::SingleEightBit::H, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "no carry bit set, full carry bit, register h")]
|
|
#[test_case(0x9C, 0xF0, 1, register::SingleEightBit::H, 0x0E, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit set, half carry bit, register h")]
|
|
#[test_case(0x9C, 0x0F, 1, register::SingleEightBit::H, 0xEE, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "carry bit set, full carry bit, register h")]
|
|
// Register L
|
|
#[test_case(0x9D, 0xFE, 0, register::SingleEightBit::L, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register l")]
|
|
#[test_case(0x9D, 0xFE, 1, register::SingleEightBit::L, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register l")]
|
|
#[test_case(0x9D, 0x00, 0, register::SingleEightBit::L, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "all zero operands give zero flag, register l")]
|
|
#[test_case(0x9D, 0x01, 1, register::SingleEightBit::L, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 1 gives zero flag with carry bit, register l")]
|
|
#[test_case(0x9D, 0x02, 0, register::SingleEightBit::L, 0x2, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 2 gives zero flag with no, register l")]
|
|
#[test_case(0x9D, 0xF0, 0, register::SingleEightBit::L, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit set, half carry bit, register l")]
|
|
#[test_case(0x9D, 0x0F, 0, register::SingleEightBit::L, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "no carry bit set, full carry bit, register l")]
|
|
#[test_case(0x9D, 0xF0, 1, register::SingleEightBit::L, 0x0E, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit set, half carry bit, register l")]
|
|
#[test_case(0x9D, 0x0F, 1, register::SingleEightBit::L, 0xEE, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "carry bit set, full carry bit, register l")]
|
|
fn test_sub_register_from_carry_from_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, 1),
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
(register::Flag::Carry, expected_flags.carry),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_subtract_immediate_from_a_value() {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = 0xFF;
|
|
let data = [0xD6, 0x0F, 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, 0xF0);
|
|
}
|
|
|
|
#[test_case(0xFF, 0x0F, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags")]
|
|
#[test_case(0xF0, 0x0F, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry")]
|
|
#[test_case(0x0F, 0xF0, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry")]
|
|
#[test_case(0x01, 0x01, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero")]
|
|
fn test_sub_immediate_from_a_flags(
|
|
initial_value: u8,
|
|
operand: u8,
|
|
expected_flags: AdditionOperationFlags,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = initial_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 = [0xD6, 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, 1),
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
(register::Flag::Carry, expected_flags.carry),
|
|
);
|
|
}
|
|
|
|
#[test_case(0xFF, 0x0F, 0, 0xF0; "no carry")]
|
|
#[test_case(0xFF, 0x0F, 1, 0xEF; "carry")]
|
|
fn test_sub_immediate_with_carry_from_a_value(
|
|
a_value: u8,
|
|
operand: u8,
|
|
carry_bit: u8,
|
|
expected: u8,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = a_value;
|
|
processor
|
|
.registers
|
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
|
|
|
let data = [0xDE, operand, 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(0xFE, 0, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags")]
|
|
#[test_case(0xFE, 1, 0x1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags")]
|
|
#[test_case(0x00, 0, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "all zero operands give zero flag")]
|
|
#[test_case(0x01, 1, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 1 gives zero flag with carry bit")]
|
|
#[test_case(0x02, 0, 0x2, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtracting from 2 gives zero flag with no")]
|
|
#[test_case(0xF0, 0, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit set, half carry bit")]
|
|
#[test_case(0x0F, 0, 0xF0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "no carry bit set, full carry bit")]
|
|
#[test_case(0xF0, 1, 0x0E, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit set, half carry bit")]
|
|
#[test_case(0x0F, 1, 0xEE, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "carry bit set, full carry bit")]
|
|
fn test_sub_immediate_from_carry_from_a_flags(
|
|
initial_value: u8,
|
|
carry_bit: u8,
|
|
operand: u8,
|
|
expected_flags: AdditionOperationFlags,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = initial_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,
|
|
),
|
|
);
|
|
|
|
// ...except for the carry bit, which we must set for the test
|
|
processor
|
|
.registers
|
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
|
|
|
let data = [0xDE, 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, 1),
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
(register::Flag::Carry, expected_flags.carry),
|
|
);
|
|
}
|
|
|
|
#[test_case(0, 0; "subtract from itself")]
|
|
#[test_case(1, 0xFF; "subtract from itself with carry bit")]
|
|
fn test_sub_a_register_from_itself_with_carry_value(carry_bit: u8, expected: u8) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = 0xEE;
|
|
processor
|
|
.registers
|
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
|
|
|
let data = [0x9F, 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, processor.registers.a);
|
|
}
|
|
|
|
#[test_case(0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "subtract from itself")]
|
|
#[test_case(1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "subtract from itself with carry bit")]
|
|
fn test_sub_a_register_from_itself_with_carry_flags(
|
|
carry_bit: u8,
|
|
expected_flags: AdditionOperationFlags,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
// 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.a = 0xEE;
|
|
processor
|
|
.registers
|
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
|
|
|
let data = [0x9F, 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, 1),
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
(register::Flag::Carry, expected_flags.carry),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sub_hl_addr_from_a_value() {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = 0xBA;
|
|
processor
|
|
.memory
|
|
.set(0xABCD, 0xA9)
|
|
.expect("failed to set memory value");
|
|
|
|
processor
|
|
.registers
|
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
|
|
|
let data = [0x96, 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!(0x11, processor.registers.a);
|
|
}
|
|
|
|
#[test_case(0xFF, 0x0F, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags")]
|
|
#[test_case(0xF0, 0x0F, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry")]
|
|
#[test_case(0x0F, 0xF0, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry")]
|
|
#[test_case(0x01, 0x01, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero")]
|
|
fn test_sub_hl_addr_from_a_flags(
|
|
a_value: u8,
|
|
operand_value: u8,
|
|
expected_flags: AdditionOperationFlags,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
// 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.a = a_value;
|
|
processor
|
|
.memory
|
|
.set(0xABCD, operand_value)
|
|
.expect("failed to set memory value");
|
|
|
|
processor
|
|
.registers
|
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
|
|
|
let data = [0x96, 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, 1),
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
(register::Flag::Carry, expected_flags.carry),
|
|
);
|
|
}
|
|
|
|
#[test_case(0xFE, 0xED, 0, 0x11; "no carry bit")]
|
|
#[test_case(0xFE, 0xED, 1, 0x10; "carry bit")]
|
|
fn test_sub_hl_from_a_flags(a_value: u8, operand_value: u8, carry_bit: u8, expected_value: u8) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = a_value;
|
|
processor
|
|
.registers
|
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
|
processor
|
|
.memory
|
|
.set(0xABCD, operand_value)
|
|
.expect("failed to set memory value");
|
|
|
|
processor
|
|
.registers
|
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
|
|
|
let data = [0x9E, 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);
|
|
}
|
|
|
|
#[test_case(0xFF, 0x0F, 0, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags")]
|
|
#[test_case(0xFF, 0x0E, 1, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 0 }; "no flags with carry bit")]
|
|
#[test_case(0xF0, 0x0F, 0, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry")]
|
|
#[test_case(0xF0, 0x0E, 1, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 0 }; "half carry with carry bit")]
|
|
#[test_case(0x0F, 0xF0, 0, AdditionOperationFlags { zero: 0, half_carry: 0, carry: 1 }; "full carry")]
|
|
#[test_case(0x0F, 0xEF, 1, AdditionOperationFlags { zero: 0, half_carry: 1, carry: 1 }; "full carry with carry bit")]
|
|
#[test_case(0x01, 0x01, 0, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero")]
|
|
#[test_case(0x01, 0x00, 1, AdditionOperationFlags { zero: 1, half_carry: 0, carry: 0 }; "zero with carry bit")]
|
|
fn test_sub_hl_addr_from_a_with_carry_flags(
|
|
a_value: u8,
|
|
operand_value: u8,
|
|
carry_bit: u8,
|
|
expected_flags: AdditionOperationFlags,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
// 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_flag_bit(register::Flag::Carry, carry_bit);
|
|
|
|
processor.registers.a = a_value;
|
|
processor
|
|
.memory
|
|
.set(0xABCD, operand_value)
|
|
.expect("failed to set memory value");
|
|
|
|
processor
|
|
.registers
|
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
|
|
|
let data = [0x9E, 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, 1),
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
(register::Flag::Carry, expected_flags.carry),
|
|
);
|
|
}
|
|
|
|
#[test_case(0xA0, 0xFB, register::SingleEightBit::B, 0x0F, 0x0B; "AND with B")]
|
|
#[test_case(0xA1, 0xFC, register::SingleEightBit::C, 0x0F, 0x0C; "AND with C")]
|
|
#[test_case(0xA2, 0xFD, register::SingleEightBit::D, 0x0F, 0x0D; "AND with D")]
|
|
#[test_case(0xA3, 0xFE, register::SingleEightBit::E, 0x0F, 0x0E; "AND with E")]
|
|
#[test_case(0xA4, 0xF0, register::SingleEightBit::H, 0x0F, 0x00; "AND with H")]
|
|
#[test_case(0xA5, 0xF1, register::SingleEightBit::L, 0x0F, 0x01; "AND with L")]
|
|
fn test_and_single_register_with_a_value(
|
|
opcode: u8,
|
|
a_value: u8,
|
|
operand_register: register::SingleEightBit,
|
|
operand: u8,
|
|
expected_value: u8,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = a_value;
|
|
processor
|
|
.registers
|
|
.set_single_8bit_register(operand_register, operand);
|
|
|
|
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);
|
|
}
|
|
|
|
#[test_case(0xA0, 0xFA, register::SingleEightBit::B, 0x0F, 0; "AND with B, not zero")]
|
|
#[test_case(0xA0, 0xFA, register::SingleEightBit::B, 0x00, 1; "AND with B, zero")]
|
|
#[test_case(0xA1, 0xFA, register::SingleEightBit::C, 0x0F, 0; "AND with C, not zero")]
|
|
#[test_case(0xA1, 0xFA, register::SingleEightBit::C, 0x00, 1; "AND with C, zero")]
|
|
#[test_case(0xA2, 0xFA, register::SingleEightBit::D, 0x0F, 0; "AND with D, not zero")]
|
|
#[test_case(0xA2, 0xFA, register::SingleEightBit::D, 0x00, 1; "AND with D, zero")]
|
|
#[test_case(0xA3, 0xFA, register::SingleEightBit::E, 0x0F, 0; "AND with E, not zero")]
|
|
#[test_case(0xA3, 0xFA, register::SingleEightBit::E, 0x00, 1; "AND with E, zero")]
|
|
fn test_and_single_register_with_a_flags(
|
|
opcode: u8,
|
|
a_value: u8,
|
|
operand_register: register::SingleEightBit,
|
|
operand: u8,
|
|
expected_zero_flag: u8,
|
|
) {
|
|
let mut processor = Processor::default();
|
|
// Set all the register to the opposite we expect to ensure they all get set
|
|
testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 1, 0));
|
|
|
|
processor.registers.a = a_value;
|
|
processor
|
|
.registers
|
|
.set_single_8bit_register(operand_register, operand);
|
|
|
|
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_zero_flag),
|
|
(register::Flag::Subtract, 0),
|
|
(register::Flag::HalfCarry, 1),
|
|
(register::Flag::Carry, 0),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_and_a_with_itself_value() {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = 0xAB;
|
|
|
|
let data = [0xA7, 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!(0xAB, processor.registers.a);
|
|
}
|
|
|
|
#[test]
|
|
fn test_and_a_with_itself_flags() {
|
|
let mut processor = Processor::default();
|
|
// Set all the register to the opposite we expect to ensure they all get set
|
|
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 1, 0));
|
|
|
|
processor.registers.a = 0xAB;
|
|
|
|
let data = [0xA7, 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, 0),
|
|
(register::Flag::Subtract, 0),
|
|
(register::Flag::HalfCarry, 1),
|
|
(register::Flag::Carry, 0),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_and_hl_value_with_a_value() {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = 0xAB;
|
|
processor
|
|
.registers
|
|
.set_combined_register(register::Combined::HL, 0x00FF);
|
|
processor
|
|
.memory
|
|
.set(0x00FF, 0xF0)
|
|
.expect("failed to set value");
|
|
|
|
let data = [0xA6, 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!(0xA0, processor.registers.a);
|
|
}
|
|
|
|
#[test_case(0xFA, 0x0F, 0; "not zero")]
|
|
#[test_case(0xFA, 0x00, 1; "zero")]
|
|
fn test_and_hl_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag: u8) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = a_value;
|
|
processor
|
|
.registers
|
|
.set_combined_register(register::Combined::HL, 0x00FF);
|
|
processor
|
|
.memory
|
|
.set(0x00FF, operand)
|
|
.expect("failed to set 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_zero_flag, 0, 1, 0));
|
|
|
|
let data = [0xA6, 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_zero_flag),
|
|
(register::Flag::Subtract, 0),
|
|
(register::Flag::HalfCarry, 1),
|
|
(register::Flag::Carry, 0),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_and_immediate_with_a_value() {
|
|
let mut processor = Processor::default();
|
|
processor.registers.a = 0xAB;
|
|
|
|
let data = [0xE6, 0x0F, 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!(0x0B, processor.registers.a);
|
|
}
|
|
|
|
#[test_case(0xFA, 0x0F, 0; "not zero")]
|
|
#[test_case(0xFA, 0x00, 1; "zero")]
|
|
fn test_and_immediate_with_a_flags(a_value: u8, operand: u8, expected_zero_flag: u8) {
|
|
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_zero_flag, 0, 1, 0));
|
|
|
|
let data = [0xE6, 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_zero_flag),
|
|
(register::Flag::Subtract, 0),
|
|
(register::Flag::HalfCarry, 1),
|
|
(register::Flag::Carry, 0),
|
|
);
|
|
}
|