romdevtools 0.13.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 (1346) hide show
  1. package/AGENTS.md +1110 -0
  2. package/CHANGELOG.md +525 -0
  3. package/LICENSE +45 -0
  4. package/NOTICE +102 -0
  5. package/README.md +84 -0
  6. package/examples/README.md +36 -0
  7. package/examples/art-first-workflow/README.md +209 -0
  8. package/examples/atari2600/main.asm +143 -0
  9. package/examples/atari2600/templates/default.asm +183 -0
  10. package/examples/atari2600/templates/mini_invaders.asm +381 -0
  11. package/examples/atari2600/templates/music_demo.asm +322 -0
  12. package/examples/atari2600/templates/paddle.asm +345 -0
  13. package/examples/atari2600/templates/single_screen.asm +242 -0
  14. package/examples/atari7800/main.c +88 -0
  15. package/examples/atari7800/templates/default.c +183 -0
  16. package/examples/atari7800/templates/hello_sprite.c +141 -0
  17. package/examples/atari7800/templates/music_demo.c +123 -0
  18. package/examples/atari7800/templates/platformer.c +159 -0
  19. package/examples/atari7800/templates/puzzle.c +164 -0
  20. package/examples/atari7800/templates/racing.c +139 -0
  21. package/examples/atari7800/templates/shmup.c +148 -0
  22. package/examples/atari7800/templates/sports.c +207 -0
  23. package/examples/c64/main.c +63 -0
  24. package/examples/c64/templates/hello_sprite.c +117 -0
  25. package/examples/c64/templates/music_demo.c +131 -0
  26. package/examples/c64/templates/platformer.c +194 -0
  27. package/examples/c64/templates/puzzle.c +178 -0
  28. package/examples/c64/templates/racing.c +140 -0
  29. package/examples/c64/templates/shmup.c +201 -0
  30. package/examples/c64/templates/sports.c +109 -0
  31. package/examples/c64/templates/tile_engine.c +174 -0
  32. package/examples/gb/main.asm +106 -0
  33. package/examples/gb/main.c +49 -0
  34. package/examples/gb/templates/default.c +58 -0
  35. package/examples/gb/templates/hello_sprite.c +130 -0
  36. package/examples/gb/templates/music_demo.c +52 -0
  37. package/examples/gb/templates/platformer.c +178 -0
  38. package/examples/gb/templates/puzzle.c +217 -0
  39. package/examples/gb/templates/racing.c +158 -0
  40. package/examples/gb/templates/shmup.c +172 -0
  41. package/examples/gb/templates/sports.c +136 -0
  42. package/examples/gb/templates/tile_engine.c +280 -0
  43. package/examples/gba/templates/gba_hello.c +64 -0
  44. package/examples/gba/templates/maxmod_demo.c +105 -0
  45. package/examples/gba/templates/platformer.c +215 -0
  46. package/examples/gba/templates/puzzle.c +237 -0
  47. package/examples/gba/templates/racing.c +175 -0
  48. package/examples/gba/templates/shmup.c +197 -0
  49. package/examples/gba/templates/sports.c +177 -0
  50. package/examples/gba/templates/tonc_hello.c +72 -0
  51. package/examples/gba/templates/tonc_hello_sprite.c +109 -0
  52. package/examples/gbc/main.asm +123 -0
  53. package/examples/gbc/templates/default.c +61 -0
  54. package/examples/gbc/templates/hello_sprite.c +140 -0
  55. package/examples/gbc/templates/music_demo.c +63 -0
  56. package/examples/gbc/templates/platformer.c +181 -0
  57. package/examples/gbc/templates/puzzle.c +217 -0
  58. package/examples/gbc/templates/racing.c +164 -0
  59. package/examples/gbc/templates/shmup.c +188 -0
  60. package/examples/gbc/templates/sports.c +142 -0
  61. package/examples/gbc/templates/tile_engine.c +280 -0
  62. package/examples/genesis/main.s +161 -0
  63. package/examples/genesis/templates/hello_sprite.c +75 -0
  64. package/examples/genesis/templates/platformer.c +166 -0
  65. package/examples/genesis/templates/puzzle.c +240 -0
  66. package/examples/genesis/templates/racing.c +170 -0
  67. package/examples/genesis/templates/sgdk_hello.c +41 -0
  68. package/examples/genesis/templates/shmup.c +188 -0
  69. package/examples/genesis/templates/shmup_2p.c +244 -0
  70. package/examples/genesis/templates/sports.c +172 -0
  71. package/examples/genesis/templates/tile_engine.c +135 -0
  72. package/examples/genesis/templates/xgm2_demo.c +53 -0
  73. package/examples/genesis/templates/xgm2_demo_data.s +27 -0
  74. package/examples/gg/main.c +10 -0
  75. package/examples/gg/templates/default.c +156 -0
  76. package/examples/gg/templates/hello_sprite.c +90 -0
  77. package/examples/gg/templates/music_demo.c +156 -0
  78. package/examples/gg/templates/platformer.c +220 -0
  79. package/examples/gg/templates/puzzle.c +204 -0
  80. package/examples/gg/templates/racing.c +161 -0
  81. package/examples/gg/templates/shmup.c +188 -0
  82. package/examples/gg/templates/sports.c +137 -0
  83. package/examples/gg/templates/tile_engine.c +137 -0
  84. package/examples/lynx/main.c +4 -0
  85. package/examples/lynx/templates/default.c +41 -0
  86. package/examples/lynx/templates/hello_sprite.c +39 -0
  87. package/examples/lynx/templates/music_demo.c +37 -0
  88. package/examples/lynx/templates/platformer.c +72 -0
  89. package/examples/lynx/templates/puzzle.c +142 -0
  90. package/examples/lynx/templates/racing.c +94 -0
  91. package/examples/lynx/templates/shmup.c +132 -0
  92. package/examples/lynx/templates/sports.c +59 -0
  93. package/examples/msx/catch_game/README.md +75 -0
  94. package/examples/msx/catch_game/_verify.mjs +93 -0
  95. package/examples/msx/catch_game/main.c +249 -0
  96. package/examples/msx/catch_game/shot_after_left.png +0 -0
  97. package/examples/msx/catch_game/shot_after_right.png +0 -0
  98. package/examples/msx/catch_game/shot_before.png +0 -0
  99. package/examples/msx/catch_game/shot_scored.png +0 -0
  100. package/examples/msx/music_sfx/README.md +38 -0
  101. package/examples/msx/music_sfx/main.c +164 -0
  102. package/examples/msx/sprite_move/README.md +44 -0
  103. package/examples/msx/sprite_move/main.c +100 -0
  104. package/examples/nes/main.c +143 -0
  105. package/examples/nes/space-shooter/README.md +69 -0
  106. package/examples/nes/space-shooter/main.c +441 -0
  107. package/examples/nes/space-shooter/nes_runtime.c +347 -0
  108. package/examples/nes/space-shooter/nes_runtime.h +141 -0
  109. package/examples/nes/templates/default.c +41 -0
  110. package/examples/nes/templates/hello_sprite.c +104 -0
  111. package/examples/nes/templates/music_demo.c +80 -0
  112. package/examples/nes/templates/platformer.c +171 -0
  113. package/examples/nes/templates/puzzle.c +232 -0
  114. package/examples/nes/templates/racing.c +203 -0
  115. package/examples/nes/templates/shmup.c +228 -0
  116. package/examples/nes/templates/sports.c +205 -0
  117. package/examples/nes/templates/tile_engine.c +224 -0
  118. package/examples/pce/catch_game/README.md +8 -0
  119. package/examples/pce/catch_game/_verify.mjs +75 -0
  120. package/examples/pce/catch_game/main.c +327 -0
  121. package/examples/pce/catch_game/shot_after.png +0 -0
  122. package/examples/pce/catch_game/shot_before.png +0 -0
  123. package/examples/pce/main.c +37 -0
  124. package/examples/pce/music_sfx/README.md +8 -0
  125. package/examples/pce/music_sfx/main.c +154 -0
  126. package/examples/pce/sprite_move/README.md +19 -0
  127. package/examples/pce/sprite_move/main.c +155 -0
  128. package/examples/porting-across-platforms/README.md +59 -0
  129. package/examples/sms/main.c +129 -0
  130. package/examples/sms/templates/default.c +110 -0
  131. package/examples/sms/templates/hello_sprite.c +90 -0
  132. package/examples/sms/templates/music_demo.c +151 -0
  133. package/examples/sms/templates/platformer.c +215 -0
  134. package/examples/sms/templates/puzzle.c +204 -0
  135. package/examples/sms/templates/racing.c +161 -0
  136. package/examples/sms/templates/shmup.c +167 -0
  137. package/examples/sms/templates/shmup_2p.c +219 -0
  138. package/examples/sms/templates/sports.c +147 -0
  139. package/examples/sms/templates/tile_engine.c +137 -0
  140. package/examples/snes/main.asm +70 -0
  141. package/examples/snes/templates/c-hello-data.asm +28 -0
  142. package/examples/snes/templates/c-hello.c +71 -0
  143. package/examples/snes/templates/default-data.asm +36 -0
  144. package/examples/snes/templates/default.c +74 -0
  145. package/examples/snes/templates/hello_sprite-data.asm +45 -0
  146. package/examples/snes/templates/hello_sprite.c +76 -0
  147. package/examples/snes/templates/music_demo-data.asm +20 -0
  148. package/examples/snes/templates/music_demo.c +83 -0
  149. package/examples/snes/templates/platformer-data.asm +27 -0
  150. package/examples/snes/templates/platformer.c +142 -0
  151. package/examples/snes/templates/puzzle-data.asm +14 -0
  152. package/examples/snes/templates/puzzle.c +199 -0
  153. package/examples/snes/templates/racing-data.asm +33 -0
  154. package/examples/snes/templates/racing.c +146 -0
  155. package/examples/snes/templates/shmup-data.asm +61 -0
  156. package/examples/snes/templates/shmup.c +199 -0
  157. package/examples/snes/templates/sports-data.asm +28 -0
  158. package/examples/snes/templates/sports.c +144 -0
  159. package/package.json +97 -0
  160. package/src/cheats/gamegenie.js +506 -0
  161. package/src/cheats/lookup.js +262 -0
  162. package/src/cheats/parse-cht.js +92 -0
  163. package/src/cli/smoke.js +283 -0
  164. package/src/cores/registry.js +99 -0
  165. package/src/cores/wasm/bluemsx_libretro.js +2 -0
  166. package/src/cores/wasm/bluemsx_libretro.wasm +0 -0
  167. package/src/cores/wasm/fceumm_libretro.js +2 -0
  168. package/src/cores/wasm/fceumm_libretro.wasm +0 -0
  169. package/src/cores/wasm/gambatte_libretro.js +2 -0
  170. package/src/cores/wasm/gambatte_libretro.wasm +0 -0
  171. package/src/cores/wasm/geargrafx_libretro.js +2 -0
  172. package/src/cores/wasm/geargrafx_libretro.wasm +0 -0
  173. package/src/cores/wasm/genesis_plus_gx_libretro.js +2 -0
  174. package/src/cores/wasm/genesis_plus_gx_libretro.wasm +0 -0
  175. package/src/cores/wasm/handy_libretro.js +2 -0
  176. package/src/cores/wasm/handy_libretro.wasm +0 -0
  177. package/src/cores/wasm/mgba_libretro.js +2 -0
  178. package/src/cores/wasm/mgba_libretro.wasm +0 -0
  179. package/src/cores/wasm/prosystem_libretro.js +2 -0
  180. package/src/cores/wasm/prosystem_libretro.wasm +0 -0
  181. package/src/cores/wasm/snes9x_libretro.js +2 -0
  182. package/src/cores/wasm/snes9x_libretro.wasm +0 -0
  183. package/src/cores/wasm/stella2014_libretro.js +2 -0
  184. package/src/cores/wasm/stella2014_libretro.wasm +0 -0
  185. package/src/cores/wasm/vice_x64_libretro.js +2 -0
  186. package/src/cores/wasm/vice_x64_libretro.wasm +0 -0
  187. package/src/host/LibretroHost.js +1469 -0
  188. package/src/host/c64-sid-state.js +161 -0
  189. package/src/host/callbacks.js +444 -0
  190. package/src/host/chafa-render.js +170 -0
  191. package/src/host/coreLoader.js +57 -0
  192. package/src/host/cpu-state.js +543 -0
  193. package/src/host/dsp-state.js +188 -0
  194. package/src/host/framebuffer.js +115 -0
  195. package/src/host/gb-apu-state.js +321 -0
  196. package/src/host/gba-video-state.js +215 -0
  197. package/src/host/gpgx-state.js +320 -0
  198. package/src/host/index.js +4 -0
  199. package/src/host/lynx-mikey-state.js +226 -0
  200. package/src/host/msx-ay-state.js +78 -0
  201. package/src/host/nes-apu-state.js +194 -0
  202. package/src/host/pce-psg-state.js +82 -0
  203. package/src/host/retroConstants.js +72 -0
  204. package/src/host/snes9x-state.js +35 -0
  205. package/src/host/types.js +332 -0
  206. package/src/http/routes.js +182 -0
  207. package/src/http/skill-doc.js +176 -0
  208. package/src/http/swagger.js +84 -0
  209. package/src/http/tool-registry.js +142 -0
  210. package/src/install/postinstall.mjs +81 -0
  211. package/src/mcp/disclosure.js +250 -0
  212. package/src/mcp/log.js +87 -0
  213. package/src/mcp/server.js +498 -0
  214. package/src/mcp/state.js +88 -0
  215. package/src/mcp/tool-manifest.js +92 -0
  216. package/src/mcp/tools/address-to-symbol.js +145 -0
  217. package/src/mcp/tools/art-loaders.js +743 -0
  218. package/src/mcp/tools/assets.js +87 -0
  219. package/src/mcp/tools/audio.js +562 -0
  220. package/src/mcp/tools/cart-parts.js +651 -0
  221. package/src/mcp/tools/cheats.js +343 -0
  222. package/src/mcp/tools/classify-region.js +107 -0
  223. package/src/mcp/tools/diff-cluster.js +32 -0
  224. package/src/mcp/tools/diff-roms.js +394 -0
  225. package/src/mcp/tools/disasm.js +1410 -0
  226. package/src/mcp/tools/find-references.js +375 -0
  227. package/src/mcp/tools/font-map.js +563 -0
  228. package/src/mcp/tools/frame.js +293 -0
  229. package/src/mcp/tools/free-space.js +71 -0
  230. package/src/mcp/tools/index.js +339 -0
  231. package/src/mcp/tools/input-layout.js +231 -0
  232. package/src/mcp/tools/input.js +227 -0
  233. package/src/mcp/tools/lifecycle.js +132 -0
  234. package/src/mcp/tools/lospec.js +187 -0
  235. package/src/mcp/tools/memory.js +472 -0
  236. package/src/mcp/tools/metasprite-tools.js +256 -0
  237. package/src/mcp/tools/platform-docs.js +113 -0
  238. package/src/mcp/tools/platform-tools.js +1300 -0
  239. package/src/mcp/tools/platforms.js +139 -0
  240. package/src/mcp/tools/playtest.js +360 -0
  241. package/src/mcp/tools/preview-tile.js +478 -0
  242. package/src/mcp/tools/project.js +1939 -0
  243. package/src/mcp/tools/record.js +180 -0
  244. package/src/mcp/tools/reinject.js +732 -0
  245. package/src/mcp/tools/rendering-context.js +838 -0
  246. package/src/mcp/tools/rom-id.js +308 -0
  247. package/src/mcp/tools/run-until.js +176 -0
  248. package/src/mcp/tools/snippets.js +209 -0
  249. package/src/mcp/tools/splice-chr.js +190 -0
  250. package/src/mcp/tools/sprite-pipeline.js +626 -0
  251. package/src/mcp/tools/state.js +198 -0
  252. package/src/mcp/tools/symbols.js +400 -0
  253. package/src/mcp/tools/tile-inspect.js +293 -0
  254. package/src/mcp/tools/toolchain.js +720 -0
  255. package/src/mcp/tools/trace-vram-source.js +81 -0
  256. package/src/mcp/tools/watch-memory.js +1036 -0
  257. package/src/mcp/tools/which-tiles.js +180 -0
  258. package/src/mcp/util.js +355 -0
  259. package/src/observer/bus.js +127 -0
  260. package/src/observer/livestream.html +594 -0
  261. package/src/observer/server.js +78 -0
  262. package/src/observer/tool-wrap.js +142 -0
  263. package/src/platforms/_guides/MUSIC_SOURCING.md +104 -0
  264. package/src/platforms/_guides/ROMHACKING_PLAYBOOK.md +245 -0
  265. package/src/platforms/atari2600/MENTAL_MODEL.md +194 -0
  266. package/src/platforms/atari2600/TROUBLESHOOTING.md +155 -0
  267. package/src/platforms/atari2600/UPSTREAM_SOURCES.md +49 -0
  268. package/src/platforms/atari2600/lib/README.md +67 -0
  269. package/src/platforms/atari2600/lib/cc65-src/crt0.s +49 -0
  270. package/src/platforms/atari2600/lib/cc65-src/ctype.s +5 -0
  271. package/src/platforms/atari2600/lib/kernel_skeleton.asm +85 -0
  272. package/src/platforms/atari2600/lib/player_kernel.asm +87 -0
  273. package/src/platforms/atari2600/lib/playfield_kernel.asm +63 -0
  274. package/src/platforms/atari2600/lib/read_joystick.asm +76 -0
  275. package/src/platforms/atari2600/lib/score_kernel.asm +141 -0
  276. package/src/platforms/atari2600/lib/vcs_constants.h +97 -0
  277. package/src/platforms/atari2600/lib/vectors.asm +16 -0
  278. package/src/platforms/atari2600/tia.js +355 -0
  279. package/src/platforms/atari7800/MENTAL_MODEL.md +324 -0
  280. package/src/platforms/atari7800/TROUBLESHOOTING.md +195 -0
  281. package/src/platforms/atari7800/UPSTREAM_SOURCES.md +43 -0
  282. package/src/platforms/atari7800/lib/README.md +45 -0
  283. package/src/platforms/atari7800/lib/c/atari7800_music.c +215 -0
  284. package/src/platforms/atari7800/lib/c/atari7800_music.h +33 -0
  285. package/src/platforms/atari7800/lib/c/atari7800_sfx.c +74 -0
  286. package/src/platforms/atari7800/lib/c/atari7800_sfx.h +45 -0
  287. package/src/platforms/atari7800/lib/cc65-src/clock.s +69 -0
  288. package/src/platforms/atari7800/lib/cc65-src/clocks_per_sec.s +34 -0
  289. package/src/platforms/atari7800/lib/cc65-src/clrscr.s +27 -0
  290. package/src/platforms/atari7800/lib/cc65-src/conio.s +226 -0
  291. package/src/platforms/atari7800/lib/cc65-src/conio_font.s +278 -0
  292. package/src/platforms/atari7800/lib/cc65-src/cputc.s +139 -0
  293. package/src/platforms/atari7800/lib/cc65-src/crt0.s +71 -0
  294. package/src/platforms/atari7800/lib/cc65-src/ctype.s +5 -0
  295. package/src/platforms/atari7800/lib/cc65-src/exehdr.s +46 -0
  296. package/src/platforms/atari7800/lib/cc65-src/extra/mono.s +28 -0
  297. package/src/platforms/atari7800/lib/cc65-src/extzp.inc +15 -0
  298. package/src/platforms/atari7800/lib/cc65-src/extzp.s +15 -0
  299. package/src/platforms/atari7800/lib/cc65-src/get_tv.s +65 -0
  300. package/src/platforms/atari7800/lib/cc65-src/irq.s +36 -0
  301. package/src/platforms/atari7800/lib/cc65-src/joy/atari7800-stdjoy.s +197 -0
  302. package/src/platforms/atari7800/lib/cc65-src/joy_stat_stddrv.s +14 -0
  303. package/src/platforms/atari7800/lib/cc65-src/libref.s +8 -0
  304. package/src/platforms/atari7800/lib/cc65-src/mono_clrscr.s +27 -0
  305. package/src/platforms/atari7800/lib/cc65-src/mono_conio.s +231 -0
  306. package/src/platforms/atari7800/lib/cc65-src/mono_cputc.s +102 -0
  307. package/src/platforms/atari7800/lib/cc65-src/mono_font.s +2065 -0
  308. package/src/platforms/atari7800/lib/cc65-src/mono_setcursor.s +214 -0
  309. package/src/platforms/atari7800/lib/cc65-src/setcursor.s +214 -0
  310. package/src/platforms/atari7800/lib/cc65-src/textcolor.s +53 -0
  311. package/src/platforms/atari7800/lib/cc65-src/wherex.s +19 -0
  312. package/src/platforms/atari7800/lib/cc65-src/wherey.s +19 -0
  313. package/src/platforms/atari7800/lib/display_list.asm +53 -0
  314. package/src/platforms/atari7800/lib/maria_init.asm +48 -0
  315. package/src/platforms/atari7800/lib/maria_registers.h +61 -0
  316. package/src/platforms/atari7800/lib/palette_load.asm +53 -0
  317. package/src/platforms/atari7800/lib/read_pad.asm +57 -0
  318. package/src/platforms/atari7800/lib/vblank_wait.asm +16 -0
  319. package/src/platforms/atari7800/maria.js +220 -0
  320. package/src/platforms/atari7800/song.js +232 -0
  321. package/src/platforms/c64/MENTAL_MODEL.md +188 -0
  322. package/src/platforms/c64/TROUBLESHOOTING.md +130 -0
  323. package/src/platforms/c64/UPSTREAM_SOURCES.md +35 -0
  324. package/src/platforms/c64/image-to-tilemap.js +190 -0
  325. package/src/platforms/c64/lib/README.md +52 -0
  326. package/src/platforms/c64/lib/basic_stub.s +25 -0
  327. package/src/platforms/c64/lib/c/c64_music.c +248 -0
  328. package/src/platforms/c64/lib/c/c64_music.h +36 -0
  329. package/src/platforms/c64/lib/c/c64_sfx.c +94 -0
  330. package/src/platforms/c64/lib/c/c64_sfx.h +37 -0
  331. package/src/platforms/c64/lib/c64_registers.h +108 -0
  332. package/src/platforms/c64/lib/cc65-src/_scrsize.s +12 -0
  333. package/src/platforms/c64/lib/cc65-src/acc_c128_speed.s +5 -0
  334. package/src/platforms/c64/lib/cc65-src/acc_c64dtv_speed.s +64 -0
  335. package/src/platforms/c64/lib/cc65-src/acc_c65_speed.s +69 -0
  336. package/src/platforms/c64/lib/cc65-src/acc_chameleon_speed.s +100 -0
  337. package/src/platforms/c64/lib/cc65-src/acc_detect_c128.s +33 -0
  338. package/src/platforms/c64/lib/cc65-src/acc_detect_c64dtv.s +44 -0
  339. package/src/platforms/c64/lib/cc65-src/acc_detect_c65.s +55 -0
  340. package/src/platforms/c64/lib/cc65-src/acc_detect_chameleon.s +39 -0
  341. package/src/platforms/c64/lib/cc65-src/acc_detect_scpu.s +34 -0
  342. package/src/platforms/c64/lib/cc65-src/acc_detect_turbomaster.s +45 -0
  343. package/src/platforms/c64/lib/cc65-src/acc_scpu_speed.s +59 -0
  344. package/src/platforms/c64/lib/cc65-src/acc_turbomaster_speed.s +56 -0
  345. package/src/platforms/c64/lib/cc65-src/bordercolor.s +17 -0
  346. package/src/platforms/c64/lib/cc65-src/break.s +108 -0
  347. package/src/platforms/c64/lib/cc65-src/cgetc.s +62 -0
  348. package/src/platforms/c64/lib/cc65-src/clrscr.s +11 -0
  349. package/src/platforms/c64/lib/cc65-src/color.s +24 -0
  350. package/src/platforms/c64/lib/cc65-src/conio.s +10 -0
  351. package/src/platforms/c64/lib/cc65-src/cputc.s +105 -0
  352. package/src/platforms/c64/lib/cc65-src/crt0.s +117 -0
  353. package/src/platforms/c64/lib/cc65-src/devnum.s +7 -0
  354. package/src/platforms/c64/lib/cc65-src/emd/c64-65816.s +377 -0
  355. package/src/platforms/c64/lib/cc65-src/emd/c64-c256k.s +508 -0
  356. package/src/platforms/c64/lib/cc65-src/emd/c64-dqbb.s +447 -0
  357. package/src/platforms/c64/lib/cc65-src/emd/c64-georam.s +355 -0
  358. package/src/platforms/c64/lib/cc65-src/emd/c64-isepic.s +276 -0
  359. package/src/platforms/c64/lib/cc65-src/emd/c64-kerberos.s +281 -0
  360. package/src/platforms/c64/lib/cc65-src/emd/c64-ram.s +270 -0
  361. package/src/platforms/c64/lib/cc65-src/emd/c64-ramcart.s +297 -0
  362. package/src/platforms/c64/lib/cc65-src/emd/c64-reu.s +286 -0
  363. package/src/platforms/c64/lib/cc65-src/emd/c64-rrr.s +363 -0
  364. package/src/platforms/c64/lib/cc65-src/emd/c64-vdc.s +405 -0
  365. package/src/platforms/c64/lib/cc65-src/emd/dtv-himem.s +251 -0
  366. package/src/platforms/c64/lib/cc65-src/extra/soft80.s +71 -0
  367. package/src/platforms/c64/lib/cc65-src/extra/soft80mono.s +74 -0
  368. package/src/platforms/c64/lib/cc65-src/extra/tgimousedata.s +21 -0
  369. package/src/platforms/c64/lib/cc65-src/get_ostype.s +43 -0
  370. package/src/platforms/c64/lib/cc65-src/get_tv.s +20 -0
  371. package/src/platforms/c64/lib/cc65-src/gettime.s +83 -0
  372. package/src/platforms/c64/lib/cc65-src/irq.s +49 -0
  373. package/src/platforms/c64/lib/cc65-src/joy/c64-hitjoy.s +218 -0
  374. package/src/platforms/c64/lib/cc65-src/joy/c64-numpad.s +155 -0
  375. package/src/platforms/c64/lib/cc65-src/joy/c64-ptvjoy.s +146 -0
  376. package/src/platforms/c64/lib/cc65-src/joy/c64-stdjoy.s +111 -0
  377. package/src/platforms/c64/lib/cc65-src/joy_stat_stddrv.s +14 -0
  378. package/src/platforms/c64/lib/cc65-src/joy_stddrv.s +14 -0
  379. package/src/platforms/c64/lib/cc65-src/kbhit.s +23 -0
  380. package/src/platforms/c64/lib/cc65-src/kbrepeat.s +14 -0
  381. package/src/platforms/c64/lib/cc65-src/kernal.s +53 -0
  382. package/src/platforms/c64/lib/cc65-src/kplot.s +22 -0
  383. package/src/platforms/c64/lib/cc65-src/libref.s +16 -0
  384. package/src/platforms/c64/lib/cc65-src/mainargs.s +137 -0
  385. package/src/platforms/c64/lib/cc65-src/mcbdefault.s +146 -0
  386. package/src/platforms/c64/lib/cc65-src/mcbspritedata.s +4 -0
  387. package/src/platforms/c64/lib/cc65-src/mou/c64-1351.s +467 -0
  388. package/src/platforms/c64/lib/cc65-src/mou/c64-inkwell.s +446 -0
  389. package/src/platforms/c64/lib/cc65-src/mou/c64-joy.s +451 -0
  390. package/src/platforms/c64/lib/cc65-src/mou/c64-pot.s +409 -0
  391. package/src/platforms/c64/lib/cc65-src/mouse_stat_stddrv.s +14 -0
  392. package/src/platforms/c64/lib/cc65-src/mouse_stddrv.s +14 -0
  393. package/src/platforms/c64/lib/cc65-src/mouseref.s +23 -0
  394. package/src/platforms/c64/lib/cc65-src/pencalib.c +94 -0
  395. package/src/platforms/c64/lib/cc65-src/randomize.s +18 -0
  396. package/src/platforms/c64/lib/cc65-src/revers.s +27 -0
  397. package/src/platforms/c64/lib/cc65-src/ser/c64-swlink.s +484 -0
  398. package/src/platforms/c64/lib/cc65-src/ser_stat_stddrv.s +14 -0
  399. package/src/platforms/c64/lib/cc65-src/ser_stddrv.s +13 -0
  400. package/src/platforms/c64/lib/cc65-src/settime.s +84 -0
  401. package/src/platforms/c64/lib/cc65-src/soft80.inc +46 -0
  402. package/src/platforms/c64/lib/cc65-src/soft80_cgetc.s +85 -0
  403. package/src/platforms/c64/lib/cc65-src/soft80_charset.s +182 -0
  404. package/src/platforms/c64/lib/cc65-src/soft80_color.s +159 -0
  405. package/src/platforms/c64/lib/cc65-src/soft80_conio.s +157 -0
  406. package/src/platforms/c64/lib/cc65-src/soft80_cpeekc.s +148 -0
  407. package/src/platforms/c64/lib/cc65-src/soft80_cpeekcolor.s +19 -0
  408. package/src/platforms/c64/lib/cc65-src/soft80_cpeekrevers.s +15 -0
  409. package/src/platforms/c64/lib/cc65-src/soft80_cpeeks.s +71 -0
  410. package/src/platforms/c64/lib/cc65-src/soft80_cputc.s +521 -0
  411. package/src/platforms/c64/lib/cc65-src/soft80_kclrscr.s +76 -0
  412. package/src/platforms/c64/lib/cc65-src/soft80_kplot.s +63 -0
  413. package/src/platforms/c64/lib/cc65-src/soft80_scrsize.s +14 -0
  414. package/src/platforms/c64/lib/cc65-src/soft80mono_cgetc.s +67 -0
  415. package/src/platforms/c64/lib/cc65-src/soft80mono_color.s +65 -0
  416. package/src/platforms/c64/lib/cc65-src/soft80mono_conio.s +168 -0
  417. package/src/platforms/c64/lib/cc65-src/soft80mono_cpeekcolor.s +17 -0
  418. package/src/platforms/c64/lib/cc65-src/soft80mono_cputc.s +204 -0
  419. package/src/platforms/c64/lib/cc65-src/soft80mono_kclrscr.s +63 -0
  420. package/src/platforms/c64/lib/cc65-src/soft80mono_kplot.s +52 -0
  421. package/src/platforms/c64/lib/cc65-src/status.s +15 -0
  422. package/src/platforms/c64/lib/cc65-src/sysuname.s +37 -0
  423. package/src/platforms/c64/lib/cc65-src/tgi/c64-hi.s +881 -0
  424. package/src/platforms/c64/lib/cc65-src/tgi_stat_stddrv.s +14 -0
  425. package/src/platforms/c64/lib/cc65-src/tgi_stddrv.s +13 -0
  426. package/src/platforms/c64/lib/cc65-src/tmcommon.s +67 -0
  427. package/src/platforms/c64/lib/cc65-src/waitvsync.s +18 -0
  428. package/src/platforms/c64/lib/read_joystick.s +28 -0
  429. package/src/platforms/c64/lib/sid_play.s +48 -0
  430. package/src/platforms/c64/lib/sprite_table.s +73 -0
  431. package/src/platforms/c64/lib/vic_init.s +47 -0
  432. package/src/platforms/c64/sid.js +128 -0
  433. package/src/platforms/c64/song.js +262 -0
  434. package/src/platforms/c64/vic.js +273 -0
  435. package/src/platforms/common/default-palette.js +139 -0
  436. package/src/platforms/common/image-to-tiles.js +418 -0
  437. package/src/platforms/common/intent.js +111 -0
  438. package/src/platforms/common/metasprite-adapters.js +279 -0
  439. package/src/platforms/common/metasprite-codegen.js +192 -0
  440. package/src/platforms/common/metasprite-core.js +201 -0
  441. package/src/platforms/common/metasprite.js +89 -0
  442. package/src/platforms/common/platform-palette.js +137 -0
  443. package/src/platforms/common/registers.js +329 -0
  444. package/src/platforms/common/render-tiles.js +86 -0
  445. package/src/platforms/common/screenshot-sprite.js +153 -0
  446. package/src/platforms/common/tile-decode.js +149 -0
  447. package/src/platforms/gb/MENTAL_MODEL.md +262 -0
  448. package/src/platforms/gb/TROUBLESHOOTING.md +218 -0
  449. package/src/platforms/gb/UPSTREAM_SOURCES.md +43 -0
  450. package/src/platforms/gb/image-to-tilemap.js +173 -0
  451. package/src/platforms/gb/lib/README.md +115 -0
  452. package/src/platforms/gb/lib/c/LICENSE-HUGEDRIVER +25 -0
  453. package/src/platforms/gb/lib/c/README.md +122 -0
  454. package/src/platforms/gb/lib/c/SDCC_GOTCHAS.md +190 -0
  455. package/src/platforms/gb/lib/c/gb_crt0.s +163 -0
  456. package/src/platforms/gb/lib/c/gb_hardware.h +113 -0
  457. package/src/platforms/gb/lib/c/gb_runtime.c +284 -0
  458. package/src/platforms/gb/lib/c/gb_runtime.h +145 -0
  459. package/src/platforms/gb/lib/c/hUGEDriver.c +191 -0
  460. package/src/platforms/gb/lib/c/hUGEDriver.h +95 -0
  461. package/src/platforms/gb/lib/c/hUGEDriver.upstream.asm +1908 -0
  462. package/src/platforms/gb/lib/c/lcd_init.c +19 -0
  463. package/src/platforms/gb/lib/c/patch-header.js +154 -0
  464. package/src/platforms/gb/lib/c/song_data.c +88 -0
  465. package/src/platforms/gb/lib/c/unroll.h +52 -0
  466. package/src/platforms/gb/lib/c/wait_vblank.c +14 -0
  467. package/src/platforms/gb/lib/dma_oam.asm +51 -0
  468. package/src/platforms/gb/lib/header.asm +56 -0
  469. package/src/platforms/gb/lib/joypad_read.asm +47 -0
  470. package/src/platforms/gb/lib/lcd_init.asm +44 -0
  471. package/src/platforms/gb/lib/load_palette.asm +25 -0
  472. package/src/platforms/gb/lib/load_tiles.asm +29 -0
  473. package/src/platforms/gb/lib/vblank_wait.asm +31 -0
  474. package/src/platforms/gb/ppu.js +574 -0
  475. package/src/platforms/gb/song.js +140 -0
  476. package/src/platforms/gba/MENTAL_MODEL.md +216 -0
  477. package/src/platforms/gba/TROUBLESHOOTING.md +250 -0
  478. package/src/platforms/gba/UPSTREAM_SOURCES.md +41 -0
  479. package/src/platforms/gba/lib/arm-archives/libc.a +0 -0
  480. package/src/platforms/gba/lib/arm-archives/libgcc.a +0 -0
  481. package/src/platforms/gba/lib/arm-archives/libnosys.a +0 -0
  482. package/src/platforms/gba/lib/c/gba_sfx.c +81 -0
  483. package/src/platforms/gba/lib/c/gba_sfx.h +48 -0
  484. package/src/platforms/gba/lib/libgba/crtbegin.o +0 -0
  485. package/src/platforms/gba/lib/libgba/crtend.o +0 -0
  486. package/src/platforms/gba/lib/libgba/crti.o +0 -0
  487. package/src/platforms/gba/lib/libgba/crtn.o +0 -0
  488. package/src/platforms/gba/lib/libgba/gba_cart.ld +319 -0
  489. package/src/platforms/gba/lib/libgba/gba_crt0.s +258 -0
  490. package/src/platforms/gba/lib/libgba/include/BoyScout.h +128 -0
  491. package/src/platforms/gba/lib/libgba/include/disc.h +36 -0
  492. package/src/platforms/gba/lib/libgba/include/disc_io.h +64 -0
  493. package/src/platforms/gba/lib/libgba/include/dldi.h +112 -0
  494. package/src/platforms/gba/lib/libgba/include/erapi.h +195 -0
  495. package/src/platforms/gba/lib/libgba/include/fade.h +76 -0
  496. package/src/platforms/gba/lib/libgba/include/gba.h +47 -0
  497. package/src/platforms/gba/lib/libgba/include/gba_affine.h +83 -0
  498. package/src/platforms/gba/lib/libgba/include/gba_base.h +122 -0
  499. package/src/platforms/gba/lib/libgba/include/gba_compression.h +66 -0
  500. package/src/platforms/gba/lib/libgba/include/gba_console.h +55 -0
  501. package/src/platforms/gba/lib/libgba/include/gba_dma.h +100 -0
  502. package/src/platforms/gba/lib/libgba/include/gba_input.h +127 -0
  503. package/src/platforms/gba/lib/libgba/include/gba_interrupt.h +146 -0
  504. package/src/platforms/gba/lib/libgba/include/gba_multiboot.h +72 -0
  505. package/src/platforms/gba/lib/libgba/include/gba_sio.h +124 -0
  506. package/src/platforms/gba/lib/libgba/include/gba_sound.h +356 -0
  507. package/src/platforms/gba/lib/libgba/include/gba_sprites.h +195 -0
  508. package/src/platforms/gba/lib/libgba/include/gba_systemcalls.h +194 -0
  509. package/src/platforms/gba/lib/libgba/include/gba_timers.h +63 -0
  510. package/src/platforms/gba/lib/libgba/include/gba_types.h +60 -0
  511. package/src/platforms/gba/lib/libgba/include/gba_video.h +307 -0
  512. package/src/platforms/gba/lib/libgba/include/mappy.h +72 -0
  513. package/src/platforms/gba/lib/libgba/include/mbv2.h +90 -0
  514. package/src/platforms/gba/lib/libgba/include/xcomms.h +93 -0
  515. package/src/platforms/gba/lib/libgba/include/xcomms_cmd.h +53 -0
  516. package/src/platforms/gba/lib/libgba/libgba.seed.a +0 -0
  517. package/src/platforms/gba/lib/libgba/libgba.seed.hash +1 -0
  518. package/src/platforms/gba/lib/libgba/src/AffineSet.c +42 -0
  519. package/src/platforms/gba/lib/libgba/src/ArcTan.s +41 -0
  520. package/src/platforms/gba/lib/libgba/src/BoyScout/BoyScout.c +1242 -0
  521. package/src/platforms/gba/lib/libgba/src/BoyScout/GBASoundRegs.h +200 -0
  522. package/src/platforms/gba/lib/libgba/src/Compression.c +84 -0
  523. package/src/platforms/gba/lib/libgba/src/CpuSet.c +41 -0
  524. package/src/platforms/gba/lib/libgba/src/Div.s +58 -0
  525. package/src/platforms/gba/lib/libgba/src/DivArm.s +50 -0
  526. package/src/platforms/gba/lib/libgba/src/InterruptDispatcher.s +113 -0
  527. package/src/platforms/gba/lib/libgba/src/IntrWait.c +35 -0
  528. package/src/platforms/gba/lib/libgba/src/MultiBoot.s +33 -0
  529. package/src/platforms/gba/lib/libgba/src/Reset.s +49 -0
  530. package/src/platforms/gba/lib/libgba/src/Sound.s +48 -0
  531. package/src/platforms/gba/lib/libgba/src/Sqrt.s +34 -0
  532. package/src/platforms/gba/lib/libgba/src/disc_io/disc.c +58 -0
  533. package/src/platforms/gba/lib/libgba/src/disc_io/dldi.c +189 -0
  534. package/src/platforms/gba/lib/libgba/src/disc_io/dldi_stub.s +78 -0
  535. package/src/platforms/gba/lib/libgba/src/disc_io/io_cf_common.c +260 -0
  536. package/src/platforms/gba/lib/libgba/src/disc_io/io_cf_common.h +72 -0
  537. package/src/platforms/gba/lib/libgba/src/disc_io/io_m3_common.c +60 -0
  538. package/src/platforms/gba/lib/libgba/src/disc_io/io_m3_common.h +48 -0
  539. package/src/platforms/gba/lib/libgba/src/disc_io/io_m3cf.c +83 -0
  540. package/src/platforms/gba/lib/libgba/src/disc_io/io_m3cf.h +45 -0
  541. package/src/platforms/gba/lib/libgba/src/disc_io/io_m3sd.c +508 -0
  542. package/src/platforms/gba/lib/libgba/src/disc_io/io_m3sd.h +45 -0
  543. package/src/platforms/gba/lib/libgba/src/disc_io/io_mpcf.c +87 -0
  544. package/src/platforms/gba/lib/libgba/src/disc_io/io_mpcf.h +42 -0
  545. package/src/platforms/gba/lib/libgba/src/disc_io/io_sc_common.c +47 -0
  546. package/src/platforms/gba/lib/libgba/src/disc_io/io_sc_common.h +43 -0
  547. package/src/platforms/gba/lib/libgba/src/disc_io/io_sccf.c +83 -0
  548. package/src/platforms/gba/lib/libgba/src/disc_io/io_sccf.h +45 -0
  549. package/src/platforms/gba/lib/libgba/src/disc_io/io_scsd.c +385 -0
  550. package/src/platforms/gba/lib/libgba/src/disc_io/io_scsd.h +48 -0
  551. package/src/platforms/gba/lib/libgba/src/disc_io/io_scsd_s.s +139 -0
  552. package/src/platforms/gba/lib/libgba/src/disc_io/io_sd_common.c +203 -0
  553. package/src/platforms/gba/lib/libgba/src/disc_io/io_sd_common.h +108 -0
  554. package/src/platforms/gba/lib/libgba/src/fade.c +185 -0
  555. package/src/platforms/gba/lib/libgba/src/input.c +127 -0
  556. package/src/platforms/gba/lib/libgba/src/interrupt.c +116 -0
  557. package/src/platforms/gba/lib/libgba/src/mappy_print.c +74 -0
  558. package/src/platforms/gba/lib/libgba/src/mb2print.c +69 -0
  559. package/src/platforms/gba/lib/libgba/src/mbv2.c +230 -0
  560. package/src/platforms/gba/lib/libgba/src/mbv2.txt +119 -0
  561. package/src/platforms/gba/lib/libgba/src/xcomms.c +203 -0
  562. package/src/platforms/gba/lib/libgba/src/xcomms_print.c +56 -0
  563. package/src/platforms/gba/lib/libgba/sysinclude/_ansi.h +82 -0
  564. package/src/platforms/gba/lib/libgba/sysinclude/_newlib_version.h +11 -0
  565. package/src/platforms/gba/lib/libgba/sysinclude/_syslist.h +41 -0
  566. package/src/platforms/gba/lib/libgba/sysinclude/alloca.h +21 -0
  567. package/src/platforms/gba/lib/libgba/sysinclude/ar.h +65 -0
  568. package/src/platforms/gba/lib/libgba/sysinclude/argz.h +33 -0
  569. package/src/platforms/gba/lib/libgba/sysinclude/assert.h +50 -0
  570. package/src/platforms/gba/lib/libgba/sysinclude/complex.h +150 -0
  571. package/src/platforms/gba/lib/libgba/sysinclude/cpio.h +30 -0
  572. package/src/platforms/gba/lib/libgba/sysinclude/ctype.h +183 -0
  573. package/src/platforms/gba/lib/libgba/sysinclude/devctl.h +78 -0
  574. package/src/platforms/gba/lib/libgba/sysinclude/dirent.h +85 -0
  575. package/src/platforms/gba/lib/libgba/sysinclude/elf.h +3147 -0
  576. package/src/platforms/gba/lib/libgba/sysinclude/envlock.h +15 -0
  577. package/src/platforms/gba/lib/libgba/sysinclude/envz.h +16 -0
  578. package/src/platforms/gba/lib/libgba/sysinclude/errno.h +11 -0
  579. package/src/platforms/gba/lib/libgba/sysinclude/fastmath.h +13 -0
  580. package/src/platforms/gba/lib/libgba/sysinclude/fcntl.h +1 -0
  581. package/src/platforms/gba/lib/libgba/sysinclude/fenv.h +42 -0
  582. package/src/platforms/gba/lib/libgba/sysinclude/float.h +631 -0
  583. package/src/platforms/gba/lib/libgba/sysinclude/fnmatch.h +55 -0
  584. package/src/platforms/gba/lib/libgba/sysinclude/ftw.h +66 -0
  585. package/src/platforms/gba/lib/libgba/sysinclude/getopt.h +185 -0
  586. package/src/platforms/gba/lib/libgba/sysinclude/glob.h +90 -0
  587. package/src/platforms/gba/lib/libgba/sysinclude/grp.h +86 -0
  588. package/src/platforms/gba/lib/libgba/sysinclude/iconv.h +63 -0
  589. package/src/platforms/gba/lib/libgba/sysinclude/ieeefp.h +295 -0
  590. package/src/platforms/gba/lib/libgba/sysinclude/inttypes.h +345 -0
  591. package/src/platforms/gba/lib/libgba/sysinclude/iso646.h +45 -0
  592. package/src/platforms/gba/lib/libgba/sysinclude/langinfo.h +332 -0
  593. package/src/platforms/gba/lib/libgba/sysinclude/libgen.h +37 -0
  594. package/src/platforms/gba/lib/libgba/sysinclude/limits.h +168 -0
  595. package/src/platforms/gba/lib/libgba/sysinclude/locale.h +96 -0
  596. package/src/platforms/gba/lib/libgba/sysinclude/machine/_arc4random.h +1 -0
  597. package/src/platforms/gba/lib/libgba/sysinclude/machine/_default_types.h +250 -0
  598. package/src/platforms/gba/lib/libgba/sysinclude/machine/_endian.h +39 -0
  599. package/src/platforms/gba/lib/libgba/sysinclude/machine/_time.h +3 -0
  600. package/src/platforms/gba/lib/libgba/sysinclude/machine/_types.h +8 -0
  601. package/src/platforms/gba/lib/libgba/sysinclude/machine/ansi.h +1 -0
  602. package/src/platforms/gba/lib/libgba/sysinclude/machine/endian.h +69 -0
  603. package/src/platforms/gba/lib/libgba/sysinclude/machine/fastmath.h +98 -0
  604. package/src/platforms/gba/lib/libgba/sysinclude/machine/ieee.h +127 -0
  605. package/src/platforms/gba/lib/libgba/sysinclude/machine/ieeefp.h +533 -0
  606. package/src/platforms/gba/lib/libgba/sysinclude/machine/malloc.h +8 -0
  607. package/src/platforms/gba/lib/libgba/sysinclude/machine/param.h +8 -0
  608. package/src/platforms/gba/lib/libgba/sysinclude/machine/setjmp-dj.h +43 -0
  609. package/src/platforms/gba/lib/libgba/sysinclude/machine/setjmp.h +524 -0
  610. package/src/platforms/gba/lib/libgba/sysinclude/machine/stdlib.h +8 -0
  611. package/src/platforms/gba/lib/libgba/sysinclude/machine/termios.h +1 -0
  612. package/src/platforms/gba/lib/libgba/sysinclude/machine/time.h +15 -0
  613. package/src/platforms/gba/lib/libgba/sysinclude/machine/types.h +13 -0
  614. package/src/platforms/gba/lib/libgba/sysinclude/malloc.h +173 -0
  615. package/src/platforms/gba/lib/libgba/sysinclude/math.h +645 -0
  616. package/src/platforms/gba/lib/libgba/sysinclude/memory.h +4 -0
  617. package/src/platforms/gba/lib/libgba/sysinclude/ndbm.h +91 -0
  618. package/src/platforms/gba/lib/libgba/sysinclude/newlib.h +427 -0
  619. package/src/platforms/gba/lib/libgba/sysinclude/paths.h +9 -0
  620. package/src/platforms/gba/lib/libgba/sysinclude/pthread.h +456 -0
  621. package/src/platforms/gba/lib/libgba/sysinclude/pwd.h +83 -0
  622. package/src/platforms/gba/lib/libgba/sysinclude/reent.h +190 -0
  623. package/src/platforms/gba/lib/libgba/sysinclude/regdef.h +7 -0
  624. package/src/platforms/gba/lib/libgba/sysinclude/regex.h +103 -0
  625. package/src/platforms/gba/lib/libgba/sysinclude/sched.h +112 -0
  626. package/src/platforms/gba/lib/libgba/sysinclude/search.h +64 -0
  627. package/src/platforms/gba/lib/libgba/sysinclude/setjmp.h +25 -0
  628. package/src/platforms/gba/lib/libgba/sysinclude/signal.h +35 -0
  629. package/src/platforms/gba/lib/libgba/sysinclude/spawn.h +111 -0
  630. package/src/platforms/gba/lib/libgba/sysinclude/ssp/ssp.h +76 -0
  631. package/src/platforms/gba/lib/libgba/sysinclude/ssp/stdio.h +101 -0
  632. package/src/platforms/gba/lib/libgba/sysinclude/ssp/stdlib.h +30 -0
  633. package/src/platforms/gba/lib/libgba/sysinclude/ssp/string.h +115 -0
  634. package/src/platforms/gba/lib/libgba/sysinclude/ssp/strings.h +55 -0
  635. package/src/platforms/gba/lib/libgba/sysinclude/ssp/unistd.h +93 -0
  636. package/src/platforms/gba/lib/libgba/sysinclude/ssp/wchar.h +97 -0
  637. package/src/platforms/gba/lib/libgba/sysinclude/stdarg.h +135 -0
  638. package/src/platforms/gba/lib/libgba/sysinclude/stdatomic.h +409 -0
  639. package/src/platforms/gba/lib/libgba/sysinclude/stdbool.h +51 -0
  640. package/src/platforms/gba/lib/libgba/sysinclude/stddef.h +463 -0
  641. package/src/platforms/gba/lib/libgba/sysinclude/stdint.h +466 -0
  642. package/src/platforms/gba/lib/libgba/sysinclude/stdio.h +807 -0
  643. package/src/platforms/gba/lib/libgba/sysinclude/stdio_ext.h +79 -0
  644. package/src/platforms/gba/lib/libgba/sysinclude/stdlib.h +345 -0
  645. package/src/platforms/gba/lib/libgba/sysinclude/string.h +183 -0
  646. package/src/platforms/gba/lib/libgba/sysinclude/strings.h +80 -0
  647. package/src/platforms/gba/lib/libgba/sysinclude/sys/_default_fcntl.h +241 -0
  648. package/src/platforms/gba/lib/libgba/sysinclude/sys/_intsup.h +199 -0
  649. package/src/platforms/gba/lib/libgba/sysinclude/sys/_locale.h +12 -0
  650. package/src/platforms/gba/lib/libgba/sysinclude/sys/_pthreadtypes.h +233 -0
  651. package/src/platforms/gba/lib/libgba/sysinclude/sys/_sigset.h +43 -0
  652. package/src/platforms/gba/lib/libgba/sysinclude/sys/_stdint.h +90 -0
  653. package/src/platforms/gba/lib/libgba/sysinclude/sys/_timespec.h +52 -0
  654. package/src/platforms/gba/lib/libgba/sysinclude/sys/_timeval.h +60 -0
  655. package/src/platforms/gba/lib/libgba/sysinclude/sys/_types.h +228 -0
  656. package/src/platforms/gba/lib/libgba/sysinclude/sys/_tz_structs.h +24 -0
  657. package/src/platforms/gba/lib/libgba/sysinclude/sys/cdefs.h +754 -0
  658. package/src/platforms/gba/lib/libgba/sysinclude/sys/config.h +314 -0
  659. package/src/platforms/gba/lib/libgba/sysinclude/sys/custom_file.h +2 -0
  660. package/src/platforms/gba/lib/libgba/sysinclude/sys/dir.h +10 -0
  661. package/src/platforms/gba/lib/libgba/sysinclude/sys/dirent.h +13 -0
  662. package/src/platforms/gba/lib/libgba/sysinclude/sys/endian.h +207 -0
  663. package/src/platforms/gba/lib/libgba/sysinclude/sys/errno.h +198 -0
  664. package/src/platforms/gba/lib/libgba/sysinclude/sys/fcntl.h +12 -0
  665. package/src/platforms/gba/lib/libgba/sysinclude/sys/features.h +551 -0
  666. package/src/platforms/gba/lib/libgba/sysinclude/sys/fenv.h +90 -0
  667. package/src/platforms/gba/lib/libgba/sysinclude/sys/file.h +2 -0
  668. package/src/platforms/gba/lib/libgba/sysinclude/sys/iconvnls.h +77 -0
  669. package/src/platforms/gba/lib/libgba/sysinclude/sys/iosupport.h +143 -0
  670. package/src/platforms/gba/lib/libgba/sysinclude/sys/lock.h +75 -0
  671. package/src/platforms/gba/lib/libgba/sysinclude/sys/param.h +35 -0
  672. package/src/platforms/gba/lib/libgba/sysinclude/sys/queue.h +919 -0
  673. package/src/platforms/gba/lib/libgba/sysinclude/sys/reent.h +913 -0
  674. package/src/platforms/gba/lib/libgba/sysinclude/sys/resource.h +24 -0
  675. package/src/platforms/gba/lib/libgba/sysinclude/sys/sched.h +69 -0
  676. package/src/platforms/gba/lib/libgba/sysinclude/sys/select.h +94 -0
  677. package/src/platforms/gba/lib/libgba/sysinclude/sys/signal.h +388 -0
  678. package/src/platforms/gba/lib/libgba/sysinclude/sys/stat.h +179 -0
  679. package/src/platforms/gba/lib/libgba/sysinclude/sys/statvfs.h +41 -0
  680. package/src/platforms/gba/lib/libgba/sysinclude/sys/stdio.h +27 -0
  681. package/src/platforms/gba/lib/libgba/sysinclude/sys/string.h +2 -0
  682. package/src/platforms/gba/lib/libgba/sysinclude/sys/syslimits.h +61 -0
  683. package/src/platforms/gba/lib/libgba/sysinclude/sys/time.h +448 -0
  684. package/src/platforms/gba/lib/libgba/sysinclude/sys/timeb.h +40 -0
  685. package/src/platforms/gba/lib/libgba/sysinclude/sys/times.h +32 -0
  686. package/src/platforms/gba/lib/libgba/sysinclude/sys/timespec.h +63 -0
  687. package/src/platforms/gba/lib/libgba/sysinclude/sys/tree.h +864 -0
  688. package/src/platforms/gba/lib/libgba/sysinclude/sys/types.h +228 -0
  689. package/src/platforms/gba/lib/libgba/sysinclude/sys/unistd.h +591 -0
  690. package/src/platforms/gba/lib/libgba/sysinclude/sys/utime.h +22 -0
  691. package/src/platforms/gba/lib/libgba/sysinclude/sys/wait.h +44 -0
  692. package/src/platforms/gba/lib/libgba/sysinclude/tar.h +43 -0
  693. package/src/platforms/gba/lib/libgba/sysinclude/termios.h +7 -0
  694. package/src/platforms/gba/lib/libgba/sysinclude/tgmath.h +127 -0
  695. package/src/platforms/gba/lib/libgba/sysinclude/threads.h +93 -0
  696. package/src/platforms/gba/lib/libgba/sysinclude/time.h +313 -0
  697. package/src/platforms/gba/lib/libgba/sysinclude/unctrl.h +42 -0
  698. package/src/platforms/gba/lib/libgba/sysinclude/unistd.h +6 -0
  699. package/src/platforms/gba/lib/libgba/sysinclude/utime.h +12 -0
  700. package/src/platforms/gba/lib/libgba/sysinclude/utmp.h +8 -0
  701. package/src/platforms/gba/lib/libgba/sysinclude/varargs.h +7 -0
  702. package/src/platforms/gba/lib/libgba/sysinclude/wchar.h +339 -0
  703. package/src/platforms/gba/lib/libgba/sysinclude/wctype.h +74 -0
  704. package/src/platforms/gba/lib/libgba/sysinclude/wordexp.h +53 -0
  705. package/src/platforms/gba/lib/libtonc/crtbegin.o +0 -0
  706. package/src/platforms/gba/lib/libtonc/crtend.o +0 -0
  707. package/src/platforms/gba/lib/libtonc/crti.o +0 -0
  708. package/src/platforms/gba/lib/libtonc/crtn.o +0 -0
  709. package/src/platforms/gba/lib/libtonc/gba_cart.ld +319 -0
  710. package/src/platforms/gba/lib/libtonc/gba_crt0.s +258 -0
  711. package/src/platforms/gba/lib/libtonc/include/tonc.h +72 -0
  712. package/src/platforms/gba/lib/libtonc/include/tonc_asminc.h +132 -0
  713. package/src/platforms/gba/lib/libtonc/include/tonc_bios.h +555 -0
  714. package/src/platforms/gba/lib/libtonc/include/tonc_core.h +573 -0
  715. package/src/platforms/gba/lib/libtonc/include/tonc_input.h +184 -0
  716. package/src/platforms/gba/lib/libtonc/include/tonc_irq.h +121 -0
  717. package/src/platforms/gba/lib/libtonc/include/tonc_legacy.h +481 -0
  718. package/src/platforms/gba/lib/libtonc/include/tonc_libgba.h +537 -0
  719. package/src/platforms/gba/lib/libtonc/include/tonc_math.h +692 -0
  720. package/src/platforms/gba/lib/libtonc/include/tonc_memdef.h +962 -0
  721. package/src/platforms/gba/lib/libtonc/include/tonc_memmap.h +583 -0
  722. package/src/platforms/gba/lib/libtonc/include/tonc_nocash.h +51 -0
  723. package/src/platforms/gba/lib/libtonc/include/tonc_oam.h +186 -0
  724. package/src/platforms/gba/lib/libtonc/include/tonc_surface.h +461 -0
  725. package/src/platforms/gba/lib/libtonc/include/tonc_text.h +270 -0
  726. package/src/platforms/gba/lib/libtonc/include/tonc_tte.h +748 -0
  727. package/src/platforms/gba/lib/libtonc/include/tonc_types.h +376 -0
  728. package/src/platforms/gba/lib/libtonc/include/tonc_video.h +615 -0
  729. package/src/platforms/gba/lib/libtonc/libtonc.seed.a +0 -0
  730. package/src/platforms/gba/lib/libtonc/libtonc.seed.hash +1 -0
  731. package/src/platforms/gba/lib/libtonc/src/asm/clr_blend_fast.s +72 -0
  732. package/src/platforms/gba/lib/libtonc/src/asm/clr_fade_fast.s +74 -0
  733. package/src/platforms/gba/lib/libtonc/src/asm/div_lut.s +54 -0
  734. package/src/platforms/gba/lib/libtonc/src/asm/sin_lut.s +90 -0
  735. package/src/platforms/gba/lib/libtonc/src/asm/tonc_bios.s +289 -0
  736. package/src/platforms/gba/lib/libtonc/src/asm/tonc_bios_ex.s +97 -0
  737. package/src/platforms/gba/lib/libtonc/src/asm/tonc_isr_master.s +92 -0
  738. package/src/platforms/gba/lib/libtonc/src/asm/tonc_isr_nest.s +98 -0
  739. package/src/platforms/gba/lib/libtonc/src/asm/tonc_memcpy.s +126 -0
  740. package/src/platforms/gba/lib/libtonc/src/asm/tonc_memset.s +123 -0
  741. package/src/platforms/gba/lib/libtonc/src/asm/tonc_nocash.s +73 -0
  742. package/src/platforms/gba/lib/libtonc/src/font/sys8.png +0 -0
  743. package/src/platforms/gba/lib/libtonc/src/font/sys8.s +46 -0
  744. package/src/platforms/gba/lib/libtonc/src/font/verdana10.png +0 -0
  745. package/src/platforms/gba/lib/libtonc/src/font/verdana10.s +293 -0
  746. package/src/platforms/gba/lib/libtonc/src/font/verdana9.png +0 -0
  747. package/src/platforms/gba/lib/libtonc/src/font/verdana9.s +167 -0
  748. package/src/platforms/gba/lib/libtonc/src/font/verdana9_b4.png +0 -0
  749. package/src/platforms/gba/lib/libtonc/src/font/verdana9_b4.s +545 -0
  750. package/src/platforms/gba/lib/libtonc/src/font/verdana9b.png +0 -0
  751. package/src/platforms/gba/lib/libtonc/src/font/verdana9b.s +167 -0
  752. package/src/platforms/gba/lib/libtonc/src/font/verdana9i.png +0 -0
  753. package/src/platforms/gba/lib/libtonc/src/font/verdana9i.s +167 -0
  754. package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_bitmap.c +289 -0
  755. package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text.c +81 -0
  756. package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text_bm.c +244 -0
  757. package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text_map.c +122 -0
  758. package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text_oam.c +113 -0
  759. package/src/platforms/gba/lib/libtonc/src/pre1.3/toncfont.s +43 -0
  760. package/src/platforms/gba/lib/libtonc/src/tonc_bg.c +61 -0
  761. package/src/platforms/gba/lib/libtonc/src/tonc_bg_affine.c +112 -0
  762. package/src/platforms/gba/lib/libtonc/src/tonc_bmp16.c +240 -0
  763. package/src/platforms/gba/lib/libtonc/src/tonc_bmp8.c +314 -0
  764. package/src/platforms/gba/lib/libtonc/src/tonc_color.c +368 -0
  765. package/src/platforms/gba/lib/libtonc/src/tonc_core.c +237 -0
  766. package/src/platforms/gba/lib/libtonc/src/tonc_input.c +118 -0
  767. package/src/platforms/gba/lib/libtonc/src/tonc_irq.c +271 -0
  768. package/src/platforms/gba/lib/libtonc/src/tonc_math.c +54 -0
  769. package/src/platforms/gba/lib/libtonc/src/tonc_oam.c +76 -0
  770. package/src/platforms/gba/lib/libtonc/src/tonc_obj_affine.c +146 -0
  771. package/src/platforms/gba/lib/libtonc/src/tonc_sbmp16.c +369 -0
  772. package/src/platforms/gba/lib/libtonc/src/tonc_sbmp8.c +405 -0
  773. package/src/platforms/gba/lib/libtonc/src/tonc_schr4c.c +588 -0
  774. package/src/platforms/gba/lib/libtonc/src/tonc_schr4r.c +462 -0
  775. package/src/platforms/gba/lib/libtonc/src/tonc_surface.c +105 -0
  776. package/src/platforms/gba/lib/libtonc/src/tonc_video.c +33 -0
  777. package/src/platforms/gba/lib/libtonc/src/tte/ase_drawg.c +83 -0
  778. package/src/platforms/gba/lib/libtonc/src/tte/bmp16_drawg.c +72 -0
  779. package/src/platforms/gba/lib/libtonc/src/tte/bmp16_drawg_b1cs.c +92 -0
  780. package/src/platforms/gba/lib/libtonc/src/tte/bmp8_drawg.c +71 -0
  781. package/src/platforms/gba/lib/libtonc/src/tte/bmp8_drawg_b1cs.c +104 -0
  782. package/src/platforms/gba/lib/libtonc/src/tte/bmp8_drawg_b1cts_fast.s +115 -0
  783. package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b1cts.c +76 -0
  784. package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b1cts_fast.s +128 -0
  785. package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b4cts.c +67 -0
  786. package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b4cts_fast.s +127 -0
  787. package/src/platforms/gba/lib/libtonc/src/tte/chr4r_drawg_b1cts.c +80 -0
  788. package/src/platforms/gba/lib/libtonc/src/tte/chr4r_drawg_b1cts_fast.s +145 -0
  789. package/src/platforms/gba/lib/libtonc/src/tte/obj_drawg.c +61 -0
  790. package/src/platforms/gba/lib/libtonc/src/tte/se_drawg.c +110 -0
  791. package/src/platforms/gba/lib/libtonc/src/tte/tte_init_ase.c +87 -0
  792. package/src/platforms/gba/lib/libtonc/src/tte/tte_init_bmp.c +118 -0
  793. package/src/platforms/gba/lib/libtonc/src/tte/tte_init_chr4c.c +86 -0
  794. package/src/platforms/gba/lib/libtonc/src/tte/tte_init_chr4r.c +87 -0
  795. package/src/platforms/gba/lib/libtonc/src/tte/tte_init_obj.c +84 -0
  796. package/src/platforms/gba/lib/libtonc/src/tte/tte_init_se.c +96 -0
  797. package/src/platforms/gba/lib/libtonc/src/tte/tte_iohook.c +264 -0
  798. package/src/platforms/gba/lib/libtonc/src/tte/tte_main.c +756 -0
  799. package/src/platforms/gba/lib/libtonc/src/tte/tte_types.s +119 -0
  800. package/src/platforms/gba/lib/maxmod/LICENSE-MAXMOD +23 -0
  801. package/src/platforms/gba/lib/maxmod/asm_include/mp_defs.inc +117 -0
  802. package/src/platforms/gba/lib/maxmod/asm_include/mp_format_mas.inc +108 -0
  803. package/src/platforms/gba/lib/maxmod/asm_include/mp_macros.inc +195 -0
  804. package/src/platforms/gba/lib/maxmod/asm_include/mp_mas.inc +40 -0
  805. package/src/platforms/gba/lib/maxmod/asm_include/mp_mas_structs.inc +189 -0
  806. package/src/platforms/gba/lib/maxmod/asm_include/mp_mixer_ds.inc +46 -0
  807. package/src/platforms/gba/lib/maxmod/asm_include/mp_mixer_gba.inc +42 -0
  808. package/src/platforms/gba/lib/maxmod/asm_include/swi_gba.inc +23 -0
  809. package/src/platforms/gba/lib/maxmod/include/maxmod.h +412 -0
  810. package/src/platforms/gba/lib/maxmod/include/mm_types.h +333 -0
  811. package/src/platforms/gba/lib/maxmod/maxmod.seed.a +0 -0
  812. package/src/platforms/gba/lib/maxmod/maxmod.seed.hash +1 -0
  813. package/src/platforms/gba/lib/maxmod/music/chiptune.xm +0 -0
  814. package/src/platforms/gba/lib/maxmod/music/chiptune_soundbank.bin +0 -0
  815. package/src/platforms/gba/lib/maxmod/music/chiptune_soundbank.h +4 -0
  816. package/src/platforms/gba/lib/maxmod/music/make_chiptune_xm.js +203 -0
  817. package/src/platforms/gba/lib/maxmod/source/mm_effect.s +767 -0
  818. package/src/platforms/gba/lib/maxmod/source/mm_main.s +115 -0
  819. package/src/platforms/gba/lib/maxmod/source/mm_mas.s +4990 -0
  820. package/src/platforms/gba/lib/maxmod/source/mm_mas_arm.s +612 -0
  821. package/src/platforms/gba/lib/maxmod/source_gba/mm_init_default.s +98 -0
  822. package/src/platforms/gba/lib/maxmod/source_gba/mm_main_gba.s +292 -0
  823. package/src/platforms/gba/lib/maxmod/source_gba/mm_mixer_gba.s +1367 -0
  824. package/src/platforms/gba/lib/sysbase/gba_iosupport.c +138 -0
  825. package/src/platforms/gbc/MENTAL_MODEL.md +178 -0
  826. package/src/platforms/gbc/TROUBLESHOOTING.md +142 -0
  827. package/src/platforms/gbc/UPSTREAM_SOURCES.md +60 -0
  828. package/src/platforms/gbc/lib/c/LICENSE-HUGEDRIVER +25 -0
  829. package/src/platforms/gbc/lib/c/README.md +122 -0
  830. package/src/platforms/gbc/lib/c/SDCC_GOTCHAS.md +190 -0
  831. package/src/platforms/gbc/lib/c/gb_crt0.s +163 -0
  832. package/src/platforms/gbc/lib/c/gb_hardware.h +113 -0
  833. package/src/platforms/gbc/lib/c/gb_runtime.c +284 -0
  834. package/src/platforms/gbc/lib/c/gb_runtime.h +145 -0
  835. package/src/platforms/gbc/lib/c/hUGEDriver.c +191 -0
  836. package/src/platforms/gbc/lib/c/hUGEDriver.h +95 -0
  837. package/src/platforms/gbc/lib/c/hUGEDriver.upstream.asm +1908 -0
  838. package/src/platforms/gbc/lib/c/lcd_init.c +19 -0
  839. package/src/platforms/gbc/lib/c/patch-header.js +154 -0
  840. package/src/platforms/gbc/lib/c/song_data.c +88 -0
  841. package/src/platforms/gbc/lib/c/unroll.h +52 -0
  842. package/src/platforms/gbc/lib/c/wait_vblank.c +14 -0
  843. package/src/platforms/gbc/song.js +3 -0
  844. package/src/platforms/genesis/MENTAL_MODEL.md +306 -0
  845. package/src/platforms/genesis/TROUBLESHOOTING.md +226 -0
  846. package/src/platforms/genesis/UPSTREAM_SOURCES.md +53 -0
  847. package/src/platforms/genesis/image-to-tilemap.js +351 -0
  848. package/src/platforms/genesis/lib/README.md +160 -0
  849. package/src/platforms/genesis/lib/c/crtbegin.o +0 -0
  850. package/src/platforms/genesis/lib/c/crtend.o +0 -0
  851. package/src/platforms/genesis/lib/c/genesis.ld +44 -0
  852. package/src/platforms/genesis/lib/c/genesis_sfx.c +51 -0
  853. package/src/platforms/genesis/lib/c/genesis_sfx.h +49 -0
  854. package/src/platforms/genesis/lib/c/libc.a +0 -0
  855. package/src/platforms/genesis/lib/c/libgcc.a +0 -0
  856. package/src/platforms/genesis/lib/c/libm.a +0 -0
  857. package/src/platforms/genesis/lib/c/sega.s +71 -0
  858. package/src/platforms/genesis/lib/header.s +96 -0
  859. package/src/platforms/genesis/lib/nmi_safe.s +79 -0
  860. package/src/platforms/genesis/lib/pad_read.s +104 -0
  861. package/src/platforms/genesis/lib/sgdk/COPYING.RUNTIME +73 -0
  862. package/src/platforms/genesis/lib/sgdk/LICENSE +12 -0
  863. package/src/platforms/genesis/lib/sgdk/include/asm.h +52 -0
  864. package/src/platforms/genesis/lib/sgdk/include/asm_mac.i +9 -0
  865. package/src/platforms/genesis/lib/sgdk/include/bmp.h +690 -0
  866. package/src/platforms/genesis/lib/sgdk/include/config.h +208 -0
  867. package/src/platforms/genesis/lib/sgdk/include/dma.h +542 -0
  868. package/src/platforms/genesis/lib/sgdk/include/ext/console.h +387 -0
  869. package/src/platforms/genesis/lib/sgdk/include/ext/everdrive.h +116 -0
  870. package/src/platforms/genesis/lib/sgdk/include/ext/fat16.h +84 -0
  871. package/src/platforms/genesis/lib/sgdk/include/ext/flash-save/flash.h +164 -0
  872. package/src/platforms/genesis/lib/sgdk/include/ext/flash-save/saveman.h +177 -0
  873. package/src/platforms/genesis/lib/sgdk/include/ext/link_cable.h +316 -0
  874. package/src/platforms/genesis/lib/sgdk/include/ext/minimusic/minimus.h +29 -0
  875. package/src/platforms/genesis/lib/sgdk/include/ext/mw/16c550.h +221 -0
  876. package/src/platforms/genesis/lib/sgdk/include/ext/mw/comm.h +93 -0
  877. package/src/platforms/genesis/lib/sgdk/include/ext/mw/gamejolt.h +541 -0
  878. package/src/platforms/genesis/lib/sgdk/include/ext/mw/jsmn.h +471 -0
  879. package/src/platforms/genesis/lib/sgdk/include/ext/mw/json.h +122 -0
  880. package/src/platforms/genesis/lib/sgdk/include/ext/mw/lsd.h +172 -0
  881. package/src/platforms/genesis/lib/sgdk/include/ext/mw/megawifi.h +984 -0
  882. package/src/platforms/genesis/lib/sgdk/include/ext/mw/mw-msg.h +392 -0
  883. package/src/platforms/genesis/lib/sgdk/include/ext/mw/ssf_ed_pro.h +38 -0
  884. package/src/platforms/genesis/lib/sgdk/include/ext/mw/ssf_ed_x7.h +73 -0
  885. package/src/platforms/genesis/lib/sgdk/include/ext/serial/buffer.h +8 -0
  886. package/src/platforms/genesis/lib/sgdk/include/ext/serial/serial.h +133 -0
  887. package/src/platforms/genesis/lib/sgdk/include/ext/stb/stb_sprintf.h +1864 -0
  888. package/src/platforms/genesis/lib/sgdk/include/genesis.h +92 -0
  889. package/src/platforms/genesis/lib/sgdk/include/joy.h +482 -0
  890. package/src/platforms/genesis/lib/sgdk/include/kdebug.h +21 -0
  891. package/src/platforms/genesis/lib/sgdk/include/map.h +409 -0
  892. package/src/platforms/genesis/lib/sgdk/include/mapper.h +186 -0
  893. package/src/platforms/genesis/lib/sgdk/include/maths.h +1071 -0
  894. package/src/platforms/genesis/lib/sgdk/include/maths3D.h +480 -0
  895. package/src/platforms/genesis/lib/sgdk/include/memory.h +346 -0
  896. package/src/platforms/genesis/lib/sgdk/include/memory_base.h +37 -0
  897. package/src/platforms/genesis/lib/sgdk/include/object.h +171 -0
  898. package/src/platforms/genesis/lib/sgdk/include/pal.h +500 -0
  899. package/src/platforms/genesis/lib/sgdk/include/pool.h +171 -0
  900. package/src/platforms/genesis/lib/sgdk/include/psg.h +153 -0
  901. package/src/platforms/genesis/lib/sgdk/include/snd/pcm/snd_dpcm2.h +79 -0
  902. package/src/platforms/genesis/lib/sgdk/include/snd/pcm/snd_pcm.h +98 -0
  903. package/src/platforms/genesis/lib/sgdk/include/snd/pcm/snd_pcm4.h +125 -0
  904. package/src/platforms/genesis/lib/sgdk/include/snd/pcm/tab_vol.h +6 -0
  905. package/src/platforms/genesis/lib/sgdk/include/snd/smp_null.h +6 -0
  906. package/src/platforms/genesis/lib/sgdk/include/snd/smp_null_dpcm.h +6 -0
  907. package/src/platforms/genesis/lib/sgdk/include/snd/sound.h +70 -0
  908. package/src/platforms/genesis/lib/sgdk/include/snd/xgm.h +399 -0
  909. package/src/platforms/genesis/lib/sgdk/include/snd/xgm2.h +389 -0
  910. package/src/platforms/genesis/lib/sgdk/include/snd/z80_def.i80 +41 -0
  911. package/src/platforms/genesis/lib/sgdk/include/snd/z80_fct.i80 +83 -0
  912. package/src/platforms/genesis/lib/sgdk/include/snd/z80_mac.i80 +1476 -0
  913. package/src/platforms/genesis/lib/sgdk/include/sprite_eng.h +1095 -0
  914. package/src/platforms/genesis/lib/sgdk/include/sprite_eng_legacy.h +1030 -0
  915. package/src/platforms/genesis/lib/sgdk/include/sram.h +110 -0
  916. package/src/platforms/genesis/lib/sgdk/include/string.h +349 -0
  917. package/src/platforms/genesis/lib/sgdk/include/sys.h +511 -0
  918. package/src/platforms/genesis/lib/sgdk/include/tab_cnv.h +19 -0
  919. package/src/platforms/genesis/lib/sgdk/include/task.h +77 -0
  920. package/src/platforms/genesis/lib/sgdk/include/task_cst.h +33 -0
  921. package/src/platforms/genesis/lib/sgdk/include/timer.h +132 -0
  922. package/src/platforms/genesis/lib/sgdk/include/tools.h +450 -0
  923. package/src/platforms/genesis/lib/sgdk/include/types.h +320 -0
  924. package/src/platforms/genesis/lib/sgdk/include/vdp.h +1150 -0
  925. package/src/platforms/genesis/lib/sgdk/include/vdp_bg.h +723 -0
  926. package/src/platforms/genesis/lib/sgdk/include/vdp_pal.h +101 -0
  927. package/src/platforms/genesis/lib/sgdk/include/vdp_spr.h +448 -0
  928. package/src/platforms/genesis/lib/sgdk/include/vdp_tile.h +1136 -0
  929. package/src/platforms/genesis/lib/sgdk/include/vram.h +270 -0
  930. package/src/platforms/genesis/lib/sgdk/include/ym2612.h +87 -0
  931. package/src/platforms/genesis/lib/sgdk/include/z80_ctrl.h +420 -0
  932. package/src/platforms/genesis/lib/sgdk/libmd.seed.a +0 -0
  933. package/src/platforms/genesis/lib/sgdk/libmd.seed.hash +1 -0
  934. package/src/platforms/genesis/lib/sgdk/md.ld +120 -0
  935. package/src/platforms/genesis/lib/sgdk/music/demo.vgm +0 -0
  936. package/src/platforms/genesis/lib/sgdk/music/demo.xgc +0 -0
  937. package/src/platforms/genesis/lib/sgdk/music/demo.xgm +0 -0
  938. package/src/platforms/genesis/lib/sgdk/res/image/font_default.png +0 -0
  939. package/src/platforms/genesis/lib/sgdk/res/image/sgdk_logo.png +0 -0
  940. package/src/platforms/genesis/lib/sgdk/res/libres.h +10 -0
  941. package/src/platforms/genesis/lib/sgdk/res/libres.res +5 -0
  942. package/src/platforms/genesis/lib/sgdk/res/libres.s +166 -0
  943. package/src/platforms/genesis/lib/sgdk/res/sound/stop_xgm.bin +0 -0
  944. package/src/platforms/genesis/lib/sgdk/rom_header.c +33 -0
  945. package/src/platforms/genesis/lib/sgdk/sega.preprocessed.s +364 -0
  946. package/src/platforms/genesis/lib/sgdk/sega.s +365 -0
  947. package/src/platforms/genesis/lib/sgdk/src/bmp.c +1539 -0
  948. package/src/platforms/genesis/lib/sgdk/src/bmp_a.s +3477 -0
  949. package/src/platforms/genesis/lib/sgdk/src/boot/rom_header.c +33 -0
  950. package/src/platforms/genesis/lib/sgdk/src/boot/sega.s +365 -0
  951. package/src/platforms/genesis/lib/sgdk/src/dma.c +782 -0
  952. package/src/platforms/genesis/lib/sgdk/src/dma_a.s +23 -0
  953. package/src/platforms/genesis/lib/sgdk/src/error_a.s +376 -0
  954. package/src/platforms/genesis/lib/sgdk/src/ext/console.c +490 -0
  955. package/src/platforms/genesis/lib/sgdk/src/ext/everdrive.c +285 -0
  956. package/src/platforms/genesis/lib/sgdk/src/ext/fat16.c +610 -0
  957. package/src/platforms/genesis/lib/sgdk/src/ext/flash-save/README.md +112 -0
  958. package/src/platforms/genesis/lib/sgdk/src/ext/flash-save/flash.c +300 -0
  959. package/src/platforms/genesis/lib/sgdk/src/ext/flash-save/saveman.c +641 -0
  960. package/src/platforms/genesis/lib/sgdk/src/ext/link_cable.c +1758 -0
  961. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/CHANGELOG.md +31 -0
  962. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/LICENSE.txt +17 -0
  963. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/README.md +18 -0
  964. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/data.z80 +148 -0
  965. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/define.z80 +173 -0
  966. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/doc/api-c.md +80 -0
  967. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/doc/format.md +132 -0
  968. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/doc/teradrive.md +33 -0
  969. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/fm.z80 +363 -0
  970. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/main.z80 +433 -0
  971. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/minimus.c +129 -0
  972. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/minimus_drv.s80 +17 -0
  973. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/psg.z80 +231 -0
  974. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/track.z80 +398 -0
  975. package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/util.z80 +98 -0
  976. package/src/platforms/genesis/lib/sgdk/src/ext/mw/16c550.c +84 -0
  977. package/src/platforms/genesis/lib/sgdk/src/ext/mw/README.md +849 -0
  978. package/src/platforms/genesis/lib/sgdk/src/ext/mw/comm.c +141 -0
  979. package/src/platforms/genesis/lib/sgdk/src/ext/mw/gamejolt.c +758 -0
  980. package/src/platforms/genesis/lib/sgdk/src/ext/mw/json.c +153 -0
  981. package/src/platforms/genesis/lib/sgdk/src/ext/mw/lsd.c +364 -0
  982. package/src/platforms/genesis/lib/sgdk/src/ext/mw/megawifi.c +1501 -0
  983. package/src/platforms/genesis/lib/sgdk/src/ext/mw/ssf_ed_pro.c +98 -0
  984. package/src/platforms/genesis/lib/sgdk/src/ext/mw/ssf_ed_x7.c +67 -0
  985. package/src/platforms/genesis/lib/sgdk/src/ext/serial/buffer.c +69 -0
  986. package/src/platforms/genesis/lib/sgdk/src/ext/serial/serial.c +158 -0
  987. package/src/platforms/genesis/lib/sgdk/src/joy.c +1361 -0
  988. package/src/platforms/genesis/lib/sgdk/src/kdebug.s +109 -0
  989. package/src/platforms/genesis/lib/sgdk/src/map.c +1915 -0
  990. package/src/platforms/genesis/lib/sgdk/src/mapper.c +280 -0
  991. package/src/platforms/genesis/lib/sgdk/src/maths.c +878 -0
  992. package/src/platforms/genesis/lib/sgdk/src/maths3D.c +480 -0
  993. package/src/platforms/genesis/lib/sgdk/src/maths3D_a.s +205 -0
  994. package/src/platforms/genesis/lib/sgdk/src/memory.c +760 -0
  995. package/src/platforms/genesis/lib/sgdk/src/memory_a.s +306 -0
  996. package/src/platforms/genesis/lib/sgdk/src/object.c +111 -0
  997. package/src/platforms/genesis/lib/sgdk/src/pal.c +484 -0
  998. package/src/platforms/genesis/lib/sgdk/src/pool.c +234 -0
  999. package/src/platforms/genesis/lib/sgdk/src/psg.c +82 -0
  1000. package/src/platforms/genesis/lib/sgdk/src/snd/drv_null.s80 +27 -0
  1001. package/src/platforms/genesis/lib/sgdk/src/snd/drv_xgm.s80 +3037 -0
  1002. package/src/platforms/genesis/lib/sgdk/src/snd/pcm/drv_dpcm2.s80 +984 -0
  1003. package/src/platforms/genesis/lib/sgdk/src/snd/pcm/drv_pcm.s80 +592 -0
  1004. package/src/platforms/genesis/lib/sgdk/src/snd/pcm/drv_pcm4.s80 +699 -0
  1005. package/src/platforms/genesis/lib/sgdk/src/snd/pcm/snd_dpcm2.c +172 -0
  1006. package/src/platforms/genesis/lib/sgdk/src/snd/pcm/snd_pcm.c +152 -0
  1007. package/src/platforms/genesis/lib/sgdk/src/snd/pcm/snd_pcm4.c +213 -0
  1008. package/src/platforms/genesis/lib/sgdk/src/snd/pcm/tab_vol.c +277 -0
  1009. package/src/platforms/genesis/lib/sgdk/src/snd/smp_null.s +22 -0
  1010. package/src/platforms/genesis/lib/sgdk/src/snd/smp_null_dpcm.s +15 -0
  1011. package/src/platforms/genesis/lib/sgdk/src/snd/sound.c +33 -0
  1012. package/src/platforms/genesis/lib/sgdk/src/snd/xgm.c +683 -0
  1013. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2.s80 +993 -0
  1014. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_fct.i80 +611 -0
  1015. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_mac.i80 +133 -0
  1016. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_pcm_fct.i80 +114 -0
  1017. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_pcm_mac.i80 +1444 -0
  1018. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_psg_fct.i80 +491 -0
  1019. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_psg_mac.i80 +43 -0
  1020. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_ym_fct.i80 +1664 -0
  1021. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_ym_mac.i80 +295 -0
  1022. package/src/platforms/genesis/lib/sgdk/src/snd/xgm2.c +1083 -0
  1023. package/src/platforms/genesis/lib/sgdk/src/sprite_eng.c +2256 -0
  1024. package/src/platforms/genesis/lib/sgdk/src/sprite_eng_legacy.c +2309 -0
  1025. package/src/platforms/genesis/lib/sgdk/src/sram.c +30 -0
  1026. package/src/platforms/genesis/lib/sgdk/src/sram_a.s +41 -0
  1027. package/src/platforms/genesis/lib/sgdk/src/string.c +720 -0
  1028. package/src/platforms/genesis/lib/sgdk/src/sys.c +1053 -0
  1029. package/src/platforms/genesis/lib/sgdk/src/sys_a.s +74 -0
  1030. package/src/platforms/genesis/lib/sgdk/src/tab_cnv.c +129 -0
  1031. package/src/platforms/genesis/lib/sgdk/src/tab_log10.c +8201 -0
  1032. package/src/platforms/genesis/lib/sgdk/src/tab_log2.c +8201 -0
  1033. package/src/platforms/genesis/lib/sgdk/src/tab_sin.c +2058 -0
  1034. package/src/platforms/genesis/lib/sgdk/src/tab_sqrt.c +8201 -0
  1035. package/src/platforms/genesis/lib/sgdk/src/task.s +148 -0
  1036. package/src/platforms/genesis/lib/sgdk/src/timer.c +201 -0
  1037. package/src/platforms/genesis/lib/sgdk/src/tools.c +1299 -0
  1038. package/src/platforms/genesis/lib/sgdk/src/tools_a.s +979 -0
  1039. package/src/platforms/genesis/lib/sgdk/src/types.c +18 -0
  1040. package/src/platforms/genesis/lib/sgdk/src/vdp.c +1060 -0
  1041. package/src/platforms/genesis/lib/sgdk/src/vdp_bg.c +511 -0
  1042. package/src/platforms/genesis/lib/sgdk/src/vdp_spr.c +322 -0
  1043. package/src/platforms/genesis/lib/sgdk/src/vdp_tile.c +1011 -0
  1044. package/src/platforms/genesis/lib/sgdk/src/vdp_tile_a.s +68 -0
  1045. package/src/platforms/genesis/lib/sgdk/src/vram.c +273 -0
  1046. package/src/platforms/genesis/lib/sgdk/src/ym2612.c +175 -0
  1047. package/src/platforms/genesis/lib/sgdk/src/z80_ctrl.c +334 -0
  1048. package/src/platforms/genesis/lib/sprite_table.s +129 -0
  1049. package/src/platforms/genesis/lib/vblank_wait.s +73 -0
  1050. package/src/platforms/genesis/lib/vdp_init.s +85 -0
  1051. package/src/platforms/genesis/lib/wram.s +88 -0
  1052. package/src/platforms/genesis/lib/z80_bootstrap.s +102 -0
  1053. package/src/platforms/genesis/vdp.js +548 -0
  1054. package/src/platforms/genesis/xgm2-pcm.js +165 -0
  1055. package/src/platforms/gg/MENTAL_MODEL.md +174 -0
  1056. package/src/platforms/gg/TROUBLESHOOTING.md +105 -0
  1057. package/src/platforms/gg/UPSTREAM_SOURCES.md +36 -0
  1058. package/src/platforms/gg/lib/c/gg_crt0.s +112 -0
  1059. package/src/platforms/gg/lib/c/gg_hw.h +62 -0
  1060. package/src/platforms/gg/lib/c/gg_music.c +155 -0
  1061. package/src/platforms/gg/lib/c/gg_music.h +89 -0
  1062. package/src/platforms/gg/lib/c/gg_sfx.c +82 -0
  1063. package/src/platforms/gg/lib/c/gg_sfx.h +40 -0
  1064. package/src/platforms/gg/lib/c/joypad_read.c +22 -0
  1065. package/src/platforms/gg/lib/c/load_palette.c +20 -0
  1066. package/src/platforms/gg/lib/c/load_tiles.c +32 -0
  1067. package/src/platforms/gg/lib/c/sprite_table.c +60 -0
  1068. package/src/platforms/gg/lib/c/vblank_wait.c +10 -0
  1069. package/src/platforms/gg/lib/c/vdp_init.c +58 -0
  1070. package/src/platforms/gg/song.js +189 -0
  1071. package/src/platforms/index.js +7 -0
  1072. package/src/platforms/lynx/MENTAL_MODEL.md +248 -0
  1073. package/src/platforms/lynx/TROUBLESHOOTING.md +105 -0
  1074. package/src/platforms/lynx/UPSTREAM_SOURCES.md +66 -0
  1075. package/src/platforms/lynx/lib/c/lynx_music.c +63 -0
  1076. package/src/platforms/lynx/lib/c/lynx_music.h +16 -0
  1077. package/src/platforms/lynx/lib/c/lynx_sfx.c +147 -0
  1078. package/src/platforms/lynx/lib/c/lynx_sfx.h +59 -0
  1079. package/src/platforms/lynx/lib/cc65-src/bllhdr.s +18 -0
  1080. package/src/platforms/lynx/lib/cc65-src/bootldr.s +195 -0
  1081. package/src/platforms/lynx/lib/cc65-src/cgetc.s +69 -0
  1082. package/src/platforms/lynx/lib/cc65-src/clock.s +87 -0
  1083. package/src/platforms/lynx/lib/cc65-src/crt0.s +135 -0
  1084. package/src/platforms/lynx/lib/cc65-src/defdir.s +29 -0
  1085. package/src/platforms/lynx/lib/cc65-src/eeprom.s +255 -0
  1086. package/src/platforms/lynx/lib/cc65-src/eeprom46.s +204 -0
  1087. package/src/platforms/lynx/lib/cc65-src/eeprom66.s +227 -0
  1088. package/src/platforms/lynx/lib/cc65-src/eeprom86.s +236 -0
  1089. package/src/platforms/lynx/lib/cc65-src/exec.s +34 -0
  1090. package/src/platforms/lynx/lib/cc65-src/exehdr.s +27 -0
  1091. package/src/platforms/lynx/lib/cc65-src/extzp.inc +23 -0
  1092. package/src/platforms/lynx/lib/cc65-src/extzp.s +30 -0
  1093. package/src/platforms/lynx/lib/cc65-src/irq.s +45 -0
  1094. package/src/platforms/lynx/lib/cc65-src/joy/lynx-stdjoy.s +93 -0
  1095. package/src/platforms/lynx/lib/cc65-src/joy_stat_stddrv.s +14 -0
  1096. package/src/platforms/lynx/lib/cc65-src/kbhit.s +56 -0
  1097. package/src/platforms/lynx/lib/cc65-src/libref.s +9 -0
  1098. package/src/platforms/lynx/lib/cc65-src/load.s +41 -0
  1099. package/src/platforms/lynx/lib/cc65-src/lseek.s +58 -0
  1100. package/src/platforms/lynx/lib/cc65-src/lynx-cart.s +98 -0
  1101. package/src/platforms/lynx/lib/cc65-src/lynx-snd.s +1270 -0
  1102. package/src/platforms/lynx/lib/cc65-src/mainargs.s +24 -0
  1103. package/src/platforms/lynx/lib/cc65-src/open.s +136 -0
  1104. package/src/platforms/lynx/lib/cc65-src/oserror.s +14 -0
  1105. package/src/platforms/lynx/lib/cc65-src/read.s +44 -0
  1106. package/src/platforms/lynx/lib/cc65-src/ser/lynx-comlynx.s +404 -0
  1107. package/src/platforms/lynx/lib/cc65-src/ser_stat_stddrv.s +14 -0
  1108. package/src/platforms/lynx/lib/cc65-src/sysuname.s +39 -0
  1109. package/src/platforms/lynx/lib/cc65-src/tgi/lynx-160-102-16.s +1075 -0
  1110. package/src/platforms/lynx/lib/cc65-src/tgi_colors.s +9 -0
  1111. package/src/platforms/lynx/lib/cc65-src/tgi_irq.s +11 -0
  1112. package/src/platforms/lynx/lib/cc65-src/tgi_stat_stddrv.s +14 -0
  1113. package/src/platforms/lynx/lib/cc65-src/tgi_stddrv.s +13 -0
  1114. package/src/platforms/lynx/lib/cc65-src/uploader.s +81 -0
  1115. package/src/platforms/lynx/song.js +291 -0
  1116. package/src/platforms/msx/MENTAL_MODEL.md +115 -0
  1117. package/src/platforms/msx/TROUBLESHOOTING.md +62 -0
  1118. package/src/platforms/msx/UPSTREAM_SOURCES.md +46 -0
  1119. package/src/platforms/msx/image-to-tilemap.js +103 -0
  1120. package/src/platforms/msx/lib/c/hello_msx.c +51 -0
  1121. package/src/platforms/msx/lib/c/msx_crt0.s +74 -0
  1122. package/src/platforms/msx/lib/c/msx_hw.h +92 -0
  1123. package/src/platforms/msx/lib/c/msx_vdp.c +150 -0
  1124. package/src/platforms/msx/tiles.js +99 -0
  1125. package/src/platforms/msx/vdp.js +160 -0
  1126. package/src/platforms/nes/MENTAL_MODEL.md +323 -0
  1127. package/src/platforms/nes/TROUBLESHOOTING.md +319 -0
  1128. package/src/platforms/nes/UPSTREAM_SOURCES.md +31 -0
  1129. package/src/platforms/nes/image-to-chr.js +195 -0
  1130. package/src/platforms/nes/image-to-tilemap.js +415 -0
  1131. package/src/platforms/nes/lib/README.md +40 -0
  1132. package/src/platforms/nes/lib/asm/LICENSE-FAMITONE +40 -0
  1133. package/src/platforms/nes/lib/asm/chr_ram_header.s +32 -0
  1134. package/src/platforms/nes/lib/asm/famitone2.s +1258 -0
  1135. package/src/platforms/nes/lib/asm/famitone_bridge.s +50 -0
  1136. package/src/platforms/nes/lib/asm/music_data.s +238 -0
  1137. package/src/platforms/nes/lib/c/chr_ram_runtime_hello_sprite.c +81 -0
  1138. package/src/platforms/nes/lib/c/chr_ram_runtime_hud_row.c +101 -0
  1139. package/src/platforms/nes/lib/c/nes_runtime.c +347 -0
  1140. package/src/platforms/nes/lib/c/nes_runtime.h +153 -0
  1141. package/src/platforms/nes/lib/c/nmi_handler.c +51 -0
  1142. package/src/platforms/nes/lib/c/nmi_trampoline.s +25 -0
  1143. package/src/platforms/nes/lib/cc65-src/Makefile.inc +9 -0
  1144. package/src/platforms/nes/lib/cc65-src/_scrsize.s +24 -0
  1145. package/src/platforms/nes/lib/cc65-src/cclear.s +29 -0
  1146. package/src/platforms/nes/lib/cc65-src/chline.s +31 -0
  1147. package/src/platforms/nes/lib/cc65-src/clock.s +31 -0
  1148. package/src/platforms/nes/lib/cc65-src/clrscr.s +72 -0
  1149. package/src/platforms/nes/lib/cc65-src/color.s +68 -0
  1150. package/src/platforms/nes/lib/cc65-src/cpeekc.s +37 -0
  1151. package/src/platforms/nes/lib/cc65-src/cpeekcolor.s +8 -0
  1152. package/src/platforms/nes/lib/cc65-src/cpeekrevers.s +37 -0
  1153. package/src/platforms/nes/lib/cc65-src/cputc.s +95 -0
  1154. package/src/platforms/nes/lib/cc65-src/crt0.s +180 -0
  1155. package/src/platforms/nes/lib/cc65-src/cvline.s +31 -0
  1156. package/src/platforms/nes/lib/cc65-src/get_tv.s +37 -0
  1157. package/src/platforms/nes/lib/cc65-src/gotox.s +21 -0
  1158. package/src/platforms/nes/lib/cc65-src/gotoxy.s +22 -0
  1159. package/src/platforms/nes/lib/cc65-src/gotoy.s +22 -0
  1160. package/src/platforms/nes/lib/cc65-src/irq.s +19 -0
  1161. package/src/platforms/nes/lib/cc65-src/joy/nes-stdjoy.s +102 -0
  1162. package/src/platforms/nes/lib/cc65-src/joy_stat_stddrv.s +14 -0
  1163. package/src/platforms/nes/lib/cc65-src/libref.s +9 -0
  1164. package/src/platforms/nes/lib/cc65-src/mainargs.s +24 -0
  1165. package/src/platforms/nes/lib/cc65-src/neschar.s +4616 -0
  1166. package/src/platforms/nes/lib/cc65-src/ppu.s +158 -0
  1167. package/src/platforms/nes/lib/cc65-src/ppubuf.s +117 -0
  1168. package/src/platforms/nes/lib/cc65-src/randomize.s +18 -0
  1169. package/src/platforms/nes/lib/cc65-src/revers.s +27 -0
  1170. package/src/platforms/nes/lib/cc65-src/setcursor.s +37 -0
  1171. package/src/platforms/nes/lib/cc65-src/sysuname.s +39 -0
  1172. package/src/platforms/nes/lib/cc65-src/tgi/nes-64-56-2.s +480 -0
  1173. package/src/platforms/nes/lib/cc65-src/tgi_stat_stddrv.s +14 -0
  1174. package/src/platforms/nes/lib/cc65-src/tgi_stddrv.s +13 -0
  1175. package/src/platforms/nes/lib/cc65-src/waitvsync.s +18 -0
  1176. package/src/platforms/nes/lib/cc65-src/wherex.s +19 -0
  1177. package/src/platforms/nes/lib/cc65-src/wherey.s +19 -0
  1178. package/src/platforms/nes/lib/clear_nametable.s +38 -0
  1179. package/src/platforms/nes/lib/clear_oam.s +18 -0
  1180. package/src/platforms/nes/lib/load_palette.s +31 -0
  1181. package/src/platforms/nes/lib/nmi_safe.s +65 -0
  1182. package/src/platforms/nes/lib/oam_dma.s +16 -0
  1183. package/src/platforms/nes/lib/read_pad.s +46 -0
  1184. package/src/platforms/nes/lib/reset.s +46 -0
  1185. package/src/platforms/nes/lib/sprite_table_populate.s +75 -0
  1186. package/src/platforms/nes/lib/wait_vblank.s +12 -0
  1187. package/src/platforms/nes/palette.js +39 -0
  1188. package/src/platforms/nes/ppu.js +448 -0
  1189. package/src/platforms/pce/MENTAL_MODEL.md +98 -0
  1190. package/src/platforms/pce/TROUBLESHOOTING.md +54 -0
  1191. package/src/platforms/pce/UPSTREAM_SOURCES.md +38 -0
  1192. package/src/platforms/pce/image-to-tilemap.js +123 -0
  1193. package/src/platforms/pce/lib/c/hello_pce.c +37 -0
  1194. package/src/platforms/pce/lib/c/pce_hw.h +130 -0
  1195. package/src/platforms/pce/lib/c/pce_input.c +36 -0
  1196. package/src/platforms/pce/lib/c/pce_sound.c +53 -0
  1197. package/src/platforms/pce/lib/c/pce_video.c +113 -0
  1198. package/src/platforms/pce/tiles.js +92 -0
  1199. package/src/platforms/pce/vce.js +59 -0
  1200. package/src/platforms/pce/vdc.js +52 -0
  1201. package/src/platforms/sms/MENTAL_MODEL.md +286 -0
  1202. package/src/platforms/sms/TROUBLESHOOTING.md +140 -0
  1203. package/src/platforms/sms/UPSTREAM_SOURCES.md +29 -0
  1204. package/src/platforms/sms/image-to-tilemap.js +260 -0
  1205. package/src/platforms/sms/lib/README.md +117 -0
  1206. package/src/platforms/sms/lib/c/joypad_read.c +33 -0
  1207. package/src/platforms/sms/lib/c/load_palette.c +24 -0
  1208. package/src/platforms/sms/lib/c/load_tiles.c +32 -0
  1209. package/src/platforms/sms/lib/c/sms_crt0.s +101 -0
  1210. package/src/platforms/sms/lib/c/sms_hw.h +53 -0
  1211. package/src/platforms/sms/lib/c/sms_music.c +178 -0
  1212. package/src/platforms/sms/lib/c/sms_music.h +50 -0
  1213. package/src/platforms/sms/lib/c/sms_sfx.c +82 -0
  1214. package/src/platforms/sms/lib/c/sms_sfx.h +40 -0
  1215. package/src/platforms/sms/lib/c/sprite_table.c +60 -0
  1216. package/src/platforms/sms/lib/c/vblank_wait.c +10 -0
  1217. package/src/platforms/sms/lib/c/vdp_init.c +58 -0
  1218. package/src/platforms/sms/lib/header.s +33 -0
  1219. package/src/platforms/sms/lib/joypad_read.s +40 -0
  1220. package/src/platforms/sms/lib/load_palette.s +30 -0
  1221. package/src/platforms/sms/lib/load_tiles.s +50 -0
  1222. package/src/platforms/sms/lib/sprite_table.s +44 -0
  1223. package/src/platforms/sms/lib/vblank_wait.s +36 -0
  1224. package/src/platforms/sms/lib/vdp_init.s +47 -0
  1225. package/src/platforms/sms/song.js +217 -0
  1226. package/src/platforms/sms/vdp.js +530 -0
  1227. package/src/platforms/snes/MENTAL_MODEL.md +289 -0
  1228. package/src/platforms/snes/TROUBLESHOOTING.md +208 -0
  1229. package/src/platforms/snes/UPSTREAM_SOURCES.md +50 -0
  1230. package/src/platforms/snes/brr.js +208 -0
  1231. package/src/platforms/snes/image-to-tilemap.js +227 -0
  1232. package/src/platforms/snes/lib/audio/apu_blob.asm +228 -0
  1233. package/src/platforms/snes/lib/audio/apu_blob.bin +0 -0
  1234. package/src/platforms/snes/lib/audio/explosion.brr +0 -0
  1235. package/src/platforms/snes/lib/audio/sample_bank.bin +0 -0
  1236. package/src/platforms/snes/lib/audio/shoot.brr +0 -0
  1237. package/src/platforms/snes/lib/audio/spc_driver.asm +241 -0
  1238. package/src/platforms/snes/lib/audio_pipeline.asm +62 -0
  1239. package/src/platforms/snes/lib/c/crt0.asm +125 -0
  1240. package/src/platforms/snes/lib/c/hdr.asm +50 -0
  1241. package/src/platforms/snes/lib/c/snes_sfx.c +116 -0
  1242. package/src/platforms/snes/lib/c/snes_sfx.h +96 -0
  1243. package/src/platforms/snes/lib/c/snes_sfx_data.asm +25 -0
  1244. package/src/platforms/snes/lib/cgram_upload.asm +43 -0
  1245. package/src/platforms/snes/lib/lorom_header.asm +47 -0
  1246. package/src/platforms/snes/lib/lorom_multibank.asm +66 -0
  1247. package/src/platforms/snes/lib/nmi_safe.asm +77 -0
  1248. package/src/platforms/snes/lib/oam_upload.asm +45 -0
  1249. package/src/platforms/snes/lib/pad_read.asm +64 -0
  1250. package/src/platforms/snes/lib/pvsneslib/LICENSE +21 -0
  1251. package/src/platforms/snes/lib/pvsneslib/include/ctype.h +6 -0
  1252. package/src/platforms/snes/lib/pvsneslib/include/float.h +4 -0
  1253. package/src/platforms/snes/lib/pvsneslib/include/hdr.asm +47 -0
  1254. package/src/platforms/snes/lib/pvsneslib/include/limits.h +13 -0
  1255. package/src/platforms/snes/lib/pvsneslib/include/math.h +10 -0
  1256. package/src/platforms/snes/lib/pvsneslib/include/setjmp.h +4 -0
  1257. package/src/platforms/snes/lib/pvsneslib/include/snes/background.h +396 -0
  1258. package/src/platforms/snes/lib/pvsneslib/include/snes/console.h +188 -0
  1259. package/src/platforms/snes/lib/pvsneslib/include/snes/dma.h +381 -0
  1260. package/src/platforms/snes/lib/pvsneslib/include/snes/input.h +289 -0
  1261. package/src/platforms/snes/lib/pvsneslib/include/snes/interrupt.h +264 -0
  1262. package/src/platforms/snes/lib/pvsneslib/include/snes/libversion.h +10 -0
  1263. package/src/platforms/snes/lib/pvsneslib/include/snes/lzss.h +43 -0
  1264. package/src/platforms/snes/lib/pvsneslib/include/snes/map.h +113 -0
  1265. package/src/platforms/snes/lib/pvsneslib/include/snes/object.h +234 -0
  1266. package/src/platforms/snes/lib/pvsneslib/include/snes/pixel.h +53 -0
  1267. package/src/platforms/snes/lib/pvsneslib/include/snes/scores.h +66 -0
  1268. package/src/platforms/snes/lib/pvsneslib/include/snes/snestypes.h +65 -0
  1269. package/src/platforms/snes/lib/pvsneslib/include/snes/sound.h +245 -0
  1270. package/src/platforms/snes/lib/pvsneslib/include/snes/sprite.h +456 -0
  1271. package/src/platforms/snes/lib/pvsneslib/include/snes/video.h +465 -0
  1272. package/src/platforms/snes/lib/pvsneslib/include/snes.h +190 -0
  1273. package/src/platforms/snes/lib/pvsneslib/include/stdarg.h +28 -0
  1274. package/src/platforms/snes/lib/pvsneslib/include/stdbool.h +53 -0
  1275. package/src/platforms/snes/lib/pvsneslib/include/stddef.h +27 -0
  1276. package/src/platforms/snes/lib/pvsneslib/include/stdint.h +7 -0
  1277. package/src/platforms/snes/lib/pvsneslib/include/stdio.h +9 -0
  1278. package/src/platforms/snes/lib/pvsneslib/include/stdlib.h +13 -0
  1279. package/src/platforms/snes/lib/pvsneslib/include/string.h +19 -0
  1280. package/src/platforms/snes/lib/pvsneslib/include/strings.h +5 -0
  1281. package/src/platforms/snes/lib/pvsneslib/source/Makefile +87 -0
  1282. package/src/platforms/snes/lib/pvsneslib/source/backgrounds.asm +834 -0
  1283. package/src/platforms/snes/lib/pvsneslib/source/consoles.asm +1028 -0
  1284. package/src/platforms/snes/lib/pvsneslib/source/crt0_snes.asm +329 -0
  1285. package/src/platforms/snes/lib/pvsneslib/source/dmas.asm +1275 -0
  1286. package/src/platforms/snes/lib/pvsneslib/source/hdr.asm +56 -0
  1287. package/src/platforms/snes/lib/pvsneslib/source/input.asm +445 -0
  1288. package/src/platforms/snes/lib/pvsneslib/source/libc.asm +485 -0
  1289. package/src/platforms/snes/lib/pvsneslib/source/libc_c.c +1214 -0
  1290. package/src/platforms/snes/lib/pvsneslib/source/libm.asm +510 -0
  1291. package/src/platforms/snes/lib/pvsneslib/source/libtcc.asm +374 -0
  1292. package/src/platforms/snes/lib/pvsneslib/source/lzsss.asm +256 -0
  1293. package/src/platforms/snes/lib/pvsneslib/source/maps.asm +1078 -0
  1294. package/src/platforms/snes/lib/pvsneslib/source/objects.asm +2881 -0
  1295. package/src/platforms/snes/lib/pvsneslib/source/scores.asm +226 -0
  1296. package/src/platforms/snes/lib/pvsneslib/source/sm_spc.asm +187 -0
  1297. package/src/platforms/snes/lib/pvsneslib/source/snesmodwla.asm +1186 -0
  1298. package/src/platforms/snes/lib/pvsneslib/source/sounds.asm +273 -0
  1299. package/src/platforms/snes/lib/pvsneslib/source/sprites.asm +3946 -0
  1300. package/src/platforms/snes/lib/pvsneslib/source/vblank.asm +917 -0
  1301. package/src/platforms/snes/lib/pvsneslib/source/videos.asm +1137 -0
  1302. package/src/platforms/snes/lib/reset_init.asm +31 -0
  1303. package/src/platforms/snes/lib/sprite_table_populate.asm +122 -0
  1304. package/src/platforms/snes/lib/vram_dma_upload.asm +42 -0
  1305. package/src/platforms/snes/ppu.js +606 -0
  1306. package/src/platforms/snes/song.js +128 -0
  1307. package/src/playtest/playtest.js +841 -0
  1308. package/src/rom-id/identifier.js +421 -0
  1309. package/src/rom-id/patch.js +217 -0
  1310. package/src/toolchains/_worker/pool.js +253 -0
  1311. package/src/toolchains/_worker/run.js +78 -0
  1312. package/src/toolchains/_worker/wasm-worker.js +233 -0
  1313. package/src/toolchains/arm-none-eabi-gcc/gcc.js +216 -0
  1314. package/src/toolchains/asar/asar.js +542 -0
  1315. package/src/toolchains/assemble-snippet.js +256 -0
  1316. package/src/toolchains/cc65/cc65.js +395 -0
  1317. package/src/toolchains/cc65/da65.js +119 -0
  1318. package/src/toolchains/cc65/dbgparse.js +274 -0
  1319. package/src/toolchains/cc65/preset-resolver.js +59 -0
  1320. package/src/toolchains/cc65/presets/nes/chr-ram-runtime.cfg +79 -0
  1321. package/src/toolchains/cc65/presets/nes/chr-ram-runtime.crt0.s +178 -0
  1322. package/src/toolchains/cc65/presets/nes/chr-ram.cfg +76 -0
  1323. package/src/toolchains/cc65/presets/nes/chr-ram.crt0.s +106 -0
  1324. package/src/toolchains/common/ar.js +121 -0
  1325. package/src/toolchains/common/reassemble.js +353 -0
  1326. package/src/toolchains/common/sdk-cache.js +116 -0
  1327. package/src/toolchains/common/symbols.js +139 -0
  1328. package/src/toolchains/dasm/dasm.js +96 -0
  1329. package/src/toolchains/gba-c/gba-c.js +838 -0
  1330. package/src/toolchains/genesis-c/README.md +61 -0
  1331. package/src/toolchains/genesis-c/genesis-c.js +600 -0
  1332. package/src/toolchains/gnu-ld-map.js +86 -0
  1333. package/src/toolchains/index.js +862 -0
  1334. package/src/toolchains/m68k-elf-gcc/gcc.js +230 -0
  1335. package/src/toolchains/objdump.js +199 -0
  1336. package/src/toolchains/parse-errors.js +338 -0
  1337. package/src/toolchains/registry.js +67 -0
  1338. package/src/toolchains/rgbds/rgbds.js +144 -0
  1339. package/src/toolchains/sdcc/preflight-lint.js +295 -0
  1340. package/src/toolchains/sdcc/sdcc.js +540 -0
  1341. package/src/toolchains/sjasm/sjasm.js +85 -0
  1342. package/src/toolchains/snes-c/snes-c.js +409 -0
  1343. package/src/toolchains/tcc816/tcc816.js +79 -0
  1344. package/src/toolchains/vasm68k/vasm68k.js +138 -0
  1345. package/src/toolchains/wladx/wladx.js +120 -0
  1346. package/src/toolchains/z80/binutils.js +82 -0
