From 4974e395e53bd24c25d062427065ba2357861aa5 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Mon, 1 May 2017 11:30:47 -0400 Subject: [PATCH] started on MAME platform support; pause on page lose focus --- css/ui.css | 2 + emsrc/sdcc/Makefile.local | 6 ++ mame/cfg/coleco.cfg | 68 ++++++++++++ src/emu.js | 133 +++++++++++++++++++++-- src/platform/coleco.js | 217 ++++++++++++++++++++++++++++++++++++++ src/platform/vcs.js | 37 ++++++- src/ui.js | 23 +++- 7 files changed, 474 insertions(+), 12 deletions(-) create mode 100644 mame/cfg/coleco.cfg create mode 100644 src/platform/coleco.js diff --git a/css/ui.css b/css/ui.css index 227774e1..f3ca98bf 100644 --- a/css/ui.css +++ b/css/ui.css @@ -193,6 +193,8 @@ a.dropdown-toggle { margin-bottom: 20px; background: #000; outline-color: #666; + width: 100%; + height: 100%; } canvas.pixelated { image-rendering: optimizeSpeed; /* Older versions of FF */ diff --git a/emsrc/sdcc/Makefile.local b/emsrc/sdcc/Makefile.local index 5f46f438..dee5ef5e 100644 --- a/emsrc/sdcc/Makefile.local +++ b/emsrc/sdcc/Makefile.local @@ -29,3 +29,9 @@ debugjs/%.js: js/%.bc -s FORCE_FILESYSTEM=1 \ $< -o $@ $(ARGS_$*) \ +js/fssdcc.js: + ln -s ./sdcc/device/include include + ln -s ./sdcc/device/lib/build lib + python $(EMSCRIPTEN)/tools/file_packager.py js/fssdcc.data \ + --preload include lib/z80 \ + --separate-metadata --js-output=js/fssdcc.js diff --git a/mame/cfg/coleco.cfg b/mame/cfg/coleco.cfg new file mode 100644 index 00000000..9a8877e0 --- /dev/null +++ b/mame/cfg/coleco.cfg @@ -0,0 +1,68 @@ + + + + + + + + KEYCODE_0 + + + + + KEYCODE_1 + + + + + KEYCODE_2 + + + + + KEYCODE_3 + + + + + KEYCODE_4 + + + + + KEYCODE_5 + + + + + KEYCODE_6 + + + + + KEYCODE_7 + + + + + KEYCODE_8 + + + + + KEYCODE_9 + + + + + KEYCODE_MINUS + + + + + KEYCODE_EQUALS + + + + + diff --git a/src/emu.js b/src/emu.js index f1d09664..761d38a5 100644 --- a/src/emu.js +++ b/src/emu.js @@ -19,8 +19,6 @@ function __createCanvas(mainElement, width, height) { canvas.width = width; canvas.height = height; canvas.classList.add("emuvideo"); - canvas.style.width = "100%"; - canvas.style.height = "100%"; canvas.tabIndex = "-1"; // Make it focusable fsElement.appendChild(canvas); @@ -594,17 +592,19 @@ var BaseZ80Platform = function() { this.cpuStateToLongString = function(c) { return cpuStateToLongString_Z80(c); } - this.getToolForFilename = function(fn) { - if (fn.endsWith(".c")) return "sdcc"; - if (fn.endsWith(".s")) return "sdasz80"; - if (fn.endsWith(".ns")) return "naken"; - return "z80asm"; - } + this.getToolForFilename = getToolForFilename_z80; this.getDefaultExtension = function() { return ".c"; }; // TODO //this.getOpcodeMetadata = function() { } } +function getToolForFilename_z80(fn) { + if (fn.endsWith(".c")) return "sdcc"; + if (fn.endsWith(".s")) return "sdasz80"; + if (fn.endsWith(".ns")) return "naken"; + return "z80asm"; +} + ////// 6809 function cpuStateToLongString_6809(c) { @@ -862,3 +862,120 @@ var BusProbe = function(bus) { bus.write(a,v); } } + +/// MAME SUPPORT + +var BaseMAMEPlatform = function() { + var self = this; + + var loaded = false; + var romfn; + var romdata; + var video; + var preload_files; + + this.luacall = function(s) { + //console.log(s); + Module.ccall('_Z13js_lua_stringPKc', 'void', ['string'], [s+""]); + } + + this.clearDebug = function() { + //TODO + } + + this.pause = function() { + if (loaded) this.luacall('emu.pause()'); + } + + this.resume = function() { + if (loaded) this.luacall('emu.unpause()'); + } + + this.reset = function() { + this.luacall('manager:machine():soft_reset()'); + } + + this.isRunning = function() { + // TODO + } + + this.startModule = function(mainElement, opts) { + romfn = opts.romfn; + if (!romdata) romdata = new RAM(opts.romsize).mem; + // create canvas + video = new RasterVideo(mainElement, opts.width, opts.height); + video.create(); + $(video.canvas).attr('id','canvas'); + // load asm.js module + console.log("loading", opts.jsfile); + var script = document.createElement('script'); + window.JSMESS = {}; + window.Module = { + arguments: [opts.driver, '-verbose', '-window', '-nokeepaspect', '-resolution', canvas.width+'x'+canvas.height, '-cart', romfn], + screenIsReadOnly: true, + print: function (text) { console.log(text); }, + canvas:video.canvas, + doNotCaptureKeyboard:true, + keyboardListeningElement:video.canvas, + preInit: function () { + 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'); + FS.writeFile(romfn, romdata, {encoding:'binary'}); + if (opts.preInit) { + opts.preInit(self); + } + $(video.canvas).click(function(e) { + video.canvas.focus(); + }); + loaded = true; + } + }; + // preload files + // TODO: ensure loaded + if (opts.cfgfile) { + $.get('mame/cfg/' + opts.cfgfile, function(data) { + opts.cfgdata = data; + console.log("loaded " + opts.cfgfile); + }, 'text'); + } + if (opts.biosfile) { + var oReq = new XMLHttpRequest(); + oReq.open("GET", 'mame/roms/' + opts.biosfile, true); + oReq.responseType = "arraybuffer"; + oReq.onload = function(oEvent) { + console.log("loaded " + opts.biosfile); + opts.biosdata = new Uint8Array(oReq.response); + }; + oReq.send(); + } + // start loading script + script.src = 'mame/' + opts.jsfile; + document.getElementsByTagName('head')[0].appendChild(script); + } + + this.loadRegion = function(region, data) { + romdata = data; + if (loaded) { + FS.writeFile(romfn, data, {encoding:'binary'}); + //self.luacall('cart=manager:machine().images["cart"]\nprint(cart:filename())\ncart:load("' + romfn + '")\n'); + var s = 'mem = manager:machine():memory().regions["' + region + '"]\n'; + for (var i=0; i= visibleScanlinesPerFrame) return; + var pixofs = sl * 256; + var outi = pixofs; // starting output pixel in frame buffer + var vramofs = (sl>>3)<<5; // offset in VRAM + var yy = sl & 7; // y offset within tile + for (var xx=0; xx<32; xx++) { + var code = ram.mem[vramofs+xx]; + var data = ram.mem[0x800 + (code<<3) + yy]; + var col = (code>>5) + (palbank<<3); + var color1 = palette[col&15]; + var color2 = 0; + for (var i=0; i<8; i++) { + var bm = 128>>i; + pixels[outi] = (data&bm) ? color2 : color1; + outi++; + } + } + } + + var CARNIVAL_KEYCODE_MAP = makeKeycodeMap([ + [Keys.VK_SPACE, 2, -0x20], + [Keys.VK_SHIFT, 2, -0x40], + [Keys.VK_LEFT, 1, -0x10], + [Keys.VK_RIGHT, 1, -0x20], + [Keys.VK_UP, 1, -0x40], + [Keys.VK_DOWN, 1, -0x80], + [Keys.VK_1, 2, -0x10], + [Keys.VK_2, 3, -0x20], + [Keys.VK_5, 3, 0x8], + ]); + + this.getPresets = function() { + return ColecoVision_PRESETS; + } + + this.start = function() { + ram = new RAM(0x400); + //bios = COLECO_BIOS; + membus = { + read: new AddressDecoder([ + [0x0000, 0x1fff, 0x1fff, function(a) { return bios ? bios[a] : null; }], + [0x6000, 0x7fff, 0x3ff, function(a) { return ram.mem[a]; }], + ]), + write: new AddressDecoder([ + [0x6000, 0x7fff, 0x3ff, function(a,v) { ram.mem[a] = v; }], + ]), + isContended: function() { return false; }, + }; + this.readAddress = membus.read; + iobus = { + read: function(addr) { + return inputs[addr&3]; + }, + write: function(addr, val) { + console.log(addr,val); + } + }; + cpu = this.newCPU(membus, iobus); + video = new RasterVideo(mainElement,visiblePixelsPerScanline,visibleScanlinesPerFrame); + audio = new MasterAudio(); + psg = new AY38910_Audio(audio); + //var speech = new VotraxSpeech(); + //audio.master.addChannel(speech); + video.create(); + var idata = video.getFrameData(); + setKeyboardFromMap(video, inputs, CARNIVAL_KEYCODE_MAP); + pixels = video.getFrameData(); + timer = new AnimationTimer(60, function() { + if (!self.isRunning()) + return; + var debugCond = self.getDebugCallback(); + var targetTstates = cpu.getTstates(); + for (var sl=0; sl