Refactor (CPU): Move more logic into `stepCPU()` in preparation for implementing single-stepping
This commit is contained in:
parent
3ac1276bfe
commit
aa6cbc3e6d
54
cpu.js
54
cpu.js
|
|
@ -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);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue