70 lines
1.5 KiB
JavaScript
70 lines
1.5 KiB
JavaScript
const TXBUF = 0;
|
|
const RXBUF = 32;
|
|
const TXDATA = 64;
|
|
const TXHEAD = 65;
|
|
const TXTAIL = 66;
|
|
const RXDATA = 67;
|
|
const RXHEAD = 68;
|
|
const RXTAIL = 69;
|
|
|
|
const TXBUF_SIZE = 32;
|
|
const RXBUF_SIZE = 32;
|
|
const PERIPHS_SIZE = 70;
|
|
|
|
const POLL_INTERVAL_MS = 20;
|
|
|
|
class Emulator {
|
|
constructor() {
|
|
this.mem = new WebAssembly.Memory({
|
|
initial: 1,
|
|
maximum: 1,
|
|
shared: true
|
|
});
|
|
this.mem_u8 = new Uint8Array(this.mem.buffer);
|
|
for (let i = 0; i < PERIPHS_SIZE; ++i)
|
|
this.mem_u8[i] = 0;
|
|
|
|
this.decoder = new TextDecoder('utf-8');
|
|
|
|
this.output = document.getElementById('output');
|
|
this.input = document.getElementById('input');
|
|
|
|
this.timer = setInterval(() => this.poll(), POLL_INTERVAL_MS);
|
|
|
|
this.worker = new Worker('boot.js');
|
|
this.worker.postMessage(this.mem);
|
|
}
|
|
|
|
poll() {
|
|
const txdata = Atomics.load(this.mem_u8, TXDATA);
|
|
if (txdata !== 0)
|
|
this.handle_txdata();
|
|
}
|
|
|
|
handle_txdata() {
|
|
const head = Atomics.load(this.mem_u8, TXHEAD);
|
|
const tail = Atomics.load(this.mem_u8, TXTAIL);
|
|
|
|
const data = [];
|
|
let i = head;
|
|
do {
|
|
data.push(this.mem_u8[TXBUF + i]);
|
|
i = (i + 1) % TXBUF_SIZE;
|
|
} while (i !== tail);
|
|
|
|
Atomics.store(this.mem_u8, TXHEAD, tail);
|
|
|
|
// More data could have been added -- only clear TXDATA if
|
|
// tail is unchanged.
|
|
if (tail === Atomics.load(this.mem_u8, TXTAIL))
|
|
Atomics.store(this.mem_u8, TXDATA, 0);
|
|
|
|
const str = this.decoder.decode(new Uint8Array(data));
|
|
this.output.innerText += str;
|
|
}
|
|
}
|
|
|
|
window.addEventListener('DOMContentLoaded', () => {
|
|
window.emu = new Emulator();
|
|
});
|