cpu - Fix overflow flag!
This commit is contained in:
parent
7b143ab000
commit
c84c86c160
136
src/cpu.js
136
src/cpu.js
|
|
@ -152,55 +152,21 @@ module.exports = class CPU {
|
|||
|
||||
add_lit: (lit) => {
|
||||
this.dbg.currentMnemonic = 'ADD lit';
|
||||
// Calculate sum
|
||||
let sum = this.acc + lit;
|
||||
if (sum > 255) {
|
||||
this.flags.C = true;
|
||||
sum = (sum % 255) - 1;
|
||||
} else {
|
||||
this.flags.C = false;
|
||||
}
|
||||
// Calculate overflow flag status
|
||||
let bitSixCarry = 0;
|
||||
if ((this.acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
||||
// let overflow = bitSixCarry ^ (this.flags & 8);
|
||||
// FIXME - re-implement overflow
|
||||
// I'm on a plane and can't remember how this works
|
||||
let overflow = 0;
|
||||
if (overflow) {
|
||||
this.flags.O = true;
|
||||
} else {
|
||||
this.flags.O = false;
|
||||
}
|
||||
const [sum, carry, overflow] = sumCarryOverflow(this.acc, lit);
|
||||
this.acc = sum;
|
||||
this.flags.C = carry;
|
||||
this.flags.O = overflow;
|
||||
this._updateFlagNegative();
|
||||
this._updateFlagZero();
|
||||
this._incrementIP(2);
|
||||
},
|
||||
|
||||
add_addr: (addr) => {
|
||||
this.dbg.currentMnemonic = 'ADD addr';
|
||||
// Calculate sum
|
||||
let sum = this.acc + this.memory[addr];
|
||||
if (sum > 255) {
|
||||
this.flags.C = true;
|
||||
sum = (sum % 255) - 1;
|
||||
} else {
|
||||
this.flags.C = false;
|
||||
}
|
||||
// Calculate overflow flag status
|
||||
let bitSixCarry = 0;
|
||||
if ((this.acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
||||
// let overflow = bitSixCarry ^ (this.flags & 8);
|
||||
// FIXME - re-implement overflow
|
||||
// I'm on a plane and can't remember how this works
|
||||
let overflow = 0;
|
||||
if (overflow) {
|
||||
this.flags.O = true;
|
||||
} else {
|
||||
this.flags.O = false;
|
||||
}
|
||||
this.dbg.currentMnemonic = `ADD addr; @ addr: $${num2hex(this.memory[addr])}`;
|
||||
const [sum, carry, overflow] = sumCarryOverflow(this.acc, this.memory[addr]);
|
||||
this.acc = sum;
|
||||
this.flags.C = carry;
|
||||
this.flags.O = overflow;
|
||||
this._updateFlagNegative();
|
||||
this._updateFlagZero();
|
||||
this._incrementIP(2);
|
||||
|
|
@ -208,55 +174,21 @@ module.exports = class CPU {
|
|||
|
||||
sub_lit: (lit) => {
|
||||
this.dbg.currentMnemonic = 'SUB lit';
|
||||
// Calculate sum
|
||||
let sum = this.acc - lit;
|
||||
if (sum < 0) {
|
||||
this.flags.C = true;
|
||||
sum = sum + 256;
|
||||
} else {
|
||||
this.flags.C = false;
|
||||
}
|
||||
// Calculate overflow flag status
|
||||
let bitSixCarry = 0;
|
||||
if ((this.acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
||||
// let overflow = bitSixCarry ^ (this.flags & 8);
|
||||
// FIXME - re-implement overflow
|
||||
// I'm on a plane and can't remember how this works
|
||||
let overflow = 0;
|
||||
if (overflow) {
|
||||
this.flags.O = true;
|
||||
} else {
|
||||
this.flags.O = false;
|
||||
}
|
||||
this.acc = sum;
|
||||
const [difference, carry, overflow] = differenceCarryOverflow(this.acc, lit);
|
||||
this.acc = difference;
|
||||
this.flags.C = carry;
|
||||
this.flags.O = overflow;
|
||||
this._updateFlagNegative();
|
||||
this._updateFlagZero();
|
||||
this._incrementIP(2);
|
||||
},
|
||||
|
||||
sub_addr: (addr) => {
|
||||
this.dbg.currentMnemonic = 'SUB addr';
|
||||
// Calculate sum
|
||||
let sum = this.acc - this.memory[addr];
|
||||
if (sum < 0) {
|
||||
this.flags.C = true;
|
||||
sum = sum + 256;
|
||||
} else {
|
||||
this.flags.C = false;
|
||||
}
|
||||
// Calculate overflow flag status
|
||||
let bitSixCarry = 0;
|
||||
if ((this.acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
||||
// let overflow = bitSixCarry ^ (this.flags & 8);
|
||||
// FIXME - re-implement overflow
|
||||
// I'm on a plane and can't remember how this works
|
||||
let overflow = 0;
|
||||
if (overflow) {
|
||||
this.flags.O = true;
|
||||
} else {
|
||||
this.flags.O = false;
|
||||
}
|
||||
this.acc = sum;
|
||||
this.dbg.currentMnemonic = `SUB addr; @ addr: $${num2hex(this.memory[addr])}`;
|
||||
const [difference, carry, overflow] = differenceCarryOverflow(this.acc, this.memory[addr]);
|
||||
this.acc = difference;
|
||||
this.flags.C = carry;
|
||||
this.flags.O = overflow;
|
||||
this._updateFlagNegative();
|
||||
this._updateFlagZero();
|
||||
this._incrementIP(2);
|
||||
|
|
@ -350,3 +282,39 @@ module.exports = class CPU {
|
|||
process.exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @arg {number} n1
|
||||
* @arg {number} n2
|
||||
* @returns {[number, boolean, boolean]} [sum, carry, overflow]
|
||||
**/
|
||||
function sumCarryOverflow(n1, n2) {
|
||||
let sum = n1 + n2;
|
||||
let carry = false;
|
||||
if (sum > 255) {
|
||||
carry = true;
|
||||
sum = (sum % 255) - 1;
|
||||
}
|
||||
|
||||
let n1_bit6 = (n1 & 64) === 64; // Bit 6 is the 64s place
|
||||
let n2_bit6 = (n2 & 64) === 64; // 64 & n == 64 where n >= 64
|
||||
let carryIntoLastBit = n1_bit6 && n2_bit6;
|
||||
console.log('c_in', carryIntoLastBit, 'c_out', carry);
|
||||
let overflow = carryIntoLastBit != carry;
|
||||
|
||||
return [sum, carry, overflow];
|
||||
}
|
||||
|
||||
/**
|
||||
* @arg {number} n1
|
||||
* @arg {number} n2
|
||||
* @returns {[number, boolean, boolean]} [sum, carry, overflow]
|
||||
**/
|
||||
function differenceCarryOverflow(n1, n2) {
|
||||
// https://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
|
||||
// > SBC simply takes the ones complement of the second value and then performs an ADC.
|
||||
//
|
||||
// https://stackoverflow.com/a/8966863
|
||||
// > The signed overflow flag value, however, must be the same for both A-B and A+(-B) because it depends on whether or not the result has the correct sign bit and in both cases the sign bit will be the same.
|
||||
return sumCarryOverflow(n1, -n2);
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
;; Test behaviour of flags during addition and subtraction
|
||||
;; with a focus on the Overflow flag
|
||||
2023-08-29
|
||||
|
||||
; http://teaching.idallen.com/dat2343/11w/notes/040_overflow.txt:
|
||||
;
|
||||
; > 1. If the sum of two numbers with the sign bits off yields a result number
|
||||
; with the sign bit on, the "overflow" flag is turned on.
|
||||
; >
|
||||
; > 0100 + 0100 = 1000 (overflow flag is turned on)
|
||||
; >
|
||||
; > 2. If the sum of two numbers with the sign bits on yields a result number
|
||||
; > with the sign bit off, the "overflow" flag is turned on.
|
||||
; >
|
||||
; > 1000 + 1000 = 0000 (overflow flag is turned on)
|
||||
; >
|
||||
; > Otherwise, the overflow flag is turned off.
|
||||
; > * 0100 + 0001 = 0101 (overflow flag is turned off)
|
||||
; > * 0110 + 1001 = 1111 (overflow flag is turned off)
|
||||
; > * 1000 + 0001 = 1001 (overflow flag is turned off)
|
||||
; > * 1100 + 1100 = 1000 (overflow flag is turned off)
|
||||
|
||||
;; Check simple addition and subtraction
|
||||
; LDA 1
|
||||
; STO 0
|
||||
; LDA 1
|
||||
; ADD 1
|
||||
; LDA 1
|
||||
; ADD (0)
|
||||
; LDA 3
|
||||
; SUB 1
|
||||
; LDA 3
|
||||
; SUB (0)
|
||||
|
||||
;; Check zero flag, negative flag
|
||||
; LDA 0
|
||||
; LDA 255
|
||||
|
||||
;; Check overflow flag
|
||||
|
||||
LDA 0b01000000
|
||||
ADD 0b01000000 ; 10000000 ; Overflow flag is on
|
||||
|
||||
LDA 0b10000000
|
||||
ADD 0b10000000 ; 00000000 ; Overflow flag is on
|
||||
|
||||
|
||||
; > * 0100 + 0001 = 0101 (overflow flag is turned off)
|
||||
; > * 0110 + 1001 = 1111 (overflow flag is turned off)
|
||||
; > * 1000 + 0001 = 1001 (overflow flag is turned off)
|
||||
; > * 1100 + 1100 = 1000 (overflow flag is turned off)
|
||||
|
||||
LDA 0b01000000
|
||||
ADD 0b00010000 ; 01010000 ; overflow off
|
||||
|
||||
LDA 0b01100000
|
||||
ADD 0b10010000 ; 11110000 ; overflow off
|
||||
|
||||
LDA 0b10000000
|
||||
ADD 0b00010000 ; 10010000 ; overflow off
|
||||
|
||||
LDA 0b11000000
|
||||
ADD 0b11000000 ; 10000000 ; overflow off
|
||||
Loading…
Reference in New Issue