Initial proof-of-concept -- a working but incomplete simulator

This commit is contained in:
n loewen 2023-07-25 15:05:11 +01:00
commit 51581e6879
2 changed files with 183 additions and 0 deletions

52
readme.md Normal file
View File

@ -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

131
simulator-sketch.js Normal file
View File

@ -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();