started on profile/memory views
This commit is contained in:
parent
8a8638b295
commit
89c3209f09
|
@ -54,3 +54,9 @@ machines.
|
||||||
SWEET16 - Woz's tiny bytecode interpreter on the Apple ][ integer BASIC ROM.
|
SWEET16 - Woz's tiny bytecode interpreter on the Apple ][ integer BASIC ROM.
|
||||||
Still emcumbered by Apple's copyright for the foreseeable future.
|
Still emcumbered by Apple's copyright for the foreseeable future.
|
||||||
http://6502.org/source/interpreters/sweet16.htm
|
http://6502.org/source/interpreters/sweet16.htm
|
||||||
|
|
||||||
|
https://github.com/EtchedPixels/FUZIX/wiki
|
||||||
|
|
||||||
|
gcc6809 - need to check this out
|
||||||
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
33
index.html
33
index.html
|
@ -75,6 +75,18 @@ div.emulator {
|
||||||
background-color: #666;
|
background-color: #666;
|
||||||
margin-top: 20px auto 0;
|
margin-top: 20px auto 0;
|
||||||
}
|
}
|
||||||
|
div.debugwindow {
|
||||||
|
position:absolute;
|
||||||
|
left:50%;
|
||||||
|
top:0;
|
||||||
|
width:50%;
|
||||||
|
background-color: #666;
|
||||||
|
color: #66ff66;
|
||||||
|
white-space: pre;
|
||||||
|
margin-top: 20px auto 0;
|
||||||
|
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
div.mem_info {
|
div.mem_info {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 51%;
|
left: 51%;
|
||||||
|
@ -83,7 +95,7 @@ div.mem_info {
|
||||||
color: #66ff66;
|
color: #66ff66;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
z-index: 2;
|
z-index: 12;
|
||||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +238,7 @@ div.bitmap_editor {
|
||||||
</span>
|
</span>
|
||||||
<select id="preset_select" name="">
|
<select id="preset_select" name="">
|
||||||
</select>
|
</select>
|
||||||
<img id="compile_spinner" src="spinner.gif" height="20em" style="visibility:hidden;margin-left:8px;margin-right:8px">
|
<img id="compile_spinner" src="images/spinner.gif" height="20em" style="visibility:hidden;margin-left:8px;margin-right:8px">
|
||||||
<span class="debug_bar" id="debug_bar">
|
<span class="debug_bar" id="debug_bar">
|
||||||
<button id="dbg_reset" type="submit" title="Reset and Break"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button>
|
<button id="dbg_reset" type="submit" title="Reset and Break"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button>
|
||||||
<button id="dbg_pause" type="button" title="Pause"><span class="glyphicon glyphicon-pause" aria-hidden="true"></span></button>
|
<button id="dbg_pause" type="button" title="Pause"><span class="glyphicon glyphicon-pause" aria-hidden="true"></span></button>
|
||||||
|
@ -235,9 +247,13 @@ div.bitmap_editor {
|
||||||
<button id="dbg_toline" type="submit" title="Run To Line"><span class="glyphicon glyphicon-save" aria-hidden="true"></span></button>
|
<button id="dbg_toline" type="submit" title="Run To Line"><span class="glyphicon glyphicon-save" aria-hidden="true"></span></button>
|
||||||
<button id="dbg_stepout" type="submit" title="Step Out of Subroutine"><span class="glyphicon glyphicon-hand-up" aria-hidden="true"></span></button>
|
<button id="dbg_stepout" type="submit" title="Step Out of Subroutine"><span class="glyphicon glyphicon-hand-up" aria-hidden="true"></span></button>
|
||||||
<button id="dbg_stepback" type="submit" title="Step Backwards"><span class="glyphicon glyphicon-step-backward" aria-hidden="true"></span></button>
|
<button id="dbg_stepback" type="submit" title="Step Backwards"><span class="glyphicon glyphicon-step-backward" aria-hidden="true"></span></button>
|
||||||
<button id="dbg_timing" type="submit" title="See Timing" style="display:none"><span class="glyphicon glyphicon-time" aria-hidden="true"></span></button>
|
|
||||||
</span>
|
</span>
|
||||||
<button id="dbg_disasm" type="submit" title="Show Disassembly" style="display:none"><span class="glyphicon glyphicon-list" aria-hidden="true"></span></button>
|
<span class="extra_bar" id="extra_bar">
|
||||||
|
<button id="dbg_timing" type="submit" title="See Timing" style="display:none"><span class="glyphicon glyphicon-time" aria-hidden="true"></span></button>
|
||||||
|
<button id="dbg_disasm" type="submit" title="Show Disassembly" style="display:none"><span class="glyphicon glyphicon-list" aria-hidden="true"></span></button>
|
||||||
|
<button id="dbg_memory" type="submit" title="Show Memory" style="display:none"><span class="glyphicon glyphicon-sunglasses" aria-hidden="true"></span></button>
|
||||||
|
<button id="dbg_profile" type="submit" title="Show Profile" style="display:none"><span class="glyphicon glyphicon-stats" aria-hidden="true"></span></button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="notebook">
|
<div id="notebook">
|
||||||
<div id="workspace">
|
<div id="workspace">
|
||||||
|
@ -249,8 +265,12 @@ div.bitmap_editor {
|
||||||
<div class="emulator" id="emulator">
|
<div class="emulator" id="emulator">
|
||||||
<div id="javatari-screen" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
<div id="javatari-screen" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
||||||
<div id="javatari-console-panel" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
<div id="javatari-console-panel" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
||||||
<div id="mem_info" class="mem_info" style="display:none">
|
</div>
|
||||||
</div>
|
<div id="mem_info" class="mem_info" style="display:none">
|
||||||
|
</div>
|
||||||
|
<div id="profileview" class="debugwindow" style="display:none;z-index:10">
|
||||||
|
</div>
|
||||||
|
<div id="memoryview" class="debugwindow" style="display:none;z-index:10">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="twitbtn">
|
<div class="twitbtn">
|
||||||
|
@ -314,6 +334,7 @@ Dest: $<span id="bitmap_editor_dest">0000/0</span>
|
||||||
<script src="FileSaver.js/FileSaver.min.js"></script>
|
<script src="FileSaver.js/FileSaver.min.js"></script>
|
||||||
<script src="octokat.js/dist/octokat.js"></script>
|
<script src="octokat.js/dist/octokat.js"></script>
|
||||||
|
|
||||||
|
<script src="src/vlist.js"></script>
|
||||||
<script src="src/emu.js"></script>
|
<script src="src/emu.js"></script>
|
||||||
<script src="src/audio.js"></script>
|
<script src="src/audio.js"></script>
|
||||||
<script src="src/util.js"></script>
|
<script src="src/util.js"></script>
|
||||||
|
|
21
src/emu.js
21
src/emu.js
|
@ -825,11 +825,26 @@ function AddressDecoder(table, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var BusProbe = function(bus) {
|
var BusProbe = function(bus) {
|
||||||
|
var active = false;
|
||||||
|
var callback;
|
||||||
|
this.activate = function(_callback) {
|
||||||
|
active = true;
|
||||||
|
callback = _callback;
|
||||||
|
}
|
||||||
|
this.deactivate = function() {
|
||||||
|
active = false;
|
||||||
|
callback = null;
|
||||||
|
}
|
||||||
this.read = function(a) {
|
this.read = function(a) {
|
||||||
var val = bus.read(a);
|
if (active) {
|
||||||
return val;
|
callback(a);
|
||||||
|
}
|
||||||
|
return bus.read(a);
|
||||||
}
|
}
|
||||||
this.write = function(a,v) {
|
this.write = function(a,v) {
|
||||||
return bus.write(a,v);
|
if (active) {
|
||||||
|
callback(a,v);
|
||||||
|
}
|
||||||
|
bus.write(a,v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,6 +264,9 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
isContended: function() { return false; },
|
isContended: function() { return false; },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
this.readMemory = function(a) {
|
||||||
|
return (a == 0x7000 || a == 0x7800) ? null : membus.read; // ignore watchdog
|
||||||
|
};
|
||||||
audio = new MasterAudio();
|
audio = new MasterAudio();
|
||||||
psg1 = new AY38910_Audio(audio);
|
psg1 = new AY38910_Audio(audio);
|
||||||
psg2 = new AY38910_Audio(audio);
|
psg2 = new AY38910_Audio(audio);
|
||||||
|
@ -368,7 +371,7 @@ var GalaxianPlatform = function(mainElement, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
|
@ -60,6 +60,7 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
]),
|
]),
|
||||||
isContended: function() { return false; },
|
isContended: function() { return false; },
|
||||||
};
|
};
|
||||||
|
this.readMemory = membus.read;
|
||||||
iobus = {
|
iobus = {
|
||||||
read: function(addr) {
|
read: function(addr) {
|
||||||
addr &= 0x3;
|
addr &= 0x3;
|
||||||
|
@ -177,7 +178,7 @@ var Midway8080BWPlatform = function(mainElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
|
@ -122,7 +122,7 @@ var KonamiSoundPlatform = function(mainElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
|
@ -137,7 +137,7 @@ var WilliamsSoundPlatform = function(mainElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
|
@ -65,7 +65,7 @@ var VCSPlatform = function() {
|
||||||
return {x:xpos, y:ypos};
|
return {x:xpos, y:ypos};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() { return Javatari.room.console.isRunning(); }
|
this.isRunning = function() { return Javatari.room && Javatari.room.console.isRunning(); }
|
||||||
this.pause = function() { Javatari.room.console.pause(); }
|
this.pause = function() { Javatari.room.console.pause(); }
|
||||||
this.resume = function() { Javatari.room.console.go(); }
|
this.resume = function() { Javatari.room.console.go(); }
|
||||||
this.step = function() { Javatari.room.console.debugSingleStepCPUClock(); }
|
this.step = function() { Javatari.room.console.debugSingleStepCPUClock(); }
|
||||||
|
|
|
@ -89,6 +89,7 @@ var AtariVectorPlatform = function(mainElement) {
|
||||||
], {gmask:0x7fff})
|
], {gmask:0x7fff})
|
||||||
|
|
||||||
};
|
};
|
||||||
|
this.readMemory = membus.read;
|
||||||
cpu = self.newCPU(bus);
|
cpu = self.newCPU(bus);
|
||||||
// create video/audio
|
// create video/audio
|
||||||
video = new VectorVideo(mainElement,1024,1024);
|
video = new VectorVideo(mainElement,1024,1024);
|
||||||
|
@ -131,7 +132,7 @@ var AtariVectorPlatform = function(mainElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
@ -275,7 +276,7 @@ var AtariColorVectorPlatform = function(mainElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
@ -401,7 +402,7 @@ var Z80ColorVectorPlatform = function(mainElement, proto) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
|
@ -15,7 +15,7 @@ var VicDualPlatform = function(mainElement) {
|
||||||
this.__proto__ = new BaseZ80Platform();
|
this.__proto__ = new BaseZ80Platform();
|
||||||
|
|
||||||
var cpu, ram, membus, iobus, rom;
|
var cpu, ram, membus, iobus, rom;
|
||||||
var video, audio, psg, timer, pixels;
|
var video, audio, psg, timer, pixels, probe;
|
||||||
var inputs = [0xff, 0xff, 0xff, 0xff^0x8]; // most things active low
|
var inputs = [0xff, 0xff, 0xff, 0xff^0x8]; // most things active low
|
||||||
var palbank = 0;
|
var palbank = 0;
|
||||||
|
|
||||||
|
@ -108,6 +108,7 @@ var VicDualPlatform = function(mainElement) {
|
||||||
]),
|
]),
|
||||||
isContended: function() { return false; },
|
isContended: function() { return false; },
|
||||||
};
|
};
|
||||||
|
this.readMemory = membus.read;
|
||||||
iobus = {
|
iobus = {
|
||||||
read: function(addr) {
|
read: function(addr) {
|
||||||
return inputs[addr&3];
|
return inputs[addr&3];
|
||||||
|
@ -119,9 +120,10 @@ var VicDualPlatform = function(mainElement) {
|
||||||
if (addr & 0x40) { palbank = val & 3; }; // palette
|
if (addr & 0x40) { palbank = val & 3; }; // palette
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
probe = new BusProbe(membus);
|
||||||
cpu = window.Z80({
|
cpu = window.Z80({
|
||||||
display: {},
|
display: {},
|
||||||
memory: membus,
|
memory: probe,
|
||||||
ioBus: iobus
|
ioBus: iobus
|
||||||
});
|
});
|
||||||
video = new RasterVideo(mainElement,256,224,{rotate:-90});
|
video = new RasterVideo(mainElement,256,224,{rotate:-90});
|
||||||
|
@ -199,7 +201,7 @@ var VicDualPlatform = function(mainElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
@ -223,6 +225,7 @@ var VicDualPlatform = function(mainElement) {
|
||||||
layers: {width:256, height:224, tiles:[]}
|
layers: {width:256, height:224, tiles:[]}
|
||||||
} : null;
|
} : null;
|
||||||
}
|
}
|
||||||
|
this.getProbe = function() { return probe; }
|
||||||
}
|
}
|
||||||
|
|
||||||
PLATFORMS['vicdual'] = VicDualPlatform;
|
PLATFORMS['vicdual'] = VicDualPlatform;
|
||||||
|
|
|
@ -278,6 +278,7 @@ var WilliamsPlatform = function(mainElement, proto) {
|
||||||
read: memread_williams,
|
read: memread_williams,
|
||||||
write: memwrite_williams,
|
write: memwrite_williams,
|
||||||
};
|
};
|
||||||
|
this.readMemory = membus.read;
|
||||||
//var probebus = new BusProbe(membus);
|
//var probebus = new BusProbe(membus);
|
||||||
var iobus = {
|
var iobus = {
|
||||||
read: function(a) {return 0;},
|
read: function(a) {return 0;},
|
||||||
|
@ -384,7 +385,7 @@ var WilliamsPlatform = function(mainElement, proto) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isRunning = function() {
|
this.isRunning = function() {
|
||||||
return timer.isRunning();
|
return timer && timer.isRunning();
|
||||||
}
|
}
|
||||||
this.pause = function() {
|
this.pause = function() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
158
src/ui.js
158
src/ui.js
|
@ -115,12 +115,10 @@ var current_preset_index = -1; // TODO: use URL
|
||||||
var current_preset_id = null;
|
var current_preset_id = null;
|
||||||
var assemblyfile = null;
|
var assemblyfile = null;
|
||||||
var sourcefile = null;
|
var sourcefile = null;
|
||||||
var pcvisits;
|
|
||||||
var trace_pending_at_pc;
|
var trace_pending_at_pc;
|
||||||
var store;
|
var store;
|
||||||
var pendingWorkerMessages = 0;
|
var pendingWorkerMessages = 0;
|
||||||
var editor;
|
var editor;
|
||||||
|
|
||||||
var disasmview = CodeMirror(document.getElementById('disassembly'), {
|
var disasmview = CodeMirror(document.getElementById('disassembly'), {
|
||||||
mode: 'z80',
|
mode: 'z80',
|
||||||
theme: 'cobalt',
|
theme: 'cobalt',
|
||||||
|
@ -129,6 +127,9 @@ var disasmview = CodeMirror(document.getElementById('disassembly'), {
|
||||||
styleActiveLine: true
|
styleActiveLine: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var memoryview;
|
||||||
|
var profileview;
|
||||||
|
|
||||||
function newEditor(mode) {
|
function newEditor(mode) {
|
||||||
var isAsm = (mode != 'text/x-csrc');
|
var isAsm = (mode != 'text/x-csrc');
|
||||||
editor = CodeMirror(document.getElementById('editor'), {
|
editor = CodeMirror(document.getElementById('editor'), {
|
||||||
|
@ -147,6 +148,11 @@ function newEditor(mode) {
|
||||||
setCode(editor.getValue());
|
setCode(editor.getValue());
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
|
editor.on('scroll', function(ed, changeobj) {
|
||||||
|
if (profileview) {
|
||||||
|
profileview.container.scrollTop = editor.getScrollInfo().top;
|
||||||
|
}
|
||||||
|
});
|
||||||
editor.setOption("mode", mode);
|
editor.setOption("mode", mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +406,8 @@ function setCompileOutput(data) {
|
||||||
platform.loadROM(getCurrentPresetTitle(), rom);
|
platform.loadROM(getCurrentPresetTitle(), rom);
|
||||||
resume();
|
resume();
|
||||||
current_output = rom;
|
current_output = rom;
|
||||||
pcvisits = {};
|
prof_reads = [];
|
||||||
|
prof_writes = [];
|
||||||
toolbar.removeClass("has-errors");
|
toolbar.removeClass("has-errors");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e); // TODO: show error
|
console.log(e); // TODO: show error
|
||||||
|
@ -447,7 +454,6 @@ function setCompileOutput(data) {
|
||||||
worker.onmessage = function(e) {
|
worker.onmessage = function(e) {
|
||||||
toolbar.removeClass("is-busy");
|
toolbar.removeClass("is-busy");
|
||||||
$('#compile_spinner').css('visibility', 'hidden');
|
$('#compile_spinner').css('visibility', 'hidden');
|
||||||
// TODO: this doesn't completely work yet
|
|
||||||
if (pendingWorkerMessages > 1) {
|
if (pendingWorkerMessages > 1) {
|
||||||
pendingWorkerMessages = 0;
|
pendingWorkerMessages = 0;
|
||||||
setCode(editor.getValue());
|
setCode(editor.getValue());
|
||||||
|
@ -523,7 +529,6 @@ function setupBreakpoint() {
|
||||||
console.log("BREAKPOINT", hex(PC));
|
console.log("BREAKPOINT", hex(PC));
|
||||||
// TODO: switch to disasm
|
// TODO: switch to disasm
|
||||||
}
|
}
|
||||||
pcvisits[PC] = pcvisits[PC] ? pcvisits[PC]+1 : 1;
|
|
||||||
showMemory(state);
|
showMemory(state);
|
||||||
updateDisassembly();
|
updateDisassembly();
|
||||||
});
|
});
|
||||||
|
@ -872,6 +877,136 @@ function _breakExpression() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateDebugWindows() {
|
||||||
|
if (platform.isRunning()) {
|
||||||
|
updateMemoryWindow();
|
||||||
|
updateProfileWindow();
|
||||||
|
}
|
||||||
|
setTimeout(updateDebugWindows, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProfileLine(line) {
|
||||||
|
var offset = sourcefile.line2offset[line];
|
||||||
|
if (offset >= 0) {
|
||||||
|
if (prof_reads[offset] > 0)
|
||||||
|
return ""+prof_reads[offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProfileWindow() {
|
||||||
|
if (profileview && sourcefile) {
|
||||||
|
$("#profileview").find('[data-index]').each(function(i,e) {
|
||||||
|
var div = $(e);
|
||||||
|
var lineno = div.attr('data-index') | 0;
|
||||||
|
var newtext = getProfileLine(lineno+1);
|
||||||
|
if (newtext) {
|
||||||
|
var oldtext = div.text();
|
||||||
|
if (oldtext != newtext)
|
||||||
|
div.text(newtext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMemoryWindow() {
|
||||||
|
if (memoryview) {
|
||||||
|
$("#memoryview").find('[data-index]').each(function(i,e) {
|
||||||
|
var div = $(e);
|
||||||
|
var offset = div.attr('data-index') * 16;
|
||||||
|
var oldtext = div.text();
|
||||||
|
var newtext = getMemoryLineAtOffset(offset);
|
||||||
|
if (oldtext != newtext)
|
||||||
|
div.text(newtext);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMemoryLineAtOffset(offset) {
|
||||||
|
var s = hex(offset,4) + ' ';
|
||||||
|
for (var i=0; i<16; i++) {
|
||||||
|
var read = platform.readMemory(offset+i);
|
||||||
|
if (i==8) s += ' ';
|
||||||
|
s += ' ' + (read>=0?hex(read,2):'??');
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEditorLineHeight() {
|
||||||
|
return $("#editor").find(".CodeMirror-line").first().height();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMemoryWindow() {
|
||||||
|
memoryview = new VirtualList({
|
||||||
|
w:$("#emulator").width(),
|
||||||
|
h:$("#emulator").height(),
|
||||||
|
itemHeight: getEditorLineHeight(),
|
||||||
|
totalRows: 0x1000,
|
||||||
|
generatorFn: function(row) {
|
||||||
|
var s = getMemoryLineAtOffset(row * 16);
|
||||||
|
var div = document.createElement("div");
|
||||||
|
div.appendChild(document.createTextNode(s));
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#memoryview").empty().append(memoryview.container);
|
||||||
|
updateMemoryWindow();
|
||||||
|
memoryview.scrollToItem(0x800); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMemoryWindow() {
|
||||||
|
if ($("#profileview").is(':visible')) toggleProfileWindow();
|
||||||
|
if ($("#memoryview").is(':visible')) {
|
||||||
|
memoryview = null;
|
||||||
|
$("#emulator").show();
|
||||||
|
$("#memoryview").hide();
|
||||||
|
} else {
|
||||||
|
showMemoryWindow();
|
||||||
|
$("#emulator").hide();
|
||||||
|
$("#memoryview").show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createProfileWindow() {
|
||||||
|
profileview = new VirtualList({
|
||||||
|
w:$("#emulator").width(),
|
||||||
|
h:$("#emulator").height(),
|
||||||
|
itemHeight: getEditorLineHeight(),
|
||||||
|
totalRows: editor.lineCount(),
|
||||||
|
generatorFn: function(row) {
|
||||||
|
var div = document.createElement("div");
|
||||||
|
div.appendChild(document.createTextNode("."));
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#profileview").empty().append(profileview.container);
|
||||||
|
updateProfileWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
var prof_reads, prof_writes;
|
||||||
|
|
||||||
|
function profileWindowCallback(a,v) {
|
||||||
|
if (v >= 0) {
|
||||||
|
prof_writes[a] = (prof_writes[a]|0)+1;
|
||||||
|
} else {
|
||||||
|
prof_reads[a] = (prof_reads[a]|0)+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleProfileWindow() {
|
||||||
|
if ($("#memoryview").is(':visible')) toggleMemoryWindow();
|
||||||
|
if ($("#profileview").is(':visible')) {
|
||||||
|
profileview = null;
|
||||||
|
platform.getProbe().deactivate();
|
||||||
|
$("#emulator").show();
|
||||||
|
$("#profileview").hide();
|
||||||
|
} else {
|
||||||
|
createProfileWindow();
|
||||||
|
platform.getProbe().activate(profileWindowCallback);
|
||||||
|
$("#emulator").hide();
|
||||||
|
$("#profileview").show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setupDebugControls(){
|
function setupDebugControls(){
|
||||||
$("#dbg_reset").click(resetAndDebug);
|
$("#dbg_reset").click(resetAndDebug);
|
||||||
$("#dbg_pause").click(pause);
|
$("#dbg_pause").click(pause);
|
||||||
|
@ -883,6 +1018,12 @@ function setupDebugControls(){
|
||||||
if (platform_id == 'vcs') {
|
if (platform_id == 'vcs') {
|
||||||
$("#dbg_timing").click(traceTiming).show();
|
$("#dbg_timing").click(traceTiming).show();
|
||||||
}
|
}
|
||||||
|
else if (platform.readAddress) {
|
||||||
|
$("#dbg_memory").click(toggleMemoryWindow).show();
|
||||||
|
}
|
||||||
|
if (platform.getProbe) {
|
||||||
|
$("#dbg_profile").click(toggleProfileWindow).show();
|
||||||
|
}
|
||||||
if (platform.saveState) { // TODO: only show if listing or disasm available
|
if (platform.saveState) { // TODO: only show if listing or disasm available
|
||||||
$("#dbg_disasm").click(toggleDisassembly).show();
|
$("#dbg_disasm").click(toggleDisassembly).show();
|
||||||
}
|
}
|
||||||
|
@ -893,6 +1034,7 @@ function setupDebugControls(){
|
||||||
$("#item_reset_file").click(_resetPreset);
|
$("#item_reset_file").click(_resetPreset);
|
||||||
$("#item_debug_expr").click(_breakExpression);
|
$("#item_debug_expr").click(_breakExpression);
|
||||||
$("#item_download_rom").click(_downloadROMImage);
|
$("#item_download_rom").click(_downloadROMImage);
|
||||||
|
updateDebugWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWelcomeMessage() {
|
function showWelcomeMessage() {
|
||||||
|
@ -938,11 +1080,6 @@ function showWelcomeMessage() {
|
||||||
|
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
function setupBitmapEditor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////
|
|
||||||
|
|
||||||
var qs = (function (a) {
|
var qs = (function (a) {
|
||||||
if (!a || a == "")
|
if (!a || a == "")
|
||||||
return {};
|
return {};
|
||||||
|
@ -975,7 +1112,6 @@ function startPlatform() {
|
||||||
// start platform and load file
|
// start platform and load file
|
||||||
preloadWorker(qs['file']);
|
preloadWorker(qs['file']);
|
||||||
setupDebugControls();
|
setupDebugControls();
|
||||||
setupBitmapEditor();
|
|
||||||
platform.start();
|
platform.start();
|
||||||
loadPreset(qs['file']);
|
loadPreset(qs['file']);
|
||||||
updateSelector();
|
updateSelector();
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/**
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Sergi Mansilla
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the 'Software'), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a virtually-rendered scrollable list.
|
||||||
|
* @param {object} config
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function VirtualList(config) {
|
||||||
|
var width = (config && config.w + 'px') || '100%';
|
||||||
|
var height = (config && config.h + 'px') || '100%';
|
||||||
|
var itemHeight = this.itemHeight = config.itemHeight;
|
||||||
|
|
||||||
|
this.items = config.items;
|
||||||
|
this.generatorFn = config.generatorFn;
|
||||||
|
this.totalRows = config.totalRows || (config.items && config.items.length);
|
||||||
|
|
||||||
|
var scroller = VirtualList.createScroller(itemHeight * this.totalRows);
|
||||||
|
this.container = VirtualList.createContainer(width, height);
|
||||||
|
this.container.appendChild(scroller);
|
||||||
|
|
||||||
|
var screenItemsLen = Math.ceil(config.h / itemHeight);
|
||||||
|
// Cache 4 times the number of items that fit in the container viewport
|
||||||
|
this.cachedItemsLen = screenItemsLen * 3;
|
||||||
|
this._renderChunk(this.container, 0);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var lastRepaintY;
|
||||||
|
var maxBuffer = screenItemsLen * itemHeight;
|
||||||
|
var lastScrolled = 0;
|
||||||
|
|
||||||
|
// As soon as scrolling has stopped, this interval asynchronouslyremoves all
|
||||||
|
// the nodes that are not used anymore
|
||||||
|
this.rmNodeInterval = setInterval(function() {
|
||||||
|
if (Date.now() - lastScrolled > 100) {
|
||||||
|
var badNodes = document.querySelectorAll('[data-rm="1"]');
|
||||||
|
for (var i = 0, l = badNodes.length; i < l; i++) {
|
||||||
|
try {
|
||||||
|
self.container.removeChild(badNodes[i]);
|
||||||
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
function onScroll(e) {
|
||||||
|
var scrollTop = e.target.scrollTop; // Triggers reflow
|
||||||
|
if (!lastRepaintY || Math.abs(scrollTop - lastRepaintY) > maxBuffer) {
|
||||||
|
var first = parseInt(scrollTop / itemHeight) - screenItemsLen;
|
||||||
|
self._renderChunk(self.container, first < 0 ? 0 : first);
|
||||||
|
lastRepaintY = scrollTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastScrolled = Date.now();
|
||||||
|
e.preventDefault && e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container.addEventListener('scroll', onScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualList.prototype.createRow = function(i) {
|
||||||
|
var item;
|
||||||
|
if (this.generatorFn)
|
||||||
|
item = this.generatorFn(i);
|
||||||
|
else if (this.items) {
|
||||||
|
if (typeof this.items[i] === 'string') {
|
||||||
|
var itemText = document.createTextNode(this.items[i]);
|
||||||
|
item = document.createElement('div');
|
||||||
|
item.style.height = this.itemHeight + 'px';
|
||||||
|
item.appendChild(itemText);
|
||||||
|
} else {
|
||||||
|
item = this.items[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item.classList.add('vrow');
|
||||||
|
item.setAttribute('data-index', ''+i);
|
||||||
|
item.style.position = 'absolute';
|
||||||
|
item.style.top = (i * this.itemHeight) + 'px';
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a particular, consecutive chunk of the total rows in the list. To
|
||||||
|
* keep acceleration while scrolling, we mark the nodes that are candidate for
|
||||||
|
* deletion instead of deleting them right away, which would suddenly stop the
|
||||||
|
* acceleration. We delete them once scrolling has finished.
|
||||||
|
*
|
||||||
|
* @param {Node} node Parent node where we want to append the children chunk.
|
||||||
|
* @param {Number} from Starting position, i.e. first children index.
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
VirtualList.prototype._renderChunk = function(node, from) {
|
||||||
|
var finalItem = from + this.cachedItemsLen;
|
||||||
|
if (finalItem > this.totalRows)
|
||||||
|
finalItem = this.totalRows;
|
||||||
|
|
||||||
|
// Append all the new rows in a document fragment that we will later append to
|
||||||
|
// the parent node
|
||||||
|
var fragment = document.createDocumentFragment();
|
||||||
|
for (var i = from; i < finalItem; i++) {
|
||||||
|
fragment.appendChild(this.createRow(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide and mark obsolete nodes for deletion.
|
||||||
|
for (var j = 1, l = node.childNodes.length; j < l; j++) {
|
||||||
|
node.childNodes[j].style.display = 'none';
|
||||||
|
node.childNodes[j].setAttribute('data-rm', '1');
|
||||||
|
}
|
||||||
|
node.appendChild(fragment);
|
||||||
|
};
|
||||||
|
|
||||||
|
VirtualList.createContainer = function(w, h) {
|
||||||
|
var c = document.createElement('div');
|
||||||
|
c.style.width = w;
|
||||||
|
c.style.height = h;
|
||||||
|
c.style.overflow = 'auto';
|
||||||
|
c.style.position = 'relative';
|
||||||
|
c.style.padding = 0;
|
||||||
|
c.style.border = '1px solid black';
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
|
||||||
|
VirtualList.createScroller = function(h) {
|
||||||
|
var scroller = document.createElement('div');
|
||||||
|
scroller.style.opacity = 0;
|
||||||
|
scroller.style.position = 'absolute';
|
||||||
|
scroller.style.top = 0;
|
||||||
|
scroller.style.left = 0;
|
||||||
|
scroller.style.width = '1px';
|
||||||
|
scroller.style.height = h + 'px';
|
||||||
|
return scroller;
|
||||||
|
};
|
||||||
|
|
||||||
|
VirtualList.prototype.scrollToItem = function(index) {
|
||||||
|
this.container.scrollTop = this.itemHeight * index;
|
||||||
|
};
|
Loading…
Reference in New Issue