1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-12 18:42:14 +00:00

probe shows values; click gutter to run to cursor

This commit is contained in:
Steven Hugg 2020-01-04 17:11:14 -06:00
parent 0e91abe6bb
commit 313dc2f863
4 changed files with 73 additions and 46 deletions

View File

@ -4,6 +4,9 @@
.gutter-offset { .gutter-offset {
width: 3em; width: 3em;
} }
.CodeMirror-gutter-elt:hover {
text-decoration: underline;
}
.gutter-bytes { .gutter-bytes {
width: 6em; width: 6em;
} }

View File

@ -120,20 +120,20 @@ export class StateRecorderImpl implements EmuRecorder {
import { Probeable, ProbeAll } from "./devices"; import { Probeable, ProbeAll } from "./devices";
export enum ProbeFlags { export enum ProbeFlags {
CLOCKS = 0x00000000, CLOCKS = 0x00000000,
EXECUTE = 0x01000000, EXECUTE = 0x01000000,
MEM_READ = 0x02000000, MEM_READ = 0x12000000,
MEM_WRITE = 0x03000000, MEM_WRITE = 0x13000000,
IO_READ = 0x04000000, IO_READ = 0x14000000,
IO_WRITE = 0x05000000, IO_WRITE = 0x15000000,
VRAM_READ = 0x06000000, VRAM_READ = 0x16000000,
VRAM_WRITE = 0x07000000, VRAM_WRITE= 0x17000000,
INTERRUPT = 0x08000000, INTERRUPT = 0x08000000,
ILLEGAL = 0x09000000, ILLEGAL = 0x09000000,
SP_PUSH = 0x0a000000, SP_PUSH = 0x0a000000,
SP_POP = 0x0b000000, SP_POP = 0x0b000000,
SCANLINE = 0x7e000000, SCANLINE = 0x7e000000,
FRAME = 0x7f000000, FRAME = 0x7f000000,
} }
class ProbeFrame { class ProbeFrame {
@ -216,23 +216,26 @@ export class ProbeRecorder implements ProbeAll {
logInterrupt(type:number) { logInterrupt(type:number) {
this.log(type | ProbeFlags.INTERRUPT); this.log(type | ProbeFlags.INTERRUPT);
} }
logValue(address:number, value:number, op:number) {
this.log((address & 0xffff) | ((value & 0xff)<<16) | op);
}
logRead(address:number, value:number) { logRead(address:number, value:number) {
this.log(address | ProbeFlags.MEM_READ); this.logValue(address, value, ProbeFlags.MEM_READ);
} }
logWrite(address:number, value:number) { logWrite(address:number, value:number) {
this.log(address | ProbeFlags.MEM_WRITE); this.logValue(address, value, ProbeFlags.MEM_WRITE);
} }
logIORead(address:number, value:number) { logIORead(address:number, value:number) {
this.log(address | ProbeFlags.IO_READ); this.logValue(address, value, ProbeFlags.IO_READ);
} }
logIOWrite(address:number, value:number) { logIOWrite(address:number, value:number) {
this.log(address | ProbeFlags.IO_WRITE); this.logValue(address, value, ProbeFlags.IO_WRITE);
} }
logVRAMRead(address:number, value:number) { logVRAMRead(address:number, value:number) {
this.log(address | ProbeFlags.VRAM_READ); this.logValue(address, value, ProbeFlags.VRAM_READ);
} }
logVRAMWrite(address:number, value:number) { logVRAMWrite(address:number, value:number) {
this.log(address | ProbeFlags.VRAM_WRITE); this.logValue(address, value, ProbeFlags.VRAM_WRITE);
} }
logIllegal(address:number) { logIllegal(address:number) {
this.log(address | ProbeFlags.ILLEGAL); this.log(address | ProbeFlags.ILLEGAL);

View File

@ -1211,22 +1211,23 @@ function getEditorPC() : number {
return wnd && wnd.getCursorPC && wnd.getCursorPC(); return wnd && wnd.getCursorPC && wnd.getCursorPC();
} }
function runToCursor() { export function runToPC(pc: number) {
if (!checkRunReady()) return; if (!checkRunReady() || !(pc >= 0)) return;
setupBreakpoint("toline"); setupBreakpoint("toline");
var pc = getEditorPC(); console.log("Run to", pc.toString(16));
if (pc >= 0) { if (platform.runToPC) {
console.log("Run to", pc.toString(16)); platform.runToPC(pc);
if (platform.runToPC) { } else {
platform.runToPC(pc); platform.runEval((c) => {
} else { return c.PC == pc;
platform.runEval((c) => { });
return c.PC == pc;
});
}
} }
} }
function runToCursor() {
runToPC(getEditorPC());
}
function runUntilReturn() { function runUntilReturn() {
if (!checkRunReady()) return; if (!checkRunReady()) return;
setupBreakpoint("stepout"); setupBreakpoint("stepout");

View File

@ -1,10 +1,10 @@
//import CodeMirror = require("codemirror"); //import CodeMirror = require("codemirror");
import { SourceFile, WorkerError, Segment, FileData } from "../common/workertypes"; import { SourceFile, WorkerError, Segment, FileData } from "../common/workertypes";
import { Platform, EmuState, lookupSymbol, BaseDebugPlatform, BaseZ80MachinePlatform, BaseZ80Platform } from "../common/baseplatform"; import { Platform, EmuState, lookupSymbol, BaseDebugPlatform, BaseZ80MachinePlatform, BaseZ80Platform, CpuState } from "../common/baseplatform";
import { hex, lpad, rpad, safeident, rgb2bgr } from "../common/util"; import { hex, lpad, rpad, safeident, rgb2bgr } from "../common/util";
import { CodeAnalyzer } from "../common/analysis"; import { CodeAnalyzer } from "../common/analysis";
import { platform, platform_id, compparams, current_project, lastDebugState, projectWindows } from "./ui"; import { platform, platform_id, compparams, current_project, lastDebugState, projectWindows, runToPC } from "./ui";
import { ProbeRecorder, ProbeFlags } from "../common/recorder"; import { ProbeRecorder, ProbeFlags } from "../common/recorder";
import { getMousePos } from "../common/emu"; import { getMousePos } from "../common/emu";
import * as pixed from "./pixeleditor"; import * as pixed from "./pixeleditor";
@ -108,12 +108,14 @@ export class SourceEditor implements ProjectView {
setupEditor() { setupEditor() {
var timer; var timer;
// update file in project (and recompile) when edits made
this.editor.on('changes', (ed, changeobj) => { this.editor.on('changes', (ed, changeobj) => {
clearTimeout(timer); clearTimeout(timer);
timer = setTimeout( () => { timer = setTimeout( () => {
current_project.updateFile(this.path, this.editor.getValue()); current_project.updateFile(this.path, this.editor.getValue());
}, 300); }, 300);
}); });
// inspect symbol when it's highlighted (double-click)
this.editor.on('cursorActivity', (ed) => { this.editor.on('cursorActivity', (ed) => {
var start = this.editor.getCursor(true); var start = this.editor.getCursor(true);
var end = this.editor.getCursor(false); var end = this.editor.getCursor(false);
@ -124,10 +126,15 @@ export class SourceEditor implements ProjectView {
this.inspect(null); this.inspect(null);
} }
}); });
//scrollProfileView(editor); // gutter clicked
this.editor.on("gutterClick", (cm, n) => {
this.toggleBreakpoint(n);
});
// set editor mode for highlighting, etc
this.editor.setOption("mode", this.mode); this.editor.setOption("mode", this.mode);
} }
inspect(ident : string) : void { inspect(ident : string) : void {
var result; var result;
if (platform.inspect) { if (platform.inspect) {
@ -333,7 +340,6 @@ export class SourceEditor implements ProjectView {
var line = this.getActiveLine(); var line = this.getActiveLine();
if (line >= 0) { if (line >= 0) {
this.setCurrentLine(line, moveCursor); this.setCurrentLine(line, moveCursor);
// TODO: switch to disasm?
} }
} }
@ -353,6 +359,10 @@ export class SourceEditor implements ProjectView {
this.refreshListing(); this.refreshListing();
this.refreshDebugState(moveCursor); this.refreshDebugState(moveCursor);
} }
tick() {
this.refreshDebugState(false);
}
getLine(line : number) { getLine(line : number) {
return this.editor.getLine(line-1); return this.editor.getLine(line-1);
@ -375,6 +385,13 @@ export class SourceEditor implements ProjectView {
undoStep() { undoStep() {
this.editor.execCommand('undo'); this.editor.execCommand('undo');
} }
toggleBreakpoint(lineno: number) {
if (this.sourcefile != null) {
var targetPC = this.sourcefile.line2offset[lineno+1];
runToPC(targetPC);
}
}
} }
/// ///
@ -859,7 +876,7 @@ abstract class ProbeViewBaseBase {
abstract tick() : void; abstract tick() : void;
redraw( eventfn:(op,addr,col,row,clk) => void ) { redraw( eventfn:(op,addr,col,row,clk,value) => void ) {
var p = this.probe; var p = this.probe;
if (!p || !p.idx) return; // if no probe, or if empty if (!p || !p.idx) return; // if no probe, or if empty
var row=0; var row=0;
@ -867,20 +884,21 @@ abstract class ProbeViewBaseBase {
var clk=0; var clk=0;
for (var i=0; i<p.idx; i++) { for (var i=0; i<p.idx; i++) {
var word = p.buf[i]; var word = p.buf[i];
var addr = word & 0xffffff; var addr = word & 0xffff;
var value = (word >> 16) & 0xff;
var op = word & 0xff000000; var op = word & 0xff000000;
switch (op) { switch (op) {
case ProbeFlags.SCANLINE: row++; col=0; break; case ProbeFlags.SCANLINE: row++; col=0; break;
case ProbeFlags.FRAME: row=0; col=0; break; case ProbeFlags.FRAME: row=0; col=0; break;
case ProbeFlags.CLOCKS: col += addr; clk += addr; break; case ProbeFlags.CLOCKS: col += addr; clk += addr; break;
default: default:
eventfn(op, addr, col, row, clk); eventfn(op, addr, col, row, clk, value);
break; break;
} }
} }
} }
opToString(op:number, addr?:number) { opToString(op:number, addr?:number, value?:number) {
var s = ""; var s = "";
switch (op) { switch (op) {
case ProbeFlags.EXECUTE: s = "Exec"; break; case ProbeFlags.EXECUTE: s = "Exec"; break;
@ -894,7 +912,9 @@ abstract class ProbeViewBaseBase {
case ProbeFlags.ILLEGAL: s = "Error"; break; case ProbeFlags.ILLEGAL: s = "Error"; break;
default: return ""; default: return "";
} }
return typeof addr == 'number' ? s + " " + this.addr2str(addr) : s; if (typeof addr == 'number') s += " " + this.addr2str(addr);
if (typeof value == 'number') s += " = $" + hex(value,2);
return s;
} }
getOpRGB(op:number) : number { getOpRGB(op:number) : number {
switch (op) { switch (op) {
@ -987,9 +1007,9 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase {
x = x|0; x = x|0;
y = y|0; y = y|0;
var s = ""; var s = "";
this.redraw( (op,addr,col,row) => { this.redraw( (op,addr,col,row,clk,value) => {
if (y == row && x == col) { if (y == row && x == col) {
s += "\n" + this.opToString(op, addr); s += "\n" + this.opToString(op, addr, value);
} }
} ); } );
return 'X: ' + x + ' Y: ' + y + ' ' + s; return 'X: ' + x + ' Y: ' + y + ' ' + s;
@ -1038,13 +1058,13 @@ export class AddressHeatMapView extends ProbeBitmapViewBase implements ProjectVi
var s = this.addr2str(a); var s = this.addr2str(a);
var pc = -1; var pc = -1;
var already = {}; var already = {};
this.redraw( (op,addr,col,row) => { this.redraw( (op,addr,col,row,clk,value) => {
if (op == ProbeFlags.EXECUTE) { if (op == ProbeFlags.EXECUTE) {
pc = addr; pc = addr;
} }
var key = op|pc; var key = op|pc;
if (addr == a && !already[key]) { if (addr == a && !already[key]) {
s += "\nPC " + this.addr2str(pc) + " " + this.opToString(op); s += "\nPC " + this.addr2str(pc) + " " + this.opToString(op, null, value);
already[key] = 1; already[key] = 1;
} }
} ); } );
@ -1134,7 +1154,7 @@ export class ProbeLogView extends ProbeViewBaseBase {
getMemoryLineAt(row : number) : string { getMemoryLineAt(row : number) : string {
var line = this.dumplines && this.dumplines[row]; var line = this.dumplines && this.dumplines[row];
if (line != null) { if (line != null) {
var xtra = line.info.join(" "); var xtra = line.info.join(", ");
return "(" + lpad(line.row,3) + ", " + lpad(line.col,3) + ") " + rpad(line.asm||"",20) + xtra; return "(" + lpad(line.row,3) + ", " + lpad(line.col,3) + ") " + rpad(line.asm||"",20) + xtra;
} else return ""; } else return "";
} }
@ -1145,7 +1165,7 @@ export class ProbeLogView extends ProbeViewBaseBase {
const isz80 = platform instanceof BaseZ80MachinePlatform || platform instanceof BaseZ80Platform; // TODO? const isz80 = platform instanceof BaseZ80MachinePlatform || platform instanceof BaseZ80Platform; // TODO?
// cache each line in frame // cache each line in frame
this.dumplines = {}; this.dumplines = {};
this.redraw((op,addr,col,row,clk) => { this.redraw((op,addr,col,row,clk,value) => {
if (isz80) clk >>= 2; if (isz80) clk >>= 2;
var line = this.dumplines[clk]; var line = this.dumplines[clk];
if (line == null) { if (line == null) {
@ -1160,7 +1180,7 @@ export class ProbeLogView extends ProbeViewBaseBase {
} }
break; break;
default: default:
var xtra = this.opToString(op, addr); var xtra = this.opToString(op, addr, value);
if (xtra != "") line.info.push(xtra); if (xtra != "") line.info.push(xtra);
break; break;
} }