use ferris_boi::{ cpu::{instructions::Instruction, Processor}, register, }; use crate::testutil; use test_case::{test_case, test_matrix}; struct AdditionOperationFlags { zero: u8, half_carry: u8, carry: u8, } struct IncrementOperationFlags { zero: u8, subtract: u8, half_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) = Instruction::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) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x02]); processor.run_instruction(ins); assert_eq!(30, processor.registers.a); } #[test_matrix( [ (0x00, 0x00, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}), (0x00, 0x01, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}), (0x0F, 0x01, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}), (0x80, 0x80, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 1}), (0xFF, 0x01, AdditionOperationFlags{zero: 1, half_carry: 1, carry: 1}) ], [ (0x80, register::SingleEightBit::B), (0x81, register::SingleEightBit::C), (0x82, register::SingleEightBit::D), (0x83, register::SingleEightBit::E), (0x84, register::SingleEightBit::H), (0x85, register::SingleEightBit::L), ] )] fn test_add_register_to_a_flags( (a_value, src_value, expected_flags): (u8, u8, AdditionOperationFlags), (opcode, src): (u8, register::SingleEightBit), ) { 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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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_matrix( [ (0x88, register::SingleEightBit::B), (0x89, register::SingleEightBit::C), (0x8A, register::SingleEightBit::D), (0x8B, register::SingleEightBit::E), (0x8C, register::SingleEightBit::H), (0x8D, register::SingleEightBit::L), ], [ (0x12, 0x05, 0, 0x17), (0x12, 0x05, 1, 0x18) ] )] fn test_add_register_with_carry_to_a_value( (opcode, operand_register): (u8, register::SingleEightBit), (initial_value, operand, carry_bit, expected_value): (u8, u8, u8, 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) = Instruction::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_matrix( [ (0x88, register::SingleEightBit::B), (0x89, register::SingleEightBit::C), (0x8A, register::SingleEightBit::D), (0x8B, register::SingleEightBit::E), (0x8C, register::SingleEightBit::H), (0x8D, register::SingleEightBit::L), ], [ (0x12, 0x05, 0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}), (0x12, 0x05, 1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}), (0x00, 0x00, 0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}), (0x00, 0x00, 1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}), (0x0F, 0x01, 0, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}), (0x0F, 0x01, 1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}), (0x0F, 0x0F, 0, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}), (0x0F, 0x0F, 1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}), (0x80, 0x82, 0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}), (0x80, 0x82, 1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}), (0x0F, 0xFF, 0, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}), (0x7F, 0x80, 1, AdditionOperationFlags{zero: 1, half_carry: 1, carry: 1}), ] ) ] fn test_add_register_with_carry_to_a_flags( (opcode, operand_register): (u8, register::SingleEightBit), (initial_value, operand, carry_bit, expected_flags): (u8, u8, u8, 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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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_matrix( [ (0x90, register::SingleEightBit::B), (0x91, register::SingleEightBit::C), (0x92, register::SingleEightBit::D), (0x93, register::SingleEightBit::E), (0x94, register::SingleEightBit::H), (0x95, register::SingleEightBit::L), ], [ (0xFF, 0x0F, 0xF0), (0x00, 0x03, 0xFD), ] )] fn test_sub_register_from_a_value( (opcode, operand_register): (u8, register::SingleEightBit), (a_value, operand, expected): (u8, u8, 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) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x02]); processor.run_instruction(ins); assert_eq!(processor.registers.a, expected); } #[test_matrix( [ (0x90, register::SingleEightBit::B), (0x91, register::SingleEightBit::C), (0x92, register::SingleEightBit::D), (0x93, register::SingleEightBit::E), (0x94, register::SingleEightBit::H), (0x95, register::SingleEightBit::L), ], [ (0xFF, 0x0F, AdditionOperationFlags{ zero: 0, half_carry: 0, carry: 0 }), (0xF0, 0x0F, AdditionOperationFlags{ zero: 0, half_carry: 1, carry: 0 }), (0x0F, 0xF0, AdditionOperationFlags{ zero: 0, half_carry: 0, carry: 1 }), (0x01, 0x01, AdditionOperationFlags{ zero: 1, half_carry: 0, carry: 0 }) ] )] fn test_sub_register_from_a_flags( (opcode, operand_register): (u8, register::SingleEightBit), (a_value, operand, expected_flags): (u8, u8, 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) = Instruction::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) = 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, 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_matrix( [ (0x98, register::SingleEightBit::B), (0x99, register::SingleEightBit::C), (0x9A, register::SingleEightBit::D), (0x9B, register::SingleEightBit::E), (0x9C, register::SingleEightBit::H), (0x9D, register::SingleEightBit::L), ], [ (0xFF, 0x0F, 0, 0xF0), (0xFF, 0x0F, 1, 0xEF) ] )] fn test_sub_register_with_carry_from_a_value( (opcode, operand_register): (u8, register::SingleEightBit), (a_value, operand, carry_bit, expected): (u8, u8, u8, 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) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x02]); processor.run_instruction(ins); assert_eq!(processor.registers.a, expected); } #[test_matrix( [ (0x98, register::SingleEightBit::B), (0x99, register::SingleEightBit::C), (0x9A, register::SingleEightBit::D), (0x9B, register::SingleEightBit::E), (0x9C, register::SingleEightBit::H), (0x9D, register::SingleEightBit::L), ], [ (0xFE, 0x01, 0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}), (0xFE, 0x01, 1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}), (0x00, 0x00, 0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}), (0x01, 0x00, 1, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}), (0x02, 0x02, 0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}), (0xF0, 0x0F, 0, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}), (0x0F, 0xF0, 0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}), (0xF0, 0x0E, 1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}), (0x0F, 0xEE, 1, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}), ] )] fn test_sub_register_from_carry_from_a_flags( (opcode, operand_register): (u8, register::SingleEightBit), (initial_value, operand, carry_bit, expected_flags): (u8, u8, u8, 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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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_matrix( [ (0xA0, register::SingleEightBit::B), (0xA1, register::SingleEightBit::C), (0xA2, register::SingleEightBit::D), (0xA3, register::SingleEightBit::E), ], [ (0xFA, 0x0F, 0), (0xFA, 0x00, 1), ] )] fn test_and_single_register_with_a_flags( (opcode, operand_register): (u8, register::SingleEightBit), (a_value, operand, expected_zero_flag): (u8, u8, 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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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) = Instruction::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_case(0xA8, 0xFF, register::SingleEightBit::B, 0xCC, 0x33; "register B")] #[test_case(0xA9, 0xFF, register::SingleEightBit::C, 0x33, 0xCC; "register C")] #[test_case(0xAA, 0xFF, register::SingleEightBit::D, 0xCC, 0x33; "register D")] #[test_case(0xAB, 0xFF, register::SingleEightBit::E, 0x33, 0xCC; "register E")] #[test_case(0xAC, 0xFF, register::SingleEightBit::H, 0xCC, 0x33; "register H")] #[test_case(0xAD, 0xFF, register::SingleEightBit::L, 0x33, 0xCC; "register L")] fn test_xor_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 .set_single_8bit_register(register::SingleEightBit::A, a_value); processor .registers .set_single_8bit_register(operand_register, operand); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!(expected_value, processor.registers.a); } #[test_matrix( [ (0xA8, register::SingleEightBit::B), (0xA9, register::SingleEightBit::C), (0xAA, register::SingleEightBit::D), (0xAB, register::SingleEightBit::E), (0xAC, register::SingleEightBit::H), (0xAD, register::SingleEightBit::L), ], [ (0xFF, 0xCC, 0), (0xCC, 0xCC, 1), ] )] fn test_xor_register_with_a_flags( (opcode, operand_register): (u8, register::SingleEightBit), (a_value, operand, expected_zero_flag): (u8, u8, 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, 0, 0)); processor.registers.a = a_value; processor .registers .set_single_8bit_register(operand_register, operand); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, expected_zero_flag), (register::Flag::Subtract, 0), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test] fn test_xor_register_a_with_itself_value() { let mut processor = Processor::default(); processor.registers.a = 0x45; let data = [0xAF, 0x01]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x01]); processor.run_instruction(ins); assert_eq!(0, processor.registers.a); } #[test] fn test_xor_register_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, (1, 0, 0, 0)); processor.registers.a = 0x45; let data = [0xAF, 0x01]; let (ins, extra_data) = Instruction::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, 1), (register::Flag::Subtract, 0), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test] fn test_xor_hl_value_with_a_value() { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xEE); processor .registers .set_combined_register(register::Combined::HL, 0xFF00); processor .memory .set(0xFF00, 0xBB) .expect("failed to set memory value"); let data = [0xAE, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!(0x55, processor.registers.a); } #[test_case(0xCC, 0x33, 0; "not zero")] #[test_case(0xCC, 0xCC, 1; "zero")] fn test_xor_hl_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag: u8) { let mut processor = Processor::default(); testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 0, 0)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, a_value); processor .registers .set_combined_register(register::Combined::HL, 0xFF00); processor .memory .set(0xFF00, operand) .expect("failed to set memory value"); let data = [0xAE, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, expected_zero_flag), (register::Flag::Subtract, 0), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test] fn test_xor_immediate_value_with_a_value() { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0x22); let data = [0xEE, 0xEE, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!(0xCC, processor.registers.a); } #[test_case(0xCC, 0x33, 0; "not zero")] #[test_case(0xCC, 0xCC, 1; "zero")] fn test_xor_immediate_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag: u8) { let mut processor = Processor::default(); testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 0, 0)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, a_value); let data = [0xEE, operand, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, expected_zero_flag), (register::Flag::Subtract, 0), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test_matrix( [ (0xB0, register::SingleEightBit:: B), (0xB1, register::SingleEightBit:: C), (0xB2, register::SingleEightBit:: D), (0xB3, register::SingleEightBit:: E), (0xB4, register::SingleEightBit:: H), (0xB5, register::SingleEightBit:: L), ], [ (0xCC, 0x11, 0xDD), (0x00, 0x1F, 0x1F) ] )] fn test_or_register_with_a_value( (opcode, operand_register): (u8, register::SingleEightBit), (a_value, operand, expected_value): (u8, u8, u8), ) { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, a_value); processor .registers .set_single_8bit_register(operand_register, operand); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!(expected_value, processor.registers.a); } #[test_matrix( [ (0xB0, register::SingleEightBit::B), (0xB1, register::SingleEightBit::C), (0xB2, register::SingleEightBit::D), (0xB3, register::SingleEightBit::E), (0xB4, register::SingleEightBit::H), (0xB5, register::SingleEightBit::L), ], [ (0xCC, 0x22, 0), (0x00, 0x00, 1), ] )] fn test_or_register_with_a_flags( (opcode, operand_register): (u8, register::SingleEightBit), (a_value, operand, expected_zero_flag): (u8, u8, 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, 0, 0)); processor.registers.a = a_value; processor .registers .set_single_8bit_register(operand_register, operand); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, expected_zero_flag), (register::Flag::Subtract, 0), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test] fn test_or_register_a_with_itself_value() { let mut processor = Processor::default(); processor.registers.a = 0x45; let data = [0xB7, 0x01]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x01]); processor.run_instruction(ins); assert_eq!(0x45, processor.registers.a); } #[test_case(0xCC, 0)] #[test_case(0x00, 1)] fn test_or_register_a_with_itself_flags(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, 0, 0)); processor.registers.a = operand; let data = [0xB7, 0x01]; let (ins, extra_data) = Instruction::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, 0), (register::Flag::Carry, 0), ); } #[test] fn test_or_hl_value_with_a_value() { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0x11); processor .registers .set_combined_register(register::Combined::HL, 0xFF00); processor .memory .set(0xFF00, 0xAA) .expect("failed to set memory value"); let data = [0xB6, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!(0xBB, processor.registers.a); } #[test_case(0xBB, 0x11, 0)] #[test_case(0x00, 0x00, 1)] fn test_or_hl_value_with_a_flags(a_value: u8, hl_value: 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, 0, 0)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, a_value); processor .registers .set_combined_register(register::Combined::HL, 0xFF00); processor .memory .set(0xFF00, hl_value) .expect("failed to set memory value"); let data = [0xB7, 0x01]; let (ins, extra_data) = Instruction::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, 0), (register::Flag::Carry, 0), ); } #[test] fn test_or_immediate_value_with_a_value() { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0x33); let data = [0xF6, 0xAA, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!(0xBB, processor.registers.a); } #[test_case(0xFF, 0x00, 0; "not zero")] #[test_case(0x00, 0x00, 1; "zero")] fn test_or_immediate_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag: u8) { let mut processor = Processor::default(); testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 0, 0)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, a_value); let data = [0xF6, operand, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, expected_zero_flag), (register::Flag::Subtract, 0), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test_case(0xB8, register::SingleEightBit::B)] #[test_case(0xB9, register::SingleEightBit::C)] #[test_case(0xBA, register::SingleEightBit::D)] #[test_case(0xBB, register::SingleEightBit::E)] #[test_case(0xBC, register::SingleEightBit::H)] #[test_case(0xBD, register::SingleEightBit::L)] fn test_compare_register_instructions_do_not_modify_register_values( opcode: u8, register: register::SingleEightBit, ) { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xFF); processor.registers.set_single_8bit_register(register, 0x22); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!( 0xFF, processor .registers .get_single_8bit_register(register::SingleEightBit::A) ); assert_eq!(0x22, processor.registers.get_single_8bit_register(register)); } #[test] fn test_compare_register_with_itself_does_not_modify_value() { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xFF); let data = [0xBF, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!( 0xFF, processor .registers .get_single_8bit_register(register::SingleEightBit::A) ); } #[test_case(0xB8, register::SingleEightBit::B)] #[test_case(0xB9, register::SingleEightBit::C)] #[test_case(0xBA, register::SingleEightBit::D)] #[test_case(0xBB, register::SingleEightBit::E)] #[test_case(0xBC, register::SingleEightBit::H)] #[test_case(0xBD, register::SingleEightBit::L)] #[test_case(0xBF, register::SingleEightBit::A)] fn test_comparing_equal_values_between_registers_sets_zero_flag( opcode: u8, register: register::SingleEightBit, ) { 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, (1, 1, 0, 0)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xFF); processor.registers.set_single_8bit_register(register, 0xFF); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!( 0xFF, processor .registers .get_single_8bit_register(register::SingleEightBit::A) ); testutil::assert_flags_eq!( processor, (register::Flag::Zero, 1), (register::Flag::Subtract, 1), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test_case(0xB8, register::SingleEightBit::B)] #[test_case(0xB9, register::SingleEightBit::C)] #[test_case(0xBA, register::SingleEightBit::D)] #[test_case(0xBB, register::SingleEightBit::E)] #[test_case(0xBC, register::SingleEightBit::H)] #[test_case(0xBD, register::SingleEightBit::L)] fn test_comparing_extremely_less_than_values_between_registers_should_set_no_flags( opcode: u8, register: register::SingleEightBit, ) { 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, 1, 0, 0)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xFF); processor.registers.set_single_8bit_register(register, 0x01); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, 0), (register::Flag::Subtract, 1), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 0), ); } #[test_case(0xB8, register::SingleEightBit::B)] #[test_case(0xB9, register::SingleEightBit::C)] #[test_case(0xBA, register::SingleEightBit::D)] #[test_case(0xBB, register::SingleEightBit::E)] #[test_case(0xBC, register::SingleEightBit::H)] #[test_case(0xBD, register::SingleEightBit::L)] fn test_comparing_extremely_somewhat_less_than_values_between_registers_should_set_half_carry_flag( opcode: u8, register: register::SingleEightBit, ) { 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, 1, 1, 0)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xFE); processor.registers.set_single_8bit_register(register, 0x1F); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, 0), (register::Flag::Subtract, 1), (register::Flag::HalfCarry, 1), (register::Flag::Carry, 0), ); } #[test_case(0xB8, register::SingleEightBit::B)] #[test_case(0xB9, register::SingleEightBit::C)] #[test_case(0xBA, register::SingleEightBit::D)] #[test_case(0xBB, register::SingleEightBit::E)] #[test_case(0xBC, register::SingleEightBit::H)] #[test_case(0xBD, register::SingleEightBit::L)] fn test_comparing_greater_than_values_between_registers_should_set_carry_flag( opcode: u8, register: register::SingleEightBit, ) { 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, 1, 0, 1)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0x1F); processor.registers.set_single_8bit_register(register, 0xFF); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, 0), (register::Flag::Subtract, 1), (register::Flag::HalfCarry, 0), (register::Flag::Carry, 1), ); } #[test_case(0xB8, register::SingleEightBit::B)] #[test_case(0xB9, register::SingleEightBit::C)] #[test_case(0xBA, register::SingleEightBit::D)] #[test_case(0xBB, register::SingleEightBit::E)] #[test_case(0xBC, register::SingleEightBit::H)] #[test_case(0xBD, register::SingleEightBit::L)] fn test_comparing_lower_nibble_greater_than_values_between_registers_should_set_carry_and_half_carry_flag( opcode: u8, register: register::SingleEightBit, ) { 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, 1, 1, 1)); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0x1E); processor.registers.set_single_8bit_register(register, 0x2F); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, 0), (register::Flag::Subtract, 1), (register::Flag::HalfCarry, 1), (register::Flag::Carry, 1), ); } #[test] fn test_comparing_hl_value_to_a_does_not_change_value() { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xFF); processor .registers .set_combined_register(register::Combined::HL, 0xFF00); processor .memory .set(0xFF00, 0x11) .expect("failde to set value"); let data = [0xBE, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!( 0xFF, processor .registers .get_single_8bit_register(register::SingleEightBit::A) ); } #[test_case(0xFF, 0xFF, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "equal values sets zero flag")] #[test_case(0xFF, 0x01, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "very less value sets no flags")] #[test_case(0xFC, 0x1F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "somewhat less value sets half carry")] #[test_case(0x1F, 0xFC, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "greater value sets carry")] #[test_case(0x1C, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "greater lower nibble value sets half carry")] fn test_comparing_hl_value_to_a(a_value: u8, operand: u8, expected_flags: AdditionOperationFlags) { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, a_value); processor .registers .set_combined_register(register::Combined::HL, 0xFF00); processor .memory .set(0xFF00, 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_flags.zero, 1, expected_flags.half_carry, expected_flags.carry, ), ); let data = [0xBE, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); 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_comparing_immediate_value_to_a_does_not_change_value() { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::A, 0xFF); let data = [0xFE, 0xBB, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!( 0xFF, processor .registers .get_single_8bit_register(register::SingleEightBit::A) ); } #[test_case(0xFF, 0xFF, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "equal values sets zero flag")] #[test_case(0xFF, 0x01, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "very less value sets no flags")] #[test_case(0xFC, 0x1F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "somewhat less value sets half carry")] #[test_case(0x1F, 0xFC, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "greater value sets carry")] #[test_case(0x1C, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "greater lower nibble value sets half carry")] fn test_comparing_immediate_value_to_a( a_value: u8, operand: u8, expected_flags: AdditionOperationFlags, ) { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register::SingleEightBit::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, 1, expected_flags.half_carry, expected_flags.carry, ), ); let data = [0xFE, operand, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); 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), ); } // increment #[test_matrix( [ (0x04, register::SingleEightBit:: B), (0x0C, register::SingleEightBit:: C), (0x14, register::SingleEightBit:: D), (0x1C, register::SingleEightBit:: E), (0x24, register::SingleEightBit:: H), (0x2C, register::SingleEightBit:: L), (0x3C, register::SingleEightBit:: A), ], [ (0x05, 0x06), (0xFF, 0x00), ] )] // decrement #[test_matrix( [ (0x05, register::SingleEightBit:: B), (0x0D, register::SingleEightBit:: C), (0x15, register::SingleEightBit:: D), (0x1D, register::SingleEightBit:: E), (0x25, register::SingleEightBit:: H), (0x2D, register::SingleEightBit:: L), (0x3D, register::SingleEightBit:: A), ], [ (0x05, 0x04), (0x00, 0xFF), ] )] fn test_increment_decrement_single_register_value( (opcode, register): (u8, register::SingleEightBit), (initial_value, expected_value): (u8, u8), ) { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register, initial_value); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!( expected_value, processor.registers.get_single_8bit_register(register) ); } #[test_matrix( [ (0x04, register::SingleEightBit::B), (0x0C, register::SingleEightBit::C), (0x14, register::SingleEightBit::D), (0x1C, register::SingleEightBit::E), (0x24, register::SingleEightBit::H), (0x2C, register::SingleEightBit::L), (0x3C, register::SingleEightBit::A), ], [ (0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 0}), (0xFF, IncrementOperationFlags { zero: 1, half_carry: 1, subtract: 0}), (0x0F, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 0}), ] )] #[test_matrix( [ (0x05, register::SingleEightBit::B), (0x0D, register::SingleEightBit::C), (0x15, register::SingleEightBit::D), (0x1D, register::SingleEightBit::E), (0x25, register::SingleEightBit::H), (0x2D, register::SingleEightBit::L), (0x3D, register::SingleEightBit::A), ], [ (0x05, IncrementOperationFlags { zero: 0, half_carry: 0, subtract: 1}), (0x01, IncrementOperationFlags { zero: 1, half_carry: 0, subtract: 1}), (0x10, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}), (0x00, IncrementOperationFlags { zero: 0, half_carry: 1, subtract: 1}), ] )] fn test_increment_decrement_single_register_flags( (opcode, register): (u8, register::SingleEightBit), (initial_value, expected_flags): (u8, IncrementOperationFlags), ) { let mut processor = Processor::default(); processor .registers .set_single_8bit_register(register, 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, expected_flags.subtract, expected_flags.half_carry, // Carry flag should remain unchanged - quick lazy hack to just set this to 1. 0, ), ); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, expected_flags.zero), (register::Flag::Subtract, expected_flags.subtract), (register::Flag::HalfCarry, expected_flags.half_carry), // Carry flag should remain unchanged (register::Flag::Carry, 1), ); } #[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 .set_combined_register(register::Combined::HL, 0xFF23); processor .memory .set(0xFF23, initial_value) .expect("failed to set memory value"); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!( expected_value, processor .memory .get(0xFF23) .expect("failed to get memory value") ); } #[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 .set_combined_register(register::Combined::HL, 0xFF23); processor .memory .set(0xFF23, initial_value) .expect("failed to set memory 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, expected_flags.subtract, expected_flags.half_carry, // Carry flag should remain unchanged - quick lazy hack to just set this to 1. 0, ), ); let data = [opcode, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::Zero, expected_flags.zero), (register::Flag::Subtract, expected_flags.subtract), (register::Flag::HalfCarry, expected_flags.half_carry), // Carry flag should remain unchanged (register::Flag::Carry, 1), ); } #[test_case(0xFF00, 0x22, 0xFF22)] #[test_case(0xFF00, -0x22, 0xFEDE)] #[test_case(0x0000, -0x22, 0xFFDE)] #[test_case(0xFFFF, 0x22, 0x0021)] fn test_adjust_stack_pointer_value(initial_sp: u16, adjustment: i8, expected_sp: u16) { let mut processor = Processor::default(); processor .registers .set_single_16bit_register(register::SingleSixteenBit::StackPointer, initial_sp); let twos_comp_adjustment = adjustment.to_be_bytes()[0]; let data = [0xE8, twos_comp_adjustment, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); assert_eq!(expected_sp, processor.registers.stack_pointer); } #[test_case(0xFF00, 0x22, false, false)] #[test_case(0x04F0, -0x22, false, true; "subtraction full carry")] #[test_case(0x0022, -0x22, true, true; "even as zero, zero flags are unset")] fn test_adjust_stack_pointer(initial_sp: u16, adjustment: i8, half_carry: bool, carry: bool) { let mut processor = Processor::default(); processor .registers .set_single_16bit_register(register::SingleSixteenBit::StackPointer, initial_sp); // 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, half_carry.into(), carry.into()), ); let twos_comp_adjustment = adjustment.to_be_bytes()[0]; let data = [0xE8, twos_comp_adjustment, 0x03]; let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction"); assert_eq!(extra_data, &[0x03]); processor.run_instruction(ins); testutil::assert_flags_eq!( processor, (register::Flag::HalfCarry, u8::from(half_carry)), (register::Flag::Carry, u8::from(carry)), // Both are always zero (register::Flag::Subtract, 0), (register::Flag::Zero, 0), ); }