cardiograph-computer/simulator-sketch.js

300 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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_table_with_title(this.memory, 'Current memory');
this.instructionPointer = this.instructionPointer += 1;
},
store_addr: (addr) => {
console.log('STO addr');
this.memory[this.memory[addr]] = this.acc;
log_table_with_title(this.memory, '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];
},
carry_clear: () => {
console.log("CFC");
this.carryFlag = 0;
this.instructionPointer += 1;
},
carry_hop: () => {
console.log("CHP");
if (this.carryFlag != 0) {
this.instructionPointer += 2;
} else {
this.instructionPointer += 1;
}
},
};
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;
case 13:
this.instructions.carry_clear(arg);
break;
case 14:
this.instructions.carry_hop(arg);
break;
default:
console.error( `Invalid opcode: ${opcode} with argument ${arg}` );
}
}
this.run_program = () => {
const initialMemory = JSON.parse(JSON.stringify(this.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("————————————————————————————————————————");
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");
}
}
return {
memoryAtStart: initialMemory,
memoryAtEnd: this.memory
}
}
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_table_with_title = (memory, tableTitle) => {
console.log();
console.group(tableTitle);
console.table(memory);
console.groupEnd(tableTitle);
};
// TESTS
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 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 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 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 test_chp = [
[5, 8], // ADD lit ... acc = 8
[14, 0], // CHP ... shouldn't hop (CF = 0)
[5, 1], // ADD lit ... acc = 9
[5, 8], // ADD lit ... acc = 1 and CF = 1
[14, 0], // CHP ... hop! (CF = 1)
[0, 0], // END
[7, 1], // SUB lit ... acc = 0
[13, 0], // CFC ... CF = 0
[0, 0], // END
]
//let comp = new CPU(test_chp);
let comp = new CPU(test_lda_sto);
let memory_snapshots = comp.run_program();
log_table_with_title(memory_snapshots.memoryAtEnd, 'Memory after running');
log_table_with_title(memory_snapshots.memoryAtStart, 'Memory before running');
// TODO: TEST HOP_addr