Clean up logic in conditional control actions

old-bit-manip
Nick Krichevsky 2023-11-26 21:05:42 -05:00
parent d53bed716a
commit 8b088da74d
2 changed files with 84 additions and 34 deletions

View File

@ -35,6 +35,7 @@ trait Run {
} }
/// `Cycles` represents the number of cycles an operation took /// `Cycles` represents the number of cycles an operation took
#[derive(Debug, Copy, Clone)]
pub struct Cycles(pub u8); pub struct Cycles(pub u8);
/// `run_instruction` will run the given instruction on the processor. /// `run_instruction` will run the given instruction on the processor.

View File

@ -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 { impl Run for ControlFlowInstruction {
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, super::Error> { fn run_on(&self, processor: &mut Processor) -> Result<Cycles, super::Error> {
@ -21,28 +33,30 @@ impl Run for ControlFlowInstruction {
Ok(Cycles(4)) Ok(Cycles(4))
} }
Self::JumpToImmediateIfFlagMatches { flag, value, addr } => { Self::JumpToImmediateIfFlagMatches { flag, value, addr } => run_conditional(
if processor.registers.get_flag_bit(flag) == value { processor,
jump_to(processor, addr); (flag, value),
Ok(Cycles(16)) |action_proc| jump_to(action_proc, addr),
} else { ConditionalCycles {
Ok(Cycles(12)) true_cycles: Cycles(16),
} false_cycles: Cycles(12),
} },
),
Self::Call { addr } => { Self::Call { addr } => {
do_call(processor, addr)?; do_call(processor, addr)?;
Ok(Cycles(24)) Ok(Cycles(24))
} }
Self::CallIfFlagMatches { flag, value, addr } => { Self::CallIfFlagMatches { flag, value, addr } => run_fallible_conditional(
if processor.registers.get_flag_bit(flag) == value { processor,
do_call(processor, addr)?; (flag, value),
Ok(Cycles(24)) |action_proc| do_call(action_proc, addr),
} else { ConditionalCycles {
Ok(Cycles(12)) true_cycles: Cycles(24),
} false_cycles: Cycles(12),
} },
),
Self::RestartAtAddress { addr } => { Self::RestartAtAddress { addr } => {
let current_pc = processor let current_pc = processor
@ -71,14 +85,15 @@ impl Run for ControlFlowInstruction {
Ok(Cycles(16)) Ok(Cycles(16))
} }
Self::ReturnIfFlagMatches { flag, value } => { Self::ReturnIfFlagMatches { flag, value } => run_fallible_conditional(
if processor.registers.get_flag_bit(flag) == value { processor,
return_to_popped_addr(processor)?; (flag, value),
Ok(Cycles(20)) return_to_popped_addr,
} else { ConditionalCycles {
Ok(Cycles(8)) true_cycles: Cycles(20),
} false_cycles: Cycles(8),
} },
),
Self::JumpRelative { offset } => { Self::JumpRelative { offset } => {
do_relative_jump(processor, offset); do_relative_jump(processor, offset);
@ -89,18 +104,52 @@ impl Run for ControlFlowInstruction {
flag, flag,
value, value,
offset, offset,
} => { } => run_conditional(
if processor.registers.get_flag_bit(flag) == value { processor,
do_relative_jump(processor, offset); (flag, value),
Ok(Cycles(12)) |action_proc| do_relative_jump(action_proc, offset),
} else { ConditionalCycles {
Ok(Cycles(8)) true_cycles: Cycles(12),
} false_cycles: Cycles(8),
} },
),
} }
} }
} }
fn run_fallible_conditional<F>(
processor: &mut Processor,
(flag, expected_value): (Flag, u8),
true_action: F,
cycles: ConditionalCycles,
) -> Result<Cycles, run::Error>
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<F>(
processor: &mut Processor,
flag_conditions: (Flag, u8),
true_action: F,
cycles: ConditionalCycles,
) -> Result<Cycles, run::Error>
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> { fn do_call(processor: &mut Processor, to_addr: u16) -> Result<(), super::Error> {
let current_pc = processor let current_pc = processor
.registers .registers