"use strict"; // Worker that manages a WebAssembly instance of the C core library (globalThis.Emulator = class Emulator { // Static initializer static initializer() { new Emulator(); } // Object constructor constructor() { // Configure instance fields this.buffers = {}; // Configure message port onmessage = e=>this.onmessage(e.data); } ///////////////////////////// Message Methods ///////////////////////////// // Message received onmessage(msg) { switch (msg.command) { case "GetRegisters": this.getRegisters(msg); break; case "Init" : this.init (msg); break; case "ReadBuffer" : this.readBuffer (msg); break; case "RunNext" : this.runNext (msg); break; case "SetRegister" : this.setRegister (msg); break; case "SetROM" : this.setROM (msg); break; case "SingleStep" : this.singleStep (msg); break; case "Write" : this.write (msg); break; } } // Retrieve the values of all the CPU registers getRegisters(msg) { msg.pc = this.core.GetProgramCounter(msg.sim, 0) >>> 0; msg.pcFrom = this.core.GetProgramCounter(msg.sim, 1) >>> 0; msg.pcTo = this.core.GetProgramCounter(msg.sim, 2) >>> 0; msg.adtre = this.core.GetSystemRegister(msg.sim, 25) >>> 0; msg.chcw = this.core.GetSystemRegister(msg.sim, 24) >>> 0; msg.ecr = this.core.GetSystemRegister(msg.sim, 4) >>> 0; msg.eipc = this.core.GetSystemRegister(msg.sim, 0) >>> 0; msg.eipsw = this.core.GetSystemRegister(msg.sim, 1) >>> 0; msg.fepc = this.core.GetSystemRegister(msg.sim, 2) >>> 0; msg.fepsw = this.core.GetSystemRegister(msg.sim, 3) >>> 0; msg.pir = this.core.GetSystemRegister(msg.sim, 6) >>> 0; msg.psw = this.core.GetSystemRegister(msg.sim, 5) >>> 0; msg.tkcw = this.core.GetSystemRegister(msg.sim, 7) >>> 0; msg.sr29 = this.core.GetSystemRegister(msg.sim, 29) >>> 0; msg.sr30 = this.core.GetSystemRegister(msg.sim, 30) >>> 0; msg.sr31 = this.core.GetSystemRegister(msg.sim, 31) >>> 0; msg.program = new Array(32); for (let x = 0; x <= 31; x++) msg.program[x] = this.core.GetProgramRegister(msg.sim, x); postMessage(msg); } // Initialize the WebAssembly core module async init(msg) { // Load and instantiate the WebAssembly module this.wasm = await WebAssembly.instantiate(msg.wasm, { env: { emscripten_notify_memory_growth: ()=>this.onmemory() }}); this.wasm.instance.exports.Init(); // Configure instance fields this.core = this.wasm.instance.exports; postMessage({ command: "Init" }); } // Read multiple data units from the bus readBuffer(msg) { let buffer = this.malloc(Uint8Array, msg.size); this.core.ReadBuffer(msg.sim, buffer.pointer, msg.address, msg.size, msg.debug ? 1 : 0); msg.buffer = this.core.memory.buffer.slice( buffer.pointer, buffer.pointer + msg.size); this.free(buffer); msg.pc = this.core.GetProgramCounter(msg.sim) >>> 0; postMessage(msg, msg.buffer); } // Attempt to advance to the next instruction runNext(msg) { this.core.RunNext(msg.sim); postMessage(msg); } // Specify a new value for a register setRegister(msg) { switch (msg.type) { case "pc" : msg.value = this.core.SetProgramCounter (msg.sim, msg.value); break; case "program": msg.value = this.core.SetProgramRegister(msg.sim, msg.id, msg.value); break; case "system" : msg.value = this.core.SetSystemRegister (msg.sim, msg.id, msg.value); } postMessage(msg); } // Supply a ROM buffer setROM(msg) { let rom = new Uint8Array(msg.rom); let buffer = this.malloc(Uint8Array, rom.length); for (let x = 0; x < rom.length; x++) buffer.data[x] = rom[x]; msg.success = !!this.core.SetROM(msg.sim, buffer.pointer, rom.length); delete msg.rom; if (msg.reset) this.core.Reset(msg.sim); postMessage(msg); } // Execute the current instruction singleStep(msg) { this.core.SingleStep(msg.sim); postMessage(msg); } // Write a single value into the bus write(msg) { this.core.Write(msg.sim, msg.address, msg.type, msg.value, msg.debug ? 1 : 0); postMessage(msg); } ///////////////////////////// Private Methods ///////////////////////////// // Delete a previously-allocated memory buffer free(buffer) { this.core.Free(buffer.pointer); delete this.buffers[buffer.pointer]; } // Allocate a typed array in WebAssembly core memory malloc(type, size) { let pointer = this.core.Malloc(size); let data = new type(this.core.memory.buffer, pointer, size); return this.buffers[pointer] = { data: data, pointer: pointer }; } // WebAssembly memory has grown onmemory() { for (let buffer of Object.values(this.buffers)) { buffer.data = new buffer.data.constructor( this.core.memory.buffer, buffer.pointer); } } }).initializer();