From f647919ae0658ea1b910e7da070fdf93cf0cc007 Mon Sep 17 00:00:00 2001 From: Nick Krichevsky Date: Wed, 6 Dec 2023 20:28:59 -0500 Subject: [PATCH] Implement SWAP r8 instructions --- src/cpu/instructions/manip.rs | 3 + src/cpu/parse/manip.rs | 16 +++++ src/cpu/run/manip.rs | 52 +++++++++++++++- .../jsmoo/testdata/{disabled => }/cb 30.json | 0 .../jsmoo/testdata/{disabled => }/cb 31.json | 0 .../jsmoo/testdata/{disabled => }/cb 32.json | 0 .../jsmoo/testdata/{disabled => }/cb 33.json | 0 .../jsmoo/testdata/{disabled => }/cb 34.json | 0 .../jsmoo/testdata/{disabled => }/cb 35.json | 0 .../jsmoo/testdata/{disabled => }/cb 37.json | 0 tests/cpu/manip.rs | 60 +++++++++++++++++++ 11 files changed, 128 insertions(+), 3 deletions(-) rename tests/cpu/jsmoo/testdata/{disabled => }/cb 30.json (100%) rename tests/cpu/jsmoo/testdata/{disabled => }/cb 31.json (100%) rename tests/cpu/jsmoo/testdata/{disabled => }/cb 32.json (100%) rename tests/cpu/jsmoo/testdata/{disabled => }/cb 33.json (100%) rename tests/cpu/jsmoo/testdata/{disabled => }/cb 34.json (100%) rename tests/cpu/jsmoo/testdata/{disabled => }/cb 35.json (100%) rename tests/cpu/jsmoo/testdata/{disabled => }/cb 37.json (100%) diff --git a/src/cpu/instructions/manip.rs b/src/cpu/instructions/manip.rs index 23981fd..ba7a266 100644 --- a/src/cpu/instructions/manip.rs +++ b/src/cpu/instructions/manip.rs @@ -23,4 +23,7 @@ pub enum BitManipulationInstruction { operand: Operand, bit: u8, }, + SwapNibbles { + operand: Operand, + }, } diff --git a/src/cpu/parse/manip.rs b/src/cpu/parse/manip.rs index 778ee70..2d445b0 100644 --- a/src/cpu/parse/manip.rs +++ b/src/cpu/parse/manip.rs @@ -22,6 +22,7 @@ impl OpcodeParser for Parser { parse_set_opcode(opcode) .or_parse(parse_clear_opcode) .or_parse(parse_bit_test_opcode) + .or_parse(parse_swap_opcode) } } @@ -40,6 +41,21 @@ fn parse_bit_test_opcode(opcode: Opcode) -> ParseResult { Ok((Instruction::BitManipulation(ins), 2)) } +fn parse_swap_opcode(opcode: Opcode) -> ParseResult { + let Opcode::SixteenBit(sixteen_bit_opcode) = opcode else { + return Err(parse::Error::UnknownOpcode(opcode)); + }; + + if !(0xCB_30..=0xCB_37).contains(&sixteen_bit_opcode) { + return Err(parse::Error::UnknownOpcode(opcode)); + } + + let operand = operand_for_opcode(sixteen_bit_opcode)?; + let ins = BitManipulationInstruction::SwapNibbles { operand }; + + Ok((Instruction::BitManipulation(ins), 2)) +} + fn parse_individual_bit_operation( opcode: Opcode, operation: IndividualBitOperation, diff --git a/src/cpu/run/manip.rs b/src/cpu/run/manip.rs index 9b4f620..1852342 100644 --- a/src/cpu/run/manip.rs +++ b/src/cpu/run/manip.rs @@ -38,7 +38,7 @@ impl Run for BitManipulationInstruction { operand: Operand::Register(register), bit, } => { - set_test_flag_bits(processor, Operand::Register(register), bit)?; + test_bit_and_set_flags(processor, Operand::Register(register), bit)?; Ok(Cycles(8)) } @@ -47,10 +47,21 @@ impl Run for BitManipulationInstruction { operand: Operand::HLValue, bit, } => { - set_test_flag_bits(processor, Operand::HLValue, bit)?; + test_bit_and_set_flags(processor, Operand::HLValue, bit)?; Ok(Cycles(12)) } + + BitManipulationInstruction::SwapNibbles { + operand: Operand::Register(register), + } => { + transform_register_value(processor, register, swap_nibbles); + set_zero_flag_after_swap(processor, register); + + Ok(Cycles(8)) + } + + _ => todo!(), } } } @@ -75,6 +86,13 @@ fn clear_nth_bit(value: u8, bit: u8) -> u8 { value & clear_mask } +fn swap_nibbles(value: u8) -> u8 { + let top = value & 0xF0; + let bottom = value & 0x0F; + + (top >> 4) | (bottom << 4) +} + fn transform_register_value u8>( processor: &mut Processor, register: SingleEightBit, @@ -125,7 +143,22 @@ fn transform_hl_value u8>( Ok(()) } -fn set_test_flag_bits( +fn set_zero_flag_after_swap(processor: &mut Processor, register: register::SingleEightBit) { + let value = processor.registers.get_single_8bit_register(register); + // Clear all flags + processor + .registers + .set_raw_flag_bits(0x00) + .expect("lower four bits of register aren't set"); + + if value == 0 { + processor.registers.set_flag_bit(register::Flag::Zero, 1); + } else { + processor.registers.set_flag_bit(register::Flag::Zero, 0); + } +} + +fn test_bit_and_set_flags( processor: &mut Processor, operand: Operand, bit: u8, @@ -174,3 +207,16 @@ fn get_operand_value(processor: &mut Processor, operand: Operand) -> Result