198 lines
4.3 KiB
JavaScript
198 lines
4.3 KiB
JavaScript
/* 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); |