"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 "SetRegister" : this.setRegister (msg); break; case "SetROM" : this.setROM (msg); break; } } // Retrieve the values of all the CPU registers getRegisters(msg) { msg.pc = this.core.GetProgramCounter(msg.sim, 0); msg.pcFrom = this.core.GetProgramCounter(msg.sim, 1); msg.pcTo = this.core.GetProgramCounter(msg.sim, 2); msg.adtre = this.core.GetSystemRegister(msg.sim, 25); msg.chcw = this.core.GetSystemRegister(msg.sim, 24); msg.ecr = this.core.GetSystemRegister(msg.sim, 4); msg.eipc = this.core.GetSystemRegister(msg.sim, 0); msg.eipsw = this.core.GetSystemRegister(msg.sim, 1); msg.fepc = this.core.GetSystemRegister(msg.sim, 2); msg.fepsw = this.core.GetSystemRegister(msg.sim, 3); msg.pir = this.core.GetSystemRegister(msg.sim, 6); msg.psw = this.core.GetSystemRegister(msg.sim, 5); msg.tkcw = this.core.GetSystemRegister(msg.sim, 7); msg.sr29 = this.core.GetSystemRegister(msg.sim, 29); msg.sr30 = this.core.GetSystemRegister(msg.sim, 30); msg.sr31 = this.core.GetSystemRegister(msg.sim, 31); 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); postMessage(msg, msg.buffer); } // 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; 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();