|
|
|
@ -15,6 +15,7 @@ struct AdditionOperationFlags {
|
|
|
|
|
|
|
|
|
|
struct IncrementOperationFlags {
|
|
|
|
|
zero: u8,
|
|
|
|
|
subtract: u8,
|
|
|
|
|
half_carry: u8,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2149,7 +2150,22 @@ fn test_comparing_immediate_value_to_a(
|
|
|
|
|
#[test_case(0x2C, register::SingleEightBit::L, 0xFF, 0x00; "add one with wrapping, register L")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0x05, 0x06; "add one, register A")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0xFF, 0x00; "add one with wrapping, register A")]
|
|
|
|
|
fn test_increment_single_register_value(
|
|
|
|
|
// decrement
|
|
|
|
|
#[test_case(0x05, register::SingleEightBit::B, 0x05, 0x04; "sub one, register B")]
|
|
|
|
|
#[test_case(0x05, register::SingleEightBit::B, 0x00, 0xFF; "sub one with wrapping, register B")]
|
|
|
|
|
#[test_case(0x0D, register::SingleEightBit::C, 0x05, 0x04; "sub one, register C")]
|
|
|
|
|
#[test_case(0x0D, register::SingleEightBit::C, 0x00, 0xFF; "sub one with wrapping, register C")]
|
|
|
|
|
#[test_case(0x15, register::SingleEightBit::D, 0x05, 0x04; "sub one, register D")]
|
|
|
|
|
#[test_case(0x15, register::SingleEightBit::D, 0x00, 0xFF; "sub one with wrapping, register D")]
|
|
|
|
|
#[test_case(0x1D, register::SingleEightBit::E, 0x05, 0x04; "sub one, register E")]
|
|
|
|
|
#[test_case(0x1D, register::SingleEightBit::E, 0x00, 0xFF; "sub one with wrapping, register E")]
|
|
|
|
|
#[test_case(0x25, register::SingleEightBit::H, 0x05, 0x04; "sub one, register H")]
|
|
|
|
|
#[test_case(0x25, register::SingleEightBit::H, 0x00, 0xFF; "sub one with wrapping, register H")]
|
|
|
|
|
#[test_case(0x2D, register::SingleEightBit::L, 0x05, 0x04; "sub one, register L")]
|
|
|
|
|
#[test_case(0x2D, register::SingleEightBit::L, 0x00, 0xFF; "sub one with wrapping, register L")]
|
|
|
|
|
#[test_case(0x3D, register::SingleEightBit::A, 0x05, 0x04; "sub one, register A")]
|
|
|
|
|
#[test_case(0x3D, register::SingleEightBit::A, 0x00, 0xFF; "sub one with wrapping, register A")]
|
|
|
|
|
fn test_increment_decrement_single_register_value(
|
|
|
|
|
opcode: u8,
|
|
|
|
|
register: register::SingleEightBit,
|
|
|
|
|
initial_value: u8,
|
|
|
|
@ -2172,28 +2188,57 @@ fn test_increment_single_register_value(
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test_case(0x04, register::SingleEightBit::B, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment, register B")]
|
|
|
|
|
#[test_case(0x04, register::SingleEightBit::B, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping, register B")]
|
|
|
|
|
#[test_case(0x04, register::SingleEightBit::B, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry, register B")]
|
|
|
|
|
#[test_case(0x0C, register::SingleEightBit::C, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment, register C")]
|
|
|
|
|
#[test_case(0x0C, register::SingleEightBit::C, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping, register C")]
|
|
|
|
|
#[test_case(0x0C, register::SingleEightBit::C, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry, register C")]
|
|
|
|
|
#[test_case(0x14, register::SingleEightBit::D, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment, register D")]
|
|
|
|
|
#[test_case(0x14, register::SingleEightBit::D, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping, register D")]
|
|
|
|
|
#[test_case(0x14, register::SingleEightBit::D, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry, register D")]
|
|
|
|
|
#[test_case(0x1C, register::SingleEightBit::E, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment, register E")]
|
|
|
|
|
#[test_case(0x1C, register::SingleEightBit::E, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping, register E")]
|
|
|
|
|
#[test_case(0x1C, register::SingleEightBit::E, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry, register E")]
|
|
|
|
|
#[test_case(0x24, register::SingleEightBit::H, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment, register H")]
|
|
|
|
|
#[test_case(0x24, register::SingleEightBit::H, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping, register H")]
|
|
|
|
|
#[test_case(0x24, register::SingleEightBit::H, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry, register H")]
|
|
|
|
|
#[test_case(0x2C, register::SingleEightBit::L, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment, register L")]
|
|
|
|
|
#[test_case(0x2C, register::SingleEightBit::L, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping, register L")]
|
|
|
|
|
#[test_case(0x2C, register::SingleEightBit::L, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry, register L")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment, register A")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping, register A")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry, register A")]
|
|
|
|
|
fn test_increment_single_register_flags(
|
|
|
|
|
#[test_case(0x04, register::SingleEightBit::B, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0}; "increment, register B")]
|
|
|
|
|
#[test_case(0x04, register::SingleEightBit::B, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0}; "increment with wrapping, register B")]
|
|
|
|
|
#[test_case(0x04, register::SingleEightBit::B, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0 }; "increment with half carry, register B")]
|
|
|
|
|
#[test_case(0x0C, register::SingleEightBit::C, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0 }; "increment, register C")]
|
|
|
|
|
#[test_case(0x0C, register::SingleEightBit::C, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0 }; "increment with wrapping, register C")]
|
|
|
|
|
#[test_case(0x0C, register::SingleEightBit::C, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0 }; "increment with half carry, register C")]
|
|
|
|
|
#[test_case(0x14, register::SingleEightBit::D, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0 }; "increment, register D")]
|
|
|
|
|
#[test_case(0x14, register::SingleEightBit::D, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0 }; "increment with wrapping, register D")]
|
|
|
|
|
#[test_case(0x14, register::SingleEightBit::D, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0 }; "increment with half carry, register D")]
|
|
|
|
|
#[test_case(0x1C, register::SingleEightBit::E, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0 }; "increment, register E")]
|
|
|
|
|
#[test_case(0x1C, register::SingleEightBit::E, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0 }; "increment with wrapping, register E")]
|
|
|
|
|
#[test_case(0x1C, register::SingleEightBit::E, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0 }; "increment with half carry, register E")]
|
|
|
|
|
#[test_case(0x24, register::SingleEightBit::H, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0 }; "increment, register H")]
|
|
|
|
|
#[test_case(0x24, register::SingleEightBit::H, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0 }; "increment with wrapping, register H")]
|
|
|
|
|
#[test_case(0x24, register::SingleEightBit::H, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0 }; "increment with half carry, register H")]
|
|
|
|
|
#[test_case(0x2C, register::SingleEightBit::L, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0 }; "increment, register L")]
|
|
|
|
|
#[test_case(0x2C, register::SingleEightBit::L, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0 }; "increment with wrapping, register L")]
|
|
|
|
|
#[test_case(0x2C, register::SingleEightBit::L, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0 }; "increment with half carry, register L")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0 }; "increment, register A")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0 }; "increment with wrapping, register A")]
|
|
|
|
|
#[test_case(0x3C, register::SingleEightBit::A, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0 }; "increment with half carry, register A")]
|
|
|
|
|
// decrement
|
|
|
|
|
#[test_case(0x05, register::SingleEightBit::B, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement, register B")]
|
|
|
|
|
#[test_case(0x05, register::SingleEightBit::B, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping, register B")]
|
|
|
|
|
#[test_case(0x05, register::SingleEightBit::B, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero, register B")]
|
|
|
|
|
#[test_case(0x05, register::SingleEightBit::B, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry, register B")]
|
|
|
|
|
#[test_case(0x0D, register::SingleEightBit::C, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement, register C")]
|
|
|
|
|
#[test_case(0x0D, register::SingleEightBit::C, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping, register C")]
|
|
|
|
|
#[test_case(0x0D, register::SingleEightBit::C, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero, register C")]
|
|
|
|
|
#[test_case(0x0D, register::SingleEightBit::C, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry, register C")]
|
|
|
|
|
#[test_case(0x15, register::SingleEightBit::D, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement, register D")]
|
|
|
|
|
#[test_case(0x15, register::SingleEightBit::D, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping, register D")]
|
|
|
|
|
#[test_case(0x15, register::SingleEightBit::D, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero, register D")]
|
|
|
|
|
#[test_case(0x15, register::SingleEightBit::D, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry, register D")]
|
|
|
|
|
#[test_case(0x1D, register::SingleEightBit::E, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement, register E")]
|
|
|
|
|
#[test_case(0x1D, register::SingleEightBit::E, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping, register E")]
|
|
|
|
|
#[test_case(0x1D, register::SingleEightBit::E, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero, register E")]
|
|
|
|
|
#[test_case(0x1D, register::SingleEightBit::E, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry, register E")]
|
|
|
|
|
#[test_case(0x25, register::SingleEightBit::H, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement, register H")]
|
|
|
|
|
#[test_case(0x25, register::SingleEightBit::H, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping, register H")]
|
|
|
|
|
#[test_case(0x25, register::SingleEightBit::H, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero, register H")]
|
|
|
|
|
#[test_case(0x25, register::SingleEightBit::H, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry, register H")]
|
|
|
|
|
#[test_case(0x2D, register::SingleEightBit::L, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement, register L")]
|
|
|
|
|
#[test_case(0x2D, register::SingleEightBit::L, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping, register L")]
|
|
|
|
|
#[test_case(0x2D, register::SingleEightBit::L, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero, register L")]
|
|
|
|
|
#[test_case(0x2D, register::SingleEightBit::L, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry, register L")]
|
|
|
|
|
#[test_case(0x3D, register::SingleEightBit::A, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement, register A")]
|
|
|
|
|
#[test_case(0x3D, register::SingleEightBit::A, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping, register A")]
|
|
|
|
|
#[test_case(0x3D, register::SingleEightBit::A, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero, register A")]
|
|
|
|
|
#[test_case(0x3D, register::SingleEightBit::A, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry, register A")]
|
|
|
|
|
fn test_increment_decrement_single_register_flags(
|
|
|
|
|
opcode: u8,
|
|
|
|
|
register: register::SingleEightBit,
|
|
|
|
|
initial_value: u8,
|
|
|
|
@ -2209,7 +2254,7 @@ fn test_increment_single_register_flags(
|
|
|
|
|
&mut processor,
|
|
|
|
|
(
|
|
|
|
|
expected_flags.zero,
|
|
|
|
|
0,
|
|
|
|
|
expected_flags.subtract,
|
|
|
|
|
expected_flags.half_carry,
|
|
|
|
|
// Carry flag should remain unchanged - quick lazy hack to just set this to 1.
|
|
|
|
|
0,
|
|
|
|
@ -2225,16 +2270,18 @@ fn test_increment_single_register_flags(
|
|
|
|
|
testutil::assert_flags_eq!(
|
|
|
|
|
processor,
|
|
|
|
|
(register::Flag::Zero, expected_flags.zero),
|
|
|
|
|
(register::Flag::Subtract, 0),
|
|
|
|
|
(register::Flag::Subtract, expected_flags.subtract),
|
|
|
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
|
|
|
// Carry flag should remain unchanged
|
|
|
|
|
(register::Flag::Carry, 1),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test_case(0x05, 0x06; "add one")]
|
|
|
|
|
#[test_case(0xFF, 0x00; "add one with wrapping")]
|
|
|
|
|
fn test_increment_hl_value(initial_value: u8, expected_value: u8) {
|
|
|
|
|
#[test_case(0x34, 0x05, 0x06; "add one")]
|
|
|
|
|
#[test_case(0x34, 0xFF, 0x00; "add one with wrapping")]
|
|
|
|
|
#[test_case(0x35, 0x05, 0x04; "sub one")]
|
|
|
|
|
#[test_case(0x35, 0x000, 0xFF; "sub one with wrapping")]
|
|
|
|
|
fn test_increment_decrement_hl_value(opcode: u8, initial_value: u8, expected_value: u8) {
|
|
|
|
|
let mut processor = Processor::default();
|
|
|
|
|
processor
|
|
|
|
|
.registers
|
|
|
|
@ -2244,7 +2291,7 @@ fn test_increment_hl_value(initial_value: u8, expected_value: u8) {
|
|
|
|
|
.set(0xFF23, initial_value)
|
|
|
|
|
.expect("failed to set memory value");
|
|
|
|
|
|
|
|
|
|
let data = [0x34, 0x03];
|
|
|
|
|
let data = [opcode, 0x03];
|
|
|
|
|
let (ins, extra_data) =
|
|
|
|
|
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
|
assert_eq!(extra_data, &[0x03]);
|
|
|
|
@ -2259,10 +2306,14 @@ fn test_increment_hl_value(initial_value: u8, expected_value: u8) {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test_case(0x05, IncrementOperationFlags { zero: 0, half_carry: 0 }; "increment")]
|
|
|
|
|
#[test_case(0xFF, IncrementOperationFlags { zero: 1, half_carry: 1 }; "increment with wrapping")]
|
|
|
|
|
#[test_case(0x0F, IncrementOperationFlags { zero: 0, half_carry: 1 }; "increment with half carry")]
|
|
|
|
|
fn test_increment_hl_flags(initial_value: u8, expected_flags: IncrementOperationFlags) {
|
|
|
|
|
#[test_case(0x34, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0}; "increment")]
|
|
|
|
|
#[test_case(0x34, 0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0}; "increment with wrapping")]
|
|
|
|
|
#[test_case(0x34, 0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0}; "increment with half carry")]
|
|
|
|
|
#[test_case(0x35, 0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}; "decrement")]
|
|
|
|
|
#[test_case(0x35, 0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}; "decrement to zero")]
|
|
|
|
|
#[test_case(0x35, 0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with wrapping")]
|
|
|
|
|
#[test_case(0x35, 0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}; "decrement with half carry")]
|
|
|
|
|
fn test_increment_decrement_hl_flags(opcode: u8, initial_value: u8, expected_flags: IncrementOperationFlags) {
|
|
|
|
|
let mut processor = Processor::default();
|
|
|
|
|
processor
|
|
|
|
|
.registers
|
|
|
|
@ -2277,14 +2328,14 @@ fn test_increment_hl_flags(initial_value: u8, expected_flags: IncrementOperation
|
|
|
|
|
&mut processor,
|
|
|
|
|
(
|
|
|
|
|
expected_flags.zero,
|
|
|
|
|
0,
|
|
|
|
|
expected_flags.subtract,
|
|
|
|
|
expected_flags.half_carry,
|
|
|
|
|
// Carry flag should remain unchanged - quick lazy hack to just set this to 1.
|
|
|
|
|
0,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let data = [0x34, 0x03];
|
|
|
|
|
let data = [opcode, 0x03];
|
|
|
|
|
let (ins, extra_data) =
|
|
|
|
|
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
|
assert_eq!(extra_data, &[0x03]);
|
|
|
|
@ -2293,7 +2344,7 @@ fn test_increment_hl_flags(initial_value: u8, expected_flags: IncrementOperation
|
|
|
|
|
testutil::assert_flags_eq!(
|
|
|
|
|
processor,
|
|
|
|
|
(register::Flag::Zero, expected_flags.zero),
|
|
|
|
|
(register::Flag::Subtract, 0),
|
|
|
|
|
(register::Flag::Subtract, expected_flags.subtract),
|
|
|
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
|
|
|
// Carry flag should remain unchanged
|
|
|
|
|
(register::Flag::Carry, 1),
|
|
|
|
|