working on call stack probe, ui tweaks

This commit is contained in:
Steven Hugg 2020-07-09 13:27:56 -05:00
parent 2e27b0d2bb
commit bf36fe2b7f
8 changed files with 126 additions and 74 deletions

View File

@ -376,10 +376,9 @@ div.replaydiv {
}
div.markdown {
background-color: #fff;
width:94%;
margin:3%;
padding:1em;
user-select: auto;
width:100%;
padding:2em;
user-select: text;
}
div.markdown table {
margin:1em;
@ -612,6 +611,11 @@ div.asset_toolbar {
color: #6666ff;
background-color: #eeeeff;
margin:1%;
width:100%;
max-width:25em;
}
.transcript-input-char {
max-width:5em;
}
.tree-header {
border: 2px solid #555;

View File

@ -177,12 +177,9 @@ TODO:
- Safari: doesn't send good exception reasons ("undefined")
- probably XMLHttpRequest.timeout (https://github.com/getsentry/sentry-javascript/issues/2210)
- C64
- debugging at reset
- gotoxy goes to $EA24 (KIL) from PLOT (kplot.s) missing UPDCRAMPTR
- emu doesn't reset properly (after gotoxy() BIOS call)
- disk image support
- https://github.com/cc65/cc65/issues/946
- sample buffer skips (need to sync w/ vsync)
- need to sync advanceFrame() w/ vsync
- upgrade to ES2020?
- https://github.com/microsoft/TypeScript/issues/16577
@ -194,8 +191,7 @@ TODO:
- ca65 line numbers are not aligned with source code
- segments not read properly
- Debug Browser
- hex viewer
- show 16/32 typed arrays
- more stuff like 7800 display lists
WEB WORKER FORMAT

View File

@ -223,7 +223,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="?platform=vector-ataricolor">Atari Color Vector (6502)</a></li>
<li><a class="dropdown-item" href="?platform=x86">x86 (FreeDOS)</a></li>
<li><a class="dropdown-item" href="?platform=zmachine">Z-Machine (Inform 6)</a></li>
<li><a class="dropdown-item" href="?platform=zmachine">Z-Machine</a></li>
<li><a class="dropdown-item" href="?platform=markdown">Markdown Text Editor</a></li>
</ul>
</li>

View File

@ -224,13 +224,13 @@ export class ProbeRecorder implements ProbeAll {
if (this.singleFrame) this.reset();
}
logExecute(address:number, SP:number) {
// TODO? record stack pushes (not all platforms use logExecute)
// record stack pushes/pops (from last instruction)
if (this.cur_sp !== SP) {
if (SP < this.cur_sp) {
this.log(ProbeFlags.SP_PUSH | (this.cur_sp - SP));
this.log(ProbeFlags.SP_PUSH | SP);
}
if (SP > this.cur_sp) {
this.log(ProbeFlags.SP_POP | (SP - this.cur_sp));
this.log(ProbeFlags.SP_POP | SP);
}
this.cur_sp = SP;
}

View File

@ -298,8 +298,8 @@ function refreshWindowList() {
return new Views.ProbeSymbolView();
});
/*
addWindowItem("#spheatmap", "Stack Probe", () => {
return new Views.RasterStackMapView();
addWindowItem("#callstack", "Call Stack", () => {
return new Views.CallStackView();
});
*/
}
@ -1125,6 +1125,8 @@ function checkRunReady() {
function openRelevantListing(state: EmuState) {
// if we clicked on another window, retain it
if (lastViewClicked != null) return;
// has to support disassembly, at least
if (!platform.disassemble) return;
// search through listings
var listings = current_project.getListings();
var bestid = "#disasm";
@ -1144,7 +1146,7 @@ function openRelevantListing(state: EmuState) {
bestid = wndid;
bestscore = pc-res.offset;
}
console.log(hex(pc,4), wndid, lstfn, bestid, bestscore);
//console.log(hex(pc,4), wndid, lstfn, bestid, bestscore);
}
}
}
@ -1568,9 +1570,6 @@ function setupDebugControls() {
uitoolbar.add('ctrl+alt+b', 'Step Backwards', 'glyphicon-step-backward', runStepBackwards).prop('id','dbg_stepback');
}
uitoolbar.newGroup();
if (platform.newCodeAnalyzer) {
uitoolbar.add(null, 'Analyze CPU Timing', 'glyphicon-time', traceTiming);
}
// add menu clicks
$(".dropdown-menu").collapse({toggle: false});
$("#item_new_file").click(_createNewFile);
@ -1613,6 +1612,9 @@ function setupDebugControls() {
if (platform.showHelp) {
uitoolbar.add('ctrl+alt+?', 'Show Help', 'glyphicon-question-sign', _lookupHelp);
}
if (platform.newCodeAnalyzer) {
uitoolbar.add(null, 'Analyze CPU Timing', 'glyphicon-time', traceTiming);
}
// setup replay slider
if (platform.setRecorder && platform.advance) {
setupReplaySlider();

View File

@ -919,6 +919,8 @@ abstract class ProbeViewBaseBase {
probe : ProbeRecorder;
tooldiv : HTMLElement;
abstract tick() : void;
addr2str(addr : number) : string {
var _addr2sym = (platform.debugSymbols && platform.debugSymbols.addr2symbol) || {};
var sym = _addr2sym[addr];
@ -951,8 +953,6 @@ abstract class ProbeViewBaseBase {
}
}
abstract tick() : void;
redraw( eventfn:(op,addr,col,row,clk,value) => void ) {
var p = this.probe;
if (!p || !p.idx) return; // if no probe, or if empty
@ -987,12 +987,15 @@ abstract class ProbeViewBaseBase {
case ProbeFlags.VRAM_WRITE: s = "VRAM Write"; break;
case ProbeFlags.INTERRUPT: s = "Interrupt"; break;
case ProbeFlags.ILLEGAL: s = "Error"; break;
//case ProbeFlags.SP_PUSH: s = "Stack Push"; break;
//case ProbeFlags.SP_POP: s = "Stack Pop"; break;
default: return "";
}
if (typeof addr == 'number') s += " " + this.addr2str(addr);
if ((op & ProbeFlags.HAS_VALUE) && typeof value == 'number') s += " = $" + hex(value,2);
return s;
}
getOpRGB(op:number) : number {
switch (op) {
case ProbeFlags.EXECUTE: return 0x018001;
@ -1015,7 +1018,9 @@ abstract class ProbeViewBase extends ProbeViewBaseBase {
canvas : HTMLCanvasElement;
ctx : CanvasRenderingContext2D;
recreateOnResize = true;
abstract drawEvent(op, addr, col, row);
createCanvas(parent:HTMLElement, width:number, height:number) {
var div = document.createElement('div');
var canvas = document.createElement('canvas');
@ -1056,8 +1061,6 @@ abstract class ProbeViewBase extends ProbeViewBaseBase {
this.clear();
this.redraw(this.drawEvent.bind(this));
}
abstract drawEvent(op, addr, col, row);
}
abstract class ProbeBitmapViewBase extends ProbeViewBase {
@ -1161,44 +1164,6 @@ export class RasterPCHeatMapView extends ProbeBitmapViewBase implements ProjectV
}
}
// TODO?
export class RasterStackMapView extends ProbeBitmapViewBase implements ProjectView {
pcstack = [];
pushed = false;
color = 0;
root = {};
drawEvent(op, addr, col, row) {
var iofs = col + row * this.canvas.width;
if (op == ProbeFlags.SP_PUSH) {
this.pcstack.push({});
this.pushed = true;
} else if (op == ProbeFlags.SP_POP) {
var entry = this.pcstack.pop();
if (entry && entry.addr !== undefined) {
var node = this.root;
for (var e of this.pcstack) {
if (node[e.addr]) {
node = node[e.addr];
} else {
node = node[e.addr] = {};
}
}
}
//if (this.pcstack.length == 1) console.log(this.root);
this.pushed = false;
} else if (op == ProbeFlags.EXECUTE) {
if (this.pushed) {
this.pcstack.pop();
this.pcstack.push({addr:addr, scol:col, srow:row});
this.pushed = false;
}
}
var data = 0xff224488 << this.pcstack.length;
this.datau32[iofs] = data;
}
}
export class ProbeLogView extends ProbeViewBaseBase {
vlist : VirtualTextScroller;
maindiv : HTMLElement;
@ -1218,6 +1183,7 @@ export class ProbeLogView extends ProbeViewBaseBase {
var xtra : string = line.info.join(", ");
s = "(" + lpad(line.row,3) + ", " + lpad(line.col,3) + ") " + rpad(line.asm||"",20) + xtra;
if (xtra.indexOf("Write ") >= 0) c = "seg_io";
// if (xtra.indexOf("Stack ") >= 0) c = "seg_code";
}
return {text:s, clas:c};
}
@ -1336,7 +1302,7 @@ class TreeNode {
children : Map<string,TreeNode>;
expanded = false;
level : number;
view : TreeViewBase;
view : ProjectView;
constructor(parent : TreeNode, name : string) {
this.parent = parent;
@ -1394,7 +1360,7 @@ class TreeNode {
text = obj+"";
// primitive types
} else if (typeof obj == 'number') {
text = obj.toString();
text = obj + "\t($" + hex(obj) + ")";
} else if (typeof obj == 'boolean') {
text = obj.toString();
} else if (typeof obj == 'string') {
@ -1470,18 +1436,23 @@ class TreeNode {
}
}
function createTreeRootNode(parent : HTMLElement, view : ProjectView) : TreeNode {
var mainnode = new TreeNode(null, null);
mainnode.view = view;
mainnode._content = parent;
var root = new TreeNode(mainnode, "/");
root.expanded = true;
root.getDiv(); // create it
root._div.style.padding = '0px';
return root; // should be cached
}
export abstract class TreeViewBase implements ProjectView {
root : TreeNode;
createDiv(parent : HTMLElement) : HTMLElement {
var mainnode = new TreeNode(null, null);
mainnode.view = this;
mainnode._content = parent;
this.root = new TreeNode(mainnode, "/");
this.root.expanded = true;
this.root.getDiv(); // create it
this.root._div.style.padding = '0px';
return this.root.getDiv(); // should be cached
this.root = createTreeRootNode(parent, this);
return this.root.getDiv();
}
refresh() {
@ -1503,6 +1474,77 @@ export class DebugBrowserView extends TreeViewBase implements ProjectView {
getRootObject() { return platform.getDebugTree(); }
}
// TODO?
interface CallGraphNode {
count : number;
calls : {[id:string] : CallGraphNode};
}
export class CallStackView extends ProbeViewBaseBase implements ProjectView {
treeroot : TreeNode;
graph : CallGraphNode;
stack : CallGraphNode[];
lastsp : number;
jsr : boolean;
createDiv(parent : HTMLElement) : HTMLElement {
this.clear();
this.treeroot = createTreeRootNode(parent, this);
return this.treeroot.getDiv();
}
refresh() {
this.tick();
}
tick() {
this.treeroot.update(this.getRootObject());
}
clear() {
this.graph = {count:0, calls:{}};
this.reset();
}
reset() {
this.stack = [this.graph]; // TODO??? should continue across frames
this.lastsp = -1;
this.jsr = false;
}
getRootObject() : Object {
this.reset();
this.redraw((op,addr,col,row,clk,value) => {
switch (op) {
case ProbeFlags.SP_PUSH:
case ProbeFlags.SP_POP:
if ((this.lastsp - addr) == 2) {
this.jsr = true;
}
if ((this.lastsp - addr) == -2 && this.stack.length > 1) {
this.stack.pop();
}
this.lastsp = addr;
break;
case ProbeFlags.EXECUTE:
if (this.jsr) {
var top = this.stack[this.stack.length-1];
var sym = this.addr2str(addr);
var child = top.calls[sym];
if (child == null) { child = top.calls[sym] = {count:0, calls:{}}; }
//this.stack.forEach((node) => node.count++);
this.stack.push(child);
child.count++;
this.jsr = false;
}
break;
}
});
return this.graph;
}
}
///

View File

@ -70,7 +70,7 @@ class X86PCPlatform implements Platform {
return "yasm";
}
getDefaultExtension(): string {
return "asm";
return ".asm";
}
getPresets() {
return PC_PRESETS;
@ -133,6 +133,9 @@ class X86PCPlatform implements Platform {
});
}
getDebugTree() {
return this.v86;
}
readAddress(addr:number) {
return this.v86.cpu.mem8[addr];
}

View File

@ -110,6 +110,11 @@ class GlkImpl {
if (this.focused) {
$(this.input).focus();
}
// change size
if (this.waitingfor == 'char')
$(this.input).addClass('transcript-input-char')
else
$(this.input).removeClass('transcript-input-char')
}
hideinput() {
$(this.input).appendTo($(this.page).parent()).hide();