diff --git a/src/cpu/run.rs b/src/cpu/run.rs index 0b27321..e46154a 100644 --- a/src/cpu/run.rs +++ b/src/cpu/run.rs @@ -35,6 +35,7 @@ trait Run { } /// `Cycles` represents the number of cycles an operation took +#[derive(Debug, Copy, Clone)] pub struct Cycles(pub u8); /// `run_instruction` will run the given instruction on the processor. diff --git a/src/cpu/run/control.rs b/src/cpu/run/control.rs index 96a0cda..096be66 100644 --- a/src/cpu/run/control.rs +++ b/src/cpu/run/control.rs @@ -1,6 +1,18 @@ -use crate::cpu::{instructions::control::ControlFlowInstruction, register, Processor}; +use crate::{ + cpu::{ + instructions::control::ControlFlowInstruction, + register, + run::{self, arithutil::CarryingAdd, Cycles, Run}, + Processor, + }, + register::Flag, +}; -use super::{arithutil::CarryingAdd, Cycles, Run}; +#[derive(Debug, Copy, Clone)] +struct ConditionalCycles { + true_cycles: Cycles, + false_cycles: Cycles, +} impl Run for ControlFlowInstruction { fn run_on(&self, processor: &mut Processor) -> Result { @@ -21,28 +33,30 @@ impl Run for ControlFlowInstruction { Ok(Cycles(4)) } - Self::JumpToImmediateIfFlagMatches { flag, value, addr } => { - if processor.registers.get_flag_bit(flag) == value { - jump_to(processor, addr); - Ok(Cycles(16)) - } else { - Ok(Cycles(12)) - } - } + Self::JumpToImmediateIfFlagMatches { flag, value, addr } => run_conditional( + processor, + (flag, value), + |action_proc| jump_to(action_proc, addr), + ConditionalCycles { + true_cycles: Cycles(16), + false_cycles: Cycles(12), + }, + ), Self::Call { addr } => { do_call(processor, addr)?; Ok(Cycles(24)) } - Self::CallIfFlagMatches { flag, value, addr } => { - if processor.registers.get_flag_bit(flag) == value { - do_call(processor, addr)?; - Ok(Cycles(24)) - } else { - Ok(Cycles(12)) - } - } + Self::CallIfFlagMatches { flag, value, addr } => run_fallible_conditional( + processor, + (flag, value), + |action_proc| do_call(action_proc, addr), + ConditionalCycles { + true_cycles: Cycles(24), + false_cycles: Cycles(12), + }, + ), Self::RestartAtAddress { addr } => { let current_pc = processor @@ -71,14 +85,15 @@ impl Run for ControlFlowInstruction { Ok(Cycles(16)) } - Self::ReturnIfFlagMatches { flag, value } => { - if processor.registers.get_flag_bit(flag) == value { - return_to_popped_addr(processor)?; - Ok(Cycles(20)) - } else { - Ok(Cycles(8)) - } - } + Self::ReturnIfFlagMatches { flag, value } => run_fallible_conditional( + processor, + (flag, value), + return_to_popped_addr, + ConditionalCycles { + true_cycles: Cycles(20), + false_cycles: Cycles(8), + }, + ), Self::JumpRelative { offset } => { do_relative_jump(processor, offset); @@ -89,18 +104,52 @@ impl Run for ControlFlowInstruction { flag, value, offset, - } => { - if processor.registers.get_flag_bit(flag) == value { - do_relative_jump(processor, offset); - Ok(Cycles(12)) - } else { - Ok(Cycles(8)) - } - } + } => run_conditional( + processor, + (flag, value), + |action_proc| do_relative_jump(action_proc, offset), + ConditionalCycles { + true_cycles: Cycles(12), + false_cycles: Cycles(8), + }, + ), } } } +fn run_fallible_conditional( + processor: &mut Processor, + (flag, expected_value): (Flag, u8), + true_action: F, + cycles: ConditionalCycles, +) -> Result +where + F: Fn(&mut Processor) -> Result<(), run::Error>, +{ + if processor.registers.get_flag_bit(flag) == expected_value { + true_action(processor).map(|_void| cycles.true_cycles) + } else { + Ok(cycles.false_cycles) + } +} + +fn run_conditional( + processor: &mut Processor, + flag_conditions: (Flag, u8), + true_action: F, + cycles: ConditionalCycles, +) -> Result +where + F: Fn(&mut Processor), +{ + let succeeding_action = |action_proc: &mut Processor| { + true_action(action_proc); + Ok(()) + }; + + run_fallible_conditional(processor, flag_conditions, succeeding_action, cycles) +} + fn do_call(processor: &mut Processor, to_addr: u16) -> Result<(), super::Error> { let current_pc = processor .registers