cardiograph-computer/simulator-sketch.js

262 lines
6.1 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_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];
},
// 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);