romdevtools 0.16.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/AGENTS.md +75 -16
  2. package/CHANGELOG.md +316 -0
  3. package/examples/README.md +2 -0
  4. package/examples/atari2600/templates/platformer.asm +460 -0
  5. package/examples/atari2600/templates/racing.asm +463 -0
  6. package/examples/atari2600/templates/shmup.asm +386 -0
  7. package/examples/atari2600/templates/sports.asm +362 -0
  8. package/examples/atari7800/templates/default.c +49 -5
  9. package/examples/atari7800/templates/hello_sprite.c +48 -4
  10. package/examples/atari7800/templates/music_demo.c +47 -2
  11. package/examples/atari7800/templates/platformer.c +43 -4
  12. package/examples/atari7800/templates/puzzle.c +39 -4
  13. package/examples/atari7800/templates/racing.c +39 -4
  14. package/examples/atari7800/templates/shmup.c +40 -2
  15. package/examples/atari7800/templates/sports.c +36 -5
  16. package/examples/c64/templates/platformer.c +19 -5
  17. package/examples/c64/templates/puzzle.c +32 -2
  18. package/examples/c64/templates/shmup.c +28 -2
  19. package/examples/c64/templates/sports.c +30 -2
  20. package/examples/c64/templates/tile_engine.c +77 -27
  21. package/examples/gb/templates/default.c +110 -16
  22. package/examples/gb/templates/hello_sprite.c +15 -6
  23. package/examples/gb/templates/music_demo.c +36 -0
  24. package/examples/gb/templates/platformer.c +28 -6
  25. package/examples/gb/templates/puzzle.c +35 -4
  26. package/examples/gb/templates/racing.c +75 -10
  27. package/examples/gb/templates/shmup.c +41 -3
  28. package/examples/gb/templates/sports.c +51 -3
  29. package/examples/gb/templates/tile_engine.c +3 -2
  30. package/examples/gba/templates/gba_hello.c +29 -11
  31. package/examples/gba/templates/maxmod_demo.c +36 -2
  32. package/examples/gba/templates/platformer.c +3 -1
  33. package/examples/gba/templates/puzzle.c +15 -3
  34. package/examples/gba/templates/racing.c +65 -3
  35. package/examples/gba/templates/shmup.c +41 -4
  36. package/examples/gba/templates/sports.c +36 -2
  37. package/examples/gba/templates/tonc_hello.c +41 -5
  38. package/examples/gba/templates/tonc_hello_sprite.c +35 -1
  39. package/examples/gbc/templates/default.c +103 -26
  40. package/examples/gbc/templates/hello_sprite.c +12 -3
  41. package/examples/gbc/templates/music_demo.c +56 -12
  42. package/examples/gbc/templates/platformer.c +28 -6
  43. package/examples/gbc/templates/puzzle.c +35 -4
  44. package/examples/gbc/templates/racing.c +88 -21
  45. package/examples/gbc/templates/shmup.c +37 -3
  46. package/examples/gbc/templates/sports.c +48 -3
  47. package/examples/gbc/templates/tile_engine.c +3 -2
  48. package/examples/genesis/main.s +53 -1
  49. package/examples/genesis/templates/hello_sprite.c +25 -3
  50. package/examples/genesis/templates/puzzle.c +37 -3
  51. package/examples/genesis/templates/racing.c +44 -11
  52. package/examples/genesis/templates/sgdk_hello.c +34 -1
  53. package/examples/genesis/templates/shmup.c +31 -1
  54. package/examples/genesis/templates/shmup_2p.c +31 -0
  55. package/examples/genesis/templates/xgm2_demo.c +20 -0
  56. package/examples/gg/templates/default.c +56 -18
  57. package/examples/gg/templates/hello_sprite.c +25 -2
  58. package/examples/gg/templates/music_demo.c +24 -2
  59. package/examples/gg/templates/platformer.c +18 -12
  60. package/examples/gg/templates/puzzle.c +38 -7
  61. package/examples/gg/templates/racing.c +58 -9
  62. package/examples/gg/templates/shmup.c +47 -3
  63. package/examples/gg/templates/sports.c +57 -16
  64. package/examples/gg/templates/tile_engine.c +12 -6
  65. package/examples/lynx/templates/default.c +39 -8
  66. package/examples/lynx/templates/hello_sprite.c +15 -1
  67. package/examples/lynx/templates/music_demo.c +13 -1
  68. package/examples/lynx/templates/puzzle.c +28 -1
  69. package/examples/lynx/templates/racing.c +34 -7
  70. package/examples/lynx/templates/shmup.c +42 -3
  71. package/examples/lynx/templates/sports.c +29 -2
  72. package/examples/msx/platformer/main.c +213 -0
  73. package/examples/msx/puzzle/main.c +250 -0
  74. package/examples/msx/racing/main.c +249 -0
  75. package/examples/msx/shmup/main.c +288 -0
  76. package/examples/msx/sports/main.c +182 -0
  77. package/examples/nes/templates/default.c +67 -19
  78. package/examples/nes/templates/hello_sprite.c +35 -0
  79. package/examples/nes/templates/music_demo.c +40 -0
  80. package/examples/nes/templates/platformer.c +65 -6
  81. package/examples/nes/templates/puzzle.c +67 -6
  82. package/examples/nes/templates/racing.c +45 -13
  83. package/examples/nes/templates/shmup.c +51 -2
  84. package/examples/nes/templates/sports.c +51 -6
  85. package/examples/pce/catch_game/main.c +22 -3
  86. package/examples/pce/music_sfx/main.c +28 -1
  87. package/examples/pce/platformer/main.c +283 -0
  88. package/examples/pce/puzzle/main.c +304 -0
  89. package/examples/pce/racing/main.c +304 -0
  90. package/examples/pce/shmup/main.c +346 -0
  91. package/examples/pce/sports/main.c +254 -0
  92. package/examples/pce/sprite_move/main.c +7 -2
  93. package/examples/sms/main.c +35 -6
  94. package/examples/sms/templates/hello_sprite.c +29 -3
  95. package/examples/sms/templates/music_demo.c +18 -4
  96. package/examples/sms/templates/puzzle.c +34 -5
  97. package/examples/sms/templates/racing.c +39 -2
  98. package/examples/sms/templates/shmup.c +41 -2
  99. package/examples/sms/templates/shmup_2p.c +24 -1
  100. package/examples/sms/templates/sports.c +47 -4
  101. package/examples/snes/main.asm +108 -17
  102. package/examples/snes/templates/c-hello-data.asm +23 -0
  103. package/examples/snes/templates/c-hello.c +18 -1
  104. package/examples/snes/templates/default.c +50 -28
  105. package/examples/snes/templates/hello_sprite-data.asm +23 -0
  106. package/examples/snes/templates/hello_sprite.c +17 -1
  107. package/examples/snes/templates/music_demo-data.asm +23 -0
  108. package/examples/snes/templates/music_demo.c +22 -4
  109. package/examples/snes/templates/platformer-data.asm +22 -0
  110. package/examples/snes/templates/platformer.c +20 -2
  111. package/examples/snes/templates/puzzle-data.asm +22 -0
  112. package/examples/snes/templates/puzzle.c +21 -2
  113. package/examples/snes/templates/racing-data.asm +22 -0
  114. package/examples/snes/templates/racing.c +17 -1
  115. package/examples/snes/templates/shmup-data.asm +22 -0
  116. package/examples/snes/templates/shmup.c +20 -1
  117. package/examples/snes/templates/sports-data.asm +22 -0
  118. package/examples/snes/templates/sports.c +16 -1
  119. package/package.json +1 -1
  120. package/src/cheats/gamegenie.js +0 -1
  121. package/src/cli/smoke.js +1 -3
  122. package/src/cores/wasm/vice_x64_libretro.js +1 -1
  123. package/src/cores/wasm/vice_x64_libretro.wasm +0 -0
  124. package/src/host/LibretroHost.js +191 -16
  125. package/src/host/callbacks.js +9 -1
  126. package/src/host/chafa-render.js +2 -0
  127. package/src/host/dsp-state.js +2 -2
  128. package/src/host/gpgx-state.js +4 -0
  129. package/src/host/types.js +15 -8
  130. package/src/http/routes.js +1 -1
  131. package/src/http/tool-registry.js +26 -1
  132. package/src/mcp/server.js +1 -1
  133. package/src/mcp/state.js +36 -0
  134. package/src/mcp/tools/address-to-symbol.js +0 -1
  135. package/src/mcp/tools/art-loaders.js +1 -1
  136. package/src/mcp/tools/cart-parts.js +75 -4
  137. package/src/mcp/tools/classify-region.js +1 -1
  138. package/src/mcp/tools/diff-roms.js +1 -1
  139. package/src/mcp/tools/disasm-rebuild.js +507 -0
  140. package/src/mcp/tools/disasm.js +97 -9
  141. package/src/mcp/tools/find-references.js +1 -2
  142. package/src/mcp/tools/font-map.js +1 -1
  143. package/src/mcp/tools/frame.js +168 -3
  144. package/src/mcp/tools/index.js +0 -49
  145. package/src/mcp/tools/input-layout.js +0 -1
  146. package/src/mcp/tools/input.js +33 -3
  147. package/src/mcp/tools/lifecycle.js +18 -4
  148. package/src/mcp/tools/lospec.js +0 -19
  149. package/src/mcp/tools/platform-docs.js +1 -1
  150. package/src/mcp/tools/platform-tools.js +4 -4
  151. package/src/mcp/tools/project.js +54 -11
  152. package/src/mcp/tools/reinject.js +0 -1
  153. package/src/mcp/tools/rom-id.js +2 -2
  154. package/src/mcp/tools/snippets.js +2 -2
  155. package/src/mcp/tools/sprite-pipeline.js +1 -2
  156. package/src/mcp/tools/state.js +201 -14
  157. package/src/mcp/tools/tile-inspect.js +1 -1
  158. package/src/mcp/tools/toolchain.js +105 -12
  159. package/src/mcp/tools/watch-memory.js +137 -16
  160. package/src/platforms/_guides/ROMHACKING_PLAYBOOK.md +34 -0
  161. package/src/platforms/atari2600/TROUBLESHOOTING.md +6 -0
  162. package/src/platforms/atari7800/TROUBLESHOOTING.md +6 -0
  163. package/src/platforms/c64/MENTAL_MODEL.md +45 -1
  164. package/src/platforms/c64/TROUBLESHOOTING.md +6 -0
  165. package/src/platforms/c64/d64.js +280 -0
  166. package/src/platforms/c64/sid.js +0 -2
  167. package/src/platforms/common/metasprite-adapters.js +1 -1
  168. package/src/platforms/common/metasprite-codegen.js +3 -3
  169. package/src/platforms/common/registers.js +5 -3
  170. package/src/platforms/gb/MENTAL_MODEL.md +10 -0
  171. package/src/platforms/gb/TROUBLESHOOTING.md +6 -0
  172. package/src/platforms/gb/lib/c/gb_runtime.c +4 -4
  173. package/src/platforms/gba/TROUBLESHOOTING.md +6 -0
  174. package/src/platforms/gbc/TROUBLESHOOTING.md +6 -0
  175. package/src/platforms/gbc/lib/c/gb_runtime.c +4 -4
  176. package/src/platforms/genesis/TROUBLESHOOTING.md +6 -0
  177. package/src/platforms/gg/TROUBLESHOOTING.md +6 -0
  178. package/src/platforms/lynx/TROUBLESHOOTING.md +6 -0
  179. package/src/platforms/msx/MENTAL_MODEL.md +10 -6
  180. package/src/platforms/msx/TROUBLESHOOTING.md +6 -0
  181. package/src/platforms/nes/MENTAL_MODEL.md +63 -2
  182. package/src/platforms/nes/TROUBLESHOOTING.md +6 -0
  183. package/src/platforms/nes/image-to-tilemap.js +3 -0
  184. package/src/platforms/nes/lib/asm/famitone2.s +5 -1
  185. package/src/platforms/pce/MENTAL_MODEL.md +9 -4
  186. package/src/platforms/pce/TROUBLESHOOTING.md +6 -0
  187. package/src/platforms/pce/lib/c/pce_video.c +1 -1
  188. package/src/platforms/sms/TROUBLESHOOTING.md +6 -0
  189. package/src/platforms/snes/TROUBLESHOOTING.md +6 -0
  190. package/src/platforms/snes/brr.js +0 -2
  191. package/src/playtest/playtest.js +0 -7
  192. package/src/rom-id/identifier.js +15 -0
  193. package/src/toolchains/asar/asar.js +0 -9
  194. package/src/toolchains/assemble-snippet.js +30 -12
  195. package/src/toolchains/cc65/ines.js +145 -0
  196. package/src/toolchains/cc65/presets/nes/chr-ram-runtime.cfg +14 -1
  197. package/src/toolchains/cc65/presets/nes/chr-rom.cfg +83 -0
  198. package/src/toolchains/cc65/presets/nes/chr-rom.crt0.s +153 -0
  199. package/src/toolchains/common/reassemble.js +10 -3
  200. package/src/toolchains/common/sdk-cache.js +1 -1
  201. package/src/toolchains/genesis-c/genesis-c.js +5 -3
  202. package/src/toolchains/index.js +27 -3
  203. package/src/toolchains/parse-errors.js +78 -1
  204. package/src/toolchains/sdcc/preflight-lint.js +5 -1
  205. package/src/toolchains/sdcc/sdcc.js +1 -1
  206. package/src/toolchains/sjasm/sjasm.js +1 -1
  207. package/src/toolchains/snes-c/snes-c.js +2 -2
  208. package/src/toolchains/vasm68k/vasm68k.js +2 -4
  209. package/src/toolchains/wladx/wladx.js +1 -1
