diff --git a/src/cpu/run/load16.rs b/src/cpu/run/load16.rs index c7f1d01..c4797fd 100644 --- a/src/cpu/run/load16.rs +++ b/src/cpu/run/load16.rs @@ -110,6 +110,7 @@ impl InstructionRunner for SixteenBitLoadRunner { ]; let popped_value = u16::from_le_bytes(popped_bytes); + println!("{popped_value:x}"); processor.registers.set_combined_register(dst, popped_value); processor.registers.set_16bit_register( diff --git a/src/register.rs b/src/register.rs index 796468b..3fb33f5 100644 --- a/src/register.rs +++ b/src/register.rs @@ -210,7 +210,12 @@ impl Registers { let [left_value, right_value] = value.to_be_bytes(); *left_register = left_value; - *right_register = right_value; + if let Combined::AF = registers { + // Special case: the lower 4 bits of F can _NEVER_ be set. + *right_register = right_value & 0xF0; + } else { + *right_register = right_value; + } } // TODO: These two could be simplified with macros @@ -258,12 +263,12 @@ mod tests { #[test_case(Combined::HL)] fn test_combined_registers(registers: Combined) { let mut register = Registers::new(); - register.set_combined_register(registers, 0xF0_0F); + register.set_combined_register(registers, 0xF0_40); let stored_value = register.get_combined_register(registers); assert_eq!( - 0xF0_0F, stored_value, - "got {stored_value:0x}, expected 0xF0_0F" + 0xF0_40, stored_value, + "got {stored_value:0x}, expected 0xF0_40" ); } @@ -322,7 +327,6 @@ mod tests { ); } - #[test_case(Combined::AF)] #[test_case(Combined::BC)] #[test_case(Combined::DE)] #[test_case(Combined::HL)] @@ -333,6 +337,14 @@ mod tests { assert_eq!(0x1122, registers.get_combined_register(register)); } + #[test] + fn test_set_sixteen_bit_register_combined_zeroes_lower_4_bits_on_af() { + let mut registers = Registers::new(); + registers.set_16bit_register(SixteenBit::Combined(Combined::AF), 0x1122); + + assert_eq!(0x1120, registers.get_combined_register(Combined::AF)); + } + #[test_case(SingleSixteenBit::StackPointer)] #[test_case(SingleSixteenBit::ProgramCounter)] fn test_set_sixteen_bit_register_single(register: SingleSixteenBit) { diff --git a/tests/cpu/load16.rs b/tests/cpu/load16.rs index 0f7032e..3648f68 100644 --- a/tests/cpu/load16.rs +++ b/tests/cpu/load16.rs @@ -157,7 +157,6 @@ fn test_load_effective_address_flags(starting_sp: u16, add_value: i8, half_carry ); } -#[test_case(0xF5, register::Combined::AF)] #[test_case(0xC5, register::Combined::BC)] #[test_case(0xD5, register::Combined::DE)] #[test_case(0xE5, register::Combined::HL)] @@ -180,7 +179,26 @@ fn test_stack_push(opcode: u8, src: register::Combined) { assert_eq!(0xFFFE - 2, processor.registers.stack_pointer); } -#[test_case(0xF1, register::Combined::AF)] +#[test] +fn test_stack_push_from_af() { + let mut processor = Processor::default(); + processor.registers.set_combined_register(register::Combined::AF, 0x1234); + processor.registers.stack_pointer = 0xFFFE; + let data = [0xF5, 0x01]; + + let (ins, extra_data) = + RunnableInstruction::from_data(&data).expect("could not parse instruction"); + + assert_eq!(extra_data, &[0x01]); + processor.run_instruction(&ins); + + // we want to pop the LSB first (i.e. we write the MSB first) + // https://rgbds.gbdev.io/docs/v0.5.2/gbz80.7#PUSH_r16 + assert_eq!(0x12, processor.memory.get(0xFFFE - 1).unwrap()); + assert_eq!(0x30, processor.memory.get(0xFFFE - 2).unwrap()); + assert_eq!(0xFFFE - 2, processor.registers.stack_pointer); +} + #[test_case(0xC1, register::Combined::BC)] #[test_case(0xD1, register::Combined::DE)] #[test_case(0xE1, register::Combined::HL)] @@ -202,3 +220,23 @@ fn test_stack_pop(opcode: u8, dst: register::Combined) { assert_eq!(0x1234, processor.registers.get_combined_register(dst)); assert_eq!(0xFFF0 + 2, processor.registers.stack_pointer); } + +#[test] +fn test_stack_pop_to_af() { + let mut processor = Processor::default(); + processor.registers.stack_pointer = 0xFFF0; + processor + .memory + .set_both(((0xFFF0, 0x34), (0xFFF1, 0x12))) + .expect("failed to set values in memory"); + let data = [0xF1, 0x01]; + + let (ins, extra_data) = + RunnableInstruction::from_data(&data).expect("could not parse instruction"); + + assert_eq!(extra_data, &[0x01]); + processor.run_instruction(&ins); + + assert_eq!(0x1230, processor.registers.get_combined_register(register::Combined::AF)); + assert_eq!(0xFFF0 + 2, processor.registers.stack_pointer); +}