1
0
mirror of https://github.com/mre/mos6502.git synced 2024-11-28 22:51:26 +00:00

Merge pull request #30 from omarandlorraine/master

First stab at implementing decimal mode for ADC
This commit is contained in:
Matthias 2021-01-28 23:09:43 +01:00 committed by GitHub
commit 5b87171c4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -516,10 +516,6 @@ impl CPU {
} }
fn add_with_carry(&mut self, value: i8) { fn add_with_carry(&mut self, value: i8) {
if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
// TODO akeeton: Implement binary-coded decimal.
debug!("binary-coded decimal not implemented for add_with_carry");
} else {
let a_before: i8 = self.registers.accumulator; let a_before: i8 = self.registers.accumulator;
let c_before: i8 = if self.registers.status.contains(Status::PS_CARRY) { let c_before: i8 = if self.registers.status.contains(Status::PS_CARRY) {
1 1
@ -533,41 +529,44 @@ impl CPU {
a_before.wrapping_add(c_before).wrapping_add(value) as u8 a_before.wrapping_add(c_before).wrapping_add(value) as u8
); );
let did_carry = (a_after as u8) < (a_before as u8); let bcd1: i8 = if (a_after & 0x0f) as u8 > 0x09 {
0x06
} else {
0x00
};
let bcd2: i8 = if (a_after.wrapping_add(bcd1) as u8 & 0xf0) as u8 > 0x90 {
0x60
} else {
0x00
};
let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
a_after.wrapping_add(bcd1).wrapping_add(bcd2)
} else {
a_after
};
let did_carry = (result as u8) < (a_before as u8);
let did_overflow = (a_before < 0 && value < 0 && a_after >= 0) let did_overflow = (a_before < 0 && value < 0 && a_after >= 0)
|| (a_before > 0 && value > 0 && a_after <= 0); || (a_before > 0 && value > 0 && a_after <= 0);
let mask = Status::PS_CARRY | Status::PS_OVERFLOW; let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
self.registers.status.set_with_mask( self.registers.status.set_with_mask( mask, Status::new(StatusArgs { carry: did_carry, overflow: did_overflow, ..StatusArgs::none() }),);
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
self.load_accumulator(a_after); self.load_accumulator(result);
debug!("accumulator: {}", self.registers.accumulator); debug!("accumulator: {}", self.registers.accumulator);
} }
}
fn and(&mut self, value: i8) { fn and(&mut self, value: i8) {
let a_after = self.registers.accumulator & value; let a_after = self.registers.accumulator & value;
self.load_accumulator(a_after); self.load_accumulator(a_after);
} }
// TODO: Implement binary-coded decimal
fn subtract_with_carry(&mut self, value: i8) { fn subtract_with_carry(&mut self, value: i8) {
if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
debug!(
"binary-coded decimal not implemented for \
subtract_with_carry"
);
} else {
// A - M - (1 - C) // A - M - (1 - C)
// nc -- 'not carry' // nc -- 'not carry'
@ -581,9 +580,6 @@ impl CPU {
let a_after = a_before.wrapping_sub(value).wrapping_sub(nc); let a_after = a_before.wrapping_sub(value).wrapping_sub(nc);
// The carry flag is set on unsigned overflow.
let did_carry = (a_after as u8) > (a_before as u8);
// The overflow flag is set on two's-complement overflow. // The overflow flag is set on two's-complement overflow.
// //
// range of A is -128 to 127 // range of A is -128 to 127
@ -599,17 +595,34 @@ impl CPU {
let mask = Status::PS_CARRY | Status::PS_OVERFLOW; let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
let bcd1: i8 = if (a_before & 0x0f).wrapping_sub(nc) < (value & 0x0f) {
0x06
} else {
0x00
};
let bcd2: i8 = if (a_after.wrapping_sub(bcd1) as u8 & 0xf0) as u8 > 0x90 {
0x60
} else {
0x00
};
let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
a_after.wrapping_sub(bcd1).wrapping_sub(bcd2)
} else {
a_after
};
// The carry flag is set on unsigned overflow.
let did_carry = (result as u8) > (a_before as u8);
self.registers.status.set_with_mask( self.registers.status.set_with_mask(
mask, mask,
Status::new(StatusArgs { Status::new(StatusArgs { carry: did_carry, overflow: did_overflow, ..StatusArgs::none() }),
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
); );
self.load_accumulator(a_after);
} self.load_accumulator(result);
} }
fn decrement_memory(&mut self, addr: Address) { fn decrement_memory(&mut self, addr: Address) {
@ -766,6 +779,53 @@ mod tests {
use super::*; use super::*;
use num::range_inclusive; use num::range_inclusive;
#[test]
fn decimal_add_test() {
let mut cpu = CPU::new();
cpu.registers.status.or(Status::PS_DECIMAL_MODE);
cpu.add_with_carry(0x09);
assert_eq!(cpu.registers.accumulator, 0x09);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.add_with_carry(0x43);
assert_eq!(cpu.registers.accumulator, 0x52);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.add_with_carry(0x48);
assert_eq!(cpu.registers.accumulator, 0x00);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), true);
}
#[test]
fn decimal_subtract_test() {
let mut cpu = CPU::new();
cpu.registers.status.or(Status::PS_DECIMAL_MODE | Status::PS_CARRY);
cpu.registers.accumulator = 0;
cpu.subtract_with_carry(0x48);
assert_eq!(cpu.registers.accumulator as u8, 0x52);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.subtract_with_carry(0x43);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
}
#[test] #[test]
fn add_with_carry_test() { fn add_with_carry_test() {
let mut cpu = CPU::new(); let mut cpu = CPU::new();