Add unknown opcode type, use it for parsing
parent
8b088da74d
commit
9e785d117c
|
@ -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<T> {
|
||||
/// 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<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> {
|
||||
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 {
|
||||
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())
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Operation, super::Error> {
|
||||
fn operation_for_opcode(opcode: Opcode) -> Result<Operation, super::Error> {
|
||||
operation_for_binary_opcode(opcode).or_parse(operation_for_unary_opcode)
|
||||
}
|
||||
|
||||
fn operand_for_opcode(opcode: u8) -> Result<OpcodeOperand, super::Error> {
|
||||
operand_for_binary_opcode(opcode).or_else(|_err| operand_for_unary_opcode(opcode))
|
||||
fn operand_for_opcode(opcode: Opcode) -> Result<OpcodeOperand, super::Error> {
|
||||
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> {
|
||||
let operation_nibble = opcode & 0xF0;
|
||||
let operand_nibble = opcode & 0x0F;
|
||||
fn operation_for_unary_opcode(opcode: Opcode) -> Result<Operation, super::Error> {
|
||||
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<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 {
|
||||
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<OpcodeOperand, super::Error> {
|
||||
fn operand_for_unary_opcode(opcode: Opcode) -> Result<OpcodeOperand, super::Error> {
|
||||
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<OpcodeOperand, super::Error>
|
|||
} 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<OpcodeOperand, super::Error>
|
|||
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");
|
||||
|
||||
|
|
|
@ -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<ConditionalControlFlowType, parse::Error> {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)),
|
||||
|
|
|
@ -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),
|
||||
)),
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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<register::SingleEightBit, pa
|
|||
0x60 if offset <= 7 => 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<register::SingleEightBit, parse::
|
|||
0x04 => Ok(register::SingleEightBit::H),
|
||||
0x05 => Ok(register::SingleEightBit::L),
|
||||
0x07 => Ok(register::SingleEightBit::A),
|
||||
_ => Err(Error::UnknownOpcode(opcode)),
|
||||
_ => Err(Error::UnknownOpcode(opcode.into())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
Loading…
Reference in New Issue