Refactor eight bit arithmetic to extract operand collection

old-bit-manip
Nick Krichevsky 2023-05-07 16:08:49 -04:00
parent 01a68e1415
commit 4fb9144c6d
4 changed files with 415 additions and 211 deletions

View File

@ -1,12 +1,90 @@
use crate::cpu::Processor;
use crate::register;
use crate::{cpu::run::Error, cpu::Processor, memory, register};
pub use add::EightBitAddRunner;
pub use sub::EightBitSubRunner;
use super::arithutil::{self, CarriedNumber};
mod add;
mod sub;
#[derive(Debug, Clone, Copy)]
enum EightBitArithmeticOperation {
SingleRegisterToA { src: register::SingleEightBit },
ImmediateToA { n: u8 },
HLAddressToA,
}
fn gather_operands(
processor: &mut Processor,
operation: EightBitArithmeticOperation,
) -> Result<(u8, u8), Error> {
match operation {
EightBitArithmeticOperation::SingleRegisterToA { src } => {
let a_value = processor
.registers
.get_single_8bit_register(register::SingleEightBit::A);
let src_register_value = processor.registers.get_single_8bit_register(src);
Ok((a_value, src_register_value))
}
EightBitArithmeticOperation::ImmediateToA { n } => {
let a_value = processor
.registers
.get_single_8bit_register(register::SingleEightBit::A);
Ok((a_value, n))
}
EightBitArithmeticOperation::HLAddressToA => {
let a_value = processor
.registers
.get_single_8bit_register(register::SingleEightBit::A);
let src_addr = processor
.registers
.get_combined_register(register::Combined::HL);
// While this is true, we really do want a wildcard match in map_err
#[allow(clippy::match_wildcard_for_single_variants)]
let hl_addr_value = processor
.memory
.get(src_addr.into())
.map_err(|err| match err {
memory::Error::GetInvalidAddress(bad_addr) => Error::InvalidRegisterAddress(
register::SixteenBit::Combined(register::Combined::HL),
bad_addr,
),
err => Error::Unknown(Box::new(err)),
})?;
Ok((a_value, hl_addr_value))
}
}
}
fn gather_operands_with_carry(
processor: &mut Processor,
operation: EightBitArithmeticOperation,
) -> Result<(u8, CarriedNumber<u8>), Error> {
let (lhs, no_carry_rhs) = gather_operands(processor, operation)?;
let rhs = attach_carry_bit_to_operand(processor, no_carry_rhs)?;
Ok((lhs, rhs))
}
fn attach_carry_bit_to_operand(
processor: &mut Processor,
operand: u8,
) -> Result<CarriedNumber<u8>, Error> {
let carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
CarriedNumber::new(operand, carry_bit).map_err(|err| match err {
arithutil::Error::InvalidCarryBit(value) => Error::InvalidCarryFlagValue(value),
})
}
fn set_subtraction_flags(processor: &mut Processor, total: u8, half_carry: bool, carry: bool) {
set_addition_flags(processor, total, half_carry, carry);
processor
@ -31,3 +109,200 @@ fn set_addition_flags(processor: &mut Processor, total: u8, half_carry: bool, ca
.registers
.set_flag_bit(register::Flag::Carry, carry.into());
}
#[cfg(test)]
mod tests {
use super::*;
use test_case::test_case;
#[test_case(register::SingleEightBit::B)]
#[test_case(register::SingleEightBit::C)]
#[test_case(register::SingleEightBit::D)]
#[test_case(register::SingleEightBit::E)]
#[test_case(register::SingleEightBit::H)]
#[test_case(register::SingleEightBit::L)]
fn test_gather_operands_from_single_register_to_a(src_register: register::SingleEightBit) {
let mut processor = Processor::default();
processor
.registers
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
processor
.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");
assert_eq!((0xAA, 0xBB), (lhs, rhs));
}
#[test]
fn test_gather_operands_from_single_register_to_a_with_itself() {
let mut processor = Processor::default();
processor
.registers
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
let (lhs, rhs) = gather_operands(
&mut processor,
EightBitArithmeticOperation::SingleRegisterToA {
src: register::SingleEightBit::A,
},
)
.expect("failed to gather operands");
assert_eq!((0xAA, 0xAA), (lhs, rhs));
}
#[test]
fn test_gather_operands_from_immediate_to_a() {
let mut processor = Processor::default();
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");
assert_eq!((0xAA, 0x45), (lhs, rhs));
}
#[test]
fn test_gather_operands_from_hl_value_a() {
let mut processor = Processor::default();
processor
.registers
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
processor
.registers
.set_combined_register(register::Combined::HL, 0xFFAA);
processor
.memory
.set(0xFFAA, 0xBB)
.expect("failed to set memory value");
let (lhs, rhs) = gather_operands(&mut processor, EightBitArithmeticOperation::HLAddressToA)
.expect("failed to gather operands");
assert_eq!((0xAA, 0xBB), (lhs, rhs));
}
#[test_case(register::SingleEightBit::B, 0; "register b, no carry bit")]
#[test_case(register::SingleEightBit::B, 1; "register b, carry bit")]
#[test_case(register::SingleEightBit::C, 0; "register c, no carry bit")]
#[test_case(register::SingleEightBit::C, 1; "register c, carry bit")]
#[test_case(register::SingleEightBit::D, 0; "register d, no carry bit")]
#[test_case(register::SingleEightBit::D, 1; "register d, carry bit")]
#[test_case(register::SingleEightBit::E, 0; "register e, carry bit")]
#[test_case(register::SingleEightBit::E, 1; "register e, no carry bit")]
#[test_case(register::SingleEightBit::H, 0; "register h, carry bit")]
#[test_case(register::SingleEightBit::H, 1; "register h, no carry bit")]
#[test_case(register::SingleEightBit::L, 0; "register l, carry bit")]
#[test_case(register::SingleEightBit::L, 1; "register l, no carry bit")]
fn test_gather_operands_with_carry_from_single_register_to_a(
src_register: register::SingleEightBit,
carry_bit: u8,
) {
let mut processor = Processor::default();
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
processor
.registers
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
processor
.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");
assert_eq!(
(0xAA, CarriedNumber::new(0xBB, carry_bit).unwrap()),
(lhs, rhs)
);
}
#[test_case(0; "no carry bit")]
#[test_case(1; "carry bit")]
fn test_gather_operands_with_carry_from_single_register_to_a_with_itself(carry_bit: u8) {
let mut processor = Processor::default();
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
processor
.registers
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
let (lhs, rhs) = gather_operands_with_carry(
&mut processor,
EightBitArithmeticOperation::SingleRegisterToA {
src: register::SingleEightBit::A,
},
)
.expect("failed to gather operands");
assert_eq!(
(0xAA, CarriedNumber::new(0xAA, carry_bit).unwrap()),
(lhs, rhs)
);
}
#[test_case(0; "no carry bit")]
#[test_case(1; "carry bit")]
fn test_gather_operands_with_carry_from_immediate_to_a(carry_bit: u8) {
let mut processor = Processor::default();
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
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");
assert_eq!(
(0xAA, CarriedNumber::new(0x45, carry_bit).unwrap()),
(lhs, rhs)
);
}
#[test_case(0; "no carry bit")]
#[test_case(1; "carry bit")]
fn test_gather_with_carry_operands_from_hl_value_a(carry_bit: u8) {
let mut processor = Processor::default();
processor
.registers
.set_flag_bit(register::Flag::Carry, carry_bit);
processor
.registers
.set_single_8bit_register(register::SingleEightBit::A, 0xAA);
processor
.registers
.set_combined_register(register::Combined::HL, 0xFFAA);
processor
.memory
.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");
assert_eq!(
(0xAA, CarriedNumber::new(0xBB, carry_bit).unwrap()),
(lhs, rhs)
);
}
}

View File

@ -1,17 +1,37 @@
use crate::{
cpu::{
instructions::arith8::EightBitAddInstruction,
run::{
arithutil::{self, CarriedNumber, CarryingAdd},
Error, InstructionRunner,
},
run::{arithutil::CarryingAdd, Error, InstructionRunner},
Processor,
},
memory, register,
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);
}
}
impl InstructionRunner<EightBitAddInstruction> for EightBitAddRunner {
fn run_instruction(
processor: &mut Processor,
@ -19,134 +39,68 @@ impl InstructionRunner<EightBitAddInstruction> for EightBitAddRunner {
) -> Result<(), Error> {
match *instruction {
EightBitAddInstruction::AddSingleRegisterToA { src } => {
let a_value = processor
.registers
.get_single_8bit_register(register::SingleEightBit::A);
let src_value = processor.registers.get_single_8bit_register(src);
let (lhs, rhs) = super::gather_operands(
processor,
EightBitArithmeticOperation::SingleRegisterToA { src },
)?;
let result = a_value.add_with_carry(src_value);
store_addition_result(processor, result);
Self::do_add(processor, lhs, rhs);
Ok(())
}
EightBitAddInstruction::AddImmediateToA { n } => {
let result = processor
.registers
.get_single_8bit_register(register::SingleEightBit::A)
.add_with_carry(n);
let (lhs, rhs) = super::gather_operands(
processor,
EightBitArithmeticOperation::ImmediateToA { n },
)?;
store_addition_result(processor, result);
Self::do_add(processor, lhs, rhs);
Ok(())
}
EightBitAddInstruction::AddHLAddressToA => {
let src_addr = processor
.registers
.get_combined_register(register::Combined::HL);
let (lhs, rhs) =
super::gather_operands(processor, EightBitArithmeticOperation::HLAddressToA)?;
// While this is true, we really do want a wildcard match in map_err
#[allow(clippy::match_wildcard_for_single_variants)]
let hl_addr_value =
processor
.memory
.get(src_addr.into())
.map_err(|err| match err {
memory::Error::GetInvalidAddress(bad_addr) => {
Error::InvalidRegisterAddress(
register::SixteenBit::Combined(register::Combined::HL),
bad_addr,
)
}
err => Error::Unknown(Box::new(err)),
})?;
let result = processor
.registers
.get_single_8bit_register(register::SingleEightBit::A)
.add_with_carry(hl_addr_value);
store_addition_result(processor, result);
Self::do_add(processor, lhs, rhs);
Ok(())
}
EightBitAddInstruction::AddSingleRegisterToAWithCarry { src } => {
let src_register_value = processor.registers.get_single_8bit_register(src);
let (lhs, rhs) = super::gather_operands_with_carry(
processor,
EightBitArithmeticOperation::SingleRegisterToA { src },
)?;
let carried_operand = CarriedNumber::new(
src_register_value,
processor.registers.get_flag_bit(register::Flag::Carry),
)
.map_err(|err| match err {
arithutil::Error::InvalidCarryBit(value) => Error::InvalidCarryFlagValue(value),
})?;
let result = processor.registers.a.add_with_carry(carried_operand);
store_addition_result(processor, result);
Self::do_add(processor, lhs, rhs);
Ok(())
}
EightBitAddInstruction::AddImmediateToAWithCarry { n } => {
let a_value = processor.registers.a;
let carried_operand =
CarriedNumber::new(n, processor.registers.get_flag_bit(register::Flag::Carry))
.map_err(|err| match err {
arithutil::Error::InvalidCarryBit(value) => {
Error::InvalidCarryFlagValue(value)
}
})?;
let (lhs, rhs) = super::gather_operands_with_carry(
processor,
EightBitArithmeticOperation::ImmediateToA { n },
)?;
let result = a_value.add_with_carry(carried_operand);
store_addition_result(processor, result);
Self::do_add(processor, lhs, rhs);
Ok(())
}
EightBitAddInstruction::AddHLAddressToAWithCarry => {
let a_value = processor.registers.a;
let src_address = processor
.registers
.get_combined_register(register::Combined::HL);
let (lhs, rhs) = super::gather_operands_with_carry(
processor,
EightBitArithmeticOperation::HLAddressToA,
)?;
// While this is true, we really do want a wildcard match in map_err
#[allow(clippy::match_wildcard_for_single_variants)]
let stored_value =
processor
.memory
.get(src_address.into())
.map_err(|err| match err {
memory::Error::GetInvalidAddress(bad_addr) => {
Error::InvalidRegisterAddress(
register::SixteenBit::Combined(register::Combined::HL),
bad_addr,
)
}
err => Error::Unknown(Box::new(err)),
})?;
let carried_operand = CarriedNumber::new(
stored_value,
processor.registers.get_flag_bit(register::Flag::Carry),
)
.map_err(|err| match err {
arithutil::Error::InvalidCarryBit(value) => Error::InvalidCarryFlagValue(value),
})?;
let result = a_value.add_with_carry(carried_operand);
store_addition_result(processor, result);
Self::do_add(processor, lhs, rhs);
Ok(())
}
}
}
}
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);
}

