Refactor arithmetic instructions to deduplicate implementations
There are now no longer instructions for each individual operand - we break it into operand and operations to be handled individuallyold-bit-manip
parent
b4b72c73dd
commit
b4a24120a2
|
@ -14,10 +14,7 @@ pub mod load8;
|
|||
pub enum Instruction {
|
||||
EightBitLoad(load8::EightBitLoadInstruction),
|
||||
SixteenBitLoad(load16::SixteenBitLoadInstruction),
|
||||
EightBitAdd(arith8::EightBitAddInstruction),
|
||||
EightBitSub(arith8::EightBitSubInstruction),
|
||||
EightBitAnd(arith8::EightBitAndInstruction),
|
||||
EightBitXor(arith8::EightBitXorInstruction),
|
||||
EightBitArithmetic(arith8::EightBitArithmeticInstruction),
|
||||
}
|
||||
|
||||
/// `RunnableInstruction` is an instruction that can run on the processor, and has any metadata needed to do so
|
||||
|
|
|
@ -1,40 +1,25 @@
|
|||
//! The `arith8` module holds instructions related to 8-bit arithmetic
|
||||
use crate::register;
|
||||
|
||||
// `EightBitAddInstruction` represents one of the Gameboy's instructions for performing addition on
|
||||
// eight bit numbers
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EightBitAddInstruction {
|
||||
AddSingleRegisterToA { src: register::SingleEightBit },
|
||||
AddImmediateToA { n: u8 },
|
||||
AddHLAddressToA,
|
||||
AddSingleRegisterToAWithCarry { src: register::SingleEightBit },
|
||||
AddImmediateToAWithCarry { n: u8 },
|
||||
AddHLAddressToAWithCarry,
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Operation {
|
||||
Add,
|
||||
AddWithCarry,
|
||||
Sub,
|
||||
SubWithCarry,
|
||||
And,
|
||||
Xor,
|
||||
}
|
||||
|
||||
// `EightBitSubInstruction` represents one of the Gameboy's instructions for performing addition on
|
||||
// eight bit numbers
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EightBitSubInstruction {
|
||||
SubSingleRegisterFromA { src: register::SingleEightBit },
|
||||
SubHLAddressFromA,
|
||||
SubImmediateFromA { n: u8 },
|
||||
SubSingleRegisterFromAWithCarry { src: register::SingleEightBit },
|
||||
SubHLAddressFromAWithCarry,
|
||||
SubImmediateFromAWithCarry { n: u8 },
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Operand {
|
||||
SingleRegister(register::SingleEightBit),
|
||||
HLAddressValue,
|
||||
Immediate(u8),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EightBitAndInstruction {
|
||||
AndSingleRegisterWithA { src: register::SingleEightBit },
|
||||
AndHLAddressWithA,
|
||||
AndImmediateWithA { n: u8 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EightBitXorInstruction {
|
||||
XorSingleRegisterWithA { src: register::SingleEightBit },
|
||||
XorHLAddressWithA,
|
||||
XorImmediateWithA { n: u8 },
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct EightBitArithmeticInstruction {
|
||||
pub operation: Operation,
|
||||
pub operand: Operand,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::{arith8::EightBitAddInstruction, Instruction},
|
||||
instructions::{
|
||||
arith8::{EightBitArithmeticInstruction, Operand, Operation},
|
||||
Instruction,
|
||||
},
|
||||
parse::{self, Error, OpcodeParser, ParseOutput, ParseResult},
|
||||
},
|
||||
memory::View,
|
||||
|
@ -56,38 +59,52 @@ impl OpcodeParser for EightBitAddParser {
|
|||
|
||||
fn build_add_register_to_a_data(src: register::SingleEightBit) -> ParseOutput {
|
||||
super::build_operation_between_register_and_a_data(src, |register| {
|
||||
Instruction::EightBitAdd(EightBitAddInstruction::AddSingleRegisterToA { src: register })
|
||||
build_add_instruction(Operand::SingleRegister(register))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_add_register_to_a_with_carry_data(src: register::SingleEightBit) -> ParseOutput {
|
||||
super::build_operation_between_register_and_a_data(src, |register| {
|
||||
Instruction::EightBitAdd(EightBitAddInstruction::AddSingleRegisterToAWithCarry {
|
||||
src: register,
|
||||
})
|
||||
build_add_with_carry_instruction(Operand::SingleRegister(register))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_add_hl_address_to_a_data() -> ParseOutput {
|
||||
super::build_operation_between_hl_value_and_a_data(Instruction::EightBitAdd(
|
||||
EightBitAddInstruction::AddHLAddressToA,
|
||||
))
|
||||
let ins = build_add_instruction(Operand::HLAddressValue);
|
||||
super::build_operation_between_hl_value_and_a_data(ins)
|
||||
}
|
||||
|
||||
fn build_add_hl_address_to_a_with_carry_data() -> ParseOutput {
|
||||
super::build_operation_between_hl_value_and_a_data(Instruction::EightBitAdd(
|
||||
EightBitAddInstruction::AddHLAddressToAWithCarry,
|
||||
))
|
||||
let ins = build_add_with_carry_instruction(Operand::HLAddressValue);
|
||||
super::build_operation_between_hl_value_and_a_data(ins)
|
||||
}
|
||||
|
||||
fn build_add_immediate_to_a_data(data: &View) -> ParseOutput {
|
||||
super::build_operation_between_immediate_and_a_data(data, |n| {
|
||||
Instruction::EightBitAdd(EightBitAddInstruction::AddImmediateToA { n })
|
||||
build_add_instruction(Operand::Immediate(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_add_immediate_to_a_with_carry_data(data: &View) -> ParseOutput {
|
||||
super::build_operation_between_immediate_and_a_data(data, |n| {
|
||||
Instruction::EightBitAdd(EightBitAddInstruction::AddImmediateToAWithCarry { n })
|
||||
build_add_with_carry_instruction(Operand::Immediate(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_add_instruction(operand: Operand) -> Instruction {
|
||||
let arith_instruction = EightBitArithmeticInstruction {
|
||||
operand,
|
||||
operation: Operation::Add,
|
||||
};
|
||||
|
||||
Instruction::EightBitArithmetic(arith_instruction)
|
||||
}
|
||||
|
||||
fn build_add_with_carry_instruction(operand: Operand) -> Instruction {
|
||||
let arith_instruction = EightBitArithmeticInstruction {
|
||||
operand,
|
||||
operation: Operation::AddWithCarry,
|
||||
};
|
||||
|
||||
Instruction::EightBitArithmetic(arith_instruction)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::{arith8::EightBitAndInstruction, Instruction},
|
||||
instructions::{
|
||||
arith8::{EightBitArithmeticInstruction, Operand, Operation},
|
||||
Instruction,
|
||||
},
|
||||
parse::{self, Error, OpcodeParser, ParseOutput, ParseResult},
|
||||
},
|
||||
memory::View,
|
||||
|
@ -29,18 +32,26 @@ impl OpcodeParser for EightBitAndParser {
|
|||
|
||||
fn build_and_register_with_a_data(src: register::SingleEightBit) -> ParseOutput {
|
||||
super::build_operation_between_register_and_a_data(src, |register| {
|
||||
Instruction::EightBitAnd(EightBitAndInstruction::AndSingleRegisterWithA { src: register })
|
||||
build_and_instruction(Operand::SingleRegister(register))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_and_hl_value_with_a_data() -> ParseOutput {
|
||||
super::build_operation_between_hl_value_and_a_data(Instruction::EightBitAnd(
|
||||
EightBitAndInstruction::AndHLAddressWithA,
|
||||
))
|
||||
let ins = build_and_instruction(Operand::HLAddressValue);
|
||||
super::build_operation_between_hl_value_and_a_data(ins)
|
||||
}
|
||||
|
||||
fn build_and_immediate_with_a_data(data: &View) -> ParseOutput {
|
||||
super::build_operation_between_immediate_and_a_data(data, |n| {
|
||||
Instruction::EightBitAnd(EightBitAndInstruction::AndImmediateWithA { n })
|
||||
build_and_instruction(Operand::Immediate(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_and_instruction(operand: Operand) -> Instruction {
|
||||
let arith_instruction = EightBitArithmeticInstruction {
|
||||
operand,
|
||||
operation: Operation::And,
|
||||
};
|
||||
|
||||
Instruction::EightBitArithmetic(arith_instruction)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::{arith8::EightBitSubInstruction, Instruction},
|
||||
instructions::{
|
||||
arith8::{EightBitArithmeticInstruction, Operand, Operation},
|
||||
Instruction,
|
||||
},
|
||||
parse::{self, Error, OpcodeParser, ParseOutput, ParseResult},
|
||||
},
|
||||
memory::View,
|
||||
|
@ -52,7 +55,7 @@ impl OpcodeParser for EightBitSubParser {
|
|||
|
||||
fn build_sub_register_from_a_data(src_register: register::SingleEightBit) -> ParseOutput {
|
||||
super::build_operation_between_register_and_a_data(src_register, |register| {
|
||||
Instruction::EightBitSub(EightBitSubInstruction::SubSingleRegisterFromA { src: register })
|
||||
build_sub_instruction(Operand::SingleRegister(register))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -60,32 +63,46 @@ fn build_sub_register_from_a_with_carry_data(
|
|||
src_register: register::SingleEightBit,
|
||||
) -> ParseOutput {
|
||||
super::build_operation_between_register_and_a_data(src_register, |register| {
|
||||
Instruction::EightBitSub(EightBitSubInstruction::SubSingleRegisterFromAWithCarry {
|
||||
src: register,
|
||||
})
|
||||
build_sub_with_carry_instruction(Operand::SingleRegister(register))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_sub_hl_value_from_a_data() -> ParseOutput {
|
||||
super::build_operation_between_hl_value_and_a_data(Instruction::EightBitSub(
|
||||
EightBitSubInstruction::SubHLAddressFromA,
|
||||
))
|
||||
let ins = build_sub_instruction(Operand::HLAddressValue);
|
||||
super::build_operation_between_hl_value_and_a_data(ins)
|
||||
}
|
||||
|
||||
fn build_sub_hl_value_from_a_with_carry_data() -> ParseOutput {
|
||||
super::build_operation_between_hl_value_and_a_data(Instruction::EightBitSub(
|
||||
EightBitSubInstruction::SubHLAddressFromAWithCarry,
|
||||
))
|
||||
let ins = build_sub_with_carry_instruction(Operand::HLAddressValue);
|
||||
super::build_operation_between_hl_value_and_a_data(ins)
|
||||
}
|
||||
|
||||
fn build_sub_immediate_from_a_data(data: &View) -> ParseOutput {
|
||||
super::build_operation_between_immediate_and_a_data(data, |n| {
|
||||
Instruction::EightBitSub(EightBitSubInstruction::SubImmediateFromA { n })
|
||||
build_sub_instruction(Operand::Immediate(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_sub_immediate_from_a_with_carry_data(data: &View) -> ParseOutput {
|
||||
super::build_operation_between_immediate_and_a_data(data, |n| {
|
||||
Instruction::EightBitSub(EightBitSubInstruction::SubImmediateFromAWithCarry { n })
|
||||
build_sub_with_carry_instruction(Operand::Immediate(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_sub_instruction(operand: Operand) -> Instruction {
|
||||
let arith_instruction = EightBitArithmeticInstruction {
|
||||
operand,
|
||||
operation: Operation::Sub,
|
||||
};
|
||||
|
||||
Instruction::EightBitArithmetic(arith_instruction)
|
||||
}
|
||||
|
||||
fn build_sub_with_carry_instruction(operand: Operand) -> Instruction {
|
||||
let arith_instruction = EightBitArithmeticInstruction {
|
||||
operand,
|
||||
operation: Operation::SubWithCarry,
|
||||
};
|
||||
|
||||
Instruction::EightBitArithmetic(arith_instruction)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::{arith8::EightBitXorInstruction, Instruction},
|
||||
instructions::{
|
||||
arith8::{EightBitArithmeticInstruction, Operand, Operation},
|
||||
Instruction,
|
||||
},
|
||||
parse::{self, Error, OpcodeParser, ParseOutput, ParseResult},
|
||||
},
|
||||
memory::View,
|
||||
|
@ -29,18 +32,26 @@ impl OpcodeParser for EightBitXorParser {
|
|||
|
||||
fn build_xor_register_with_a_data(src: register::SingleEightBit) -> ParseOutput {
|
||||
super::build_operation_between_register_and_a_data(src, |register| {
|
||||
Instruction::EightBitXor(EightBitXorInstruction::XorSingleRegisterWithA { src: register })
|
||||
build_xor_instruction(Operand::SingleRegister(register))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_xor_hl_value_with_a_data() -> ParseOutput {
|
||||
super::build_operation_between_hl_value_and_a_data(Instruction::EightBitXor(
|
||||
EightBitXorInstruction::XorHLAddressWithA,
|
||||
))
|
||||
let ins = build_xor_instruction(Operand::HLAddressValue);
|
||||
super::build_operation_between_hl_value_and_a_data(ins)
|
||||
}
|
||||
|
||||
fn build_xor_immediate_with_a_data(data: &View) -> ParseOutput {
|
||||
super::build_operation_between_immediate_and_a_data(data, |n| {
|
||||
Instruction::EightBitXor(EightBitXorInstruction::XorImmediateWithA { n })
|
||||
build_xor_instruction(Operand::Immediate(n))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_xor_instruction(operand: Operand) -> Instruction {
|
||||
let arith_instruction = EightBitArithmeticInstruction {
|
||||
operand,
|
||||
operation: Operation::Xor,
|
||||
};
|
||||
|
||||
Instruction::EightBitArithmetic(arith_instruction)
|
||||
}
|
||||
|
|
|
@ -41,17 +41,8 @@ pub fn run_instruction(processor: &mut Processor, instruction: Instruction) -> R
|
|||
Instruction::SixteenBitLoad(load_instruction) => {
|
||||
load16::SixteenBitLoadRunner::run_instruction(processor, load_instruction)
|
||||
}
|
||||
Instruction::EightBitAdd(add_instruction) => {
|
||||
arith8::EightBitAddRunner::run_instruction(processor, add_instruction)
|
||||
}
|
||||
Instruction::EightBitSub(sub_instruction) => {
|
||||
arith8::EightBitSubRunner::run_instruction(processor, sub_instruction)
|
||||
}
|
||||
Instruction::EightBitAnd(and_instruction) => {
|
||||
arith8::EightBitAndRunner::run_instruction(processor, and_instruction)
|
||||
}
|
||||
Instruction::EightBitXor(xor_instruction) => {
|
||||
arith8::EightBitXorRunner::run_instruction(processor, xor_instruction)
|
||||
Instruction::EightBitArithmetic(arith_instruction) => {
|
||||
arith8::EightBitArithmeticRunner::run_instruction(processor, arith_instruction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,68 @@
|
|||
use crate::{cpu::run::Error, cpu::Processor, memory, register};
|
||||
use crate::{
|
||||
cpu::{instructions::arith8::EightBitArithmeticInstruction, run::Error},
|
||||
cpu::{
|
||||
instructions::arith8::{Operand, Operation},
|
||||
Processor,
|
||||
},
|
||||
memory, register,
|
||||
};
|
||||
|
||||
pub use add::EightBitAddRunner;
|
||||
pub use and::EightBitAndRunner;
|
||||
pub use sub::EightBitSubRunner;
|
||||
pub use xor::EightBitXorRunner;
|
||||
|
||||
use super::arithutil::{self, CarriedNumber};
|
||||
use super::{
|
||||
arithutil::{self, CarriedNumber},
|
||||
InstructionRunner,
|
||||
};
|
||||
|
||||
mod add;
|
||||
mod and;
|
||||
mod sub;
|
||||
mod xor;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum EightBitArithmeticOperation {
|
||||
SingleRegisterToA { src: register::SingleEightBit },
|
||||
ImmediateToA { n: u8 },
|
||||
HLAddressToA,
|
||||
pub struct EightBitArithmeticRunner;
|
||||
|
||||
impl InstructionRunner<EightBitArithmeticInstruction> for EightBitArithmeticRunner {
|
||||
fn run_instruction(
|
||||
processor: &mut Processor,
|
||||
instruction: EightBitArithmeticInstruction,
|
||||
) -> Result<(), Error> {
|
||||
match instruction.operation {
|
||||
Operation::And => {
|
||||
let (lhs, rhs) = gather_operands(processor, instruction.operand)?;
|
||||
and::run(processor, lhs, rhs);
|
||||
}
|
||||
|
||||
Operation::Xor => {
|
||||
let (lhs, rhs) = gather_operands(processor, instruction.operand)?;
|
||||
xor::run(processor, lhs, rhs);
|
||||
}
|
||||
|
||||
Operation::Add => {
|
||||
let (lhs, rhs) = gather_operands(processor, instruction.operand)?;
|
||||
add::run(processor, lhs, rhs);
|
||||
}
|
||||
|
||||
Operation::AddWithCarry => {
|
||||
let (lhs, rhs) = gather_operands_with_carry(processor, instruction.operand)?;
|
||||
add::run(processor, lhs, rhs);
|
||||
}
|
||||
|
||||
Operation::Sub => {
|
||||
let (lhs, rhs) = gather_operands(processor, instruction.operand)?;
|
||||
sub::run(processor, lhs, rhs);
|
||||
}
|
||||
|
||||
Operation::SubWithCarry => {
|
||||
let (lhs, rhs) = gather_operands_with_carry(processor, instruction.operand)?;
|
||||
sub::run(processor, lhs, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_operands(
|
||||
processor: &mut Processor,
|
||||
operation: EightBitArithmeticOperation,
|
||||
) -> Result<(u8, u8), Error> {
|
||||
match operation {
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src } => {
|
||||
fn gather_operands(processor: &mut Processor, operand: Operand) -> Result<(u8, u8), Error> {
|
||||
match operand {
|
||||
Operand::SingleRegister(src) => {
|
||||
let a_value = processor
|
||||
.registers
|
||||
.get_single_8bit_register(register::SingleEightBit::A);
|
||||
|
@ -33,7 +71,7 @@ fn gather_operands(
|
|||
Ok((a_value, src_register_value))
|
||||
}
|
||||
|
||||
EightBitArithmeticOperation::ImmediateToA { n } => {
|
||||
Operand::Immediate(n) => {
|
||||
let a_value = processor
|
||||
.registers
|
||||
.get_single_8bit_register(register::SingleEightBit::A);
|
||||
|
@ -41,7 +79,7 @@ fn gather_operands(
|
|||
Ok((a_value, n))
|
||||
}
|
||||
|
||||
EightBitArithmeticOperation::HLAddressToA => {
|
||||
Operand::HLAddressValue => {
|
||||
let a_value = processor
|
||||
.registers
|
||||
.get_single_8bit_register(register::SingleEightBit::A);
|
||||
|
@ -70,9 +108,9 @@ fn gather_operands(
|
|||
|
||||
fn gather_operands_with_carry(
|
||||
processor: &mut Processor,
|
||||
operation: EightBitArithmeticOperation,
|
||||
operand: Operand,
|
||||
) -> Result<(u8, CarriedNumber<u8>), Error> {
|
||||
let (lhs, no_carry_rhs) = gather_operands(processor, operation)?;
|
||||
let (lhs, no_carry_rhs) = gather_operands(processor, operand)?;
|
||||
let rhs = attach_carry_bit_to_operand(processor, no_carry_rhs)?;
|
||||
|
||||
Ok((lhs, rhs))
|
||||
|
@ -134,11 +172,8 @@ mod tests {
|
|||
.registers
|
||||
.set_single_8bit_register(src_register, 0xBB);
|
||||
|
||||
let (lhs, rhs) = gather_operands(
|
||||
&mut processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src: src_register },
|
||||
)
|
||||
.expect("failed to gather operands");
|
||||
let (lhs, rhs) = gather_operands(&mut processor, Operand::SingleRegister(src_register))
|
||||
.expect("failed to gather operands");
|
||||
|
||||
assert_eq!((0xAA, 0xBB), (lhs, rhs));
|
||||
}
|
||||
|
@ -152,9 +187,7 @@ mod tests {
|
|||
|
||||
let (lhs, rhs) = gather_operands(
|
||||
&mut processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA {
|
||||
src: register::SingleEightBit::A,
|
||||
},
|
||||
Operand::SingleRegister(register::SingleEightBit::A),
|
||||
)
|
||||
.expect("failed to gather operands");
|
||||
|
||||
|
@ -167,11 +200,8 @@ mod tests {
|
|||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
|
||||
let (lhs, rhs) = gather_operands(
|
||||
&mut processor,
|
||||
EightBitArithmeticOperation::ImmediateToA { n: 0x45 },
|
||||
)
|
||||
.expect("failed to gather operands");
|
||||
let (lhs, rhs) = gather_operands(&mut processor, Operand::Immediate(0x45))
|
||||
.expect("failed to gather operands");
|
||||
|
||||
assert_eq!((0xAA, 0x45), (lhs, rhs));
|
||||
}
|
||||
|
@ -190,7 +220,7 @@ mod tests {
|
|||
.set(0xFFAA, 0xBB)
|
||||
.expect("failed to set memory value");
|
||||
|
||||
let (lhs, rhs) = gather_operands(&mut processor, EightBitArithmeticOperation::HLAddressToA)
|
||||
let (lhs, rhs) = gather_operands(&mut processor, Operand::HLAddressValue)
|
||||
.expect("failed to gather operands");
|
||||
|
||||
assert_eq!((0xAA, 0xBB), (lhs, rhs));
|
||||
|
@ -223,11 +253,9 @@ mod tests {
|
|||
.registers
|
||||
.set_single_8bit_register(src_register, 0xBB);
|
||||
|
||||
let (lhs, rhs) = gather_operands_with_carry(
|
||||
&mut processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src: src_register },
|
||||
)
|
||||
.expect("failed to gather operands");
|
||||
let (lhs, rhs) =
|
||||
gather_operands_with_carry(&mut processor, Operand::SingleRegister(src_register))
|
||||
.expect("failed to gather operands");
|
||||
|
||||
assert_eq!(
|
||||
(0xAA, CarriedNumber::new(0xBB, carry_bit).unwrap()),
|
||||
|
@ -248,9 +276,7 @@ mod tests {
|
|||
|
||||
let (lhs, rhs) = gather_operands_with_carry(
|
||||
&mut processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA {
|
||||
src: register::SingleEightBit::A,
|
||||
},
|
||||
Operand::SingleRegister(register::SingleEightBit::A),
|
||||
)
|
||||
.expect("failed to gather operands");
|
||||
|
||||
|
@ -270,11 +296,8 @@ mod tests {
|
|||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
|
||||
let (lhs, rhs) = gather_operands_with_carry(
|
||||
&mut processor,
|
||||
EightBitArithmeticOperation::ImmediateToA { n: 0x45 },
|
||||
)
|
||||
.expect("failed to gather operands");
|
||||
let (lhs, rhs) = gather_operands_with_carry(&mut processor, Operand::Immediate(0x45))
|
||||
.expect("failed to gather operands");
|
||||
|
||||
assert_eq!(
|
||||
(0xAA, CarriedNumber::new(0x45, carry_bit).unwrap()),
|
||||
|
@ -300,9 +323,8 @@ mod tests {
|
|||
.set(0xFFAA, 0xBB)
|
||||
.expect("failed to set memory value");
|
||||
|
||||
let (lhs, rhs) =
|
||||
gather_operands_with_carry(&mut processor, EightBitArithmeticOperation::HLAddressToA)
|
||||
.expect("failed to gather operands");
|
||||
let (lhs, rhs) = gather_operands_with_carry(&mut processor, Operand::HLAddressValue)
|
||||
.expect("failed to gather operands");
|
||||
|
||||
assert_eq!(
|
||||
(0xAA, CarriedNumber::new(0xBB, carry_bit).unwrap()),
|
||||
|
|
|
@ -1,106 +1,20 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::arith8::EightBitAddInstruction,
|
||||
run::{arithutil::CarryingAdd, Error, InstructionRunner},
|
||||
Processor,
|
||||
},
|
||||
cpu::{run::arithutil::CarryingAdd, Processor},
|
||||
register,
|
||||
};
|
||||
|
||||
use super::EightBitArithmeticOperation;
|
||||
|
||||
pub struct EightBitAddRunner;
|
||||
|
||||
impl EightBitAddRunner {
|
||||
fn do_add<T>(processor: &mut Processor, lhs: u8, rhs: T)
|
||||
where
|
||||
u8: CarryingAdd<T, Output = u8>,
|
||||
{
|
||||
let result = lhs.add_with_carry(rhs);
|
||||
Self::store_addition_result(processor, result);
|
||||
}
|
||||
|
||||
fn store_addition_result(
|
||||
processor: &mut Processor,
|
||||
(total, half_carry, carry): (u8, bool, bool),
|
||||
) {
|
||||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register::SingleEightBit::A, total);
|
||||
|
||||
super::set_addition_flags(processor, total, half_carry, carry);
|
||||
}
|
||||
pub fn run<T>(processor: &mut Processor, lhs: u8, rhs: T)
|
||||
where
|
||||
u8: CarryingAdd<T, Output = u8>,
|
||||
{
|
||||
let result = lhs.add_with_carry(rhs);
|
||||
store_addition_result(processor, result);
|
||||
}
|
||||
|
||||
impl InstructionRunner<EightBitAddInstruction> for EightBitAddRunner {
|
||||
fn run_instruction(
|
||||
processor: &mut Processor,
|
||||
instruction: EightBitAddInstruction,
|
||||
) -> Result<(), Error> {
|
||||
match instruction {
|
||||
EightBitAddInstruction::AddSingleRegisterToA { src } => {
|
||||
let (lhs, rhs) = super::gather_operands(
|
||||
processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src },
|
||||
)?;
|
||||
fn store_addition_result(processor: &mut Processor, (total, half_carry, carry): (u8, bool, bool)) {
|
||||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register::SingleEightBit::A, total);
|
||||
|
||||
Self::do_add(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitAddInstruction::AddImmediateToA { n } => {
|
||||
let (lhs, rhs) = super::gather_operands(
|
||||
processor,
|
||||
EightBitArithmeticOperation::ImmediateToA { n },
|
||||
)?;
|
||||
|
||||
Self::do_add(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitAddInstruction::AddHLAddressToA => {
|
||||
let (lhs, rhs) =
|
||||
super::gather_operands(processor, EightBitArithmeticOperation::HLAddressToA)?;
|
||||
|
||||
Self::do_add(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitAddInstruction::AddSingleRegisterToAWithCarry { src } => {
|
||||
let (lhs, rhs) = super::gather_operands_with_carry(
|
||||
processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src },
|
||||
)?;
|
||||
|
||||
Self::do_add(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitAddInstruction::AddImmediateToAWithCarry { n } => {
|
||||
let (lhs, rhs) = super::gather_operands_with_carry(
|
||||
processor,
|
||||
EightBitArithmeticOperation::ImmediateToA { n },
|
||||
)?;
|
||||
|
||||
Self::do_add(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitAddInstruction::AddHLAddressToAWithCarry => {
|
||||
let (lhs, rhs) = super::gather_operands_with_carry(
|
||||
processor,
|
||||
EightBitArithmeticOperation::HLAddressToA,
|
||||
)?;
|
||||
|
||||
Self::do_add(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
super::set_addition_flags(processor, total, half_carry, carry);
|
||||
}
|
||||
|
|
|
@ -1,59 +1,17 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::arith8::EightBitAndInstruction,
|
||||
run::{Error, InstructionRunner},
|
||||
Processor,
|
||||
},
|
||||
register,
|
||||
};
|
||||
use crate::{cpu::Processor, register};
|
||||
|
||||
use super::EightBitArithmeticOperation;
|
||||
pub fn run(processor: &mut Processor, lhs: u8, rhs: u8) {
|
||||
let result = lhs & rhs;
|
||||
|
||||
pub struct EightBitAndRunner;
|
||||
|
||||
impl From<EightBitAndInstruction> for EightBitArithmeticOperation {
|
||||
fn from(value: EightBitAndInstruction) -> Self {
|
||||
match value {
|
||||
EightBitAndInstruction::AndSingleRegisterWithA { src } => {
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src }
|
||||
}
|
||||
|
||||
EightBitAndInstruction::AndImmediateWithA { n } => {
|
||||
EightBitArithmeticOperation::ImmediateToA { n }
|
||||
}
|
||||
|
||||
EightBitAndInstruction::AndHLAddressWithA => EightBitArithmeticOperation::HLAddressToA,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EightBitAndRunner {
|
||||
fn do_and(processor: &mut Processor, lhs: u8, rhs: u8) {
|
||||
let result = lhs & rhs;
|
||||
|
||||
processor.registers.a = result;
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Zero, (result == 0).into());
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Subtract, 0);
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::HalfCarry, 1);
|
||||
processor.registers.set_flag_bit(register::Flag::Carry, 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl InstructionRunner<EightBitAndInstruction> for EightBitAndRunner {
|
||||
fn run_instruction(
|
||||
processor: &mut Processor,
|
||||
instruction: EightBitAndInstruction,
|
||||
) -> Result<(), Error> {
|
||||
let (lhs, rhs) = super::gather_operands(processor, instruction.into())?;
|
||||
|
||||
Self::do_and(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
processor.registers.a = result;
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Zero, (result == 0).into());
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Subtract, 0);
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::HalfCarry, 1);
|
||||
processor.registers.set_flag_bit(register::Flag::Carry, 0);
|
||||
}
|
||||
|
|
|
@ -1,106 +1,23 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::arith8::EightBitSubInstruction,
|
||||
run::{arithutil::CarryingSub, Error, InstructionRunner},
|
||||
Processor,
|
||||
},
|
||||
cpu::{run::arithutil::CarryingSub, Processor},
|
||||
register,
|
||||
};
|
||||
|
||||
use super::EightBitArithmeticOperation;
|
||||
|
||||
pub struct EightBitSubRunner;
|
||||
|
||||
impl EightBitSubRunner {
|
||||
fn do_sub<T>(processor: &mut Processor, lhs: u8, rhs: T)
|
||||
where
|
||||
u8: CarryingSub<T, Output = u8>,
|
||||
{
|
||||
let result = lhs.sub_with_carry(rhs);
|
||||
Self::store_subtraction_result(processor, result);
|
||||
}
|
||||
|
||||
fn store_subtraction_result(
|
||||
processor: &mut Processor,
|
||||
(total, half_carry, carry): (u8, bool, bool),
|
||||
) {
|
||||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register::SingleEightBit::A, total);
|
||||
|
||||
super::set_subtraction_flags(processor, total, half_carry, carry);
|
||||
}
|
||||
pub fn run<T>(processor: &mut Processor, lhs: u8, rhs: T)
|
||||
where
|
||||
u8: CarryingSub<T, Output = u8>,
|
||||
{
|
||||
let result = lhs.sub_with_carry(rhs);
|
||||
store_subtraction_result(processor, result);
|
||||
}
|
||||
|
||||
impl InstructionRunner<EightBitSubInstruction> for EightBitSubRunner {
|
||||
fn run_instruction(
|
||||
processor: &mut Processor,
|
||||
instruction: EightBitSubInstruction,
|
||||
) -> Result<(), Error> {
|
||||
match instruction {
|
||||
EightBitSubInstruction::SubSingleRegisterFromA { src } => {
|
||||
let (lhs, rhs) = super::gather_operands(
|
||||
processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src },
|
||||
)?;
|
||||
fn store_subtraction_result(
|
||||
processor: &mut Processor,
|
||||
(total, half_carry, carry): (u8, bool, bool),
|
||||
) {
|
||||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register::SingleEightBit::A, total);
|
||||
|
||||
Self::do_sub(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitSubInstruction::SubImmediateFromA { n } => {
|
||||
let (lhs, rhs) = super::gather_operands(
|
||||
processor,
|
||||
EightBitArithmeticOperation::ImmediateToA { n },
|
||||
)?;
|
||||
|
||||
Self::do_sub(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitSubInstruction::SubHLAddressFromA => {
|
||||
let (lhs, rhs) =
|
||||
super::gather_operands(processor, EightBitArithmeticOperation::HLAddressToA)?;
|
||||
|
||||
Self::do_sub(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitSubInstruction::SubSingleRegisterFromAWithCarry { src } => {
|
||||
let (lhs, rhs) = super::gather_operands_with_carry(
|
||||
processor,
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src },
|
||||
)?;
|
||||
|
||||
Self::do_sub(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitSubInstruction::SubImmediateFromAWithCarry { n } => {
|
||||
let (lhs, rhs) = super::gather_operands_with_carry(
|
||||
processor,
|
||||
EightBitArithmeticOperation::ImmediateToA { n },
|
||||
)?;
|
||||
|
||||
Self::do_sub(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
EightBitSubInstruction::SubHLAddressFromAWithCarry => {
|
||||
let (lhs, rhs) = super::gather_operands_with_carry(
|
||||
processor,
|
||||
EightBitArithmeticOperation::HLAddressToA,
|
||||
)?;
|
||||
|
||||
Self::do_sub(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
super::set_subtraction_flags(processor, total, half_carry, carry);
|
||||
}
|
||||
|
|
|
@ -1,57 +1,16 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::arith8::EightBitXorInstruction,
|
||||
run::{Error, InstructionRunner},
|
||||
Processor,
|
||||
},
|
||||
register,
|
||||
};
|
||||
use crate::{cpu::Processor, register};
|
||||
|
||||
use super::{gather_operands, EightBitArithmeticOperation};
|
||||
|
||||
pub struct EightBitXorRunner;
|
||||
|
||||
impl From<EightBitXorInstruction> for EightBitArithmeticOperation {
|
||||
fn from(value: EightBitXorInstruction) -> Self {
|
||||
match value {
|
||||
EightBitXorInstruction::XorSingleRegisterWithA { src } => {
|
||||
EightBitArithmeticOperation::SingleRegisterToA { src }
|
||||
}
|
||||
|
||||
EightBitXorInstruction::XorImmediateWithA { n } => {
|
||||
EightBitArithmeticOperation::ImmediateToA { n }
|
||||
}
|
||||
|
||||
EightBitXorInstruction::XorHLAddressWithA => EightBitArithmeticOperation::HLAddressToA,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EightBitXorRunner {
|
||||
fn do_xor(processor: &mut Processor, lhs: u8, rhs: u8) {
|
||||
let result = lhs ^ rhs;
|
||||
processor.registers.a = result;
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Zero, (result == 0).into());
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Subtract, 0);
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::HalfCarry, 0);
|
||||
processor.registers.set_flag_bit(register::Flag::Carry, 0);
|
||||
}
|
||||
}
|
||||
|
||||
impl InstructionRunner<EightBitXorInstruction> for EightBitXorRunner {
|
||||
fn run_instruction(
|
||||
processor: &mut Processor,
|
||||
instruction: EightBitXorInstruction,
|
||||
) -> Result<(), Error> {
|
||||
let (lhs, rhs) = gather_operands(processor, instruction.into())?;
|
||||
Self::do_xor(processor, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn run(processor: &mut Processor, lhs: u8, rhs: u8) {
|
||||
let result = lhs ^ rhs;
|
||||
processor.registers.a = result;
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Zero, (result == 0).into());
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::Subtract, 0);
|
||||
processor
|
||||
.registers
|
||||
.set_flag_bit(register::Flag::HalfCarry, 0);
|
||||
processor.registers.set_flag_bit(register::Flag::Carry, 0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue