Clean up logic in conditional control actions
parent
d53bed716a
commit
8b088da74d
|
@ -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.
|
||||
|
|
|
@ -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,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<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> {
|
||||
let current_pc = processor
|
||||
.registers
|
||||
|
|
Loading…
Reference in New Issue