/// 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; inumber) : 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); } }