// 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();