diff --git a/src/cpu/parse/control.rs b/src/cpu/parse/control.rs index e731ef5..042130e 100644 --- a/src/cpu/parse/control.rs +++ b/src/cpu/parse/control.rs @@ -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 { + 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)), } }