mirror of
https://github.com/FranLMSP/snes.git
synced 2026-01-01 07:21:35 -05:00
BCD addition for 8 and 16 bits
This commit is contained in:
@@ -30,14 +30,63 @@ pub fn adc16bin(target: u16, value: u16, carry: bool) -> (u16, bool, bool, bool)
|
||||
(result, is_carry, is_negative, is_zero)
|
||||
}
|
||||
|
||||
pub fn adc8bcd() {
|
||||
pub fn adc8bcd(target: u8, value: u8, carry: bool) -> (u8, bool, bool, bool) {
|
||||
let mut is_carry = carry;
|
||||
let mut result: u8 = 0;
|
||||
let mut operand_mask: u8 = 0x0F;
|
||||
let mut result_mask: u8 = 0x00;
|
||||
let mut carry_check: u8= 0x09;
|
||||
let mut carry_add: u8 = 0x06;
|
||||
let mut is_carry_shifts: u8 = 0;
|
||||
for _ in 0..2 {
|
||||
result = (result & result_mask)
|
||||
.wrapping_add(target & operand_mask)
|
||||
.wrapping_add(value & operand_mask)
|
||||
.wrapping_add((is_carry as u8) << is_carry_shifts);
|
||||
is_carry = result > carry_check;
|
||||
if is_carry {
|
||||
result = result.wrapping_add(carry_add);
|
||||
}
|
||||
operand_mask = operand_mask << 4;
|
||||
carry_add = carry_add << 4;
|
||||
carry_check = (carry_check << 4) | 0x0F;
|
||||
result_mask = (result_mask << 4) | 0x0F;
|
||||
is_carry_shifts += 4;
|
||||
}
|
||||
let is_negative = (result >> 7) == 1;
|
||||
let is_zero = result == 0;
|
||||
(result, is_carry, is_negative, is_zero)
|
||||
}
|
||||
|
||||
pub fn adc16bcd() {
|
||||
pub fn adc16bcd(target: u16, value: u16, carry: bool) -> (u16, bool, bool, bool) {
|
||||
let mut is_carry = carry;
|
||||
let mut result: u16 = 0;
|
||||
let mut operand_mask: u16 = 0x0F;
|
||||
let mut result_mask: u16 = 0x00;
|
||||
let mut carry_check: u16 = 0x09;
|
||||
let mut carry_add: u16 = 0x06;
|
||||
let mut is_carry_shifts: u16 = 0;
|
||||
for _ in 0..4 {
|
||||
result = (result & result_mask)
|
||||
.wrapping_add(target & operand_mask)
|
||||
.wrapping_add(value & operand_mask)
|
||||
.wrapping_add((is_carry as u16) << is_carry_shifts);
|
||||
is_carry = result > carry_check;
|
||||
if is_carry {
|
||||
result = result.wrapping_add(carry_add);
|
||||
}
|
||||
operand_mask = operand_mask << 4;
|
||||
carry_add = carry_add << 4;
|
||||
carry_check = (carry_check << 4) | 0x0F;
|
||||
result_mask = (result_mask << 4) | 0x0F;
|
||||
is_carry_shifts += 4;
|
||||
}
|
||||
let is_negative = (result >> 15) == 1;
|
||||
let is_zero = result == 0;
|
||||
(result, is_carry, is_negative, is_zero)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod alu_tests {
|
||||
use super::*;
|
||||
@@ -110,34 +159,73 @@ mod alu_tests {
|
||||
|
||||
#[test]
|
||||
fn test_adc8bcd() {
|
||||
let (result, carry, negative, zero) = adc8bcd(5, 5, false);
|
||||
assert_eq!(result, 0b0001_0000);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(7, 9, false);
|
||||
assert_eq!(result, 0b0001_0110);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(5, 4, true);
|
||||
assert_eq!(result, 0b0001_0000);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(7, 8, true);
|
||||
assert_eq!(result, 0b0001_0110);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(0, 0, false);
|
||||
assert_eq!(result, 0);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, true);
|
||||
}
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(0, 50, false);
|
||||
assert_eq!(result, 50);
|
||||
#[test]
|
||||
fn test_adc16bcd() {
|
||||
let (result, carry, negative, zero) = adc16bcd(5, 5, false);
|
||||
assert_eq!(result, 0b0001_0000);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(200, 155, false);
|
||||
assert_eq!(result, 99);
|
||||
assert_eq!(carry, true);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(200, 155, true);
|
||||
assert_eq!(result, 100);
|
||||
assert_eq!(carry, true);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc8bcd(200, 54, true);
|
||||
assert_eq!(result, 255);
|
||||
let (result, carry, negative, zero) = adc16bcd(7, 9, false);
|
||||
assert_eq!(result, 0b0001_0110);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, true);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bcd(5, 4, true);
|
||||
assert_eq!(result, 0b0001_0000);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bcd(7, 8, true);
|
||||
assert_eq!(result, 0b0001_0110);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bcd(0, 0, false);
|
||||
assert_eq!(result, 0);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, true);
|
||||
|
||||
let (result, carry, negative, zero) = adc16bcd(0x0500, 0x0500, false);
|
||||
assert_eq!(result, 0b0001_0000_0000_0000);
|
||||
assert_eq!(carry, false);
|
||||
assert_eq!(negative, false);
|
||||
assert_eq!(zero, false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user