// This is a sketch of a simulator for my paper computer, // made for two purposes: // // (1) figuring out the basic structure for a simple simulator // (2) testing some simple programs (hopefully) // // NOTA BENE: this simple version makes naive use of // Javascript numbers for opcodes, and a Javascript array // for the computer's "memory." This may cause some problems. 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; }, hop_lit: (lit) => { console.log("HOP lit"); console.log(" ↳ Memory at IP+1:", this.memory[this.instructionPointer+1]); if (this.acc === lit) { this.instructionPointer += 2; } else { this.instructionPointer += 1; } }, hop_addr: (addr) => { console.log("HOP addr"); if (this.acc === this.memory[addr]) { this.instructionPointer += 2; } else { this.instructionPointer += 1; } }, jump_lit: (lit) => { console.log("JMP lit"); this.instructionPointer = lit; }, jump_addr: (addr) => { console.log("JMP addr"); this.instructionPointer = this.memory[addr]; }, // TODO: UNIMPLEMENTED carry_toggle: () => { return; }, carry_hop: () => { return; }, }; 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; case 9: this.instructions.hop_lit(arg); break; case 10: this.instructions.hop_addr(arg); break; case 11: this.instructions.jump_lit(arg); break; case 12: this.instructions.jump_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"); } } } log_debug_state = () => { console.log(); console.group('CPU state'); console.log( `Acc: ${this.acc} IP: ${this.instructionPointer} 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'); }; }; // 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(); let test_hop = [ [5, 8], // ADD lit ... acc = 8 [9, 8], // HOP lit ... hop over next op if acc = 8 [0, 0], // END ... (hopped over) [7, 8], // SUB lit ... acc = 0 [0, 0] ] //let comp = new CPU(test_hop); //comp.run_program(); // TODO: TEST HOP_addr let test_jmp = [ [11, 4], // 0 [0, 0], // 1 ... END ... JMP'd over [0, 0], // 2 [0, 0], // 3 [5, 8], // 4 ... ADD lit ... acc = 8 [0, 0], // 5 ... END ] let comp = new CPU(test_jmp); comp.run_program(); console.table(comp.memory);