cpu - Create sketch for a lower-level cpu simulator
- includes passing data through address and data buses, for example - incomplete (and in need of some re-thinking), but instructive - see dev notes from 2023-09-03 and 2023-09-04 for more commentary
This commit is contained in:
parent
77a41d47c3
commit
871fecb9af
|
|
@ -0,0 +1,198 @@
|
||||||
|
/* CPU sketch */
|
||||||
|
|
||||||
|
class CPU {
|
||||||
|
constructor () {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
IP = 0;
|
||||||
|
A = 0;
|
||||||
|
flags = 0b00000000;
|
||||||
|
instruction = 0x00;
|
||||||
|
operand = 0x00;
|
||||||
|
|
||||||
|
//What do I want for interrupts…?
|
||||||
|
// interruptRequest = 0;
|
||||||
|
|
||||||
|
// TODO: can it be a simple setup with fixed instruction cycle length pls?
|
||||||
|
_instructionCycleStep = 0;
|
||||||
|
_decodedOp = {};
|
||||||
|
_calculatedIP = 0;
|
||||||
|
|
||||||
|
tickClock () {
|
||||||
|
console.log('cpu tick');
|
||||||
|
if (connections.cpuWait) return false;
|
||||||
|
|
||||||
|
switch (this._instructionCycleStep) {
|
||||||
|
// Fetch - instruction
|
||||||
|
case 0:
|
||||||
|
// initiate read
|
||||||
|
connections.addressBus = this.IP;
|
||||||
|
connections.memoryReadSignal = 1;
|
||||||
|
this._calculatedIP += 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// complete read
|
||||||
|
connections.memoryReadSignal = 0;
|
||||||
|
this.instruction = connections.dataBus;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Fetch - operand
|
||||||
|
case 2:
|
||||||
|
// initiate read
|
||||||
|
connections.addressBus = this.IP;
|
||||||
|
connections.memoryReadSignal = 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// complete read
|
||||||
|
connections.memoryReadSignal = 0;
|
||||||
|
this.operand = connections.dataBus;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Decode
|
||||||
|
case 4:
|
||||||
|
// decode
|
||||||
|
this._decode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
case 5:
|
||||||
|
this._ops[this._decodedOp]();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// execute more
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this._instructionCycleStep = (this._instructionCycleStep + 1) % 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset () {
|
||||||
|
this.IP = 0xFE;
|
||||||
|
this.A = 0;
|
||||||
|
this.flags = 0b00000000;
|
||||||
|
connections.dataBus = 0b00000000;
|
||||||
|
this._instructionCycleStep = 0;
|
||||||
|
this.debug.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_decode (instruction) {
|
||||||
|
/*
|
||||||
|
// gg aa iiii
|
||||||
|
let group = 0b11000000 & instruction;
|
||||||
|
let mode = 0b00110000 & instruction;
|
||||||
|
let instr = 0b00001111 & instruction;
|
||||||
|
console.log(group, mode, instr);
|
||||||
|
*/
|
||||||
|
|
||||||
|
let mode = (0b00110000 & instruction) === 16 ? 'indirect' : 'direct';
|
||||||
|
|
||||||
|
const instrs = {
|
||||||
|
0x00 : 'END',
|
||||||
|
0x01 : 'NOP',
|
||||||
|
0x50 : 'STO_indirect',
|
||||||
|
0x51 : 'LDA_indirect',
|
||||||
|
0x52 : 'ADD_indirect',
|
||||||
|
0x53 : 'SUB_indirect',
|
||||||
|
0x54 : 'HOP_indirect',
|
||||||
|
0x55 : 'JMP_indirect',
|
||||||
|
0x56 : 'FTG_indirect',
|
||||||
|
0x57 : 'FHP_indirect',
|
||||||
|
0x60 : 'STO_direct',
|
||||||
|
0x61 : 'LDA_direct',
|
||||||
|
0x62 : 'ADD_direct',
|
||||||
|
0x63 : 'SUB_direct',
|
||||||
|
0x64 : 'HOP_direct',
|
||||||
|
0x65 : 'JMP_direct',
|
||||||
|
0x66 : 'FTG_direct',
|
||||||
|
0x67 : 'FHP_direct',
|
||||||
|
};
|
||||||
|
// return { instruction: instrs[instruction], mode: mode };
|
||||||
|
this._decodedOp = instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ops = {
|
||||||
|
JMP_direct: (lit) => {
|
||||||
|
this.debug.currentMnemonic = 'JMP lit';
|
||||||
|
this._calculatedIP = lit;
|
||||||
|
},
|
||||||
|
|
||||||
|
JMP_indirect: (addr) => {
|
||||||
|
this.debug.currentMnemonic = 'JMP addr';
|
||||||
|
this._calculatedIP = addr;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
debug = {
|
||||||
|
// TODO include the rest of the stuff that I have here in the current version
|
||||||
|
running: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Memory {
|
||||||
|
// ROM format: { addr: nn, data: nn }
|
||||||
|
constructor (sizeInBytes, ROM) {
|
||||||
|
// memory format: [ { data: nn, type: ‘str’ } ]
|
||||||
|
this.memory = new Array(sizeInBytes);
|
||||||
|
ROM.forEach((byte) => {
|
||||||
|
this.memory[byte.address] = { data: byte.data, type: 'ROM' };
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tickClock () {
|
||||||
|
if (connections.memoryReadSignal) this._read();
|
||||||
|
if (connections.memoryWriteSignal) this._write();
|
||||||
|
}
|
||||||
|
|
||||||
|
_read () {
|
||||||
|
connections.dataBus = this.memory[connections.addressBus].data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_write () {
|
||||||
|
if (this.memory[connections.addressBus].type === 'ROM') throw new Error('Attempted write to ROM');
|
||||||
|
this.memory[connections.addressBus].data = connections.dataBus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** DMA controller for screen, keypad... **/
|
||||||
|
class IO {
|
||||||
|
// TODO…
|
||||||
|
constructor (connections) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Connections {
|
||||||
|
dataBus = 0;
|
||||||
|
addressBus = 0;
|
||||||
|
memoryReadSignal = 0;
|
||||||
|
memoryWriteSignal = 0;
|
||||||
|
cpuWait = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// let rom = // TODO read in…
|
||||||
|
|
||||||
|
const rom = [
|
||||||
|
{ address: 0xFE, data: 0x55, },
|
||||||
|
{ address: 0xFF, data: 0x00, },
|
||||||
|
{ address: 0x00, data: 0x51, },
|
||||||
|
{ address: 0x01, data: 0x0F, },
|
||||||
|
{ address: 0x02, data: 0x62, },
|
||||||
|
{ address: 0x03, data: 0x01, },
|
||||||
|
{ address: 0x04, data: 0x00, },
|
||||||
|
];
|
||||||
|
|
||||||
|
let connections = new Connections();
|
||||||
|
let memory = new Memory(256, rom);
|
||||||
|
let cpu = new CPU();
|
||||||
|
|
||||||
|
let intervalTimer = setInterval( () => {
|
||||||
|
cpu.tickClock();
|
||||||
|
memory.tickClock();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
console.log(intervalTimer);
|
||||||
Loading…
Reference in New Issue