Refactor (CPU): Move more logic into `stepCPU()` in preparation for implementing single-stepping

This commit is contained in:
n loewen 2023-08-16 12:50:00 +01:00
parent 3ac1276bfe
commit aa6cbc3e6d
1 changed files with 35 additions and 27 deletions

54
cpu.js
View File

@ -4,24 +4,19 @@ const display = require('./display.js');
// STATE // STATE
const CPU = { const CPU = {
// Core state
running: false, running: false,
IP: INITIAL_IP_ADDRESS, IP: INITIAL_IP_ADDRESS,
FLAGS: 0, // A bit field! 0000 = NZOC FLAGS: 0, // A bit field! 0000 = NZOC
Acc: 0, Acc: 0,
memory: null, memory: null,
currentInstruction: { // Functions that update core state
opcode: null,
operand: null,
mnemonic: null,
},
/** @param {Uint8Array} data */ /** @param {Uint8Array} data */
loadMemory: (data) => { loadMemory: (data) => {
if (data.length > 256) { throw new Error("Out of memory error (program too long)"); } if (data.length > 256) { throw new Error("Out of memory error (program too long)"); }
CPU.memory = data; CPU.memory = data;
}, },
setFlagNegative: () => { CPU.FLAGS |= 8 }, setFlagNegative: () => { CPU.FLAGS |= 8 },
setFlagZero: () => { CPU.FLAGS |= 4 }, setFlagZero: () => { CPU.FLAGS |= 4 },
setFlagOverflow: () => { CPU.FLAGS |= 2 }, setFlagOverflow: () => { CPU.FLAGS |= 2 },
@ -30,7 +25,6 @@ const CPU = {
unsetFlagZero: () => { CPU.FLAGS &= ~4 }, unsetFlagZero: () => { CPU.FLAGS &= ~4 },
unsetFlagOverflow: () => { CPU.FLAGS &= ~2 }, unsetFlagOverflow: () => { CPU.FLAGS &= ~2 },
unsetFlagCarry: () => { CPU.FLAGS &= ~1 }, unsetFlagCarry: () => { CPU.FLAGS &= ~1 },
updateFlagZero: () => { updateFlagZero: () => {
if (CPU.Acc === 0) { if (CPU.Acc === 0) {
CPU.setFlagZero(); CPU.setFlagZero();
@ -38,9 +32,17 @@ const CPU = {
CPU.unsetFlagZero(); CPU.unsetFlagZero();
} }
}, },
updateFlagNegative: () => { updateFlagNegative: () => {
CPU.Acc & 128 ? CPU.setFlagNegative : CPU.unsetFlagNegative }, CPU.Acc & 128 ? CPU.setFlagNegative : CPU.unsetFlagNegative
},
// Debug info
currentInstruction: {
opcode: null,
operand: null,
mnemonic: null,
},
cycleCounter: 0,
} }
@ -266,17 +268,33 @@ const opcodes2mnemonics = {
**/ **/
function startCPU(code) { function startCPU(code) {
CPU.loadMemory(code); CPU.loadMemory(code);
CPU.cycleCounter = 0;
CPU.running = true; CPU.running = true;
} }
/** /**
* Execute just the next instruction in memory * Execute just the next instruction in memory
**/ **/
function stepCPU() { async function stepCPU(debug = false) {
if (CYCLE_LIMIT) { // Temporary limit as a lazy way to halt infinite loops
if (CPU.cycleCounter > CYCLE_LIMIT) {
console.warn('HALTING - reached cycle limit');
CPU.running = false;
}
}
if (CPU.running) {
if (CPU.IP >= CPU.memory.length) {
console.error('HALTING - IP greater than memory size');
CPU.running = false;
} else {
CPU.currentInstruction.opcode = CPU.memory[CPU.IP]; CPU.currentInstruction.opcode = CPU.memory[CPU.IP];
CPU.currentInstruction.operand = CPU.memory[CPU.IP+1]; CPU.currentInstruction.operand = CPU.memory[CPU.IP+1];
let executeInstruction = opcodes2mnemonics[CPU.currentInstruction.opcode]; let executeInstruction = opcodes2mnemonics[CPU.currentInstruction.opcode];
executeInstruction(CPU.currentInstruction.operand); executeInstruction(CPU.currentInstruction.operand);
CPU.cycleCounter += 1;
}
}
await logCPUState(debug);
} }
/** /**
@ -285,18 +303,8 @@ function stepCPU() {
**/ **/
exports.runProgram = async (code, debug = false) => { exports.runProgram = async (code, debug = false) => {
startCPU(code); startCPU(code);
let step = 0; while (CPU.running) {
while (true) { stepCPU(debug);
step = step + 1;
// Temporary limit as a lazy way to halt infinite loops:
if (CYCLE_LIMIT && (step > CYCLE_LIMIT)) {
console.log('SIMULATION HALTING - reached cycle limit');
break;
}
if (!CPU.running) break;
if (CPU.IP >= CPU.memory.length) break;
stepCPU();
await logCPUState(debug);
}; };
} }