run-cpu / cpu - Change command-line interface to use more standard flags (--debug --step --pretty)
This commit is contained in:
parent
4bb394f039
commit
7cfad439f8
52
cpu.js
52
cpu.js
|
|
@ -322,8 +322,10 @@ function startCPU(code) {
|
|||
|
||||
/**
|
||||
* Execute just the next instruction in memory
|
||||
* @param {Object} debugInfo
|
||||
* @param {Boolean} [debug] - Print machine status and the line of code being executed
|
||||
**/
|
||||
async function stepCPU(debugInfo, debug = false) {
|
||||
async function stepCPU(debugInfo, debug = false, prettyPrintDisplay = 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');
|
||||
|
|
@ -351,33 +353,41 @@ async function stepCPU(debugInfo, debug = false) {
|
|||
CPU.cycleCounter += 1;
|
||||
}
|
||||
}
|
||||
logCPUState(debugInfo, debug);
|
||||
logCPUState(debugInfo, debug, prettyPrintDisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} code - Machine code to run
|
||||
* @param {any} debugInfo TODO type
|
||||
* @param {Boolean} [debug] - Enable/disable debugging printouts
|
||||
* @param {Number} [clockSpeed] - CPU clock speed in milliseconds
|
||||
* @param {Uint8Array} code - Machine code to run
|
||||
* @param {Object} debugInfo TODO type
|
||||
* @param {Boolean} [debug] - Enable/disable debugging printouts
|
||||
* @param {Boolean} [singleStep]
|
||||
* @param {Boolean} [prettyPrint] - Print display with black and white emoji, instead of in hex
|
||||
* @param {Number} [clockSpeed] - CPU clock speed in milliseconds
|
||||
**/
|
||||
exports.runProgram = (code, debugInfo, debug = false, clockSpeed = 100) => {
|
||||
startCPU(code);
|
||||
// Animate the output by pausing between steps
|
||||
const loop = setInterval(async () => {
|
||||
stepCPU(debugInfo, debug);
|
||||
if (!CPU.running) clearInterval(loop);
|
||||
}, clockSpeed);
|
||||
}
|
||||
exports.runProgram =
|
||||
(code, debugInfo, debug=false, singleStep=false, prettyPrint=false, clockSpeed=100) => {
|
||||
if (singleStep) {
|
||||
this.singleStepProgram(code, debugInfo, debug, prettyPrint);
|
||||
} else {
|
||||
startCPU(code);
|
||||
// Animate the output by pausing between steps
|
||||
const loop = setInterval(async () => {
|
||||
stepCPU(debugInfo, debug, prettyPrint);
|
||||
if (!CPU.running) clearInterval(loop);
|
||||
}, clockSpeed);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} code - Machine code to run
|
||||
* @param {any} debugInfo - TODO
|
||||
* @param {Boolean} [debug] - Enable/disable debugging printouts
|
||||
* @param {Boolean} [prettyPrintDisplay] - Print display using black and white emoji
|
||||
**/
|
||||
exports.singleStepProgram = (code, debugInfo, debug = false) => {
|
||||
exports.singleStepProgram = (code, debugInfo, debug = false, prettyPrintDisplay = false) => {
|
||||
startCPU(code);
|
||||
while (CPU.running) {
|
||||
stepCPU(debugInfo, debug);
|
||||
stepCPU(debugInfo, debug, prettyPrintDisplay);
|
||||
// FIXME: this prevents exiting with Ctrl+C:
|
||||
let key = readlineSync.keyIn('S to step, Q to quit > ', {
|
||||
limit: ['s', 'S', 'q', 'Q'],
|
||||
|
|
@ -393,19 +403,19 @@ exports.singleStepProgram = (code, debugInfo, debug = false) => {
|
|||
/**
|
||||
* @param {Boolean} [debug] - Enable/disable debugging printouts
|
||||
**/
|
||||
function logCPUState(debugInfo, debug = false) {
|
||||
console.group(`Step ${CPU.cycleCounter}`);
|
||||
function logCPUState(debugInfo, debug = false, prettyPrintDisplay = false) {
|
||||
console.group(`Line ${debugInfo[CPU.previousIP].lineNumber} - Step ${CPU.cycleCounter}`);
|
||||
console.log();
|
||||
if (!debug) console.clear();
|
||||
if (debug) {
|
||||
if (debug && !prettyPrintDisplay) {
|
||||
display.printDisplay(CPU.memory);
|
||||
} else {
|
||||
display.prettyPrintDisplay(CPU.memory);
|
||||
}
|
||||
console.log();
|
||||
console.log(`Line ${debugInfo[CPU.previousIP].lineNumber}: ${debugInfo[CPU.previousIP].source}`);
|
||||
console.log('Mnemonic:', CPU.currentInstruction.mnemonic);
|
||||
console.log(`Machine: $${num2hex(CPU.currentInstruction.opcode)} $${num2hex(CPU.currentInstruction.operand)}`);
|
||||
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)} ONZC: ${num2bin_4bit(CPU.FLAGS)}`);
|
||||
console.log(`KEY: $${num2hex(CPU.memory[KEYPAD_ADDR])} ${CPU.running ? "running" : "halted" }`);
|
||||
|
|
|
|||
63
run-cpu.js
63
run-cpu.js
|
|
@ -1,30 +1,55 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// Run: `./run-cpu.js run assembly.asm`
|
||||
// Debug: `./run-cpu.js debug assembly.asm`
|
||||
// Run with single-stepping: `./run-cpu.js step assembly.asm`
|
||||
// Debug with single-stepping: `./run-cpu.js stepdebug assembly.asm`
|
||||
// Usage: ./run-cpu.js -f code.asm [--debug] [--step] [--pretty]
|
||||
|
||||
const fs = require('fs');
|
||||
const computer = require('./cpu.js');
|
||||
const assembler = require('./assembler.js');
|
||||
const { logRunningHeader, logMemory } = require('./logging.js');
|
||||
const { logRunningHeader } = require('./logging.js');
|
||||
|
||||
const mode = process.argv[2];
|
||||
|
||||
// console.log(`Reading ${filename}`);
|
||||
const filename = process.argv[3];
|
||||
// Load file...
|
||||
|
||||
let filename = null;
|
||||
process.argv.forEach((arg, index) => {
|
||||
if (arg === '-f' && process.argv.length > (index -1)) {
|
||||
filename = process.argv[index + 1];
|
||||
}
|
||||
});
|
||||
|
||||
if (!filename) {
|
||||
console.error('Filename required');
|
||||
console.error('eg: run-cpu.js -f code.asm');
|
||||
process.exit()
|
||||
}
|
||||
|
||||
const inputFile_str = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
|
||||
// Check optional arguments...
|
||||
|
||||
let debug = false;
|
||||
let singleStep = false;
|
||||
let prettyPrint = false;
|
||||
process.argv.forEach((arg) => { if (arg === '--debug') { debug = true } });
|
||||
process.argv.forEach((arg) => { if (arg === '--step') { singleStep = true } });
|
||||
process.argv.forEach((arg) => { if (arg === '--pretty') { prettyPrint = true } });
|
||||
|
||||
let speed = null;
|
||||
process.argv.forEach((arg, index) => {
|
||||
if (arg === '--speed' && process.argv.length > (index -1)) {
|
||||
speed = parseInt(process.argv[index + 1]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let assemblerOutput = assembler.assemble(inputFile_str);
|
||||
if (mode === "debug") {
|
||||
logRunningHeader();
|
||||
computer.runProgram(assemblerOutput.machineCode, assemblerOutput.debugInfo, true);
|
||||
} else if (mode === "stepdebug") {
|
||||
logRunningHeader();
|
||||
computer.singleStepProgram(assemblerOutput.machineCode, assemblerOutput.debugInfo, true);
|
||||
} else if (mode === "step") {
|
||||
computer.singleStepProgram(assemblerOutput.machineCode, assemblerOutput.debugInfo, false);
|
||||
} else {
|
||||
computer.runProgram(assemblerOutput.machineCode, assemblerOutput.debugInfo, false, 200);
|
||||
}
|
||||
logRunningHeader();
|
||||
computer.runProgram(
|
||||
assemblerOutput.machineCode,
|
||||
assemblerOutput.debugInfo,
|
||||
debug,
|
||||
singleStep,
|
||||
prettyPrint,
|
||||
speed
|
||||
);
|
||||
Loading…
Reference in New Issue