function CPU(mem) { this.memory = mem; this.running = false; this.instructionPointer = 0; this.carryFlag = 0; this.acc = 0; this.instructions = { end: () => { console.log('END'); this.running = false }, store_lit: (lit) => { console.log('STO lit#'); this.memory[lit] = this.acc; log_memory(); this.instructionPointer = this.instructionPointer += 1; }, store_addr: (addr) => { console.log('STO addr'); this.memory[this.memory[addr]] = this.acc; log_memory(); this.instructionPointer = this.instructionPointer += 1; }, load_lit: (lit) => { console.log('LDA lit#'); this.acc = lit; this.instructionPointer = this.instructionPointer += 1; }, load_addr: (addr) => { console.log('LDA addr'); console.log('mem at addr: ', this.memory[addr]); this.acc = this.memory[addr]; this.instructionPointer = this.instructionPointer += 1; }, add_lit: (lit) => { console.log("ADD lit"); if ( (this.acc + lit) > 15 ) { this.carryFlag = 1; } this.acc = (this.acc + lit % 15); this.instructionPointer = this.instructionPointer += 1; }, add_addr: (addr) => { console.log("ADD addr"); if ( (this.acc + this.memory[addr]) > 15 ) { this.carryFlag = 1; } this.acc = (this.acc + this.memory[addr] % 15); this.instructionPointer = this.instructionPointer += 1; }, sub_lit: (lit) => { // TODO: carry flag console.log("SUB lit"); this.acc = this.acc - lit; this.instructionPointer = this.instructionPointer += 1; }, sub_addr: (addr) => { // TODO: carry flag console.log("SUB addr"); this.acc = this.acc - this.memory[addr]; this.instructionPointer = this.instructionPointer += 1; }, }; log_debug_state = () => { console.log(); console.group('CPU state'); console.log( `IP: ${this.instructionPointer} Acc: ${this.acc}  CF: ${this.carryFlag}  ${this.running ? "running" : "halted" }` ); console.log(); console.groupEnd('CPU state'); }; log_memory = () => { console.log(); console.group('Memory'); console.table(this.memory); console.groupEnd('Memory'); } this.perform_operation = (opcode, arg) => { switch (opcode) { case 0: this.instructions.end(arg); break; case 1: this.instructions.store_lit(arg); break; case 2: this.instructions.store_addr(arg); break; case 3: this.instructions.load_lit(arg); break; case 4: this.instructions.load_addr(arg); break; case 5: this.instructions.add_lit(arg); break; case 6: this.instructions.add_addr(arg); break; case 7: this.instructions.sub_lit(arg); break; case 8: this.instructions.sub_addr(arg); break; default: console.error( `Invalid opcode: ${opcode} with argument ${arg}` ); } }; this.run_program = () => { console.log(); console.log( "Running program..." ); log_debug_state(); this.running = true; for (let i = 1; i < 16; i++) { if ( this.running && (this.instructionPointer < this.memory.length) ) { let op_arg_tuple = this.memory[this.instructionPointer]; console.group("Proccessing instruction"); console.log( op_arg_tuple ); // console.log( `processing opcode ${op_arg_tuple[0]} with arg ${op_arg_tuple[1]}` ); this.perform_operation(op_arg_tuple[0], op_arg_tuple[1]); log_debug_state(); console.groupEnd("Processing instruction"); } } } }; // UNIMPLEMENTED let hop_lit = function(lit) { return; } let hop_addr = function(addr) { return; } let jump_lit = function(lit) { return; } let jump_addr = function(addr) { return; } let carry_toggle = function() { return; } let carry_hop = function() { return; } // TEST let halt_and_catch_fire = [ [0, 0], [1, 0], ]; let test_lda_sto = [ [3, 8], // LDA lit [1, 5], // STO lit [4, 5], // LDA addr [2, 6], // STO addr [0, 0], // END ]; // let comp = new CPU(test_lda_sto); // comp.run_program(); let test_add_sub_nocarry = [ [5, 6], // ADD lit ... acc = 6 [7, 1], // SUB lit ... acc = 5 [1, 8], // STO lit ... mem[8] = 5 [6, 8], // ADD addr ... acc = 10 [8, 8], // SUB addr ... acc = 5 [0, 0], // END ] let test_add_sub = [ [5, 26], // ADD lit [0, 0], // END ] let comp = new CPU(test_add_sub); comp.run_program();