mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-01-10 01:29:42 +00:00
203 lines
7.7 KiB
JavaScript
203 lines
7.7 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.BaseWASMMachine = void 0;
|
|
const devices_1 = require("./devices");
|
|
const emu_1 = require("./emu");
|
|
// WASM Support
|
|
// TODO: detangle from c64
|
|
class BaseWASMMachine {
|
|
constructor(prefix) {
|
|
this.maxROMSize = 0x40000;
|
|
this.videoOffsetBytes = 0;
|
|
this.prefix = prefix;
|
|
var self = this;
|
|
this.cpu = {
|
|
getPC: self.getPC.bind(self),
|
|
getSP: self.getSP.bind(self),
|
|
isStable: self.isStable.bind(self),
|
|
reset: self.reset.bind(self),
|
|
saveState: () => {
|
|
return self.getCPUState();
|
|
},
|
|
loadState: () => {
|
|
console.log("loadState not implemented");
|
|
},
|
|
connectMemoryBus() {
|
|
console.log("connectMemoryBus not implemented");
|
|
},
|
|
};
|
|
}
|
|
getImports(wmod) {
|
|
return {};
|
|
}
|
|
async fetchWASM() {
|
|
var wasmResponse = await fetch('res/' + this.prefix + '.wasm');
|
|
if (wasmResponse.status == 200 || wasmResponse.size) {
|
|
var wasmBinary = await wasmResponse.arrayBuffer();
|
|
var wasmCompiled = await WebAssembly.compile(wasmBinary);
|
|
var wasmResult = await WebAssembly.instantiate(wasmCompiled, this.getImports(wasmCompiled));
|
|
this.instance = wasmResult;
|
|
this.exports = wasmResult.exports;
|
|
}
|
|
else
|
|
throw new Error('could not load WASM file');
|
|
}
|
|
allocateBIOS(biosBinary) {
|
|
this.biosptr = this.exports.malloc(biosBinary.byteLength);
|
|
this.biosarr = new Uint8Array(this.exports.memory.buffer, this.biosptr, biosBinary.byteLength);
|
|
}
|
|
async fetchBIOS() {
|
|
var biosResponse = await fetch('res/' + this.prefix + '.bios');
|
|
if (biosResponse.status == 200 || biosResponse.size) {
|
|
var biosBinary = new Uint8Array(await biosResponse.arrayBuffer());
|
|
this.allocateBIOS(biosBinary);
|
|
this.loadBIOS(biosBinary);
|
|
}
|
|
else
|
|
throw new Error('could not load BIOS file');
|
|
}
|
|
async initWASM() {
|
|
// init machine instance
|
|
this.sys = this.exports.machine_init(this.biosptr);
|
|
let statesize = this.exports.machine_get_state_size();
|
|
this.stateptr = this.exports.malloc(statesize);
|
|
let ctrlstatesize = this.exports.machine_get_controls_state_size();
|
|
this.ctrlstateptr = this.exports.malloc(ctrlstatesize);
|
|
let cpustatesize = this.exports.machine_get_cpu_state_size();
|
|
this.cpustateptr = this.exports.malloc(cpustatesize);
|
|
this.romptr = this.exports.malloc(this.maxROMSize);
|
|
// create state buffers
|
|
// must do this after allocating memory (and everytime we grow memory?)
|
|
this.statearr = new Uint8Array(this.exports.memory.buffer, this.stateptr, statesize);
|
|
this.ctrlstatearr = new Uint8Array(this.exports.memory.buffer, this.ctrlstateptr, ctrlstatesize);
|
|
this.cpustatearr = new Uint8Array(this.exports.memory.buffer, this.cpustateptr, cpustatesize);
|
|
// create audio buffer
|
|
let sampbufsize = 4096 * 4;
|
|
this.audioarr = new Float32Array(this.exports.memory.buffer, this.exports.machine_get_sample_buffer(), sampbufsize);
|
|
// create ROM buffer
|
|
this.romarr = new Uint8Array(this.exports.memory.buffer, this.romptr, this.maxROMSize);
|
|
// enable c64 joystick map to arrow keys (TODO)
|
|
//this.exports.c64_set_joystick_type(this.sys, 1);
|
|
console.log('machine_init', this.sys, statesize, ctrlstatesize, cpustatesize, sampbufsize);
|
|
}
|
|
async loadWASM() {
|
|
await this.fetchWASM();
|
|
this.exports.memory.grow(96); // TODO: need more when probing?
|
|
await this.fetchBIOS();
|
|
await this.initWASM();
|
|
}
|
|
getPC() {
|
|
return this.exports.machine_cpu_get_pc(this.sys);
|
|
}
|
|
getSP() {
|
|
return this.exports.machine_cpu_get_sp(this.sys);
|
|
}
|
|
isStable() {
|
|
return this.exports.machine_cpu_is_stable(this.sys);
|
|
}
|
|
loadROM(rom) {
|
|
if (rom.length > this.maxROMSize)
|
|
throw new emu_1.EmuHalt(`Rom size too big: ${rom.length} bytes`);
|
|
this.romarr.set(rom);
|
|
this.romlen = rom.length;
|
|
console.log('load rom', rom.length, 'bytes');
|
|
this.reset(); // TODO?
|
|
}
|
|
// TODO: can't load after machine_init
|
|
loadBIOS(srcArray) {
|
|
this.biosarr.set(srcArray);
|
|
}
|
|
reset() {
|
|
this.exports.machine_reset(this.sys);
|
|
}
|
|
/* TODO: we don't need this because c64_exec does this?
|
|
pollControls() {
|
|
this.exports.machine_start_frame(this.sys);
|
|
}
|
|
*/
|
|
read(address) {
|
|
return this.exports.machine_mem_read(this.sys, address & 0xffff);
|
|
}
|
|
readConst(address) {
|
|
return this.exports.machine_mem_read(this.sys, address & 0xffff);
|
|
}
|
|
write(address, value) {
|
|
this.exports.machine_mem_write(this.sys, address & 0xffff, value & 0xff);
|
|
}
|
|
getAudioParams() {
|
|
return { sampleRate: 44100, stereo: false };
|
|
}
|
|
connectVideo(pixels) {
|
|
this.pixel_dest = pixels;
|
|
var pixbuf = this.exports.machine_get_pixel_buffer(this.sys); // save video pointer
|
|
console.log('connectVideo', pixbuf, pixels.length);
|
|
this.pixel_src = new Uint32Array(this.exports.memory.buffer, pixbuf + this.videoOffsetBytes, pixels.length);
|
|
}
|
|
syncVideo() {
|
|
if (this.exports.machine_update_video) {
|
|
this.exports.machine_update_video(this.sys);
|
|
}
|
|
if (this.pixel_dest != null) {
|
|
this.pixel_dest.set(this.pixel_src);
|
|
}
|
|
}
|
|
// assume controls buffer is smaller than cpu buffer
|
|
saveControlsState() {
|
|
//console.log(1, this.romptr, this.romlen, this.ctrlstateptr, this.romarr.slice(0,4), this.ctrlstatearr.slice(0,4));
|
|
this.exports.machine_save_controls_state(this.sys, this.ctrlstateptr);
|
|
//console.log(2, this.romptr, this.romlen, this.ctrlstateptr, this.romarr.slice(0,4), this.ctrlstatearr.slice(0,4));
|
|
return { controls: this.ctrlstatearr.slice(0) };
|
|
}
|
|
loadControlsState(state) {
|
|
this.ctrlstatearr.set(state.controls);
|
|
this.exports.machine_load_controls_state(this.sys, this.ctrlstateptr);
|
|
}
|
|
connectAudio(audio) {
|
|
this.audio = audio;
|
|
}
|
|
syncAudio() {
|
|
if (this.audio != null) {
|
|
var n = this.exports.machine_get_sample_count();
|
|
for (var i = 0; i < n; i++) {
|
|
this.audio.feedSample(this.audioarr[i], 1);
|
|
}
|
|
}
|
|
}
|
|
// TODO: tick might advance 1 instruction
|
|
advanceFrameClock(trap, cpf) {
|
|
var i;
|
|
if (trap) {
|
|
for (i = 0; i < cpf; i++) {
|
|
if (trap()) {
|
|
break;
|
|
}
|
|
this.exports.machine_tick(this.sys);
|
|
}
|
|
}
|
|
else {
|
|
this.exports.machine_exec(this.sys, cpf);
|
|
i = cpf;
|
|
}
|
|
this.syncVideo();
|
|
this.syncAudio();
|
|
return i;
|
|
}
|
|
copyProbeData() {
|
|
if (this.probe && !(this.probe instanceof devices_1.NullProbe)) {
|
|
var datalen = this.exports.machine_get_probe_buffer_size();
|
|
var dataaddr = this.exports.machine_get_probe_buffer_address();
|
|
// TODO: more efficient way to put into probe
|
|
var databuf = new Uint32Array(this.exports.memory.buffer, dataaddr, datalen);
|
|
this.probe.logNewFrame(); // TODO: machine should do this
|
|
this.probe.addLogBuffer(databuf);
|
|
}
|
|
}
|
|
connectProbe(probe) {
|
|
this.probe = probe;
|
|
}
|
|
getDebugTree() {
|
|
return this.saveState();
|
|
}
|
|
}
|
|
exports.BaseWASMMachine = BaseWASMMachine;
|
|
//# sourceMappingURL=wasmplatform.js.map
|