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 individually
old-bit-manip
Nick Krichevsky 2023-05-13 13:27:13 -04:00
parent b4b72c73dd
commit b4a24120a2
12 changed files with 243 additions and 444 deletions

View File

@ -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

View File

@ -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,
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}
}
}

View File

@ -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()),

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}