@@ -26,16 +26,22 @@
26
26
  #include "snes_sfx.c"
27
27
 
28
28
  extern char tilfont, palfont;
29
+ extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
29
30
 
30
31
  /* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
31
32
  * No public prototype in console.h, so declare it; call once per frame. */
32
33
  extern void consoleVblank(void);
33
34
 
35
+ /* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
36
+ * screen never reads as a flat/blank backdrop. Filled at runtime. */
37
+ static u16 bg_map[32 * 32];
38
+
34
39
  int main(void) {
35
40
  u16 pad;
36
41
  u16 prev = 0;
37
42
  u16 frame = 0;
38
43
  u8 music_running;
44
+ u16 i;
39
45
 
40
46
  /* ── Text-mode setup (PVSnesLib convention) ─────────────────── */
41
47
  consoleSetTextMapPtr(0x6800);
@@ -47,11 +53,18 @@ int main(void) {
47
53
  * registers — point BG0 at the same font ($3000) + map ($6800). */
48
54
  bgSetGfxPtr(0, 0x3000);
49
55
  bgSetMapPtr(0, 0x6800, SC_32x32);
50
- bgSetDisable(1);
51
- bgSetDisable(2);
52
56
 
53
- /* ── Upload SPC driver + sample bank + song table to ARAM ──── */
54
- sfx_init();
57
+ /* BG1 = full-screen wallpaper so the screen never reads as blank.
58
+ * Tiles -> VRAM $2000, map -> VRAM $4000 (clear of the console gfx
59
+ * $3000 / map $6800). Map entries use palette block 1 (0x0400) so the
60
+ * wallpaper palette doesn't disturb the console font palette in block 0
61
+ * (HUD text stays legible). */
62
+ bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
63
+ 32, 32, BG_16COLORS, 0x2000);
64
+ for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0400;
65
+ bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
66
+ bgSetEnable(1);
67
+ bgSetDisable(2);
55
68
 
56
69
  consoleDrawText( 8, 6, "SNES MUSIC DEMO");
57
70
  consoleDrawText( 3, 11, "B = SHOOT SFX");
@@ -60,6 +73,11 @@ int main(void) {
60
73
 
61
74
  setScreenOn();
62
75
 
76
+ /* Upload SPC driver + sample bank + song table to ARAM. sfx_init() must
77
+ * run AFTER setScreenOn() (snes_sfx.h:63) — if the SPC stalls before the
78
+ * screen is on you get a black/forced-blank screen forever. */
79
+ sfx_init();
80
+
63
81
  /* Auto-start music. */
64
82
  sfx_music_play();
65
83
  music_running = 1;
@@ -322,4 +322,26 @@ palsprite:
322
322
  .db $00, $00, $00, $00, $00, $00, $00, $00
323
323
  .db $00, $00, $00, $00, $00, $00, $00, $00
324
324
 
325
+ ; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
326
+ ; Tiled across BG1 it paints the whole screen in four muted colours so the
327
+ ; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
328
+ ; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
329
+ ; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
330
+ tilbg:
331
+ .db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
332
+ .db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
333
+ .db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
334
+ .db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
335
+
336
+ palbg:
337
+ ; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
338
+ .db $00, $00 ; 0 unused (BG fully opaque)
339
+ .db $C4, $30 ; 1 dark blue
340
+ .db $42, $29 ; 2 dark teal
341
+ .db $88, $30 ; 3 dark purple
342
+ .db $C6, $24 ; 4 dark slate
343
+ .db $00, $00, $00, $00, $00, $00, $00, $00
344
+ .db $00, $00, $00, $00, $00, $00, $00, $00
345
+ .db $00, $00, $00, $00, $00, $00
346
+
325
347
  .ends
@@ -23,11 +23,16 @@
23
23
 
24
24
  extern char tilfont, palfont;
25
25
  extern char tilsprite, palsprite;
26
+ extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
26
27
 
27
28
  /* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
28
29
  * No public prototype in console.h, so declare it; call once per frame. */
29
30
  extern void consoleVblank(void);
30
31
 
32
+ /* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
33
+ * playfield reads as a real backdrop, not flat blank. Filled at runtime. */
34
+ static u16 bg_map[32 * 32];
35
+
31
36
  typedef struct { s16 x, y, w, h; } Rect;
32
37
 
33
38
  #define WORLD_W 512
@@ -80,7 +85,17 @@ int main(void) {
80
85
  * registers — point BG0 at the same font ($3000) + map ($6800). */
81
86
  bgSetGfxPtr(0, 0x3000);
82
87
  bgSetMapPtr(0, 0x6800, SC_32x32);
83
- bgSetDisable(1);
88
+
89
+ /* BG1 = full-screen wallpaper so the playfield never reads as blank.
90
+ * Tiles -> VRAM $2000, map -> VRAM $4000 (clear of sprites $0000 and
91
+ * the console gfx $3000 / map $6800). Map entries use palette block 1
92
+ * (0x0400) so the wallpaper palette doesn't disturb the console font
93
+ * palette in block 0 (HUD text stays legible). */
94
+ bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
95
+ 32, 32, BG_16COLORS, 0x2000);
96
+ for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0400;
97
+ bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
98
+ bgSetEnable(1);
84
99
  bgSetDisable(2);
85
100
 
86
101
  oamInitGfxSet(&tilsprite, 32, &palsprite, 32, 0, 0x0000, OBJ_SIZE8_L16);
@@ -92,10 +107,13 @@ int main(void) {
92
107
  consoleDrawText( 9, 12, "|64");
93
108
  consoleDrawText(17, 12, "|128");
94
109
  consoleDrawText(25, 12, "|192");
95
- sfx_init();
96
110
 
97
111
  oamSet(0, 32, 100, 3, 0, 0, 0, 0);
112
+ /* Screen ON first, THEN sound. sfx_init() must run AFTER setScreenOn()
113
+ * (snes_sfx.h:63) — if the SPC stalls before the screen is on you get a
114
+ * black/forced-blank screen forever. */
98
115
  setScreenOn();
116
+ sfx_init();
99
117
 
100
118
  while (1) {
101
119
  pad = padsCurrent(0);
@@ -309,4 +309,26 @@ palfont:
309
309
  .db $00, $00, $00, $00, $00, $00, $00, $00
310
310
  .db $00, $00
311
311
 
312
+ ; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
313
+ ; Tiled across BG1 it paints the whole screen in four muted colours so the
314
+ ; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
315
+ ; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
316
+ ; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
317
+ tilbg:
318
+ .db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
319
+ .db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
320
+ .db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
321
+ .db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
322
+
323
+ palbg:
324
+ ; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
325
+ .db $00, $00 ; 0 unused (BG fully opaque)
326
+ .db $C4, $30 ; 1 dark blue
327
+ .db $42, $29 ; 2 dark teal
328
+ .db $88, $30 ; 3 dark purple
329
+ .db $C6, $24 ; 4 dark slate
330
+ .db $00, $00, $00, $00, $00, $00, $00, $00
331
+ .db $00, $00, $00, $00, $00, $00, $00, $00
332
+ .db $00, $00, $00, $00, $00, $00
333
+
312
334
  .ends
@@ -15,11 +15,16 @@
15
15
  #include "snes_sfx.c"
16
16
 
17
17
  extern char tilfont, palfont;
18
+ extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
18
19
 
19
20
  /* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
20
21
  * No public prototype in console.h, so declare it; call once per frame. */
21
22
  extern void consoleVblank(void);
22
23
 
24
+ /* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
25
+ * playfield reads as a real backdrop, not flat blank. Filled at runtime. */
26
+ static u16 bg_map[32 * 32];
27
+
23
28
  #define COLS 6
24
29
  #define ROWS 12
25
30
 
@@ -136,6 +141,7 @@ static void render_score(void) {
136
141
  int main(void) {
137
142
  s16 r, c;
138
143
  u16 pad, prev = 0, fall_rate;
144
+ u16 i;
139
145
  u8 t;
140
146
 
141
147
  consoleSetTextMapPtr(0x6800);
@@ -147,7 +153,17 @@ int main(void) {
147
153
  * registers — point BG0 at the same font ($3000) + map ($6800). */
148
154
  bgSetGfxPtr(0, 0x3000);
149
155
  bgSetMapPtr(0, 0x6800, SC_32x32);
150
- bgSetDisable(1);
156
+
157
+ /* BG1 = full-screen wallpaper so the playfield never reads as blank.
158
+ * Tiles -> VRAM $2000, map -> VRAM $4000 (clear of sprites $0000 and
159
+ * the console gfx $3000 / map $6800). Map entries use palette block 1
160
+ * (0x0400) so the wallpaper palette doesn't disturb the console font
161
+ * palette in block 0 (HUD/grid text stays legible). */
162
+ bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
163
+ 32, 32, BG_16COLORS, 0x2000);
164
+ for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0400;
165
+ bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
166
+ bgSetEnable(1);
151
167
  bgSetDisable(2);
152
168
 
153
169
  for (r = 0; r < ROWS; r++)
@@ -160,10 +176,13 @@ int main(void) {
160
176
 
161
177
  consoleDrawText(14, 2, "SCORE");
162
178
  consoleDrawText(2, 26, "LR MOVE A ROT START DROP");
163
- sfx_init();
164
179
  draw_grid();
165
180
 
181
+ /* Screen ON first, THEN sound. sfx_init() must run AFTER setScreenOn()
182
+ * (snes_sfx.h:63) — if the SPC stalls before the screen is on you get a
183
+ * black/forced-blank screen forever. */
166
184
  setScreenOn();
185
+ sfx_init();
167
186
 
168
187
  while (1) {
169
188
  pad = padsCurrent(0);
@@ -328,4 +328,26 @@ palsprite:
328
328
  .db $00, $00, $00, $00, $00, $00, $00, $00
329
329
  .db $00, $00, $00, $00, $00, $00, $00, $00
330
330
 
331
+ ; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
332
+ ; Tiled across BG1 it paints the whole screen in four muted colours so the
333
+ ; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
334
+ ; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
335
+ ; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
336
+ tilbg:
337
+ .db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
338
+ .db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
339
+ .db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
340
+ .db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
341
+
342
+ palbg:
343
+ ; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
344
+ .db $00, $00 ; 0 unused (BG fully opaque)
345
+ .db $C4, $30 ; 1 dark blue
346
+ .db $42, $29 ; 2 dark teal
347
+ .db $88, $30 ; 3 dark purple
348
+ .db $C6, $24 ; 4 dark slate
349
+ .db $00, $00, $00, $00, $00, $00, $00, $00
350
+ .db $00, $00, $00, $00, $00, $00, $00, $00
351
+ .db $00, $00, $00, $00, $00, $00
352
+
331
353
  .ends
@@ -12,11 +12,16 @@
12
12
 
13
13
  extern char tilfont, palfont;
14
14
  extern char tilsprite, palsprite;
15
+ extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
15
16
 
16
17
  /* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
17
18
  * No public prototype in console.h, so declare it; call once per frame. */
18
19
  extern void consoleVblank(void);
19
20
 
21
+ /* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
22
+ * playfield reads as a real backdrop, not flat blank. Filled at runtime. */
23
+ static u16 bg_map[32 * 32];
24
+
20
25
  #define LANE_LEFT_X 72
21
26
  #define LANE_MID_X 124
22
27
  #define LANE_RIGHT_X 176
@@ -103,6 +108,7 @@ static void draw_road(void) {
103
108
  int main(void) {
104
109
  u16 pad;
105
110
  u8 i;
111
+ u16 bi;
106
112
  s16 step;
107
113
 
108
114
  consoleSetTextMapPtr(0x6800);
@@ -114,7 +120,17 @@ int main(void) {
114
120
  * registers — point BG0 at the same font ($3000) + map ($6800). */
115
121
  bgSetGfxPtr(0, 0x3000);
116
122
  bgSetMapPtr(0, 0x6800, SC_32x32);
117
- bgSetDisable(1);
123
+
124
+ /* BG1 = full-screen wallpaper so the playfield never reads as blank.
125
+ * Tiles -> VRAM $2000, map -> VRAM $4000 (clear of sprites $0000 and
126
+ * the console gfx $3000 / map $6800). Map entries use palette block 1
127
+ * (0x0400) so the wallpaper palette doesn't disturb the console font
128
+ * palette in block 0 (HUD/road text stays legible). */
129
+ bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
130
+ 32, 32, BG_16COLORS, 0x2000);
131
+ for (bi = 0; bi < 32 * 32; bi++) bg_map[bi] = 0x0400;
132
+ bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
133
+ bgSetEnable(1);
118
134
  bgSetDisable(2);
119
135
 
120
136
  /* 2 sprite tiles × 32 bytes = 64 bytes */
@@ -351,4 +351,26 @@ palsprite:
351
351
  .db $00, $00, $00, $00, $00, $00, $00, $00
352
352
  .db $00, $00, $00, $00, $00, $00, $00, $00
353
353
 
354
+ ; ── Background wallpaper (one 8×8 4bpp tile, 4 solid colour quadrants) ──
355
+ ; Tiled across BG1 it paints the whole screen in four muted colours so the
356
+ ; playfield never reads as a flat/blank backdrop. Quadrant→colour: TL=1,
357
+ ; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
358
+ ; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
359
+ tilbg:
360
+ .db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
361
+ .db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
362
+ .db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
363
+ .db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
364
+
365
+ palbg:
366
+ ; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
367
+ .db $00, $00 ; 0 unused (BG fully opaque)
368
+ .db $C4, $30 ; 1 dark blue
369
+ .db $42, $29 ; 2 dark teal
370
+ .db $88, $30 ; 3 dark purple
371
+ .db $C6, $24 ; 4 dark slate
372
+ .db $00, $00, $00, $00, $00, $00, $00, $00
373
+ .db $00, $00, $00, $00, $00, $00, $00, $00
374
+ .db $00, $00, $00, $00, $00, $00
375
+
354
376
  .ends
@@ -31,6 +31,7 @@
31
31
 
32
32
  extern char tilfont, palfont;
33
33
  extern char tilsprite, palsprite;
34
+ extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
34
35
 
35
36
  /* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
36
37
  * No public prototype in console.h, so declare it; call once per frame. */
@@ -39,6 +40,10 @@ extern void consoleVblank(void);
39
40
  /* OAM is addressed by BYTE OFFSET; sprite slot N = offset N*4. */
40
41
  #define SPR(slot) ((slot) << 2)
41
42
 
43
+ /* BG1 wallpaper map: a full 32×32 screen of the 4-colour tile so the
44
+ * playfield reads as a real backdrop, not flat blank. Filled at runtime. */
45
+ static u16 bg_map[32 * 32];
46
+
42
47
  #define MAX_BULLETS 6
43
48
  #define MAX_ENEMIES 6
44
49
 
@@ -124,7 +129,21 @@ int main(void) {
124
129
  * font ($3000) + map ($6800) so the HUD text renders. */
125
130
  bgSetGfxPtr(0, 0x3000);
126
131
  bgSetMapPtr(0, 0x6800, SC_32x32);
127
- bgSetDisable(1);
132
+
133
+ /* BG1 = full-screen wallpaper so the playfield never reads as blank.
134
+ * Tiles → VRAM $2000, map → VRAM $4000 (clear of sprites $0000 and the
135
+ * console gfx $3000 / map $6800). One 8×8 tile = 32 bytes of gfx +
136
+ * 32 bytes of palette. */
137
+ bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg,
138
+ 1, /* load palbg into CGRAM palette block 1 */
139
+ 32, 32, BG_16COLORS, 0x2000);
140
+ /* Every map entry: tile 0, palette block 1 (bits 10-12 = 1 → 0x0400),
141
+ * so the wallpaper uses palbg and leaves the console font palette
142
+ * (block 0) untouched — HUD text stays white/legible. */
143
+ for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0400;
144
+ bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
145
+ bgSetEnable(1);
146
+
128
147
  bgSetDisable(2);
129
148
  setPaletteColor(0, RGB5(0, 0, 6)); /* dark-blue backdrop (CGRAM 0) */
130
149
 
@@ -323,4 +323,26 @@ palsprite:
323
323
  .db $00, $00, $00, $00, $00, $00, $00, $00
324
324
  .db $00, $00, $00, $00, $00, $00, $00, $00
325
325
 
326
+ ; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
327
+ ; Tiled across BG1 it paints the whole screen in four muted colours so the
328
+ ; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
329
+ ; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
330
+ ; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
331
+ tilbg:
332
+ .db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
333
+ .db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
334
+ .db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
335
+ .db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
336
+
337
+ palbg:
338
+ ; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
339
+ .db $00, $00 ; 0 unused (BG fully opaque)
340
+ .db $C4, $30 ; 1 dark blue
341
+ .db $42, $29 ; 2 dark teal
342
+ .db $88, $30 ; 3 dark purple
343
+ .db $C6, $24 ; 4 dark slate
344
+ .db $00, $00, $00, $00, $00, $00, $00, $00
345
+ .db $00, $00, $00, $00, $00, $00, $00, $00
346
+ .db $00, $00, $00, $00, $00, $00
347
+
326
348
  .ends
@@ -15,11 +15,16 @@
15
15
 
16
16
  extern char tilfont, palfont;
17
17
  extern char tilsprite, palsprite;
18
+ extern char tilbg, palbg; /* wallpaper tile + palette (data.asm) */
18
19
 
19
20
  /* consoleVblank() copies the dirty text tilemap to VRAM during VBlank.
20
21
  * No public prototype in console.h, so declare it; call once per frame. */
21
22
  extern void consoleVblank(void);
22
23
 
24
+ /* BG1 wallpaper map: a full 32x32 screen of the 4-colour tile so the
25
+ * court reads as a real backdrop, not flat blank. Filled at runtime. */
26
+ static u16 bg_map[32 * 32];
27
+
23
28
  #define COURT_TOP 16
24
29
  #define COURT_BOT 208
25
30
  #define PADDLE_H 24
@@ -96,7 +101,17 @@ int main(void) {
96
101
  * registers — point BG0 at the same font ($3000) + map ($6800). */
97
102
  bgSetGfxPtr(0, 0x3000);
98
103
  bgSetMapPtr(0, 0x6800, SC_32x32);
99
- bgSetDisable(1);
104
+
105
+ /* BG1 = full-screen wallpaper so the court never reads as blank.
106
+ * Tiles -> VRAM $2000, map -> VRAM $4000 (clear of sprites $0000 and
107
+ * the console gfx $3000 / map $6800). Map entries use palette block 1
108
+ * (0x0400) so the wallpaper palette doesn't disturb the console font
109
+ * palette in block 0 (HUD/court text stays legible). */
110
+ bgInitTileSet(1, (u8 *)&tilbg, (u8 *)&palbg, 1,
111
+ 32, 32, BG_16COLORS, 0x2000);
112
+ for (i = 0; i < 32 * 32; i++) bg_map[i] = 0x0400;
113
+ bgInitMapSet(1, (u8 *)bg_map, sizeof(bg_map), SC_32x32, 0x4000);
114
+ bgSetEnable(1);
100
115
  bgSetDisable(2);
101
116
 
102
117
  oamInitGfxSet(&tilsprite, 32, &palsprite, 32, 0, 0x0000, OBJ_SIZE8_L16);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "romdevtools",
3
- "version": "0.16.0",
3
+ "version": "0.22.0",
4
4
  "description": "Tool server giving coding agents full control of homebrew ROM development AND reverse-engineering/romhacking across 14 retro platforms (NES, SNES, GB, Genesis, Atari, C64, PC Engine, MSX, ...) via WASM toolchains + emulator cores. Use over plain HTTP, as an Agent Skill, or as an MCP server.",
5
5
  "type": "module",
6
6
  "main": "src/mcp/server.js",
@@ -446,7 +446,6 @@ export function decodeWithDevice(code, platform) {
446
446
 
447
447
  /** Format a raw ADDR:VAL[:COMPARE] code from decoded parts (hex, no 0x). */
448
448
  export function encodeRaw({ address, value, compare }) {
449
- const h = (n, w) => (n & ((1 << (4 * w)) - 1) >>> 0).toString(16).toUpperCase().padStart(w, "0");
450
449
  const addrHex = (address >>> 0).toString(16).toUpperCase();
451
450
  const valHex = (value & 0xFF).toString(16).toUpperCase().padStart(2, "0");
452
451
  return compare != null
package/src/cli/smoke.js CHANGED
@@ -14,7 +14,7 @@
14
14
  // temp file and loaded into the matching libretro core. Platform is
15
15
  // inferred from the file extension if not given.
16
16
 
17
- import { writeFile, mkdtemp, readdir } from "node:fs/promises";
17
+ import { writeFile, mkdtemp } from "node:fs/promises";
18
18
  import { existsSync, statSync } from "node:fs";
19
19
  import { tmpdir } from "node:os";
20
20
  import path from "node:path";
@@ -108,12 +108,10 @@ async function playCommand(romPath, opts) {
108
108
 
109
109
  // Extract zip if needed
110
110
  let actualPath = romPath;
111
- let extracted = false;
112
111
  if (path.extname(romPath).toLowerCase() === ".zip") {
113
112
  console.error(`unzipping ${path.basename(romPath)}...`);
114
113
  const { tempPath, originalName } = await extractFirstRomFromZip(romPath);
115
114
  actualPath = tempPath;
116
- extracted = true;
117
115
  console.error(` → ${originalName} (${statSync(tempPath).size} bytes)`);
118
116
  }
119
117