Add unknown opcode type, use it for parsing

old-bit-manip
Nick Krichevsky 2023-11-26 22:48:41 -05:00
parent 8b088da74d
commit 9e785d117c
12 changed files with 255 additions and 140 deletions

View File

@ -11,13 +11,14 @@ mod control;
mod load16; mod load16;
mod load8; mod load8;
mod misc; mod misc;
mod unparsed;
#[derive(Error, Debug, Clone)] #[derive(Error, Debug, Clone)]
pub enum Error { pub enum Error {
#[error("given empty data to parse opcode from")] #[error("given empty data to parse opcode from")]
NoData, NoData,
#[error("unknown opcode 0x{0:X}")] #[error("unknown opcode 0x{0:X}")]
UnknownOpcode(u8), UnknownOpcode(unparsed::Opcode),
#[error("not enough arguments provided for opcode 0x{0:X}")] #[error("not enough arguments provided for opcode 0x{0:X}")]
NotEnoughArgs(u8), NotEnoughArgs(u8),
} }
@ -37,11 +38,17 @@ trait OpcodeParser {
trait OrParse<T> { trait OrParse<T> {
/// If the current parse failed to parse the given opcode (i.e. this is Err(UnknownOpcode)), attempt to /// 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. /// parse again with the given parse function. Otherwise, this result itself is returned.
fn or_parse<F: Fn(u8) -> Result<T, Error>>(self, parse_func: F) -> Result<T, Error>; fn or_parse<F: Fn(unparsed::Opcode) -> Result<T, Error>>(
self,
parse_func: F,
) -> Result<T, Error>;
} }
impl<T> OrParse<T> for Result<T, Error> { impl<T> OrParse<T> for Result<T, Error> {
fn or_parse<F: Fn(u8) -> Result<T, Error>>(self, parse_func: F) -> Result<T, Error> { fn or_parse<F: Fn(unparsed::Opcode) -> Result<T, Error>>(
self,
parse_func: F,
) -> Result<T, Error> {
if let Err(Error::UnknownOpcode(opcode)) = self { if let Err(Error::UnknownOpcode(opcode)) = self {
parse_func(opcode) parse_func(opcode)
} else { } else {
@ -74,10 +81,11 @@ pub fn next_instruction(data: &View) -> ParseResult {
} }
} }
// TODO: support 16bit, too
let opcode = get_opcode_from_data(data); let opcode = get_opcode_from_data(data);
Err(Error::UnknownOpcode(opcode)) Err(Error::UnknownOpcode(opcode))
} }
fn get_opcode_from_data(data: &View) -> u8 { fn get_opcode_from_data(data: &View) -> unparsed::Opcode {
data.get() unparsed::Opcode::EightBit(data.get())
} }

View File

@ -8,7 +8,7 @@ use crate::{
memory::View, memory::View,
}; };
use super::ParseOutput; use super::{unparsed, ParseOutput};
pub struct Parser; pub struct Parser;
@ -16,32 +16,45 @@ impl OpcodeParser for Parser {
fn parse_opcode(data: &View) -> ParseResult { fn parse_opcode(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0x09 => Ok(build_add_hl_to_register_data(SixteenBit::Combined( unparsed::Opcode::EightBit(0x09) => Ok(build_add_hl_to_register_data(
Combined::BC, SixteenBit::Combined(Combined::BC),
))), )),
0x19 => Ok(build_add_hl_to_register_data(SixteenBit::Combined( unparsed::Opcode::EightBit(0x19) => Ok(build_add_hl_to_register_data(
Combined::DE, SixteenBit::Combined(Combined::DE),
))), )),
0x29 => Ok(build_add_hl_to_register_data(SixteenBit::Combined( unparsed::Opcode::EightBit(0x29) => Ok(build_add_hl_to_register_data(
Combined::HL, SixteenBit::Combined(Combined::HL),
))), )),
0x39 => Ok(build_add_hl_to_register_data(SixteenBit::Single( 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, SingleSixteenBit::StackPointer,
))), ))),
0x03 => Ok(build_inc_register_data(SixteenBit::Combined(Combined::BC))), unparsed::Opcode::EightBit(0x0B) => {
0x13 => Ok(build_inc_register_data(SixteenBit::Combined(Combined::DE))), Ok(build_dec_register_data(SixteenBit::Combined(Combined::BC)))
0x23 => Ok(build_inc_register_data(SixteenBit::Combined(Combined::HL))), }
0x33 => Ok(build_inc_register_data(SixteenBit::Single( 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, 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)), _ => Err(Error::UnknownOpcode(opcode)),
} }
} }

