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
#[derive(Debug, Copy, Clone)]
pub struct Cycles(pub u8);
/// `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 {
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, super::Error> {
@ -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,16 +104,50 @@ impl Run for ControlFlowInstruction {
flag,
value,
offset,
} => {
if processor.registers.get_flag_bit(flag) == value {
do_relative_jump(processor, offset);
Ok(Cycles(12))
} => 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<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(8))
}
}
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> {