moved profiler to separate class, profiler ticks when replay scroller used

This commit is contained in:
Steven Hugg 2019-06-09 11:13:25 -04:00
parent e8260a8e46
commit e9da7aac4a
12 changed files with 127 additions and 58 deletions

View File

@ -103,6 +103,8 @@ TODO:
- click on profiler to step to position
- breakpoints stop profiler from running
- single-screen profiler
- hide labels that aren't available, like BIOS addrs
- show interrupts, other events
- https://remotestoragejs.readthedocs.io/en/latest/getting-started/how-to-add.html ?
- Verilog
- larger scope range, better scrolling
@ -153,6 +155,8 @@ TODO:
- emulator needs reset shortcut for nes
- switching platform of a repo?
- make sure to flatten subdirs
- astrocade
- EI should trigger interrupt if pending? (see stash, might need z80 option)
- ctrl+alt+l on ubuntu locks screen
WEB WORKER FORMAT

View File

@ -279,12 +279,12 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<span class="control-def"><span class="control-key small">Space</span> Trigger</span>
<span class="control-def"><span class="control-key small">Mouse X</span> Knob</span>
<span class="control-def"><span class="control-key small" style="display:inline-block;font-family:monospace">
C A Z P<br>
R S H /<br>
U I O P<br>
J K L /<br>
7 8 9 X<br>
4 5 6 -<br>
1 2 3 ,<br>
E 0 . =</span> Keypad</span>
\ 0 . =</span> Keypad</span>
</div>
<!-- -->
<div id="emuoverlay" class="emuoverlay" style="display:none">

View File