View File

@ -1,17 +1,37 @@
use crate::{
cpu::{
instructions::arith8::EightBitSubInstruction,
run::{
arithutil::{self, CarriedNumber, CarryingSub},
Error, InstructionRunner,
},
run::{arithutil::CarryingSub, Error, InstructionRunner},
Processor,
},
memory, register,
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);
}
}
impl InstructionRunner<EightBitSubInstruction> for EightBitSubRunner {
fn run_instruction(
processor: &mut Processor,
@ -19,127 +39,68 @@ impl InstructionRunner<EightBitSubInstruction> for EightBitSubRunner {
) -> Result<(), Error> {
match *instruction {
EightBitSubInstruction::SubSingleRegisterFromA { src } => {
let a_value = processor.registers.a;
let src_register_value = processor.registers.get_single_8bit_register(src);
let result = a_value.sub_with_carry(src_register_value);
store_subtraction_result(processor, result);
let (lhs, rhs) = super::gather_operands(
processor,
EightBitArithmeticOperation::SingleRegisterToA { src },
)?;
Self::do_sub(processor, lhs, rhs);
Ok(())
}
EightBitSubInstruction::SubImmediateFromA { n } => {
let a_value = processor.registers.a;
let (lhs, rhs) = super::gather_operands(
processor,
EightBitArithmeticOperation::ImmediateToA { n },
)?;
let result = a_value.sub_with_carry(n);
store_subtraction_result(processor, result);
Ok(())
}
EightBitSubInstruction::SubSingleRegisterFromAWithCarry { src } => {
let a_value = processor.registers.a;
let src_register_value = processor.registers.get_single_8bit_register(src);
let carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
let carried_operand =
CarriedNumber::new(src_register_value, carry_bit).map_err(|err| match err {
arithutil::Error::InvalidCarryBit(value) => {
Error::InvalidCarryFlagValue(value)
}
})?;
let result = a_value.sub_with_carry(carried_operand);
store_subtraction_result(processor, result);
Self::do_sub(processor, lhs, rhs);
Ok(())
}
EightBitSubInstruction::SubHLAddressFromA => {
let a_value = processor.registers.a;
let src_addr = processor
.registers
.get_combined_register(register::Combined::HL);
// While this is true, we really do want a wildcard match in map_err
#[allow(clippy::match_wildcard_for_single_variants)]
let hl_addr_value =
processor
.memory
.get(src_addr.into())
.map_err(|err| match err {
memory::Error::GetInvalidAddress(bad_addr) => {
Error::InvalidRegisterAddress(
register::SixteenBit::Combined(register::Combined::HL),
bad_addr,
)
}
err => Error::Unknown(Box::new(err)),
})?;
let (lhs, rhs) =
super::gather_operands(processor, EightBitArithmeticOperation::HLAddressToA)?;
let result = a_value.sub_with_carry(hl_addr_value);
store_subtraction_result(processor, result);
Self::do_sub(processor, lhs, rhs);
Ok(())
}
EightBitSubInstruction::SubHLAddressFromAWithCarry => {
let a_value = processor.registers.a;
let carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
let src_addr = processor
.registers
.get_combined_register(register::Combined::HL);
// While this is true, we really do want a wildcard match in map_err
#[allow(clippy::match_wildcard_for_single_variants)]
let hl_addr_value =
processor
.memory
.get(src_addr.into())
.map_err(|err| match err {
memory::Error::GetInvalidAddress(bad_addr) => {
Error::InvalidRegisterAddress(
register::SixteenBit::Combined(register::Combined::HL),
bad_addr,
)
}
err => Error::Unknown(Box::new(err)),
})?;
let carried_operand =
CarriedNumber::new(hl_addr_value, carry_bit).map_err(|err| match err {
arithutil::Error::InvalidCarryBit(value) => {
Error::InvalidCarryFlagValue(value)
}
})?;
EightBitSubInstruction::SubSingleRegisterFromAWithCarry { src } => {
let (lhs, rhs) = super::gather_operands_with_carry(
processor,
EightBitArithmeticOperation::SingleRegisterToA { src },
)?;
let result = a_value.sub_with_carry(carried_operand);
store_subtraction_result(processor, result);
Self::do_sub(processor, lhs, rhs);
Ok(())
}
EightBitSubInstruction::SubImmediateFromAWithCarry { n } => {
let a_value = processor.registers.a;
let carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
let carried_operand =
CarriedNumber::new(n, carry_bit).map_err(|err| match err {
arithutil::Error::InvalidCarryBit(value) => {
Error::InvalidCarryFlagValue(value)
}
})?;
let (lhs, rhs) = super::gather_operands_with_carry(
processor,
EightBitArithmeticOperation::ImmediateToA { n },
)?;
let result = a_value.sub_with_carry(carried_operand);
store_subtraction_result(processor, result);
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(())
}
}
}
}
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);
}

