use ferris_boi::{ cpu::{instructions::RunnableInstruction, 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) = RunnableInstruction::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) = RunnableInstruction::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) = 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, 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) = RunnableInstruction::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) = RunnableInstruction::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()); }