From dd0fdd3b062d0c5bcd93308be919e910f0765713 Mon Sep 17 00:00:00 2001 From: n loewen Date: Wed, 16 Aug 2023 13:56:23 +0100 Subject: [PATCH] Feature (CPU): Implement a simple single-stepping mode --- cpu.js | 19 +++++++++++++++++++ notes/2023-08-16--dev-notes.md | 2 +- package-lock.json | 11 +++++++++++ package.json | 5 ++++- readme.md | 6 ++++++ run-cpu.js | 11 ++++++++--- sketches/stdin.js | 23 +++++++++++++++++++++++ 7 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 sketches/stdin.js diff --git a/cpu.js b/cpu.js index 3c04c19..c70ce3a 100644 --- a/cpu.js +++ b/cpu.js @@ -1,3 +1,5 @@ +const readlineSync = require('readline-sync'); + const { INITIAL_IP_ADDRESS, CYCLE_LIMIT } = require('./machine.config'); const { num2hex, num2bin_4bit } = require('./logging.js'); const display = require('./display.js'); @@ -311,6 +313,23 @@ exports.runProgram = (code, debug = false, clockSpeed = 10) => { }, clockSpeed); } +/** + * @param {Uint8Array} code - Machine code to run + * @param {Boolean} [debug] - Enable/disable debugging printouts + **/ +exports.singleStepProgram = (code, debug = false) => { + startCPU(code); + while (CPU.running) { + stepCPU(debug); + // FIXME: this prevents exiting with Ctrl+C: + let key = readlineSync.keyIn('S to step, Q to quit > ', { + limit: ['s', 'S', 'q', 'Q'], + }); + if (key.toLowerCase() === 'q') { process.exit(); } + console.log(); + } +} + // FUNCTIONS THAT PULL INFO FROM STATE TO DISPLAY diff --git a/notes/2023-08-16--dev-notes.md b/notes/2023-08-16--dev-notes.md index 7667238..d1d498c 100644 --- a/notes/2023-08-16--dev-notes.md +++ b/notes/2023-08-16--dev-notes.md @@ -8,7 +8,7 @@ - [ ] Notes re: ROM and/or tape loader - [ ] CPU updates - [x] Rename to CPU - - [ ] Implement single-stepping + - [x] Implement single-stepping - [ ] Implement keypad input - [ ] Look at KIM-1 and VIP buttons for memory editing diff --git a/package-lock.json b/package-lock.json index 6cc63b5..f7b9e0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,9 @@ "packages": { "": { "name": "paper-computer", + "dependencies": { + "readline-sync": "^1.4.10" + }, "devDependencies": { "jsdoc": "^4.0.2", "jsdoc-to-markdown": "^8.0.0" @@ -720,6 +723,14 @@ "node": ">=0.10.0" } }, + "node_modules/readline-sync": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", + "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/reduce-extract": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/reduce-extract/-/reduce-extract-1.0.0.tgz", diff --git a/package.json b/package.json index 1d497cb..fa555ee 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,13 @@ { "name": "paper-computer", "scripts": { - "jsdoc": "./node_modules/.bin/jsdoc" + "jsdoc": "./node_modules/.bin/jsdoc" }, "devDependencies": { "jsdoc": "^4.0.2", "jsdoc-to-markdown": "^8.0.0" + }, + "dependencies": { + "readline-sync": "^1.4.10" } } diff --git a/readme.md b/readme.md index e85b2f1..77d6bfe 100644 --- a/readme.md +++ b/readme.md @@ -25,6 +25,12 @@ With animated display of screen memory: With verbose debugging output: ```./run-cpu debug source_code.asm``` +With single stepping + pretty-printed display: +```./run-cpu step source_code.asm``` + +With single stepping + verbose debugging output: +```./run-cpu stepdebug source_code.asm``` + ## Instruction set 00 END diff --git a/run-cpu.js b/run-cpu.js index dae2798..0a15efc 100755 --- a/run-cpu.js +++ b/run-cpu.js @@ -2,6 +2,8 @@ // 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` // TODO: allow running pre-compiled machine code. // @@ -22,12 +24,15 @@ const mode = process.argv[2]; const filename = process.argv[3]; const inputFile_str = fs.readFileSync(filename, 'utf8'); -let machineCode; +let machineCode = assembler.assemble(inputFile_str); if (mode === "debug") { logRunningHeader(); - machineCode = assembler.assemble(inputFile_str); computer.runProgram(machineCode, true); +} else if (mode === "stepdebug") { + logRunningHeader(); + computer.singleStepProgram(machineCode, true); +} else if (mode === "step") { + computer.singleStepProgram(machineCode, false); } else { - machineCode = assembler.assemble(inputFile_str); computer.runProgram(machineCode, false, 200); } \ No newline at end of file diff --git a/sketches/stdin.js b/sketches/stdin.js new file mode 100644 index 0000000..f5bb772 --- /dev/null +++ b/sketches/stdin.js @@ -0,0 +1,23 @@ +const readlineSync = require('readline-sync'); + +let key = readlineSync.keyIn('? ') +console.log(key); + +/* This works without external dependencies, + * but it's for a full line at a time +const readline = require('readline/promises'); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +async function getInput(prompt) { + let input = await rl.question(prompt) + console.log(input); + console.log("Later"); + rl.close(); +} + +getInput('?'); +*/ \ No newline at end of file