mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-16 17:30:27 +00:00
call stack view: swapped push/pop, check for real jump, made top level list flat; header for symbol probe
This commit is contained in:
parent
b76c18e013
commit
52d6f69d09
@ -999,8 +999,8 @@ abstract class ProbeViewBaseBase {
|
|||||||
case ProbeFlags.VRAM_WRITE: s = "VRAM Write"; break;
|
case ProbeFlags.VRAM_WRITE: s = "VRAM Write"; break;
|
||||||
case ProbeFlags.INTERRUPT: s = "Interrupt"; break;
|
case ProbeFlags.INTERRUPT: s = "Interrupt"; break;
|
||||||
case ProbeFlags.ILLEGAL: s = "Error"; break;
|
case ProbeFlags.ILLEGAL: s = "Error"; break;
|
||||||
//case ProbeFlags.SP_PUSH: s = "Stack Push"; break;
|
case ProbeFlags.SP_PUSH: s = "Stack Dec"; break;
|
||||||
//case ProbeFlags.SP_POP: s = "Stack Pop"; break;
|
case ProbeFlags.SP_POP: s = "Stack Inc"; break;
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
if (typeof addr == 'number') s += " " + this.addr2str(addr);
|
if (typeof addr == 'number') s += " " + this.addr2str(addr);
|
||||||
@ -1248,12 +1248,16 @@ export class ProbeSymbolView extends ProbeViewBaseBase {
|
|||||||
this.keys = ['no symbols defined'];
|
this.keys = ['no symbols defined'];
|
||||||
}
|
}
|
||||||
this.vlist = new VirtualTextScroller(parent);
|
this.vlist = new VirtualTextScroller(parent);
|
||||||
this.vlist.create(parent, this.keys.length, this.getMemoryLineAt.bind(this));
|
this.vlist.create(parent, this.keys.length + 1, this.getMemoryLineAt.bind(this));
|
||||||
return this.vlist.maindiv;
|
return this.vlist.maindiv;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMemoryLineAt(row : number) : VirtualTextLine {
|
getMemoryLineAt(row : number) : VirtualTextLine {
|
||||||
var sym = this.keys[row];
|
// header line
|
||||||
|
if (row == 0) {
|
||||||
|
return {text: lpad("Symbol",35)+lpad("Reads",8)+lpad("Writes",8)};
|
||||||
|
}
|
||||||
|
var sym = this.keys[row-1];
|
||||||
var line = this.dumplines && this.dumplines[sym];
|
var line = this.dumplines && this.dumplines[sym];
|
||||||
function getop(op) {
|
function getop(op) {
|
||||||
var n = line[op] | 0;
|
var n = line[op] | 0;
|
||||||
@ -1510,7 +1514,9 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView {
|
|||||||
graph : CallGraphNode;
|
graph : CallGraphNode;
|
||||||
stack : CallGraphNode[];
|
stack : CallGraphNode[];
|
||||||
lastsp : number;
|
lastsp : number;
|
||||||
|
lastpc : number;
|
||||||
jsr : boolean;
|
jsr : boolean;
|
||||||
|
rts : boolean;
|
||||||
cumulativeData = true;
|
cumulativeData = true;
|
||||||
|
|
||||||
createDiv(parent : HTMLElement) : HTMLElement {
|
createDiv(parent : HTMLElement) : HTMLElement {
|
||||||
@ -1536,54 +1542,68 @@ export class CallStackView extends ProbeViewBaseBase implements ProjectView {
|
|||||||
reset() {
|
reset() {
|
||||||
this.stack = [];
|
this.stack = [];
|
||||||
this.lastsp = -1;
|
this.lastsp = -1;
|
||||||
|
this.lastpc = 0;
|
||||||
this.jsr = false;
|
this.jsr = false;
|
||||||
|
this.rts = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoot(pc : number, sp : number) {
|
||||||
|
if (this.stack.length == 0) {
|
||||||
|
this.graph = {count:0, $$SP:sp, calls:{}};
|
||||||
|
this.stack.unshift(this.graph);
|
||||||
|
} else if (sp > this.stack[0].$$SP) {
|
||||||
|
let calls = {};
|
||||||
|
calls[this.addr2str(pc)] = this.stack[0];
|
||||||
|
this.graph = {count:0, $$SP:sp, calls:calls};
|
||||||
|
this.stack.unshift(this.graph);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getRootObject() : Object {
|
getRootObject() : Object {
|
||||||
// TODO: we don't capture every frame, so if we don't start @ the top frame we may have problems
|
// TODO: we don't capture every frame, so if we don't start @ the top frame we may have problems
|
||||||
this.redraw((op,addr,col,row,clk,value) => {
|
this.redraw((op,addr,col,row,clk,value) => {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case ProbeFlags.SP_PUSH:
|
|
||||||
// need a new root?
|
|
||||||
if (this.stack.length == 0) {
|
|
||||||
this.graph = {count:0, $$SP:addr, calls:{}};
|
|
||||||
this.stack.unshift(this.graph);
|
|
||||||
} else if (addr > this.stack[0].$$SP) {
|
|
||||||
let calls = {};
|
|
||||||
if (this.stack[0].$$PC != null) calls[this.stack[0].$$PC] = this.stack[0];
|
|
||||||
this.graph = {count:0, $$SP:addr, calls:calls};
|
|
||||||
this.stack.unshift(this.graph);
|
|
||||||
}
|
|
||||||
case ProbeFlags.SP_POP:
|
case ProbeFlags.SP_POP:
|
||||||
|
this.newRoot(this.lastpc, this.lastsp);
|
||||||
|
case ProbeFlags.SP_PUSH:
|
||||||
if (this.stack.length) {
|
if (this.stack.length) {
|
||||||
let top = this.stack[this.stack.length-1];
|
let top = this.stack[this.stack.length-1];
|
||||||
if ((this.lastsp - addr) == 2 && addr < top.$$SP) { // TODO: look for opcode?
|
var delta = this.lastsp - addr;
|
||||||
|
if ((delta == 2 || delta == 3) && addr < top.$$SP) { // TODO: look for opcode?
|
||||||
this.jsr = true;
|
this.jsr = true;
|
||||||
}
|
}
|
||||||
if ((this.lastsp - addr) == -2 && this.stack.length > 1 && addr > top.$$SP) {
|
if ((delta == -2 || delta == -3) && this.stack.length > 1 && addr > top.$$SP) {
|
||||||
this.stack.pop().endLine = row;
|
this.rts = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.lastsp = addr;
|
this.lastsp = addr;
|
||||||
break;
|
break;
|
||||||
case ProbeFlags.EXECUTE:
|
case ProbeFlags.EXECUTE:
|
||||||
if (this.jsr && this.stack.length) {
|
// TODO: better check for CALL/RET opcodes
|
||||||
let top = this.stack[this.stack.length-1];
|
if (Math.abs(addr - this.lastpc) >= 4) { // make sure we're jumping a distance (TODO)
|
||||||
let sym = this.addr2str(addr);
|
if (this.jsr && this.stack.length) {
|
||||||
let child = top.calls[sym];
|
let top = this.stack[this.stack.length-1];
|
||||||
if (child == null) { child = top.calls[sym] = {count:0, $$PC:addr, $$SP:this.lastsp, calls:{}}; }
|
let sym = this.addr2str(addr);
|
||||||
else if (child.$$PC == null) child.$$PC = addr;
|
let child = top.calls[sym];
|
||||||
//this.stack.forEach((node) => node.count++);
|
if (child == null) { child = top.calls[sym] = {count:0, $$PC:addr, $$SP:this.lastsp, calls:{}}; }
|
||||||
this.stack.push(child);
|
else if (child.$$PC == null) child.$$PC = addr;
|
||||||
child.count++;
|
//this.stack.forEach((node) => node.count++);
|
||||||
child.startLine = row;
|
this.stack.push(child);
|
||||||
|
child.count++;
|
||||||
|
child.startLine = row;
|
||||||
|
}
|
||||||
this.jsr = false;
|
this.jsr = false;
|
||||||
|
if (this.rts && this.stack.length) {
|
||||||
|
this.stack.pop().endLine = row;
|
||||||
|
}
|
||||||
|
this.rts = false;
|
||||||
}
|
}
|
||||||
|
this.lastpc = addr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (this.graph) this.graph['$$Stack'] = this.stack;
|
if (this.graph) this.graph['$$Stack'] = this.stack;
|
||||||
return this.graph;
|
return TREE_SHOW_DOLLAR_IDENTS ? this.graph : this.graph && this.graph.calls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +203,11 @@ async function testPlatform(platid, romname, maxframes, callback) {
|
|||||||
}
|
}
|
||||||
assert.equal(proberec.fclk, proberec.countClocks());
|
assert.equal(proberec.fclk, proberec.countClocks());
|
||||||
}
|
}
|
||||||
|
// debug tree
|
||||||
|
if (platform.getDebugTree) {
|
||||||
|
var dbgtree = platform.getDebugTree();
|
||||||
|
JSON.stringify(dbgtree);
|
||||||
|
}
|
||||||
// misc
|
// misc
|
||||||
assert.ok(platform.getDefaultExtension().startsWith('.'));
|
assert.ok(platform.getDefaultExtension().startsWith('.'));
|
||||||
if (platform.getROMExtension) assert.ok(platform.getROMExtension().startsWith("."));
|
if (platform.getROMExtension) assert.ok(platform.getROMExtension().startsWith("."));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user