mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-12-22 12:30:01 +00:00
moved profiler to separate class, profiler ticks when replay scroller used
This commit is contained in:
parent
e8260a8e46
commit
e9da7aac4a
@ -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
|
||||
|
@ -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">
|
||||
|
@ -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");
|
||||
|
@ -146,8 +146,3 @@ _begin_music:
|
||||
SYSTEM BMUSIC
|
||||
ret
|
||||
|
||||
; EMUSIC
|
||||
.globl _end_music
|
||||
_end_music:
|
||||
SYSTEM EMUSIC
|
||||
ret
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
17
src/views.ts
17
src/views.ts
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user