Add conditional jumps

old-bit-manip
Nick Krichevsky 2023-11-21 20:06:24 -05:00
parent a5e838dda4
commit 827aef74f8
8 changed files with 58 additions and 2 deletions

View File

@ -14,4 +14,9 @@ pub enum ControlFlowInstruction {
value: u8, value: u8,
addr: u16, addr: u16,
}, },
JumpToImmediateIfFlagMatches {
flag: register::Flag,
value: u8,
addr: u16,
},
} }

View File

@ -22,6 +22,38 @@ impl OpcodeParser for Parser {
data, data,
|addr| ControlFlowInstruction::Call { addr }, |addr| ControlFlowInstruction::Call { addr },
)), )),
0xC2 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Zero,
value: 0,
addr,
},
)),
0xD2 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Carry,
value: 0,
addr,
},
)),
0xCA => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Zero,
value: 1,
addr,
},
)),
0xDA => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Carry,
value: 1,
addr,
},
)),
0xC4 => Ok(build_immediate_parameterized_control_flow_data( 0xC4 => Ok(build_immediate_parameterized_control_flow_data(
data, data,
|addr| ControlFlowInstruction::CallIfFlagMatches { |addr| ControlFlowInstruction::CallIfFlagMatches {

View File

@ -12,6 +12,17 @@ impl Run for ControlFlowInstruction {
Ok(Cycles(16)) Ok(Cycles(16))
} }
Self::JumpToImmediateIfFlagMatches { flag, value, addr } => {
if processor.registers.get_flag_bit(flag) == value {
processor.registers.set_single_16bit_register(
register::SingleSixteenBit::ProgramCounter,
addr,
);
Ok(Cycles(16))
} else {
Ok(Cycles(12))
}
}
Self::Call { addr } => { Self::Call { addr } => {
do_call(processor, addr)?; do_call(processor, addr)?;
Ok(Cycles(24)) Ok(Cycles(24))

View File

@ -56,7 +56,11 @@ fn test_call_pushes_pc_onto_stack() {
#[test_case(0xDC, Flag::Carry, 1; "CALL C")] #[test_case(0xDC, Flag::Carry, 1; "CALL C")]
#[test_case(0xC4, Flag::Zero, 0; "CALL NZ")] #[test_case(0xC4, Flag::Zero, 0; "CALL NZ")]
#[test_case(0xD4, Flag::Carry, 0; "CALL NC")] #[test_case(0xD4, Flag::Carry, 0; "CALL NC")]
fn test_call_jumps_if_condition_matches(opcode: u8, flag: Flag, expected_value: u8) { #[test_case(0xCA, Flag::Zero, 1; "JP Z")]
#[test_case(0xDA, Flag::Carry, 1; "JP C")]
#[test_case(0xC2, Flag::Zero, 0; "JP NZ")]
#[test_case(0xD2, Flag::Carry, 0; "JP NC")]
fn test_call_and_jump_jumps_if_condition_matches(opcode: u8, flag: Flag, expected_value: u8) {
let mut processor = Processor::default(); let mut processor = Processor::default();
processor.registers.set_flag_bit(flag, expected_value); processor.registers.set_flag_bit(flag, expected_value);
@ -93,7 +97,11 @@ fn test_call_grows_stack_if_condition_matches(opcode: u8, flag: Flag, expected_v
#[test_case(0xDC, Flag::Carry, 1; "CALL C")] #[test_case(0xDC, Flag::Carry, 1; "CALL C")]
#[test_case(0xC4, Flag::Zero, 0; "CALL NZ")] #[test_case(0xC4, Flag::Zero, 0; "CALL NZ")]
#[test_case(0xD4, Flag::Carry, 0; "CALL NC")] #[test_case(0xD4, Flag::Carry, 0; "CALL NC")]
fn test_call_does_nothing_if_condition_fails(opcode: u8, flag: Flag, expected_value: u8) { #[test_case(0xCA, Flag::Zero, 1; "JP Z")]
#[test_case(0xDA, Flag::Carry, 1; "JP C")]
#[test_case(0xC2, Flag::Zero, 0; "JP NZ")]
#[test_case(0xD2, Flag::Carry, 0; "JP NC")]
fn test_call_and_jump_does_nothing_if_condition_fails(opcode: u8, flag: Flag, expected_value: u8) {
let mut processor = Processor::default(); let mut processor = Processor::default();
processor processor
.registers .registers