package/AGENTS.md ADDED
@@ -0,0 +1,1110 @@
1
+ # romdev — Agent guide
2
+
3
+ You are reading this because romdev is connected. This is the orientation. Read it once; you won't need to re-read it during a session.
4
+
5
+ ## What this server does
6
+
7
+ Drives the full homebrew ROM dev loop for 14 retro game platforms (NES, SNES, Game Boy, Game Boy Color, Game Boy Advance, Genesis, Sega Master System, Game Gear, Atari 2600/7800, Atari Lynx, Commodore 64, PC Engine / TurboGrafx-16, and MSX / MSX2). Build → run → screenshot → inspect → patch → iterate. Also a strong reverse-engineering kit: disassemble existing ROMs into byte-exact rebuildable projects (`disasm({target:'project'})`/`disasm({target:'references'})` — the workhorse for any structural hack), find a value's address with the Cheat-Engine search loop (`memory({op:'search'})`/`memory({op:'searchNext'})`), find the EXACT instruction that wrote a RAM byte (`breakpoint({on:'write'})`, a core-level write watchpoint), confirm a patch is live in the running image (`memory({op:'readCart'})`), tell whether a "found table" is really ASCII (`memory({op:'classify'})`), trace which ROM offset a Genesis graphic was DMA'd from (`dmaTrace({precision:'sampled'})`), drive menus by screen-change (`navigate`), and look up cheats (`cheats({op:'lookup'})`/`cheats({op:'search'})`: a free, crowd-sourced labeled RAM/code map for known ROMs), apply + create cheats, convert assets, study patterns from real games. **Doing a romhack? Start with `platform({op:'doc', platform:'romhacking', name:'playbook'})`** — the decision tree that wires all of the above together. Bundled WASM toolchains and emulator cores — no system dependencies, no installs.
8
+
9
+ You drive the work. The human is a director — they may want a game, a ROM disassembly, a tool-assisted reverse-engineering session, or anything else this server can do.
10
+
11
+ ## The one hard rule: NEVER install a compiler or emulator. romdev bundles every one.
12
+
13
+ Internalize this above all else: **you never need — and must never install — a compiler or an emulator to build or run a ROM here.** Every compiler/assembler/linker (cc65, sdcc, gcc, tcc, wla, rgbds, vasm, m68k-gcc, arm-none-eabi-gcc, …), every devkit/SDK (SGDK, PVSnesLib, libtonc/libgba, cc65 libs, …), and every emulator core (fceumm, snes9x, gpgx, gambatte, mGBA, handy, vice, prosystem, stella, …) is **already bundled as WASM** and runs in-process through these MCP tools. The whole build → link → run → inspect loop is `build({output:'rom'})` / `build({output:'run'})` / `build({output:'project'})` / `loadMedia` / `frame({op:'screenshot'})` / `inspect*` / `playtest` — never a host `gcc` or a downloaded toolchain.
14
+
15
+ **So if a build toolchain or emulator is ever invoked or prompts to install — `clang`, `gcc`, Xcode / macOS Command Line Tools, `node-gyp`, devkitPro, `brew/apt install <compiler>` — that is a DEFECT, not your cue to proceed.** Stop, do NOT install it, do NOT investigate it with host-side diagnostic commands (that just alarms the user), and surface it: "romdev should provide this — a host compiler/emulator should never be needed." Then find the romdev tool or report the gap. `platform({op:'list'})` / `platform({op:'toolchains'})` show what's bundled.
16
+
17
+ ### Host content tools (art / audio / map editors) are totally fine
18
+
19
+ This rule is about **compilers and emulators only** — NOT about content tools. ImageMagick, GIMP, Aseprite/LibreSprite, Audacity, Tiled, a tracker (FamiStudio/Deflemask), Python for a quick art script — all fine to use, and fine for the user to install. They produce **raw source art/audio** (a PNG, a sprite sheet, a `.wav`, a `.tmx`); romdev then **imports and packs** that into platform-native data. Use them freely when they help; just don't reach for a *compiler or emulator*.
20
+
21
+ ### romdev also packs assets in-server — reach for these first
22
+
23
+ Asset conversion is bundled too, so you often don't need the host tools at all. First-class tools: `encodeArt({stage:'tiles'})`, `encodeArt({stage:'tilemap'})`, `encodeArt({stage:'quantize'})`, `palette({source:'platformMaster'})`, `palette({source:'lospec'})`, `encodeArt({stage:'validate'})`, the loaders `importArt({from:'texturepacker'})` / `importArt({from:'aseprite'})` / `importArt({from:'gif'})` / `importArt({from:'tiled'})`, and helpers like `sprites({op:'capture'})` / `importArt({from:'rom'})`. The canonical quantize→tile→pack path lives here. Typical flow: paint pixels in a host editor (or generate a PNG), then `encodeArt({stage:'quantize'})` → `encodeArt({stage:'tiles'})` to get platform-native tiles. (You can do the whole thing in-server too when the art is procedural.)
24
+
25
+ ### Native-addon prompts are a packaging bug — never compile on the host
26
+
27
+ A couple of optional features load a native Node addon (most notably the `playtest` SDL window, via `@kmamal/sdl`). These ship **prebuilt** — they must never compile on your machine. If you see a `clang` / Xcode / Command Line Tools / `node-gyp` build kick off while using romdev, the prebuilt binary is missing or mismatched: **do not let it compile, do not install a toolchain — report it.** `playtest` itself self-heals by downloading its prebuilt binary and, if it can't, returns `{opened:false, reason:"sdl-binary-missing", fixCommand}` with the exact one-line fix — it never needs a host compiler.
28
+
29
+ ## If a human is watching, open playtest early
30
+
31
+ If a human is sitting next to you during this session — and that's most sessions in practice — open the playtest window as soon as your first build succeeds. `playtest()` opens a native SDL window that runs your ROM live and accepts USB gamepads (hot-plugged controllers are picked up automatically). It returns **immediately** — the render loop runs in the background, so you keep calling other tools while the human plays. Every other MCP tool keeps working against that same running ROM, and **`build({output:'run'})`/`loadMedia` rebuilds update the window in place** — the window follows your latest build, no relaunch and no crash on rebuild. A human sitting next to you should be **playing the game** while you iterate, not watching screenshots scroll past.
32
+
33
+ ```
34
+ playtest() // opens the SDL window (returns immediately). op:'open' is the default;
35
+ // playtest({op:'stop'|'status'|'framebuffer'}) close / check / capture-what-the-human-sees
36
+ ```
37
+
38
+ After that, keep iterating with `build({output:'run'})` / `build({output:'rom'})` / memory({op:'read'}) / frame({op:'screenshot'}) exactly as before — they all act on the live emulator the user is playing. Because the window and `frame({op:'screenshot'})` read the **same** live host, what you capture is what the human sees. (If you ever need to be explicit — e.g. to double-check the human's exact frame — `playtest({op:'framebuffer'})` captures the window's framebuffer directly, with `source`/`loadedMediaPath`/`frameCount` metadata.)
39
+
40
+ **No gamepad?** `playtest()`'s response includes a `keyboardControls` map and a `tellUser` note when no controller is detected — relay the keys to the human (arrows = D-pad, Z = main action, Enter = START, ESC closes) so they know how to play.
41
+
42
+ Skip playtest only when there's clearly no human in the loop: CI runs, automated test suites, batch reverse-engineering, or when the user has explicitly said "headless." `playtest()` needs a desktop session to draw into; if it can't open a window it returns `{opened:false, reason, message}` and the `message` tells you exactly how to fix it. Two distinct cases: `reason:"sdl-binary-missing"` means the `@kmamal/sdl` native binary isn't installed (the server tries to self-heal, but if it can't, the message gives a `fixCommand` to run + restart) — a one-time native-addon fix, NOT a display problem. `reason:"sdl-error"` means SDL ran but couldn't get a display — usually no desktop session (run the server yourself in a terminal inside your desktop session, then connect your agent). Either way, every other tool (build, run, screenshot, inspect) is fully headless and unaffected. When in doubt, ask once, then default to opening it.
43
+
44
+ ## Tool surface: everything is loaded — just call the tool
45
+
46
+ **All ~34 tools are registered and callable from session init — there is no loading step.** If you see a tool name anywhere in this doc or via `catalog({op:'categories'})`, you can call it right now. Each tool is a small VERB with an operation axis — `memory({op})`, `build({output})`, `sprites({op})`, `breakpoint({on})`, `cpu({op})` — so the whole surface is a few dozen names, not a few hundred.
47
+
48
+ (We used to lazy-load tools behind a `loadCategory` call. It caused more harm than good — agents burned round-trips re-loading categories, and dynamic registration never propagated reliably to clients anyway. The consolidation shrank the surface enough that the entire thing loads up front; the old `loadCategory`/`describeTool` discovery tools are gone.)
49
+
50
+ `catalog({op:'categories'})` still exists as a **map of what's available, grouped by purpose** — useful for discovery, not a gate:
51
+
52
+ - `platforms` — which platforms + languages are supported
53
+ - `run` — load ROMs, step frames, screenshot (works for existing ROMs you didn't compile)
54
+ - `input` — drive controllers, look up hardware bit layouts. `navigate` walks menus by advancing on SCREEN CHANGE (not fixed frames) and reports whether each press was consumed — the fast, reliable way to script a UI.
55
+ - `state` — savestates and forensic state inspection (`state({op:'save'})`, `state({op:'load'})`, `state({op:'export'})` a slot to disk without touching the live host, `state({op:'list'})`, `state({op:'dump'})`)
56
+ - `memory` — read/write VRAM/OAM/CGRAM/ARAM and other regions (all 14 platforms). `memory({op:'read'})` takes `offsets:[…]` to batch scattered reads in one call. **`memory({op:'search'})`/`memory({op:'searchNext'})`** = the Cheat-Engine value-search loop ("find the address of X, narrow as X changes"). **`memory({op:'readCart'})`** reads the loaded cart image to confirm a patch is live. **`memory({op:'classify'})`** says whether bytes look like ASCII/code/tile-data (kills the "found table that's really a string" trap). `memory({op:'snapshot'})` + `memory({op:'diff'})` answer "which bytes changed across this event?" (diff defaults to a clustered summary with stride detection); `state({op:'diff'})` is the coarse whole-machine version.
57
+ - `debug` — `sprites({op:'inspect'})`, `palette({source:'live'})`, `cpu({op:'read'})` (all 14), `audioDebug({op:'inspect'})` (the 12 systems with a sound chip — all but Atari 2600/7800; pass `frames:N` to TRACE a per-channel note-timeline for headless melody asserts), `background({view:'renderState'})`, `breakpoint({on:'write'})` (write watchpoint, all 14), **`dmaTrace({precision:'sampled'})`** (Genesis: which ROM offset a VRAM graphic was DMA'd from), **`disasm({target:'bytes'|'rom'|'references'|'project'})`** (ALL 14 — native binutils objdump per CPU, incl. GBA ARM7/Thumb; the byte-exact `disasm({target:'project'})` reassembles through native as/ld/objcopy), `symbols({op})` lookup, `background({view:'rendered'})`, plus **`cheats({op})`** (`cheats({op:'lookup'})` = a free labeled RAM/code map for known ROMs, `cheats({op:'search'})` to fuzzy-find a game by name, `cheats({op:'apply'})`/`cheats({op:'clear'})` non-destructively, `cheats({op:'make'})` to create codes)
58
+ - `assets` — convert PNGs to tiles (`encodeArt`/`importArt`), WAVs to BRR, identify ROMs (`cart({op:'identify'})`), plus the hacking toolkit (`romPatch({op})` — write/writeMany/spliceCHR/relocate/makeStored/findFree/findPointer/diff, `assembleSnippet`, `cart({op:'extract'})`, `cart({op:'wrap'})`)
59
+ - `project` — starter snippets per platform
60
+ - `show` — `playtest({op})`: `op:'open'` opens the live SDL window for a human, `op:'stop'` closes it, `op:'status'` reports liveness, `op:'framebuffer'` captures exactly what the human's window shows
61
+ - `advanced` — `runUntil`, **`watch({on:'mem'|'range'|'pc'})`** (LOG-ALL tracing), **`breakpoint({on:'write'})`** (the EXACT instruction that wrote a byte, via a core watchpoint — fixes the frame-sampled-PC problem; `precision:'sampled'` is the cheap frame-PC version), **`breakpoint({on:'pc'})`** (execution breakpoint — freeze the CPU AT an instruction and read its registers), **`breakpoint({on:'read'})`** (the EXACT instruction that read a byte), **`frame({op:'stepInstruction'})`** (CPU single-step) — all 14 platforms; input recording
62
+
63
+ **"Disassemble this NES ROM"** is now just: `disasm({target:'rom', path, startAddress, length})`. No discovery step.
64
+
65
+ ### Romhacking / reverse-engineering: check `cheats({op:'lookup'})` early — it's a free RAM map
66
+
67
+ > **Doing a romhack? Read the playbook first:** `platform({op:'doc', platform:'romhacking', name:'playbook'})`
68
+ > — the full decision tree (find a value's address with `memory({op:'search'})`, tell whether
69
+ > on-screen text is a string or a pre-rendered bitmap, confirm a patch is live with
70
+ > `memory({op:'readCart'})`, drive menus fast with `navigate`, avoid the "found table that's
71
+ > really ASCII" trap with `memory({op:'classify'})`). It encodes the traps below so you don't
72
+ > rediscover them the hard way.
73
+
74
+ When the task is to **modify an existing game**, you have two complementary
75
+ entry tools, and which leads depends on the kind of hack:
76
+
77
+ - **`cheats({op:'lookup', path})`** — the bundled cheat DB is a crowd-sourced **labeled
78
+ memory/code map** for thousands of known ROMs: each RAM cheat is a named address
79
+ (`"Infinite Health" → $00CD`), each Game Genie code is a named code site. It
80
+ answers *"which byte holds X?"* for free, in one call — when an entry exists.
81
+ Cheap to check, so check it early. But it only helps for **values it happens to
82
+ label**, and only for ROMs in the DB.
83
+ - **`disasm({target:'rom'})` / `disasm({target:'project'})` / `disasm({target:'references'})`** — the actual
84
+ code. This is how you understand *how* something works and the **only** path for
85
+ structural hacks: new logic/behavior, text, graphics, AI, anything no cheat
86
+ names — and for any game the cheat DB doesn't cover.
87
+
88
+ **Don't treat one as a mere fallback for the other — they answer different
89
+ questions, and running both early is normal.** A good default:
90
+
91
+ 1. **`cart({op:'identify', path})`** → platform + title (sniffs zip-wrapped ROMs too).
92
+ 2. **`cheats({op:'lookup', path})`** — a fast lookup. If it names the address you need,
93
+ you may have just skipped a long memory hunt. If it returns nothing useful (no
94
+ match, or no cheat for *your* target), that's fine — move on, no time lost.
95
+ 3. **Disassemble / trace** whenever the hack is about CODE or about data the
96
+ cheats don't cover: `disasm({target:'project'})` for a rebuildable project,
97
+ `disasm({target:'references'})` for "what touches this address", `breakpoint({on:'write'})` for the exact
98
+ instruction that wrote a byte, `watch({on:'mem'})`/`breakpoint({on:'write',precision:'sampled'})` to find an address
99
+ empirically. For a no-cheats game or a logic/text/graphics change, this is
100
+ where the real work is — start here, don't wait on a cheat lookup.
101
+ 4. **VERIFY before patching**: `memory({op:'write'})` the address live and watch the effect
102
+ (cheat labels are *probable* — matched by name, not verified CRC; static
103
+ "matches the pattern" ≠ "actually runs").
104
+ 5. **Patch**: `romPatch({op:'write'})`/`romPatch({op:'writeMany'})` with `expect:` bytes (refuses a wrong-revision
105
+ write) — or `cheats({op:'apply'})` to prototype a value change live first.
106
+
107
+ Rule of thumb: **cheats are a shortcut for finding a known value's address;
108
+ disassembly is how you change behavior.** Most non-trivial hacks need the
109
+ disassembler regardless — so reach for it freely, and let `cheats({op:'lookup'})` save you a
110
+ hunt when it can, not gate the work when it can't.
111
+
112
+ **If your session ever returns a 404 "session not found"** (the server restarted), your MCP client should auto-reconnect (re-`initialize`) — and the fresh session again has every tool loaded. You don't re-arm anything. If your client does NOT auto-reconnect on 404, restart its MCP connection once; that's a client limitation, not a server step.
113
+
114
+ ## Large output: write to a path, or ask for it inline
115
+
116
+ Tools that can return a LARGE payload (ROM bytes, full disassembly, big memory dumps, build logs, tile blobs, **and screenshots/inspect images**) follow ONE rule so they don't silently flood your context:
117
+
118
+ - **`inline: false` is the default → you MUST pass an output path** (`outputPath` / `outputDir` / `path`). The payload is written there and you get back just `{ path, bytes }`. Calling such a tool with neither a path nor `inline:true` returns a clear error telling you which to pass.
119
+ - **`inline: true` → the payload comes back in the response** (base64 / hex / text / the image). Use this when you actually want it in context.
120
+
121
+ There is **no hidden default location** — nothing ever lands in a temp dir you can't find, so you never lose a ROM to `/tmp`. You (the agent) decide where output goes; pass your project directory.
122
+
123
+ Ergonomic exceptions:
124
+ - **Small reads stay inline.** `memory({op:'read'})` of ≤4 KB returns hex inline with no path needed (peeking a few RAM/OAM/palette bytes is the common case). Only large reads require a path/inline.
125
+ - **`build({output:'run'})` returns its screenshot inline by default** — its whole purpose is "build + run + show me." Pass `screenshotPath` only if your client can't display inline images.
126
+
127
+ **On images specifically:** the `inline:true` image is only useful if YOUR client actually delivers inline images to you — some clients silently drop or down-convert image content. If you're not certain you can see them, **work from the structured data instead**: `sprites({op:'inspect'})` / `palette({source:'live'})` / `background({view:'renderState'})` always return their decoded JSON (sprite lists, palette entries, render flags) regardless of inline/path, and `frame({op:'screenshot', format:'ascii'})` gives a text render. The inline PNG is an opt-in luxury, not the primary signal.
128
+
129
+ ## Trust hierarchy — where to find ground truth (R58 + R58b)
130
+
131
+ Two parallel paths depending on what you need:
132
+
133
+ ### Path A — Scaffold a working project (the dumb-model-friendly path)
134
+
135
+ Most agent sessions start here. You want a working ROM, not a
136
+ research project. Use the high-level scaffolding tools and don't
137
+ worry about ground truth:
138
+
139
+ 1. **`scaffold({op:'project', platform, template, name, path})`** — drops a
140
+ complete, self-contained project tree on disk (main.c + the
141
+ runtime files it needs + your `vendor/` library source for
142
+ reference + README + .gitignore). Build with `build({output:'run'})` against
143
+ the project's files; the bundled examples ARE the reference
144
+ implementation.
145
+ 2. **`scaffold({op:'game', platform, genre})`** — same but picks a known-good
146
+ genre scaffold (shmup / platformer / puzzle / sports / racing).
147
+ 3. **`scaffold({op:'snippets', platform, mode})`** (mode `list`/`get`/`getAll`)
148
+ / **`scaffold({op:'copySnippets', platform, destinationDir})`** — fetch
149
+ vetted helper files (reset routine, read_pad, OAM DMA, palette
150
+ upload, etc.) when building from a smaller starting point.
151
+ `scaffold({op:'copySnippets'})` writes the files to disk in one call
152
+ without round-tripping bytes through your context — preferred
153
+ when you're scaffolding into a project dir.
154
+
155
+ For most workflows, path A is all you need. Read MENTAL_MODEL.md +
156
+ TROUBLESHOOTING.md when stuck. File a feedback round if the bundled
157
+ examples are wrong.
158
+
159
+ ### Path B — Debug when the bundled code disagrees with behavior
160
+
161
+ When the example builds clean but doesn't render / sound / behave
162
+ right, when an API call doesn't do what you expect, when you need
163
+ ground truth on what a library function actually does — dig in this
164
+ order:
165
+
166
+ 1. **Bundled examples** (`examples/<platform>/templates/*.{c,asm}`) —
167
+ verified to compile + (usually) run. Start here for the working pattern.
168
+ 2. **Your own project's runtime source** (alongside `main.c`) — our
169
+ thin wrappers (gb_runtime.c, lynx_sfx.c, sms_vdp_init.c, etc.).
170
+ All ~50-200 lines, fully readable. Read these when an API call
171
+ isn't doing what you expect.
172
+ 3. **Your own project's `vendor/` library source** (R58b — auto-
173
+ copied into every project at scaffold time). The FULL source of
174
+ every library your ROM links against — `vendor/cc65/libsrc/<p>/`
175
+ for cc65 platforms, `vendor/libtonc/src/` + `vendor/libgba/src/`
176
+ for GBA, `vendor/pvsneslib/source/` for SNES, `vendor/sgdk/src/`
177
+ for Genesis. **`grep -rn <symbol> vendor/`** inside your project
178
+ finds the actual implementation of any library function. No MCP
179
+ call needed.
180
+ 4. **`platform({op:'doc', platform, name:"upstream_sources"})`** — per-
181
+ platform pointers at every bundled source path + upstream GitHub
182
+ links for the compilers + emulators we DON'T bundle (cc65,
183
+ sdcc, m68k-gcc, snes9x, gambatte, handy, etc.). Use as a
184
+ cheat-sheet for "where do I look for X?"
185
+ 5. **Upstream GitHub** for compilers + emulators when the bug is
186
+ below our thin wrappers. Don't bundle (gigabytes for gcc/binutils
187
+ source) but the link is one click.
188
+ 6. **Hit a real bug in romdev itself?** Open an issue at
189
+ https://github.com/monteslu/romdev/issues with repro details. File
190
+ only with a diagnosis (not bare "it doesn't work") — read the bundled
191
+ source first.
192
+
193
+ **Important constraint on path B:** the `vendor/` library source is
194
+ **read-only in practice**. You can read + grep it freely, but if
195
+ you EDIT a file there, the linker still uses our precompiled
196
+ `libtonc.a` / `libmd.a` / etc., so your ROM won't pick up the
197
+ change. R59 (planned) will fix this with a per-TU object cache +
198
+ source-first library build. Until then, treat `vendor/` as a window
199
+ into "what the linked code actually does."
200
+
201
+ The "vendor/" library source in your project is new in R58b (it was
202
+ previously in the install only; you'd have to call
203
+ `scaffold({op:'copySnippets'})` to pull it in). Now it lands automatically
204
+ when you `scaffold({op:'project'})`. Round 30/31 Lynx wedges took 5 friction
205
+ rounds partly because cc65's TGI driver source wasn't visible;
206
+ post-R58b you can `grep -rn bar_c vendor/cc65/libsrc/lynx/` from
207
+ inside your project directory and read the actual blitter code.
208
+
209
+ **Practical rule for path B:** if you find yourself filing a
210
+ feedback round without first `grep`ping `vendor/` for the symbol
211
+ you're debugging, you're skipping the cheap diagnosis path. The
212
+ bundled examples are starting points, NOT ground truth — when they
213
+ disagree with behavior, trust the library source over the example.
214
+
215
+ ### Which path to use
216
+
217
+ - **Just need a working game** → Path A. Use `scaffold({op:'game'})`, iterate.
218
+ - **Hit a bug or unexpected behavior** → switch to Path B.
219
+ - **Don't know which** → start in Path A; if iterations fail to
220
+ converge after 2-3 attempts, you're hitting something path A
221
+ can't fix and need path B.
222
+
223
+ ### Where files land in your project tree
224
+
225
+ A scaffolded project (whether via `scaffold({op:'project'})` or `scaffold({op:'game'})`) is
226
+ **FLAT** for everything you author. `main.c` / `main.asm`, your
227
+ helper modules (e.g. `gb_runtime.c`, `nes_runtime.c`,
228
+ `atari7800_sfx.c`, `vcs_constants.h`), the platform crt0 + linker
229
+ config — all sit at the project root, next to each other. Asm
230
+ `include "vcs_constants.h"` / C `#include "gb_runtime.h"` resolves
231
+ without `-I` flags because dasm / cc65 / sdcc all default to the
232
+ current directory.
233
+
234
+ The **only** subdir you'll see at scaffold time is `vendor/` —
235
+ that's the read-only library source tree (cc65 libsrc, libtonc /
236
+ libgba src, PVSnesLib source, SGDK src) auto-bundled by R58b so
237
+ you can `grep -rn vendor/` when debugging. Don't put your own
238
+ source under `vendor/`.
239
+
240
+ So when `scaffold({op:'copySnippets'})` drops e.g. `read_joystick.asm` into
241
+ your project dir, it lands at `./read_joystick.asm` (alongside
242
+ `main.asm`), NOT under `./include/` or `./lib/`. Every platform
243
+ follows the same flat layout.
244
+
245
+ Because the layout is flat, **`build({output:'project', path, platform})` rebuilds the
246
+ whole directory in one call — no per-iteration file manifest.** It finds `main.c`
247
+ (C / SGDK Genesis / GBA / cc65-C / SDCC-C) or `main.s` / `main.asm` (asm), links every
248
+ `.c`/`.s` in the dir, treats `.h`/`.inc` as includes, and folds binary assets
249
+ (`.bin/.chr/.pcm/.brr/.vgm/...`) in as `binaryIncludes`. So iterating an on-disk project is
250
+ just `build({output:'project', path:'/my/proj', platform})` every time — you don't re-send
251
+ `sources`/`includes` each build. (Use `build({output:'rom'})` with explicit `sources` when
252
+ the files aren't on disk, e.g. generated in-context.)
253
+
254
+ ## Supported platforms
255
+
256
+ **13 tier-1 platforms** (build + run + screenshot + inspect + ≥5 genre scaffolds + sound + music + per-platform MENTAL_MODEL.md + TROUBLESHOOTING.md):
257
+
258
+ NES, Game Boy, Game Boy Color, SNES, Genesis, Game Boy Advance, SMS, Game Gear, C64, Atari 2600, Atari 7800, Lynx — all with `scaffold({op:'game', genre: shmup|platformer|puzzle|sports|racing})` available except Atari 2600 (asm-only — no genre scaffolds). The `platformer` scaffold side-scrolls (hardware camera + per-platform column streaming) on every one of these except NES, which is single-screen. Every tier-1 platform also ships a `music_demo` template using the platform's de-facto music engine: FamiTone2 (NES), hUGEDriver (GB/GBC), SPC700 driver (SNES), XGM2 via SGDK (Genesis), maxmod + .xm soundbank (GBA), PSG trackers (SMS/GG), SID sequencer (C64), `lynx_snd_play` (Lynx), 2-voice TIA (Atari 2600/7800).
259
+
260
+ **Bring-up only** (build pipeline works, single `default` template, no genre scaffolds or sound/music wrappers yet): MSX, ColecoVision. Both use SDCC z80 same as SMS/GG — the genre scaffolds are queued.
261
+
262
+ **Delisted** (toolchain works but core-side issue blocks the run loop): Atari 5200 (atari800 BIOS-load path), ZX Spectrum (fuse tape-load path).
263
+
264
+ Call `platform({op:'list'})` (in the `platforms` category) for the live capability matrix, including per-platform language defaults and quirks. **Defaults are picked to maximize agent effectiveness** — for every platform that has a bundled C compiler, C is the default (LLMs write C cleanly; the compiler handles register allocation + memory mapping). Platforms whose only bundled toolchain is an assembler default to asm. Override with `language: "asm"` or `language: "c"` when you specifically need the non-default.
265
+
266
+ For maintainers: the platform / core / patch / region-ID matrix and the recipe for adding a new platform live in the project repo at https://github.com/monteslu/romdev.
267
+
268
+ ## Deep debug tooling status per platform
269
+
270
+ Different platforms have different levels of MCP-exposed debugging — different hardware needs different tools, and we've patched the cores where it's been worth it. The generic shapes — `cpu({op:'read'})`, `breakpoint({on:'write'})`, `disasm({target:'rom'})`/`disasm({target:'references'})`/`disasm({target:'project'})`, `memory({op:'search'})`/`memory({op:'readCart'})`/`memory({op:'classify'})`, cheats — work on **all 14 platforms** (disassembly via native binutils `objdump` compiled to WASM, one per CPU family — incl. GBA ARM7/Thumb). The deep per-platform inspectors (`sprites({op:'inspect'})`, `palette({source:'live'})`, `background({view:'renderState'})`, `audioDebug({op:'inspect'})`) are detailed for **12 systems** below; **PC Engine and MSX** currently have the generic shapes + their core's native regions but not yet the full custom-inspector treatment (extend by patching their cores per the snes9x/gpgx pattern). `audioDebug({op:'inspect'})` covers the **12 with a sound chip** (all but Atari 2600/7800). A few are honest hardware-shaped exceptions, noted inline below (the Lynx has no fixed OAM so `sprites({op:'inspect'})` returns the SCB list head). Coverage detail per platform:
271
+
272
+ > **Universal across ALL 14 platforms:** `breakpoint({on:'write'})` (the core-level
273
+ > instruction write watchpoint — the exact PC that wrote a RAM byte, all 14 CPU
274
+ > families), **`breakpoint({on:'pc'})`** (execution breakpoint — freeze the CPU AT an
275
+ > instruction and read its registers), **`breakpoint({on:'read'})`** (the exact PC that read
276
+ > a byte — read-side mirror of `breakpoint({on:'write'})`), **`frame({op:'stepInstruction'})`** (CPU single-step),
277
+ > **`cpu({op:'setReg'})`** (write a CPU register), **`cpu({op:'call'})`/`cpu({op:'decompress'})`**
278
+ > (drive the ROM's OWN routine — e.g. its decompressor — and capture the output;
279
+ > a per-instruction watchdog on **every CPU core** (m68k, 6502/6507/6510/65c02/65816,
280
+ > z80 incl. SMS/GG, sm83, arm7tdmi, huc6280) force-stops a runaway routine and
281
+ > returns `{watchdog:true, finalPC, finalRegs}` instead of hanging. It catches BOTH
282
+ > a tight infinite loop AND a wrong-entry FREE-RUN (a wrapper PC with a bad source
283
+ > that falls back into the game's main loop): the default budget is PER-CPU, sized
284
+ > to trip before the frame cap on the slow ~1MHz cores too. Pass `maxInstructions`
285
+ > to override the budget, `presetMemory`/`stopAtPC` for codecs that read RAM globals
286
+ > or need a mid-routine halt),
287
+ > **`watch({on:'range'})`** (log EVERY read/write hitting an address range — discovery),
288
+ > **`watch({on:'pc'})`** (coverage trace — distinct PCs executed in a window),
289
+ > **the RE-INJECT trio** (put an edited asset BACK, all 14): **`romPatch({op:'findPointer'})`**
290
+ > (find every pointer to a ROM offset — Genesis 32-bit BE, SNES LoROM/HiROM, GBA
291
+ > 0x08000000+offset incl. literal pools, banked 8-bit 16-bit-LE aliases),
292
+ > **`romPatch({op:'makeStored'})`** (wrap raw bytes so the game's OWN decompressor expands them
293
+ > verbatim — GBA LZ77 / SNES LC_LZ2 / SMS+MSX RLE / NES PackBits / `raw` for the
294
+ > uncompressed-graphics systems; Nemesis + C64 crunchers honestly refused), and
295
+ > **`romPatch({op:'relocate'})`** (write to free space + repoint),
296
+ > `cheats({op:'lookup'})`/`cheats({op:'search'})`/`cheats({op:'apply'})`/`cheats({op:'make'})` (cheat
297
+ > lookup/apply/create), `cpu({op:'read'})`, `memory({op:'search'})`/`memory({op:'searchNext'})`/`memory({op:'readCart'})`/`memory({op:'classify'})`,
298
+ > `memory({op:'snapshot'})`/`memory({op:'diff'})`/`state({op:'diff'})`, `watch({on:'mem'})`/`breakpoint({on:'write',precision:'sampled'})`.
299
+ > `audioDebug({op:'inspect'})` covers the 12 systems with a sound chip (all but Atari 2600/7800).
300
+ > **`dmaTrace({precision:'exact'})`** (which DMA wrote a VRAM tile, and from where) is **Genesis-only**
301
+ > (VDP DMA) — elsewhere use `breakpoint({on:'write'})`/`watch({on:'range'})`. All other RE tools above
302
+ > work on every platform that has the register-write/watch core hooks (all 14).
303
+ > `disasm({target:'rom'})` + `disasm({target:'references'})` + `disasm({target:'project'})` cover **all 14** — every
304
+ > CPU family disassembles through a native binutils `objdump` (WASM), and
305
+ > `disasm({target:'project'})` reassembles byte-exact through the matching native
306
+ > `as`/`ld`/`objcopy`. The per-platform notes below cover the platform-SPECIFIC
307
+ > inspectors + chips (PC Engine + MSX: generic shapes only so far).
308
+
309
+ - **SNES** (snes9x patched): `sprites({op:'inspect'})`, `palette({source:'live'})`, `cpu({op:'read', cpu:'main'|'spc700'})`, getDspState (full per-voice + master mixer), `memory({op:'read'})` regions for OAM/CGRAM/ARAM/FillRAM. Audio + video both deeply introspectable.
310
+ - **NES** (fceumm patched): `sprites({op:'inspect'})`, `palette({source:'live'})`, `cpu({op:'read'})` (6502), `background({view:'renderState'})` (PPUCTRL/PPUMASK decoded → active CHR bank + file offset), `memory({op:'read'})` regions for OAM/Palette/Nametables/CHR/CPU_REGS/PPU_REGS/APU_REGS.
311
+ - **Genesis** (gpgx patched): `sprites({op:'inspect'})`, `palette({source:'live'})`, `cpu({op:'read', cpu:'main'})` for 68K, getYm2612State (limited — internal struct), getPsgState, `memory({op:'read'})` regions for CRAM/VSRAM/VDP_REGS/Z80_RAM/M68K/YM2612/PSG/VRAM.
312
+ - **SMS / Game Gear** (gpgx patched): `sprites({op:'inspect'})` (SAT decode + sprite-sheet PNG), `palette({source:'live'})` (6-bit BGR for SMS, 12-bit BGR for GG), `tiles({op:'png'})` (4bpp interleaved, 16KB VRAM as 512-tile sheet), `cpu({op:'read'})` (Z80 — A/F/BC/DE/HL/IX/IY/shadows + flags + interrupt state), `audioDebug({op:'inspect', chip:'psg'})` (SN76489 — 3 tone + 1 noise; same gpgx region as Genesis), `background({view:'renderState'})` (VDP regs → name table / BG-tile / sprite-tile / SAT addresses + scroll + display state), `memory({op:'read'})` regions for sms_vram, sms_cram, sms_vdp_regs, sms_z80_regs (gg_vram, gg_cram for Game Gear's 64-byte palette). `disasm({target:'rom'})` + `disasm({target:'references'})` + `disasm({target:'project'})` run through the native binutils z80 `objdump` (WASM, `-m z80`) with full prefix coverage (CB/ED/DD/FD/DDCB/FDCB) and the same auto-label / register-annotation / file-offset / untilReturn pipeline as NES/SNES.
313
+ - **Game Boy / Game Boy Color** (gambatte patched): `sprites({op:'inspect'})` (40-sprite OAM decode + sprite-sheet PNG with sprite-priority + h/v flip), `palette({source:'live'})` (DMG: BGP/OBP0/OBP1 byte decode → 4 shades each; GBC: 64-byte BCPS/OCPS palette RAM → 8 palettes × 4 colors BGR555), `tiles({op:'png'})` (384 tiles from $8000-$97FF), `cpu({op:'read'})` (SM83 — A/F/BC/DE/HL + flags + IME/halt), `audioDebug({op:'inspect', chip:'gb'})` (DMG APU — 2 pulse + wave + noise with timer→freq→note, sweep, duty, panning), `background({view:'renderState'})` (LCDC bit-by-bit, scroll, LY/LYC, window, GBC extras: VRAM bank / KEY1 / BCPS/OCPS index), `memory({op:'read'})` regions for gb_vram, gb_oam, gb_io, gb_hram, gb_bgpdata, gb_objpdata, gb_cpu_regs. `disasm({target:'rom'})` + `disasm({target:'references'})` + `disasm({target:'project'})` route through the native binutils z80 `objdump` in its `gbz80` machine (WASM, `-m gbz80`) — full CB-prefix coverage + SM83-specific opcodes (`ld (hl+),a`, `ldh`, `reti`, `ld hl,sp+e8`). One z80-elf binutils serves both plain Z80 (SMS/GG/MSX) and the GB CPU.
314
+ - **Toolchains:** default is **C** via SDCC's sm83 port (same SDCC that powers SMS/GG/MSX/Coleco). For hand-tuned asm, pass `language:"asm"` to route through RGBDS. The C path uses `__sfr __at 0xFFNN` to bind GB I/O regs; helper headers under `src/platforms/gb/lib/c/gb_hardware.h` define LCDC/STAT/SCY/SCX/LY/BGP/OBP0/OBP1/etc. for both DMG and CGB. The SDCC 4.4.0 codegen quirk (`for (;;) { switch + write to __sfr }` crashes the register allocator) applies — use `do { ... } while (1)` and table-lookup writes instead.
315
+ - **Atari 2600** (stella2014 patched): `palette({source:'live'})` (NTSC 128-color palette PNG; current background luma+hue extracted from TIA snapshot), `sprites({op:'inspect'})` (no OAM — returns the 5 graphics objects state P0/P1/M0/M1/Ball + a current-scanline PNG showing TIA composition), `cpu({op:'read'})` (6502 — A/X/Y/P/SP/PC from the M6502 internal regs), `background({view:'renderState'})` (decodes the 32-byte TIA snapshot into playfield/sprite/colors), `memory({op:'read'})` regions for `system_ram` (128 bytes of RIOT RAM), `a26_tia_regs` (32-byte TIA snapshot), `a26_cpu_regs` (7-byte 6502 snapshot). `disasm({target:'rom'})` + `disasm({target:'references'})` anchor to the top of the bank ($F000-$FFFF) with vector-table labels (NMI/RESET/IRQ at $FFFA).
316
+ - **Atari 7800** (prosystem patched): `palette({source:'live'})` (256-color master PNG; MARIA palette block at $20-$3F decoded into 8 palettes × 3 colors + backdrop), `sprites({op:'inspect'})` (no OAM — returns the MARIA control regs + the DPP display-list-list pointer for the agent to walk), `cpu({op:'read'})` (6502 — A/X/Y/P/SP/PC from prosystem's sally globals), `background({view:'renderState'})` (MARIA CTRL bits + DPP + CHARBASE + dlistPtr), `memory({op:'read'})` regions for `system_ram` (the entire 64KB 6502 address space — MARIA regs, RAM, ROM all visible) + `a78_cpu_regs`. `disasm({target:'rom'})` + `disasm({target:'references'})` default to the top 16KB ($C000-$FFFF) where the reset vector lands.
317
+ - **Commodore 64** (vice patched): `palette({source:'live'})` (the 16-color hardware-fixed palette PNG + current border/background/extra-bg indices decoded from VIC-II regs), `sprites({op:'inspect'})` (8 MOBs decoded into the generic shape with X/Y/color/multicolor/expand-X/expand-Y/priority + the screen-RAM sprite-data pointers at $07F8 so the agent can locate sprite pixel blocks), `cpu({op:'read'})` (6510 — A/X/Y/P/SP/PC from a `#define`-aliased live register file + the I/O port at $0001 decoded into LORAM/HIRAM/CHAREN), `audioDebug({op:'inspect', chip:'sid'})` (6581/8580 — 3 voices {waveform, freq→note, pulse-width, ADSR} + filter cutoff/resonance/mode), `background({view:'renderState'})` (VIC-II regs decoded into mode/scroll/colors/sprites, VIC bank from CIA2 $DD00, absolute screen + char base addresses), `memory({op:'read'})` regions for `system_ram` (64 KB RAM), `c64_color_ram` (1 KB), `c64_vic_regs` (64 B), `c64_sid_regs` (29 B via sid_peek), `c64_cia1_regs`/`c64_cia2_regs` (16 B each from `c_cia[]`), `c64_cpu_regs` (7 B). `disasm({target:'rom'})` + `disasm({target:'references'})` accept `.prg` files (2-byte load-address header) and the C64 register annotation table for VIC-II / SID / CIA registers. Starter snippets cover vic_init / sprite_table / sid_play / read_joystick / basic_stub.
318
+ - **Game Boy Advance** (mgba patched): `sprites({op:'inspect'})` (128 OAM sprites → generic shape with shape/size, 9-bit signed X, affine/hidden, tile/palette/priority), `palette({source:'live'})` (256 BG + 256 OBJ 15-bit BGR555, `area:'bg'|'sprite'`), `cpu({op:'read'})` (ARM7TDMI — 16 gprs r0-r15 + cpsr/spsr + mode + ARM/THUMB, plus `execPc` adjusted for pipeline prefetch), `audioDebug({op:'inspect', chip:'gba'})` (4 DMG PSG channels + 2 Direct Sound DMA FIFOs, master/bias), `background({view:'renderState'})` (DISPCNT bg-mode + per-BG enable/priority/char-base/map-base/color-mode, forced-blank, OBJ enable), `memory({op:'read'})` regions for `gba_cpu_regs`, `gba_io_regs` (the IO page — video AND audio regs), `gba_palette`, `gba_oam`, plus system_ram/video_ram/save_ram. `disasm({target:'rom'})` + `disasm({target:'references'})` + `disasm({target:'project'})` run through the native binutils `arm-none-eabi-objdump` (WASM) — ARM by default, `thumb:true` for Thumb code; the byte-exact project reassembles through `arm-none-eabi-as`/`ld`/`objcopy`. (Note: GBA C compiles mostly to Thumb reached via an ARM crt0 stub, so an ARM-mode disasm of a full ROM decodes the Thumb spans as `.byte` — still byte-exact, just less readable until ARM/Thumb mode-tracking lands.)
319
+ - **Atari Lynx** (handy patched): `palette({source:'live'})` (16-entry 12-bit Mikey palette → RGB), `cpu({op:'read'})` (65C02 — A/X/Y/P/SP/PC + flags), `audioDebug({op:'inspect', chip:'mikey'})` (4 channels — volume, timer→freq→note, 12-bit LFSR state), `background({view:'renderState'})` (DISPCTL DMA-enable/flip/color-mode + display base address), `memory({op:'read'})` regions for `lynx_cpu_regs`, `lynx_hw_regs` (the $FC00-$FDFF Suzy+Mikey window — sprite engine regs, LCD control, audio, palette), plus system_ram. **`sprites({op:'inspect'})` is a special case:** the Lynx has NO fixed OAM — sprites are SCB (Sprite Control Block) linked lists in RAM walked by Suzy, so `sprites({op:'inspect'})` returns the SCB list head (SCBNEXT $FC10/$FC11) and instructions to walk the chain over system_ram rather than a sprite table.
320
+ - **MSX, ColecoVision**: standard system_ram + save_ram + video_ram. Deeper introspection not yet added — extend by patching their cores following the snes9x/gpgx/fceumm/vice pattern (see scripts/patches/).
321
+
322
+ Starter snippets per platform live under `src/platforms/<platform>/lib/`. Discover via `scaffold({op:'snippets', platform})` (default `mode:'list'`), fetch one via `scaffold({op:'snippets', platform, mode:'get', name})`. SNES + NES + Genesis + SMS + Game Boy + Atari 2600 + Atari 7800 have substantial snippet libraries; others are minimal.
323
+
324
+ ## ROMs are finalized for real hardware automatically
325
+
326
+ `build({output:'rom'})` / `build({output:'run'})` return ROMs that boot on **real hardware,
327
+ flashcarts, and strict emulators (RetroDECK / RetroArch)** — not just our
328
+ lenient WASM cores. The build pipeline runs each platform's required
329
+ post-link finalize step for you. **You do NOT need to checksum, pad, or
330
+ header-patch the output yourself.** What gets fixed:
331
+
332
+ - **Genesis** — padded to a 128KB boundary (min 512KB) + `$18E` checksum.
333
+ - **GB / GBC** — `rgbfix`: Nintendo logo ($0104), header checksum ($014D),
334
+ global checksum, CGB flag ($0143 = $00 for `.gb`, $C0 for `.gbc`).
335
+ - **SMS** — `TMR SEGA` header at $7FF0 + checksum ($7FFA) + region/size byte
336
+ (export region $4) so the SMS BIOS doesn't reject it. (GG BIOS doesn't
337
+ check, but it's written anyway.)
338
+ - **SNES** — padded to a power of 2 (min 32KB) + internal checksum ($FFDE) +
339
+ complement ($FFDC), LoROM/HiROM auto-detected.
340
+ - **NES** — the iNES header is emitted by the linker config; nothing to add.
341
+
342
+ Why this matters: our WASM emulator skips the boot-ROM validation that real
343
+ hardware runs, so a ROM can look perfect in `frame({op:'screenshot'})`/`playtest` yet fail
344
+ to boot on a console or RetroDECK. The finalize step closes that gap. The
345
+ build response `romLayout` / `log` states what was applied.
346
+
347
+ ## First, try build({output:'run'})
348
+
349
+ **`build({output:'run'})` is the primary tool.** It does build + load + run + screenshot
350
+ in a single call, returning the image inline. Reach for it before any 4-call
351
+ sequence of build({output:'rom'}) → loadMedia → frame({op:'step'}) → frame({op:'screenshot'}).
352
+
353
+ ```js
354
+ build({
355
+ output: "run",
356
+ platform: "gbc",
357
+ source: /* your C or asm */,
358
+ frames: 60,
359
+ holdInputs: [{ a: true }], // optional — hold buttons during the run
360
+ })
361
+ ```
362
+
363
+ Round trip is ~50-500 ms depending on platform. Use it for fast iteration,
364
+ prototyping, "does my change still render correctly", "does the d-pad
365
+ move the sprite". When you change a line of code, the next call is usually
366
+ just another `build({output:'run'})` with the same args.
367
+
368
+ **Where it shines:**
369
+ - Trying out a new game-loop change
370
+ - Verifying a sprite renders at the right position
371
+ - Testing input handling — `holdInputs: [{right: true}]` for 60 frames and
372
+ see if the player moved right
373
+ - Quick "did I break it" sanity checks after a refactor
374
+
375
+ You don't need `loadMedia` / `frame({op:'step'})` / `frame({op:'screenshot'})` separately for any
376
+ of these. The 4-call workflow only matters when you want to drive multiple
377
+ emulator-state changes within one ROM lifetime (e.g. screenshot at frame 30,
378
+ save state, screenshot at frame 60, etc.).
379
+
380
+ ## Going deeper
381
+
382
+ When `build({output:'run'})` is too coarse, the long-form workflow:
383
+
384
+ 1. `build({output:'rom', platform, source})` → get a ROM as base64 bytes
385
+ 2. `loadMediaBytes({ platform, base64 })` → load without disk I/O
386
+ 3. `frame({op:'step', frames: N})` or `runUntil({ condition })` → advance time
387
+ 4. `frame({op:'screenshot'})` for vibes, `tiles({op:'pixels'})`/`tiles({op:'fingerprints'})` for byte-precise work, `memory({op:'read'})` for game state
388
+ 5. `input({op:'set'})` / `input({op:'press'})` / `input({op:'sequence'})` to drive the game
389
+ 6. `state({op:'save'}, "checkpoint")` / `state({op:'load'}, "checkpoint")` for try/undo
390
+
391
+ ## Build errors
392
+
393
+ Every build tool returns `issues: [{file, line, col, severity, message, stage}, ...]`. Use that array, not the raw `log`. If `issues` is empty but `ok: false`, fall back to `log`.
394
+
395
+ **Crash isolation (R12).** Every WASM toolchain call runs in a child worker process. If a tool aborts (`_abort()`, SIGSEGV, OOM), only the worker dies — the MCP server keeps running, all other agent sessions are unaffected, tool registration + save states + playtest windows survive. The build response surfaces as `{ ok: false, stage: "crash", log: "[crash] worker exited unexpectedly — signal=… code=…", crash: { exitCode, signal } }`. Treat `stage: "crash"` as "the toolchain blew up — log the args + source somewhere durable so it can be triaged; you can keep iterating in this session without reconnecting".
396
+
397
+ ## ROM hacking workflow
398
+
399
+ The full byte-patch loop is six MCP calls, no custom scripts:
400
+
401
+ ```js
402
+ cart({op:'identify', path }) // 1. what is it?
403
+ disasm({target:'rom', path, startAddress, untilReturn:true })
404
+ // 2. find the target
405
+ // (auto-tagged reset/nmi/irq labels,
406
+ // HW register names, file-offset
407
+ // comments — for NES, BOTH .nes and
408
+ // prg.bin offsets emitted —
409
+ // mapper-aware addresses)
410
+ assembleSnippet({ cpu, origin, code: "lda #$00\nrts" })
411
+ // 3. encode replacement bytes
412
+ memory({op:'write', region:"system_ram", offset:0xRAM, hex })
413
+ // 4. VERIFY first — write the value
414
+ // on the live emulator, watch for
415
+ // the expected behavior. Cheaper than
416
+ // a wrong patch.
417
+ romPatch({op:'write', path, offset, hex, expect: "<current bytes>" })
418
+ // 5. patch with safety check —
419
+ // refuses if existing bytes differ
420
+ romPatch({op:'diff', platform, a: original, b: patched }) // 6. verify the patch landed
421
+ loadMedia({ platform, path: patched }) → frame({op:'screenshot'}) // 7. run it
422
+ ```
423
+
424
+ **Finding which CODE wrote a byte.** Static disasm reading is the slow part —
425
+ multiple `cmp #$XX` instructions look identical. Don't guess. Two tools, in order
426
+ of precision:
427
+
428
+ - **`breakpoint({on:'write', address, maxFrames, pressDuring})` — the precise one (NES).**
429
+ Arms a core-level WRITE WATCHPOINT and returns the EXACT writing instruction's
430
+ PC, captured inside the CPU write path — correct even for NMI/IRQ-driven writes
431
+ (the common NES case, where a frame-sampled PC is just the idle loop). This is
432
+ the right tool when you need the actual writer.
433
+ ```js
434
+ breakpoint({ on:'write', address: 0x00CD, maxFrames: 300, pressDuring:[{ frame:30, button:"A" }] })
435
+ → { found:true, pc:"$AF85", value:"0x81", hits:19 }
436
+ disasm({ target:'rom', path, startAddress: 0xAF85 }) // → the real store instruction
437
+ ```
438
+ Supported on **all 14 tier-1 systems** — NES, GB/GBC, Genesis, SMS/GG, SNES,
439
+ Atari 2600/7800, C64, Lynx (65C02), PC Engine (HuC6280), MSX (Z80), and GBA
440
+ (ARM7) — every bundled CPU family. On a banked mapper a `$8000-$BFFF` pc may be
441
+ in a switchable bank; `breakpoint({on:'write'})` reports the `bank` (NES/GB/SMS-GG) so you can
442
+ pass it to `disasm({target:'rom'})`.
443
+ - **`watch({on:'mem'})` / `breakpoint({on:'write',precision:'sampled'})` — cross-platform, frame-sampled.** Step until
444
+ the byte changes; the returned `pc` is a frame-boundary sample (a lead, not a
445
+ guarantee under interrupts — cross-check the value trace). Use on non-NES, or
446
+ for the value timeline.
447
+ - **`memory({op:'snapshot'})` + `memory({op:'diff'})` — "which bytes did THIS event touch?"** When
448
+ you don't yet know the address: `memory({op:'snapshot'})` before the event, trigger it
449
+ (`input({op:'press'})`/`frame({op:'step'})`), then `memory({op:'diff'})` — you get just the changed offsets
450
+ with before/after, no eyeballing two RAM dumps. The fast way to find an area-id
451
+ / phase / flag byte a transition writes. (`state({op:'diff'})` is the coarse
452
+ whole-machine "did anything change?" version.)
453
+
454
+ ```js
455
+ breakpoint({ on:'write', precision:'sampled', region:"system_ram", offset:0x03B6, maxFrames:300,
456
+ pressDuring:[{ frame:30, button:"A" }] })
457
+ → { pc: "$E3AF" (frame-sampled), changes:[{ before:31, after:32 }] }
458
+ ```
459
+
460
+ **Execution breakpoints (all 14 platforms) — read the register at the instruction.**
461
+ When the answer isn't a flat table but a value computed in a register, stop the
462
+ CPU *at the instruction* and read it:
463
+ - **`breakpoint({on:'pc', address, maxFrames, pressDuring})`** — runs until the CPU PC
464
+ reaches `address`, then FREEZES the CPU exactly there. Then `cpu({op:'read'})` reads
465
+ the full register file at that precise moment. The canonical RE move: break at a
466
+ decoder's `move.b (a0),d0`, read `A0` → the source pointer, `memory({op:'readCart'})`/
467
+ `memory({op:'read'})` at it. Turns "infer for hours" into ~3 calls.
468
+ - **`breakpoint({on:'read', address, ...})`** — the read-side mirror of `breakpoint({on:'write'})`: the
469
+ EXACT instruction PC that READ an address (who *consumes* a value).
470
+ - **`frame({op:'stepInstruction'})`** — CPU-level single-step; pair with `cpu({op:'read'})` to watch
471
+ registers change one instruction at a time.
472
+ - These work on all 14 platforms (every bundled CPU family) — including `breakpoint({on:'write'})`
473
+ (as of 0.6.0 PC Engine gained its write watchpoint, so no platform is the exception
474
+ anymore).
475
+
476
+ ```js
477
+ breakpoint({ on:'write', address:0xFF2000 }) → { pc:"$49E", ... } // get a real instruction PC
478
+ breakpoint({ on:'pc', address:0x49E }) → { hit:true, pc:"$49E" } // CPU frozen here
479
+ cpu({ op:'read', platform:"genesis", cpu:"main" }) // → registers.A0 = the pointer
480
+ ```
481
+
482
+ All in the `assets` category except `disasm({target:'rom'})` (in `debug`); the breakpoint
483
+ trio (`breakpoint({on:'pc'})`/`breakpoint({on:'read'})`/`frame({op:'stepInstruction'})`) is in `advanced`.
484
+
485
+ ### Before you hunt — check the cheat database (`cheats({op:'lookup'})`)
486
+
487
+ For a KNOWN commercial ROM, the fastest way to find the byte is to not hunt at
488
+ all: the bundled cheat database is a free, crowd-sourced **map of labeled RAM
489
+ addresses and code sites**. Call `cheats({op:'lookup', path})` FIRST — for a matched
490
+ game it returns that game's cheats with the address decoded out of each one:
491
+
492
+ ```js
493
+ cheats({ op:'lookup', path: "Rygar (USA).nes" })
494
+ // → { matched:true, confidence:"name", game:"Rygar (USA)", crc32:"...",
495
+ // entries:[
496
+ // { desc:"Infinite Magic Attack", code:"00CD:FF",
497
+ // parts:[{ address:"$00CD", value:"0xFF", kind:"ram" }] }, // ← labeled RAM var
498
+ // { desc:"Infinite Health", code:"SXUZXTSA",
499
+ // parts:[{ address:"$8E20", value:"0xA5", compare:"0x85", kind:"code" }] }, // ← code site
500
+ // ...] }
501
+ ```
502
+
503
+ So "which byte holds magic?" is answered in one call: `$00CD`. A RAM cheat
504
+ (`kind:"ram"`) is a **labeled variable**; a ROM cheat (`kind:"code"`, has a
505
+ `compare`) is a **labeled patch site** — point `disasm({target:'rom'})` at its address
506
+ to read the routine. Filter a long list with `filter:"health"` or `kind:"ram"`.
507
+
508
+ **Device types are labeled — it's not all "Game Genie."** Each decoded part
509
+ carries a `device` so you know exactly what you're looking at:
510
+ `game-genie` (NES/Genesis/SNES/GB ROM patches), `pro-action-replay` (SNES — the
511
+ most common SNES device, RAM pokes like `7E0DBF63`), `gameshark` (GB RAM),
512
+ `action-replay` (SMS/GG), or `raw` (`ADDR:VAL`). A few formats (e.g. the SMS/GG
513
+ Game Genie variant) are labeled with their device but left address-undecoded
514
+ rather than guessing — honest over wrong.
515
+
516
+ **Trust it like you trust disasm — verify, don't assume.** A match is by
517
+ No-Intro name / filename, NOT a verified CRC, so it's a PROBABLE match: very
518
+ likely right, but a different region/revision can use different addresses. The
519
+ `note` says so explicitly. Confirm a label before patching — the cheapest
520
+ confirmation is to apply it and watch:
521
+
522
+ ```js
523
+ cheats({ op:'apply', path:"Rygar (USA).nes", desc:"Infinite Magic Attack" }) // enable it live
524
+ frame({ op:'screenshot' }) // see the effect → label confirmed
525
+ // or apply a RAW code from anywhere:
526
+ cheats({ op:'apply', code:"00CD:FF" }) // RAM poke → appliedAs:"ram"
527
+ cheats({ op:'apply', code:"SXIOPO" }) // Game Genie (core decodes it)
528
+ cheats({ op:'apply', code:"C06C:0C:26" }) // raw ROM patch → auto-re-encoded to a read-intercept (appliedAs:"rom", reencodedFrom)
529
+ cheats({ op:'clear' }) // remove all
530
+ ```
531
+
532
+ **`appliedAs` tells you how it went in** — `"ram"` (per-frame poke), `"rom"` (in-core
533
+ read-intercept), `"raw"` (core-decoded device code), or `"rom-unencodable"` (a ROM
534
+ address that couldn't be made into a working ROM patch — likely a no-op; add a COMPARE
535
+ byte). A raw `ADDR:VAL:COMPARE` on a ROM address would otherwise silently no-op as a RAM
536
+ poke, so `cheats({op:'apply'})` transparently re-encodes it to the platform's ROM-patch device (NES/
537
+ Genesis/GB Game Genie, SNES Game Genie — NOT Pro Action Replay, which is RAM). **Boot-time
538
+ cheats:** pass `loadMedia({ cheats:[…] })` to apply codes BEFORE frame 0 (iterating on a
539
+ boot-seeded value), and use `host({op:'reset', hard:true})` for a true power-cycle — plain `host({op:'reset'})`
540
+ is the RESET button and leaves work RAM (and boot-seeded state) intact.
541
+
542
+ `cheats({op:'apply'})` is also just **fun** — play any matched game with infinite lives,
543
+ invincibility, etc. It is **NON-DESTRUCTIVE**, exactly like RetroArch: the cheat
544
+ lives in volatile core state (a per-frame RAM write, or an in-core read-intercept
545
+ for ROM cheats), the ROM file on disk is NEVER touched, and `host({op:'reset'})` / `state({op:'load'})`
546
+ / `cheats({op:'clear'})` removes it. **`cheats({op:'lookup'})` DB coverage (13/14):** NES, GB/GBC,
547
+ SNES, Genesis, SMS/GG, Atari 2600/7800, **Lynx**, **GBA**, **PC Engine**, **MSX** —
548
+ every tier-1 system except **C64** (the cheat database ships no C64 entries, so
549
+ there's nothing to look up; `cheats({op:'make'})` still works on C64). The DB is its own
550
+ package (`romdev_game_codes`), lazy-loaded per platform; `cheats({op:'search', platform,
551
+ query})` fuzzy-finds a game by name. One caveat: **GBA** DB cheats are
552
+ Code Breaker / GameShark (encrypted), so they're **apply-only** — the `code`
553
+ applies live, but the address isn't descrambled into a labeled map the way the
554
+ other systems are (the response says so via `mapNote`). **`cheats({op:'apply'})` /
555
+ `cheats({op:'make'})` work on all 14.** Unmatched ROMs (homebrew, your own WIP, an
556
+ unlisted dump) return `matched:false` with a clear reason — the tool never
557
+ guesses.
558
+
559
+ ### Creating NEW cheat codes (`cheats({op:'make'})`)
560
+
561
+ The inverse of decoding: turn a byte you found into a shareable code — for ANY
562
+ ROM, **including your own homebrew/WIP** where no DB entry exists. This closes
563
+ the loop with the byte-hunting tools:
564
+
565
+ ```js
566
+ breakpoint({ on:'write', precision:'sampled', region:"system_ram", offset:0xCD }) // 1. find the byte (or use cheats({op:'lookup'}))
567
+ cheats({ op:'make', platform:"nes", address:0x00CD, value:0xFF })
568
+ // → { raw:"CD:FF", note:"RAM cheat...", ... } // 2. RAM poke → raw code
569
+ // For a ROM/Game-Genie patch, read the current byte and pass it as `compare`:
570
+ memory({ op:'read', region:"prg_rom", offset:0x8E20 }) // (current byte = 0x85)
571
+ cheats({ op:'make', platform:"nes", address:0x8E20, value:0xA5, compare:0x85 })
572
+ // → { gameGenie:"SZZAETSA", verified:true, raw:"8E20:A5:85", ... }
573
+ cheats({ op:'apply', code:"SZZAETSA" }) → frame({ op:'screenshot' }) // 3. confirm it works
574
+ ```
575
+
576
+ `cheats({op:'make'})` encodes for the platform's NATIVE device(s) and **labels each one**
577
+ — NES/Genesis → Game Genie; SNES → Pro Action Replay **and** Game Genie; GB/GBC
578
+ → Game Genie (ROM) + GameShark (RAM); SMS/GG → Action Replay — plus the raw
579
+ `ADDR:VAL` always. Each generated code carries `verified:true` (decoded back and
580
+ confirmed; the encoders round-trip 100% against the full DB — NES/Genesis/GB/GBC
581
+ Game Genie, SNES Game Genie + PAR, GB GameShark). Force a specific device with
582
+ `device:`. A RAM cheat needs just `address`+`value`; a ROM patch adds `compare`
583
+ (the byte currently there). Nothing is ever written to a ROM file.
584
+ **`cheats({op:'make'})` works on all 14 tier-1 systems** — the systems with no native
585
+ letter-code device (Atari 2600/7800, Lynx, GBA, C64, PC Engine, MSX) get a
586
+ verified raw `ADDR:VAL` code that `cheats({op:'apply'})` passes straight to the core.
587
+
588
+ ```js
589
+ cheats({ op:'make', platform:"snes", address:0x7E0DBF, value:0x63 })
590
+ // → { codes:[ {device:"pro-action-replay", code:"7E0DBF63", verified:true},
591
+ // {device:"game-genie", code:"17D8-9EE8", verified:true} ],
592
+ // raw:"7E0DBF:63", ... }
593
+ ```
594
+
595
+ ### Editing in-game TEXT (font maps)
596
+
597
+ Games store text as their own tile-index encoding (Excitebike: A=$0A; Mario:
598
+ ASCII-offset; FF: sparse). Three tools automate the round-trip instead of
599
+ hand-deriving the table:
600
+
601
+ - **`text({op:'learn'})`** — infer the char→tile-ID map. TWO modes:
602
+ - ROM mode: `knownStrings:[{text, offset}]` when you found the text's bytes.
603
+ - **LIVE mode: `fromScreen:[{text, row, col}]`** — the text is on screen RIGHT
604
+ NOW; reads the tile IDs straight from the live BG map at a tile position. This
605
+ breaks the chicken-and-egg (you'd otherwise need the ROM offset you're
606
+ hunting). Works on every tilemap platform (NES/SNES/Genesis/GB/GBC/SMS/GG/C64);
607
+ `background({view:'map'})` shows you where the text sits. (atari2600/7800, lynx,
608
+ gba have no text-tile nametable → use ROM mode.)
609
+ - **`text({op:'find', romPath, text, fontMap})`** — locate the string in the
610
+ ROM. Returns `fileOffset` (.nes), `prgFileOffset` (prg.bin), and a bank-aware
611
+ `cpuAddress` + `bank` (NES/GB/GBC in-bank address, Genesis flat; SNES is
612
+ mapper-dependent → use the offsets) — feed `{startAddress, bank}` to
613
+ `disasm({target:'rom'})`. Flags a likely length-prefix byte to avoid the classic
614
+ overrun.
615
+ - **`text({op:'encode'})`** — text + map → bytes, ready for `romPatch({op:'write'})`.
616
+
617
+ ```js
618
+ text({ op:'learn', fromScreen:[{ text:"START", row:13, col:11 }] }) // read tiles off the live screen
619
+ text({ op:'find', romPath, text:"MOUNTAIN", fontMap }) // → offsets + bank + context
620
+ text({ op:'encode', text:"NEW TEXT ", fontMap }) → romPatch({ op:'write', ... }) // rewrite it
621
+ ```
622
+
623
+ **Tools for hacking, by category:**
624
+
625
+ - `romPatch({op:'write', path, offset, hex, expect, allowExpand})` — generic byte
626
+ splicer with safety check. THE primitive — every other hack tool
627
+ composes through it. `expect` refuses the write if existing bytes don't
628
+ match, catching the silent corruption when a patch authored against
629
+ region A is applied to region B.
630
+ - `assembleSnippet({cpu, origin, code})` — assemble a tiny chunk of asm
631
+ to raw bytes. No header, no linker config, no segments. Supports
632
+ `6502 / 65c02 / 65816 / 68k / z80 / sm83 / gb / gbc / huc6280`.
633
+ Z80 NOTE: sdas dialect requires `#` on immediates (`ld a,#5`, not
634
+ `ld a,5`).
635
+ - `romPatch({op:'diff', platform, a, b})` — mapper-aware ROM diff. Reports CPU
636
+ addresses (NROM-128 mirrors correctly, SNES LoROM banks as `XX:XXXX`),
637
+ per-region tallies (PRG vs CHR vs header), and `tile: N` annotations
638
+ on CHR changes for direct sprite-hack identification.
639
+ - `romPatch({op:'findFree', path, minLength, fillBytes})` — locate runs of $FF
640
+ or $00 for asm overlays. Sorted longest-first.
641
+ - `disasm({target:'references', path, platform, address})` — find every instruction
642
+ that references a target address. Classifies refs as
643
+ `call/jump/branch/read/write/use/ref`. Walks the vector table too.
644
+ Limitation: only direct addressing modes; indirect/computed jumps
645
+ not detected.
646
+ - `romPatch({op:'spliceCHR', path, platform, pngBase64, tileIndex, expect, bank, paletteHint})` —
647
+ composition: PNG → tile bytes → splice into CHR at tile slot N.
648
+ Auto-locates iNES CHR base. `expect` checks the existing tile bytes.
649
+ `bank: N` (NES) replaces magic file offsets; `paletteHint:["#RRGGBB",...]`
650
+ gives explicit RGB→palette-index mapping (skips the default quantization
651
+ that requires PNGs with exactly 4 distinct grayscale levels).
652
+ - `cheats({op:'lookup', path, filter, kind})` — match a KNOWN ROM to the bundled
653
+ cheat DB and return THIS game's labeled RAM addresses + code sites
654
+ (decoded from each cheat). The free "which byte holds X?" map. Probable
655
+ match (name/filename, not CRC) — verify before patching.
656
+ - `cheats({op:'apply', code | desc+path, index, enabled})` /
657
+ `cheats({op:'clear'})` — apply a cheat to the loaded game LIVE and
658
+ non-destructively (the RetroArch way: volatile core state, ROM file
659
+ never touched). Use a raw `code` or a matched `desc`. Doubles as the
660
+ cheapest way to VERIFY a `cheats({op:'lookup'})` label (apply → screenshot), and
661
+ as a fun-bonus (play with infinite lives, etc.).
662
+ - `cheats({op:'make', platform, address, value, compare?, style})` — CREATE a new
663
+ cheat code from an address+value (the inverse of decoding). Returns a
664
+ Game Genie letter code + the raw ADDR:VAL, with a `verified` round-trip
665
+ check. Works on any ROM incl. homebrew/WIP. Pair with `breakpoint({on:'write',precision:'sampled'})`/
666
+ `cheats({op:'lookup'})` (find the byte) → `cheats({op:'make'})` (encode) → `cheats({op:'apply'})` (confirm).
667
+ - `watch({on:'mem', region, offset, length, frames, pressDuring})` /
668
+ `breakpoint({on:'write', precision:'sampled', region, offset, maxFrames, pressDuring})` — frame-level
669
+ memory-write trace. Reports every change with PC, so you can map a
670
+ RAM byte back to the writing code path. Cross-platform. The "find
671
+ the byte" half of hacking, mechanized. (Reach for this when a ROM
672
+ ISN'T in the cheat DB, or to find a byte no cheat covers.)
673
+ - `background({view:'rendered'})` — at the current emulator state, walk the
674
+ BG nametable + OAM and return the set of tile IDs actually being
675
+ drawn. Sample at known game states (title / gameplay / menu) and diff
676
+ the sets to map tile IDs to game assets without scanning sheets by eye.
677
+ - `cart({op:'extract', path, outputDir})` — split ROM into standard parts
678
+ (NES: header.bin/prg.bin/chr.bin; SNES: copier_header + rom + internal
679
+ header; Genesis: vectors/header/body; GB: boot/header/body) plus a
680
+ manifest.json with mapper, mirroring, etc.
681
+ - `cart({op:'wrap', platform, ...})` — counterpart to `cart({op:'extract'})`.
682
+ Emits `wrapperSource` (.s) + `linkerConfig` (cc65 ld65 cfg) ready
683
+ for `build({output:'rom'})`. Per-platform templates.
684
+ - `disasm({target:'rom'})` — see "Disassembler" section below for the full
685
+ annotation set.
686
+
687
+ For graphics swaps specifically:
688
+ - `tiles({op:'png', source:'path', platform, path, bank, paletteFromEmulator, paletteIndex})`
689
+ from a source game → PNG of its tiles. `bank: N` (NES 4 KB CHR bank
690
+ index) replaces magic file-offset math. `paletteFromEmulator: true`
691
+ + `paletteIndex` colors the export with the live game palette
692
+ (instead of grayscale) — much easier to recognize art and edit in a
693
+ pixel tool.
694
+ - `importArt({from:'rom', sourceRom, sourcePlatform, sourceBank,
695
+ sourceTileX/Y/W/H, targetPlatform, outputPng, intent, paletteIndex})`
696
+ — one-call lift of a tile region from a source game's ROM into the
697
+ target platform's tile format. Combines extract + crop + quantize +
698
+ optional manifest. Under `intent:"homebrew"` reads the live source
699
+ palette automatically (same `paletteFromEmulator` semantics as
700
+ `tiles({op:'png',source:'path'})`); under `intent:"rom-hack"` preserves source
701
+ bytes verbatim. Output PNG + manifest feed straight into
702
+ `importArt({from:'texturepacker'})`.
703
+ - `encodeArt({stage:'tiles', platform, pngBase64})` → target-platform tile bytes
704
+ - `romPatch({op:'spliceCHR'})` to write them into the CHR region of your target ROM
705
+ (handles the `encodeArt({stage:'tiles'})` + `romPatch({op:'write'})` composition in one call)
706
+
707
+ ## Disassembler
708
+
709
+ `disasm({target:'rom'})` ships with every annotation enabled by default:
710
+
711
+ ```js
712
+ disasm({target:'rom', path, platform:"nes", startAddress:0xC184,
713
+ length:64, untilReturn:true})
714
+ // →
715
+ // reset: sei ; C184 78 x @0x194 (prg @0x184)
716
+ // cld ; C185 D8 . @0x195 (prg @0x185)
717
+ // lda #$00 ; C186 A9 00 .. @0x196 (prg @0x186)
718
+ // sta $2000 ; C188 8D 00 20 .. @0x198 (prg @0x188) PPUCTRL
719
+ // ldx #$FF ; C18B A2 FF .. @0x19B (prg @0x18B)
720
+ // ...
721
+ ```
722
+
723
+ What you get:
724
+ - **Vector labels** (`reset:`, `nmi:`, `irq:`) auto-tagged from the iNES /
725
+ SNES / Genesis vector tables. For SMS/GG, fixed Z80 vectors are tagged:
726
+ `reset:` at $0000, `rst08`/`rst10`/`rst18`/`rst20`/`rst28`/`rst30:` at
727
+ their RST addresses, `irq:` at $0038 (SMS vblank handler), `nmi:` at
728
+ $0066 (pause button). For GB/GBC, the SM83 vectors get the same
729
+ treatment plus the dedicated IRQ vectors: `vblank:` at $0040,
730
+ `lcd_stat:` at $0048, `timer:` at $0050, `serial:` at $0058,
731
+ `joypad:` at $0060, and `entry:` at $0100. `autoLabelVectors:false`
732
+ to turn off.
733
+ - **Hardware register names** (`; PPUCTRL`, `; PPUMASK`, `; SND_CHN`,
734
+ `; VRAM`, `; LCDC`, `; VDP_CTRL`, `; IO_PORT_A` etc) on any operand
735
+ that hits a known platform register. NES + SNES + Genesis + GB + SMS/GG
736
+ tables built in. `annotateRegisters:false`.
737
+ - **File-offset comments** (`; @0xNNNN`) on every disassembled line —
738
+ mapper-aware, so $C184 on NROM-128 correctly reports `@0x194`. Direct
739
+ input to `romPatch({op:'write'})`'s `offset`. For NES iNES files, the header-stripped
740
+ PRG offset is ALSO reported (`@0x194 (prg @0x184)`) so you can patch
741
+ either the `.nes` file or `prg.bin` from `cart({op:'extract'})` without doing
742
+ the -16 math. `annotateFileOffsets:false` to turn off.
743
+ - **Mapper-aware addressing**: NROM-128 mirror at $C000, MMC1/MMC3/UxROM
744
+ top bank fixed at $C000, SMS sega-mapper slot-0/1/2 1:1 file mapping,
745
+ GB/GBC slot 0 fixed + slot 1 banked (pass `bank` to target a non-
746
+ default ROM bank). No more manual `startAddress: 49152` because the
747
+ disassembler understood the mapping.
748
+ - **`endAddress` alternative to `length`** — disassemble "from X to Y"
749
+ without computing byte count yourself.
750
+ - **`untilReturn: true`** — truncates at the first `rts/rti/rtl/bare jmp`
751
+ (6502) or `ret/reti/retn/bare jp` (Z80) or `ret/reti/bare jp/jp hl`
752
+ (SM83). Combine with an auto-tagged `reset:` label to grab exactly
753
+ one routine.
754
+ - **`dataRanges: [{start, length}]`** — mark address ranges as `.byte`
755
+ tables instead of bizarre disassembled "code." Useful for embedded
756
+ sprite tables, music data, lookup tables.
757
+ - **`outputPath`** — writes raw asm to disk instead of returning a
758
+ 188KB JSON wad. Returns `{outputPath, asmBytes, asmLines}` for log/inspection.
759
+
760
+ Every CPU family disassembles through a native binutils disassembler compiled to
761
+ WASM: 6502/65816 via cc65's `da65`; Z80 (SMS/GG/MSX) + SM83 (GB/GBC) via one
762
+ z80-elf `objdump` (`-m z80` / `-m gbz80`); m68k (Genesis) via `m68k-elf-objdump`;
763
+ ARM/Thumb (GBA) via `arm-none-eabi-objdump`. No hand-rolled JS decoders. The
764
+ auto-label / register-annotation / file-offset / untilReturn handling is
765
+ post-processing layered on the objdump output.
766
+
767
+ ### Whole-ROM, rebuildable projects — `disasm({target:'project'})`
768
+
769
+ `disasm({target:'rom'})` gives you one routine as text. `disasm({target:'project'})` turns an
770
+ **entire ROM into a complete, re-buildable project in one call**, across **all 14
771
+ systems** (NES, SNES, GB/GBC, SMS/GG, Genesis, **GBA**, C64, Atari 2600/7800,
772
+ **Lynx** — 65C02, **PC Engine** — HuC6280, and **MSX** — Z80; always byte-exact).
773
+ Each region disassembles through the CPU's native objdump and reassembles through
774
+ the matching native `as`/`ld`/`objcopy`, so the round-trip is guaranteed byte-for-byte:
775
+
776
+ ```js
777
+ disasm({ target:'project', path: "game.nes", outputDir: "./game-disasm" })
778
+ // → { ok, platform, regions:[{file, startAddress, roundTripOk, readablePercent}],
779
+ // roundTrip:{ allByteExact, failed:[] }, readablePercentAvg }
780
+ ```
781
+
782
+ It splits the ROM into regions (per-16KB bank for banked NES, per-32KB bank for
783
+ SNES LoROM, slot0+slotX for GB, one flat region for SMS/Genesis/C64/Atari),
784
+ disassembles each, then **reassembles it and verifies the result is byte-exact
785
+ against the original**. Any line that doesn't reassemble faithfully falls back
786
+ to `.byte`/`db` data recovered from the address comments — so the emitted `.asm`
787
+ files ALWAYS rebuild to the original bytes (`roundTrip.allByteExact`). The
788
+ `readablePercent` per region tells you how much came back as real instructions
789
+ vs. data. Each `.asm` carries a provenance + round-trip header and is ready to
790
+ edit and rebuild with the platform's native toolchain.
791
+
792
+ Reassembler per CPU family (all bundled WASM, no installs): **cc65** ca65/ld65
793
+ for 6502 + 65816; native binutils **`as`/`ld`/`objcopy`** for the GNU CPUs —
794
+ `m68k-elf` (Genesis), `arm-none-eabi` (GBA), and one `z80-elf` for both Z80
795
+ (SMS/GG/MSX) and gbz80 (GB/GBC). objdump and `as` share GNU syntax, so objdump's
796
+ output feeds straight back into `as` with no translation; any line the assembler
797
+ won't reproduce exactly is healed to a `.byte` of its real bytes.
798
+
799
+ Caveats worth knowing up front:
800
+ - **SNES and large Genesis ROMs come back byte-exact but DATA-ONLY**
801
+ (low `readablePercent`). Flat whole-ROM disassembly of a mostly-data image
802
+ heals down to `.byte`; meaningful instruction coverage there needs recursive
803
+ entry-point following, a known follow-up. The bytes are always correct.
804
+ - **GBA** rebuilds byte-exact but reads LOW: GBA C compiles mostly to Thumb,
805
+ reached via an ARM crt0 stub, so an ARM-mode disasm decodes the Thumb spans as
806
+ `.byte`. ARM/Thumb mode-tracking is the readability follow-up; the bytes are
807
+ always correct. (The 192-byte GBA header is emitted as a clean data region.)
808
+ - Banked-NES is the strongest case — per-bank regions come back ~100%
809
+ instructions. GB/GBC, SMS/GG, C64, and Atari are also near-100%.
810
+ - Platform is sniffed from the file extension; pass `platform:` to override.
811
+
812
+ ## CHR/tile tools — file vs emulator source
813
+
814
+ `tiles({op:'pixels'})`, `tiles({op:'png'})`, `tiles({op:'png',source:'path'})`, `tiles({op:'fingerprints'})`,
815
+ and `tiles({op:'ascii'})` all accept an optional `path` arg:
816
+ - **With `path` set**: reads CHR straight from a file (iNES auto-locates
817
+ CHR; raw `.chr`/`.bin` files read as-is). Use to survey assets BEFORE
818
+ loading. Response reports `source: "file"`.
819
+ - **Without `path`**: reads from the running emulator's pattern table /
820
+ VRAM. Response reports `source: "emulator"`.
821
+
822
+ ## Demake / enhance / cross-platform workflow
823
+
824
+ The full "take game X on platform A, make it on platform B" pipeline:
825
+
826
+ 1. Study source: `loadMedia({ platform: A, path })`, `recordSession`, `disasm({target:'rom'})`
827
+ 2. Rip art: `tiles({op:'png', source:'path', platform: A, path})` returns a PNG sheet
828
+ 3. Recook art: `encodeArt({stage:'tiles', platform: B, pngBase64})` re-encodes in B's tile format and bit depth
829
+ 4. Write target game: `build({output:'run', platform: B, source})` for fast iteration
830
+ 5. Embed converted art: `romPatch({op:'writeMany'})` to inject the new CHR/tile bytes
831
+
832
+ The tile codec handles 4 bit-layouts × 4 bit-depths. NES↔GB is byte-exact at 2bpp. Going up in bit depth (NES→SNES) gains palette headroom. Going down (Genesis→GB) requires color quantization that the codec does automatically.
833
+
834
+ ### Lifting a CHARACTER (not a rectangular tile region) — use meta-sprite capture
835
+
836
+ `tiles({op:'png',source:'path'})` / `encodeArt({stage:'crop'})` / `importArt({from:'rom'})` work on **rectangular tile-grid regions**. That is the WRONG model for a real character, which is built from **multiple independent hardware sprites** (OAM/SAT entries), each with its own position, size, tile index, palette, flips, priority, and a non-contiguous tile range. Cropping a screenshot or a tile sheet looks right and then renders as garbage in-game because the hardware multi-cell tile order differs per platform (Genesis is column-major; SNES large OBJ + NES/GB 8×16 are their own orders). The meta-sprite tools handle all of it. Works on **genesis, snes, nes, gb, gbc, sms, gg** (C64 MOBs are 24×21 bitmaps, not tiles — not supported):
837
+
838
+ 1. `loadMedia` → step / press to a frame where the character is fully on screen (NOT a menu — if no sprites are up, captures come back empty).
839
+ 2. `sprites({op:'group', platform})` → clusters on-screen OAM/SAT entries into objects, largest-first (usually the player). Pick a group's `slots`.
840
+ 3. `sprites({op:'capture', platform, slots:[...] /* or rect:{x,y,w,h} */, name:"enemy", emit:"both", outputDir:"..."})` → writes `tiles.bin`, `palette.bin`/`.json`, `layout.json`, `preview.png` (re-rendered from the EXPORTED data, not a screenshot crop), and a platform-idiomatic `<name>.h`. Hardware tile order is preserved per platform.
841
+ 4. Inspect `preview.png`. Re-verify any time with `sprites({op:'render', tilesPath, layoutPath})` — no rebuild needed.
842
+ 5. Include `<name>.h` (Genesis → SGDK `_draw()` helper; NES/GB → shadow-OAM cell table; SNES → oamSet pieces; SMS → SAT cells) — or get it later via `sprites({op:'emitC'})`. Build with `build({output:'run'})`.
843
+
844
+ This keeps the lifted asset faithful to the source ROM's hardware composition instead of the lossy crop-the-screenshot fallback.
845
+
846
+ ## Visual vs programmatic inspection
847
+
848
+ You have two modes. Pick per task:
849
+
850
+ **Image mode** — `frame({op:'screenshot'})`, `tiles({op:'png'})`, `background({view:'map', render: true})`, `palette({source:'live'})`. Returns PNGs. Best for aesthetic judgment ("does this look right?", "did the explosion play?").
851
+
852
+ **Text mode** — `tiles({op:'pixels'})`, `tiles({op:'ascii'})`, `tiles({op:'fingerprints'})`, `memory({op:'read'})`. Returns structured data or ASCII art. Best for precise comparison ("is this tile blank?", "did $00F4 change between frame 60 and 90?", "find all tiles whose hash matches X").
853
+
854
+ Both work fine. Image mode is more flexible but burns more tokens per call. Use text mode for scans and diffs, image mode for "does this look like Mario?" questions.
855
+
856
+ ## NES-specific (most common platform)
857
+
858
+ Patched fceumm exposes extra memory regions beyond the libretro standard:
859
+
860
+ | Region | Contents |
861
+ | ----------------- | ---------------------------------------------- |
862
+ | `system_ram` | 2KB CPU RAM ($0000-$07FF) |
863
+ | `nes_chr` | 8KB CHR (gathered from VPage[0..7]; R59 fixed an off-by-page-offset bug that returned zeros for offsets >= 4096 — if you see CHR uploads "fail" only above 4 KB, you're on a pre-R59 build) |
864
+ | `nes_nametables` | 2KB CIRAM (background tile maps) |
865
+ | `nes_palette` | 32 bytes ($3F00-$3F1F) |
866
+ | `nes_oam` | 256 bytes sprite list (64 sprites × 4 bytes) |
867
+
868
+ OAM format: bytes per sprite are `[y, tileIndex, attributes, x]`.
869
+
870
+ `background({view:'map', render: true})` composites the active CHR + nametable + palette into a real 256×240 PNG — what the BG layer would look like even if rendering is currently disabled.
871
+
872
+ ## Save-state semantics
873
+
874
+ `state({op:'save'}, name)` / `state({op:'load'}, name)` slots are **in-memory** and discarded on `host({op:'shutdown'})` or new media. To persist a state across sessions:
875
+ - `state({op:'save', path})` writes the CURRENT live host to a file directly.
876
+ - `state({op:'export', fromSlot, path})` copies an EXISTING in-memory slot (e.g. one the human saved with a playtest emulator-hotkey — it appears in `state({op:'list'})`) to a file **without disturbing the live host** (no pause/resume needed). Reload either with `state({op:'load', path})`.
877
+
878
+ `state({op:'load'})` removes any active cheats (a save-state blob doesn't carry frontend cheat state) and reports `cheatsCleared`. `host({op:'reset'})` resets the frame counter + core state (and clears cheats) but keeps the loaded ROM.
879
+
880
+ ## Project scaffolding
881
+
882
+ Three shapes, pick the one that matches what you're doing:
883
+
884
+ - **`scaffold({op:'project', platform, name, path, template?})`** — writes a starter directory: `main.{c,asm,s}` (from `examples/<platform>/templates/`) + every runtime file the template depends on (headers, crt0, linker .cfg) + README + `.gitignore`. Self-contained: take it elsewhere and rebuild with stock cc65/sdcc, no romdev install needed. Defaults to `template:"default"` (smallest visible-and-runnable program); most tier-1 platforms also have `hello_sprite` + `tile_engine` + the 5 genre templates.
885
+
886
+ - **`scaffold({op:'project', ..., withSnippets: true})`** — same as above, **plus** drops every vetted starter snippet for the platform alongside main.c. Use when you want "main.c + every helper file ready to edit" in one shot, without picking a genre. Snippets that overlap with the template's runtime are skipped (no double-writes). Response includes `snippetsCopied: string[]`.
887
+
888
+ - **`scaffold({op:'game', platform, genre})`** — genre-shaped scaffold (`shmup` / `platformer` / `puzzle` / `sports` / `racing`). Higher-level than `scaffold({op:'project'})` — picks the right template + runtime + crt0 + linker config for the genre. Available on **NES, GB, GBC, SNES, Genesis, SMS, GG, C64, GBA, Lynx, Atari 7800** — i.e. every platform that has genre templates. Availability is derived from the registered templates (not a hardcoded list), so the error message for an unsupported platform always names the current set; Atari 2600 (asm-only) + MSX + ColecoVision (bring-up only) have no genre scaffolds and are rejected. Ships a complete working ROM with state machine + sprite allocation + sound wired — fill in gameplay logic on top. **Want a side-scroller? Use `genre:"platformer"`** — and on every platform EXCEPT NES the scaffold already side-scrolls: a hardware camera follows the player (SCX/$D016/R8/BG?HOFS/REG_BG?HOFS/bgSetScroll depending on platform), with software tile-column streaming where the world is wider than one nametable/plane. NES is still single-screen (platforms drawn as sprites); to make it scroll, draw platforms into the background nametables + `ppu_scroll(camX,0)` (it flips the PPUCTRL nametable-select bit past 256 px) + stream columns past 512 px. Each platformer's `describe` text gives the per-platform specifics; the scroll-register details live in the platform's MENTAL_MODEL.md "Horizontal scrolling" section.
889
+
890
+ Then iterate with `build({output:'run'})` against the source you read from `path/main.*`.
891
+
892
+ ## Symbol-aware debugging — assert state headlessly instead of screenshotting ⭐
893
+
894
+ **The single biggest win for headless verification:** every "did the score go up / HP
895
+ drop / level change?" check is one byte of RAM. Build with debug, resolve the C global,
896
+ read it — no screenshot, no visual interpretation. Works on **every platform with a C
897
+ toolchain** (all 12 buildable ones):
898
+
899
+ ```js
900
+ const b = build({ output: "romWithDebug", platform, source, inline: true })
901
+ const sym = symbols({ op: "resolve", /* dbg or map: */ name: "score" })
902
+ memory({ op: "read", region, offset }) // the live value — 0 image tokens
903
+ ```
904
+
905
+ `build({output:'romWithDebug'})` returns the right debug artifact for your platform; pass
906
+ whichever it gives you to `symbols`:
907
+
908
+ | Platform | debug artifact | pass to `symbols` |
909
+ |----------|---------------|-------------------|
910
+ | NES, C64, Atari7800, Lynx, PCE (cc65) | `.dbg` | `{ dbg }` |
911
+ | GB, GBC, SMS, GG, MSX (SDCC) | sdld `.map` (`mapText`) | `{ map }` |
912
+ | Genesis (m68k-elf) | GNU ld `.map` (`mapText`) | `{ map }` |
913
+ | GBA (arm-none-eabi) | GNU ld `.map` (`mapText`) | `{ map }` |
914
+
915
+ All five ops — `resolve` (name→addr), `lookup` (addr→sym), `list`, `map` (layout by
916
+ region), `addr` (live PC→enclosing C function) — work for **all** of these now (`map`
917
+ auto-detects sdld vs GNU ld). cc65 prepends `_` to C identifiers (`score`→`_score`);
918
+ `resolve` tries both spellings, and SDCC/GNU names come back without the underscore.
919
+
920
+ **Genesis (and GBA) specifics:**
921
+ - Genesis C globals live in the `$E0FF0000` work-RAM mirror. `resolve` hands you a
922
+ `ramOffset` (the low 16 bits) **and** a ready `readHint` — read with
923
+ `memory({op:'read', region:'system_ram', offset: ramOffset})`. (gpgx word-swaps WRAM,
924
+ so a 16-bit value's two bytes are swapped at the offset — read bytes, or account for it.)
925
+ - `static` file-local globals resolve too (per-symbol sections). A non-`static` global
926
+ that's never read can be DCE'd at -O2 — mark state vars you inspect `volatile`.
927
+ - PC→function: `symbols({op:'addr', pc, symbolsText: b.mapText})` names the routine a live
928
+ `cpu({op:'read'}).pc` sits in.
929
+
930
+ When you don't know the symbol yet, `memory({op:'snapshot'})` → trigger the event →
931
+ `memory({op:'diff'})` shows exactly which bytes changed.
932
+
933
+ ## Playtest mode (optional)
934
+
935
+ `playtest({ scale: 3 })` opens a real SDL window for a human to play the loaded ROM with a keyboard or USB controller. It **returns immediately** — the render loop runs in the background and you keep using every other tool against the same live host (so `build({output:'run'})`/`loadMedia` rebuilds update the window in place; it does not relaunch or crash on rebuild). Close it with `playtest({op:'stop'})` (or the human pressing ESC / Select+Start). Needs a desktop display *and* the optional `@kmamal/sdl` dep; with neither it returns `{opened:false, reason:...}` and the rest of the server keeps working headless. Use this when the human wants to feel the game, not when you want to test it (for your own checks, use `frame({op:'screenshot'})` — it reads the same live host the window shows). `playtest({op:'status'})` reports liveness + the window's media/frame; `playtest({op:'framebuffer'})` captures exactly what the human sees.
936
+
937
+ **Windows are PER SESSION.** The server is multi-session (several agents, or a user with 2-3 games open at once); each session gets its OWN window — opening one never disturbs another agent's, `playtest({op:'stop'})` closes only yours, and a session disconnecting tears down just its own window. **Aspect:** the window defaults to `aspect:"tv"` (the 4:3 / native-LCD shape the game was authored for) with nearest-neighbor scaling, so it looks like real hardware and stays crisp + correct aspect when the human resizes it; pass `aspect:"fb"` for raw square-pixel dev geometry.
938
+
939
+ ## Common gotchas
940
+
941
+ - **CHR-RAM vs CHR-ROM**: Most NES homebrew uses CHR-RAM. CHR tools (`tiles({op:'pixels'})`, `tiles({op:'png'})`, `tiles({op:'fingerprints'})`, `tiles({op:'ascii'})`, `tiles({op:'png',source:'path'})`) all accept an optional `path` arg — pass it to read CHR from the iNES file (CHR-ROM carts), omit to read live CHR-RAM from the running emulator. Response always reports `source: "file" | "emulator"`. NES homebrew built with `linkerConfig:"chr-ram"` has no CHR in the file — must read from the emulator after upload.
942
+ - **Mapper-aware addressing**: NES NROM 16KB carts mirror PRG at $8000 and $C000 (`disasm({target:'rom'})` reports the canonical $C000+ addresses since that's where the reset vector points). Banked mappers (MMC1/MMC3/UxROM) have the top 16KB fixed at $C000 with bank 0 at $8000 by default — pass a startAddress in the right range to disassemble a different bank.
943
+ - **C64 isn't a console**: media is `.prg` / `.d64` / `.t64`, not "ROM". `loadMedia` takes a `mediaKind` arg; auto-defaults are usually right.
944
+ - **Atari 5200 build works but doesn't run**: cc65 produces .a52 files, but our atari800 core needs Asyncify which isn't yet wired into the host. Use Atari 7800 or Lynx if you want a 6502 platform that actually runs.
945
+ - **Genesis BG init**: a freshly-booted Genesis ROM shows a black screen for many frames because VDP init is slow. Step 60+ frames before screenshotting.
946
+ - **`framesRun` is monotonic**: `state({op:'load'})` restores the core but doesn't roll back our frame counter. Use it for state, not for "what frame am I on" precision.
947
+
948
+ ## Before writing input or memory-layout code
949
+
950
+ Two tools that save real time and frustration:
951
+
952
+ - `input({op:'layout', platform})` — returns the platform's controller protocol, bit order, libretro id mapping, AND which buttons physically exist. Read this before writing an asm `read_pad` routine OR before designing controls (so you don't bind to a button the platform doesn't have).
953
+ - `symbols({op:'map', dbg, platform})` — after `build({output:'romWithDebug'})`, returns where every variable in your source actually landed in memory, grouped by region (zeropage / system RAM / code / data). cc65 reserves the first 2 zeropage bytes for its runtime; your first `.res 1` lands at `$02`, not `$00`. Don't guess.
954
+
955
+ ## Cross-platform inputs
956
+
957
+ `input({op:'set'})` accepts an Xbox-shaped controller: D-pad, 4 face buttons (use `north/east/south/west` for portable code — they translate per platform), shoulders (`l/r`), triggers (`l2/r2`), sticks (`l3/r3`), plus `start`/`select`. Older platforms are subsets — `input({op:'layout'})` tells you which buttons are real. Pressing a non-existent button is a silent no-op.
958
+
959
+ ⚠ **The raw libretro names `a`/`b`/`x`/`y` are NOT the platform's printed button labels — and on the three genesis_plus_gx platforms (Genesis, SMS, Game Gear) they're INVERTED.** Verified live across all 14 platforms:
960
+ - **Genesis**: gpgx maps Genesis A/B/C onto libretro **y/b/a** — so `input({op:'set', a:true})` presses Genesis **C**, and Genesis A (SGDK `BUTTON_A`) is `{y:true}` / `{west:true}`.
961
+ - **SMS / Game Gear**: button 1 (TL, main fire) is libretro **b**, button 2 (TR) is libretro **a** — so `{a:true}` presses button 2, not 1.
962
+ - **Every other core maps straight through** (`{a}`→A, `{b}`→B): NES, GB/GBC, SNES (incl. x/y/l/r), GBA, PC Engine (a=I, b=II), MSX (a=trig 1), Lynx (a=A). C64 + Atari 2600 are single-fire — fire is `{b}`/`{south}`, `{a}` is a no-op. Atari 7800 boots in 1-button mode (both fires read INPT4) until you enable 2-button mode.
963
+
964
+ **The safe habit: use the spatial names (`north/east/south/west`) or `input({op:'press', button:'a'|'b'|'c'|'1'|'2'})` — both resolve to the correct physical button per platform.** Reach for raw `a`/`b` only when you mean the literal libretro id. `input({op:'layout', platform}).faceButtons` is the authoritative per-platform map; each platform's MENTAL_MODEL has a "Driving input over MCP" note.
965
+
966
+ ## Starter snippets
967
+
968
+ `scaffold({op:'snippets', platform})` (default `mode:'list'`) and `scaffold({op:'snippets', platform, mode:'get', name})` give you vetted boilerplate — reset routine, `read_pad`, OAM DMA, palette upload, nametable clear. Each snippet's comments encode foot-guns prior agent sessions already hit. Always check what's available for your platform before writing platform-specific boilerplate from scratch. NES, SNES, SMS, GG, GB/GBC, Genesis, GBA, C64, Atari 7800 all have substantial snippet libraries.
969
+
970
+ **Three ways to actually use them:**
971
+
972
+ - `scaffold({op:'snippets', platform, mode:'get', name})` — one snippet's contents, returned as a string.
973
+ - `scaffold({op:'snippets', platform, mode:'getAll', language?})` — every snippet joined into one string. Useful for **reading**; the giant blob lands in your context (or pass `outputPath` to write it to disk instead).
974
+ - **`scaffold({op:'copySnippets', platform, destinationDir, language?, include?})`** — writes every snippet (or a filtered subset) straight to disk. **Bytes never pass through your context.** Use this when you're scaffolding into a project dir. Flattens `lib/<lang>/foo.c` → `<destinationDir>/foo.c`. Optional `include: ["vdp_init", "joypad_read"]` whitelist for cherry-picking. Default `overwrite: true` (vetted boilerplate is meant to be regenerated).
975
+
976
+ Or skip the separate call entirely: `scaffold({op:'project', withSnippets: true})` does the same thing as a one-shot.
977
+
978
+ ## Don't burn your own context with binary data
979
+
980
+ The biggest mistake agents make on this server is reading binary files into their own context just to forward them to a tool. Don't. Every tool that consumes large binary inputs accepts paths:
981
+
982
+ - `loadMedia({ platform, path })` instead of inlining `base64`
983
+ - `build({ output:'rom', sourcePath, binaryIncludePaths, includePaths, outputPath })` — paths in AND a path back out (`binaryPath`). Inline base64 only on opt-in `inline: true`. (Or `build({output:'project', path})` to build a whole dir without a manifest.)
984
+ - `encodeArt({ stage:'tilemap', platform, pngPath, outputDir })` — full-screen PNG → deduped tiles + tilemap + palette, input from disk, output to disk. **This is the tool for splash/title screens** (see the splash-screen section below). Supported: nes, snes, genesis, sms, gg, gb, gbc, c64.
985
+ - `frame({ op:'screenshot', path })` — writes PNG to disk, skips inline payload. For a quick "did it change?" sanity check, add `scale: 0.5` (nearest-neighbor, pixel-art-safe) — ~75% fewer image tokens; reserve full resolution for when you actually need pixel detail. **Cheaper still: `symbols({op:'resolve'})` → `memory({op:'read'})` reads the one byte of state with zero image tokens (see Symbol-aware debugging).**
986
+ - `tiles({ op:'png', source:'path', outputPath })` — render a ROM file's tiles to a PNG sheet
987
+ - `encodeArt({ stage:'tiles', platform, pngPath, outputDir })` — PNG → native tile bytes, input from disk. Pass `tileOrder:'sprite'` for COLUMN-major (Genesis/Lynx multi-cell hardware-sprite order) instead of the default row-major.
988
+ - `encodeAudio({ target:'brr', pcmPath, outputPath })` — SNES BRR (the SPC700's only sample format)
989
+ - `encodeAudio({ target:'xgm2pcm', wavPath, name, outputCPath })` — GENESIS sample SFX: WAV → XGM2 PCM (8-bit signed mono, 13.3 kHz / 6.65 half-rate, 256-padded) + a 256-aligned C array you `#include` and play with `XGM2_playPCM`. Bakes in the format rules so you don't botch sign/rate/alignment/padding.
990
+ - `encodeAudio({ target:'xgm2', vgmPath, name, outputCPath })` — **GENESIS MUSIC: a `.vgm`/`.vgz` → a COMPILED XGM2 blob** + a 256-aligned C array you `#include` and `XGM2_play()`. `XGM2_play()` needs a *compiled* blob (split FM/PSG streams + sample table), NOT raw VGM — this does that compile (a pure-JS port of SGDK's `xgm2tool`; no Java/jar). PSG-only tracks coexist with `xgm2pcm` SFX. `system:'ntsc'|'pal'` forces the timing flag.
991
+
992
+ When a tool has `path` and `base64` variants, prefer `path`. The server runs on the same machine; both sides share the filesystem. There's no reason to round-trip 50KB of base64 through your prompt.
993
+
994
+ ## Art-first workflow (user does the pixel art, agent wires the ROM)
995
+
996
+ For users who'd rather paint sprites in LibreSprite than write tile bytes by hand, four asset-loader tools parse FOSS editor outputs directly into platform-native tile data — no `encodeArt({stage:'tiles'})` + ImageMagick chain, no installs beyond the editor itself.
997
+
998
+ - **`importArt({from:'aseprite', path, platform, outputDir})`** — parse `.ase` (LibreSprite, GPLv2 fork of Aseprite). Returns deduped `tile_bytes` + named `tiles[sliceName] = { tile_indices, width_tiles, height_tiles }` + `tags[name] = { from, to, delays_ms[] }` for animations. Indexed-mode .ase preserves the artist's palette; RGBA mode falls back to platform-master nearest-neighbour. The artist names their slices ("player_idle", "chalice") → game code references the same names. **The killer DX feature** for art-led projects.
999
+
1000
+ - **`importArt({from:'tiled', path, platform, outputDir})`** — parse Tiled `.tmj` (BSD, the de facto FOSS level editor; export as JSON, not XML `.tmx`). Returns per-layer `data` blob + `empty_mask` bitfield (so "no tile" stays distinguishable from "tile 0") + `object_layers[name]` with named placements (player_start, doors, chests) and arbitrary key/value properties. **Multi-layer + object support** means the artist owns level design end-to-end, including spawn data.
1001
+
1002
+ - **`importArt({from:'gif', path, platform, outputDir, frame_indices?})`** — extract frames + delays from any GIF. Every editor exports GIF; this is the universal animation pipeline. omggif under the hood — no native deps. Caveat: doesn't apply GIF disposal, so export with `Disposal: Replace` for full-frame anims.
1003
+
1004
+ - **`importArt({from:'texturepacker', pngPath, manifestPath, platform, outputDir})`** — TexturePacker-style PNG+JSON. LibreSprite's `Export Sprite Sheet → JSON-Hash` writes this directly. Supports `meta.frameTags` for animation grouping.
1005
+
1006
+ **Palette interop:**
1007
+
1008
+ - `palette({source:'platformMaster', platform, format: "png" | "lospec" | "hex", outputPath?})` — `"png"` is the swatch sheet for `-remap` dithering (existing behavior). `"lospec"` returns `{name, author, colors:[hex_no_hash]}` for direct LibreSprite/lospec.com import. `"hex"` returns one `#RRGGBB` per line — universal interchange.
1009
+
1010
+ - `encodeArt({stage:'tiles'})` now validates the input PNG against the platform's master palette (PLTE for indexed PNGs, distinct-RGB scan for truecolor) with ±8/channel tolerance and surfaces colors-outside-gamut as `warnings[]`. Doesn't throw — silent color shift was the most common newbie failure; now it's loud.
1011
+
1012
+ **Workflow walkthrough** + canonical glue code: [`examples/art-first-workflow/README.md`](examples/art-first-workflow/README.md). Six-step path from picking a Lospec palette through `importArt({from:'aseprite'})` + `importArt({from:'tiled'})` to a working ROM.
1013
+
1014
+ For repeated builds in an iteration loop, this compounds: a 256KB SNES ROM in 20 build cycles = 7 MB of base64 text accumulated in your context. Paths cost ~60 bytes per call.
1015
+
1016
+ ## Splash / title / full-screen background images — USE `encodeArt({stage:'tilemap'})`, do NOT hand-roll
1017
+
1018
+ If you want a full-screen picture (a splash screen, title card, cutscene still, status panel), there is exactly ONE correct path. **Do not write your own PNG→tile loop** — packing 4bpp/2bpp bitplanes, deduping tiles, assigning palette lines, and building the name-table entry words by hand is fiddly and the failure mode is ugly: the image comes out with the right *shapes* but wrong colors (everything one color) and vertical striping/choppiness. That means your tile bytes were raw RGB-ish values instead of palette indices, or the bit packing/row stride was off.
1019
+
1020
+ The correct workflow (all platforms with a tilemap — nes, snes, **genesis**, sms, gg, gb, gbc, c64):
1021
+
1022
+ 1. **Size the source** to the platform's screen: Genesis **320×224**, NES/SNES/SMS 256×224/256×192, GB 160×144, C64 320×200.
1023
+ 2. **Quantize to the platform palette** so colors land on hardware-displayable values:
1024
+ ```
1025
+ palette({ source:'platformMaster', platform:"genesis", format:"png", outputPath:"/tmp/pal.png" })
1026
+ magick splash.png -dither FloydSteinberg -remap /tmp/pal.png splash_q.png
1027
+ ```
1028
+ 3. **Convert in one call:**
1029
+ ```
1030
+ encodeArt({ stage:'tilemap', platform:"genesis", pngPath:"splash_q.png", outputDir:"out/" })
1031
+ ```
1032
+ You get `out/chr.bin` (deduped tiles), `out/nametable.bin` (tilemap entries), `out/palette.bin`, and `out/preview.png`. **Look at `preview.png`** — it's the tool re-rendering its own output, so if the preview is correct your in-game result will be too. If the preview is wrong, the input PNG is the problem, not the encode.
1033
+ 4. **Wire it in:** DMA `chr.bin` to VRAM, load `palette.bin` into CRAM/CGRAM, write `nametable.bin` to your BG plane base. The response `note` tells you the exact sizes + where each blob goes per platform.
1034
+
1035
+ Genesis specifics: 4bpp tiles (32 B each), **40×28 cells**, up to **4 palette lines of 16 colors** — `encodeArt({stage:'tilemap'})` bin-packs your image's colors across the lines and picks the right line per 8×8 cell automatically. Name-table entries are 16-bit big-endian. Set your Plane A width to 64 cells. The response's `genesis.warnings[]` flags any 8×8 cell that needs >16 colors (the VDP's hard limit) — if you see those, the source art has too many colors crammed into one cell; re-author or accept the approximation.
1036
+
1037
+ If a platform genuinely lacks a tilemap (Atari 2600 races the beam; 7800 uses display lists) `encodeArt({stage:'tilemap'})` throws with an explanation — those need hand-authored per-scanline data, there is no automated path.
1038
+
1039
+ ## Known toolchain landmines
1040
+
1041
+ A few platform-tool quirks worth knowing up front:
1042
+
1043
+ - **asar (SNES) silent fails** on certain idioms: `$ - label` size expressions crash with a heap-pointer exit code (use `end_label - start_label` instead). Some opcode + operand arithmetic like `STA SYMBOL + N` where SYMBOL is `=`-defined also crashes silently — our preflight catches the common cases. When `ok: false, issues: []`, the wrapper now synthesizes a fallback issue with a hint.
1044
+ - **asar bank-border-crossed** can happen if your `org` + `dw` runs past $00FFFF. Native vectors are at $FFE4-$FFEE; emulation vectors at $FFF4-$FFFF. Use `scaffold({op:'snippets', platform: "snes", mode: "get", name: "lorom_header.asm"})` for the layout.
1045
+ - **cc65 (NES, C64, etc.) zero page** starts at $02. cc65 reserves $00-$01 for its runtime. Your first `.res 1` lands at $02, not $00. Use `symbols({op:'map'})` after `build({output:'romWithDebug'})` to confirm.
1046
+ - **NES pattern table cap = 256 tiles per nametable**. The tilemap index is 8-bit, so per-frame BG can use at most 256 unique tiles per pattern table. Auto-converting a busy illustration usually overflows. `encodeArt({stage:'tilemap'})` warns; the only workaround is mid-frame CHR bank switching (MMC3-class mapper).
1047
+ - **NES + GB/GBC turnkey** (R9/R10 self-contained + sound, 2026-05-25): use `scaffold({op:'project', platform, template, name, path})` to scaffold a project. The pipeline copies every file the template depends on — `{nes,gb}_runtime.{h,c}`, `gb_hardware.h`, custom `crt0.s`, linker `.cfg`, `patch-header.js` (GB) — into the project directory alongside `main.c`. **No auto-injection at build time.** The build pipeline compiles exactly what you tell it via `sources` / `sourcesPaths` / `includes` / `includePaths` / `crt0` / `crt0Path` / `linkerConfig` / `codeLoc`. Take the project elsewhere with stock cc65/sdcc and it builds the same way. The runtime APIs include sprites, BG, input, AND **sound** — `sound_init` / `sound_play_tone(channel, period, vol, length)` / `sound_play_noise` / `sound_off`. NES drives pulse1+pulse2+triangle+noise via $4000-$400F + $4015; GB drives the 4-channel APU via NR10-NR52. SFX-grade, fire-and-forget — for full music tracks, drop in famitone2 (NES) or your own driver. Templates: `default` (palette cycle), `hello_sprite` (sprite + d-pad + **beep on A press**), `tile_engine` (multi-room tile map). Docs: [`src/platforms/nes/MENTAL_MODEL.md`](src/platforms/nes/MENTAL_MODEL.md) + [`TROUBLESHOOTING.md`](src/platforms/nes/TROUBLESHOOTING.md); [`src/platforms/gb/MENTAL_MODEL.md`](src/platforms/gb/MENTAL_MODEL.md) + [`TROUBLESHOOTING.md`](src/platforms/gb/TROUBLESHOOTING.md). **Game-loop order matters on NES:** stage `oam_clear`+`oam_spr` BEFORE `ppu_wait_nmi`, not after — the NMI handler DMA's whatever shadow_oam contains at vblank-start. **GB ROM header:** both asm and C builds now auto-run `rgbfix` inside `build({output:'rom'})`, so the Nintendo logo + checksums + CGB flag are correct out of the box — no manual `patchGbHeader` step needed.
1048
+ - **Game Boy / GBC silent-failure footguns** (R54 cleanup, full detail in `platform({op:'doc', platform:"gb"|"gbc", name:"mental_model"})`):
1049
+ - **The bundled `gb_crt0.s` is now actually linked.** Pre-r54 a fundamental bug in `buildZ80C` was shipping the raw .s text to sdld as if pre-assembled — sdld silently rejected it and fell back to SDCC's stock sm83 crt0 (no GB cart boot, no IRQ vectors). Map showed no `init` symbol, $0000 was $FF, $0100 was $FF. Every GB ROM ran on stock crt0 invisibly. Fixed by auto-detecting .s source vs .rel object and running it through sdasgb first. Post-fix: `init` at $0150, entry $0100 = `00 c3 50 01` (nop; jp $0150), reset vector $0000 = $C9. **This was the root cause for #14 audio AND part of why every previous "runtime should work OOTB" round still felt friction-heavy.**
1050
+ - **GB/GBC C builds now auto-fix the header at build time** (rgbfix runs inside `build({output:'rom'})`): Nintendo logo at $0104, header checksum at $014D, global checksum, and the CGB flag at $0143 ($00 for `.gb`, $C0 for `.gbc`). You no longer need to call `patchGbHeader` manually — the ROM `build({output:'rom'})` hands back boots on real hardware as-is. `patchGbHeader({path})` still exists if you want to override title / cart type / RAM size / etc. on an existing file.
1051
+ - **`shadow_oam` is pinned at $C100** in the bundled `gb_runtime.c` via `__at(0xC100)`. OAM DMA reads ONLY the high byte and copies 160 bytes from `$XX00` — a plain `uint8_t my_oam[160]` may land at $C017 and DMA garbage. If you roll your own OAM buffer, pick an address with `0x00` low byte (e.g. $C200) and pass it directly to `oam_dma_copy`.
1052
+ - **Call `enable_vblank_irq()` once at boot.** Without it, `wait_vblank()` busy-polls `LY` which updates only at WASM `frame({op:'step'})` quantum boundaries → game loop runs at ~1/30 intended speed on the emulator. After enable, `wait_vblank()` compiles to `HALT` + vblank IRQ wake (~10 cycles per frame).
1053
+ - **Use `memcpy_vram(dst, src, n)` for VRAM bulk writes**, NOT raw `(uint8_t*)0x8000` casts — SDCC sm83 may elide the latter as dead code. The bundled `gb_hardware.h` declares every $FFxx register as `volatile`-typed so direct writes like `BGP = 0xE4;` are fine; the hazard is only on cast-through-pointer block copies.
1054
+ - **`background({view:'map', platform:"gb"})` now renders a 256×256 PNG of the BG plane.** Pass `which: 1` for $9C00 map base, `window: true` to render the Window map instead. Returns `mapBase` + `mode` + `scy/scx` so you can see where the visible 160×144 region falls.
1055
+ - **`memory({op:'read', region:"video_ram"})` doesn't work on GB** — gambatte exposes VRAM as `gb_vram` (not the generic libretro id). r54 errors now suggest this directly. Also: `gb_oam`, `gb_io`, `gb_hram`, `gb_bgpdata`, `gb_objpdata`, `gb_cpu_regs`. `tiles({op:'png'})` / `background({view:'map'})` / `sprites({op:'inspect'})` abstract over this.
1056
+ - **SMS / Game Gear VDP footguns** (R53 cleanup, full detail in `platform({op:'doc', platform:"gg"|"sms", name:"mental_model"})`):
1057
+ - **8 sprites per scanline** is a hard VDP limit. Extra sprites on the same Y row silently drop — symptom: "first 8 letters of CATCH THE COIN render, rest vanish." Split text across multiple Y rows OR draw it via the BG name table (no per-line limit).
1058
+ - **GG OAM coords are hardware-space, NOT visible-space.** The libretro screenshot returns the 160×144 visible region but OAM bytes are still 256×192 hw-coord. Visible region = OAM x∈[48,207], y∈[24,167]. `sprites({op:'inspect'})` reports hardware coords too.
1059
+ - **SAT $D0 is the renderer terminator.** R53 fixed `sms_sprite_init` / `gg_sprite_init` so they no longer fill Y with $D0 (they use $E0 now — off-screen but not the terminator). You only hit the trap if you write $D0 yourself; if sprites past a given slot are missing in `sprites({op:'inspect'})`, that's still the diagnosis.
1060
+ - **R6 = 0xFB → sprite tiles at $0000**, not $2000 (older comments lied — fixed). Bit 2 SET = $2000, CLEAR = $0000. Trust `sprites({op:'inspect'})`' `spriteTileDataBase` field over comments.
1061
+ - **SNES CHR/tilemap can overlap in VRAM** if you put them carelessly. CHR starts at word $0000; if your CHR is 16KB the tilemap can't be at word $2000. Put tilemap at word $4000 or later when your CHR is big.
1062
+ - **SNES audio is a separate ROM build** — the Sony SPC700 coprocessor handles all sound; the main 65816 can only upload a driver + samples then send commands. Workflow: write your SPC driver in `arch spc700` .asm, `build({output:'rom', platform:"spc700", source})` to flat raw bytes, then `.incbin` the result into your main 65816 .asm + write the $BBAA handshake at $2140-$2143 to upload it. `encodeAudio({target:'brr', pcmPath, outputPath})` encodes 16-bit PCM into the SNES BRR format the SPC needs. See `src/platforms/snes/lib/audio_pipeline.asm` for the protocol overview, and the SPC driver bundled into any SNES game project scaffolded with a sound genre.
1063
+ - **All SDCC-built platforms (GB, GBC, SMS, GG, MSX, ColecoVision)** share a few SDCC-sm83 / -z80 quirks. The detailed reference is [`src/platforms/gb/lib/c/SDCC_GOTCHAS.md`](src/platforms/gb/lib/c/SDCC_GOTCHAS.md).
1064
+ **2026-05-25: The "for-loop + function-call crash family" (`dbuf_append_str NULL` assertion) is FIXED.** It was emscripten's default 64 KB stack overflowing the static `sm83_regs[]` table at runtime — not a SDCC codegen bug. Fixed by adding `-s STACK_SIZE=8388608` to `scripts/_lib.sh`. Patterns #1..#10 / #37 / #38 / #39 from previous agent notes all compile cleanly now. You don't need `unroll.h`, you don't need to split files into ≤200-line TUs, you don't need array-of-structs refactors. Write the natural code.
1065
+ **C89-only.** SDCC sm83 is C89. No inline `for (int i = 0; ...)`, no mid-block declarations, no compound literals. SDCC's syntax-error line is usually wrong (points at the FIRST decl after non-decl code); use the linter's line numbers instead.
1066
+ **Pre-flight linter:** `build({output:'rom'})` runs a syntax scan before invoking SDCC. C89 violations show up in `issues[]` with `stage: "lint"` and a `ref:` pointing at the right GOTCHAS section. Pass `lint:"strict"` to fail the build on any lint hit; default is advisory. **The linter reports EVERY mid-block decl in a block**, ordinal-tagged (`#2`, `#3` etc.) so a subtle earlier decl doesn't silence the obvious later one (R53 fix). If a flagged line doesn't look like a decl to you, double-check: typedef'd names ending in `_t`, plus `struct`/`union`/`enum` declarations, all count.
1067
+ **Multi-TU still helps iteration speed** (`sourcesPaths: {"main.c":..., "render.c":...}`): smaller TUs rebuild faster, easier to navigate. When a multi-TU build fails, the response includes `failedTU` + `compiledOK` so you know exactly which file to bisect.
1068
+ SMS/GG: `scaffold({op:'project', platform:"sms"|"gg"})` ships `sms_crt0.s` / `gg_crt0.s` into the project automatically — these crt0s give a proper cartridge reset vector + IM 1 + stack setup before calling `main()`. SDCC's stock z80 crt0 traps `rst $08` and any VDP-touching code hangs at PC=$0007, so the bundled crt0 is mandatory for real-hardware boot. GB/GBC: see the NES + GB/GBC self-contained-project bullet above.
1069
+
1070
+ ## Session continuity — REUSE YOUR SESSION
1071
+
1072
+ **MCP sessions on romdev do NOT expire.** They are persistent for
1073
+ the lifetime of the server process — which is hours/days, not minutes.
1074
+ If you call `initialize` ONCE at conversation start, that same session
1075
+ key works for every subsequent tool call all session long.
1076
+
1077
+ **DO NOT** call `initialize` again "just to be safe," "because the
1078
+ session might have timed out," or "because it's been a few minutes."
1079
+ None of those things happen here. Every tool is already registered at
1080
+ session init (no loading step), but creating a fresh session breaks the
1081
+ per-session emulator state (loaded ROM, save states, scroll position,
1082
+ etc. live PER session) — you'd have to re-`loadMedia` and lose your place.
1083
+
1084
+ You ONLY need to re-initialize in TWO cases:
1085
+
1086
+ 1. **Server restart.** You'll see HTTP 404 with "unknown session id"
1087
+ on your next tool call. Send `initialize` once — every tool re-registers automatically (no category reload). You can confirm a restart by checking
1088
+ the server's process lifetime — but really, just react to the 404
1089
+ when it happens; don't preemptively reconnect.
1090
+
1091
+ 2. **`Mcp-Session-Id` header missing from your tool call.** If
1092
+ somehow your client lost the session ID, you'll get an explicit
1093
+ error pointing you at re-initialize. The header is sticky in
1094
+ normal MCP client usage; you won't lose it without something going
1095
+ wrong on the client side.
1096
+
1097
+ **Known historical friction (acknowledged 2026-05-25, since fixed):**
1098
+ real-world agents previously reported losing connections ~30% of long
1099
+ sessions. Server-side persistence is stable now. If you DO observe a
1100
+ session drop without a server restart, open an issue at
1101
+ https://github.com/monteslu/romdev/issues with the timing — it's a
1102
+ regression we want to catch.
1103
+
1104
+ **Anti-pattern to AVOID:** opening a new session before every "block"
1105
+ of work. This is almost always wrong, loses your per-session emulator state, and bloats the server's session table. One session per
1106
+ conversation, end of story.
1107
+
1108
+ ## When in doubt
1109
+
1110
+ `platform({op:'list'})` for capabilities. `catalog({op:'status'})` for what's currently loaded. `platform({op:'toolchains'})` for build tools. `state({op:'list'})` for save slots. Tools are introspectable; you don't have to remember the matrix.