1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-29 14:51:17 +00:00

fixed callbackGetRemote(); started on profiler

This commit is contained in:
Steven Hugg 2019-03-03 10:32:25 -06:00
parent ce019b5632
commit ab1500ccb6
8 changed files with 197 additions and 44 deletions

View File

@ -98,6 +98,9 @@ export interface Platform {
showHelp?(tool:string, ident?:string) : void; showHelp?(tool:string, ident?:string) : void;
resize?() : void; resize?() : void;
startProfiling?() : ProfilerOutput;
getRasterScanline?() : number;
debugSymbols? : DebugSymbols; debugSymbols? : DebugSymbols;
} }
@ -122,6 +125,17 @@ export interface EmuRecorder {
recordFrame(state : EmuState); recordFrame(state : EmuState);
} }
export interface ProfilerScanline {
start,end : number; // start/end frameindex
}
export interface ProfilerFrame {
iptab : Uint32Array; // array of IPs
lines : ProfilerScanline[];
}
export interface ProfilerOutput {
frame : ProfilerFrame;
}
///// /////
export abstract class BasePlatform { export abstract class BasePlatform {
@ -194,10 +208,31 @@ export abstract class BaseDebugPlatform extends BasePlatform {
this.advance(novideo); this.advance(novideo);
this.postFrame(); this.postFrame();
} }
startProfiling() : ProfilerOutput {
var frame = null;
var output = {frame:null};
var i = 0;
var lastsl = 9999;
var start = 0;
(this as any).runEval((c:CpuState) => {
var sl = (this as any).getRasterScanline();
if (sl != lastsl) {
if (frame) frame.lines.push({start:start,end:i});
if (sl < lastsl) {
output.frame = frame;
frame = {iptab:new Uint32Array(14672), lines:[]};
i = 0;
}
start = i+1;
lastsl = sl;
}
frame.iptab[i++] = c.EPC || c.PC;
return false; // profile forever
});
return output;
}
} }
//////
////// 6502 ////// 6502
export function getToolForFilename_6502(fn:string) : string { export function getToolForFilename_6502(fn:string) : string {
@ -933,7 +968,7 @@ export function dumpStackToString(platform:Platform, mem:Uint8Array|number[], st
var opcode = read(addr + jsrofs); // might be out of bounds var opcode = read(addr + jsrofs); // might be out of bounds
if (opcode == jsrop) { // JSR if (opcode == jsrop) { // JSR
s += "\n$" + hex(sp) + ": "; s += "\n$" + hex(sp) + ": ";
s += hex(addr,4) + " " + lookupSymbol(platform, addr); s += hex(addr,4) + " " + lookupSymbol(platform, addr, true);
sp++; sp++;
nraw = 0; nraw = 0;
} else { } else {
@ -946,20 +981,18 @@ export function dumpStackToString(platform:Platform, mem:Uint8Array|number[], st
return s+"\n"; return s+"\n";
} }
export function lookupSymbol(platform:Platform, addr:number) { export function lookupSymbol(platform:Platform, addr:number, extra:boolean) {
var start = addr; var start = addr;
var foundsym;
var addr2symbol = platform.debugSymbols && platform.debugSymbols.addr2symbol; var addr2symbol = platform.debugSymbols && platform.debugSymbols.addr2symbol;
while (addr2symbol && addr >= 0) { while (addr2symbol && addr >= 0) {
var sym = addr2symbol[addr]; var sym = addr2symbol[addr];
if (sym && sym.startsWith('_')) { // return first C symbol we find if (sym) { // return first symbol we find
return addr2symbol[addr] + " + " + (start-addr); var sym = addr2symbol[addr];
} else if (sym && !foundsym) { // cache first non-C symbol found return extra ? (sym + " + " + (start-addr)) : sym;
foundsym = sym;
} }
addr--; addr--;
} }
return foundsym || ""; return "";
} }
///// Basic Platforms ///// Basic Platforms
@ -1074,4 +1107,3 @@ export abstract class BasicZ80ScanlinePlatform extends BaseZ80Platform {
this.cpu.setTstates(0); this.cpu.setTstates(0);
} }
} }

View File

@ -1,6 +1,6 @@
"use strict"; "use strict";
import { Platform, Base6502Platform, BaseMAMEPlatform, getOpcodeMetadata_6502, cpuStateToLongString_6502, getToolForFilename_6502, dumpStackToString } from "../baseplatform"; import { Platform, Base6502Platform, BaseMAMEPlatform, getOpcodeMetadata_6502, cpuStateToLongString_6502, getToolForFilename_6502, dumpStackToString, ProfilerOutput } from "../baseplatform";
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, KeyFlags } from "../emu"; import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap, dumpRAM, KeyFlags } from "../emu";
import { hex, lpad, lzgmini } from "../util"; import { hex, lpad, lzgmini } from "../util";
import { CodeAnalyzer_nes } from "../analysis"; import { CodeAnalyzer_nes } from "../analysis";
@ -131,9 +131,7 @@ const _JSNESPlatform = function(mainElement) {
nes.cpu._emulate = nes.cpu.emulate; nes.cpu._emulate = nes.cpu.emulate;
nes.cpu.emulate = () => { nes.cpu.emulate = () => {
var cycles = nes.cpu._emulate(); var cycles = nes.cpu._emulate();
//if (self.debugCondition && !self.debugBreakState && self.debugClock < 100) console.log(self.debugClock, nes.cpu.REG_PC);
this.evalDebugCondition(); this.evalDebugCondition();
// TODO: doesn't stop on breakpoint
return cycles; return cycles;
} }
timer = new AnimationTimer(60, this.nextFrame.bind(this)); timer = new AnimationTimer(60, this.nextFrame.bind(this));
@ -227,7 +225,35 @@ const _JSNESPlatform = function(mainElement) {
runToVsync() { runToVsync() {
var frame0 = frameindex; var frame0 = frameindex;
this.runEval(function(c) { return frameindex>frame0; }); this.runEval((c) => { return frameindex>frame0; });
}
getRasterScanline() : number {
return nes.ppu.scanline;
}
startProfiling() : ProfilerOutput {
var frame0 = frameindex;
var frame = null;
var output = {frame:null};
var i = 0;
var lastsl = 9999;
var start = 0;
this.runEval((c) => {
var sl = this.getRasterScanline();
if (sl != lastsl) {
if (frame) frame.lines.push({start:start,end:i});
if (sl < lastsl) {
output.frame = frame;
frame = {iptab:new Uint32Array(14672), lines:[]};
i = 0;
}
start = i+1;
lastsl = sl;
}
frame.iptab[i++] = c.EPC || c.PC;
return false; //frameindex>frame0; // TODO
});
return output;
} }
getCPUState() { getCPUState() {

View File

@ -112,6 +112,9 @@ class VCSPlatform extends BasePlatform {
var ypos = row-39; var ypos = row-39;
return {x:xpos, y:ypos}; return {x:xpos, y:ypos};
} }
getRasterScanline() : number {
return this.getRasterPosition().y;
}
// TODO: Clock changes this on event, so it may not be current // TODO: Clock changes this on event, so it may not be current
isRunning() { isRunning() {

View File

@ -209,20 +209,18 @@ export class CodeProject {
webpath += ".a"; // legacy stuff webpath += ".a"; // legacy stuff
// try to GET file, use file ext to determine text/binary // try to GET file, use file ext to determine text/binary
this.callbackGetRemote( webpath, (data:FileData) => { this.callbackGetRemote( webpath, (data:FileData) => {
if (data == null) {
console.log("Could not load preset file", path);
this.filedata[path] = null; // mark cache entry as invalid
} else {
if (data instanceof ArrayBuffer) if (data instanceof ArrayBuffer)
data = new Uint8Array(data); // convert to typed array data = new Uint8Array(data); // convert to typed array
console.log("GET",webpath,data.length,'bytes'); console.log("GET",webpath,data.length,'bytes');
this.filedata[path] = data; // do not update store, just cache this.filedata[path] = data; // do not update store, just cache
addResult(path, data); addResult(path, data);
}
loadNext(); loadNext();
}, isProbablyBinary(path) ? 'arraybuffer' : 'text') }, isProbablyBinary(path) ? 'arraybuffer' : 'text');
.fail( (err:XMLHttpRequest) => {
console.log("Could not load preset file", path, err.status);
// only cache result if status is 404 (not found)
if (err.status && err.status == 404)
this.filedata[path] = null; // mark cache entry as invalid
loadNext();
});
} else { } else {
// not gonna find it, keep going // not gonna find it, keep going
loadNext(); loadNext();

View File

@ -100,7 +100,12 @@ function getWithBinary(url:string, success:(text:FileData)=>void, datatype:'text
oReq.open("GET", url, true); oReq.open("GET", url, true);
oReq.responseType = datatype; oReq.responseType = datatype;
oReq.onload = function (oEvent) { oReq.onload = function (oEvent) {
if (oReq.status == 200)
success(oReq.response); success(oReq.response);
else if (oReq.status == 404)
success(null);
else
throw "Error " + oReq.status + " loading " + url;
} }
oReq.send(null); oReq.send(null);
} }
@ -210,6 +215,11 @@ function refreshWindowList() {
return new Views.MemoryMapView(); return new Views.MemoryMapView();
}); });
} }
if (platform.startProfiling && platform.runEval && platform.getRasterScanline) {
addWindowItem("#profiler", "Profiler", function() {
return new Views.ProfileView();
});
}
} }
// can pass integer or string id // can pass integer or string id

View File

@ -4,7 +4,7 @@ import $ = require("jquery");
//import CodeMirror = require("codemirror"); //import CodeMirror = require("codemirror");
import { CodeProject } from "./project"; import { CodeProject } from "./project";
import { SourceFile, WorkerError, Segment } from "./workertypes"; import { SourceFile, WorkerError, Segment } from "./workertypes";
import { Platform, EmuState } from "./baseplatform"; import { Platform, EmuState, ProfilerOutput, lookupSymbol } from "./baseplatform";
import { hex, lpad, rpad } from "./util"; import { hex, lpad, rpad } from "./util";
import { CodeAnalyzer } from "./analysis"; import { CodeAnalyzer } from "./analysis";
import { platform, platform_id, compparams, current_project, lastDebugState, projectWindows } from "./ui"; import { platform, platform_id, compparams, current_project, lastDebugState, projectWindows } from "./ui";
@ -833,3 +833,82 @@ export class MemoryMapView implements ProjectView {
} }
} }
///
export class ProfileView implements ProjectView {
profilelist;
prof : ProfilerOutput;
maindiv : HTMLElement;
symcache : {};
createDiv(parent : HTMLElement) {
var div = document.createElement('div');
div.setAttribute("class", "memdump");
parent.appendChild(div);
this.showMemoryWindow(parent, div);
return this.maindiv = div;
}
showMemoryWindow(workspace:HTMLElement, parent:HTMLElement) {
this.profilelist = new VirtualList({
w: $(workspace).width(),
h: $(workspace).height(),
itemHeight: getVisibleEditorLineHeight(),
totalRows: 262,
generatorFn: (row : number) => {
var s = this.getProfileLineAt(row);
var linediv = document.createElement("div");
linediv.appendChild(document.createTextNode(s));
return linediv;
}
});
$(parent).append(this.profilelist.container);
this.symcache = {};
this.tick();
}
getProfileLineAt(row : number) : string {
var s = lpad(row+': ',5);
if (!this.prof) return s;
var f = this.prof.frame;
if (!f) return s;
var l = f.lines[row];
if (!l) return s;
var lastsym = '';
for (var i=l.start; i<=l.end; i++) {
var pc = f.iptab[i];
var sym = this.symcache[pc];
if (!sym) {
sym = lookupSymbol(platform, pc, false);
this.symcache[pc] = sym;
}
if (sym != lastsym) {
s += sym + ' ';
lastsym = sym;
}
}
return s;
}
refresh() {
this.tick();
}
tick() {
if (this.profilelist) {
$(this.maindiv).find('[data-index]').each( (i,e) => {
var div = $(e);
var row = parseInt(div.attr('data-index'));
var oldtext = div.text();
var newtext = this.getProfileLineAt(row);
if (oldtext != newtext)
div.text(newtext);
});
}
// TODO: better way to keep it profiling? also, it clears the buffer
if (platform.isRunning()) {
this.prof = platform.startProfiling();
}
}
}

View File

@ -934,10 +934,12 @@ function linkLD65(step:BuildStep) {
var toks = s.split(" "); var toks = s.split(" ");
if (toks[0] == 'al') { if (toks[0] == 'al') {
let ident = toks[2].substr(1); let ident = toks[2].substr(1);
if (ident.length != 5 || !ident.startsWith('L')) { // no line numbers
let ofs = parseInt(toks[1], 16); let ofs = parseInt(toks[1], 16);
symbolmap[ident] = ofs; symbolmap[ident] = ofs;
} }
} }
}
// build segment map // build segment map
var seg_re = /^__(\w+)_SIZE__$/; var seg_re = /^__(\w+)_SIZE__$/;
var segments = [].concat(params.extra_segments||[]); var segments = [].concat(params.extra_segments||[]);
@ -1226,7 +1228,7 @@ function linkSDLDZ80(step:BuildStep)
var symbolmap = {}; var symbolmap = {};
for (var s of noiout.split("\n")) { for (var s of noiout.split("\n")) {
var toks = s.split(" "); var toks = s.split(" ");
if (toks[0] == 'DEF' && !toks[1].startsWith("A$main$")) { if (toks[0] == 'DEF' && !toks[1].startsWith("A$")) {
symbolmap[toks[1]] = parseInt(toks[2], 16); symbolmap[toks[1]] = parseInt(toks[2], 16);
} }
} }

View File

@ -76,7 +76,10 @@ describe('Store', function() {
var platform = {}; var platform = {};
var project = new prj.CodeProject(worker, test_platform_id, platform, store); var project = new prj.CodeProject(worker, test_platform_id, platform, store);
var remote = []; var remote = [];
project.callbackGetRemote = function(path) { remote.push(path); return {fail:function(failfn){failfn({status:404})}} }; project.callbackGetRemote = function(path, success, datatype) {
remote.push(path);
success();
};
project.loadFiles(['local/test','test'], function(err, result) { project.loadFiles(['local/test','test'], function(err, result) {
assert.equal(null, err); assert.equal(null, err);
assert.deepEqual(["presets/_TEST/test"], remote); assert.deepEqual(["presets/_TEST/test"], remote);