Simplify control flow parsing logic

old-bit-manip
Nick Krichevsky 2023-11-21 20:57:16 -05:00
parent fc76248853
commit 01cf67ca35
1 changed files with 61 additions and 78 deletions

View File

@ -1,93 +1,76 @@
use crate::{
cpu::{
instructions::{control::ControlFlowInstruction, Instruction},
parse, register,
parse,
},
memory::{GetViewTuple, View},
register::Flag,
};
use super::{OpcodeParser, ParseOutput, ParseResult};
use super::{OpcodeParser, OrParse, ParseOutput, ParseResult};
pub struct Parser;
enum ConditionalControlFlowType {
Call,
Jump,
}
impl OpcodeParser for Parser {
fn parse_opcode(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data);
match opcode {
0xC3 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediate { addr },
)),
0xCD => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::Call { addr },
)),
0xC2 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Zero,
value: 0,
addr,
},
)),
0xD2 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Carry,
value: 0,
addr,
},
)),
0xCA => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Zero,
value: 1,
addr,
},
)),
0xDA => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches {
flag: register::Flag::Carry,
value: 1,
addr,
},
)),
0xC4 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::CallIfFlagMatches {
flag: register::Flag::Zero,
value: 0,
addr,
},
)),
0xD4 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::CallIfFlagMatches {
flag: register::Flag::Carry,
value: 0,
addr,
},
)),
0xCC => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::CallIfFlagMatches {
flag: register::Flag::Zero,
value: 1,
addr,
},
)),
0xDC => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::CallIfFlagMatches {
flag: register::Flag::Carry,
value: 1,
addr,
},
)),
_ => Err(parse::Error::UnknownOpcode(opcode)),
}
parse_unconditional_control_operation(data)
.or_parse(|_opcode| parse_conditional_control_operation(data))
}
}
fn parse_unconditional_control_operation(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data);
match opcode {
0xC3 => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediate { addr },
)),
0xCD => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::Call { addr },
)),
_ => Err(parse::Error::UnknownOpcode(opcode)),
}
}
fn parse_conditional_control_operation(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data);
let (flag, value) = conditional_control_flow_flag_for_opcode(opcode)?;
let control_flow_type = conditional_control_flow_type_for_opcode(opcode)?;
match control_flow_type {
ConditionalControlFlowType::Jump => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::JumpToImmediateIfFlagMatches { flag, value, addr },
)),
ConditionalControlFlowType::Call => Ok(build_immediate_parameterized_control_flow_data(
data,
|addr| ControlFlowInstruction::CallIfFlagMatches { flag, value, addr },
)),
}
}
fn conditional_control_flow_type_for_opcode(opcode: u8) -> Result<ConditionalControlFlowType, parse::Error> {
match opcode {
0xC2 | 0xD2 | 0xCA | 0xDA => Ok(ConditionalControlFlowType::Jump),
0xC4 | 0xD4 | 0xCC | 0xDC => Ok(ConditionalControlFlowType::Call),
_ => Err(parse::Error::UnknownOpcode(opcode)),
}
}
fn conditional_control_flow_flag_for_opcode(opcode: u8) -> Result<(Flag, u8), parse::Error> {
match opcode {
0xC2 | 0xC4 => Ok((Flag::Zero, 0)),
0xD2 | 0xD4 => Ok((Flag::Carry, 0)),
0xCA | 0xCC => Ok((Flag::Zero, 1)),
0xDA | 0xDC => Ok((Flag::Carry, 1)),
_ => Err(parse::Error::UnknownOpcode(opcode)),
}
}