202 lines
5.9 KiB
Rust
202 lines
5.9 KiB
Rust
use ferris_boi::{
|
|
cpu::{instructions::Instruction, Processor},
|
|
register,
|
|
};
|
|
|
|
use test_case::test_matrix;
|
|
|
|
use crate::testutil;
|
|
|
|
struct AdditionOperationFlags {
|
|
half_carry: u8,
|
|
carry: u8,
|
|
}
|
|
|
|
#[test]
|
|
fn test_add_hl_to_itself() {
|
|
let mut processor = Processor::default();
|
|
processor.registers.set_16bit_register(
|
|
register::SixteenBit::Combined(register::Combined::HL),
|
|
0x2244,
|
|
);
|
|
let data = [0x29, 0x02];
|
|
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
assert_eq!(extra_data, &[0x02]);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(
|
|
0x4488,
|
|
processor
|
|
.registers
|
|
.get_combined_register(register::Combined::HL)
|
|
);
|
|
}
|
|
|
|
#[test_matrix(
|
|
[
|
|
(0x09, register::SixteenBit::Combined(register::Combined::BC)),
|
|
(0x19, register::SixteenBit::Combined(register::Combined::DE)),
|
|
(0x39, register::SixteenBit::Single(register::SingleSixteenBit::StackPointer)),
|
|
],
|
|
[
|
|
(0xAAAA, 0x1122, 0xBBCC),
|
|
(0xFFFF, 0x0002, 0x0001),
|
|
]
|
|
)]
|
|
fn test_add_hl_to_registers_value(
|
|
(opcode, operand_register): (u8, register::SixteenBit),
|
|
(hl_value, operand_value, expected): (u16, u16, u16),
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.set_16bit_register(
|
|
register::SixteenBit::Combined(register::Combined::HL),
|
|
hl_value,
|
|
);
|
|
processor
|
|
.registers
|
|
.set_16bit_register(operand_register, operand_value);
|
|
let data = [opcode, 0x02];
|
|
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
assert_eq!(extra_data, &[0x02]);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(
|
|
expected,
|
|
processor
|
|
.registers
|
|
.get_combined_register(register::Combined::HL)
|
|
);
|
|
}
|
|
|
|
#[test_matrix(
|
|
[
|
|
(0x09, register::SixteenBit::Combined(register::Combined::BC)),
|
|
(0x19, register::SixteenBit::Combined(register::Combined::DE)),
|
|
(0x39, register::SixteenBit::Single(register::SingleSixteenBit::StackPointer)),
|
|
],
|
|
[
|
|
(0xAAAA, 0x1122, AdditionOperationFlags{ half_carry: 0, carry: 0}),
|
|
(0xAAAA, 0x0FFF, AdditionOperationFlags{ half_carry: 1, carry: 0}),
|
|
(0xFFFF, 0x0001, AdditionOperationFlags{ half_carry: 1, carry: 1}),
|
|
(0xFFFF, 0x0002, AdditionOperationFlags{ half_carry: 1, carry: 1}),
|
|
(0x8000, 0xC000, AdditionOperationFlags{ half_carry: 0, carry: 1}),
|
|
]
|
|
)]
|
|
fn test_add_hl_to_registers_flags(
|
|
(opcode, operand_register): (u8, register::SixteenBit),
|
|
(hl_value, operand_value, expected_flags): (u16, u16, AdditionOperationFlags),
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.set_16bit_register(
|
|
register::SixteenBit::Combined(register::Combined::HL),
|
|
hl_value,
|
|
);
|
|
processor
|
|
.registers
|
|
.set_16bit_register(operand_register, operand_value);
|
|
let data = [opcode, 0x02];
|
|
|
|
let (ins, extra_data) = Instruction::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, expected_flags.half_carry, expected_flags.carry),
|
|
);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
testutil::assert_flags_eq!(
|
|
processor,
|
|
(register::Flag::Zero, 1),
|
|
(register::Flag::Subtract, 0),
|
|
(register::Flag::HalfCarry, expected_flags.half_carry),
|
|
(register::Flag::Carry, expected_flags.carry),
|
|
);
|
|
}
|
|
|
|
#[test_matrix(
|
|
[
|
|
(0x03, register::SixteenBit::Combined(register::Combined::BC)),
|
|
(0x13, register::SixteenBit::Combined(register::Combined::DE)),
|
|
(0x23, register::SixteenBit::Combined(register::Combined::HL)),
|
|
(0x33, register::SixteenBit::Single(register::SingleSixteenBit::StackPointer)),
|
|
],
|
|
[
|
|
(0xAAAA, 0xAAAB),
|
|
(0xFFFF, 0x0000),
|
|
(0x0000, 0x0001),
|
|
]
|
|
)]
|
|
fn test_increment(
|
|
(opcode, operand_register): (u8, register::SixteenBit),
|
|
(start_value, expected): (u16, u16),
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor
|
|
.registers
|
|
.set_16bit_register(operand_register, start_value);
|
|
processor
|
|
.registers
|
|
.set_raw_flag_bits(0xA0)
|
|
.expect("Failed to set flag bits");
|
|
let data = [opcode, 0x02];
|
|
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
assert_eq!(extra_data, &[0x02]);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(
|
|
expected,
|
|
processor.registers.get_16bit_register(operand_register)
|
|
);
|
|
// Flags are untouched
|
|
assert_eq!(0xA0, processor.registers.get_raw_flag_bits());
|
|
}
|
|
|
|
#[test_matrix(
|
|
[
|
|
(0x0B, register::SixteenBit::Combined(register::Combined::BC)),
|
|
(0x1B, register::SixteenBit::Combined(register::Combined::DE)),
|
|
(0x2B, register::SixteenBit::Combined(register::Combined::HL)),
|
|
(0x3B, register::SixteenBit::Single(register::SingleSixteenBit::StackPointer)),
|
|
],
|
|
[
|
|
(0xAAAB, 0xAAAA),
|
|
(0x0000, 0xFFFF),
|
|
(0x0001, 0x0000),
|
|
]
|
|
)]
|
|
fn test_decrement(
|
|
(opcode, operand_register): (u8, register::SixteenBit),
|
|
(start_value, expected): (u16, u16),
|
|
) {
|
|
let mut processor = Processor::default();
|
|
processor
|
|
.registers
|
|
.set_16bit_register(operand_register, start_value);
|
|
processor
|
|
.registers
|
|
.set_raw_flag_bits(0xA0)
|
|
.expect("Failed to set flag bits");
|
|
let data = [opcode, 0x02];
|
|
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
assert_eq!(extra_data, &[0x02]);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(
|
|
expected,
|
|
processor.registers.get_16bit_register(operand_register)
|
|
);
|
|
// Flags are untouched
|
|
assert_eq!(0xA0, processor.registers.get_raw_flag_bits());
|
|
}
|