split baseplatform.ts into mame/wasm

This commit is contained in:
Steven Hugg 2021-08-05 19:16:13 -05:00
parent e1b6a2397d
commit ed41c1fb2a
14 changed files with 696 additions and 679 deletions

View File

@ -1,4 +1,6 @@
import { SampledAudioSink } from "./devices";
// from TSS
declare var MasterChannel, AudioLooper, PsgDeviceChannel;
@ -511,8 +513,6 @@ export class SampledAudio {
}
}
import { SampledAudioSink } from "./devices";
interface TssChannel {
setBufferLength(len : number) : void;
setSampleRate(rate : number) : void;

View File

@ -1,12 +1,20 @@
import { RAM, RasterVideo, KeyFlags, dumpRAM, AnimationTimer, setKeyboardFromMap, padBytes, ControllerPoller, EmuHalt } from "./emu";
import { hex, printFlags, invertMap, getBasePlatform, byteToASCII } from "./util";
import { RasterVideo, dumpRAM, AnimationTimer, ControllerPoller } from "./emu";
import { hex, printFlags, invertMap, byteToASCII } from "./util";
import { CodeAnalyzer } from "./analysis";
import { Segment, FileData } from "./workertypes";
import { disassemble6502 } from "./cpu/disasm6502";
import { disassembleZ80 } from "./cpu/disasmz80";
import { Z80 } from "./cpu/ZilogZ80";
import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsBIOS, AcceptsKeyInput, SavesState, SavesInputState, HasCPU, HasSerialIO, SerialIOInterface, AcceptsJoyInput } from "./devices";
import { Probeable, RasterFrameBased, AcceptsPaddleInput } from "./devices";
import { SampledAudio } from "./audio";
import { ProbeRecorder } from "./recorder";
import { BaseWASMMachine } from "./wasmplatform";
///
declare var jt, CPU6809;
export interface OpcodeMetadata {
@ -654,384 +662,6 @@ export abstract class Base6809Platform extends BaseZ80Platform {
}
}
/// MAME SUPPORT
declare var FS, ENV, Module; // mame emscripten
export abstract class BaseMAMEPlatform {
loaded : boolean = false;
preinitted : boolean = false;
started : boolean = false;
romfn : string;
romdata : Uint8Array;
romtype : string = 'cart';
video;
running = false;
initluavars : boolean = false;
luadebugscript : string;
js_lua_string;
onBreakpointHit;
mainElement : HTMLElement;
timer : AnimationTimer;
constructor(mainElement) {
this.mainElement = mainElement;
this.timer = new AnimationTimer(20, this.poll.bind(this));
}
// http://docs.mamedev.org/techspecs/luaengine.html
luacall(s:string) : string {
if (!this.js_lua_string) this.js_lua_string = Module.cwrap('_Z13js_lua_stringPKc', 'string', ['string']);
return this.js_lua_string(s || "");
}
_pause() {
this.running = false;
this.timer.stop();
}
pause() {
if (this.loaded && this.running) {
this.luacall('emu.pause()');
this._pause();
}
}
_resume() {
this.luacall('emu.unpause()');
this.running = true;
this.timer.start();
}
resume() {
if (this.loaded && !this.running) { // TODO
this._resume();
}
}
reset() {
if (this.loaded) {
this.luacall('manager:machine():soft_reset()');
this.running = true;
this.initluavars = false;
}
}
isRunning() {
return this.running;
}
bufferConsoleOutput(s) {
if (typeof s !== 'string') return;
console.log(s);
}
startModule(mainElement, opts) {
this.started = true;
var romfn = this.romfn = this.romfn || opts.romfn;
var romdata = this.romdata = this.romdata || opts.romdata || new RAM(opts.romsize).mem;
var romtype = this.romtype = this.romtype || opts.romtype;
// create canvas
var video = this.video = new RasterVideo(this.mainElement, opts.width, opts.height);
video.create();
$(video.canvas).attr('id','canvas');
// load asm.js module
console.log("loading", opts.jsfile);
var modargs = [opts.driver,
'-debug',
'-debugger', 'none',
'-verbose', '-window', '-nokeepaspect',
'-resolution', video.canvas.width+'x'+video.canvas.height
];
if (romfn) {
modargs.push('-'+romtype, romfn);
}
if (opts.extraargs) {
modargs = modargs.concat(opts.extraargs);
}
console.log(modargs);
window['JSMESS'] = {};
window['Module'] = {
arguments: modargs,
screenIsReadOnly: true,
print: this.bufferConsoleOutput,
canvas:video.canvas,
doNotCaptureKeyboard:true,
keyboardListeningElement:video.canvas,
preInit: () => {
console.log("loading FS");
ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = 'canvas';
if (opts.cfgfile) {
FS.mkdir('/cfg');
FS.writeFile('/cfg/' + opts.cfgfile, opts.cfgdata, {encoding:'utf8'});
}
if (opts.biosfile) {
FS.mkdir('/roms');
FS.mkdir('/roms/' + opts.driver);
FS.writeFile('/roms/' + opts.biosfile, opts.biosdata, {encoding:'binary'});
}
FS.mkdir('/emulator');
if (romfn) {
FS.writeFile(romfn, romdata, {encoding:'binary'});
}
//FS.writeFile('/debug.ini', 'debugger none\n', {encoding:'utf8'});
if (opts.preInit) {
opts.preInit(self);
}
this.preinitted = true;
},
preRun: [
() => {
$(video.canvas).click((e) =>{
video.canvas.focus();
});
this.loaded = true;
console.log("about to run...");
}
]
};
// preload files
// TODO: ensure loaded
var fetch_cfg, fetch_lua;
var fetch_bios = $.Deferred();
var fetch_wasm = $.Deferred();
// fetch config file
if (opts.cfgfile) {
fetch_cfg = $.get('mame/cfg/' + opts.cfgfile, (data) => {
opts.cfgdata = data;
console.log("loaded " + opts.cfgfile);
}, 'text');
}
// fetch BIOS file
if (opts.biosfile) {
var oReq1 = new XMLHttpRequest();
oReq1.open("GET", 'mame/roms/' + opts.biosfile, true);
oReq1.responseType = "arraybuffer";
oReq1.onload = (oEvent) => {
opts.biosdata = new Uint8Array(oReq1.response);
console.log("loaded " + opts.biosfile); // + " (" + oEvent.total + " bytes)");
fetch_bios.resolve();
};
oReq1.ontimeout = function (oEvent) {
throw Error("Timeout loading " + opts.biosfile);
}
oReq1.send();
} else {
fetch_bios.resolve();
}
// load debugger Lua script
fetch_lua = $.get('mame/debugger.lua', (data) => {
this.luadebugscript = data;
console.log("loaded debugger.lua");
}, 'text');
// load WASM
{
var oReq2 = new XMLHttpRequest();
oReq2.open("GET", 'mame/' + opts.jsfile.replace('.js','.wasm'), true);
oReq2.responseType = "arraybuffer";
oReq2.onload = (oEvent) => {
console.log("loaded WASM file");
window['Module'].wasmBinary = new Uint8Array(oReq2.response);
fetch_wasm.resolve();
};
oReq2.ontimeout = function (oEvent) {
throw Error("Timeout loading " + opts.jsfile);
}
oReq2.send();
}
// start loading script
$.when(fetch_lua, fetch_cfg, fetch_bios, fetch_wasm).done( () => {
var script = document.createElement('script');
script.src = 'mame/' + opts.jsfile;
document.getElementsByTagName('head')[0].appendChild(script);
console.log("created script element");
});
// for debugging via browser console
window['mamelua'] = (s:string) => {
this.initlua();
return [s, this.luacall(s)];
};
}
loadROMFile(data) {
this.romdata = data;
if (this.preinitted && this.romfn) {
FS.writeFile(this.romfn, data, {encoding:'binary'});
}
}
loadRegion(region, data) {
if (this.loaded && data.length > 0) {
//this.luacall('cart=manager:machine().images["cart"]\nprint(cart:filename())\ncart:load("' + region + '")\n');
var s = 'rgn = manager:machine():memory().regions["' + region + '"]\n';
//s += 'print(rgn.size)\n';
for (var i=0; i<data.length; i+=4) {
var v = data[i] + (data[i+1]<<8) + (data[i+2]<<16) + (data[i+3]<<24);
s += 'rgn:write_u32(' + i + ',' + v + ')\n'; // TODO: endian?
}
this.luacall(s);
this.reset();
}
}
// DEBUGGING SUPPORT
initlua() {
if (!this.initluavars) {
this.luacall(this.luadebugscript);
this.luacall('mamedbg.init()')
this.initluavars = true;
}
}
readAddress(a:number) : number {
this.initlua();
return parseInt(this.luacall('return mem:read_u8(' + a + ')'));
}
getCPUReg(reg:string) {
if (!this.loaded) return 0; // TODO
this.initlua();
return parseInt(this.luacall('return cpu.state.'+reg+'.value'));
}
grabState(expr:string) {
this.initlua();
return {
c:this.getCPUState(),
buf:this.luacall("return string.tohex(" + expr + ")")
}
}
saveState() {
return this.grabState("manager:machine():buffer_save()");
}
loadState(state) {
this.initlua();
return this.luacall("manager:machine():buffer_load(string.fromhex('" + state.buf + "'))");
}
poll() {
if (this.onBreakpointHit && this.luacall("return tostring(mamedbg.is_stopped())") == 'true') {
this._pause();
//this.luacall("manager:machine():buffer_load(lastBreakState)");
var state = this.grabState("lastBreakState");
this.onBreakpointHit(state);
}
}
clearDebug() {
this.onBreakpointHit = null;
if (this.loaded) {
this.initlua();
this.luacall('mamedbg.reset()');
}
}
getDebugCallback() {
return this.onBreakpointHit;// TODO?
}
setupDebug(callback) {
this.onBreakpointHit = callback;
}
debugcmd(s) {
this.initlua()
this.luacall(s);
this._resume();
}
runToPC(pc) {
this.debugcmd('mamedbg.runTo(' + pc + ')');
}
runToVsync() {
this.debugcmd('mamedbg.runToVsync()');
}
runUntilReturn() {
this.debugcmd('mamedbg.runUntilReturn()');
}
// TODO
runEval() {
this.reset();
this.step();
}
step() {
this.debugcmd('mamedbg.step()');
}
getDebugCategories() {
return ['CPU'];
}
getDebugInfo(category:string, state:EmuState) : string {
switch (category) {
case 'CPU': return this.cpuStateToLongString(state.c);
}
}
getDebugTree() {
this.initlua();
var devices = JSON.parse(this.luacall(`return table.tojson(manager:machine().devices)`));
var images = JSON.parse(this.luacall(`return table.tojson(manager:machine().images)`));
var regions = JSON.parse(this.luacall(`return table.tojson(manager:machine():memory().regions)`));
return {
devices: devices,
images: images,
regions: regions,
}
}
abstract cpuStateToLongString(c) : string;
abstract getCPUState() : any;
}
export abstract class BaseMAME6502Platform extends BaseMAMEPlatform {
getPC() : number {
return this.getCPUReg('PC');
}
getSP() : number {
return this.getCPUReg('SP');
}
isStable() { return true; }
getCPUState() {
return {
PC:this.getPC(),
SP:this.getSP(),
A:this.getCPUReg('A'),
X:this.getCPUReg('X'),
Y:this.getCPUReg('Y'),
flags:this.getCPUReg('P'),
};
}
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
return disassemble6502(pc, read(pc), read(pc+1), read(pc+2));
}
cpuStateToLongString(c) {
return cpuStateToLongString_6502(c);
}
}
export abstract class BaseMAMEZ80Platform extends BaseMAMEPlatform {
getPC() : number {
return this.getCPUReg('PC');
}
getSP() : number {
return this.getCPUReg('SP');
}
isStable() { return true; }
getCPUState() {
return {
PC:this.getPC(),
SP:this.getSP(),
AF:this.getCPUReg('AF'),
BC:this.getCPUReg('BC'),
DE:this.getCPUReg('DE'),
HL:this.getCPUReg('HL'),
IX:this.getCPUReg('IX'),
IY:this.getCPUReg('IY'),
IR:this.getCPUReg('R') + (this.getCPUReg('I') << 8),
};
}
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
return disassembleZ80(pc, read(pc), read(pc+1), read(pc+2), read(pc+3));
}
cpuStateToLongString(c) {
return cpuStateToLongString_Z80(c);
}
}
//TODO: how to get stack_end?
export function dumpStackToString(platform:Platform, mem:Uint8Array|number[], start:number, end:number, sp:number, jsrop:number) : string {
@ -1082,11 +712,6 @@ export function lookupSymbol(platform:Platform, addr:number, extra:boolean) {
/// new Machine platform adapters
import { Bus, Resettable, FrameBased, VideoSource, SampledAudioSource, AcceptsROM, AcceptsBIOS, AcceptsKeyInput, SavesState, SavesInputState, HasCPU, TrapCondition, CPU, HasSerialIO, SerialIOInterface, SerialEvent, AcceptsJoyInput } from "./devices";
import { Probeable, RasterFrameBased, AcceptsPaddleInput, SampledAudioSink, ProbeAll, NullProbe } from "./devices";
import { SampledAudio } from "./audio";
import { ProbeRecorder } from "./recorder";
export interface Machine extends Bus, Resettable, FrameBased, AcceptsROM, HasCPU, SavesState<EmuState>, SavesInputState<any> {
}
@ -1347,275 +972,7 @@ export abstract class BaseZ80MachinePlatform<T extends Machine> extends BaseMach
}
// WASM Support
// TODO: detangle from c64
export abstract class BaseWASMMachine {
prefix : string;
instance : WebAssembly.Instance;
exports : any;
sys : number;
pixel_dest : Uint32Array;
pixel_src : Uint32Array;
stateptr : number;
statearr : Uint8Array;
cpustateptr : number;
cpustatearr : Uint8Array;
ctrlstateptr : number;
ctrlstatearr : Uint8Array;
cpu : CPU;
romptr : number;
romlen : number;
romarr : Uint8Array;
biosptr : number;
biosarr : Uint8Array;
audio : SampledAudioSink;
audioarr : Float32Array;
probe : ProbeAll;
maxROMSize : number = 0x40000;
abstract getCPUState() : CpuState;
abstract saveState() : EmuState;
abstract loadState(state: EmuState);
constructor(prefix: string) {
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: WebAssembly.Module) {
return {};
}
async fetchWASM() {
var wasmResponse = await fetch('res/'+this.prefix+'.wasm');
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;
}
async fetchBIOS() {
var biosResponse = await fetch('res/'+this.prefix+'.bios');
var biosBinary = await biosResponse.arrayBuffer();
this.biosptr = this.exports.malloc(biosBinary.byteLength);
this.biosarr = new Uint8Array(this.exports.memory.buffer, this.biosptr, biosBinary.byteLength);
this.loadBIOS(new Uint8Array(biosBinary));
}
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(64); // TODO: need more when probing?
await this.fetchBIOS();
await this.initWASM();
}
getPC() : number {
return this.exports.machine_cpu_get_pc(this.sys);
}
getSP() : number {
return this.exports.machine_cpu_get_sp(this.sys);
}
isStable() : boolean {
return this.exports.machine_cpu_is_stable(this.sys);
}
loadROM(rom: Uint8Array) {
if (rom.length > this.maxROMSize) throw new 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: Uint8Array) {
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: number) : number {
return this.exports.machine_mem_read(this.sys, address & 0xffff);
}
readConst(address: number) : number {
return this.exports.machine_mem_read(this.sys, address & 0xffff);
}
write(address: number, value: number) : void {
this.exports.machine_mem_write(this.sys, address & 0xffff, value & 0xff);
}
getAudioParams() {
return {sampleRate:44100, stereo:false};
}
connectVideo(pixels:Uint32Array) : void {
this.pixel_dest = pixels;
var pixbuf = this.exports.machine_get_pixel_buffer(this.sys); // save video pointer
this.pixel_src = new Uint32Array(this.exports.memory.buffer, pixbuf, pixels.length);
console.log('connectVideo', pixbuf, 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() : any {
//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) : void {
this.ctrlstatearr.set(state.controls);
this.exports.machine_load_controls_state(this.sys, this.ctrlstateptr);
}
connectAudio(audio : SampledAudioSink) : void {
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:number) : number {
var i : number;
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 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: ProbeAll): void {
this.probe = probe;
}
getDebugTree() {
return this.saveState();
}
}
import { loadScript } from "../common/util";
import { WasmFs } from "@wasmer/wasmfs";
let stub = function() { console.log(arguments); return 0 }
export abstract class BaseWASIMachine extends BaseWASMMachine {
m_wasi;
wasiInstance;
wasmFs : WasmFs;
constructor(prefix: string) {
super(prefix);
}
getImports(wmod: WebAssembly.Module) {
var imports = this.wasiInstance.getImports(wmod);
// TODO: eliminate these imports
imports.env = {
system: stub,
__sys_mkdir: stub,
__sys_chmod: stub,
__sys_stat64: stub,
__sys_unlink: stub,
__sys_rename: stub,
__sys_getdents64: stub,
__sys_getcwd: stub,
__sys_rmdir: stub,
emscripten_thread_sleep: stub,
}
return imports;
}
stdoutWrite(buffer) {
console.log('>>>', buffer.toString());
return buffer.length;
}
async loadWASM() {
await loadScript('node_modules/@wasmer/wasi/lib/index.iife.js'); //TODO: require('@wasmer/wasi');
await loadScript('node_modules/@wasmer/wasmfs/lib/index.iife.js'); //TODO: require('@wasmer/wasi');
let WASI = window['WASI'];
let WasmFs = window['WasmFs'];
this.wasmFs = new WasmFs.WasmFs();
let bindings = WASI.WASI.defaultBindings;
bindings.fs = this.wasmFs.fs;
bindings.fs.mkdirSync('/tmp');
bindings.path = bindings.path.default;
this.wasiInstance = new WASI.WASI({
preopenDirectories: {'/tmp':'/tmp'},
env: {},
args: [],
bindings: bindings
});
this.wasmFs.volume.fds[1].write = this.stdoutWrite.bind(this);
this.wasmFs.volume.fds[2].write = this.stdoutWrite.bind(this);
await this.fetchWASM();
this.wasiInstance.start(this.instance);
await this.initWASM();
}
}
/////
///
class SerialIOVisualizer {

384
src/common/mameplatform.ts Normal file
View File

@ -0,0 +1,384 @@
/// MAME SUPPORT
import { EmuState, DisasmLine, cpuStateToLongString_6502, cpuStateToLongString_Z80 } from "./baseplatform";
import { disassemble6502 } from "./cpu/disasm6502";
import { disassembleZ80 } from "./cpu/disasmz80";
import { AnimationTimer, RAM, RasterVideo } from "./emu";
declare var FS, ENV, Module; // mame emscripten
export abstract class BaseMAMEPlatform {
loaded : boolean = false;
preinitted : boolean = false;
started : boolean = false;
romfn : string;
romdata : Uint8Array;
romtype : string = 'cart';
video;
running = false;
initluavars : boolean = false;
luadebugscript : string;
js_lua_string;
onBreakpointHit;
mainElement : HTMLElement;
timer : AnimationTimer;
constructor(mainElement) {
this.mainElement = mainElement;
this.timer = new AnimationTimer(20, this.poll.bind(this));
}
// http://docs.mamedev.org/techspecs/luaengine.html
luacall(s:string) : string {
if (!this.js_lua_string) this.js_lua_string = Module.cwrap('_Z13js_lua_stringPKc', 'string', ['string']);
return this.js_lua_string(s || "");
}
_pause() {
this.running = false;
this.timer.stop();
}
pause() {
if (this.loaded && this.running) {
this.luacall('emu.pause()');
this._pause();
}
}
_resume() {
this.luacall('emu.unpause()');
this.running = true;
this.timer.start();
}
resume() {
if (this.loaded && !this.running) { // TODO
this._resume();
}
}
reset() {
if (this.loaded) {
this.luacall('manager:machine():soft_reset()');
this.running = true;
this.initluavars = false;
}
}
isRunning() {
return this.running;
}
bufferConsoleOutput(s) {
if (typeof s !== 'string') return;
console.log(s);
}
startModule(mainElement, opts) {
this.started = true;
var romfn = this.romfn = this.romfn || opts.romfn;
var romdata = this.romdata = this.romdata || opts.romdata || new RAM(opts.romsize).mem;
var romtype = this.romtype = this.romtype || opts.romtype;
// create canvas
var video = this.video = new RasterVideo(this.mainElement, opts.width, opts.height);
video.create();
$(video.canvas).attr('id','canvas');
// load asm.js module
console.log("loading", opts.jsfile);
var modargs = [opts.driver,
'-debug',
'-debugger', 'none',
'-verbose', '-window', '-nokeepaspect',
'-resolution', video.canvas.width+'x'+video.canvas.height
];
if (romfn) {
modargs.push('-'+romtype, romfn);
}
if (opts.extraargs) {
modargs = modargs.concat(opts.extraargs);
}
console.log(modargs);
window['JSMESS'] = {};
window['Module'] = {
arguments: modargs,
screenIsReadOnly: true,
print: this.bufferConsoleOutput,
canvas:video.canvas,
doNotCaptureKeyboard:true,
keyboardListeningElement:video.canvas,
preInit: () => {
console.log("loading FS");
ENV.SDL_EMSCRIPTEN_KEYBOARD_ELEMENT = 'canvas';
if (opts.cfgfile) {
FS.mkdir('/cfg');
FS.writeFile('/cfg/' + opts.cfgfile, opts.cfgdata, {encoding:'utf8'});
}
if (opts.biosfile) {
FS.mkdir('/roms');
FS.mkdir('/roms/' + opts.driver);
FS.writeFile('/roms/' + opts.biosfile, opts.biosdata, {encoding:'binary'});
}
FS.mkdir('/emulator');
if (romfn) {
FS.writeFile(romfn, romdata, {encoding:'binary'});
}
//FS.writeFile('/debug.ini', 'debugger none\n', {encoding:'utf8'});
if (opts.preInit) {
opts.preInit(self);
}
this.preinitted = true;
},
preRun: [
() => {
$(video.canvas).click((e) =>{
video.canvas.focus();
});
this.loaded = true;
console.log("about to run...");
}
]
};
// preload files
// TODO: ensure loaded
var fetch_cfg, fetch_lua;
var fetch_bios = $.Deferred();
var fetch_wasm = $.Deferred();
// fetch config file
if (opts.cfgfile) {
fetch_cfg = $.get('mame/cfg/' + opts.cfgfile, (data) => {
opts.cfgdata = data;
console.log("loaded " + opts.cfgfile);
}, 'text');
}
// fetch BIOS file
if (opts.biosfile) {
var oReq1 = new XMLHttpRequest();
oReq1.open("GET", 'mame/roms/' + opts.biosfile, true);
oReq1.responseType = "arraybuffer";
oReq1.onload = (oEvent) => {
opts.biosdata = new Uint8Array(oReq1.response);
console.log("loaded " + opts.biosfile); // + " (" + oEvent.total + " bytes)");
fetch_bios.resolve();
};
oReq1.ontimeout = function (oEvent) {
throw Error("Timeout loading " + opts.biosfile);
}
oReq1.send();
} else {
fetch_bios.resolve();
}
// load debugger Lua script
fetch_lua = $.get('mame/debugger.lua', (data) => {
this.luadebugscript = data;
console.log("loaded debugger.lua");
}, 'text');
// load WASM
{
var oReq2 = new XMLHttpRequest();
oReq2.open("GET", 'mame/' + opts.jsfile.replace('.js','.wasm'), true);
oReq2.responseType = "arraybuffer";
oReq2.onload = (oEvent) => {
console.log("loaded WASM file");
window['Module'].wasmBinary = new Uint8Array(oReq2.response);
fetch_wasm.resolve();
};
oReq2.ontimeout = function (oEvent) {
throw Error("Timeout loading " + opts.jsfile);
}
oReq2.send();
}
// start loading script
$.when(fetch_lua, fetch_cfg, fetch_bios, fetch_wasm).done( () => {
var script = document.createElement('script');
script.src = 'mame/' + opts.jsfile;
document.getElementsByTagName('head')[0].appendChild(script);
console.log("created script element");
});
// for debugging via browser console
window['mamelua'] = (s:string) => {
this.initlua();
return [s, this.luacall(s)];
};
}
loadROMFile(data) {
this.romdata = data;
if (this.preinitted && this.romfn) {
FS.writeFile(this.romfn, data, {encoding:'binary'});
}
}
loadRegion(region, data) {
if (this.loaded && data.length > 0) {
//this.luacall('cart=manager:machine().images["cart"]\nprint(cart:filename())\ncart:load("' + region + '")\n');
var s = 'rgn = manager:machine():memory().regions["' + region + '"]\n';
//s += 'print(rgn.size)\n';
for (var i=0; i<data.length; i+=4) {
var v = data[i] + (data[i+1]<<8) + (data[i+2]<<16) + (data[i+3]<<24);
s += 'rgn:write_u32(' + i + ',' + v + ')\n'; // TODO: endian?
}
this.luacall(s);
this.reset();
}
}
// DEBUGGING SUPPORT
initlua() {
if (!this.initluavars) {
this.luacall(this.luadebugscript);
this.luacall('mamedbg.init()')
this.initluavars = true;
}
}
readAddress(a:number) : number {
this.initlua();
return parseInt(this.luacall('return mem:read_u8(' + a + ')'));
}
getCPUReg(reg:string) {
if (!this.loaded) return 0; // TODO
this.initlua();
return parseInt(this.luacall('return cpu.state.'+reg+'.value'));
}
grabState(expr:string) {
this.initlua();
return {
c:this.getCPUState(),
buf:this.luacall("return string.tohex(" + expr + ")")
}
}
saveState() {
return this.grabState("manager:machine():buffer_save()");
}
loadState(state) {
this.initlua();
return this.luacall("manager:machine():buffer_load(string.fromhex('" + state.buf + "'))");
}
poll() {
if (this.onBreakpointHit && this.luacall("return tostring(mamedbg.is_stopped())") == 'true') {
this._pause();
//this.luacall("manager:machine():buffer_load(lastBreakState)");
var state = this.grabState("lastBreakState");
this.onBreakpointHit(state);
}
}
clearDebug() {
this.onBreakpointHit = null;
if (this.loaded) {
this.initlua();
this.luacall('mamedbg.reset()');
}
}
getDebugCallback() {
return this.onBreakpointHit;// TODO?
}
setupDebug(callback) {
this.onBreakpointHit = callback;
}
debugcmd(s) {
this.initlua()
this.luacall(s);
this._resume();
}
runToPC(pc) {
this.debugcmd('mamedbg.runTo(' + pc + ')');
}
runToVsync() {
this.debugcmd('mamedbg.runToVsync()');
}
runUntilReturn() {
this.debugcmd('mamedbg.runUntilReturn()');
}
// TODO
runEval() {
this.reset();
this.step();
}
step() {
this.debugcmd('mamedbg.step()');
}
getDebugCategories() {
return ['CPU'];
}
getDebugInfo(category:string, state:EmuState) : string {
switch (category) {
case 'CPU': return this.cpuStateToLongString(state.c);
}
}
getDebugTree() {
this.initlua();
var devices = JSON.parse(this.luacall(`return table.tojson(manager:machine().devices)`));
var images = JSON.parse(this.luacall(`return table.tojson(manager:machine().images)`));
var regions = JSON.parse(this.luacall(`return table.tojson(manager:machine():memory().regions)`));
return {
devices: devices,
images: images,
regions: regions,
}
}
abstract cpuStateToLongString(c) : string;
abstract getCPUState() : any;
}
export abstract class BaseMAME6502Platform extends BaseMAMEPlatform {
getPC() : number {
return this.getCPUReg('PC');
}
getSP() : number {
return this.getCPUReg('SP');
}
isStable() { return true; }
getCPUState() {
return {
PC:this.getPC(),
SP:this.getSP(),
A:this.getCPUReg('A'),
X:this.getCPUReg('X'),
Y:this.getCPUReg('Y'),
flags:this.getCPUReg('P'),
};
}
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
return disassemble6502(pc, read(pc), read(pc+1), read(pc+2));
}
cpuStateToLongString(c) {
return cpuStateToLongString_6502(c);
}
}
export abstract class BaseMAMEZ80Platform extends BaseMAMEPlatform {
getPC() : number {
return this.getCPUReg('PC');
}
getSP() : number {
return this.getCPUReg('SP');
}
isStable() { return true; }
getCPUState() {
return {
PC:this.getPC(),
SP:this.getSP(),
AF:this.getCPUReg('AF'),
BC:this.getCPUReg('BC'),
DE:this.getCPUReg('DE'),
HL:this.getCPUReg('HL'),
IX:this.getCPUReg('IX'),
IY:this.getCPUReg('IY'),
IR:this.getCPUReg('R') + (this.getCPUReg('I') << 8),
};
}
disassemble(pc:number, read:(addr:number)=>number) : DisasmLine {
return disassembleZ80(pc, read(pc), read(pc+1), read(pc+2), read(pc+3));
}
cpuStateToLongString(c) {
return cpuStateToLongString_Z80(c);
}
}

271
src/common/wasmplatform.ts Normal file
View File

@ -0,0 +1,271 @@
import { loadScript } from "../common/util";
import { WasmFs } from "@wasmer/wasmfs";
import { CpuState, EmuState } from "./baseplatform";
import { CPU, SampledAudioSink, ProbeAll, NullProbe } from "./devices";
import { EmuHalt } from "./emu";
// WASM Support
// TODO: detangle from c64
export abstract class BaseWASMMachine {
prefix : string;
instance : WebAssembly.Instance;
exports : any;
sys : number;
pixel_dest : Uint32Array;
pixel_src : Uint32Array;
stateptr : number;
statearr : Uint8Array;
cpustateptr : number;
cpustatearr : Uint8Array;
ctrlstateptr : number;
ctrlstatearr : Uint8Array;
cpu : CPU;
romptr : number;
romlen : number;
romarr : Uint8Array;
biosptr : number;
biosarr : Uint8Array;
audio : SampledAudioSink;
audioarr : Float32Array;
probe : ProbeAll;
maxROMSize : number = 0x40000;
abstract getCPUState() : CpuState;
abstract saveState() : EmuState;
abstract loadState(state: EmuState);
constructor(prefix: string) {
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: WebAssembly.Module) {
return {};
}
async fetchWASM() {
var wasmResponse = await fetch('res/'+this.prefix+'.wasm');
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;
}
async fetchBIOS() {
var biosResponse = await fetch('res/'+this.prefix+'.bios');
var biosBinary = await biosResponse.arrayBuffer();
this.biosptr = this.exports.malloc(biosBinary.byteLength);
this.biosarr = new Uint8Array(this.exports.memory.buffer, this.biosptr, biosBinary.byteLength);
this.loadBIOS(new Uint8Array(biosBinary));
}
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(64); // TODO: need more when probing?
await this.fetchBIOS();
await this.initWASM();
}
getPC() : number {
return this.exports.machine_cpu_get_pc(this.sys);
}
getSP() : number {
return this.exports.machine_cpu_get_sp(this.sys);
}
isStable() : boolean {
return this.exports.machine_cpu_is_stable(this.sys);
}
loadROM(rom: Uint8Array) {
if (rom.length > this.maxROMSize) throw new 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: Uint8Array) {
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: number) : number {
return this.exports.machine_mem_read(this.sys, address & 0xffff);
}
readConst(address: number) : number {
return this.exports.machine_mem_read(this.sys, address & 0xffff);
}
write(address: number, value: number) : void {
this.exports.machine_mem_write(this.sys, address & 0xffff, value & 0xff);
}
getAudioParams() {
return {sampleRate:44100, stereo:false};
}
connectVideo(pixels:Uint32Array) : void {
this.pixel_dest = pixels;
var pixbuf = this.exports.machine_get_pixel_buffer(this.sys); // save video pointer
this.pixel_src = new Uint32Array(this.exports.memory.buffer, pixbuf, pixels.length);
console.log('connectVideo', pixbuf, 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() : any {
//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) : void {
this.ctrlstatearr.set(state.controls);
this.exports.machine_load_controls_state(this.sys, this.ctrlstateptr);
}
connectAudio(audio : SampledAudioSink) : void {
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:number) : number {
var i : number;
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 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: ProbeAll): void {
this.probe = probe;
}
getDebugTree() {
return this.saveState();
}
}
let stub = function() { console.log(arguments); return 0 }
export abstract class BaseWASIMachine extends BaseWASMMachine {
m_wasi;
wasiInstance;
wasmFs : WasmFs;
constructor(prefix: string) {
super(prefix);
}
getImports(wmod: WebAssembly.Module) {
var imports = this.wasiInstance.getImports(wmod);
// TODO: eliminate these imports
imports.env = {
system: stub,
__sys_mkdir: stub,
__sys_chmod: stub,
__sys_stat64: stub,
__sys_unlink: stub,
__sys_rename: stub,
__sys_getdents64: stub,
__sys_getcwd: stub,
__sys_rmdir: stub,
emscripten_thread_sleep: stub,
}
return imports;
}
stdoutWrite(buffer) {
console.log('>>>', buffer.toString());
return buffer.length;
}
async loadWASM() {
await loadScript('node_modules/@wasmer/wasi/lib/index.iife.js'); //TODO: require('@wasmer/wasi');
await loadScript('node_modules/@wasmer/wasmfs/lib/index.iife.js'); //TODO: require('@wasmer/wasi');
let WASI = window['WASI'];
let WasmFs = window['WasmFs'];
this.wasmFs = new WasmFs.WasmFs();
let bindings = WASI.WASI.defaultBindings;
bindings.fs = this.wasmFs.fs;
bindings.fs.mkdirSync('/tmp');
bindings.path = bindings.path.default;
this.wasiInstance = new WASI.WASI({
preopenDirectories: {'/tmp':'/tmp'},
env: {},
args: [],
bindings: bindings
});
this.wasmFs.volume.fds[1].write = this.stdoutWrite.bind(this);
this.wasmFs.volume.fds[2].write = this.stdoutWrite.bind(this);
await this.fetchWASM();
this.wasiInstance.start(this.instance);
await this.initWASM();
}
}

View File

@ -1,7 +1,8 @@
import { BaseWASIMachine, Machine } from "../common/baseplatform";
import { Machine } from "../common/baseplatform";
import { AcceptsKeyInput, AcceptsPaddleInput, AcceptsROM, FrameBased, Probeable, RasterFrameBased, TrapCondition, VideoSource } from "../common/devices";
import { KeyFlags } from "../common/emu";
import { hex } from "../common/util";
import { BaseWASIMachine } from "../common/wasmplatform";
export class Atari8_WASMMachine extends BaseWASIMachine
implements Machine, Probeable, VideoSource, AcceptsROM, FrameBased, AcceptsKeyInput, AcceptsPaddleInput {

View File

@ -12,8 +12,9 @@ import { lzgmini, stringToByteArray, hex, rgb2bgr } from "../common/util";
//// WASM Machine
import { Machine, BaseWASMMachine } from "../common/baseplatform";
import { Machine } from "../common/baseplatform";
import { TrapCondition } from "../common/devices";
import { BaseWASMMachine } from "../common/wasmplatform";
export class C64_WASMMachine extends BaseWASMMachine implements Machine, Probeable {

View File

@ -6,8 +6,9 @@ import { lzgmini, stringToByteArray, hex, rgb2bgr } from "../common/util";
//// WASM Machine
import { Machine, BaseWASMMachine } from "../common/baseplatform";
import { Machine } from "../common/baseplatform";
import { TrapCondition } from "../common/devices";
import { BaseWASMMachine } from "../common/wasmplatform";
export class ZX_WASMMachine extends BaseWASMMachine implements Machine {

View File

@ -1,6 +1,10 @@
import { Platform, getOpcodeMetadata_6502, getToolForFilename_6502, BaseMAME6502Platform } from "../common/baseplatform";
import { Platform, getOpcodeMetadata_6502, getToolForFilename_6502 } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";
import { AppleII } from "../machine/apple2";
import { Base6502MachinePlatform } from "../common/baseplatform";
import { CodeAnalyzer_apple2 } from "../common/analysis";
import { BaseMAME6502Platform } from "../common/mameplatform";
const APPLE2_PRESETS = [
{id:'sieve.c', name:'Sieve'},
@ -55,10 +59,6 @@ class Apple2MAMEPlatform extends BaseMAME6502Platform implements Platform {
///
import { AppleII } from "../machine/apple2";
import { Base6502MachinePlatform } from "../common/baseplatform";
import { CodeAnalyzer_apple2 } from "../common/analysis";
class NewApple2Platform extends Base6502MachinePlatform<AppleII> implements Platform {
newMachine() { return new AppleII(); }

View File

@ -1,7 +1,8 @@
"use strict";
import { Platform, getOpcodeMetadata_6502, getToolForFilename_6502, Base6502MachinePlatform, BaseMAME6502Platform } from "../common/baseplatform";
import { Platform, getOpcodeMetadata_6502, getToolForFilename_6502, Base6502MachinePlatform } from "../common/baseplatform";
import { PLATFORMS, Keys, makeKeycodeMap } from "../common/emu";
import { BaseMAME6502Platform } from "../common/mameplatform";
import { Atari8_WASMMachine } from "../machine/atari8";
declare var jt; // for 6502

View File

@ -1,7 +1,8 @@
import { C64_WASMMachine } from "../machine/c64";
import { Platform, Base6502MachinePlatform, getToolForFilename_6502, getOpcodeMetadata_6502, BaseMAME6502Platform } from "../common/baseplatform";
import { Platform, Base6502MachinePlatform, getToolForFilename_6502, getOpcodeMetadata_6502 } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";
import { BaseMAME6502Platform } from "../common/mameplatform";
const C64_PRESETS = [
{id:'hello.dasm', name:'Hello World (ASM)'},

View File

@ -1,7 +1,8 @@
import { ColecoVision } from "../machine/coleco";
import { Platform, BaseZ80MachinePlatform, getToolForFilename_z80, BaseMAMEZ80Platform } from "../common/baseplatform";
import { Platform, BaseZ80MachinePlatform, getToolForFilename_z80 } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";
import { BaseMAMEZ80Platform } from "../common/mameplatform";
export var ColecoVision_PRESETS = [
{ id: 'text.c', name: 'Text Mode' },

View File

@ -1,13 +1,14 @@
import { Platform, Base6502Platform, getOpcodeMetadata_6502, cpuStateToLongString_6502, getToolForFilename_6502, dumpStackToString, BaseMAME6502Platform } from "../common/baseplatform";
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, KeyFlags, EmuHalt, ControllerPoller } from "../common/emu";
import { hex, lpad, lzgmini, byteArrayToString } from "../common/util";
import { Platform, Base6502Platform, getOpcodeMetadata_6502, getToolForFilename_6502 } from "../common/baseplatform";
import { PLATFORMS, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, KeyFlags, EmuHalt, ControllerPoller } from "../common/emu";
import { hex, byteArrayToString } from "../common/util";
import { CodeAnalyzer_nes } from "../common/analysis";
import { SampleAudio } from "../common/audio";
import { ProbeRecorder } from "../common/recorder";
import { NullProbe, Probeable, ProbeAll } from "../common/devices";
import Mousetrap = require('mousetrap');
import jsnes = require('../../jsnes');
import { BaseMAME6502Platform } from "../common/mameplatform";
const JSNES_PRESETS = [
{id:'hello.c', name:'Hello World'},

View File

@ -1,12 +1,13 @@
"use strict";
import { Platform, BasePlatform, cpuStateToLongString_6502, EmuRecorder, dumpStackToString, DisasmLine, CpuState, DebugCondition, BaseMAME6502Platform } from "../common/baseplatform";
import { PLATFORMS, RAM, newAddressDecoder, dumpRAM, EmuHalt } from "../common/emu";
import { hex, lpad, tobin, byte2signed } from "../common/util";
import { Platform, BasePlatform, cpuStateToLongString_6502, dumpStackToString, DisasmLine, CpuState } from "../common/baseplatform";
import { PLATFORMS, dumpRAM, EmuHalt } from "../common/emu";
import { hex, lpad, tobin } from "../common/util";
import { CodeAnalyzer_vcs } from "../common/analysis";
import { disassemble6502 } from "../common/cpu/disasm6502";
import { ProbeRecorder } from "../common/recorder";
import { NullProbe, Probeable, ProbeAll } from "../common/devices";
import { NullProbe, ProbeAll } from "../common/devices";
import { BaseMAME6502Platform } from "../common/mameplatform";
declare var Javatari : any;
declare var jt : any; // 6502

View File

@ -3,6 +3,8 @@
import type { WorkerResult, WorkerFileUpdate, WorkerBuildStep, WorkerMessage, WorkerError, Dependency, SourceLine, CodeListing, CodeListingMap, Segment, WorkerOutput, SourceLocation } from "../common/workertypes";
import { getBasePlatform, getRootBasePlatform, hex } from "../common/util";
import { Assembler } from "./assembler";
import * as vxmlparser from '../common/hdl/vxmlparser';
import * as basic_compiler from '../common/basic/compiler';
interface EmscriptenModule {
callMain: (args: string[]) => void;
@ -1898,9 +1900,6 @@ function compileInlineASM(code:string, platform, options, errors, asmlines) {
return code;
}
import * as hdltypes from '../common/hdl/hdltypes';
import * as vxmlparser from '../common/hdl/vxmlparser';
function compileVerilator(step:BuildStep) {
loadNative("verilator_bin");
var platform = step.platform || 'verilog';
@ -2936,8 +2935,6 @@ function compileFastBasic(step:BuildStep) {
};
}
import * as basic_compiler from '../common/basic/compiler';
function compileBASIC(step:BuildStep) {
var jsonpath = step.path + ".json";
gatherFiles(step);