started on mame WASM, debugging support, colecovision
This commit is contained in:
parent
495896c43d
commit
ef561b4425
|
@ -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")
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
148
src/emu.js
148
src/emu.js
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
17
src/ui.js
17
src/ui.js
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue