138 lines
4.7 KiB
JavaScript
138 lines
4.7 KiB
JavaScript
"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) >>> 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);
|
|
}
|
|
|
|
// 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();
|