diff --git a/doc/notes.txt b/doc/notes.txt
index 6bda7ff2..85b434fc 100644
--- a/doc/notes.txt
+++ b/doc/notes.txt
@@ -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
diff --git a/index.html b/index.html
index 4c1687fb..f6f222a6 100644
--- a/index.html
+++ b/index.html
@@ -279,12 +279,12 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
Space Trigger
Mouse X Knob
- C A Z P
- R S H /
+ U I O P
+ J K L /
7 8 9 X
4 5 6 -
1 2 3 ,
- E 0 . = Keypad
+ \ 0 . = Keypad
diff --git a/presets/astrocade/acbios.h b/presets/astrocade/acbios.h
index 0dbb79eb..7ef995e6 100644
--- a/presets/astrocade/acbios.h
+++ b/presets/astrocade/acbios.h
@@ -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");
diff --git a/presets/astrocade/acbios.s b/presets/astrocade/acbios.s
index 5cf1cf95..1767a426 100644
--- a/presets/astrocade/acbios.s
+++ b/presets/astrocade/acbios.s
@@ -146,8 +146,3 @@ _begin_music:
SYSTEM BMUSIC
ret
-; EMUSIC
- .globl _end_music
-_end_music:
- SYSTEM EMUSIC
- ret
diff --git a/presets/astrocade/cosmic.c b/presets/astrocade/cosmic.c
index 65f3257f..cfa59afd 100644
--- a/presets/astrocade/cosmic.c
+++ b/presets/astrocade/cosmic.c
@@ -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
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();
}
diff --git a/presets/astrocade/hello.c b/presets/astrocade/hello.c
index b70ea3f1..db1043b8 100644
--- a/presets/astrocade/hello.c
+++ b/presets/astrocade/hello.c
@@ -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
diff --git a/src/baseplatform.ts b/src/baseplatform.ts
index ab46f7ee..f3652bb4 100644
--- a/src/baseplatform.ts
+++ b/src/baseplatform.ts
@@ -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();
}
diff --git a/src/pixed/pixeleditor.ts b/src/pixed/pixeleditor.ts
index 440402c3..655d03ed 100644
--- a/src/pixed/pixeleditor.ts
+++ b/src/pixed/pixeleditor.ts
@@ -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);
diff --git a/src/platform/astrocade.ts b/src/platform/astrocade.ts
index dbf905db..ee52b419 100644
--- a/src/platform/astrocade.ts
+++ b/src/platform/astrocade.ts
@@ -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) {
diff --git a/src/recorder.ts b/src/recorder.ts
index f6e40e46..314eb05c 100644
--- a/src/recorder.ts
+++ b/src/recorder.ts
@@ -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');
+ }
+}
diff --git a/src/ui.ts b/src/ui.ts
index 2b4d84bb..827d7874 100644
--- a/src/ui.ts
+++ b/src/ui.ts
@@ -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 = (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);
}
};
diff --git a/src/views.ts b/src/views.ts
index 3f8b71d5..53675186 100644
--- a/src/views.ts
+++ b/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();
}
}