@ -91,6 +91,15 @@ void end_music(void);
// QUICK MACROS
#define SYS_ACTINT()\
__asm__("rst 0x38");\
__asm__(".db 0x0f");\
#define SYS_PAWS(frames)\
__asm__("rst 0x38");\
__asm__(".db 0x51");\
__asm__(".db "#frames);\
#define SYS_SETOUT(verbl,horcb,inmod)\
__asm__("rst 0x38");\
__asm__(".db 0x17");\
@ -112,6 +121,26 @@ void end_music(void);
__asm__(".dw "#count);\
__asm__(".dw "#src);\
#define SYS_RECTAN(x,y,width,height,color)\
__asm__("rst 0x38");\
__asm__(".db 0x1d");\
__asm__(".db "#x);\
__asm__(".db "#y);\
__asm__(".db "#width);\
__asm__(".db "#height);\
__asm__(".db "#color);\
#define SYS_BMUSIC(stack,voices,musicdata)\
__asm__("rst 0x38");\
__asm__(".db 0x13");\
__asm__(".dw "#stack);\
__asm__(".db "#voices);\
__asm__(".dw "#musicdata);\
#define SYS_EMUSIC()\
__asm__("rst 0x38");\
__asm__(".db 0x15");\
#define RESET_TIMEOUT() \
__asm__("ld a,#0xff");\
__asm__("ld (0x4FEC),a");

View File

@ -146,8 +146,3 @@ _begin_music:
SYSTEM BMUSIC
ret
; EMUSIC
.globl _end_music
_end_music:
SYSTEM EMUSIC
ret

View File

@ -64,6 +64,8 @@ const byte palette[8] = {
#define MAXLIVES 5
#define PLYRHEIGHT 9
#define ENEMY_WIDTH 8
#define ENEMY_HEIGHT 8
#define ENEMY_SPACING_X 14
#define ENEMY_SPACING_Y 11
#define ENEMY_WIDTH 8
@ -208,6 +210,7 @@ void delete_enemy(Enemy* e) {
}
memmove(e, e+1, sizeof(Enemy)*(enemies-e+MAX_ENEMIES-1));
num_enemies--; // update_next_enemy() will check enemy_index
// TODO: enemy_index might skip updating an enemy
}
void update_next_enemy() {
@ -255,7 +258,7 @@ Enemy* find_enemy_at(byte x, byte y) {
byte i;
for (i=0; i<num_enemies; i++) {
Enemy* e = &enemies[i];
if (in_rect(e, x, y, 4, 5)) {
if (in_rect(e, x, y, 4, 1)) {
return e;
}
}
@ -303,11 +306,11 @@ void drop_bomb() {
byte i = rand() % num_enemies;
Enemy* e = &enemies[i];
// don't drop on someone else!
if (find_enemy_at(e->x, e->y+ENEMY_SPACING_Y*2)) {
if (find_enemy_at(e->x, e->y+ENEMY_HEIGHT+ENEMY_SPACING_Y+1)) {
return;
}
bomb_x = e->x + ENEMY_WIDTH/4;
bomb_y = e->y + ENEMY_SPACING_Y;
bomb_y = e->y + ENEMY_HEIGHT;
xor_bomb();
}
@ -321,7 +324,7 @@ void move_bomb() {
xor_bomb();
if (hw_intst & 0xf0) { // any pixels leftover?
erase_sprite(bomb_bitmap, bomb_x, bomb_y);
if (bomb_y >= player_y) {
if (bomb_y >= player_y-2) {
// player was hit (probably)
destroy_player();
}

View File

@ -51,8 +51,9 @@ void main(void) {
// set screen height
// set horizontal color split (position / 4)
// set interrupt status
// use SYS_SETOUT macro
SYS_SETOUT(89*2, 23, 0);
// clear screen
// clear screen w/ SYS_FILL macro
SYS_FILL(0x4000, 89*40, 0);
// display standard characters
display_string(2, 2, OPT_ON(1), "HELLO, WORLD!\xb1\xb2\xb3\xb4\xb5");
@ -69,7 +70,8 @@ void main(void) {
display_string(4, 80, OPT_ON(1), "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9");
// paint a rectangle with a pattern mask (0xa5)
paint_rectangle(4, 72, 100, 5, 0x55);
paint_rectangle(6, 74, 100, 4, 0xaa);
// more compact macro
SYS_RECTAN(6, 74, 100, 4, 0xaa);
// write from pattern block
write_relative(50, 80, M_XPAND, BALL);
write_relative(60, 80, M_XPAND, BALL);
@ -83,6 +85,7 @@ void main(void) {
// make sure screen doesn't black out
RESET_TIMEOUT();
// play music
//SYS_BMUSIC(_music_stack, 0b11111100, _MUSICDATA);
//begin_music(music_stack, 0b11111100, MUSICDATA);
while (1) {
// wait for SENTRY result

View File

@ -104,6 +104,9 @@ export interface Platform {
startProfiling?() : ProfilerOutput;
stopProfiling?() : void;
getRasterScanline?() : number;
setBreakpoint?(id : string, cond : DebugCondition);
clearBreakpoint?(id : string);
getCPUState?() : CpuState;
debugSymbols? : DebugSymbols;
}
@ -160,6 +163,10 @@ export interface ProfilerFrame {
export interface ProfilerOutput {
frame : ProfilerFrame;
}
export interface EmuProfiler {
start() : ProfilerOutput;
stop();
}
/////
@ -207,35 +214,6 @@ export abstract class BaseDebugPlatform extends BasePlatform {
clearBreakpoint(id : string) {
delete this.breakpoints.id2bp[id];
}
startProfiling() : ProfilerOutput {
var frame = null;
var output = {frame:null};
var i = 0;
var lastsl = 9999;
var start = 0;
this.setBreakpoint('profile', () => {
var sl = (this as any).getRasterScanline();
if (sl != lastsl) {
if (frame) {
frame.lines.push({start:start,end:i-1});
}
if (sl < lastsl) {
output.frame = frame;
frame = {iptab:new Uint32Array(0x8000), lines:[]}; // TODO: const
i = 0;
}
start = i;
lastsl = sl;
}
var c = this.getCPUState();
frame.iptab[i++] = c.EPC || c.PC;
return false; // profile forever
});
return output;
}
stopProfiling() {
this.clearBreakpoint('profile');
}
getDebugCallback() : DebugCondition {
return this.breakpoints.getDebugCondition();
}

View File

@ -435,7 +435,7 @@ export class TextDataNode extends CodeProjectDataNode {
}
updateLeft() {
if (this.right.words.length != this.words.length)
throw "Expected " + this.words.length + " bytes; image has " + this.right.words.length;
throw "Expected " + this.right.words.length + " bytes; image has " + this.words.length;
this.words = this.right.words;
// TODO: reload editors?
var datastr = this.text.substring(this.start, this.end);

View File

@ -36,6 +36,12 @@ const ASTROCADE_KEYCODE_MAP = makeKeycodeMap([
[Keys.LEFT, 0x10, 0x4],
[Keys.RIGHT, 0x10, 0x8],
[Keys.A, 0x10, 0x10],
// player 2
[Keys.P2_UP, 0x11, 0x1],
[Keys.P2_DOWN, 0x11, 0x2],
[Keys.P2_LEFT, 0x11, 0x4],
[Keys.P2_RIGHT, 0x11, 0x8],
[Keys.P2_A, 0x11, 0x10],
// keypad $14
[Keys.VK_P, 0x14, 0x1],
[Keys.VK_SLASH, 0x14, 0x2],
@ -44,26 +50,26 @@ const ASTROCADE_KEYCODE_MAP = makeKeycodeMap([
[Keys.VK_COMMA, 0x14, 0x10],
[Keys.VK_EQUALS,0x14, 0x20],
// keypad $15
[Keys.VK_Z, 0x15, 0x1],
[Keys.VK_H, 0x15, 0x2],
[Keys.VK_O, 0x15, 0x1],
[Keys.VK_L, 0x15, 0x2],
[Keys.VK_9, 0x15, 0x4],
[Keys.VK_6, 0x15, 0x8],
[Keys.VK_3, 0x15, 0x10],
[Keys.VK_PERIOD,0x15, 0x20],
// keypad $16
[Keys.VK_A, 0x16, 0x1],
[Keys.VK_S, 0x16, 0x2],
[Keys.VK_I, 0x16, 0x1],
[Keys.VK_K, 0x16, 0x2],
[Keys.VK_8, 0x16, 0x4],
[Keys.VK_5, 0x16, 0x8],
[Keys.VK_2, 0x16, 0x10],
[Keys.VK_0, 0x16, 0x20],
// keypad $17
[Keys.VK_C, 0x17, 0x1],
[Keys.VK_R, 0x17, 0x2],
[Keys.VK_U, 0x17, 0x1],
[Keys.VK_J, 0x17, 0x2],
[Keys.VK_7, 0x17, 0x4],
[Keys.VK_4, 0x17, 0x8],
[Keys.VK_1, 0x17, 0x10],
[Keys.VK_E, 0x17, 0x20],
[Keys.VK_BACK_SLASH, 0x17, 0x20],
]);
const _BallyAstrocadePlatform = function(mainElement, arcade) {

View File

@ -1,7 +1,10 @@
import { Platform, EmuState, EmuControlsState, EmuRecorder } from "./baseplatform";
import { BaseDebugPlatform, EmuProfiler, ProfilerOutput } from "./baseplatform";
import { getNoiseSeed, setNoiseSeed } from "./emu";
// RECORDER
type FrameRec = {controls:EmuControlsState, seed:number};
export class StateRecorderImpl implements EmuRecorder {
@ -111,3 +114,44 @@ export class StateRecorderImpl implements EmuRecorder {
return this.checkpoints.length && this.checkpoints[this.checkpoints.length-1];
}
}
// PROFILER
export class EmuProfilerImpl implements EmuProfiler {
platform : Platform;
constructor(platform : Platform) {
this.platform = platform;
}
start() : ProfilerOutput {
var frame = null;
var output = {frame:null};
var i = 0;
var lastsl = 9999;
var start = 0;
this.platform.setBreakpoint('profile', () => {
var sl = this.platform.getRasterScanline();
if (sl != lastsl) {
if (frame) {
frame.lines.push({start:start,end:i-1});
}
if (sl < lastsl) {
output.frame = frame;
frame = {iptab:new Uint32Array(0x8000), lines:[]}; // TODO: const
i = 0;
}
start = i;
lastsl = sl;
}
var c = this.platform.getCPUState();
frame.iptab[i++] = c.EPC || c.PC;
return false; // profile forever
});
return output;
}
stop() {
this.platform.clearBreakpoint('profile');
}
}

View File

@ -235,7 +235,7 @@ function refreshWindowList() {
return new Views.MemoryMapView();
});
}
if (platform.startProfiling && platform.runEval && platform.getRasterScanline) {
if (platform.getRasterScanline && platform.setBreakpoint && platform.getCPUState) { // TODO: use profiler class to determine compat
addWindowItem("#profiler", "Profiler", () => {
return new Views.ProfileView();
});
@ -1506,6 +1506,7 @@ function setupReplaySlider() {
var frame = (<any>e.target).value;
if (stateRecorder.loadFrame(frame)) {
updateFrameNo(frame);
projectWindows.tick();
}
};
var setFrameTo = (frame:number) => {
@ -1513,6 +1514,7 @@ function setupReplaySlider() {
if (stateRecorder.loadFrame(frame)) {
replayslider.val(frame);
updateFrameNo(frame);
projectWindows.tick();
console.log('seek to frame',frame);
}
};

View File

@ -3,10 +3,11 @@
import $ = require("jquery");
//import CodeMirror = require("codemirror");
import { SourceFile, WorkerError, Segment, FileData } from "./workertypes";
import { Platform, EmuState, ProfilerOutput, lookupSymbol } from "./baseplatform";
import { Platform, EmuState, ProfilerOutput, lookupSymbol, BaseDebugPlatform } from "./baseplatform";
import { hex, lpad, rpad, safeident, rgb2bgr } from "./util";
import { CodeAnalyzer } from "./analysis";
import { platform, platform_id, compparams, current_project, lastDebugState, projectWindows } from "./ui";
import { EmuProfilerImpl } from "./recorder";
import * as pixed from "./pixed/pixeleditor";
declare var Mousetrap;
@ -819,8 +820,9 @@ export class MemoryMapView implements ProjectView {
///
export class ProfileView implements ProjectView {
prof : EmuProfilerImpl;
profilelist;
prof : ProfilerOutput;
out : ProfilerOutput;
maindiv : HTMLElement;
symcache : {};
recreateOnResize = true;
@ -852,8 +854,8 @@ export class ProfileView implements ProjectView {
addProfileLine(div : HTMLElement, row : number) : void {
div.appendChild(createTextSpan(lpad(row+':',4), "profiler-lineno"));
if (!this.prof) return;
var f = this.prof.frame;
if (!this.out) return;
var f = this.out.frame;
if (!f) return;
var l = f.lines[row];
if (!l) return;
@ -899,10 +901,13 @@ export class ProfileView implements ProjectView {
}
setVisible(showing : boolean) : void {
if (!this.prof) {
this.prof = new EmuProfilerImpl(platform);
}
if (showing)
this.prof = platform.startProfiling();
this.out = this.prof.start();
else
platform.stopProfiling();
this.prof.stop();
}
}