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
|
/// `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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue