Initial proof-of-concept -- a working but incomplete simulator
This commit is contained in:
commit
51581e6879
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Paper computer simulator experiment
|
||||||
|
|
||||||
|
## ISA
|
||||||
|
|
||||||
|
0 END
|
||||||
|
1 STO lit# ; store ... mem[lit#] <- A
|
||||||
|
2 STO addr ; store ... mem[mem[addr]] <- A
|
||||||
|
3 LDA lit# ; load ... A <- lit#
|
||||||
|
4 LDA addr ; load ... A <- mem[addr]
|
||||||
|
5 ADD lit# ; add ... A <- A + lit# ... and un/set carry flag
|
||||||
|
6 ADD addr ; add ... A <- A + mem[addr] ... and un/set carry flag
|
||||||
|
7 SUB lit# ; sub ... A <- A - lit# ... and un/set carry flag
|
||||||
|
8 SUB addr ; sub ... A <- A - mem[addr] ... and un/set carry flag
|
||||||
|
9 HOP lit# ; skip next instruction if A == lit# ... when true: IP <- PC + 2
|
||||||
|
A HOP addr ; skip next instruction if A == addr ... when true: IP <- PC + 2
|
||||||
|
B JMP lit# ; ... IP <- lit#
|
||||||
|
C JMP addr ; ... IP <- addr
|
||||||
|
D CAT ---- ; Carry Flag Toggle ... CF <- !CF
|
||||||
|
E CHP ---- ; skip next instruction if Carry Flag is set ... when true: IP <- PC + 2
|
||||||
|
F
|
||||||
|
|
||||||
|
### Nice features that didn't fit
|
||||||
|
|
||||||
|
- hop IF< and hop IF>
|
||||||
|
- MUL and DIV
|
||||||
|
- rotates and shifts
|
||||||
|
|
||||||
|
## Registers
|
||||||
|
|
||||||
|
- A -- accumulator
|
||||||
|
- IP -- instruction pointer (aka program counter)
|
||||||
|
|
||||||
|
## Flags
|
||||||
|
|
||||||
|
- CF -- carry flag
|
||||||
|
|
||||||
|
## Memory-mapped peripherals
|
||||||
|
|
||||||
|
- 4x4 display
|
||||||
|
- hex keypad (details TBD)
|
||||||
|
- ? bank selector (for bank-switching)
|
||||||
|
|
||||||
|
### Maybe someday
|
||||||
|
|
||||||
|
- timer (for a version in software/electronic-hardware)
|
||||||
|
|
||||||
|
## Tentative memory map
|
||||||
|
|
||||||
|
00-0F - display
|
||||||
|
10-1F - keypad? (details TBD)
|
||||||
|
20 - initial value for IP ?
|
||||||
|
21-FF - free
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 add_lit = function(lit) { return; }
|
||||||
|
let add_addr = function(addr) { return; }
|
||||||
|
let subtract_lit = function(lit) { return; }
|
||||||
|
let subtract_addr = function(addr) { return; }
|
||||||
|
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 basic_test = [
|
||||||
|
[3, 8], // LDA lit
|
||||||
|
[1, 5], // STO lit
|
||||||
|
[4, 5], // LDA addr
|
||||||
|
[2, 6], // STO addr
|
||||||
|
[0, 0], // END
|
||||||
|
];
|
||||||
|
|
||||||
|
let comp = new CPU(basic_test);
|
||||||
|
comp.run_program();
|
||||||
Loading…
Reference in New Issue