cpu - Change structure of CPU object to group State and Debug info
This commit is contained in:
parent
2d210303e6
commit
b173d46cb6
233
src/cpu.js
233
src/cpu.js
|
|
@ -16,39 +16,56 @@ const display = require('./display.js');
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
const CPU = {
|
const CPU = {
|
||||||
// Core state
|
|
||||||
running: false,
|
|
||||||
IP: INITIAL_IP_ADDRESS,
|
|
||||||
FLAGS: {'C': false, 'Z': false, 'N': false, 'O': false},
|
|
||||||
FLAGNUMS2NAMES: {0: 'C', 1: 'Z', 2: 'N', 3: 'O'},
|
|
||||||
Acc: 0,
|
|
||||||
memory: null,
|
|
||||||
|
|
||||||
// Functions that update core state
|
/** Core state **/
|
||||||
|
state: {
|
||||||
|
running: false,
|
||||||
|
IP: INITIAL_IP_ADDRESS,
|
||||||
|
flags: {'C': false, 'Z': false, 'N': false, 'O': false},
|
||||||
|
FLAGNUMS2NAMES: {0: 'C', 1: 'Z', 2: 'N', 3: 'O'},
|
||||||
|
acc: 0,
|
||||||
|
memory: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Debug info **/
|
||||||
|
debug: {
|
||||||
|
previousIP: 0,
|
||||||
|
currentInstruction: {
|
||||||
|
opcode: null,
|
||||||
|
operand: null,
|
||||||
|
mnemonic: null,
|
||||||
|
},
|
||||||
|
cycleCounter: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Functions that update state **/
|
||||||
|
|
||||||
/** @param {Uint8Array} data */
|
/** @param {Uint8Array} data */
|
||||||
loadMemory: (data) => {
|
loadMemory(data) {
|
||||||
CPU.memory = new Uint8Array(256);
|
this.state.memory = new Uint8Array(256);
|
||||||
CPU.memory.set(data, 0);
|
this.state.memory.set(data, 0);
|
||||||
},
|
},
|
||||||
incrementIP: (offset) => {
|
|
||||||
CPU.previousIP = CPU.IP;
|
|
||||||
CPU.IP = CPU.IP + offset;
|
|
||||||
},
|
|
||||||
setIP: (address) => {
|
|
||||||
CPU.previousIP = CPU.IP;
|
|
||||||
CPU.IP = address;
|
|
||||||
},
|
|
||||||
updateFlagZero: () => { CPU.FLAGS.Z = CPU.Acc === 0; },
|
|
||||||
updateFlagNegative: () => { CPU.Acc & 128 ? CPU.FLAGS.N = true : CPU.FLAGS.N = false },
|
|
||||||
|
|
||||||
// Debug info
|
incrementIP(offset) {
|
||||||
previousIP: 0,
|
this.state.previousIP = this.state.IP;
|
||||||
currentInstruction: {
|
this.state.IP = this.state.IP + offset;
|
||||||
opcode: null,
|
|
||||||
operand: null,
|
|
||||||
mnemonic: null,
|
|
||||||
},
|
},
|
||||||
cycleCounter: 0,
|
|
||||||
|
setIP(address) {
|
||||||
|
this.state.previousIP = this.state.IP;
|
||||||
|
this.state.IP = address;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateFlagZero() { this.state.flags.Z = this.state.acc === 0; },
|
||||||
|
updateFlagNegative() { this.state.acc & 128 ? this.state.flags.N = true : this.state.flags.N = false },
|
||||||
|
|
||||||
|
|
||||||
|
/** Hooks **/
|
||||||
|
|
||||||
|
onTickHooks: [],
|
||||||
|
|
||||||
|
/** @param {function} fn **/
|
||||||
|
onTick(fn) { this.onTickHooks.push(fn) },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -56,154 +73,154 @@ const CPU = {
|
||||||
|
|
||||||
const Instructions = {
|
const Instructions = {
|
||||||
end: () => {
|
end: () => {
|
||||||
CPU.currentInstruction.mnemonic = 'END';
|
CPU.debug.currentInstruction.mnemonic = 'END';
|
||||||
CPU.running = false;
|
CPU.state.running = false;
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
store_lit: (lit) => {
|
store_lit: (lit) => {
|
||||||
CPU.currentInstruction.mnemonic = 'STO lit';
|
CPU.debug.currentInstruction.mnemonic = 'STO lit';
|
||||||
CPU.memory[lit] = CPU.Acc;
|
CPU.state.memory[lit] = CPU.state.acc;
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
store_addr: (addr) => {
|
store_addr: (addr) => {
|
||||||
CPU.currentInstruction.mnemonic = `STO addr; @addr: ${num2hex(CPU.memory[addr])}`;
|
CPU.debug.currentInstruction.mnemonic = `STO addr; @addr: ${num2hex(CPU.state.memory[addr])}`;
|
||||||
CPU.memory[CPU.memory[addr]] = CPU.Acc;
|
CPU.state.memory[CPU.state.memory[addr]] = CPU.state.acc;
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
load_lit: (lit) => {
|
load_lit: (lit) => {
|
||||||
CPU.currentInstruction.mnemonic = 'LDA lit';
|
CPU.debug.currentInstruction.mnemonic = 'LDA lit';
|
||||||
CPU.Acc = lit;
|
CPU.state.acc = lit;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
CPU.updateFlagZero();
|
CPU.updateFlagZero();
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
load_addr: (addr) => {
|
load_addr: (addr) => {
|
||||||
CPU.currentInstruction.mnemonic = `LDA addr; @ addr: ${num2hex(CPU.memory[addr])}`;
|
CPU.debug.currentInstruction.mnemonic = `LDA addr; @ addr: ${num2hex(CPU.state.memory[addr])}`;
|
||||||
CPU.Acc = CPU.memory[addr];
|
CPU.state.acc = CPU.state.memory[addr];
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
CPU.updateFlagZero();
|
CPU.updateFlagZero();
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
add_lit: (lit) => {
|
add_lit: (lit) => {
|
||||||
CPU.currentInstruction.mnemonic = 'ADD lit';
|
CPU.debug.currentInstruction.mnemonic = 'ADD lit';
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc + lit;
|
let sum = CPU.state.acc + lit;
|
||||||
if (sum > 255) {
|
if (sum > 255) {
|
||||||
CPU.FLAGS.C = true;
|
CPU.state.flags.C = true;
|
||||||
sum = (sum % 255) - 1;
|
sum = (sum % 255) - 1;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.C = false;
|
CPU.state.flags.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
if ((CPU.state.acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
||||||
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.state.flags & 8);
|
||||||
// FIXME FIXME FIXME
|
// FIXME FIXME FIXME
|
||||||
// I'm on a plane and can't remember how this works
|
// I'm on a plane and can't remember how this works
|
||||||
let overflow = 0;
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.FLAGS.O = true;
|
CPU.state.flags.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.O = false;
|
CPU.state.flags.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.state.acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
CPU.updateFlagZero();
|
CPU.updateFlagZero();
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
add_addr: (addr) => {
|
add_addr: (addr) => {
|
||||||
CPU.currentInstruction.mnemonic = 'ADD addr';
|
CPU.debug.currentInstruction.mnemonic = 'ADD addr';
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc + CPU.memory[addr];
|
let sum = CPU.state.acc + CPU.state.memory[addr];
|
||||||
if (sum > 255) {
|
if (sum > 255) {
|
||||||
CPU.FLAGS.C = true;
|
CPU.state.flags.C = true;
|
||||||
sum = (sum % 255) - 1;
|
sum = (sum % 255) - 1;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.C = false;
|
CPU.state.flags.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
if ((CPU.state.acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
||||||
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.state.flags & 8);
|
||||||
// FIXME FIXME FIXME
|
// FIXME FIXME FIXME
|
||||||
// I'm on a plane and can't remember how this works
|
// I'm on a plane and can't remember how this works
|
||||||
let overflow = 0;
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.FLAGS.O = true;
|
CPU.state.flags.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.O = false;
|
CPU.state.flags.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.state.acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
CPU.updateFlagZero();
|
CPU.updateFlagZero();
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
sub_lit: (lit) => {
|
sub_lit: (lit) => {
|
||||||
CPU.currentInstruction.mnemonic = 'SUB lit';
|
CPU.debug.currentInstruction.mnemonic = 'SUB lit';
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc - lit;
|
let sum = CPU.state.acc - lit;
|
||||||
if (sum < 0) {
|
if (sum < 0) {
|
||||||
CPU.FLAGS.C = true;
|
CPU.state.flags.C = true;
|
||||||
sum = sum + 256;
|
sum = sum + 256;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.C = false;
|
CPU.state.flags.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
if ((CPU.state.acc & 64) && (lit & 64)) { bitSixCarry = 1; }
|
||||||
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.state.flags & 8);
|
||||||
// FIXME FIXME FIXME
|
// FIXME FIXME FIXME
|
||||||
// I'm on a plane and can't remember how this works
|
// I'm on a plane and can't remember how this works
|
||||||
let overflow = 0;
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.FLAGS.O = true;
|
CPU.state.flags.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.O = false;
|
CPU.state.flags.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.state.acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
CPU.updateFlagZero();
|
CPU.updateFlagZero();
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
sub_addr: (addr) => {
|
sub_addr: (addr) => {
|
||||||
CPU.currentInstruction.mnemonic = 'SUB addr';
|
CPU.debug.currentInstruction.mnemonic = 'SUB addr';
|
||||||
// Calculate sum
|
// Calculate sum
|
||||||
let sum = CPU.Acc - CPU.memory[addr];
|
let sum = CPU.state.acc - CPU.state.memory[addr];
|
||||||
if (sum < 0) {
|
if (sum < 0) {
|
||||||
CPU.FLAGS.C = true;
|
CPU.state.flags.C = true;
|
||||||
sum = sum + 256;
|
sum = sum + 256;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.C = false;
|
CPU.state.flags.C = false;
|
||||||
}
|
}
|
||||||
// Calculate overflow flag status
|
// Calculate overflow flag status
|
||||||
let bitSixCarry = 0;
|
let bitSixCarry = 0;
|
||||||
if ((CPU.Acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
if ((CPU.state.acc & 64) && (addr & 64)) { bitSixCarry = 1; }
|
||||||
// let overflow = bitSixCarry ^ (CPU.FLAGS & 8);
|
// let overflow = bitSixCarry ^ (CPU.state.flags & 8);
|
||||||
// FIXME FIXME FIXME
|
// FIXME FIXME FIXME
|
||||||
// I'm on a plane and can't remember how this works
|
// I'm on a plane and can't remember how this works
|
||||||
let overflow = 0;
|
let overflow = 0;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
CPU.FLAGS.O = true;
|
CPU.state.flags.O = true;
|
||||||
} else {
|
} else {
|
||||||
CPU.FLAGS.O = false;
|
CPU.state.flags.O = false;
|
||||||
}
|
}
|
||||||
CPU.Acc = sum;
|
CPU.state.acc = sum;
|
||||||
CPU.updateFlagNegative();
|
CPU.updateFlagNegative();
|
||||||
CPU.updateFlagZero();
|
CPU.updateFlagZero();
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
hop_lit: (lit) => {
|
hop_lit: (lit) => {
|
||||||
CPU.currentInstruction.mnemonic = `HOP lit; IP+2: ${CPU.memory[CPU.IP+2]}, IP+3: ${CPU.memory[CPU.IP+3]}`;
|
CPU.debug.currentInstruction.mnemonic = `HOP lit; IP+2: ${CPU.state.memory[CPU.state.IP+2]}, IP+3: ${CPU.state.memory[CPU.state.IP+3]}`;
|
||||||
if (CPU.Acc === lit) {
|
if (CPU.state.acc === lit) {
|
||||||
CPU.incrementIP(4);
|
CPU.incrementIP(4);
|
||||||
} else {
|
} else {
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
|
|
@ -211,8 +228,8 @@ const Instructions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
hop_addr: (addr) => {
|
hop_addr: (addr) => {
|
||||||
CPU.currentInstruction.mnemonic = 'HOP addr';
|
CPU.debug.currentInstruction.mnemonic = 'HOP addr';
|
||||||
if (CPU.Acc === CPU.memory[addr]) {
|
if (CPU.state.acc === CPU.state.memory[addr]) {
|
||||||
CPU.incrementIP(4);
|
CPU.incrementIP(4);
|
||||||
} else {
|
} else {
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
|
|
@ -220,13 +237,13 @@ const Instructions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
jump_lit: (lit) => {
|
jump_lit: (lit) => {
|
||||||
CPU.currentInstruction.mnemonic = 'JMP lit';
|
CPU.debug.currentInstruction.mnemonic = 'JMP lit';
|
||||||
CPU.setIP(lit);
|
CPU.setIP(lit);
|
||||||
},
|
},
|
||||||
|
|
||||||
jump_addr: (addr) => {
|
jump_addr: (addr) => {
|
||||||
CPU.currentInstruction.mnemonic = 'JMP addr';
|
CPU.debug.currentInstruction.mnemonic = 'JMP addr';
|
||||||
CPU.setIP(CPU.memory[addr]);
|
CPU.setIP(CPU.state.memory[addr]);
|
||||||
},
|
},
|
||||||
|
|
||||||
flag_toggle: (flagNum) => {
|
flag_toggle: (flagNum) => {
|
||||||
|
|
@ -235,8 +252,8 @@ const Instructions = {
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
|
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
|
||||||
CPU.currentInstruction.mnemonic = `FTG ${flagName}`;
|
CPU.debug.currentInstruction.mnemonic = `FTG ${flagName}`;
|
||||||
CPU.FLAGS[flagName] = !CPU.FLAGS[flagName];
|
CPU.state.flags[flagName] = !CPU.state.flags[flagName];
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -246,8 +263,8 @@ const Instructions = {
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
|
const flagName = CPU.FLAGNUMS2NAMES[flagNum];
|
||||||
CPU.currentInstruction.mnemonic = `FHP ${flagName}; IP+2: ${CPU.memory[CPU.IP+2]}, IP+3: ${CPU.memory[CPU.IP+3]}`;
|
CPU.debug.currentInstruction.mnemonic = `FHP ${flagName}; IP+2: ${CPU.state.memory[CPU.state.IP+2]}, IP+3: ${CPU.state.memory[CPU.state.IP+3]}`;
|
||||||
if (CPU.FLAGS[CPU.FLAGNUMS2NAMES[flagNum]]) {
|
if (CPU.state.flags[CPU.FLAGNUMS2NAMES[flagNum]]) {
|
||||||
CPU.incrementIP(4);
|
CPU.incrementIP(4);
|
||||||
} else {
|
} else {
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
|
|
@ -255,7 +272,7 @@ const Instructions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
no_op: () => {
|
no_op: () => {
|
||||||
CPU.currentInstruction.mnemonic = `NOP`;
|
CPU.debug.currentInstruction.mnemonic = `NOP`;
|
||||||
CPU.incrementIP(2);
|
CPU.incrementIP(2);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -280,13 +297,13 @@ const opcodes2mnemonics = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load code into memory and set CPU state to "running"
|
* Load code into memory and set CPU state to "state.running"
|
||||||
* @param {Uint8Array} code - Machine code to load
|
* @param {Uint8Array} code - Machine code to load
|
||||||
**/
|
**/
|
||||||
function startCPU(code) {
|
function startCPU(code) {
|
||||||
CPU.loadMemory(code);
|
CPU.loadMemory(code);
|
||||||
CPU.cycleCounter = 0;
|
CPU.debug.cycleCounter = 0;
|
||||||
CPU.running = true;
|
CPU.state.running = true;
|
||||||
|
|
||||||
// FIXME: This conflicts with single-stepping
|
// FIXME: This conflicts with single-stepping
|
||||||
// (you can single-step, but keys aren't passed
|
// (you can single-step, but keys aren't passed
|
||||||
|
|
@ -309,7 +326,7 @@ function startCPU(code) {
|
||||||
if (key.sequence === '\x03') process.exit();
|
if (key.sequence === '\x03') process.exit();
|
||||||
let name = key.name.toUpperCase();
|
let name = key.name.toUpperCase();
|
||||||
if (name in KEY_MAP) {
|
if (name in KEY_MAP) {
|
||||||
CPU.memory[KEYPAD_ADDR] = KEY_MAP[name];
|
CPU.state.memory[KEYPAD_ADDR] = KEY_MAP[name];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -320,14 +337,14 @@ function startCPU(code) {
|
||||||
* @param {Boolean} [debug] - Print machine status and the line of code being executed
|
* @param {Boolean} [debug] - Print machine status and the line of code being executed
|
||||||
**/
|
**/
|
||||||
async function stepCPU(debugInfo, debug = false, prettyPrintDisplay = false) {
|
async function stepCPU(debugInfo, debug = false, prettyPrintDisplay = false) {
|
||||||
if (CPU.IP >= CPU.memory.length) {
|
if (CPU.state.IP >= CPU.state.memory.length) {
|
||||||
console.error('HALTING - IP greater than memory size');
|
console.error('HALTING - IP greater than memory size');
|
||||||
CPU.running = false;
|
CPU.state.running = false;
|
||||||
process.exit();
|
process.exit();
|
||||||
} else {
|
} else {
|
||||||
CPU.currentInstruction.opcode = CPU.memory[CPU.IP];
|
CPU.debug.currentInstruction.opcode = CPU.state.memory[CPU.state.IP];
|
||||||
CPU.currentInstruction.operand = CPU.memory[CPU.IP+1];
|
CPU.debug.currentInstruction.operand = CPU.state.memory[CPU.state.IP+1];
|
||||||
let executeInstruction = opcodes2mnemonics[CPU.currentInstruction.opcode];
|
let executeInstruction = opcodes2mnemonics[CPU.debug.currentInstruction.opcode];
|
||||||
if (typeof executeInstruction === 'undefined') {
|
if (typeof executeInstruction === 'undefined') {
|
||||||
let info = debugInfo[CPU.previousIP];
|
let info = debugInfo[CPU.previousIP];
|
||||||
console.error();
|
console.error();
|
||||||
|
|
@ -336,17 +353,17 @@ async function stepCPU(debugInfo, debug = false, prettyPrintDisplay = false) {
|
||||||
console.error(` from line ${info.lineNumber}: ${info.source}`);
|
console.error(` from line ${info.lineNumber}: ${info.source}`);
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
executeInstruction(CPU.currentInstruction.operand);
|
executeInstruction(CPU.debug.currentInstruction.operand);
|
||||||
CPU.cycleCounter += 1;
|
CPU.debug.cycleCounter += 1;
|
||||||
}
|
}
|
||||||
logCPUState(debugInfo, debug, prettyPrintDisplay);
|
logCPUState(debugInfo, debug, prettyPrintDisplay);
|
||||||
if (DEFAULT_CYCLE_LIMIT) { // Temporary limit as a lazy way to halt infinite loops
|
if (DEFAULT_CYCLE_LIMIT) { // Temporary limit as a lazy way to halt infinite loops
|
||||||
if (CPU.cycleCounter >= DEFAULT_CYCLE_LIMIT) {
|
if (CPU.debug.cycleCounter >= DEFAULT_CYCLE_LIMIT) {
|
||||||
console.warn(' HALTING - reached cycle limit');
|
console.warn(' HALTING - reached cycle limit');
|
||||||
CPU.running = false;
|
CPU.state.running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!CPU.running) process.exit();
|
if (!CPU.state.running) process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -366,7 +383,7 @@ exports.runProgram =
|
||||||
// Animate the output by pausing between steps
|
// Animate the output by pausing between steps
|
||||||
const loop = setInterval(async () => {
|
const loop = setInterval(async () => {
|
||||||
stepCPU(debugInfo, debug, prettyPrint);
|
stepCPU(debugInfo, debug, prettyPrint);
|
||||||
if (!CPU.running) {
|
if (!CPU.state.running) {
|
||||||
logCPUState(debugInfo, debug, prettyPrint);
|
logCPUState(debugInfo, debug, prettyPrint);
|
||||||
console.log('Halted');
|
console.log('Halted');
|
||||||
process.exit();
|
process.exit();
|
||||||
|
|
@ -383,7 +400,7 @@ exports.runProgram =
|
||||||
**/
|
**/
|
||||||
exports.singleStepProgram = (code, debugInfo, debug = false, prettyPrintDisplay = false) => {
|
exports.singleStepProgram = (code, debugInfo, debug = false, prettyPrintDisplay = false) => {
|
||||||
startCPU(code);
|
startCPU(code);
|
||||||
while (CPU.running) {
|
while (CPU.state.running) {
|
||||||
stepCPU(debugInfo, debug, prettyPrintDisplay);
|
stepCPU(debugInfo, debug, prettyPrintDisplay);
|
||||||
// FIXME: this prevents exiting with Ctrl+C:
|
// FIXME: this prevents exiting with Ctrl+C:
|
||||||
let key = readlineSync.keyIn('S to step, Q to quit > ', {
|
let key = readlineSync.keyIn('S to step, Q to quit > ', {
|
||||||
|
|
@ -402,20 +419,20 @@ exports.singleStepProgram = (code, debugInfo, debug = false, prettyPrintDisplay
|
||||||
**/
|
**/
|
||||||
function logCPUState(debugInfo, debug = false, prettyPrintDisplay = false) {
|
function logCPUState(debugInfo, debug = false, prettyPrintDisplay = false) {
|
||||||
debugInfo = debugInfo[CPU.previousIP] !== 'undefined' ? debugInfo[CPU.previousIP] : false;
|
debugInfo = debugInfo[CPU.previousIP] !== 'undefined' ? debugInfo[CPU.previousIP] : false;
|
||||||
console.group(`Step ${CPU.cycleCounter}`);
|
console.group(`Step ${CPU.debug.cycleCounter}`);
|
||||||
console.log();
|
console.log();
|
||||||
if (!debug) console.clear();
|
if (!debug) console.clear();
|
||||||
display.show(CPU.memory, prettyPrintDisplay);
|
display.show(CPU.state.memory, prettyPrintDisplay);
|
||||||
console.log();
|
console.log();
|
||||||
if (debugInfo) {
|
if (debugInfo) {
|
||||||
console.log(`Line ${debugInfo.lineNumber}: ${debugInfo.source}`);
|
console.log(`Line ${debugInfo.lineNumber}: ${debugInfo.source}`);
|
||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
console.log('Mnemonic:', CPU.currentInstruction.mnemonic);
|
console.log('Mnemonic:', CPU.debug.currentInstruction.mnemonic);
|
||||||
console.log(`Machine: $${num2hex(CPU.currentInstruction.opcode)} $${num2hex(CPU.currentInstruction.operand)}`);
|
console.log(`Machine: $${num2hex(CPU.debug.currentInstruction.opcode)} $${num2hex(CPU.debug.currentInstruction.operand)}`);
|
||||||
console.log();
|
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(`IP: $${num2hex(CPU.state.IP)} Acc: $${num2hex(CPU.state.acc)} ONZC ${bool2bit(CPU.state.flags.O)}${bool2bit(CPU.state.flags.N)}${bool2bit(CPU.state.flags.Z)}${bool2bit(CPU.state.flags.C)}`);
|
||||||
console.log(`KEY: $${num2hex(CPU.memory[KEYPAD_ADDR])} ${CPU.running ? "running" : "halted" }`);
|
console.log(`KEY: $${num2hex(CPU.state.memory[KEYPAD_ADDR])} ${CPU.state.running ? "state.running" : "halted" }`);
|
||||||
console.log();
|
console.log();
|
||||||
console.log();
|
console.log();
|
||||||
console.groupEnd();
|
console.groupEnd();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue