started on mame WASM, debugging support, colecovision

This commit is contained in:
Steven Hugg 2018-06-18 04:12:52 -04:00
parent 495896c43d
commit ef561b4425
11 changed files with 258 additions and 54 deletions

70
mame/debugger.lua Normal file
View File

@ -0,0 +1,70 @@
-- JS debug support for MAME using -debugger none
mamedbg = {}
local debugging = false
local stopped = false
function mamedbg.init()
cpu = manager:machine().devices[":maincpu"]
mem = cpu.spaces["program"]
debugger = manager:machine():debugger()
mamedbg.reset()
emu.register_periodic(function ()
if debugging then
if not stopped then
--debugger:command("symlist")
--log = debugger.consolelog
--for i=1,#log do print(log[i]) end
--print(string.format("%4x", cpu.state["PC"].value))
--manager:machine():save("state")
emu.pause()
stopped = true
-- callback to JS via console i/o
mamedbg.printstate()
print(">>>debug_stopped")
print("1")
end
end
end)
end
function mamedbg.printstate()
for k,v in pairs(cpu.state) do print(">>>cpu_"..k); print(v.value) end
end
function mamedbg.reset()
debugging = false
stopped = false
end
function mamedbg.start()
debugging = true
stopped = false
end
function mamedbg.is_stopped()
return debugging and stopped
end
function mamedbg.runTo(addr)
debugger:command("g " .. string.format("%x", addr))
mamedbg.start()
end
function mamedbg.runToVsync(addr)
debugger:command("gv")
mamedbg.start()
end
function mamedbg.runUntilReturn(addr)
debugger:command("out")
mamedbg.start()
end
function mamedbg.step()
debugger:command("step")
mamedbg.start()
end
print("parsed Lua debugger script")

4
mame/mamea2600.js Normal file

File diff suppressed because one or more lines are too long

BIN
mame/mamea2600.wasm Normal file

Binary file not shown.

4
mame/mamecoleco.js Normal file

File diff suppressed because one or more lines are too long

BIN
mame/mamecoleco.wasm Normal file

Binary file not shown.

4
mame/mamenes.js Normal file

File diff suppressed because one or more lines are too long

BIN
mame/mamenes.wasm Normal file

Binary file not shown.

View File