View File

@ -9,7 +9,7 @@ use crate::{
register, 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 // similar to `arith8::Operand`, but only for the parts that can be uniquely determined from the opcode
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -31,7 +31,6 @@ impl OpcodeParser for Parser {
fn parse_eight_bit_arithmetic_instruction(data: &View) -> super::ParseResult { fn parse_eight_bit_arithmetic_instruction(data: &View) -> super::ParseResult {
let opcode = super::get_opcode_from_data(data); let opcode = super::get_opcode_from_data(data);
let operation = operation_for_opcode(opcode)?; let operation = operation_for_opcode(opcode)?;
let operand = operand_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 { fn parse_stack_pointer_adjust_instruction(data: &View) -> super::ParseResult {
let opcode = super::get_opcode_from_data(data); let opcode = super::get_opcode_from_data(data);
if opcode == 0xE8 { if opcode == Opcode::EightBit(0xE8) {
Ok(build_stack_pointer_adjust_data(data)) Ok(build_stack_pointer_adjust_data(data))
} else { } else {
Err(super::Error::UnknownOpcode(opcode)) Err(super::Error::UnknownOpcode(opcode))
} }
} }
fn operation_for_opcode(opcode: u8) -> Result<Operation, super::Error> { fn operation_for_opcode(opcode: Opcode) -> Result<Operation, super::Error> {
operation_for_binary_opcode(opcode).or_parse(operation_for_unary_opcode) operation_for_binary_opcode(opcode).or_parse(operation_for_unary_opcode)
} }
fn operand_for_opcode(opcode: u8) -> Result<OpcodeOperand, super::Error> { fn operand_for_opcode(opcode: Opcode) -> Result<OpcodeOperand, super::Error> {
operand_for_binary_opcode(opcode).or_else(|_err| operand_for_unary_opcode(opcode)) 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<Operation, super::Error> { fn operation_for_unary_opcode(opcode: Opcode) -> Result<Operation, super::Error> {
let operation_nibble = opcode & 0xF0; let Opcode::EightBit(eight_bit_opcode) = opcode else {
let operand_nibble = opcode & 0x0F; return Err(super::Error::UnknownOpcode(opcode));
};
let operation_nibble = eight_bit_opcode & 0xF0;
let operand_nibble = eight_bit_opcode & 0x0F;
match operation_nibble { match operation_nibble {
0x00..=0x30 if operand_nibble == 0x04 || operand_nibble == 0x0C => Ok(Operation::Inc), 0x00..=0x30 if operand_nibble == 0x04 || operand_nibble == 0x0C => Ok(Operation::Inc),
@ -75,30 +82,45 @@ fn operation_for_unary_opcode(opcode: u8) -> Result<Operation, super::Error> {
} }
} }
fn operation_for_binary_opcode(opcode: u8) -> Result<Operation, super::Error> { fn operation_for_binary_opcode(opcode: Opcode) -> Result<Operation, super::Error> {
match opcode { match opcode {
0x80..=0x87 | 0xC6 => Ok(Operation::Add), Opcode::EightBit(0x80..=0x87 | 0xC6) => Ok(Operation::Add),
0x88..=0x8F | 0xCE => Ok(Operation::AddWithCarry), Opcode::EightBit(0x88..=0x8F | 0xCE) => Ok(Operation::AddWithCarry),
0x90..=0x97 | 0xD6 => Ok(Operation::Sub), Opcode::EightBit(0x90..=0x97 | 0xD6) => Ok(Operation::Sub),
0x98..=0x9F | 0xDE => Ok(Operation::SubWithCarry), Opcode::EightBit(0x98..=0x9F | 0xDE) => Ok(Operation::SubWithCarry),
0xA0..=0xA7 | 0xE6 => Ok(Operation::And), Opcode::EightBit(0xA0..=0xA7 | 0xE6) => Ok(Operation::And),
0xA8..=0xAF | 0xEE => Ok(Operation::Xor), Opcode::EightBit(0xA8..=0xAF | 0xEE) => Ok(Operation::Xor),
0xB0..=0xB7 | 0xF6 => Ok(Operation::Or), Opcode::EightBit(0xB0..=0xB7 | 0xF6) => Ok(Operation::Or),
0xB8..=0xBF | 0xFE => Ok(Operation::Compare), Opcode::EightBit(0xB8..=0xBF | 0xFE) => Ok(Operation::Compare),
_ => Err(super::Error::UnknownOpcode(opcode)), _ => Err(super::Error::UnknownOpcode(opcode)),
} }
} }
fn operand_for_unary_opcode(opcode: u8) -> Result<OpcodeOperand, super::Error> { fn operand_for_unary_opcode(opcode: Opcode) -> Result<OpcodeOperand, super::Error> {
match opcode { match opcode {
0x04 | 0x05 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::B)), Opcode::EightBit(0x04 | 0x05) => {
0x0C | 0x0D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::C)), Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::B))
0x14 | 0x15 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::D)), }
0x1C | 0x1D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::E)), Opcode::EightBit(0x0C | 0x0D) => {
0x24 | 0x25 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::H)), Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::C))
0x2C | 0x2D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::L)), }
0x34 | 0x35 => Ok(OpcodeOperand::HLAddressValue), Opcode::EightBit(0x14 | 0x15) => {
0x3C | 0x3D => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::A)), 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)), _ => Err(super::Error::UnknownOpcode(opcode)),
} }
} }
@ -109,7 +131,7 @@ fn operand_for_binary_opcode(opcode: u8) -> Result<OpcodeOperand, super::Error>
} else if !matches!(opcode & 0xF0, 0x80..=0xB0) { } else if !matches!(opcode & 0xF0, 0x80..=0xB0) {
// If it's not an immediate operation (covered above), or a standard arith operation (covered below), // If it's not an immediate operation (covered above), or a standard arith operation (covered below),
// we shouldn't try and parse it // we shouldn't try and parse it
return Err(super::Error::UnknownOpcode(opcode)); return Err(super::Error::UnknownOpcode(opcode.into()));
} }
match opcode & 0x07 { match opcode & 0x07 {
@ -121,7 +143,7 @@ fn operand_for_binary_opcode(opcode: u8) -> Result<OpcodeOperand, super::Error>
0x05 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::L)), 0x05 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::L)),
0x06 => Ok(OpcodeOperand::HLAddressValue), 0x06 => Ok(OpcodeOperand::HLAddressValue),
0x07 => Ok(OpcodeOperand::SingleRegister(register::SingleEightBit::A)), 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(0x2D, (Operation::Dec, OpcodeOperand::SingleRegister(register::SingleEightBit::L)))]
#[test_case(0x35, (Operation::Dec, OpcodeOperand::HLAddressValue))] #[test_case(0x35, (Operation::Dec, OpcodeOperand::HLAddressValue))]
#[test_case(0x3D, (Operation::Dec, OpcodeOperand::SingleRegister(register::SingleEightBit::A)))] #[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 operation = operation_for_opcode(opcode).expect("could not parse");
let operand = operand_for_opcode(opcode).expect("could not parse"); let operand = operand_for_opcode(opcode).expect("could not parse");

