diff --git a/src/devices.ts b/src/devices.ts index 825834a2..83d017ae 100644 --- a/src/devices.ts +++ b/src/devices.ts @@ -113,68 +113,6 @@ export function xorshift32(x : number) : number { return x; } -/// HOOKS - -export interface Hook { - //target : T; - unhook(); -} - -export class BusHook implements Hook { - //target : Bus; - constructor(bus : Bus, profiler : ProbeBus) { - //this.target = bus; - var oldread = bus.read.bind(bus); - var oldwrite = bus.write.bind(bus); - bus.read = (a:number):number => { - var val = oldread(a); - profiler.logRead(a,val); - return val; - } - bus.write = (a:number,v:number) => { - profiler.logWrite(a,v); - oldwrite(a,v); - } - this.unhook = () => { - bus.read = oldread; - bus.write = oldwrite; - } - } - unhook : () => void; -} - -export class CPUClockHook implements Hook { - //target : CPU&ClockBased; - constructor(cpu : CPU&ClockBased, profiler : ProbeCPU) { - //this.target = cpu; - var oldclock = cpu.advanceClock.bind(cpu); - cpu.advanceClock = () => { - profiler.logExecute(cpu.getPC()); - return oldclock(); - } - this.unhook = () => { - cpu.advanceClock = oldclock; - } - } - unhook : () => void; -} - -export class CPUInsnHook implements Hook { - //target : CPU&InstructionBased; - constructor(cpu : CPU&InstructionBased, profiler : ProbeCPU) { - //this.target = cpu; - var oldinsn = cpu.advanceInsn.bind(cpu); - cpu.advanceInsn = () => { - profiler.logExecute(cpu.getPC()); - return oldinsn(); - } - this.unhook = () => { - cpu.advanceInsn = oldinsn; - } - } - unhook : () => void; -} - /// PROFILER export interface ProbeTime { @@ -184,7 +122,7 @@ export interface ProbeTime { } export interface ProbeCPU { - logExecute(address:number); + logExecute(address:number, SP:number); logInterrupt(type:number); logIllegal(address:number); } @@ -288,7 +226,7 @@ export abstract class BasicHeadlessMachine implements HasCPU, Bus, AcceptsROM, P advanceCPU() { var c = this.cpu as any; var n = 1; - if (this.cpu.isStable()) { this.probe.logExecute(this.cpu.getPC()); } + if (this.cpu.isStable()) { this.probe.logExecute(this.cpu.getPC(), this.cpu.getSP()); } if (c.advanceClock) { c.advanceClock(); } else if (c.advanceInsn) { n = c.advanceInsn(1); } this.probe.logClocks(n); diff --git a/src/platform/nes.ts b/src/platform/nes.ts index a2cb3690..917814d5 100644 --- a/src/platform/nes.ts +++ b/src/platform/nes.ts @@ -138,7 +138,7 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable { // insert debug hook this.nes.cpu._emulate = this.nes.cpu.emulate; this.nes.cpu.emulate = () => { - this.probe.logExecute(this.nes.cpu.REG_PC-1); + this.probe.logExecute(this.nes.cpu.REG_PC-1, this.nes.cpu.REG_SP); var cycles = this.nes.cpu._emulate(); this.evalDebugCondition(); this.probe.logClocks(cycles); diff --git a/src/recorder.ts b/src/recorder.ts index 2f333cf9..9b04dcff 100644 --- a/src/recorder.ts +++ b/src/recorder.ts @@ -130,6 +130,8 @@ export enum ProbeFlags { VRAM_WRITE = 0x07000000, INTERRUPT = 0x08000000, ILLEGAL = 0x09000000, + SP_PUSH = 0x0a000000, + SP_POP = 0x0b000000, SCANLINE = 0x7e000000, FRAME = 0x7f000000, } @@ -145,6 +147,7 @@ export class ProbeRecorder implements ProbeAll { idx = 0; fclk = 0; sl = 0; + cur_sp = -1; m : Probeable; singleFrame : boolean = true; @@ -161,7 +164,7 @@ export class ProbeRecorder implements ProbeAll { this.idx = 0; } log(a:number) { - // TODO: coalesce READ and EXECUTE + // TODO: coalesce READ and EXECUTE and PUSH/POP if (this.idx >= this.buf.length) return; this.buf[this.idx++] = a; } @@ -198,7 +201,16 @@ export class ProbeRecorder implements ProbeAll { this.sl = 0; if (this.singleFrame) this.reset(); } - logExecute(address:number) { + logExecute(address:number, SP:number) { + if (this.cur_sp !== SP) { + if (SP < this.cur_sp) { + this.log(ProbeFlags.SP_PUSH | (this.cur_sp - SP)); + } + if (SP > this.cur_sp) { + this.log(ProbeFlags.SP_POP | (SP - this.cur_sp)); + } + this.cur_sp = SP; + } this.log(address | ProbeFlags.EXECUTE); } logInterrupt(type:number) { diff --git a/src/ui.ts b/src/ui.ts index 121e0d16..4d910494 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -276,6 +276,9 @@ function refreshWindowList() { addWindowItem("#crtheatmap", "CRT Probe", () => { return new Views.RasterPCHeatMapView(); }); + addWindowItem("#spheatmap", "Stack Probe", () => { + return new Views.RasterStackMapView(); + }); } addWindowItem('#asseteditor', 'Asset Editor', () => { return new Views.AssetEditorView(); diff --git a/src/views.ts b/src/views.ts index eea15802..55d9e941 100644 --- a/src/views.ts +++ b/src/views.ts @@ -1055,7 +1055,6 @@ export class RasterHeatMapView extends ProbeBitmapViewBase implements ProjectVie data = data | rgb | 0xff000000; this.datau32[iofs] = data; } - } */ @@ -1069,7 +1068,43 @@ export class RasterPCHeatMapView extends ProbeBitmapViewBase implements ProjectV data = data | rgb | 0xff000000; this.datau32[iofs] = data; } - +} + +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; + } } ///