mirror of
https://github.com/FranLMSP/snes.git
synced 2026-08-03 08:30:01 -04:00
Refactor adc_bin
This commit is contained in:
@@ -139,6 +139,7 @@ impl CPU {
|
||||
self.registers.increment_pc(bytes);
|
||||
self.cycles += cycles;
|
||||
// Add 2 cycles if m = 1
|
||||
// TODO: Consider that this may be adding one byte more
|
||||
self.common_conditions(addressing_mode, &[Condition::MemorySelectFlag]);
|
||||
self.common_conditions(addressing_mode, &[
|
||||
Condition::MemorySelectFlag,
|
||||
|
||||
@@ -36,7 +36,7 @@ impl CPU {
|
||||
let value = self.get_8bit_from_address(bus, addressing_mode);
|
||||
let (result, is_carry, is_negative, is_zero) = match is_decimal_mode {
|
||||
true => alu::adc8bcd(target as u8, value, carry_flag),
|
||||
false => alu::adc8bin(target as u8, value, carry_flag),
|
||||
false => alu::adc_bin(target as u8, value, carry_flag),
|
||||
};
|
||||
self.registers.set_low_a(result as u8);
|
||||
self.registers.set_carry_flag(is_carry);
|
||||
@@ -47,7 +47,7 @@ impl CPU {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
let (result, is_carry, is_negative, is_zero) = match is_decimal_mode {
|
||||
true => alu::adc16bcd(target, value, carry_flag),
|
||||
false => alu::adc16bin(target, value, carry_flag),
|
||||
false => alu::adc_bin(target, value, carry_flag),
|
||||
};
|
||||
self.registers.a = result;
|
||||
self.registers.set_carry_flag(is_carry);
|
||||
|
||||
+22
-38
@@ -1,34 +1,12 @@
|
||||
/// TODO: refactor functions to work with generic types (either u8 or 16) to reduce duplication
|
||||
|
||||
pub fn adc8bin(target: u8, value: u8, carry: bool) -> (u8, bool, bool, bool) {
|
||||
let is_carry = match target.checked_add(value) {
|
||||
None => true,
|
||||
Some(res) => match res.checked_add(carry as u8) {
|
||||
None => true,
|
||||
Some(_) => false,
|
||||
},
|
||||
};
|
||||
let result = target
|
||||
.wrapping_add(value)
|
||||
.wrapping_add(carry as u8);
|
||||
let is_negative = (result >> 7) == 1;
|
||||
let is_zero = result == 0;
|
||||
(result, is_carry, is_negative, is_zero)
|
||||
}
|
||||
use super::num_trait::SnesNum;
|
||||
|
||||
pub fn adc16bin(target: u16, value: u16, carry: bool) -> (u16, bool, bool, bool) {
|
||||
let is_carry = match target.checked_add(value) {
|
||||
None => true,
|
||||
Some(res) => match res.checked_add(carry as u16) {
|
||||
None => true,
|
||||
Some(_) => false,
|
||||
},
|
||||
};
|
||||
let result = target
|
||||
.wrapping_add(value)
|
||||
.wrapping_add(carry as u16);
|
||||
let is_negative = (result >> 15) == 1;
|
||||
let is_zero = result == 0;
|
||||
pub fn adc_bin<T: SnesNum>(target: T, value: T, carry: bool) -> (T, bool, bool, bool) {
|
||||
let is_carry = target.add_will_carry(value, carry);
|
||||
let result = target.add_snes(value, carry);
|
||||
let is_negative = result.is_negative();
|
||||
let is_zero = result.is_zero();
|
||||
(result, is_carry, is_negative, is_zero)
|
||||
}
|
||||
|
||||
@@ -187,31 +165,37 @@ mod alu_tests {
|
||||
|
||||
#[test]
|
||||
fn test_adc8bin() {
|
||||
let (result, carry, negative, zero) = adc8bin(0, 0, false);
|
||||
let (result, carry, negative, zero) = adc_bin(0_u8, 0_u8, false);
|
||||
assert_eq!(result, 0);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, true);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bin(0, 50, false);
|
||||
let (result, carry, negative, zero) = adc_bin(0_u8, 50_u8, false);
|
||||
assert_eq!(result, 50);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bin(200, 155, false);
|
||||
let (result, carry, negative, zero) = adc_bin(200_u8, 155_u8, false);
|
||||
assert_eq!(result, 99);
|
||||
assert_eq!(carry, true);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bin(200, 155, true);
|
||||
let (result, carry, negative, zero) = adc_bin(200_u8, 155_u8, true);
|
||||
assert_eq!(result, 100);
|
||||
assert_eq!(carry, true);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bin(200, 54, true);
|
||||
let (result, carry, negative, zero) = adc_bin(200_u8, 54_u8, true);
|
||||
assert_eq!(result, 255);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, true);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc_bin(200_u8, 54_u8, true);
|
||||
assert_eq!(result, 255);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, true);
|
||||
@@ -220,31 +204,31 @@ mod alu_tests {
|
||||
|
||||
#[test]
|
||||
fn test_adc16bin() {
|
||||
let (result, carry, negative, zero) = adc16bin(0, 0, false);
|
||||
let (result, carry, negative, zero) = adc_bin(0_u16, 0_u16, false);
|
||||
assert_eq!(result, 0);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, true);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bin(0, 50, false);
|
||||
let (result, carry, negative, zero) = adc_bin(0_u16, 50_u16, false);
|
||||
assert_eq!(result, 50);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bin(65530, 10, false);
|
||||
let (result, carry, negative, zero) = adc_bin(65530_u16, 10_u16, false);
|
||||
assert_eq!(result, 4);
|
||||
assert_eq!(carry, true);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bin(65530, 10, true);
|
||||
let (result, carry, negative, zero) = adc_bin(65530_u16, 10_u16, true);
|
||||
assert_eq!(result, 5);
|
||||
assert_eq!(carry, true);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bin(65530, 4, true);
|
||||
let (result, carry, negative, zero) = adc_bin(65530_u16, 4_u16, true);
|
||||
assert_eq!(result, 65535);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, true);
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod alu;
|
||||
pub mod addressing;
|
||||
pub mod num_trait;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
pub trait SnesNum: Copy + Clone + Sized + Eq + PartialEq {
|
||||
fn add_will_carry(&self, v: Self, carry: bool) -> bool;
|
||||
fn sub_will_carry(&self, v: Self, carry: bool) -> bool;
|
||||
fn add_snes(&self, v: Self, carry: bool) -> Self;
|
||||
fn sub_snes(&self, v: Self, carry: bool) -> Self;
|
||||
fn is_negative(&self) -> bool;
|
||||
fn is_zero(&self) -> bool;
|
||||
}
|
||||
|
||||
macro_rules! define_will_carry {
|
||||
($t:ty, $method:ident, $inner_method:ident) => {
|
||||
fn $method(&self, v: $t, carry: bool) -> bool {
|
||||
match self.$inner_method(v) {
|
||||
None => true,
|
||||
Some(res) => match res.$inner_method(carry as $t) {
|
||||
None => true,
|
||||
Some(_) => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_operation {
|
||||
($t:ty, $method:ident, $inner_method:ident) => {
|
||||
fn $method(&self, v: $t, carry: bool) -> $t {
|
||||
self.$inner_method(v).$inner_method(carry as $t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_impl {
|
||||
($t:ty) => {
|
||||
impl SnesNum for $t {
|
||||
define_will_carry!($t, add_will_carry, checked_add);
|
||||
define_will_carry!($t, sub_will_carry, checked_sub);
|
||||
|
||||
define_operation!($t, add_snes, wrapping_add);
|
||||
define_operation!($t, sub_snes, wrapping_sub);
|
||||
|
||||
fn is_negative(&self) -> bool {
|
||||
(*self) & !(<$t>::MAX >> 1) != 0
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
(*self) == 0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
define_impl!(u8);
|
||||
define_impl!(u16);
|
||||
Reference in New Issue
Block a user