View File

@ -50,25 +50,29 @@ where
/// `CarryingAdd` describes a type that can perform addition to produce the carry flags needed for the operation
/// of the gameboy
pub trait CarryingAdd<R, O> {
pub trait CarryingAdd<R = Self> {
type Output;
/// `add_with_carry` will perform an add operation, and then return the result, whether or not a half carry was
/// performed, and whether or not a full carry was performed. This can be thought of analgous to
/// [`u8::overflowing_add`] (or `overflowing_add` on any of the other numeric types), but with the addition of
/// the half carry flag
fn add_with_carry(self, rhs: R) -> (O, bool, bool);
fn add_with_carry(self, rhs: R) -> (Self::Output, bool, bool);
}
/// `CarryingSub` describes a type that can perform addition to produce the carry flags needed for the operation
/// of the gameboy
pub trait CarryingSub<R, O> {
pub trait CarryingSub<R = Self> {
type Output;
/// `sub_with_carry` will perform a sub operation, and then return the result, whether or not a half carry was
/// performed, and whether or not a full carry was performed. This can be thought of analgous to
/// [`u8::overflowing_sub`] (or `overflowing_sub` on any of the other numeric types), but with the addition of
/// the half carry flag
fn sub_with_carry(self, rhs: R) -> (O, bool, bool);
fn sub_with_carry(self, rhs: R) -> (Self::Output, bool, bool);
}
impl CarryingAdd<u8, u8> for u8 {
impl CarryingAdd for u8 {
type Output = u8;
fn add_with_carry(self, rhs: u8) -> (u8, bool, bool) {
let (total, carry) = self.overflowing_add(rhs);
@ -76,7 +80,9 @@ impl CarryingAdd<u8, u8> for u8 {
}
}
impl CarryingAdd<u8, u16> for u16 {
impl CarryingAdd<u8> for u16 {
type Output = u16;
fn add_with_carry(self, rhs: u8) -> (u16, bool, bool) {
let (total, _16_bit_carry) = self.overflowing_add(rhs.into());
let half_carry = did_8bit_add_half_carry(self, rhs);
@ -86,7 +92,9 @@ impl CarryingAdd<u8, u16> for u16 {
}
}
impl CarryingAdd<i8, u16> for u16 {
impl CarryingAdd<i8> for u16 {
type Output = u16;
fn add_with_carry(self, rhs: i8) -> (u16, bool, bool) {
let [upper_8_bits, lower_8_bits] = self.to_be_bytes();
let operand = twos_comp_abs(rhs);
@ -111,7 +119,9 @@ impl CarryingAdd<i8, u16> for u16 {
}
}
impl CarryingAdd<CarriedNumber<u8>, u8> for u8 {
impl CarryingAdd<CarriedNumber<u8>> for u8 {
type Output = u8;
fn add_with_carry(self, rhs: CarriedNumber<u8>) -> (u8, bool, bool) {
let total = rhs.value() + u16::from(self);
// Given this is adding two u8s, the largest value we can produce is 0x01FF (both operands 0xFF, plus a carry bit)
@ -126,7 +136,9 @@ impl CarryingAdd<CarriedNumber<u8>, u8> for u8 {
}
}
impl CarryingSub<u8, u8> for u8 {
impl CarryingSub<u8> for u8 {
type Output = u8;
fn sub_with_carry(self, rhs: u8) -> (u8, bool, bool) {
let (total, carry) = self.overflowing_sub(rhs);
let half_carry = did_8bit_sub_half_carry(self, rhs);
@ -135,7 +147,9 @@ impl CarryingSub<u8, u8> for u8 {
}
}
impl CarryingSub<CarriedNumber<u8>, u8> for u8 {
impl CarryingSub<CarriedNumber<u8>> for u8 {
type Output = u8;
fn sub_with_carry(self, rhs: CarriedNumber<u8>) -> (u8, bool, bool) {
let total = self.wrapping_sub(rhs.num).wrapping_sub(rhs.carry_bit);
let half_carry = did_8bit_sub_half_carry_including_carry_bit(self, rhs.num, rhs.carry_bit);