From 85dd92615ddae7194e0e90734a524060533ffa2e Mon Sep 17 00:00:00 2001 From: Sam M W Date: Mon, 25 Jan 2021 22:57:28 +0000 Subject: [PATCH 1/7] First stab at implementing decimal mode for ADC --- src/cpu.rs | 70 +++++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 5e6705e..db21458 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -515,45 +515,51 @@ impl CPU { ); } - 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 c_before: i8 = if self.registers.status.contains(Status::PS_CARRY) { - 1 - } else { - 0 - }; - let a_after: i8 = a_before.wrapping_add(c_before).wrapping_add(value); + fn add_with_carry(&mut self, value: i8) { + let a_before: i8 = self.registers.accumulator; + let c_before: i8 = if self.registers.status.contains(Status::PS_CARRY) { + 1 + } else { + 0 + }; + let a_after: i8 = a_before.wrapping_add(c_before).wrapping_add(value); - debug_assert_eq!( - a_after as u8, - a_before.wrapping_add(c_before).wrapping_add(value) as u8 - ); + debug_assert_eq!( + a_after 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 did_overflow = (a_before < 0 && value < 0 && a_after >= 0) - || (a_before > 0 && value > 0 && a_after <= 0); + let bcd2: i8 = if (a_after.wrapping_add(bcd1) as u8 & 0xf0) as u8 > 0x90 { + 0x60 + } else { + 0x00 + }; - let mask = Status::PS_CARRY | Status::PS_OVERFLOW; + let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) { + a_after.wrapping_add(bcd1).wrapping_add(bcd2) + } else { + a_after + }; - self.registers.status.set_with_mask( - mask, - Status::new(StatusArgs { - carry: did_carry, - overflow: did_overflow, - ..StatusArgs::none() - }), - ); + let did_carry = (result as u8) < (a_before as u8); - self.load_accumulator(a_after); + let did_overflow = (a_before < 0 && value < 0 && a_after >= 0) + || (a_before > 0 && value > 0 && a_after <= 0); - debug!("accumulator: {}", self.registers.accumulator); - } - } + let mask = Status::PS_CARRY | Status::PS_OVERFLOW; + + self.registers.status.set_with_mask( mask, Status::new(StatusArgs { carry: did_carry, overflow: did_overflow, ..StatusArgs::none() }),); + + self.load_accumulator(result); + + debug!("accumulator: {}", self.registers.accumulator); + } fn and(&mut self, value: i8) { let a_after = self.registers.accumulator & value; From 153f8e4bd7217977c224fb6a021470099006ee1c Mon Sep 17 00:00:00 2001 From: Sam M W Date: Tue, 26 Jan 2021 20:58:09 +0000 Subject: [PATCH 2/7] Some unit testing for decimal mode --- src/cpu.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index db21458..551c0ff 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -772,6 +772,34 @@ mod tests { use super::*; use num::range_inclusive; + #[test] + fn decimal_mode_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 add_with_carry_test() { let mut cpu = CPU::new(); From 3844a730f0356a109910c3c4ff011f95d2ebe132 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Wed, 27 Jan 2021 20:31:36 +0000 Subject: [PATCH 3/7] whitespace --- src/cpu.rs | 69 +++++++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 551c0ff..3b080e1 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -567,56 +567,45 @@ impl CPU { } // TODO: Implement binary-coded decimal - 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) + fn subtract_with_carry(&mut self, value: i8) { + // A - M - (1 - C) - // nc -- 'not carry' - let nc: i8 = if self.registers.status.contains(Status::PS_CARRY) { - 0 - } else { - 1 - }; + // nc -- 'not carry' + let nc: i8 = if self.registers.status.contains(Status::PS_CARRY) { + 0 + } else { + 1 + }; - let a_before: i8 = self.registers.accumulator; + let a_before: i8 = self.registers.accumulator; - 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 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. - // - // range of A is -128 to 127 - // range of - M - (1 - C) is -128 to 128 - // -(127 + 1) to -(-128 + 0) - // - let over = - ((nc == 0 && value < 0) || (nc == 1 && value < -1)) && a_before >= 0 && a_after < 0; + // The overflow flag is set on two's-complement overflow. + // + // range of A is -128 to 127 + // range of - M - (1 - C) is -128 to 128 + // -(127 + 1) to -(-128 + 0) + // + let over = + ((nc == 0 && value < 0) || (nc == 1 && value < -1)) && a_before >= 0 && a_after < 0; - let under = (a_before < 0) && (-value - nc < 0) && a_after >= 0; + let under = (a_before < 0) && (-value - nc < 0) && a_after >= 0; - let did_overflow = over || under; + let did_overflow = over || under; - let mask = Status::PS_CARRY | Status::PS_OVERFLOW; + let mask = Status::PS_CARRY | Status::PS_OVERFLOW; - self.registers.status.set_with_mask( - mask, - Status::new(StatusArgs { - carry: did_carry, - overflow: did_overflow, - ..StatusArgs::none() - }), - ); + self.registers.status.set_with_mask( + mask, + Status::new(StatusArgs { carry: did_carry, overflow: did_overflow, ..StatusArgs::none() }), + ); - self.load_accumulator(a_after); - } - } + self.load_accumulator(a_after); + } fn decrement_memory(&mut self, addr: Address) { let value_new = self.memory.get_byte(addr).wrapping_sub(1); From 51775fbe954be78117555dab5f951a31cb9be83d Mon Sep 17 00:00:00 2001 From: Sam M W Date: Wed, 27 Jan 2021 22:44:20 +0000 Subject: [PATCH 4/7] Decimal mode for SBC --- src/cpu.rs | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 3b080e1..d7243aa 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -581,9 +581,6 @@ impl CPU { 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. // // range of A is -128 to 127 @@ -599,12 +596,34 @@ impl CPU { 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( mask, Status::new(StatusArgs { carry: did_carry, overflow: did_overflow, ..StatusArgs::none() }), ); - self.load_accumulator(a_after); + + self.load_accumulator(result); } fn decrement_memory(&mut self, addr: Address) { @@ -786,7 +805,19 @@ mod tests { 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); - + + 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] From 2d87640692e5ce6047954f79934244b0d70eee50 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Thu, 28 Jan 2021 08:58:04 +0000 Subject: [PATCH 5/7] remove worthless comment --- src/cpu.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cpu.rs b/src/cpu.rs index d7243aa..d03b6d4 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -566,7 +566,6 @@ impl CPU { self.load_accumulator(a_after); } - // TODO: Implement binary-coded decimal fn subtract_with_carry(&mut self, value: i8) { // A - M - (1 - C) From ad40c72dfe648180ea58daaa38cb9600ff7cb6ea Mon Sep 17 00:00:00 2001 From: Sam M W Date: Thu, 28 Jan 2021 10:13:44 +0000 Subject: [PATCH 6/7] separate unit test for decimal sbc --- src/cpu.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cpu.rs b/src/cpu.rs index d03b6d4..9dc5aa1 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -780,7 +780,7 @@ mod tests { use num::range_inclusive; #[test] - fn decimal_mode_test() { + fn decimal_add_test() { let mut cpu = CPU::new(); cpu.registers.status.or(Status::PS_DECIMAL_MODE); @@ -804,7 +804,13 @@ mod tests { 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); + cpu.subtract_with_carry(0x48); assert_eq!(cpu.registers.accumulator as u8, 0x52); assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true); From b39a67b0a185892a77ac2a1535abc7ee354d7c03 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Thu, 28 Jan 2021 10:17:10 +0000 Subject: [PATCH 7/7] separate unit test for decimal sbc should set carry --- src/cpu.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cpu.rs b/src/cpu.rs index 9dc5aa1..9d24eef 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -809,7 +809,8 @@ mod tests { #[test] fn decimal_subtract_test() { let mut cpu = CPU::new(); - cpu.registers.status.or(Status::PS_DECIMAL_MODE); + 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);