cpu - Refactor CPU flags -- stop using a bitmask to make them easier to handle
This commit is contained in:
parent
ddab8f42c4
commit
b290eb1568
118
cpu.js
118
cpu.js
|
|
@ -10,7 +10,7 @@ const {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
num2hex,
|
num2hex,
|
||||||
num2bin_4bit,
|
bool2bit,
|
||||||
} = require('./logging.js');
|
} = require('./logging.js');
|
||||||
const display = require('./display.js');
|
const display = require('./display.js');
|
||||||
|
|
||||||
|
|
@ -19,8 +19,8 @@ const CPU = {
|
||||||
// Core state
|
// Core state
|
||||||
running: false,
|
running: false,
|
||||||
IP: INITIAL_IP_ADDRESS,
|
IP: INITIAL_IP_ADDRESS,
|
||||||
FLAGS: 0, // A bit field! 0000 = ONZC
|
FLAGS: {'C': false, 'Z': false, 'N': false, 'O': false},
|
||||||
FlagNames: ['C', 'Z', 'N', 'O'],
|
FLAGNUMS2NAMES: {0: 'C', 1: 'Z', 2: 'N', 3: 'O'},
|
||||||
Acc: 0,
|
Acc: 0,
|
||||||
memory: null,
|
memory: null,
|
||||||
|
|
||||||
|
|
@ -38,24 +38,8 @@ const CPU = {
|
||||||
CPU.previousIP = CPU.IP;
|
CPU.previousIP = CPU.IP;
|
||||||
CPU.IP = address;
|
CPU.IP = address;
|
||||||
},
|
},
|
||||||
setFlagOverflow: () => { CPU.FLAGS |= 4 },
|
updateFlagZero: () => { CPU.FLAGS.Z = CPU.Acc === 0; },
|
||||||
setFlagNegative: () => { CPU.FLAGS |= 4 },
|
updateFlagNegative: () => { CPU.Acc & 128 ? CPU.FLAGS.N = true : CPU.FLAGS.N = false },
|
||||||
setFlagZero: () => { CPU.FLAGS |= 2 },
|
|
||||||
setFlagCarry: () => { CPU.FLAGS |= 1 },
|
|
||||||
unsetFlagOverflow: () => { CPU.FLAGS &= ~8 },
|
|
||||||
unsetFlagNegative: () => { CPU.FLAGS &= ~4 },
|
|
||||||
unsetFlagZero: () => { 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
|
|
||||||
},
|
|
||||||
|
|
||||||
// Debug info
|
// Debug info
|
||||||
previousIP: 0,
|
previousIP: 0,
|
||||||
|
|
@ -110,19 +94,22 @@ const Instructions = {
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc + lit;
|
let sum = CPU.Acc + lit;
|
||||||
if (sum > 255) {
|
if (sum > 255) {
|
||||||
CPU.setFlagCarry();
|
CPU.FLAGS.C = true;
|
||||||
sum = (sum % 255) - 1;
|
sum = (sum % 255) - 1;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagCarry();
|
CPU.FLAGS.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
||||||
let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
||||||
|
// FIXME FIXME FIXME
|
||||||
|
// I'm on a plane and can't remember how this works
|
||||||
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.setFlagOverflow();
|
CPU.FLAGS.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagOverflow();
|
CPU.FLAGS.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.Acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
|
|
@ -135,19 +122,22 @@ const Instructions = {
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc + CPU.memory[addr];
|
let sum = CPU.Acc + CPU.memory[addr];
|
||||||
if (sum > 255) {
|
if (sum > 255) {
|
||||||
CPU.setFlagCarry();
|
CPU.FLAGS.C = true;
|
||||||
sum = (sum % 255) - 1;
|
sum = (sum % 255) - 1;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagCarry();
|
CPU.FLAGS.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
||||||
let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
||||||
|
// FIXME FIXME FIXME
|
||||||
|
// I'm on a plane and can't remember how this works
|
||||||
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.setFlagOverflow();
|
CPU.FLAGS.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagOverflow();
|
CPU.FLAGS.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.Acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
|
|
@ -160,19 +150,22 @@ const Instructions = {
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc - lit;
|
let sum = CPU.Acc - lit;
|
||||||
if (sum < 0) {
|
if (sum < 0) {
|
||||||
CPU.setFlagCarry();
|
CPU.FLAGS.C = true;
|
||||||
sum = sum + 256;
|
sum = sum + 256;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagCarry();
|
CPU.FLAGS.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
||||||
let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
||||||
|
// FIXME FIXME FIXME
|
||||||
|
// I'm on a plane and can't remember how this works
|
||||||
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.setFlagOverflow();
|
CPU.FLAGS.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagOverflow();
|
CPU.FLAGS.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.Acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
|
|
@ -185,19 +178,22 @@ const Instructions = {
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc - CPU.memory[addr];
|
let sum = CPU.Acc - CPU.memory[addr];
|
||||||
if (sum < 0) {
|
if (sum < 0) {
|
||||||
CPU.setFlagCarry();
|
CPU.FLAGS.C = true;
|
||||||
sum = sum + 256;
|
sum = sum + 256;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagCarry();
|
CPU.FLAGS.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
||||||
let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
||||||
|
// FIXME FIXME FIXME
|
||||||
|
// I'm on a plane and can't remember how this works
|
||||||
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.setFlagOverflow();
|
CPU.FLAGS.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.unsetFlagOverflow();
|
CPU.FLAGS.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.Acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
|
|
@ -234,26 +230,24 @@ const Instructions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
flag_toggle: (flagNum) => {
|
flag_toggle: (flagNum) => {
|
||||||
CPU.currentInstruction.mnemonic = `FTG; ${CPU.FlagNames[flagNum]}`;
|
if (flagNum === null) {
|
||||||
let mask = null;
|
console.error('Invalid flag number');
|
||||||
if (flagNum === 0) { mask = 1; }
|
process.exit();
|
||||||
if (flagNum === 1) { mask = 2; }
|
}
|
||||||
if (flagNum === 2) { mask = 8; }
|
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
|
||||||
if (flagNum === 3) { mask = 16; }
|
CPU.currentInstruction.mnemonic = `FTG ${flagName}`;
|
||||||
if (mask === null) { throw new Error('Invalid flag number'); }
|
CPU.FLAGS[flagName] = !CPU.FLAGS[flagName];
|
||||||
CPU.FLAGS = CPU.FLAGS ^= mask;
|
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
flag_hop: (flagNum) => {
|
flag_hop: (flagNum) => {
|
||||||
CPU.currentInstruction.mnemonic = `FTG; ${CPU.FlagNames[flagNum]}; IP+2: ${CPU.memory[CPU.IP+2]}, IP+3: ${CPU.memory[CPU.IP+3]}`;
|
if (flagNum === null) {
|
||||||
let mask = null;
|
console.error('Invalid flag number');
|
||||||
if (flagNum === 0) { mask = 1; }
|
process.exit();
|
||||||
if (flagNum === 1) { mask = 2; }
|
}
|
||||||
if (flagNum === 2) { mask = 8; }
|
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
|
||||||
if (flagNum === 3) { mask = 16; }
|
CPU.currentInstruction.mnemonic = `FHP ${flagName}; IP+2: ${CPU.memory[CPU.IP+2]}, IP+3: ${CPU.memory[CPU.IP+3]}`;
|
||||||
if (mask === null) { throw new Error('Invalid flag number'); }
|
if (CPU.FLAGS[CPU.FLAGNUMS2NAMES[flagNum]]) {
|
||||||
if (CPU.FLAGS & mask) {
|
|
||||||
CPU.incrementIP(4);
|
CPU.incrementIP(4);
|
||||||
} else {
|
} else {
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
|
|
@ -373,7 +367,11 @@ exports.runProgram =
|
||||||
// Animate the output by pausing between steps
|
// Animate the output by pausing between steps
|
||||||
const loop = setInterval(async () => {
|
const loop = setInterval(async () => {
|
||||||
stepCPU(debugInfo, debug, prettyPrint);
|
stepCPU(debugInfo, debug, prettyPrint);
|
||||||
if (!CPU.running) process.exit();
|
if (!CPU.running) {
|
||||||
|
logCPUState(debugInfo, debug, prettyPrint);
|
||||||
|
console.log('Halted');
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
}, clockSpeed);
|
}, clockSpeed);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -412,12 +410,12 @@ function logCPUState(debugInfo, debug = false, prettyPrintDisplay = false) {
|
||||||
console.log();
|
console.log();
|
||||||
if (debugInfo) {
|
if (debugInfo) {
|
||||||
console.log(`Line ${debugInfo.lineNumber}: ${debugInfo.source}`);
|
console.log(`Line ${debugInfo.lineNumber}: ${debugInfo.source}`);
|
||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
console.log('Mnemonic:', CPU.currentInstruction.mnemonic);
|
console.log('Mnemonic:', CPU.currentInstruction.mnemonic);
|
||||||
console.log(`Machine: $${num2hex(CPU.currentInstruction.opcode)} $${num2hex(CPU.currentInstruction.operand)}`);
|
console.log(`Machine: $${num2hex(CPU.currentInstruction.opcode)} $${num2hex(CPU.currentInstruction.operand)}`);
|
||||||
console.log();
|
console.log();
|
||||||
console.log(`IP: $${num2hex(CPU.IP)} Acc: $${num2hex(CPU.Acc)} ONZC: ${num2bin_4bit(CPU.FLAGS)}`);
|
console.log(`IP: $${num2hex(CPU.IP)} Acc: $${num2hex(CPU.Acc)} ONZC ${bool2bit(CPU.FLAGS.O)}${bool2bit(CPU.FLAGS.N)}${bool2bit(CPU.FLAGS.Z)}${bool2bit(CPU.FLAGS.C)}`);
|
||||||
console.log(`KEY: $${num2hex(CPU.memory[KEYPAD_ADDR])} ${CPU.running ? "running" : "halted" }`);
|
console.log(`KEY: $${num2hex(CPU.memory[KEYPAD_ADDR])} ${CPU.running ? "running" : "halted" }`);
|
||||||
console.log();
|
console.log();
|
||||||
console.log();
|
console.log();
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,12 @@ const num2bin_4bit = (num) => (num >>> 0).toString(2).padStart(4, "0");
|
||||||
*/
|
*/
|
||||||
const bin2num = (bin) => parseInt(bin, 2)
|
const bin2num = (bin) => parseInt(bin, 2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Boolean} bool
|
||||||
|
* @returns {0|1}
|
||||||
|
**/
|
||||||
|
const bool2bit = (bool) => bool ? 1 : 0;
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"logMemory": logMemory,
|
"logMemory": logMemory,
|
||||||
|
|
@ -81,4 +87,5 @@ module.exports = {
|
||||||
"num2bin": num2bin,
|
"num2bin": num2bin,
|
||||||
"num2bin_4bit": num2bin_4bit,
|
"num2bin_4bit": num2bin_4bit,
|
||||||
"bin2num": bin2num,
|
"bin2num": bin2num,
|
||||||
|
"bool2bit": bool2bit,
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue