diff --git a/css/ui.css b/css/ui.css index d8d1ddd7..9565a069 100644 --- a/css/ui.css +++ b/css/ui.css @@ -4,6 +4,9 @@ .gutter-offset { width: 3em; } +.CodeMirror-gutter-elt:hover { + text-decoration: underline; +} .gutter-bytes { width: 6em; } diff --git a/src/common/recorder.ts b/src/common/recorder.ts index 9b04dcff..0d362922 100644 --- a/src/common/recorder.ts +++ b/src/common/recorder.ts @@ -120,20 +120,20 @@ export class StateRecorderImpl implements EmuRecorder { import { Probeable, ProbeAll } from "./devices"; export enum ProbeFlags { - CLOCKS = 0x00000000, - EXECUTE = 0x01000000, - MEM_READ = 0x02000000, - MEM_WRITE = 0x03000000, - IO_READ = 0x04000000, - IO_WRITE = 0x05000000, - VRAM_READ = 0x06000000, - VRAM_WRITE = 0x07000000, + CLOCKS = 0x00000000, + EXECUTE = 0x01000000, + MEM_READ = 0x12000000, + MEM_WRITE = 0x13000000, + IO_READ = 0x14000000, + IO_WRITE = 0x15000000, + VRAM_READ = 0x16000000, + VRAM_WRITE= 0x17000000, INTERRUPT = 0x08000000, - ILLEGAL = 0x09000000, - SP_PUSH = 0x0a000000, - SP_POP = 0x0b000000, + ILLEGAL = 0x09000000, + SP_PUSH = 0x0a000000, + SP_POP = 0x0b000000, SCANLINE = 0x7e000000, - FRAME = 0x7f000000, + FRAME = 0x7f000000, } class ProbeFrame { @@ -216,23 +216,26 @@ export class ProbeRecorder implements ProbeAll { logInterrupt(type:number) { 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) { - this.log(address | ProbeFlags.MEM_READ); + this.logValue(address, value, ProbeFlags.MEM_READ); } logWrite(address:number, value:number) { - this.log(address | ProbeFlags.MEM_WRITE); + this.logValue(address, value, ProbeFlags.MEM_WRITE); } logIORead(address:number, value:number) { - this.log(address | ProbeFlags.IO_READ); + this.logValue(address, value, ProbeFlags.IO_READ); } logIOWrite(address:number, value:number) { - this.log(address | ProbeFlags.IO_WRITE); + this.logValue(address, value, ProbeFlags.IO_WRITE); } logVRAMRead(address:number, value:number) { - this.log(address | ProbeFlags.VRAM_READ); + this.logValue(address, value, ProbeFlags.VRAM_READ); } logVRAMWrite(address:number, value:number) { - this.log(address | ProbeFlags.VRAM_WRITE); + this.logValue(address, value, ProbeFlags.VRAM_WRITE); } logIllegal(address:number) { this.log(address | ProbeFlags.ILLEGAL); diff --git a/src/ide/ui.ts b/src/ide/ui.ts index 1d767267..d4c49a0c 100644 --- a/src/ide/ui.ts +++ b/src/ide/ui.ts @@ -1211,22 +1211,23 @@ function getEditorPC() : number { return wnd && wnd.getCursorPC && wnd.getCursorPC(); } -function runToCursor() { - if (!checkRunReady()) return; +export function runToPC(pc: number) { + if (!checkRunReady() || !(pc >= 0)) return; setupBreakpoint("toline"); - var pc = getEditorPC(); - if (pc >= 0) { - console.log("Run to", pc.toString(16)); - if (platform.runToPC) { - platform.runToPC(pc); - } else { - platform.runEval((c) => { - return c.PC == pc; - }); - } + console.log("Run to", pc.toString(16)); + if (platform.runToPC) { + platform.runToPC(pc); + } else { + platform.runEval((c) => { + return c.PC == pc; + }); } } +function runToCursor() { + runToPC(getEditorPC()); +} + function runUntilReturn() { if (!checkRunReady()) return; setupBreakpoint("stepout"); diff --git a/src/ide/views.ts b/src/ide/views.ts index f650b812..7b645cbc 100644 --- a/src/ide/views.ts +++ b/src/ide/views.ts @@ -1,10 +1,10 @@ //import CodeMirror = require("codemirror"); 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 { 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 { getMousePos } from "../common/emu"; import * as pixed from "./pixeleditor"; @@ -108,12 +108,14 @@ export class SourceEditor implements ProjectView { setupEditor() { var timer; + // update file in project (and recompile) when edits made this.editor.on('changes', (ed, changeobj) => { clearTimeout(timer); timer = setTimeout( () => { current_project.updateFile(this.path, this.editor.getValue()); }, 300); }); + // inspect symbol when it's highlighted (double-click) this.editor.on('cursorActivity', (ed) => { var start = this.editor.getCursor(true); var end = this.editor.getCursor(false); @@ -124,10 +126,15 @@ export class SourceEditor implements ProjectView { 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); } + inspect(ident : string) : void { var result; if (platform.inspect) { @@ -333,7 +340,6 @@ export class SourceEditor implements ProjectView { var line = this.getActiveLine(); if (line >= 0) { this.setCurrentLine(line, moveCursor); - // TODO: switch to disasm? } } @@ -353,6 +359,10 @@ export class SourceEditor implements ProjectView { this.refreshListing(); this.refreshDebugState(moveCursor); } + + tick() { + this.refreshDebugState(false); + } getLine(line : number) { return this.editor.getLine(line-1); @@ -375,6 +385,13 @@ export class SourceEditor implements ProjectView { undoStep() { 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; - redraw( eventfn:(op,addr,col,row,clk) => 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 var row=0; @@ -867,20 +884,21 @@ abstract class ProbeViewBaseBase { var clk=0; for (var i=0; i> 16) & 0xff; var op = word & 0xff000000; switch (op) { case ProbeFlags.SCANLINE: row++; col=0; break; case ProbeFlags.FRAME: row=0; col=0; break; case ProbeFlags.CLOCKS: col += addr; clk += addr; break; default: - eventfn(op, addr, col, row, clk); + eventfn(op, addr, col, row, clk, value); break; } } } - opToString(op:number, addr?:number) { + opToString(op:number, addr?:number, value?:number) { var s = ""; switch (op) { case ProbeFlags.EXECUTE: s = "Exec"; break; @@ -894,7 +912,9 @@ abstract class ProbeViewBaseBase { case ProbeFlags.ILLEGAL: s = "Error"; break; 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 { switch (op) { @@ -987,9 +1007,9 @@ abstract class ProbeBitmapViewBase extends ProbeViewBase { x = x|0; y = y|0; var s = ""; - this.redraw( (op,addr,col,row) => { + this.redraw( (op,addr,col,row,clk,value) => { if (y == row && x == col) { - s += "\n" + this.opToString(op, addr); + s += "\n" + this.opToString(op, addr, value); } } ); return 'X: ' + x + ' Y: ' + y + ' ' + s; @@ -1038,13 +1058,13 @@ export class AddressHeatMapView extends ProbeBitmapViewBase implements ProjectVi var s = this.addr2str(a); var pc = -1; var already = {}; - this.redraw( (op,addr,col,row) => { + this.redraw( (op,addr,col,row,clk,value) => { if (op == ProbeFlags.EXECUTE) { pc = addr; } var key = op|pc; 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; } } ); @@ -1134,7 +1154,7 @@ export class ProbeLogView extends ProbeViewBaseBase { getMemoryLineAt(row : number) : string { var line = this.dumplines && this.dumplines[row]; 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; } else return ""; } @@ -1145,7 +1165,7 @@ export class ProbeLogView extends ProbeViewBaseBase { const isz80 = platform instanceof BaseZ80MachinePlatform || platform instanceof BaseZ80Platform; // TODO? // cache each line in frame this.dumplines = {}; - this.redraw((op,addr,col,row,clk) => { + this.redraw((op,addr,col,row,clk,value) => { if (isz80) clk >>= 2; var line = this.dumplines[clk]; if (line == null) { @@ -1160,7 +1180,7 @@ export class ProbeLogView extends ProbeViewBaseBase { } break; default: - var xtra = this.opToString(op, addr); + var xtra = this.opToString(op, addr, value); if (xtra != "") line.info.push(xtra); break; }