Feature (simulator): Implement Negative, Zero, and Overflow flags

This commit is contained in:
n loewen 2023-08-15 15:22:21 +01:00
parent b1dc2a7c7e
commit 3af5d66626
2 changed files with 108 additions and 22 deletions

View File

@ -2,12 +2,6 @@ const { INITIAL_IP_ADDRESS, CYCLE_LIMIT } = require('./machine.config');
const { num2hex, num2bin_4bit } = require('./logging.js');
const display = require('./display.js');
// TODO:
// implement setting and clearing of:
// - [ ] overflow flag
// - [ ] zero flag
// - [ ] negative flag
// STATE
const CPU = {
running: false,
@ -36,6 +30,17 @@ const CPU = {
unsetFlagZero: () => { CPU.FLAGS &= ~4 },
unsetFlagOverflow: () => { CPU.FLAGS &= ~2 },
unsetFlagCarry: () => { CPU.FLAGS &= ~1 },
updateFlagZero: () => {
if (CPU.Acc === 0) {
CPU.setFlagZero();
} else {
CPU.unsetFlagZero();
}
},
updateFlagNegative: () => {
CPU.Acc & 128 ? CPU.setFlagNegative : CPU.unsetFlagNegative },
}
@ -62,68 +67,116 @@ const Instructions = {
load_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'LDA lit';
CPU.Acc = lit;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.IP = CPU.IP += 2;
},
load_addr: (addr) => {
CPU.currentInstruction.mnemonic = `LDA addr; @ addr: ${num2hex(CPU.memory[addr])}`;
CPU.Acc = CPU.memory[addr];
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.IP = CPU.IP += 2;
},
add_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'ADD lit';
// Calculate sum
let sum = CPU.Acc + lit;
// TODO: implement NZO flags
if (sum > 255) {
CPU.setFlagCarry();
CPU.Acc = (sum % 255) - 1;
sum = (sum % 255) - 1;
} else {
CPU.unsetFlagCarry();
CPU.Acc = sum;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
let overflow = bitSixCarry ^ (CPU.FLAGS & 1)
if (overflow) {
CPU.setFlagOverflow();
} else {
CPU.unsetFlagOverflow();
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.IP = CPU.IP += 2;
},
add_addr: (addr) => {
CPU.currentInstruction.mnemonic = 'ADD addr';
// Calculate sum
let sum = CPU.Acc + CPU.memory[addr];
// TODO: implement NZO flags
if (sum > 255) {
CPU.setFlagCarry();
CPU.Acc = (sum % 255) - 1;
sum = (sum % 255) - 1;
} else {
CPU.unsetFlagCarry();
CPU.Acc = sum;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
let overflow = bitSixCarry ^ (CPU.FLAGS & 1)
if (overflow) {
CPU.setFlagOverflow();
} else {
CPU.unsetFlagOverflow();
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.IP = CPU.IP += 2;
},
sub_lit: (lit) => {
CPU.currentInstruction.mnemonic = 'SUB lit';
// Calculate sum
let sum = CPU.Acc - lit;
// TODO: implement NZO flags
if (sum < 0) {
CPU.setFlagCarry();
CPU.Acc = 255 + sum + 1;
sum = sum + 256;
} else {
CPU.unsetFlagCarry();
CPU.Acc = sum;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
let overflow = bitSixCarry ^ (CPU.FLAGS & 1)
if (overflow) {
CPU.setFlagOverflow();
} else {
CPU.unsetFlagOverflow();
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.IP = CPU.IP += 2;
},
sub_addr: (addr) => {
CPU.currentInstruction.mnemonic = 'SUB addr';
// Calculate sum
let sum = CPU.Acc - CPU.memory[addr];
// TODO: implement NZO flags
if (sum < 0) {
CPU.setFlagCarry();
CPU.Acc = 255 + sum + 1;
sum = sum + 256;
} else {
CPU.unsetFlagCarry();
CPU.Acc = sum;
}
// Calculate overflow flag status
let bitSixCarry = 0;
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
let overflow = bitSixCarry ^ (CPU.FLAGS & 1)
if (overflow) {
CPU.setFlagOverflow();
} else {
CPU.unsetFlagOverflow();
}
CPU.Acc = sum;
CPU.updateFlagNegative();
CPU.updateFlagZero();
CPU.IP = CPU.IP += 2;
},
@ -163,21 +216,18 @@ const Instructions = {
if (flagNum === 2) { mask = 4; }
if (flagNum === 3) { mask = 8; }
if (mask === null) { throw new Error('Invalid flag number'); }
console.log('flag mask:', mask);
CPU.FLAGS = CPU.FLAGS ^= mask;
CPU.IP += 2;
},
flag_hop: (flagNum) => {
CPU.currentInstruction.mnemonic = `FHP; IP+2: ${CPU.memory[CPU.IP+2]}, IP+3: ${CPU.memory[CPU.IP+3]}`;
console.log('flag number:', flagNum);
let mask = null;
if (flagNum === 0) { mask = 1; }
if (flagNum === 1) { mask = 2; }
if (flagNum === 2) { mask = 4; }
if (flagNum === 3) { mask = 8; }
if (mask === null) { throw new Error('Invalid flag number'); }
console.log('flag mask:', mask);
if (CPU.FLAGS & mask) {
CPU.IP += 4;
} else {
@ -264,7 +314,7 @@ async function logCPUState(debug = false) {
console.log('Mnemonic:', CPU.currentInstruction.mnemonic);
console.log(`Machine: $${num2hex(CPU.currentInstruction.opcode)} $${num2hex(CPU.currentInstruction.operand)}`);
console.log();
console.log(`IP: $${num2hex(CPU.IP)} Acc: $${num2hex(CPU.Acc)} FLAGS: ${num2bin_4bit(CPU.FLAGS)}  ${CPU.running ? "running" : "halted" }`);
console.log(`IP: $${num2hex(CPU.IP)} Acc: $${num2hex(CPU.Acc)} NVOC: ${num2bin_4bit(CPU.FLAGS)}  ${CPU.running ? "running" : "halted" }`);
console.log();
// Pause to show animated display:
if (!debug) await new Promise(resolve => setTimeout(resolve, 75));

View File

@ -0,0 +1,36 @@
;; test overflow flag
; https://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
LDA $50
ADD $10 ; CF, OF: 0 0
LDA $50
ADD $50 ; CF, OF: 0 1
LDA $50
ADD $90 ; CF, OF: 0 0
LDA $50
ADD $D0 ; CF, OF: 1 0
LDA $D0
ADD $10 ; CF, OF: 0 0
LDA $D0
ADD $50 ; CF, OF: 1 0
LDA $D0
ADD $90 ; CF, OF: 1 1
LDA $D0
ADD $D0 ; CF, OF: 1 0
LDA $50
SUB $F0 ; CF, OF: 1 0
LDA $50
SUB $B0 ; CF, OF: 1 1
LDA $50
SUB $70 ; CF, OF: 1 0
LDA $50
SUB $30 ; CF, OF: 0 0
LDA $D0
SUB $F0 ; CF, OF: 1 0
LDA $D0
SUB $B0 ; CF, OF: 0 0
LDA $D0
SUB $70 ; CF, OF: 0 1
LDA $D0
SUB $30 ; CF, OF: 0 0