diff --git a/src/cpu/parse.rs b/src/cpu/parse.rs index 61e5830..db94ee2 100644 --- a/src/cpu/parse.rs +++ b/src/cpu/parse.rs @@ -11,13 +11,14 @@ mod control; mod load16; mod load8; mod misc; +mod unparsed; #[derive(Error, Debug, Clone)] pub enum Error { #[error("given empty data to parse opcode from")] NoData, #[error("unknown opcode 0x{0:X}")] - UnknownOpcode(u8), + UnknownOpcode(unparsed::Opcode), #[error("not enough arguments provided for opcode 0x{0:X}")] NotEnoughArgs(u8), } @@ -37,11 +38,17 @@ trait OpcodeParser { trait OrParse { /// If the current parse failed to parse the given opcode (i.e. this is Err(UnknownOpcode)), attempt to /// parse again with the given parse function. Otherwise, this result itself is returned. - fn or_parse Result>(self, parse_func: F) -> Result; + fn or_parse Result>( + self, + parse_func: F, + ) -> Result; } impl OrParse for Result { - fn or_parse Result>(self, parse_func: F) -> Result { + fn or_parse Result>( + self, + parse_func: F, + ) -> Result { if let Err(Error::UnknownOpcode(opcode)) = self { parse_func(opcode) } else { @@ -74,10 +81,11 @@ pub fn next_instruction(data: &View) -> ParseResult { } } + // TODO: support 16bit, too let opcode = get_opcode_from_data(data); Err(Error::UnknownOpcode(opcode)) } -fn get_opcode_from_data(data: &View) -> u8 { - data.get() +fn get_opcode_from_data(data: &View) -> unparsed::Opcode { + unparsed::Opcode::EightBit(data.get()) } diff --git a/src/cpu/parse/arith16.rs b/src/cpu/parse/arith16.rs index c2352c3..f51f5fb 100644 --- a/src/cpu/parse/arith16.rs +++ b/src/cpu/parse/arith16.rs @@ -8,7 +8,7 @@ use crate::{ memory::View, }; -use super::ParseOutput; +use super::{unparsed, ParseOutput}; pub struct Parser; @@ -16,32 +16,45 @@ impl OpcodeParser for Parser { fn parse_opcode(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x09 => Ok(build_add_hl_to_register_data(SixteenBit::Combined( - Combined::BC, - ))), - 0x19 => Ok(build_add_hl_to_register_data(SixteenBit::Combined( - Combined::DE, - ))), - 0x29 => Ok(build_add_hl_to_register_data(SixteenBit::Combined( - Combined::HL, - ))), - 0x39 => Ok(build_add_hl_to_register_data(SixteenBit::Single( + unparsed::Opcode::EightBit(0x09) => Ok(build_add_hl_to_register_data( + SixteenBit::Combined(Combined::BC), + )), + unparsed::Opcode::EightBit(0x19) => Ok(build_add_hl_to_register_data( + SixteenBit::Combined(Combined::DE), + )), + unparsed::Opcode::EightBit(0x29) => Ok(build_add_hl_to_register_data( + SixteenBit::Combined(Combined::HL), + )), + unparsed::Opcode::EightBit(0x39) => Ok(build_add_hl_to_register_data( + SixteenBit::Single(SingleSixteenBit::StackPointer), + )), + + unparsed::Opcode::EightBit(0x03) => { + Ok(build_inc_register_data(SixteenBit::Combined(Combined::BC))) + } + unparsed::Opcode::EightBit(0x13) => { + Ok(build_inc_register_data(SixteenBit::Combined(Combined::DE))) + } + unparsed::Opcode::EightBit(0x23) => { + Ok(build_inc_register_data(SixteenBit::Combined(Combined::HL))) + } + unparsed::Opcode::EightBit(0x33) => Ok(build_inc_register_data(SixteenBit::Single( SingleSixteenBit::StackPointer, ))), - 0x03 => Ok(build_inc_register_data(SixteenBit::Combined(Combined::BC))), - 0x13 => Ok(build_inc_register_data(SixteenBit::Combined(Combined::DE))), - 0x23 => Ok(build_inc_register_data(SixteenBit::Combined(Combined::HL))), - 0x33 => Ok(build_inc_register_data(SixteenBit::Single( + unparsed::Opcode::EightBit(0x0B) => { + Ok(build_dec_register_data(SixteenBit::Combined(Combined::BC))) + } + unparsed::Opcode::EightBit(0x1B) => { + Ok(build_dec_register_data(SixteenBit::Combined(Combined::DE))) + } + unparsed::Opcode::EightBit(0x2B) => { + Ok(build_dec_register_data(SixteenBit::Combined(Combined::HL))) + } + unparsed::Opcode::EightBit(0x3B) => Ok(build_dec_register_data(SixteenBit::Single( SingleSixteenBit::StackPointer, ))), - 0x0B => Ok(build_dec_register_data(SixteenBit::Combined(Combined::BC))), - 0x1B => Ok(build_dec_register_data(SixteenBit::Combined(Combined::DE))), - 0x2B => Ok(build_dec_register_data(SixteenBit::Combined(Combined::HL))), - 0x3B => Ok(build_dec_register_data(SixteenBit::Single( - SingleSixteenBit::StackPointer, - ))), _ => Err(Error::UnknownOpcode(opcode)), } } diff --git a/src/cpu/parse/arith8.rs b/src/cpu/parse/arith8.rs index 69b19e0..5ef86b1 100644 --- a/src/cpu/parse/arith8.rs +++ b/src/cpu/parse/arith8.rs @@ -9,7 +9,7 @@ use crate::{ register, }; -use super::{OpcodeParser, OrParse, ParseOutput}; +use super::{unparsed::Opcode, OpcodeParser, OrParse, ParseOutput}; // similar to `arith8::Operand`, but only for the parts that can be uniquely determined from the opcode #[derive(Debug, Copy, Clone)] @@ -31,7 +31,6 @@ impl OpcodeParser for Parser { fn parse_eight_bit_arithmetic_instruction(data: &View) -> super::ParseResult { let opcode = super::get_opcode_from_data(data); - let operation = operation_for_opcode(opcode)?; let operand = operand_for_opcode(opcode)?; @@ -49,24 +48,32 @@ fn parse_eight_bit_arithmetic_instruction(data: &View) -> super::ParseResult { fn parse_stack_pointer_adjust_instruction(data: &View) -> super::ParseResult { let opcode = super::get_opcode_from_data(data); - if opcode == 0xE8 { + if opcode == Opcode::EightBit(0xE8) { Ok(build_stack_pointer_adjust_data(data)) } else { Err(super::Error::UnknownOpcode(opcode)) } } -fn operation_for_opcode(opcode: u8) -> Result { +fn operation_for_opcode(opcode: Opcode) -> Result { operation_for_binary_opcode(opcode).or_parse(operation_for_unary_opcode) } -fn operand_for_opcode(opcode: u8) -> Result { - operand_for_binary_opcode(opcode).or_else(|_err| operand_for_unary_opcode(opcode)) +fn operand_for_opcode(opcode: Opcode) -> Result { + let Opcode::EightBit(eight_bit_opcode) = opcode else { + return Err(super::Error::UnknownOpcode(opcode)); + }; + + operand_for_binary_opcode(eight_bit_opcode).or_parse(operand_for_unary_opcode) } -fn operation_for_unary_opcode(opcode: u8) -> Result { - let operation_nibble = opcode & 0xF0; - let operand_nibble = opcode & 0x0F; +fn operation_for_unary_opcode(opcode: Opcode) -> Result { + let Opcode::EightBit(eight_bit_opcode) = opcode else { + return Err(super::Error::UnknownOpcode(opcode)); + }; + + let operation_nibble = eight_bit_opcode & 0xF0; + let operand_nibble = eight_bit_opcode & 0x0F; match operation_nibble { 0x00..=0x30 if operand_nibble == 0x04 || operand_nibble == 0x0C => Ok(Operation::Inc), @@ -75,30 +82,45 @@ fn operation_for_unary_opcode(opcode: u8) -> Result { } } -fn operation_for_binary_opcode(opcode: u8) -> Result { +fn operation_for_binary_opcode(opcode: Opcode) -> Result { match opcode { - 0x80..=0x87 | 0xC6 => Ok(Operation::Add), - 0x88..=0x8F | 0xCE => Ok(Operation::AddWithCarry), - 0x90..=0x97 | 0xD6 => Ok(Operation::Sub), - 0x98..=0x9F | 0xDE => Ok(Operation::SubWithCarry), - 0xA0..=0xA7 | 0xE6 => Ok(Operation::And), - 0xA8..=0xAF | 0xEE => Ok(Operation::Xor), - 0xB0..=0xB7 | 0xF6 => Ok(Operation::Or), - 0xB8..=0xBF | 0xFE => Ok(Operation::Compare), + Opcode::EightBit(0x80..=0x87 | 0xC6) => Ok(Operation::Add), + Opcode::EightBit(0x88..=0x8F | 0xCE) => Ok(Operation::AddWithCarry), + Opcode::EightBit(0x90..=0x97 | 0xD6) => Ok(Operation::Sub), + Opcode::EightBit(0x98..=0x9F | 0xDE) => Ok(Operation::SubWithCarry), + Opcode::EightBit(0xA0..=0xA7 | 0xE6) => Ok(Operation::And), + Opcode::EightBit(0xA8..=0xAF | 0xEE) => Ok(Operation::Xor), + Opcode::EightBit(0xB0..=0xB7 | 0xF6) => Ok(Operation::Or), + Opcode::EightBit(0xB8..=0xBF | 0xFE) => Ok(Operation::Compare), + _ => Err(super::Error::UnknownOpcode(opcode)), } } -fn operand_for_unary_opcode(opcode: u8) -> Result { +fn operand_for_unary_opcode(opcode: Opcode) -> Result { match opcode { - 0x04 | 0x05 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::B)), - 0x0C | 0x0D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::C)), - 0x14 | 0x15 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::D)), - 0x1C | 0x1D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::E)), - 0x24 | 0x25 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::H)), - 0x2C | 0x2D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::L)), - 0x34 | 0x35 => Ok(OpcodeOperand::HLAddressValue), - 0x3C | 0x3D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::A)), + Opcode::EightBit(0x04 | 0x05) => { + Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::B)) + } + Opcode::EightBit(0x0C | 0x0D) => { + Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::C)) + } + Opcode::EightBit(0x14 | 0x15) => { + Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::D)) + } + Opcode::EightBit(0x1C | 0x1D) => { + Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::E)) + } + Opcode::EightBit(0x24 | 0x25) => { + Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::H)) + } + Opcode::EightBit(0x2C | 0x2D) => { + Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::L)) + } + Opcode::EightBit(0x34 | 0x35) => Ok(OpcodeOperand::HLAddressValue), + Opcode::EightBit(0x3C | 0x3D) => { + Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::A)) + } _ => Err(super::Error::UnknownOpcode(opcode)), } } @@ -109,7 +131,7 @@ fn operand_for_binary_opcode(opcode: u8) -> Result } else if !matches!(opcode & 0xF0, 0x80..=0xB0) { // If it's not an immediate operation (covered above), or a standard arith operation (covered below), // we shouldn't try and parse it - return Err(super::Error::UnknownOpcode(opcode)); + return Err(super::Error::UnknownOpcode(opcode.into())); } match opcode & 0x07 { @@ -121,7 +143,7 @@ fn operand_for_binary_opcode(opcode: u8) -> Result 0x05 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::L)), 0x06 => Ok(OpcodeOperand::HLAddressValue), 0x07 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::A)), - _ => Err(super::Error::UnknownOpcode(opcode)), + _ => Err(super::Error::UnknownOpcode(opcode.into())), } } @@ -278,7 +300,8 @@ mod tests { #[test_case(0x2D, (Operation::Dec, OpcodeOperand::SingleRegister(register::SingleEightBit::L)))] #[test_case(0x35, (Operation::Dec, OpcodeOperand::HLAddressValue))] #[test_case(0x3D, (Operation::Dec, OpcodeOperand::SingleRegister(register::SingleEightBit::A)))] - fn test_opcode_operand_and_operation(opcode: u8, expected: (Operation, OpcodeOperand)) { + fn test_opcode_operand_and_operation(raw_opcode: u8, expected: (Operation, OpcodeOperand)) { + let opcode = Opcode::EightBit(raw_opcode); let operation = operation_for_opcode(opcode).expect("could not parse"); let operand = operand_for_opcode(opcode).expect("could not parse"); diff --git a/src/cpu/parse/control.rs b/src/cpu/parse/control.rs index 05213a4..0f10edf 100644 --- a/src/cpu/parse/control.rs +++ b/src/cpu/parse/control.rs @@ -7,7 +7,7 @@ use crate::{ register::Flag, }; -use super::{OpcodeParser, OrParse, ParseOutput, ParseResult}; +use super::{unparsed::Opcode, OpcodeParser, OrParse, ParseOutput, ParseResult}; pub struct Parser; @@ -35,37 +35,45 @@ fn parse_unconditional_control_operation(data: &View) -> ParseResult { fn parse_unconditional_parameterized_control_flow_operation(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0xC3 => Ok(build_immediate_addr_parameterized_control_flow_data( + Opcode::EightBit(0xC3) => Ok(build_immediate_addr_parameterized_control_flow_data( data, |addr| ControlFlowInstruction::JumpToImmediate { addr }, )), - 0xCD => Ok(build_immediate_addr_parameterized_control_flow_data( + Opcode::EightBit(0xCD) => Ok(build_immediate_addr_parameterized_control_flow_data( data, |addr| ControlFlowInstruction::Call { addr }, )), - 0xE9 => Ok(( + Opcode::EightBit(0xE9) => Ok(( Instruction::ControlFlow(ControlFlowInstruction::JumpToAddressInHL), 1, )), + _ => Err(parse::Error::UnknownOpcode(opcode)), } } -fn parse_restart_instruction(opcode: u8) -> ParseResult { - if !(matches!(opcode & 0xF0, 0xC0..=0xF0) && matches!(opcode & 0x0F, 0x07 | 0x0F)) { +fn parse_restart_instruction(opcode: Opcode) -> ParseResult { + let Opcode::EightBit(eight_bit_opcode) = opcode else { + return Err(parse::Error::UnknownOpcode(opcode)); + }; + + if !(matches!(eight_bit_opcode & 0xF0, 0xC0..=0xF0) + && matches!(eight_bit_opcode & 0x0F, 0x07 | 0x0F)) + { return Err(parse::Error::UnknownOpcode(opcode)); } - let addr = u16::from((opcode & 0xF0) - 0xC0) | u16::from((opcode & 0x0F) - 0x07); + let addr = + u16::from((eight_bit_opcode & 0xF0) - 0xC0) | u16::from((eight_bit_opcode & 0x0F) - 0x07); let control_flow_instruction = ControlFlowInstruction::RestartAtAddress { addr }; Ok((Instruction::ControlFlow(control_flow_instruction), 1)) } -fn parse_unconditional_return(opcode: u8) -> ParseResult { +fn parse_unconditional_return(opcode: Opcode) -> ParseResult { match opcode { - 0xC9 => Ok((Instruction::ControlFlow(ControlFlowInstruction::Return), 1)), - 0xD9 => Ok(( + Opcode::EightBit(0xC9) => Ok((Instruction::ControlFlow(ControlFlowInstruction::Return), 1)), + Opcode::EightBit(0xD9) => Ok(( Instruction::ControlFlow(ControlFlowInstruction::ReturnAndEnableInterrupts), 1, )), @@ -75,7 +83,7 @@ fn parse_unconditional_return(opcode: u8) -> ParseResult { fn parse_unconditional_relative_jump(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); - if opcode != 0x18 { + if opcode != Opcode::EightBit(0x18) { return Err(parse::Error::UnknownOpcode(opcode)); } @@ -115,23 +123,25 @@ fn parse_conditional_control_operation(data: &View) -> ParseResult { } fn conditional_control_flow_type_for_opcode( - opcode: u8, + opcode: Opcode, ) -> Result { match opcode { - 0xC2 | 0xD2 | 0xCA | 0xDA => Ok(ConditionalControlFlowType::Jump), - 0xC4 | 0xD4 | 0xCC | 0xDC => Ok(ConditionalControlFlowType::Call), - 0xC0 | 0xD0 | 0xC8 | 0xD8 => Ok(ConditionalControlFlowType::Return), - 0x20 | 0x30 | 0x28 | 0x38 => Ok(ConditionalControlFlowType::RelativeJump), + Opcode::EightBit(0xC2 | 0xD2 | 0xCA | 0xDA) => Ok(ConditionalControlFlowType::Jump), + Opcode::EightBit(0xC4 | 0xD4 | 0xCC | 0xDC) => Ok(ConditionalControlFlowType::Call), + Opcode::EightBit(0xC0 | 0xD0 | 0xC8 | 0xD8) => Ok(ConditionalControlFlowType::Return), + Opcode::EightBit(0x20 | 0x30 | 0x28 | 0x38) => Ok(ConditionalControlFlowType::RelativeJump), + _ => Err(parse::Error::UnknownOpcode(opcode)), } } -fn conditional_control_flow_flag_for_opcode(opcode: u8) -> Result<(Flag, u8), parse::Error> { +fn conditional_control_flow_flag_for_opcode(opcode: Opcode) -> Result<(Flag, u8), parse::Error> { match opcode { - 0xC0 | 0xC2 | 0xC4 | 0x20 => Ok((Flag::Zero, 0)), - 0xD0 | 0xD2 | 0xD4 | 0x30 => Ok((Flag::Carry, 0)), - 0xC8 | 0xCA | 0xCC | 0x28 => Ok((Flag::Zero, 1)), - 0xD8 | 0xDA | 0xDC | 0x38 => Ok((Flag::Carry, 1)), + Opcode::EightBit(0xC0 | 0xC2 | 0xC4 | 0x20) => Ok((Flag::Zero, 0)), + Opcode::EightBit(0xD0 | 0xD2 | 0xD4 | 0x30) => Ok((Flag::Carry, 0)), + Opcode::EightBit(0xC8 | 0xCA | 0xCC | 0x28) => Ok((Flag::Zero, 1)), + Opcode::EightBit(0xD8 | 0xDA | 0xDC | 0x38) => Ok((Flag::Carry, 1)), + _ => Err(parse::Error::UnknownOpcode(opcode)), } } diff --git a/src/cpu/parse/load16/immediate.rs b/src/cpu/parse/load16/immediate.rs index dc09354..9b9478d 100644 --- a/src/cpu/parse/load16/immediate.rs +++ b/src/cpu/parse/load16/immediate.rs @@ -1,4 +1,5 @@ use crate::cpu::instructions::load16::SixteenBitLoadInstruction; +use crate::cpu::parse::unparsed::Opcode; use crate::cpu::parse::ParseOutput; use crate::cpu::{ instructions::Instruction, @@ -15,23 +16,24 @@ impl OpcodeParser for Parser { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x01 => Ok(make_load_immediate_data( + Opcode::EightBit(0x01) => Ok(make_load_immediate_data( register::SixteenBit::Combined(register::Combined::BC), data, )), - 0x11 => Ok(make_load_immediate_data( + Opcode::EightBit(0x11) => Ok(make_load_immediate_data( register::SixteenBit::Combined(register::Combined::DE), data, )), - 0x21 => Ok(make_load_immediate_data( + Opcode::EightBit(0x21) => Ok(make_load_immediate_data( register::SixteenBit::Combined(register::Combined::HL), data, )), - 0x31 => Ok(make_load_immediate_data( + Opcode::EightBit(0x31) => Ok(make_load_immediate_data( register::SixteenBit::Single(register::SingleSixteenBit::StackPointer), data, )), - 0xF8 => Ok(make_load_effective_address(register::Combined::HL, data)), + Opcode::EightBit(0xF8) => Ok(make_load_effective_address(register::Combined::HL, data)), + _ => Err(Error::UnknownOpcode(opcode)), } } diff --git a/src/cpu/parse/load16/stack.rs b/src/cpu/parse/load16/stack.rs index 823823e..aa59c94 100644 --- a/src/cpu/parse/load16/stack.rs +++ b/src/cpu/parse/load16/stack.rs @@ -1,5 +1,6 @@ use crate::cpu::instructions::load16::SixteenBitLoadInstruction; use crate::cpu::instructions::Instruction; +use crate::cpu::parse::unparsed::Opcode; use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult}; use crate::memory::{GetViewTuple, View}; use crate::register; @@ -17,37 +18,37 @@ impl OpcodeParser for Parser { fn parse_opcode(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x08 => Ok(make_load_sp_to_address_data(data)), - 0xF5 => Ok(make_stack_operation_data( + Opcode::EightBit(0x08) => Ok(make_load_sp_to_address_data(data)), + Opcode::EightBit(0xF5) => Ok(make_stack_operation_data( Operation::Push, register::Combined::AF, )), - 0xC5 => Ok(make_stack_operation_data( + Opcode::EightBit(0xC5) => Ok(make_stack_operation_data( Operation::Push, register::Combined::BC, )), - 0xD5 => Ok(make_stack_operation_data( + Opcode::EightBit(0xD5) => Ok(make_stack_operation_data( Operation::Push, register::Combined::DE, )), - 0xE5 => Ok(make_stack_operation_data( + Opcode::EightBit(0xE5) => Ok(make_stack_operation_data( Operation::Push, register::Combined::HL, )), - 0xF1 => Ok(make_stack_operation_data( + Opcode::EightBit(0xF1) => Ok(make_stack_operation_data( Operation::Pop, register::Combined::AF, )), - 0xC1 => Ok(make_stack_operation_data( + Opcode::EightBit(0xC1) => Ok(make_stack_operation_data( Operation::Pop, register::Combined::BC, )), - 0xD1 => Ok(make_stack_operation_data( + Opcode::EightBit(0xD1) => Ok(make_stack_operation_data( Operation::Pop, register::Combined::DE, )), - 0xE1 => Ok(make_stack_operation_data( + Opcode::EightBit(0xE1) => Ok(make_stack_operation_data( Operation::Pop, register::Combined::HL, )), diff --git a/src/cpu/parse/load16/transfer.rs b/src/cpu/parse/load16/transfer.rs index 1d8460b..57386ce 100644 --- a/src/cpu/parse/load16/transfer.rs +++ b/src/cpu/parse/load16/transfer.rs @@ -1,5 +1,6 @@ use crate::cpu::instructions::load16::SixteenBitLoadInstruction; use crate::cpu::instructions::Instruction; +use crate::cpu::parse::unparsed::Opcode; use crate::cpu::parse::ParseOutput; use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult}; use crate::memory::View; @@ -12,7 +13,7 @@ impl OpcodeParser for Parser { fn parse_opcode(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0xF9 => Ok(make_load_between_register_data( + Opcode::EightBit(0xF9) => Ok(make_load_between_register_data( register::SixteenBit::Single(register::SingleSixteenBit::StackPointer), register::SixteenBit::Combined(register::Combined::HL), )), diff --git a/src/cpu/parse/load8/immediate.rs b/src/cpu/parse/load8/immediate.rs index 2e18f25..06421b0 100644 --- a/src/cpu/parse/load8/immediate.rs +++ b/src/cpu/parse/load8/immediate.rs @@ -1,5 +1,6 @@ use crate::cpu::instructions::load8::EightBitLoadInstruction; use crate::cpu::instructions::Instruction; +use crate::cpu::parse::unparsed::Opcode; use crate::cpu::parse::ParseOutput; use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult}; use crate::memory::{GetViewTuple, View}; @@ -14,13 +15,27 @@ impl OpcodeParser for Parser { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x3E => Ok(make_load_immediate_data(register::SingleEightBit::A, data)), - 0x06 => Ok(make_load_immediate_data(register::SingleEightBit::B, data)), - 0x0E => Ok(make_load_immediate_data(register::SingleEightBit::C, data)), - 0x16 => Ok(make_load_immediate_data(register::SingleEightBit::D, data)), - 0x1E => Ok(make_load_immediate_data(register::SingleEightBit::E, data)), - 0x26 => Ok(make_load_immediate_data(register::SingleEightBit::H, data)), - 0x2E => Ok(make_load_immediate_data(register::SingleEightBit::L, data)), + Opcode::EightBit(0x3E) => { + Ok(make_load_immediate_data(register::SingleEightBit::A, data)) + } + Opcode::EightBit(0x06) => { + Ok(make_load_immediate_data(register::SingleEightBit::B, data)) + } + Opcode::EightBit(0x0E) => { + Ok(make_load_immediate_data(register::SingleEightBit::C, data)) + } + Opcode::EightBit(0x16) => { + Ok(make_load_immediate_data(register::SingleEightBit::D, data)) + } + Opcode::EightBit(0x1E) => { + Ok(make_load_immediate_data(register::SingleEightBit::E, data)) + } + Opcode::EightBit(0x26) => { + Ok(make_load_immediate_data(register::SingleEightBit::H, data)) + } + Opcode::EightBit(0x2E) => { + Ok(make_load_immediate_data(register::SingleEightBit::L, data)) + } _ => Err(Error::UnknownOpcode(opcode)), } diff --git a/src/cpu/parse/load8/memory.rs b/src/cpu/parse/load8/memory.rs index 5d3f67b..56c8858 100644 --- a/src/cpu/parse/load8/memory.rs +++ b/src/cpu/parse/load8/memory.rs @@ -1,5 +1,6 @@ use crate::cpu::instructions::load8::EightBitLoadInstruction; use crate::cpu::instructions::Instruction; +use crate::cpu::parse::unparsed::Opcode; use crate::cpu::parse::{self, Error, OpcodeParser, OrParse, ParseOutput, ParseResult}; use crate::memory::{GetViewTuple, View}; use crate::register; @@ -19,39 +20,39 @@ impl OpcodeParser for Parser { fn parse_load_from_register_to_address(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x02 => Ok(make_load_to_register_address( + Opcode::EightBit(0x02) => Ok(make_load_to_register_address( register::Combined::BC, register::SingleEightBit::A, )), - 0x12 => Ok(make_load_to_register_address( + Opcode::EightBit(0x12) => Ok(make_load_to_register_address( register::Combined::DE, register::SingleEightBit::A, )), - 0x70 => Ok(make_load_to_register_address( + Opcode::EightBit(0x70) => Ok(make_load_to_register_address( register::Combined::HL, register::SingleEightBit::B, )), - 0x71 => Ok(make_load_to_register_address( + Opcode::EightBit(0x71) => Ok(make_load_to_register_address( register::Combined::HL, register::SingleEightBit::C, )), - 0x72 => Ok(make_load_to_register_address( + Opcode::EightBit(0x72) => Ok(make_load_to_register_address( register::Combined::HL, register::SingleEightBit::D, )), - 0x73 => Ok(make_load_to_register_address( + Opcode::EightBit(0x73) => Ok(make_load_to_register_address( register::Combined::HL, register::SingleEightBit::E, )), - 0x74 => Ok(make_load_to_register_address( + Opcode::EightBit(0x74) => Ok(make_load_to_register_address( register::Combined::HL, register::SingleEightBit::H, )), - 0x75 => Ok(make_load_to_register_address( + Opcode::EightBit(0x75) => Ok(make_load_to_register_address( register::Combined::HL, register::SingleEightBit::L, )), - 0x77 => Ok(make_load_to_register_address( + Opcode::EightBit(0x77) => Ok(make_load_to_register_address( register::Combined::HL, register::SingleEightBit::A, )), @@ -62,58 +63,58 @@ fn parse_load_from_register_to_address(data: &View) -> ParseResult { fn parse_load_from_address_to_register(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x0A => Ok(make_load_from_register_address( + Opcode::EightBit(0x0A) => Ok(make_load_from_register_address( register::SingleEightBit::A, register::Combined::BC, )), - 0x1A => Ok(make_load_from_register_address( + Opcode::EightBit(0x1A) => Ok(make_load_from_register_address( register::SingleEightBit::A, register::Combined::DE, )), - 0x46 => Ok(make_load_from_register_address( + Opcode::EightBit(0x46) => Ok(make_load_from_register_address( register::SingleEightBit::B, register::Combined::HL, )), - 0x4E => Ok(make_load_from_register_address( + Opcode::EightBit(0x4E) => Ok(make_load_from_register_address( register::SingleEightBit::C, register::Combined::HL, )), - 0x56 => Ok(make_load_from_register_address( + Opcode::EightBit(0x56) => Ok(make_load_from_register_address( register::SingleEightBit::D, register::Combined::HL, )), - 0x5E => Ok(make_load_from_register_address( + Opcode::EightBit(0x5E) => Ok(make_load_from_register_address( register::SingleEightBit::E, register::Combined::HL, )), - 0x66 => Ok(make_load_from_register_address( + Opcode::EightBit(0x66) => Ok(make_load_from_register_address( register::SingleEightBit::H, register::Combined::HL, )), - 0x6E => Ok(make_load_from_register_address( + Opcode::EightBit(0x6E) => Ok(make_load_from_register_address( register::SingleEightBit::L, register::Combined::HL, )), - 0x7E => Ok(make_load_from_register_address( + Opcode::EightBit(0x7E) => Ok(make_load_from_register_address( register::SingleEightBit::A, register::Combined::HL, )), - 0xF2 => Ok(make_load_from_memory_relative_to_io_register_start( + Opcode::EightBit(0xF2) => Ok(make_load_from_memory_relative_to_io_register_start( register::SingleEightBit::C, register::SingleEightBit::A, )), - 0xE2 => Ok(make_load_to_memory_relative_to_io_register_start( + Opcode::EightBit(0xE2) => Ok(make_load_to_memory_relative_to_io_register_start( register::SingleEightBit::C, register::SingleEightBit::A, )), - 0xF0 => Ok( + Opcode::EightBit(0xF0) => Ok( make_load_from_memory_relative_to_io_register_start_by_immediate( register::SingleEightBit::A, data, ), ), - 0xE0 => Ok( + Opcode::EightBit(0xE0) => Ok( make_load_to_memory_relative_to_io_register_start_by_immediate( register::SingleEightBit::A, data, @@ -127,12 +128,12 @@ fn parse_load_from_address_to_register(data: &View) -> ParseResult { fn parse_load_immediate_instructions(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x36 => Ok(make_load_n_to_hl_address(data)), - 0xFA => Ok(make_load_from_immediate_address( + Opcode::EightBit(0x36) => Ok(make_load_n_to_hl_address(data)), + Opcode::EightBit(0xFA) => Ok(make_load_from_immediate_address( register::SingleEightBit::A, data, )), - 0xEA => Ok(make_load_to_immediate_address( + Opcode::EightBit(0xEA) => Ok(make_load_to_immediate_address( register::SingleEightBit::A, data, )), @@ -143,22 +144,22 @@ fn parse_load_immediate_instructions(data: &View) -> ParseResult { fn parse_load_from_register_to_address_and_do_arithmetic(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); match opcode { - 0x32 => Ok(make_load_to_address_and_do_arithmetic( + Opcode::EightBit(0x32) => Ok(make_load_to_address_and_do_arithmetic( register::Combined::HL, register::SingleEightBit::A, |dst, src| EightBitLoadInstruction::LoadToRegisterAddressThenDec { dst, src }, )), - 0x22 => Ok(make_load_to_address_and_do_arithmetic( + Opcode::EightBit(0x22) => Ok(make_load_to_address_and_do_arithmetic( register::Combined::HL, register::SingleEightBit::A, |dst, src| EightBitLoadInstruction::LoadToRegisterAddressThenInc { dst, src }, )), - 0x3A => Ok(make_load_from_address_and_do_arithmetic( + Opcode::EightBit(0x3A) => Ok(make_load_from_address_and_do_arithmetic( register::SingleEightBit::A, register::Combined::HL, |dst, src| EightBitLoadInstruction::LoadFromRegisterAddressThenDec { dst, src }, )), - 0x2A => Ok(make_load_from_address_and_do_arithmetic( + Opcode::EightBit(0x2A) => Ok(make_load_from_address_and_do_arithmetic( register::SingleEightBit::A, register::Combined::HL, |dst, src| EightBitLoadInstruction::LoadFromRegisterAddressThenInc { dst, src }, diff --git a/src/cpu/parse/load8/transfer.rs b/src/cpu/parse/load8/transfer.rs index 374c6a2..864ccc3 100644 --- a/src/cpu/parse/load8/transfer.rs +++ b/src/cpu/parse/load8/transfer.rs @@ -1,5 +1,6 @@ use crate::cpu::instructions::load8::EightBitLoadInstruction; use crate::cpu::instructions::Instruction; +use crate::cpu::parse::unparsed::Opcode; use crate::cpu::parse::ParseOutput; use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult}; use crate::memory::View; @@ -11,8 +12,12 @@ impl OpcodeParser for Parser { /// Parses an opcode that transfers an 8bit values between single 8 bit registers. fn parse_opcode(data: &View) -> ParseResult { let opcode = parse::get_opcode_from_data(data); - let dst = parse_destination_register(opcode)?; - let src = parse_source_register(opcode)?; + let Opcode::EightBit(eight_bit_opcode) = opcode else { + return Err(Error::UnknownOpcode(opcode)); + }; + + let dst = parse_destination_register(eight_bit_opcode)?; + let src = parse_source_register(eight_bit_opcode)?; Ok(make_load_between_register_data(dst, src)) } @@ -28,7 +33,7 @@ fn parse_destination_register(opcode: u8) -> Result Ok(register::SingleEightBit::H), 0x60 if offset > 7 => Ok(register::SingleEightBit::L), 0x70 if offset > 7 => Ok(register::SingleEightBit::A), - _ => Err(Error::UnknownOpcode(opcode)), + _ => Err(Error::UnknownOpcode(opcode.into())), } } @@ -42,7 +47,7 @@ fn parse_source_register(opcode: u8) -> Result Ok(register::SingleEightBit::H), 0x05 => Ok(register::SingleEightBit::L), 0x07 => Ok(register::SingleEightBit::A), - _ => Err(Error::UnknownOpcode(opcode)), + _ => Err(Error::UnknownOpcode(opcode.into())), } } diff --git a/src/cpu/parse/misc.rs b/src/cpu/parse/misc.rs index 826e2e1..c183338 100644 --- a/src/cpu/parse/misc.rs +++ b/src/cpu/parse/misc.rs @@ -1,4 +1,4 @@ -use super::{OpcodeParser, ParseOutput, ParseResult}; +use super::{unparsed::Opcode, OpcodeParser, ParseOutput, ParseResult}; use crate::{ cpu::instructions::{misc::MiscInstruction, Instruction}, memory::View, @@ -10,13 +10,13 @@ impl OpcodeParser for Parser { fn parse_opcode(data: &View) -> ParseResult { let opcode = super::get_opcode_from_data(data); match opcode { - 0x37 => Ok(build_set_carry_flag_data()), - 0x3F => Ok(build_complement_carry_flag_data()), - 0x27 => Ok(build_daa_data()), - 0x2F => Ok(build_complement_a_register_data()), - 0x00 => Ok(build_nop_data()), - 0xFB => Ok(build_enable_interrupts_data()), - 0xF3 => Ok(build_disable_interrupts_data()), + Opcode::EightBit(0x37) => Ok(build_set_carry_flag_data()), + Opcode::EightBit(0x3F) => Ok(build_complement_carry_flag_data()), + Opcode::EightBit(0x27) => Ok(build_daa_data()), + Opcode::EightBit(0x2F) => Ok(build_complement_a_register_data()), + Opcode::EightBit(0x00) => Ok(build_nop_data()), + Opcode::EightBit(0xFB) => Ok(build_enable_interrupts_data()), + Opcode::EightBit(0xF3) => Ok(build_disable_interrupts_data()), _ => Err(super::Error::UnknownOpcode(opcode)), } } diff --git a/src/cpu/parse/unparsed.rs b/src/cpu/parse/unparsed.rs new file mode 100644 index 0000000..f7dc01b --- /dev/null +++ b/src/cpu/parse/unparsed.rs @@ -0,0 +1,36 @@ +use std::fmt::{self, Display, LowerHex, UpperHex}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Opcode { + EightBit(u8), + SixteenBit(u16), +} + +impl From for Opcode { + fn from(value: u8) -> Self { + Self::EightBit(value) + } +} + +impl From for Opcode { + fn from(value: u16) -> Self { + Self::SixteenBit(value) + } +} + +macro_rules! impl_formatter_trait { + ($trait: ident) => { + impl $trait for Opcode { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Self::EightBit(ref opcode) => $trait::fmt(opcode, formatter), + Self::SixteenBit(ref opcode) => $trait::fmt(opcode, formatter), + } + } + } + }; +} + +impl_formatter_trait!(Display); +impl_formatter_trait!(UpperHex); +impl_formatter_trait!(LowerHex);