View File

@ -7,7 +7,7 @@ use crate::{
register::Flag, register::Flag,
}; };
use super::{OpcodeParser, OrParse, ParseOutput, ParseResult}; use super::{unparsed::Opcode, OpcodeParser, OrParse, ParseOutput, ParseResult};
pub struct Parser; 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 { fn parse_unconditional_parameterized_control_flow_operation(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0xC3 => Ok(build_immediate_addr_parameterized_control_flow_data( Opcode::EightBit(0xC3) => Ok(build_immediate_addr_parameterized_control_flow_data(
data, data,
|addr| ControlFlowInstruction::JumpToImmediate { addr }, |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, data,
|addr| ControlFlowInstruction::Call { addr }, |addr| ControlFlowInstruction::Call { addr },
)), )),
0xE9 => Ok(( Opcode::EightBit(0xE9) => Ok((
Instruction::ControlFlow(ControlFlowInstruction::JumpToAddressInHL), Instruction::ControlFlow(ControlFlowInstruction::JumpToAddressInHL),
1, 1,
)), )),
_ => Err(parse::Error::UnknownOpcode(opcode)), _ => Err(parse::Error::UnknownOpcode(opcode)),
} }
} }
fn parse_restart_instruction(opcode: u8) -> ParseResult { fn parse_restart_instruction(opcode: Opcode) -> ParseResult {
if !(matches!(opcode & 0xF0, 0xC0..=0xF0) && matches!(opcode & 0x0F, 0x07 | 0x0F)) { 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)); 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 }; let control_flow_instruction = ControlFlowInstruction::RestartAtAddress { addr };
Ok((Instruction::ControlFlow(control_flow_instruction), 1)) Ok((Instruction::ControlFlow(control_flow_instruction), 1))
} }
fn parse_unconditional_return(opcode: u8) -> ParseResult { fn parse_unconditional_return(opcode: Opcode) -> ParseResult {
match opcode { match opcode {
0xC9 => Ok((Instruction::ControlFlow(ControlFlowInstruction::Return), 1)), Opcode::EightBit(0xC9) => Ok((Instruction::ControlFlow(ControlFlowInstruction::Return), 1)),
0xD9 => Ok(( Opcode::EightBit(0xD9) => Ok((
Instruction::ControlFlow(ControlFlowInstruction::ReturnAndEnableInterrupts), Instruction::ControlFlow(ControlFlowInstruction::ReturnAndEnableInterrupts),
1, 1,
)), )),
@ -75,7 +83,7 @@ fn parse_unconditional_return(opcode: u8) -> ParseResult {
fn parse_unconditional_relative_jump(data: &View) -> ParseResult { fn parse_unconditional_relative_jump(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
if opcode != 0x18 { if opcode != Opcode::EightBit(0x18) {
return Err(parse::Error::UnknownOpcode(opcode)); 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( fn conditional_control_flow_type_for_opcode(
opcode: u8, opcode: Opcode,
) -> Result<ConditionalControlFlowType, parse::Error> { ) -> Result<ConditionalControlFlowType, parse::Error> {
match opcode { match opcode {
0xC2 | 0xD2 | 0xCA | 0xDA => Ok(ConditionalControlFlowType::Jump), Opcode::EightBit(0xC2 | 0xD2 | 0xCA | 0xDA) => Ok(ConditionalControlFlowType::Jump),
0xC4 | 0xD4 | 0xCC | 0xDC => Ok(ConditionalControlFlowType::Call), Opcode::EightBit(0xC4 | 0xD4 | 0xCC | 0xDC) => Ok(ConditionalControlFlowType::Call),
0xC0 | 0xD0 | 0xC8 | 0xD8 => Ok(ConditionalControlFlowType::Return), Opcode::EightBit(0xC0 | 0xD0 | 0xC8 | 0xD8) => Ok(ConditionalControlFlowType::Return),
0x20 | 0x30 | 0x28 | 0x38 => Ok(ConditionalControlFlowType::RelativeJump), Opcode::EightBit(0x20 | 0x30 | 0x28 | 0x38) => Ok(ConditionalControlFlowType::RelativeJump),
_ => Err(parse::Error::UnknownOpcode(opcode)), _ => 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 { match opcode {
0xC0 | 0xC2 | 0xC4 | 0x20 => Ok((Flag::Zero, 0)), Opcode::EightBit(0xC0 | 0xC2 | 0xC4 | 0x20) => Ok((Flag::Zero, 0)),
0xD0 | 0xD2 | 0xD4 | 0x30 => Ok((Flag::Carry, 0)), Opcode::EightBit(0xD0 | 0xD2 | 0xD4 | 0x30) => Ok((Flag::Carry, 0)),
0xC8 | 0xCA | 0xCC | 0x28 => Ok((Flag::Zero, 1)), Opcode::EightBit(0xC8 | 0xCA | 0xCC | 0x28) => Ok((Flag::Zero, 1)),
0xD8 | 0xDA | 0xDC | 0x38 => Ok((Flag::Carry, 1)), Opcode::EightBit(0xD8 | 0xDA | 0xDC | 0x38) => Ok((Flag::Carry, 1)),
_ => Err(parse::Error::UnknownOpcode(opcode)), _ => Err(parse::Error::UnknownOpcode(opcode)),
} }
} }

View File

@ -1,4 +1,5 @@
use crate::cpu::instructions::load16::SixteenBitLoadInstruction; use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
use crate::cpu::parse::unparsed::Opcode;
use crate::cpu::parse::ParseOutput; use crate::cpu::parse::ParseOutput;
use crate::cpu::{ use crate::cpu::{
instructions::Instruction, instructions::Instruction,
@ -15,23 +16,24 @@ impl OpcodeParser for Parser {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0x01 => Ok(make_load_immediate_data( Opcode::EightBit(0x01) => Ok(make_load_immediate_data(
register::SixteenBit::Combined(register::Combined::BC), register::SixteenBit::Combined(register::Combined::BC),
data, data,
)), )),
0x11 => Ok(make_load_immediate_data( Opcode::EightBit(0x11) => Ok(make_load_immediate_data(
register::SixteenBit::Combined(register::Combined::DE), register::SixteenBit::Combined(register::Combined::DE),
data, data,
)), )),
0x21 => Ok(make_load_immediate_data( Opcode::EightBit(0x21) => Ok(make_load_immediate_data(
register::SixteenBit::Combined(register::Combined::HL), register::SixteenBit::Combined(register::Combined::HL),
data, data,
)), )),
0x31 => Ok(make_load_immediate_data( Opcode::EightBit(0x31) => Ok(make_load_immediate_data(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer), register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
data, 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)), _ => Err(Error::UnknownOpcode(opcode)),
} }
} }

View File

@ -1,5 +1,6 @@
use crate::cpu::instructions::load16::SixteenBitLoadInstruction; use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
use crate::cpu::instructions::Instruction; use crate::cpu::instructions::Instruction;
use crate::cpu::parse::unparsed::Opcode;
use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult}; use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult};
use crate::memory::{GetViewTuple, View}; use crate::memory::{GetViewTuple, View};
use crate::register; use crate::register;
@ -17,37 +18,37 @@ impl OpcodeParser for Parser {
fn parse_opcode(data: &View) -> ParseResult { fn parse_opcode(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0x08 => Ok(make_load_sp_to_address_data(data)), Opcode::EightBit(0x08) => Ok(make_load_sp_to_address_data(data)),
0xF5 => Ok(make_stack_operation_data( Opcode::EightBit(0xF5) => Ok(make_stack_operation_data(
Operation::Push, Operation::Push,
register::Combined::AF, register::Combined::AF,
)), )),
0xC5 => Ok(make_stack_operation_data( Opcode::EightBit(0xC5) => Ok(make_stack_operation_data(
Operation::Push, Operation::Push,
register::Combined::BC, register::Combined::BC,
)), )),
0xD5 => Ok(make_stack_operation_data( Opcode::EightBit(0xD5) => Ok(make_stack_operation_data(
Operation::Push, Operation::Push,
register::Combined::DE, register::Combined::DE,
)), )),
0xE5 => Ok(make_stack_operation_data( Opcode::EightBit(0xE5) => Ok(make_stack_operation_data(
Operation::Push, Operation::Push,
register::Combined::HL, register::Combined::HL,
)), )),
0xF1 => Ok(make_stack_operation_data( Opcode::EightBit(0xF1) => Ok(make_stack_operation_data(
Operation::Pop, Operation::Pop,
register::Combined::AF, register::Combined::AF,
)), )),
0xC1 => Ok(make_stack_operation_data( Opcode::EightBit(0xC1) => Ok(make_stack_operation_data(
Operation::Pop, Operation::Pop,
register::Combined::BC, register::Combined::BC,
)), )),
0xD1 => Ok(make_stack_operation_data( Opcode::EightBit(0xD1) => Ok(make_stack_operation_data(
Operation::Pop, Operation::Pop,
register::Combined::DE, register::Combined::DE,
)), )),
0xE1 => Ok(make_stack_operation_data( Opcode::EightBit(0xE1) => Ok(make_stack_operation_data(
Operation::Pop, Operation::Pop,
register::Combined::HL, register::Combined::HL,
)), )),

View File

@ -1,5 +1,6 @@
use crate::cpu::instructions::load16::SixteenBitLoadInstruction; use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
use crate::cpu::instructions::Instruction; use crate::cpu::instructions::Instruction;
use crate::cpu::parse::unparsed::Opcode;
use crate::cpu::parse::ParseOutput; use crate::cpu::parse::ParseOutput;
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult}; use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
use crate::memory::View; use crate::memory::View;
@ -12,7 +13,7 @@ impl OpcodeParser for Parser {
fn parse_opcode(data: &View) -> ParseResult { fn parse_opcode(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { 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::Single(register::SingleSixteenBit::StackPointer),
register::SixteenBit::Combined(register::Combined::HL), register::SixteenBit::Combined(register::Combined::HL),
)), )),

View File

@ -1,5 +1,6 @@
use crate::cpu::instructions::load8::EightBitLoadInstruction; use crate::cpu::instructions::load8::EightBitLoadInstruction;
use crate::cpu::instructions::Instruction; use crate::cpu::instructions::Instruction;
use crate::cpu::parse::unparsed::Opcode;
use crate::cpu::parse::ParseOutput; use crate::cpu::parse::ParseOutput;
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult}; use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
use crate::memory::{GetViewTuple, View}; use crate::memory::{GetViewTuple, View};
@ -14,13 +15,27 @@ impl OpcodeParser for Parser {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0x3E => Ok(make_load_immediate_data(register::SingleEightBit::A, data)), Opcode::EightBit(0x3E) => {
0x06 => Ok(make_load_immediate_data(register::SingleEightBit::B, data)), Ok(make_load_immediate_data(register::SingleEightBit::A, data))
0x0E => Ok(make_load_immediate_data(register::SingleEightBit::C, data)), }
0x16 => Ok(make_load_immediate_data(register::SingleEightBit::D, data)), Opcode::EightBit(0x06) => {
0x1E => Ok(make_load_immediate_data(register::SingleEightBit::E, data)), Ok(make_load_immediate_data(register::SingleEightBit::B, data))
0x26 => Ok(make_load_immediate_data(register::SingleEightBit::H, data)), }
0x2E => Ok(make_load_immediate_data(register::SingleEightBit::L, 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)), _ => Err(Error::UnknownOpcode(opcode)),
} }

View File

@ -1,5 +1,6 @@
use crate::cpu::instructions::load8::EightBitLoadInstruction; use crate::cpu::instructions::load8::EightBitLoadInstruction;
use crate::cpu::instructions::Instruction; use crate::cpu::instructions::Instruction;
use crate::cpu::parse::unparsed::Opcode;
use crate::cpu::parse::{self, Error, OpcodeParser, OrParse, ParseOutput, ParseResult}; use crate::cpu::parse::{self, Error, OpcodeParser, OrParse, ParseOutput, ParseResult};
use crate::memory::{GetViewTuple, View}; use crate::memory::{GetViewTuple, View};
use crate::register; use crate::register;
@ -19,39 +20,39 @@ impl OpcodeParser for Parser {
fn parse_load_from_register_to_address(data: &View) -> ParseResult { fn parse_load_from_register_to_address(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0x02 => Ok(make_load_to_register_address( Opcode::EightBit(0x02) => Ok(make_load_to_register_address(
register::Combined::BC, register::Combined::BC,
register::SingleEightBit::A, register::SingleEightBit::A,
)), )),
0x12 => Ok(make_load_to_register_address( Opcode::EightBit(0x12) => Ok(make_load_to_register_address(
register::Combined::DE, register::Combined::DE,
register::SingleEightBit::A, register::SingleEightBit::A,
)), )),
0x70 => Ok(make_load_to_register_address( Opcode::EightBit(0x70) => Ok(make_load_to_register_address(
register::Combined::HL, register::Combined::HL,
register::SingleEightBit::B, register::SingleEightBit::B,
)), )),
0x71 => Ok(make_load_to_register_address( Opcode::EightBit(0x71) => Ok(make_load_to_register_address(
register::Combined::HL, register::Combined::HL,
register::SingleEightBit::C, register::SingleEightBit::C,
)), )),
0x72 => Ok(make_load_to_register_address( Opcode::EightBit(0x72) => Ok(make_load_to_register_address(
register::Combined::HL, register::Combined::HL,
register::SingleEightBit::D, register::SingleEightBit::D,
)), )),
0x73 => Ok(make_load_to_register_address( Opcode::EightBit(0x73) => Ok(make_load_to_register_address(
register::Combined::HL, register::Combined::HL,
register::SingleEightBit::E, register::SingleEightBit::E,
)), )),
0x74 => Ok(make_load_to_register_address( Opcode::EightBit(0x74) => Ok(make_load_to_register_address(
register::Combined::HL, register::Combined::HL,
register::SingleEightBit::H, register::SingleEightBit::H,
)), )),
0x75 => Ok(make_load_to_register_address( Opcode::EightBit(0x75) => Ok(make_load_to_register_address(
register::Combined::HL, register::Combined::HL,
register::SingleEightBit::L, register::SingleEightBit::L,
)), )),
0x77 => Ok(make_load_to_register_address( Opcode::EightBit(0x77) => Ok(make_load_to_register_address(
register::Combined::HL, register::Combined::HL,
register::SingleEightBit::A, 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 { fn parse_load_from_address_to_register(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0x0A => Ok(make_load_from_register_address( Opcode::EightBit(0x0A) => Ok(make_load_from_register_address(
register::SingleEightBit::A, register::SingleEightBit::A,
register::Combined::BC, register::Combined::BC,
)), )),
0x1A => Ok(make_load_from_register_address( Opcode::EightBit(0x1A) => Ok(make_load_from_register_address(
register::SingleEightBit::A, register::SingleEightBit::A,
register::Combined::DE, register::Combined::DE,
)), )),
0x46 => Ok(make_load_from_register_address( Opcode::EightBit(0x46) => Ok(make_load_from_register_address(
register::SingleEightBit::B, register::SingleEightBit::B,
register::Combined::HL, register::Combined::HL,
)), )),
0x4E => Ok(make_load_from_register_address( Opcode::EightBit(0x4E) => Ok(make_load_from_register_address(
register::SingleEightBit::C, register::SingleEightBit::C,
register::Combined::HL, register::Combined::HL,
)), )),
0x56 => Ok(make_load_from_register_address( Opcode::EightBit(0x56) => Ok(make_load_from_register_address(
register::SingleEightBit::D, register::SingleEightBit::D,
register::Combined::HL, register::Combined::HL,
)), )),
0x5E => Ok(make_load_from_register_address( Opcode::EightBit(0x5E) => Ok(make_load_from_register_address(
register::SingleEightBit::E, register::SingleEightBit::E,
register::Combined::HL, register::Combined::HL,
)), )),
0x66 => Ok(make_load_from_register_address( Opcode::EightBit(0x66) => Ok(make_load_from_register_address(
register::SingleEightBit::H, register::SingleEightBit::H,
register::Combined::HL, register::Combined::HL,
)), )),
0x6E => Ok(make_load_from_register_address( Opcode::EightBit(0x6E) => Ok(make_load_from_register_address(
register::SingleEightBit::L, register::SingleEightBit::L,
register::Combined::HL, register::Combined::HL,
)), )),
0x7E => Ok(make_load_from_register_address( Opcode::EightBit(0x7E) => Ok(make_load_from_register_address(
register::SingleEightBit::A, register::SingleEightBit::A,
register::Combined::HL, 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::C,
register::SingleEightBit::A, 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::C,
register::SingleEightBit::A, register::SingleEightBit::A,
)), )),
0xF0 => Ok( Opcode::EightBit(0xF0) => Ok(
make_load_from_memory_relative_to_io_register_start_by_immediate( make_load_from_memory_relative_to_io_register_start_by_immediate(
register::SingleEightBit::A, register::SingleEightBit::A,
data, data,
), ),
), ),
0xE0 => Ok( Opcode::EightBit(0xE0) => Ok(
make_load_to_memory_relative_to_io_register_start_by_immediate( make_load_to_memory_relative_to_io_register_start_by_immediate(
register::SingleEightBit::A, register::SingleEightBit::A,
data, data,
@ -127,12 +128,12 @@ fn parse_load_from_address_to_register(data: &View) -> ParseResult {
fn parse_load_immediate_instructions(data: &View) -> ParseResult { fn parse_load_immediate_instructions(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0x36 => Ok(make_load_n_to_hl_address(data)), Opcode::EightBit(0x36) => Ok(make_load_n_to_hl_address(data)),
0xFA => Ok(make_load_from_immediate_address( Opcode::EightBit(0xFA) => Ok(make_load_from_immediate_address(
register::SingleEightBit::A, register::SingleEightBit::A,
data, data,
)), )),
0xEA => Ok(make_load_to_immediate_address( Opcode::EightBit(0xEA) => Ok(make_load_to_immediate_address(
register::SingleEightBit::A, register::SingleEightBit::A,
data, 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 { fn parse_load_from_register_to_address_and_do_arithmetic(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
match opcode { 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::Combined::HL,
register::SingleEightBit::A, register::SingleEightBit::A,
|dst, src| EightBitLoadInstruction::LoadToRegisterAddressThenDec { dst, src }, |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::Combined::HL,
register::SingleEightBit::A, register::SingleEightBit::A,
|dst, src| EightBitLoadInstruction::LoadToRegisterAddressThenInc { dst, src }, |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::SingleEightBit::A,
register::Combined::HL, register::Combined::HL,
|dst, src| EightBitLoadInstruction::LoadFromRegisterAddressThenDec { dst, src }, |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::SingleEightBit::A,
register::Combined::HL, register::Combined::HL,
|dst, src| EightBitLoadInstruction::LoadFromRegisterAddressThenInc { dst, src }, |dst, src| EightBitLoadInstruction::LoadFromRegisterAddressThenInc { dst, src },

View File

@ -1,5 +1,6 @@
use crate::cpu::instructions::load8::EightBitLoadInstruction; use crate::cpu::instructions::load8::EightBitLoadInstruction;
use crate::cpu::instructions::Instruction; use crate::cpu::instructions::Instruction;
use crate::cpu::parse::unparsed::Opcode;
use crate::cpu::parse::ParseOutput; use crate::cpu::parse::ParseOutput;
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult}; use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
use crate::memory::View; 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. /// Parses an opcode that transfers an 8bit values between single 8 bit registers.
fn parse_opcode(data: &View) -> ParseResult { fn parse_opcode(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data); let opcode = parse::get_opcode_from_data(data);
let dst = parse_destination_register(opcode)?; let Opcode::EightBit(eight_bit_opcode) = opcode else {
let src = parse_source_register(opcode)?; 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)) Ok(make_load_between_register_data(dst, src))
} }
@ -28,7 +33,7 @@ fn parse_destination_register(opcode: u8) -> Result<register::SingleEightBit, pa
0x60 if offset <= 7 => Ok(register::SingleEightBit::H), 0x60 if offset <= 7 => Ok(register::SingleEightBit::H),
0x60 if offset > 7 => Ok(register::SingleEightBit::L), 0x60 if offset > 7 => Ok(register::SingleEightBit::L),
0x70 if offset > 7 => Ok(register::SingleEightBit::A), 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<register::SingleEightBit, parse::
0x04 => Ok(register::SingleEightBit::H), 0x04 => Ok(register::SingleEightBit::H),
0x05 => Ok(register::SingleEightBit::L), 0x05 => Ok(register::SingleEightBit::L),
0x07 => Ok(register::SingleEightBit::A), 0x07 => Ok(register::SingleEightBit::A),
_ => Err(Error::UnknownOpcode(opcode)), _ => Err(Error::UnknownOpcode(opcode.into())),
} }
} }

View File

@ -1,4 +1,4 @@
use super::{OpcodeParser, ParseOutput, ParseResult}; use super::{unparsed::Opcode, OpcodeParser, ParseOutput, ParseResult};
use crate::{ use crate::{
cpu::instructions::{misc::MiscInstruction, Instruction}, cpu::instructions::{misc::MiscInstruction, Instruction},
memory::View, memory::View,
@ -10,13 +10,13 @@ impl OpcodeParser for Parser {
fn parse_opcode(data: &View) -> ParseResult { fn parse_opcode(data: &View) -> ParseResult {
let opcode = super::get_opcode_from_data(data); let opcode = super::get_opcode_from_data(data);
match opcode { match opcode {
0x37 => Ok(build_set_carry_flag_data()), Opcode::EightBit(0x37) => Ok(build_set_carry_flag_data()),
0x3F => Ok(build_complement_carry_flag_data()), Opcode::EightBit(0x3F) => Ok(build_complement_carry_flag_data()),
0x27 => Ok(build_daa_data()), Opcode::EightBit(0x27) => Ok(build_daa_data()),
0x2F => Ok(build_complement_a_register_data()), Opcode::EightBit(0x2F) => Ok(build_complement_a_register_data()),
0x00 => Ok(build_nop_data()), Opcode::EightBit(0x00) => Ok(build_nop_data()),
0xFB => Ok(build_enable_interrupts_data()), Opcode::EightBit(0xFB) => Ok(build_enable_interrupts_data()),
0xF3 => Ok(build_disable_interrupts_data()), Opcode::EightBit(0xF3) => Ok(build_disable_interrupts_data()),
_ => Err(super::Error::UnknownOpcode(opcode)), _ => Err(super::Error::UnknownOpcode(opcode)),
} }
} }

36
src/cpu/parse/unparsed.rs Normal file
View File

@ -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<u8> for Opcode {
fn from(value: u8) -> Self {
Self::EightBit(value)
}
}
impl From<u16> 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);