cardiograph-computer/javascript-old/cardiograph.js

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);
});
}