130 lines
3.2 KiB
JavaScript
130 lines
3.2 KiB
JavaScript
// STATE
|
||
|
||
const CPU = {
|
||
running: false,
|
||
IP: 0,
|
||
CF: 0,
|
||
Acc: 0,
|
||
memory: null,
|
||
loadMemory: (data) => { // data: Uint8Array
|
||
// TODO: check length of data
|
||
CPU.memory = data;
|
||
},
|
||
}
|
||
|
||
|
||
// FUNCTIONS THAT MODIFY STATE
|
||
|
||
const Instructions = {
|
||
end: () => {
|
||
console.log('END');
|
||
CPU.running = false;
|
||
},
|
||
|
||
store_lit: (lit) => {
|
||
console.log('STO lit#');
|
||
CPU.memory[lit] = CPU.acc;
|
||
logTableTitled(CPU.memory, 'Current memory');
|
||
CPU.IP = CPU.IP += 2;
|
||
},
|
||
|
||
store_addr: (addr) => {
|
||
console.log('STO addr');
|
||
CPU.memory[CPU.memory[addr]] = CPU.acc;
|
||
logTableTitled(CPU.memory, 'Memory');
|
||
CPU.IP = CPU.IP += 2;
|
||
},
|
||
|
||
load_lit: (lit) => {
|
||
console.log('LDA lit#');
|
||
CPU.acc = lit;
|
||
CPU.IP = CPU.IP += 2;
|
||
},
|
||
|
||
load_addr: (addr) => {
|
||
console.log('LDA addr');
|
||
console.log('mem at addr: ', CPU.memory[addr]);
|
||
CPU.acc = CPU.memory[addr];
|
||
CPU.IP = CPU.IP += 2;
|
||
},
|
||
}
|
||
|
||
const instructionLookupTable = {
|
||
0: (arg) => Instructions.end(arg),
|
||
1: (arg) => Instructions.store_lit(arg),
|
||
2: (arg) => Instructions.store_addr(arg),
|
||
3: (arg) => Instructions.load_lit(arg),
|
||
4: (arg) => Instructions.load_addr(arg),
|
||
};
|
||
|
||
function stepCPU() {
|
||
console.group("Step CPU");
|
||
let opcode = CPU.memory[CPU.IP];
|
||
let argument = CPU.memory[CPU.IP+1];
|
||
|
||
console.log(`OP: ${opcode} ARG: ${argument}`);
|
||
|
||
let instruction = instructionLookupTable[opcode];
|
||
instruction(argument);
|
||
|
||
logCPUState();
|
||
console.groupEnd("Step CPU");
|
||
}
|
||
|
||
function runCPU() {
|
||
const initialMemory = JSON.parse(JSON.stringify(CPU.memory)); // Hack to make a copy-by-value -- https://stackoverflow.com/questions/18829099/copy-a-variables-value-into-another
|
||
console.log();
|
||
console.log("————————————————————————————————————————");
|
||
let time = new Date();
|
||
console.log( `Running at ${time.toLocaleTimeString('en-US')}` );
|
||
console.log("————————————————————————————————————————");
|
||
logCPUState();
|
||
|
||
CPU.running = true;
|
||
for (let i = 0; i < 255; i++) { // FIXME: temporary limit as a lazy way to halt infinite loops
|
||
if (!CPU.running) break;
|
||
if (CPU.IP >= CPU.memory.length) break;
|
||
stepCPU();
|
||
};
|
||
}
|
||
|
||
|
||
// FUNCTIONS THAT PULL INFO FROM STATE TO DISPLAY
|
||
|
||
function logCPUState() {
|
||
console.log();
|
||
console.group('CPU state');
|
||
console.log( `Acc: ${CPU.acc} IP: ${CPU.IP} CF: ${CPU.CF} ${CPU.running ? "running" : "halted" }` );
|
||
console.log();
|
||
console.groupEnd('CPU state');
|
||
};
|
||
|
||
|
||
// FUNCTIONS FOR DISPLAYING DATA
|
||
|
||
function num2hex(num) { num.toString(16) };
|
||
function hex2num(hex) { parseInt(hex, 16) };
|
||
|
||
logTableTitled = (memory, tableTitle) => {
|
||
console.log();
|
||
console.group(tableTitle);
|
||
console.table(memory);
|
||
console.groupEnd(tableTitle);
|
||
};
|
||
|
||
|
||
// RUN IT !
|
||
|
||
const test_lda_sto = new Uint8Array([
|
||
3, 17, // LDA lit ... acc = 17
|
||
1, 14, // STO lit ... @14 = acc = 17
|
||
3, 16, // LDA lit ... acc = 16
|
||
1, 15, // STO lit ... @15 = acc = 16
|
||
2, 15, // STO addr ... @[@15] = acc = 16 ... mem[mem[addr]] <- Acc
|
||
4, 0, // LDA addr ... acc = @00 = 03
|
||
0, 0, // END
|
||
0, 0, // DATA
|
||
]);
|
||
|
||
CPU.loadMemory(test_lda_sto);
|
||
runCPU(); |