diff --git a/src/sketch.cpu.js b/src/sketch.cpu.js new file mode 100644 index 0000000..49bb38a --- /dev/null +++ b/src/sketch.cpu.js @@ -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); \ No newline at end of file