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

62
cpu.js
View File

@ -4,24 +4,19 @@ const display = require('./display.js');
// STATE
const CPU = {
// Core state
running: false,
IP: INITIAL_IP_ADDRESS,
FLAGS: 0, // A bit field! 0000 = NZOC
Acc: 0,
memory: null,
currentInstruction: {
opcode: null,
operand: null,
mnemonic: null,
},
// Functions that update core state
/** @param {Uint8Array} data */
loadMemory: (data) => {
if (data.length > 256) { throw new Error("Out of memory error (program too long)"); }
CPU.memory = data;
},
setFlagNegative: () => { CPU.FLAGS |= 8 },
setFlagZero: () => { CPU.FLAGS |= 4 },
setFlagOverflow: () => { CPU.FLAGS |= 2 },
@ -30,7 +25,6 @@ const CPU = {
unsetFlagZero: () => { CPU.FLAGS &= ~4 },
unsetFlagOverflow: () => { CPU.FLAGS &= ~2 },
unsetFlagCarry: () => { CPU.FLAGS &= ~1 },
updateFlagZero: () => {
if (CPU.Acc === 0) {
CPU.setFlagZero();
@ -38,9 +32,17 @@ const CPU = {
CPU.unsetFlagZero();
}
},
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) {
CPU.loadMemory(code);
CPU.cycleCounter = 0;
CPU.running = true;
}
/**
* Execute just the next instruction in memory
**/
function stepCPU() {
CPU.currentInstruction.opcode = CPU.memory[CPU.IP];
CPU.currentInstruction.operand = CPU.memory[CPU.IP+1];
let executeInstruction = opcodes2mnemonics[CPU.currentInstruction.opcode];
executeInstruction(CPU.currentInstruction.operand);
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.operand = CPU.memory[CPU.IP+1];
let executeInstruction = opcodes2mnemonics[CPU.currentInstruction.opcode];
executeInstruction(CPU.currentInstruction.operand);
CPU.cycleCounter += 1;
}
}
await logCPUState(debug);
}
/**
@ -285,18 +303,8 @@ function stepCPU() {
**/
exports.runProgram = async (code, debug = false) => {
startCPU(code);
let step = 0;
while (true) {
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);
while (CPU.running) {
stepCPU(debug);
};
}