@ -903,6 +903,8 @@ var BaseMAMEPlatform = function() {
var console_vars = {};
var console_varname;
var initluavars = false;
var luadebugscript;
var js_lua_string;
this.luareset = function() {
console_vars = {};
@ -911,11 +913,9 @@ var BaseMAMEPlatform = function() {
// http://docs.mamedev.org/techspecs/luaengine.html
this.luacall = function(s) {
console_varname = null;
Module.ccall('_Z13js_lua_stringPKc', 'void', ['string'], [s+""]);
}
this.clearDebug = function() {
//TODO
//Module.ccall('_Z13js_lua_stringPKc', 'void', ['string'], [s+""]);
if (!js_lua_string) js_lua_string = Module.cwrap('_Z13js_lua_stringPKc', 'void', ['string']);
js_lua_string(s || "");
}
this.pause = function() {
@ -926,7 +926,7 @@ var BaseMAMEPlatform = function() {
}
this.resume = function() {
if (loaded && !running) {
if (loaded && !running) { // TODO
this.luacall('emu.unpause()');
running = true;
}
@ -949,6 +949,13 @@ var BaseMAMEPlatform = function() {
if (console_varname) console_vars[console_varname] = [];
} else if (console_varname) {
console_vars[console_varname].push(s);
if (console_varname == 'debug_stopped') {
var debugSaveState = self.preserveState();
self.pause();
if (onBreakpointHit) {
onBreakpointHit(debugSaveState);
}
}
} else {
console.log(s);
}
@ -964,10 +971,14 @@ var BaseMAMEPlatform = function() {
$(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, '-debug', '-verbose', '-window', '-nokeepaspect', '-resolution', canvas.width+'x'+canvas.height, '-cart', romfn],
arguments: [opts.driver,
'-debug',
'-debugger', 'none',
'-verbose', '-window', '-nokeepaspect',
'-resolution', canvas.width+'x'+canvas.height,
'-cart', romfn],
screenIsReadOnly: true,
print: bufferConsoleOutput,
canvas:video.canvas,
@ -986,38 +997,72 @@ var BaseMAMEPlatform = function() {
FS.writeFile('/roms/' + opts.biosfile, opts.biosdata, {encoding:'binary'});
}
FS.mkdir('/emulator');
FS.writeFile(romfn, romdata, {encoding:'binary'});
FS.writeFile('/debug.ini', 'debugger none\n', {encoding:'utf8'});
if (romfn) FS.writeFile(romfn, new Uint8Array(romdata), {encoding:'binary'});
//FS.writeFile('/debug.ini', 'debugger none\n', {encoding:'utf8'});
if (opts.preInit) {
opts.preInit(self);
}
$(video.canvas).click(function(e) {
video.canvas.focus();
});
loaded = true;
}
},
preRun: [
function() {
$(video.canvas).click(function(e) {
video.canvas.focus();
});
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) {
$.get('mame/cfg/' + opts.cfgfile, function(data) {
fetch_cfg = $.get('mame/cfg/' + opts.cfgfile, function(data) {
opts.cfgdata = data;
console.log("loaded " + opts.cfgfile);
}, 'text');
}
// fetch BIOS file
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);
var oReq1 = new XMLHttpRequest();
oReq1.open("GET", 'mame/roms/' + opts.biosfile, true);
oReq1.responseType = "arraybuffer";
oReq1.onload = function(oEvent) {
opts.biosdata = new Uint8Array(oReq1.response);
console.log("loaded " + opts.biosfile + " (" + oEvent.total + " bytes)");
fetch_bios.resolve();
};
oReq.send();
oReq1.send();
} else {
fetch_bios.resolve();
}
// load debugger Lua script
fetch_lua = $.get('mame/debugger.lua', function(data) {
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 = function(oEvent) {
console.log("loaded WASM file");
window.Module.wasmBinary = new Uint8Array(oReq2.response);
fetch_wasm.resolve();
};
oReq2.send();
}
// start loading script
script.src = 'mame/' + opts.jsfile;
document.getElementsByTagName('head')[0].appendChild(script);
$.when(fetch_lua, fetch_cfg, fetch_bios, fetch_wasm).done(function() {
var script = document.createElement('script');
script.src = 'mame/' + opts.jsfile;
document.getElementsByTagName('head')[0].appendChild(script);
console.log("created script element");
});
}
this.loadROMFile = function(data) {
@ -1041,9 +1086,7 @@ var BaseMAMEPlatform = function() {
}
}
this.saveState = function() {
this.luareset();
this.luacall('cpu = manager:machine().devices[":maincpu"]\nfor k,v in pairs(cpu.state) do print(">>>cpu_"..k); print(v.value) end');
this.preserveState = function() {
var state = {c:{}};
for (var k in console_vars) {
if (k.startsWith("cpu_")) {
@ -1051,15 +1094,26 @@ var BaseMAMEPlatform = function() {
state.c[k.slice(4)] = v;
}
}
// TODO
// TODO: memory?
return state;
}
this.readAddress = function(a) {
this.saveState = function() {
this.luareset();
this.luacall('mamedbg.printstate()');
return self.preserveState();
}
this.initlua = function() {
if (!initluavars) {
self.luacall('cpu = manager:machine().devices[":maincpu"]\nmem = cpu.spaces["program"]\n')
self.luacall(luadebugscript);
self.luacall('mamedbg.init()')
initluavars = true;
}
}
this.readAddress = function(a) {
self.initlua();
self.luacall('print(">>>v"); print(mem:read_u8(' + a + '))');
return parseInt(console_vars.v[0]);
}
@ -1068,17 +1122,39 @@ var BaseMAMEPlatform = function() {
var onBreakpointHit;
this.clearDebug = function() {
onBreakpointHit = null;
}
this.getDebugCallback = function() {
// TODO
return onBreakpointHit;
}
this.setupDebug = function(callback) {
self.initlua();
self.luareset();
onBreakpointHit = callback;
}
this.runToPC = function(pc) {
self.luacall('mamedbg.runTo(' + pc + ')');
self.resume();
}
this.runToVsync = function() {
self.luacall('mamedbg.runToVsync()');
self.resume();
}
this.runUntilReturn = function() {
self.luacall('mamedbg.runUntilReturn()');
self.resume();
}
this.step = function() {
self.readAddress(0);
//self.luacall('cpu.debug()\n')
self.luacall('debugger = manager:machine().debugger()')
self.luacall('print(debugger)') // TODO
self.luacall('mamedbg.step()');
self.resume();
}
// TODO: other than z80
this.cpuStateToLongString = function(c) {
if (c.HL)
return cpuStateToLongString_Z80(c);
else
return null; // TODO
}
}

View File

@ -956,4 +956,39 @@ var APPLEIIGO_LZG = [
76,237,253,165,72,72,165,69,166,70,164,71,52,110,22,52,62,27,59,30,59,14,245,3,251,3,98,250,98,250
];
/// MAME support
var Apple2MAMEPlatform = function(mainElement) {
var self = this;
this.__proto__ = new BaseMAMEPlatform();
this.start = function() {
self.startModule(mainElement, {
jsfile:'mameapple2e.js',
//cfgfile:'nes.cfg',
driver:'apple2e',
width:256*2,
height:240*2,
//romfn:'/emulator/cart.nes',
//romsize:romSize,
//romdata:new lzgmini().decode(lzgRom).slice(0, romSize),
preInit:function(_self) {
},
});
}
this.getOpcodeMetadata = Javatari.getOpcodeMetadata;
this.getToolForFilename = getToolForFilename_6502;
this.getDefaultExtension = function() { return ".c"; };
this.getPresets = function() { return APPLE2_PRESETS; }
this.loadROM = function(title, data) {
this.loadROMFile(data);
this.loadRegion(":nes_slot:cart:prg_rom", data.slice(0x10, 0x8010));
this.loadRegion(":nes_slot:cart:chr_rom", data.slice(0x8010, 0xa010));
}
}
PLATFORMS['apple2'] = Apple2Platform;
PLATFORMS['apple2-e'] = Apple2MAMEPlatform;

View File

@ -590,9 +590,8 @@ var lastDebugInfo;
var lastDebugState;
function showMemory(state) {
var s = "";
if (state && platform.cpuStateToLongString) {
s = platform.cpuStateToLongString(state.c);
var s = state && platform.cpuStateToLongString && platform.cpuStateToLongString(state.c);
if (s) {
if (platform.getRasterPosition) {
var pos = platform.getRasterPosition();
s += "H:" + pos.x + " V:" + pos.y + "\n"; // TODO: padding
@ -700,9 +699,13 @@ function runToCursor() {
var pc = getCurrentPC();
if (pc >= 0) {
console.log("Run to", pc.toString(16));
platform.runEval(function(c) {
return c.PC == pc;
});
if (platform.runToPC) {
platform.runToPC(pc);
} else {
platform.runEval(function(c) {
return c.PC == pc;
});
}
}
}
@ -1282,7 +1285,7 @@ function setupDebugControls(){
$("#dbg_tovsync").click(singleFrameStep).show();
else
$("#dbg_tovsync").hide();
if (platform.runEval && platform_id != 'verilog')
if ((platform.runEval || platform.runToPC) && platform_id != 'verilog')
$("#dbg_toline").click(runToCursor).show();
else
$("#dbg_toline").hide();

View File

@ -60,6 +60,7 @@ var PLATFORM_PARAMS = {
'coleco': {
rom_start: 0x8000,
code_start: 0x8100,
code_offset: 0x8147, // TODO: right after cv_start()
rom_size: 0x8000,
data_start: 0x7000,
data_size: 0x400,
@ -71,8 +72,8 @@ var PLATFORM_PARAMS = {
'main.rel'],
},
'nes-conio': {
define: '__NES__',
cfgfile: 'nes.cfg',
define: '__NES__',
libargs: ['nes.lib'],
},
'nes-lib': {
@ -85,6 +86,11 @@ var PLATFORM_PARAMS = {
cfgfile: 'apple2.cfg',
libargs: ['apple2.lib'],
},
'apple2-e': {
define: '__APPLE2__',
cfgfile: 'apple2.cfg',
libargs: ['apple2.lib'],
},
'verilog': {
},
};
@ -289,8 +295,9 @@ function extractErrors(regex, strings) {
return errors;
}
function parseListing(code, lineMatch, iline, ioffset, iinsns) {
function parseListing(code, lineMatch, iline, ioffset, iinsns, origin) {
var lines = [];
origin |= 0;
for (var line of code.split(/\r?\n/)) {
var linem = lineMatch.exec(line);
if (linem && linem[1]) {
@ -300,7 +307,7 @@ function parseListing(code, lineMatch, iline, ioffset, iinsns) {
if (insns) {
lines.push({
line:linenum,
offset:offset,
offset:offset + origin,
insns:insns,
});
}
@ -309,9 +316,10 @@ function parseListing(code, lineMatch, iline, ioffset, iinsns) {
return lines;
}
function parseSourceLines(code, lineMatch, offsetMatch) {
function parseSourceLines(code, lineMatch, offsetMatch, origin) {
var lines = [];
var lastlinenum = 0;
origin |= 0;
for (var line of code.split(/\r?\n/)) {
var linem = lineMatch.exec(line);
if (linem && linem[1]) {
@ -322,7 +330,7 @@ function parseSourceLines(code, lineMatch, offsetMatch) {
var offset = parseInt(linem[1], 16);
lines.push({
line:lastlinenum,
offset:offset,
offset:offset + origin,
});
lastlinenum = 0;
}
@ -686,7 +694,7 @@ l_main00101 = 0003, L: test
*/
var amap = FS.readFile("main.map", {'encoding':'utf8'}); // TODO
var aout = FS.readFile("main.bin", {'encoding':'binary'});
var asmlines = parseListing(alst, /^(\d+)\s+([0-9A-F]+)\s+([0-9A-F][0-9A-F ]*[0-9A-F])\s+/i, 1, 2, 3, 4);
var asmlines = parseListing(alst, /^(\d+)\s+([0-9A-F]+)\s+([0-9A-F][0-9A-F ]*[0-9A-F])\s+/i, 1, 2, 3, params.rom_start|0);
var srclines = parseListing(alst, /^(\d+)\s+([0-9A-F]+)\s+;[(]null[)]:(\d+)/i, 3, 2, 1);
return {
output:aout,
@ -813,9 +821,9 @@ function assemblelinkSDASZ80(code, platform) {
var rstout = updateListing ? FS.readFile("main.rst", {encoding:'utf8'}) : lstout;
//var dbgout = FS.readFile("main.cdb", {encoding:'utf8'});
// 0000 21 02 00 [10] 52 ld hl, #2
// TODO: offset by start address?
var asmlines = parseListing(lstout, /^\s*([0-9A-F]+)\s+([0-9A-F][0-9A-F r]*[0-9A-F])\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 4, 1, 2, 5, 3);
var srclines = parseSourceLines(lstout, /^\s+\d+ ;<stdin>:(\d+):/i, /^\s*([0-9A-F]{4})/i);
// TODO: use map to find code_offset
var asmlines = parseListing(lstout, /^\s*([0-9A-F]+)\s+([0-9A-F][0-9A-F r]*[0-9A-F])\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 4, 1, 2, params.code_offset); //, 5, 3);
var srclines = parseSourceLines(lstout, /^\s+\d+ ;<stdin>:(\d+):/i, /^\s*([0-9A-F]{4})/i, params.code_offset);
// parse symbol map
var symbolmap = {};
for (var s of mapout.split("\n")) {
@ -935,7 +943,7 @@ function assembleXASM6809(code, platform) {
try {
var aout = FS.readFile("main.bin", {encoding:'binary'});
// 00001 0000 [ 2] 1048 asld
var asmlines = parseListing(alst, /^\s*([0-9A-F]+)\s+([0-9A-F]+)\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 1, 2, 4, 5, 3);
var asmlines = parseListing(alst, /^\s*([0-9A-F]+)\s+([0-9A-F]+)\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 1, 2, 4, params.code_offset); //, 5, 3);
return {
output:aout,
errors:msvc_errors,
@ -1015,7 +1023,7 @@ function assembleNAKEN(code, platform) {
var alst = FS.readFile("out.lst", {encoding:'utf8'});
//console.log(alst);
// 0x0000: 77 ld (hl),a cycles: 4
var asmlines = parseListing(alst, /^0x([0-9a-f]+):\s+([0-9a-f]+)\s+(.+)cycles: (\d+)/i, 0, 1, 2, 3);
var asmlines = parseListing(alst, /^0x([0-9a-f]+):\s+([0-9a-f]+)\s+(.+)cycles: (\d+)/i, 0, 1, 2); //, 3);
return {
output:aout,
errors:errors,