99 lines
2.7 KiB
JavaScript
Executable File
99 lines
2.7 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
const fs = require('fs');
|
|
|
|
const DBG = require('./dbg.js');
|
|
const Opter = require('./opter/opter.js');
|
|
const { num2hex, bool2bit } = require('./conversions.js');
|
|
|
|
const CFG = require('./machine.config.js');
|
|
const CPU = require('./cpu.js');
|
|
const io = require('./io.js');
|
|
|
|
|
|
/** SETUP **/
|
|
const dbg = new DBG('nitpick');
|
|
let cpu = new CPU(CFG.initialIP, CFG.defaultCycleLimit);
|
|
|
|
main();
|
|
|
|
async function main() {
|
|
const opter = new Opter();
|
|
opter.addOption('-i', '--in', false, true, 1);
|
|
const opts = opter.parse(process.argv);
|
|
|
|
let input = null;
|
|
if ('in' in opts) { // Read from file
|
|
input = fs.readFileSync(opts.in[0], 'utf8');
|
|
} else { // Read from stdin
|
|
input = await readPipedStdin();
|
|
}
|
|
|
|
let code = null;
|
|
let sourceAnnotations = null;
|
|
|
|
try {
|
|
const parsedInput = JSON.parse(input);
|
|
sourceAnnotations = parsedInput.sourceAnnotations;
|
|
code = new Uint8Array(parsedInput.machineCode);
|
|
} catch (error) {
|
|
if (error.name === 'SyntaxError') {
|
|
code = new Uint8Array(input.split(' '));
|
|
}
|
|
}
|
|
|
|
cpu.loadMemory(code);
|
|
if (sourceAnnotations !== null) { cpu.loadSourceAnnotations(sourceAnnotations); }
|
|
|
|
cpu.onCycleEnd(tick);
|
|
cpu.onCycleEnd(logCPUState);
|
|
|
|
cpu.start();
|
|
io.getKeypadInput(cpu);
|
|
cpu.step();
|
|
}
|
|
|
|
|
|
async function tick() {
|
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
await sleep(100);
|
|
cpu.step();
|
|
if (!cpu.running) {
|
|
console.log('Halted');
|
|
process.exit();
|
|
}
|
|
}
|
|
|
|
function logCPUState() {
|
|
let lineInfo = null;
|
|
if (cpu.dbg.sourceAnnotations) {
|
|
lineInfo = cpu.dbg.sourceAnnotations[cpu.dbg.previousIP];
|
|
}
|
|
console.group(`Step ${cpu.dbg.cycleCounter}`);
|
|
console.log();
|
|
io.showDisplay(cpu.memory, true); // FIXME - display - allow printing hex as well as pretty-printing
|
|
console.log();
|
|
if (lineInfo) {
|
|
console.log(`Line ${lineInfo.lineNumber}: ${lineInfo.source}`);
|
|
console.log();
|
|
}
|
|
console.log('Mnemonic:', cpu.dbg.currentMnemonic);
|
|
console.log(`Machine: $${num2hex(cpu.instruction.opcode)} $${num2hex(cpu.instruction.operand)}`);
|
|
console.log();
|
|
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: ${io.readKeyMem(cpu.memory)} ${cpu.running ? "running" : "halted" }`);
|
|
console.log();
|
|
console.groupEnd();
|
|
};
|
|
|
|
async function readPipedStdin() {
|
|
// https://wellingguzman.com/notes/node-pipe-input
|
|
return new Promise(function (resolve, reject) {
|
|
const stdin = process.stdin;
|
|
stdin.setEncoding('utf8');
|
|
let data = '';
|
|
stdin.on('data', function (chunk) { data += chunk; });
|
|
stdin.on('end', function () { resolve(data); });
|
|
stdin.on('error', reject);
|
|
});
|
|
} |