1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-25 18:33:11 +00:00

more tooltips for probe views; removed Event Probe view; fixed NES probe installation

This commit is contained in:
Steven Hugg 2019-08-27 16:10:10 -04:00
parent 236c4bd0dd
commit 9d6e97749d
7 changed files with 78 additions and 135 deletions

View File

@ -50,7 +50,7 @@ export class DebugSymbols {
this.symbolmap = symbolmap;
this.addr2symbol = invertMap(symbolmap);
//// TODO: shouldn't be necc.
if (!this.addr2symbol[0x0]) this.addr2symbol[0x0] = '__START__'; // needed for ...
if (!this.addr2symbol[0x0]) this.addr2symbol[0x0] = ' '; // needed for ...
this.addr2symbol[0x10000] = '__END__'; // ... dump memory to work
}
}
@ -1089,7 +1089,6 @@ export abstract class Base6502MachinePlatform<T extends Machine> extends BaseMac
default: return isDebuggable(this.machine) && this.machine.getDebugInfo(category, state);
}
}
}
export abstract class BaseZ80MachinePlatform<T extends Machine> extends BaseMachinePlatform<T> {

View File

@ -351,6 +351,7 @@ export abstract class BasicMachine implements HasCPU, Bus, SampledAudioSource, A
connectCPUIOBus(iobus:Bus) : void {
this.cpu['connectIOBus'](this.probeIOBus(iobus));
}
// TODO: probe interrupts
}
export abstract class BasicScanlineMachine extends BasicMachine implements RasterFrameBased {

View File

@ -144,23 +144,6 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
this.probe.logClocks(cycles);
return cycles;
}
var ppu = this.nes.ppu;
var old_endScanline = ppu.endScanline.bind(ppu);
var old_startFrame = ppu.startFrame.bind(ppu);
var old_writeMem = ppu.writeMem.bind(ppu);
ppu.endScanline = () => {
old_endScanline();
this.probe.logNewScanline();
}
ppu.startFrame = () => {
old_startFrame();
this.probe.logNewFrame();
}
ppu.writeMem = (a,v) => {
old_writeMem(a,v);
this.probe.logVRAMWrite(a,v);
}
this.timer = new AnimationTimer(60, this.nextFrame.bind(this));
// set keyboard map
this.poller = setKeyboardFromMap(this.video, [], JSNES_KEYCODE_MAP, (o,key,code,flags) => {
@ -221,33 +204,55 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
var romstr = byteArrayToString(data);
this.nes.loadROM(romstr);
this.frameindex = 0;
this.installIntercepts();
}
installIntercepts() {
// intercept bus calls, unless we did it already
if (!this.nes.mmap.haveProxied) {
var oldload = this.nes.mmap.load.bind(this.nes.mmap);
var oldwrite = this.nes.mmap.write.bind(this.nes.mmap);
//var oldregLoad = this.nes.mmap.regLoad.bind(this.nes.mmap);
//var oldregWrite = this.nes.mmap.regWrite.bind(this.nes.mmap);
this.nes.mmap.load = (addr) => {
var mmap = this.nes.mmap;
if (!mmap.haveProxied) {
var oldload = mmap.load.bind(mmap);
var oldwrite = mmap.write.bind(mmap);
//var oldregLoad = mmap.regLoad.bind(mmap);
//var oldregWrite = mmap.regWrite.bind(mmap);
mmap.load = (addr) => {
var val = oldload(addr);
this.probe.logRead(addr, val);
return val;
}
this.nes.mmap.write = (addr, val) => {
mmap.write = (addr, val) => {
this.probe.logWrite(addr, val);
oldwrite(addr, val);
}
/*
this.nes.mmap.regLoad = (addr) => {
mmap.regLoad = (addr) => {
var val = oldregLoad(addr);
this.probe.logIORead(addr, val);
return val;
}
this.nes.mmap.regWrite = (addr, val) => {
mmap.regWrite = (addr, val) => {
this.probe.logIOWrite(addr, val);
oldregWrite(addr, val);
}
*/
this.nes.mmap.haveProxied = true;
mmap.haveProxied = true;
}
var ppu = this.nes.ppu;
if (!ppu.haveProxied) {
var old_endScanline = ppu.endScanline.bind(ppu);
var old_startFrame = ppu.startFrame.bind(ppu);
var old_writeMem = ppu.writeMem.bind(ppu);
ppu.endScanline = () => {
old_endScanline();
this.probe.logNewScanline();
}
ppu.startFrame = () => {
old_startFrame();
this.probe.logNewFrame();
}
ppu.writeMem = (a,v) => {
old_writeMem(a,v);
this.probe.logVRAMWrite(a,v);
}
}
}
newCodeAnalyzer() {
@ -261,6 +266,7 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
reset() {
//this.nes.cpu.reset(); // doesn't work right, crashes
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_RESET);
this.installIntercepts();
}
isRunning() {
return this.timer.isRunning();
@ -312,6 +318,7 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
this.nes.ppu.spriteMem = state.ppu.spriteMem.slice(0);
this.loadControlsState(state.ctrl);
//$.extend(this.nes, state);
this.installIntercepts();
}
saveControlsState() {
return {
@ -324,10 +331,10 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
this.nes.controllers[2].state = state.c2;
}
readAddress(addr) {
return this.nes.cpu.mem[addr] & 0xff;
return this.nes.cpu.mem[addr];
}
readVRAMAddress(addr : number) : number {
return this.nes.ppu.vramMem[addr & 0x7fff] & 0xff;
return this.nes.ppu.vramMem[addr];
}
copy6502REGvars(c) {
c.T = 0;

View File

@ -215,7 +215,6 @@ export class ProbeRecorder implements ProbeAll {
}
start() {
this.m.connectProbe(this);
this.reset();
}
stop() {
this.m.connectProbe(null);

View File

@ -250,14 +250,11 @@ function refreshWindowList() {
});
}
if (platform.startProbing) {
addWindowItem("#eventprobe", "Event Probe", () => {
return new Views.EventProbeView();
});
addWindowItem("#memheatmap", "Memory Heatmap", () => {
addWindowItem("#memheatmap", "Memory Probe", () => {
return new Views.AddressHeatMapView();
});
// TODO: only if raster
addWindowItem("#crtheatmap", "Screen Heatmap", () => {
addWindowItem("#crtheatmap", "CRT Probe", () => {
return new Views.RasterPCHeatMapView();
});
}

View File

@ -1,5 +1,4 @@
import $ = require("jquery");
//import CodeMirror = require("codemirror");
import { SourceFile, WorkerError, Segment, FileData } from "./workertypes";
import { Platform, EmuState, ProfilerOutput, lookupSymbol, BaseDebugPlatform } from "./baseplatform";
@ -536,6 +535,7 @@ export class MemoryView implements ProjectView {
maindiv : HTMLElement;
static IGNORE_SYMS = {s__INITIALIZER:true, /* s__GSINIT:true, */ _color_prom:true};
recreateOnResize = true;
totalRows = 0x1400;
createDiv(parent : HTMLElement) {
var div = document.createElement('div');
@ -550,7 +550,7 @@ export class MemoryView implements ProjectView {
w: $(workspace).width(),
h: $(workspace).height(),
itemHeight: getVisibleEditorLineHeight(),
totalRows: 0x1400,
totalRows: this.totalRows,
generatorFn: (row : number) => {
var s = this.getMemoryLineAt(row);
var linediv = document.createElement("div");
@ -695,6 +695,7 @@ export class MemoryView implements ProjectView {
}
export class VRAMMemoryView extends MemoryView {
totalRows = 0x800;
readAddress(n : number) {
return platform.readVRAMAddress(n);
}
@ -959,6 +960,15 @@ abstract class ProbeViewBase {
return this.maindiv = div;
}
addr2str(addr : number) : string {
var _addr2sym = (platform.debugSymbols && platform.debugSymbols.addr2symbol) || {};
var sym = _addr2sym[addr];
if (typeof sym === 'string')
return '$' + hex(addr) + ' (' + sym + ')';
else
return '$' + hex(addr);
}
initCanvas() {
}
@ -982,6 +992,7 @@ abstract class ProbeViewBase {
setVisible(showing : boolean) : void {
if (showing) {
this.probe = platform.startProbing();
this.tick();
} else {
platform.stopProbing();
this.probe = null;
@ -989,14 +1000,6 @@ abstract class ProbeViewBase {
}
clear() {
var ctx = this.ctx;
//ctx.globalCompositeOperation = 'source-over';
//ctx.globalAlpha = 1.0;
//ctx.fillStyle = '#000000';
//ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'lighter';
}
redraw( eventfn:(op,addr,col,row) => void ) {
@ -1020,23 +1023,8 @@ abstract class ProbeViewBase {
}
tick() {
var ctx = this.ctx;
this.clear();
this.redraw(this.drawEvent.bind(this));
if (this.probe && !this.probe.singleFrame) this.probe.reset();
}
setContextForOp(op) {
var ctx = this.ctx;
switch (op) {
//case ProbeFlags.EXECUTE: ctx.fillStyle = "green"; break;
//case ProbeFlags.MEM_READ: ctx.fillStyle = "#7f7f7f"; break;
case ProbeFlags.MEM_WRITE: ctx.fillStyle = "red"; break;
case ProbeFlags.IO_READ: ctx.fillStyle = "green"; break;
case ProbeFlags.IO_WRITE: ctx.fillStyle = "magenta"; break;
case ProbeFlags.INTERRUPT: ctx.fillStyle = "yellow"; break;
default: ctx.fillStyle = "blue"; break;
}
}
abstract drawEvent(op, addr, col, row);
@ -1067,13 +1055,13 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase {
y = y|0;
var s = "";
this.redraw( (op,addr,col,row) => {
if (col == x && row == y) {
if (y == row && x == col) {
s += "\n" + this.opToString(op, addr);
}
} );
return '(' + x + ',' + y + ')' + s;
}
opToString(op:number, addr:number) {
return 'X: ' + x + ' Y: ' + y + ' ' + s;
}
opToString(op:number, addr?:number) {
var s = "";
switch (op) {
case ProbeFlags.EXECUTE: s = "Exec"; break;
@ -1086,7 +1074,7 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase {
case ProbeFlags.INTERRUPT: s = "Interrupt"; break;
default: s = ""; break;
}
return s + " $" + hex(addr);
return typeof addr == 'number' ? s + " " + this.addr2str(addr) : s;
}
refresh() {
@ -1107,9 +1095,9 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase {
case ProbeFlags.MEM_WRITE: return 0x010180;
case ProbeFlags.IO_READ: return 0x018080;
case ProbeFlags.IO_WRITE: return 0xc00180;
case ProbeFlags.VRAM_READ: return 0x018080;
case ProbeFlags.VRAM_WRITE: return 0xc00180;
case ProbeFlags.INTERRUPT: return 0xc0c001;
case ProbeFlags.VRAM_READ: return 0x808001;
case ProbeFlags.VRAM_WRITE: return 0x4080c0;
case ProbeFlags.INTERRUPT: return 0xcfcfcf;
default: return 0;
}
}
@ -1141,9 +1129,22 @@ export class AddressHeatMapView extends ProbeBitmapViewBase implements ProjectVi
}
getTooltipText(x:number, y:number) : string {
var addr = (x & 0xff) + (y << 8);
return '$'+hex(addr);
}
var a = (x & 0xff) + (y << 8);
var s = this.addr2str(a);
var pc = -1;
var already = {};
this.redraw( (op,addr,col,row) => {
if (op == ProbeFlags.EXECUTE) {
pc = addr;
}
var key = op|pc;
if (addr == a && !already[key]) {
s += "\nPC " + this.addr2str(pc) + " " + this.opToString(op);
already[key] = 1;
}
} );
return s;
}
}
/*
@ -1175,68 +1176,6 @@ export class RasterPCHeatMapView extends ProbeBitmapViewBase implements ProjectV
}
export class EventProbeView extends ProbeViewBase implements ProjectView {
symcache : Map<number,symbol> = new Map();
xmax : number = 1;
ymax : number = 1;
lastsym : string;
xx : number;
yy : number;
createDiv(parent : HTMLElement) {
return this.createCanvas( parent, $(parent).width(), $(parent).height() );
}
drawEvent(op, addr, col, row) {
var ctx = this.ctx;
this.xmax = Math.max(this.xmax, col);
this.ymax = Math.max(this.ymax, row);
var xscale = this.canvas.width / this.xmax; // TODO: pixels
var yscale = (this.canvas.height - 12) / this.ymax; // TODO: lines
var x = col * xscale;
var y = row * yscale;
x = this.xx;
y = this.yy = Math.max(this.yy, y);
var sym = this.getSymbol(addr);
if (!sym && op == ProbeFlags.IO_WRITE) sym = hex(addr,4);
//TODO if (!sym && op == ProbeFlags.IO_READ) sym = hex(addr,4);
if (sym && sym != this.lastsym) {
this.setContextForOp(op);
ctx.textAlign = 'left'; //ctx.textAlign = (x < this.canvas.width/2) ? 'left' : 'right';
ctx.textBaseline = 'top'; //ctx.textBaseline = (y < this.canvas.height/2) ? 'top' : 'bottom';
var mt = ctx.measureText(sym);
if (x + mt.width > this.canvas.width) {
x = 0;
y += 12;
}
ctx.fillText(sym, x, y);
this.xx = x + mt.width + 10;
this.yy = y;
this.lastsym = sym;
}
}
getSymbol(addr:number) : string {
var sym = this.symcache[addr];
if (!sym) {
sym = lookupSymbol(platform, addr, false);
this.symcache[addr] = sym;
}
return sym;
}
tick() {
this.xx = this.yy = 0;
this.lastsym = '';
super.tick();
}
refresh() {
this.tick();
this.symcache.clear();
}
}
///
export class AssetEditorView implements ProjectView, pixed.EditorContext {

View File

@ -974,6 +974,7 @@ function linkLD65(step:BuildStep) {
}
// build segment map
var seg_re = /^__(\w+)_SIZE__$/;
// TODO: move to Platform class
var segments = [];
segments.push({name:'CPU Stack',start:0x100,size:0x100,type:'ram'});
segments.push({name:'CPU Vectors',start:0xfffa,size:0x6,type:'rom'});