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.
- package/AGENTS.md +1110 -0
- package/CHANGELOG.md +525 -0
- package/LICENSE +45 -0
- package/NOTICE +102 -0
- package/README.md +84 -0
- package/examples/README.md +36 -0
- package/examples/art-first-workflow/README.md +209 -0
- package/examples/atari2600/main.asm +143 -0
- package/examples/atari2600/templates/default.asm +183 -0
- package/examples/atari2600/templates/mini_invaders.asm +381 -0
- package/examples/atari2600/templates/music_demo.asm +322 -0
- package/examples/atari2600/templates/paddle.asm +345 -0
- package/examples/atari2600/templates/single_screen.asm +242 -0
- package/examples/atari7800/main.c +88 -0
- package/examples/atari7800/templates/default.c +183 -0
- package/examples/atari7800/templates/hello_sprite.c +141 -0
- package/examples/atari7800/templates/music_demo.c +123 -0
- package/examples/atari7800/templates/platformer.c +159 -0
- package/examples/atari7800/templates/puzzle.c +164 -0
- package/examples/atari7800/templates/racing.c +139 -0
- package/examples/atari7800/templates/shmup.c +148 -0
- package/examples/atari7800/templates/sports.c +207 -0
- package/examples/c64/main.c +63 -0
- package/examples/c64/templates/hello_sprite.c +117 -0
- package/examples/c64/templates/music_demo.c +131 -0
- package/examples/c64/templates/platformer.c +194 -0
- package/examples/c64/templates/puzzle.c +178 -0
- package/examples/c64/templates/racing.c +140 -0
- package/examples/c64/templates/shmup.c +201 -0
- package/examples/c64/templates/sports.c +109 -0
- package/examples/c64/templates/tile_engine.c +174 -0
- package/examples/gb/main.asm +106 -0
- package/examples/gb/main.c +49 -0
- package/examples/gb/templates/default.c +58 -0
- package/examples/gb/templates/hello_sprite.c +130 -0
- package/examples/gb/templates/music_demo.c +52 -0
- package/examples/gb/templates/platformer.c +178 -0
- package/examples/gb/templates/puzzle.c +217 -0
- package/examples/gb/templates/racing.c +158 -0
- package/examples/gb/templates/shmup.c +172 -0
- package/examples/gb/templates/sports.c +136 -0
- package/examples/gb/templates/tile_engine.c +280 -0
- package/examples/gba/templates/gba_hello.c +64 -0
- package/examples/gba/templates/maxmod_demo.c +105 -0
- package/examples/gba/templates/platformer.c +215 -0
- package/examples/gba/templates/puzzle.c +237 -0
- package/examples/gba/templates/racing.c +175 -0
- package/examples/gba/templates/shmup.c +197 -0
- package/examples/gba/templates/sports.c +177 -0
- package/examples/gba/templates/tonc_hello.c +72 -0
- package/examples/gba/templates/tonc_hello_sprite.c +109 -0
- package/examples/gbc/main.asm +123 -0
- package/examples/gbc/templates/default.c +61 -0
- package/examples/gbc/templates/hello_sprite.c +140 -0
- package/examples/gbc/templates/music_demo.c +63 -0
- package/examples/gbc/templates/platformer.c +181 -0
- package/examples/gbc/templates/puzzle.c +217 -0
- package/examples/gbc/templates/racing.c +164 -0
- package/examples/gbc/templates/shmup.c +188 -0
- package/examples/gbc/templates/sports.c +142 -0
- package/examples/gbc/templates/tile_engine.c +280 -0
- package/examples/genesis/main.s +161 -0
- package/examples/genesis/templates/hello_sprite.c +75 -0
- package/examples/genesis/templates/platformer.c +166 -0
- package/examples/genesis/templates/puzzle.c +240 -0
- package/examples/genesis/templates/racing.c +170 -0
- package/examples/genesis/templates/sgdk_hello.c +41 -0
- package/examples/genesis/templates/shmup.c +188 -0
- package/examples/genesis/templates/shmup_2p.c +244 -0
- package/examples/genesis/templates/sports.c +172 -0
- package/examples/genesis/templates/tile_engine.c +135 -0
- package/examples/genesis/templates/xgm2_demo.c +53 -0
- package/examples/genesis/templates/xgm2_demo_data.s +27 -0
- package/examples/gg/main.c +10 -0
- package/examples/gg/templates/default.c +156 -0
- package/examples/gg/templates/hello_sprite.c +90 -0
- package/examples/gg/templates/music_demo.c +156 -0
- package/examples/gg/templates/platformer.c +220 -0
- package/examples/gg/templates/puzzle.c +204 -0
- package/examples/gg/templates/racing.c +161 -0
- package/examples/gg/templates/shmup.c +188 -0
- package/examples/gg/templates/sports.c +137 -0
- package/examples/gg/templates/tile_engine.c +137 -0
- package/examples/lynx/main.c +4 -0
- package/examples/lynx/templates/default.c +41 -0
- package/examples/lynx/templates/hello_sprite.c +39 -0
- package/examples/lynx/templates/music_demo.c +37 -0
- package/examples/lynx/templates/platformer.c +72 -0
- package/examples/lynx/templates/puzzle.c +142 -0
- package/examples/lynx/templates/racing.c +94 -0
- package/examples/lynx/templates/shmup.c +132 -0
- package/examples/lynx/templates/sports.c +59 -0
- package/examples/msx/catch_game/README.md +75 -0
- package/examples/msx/catch_game/_verify.mjs +93 -0
- package/examples/msx/catch_game/main.c +249 -0
- package/examples/msx/catch_game/shot_after_left.png +0 -0
- package/examples/msx/catch_game/shot_after_right.png +0 -0
- package/examples/msx/catch_game/shot_before.png +0 -0
- package/examples/msx/catch_game/shot_scored.png +0 -0
- package/examples/msx/music_sfx/README.md +38 -0
- package/examples/msx/music_sfx/main.c +164 -0
- package/examples/msx/sprite_move/README.md +44 -0
- package/examples/msx/sprite_move/main.c +100 -0
- package/examples/nes/main.c +143 -0
- package/examples/nes/space-shooter/README.md +69 -0
- package/examples/nes/space-shooter/main.c +441 -0
- package/examples/nes/space-shooter/nes_runtime.c +347 -0
- package/examples/nes/space-shooter/nes_runtime.h +141 -0
- package/examples/nes/templates/default.c +41 -0
- package/examples/nes/templates/hello_sprite.c +104 -0
- package/examples/nes/templates/music_demo.c +80 -0
- package/examples/nes/templates/platformer.c +171 -0
- package/examples/nes/templates/puzzle.c +232 -0
- package/examples/nes/templates/racing.c +203 -0
- package/examples/nes/templates/shmup.c +228 -0
- package/examples/nes/templates/sports.c +205 -0
- package/examples/nes/templates/tile_engine.c +224 -0
- package/examples/pce/catch_game/README.md +8 -0
- package/examples/pce/catch_game/_verify.mjs +75 -0
- package/examples/pce/catch_game/main.c +327 -0
- package/examples/pce/catch_game/shot_after.png +0 -0
- package/examples/pce/catch_game/shot_before.png +0 -0
- package/examples/pce/main.c +37 -0
- package/examples/pce/music_sfx/README.md +8 -0
- package/examples/pce/music_sfx/main.c +154 -0
- package/examples/pce/sprite_move/README.md +19 -0
- package/examples/pce/sprite_move/main.c +155 -0
- package/examples/porting-across-platforms/README.md +59 -0
- package/examples/sms/main.c +129 -0
- package/examples/sms/templates/default.c +110 -0
- package/examples/sms/templates/hello_sprite.c +90 -0
- package/examples/sms/templates/music_demo.c +151 -0
- package/examples/sms/templates/platformer.c +215 -0
- package/examples/sms/templates/puzzle.c +204 -0
- package/examples/sms/templates/racing.c +161 -0
- package/examples/sms/templates/shmup.c +167 -0
- package/examples/sms/templates/shmup_2p.c +219 -0
- package/examples/sms/templates/sports.c +147 -0
- package/examples/sms/templates/tile_engine.c +137 -0
- package/examples/snes/main.asm +70 -0
- package/examples/snes/templates/c-hello-data.asm +28 -0
- package/examples/snes/templates/c-hello.c +71 -0
- package/examples/snes/templates/default-data.asm +36 -0
- package/examples/snes/templates/default.c +74 -0
- package/examples/snes/templates/hello_sprite-data.asm +45 -0
- package/examples/snes/templates/hello_sprite.c +76 -0
- package/examples/snes/templates/music_demo-data.asm +20 -0
- package/examples/snes/templates/music_demo.c +83 -0
- package/examples/snes/templates/platformer-data.asm +27 -0
- package/examples/snes/templates/platformer.c +142 -0
- package/examples/snes/templates/puzzle-data.asm +14 -0
- package/examples/snes/templates/puzzle.c +199 -0
- package/examples/snes/templates/racing-data.asm +33 -0
- package/examples/snes/templates/racing.c +146 -0
- package/examples/snes/templates/shmup-data.asm +61 -0
- package/examples/snes/templates/shmup.c +199 -0
- package/examples/snes/templates/sports-data.asm +28 -0
- package/examples/snes/templates/sports.c +144 -0
- package/package.json +97 -0
- package/src/cheats/gamegenie.js +506 -0
- package/src/cheats/lookup.js +262 -0
- package/src/cheats/parse-cht.js +92 -0
- package/src/cli/smoke.js +283 -0
- package/src/cores/registry.js +99 -0
- package/src/cores/wasm/bluemsx_libretro.js +2 -0
- package/src/cores/wasm/bluemsx_libretro.wasm +0 -0
- package/src/cores/wasm/fceumm_libretro.js +2 -0
- package/src/cores/wasm/fceumm_libretro.wasm +0 -0
- package/src/cores/wasm/gambatte_libretro.js +2 -0
- package/src/cores/wasm/gambatte_libretro.wasm +0 -0
- package/src/cores/wasm/geargrafx_libretro.js +2 -0
- package/src/cores/wasm/geargrafx_libretro.wasm +0 -0
- package/src/cores/wasm/genesis_plus_gx_libretro.js +2 -0
- package/src/cores/wasm/genesis_plus_gx_libretro.wasm +0 -0
- package/src/cores/wasm/handy_libretro.js +2 -0
- package/src/cores/wasm/handy_libretro.wasm +0 -0
- package/src/cores/wasm/mgba_libretro.js +2 -0
- package/src/cores/wasm/mgba_libretro.wasm +0 -0
- package/src/cores/wasm/prosystem_libretro.js +2 -0
- package/src/cores/wasm/prosystem_libretro.wasm +0 -0
- package/src/cores/wasm/snes9x_libretro.js +2 -0
- package/src/cores/wasm/snes9x_libretro.wasm +0 -0
- package/src/cores/wasm/stella2014_libretro.js +2 -0
- package/src/cores/wasm/stella2014_libretro.wasm +0 -0
- package/src/cores/wasm/vice_x64_libretro.js +2 -0
- package/src/cores/wasm/vice_x64_libretro.wasm +0 -0
- package/src/host/LibretroHost.js +1469 -0
- package/src/host/c64-sid-state.js +161 -0
- package/src/host/callbacks.js +444 -0
- package/src/host/chafa-render.js +170 -0
- package/src/host/coreLoader.js +57 -0
- package/src/host/cpu-state.js +543 -0
- package/src/host/dsp-state.js +188 -0
- package/src/host/framebuffer.js +115 -0
- package/src/host/gb-apu-state.js +321 -0
- package/src/host/gba-video-state.js +215 -0
- package/src/host/gpgx-state.js +320 -0
- package/src/host/index.js +4 -0
- package/src/host/lynx-mikey-state.js +226 -0
- package/src/host/msx-ay-state.js +78 -0
- package/src/host/nes-apu-state.js +194 -0
- package/src/host/pce-psg-state.js +82 -0
- package/src/host/retroConstants.js +72 -0
- package/src/host/snes9x-state.js +35 -0
- package/src/host/types.js +332 -0
- package/src/http/routes.js +182 -0
- package/src/http/skill-doc.js +176 -0
- package/src/http/swagger.js +84 -0
- package/src/http/tool-registry.js +142 -0
- package/src/install/postinstall.mjs +81 -0
- package/src/mcp/disclosure.js +250 -0
- package/src/mcp/log.js +87 -0
- package/src/mcp/server.js +498 -0
- package/src/mcp/state.js +88 -0
- package/src/mcp/tool-manifest.js +92 -0
- package/src/mcp/tools/address-to-symbol.js +145 -0
- package/src/mcp/tools/art-loaders.js +743 -0
- package/src/mcp/tools/assets.js +87 -0
- package/src/mcp/tools/audio.js +562 -0
- package/src/mcp/tools/cart-parts.js +651 -0
- package/src/mcp/tools/cheats.js +343 -0
- package/src/mcp/tools/classify-region.js +107 -0
- package/src/mcp/tools/diff-cluster.js +32 -0
- package/src/mcp/tools/diff-roms.js +394 -0
- package/src/mcp/tools/disasm.js +1410 -0
- package/src/mcp/tools/find-references.js +375 -0
- package/src/mcp/tools/font-map.js +563 -0
- package/src/mcp/tools/frame.js +293 -0
- package/src/mcp/tools/free-space.js +71 -0
- package/src/mcp/tools/index.js +339 -0
- package/src/mcp/tools/input-layout.js +231 -0
- package/src/mcp/tools/input.js +227 -0
- package/src/mcp/tools/lifecycle.js +132 -0
- package/src/mcp/tools/lospec.js +187 -0
- package/src/mcp/tools/memory.js +472 -0
- package/src/mcp/tools/metasprite-tools.js +256 -0
- package/src/mcp/tools/platform-docs.js +113 -0
- package/src/mcp/tools/platform-tools.js +1300 -0
- package/src/mcp/tools/platforms.js +139 -0
- package/src/mcp/tools/playtest.js +360 -0
- package/src/mcp/tools/preview-tile.js +478 -0
- package/src/mcp/tools/project.js +1939 -0
- package/src/mcp/tools/record.js +180 -0
- package/src/mcp/tools/reinject.js +732 -0
- package/src/mcp/tools/rendering-context.js +838 -0
- package/src/mcp/tools/rom-id.js +308 -0
- package/src/mcp/tools/run-until.js +176 -0
- package/src/mcp/tools/snippets.js +209 -0
- package/src/mcp/tools/splice-chr.js +190 -0
- package/src/mcp/tools/sprite-pipeline.js +626 -0
- package/src/mcp/tools/state.js +198 -0
- package/src/mcp/tools/symbols.js +400 -0
- package/src/mcp/tools/tile-inspect.js +293 -0
- package/src/mcp/tools/toolchain.js +720 -0
- package/src/mcp/tools/trace-vram-source.js +81 -0
- package/src/mcp/tools/watch-memory.js +1036 -0
- package/src/mcp/tools/which-tiles.js +180 -0
- package/src/mcp/util.js +355 -0
- package/src/observer/bus.js +127 -0
- package/src/observer/livestream.html +594 -0
- package/src/observer/server.js +78 -0
- package/src/observer/tool-wrap.js +142 -0
- package/src/platforms/_guides/MUSIC_SOURCING.md +104 -0
- package/src/platforms/_guides/ROMHACKING_PLAYBOOK.md +245 -0
- package/src/platforms/atari2600/MENTAL_MODEL.md +194 -0
- package/src/platforms/atari2600/TROUBLESHOOTING.md +155 -0
- package/src/platforms/atari2600/UPSTREAM_SOURCES.md +49 -0
- package/src/platforms/atari2600/lib/README.md +67 -0
- package/src/platforms/atari2600/lib/cc65-src/crt0.s +49 -0
- package/src/platforms/atari2600/lib/cc65-src/ctype.s +5 -0
- package/src/platforms/atari2600/lib/kernel_skeleton.asm +85 -0
- package/src/platforms/atari2600/lib/player_kernel.asm +87 -0
- package/src/platforms/atari2600/lib/playfield_kernel.asm +63 -0
- package/src/platforms/atari2600/lib/read_joystick.asm +76 -0
- package/src/platforms/atari2600/lib/score_kernel.asm +141 -0
- package/src/platforms/atari2600/lib/vcs_constants.h +97 -0
- package/src/platforms/atari2600/lib/vectors.asm +16 -0
- package/src/platforms/atari2600/tia.js +355 -0
- package/src/platforms/atari7800/MENTAL_MODEL.md +324 -0
- package/src/platforms/atari7800/TROUBLESHOOTING.md +195 -0
- package/src/platforms/atari7800/UPSTREAM_SOURCES.md +43 -0
- package/src/platforms/atari7800/lib/README.md +45 -0
- package/src/platforms/atari7800/lib/c/atari7800_music.c +215 -0
- package/src/platforms/atari7800/lib/c/atari7800_music.h +33 -0
- package/src/platforms/atari7800/lib/c/atari7800_sfx.c +74 -0
- package/src/platforms/atari7800/lib/c/atari7800_sfx.h +45 -0
- package/src/platforms/atari7800/lib/cc65-src/clock.s +69 -0
- package/src/platforms/atari7800/lib/cc65-src/clocks_per_sec.s +34 -0
- package/src/platforms/atari7800/lib/cc65-src/clrscr.s +27 -0
- package/src/platforms/atari7800/lib/cc65-src/conio.s +226 -0
- package/src/platforms/atari7800/lib/cc65-src/conio_font.s +278 -0
- package/src/platforms/atari7800/lib/cc65-src/cputc.s +139 -0
- package/src/platforms/atari7800/lib/cc65-src/crt0.s +71 -0
- package/src/platforms/atari7800/lib/cc65-src/ctype.s +5 -0
- package/src/platforms/atari7800/lib/cc65-src/exehdr.s +46 -0
- package/src/platforms/atari7800/lib/cc65-src/extra/mono.s +28 -0
- package/src/platforms/atari7800/lib/cc65-src/extzp.inc +15 -0
- package/src/platforms/atari7800/lib/cc65-src/extzp.s +15 -0
- package/src/platforms/atari7800/lib/cc65-src/get_tv.s +65 -0
- package/src/platforms/atari7800/lib/cc65-src/irq.s +36 -0
- package/src/platforms/atari7800/lib/cc65-src/joy/atari7800-stdjoy.s +197 -0
- package/src/platforms/atari7800/lib/cc65-src/joy_stat_stddrv.s +14 -0
- package/src/platforms/atari7800/lib/cc65-src/libref.s +8 -0
- package/src/platforms/atari7800/lib/cc65-src/mono_clrscr.s +27 -0
- package/src/platforms/atari7800/lib/cc65-src/mono_conio.s +231 -0
- package/src/platforms/atari7800/lib/cc65-src/mono_cputc.s +102 -0
- package/src/platforms/atari7800/lib/cc65-src/mono_font.s +2065 -0
- package/src/platforms/atari7800/lib/cc65-src/mono_setcursor.s +214 -0
- package/src/platforms/atari7800/lib/cc65-src/setcursor.s +214 -0
- package/src/platforms/atari7800/lib/cc65-src/textcolor.s +53 -0
- package/src/platforms/atari7800/lib/cc65-src/wherex.s +19 -0
- package/src/platforms/atari7800/lib/cc65-src/wherey.s +19 -0
- package/src/platforms/atari7800/lib/display_list.asm +53 -0
- package/src/platforms/atari7800/lib/maria_init.asm +48 -0
- package/src/platforms/atari7800/lib/maria_registers.h +61 -0
- package/src/platforms/atari7800/lib/palette_load.asm +53 -0
- package/src/platforms/atari7800/lib/read_pad.asm +57 -0
- package/src/platforms/atari7800/lib/vblank_wait.asm +16 -0
- package/src/platforms/atari7800/maria.js +220 -0
- package/src/platforms/atari7800/song.js +232 -0
- package/src/platforms/c64/MENTAL_MODEL.md +188 -0
- package/src/platforms/c64/TROUBLESHOOTING.md +130 -0
- package/src/platforms/c64/UPSTREAM_SOURCES.md +35 -0
- package/src/platforms/c64/image-to-tilemap.js +190 -0
- package/src/platforms/c64/lib/README.md +52 -0
- package/src/platforms/c64/lib/basic_stub.s +25 -0
- package/src/platforms/c64/lib/c/c64_music.c +248 -0
- package/src/platforms/c64/lib/c/c64_music.h +36 -0
- package/src/platforms/c64/lib/c/c64_sfx.c +94 -0
- package/src/platforms/c64/lib/c/c64_sfx.h +37 -0
- package/src/platforms/c64/lib/c64_registers.h +108 -0
- package/src/platforms/c64/lib/cc65-src/_scrsize.s +12 -0
- package/src/platforms/c64/lib/cc65-src/acc_c128_speed.s +5 -0
- package/src/platforms/c64/lib/cc65-src/acc_c64dtv_speed.s +64 -0
- package/src/platforms/c64/lib/cc65-src/acc_c65_speed.s +69 -0
- package/src/platforms/c64/lib/cc65-src/acc_chameleon_speed.s +100 -0
- package/src/platforms/c64/lib/cc65-src/acc_detect_c128.s +33 -0
- package/src/platforms/c64/lib/cc65-src/acc_detect_c64dtv.s +44 -0
- package/src/platforms/c64/lib/cc65-src/acc_detect_c65.s +55 -0
- package/src/platforms/c64/lib/cc65-src/acc_detect_chameleon.s +39 -0
- package/src/platforms/c64/lib/cc65-src/acc_detect_scpu.s +34 -0
- package/src/platforms/c64/lib/cc65-src/acc_detect_turbomaster.s +45 -0
- package/src/platforms/c64/lib/cc65-src/acc_scpu_speed.s +59 -0
- package/src/platforms/c64/lib/cc65-src/acc_turbomaster_speed.s +56 -0
- package/src/platforms/c64/lib/cc65-src/bordercolor.s +17 -0
- package/src/platforms/c64/lib/cc65-src/break.s +108 -0
- package/src/platforms/c64/lib/cc65-src/cgetc.s +62 -0
- package/src/platforms/c64/lib/cc65-src/clrscr.s +11 -0
- package/src/platforms/c64/lib/cc65-src/color.s +24 -0
- package/src/platforms/c64/lib/cc65-src/conio.s +10 -0
- package/src/platforms/c64/lib/cc65-src/cputc.s +105 -0
- package/src/platforms/c64/lib/cc65-src/crt0.s +117 -0
- package/src/platforms/c64/lib/cc65-src/devnum.s +7 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-65816.s +377 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-c256k.s +508 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-dqbb.s +447 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-georam.s +355 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-isepic.s +276 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-kerberos.s +281 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-ram.s +270 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-ramcart.s +297 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-reu.s +286 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-rrr.s +363 -0
- package/src/platforms/c64/lib/cc65-src/emd/c64-vdc.s +405 -0
- package/src/platforms/c64/lib/cc65-src/emd/dtv-himem.s +251 -0
- package/src/platforms/c64/lib/cc65-src/extra/soft80.s +71 -0
- package/src/platforms/c64/lib/cc65-src/extra/soft80mono.s +74 -0
- package/src/platforms/c64/lib/cc65-src/extra/tgimousedata.s +21 -0
- package/src/platforms/c64/lib/cc65-src/get_ostype.s +43 -0
- package/src/platforms/c64/lib/cc65-src/get_tv.s +20 -0
- package/src/platforms/c64/lib/cc65-src/gettime.s +83 -0
- package/src/platforms/c64/lib/cc65-src/irq.s +49 -0
- package/src/platforms/c64/lib/cc65-src/joy/c64-hitjoy.s +218 -0
- package/src/platforms/c64/lib/cc65-src/joy/c64-numpad.s +155 -0
- package/src/platforms/c64/lib/cc65-src/joy/c64-ptvjoy.s +146 -0
- package/src/platforms/c64/lib/cc65-src/joy/c64-stdjoy.s +111 -0
- package/src/platforms/c64/lib/cc65-src/joy_stat_stddrv.s +14 -0
- package/src/platforms/c64/lib/cc65-src/joy_stddrv.s +14 -0
- package/src/platforms/c64/lib/cc65-src/kbhit.s +23 -0
- package/src/platforms/c64/lib/cc65-src/kbrepeat.s +14 -0
- package/src/platforms/c64/lib/cc65-src/kernal.s +53 -0
- package/src/platforms/c64/lib/cc65-src/kplot.s +22 -0
- package/src/platforms/c64/lib/cc65-src/libref.s +16 -0
- package/src/platforms/c64/lib/cc65-src/mainargs.s +137 -0
- package/src/platforms/c64/lib/cc65-src/mcbdefault.s +146 -0
- package/src/platforms/c64/lib/cc65-src/mcbspritedata.s +4 -0
- package/src/platforms/c64/lib/cc65-src/mou/c64-1351.s +467 -0
- package/src/platforms/c64/lib/cc65-src/mou/c64-inkwell.s +446 -0
- package/src/platforms/c64/lib/cc65-src/mou/c64-joy.s +451 -0
- package/src/platforms/c64/lib/cc65-src/mou/c64-pot.s +409 -0
- package/src/platforms/c64/lib/cc65-src/mouse_stat_stddrv.s +14 -0
- package/src/platforms/c64/lib/cc65-src/mouse_stddrv.s +14 -0
- package/src/platforms/c64/lib/cc65-src/mouseref.s +23 -0
- package/src/platforms/c64/lib/cc65-src/pencalib.c +94 -0
- package/src/platforms/c64/lib/cc65-src/randomize.s +18 -0
- package/src/platforms/c64/lib/cc65-src/revers.s +27 -0
- package/src/platforms/c64/lib/cc65-src/ser/c64-swlink.s +484 -0
- package/src/platforms/c64/lib/cc65-src/ser_stat_stddrv.s +14 -0
- package/src/platforms/c64/lib/cc65-src/ser_stddrv.s +13 -0
- package/src/platforms/c64/lib/cc65-src/settime.s +84 -0
- package/src/platforms/c64/lib/cc65-src/soft80.inc +46 -0
- package/src/platforms/c64/lib/cc65-src/soft80_cgetc.s +85 -0
- package/src/platforms/c64/lib/cc65-src/soft80_charset.s +182 -0
- package/src/platforms/c64/lib/cc65-src/soft80_color.s +159 -0
- package/src/platforms/c64/lib/cc65-src/soft80_conio.s +157 -0
- package/src/platforms/c64/lib/cc65-src/soft80_cpeekc.s +148 -0
- package/src/platforms/c64/lib/cc65-src/soft80_cpeekcolor.s +19 -0
- package/src/platforms/c64/lib/cc65-src/soft80_cpeekrevers.s +15 -0
- package/src/platforms/c64/lib/cc65-src/soft80_cpeeks.s +71 -0
- package/src/platforms/c64/lib/cc65-src/soft80_cputc.s +521 -0
- package/src/platforms/c64/lib/cc65-src/soft80_kclrscr.s +76 -0
- package/src/platforms/c64/lib/cc65-src/soft80_kplot.s +63 -0
- package/src/platforms/c64/lib/cc65-src/soft80_scrsize.s +14 -0
- package/src/platforms/c64/lib/cc65-src/soft80mono_cgetc.s +67 -0
- package/src/platforms/c64/lib/cc65-src/soft80mono_color.s +65 -0
- package/src/platforms/c64/lib/cc65-src/soft80mono_conio.s +168 -0
- package/src/platforms/c64/lib/cc65-src/soft80mono_cpeekcolor.s +17 -0
- package/src/platforms/c64/lib/cc65-src/soft80mono_cputc.s +204 -0
- package/src/platforms/c64/lib/cc65-src/soft80mono_kclrscr.s +63 -0
- package/src/platforms/c64/lib/cc65-src/soft80mono_kplot.s +52 -0
- package/src/platforms/c64/lib/cc65-src/status.s +15 -0
- package/src/platforms/c64/lib/cc65-src/sysuname.s +37 -0
- package/src/platforms/c64/lib/cc65-src/tgi/c64-hi.s +881 -0
- package/src/platforms/c64/lib/cc65-src/tgi_stat_stddrv.s +14 -0
- package/src/platforms/c64/lib/cc65-src/tgi_stddrv.s +13 -0
- package/src/platforms/c64/lib/cc65-src/tmcommon.s +67 -0
- package/src/platforms/c64/lib/cc65-src/waitvsync.s +18 -0
- package/src/platforms/c64/lib/read_joystick.s +28 -0
- package/src/platforms/c64/lib/sid_play.s +48 -0
- package/src/platforms/c64/lib/sprite_table.s +73 -0
- package/src/platforms/c64/lib/vic_init.s +47 -0
- package/src/platforms/c64/sid.js +128 -0
- package/src/platforms/c64/song.js +262 -0
- package/src/platforms/c64/vic.js +273 -0
- package/src/platforms/common/default-palette.js +139 -0
- package/src/platforms/common/image-to-tiles.js +418 -0
- package/src/platforms/common/intent.js +111 -0
- package/src/platforms/common/metasprite-adapters.js +279 -0
- package/src/platforms/common/metasprite-codegen.js +192 -0
- package/src/platforms/common/metasprite-core.js +201 -0
- package/src/platforms/common/metasprite.js +89 -0
- package/src/platforms/common/platform-palette.js +137 -0
- package/src/platforms/common/registers.js +329 -0
- package/src/platforms/common/render-tiles.js +86 -0
- package/src/platforms/common/screenshot-sprite.js +153 -0
- package/src/platforms/common/tile-decode.js +149 -0
- package/src/platforms/gb/MENTAL_MODEL.md +262 -0
- package/src/platforms/gb/TROUBLESHOOTING.md +218 -0
- package/src/platforms/gb/UPSTREAM_SOURCES.md +43 -0
- package/src/platforms/gb/image-to-tilemap.js +173 -0
- package/src/platforms/gb/lib/README.md +115 -0
- package/src/platforms/gb/lib/c/LICENSE-HUGEDRIVER +25 -0
- package/src/platforms/gb/lib/c/README.md +122 -0
- package/src/platforms/gb/lib/c/SDCC_GOTCHAS.md +190 -0
- package/src/platforms/gb/lib/c/gb_crt0.s +163 -0
- package/src/platforms/gb/lib/c/gb_hardware.h +113 -0
- package/src/platforms/gb/lib/c/gb_runtime.c +284 -0
- package/src/platforms/gb/lib/c/gb_runtime.h +145 -0
- package/src/platforms/gb/lib/c/hUGEDriver.c +191 -0
- package/src/platforms/gb/lib/c/hUGEDriver.h +95 -0
- package/src/platforms/gb/lib/c/hUGEDriver.upstream.asm +1908 -0
- package/src/platforms/gb/lib/c/lcd_init.c +19 -0
- package/src/platforms/gb/lib/c/patch-header.js +154 -0
- package/src/platforms/gb/lib/c/song_data.c +88 -0
- package/src/platforms/gb/lib/c/unroll.h +52 -0
- package/src/platforms/gb/lib/c/wait_vblank.c +14 -0
- package/src/platforms/gb/lib/dma_oam.asm +51 -0
- package/src/platforms/gb/lib/header.asm +56 -0
- package/src/platforms/gb/lib/joypad_read.asm +47 -0
- package/src/platforms/gb/lib/lcd_init.asm +44 -0
- package/src/platforms/gb/lib/load_palette.asm +25 -0
- package/src/platforms/gb/lib/load_tiles.asm +29 -0
- package/src/platforms/gb/lib/vblank_wait.asm +31 -0
- package/src/platforms/gb/ppu.js +574 -0
- package/src/platforms/gb/song.js +140 -0
- package/src/platforms/gba/MENTAL_MODEL.md +216 -0
- package/src/platforms/gba/TROUBLESHOOTING.md +250 -0
- package/src/platforms/gba/UPSTREAM_SOURCES.md +41 -0
- package/src/platforms/gba/lib/arm-archives/libc.a +0 -0
- package/src/platforms/gba/lib/arm-archives/libgcc.a +0 -0
- package/src/platforms/gba/lib/arm-archives/libnosys.a +0 -0
- package/src/platforms/gba/lib/c/gba_sfx.c +81 -0
- package/src/platforms/gba/lib/c/gba_sfx.h +48 -0
- package/src/platforms/gba/lib/libgba/crtbegin.o +0 -0
- package/src/platforms/gba/lib/libgba/crtend.o +0 -0
- package/src/platforms/gba/lib/libgba/crti.o +0 -0
- package/src/platforms/gba/lib/libgba/crtn.o +0 -0
- package/src/platforms/gba/lib/libgba/gba_cart.ld +319 -0
- package/src/platforms/gba/lib/libgba/gba_crt0.s +258 -0
- package/src/platforms/gba/lib/libgba/include/BoyScout.h +128 -0
- package/src/platforms/gba/lib/libgba/include/disc.h +36 -0
- package/src/platforms/gba/lib/libgba/include/disc_io.h +64 -0
- package/src/platforms/gba/lib/libgba/include/dldi.h +112 -0
- package/src/platforms/gba/lib/libgba/include/erapi.h +195 -0
- package/src/platforms/gba/lib/libgba/include/fade.h +76 -0
- package/src/platforms/gba/lib/libgba/include/gba.h +47 -0
- package/src/platforms/gba/lib/libgba/include/gba_affine.h +83 -0
- package/src/platforms/gba/lib/libgba/include/gba_base.h +122 -0
- package/src/platforms/gba/lib/libgba/include/gba_compression.h +66 -0
- package/src/platforms/gba/lib/libgba/include/gba_console.h +55 -0
- package/src/platforms/gba/lib/libgba/include/gba_dma.h +100 -0
- package/src/platforms/gba/lib/libgba/include/gba_input.h +127 -0
- package/src/platforms/gba/lib/libgba/include/gba_interrupt.h +146 -0
- package/src/platforms/gba/lib/libgba/include/gba_multiboot.h +72 -0
- package/src/platforms/gba/lib/libgba/include/gba_sio.h +124 -0
- package/src/platforms/gba/lib/libgba/include/gba_sound.h +356 -0
- package/src/platforms/gba/lib/libgba/include/gba_sprites.h +195 -0
- package/src/platforms/gba/lib/libgba/include/gba_systemcalls.h +194 -0
- package/src/platforms/gba/lib/libgba/include/gba_timers.h +63 -0
- package/src/platforms/gba/lib/libgba/include/gba_types.h +60 -0
- package/src/platforms/gba/lib/libgba/include/gba_video.h +307 -0
- package/src/platforms/gba/lib/libgba/include/mappy.h +72 -0
- package/src/platforms/gba/lib/libgba/include/mbv2.h +90 -0
- package/src/platforms/gba/lib/libgba/include/xcomms.h +93 -0
- package/src/platforms/gba/lib/libgba/include/xcomms_cmd.h +53 -0
- package/src/platforms/gba/lib/libgba/libgba.seed.a +0 -0
- package/src/platforms/gba/lib/libgba/libgba.seed.hash +1 -0
- package/src/platforms/gba/lib/libgba/src/AffineSet.c +42 -0
- package/src/platforms/gba/lib/libgba/src/ArcTan.s +41 -0
- package/src/platforms/gba/lib/libgba/src/BoyScout/BoyScout.c +1242 -0
- package/src/platforms/gba/lib/libgba/src/BoyScout/GBASoundRegs.h +200 -0
- package/src/platforms/gba/lib/libgba/src/Compression.c +84 -0
- package/src/platforms/gba/lib/libgba/src/CpuSet.c +41 -0
- package/src/platforms/gba/lib/libgba/src/Div.s +58 -0
- package/src/platforms/gba/lib/libgba/src/DivArm.s +50 -0
- package/src/platforms/gba/lib/libgba/src/InterruptDispatcher.s +113 -0
- package/src/platforms/gba/lib/libgba/src/IntrWait.c +35 -0
- package/src/platforms/gba/lib/libgba/src/MultiBoot.s +33 -0
- package/src/platforms/gba/lib/libgba/src/Reset.s +49 -0
- package/src/platforms/gba/lib/libgba/src/Sound.s +48 -0
- package/src/platforms/gba/lib/libgba/src/Sqrt.s +34 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/disc.c +58 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/dldi.c +189 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/dldi_stub.s +78 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_cf_common.c +260 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_cf_common.h +72 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_m3_common.c +60 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_m3_common.h +48 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_m3cf.c +83 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_m3cf.h +45 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_m3sd.c +508 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_m3sd.h +45 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_mpcf.c +87 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_mpcf.h +42 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_sc_common.c +47 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_sc_common.h +43 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_sccf.c +83 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_sccf.h +45 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_scsd.c +385 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_scsd.h +48 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_scsd_s.s +139 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_sd_common.c +203 -0
- package/src/platforms/gba/lib/libgba/src/disc_io/io_sd_common.h +108 -0
- package/src/platforms/gba/lib/libgba/src/fade.c +185 -0
- package/src/platforms/gba/lib/libgba/src/input.c +127 -0
- package/src/platforms/gba/lib/libgba/src/interrupt.c +116 -0
- package/src/platforms/gba/lib/libgba/src/mappy_print.c +74 -0
- package/src/platforms/gba/lib/libgba/src/mb2print.c +69 -0
- package/src/platforms/gba/lib/libgba/src/mbv2.c +230 -0
- package/src/platforms/gba/lib/libgba/src/mbv2.txt +119 -0
- package/src/platforms/gba/lib/libgba/src/xcomms.c +203 -0
- package/src/platforms/gba/lib/libgba/src/xcomms_print.c +56 -0
- package/src/platforms/gba/lib/libgba/sysinclude/_ansi.h +82 -0
- package/src/platforms/gba/lib/libgba/sysinclude/_newlib_version.h +11 -0
- package/src/platforms/gba/lib/libgba/sysinclude/_syslist.h +41 -0
- package/src/platforms/gba/lib/libgba/sysinclude/alloca.h +21 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ar.h +65 -0
- package/src/platforms/gba/lib/libgba/sysinclude/argz.h +33 -0
- package/src/platforms/gba/lib/libgba/sysinclude/assert.h +50 -0
- package/src/platforms/gba/lib/libgba/sysinclude/complex.h +150 -0
- package/src/platforms/gba/lib/libgba/sysinclude/cpio.h +30 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ctype.h +183 -0
- package/src/platforms/gba/lib/libgba/sysinclude/devctl.h +78 -0
- package/src/platforms/gba/lib/libgba/sysinclude/dirent.h +85 -0
- package/src/platforms/gba/lib/libgba/sysinclude/elf.h +3147 -0
- package/src/platforms/gba/lib/libgba/sysinclude/envlock.h +15 -0
- package/src/platforms/gba/lib/libgba/sysinclude/envz.h +16 -0
- package/src/platforms/gba/lib/libgba/sysinclude/errno.h +11 -0
- package/src/platforms/gba/lib/libgba/sysinclude/fastmath.h +13 -0
- package/src/platforms/gba/lib/libgba/sysinclude/fcntl.h +1 -0
- package/src/platforms/gba/lib/libgba/sysinclude/fenv.h +42 -0
- package/src/platforms/gba/lib/libgba/sysinclude/float.h +631 -0
- package/src/platforms/gba/lib/libgba/sysinclude/fnmatch.h +55 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ftw.h +66 -0
- package/src/platforms/gba/lib/libgba/sysinclude/getopt.h +185 -0
- package/src/platforms/gba/lib/libgba/sysinclude/glob.h +90 -0
- package/src/platforms/gba/lib/libgba/sysinclude/grp.h +86 -0
- package/src/platforms/gba/lib/libgba/sysinclude/iconv.h +63 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ieeefp.h +295 -0
- package/src/platforms/gba/lib/libgba/sysinclude/inttypes.h +345 -0
- package/src/platforms/gba/lib/libgba/sysinclude/iso646.h +45 -0
- package/src/platforms/gba/lib/libgba/sysinclude/langinfo.h +332 -0
- package/src/platforms/gba/lib/libgba/sysinclude/libgen.h +37 -0
- package/src/platforms/gba/lib/libgba/sysinclude/limits.h +168 -0
- package/src/platforms/gba/lib/libgba/sysinclude/locale.h +96 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/_arc4random.h +1 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/_default_types.h +250 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/_endian.h +39 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/_time.h +3 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/_types.h +8 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/ansi.h +1 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/endian.h +69 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/fastmath.h +98 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/ieee.h +127 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/ieeefp.h +533 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/malloc.h +8 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/param.h +8 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/setjmp-dj.h +43 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/setjmp.h +524 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/stdlib.h +8 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/termios.h +1 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/time.h +15 -0
- package/src/platforms/gba/lib/libgba/sysinclude/machine/types.h +13 -0
- package/src/platforms/gba/lib/libgba/sysinclude/malloc.h +173 -0
- package/src/platforms/gba/lib/libgba/sysinclude/math.h +645 -0
- package/src/platforms/gba/lib/libgba/sysinclude/memory.h +4 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ndbm.h +91 -0
- package/src/platforms/gba/lib/libgba/sysinclude/newlib.h +427 -0
- package/src/platforms/gba/lib/libgba/sysinclude/paths.h +9 -0
- package/src/platforms/gba/lib/libgba/sysinclude/pthread.h +456 -0
- package/src/platforms/gba/lib/libgba/sysinclude/pwd.h +83 -0
- package/src/platforms/gba/lib/libgba/sysinclude/reent.h +190 -0
- package/src/platforms/gba/lib/libgba/sysinclude/regdef.h +7 -0
- package/src/platforms/gba/lib/libgba/sysinclude/regex.h +103 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sched.h +112 -0
- package/src/platforms/gba/lib/libgba/sysinclude/search.h +64 -0
- package/src/platforms/gba/lib/libgba/sysinclude/setjmp.h +25 -0
- package/src/platforms/gba/lib/libgba/sysinclude/signal.h +35 -0
- package/src/platforms/gba/lib/libgba/sysinclude/spawn.h +111 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ssp/ssp.h +76 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ssp/stdio.h +101 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ssp/stdlib.h +30 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ssp/string.h +115 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ssp/strings.h +55 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ssp/unistd.h +93 -0
- package/src/platforms/gba/lib/libgba/sysinclude/ssp/wchar.h +97 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stdarg.h +135 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stdatomic.h +409 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stdbool.h +51 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stddef.h +463 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stdint.h +466 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stdio.h +807 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stdio_ext.h +79 -0
- package/src/platforms/gba/lib/libgba/sysinclude/stdlib.h +345 -0
- package/src/platforms/gba/lib/libgba/sysinclude/string.h +183 -0
- package/src/platforms/gba/lib/libgba/sysinclude/strings.h +80 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_default_fcntl.h +241 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_intsup.h +199 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_locale.h +12 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_pthreadtypes.h +233 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_sigset.h +43 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_stdint.h +90 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_timespec.h +52 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_timeval.h +60 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_types.h +228 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/_tz_structs.h +24 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/cdefs.h +754 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/config.h +314 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/custom_file.h +2 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/dir.h +10 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/dirent.h +13 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/endian.h +207 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/errno.h +198 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/fcntl.h +12 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/features.h +551 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/fenv.h +90 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/file.h +2 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/iconvnls.h +77 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/iosupport.h +143 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/lock.h +75 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/param.h +35 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/queue.h +919 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/reent.h +913 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/resource.h +24 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/sched.h +69 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/select.h +94 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/signal.h +388 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/stat.h +179 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/statvfs.h +41 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/stdio.h +27 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/string.h +2 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/syslimits.h +61 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/time.h +448 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/timeb.h +40 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/times.h +32 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/timespec.h +63 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/tree.h +864 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/types.h +228 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/unistd.h +591 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/utime.h +22 -0
- package/src/platforms/gba/lib/libgba/sysinclude/sys/wait.h +44 -0
- package/src/platforms/gba/lib/libgba/sysinclude/tar.h +43 -0
- package/src/platforms/gba/lib/libgba/sysinclude/termios.h +7 -0
- package/src/platforms/gba/lib/libgba/sysinclude/tgmath.h +127 -0
- package/src/platforms/gba/lib/libgba/sysinclude/threads.h +93 -0
- package/src/platforms/gba/lib/libgba/sysinclude/time.h +313 -0
- package/src/platforms/gba/lib/libgba/sysinclude/unctrl.h +42 -0
- package/src/platforms/gba/lib/libgba/sysinclude/unistd.h +6 -0
- package/src/platforms/gba/lib/libgba/sysinclude/utime.h +12 -0
- package/src/platforms/gba/lib/libgba/sysinclude/utmp.h +8 -0
- package/src/platforms/gba/lib/libgba/sysinclude/varargs.h +7 -0
- package/src/platforms/gba/lib/libgba/sysinclude/wchar.h +339 -0
- package/src/platforms/gba/lib/libgba/sysinclude/wctype.h +74 -0
- package/src/platforms/gba/lib/libgba/sysinclude/wordexp.h +53 -0
- package/src/platforms/gba/lib/libtonc/crtbegin.o +0 -0
- package/src/platforms/gba/lib/libtonc/crtend.o +0 -0
- package/src/platforms/gba/lib/libtonc/crti.o +0 -0
- package/src/platforms/gba/lib/libtonc/crtn.o +0 -0
- package/src/platforms/gba/lib/libtonc/gba_cart.ld +319 -0
- package/src/platforms/gba/lib/libtonc/gba_crt0.s +258 -0
- package/src/platforms/gba/lib/libtonc/include/tonc.h +72 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_asminc.h +132 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_bios.h +555 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_core.h +573 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_input.h +184 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_irq.h +121 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_legacy.h +481 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_libgba.h +537 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_math.h +692 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_memdef.h +962 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_memmap.h +583 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_nocash.h +51 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_oam.h +186 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_surface.h +461 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_text.h +270 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_tte.h +748 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_types.h +376 -0
- package/src/platforms/gba/lib/libtonc/include/tonc_video.h +615 -0
- package/src/platforms/gba/lib/libtonc/libtonc.seed.a +0 -0
- package/src/platforms/gba/lib/libtonc/libtonc.seed.hash +1 -0
- package/src/platforms/gba/lib/libtonc/src/asm/clr_blend_fast.s +72 -0
- package/src/platforms/gba/lib/libtonc/src/asm/clr_fade_fast.s +74 -0
- package/src/platforms/gba/lib/libtonc/src/asm/div_lut.s +54 -0
- package/src/platforms/gba/lib/libtonc/src/asm/sin_lut.s +90 -0
- package/src/platforms/gba/lib/libtonc/src/asm/tonc_bios.s +289 -0
- package/src/platforms/gba/lib/libtonc/src/asm/tonc_bios_ex.s +97 -0
- package/src/platforms/gba/lib/libtonc/src/asm/tonc_isr_master.s +92 -0
- package/src/platforms/gba/lib/libtonc/src/asm/tonc_isr_nest.s +98 -0
- package/src/platforms/gba/lib/libtonc/src/asm/tonc_memcpy.s +126 -0
- package/src/platforms/gba/lib/libtonc/src/asm/tonc_memset.s +123 -0
- package/src/platforms/gba/lib/libtonc/src/asm/tonc_nocash.s +73 -0
- package/src/platforms/gba/lib/libtonc/src/font/sys8.png +0 -0
- package/src/platforms/gba/lib/libtonc/src/font/sys8.s +46 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana10.png +0 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana10.s +293 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9.png +0 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9.s +167 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9_b4.png +0 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9_b4.s +545 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9b.png +0 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9b.s +167 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9i.png +0 -0
- package/src/platforms/gba/lib/libtonc/src/font/verdana9i.s +167 -0
- package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_bitmap.c +289 -0
- package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text.c +81 -0
- package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text_bm.c +244 -0
- package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text_map.c +122 -0
- package/src/platforms/gba/lib/libtonc/src/pre1.3/tonc_text_oam.c +113 -0
- package/src/platforms/gba/lib/libtonc/src/pre1.3/toncfont.s +43 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_bg.c +61 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_bg_affine.c +112 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_bmp16.c +240 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_bmp8.c +314 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_color.c +368 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_core.c +237 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_input.c +118 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_irq.c +271 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_math.c +54 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_oam.c +76 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_obj_affine.c +146 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_sbmp16.c +369 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_sbmp8.c +405 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_schr4c.c +588 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_schr4r.c +462 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_surface.c +105 -0
- package/src/platforms/gba/lib/libtonc/src/tonc_video.c +33 -0
- package/src/platforms/gba/lib/libtonc/src/tte/ase_drawg.c +83 -0
- package/src/platforms/gba/lib/libtonc/src/tte/bmp16_drawg.c +72 -0
- package/src/platforms/gba/lib/libtonc/src/tte/bmp16_drawg_b1cs.c +92 -0
- package/src/platforms/gba/lib/libtonc/src/tte/bmp8_drawg.c +71 -0
- package/src/platforms/gba/lib/libtonc/src/tte/bmp8_drawg_b1cs.c +104 -0
- package/src/platforms/gba/lib/libtonc/src/tte/bmp8_drawg_b1cts_fast.s +115 -0
- package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b1cts.c +76 -0
- package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b1cts_fast.s +128 -0
- package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b4cts.c +67 -0
- package/src/platforms/gba/lib/libtonc/src/tte/chr4c_drawg_b4cts_fast.s +127 -0
- package/src/platforms/gba/lib/libtonc/src/tte/chr4r_drawg_b1cts.c +80 -0
- package/src/platforms/gba/lib/libtonc/src/tte/chr4r_drawg_b1cts_fast.s +145 -0
- package/src/platforms/gba/lib/libtonc/src/tte/obj_drawg.c +61 -0
- package/src/platforms/gba/lib/libtonc/src/tte/se_drawg.c +110 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_init_ase.c +87 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_init_bmp.c +118 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_init_chr4c.c +86 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_init_chr4r.c +87 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_init_obj.c +84 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_init_se.c +96 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_iohook.c +264 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_main.c +756 -0
- package/src/platforms/gba/lib/libtonc/src/tte/tte_types.s +119 -0
- package/src/platforms/gba/lib/maxmod/LICENSE-MAXMOD +23 -0
- package/src/platforms/gba/lib/maxmod/asm_include/mp_defs.inc +117 -0
- package/src/platforms/gba/lib/maxmod/asm_include/mp_format_mas.inc +108 -0
- package/src/platforms/gba/lib/maxmod/asm_include/mp_macros.inc +195 -0
- package/src/platforms/gba/lib/maxmod/asm_include/mp_mas.inc +40 -0
- package/src/platforms/gba/lib/maxmod/asm_include/mp_mas_structs.inc +189 -0
- package/src/platforms/gba/lib/maxmod/asm_include/mp_mixer_ds.inc +46 -0
- package/src/platforms/gba/lib/maxmod/asm_include/mp_mixer_gba.inc +42 -0
- package/src/platforms/gba/lib/maxmod/asm_include/swi_gba.inc +23 -0
- package/src/platforms/gba/lib/maxmod/include/maxmod.h +412 -0
- package/src/platforms/gba/lib/maxmod/include/mm_types.h +333 -0
- package/src/platforms/gba/lib/maxmod/maxmod.seed.a +0 -0
- package/src/platforms/gba/lib/maxmod/maxmod.seed.hash +1 -0
- package/src/platforms/gba/lib/maxmod/music/chiptune.xm +0 -0
- package/src/platforms/gba/lib/maxmod/music/chiptune_soundbank.bin +0 -0
- package/src/platforms/gba/lib/maxmod/music/chiptune_soundbank.h +4 -0
- package/src/platforms/gba/lib/maxmod/music/make_chiptune_xm.js +203 -0
- package/src/platforms/gba/lib/maxmod/source/mm_effect.s +767 -0
- package/src/platforms/gba/lib/maxmod/source/mm_main.s +115 -0
- package/src/platforms/gba/lib/maxmod/source/mm_mas.s +4990 -0
- package/src/platforms/gba/lib/maxmod/source/mm_mas_arm.s +612 -0
- package/src/platforms/gba/lib/maxmod/source_gba/mm_init_default.s +98 -0
- package/src/platforms/gba/lib/maxmod/source_gba/mm_main_gba.s +292 -0
- package/src/platforms/gba/lib/maxmod/source_gba/mm_mixer_gba.s +1367 -0
- package/src/platforms/gba/lib/sysbase/gba_iosupport.c +138 -0
- package/src/platforms/gbc/MENTAL_MODEL.md +178 -0
- package/src/platforms/gbc/TROUBLESHOOTING.md +142 -0
- package/src/platforms/gbc/UPSTREAM_SOURCES.md +60 -0
- package/src/platforms/gbc/lib/c/LICENSE-HUGEDRIVER +25 -0
- package/src/platforms/gbc/lib/c/README.md +122 -0
- package/src/platforms/gbc/lib/c/SDCC_GOTCHAS.md +190 -0
- package/src/platforms/gbc/lib/c/gb_crt0.s +163 -0
- package/src/platforms/gbc/lib/c/gb_hardware.h +113 -0
- package/src/platforms/gbc/lib/c/gb_runtime.c +284 -0
- package/src/platforms/gbc/lib/c/gb_runtime.h +145 -0
- package/src/platforms/gbc/lib/c/hUGEDriver.c +191 -0
- package/src/platforms/gbc/lib/c/hUGEDriver.h +95 -0
- package/src/platforms/gbc/lib/c/hUGEDriver.upstream.asm +1908 -0
- package/src/platforms/gbc/lib/c/lcd_init.c +19 -0
- package/src/platforms/gbc/lib/c/patch-header.js +154 -0
- package/src/platforms/gbc/lib/c/song_data.c +88 -0
- package/src/platforms/gbc/lib/c/unroll.h +52 -0
- package/src/platforms/gbc/lib/c/wait_vblank.c +14 -0
- package/src/platforms/gbc/song.js +3 -0
- package/src/platforms/genesis/MENTAL_MODEL.md +306 -0
- package/src/platforms/genesis/TROUBLESHOOTING.md +226 -0
- package/src/platforms/genesis/UPSTREAM_SOURCES.md +53 -0
- package/src/platforms/genesis/image-to-tilemap.js +351 -0
- package/src/platforms/genesis/lib/README.md +160 -0
- package/src/platforms/genesis/lib/c/crtbegin.o +0 -0
- package/src/platforms/genesis/lib/c/crtend.o +0 -0
- package/src/platforms/genesis/lib/c/genesis.ld +44 -0
- package/src/platforms/genesis/lib/c/genesis_sfx.c +51 -0
- package/src/platforms/genesis/lib/c/genesis_sfx.h +49 -0
- package/src/platforms/genesis/lib/c/libc.a +0 -0
- package/src/platforms/genesis/lib/c/libgcc.a +0 -0
- package/src/platforms/genesis/lib/c/libm.a +0 -0
- package/src/platforms/genesis/lib/c/sega.s +71 -0
- package/src/platforms/genesis/lib/header.s +96 -0
- package/src/platforms/genesis/lib/nmi_safe.s +79 -0
- package/src/platforms/genesis/lib/pad_read.s +104 -0
- package/src/platforms/genesis/lib/sgdk/COPYING.RUNTIME +73 -0
- package/src/platforms/genesis/lib/sgdk/LICENSE +12 -0
- package/src/platforms/genesis/lib/sgdk/include/asm.h +52 -0
- package/src/platforms/genesis/lib/sgdk/include/asm_mac.i +9 -0
- package/src/platforms/genesis/lib/sgdk/include/bmp.h +690 -0
- package/src/platforms/genesis/lib/sgdk/include/config.h +208 -0
- package/src/platforms/genesis/lib/sgdk/include/dma.h +542 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/console.h +387 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/everdrive.h +116 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/fat16.h +84 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/flash-save/flash.h +164 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/flash-save/saveman.h +177 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/link_cable.h +316 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/minimusic/minimus.h +29 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/16c550.h +221 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/comm.h +93 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/gamejolt.h +541 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/jsmn.h +471 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/json.h +122 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/lsd.h +172 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/megawifi.h +984 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/mw-msg.h +392 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/ssf_ed_pro.h +38 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/mw/ssf_ed_x7.h +73 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/serial/buffer.h +8 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/serial/serial.h +133 -0
- package/src/platforms/genesis/lib/sgdk/include/ext/stb/stb_sprintf.h +1864 -0
- package/src/platforms/genesis/lib/sgdk/include/genesis.h +92 -0
- package/src/platforms/genesis/lib/sgdk/include/joy.h +482 -0
- package/src/platforms/genesis/lib/sgdk/include/kdebug.h +21 -0
- package/src/platforms/genesis/lib/sgdk/include/map.h +409 -0
- package/src/platforms/genesis/lib/sgdk/include/mapper.h +186 -0
- package/src/platforms/genesis/lib/sgdk/include/maths.h +1071 -0
- package/src/platforms/genesis/lib/sgdk/include/maths3D.h +480 -0
- package/src/platforms/genesis/lib/sgdk/include/memory.h +346 -0
- package/src/platforms/genesis/lib/sgdk/include/memory_base.h +37 -0
- package/src/platforms/genesis/lib/sgdk/include/object.h +171 -0
- package/src/platforms/genesis/lib/sgdk/include/pal.h +500 -0
- package/src/platforms/genesis/lib/sgdk/include/pool.h +171 -0
- package/src/platforms/genesis/lib/sgdk/include/psg.h +153 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/pcm/snd_dpcm2.h +79 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/pcm/snd_pcm.h +98 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/pcm/snd_pcm4.h +125 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/pcm/tab_vol.h +6 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/smp_null.h +6 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/smp_null_dpcm.h +6 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/sound.h +70 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/xgm.h +399 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/xgm2.h +389 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/z80_def.i80 +41 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/z80_fct.i80 +83 -0
- package/src/platforms/genesis/lib/sgdk/include/snd/z80_mac.i80 +1476 -0
- package/src/platforms/genesis/lib/sgdk/include/sprite_eng.h +1095 -0
- package/src/platforms/genesis/lib/sgdk/include/sprite_eng_legacy.h +1030 -0
- package/src/platforms/genesis/lib/sgdk/include/sram.h +110 -0
- package/src/platforms/genesis/lib/sgdk/include/string.h +349 -0
- package/src/platforms/genesis/lib/sgdk/include/sys.h +511 -0
- package/src/platforms/genesis/lib/sgdk/include/tab_cnv.h +19 -0
- package/src/platforms/genesis/lib/sgdk/include/task.h +77 -0
- package/src/platforms/genesis/lib/sgdk/include/task_cst.h +33 -0
- package/src/platforms/genesis/lib/sgdk/include/timer.h +132 -0
- package/src/platforms/genesis/lib/sgdk/include/tools.h +450 -0
- package/src/platforms/genesis/lib/sgdk/include/types.h +320 -0
- package/src/platforms/genesis/lib/sgdk/include/vdp.h +1150 -0
- package/src/platforms/genesis/lib/sgdk/include/vdp_bg.h +723 -0
- package/src/platforms/genesis/lib/sgdk/include/vdp_pal.h +101 -0
- package/src/platforms/genesis/lib/sgdk/include/vdp_spr.h +448 -0
- package/src/platforms/genesis/lib/sgdk/include/vdp_tile.h +1136 -0
- package/src/platforms/genesis/lib/sgdk/include/vram.h +270 -0
- package/src/platforms/genesis/lib/sgdk/include/ym2612.h +87 -0
- package/src/platforms/genesis/lib/sgdk/include/z80_ctrl.h +420 -0
- package/src/platforms/genesis/lib/sgdk/libmd.seed.a +0 -0
- package/src/platforms/genesis/lib/sgdk/libmd.seed.hash +1 -0
- package/src/platforms/genesis/lib/sgdk/md.ld +120 -0
- package/src/platforms/genesis/lib/sgdk/music/demo.vgm +0 -0
- package/src/platforms/genesis/lib/sgdk/music/demo.xgc +0 -0
- package/src/platforms/genesis/lib/sgdk/music/demo.xgm +0 -0
- package/src/platforms/genesis/lib/sgdk/res/image/font_default.png +0 -0
- package/src/platforms/genesis/lib/sgdk/res/image/sgdk_logo.png +0 -0
- package/src/platforms/genesis/lib/sgdk/res/libres.h +10 -0
- package/src/platforms/genesis/lib/sgdk/res/libres.res +5 -0
- package/src/platforms/genesis/lib/sgdk/res/libres.s +166 -0
- package/src/platforms/genesis/lib/sgdk/res/sound/stop_xgm.bin +0 -0
- package/src/platforms/genesis/lib/sgdk/rom_header.c +33 -0
- package/src/platforms/genesis/lib/sgdk/sega.preprocessed.s +364 -0
- package/src/platforms/genesis/lib/sgdk/sega.s +365 -0
- package/src/platforms/genesis/lib/sgdk/src/bmp.c +1539 -0
- package/src/platforms/genesis/lib/sgdk/src/bmp_a.s +3477 -0
- package/src/platforms/genesis/lib/sgdk/src/boot/rom_header.c +33 -0
- package/src/platforms/genesis/lib/sgdk/src/boot/sega.s +365 -0
- package/src/platforms/genesis/lib/sgdk/src/dma.c +782 -0
- package/src/platforms/genesis/lib/sgdk/src/dma_a.s +23 -0
- package/src/platforms/genesis/lib/sgdk/src/error_a.s +376 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/console.c +490 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/everdrive.c +285 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/fat16.c +610 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/flash-save/README.md +112 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/flash-save/flash.c +300 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/flash-save/saveman.c +641 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/link_cable.c +1758 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/CHANGELOG.md +31 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/LICENSE.txt +17 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/README.md +18 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/data.z80 +148 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/define.z80 +173 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/doc/api-c.md +80 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/doc/format.md +132 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/doc/teradrive.md +33 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/fm.z80 +363 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/main.z80 +433 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/minimus.c +129 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/minimus_drv.s80 +17 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/psg.z80 +231 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/track.z80 +398 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/minimusic/util.z80 +98 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/16c550.c +84 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/README.md +849 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/comm.c +141 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/gamejolt.c +758 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/json.c +153 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/lsd.c +364 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/megawifi.c +1501 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/ssf_ed_pro.c +98 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/mw/ssf_ed_x7.c +67 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/serial/buffer.c +69 -0
- package/src/platforms/genesis/lib/sgdk/src/ext/serial/serial.c +158 -0
- package/src/platforms/genesis/lib/sgdk/src/joy.c +1361 -0
- package/src/platforms/genesis/lib/sgdk/src/kdebug.s +109 -0
- package/src/platforms/genesis/lib/sgdk/src/map.c +1915 -0
- package/src/platforms/genesis/lib/sgdk/src/mapper.c +280 -0
- package/src/platforms/genesis/lib/sgdk/src/maths.c +878 -0
- package/src/platforms/genesis/lib/sgdk/src/maths3D.c +480 -0
- package/src/platforms/genesis/lib/sgdk/src/maths3D_a.s +205 -0
- package/src/platforms/genesis/lib/sgdk/src/memory.c +760 -0
- package/src/platforms/genesis/lib/sgdk/src/memory_a.s +306 -0
- package/src/platforms/genesis/lib/sgdk/src/object.c +111 -0
- package/src/platforms/genesis/lib/sgdk/src/pal.c +484 -0
- package/src/platforms/genesis/lib/sgdk/src/pool.c +234 -0
- package/src/platforms/genesis/lib/sgdk/src/psg.c +82 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/drv_null.s80 +27 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/drv_xgm.s80 +3037 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/pcm/drv_dpcm2.s80 +984 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/pcm/drv_pcm.s80 +592 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/pcm/drv_pcm4.s80 +699 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/pcm/snd_dpcm2.c +172 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/pcm/snd_pcm.c +152 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/pcm/snd_pcm4.c +213 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/pcm/tab_vol.c +277 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/smp_null.s +22 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/smp_null_dpcm.s +15 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/sound.c +33 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm.c +683 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2.s80 +993 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_fct.i80 +611 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_mac.i80 +133 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_pcm_fct.i80 +114 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_pcm_mac.i80 +1444 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_psg_fct.i80 +491 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_psg_mac.i80 +43 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_ym_fct.i80 +1664 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2/drv_xgm2_ym_mac.i80 +295 -0
- package/src/platforms/genesis/lib/sgdk/src/snd/xgm2.c +1083 -0
- package/src/platforms/genesis/lib/sgdk/src/sprite_eng.c +2256 -0
- package/src/platforms/genesis/lib/sgdk/src/sprite_eng_legacy.c +2309 -0
- package/src/platforms/genesis/lib/sgdk/src/sram.c +30 -0
- package/src/platforms/genesis/lib/sgdk/src/sram_a.s +41 -0
- package/src/platforms/genesis/lib/sgdk/src/string.c +720 -0
- package/src/platforms/genesis/lib/sgdk/src/sys.c +1053 -0
- package/src/platforms/genesis/lib/sgdk/src/sys_a.s +74 -0
- package/src/platforms/genesis/lib/sgdk/src/tab_cnv.c +129 -0
- package/src/platforms/genesis/lib/sgdk/src/tab_log10.c +8201 -0
- package/src/platforms/genesis/lib/sgdk/src/tab_log2.c +8201 -0
- package/src/platforms/genesis/lib/sgdk/src/tab_sin.c +2058 -0
- package/src/platforms/genesis/lib/sgdk/src/tab_sqrt.c +8201 -0
- package/src/platforms/genesis/lib/sgdk/src/task.s +148 -0
- package/src/platforms/genesis/lib/sgdk/src/timer.c +201 -0
- package/src/platforms/genesis/lib/sgdk/src/tools.c +1299 -0
- package/src/platforms/genesis/lib/sgdk/src/tools_a.s +979 -0
- package/src/platforms/genesis/lib/sgdk/src/types.c +18 -0
- package/src/platforms/genesis/lib/sgdk/src/vdp.c +1060 -0
- package/src/platforms/genesis/lib/sgdk/src/vdp_bg.c +511 -0
- package/src/platforms/genesis/lib/sgdk/src/vdp_spr.c +322 -0
- package/src/platforms/genesis/lib/sgdk/src/vdp_tile.c +1011 -0
- package/src/platforms/genesis/lib/sgdk/src/vdp_tile_a.s +68 -0
- package/src/platforms/genesis/lib/sgdk/src/vram.c +273 -0
- package/src/platforms/genesis/lib/sgdk/src/ym2612.c +175 -0
- package/src/platforms/genesis/lib/sgdk/src/z80_ctrl.c +334 -0
- package/src/platforms/genesis/lib/sprite_table.s +129 -0
- package/src/platforms/genesis/lib/vblank_wait.s +73 -0
- package/src/platforms/genesis/lib/vdp_init.s +85 -0
- package/src/platforms/genesis/lib/wram.s +88 -0
- package/src/platforms/genesis/lib/z80_bootstrap.s +102 -0
- package/src/platforms/genesis/vdp.js +548 -0
- package/src/platforms/genesis/xgm2-pcm.js +165 -0
- package/src/platforms/gg/MENTAL_MODEL.md +174 -0
- package/src/platforms/gg/TROUBLESHOOTING.md +105 -0
- package/src/platforms/gg/UPSTREAM_SOURCES.md +36 -0
- package/src/platforms/gg/lib/c/gg_crt0.s +112 -0
- package/src/platforms/gg/lib/c/gg_hw.h +62 -0
- package/src/platforms/gg/lib/c/gg_music.c +155 -0
- package/src/platforms/gg/lib/c/gg_music.h +89 -0
- package/src/platforms/gg/lib/c/gg_sfx.c +82 -0
- package/src/platforms/gg/lib/c/gg_sfx.h +40 -0
- package/src/platforms/gg/lib/c/joypad_read.c +22 -0
- package/src/platforms/gg/lib/c/load_palette.c +20 -0
- package/src/platforms/gg/lib/c/load_tiles.c +32 -0
- package/src/platforms/gg/lib/c/sprite_table.c +60 -0
- package/src/platforms/gg/lib/c/vblank_wait.c +10 -0
- package/src/platforms/gg/lib/c/vdp_init.c +58 -0
- package/src/platforms/gg/song.js +189 -0
- package/src/platforms/index.js +7 -0
- package/src/platforms/lynx/MENTAL_MODEL.md +248 -0
- package/src/platforms/lynx/TROUBLESHOOTING.md +105 -0
- package/src/platforms/lynx/UPSTREAM_SOURCES.md +66 -0
- package/src/platforms/lynx/lib/c/lynx_music.c +63 -0
- package/src/platforms/lynx/lib/c/lynx_music.h +16 -0
- package/src/platforms/lynx/lib/c/lynx_sfx.c +147 -0
- package/src/platforms/lynx/lib/c/lynx_sfx.h +59 -0
- package/src/platforms/lynx/lib/cc65-src/bllhdr.s +18 -0
- package/src/platforms/lynx/lib/cc65-src/bootldr.s +195 -0
- package/src/platforms/lynx/lib/cc65-src/cgetc.s +69 -0
- package/src/platforms/lynx/lib/cc65-src/clock.s +87 -0
- package/src/platforms/lynx/lib/cc65-src/crt0.s +135 -0
- package/src/platforms/lynx/lib/cc65-src/defdir.s +29 -0
- package/src/platforms/lynx/lib/cc65-src/eeprom.s +255 -0
- package/src/platforms/lynx/lib/cc65-src/eeprom46.s +204 -0
- package/src/platforms/lynx/lib/cc65-src/eeprom66.s +227 -0
- package/src/platforms/lynx/lib/cc65-src/eeprom86.s +236 -0
- package/src/platforms/lynx/lib/cc65-src/exec.s +34 -0
- package/src/platforms/lynx/lib/cc65-src/exehdr.s +27 -0
- package/src/platforms/lynx/lib/cc65-src/extzp.inc +23 -0
- package/src/platforms/lynx/lib/cc65-src/extzp.s +30 -0
- package/src/platforms/lynx/lib/cc65-src/irq.s +45 -0
- package/src/platforms/lynx/lib/cc65-src/joy/lynx-stdjoy.s +93 -0
- package/src/platforms/lynx/lib/cc65-src/joy_stat_stddrv.s +14 -0
- package/src/platforms/lynx/lib/cc65-src/kbhit.s +56 -0
- package/src/platforms/lynx/lib/cc65-src/libref.s +9 -0
- package/src/platforms/lynx/lib/cc65-src/load.s +41 -0
- package/src/platforms/lynx/lib/cc65-src/lseek.s +58 -0
- package/src/platforms/lynx/lib/cc65-src/lynx-cart.s +98 -0
- package/src/platforms/lynx/lib/cc65-src/lynx-snd.s +1270 -0
- package/src/platforms/lynx/lib/cc65-src/mainargs.s +24 -0
- package/src/platforms/lynx/lib/cc65-src/open.s +136 -0
- package/src/platforms/lynx/lib/cc65-src/oserror.s +14 -0
- package/src/platforms/lynx/lib/cc65-src/read.s +44 -0
- package/src/platforms/lynx/lib/cc65-src/ser/lynx-comlynx.s +404 -0
- package/src/platforms/lynx/lib/cc65-src/ser_stat_stddrv.s +14 -0
- package/src/platforms/lynx/lib/cc65-src/sysuname.s +39 -0
- package/src/platforms/lynx/lib/cc65-src/tgi/lynx-160-102-16.s +1075 -0
- package/src/platforms/lynx/lib/cc65-src/tgi_colors.s +9 -0
- package/src/platforms/lynx/lib/cc65-src/tgi_irq.s +11 -0
- package/src/platforms/lynx/lib/cc65-src/tgi_stat_stddrv.s +14 -0
- package/src/platforms/lynx/lib/cc65-src/tgi_stddrv.s +13 -0
- package/src/platforms/lynx/lib/cc65-src/uploader.s +81 -0
- package/src/platforms/lynx/song.js +291 -0
- package/src/platforms/msx/MENTAL_MODEL.md +115 -0
- package/src/platforms/msx/TROUBLESHOOTING.md +62 -0
- package/src/platforms/msx/UPSTREAM_SOURCES.md +46 -0
- package/src/platforms/msx/image-to-tilemap.js +103 -0
- package/src/platforms/msx/lib/c/hello_msx.c +51 -0
- package/src/platforms/msx/lib/c/msx_crt0.s +74 -0
- package/src/platforms/msx/lib/c/msx_hw.h +92 -0
- package/src/platforms/msx/lib/c/msx_vdp.c +150 -0
- package/src/platforms/msx/tiles.js +99 -0
- package/src/platforms/msx/vdp.js +160 -0
- package/src/platforms/nes/MENTAL_MODEL.md +323 -0
- package/src/platforms/nes/TROUBLESHOOTING.md +319 -0
- package/src/platforms/nes/UPSTREAM_SOURCES.md +31 -0
- package/src/platforms/nes/image-to-chr.js +195 -0
- package/src/platforms/nes/image-to-tilemap.js +415 -0
- package/src/platforms/nes/lib/README.md +40 -0
- package/src/platforms/nes/lib/asm/LICENSE-FAMITONE +40 -0
- package/src/platforms/nes/lib/asm/chr_ram_header.s +32 -0
- package/src/platforms/nes/lib/asm/famitone2.s +1258 -0
- package/src/platforms/nes/lib/asm/famitone_bridge.s +50 -0
- package/src/platforms/nes/lib/asm/music_data.s +238 -0
- package/src/platforms/nes/lib/c/chr_ram_runtime_hello_sprite.c +81 -0
- package/src/platforms/nes/lib/c/chr_ram_runtime_hud_row.c +101 -0
- package/src/platforms/nes/lib/c/nes_runtime.c +347 -0
- package/src/platforms/nes/lib/c/nes_runtime.h +153 -0
- package/src/platforms/nes/lib/c/nmi_handler.c +51 -0
- package/src/platforms/nes/lib/c/nmi_trampoline.s +25 -0
- package/src/platforms/nes/lib/cc65-src/Makefile.inc +9 -0
- package/src/platforms/nes/lib/cc65-src/_scrsize.s +24 -0
- package/src/platforms/nes/lib/cc65-src/cclear.s +29 -0
- package/src/platforms/nes/lib/cc65-src/chline.s +31 -0
- package/src/platforms/nes/lib/cc65-src/clock.s +31 -0
- package/src/platforms/nes/lib/cc65-src/clrscr.s +72 -0
- package/src/platforms/nes/lib/cc65-src/color.s +68 -0
- package/src/platforms/nes/lib/cc65-src/cpeekc.s +37 -0
- package/src/platforms/nes/lib/cc65-src/cpeekcolor.s +8 -0
- package/src/platforms/nes/lib/cc65-src/cpeekrevers.s +37 -0
- package/src/platforms/nes/lib/cc65-src/cputc.s +95 -0
- package/src/platforms/nes/lib/cc65-src/crt0.s +180 -0
- package/src/platforms/nes/lib/cc65-src/cvline.s +31 -0
- package/src/platforms/nes/lib/cc65-src/get_tv.s +37 -0
- package/src/platforms/nes/lib/cc65-src/gotox.s +21 -0
- package/src/platforms/nes/lib/cc65-src/gotoxy.s +22 -0
- package/src/platforms/nes/lib/cc65-src/gotoy.s +22 -0
- package/src/platforms/nes/lib/cc65-src/irq.s +19 -0
- package/src/platforms/nes/lib/cc65-src/joy/nes-stdjoy.s +102 -0
- package/src/platforms/nes/lib/cc65-src/joy_stat_stddrv.s +14 -0
- package/src/platforms/nes/lib/cc65-src/libref.s +9 -0
- package/src/platforms/nes/lib/cc65-src/mainargs.s +24 -0
- package/src/platforms/nes/lib/cc65-src/neschar.s +4616 -0
- package/src/platforms/nes/lib/cc65-src/ppu.s +158 -0
- package/src/platforms/nes/lib/cc65-src/ppubuf.s +117 -0
- package/src/platforms/nes/lib/cc65-src/randomize.s +18 -0
- package/src/platforms/nes/lib/cc65-src/revers.s +27 -0
- package/src/platforms/nes/lib/cc65-src/setcursor.s +37 -0
- package/src/platforms/nes/lib/cc65-src/sysuname.s +39 -0
- package/src/platforms/nes/lib/cc65-src/tgi/nes-64-56-2.s +480 -0
- package/src/platforms/nes/lib/cc65-src/tgi_stat_stddrv.s +14 -0
- package/src/platforms/nes/lib/cc65-src/tgi_stddrv.s +13 -0
- package/src/platforms/nes/lib/cc65-src/waitvsync.s +18 -0
- package/src/platforms/nes/lib/cc65-src/wherex.s +19 -0
- package/src/platforms/nes/lib/cc65-src/wherey.s +19 -0
- package/src/platforms/nes/lib/clear_nametable.s +38 -0
- package/src/platforms/nes/lib/clear_oam.s +18 -0
- package/src/platforms/nes/lib/load_palette.s +31 -0
- package/src/platforms/nes/lib/nmi_safe.s +65 -0
- package/src/platforms/nes/lib/oam_dma.s +16 -0
- package/src/platforms/nes/lib/read_pad.s +46 -0
- package/src/platforms/nes/lib/reset.s +46 -0
- package/src/platforms/nes/lib/sprite_table_populate.s +75 -0
- package/src/platforms/nes/lib/wait_vblank.s +12 -0
- package/src/platforms/nes/palette.js +39 -0
- package/src/platforms/nes/ppu.js +448 -0
- package/src/platforms/pce/MENTAL_MODEL.md +98 -0
- package/src/platforms/pce/TROUBLESHOOTING.md +54 -0
- package/src/platforms/pce/UPSTREAM_SOURCES.md +38 -0
- package/src/platforms/pce/image-to-tilemap.js +123 -0
- package/src/platforms/pce/lib/c/hello_pce.c +37 -0
- package/src/platforms/pce/lib/c/pce_hw.h +130 -0
- package/src/platforms/pce/lib/c/pce_input.c +36 -0
- package/src/platforms/pce/lib/c/pce_sound.c +53 -0
- package/src/platforms/pce/lib/c/pce_video.c +113 -0
- package/src/platforms/pce/tiles.js +92 -0
- package/src/platforms/pce/vce.js +59 -0
- package/src/platforms/pce/vdc.js +52 -0
- package/src/platforms/sms/MENTAL_MODEL.md +286 -0
- package/src/platforms/sms/TROUBLESHOOTING.md +140 -0
- package/src/platforms/sms/UPSTREAM_SOURCES.md +29 -0
- package/src/platforms/sms/image-to-tilemap.js +260 -0
- package/src/platforms/sms/lib/README.md +117 -0
- package/src/platforms/sms/lib/c/joypad_read.c +33 -0
- package/src/platforms/sms/lib/c/load_palette.c +24 -0
- package/src/platforms/sms/lib/c/load_tiles.c +32 -0
- package/src/platforms/sms/lib/c/sms_crt0.s +101 -0
- package/src/platforms/sms/lib/c/sms_hw.h +53 -0
- package/src/platforms/sms/lib/c/sms_music.c +178 -0
- package/src/platforms/sms/lib/c/sms_music.h +50 -0
- package/src/platforms/sms/lib/c/sms_sfx.c +82 -0
- package/src/platforms/sms/lib/c/sms_sfx.h +40 -0
- package/src/platforms/sms/lib/c/sprite_table.c +60 -0
- package/src/platforms/sms/lib/c/vblank_wait.c +10 -0
- package/src/platforms/sms/lib/c/vdp_init.c +58 -0
- package/src/platforms/sms/lib/header.s +33 -0
- package/src/platforms/sms/lib/joypad_read.s +40 -0
- package/src/platforms/sms/lib/load_palette.s +30 -0
- package/src/platforms/sms/lib/load_tiles.s +50 -0
- package/src/platforms/sms/lib/sprite_table.s +44 -0
- package/src/platforms/sms/lib/vblank_wait.s +36 -0
- package/src/platforms/sms/lib/vdp_init.s +47 -0
- package/src/platforms/sms/song.js +217 -0
- package/src/platforms/sms/vdp.js +530 -0
- package/src/platforms/snes/MENTAL_MODEL.md +289 -0
- package/src/platforms/snes/TROUBLESHOOTING.md +208 -0
- package/src/platforms/snes/UPSTREAM_SOURCES.md +50 -0
- package/src/platforms/snes/brr.js +208 -0
- package/src/platforms/snes/image-to-tilemap.js +227 -0
- package/src/platforms/snes/lib/audio/apu_blob.asm +228 -0
- package/src/platforms/snes/lib/audio/apu_blob.bin +0 -0
- package/src/platforms/snes/lib/audio/explosion.brr +0 -0
- package/src/platforms/snes/lib/audio/sample_bank.bin +0 -0
- package/src/platforms/snes/lib/audio/shoot.brr +0 -0
- package/src/platforms/snes/lib/audio/spc_driver.asm +241 -0
- package/src/platforms/snes/lib/audio_pipeline.asm +62 -0
- package/src/platforms/snes/lib/c/crt0.asm +125 -0
- package/src/platforms/snes/lib/c/hdr.asm +50 -0
- package/src/platforms/snes/lib/c/snes_sfx.c +116 -0
- package/src/platforms/snes/lib/c/snes_sfx.h +96 -0
- package/src/platforms/snes/lib/c/snes_sfx_data.asm +25 -0
- package/src/platforms/snes/lib/cgram_upload.asm +43 -0
- package/src/platforms/snes/lib/lorom_header.asm +47 -0
- package/src/platforms/snes/lib/lorom_multibank.asm +66 -0
- package/src/platforms/snes/lib/nmi_safe.asm +77 -0
- package/src/platforms/snes/lib/oam_upload.asm +45 -0
- package/src/platforms/snes/lib/pad_read.asm +64 -0
- package/src/platforms/snes/lib/pvsneslib/LICENSE +21 -0
- package/src/platforms/snes/lib/pvsneslib/include/ctype.h +6 -0
- package/src/platforms/snes/lib/pvsneslib/include/float.h +4 -0
- package/src/platforms/snes/lib/pvsneslib/include/hdr.asm +47 -0
- package/src/platforms/snes/lib/pvsneslib/include/limits.h +13 -0
- package/src/platforms/snes/lib/pvsneslib/include/math.h +10 -0
- package/src/platforms/snes/lib/pvsneslib/include/setjmp.h +4 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/background.h +396 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/console.h +188 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/dma.h +381 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/input.h +289 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/interrupt.h +264 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/libversion.h +10 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/lzss.h +43 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/map.h +113 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/object.h +234 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/pixel.h +53 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/scores.h +66 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/snestypes.h +65 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/sound.h +245 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/sprite.h +456 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes/video.h +465 -0
- package/src/platforms/snes/lib/pvsneslib/include/snes.h +190 -0
- package/src/platforms/snes/lib/pvsneslib/include/stdarg.h +28 -0
- package/src/platforms/snes/lib/pvsneslib/include/stdbool.h +53 -0
- package/src/platforms/snes/lib/pvsneslib/include/stddef.h +27 -0
- package/src/platforms/snes/lib/pvsneslib/include/stdint.h +7 -0
- package/src/platforms/snes/lib/pvsneslib/include/stdio.h +9 -0
- package/src/platforms/snes/lib/pvsneslib/include/stdlib.h +13 -0
- package/src/platforms/snes/lib/pvsneslib/include/string.h +19 -0
- package/src/platforms/snes/lib/pvsneslib/include/strings.h +5 -0
- package/src/platforms/snes/lib/pvsneslib/source/Makefile +87 -0
- package/src/platforms/snes/lib/pvsneslib/source/backgrounds.asm +834 -0
- package/src/platforms/snes/lib/pvsneslib/source/consoles.asm +1028 -0
- package/src/platforms/snes/lib/pvsneslib/source/crt0_snes.asm +329 -0
- package/src/platforms/snes/lib/pvsneslib/source/dmas.asm +1275 -0
- package/src/platforms/snes/lib/pvsneslib/source/hdr.asm +56 -0
- package/src/platforms/snes/lib/pvsneslib/source/input.asm +445 -0
- package/src/platforms/snes/lib/pvsneslib/source/libc.asm +485 -0
- package/src/platforms/snes/lib/pvsneslib/source/libc_c.c +1214 -0
- package/src/platforms/snes/lib/pvsneslib/source/libm.asm +510 -0
- package/src/platforms/snes/lib/pvsneslib/source/libtcc.asm +374 -0
- package/src/platforms/snes/lib/pvsneslib/source/lzsss.asm +256 -0
- package/src/platforms/snes/lib/pvsneslib/source/maps.asm +1078 -0
- package/src/platforms/snes/lib/pvsneslib/source/objects.asm +2881 -0
- package/src/platforms/snes/lib/pvsneslib/source/scores.asm +226 -0
- package/src/platforms/snes/lib/pvsneslib/source/sm_spc.asm +187 -0
- package/src/platforms/snes/lib/pvsneslib/source/snesmodwla.asm +1186 -0
- package/src/platforms/snes/lib/pvsneslib/source/sounds.asm +273 -0
- package/src/platforms/snes/lib/pvsneslib/source/sprites.asm +3946 -0
- package/src/platforms/snes/lib/pvsneslib/source/vblank.asm +917 -0
- package/src/platforms/snes/lib/pvsneslib/source/videos.asm +1137 -0
- package/src/platforms/snes/lib/reset_init.asm +31 -0
- package/src/platforms/snes/lib/sprite_table_populate.asm +122 -0
- package/src/platforms/snes/lib/vram_dma_upload.asm +42 -0
- package/src/platforms/snes/ppu.js +606 -0
- package/src/platforms/snes/song.js +128 -0
- package/src/playtest/playtest.js +841 -0
- package/src/rom-id/identifier.js +421 -0
- package/src/rom-id/patch.js +217 -0
- package/src/toolchains/_worker/pool.js +253 -0
- package/src/toolchains/_worker/run.js +78 -0
- package/src/toolchains/_worker/wasm-worker.js +233 -0
- package/src/toolchains/arm-none-eabi-gcc/gcc.js +216 -0
- package/src/toolchains/asar/asar.js +542 -0
- package/src/toolchains/assemble-snippet.js +256 -0
- package/src/toolchains/cc65/cc65.js +395 -0
- package/src/toolchains/cc65/da65.js +119 -0
- package/src/toolchains/cc65/dbgparse.js +274 -0
- package/src/toolchains/cc65/preset-resolver.js +59 -0
- package/src/toolchains/cc65/presets/nes/chr-ram-runtime.cfg +79 -0
- package/src/toolchains/cc65/presets/nes/chr-ram-runtime.crt0.s +178 -0
- package/src/toolchains/cc65/presets/nes/chr-ram.cfg +76 -0
- package/src/toolchains/cc65/presets/nes/chr-ram.crt0.s +106 -0
- package/src/toolchains/common/ar.js +121 -0
- package/src/toolchains/common/reassemble.js +353 -0
- package/src/toolchains/common/sdk-cache.js +116 -0
- package/src/toolchains/common/symbols.js +139 -0
- package/src/toolchains/dasm/dasm.js +96 -0
- package/src/toolchains/gba-c/gba-c.js +838 -0
- package/src/toolchains/genesis-c/README.md +61 -0
- package/src/toolchains/genesis-c/genesis-c.js +600 -0
- package/src/toolchains/gnu-ld-map.js +86 -0
- package/src/toolchains/index.js +862 -0
- package/src/toolchains/m68k-elf-gcc/gcc.js +230 -0
- package/src/toolchains/objdump.js +199 -0
- package/src/toolchains/parse-errors.js +338 -0
- package/src/toolchains/registry.js +67 -0
- package/src/toolchains/rgbds/rgbds.js +144 -0
- package/src/toolchains/sdcc/preflight-lint.js +295 -0
- package/src/toolchains/sdcc/sdcc.js +540 -0
- package/src/toolchains/sjasm/sjasm.js +85 -0
- package/src/toolchains/snes-c/snes-c.js +409 -0
- package/src/toolchains/tcc816/tcc816.js +79 -0
- package/src/toolchains/vasm68k/vasm68k.js +138 -0
- package/src/toolchains/wladx/wladx.js +120 -0
- package/src/toolchains/z80/binutils.js +82 -0
|
@@ -0,0 +1,1036 @@
|
|
|
1
|
+
// `watchMemory` — run the emulator forward and report every frame that changed
|
|
2
|
+
// a watched byte range. Cross-platform (no core patches): polls the region
|
|
3
|
+
// before/after each frame, diffs the result, records (frame, offset, before,
|
|
4
|
+
// after, PC).
|
|
5
|
+
//
|
|
6
|
+
// `runUntilWrite` — narrower: step until target address is written, then stop.
|
|
7
|
+
// Returns the same shape minus the full timeline.
|
|
8
|
+
//
|
|
9
|
+
// Granularity: this is frame-level, not instruction-level. If a single frame
|
|
10
|
+
// writes to the same address ten times, we only see the LAST value. For most
|
|
11
|
+
// ROM-hacking workflows this is enough — you usually just want "what code is
|
|
12
|
+
// touching this byte and what does the screen look like after," not a complete
|
|
13
|
+
// CPU trace. Instruction-level tracing would need core-side breakpoint hooks.
|
|
14
|
+
|
|
15
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { getHost } from "../state.js";
|
|
18
|
+
import { jsonContent, safeTool } from "../util.js";
|
|
19
|
+
import { getCPUState } from "../../host/cpu-state.js";
|
|
20
|
+
import { MemoryRegionToRetro } from "../../host/types.js";
|
|
21
|
+
import { resolveButtonAlias } from "./input.js";
|
|
22
|
+
import { getCPUStateCore } from "./platform-tools.js";
|
|
23
|
+
import { traceVramSourceCore } from "./trace-vram-source.js";
|
|
24
|
+
|
|
25
|
+
// Let a human watching /livestream (or a playtest window) SEE what a
|
|
26
|
+
// breakpoint/watch tool just did — the frozen breakpoint frame, the state when a
|
|
27
|
+
// write was caught — even though the AGENT gets only a small JSON result.
|
|
28
|
+
//
|
|
29
|
+
// CRITICAL: this must NOT slow the agent down. The PNG encode is the expensive
|
|
30
|
+
// part, so we do NOT encode here on the tool's critical path. Instead we attach a
|
|
31
|
+
// `_observerFrameProvider` thunk (just captures the host ref — free) and the
|
|
32
|
+
// observer wrapper encodes it ASYNCHRONOUSLY, after the agent's response has
|
|
33
|
+
// already gone out. The provider is stripped from the agent-visible result. The
|
|
34
|
+
// frame is captured by reference now (correct frozen state) but rasterized later.
|
|
35
|
+
function attachObserverFrame(json, host) {
|
|
36
|
+
json._observerFrameProvider = () => {
|
|
37
|
+
try {
|
|
38
|
+
const shot = host.screenshot(); // { pngBase64, width, height }
|
|
39
|
+
return shot && shot.pngBase64
|
|
40
|
+
? { kind: "image", mimeType: "image/png", base64: shot.pngBase64 }
|
|
41
|
+
: null;
|
|
42
|
+
} catch { return null; }
|
|
43
|
+
};
|
|
44
|
+
return json;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Drive scheduled `pressDuring` input through the host's ONLY input API
|
|
48
|
+
// (setInput) — the watch loop owns stepFrames, so this must never advance the
|
|
49
|
+
// emulator itself. Returns a stateful driver: call applyForFrame(i) at the top
|
|
50
|
+
// of each watched frame (before stepFrames) to set the held-button state, and
|
|
51
|
+
// finish() once at the end to release everything. `presses` is the sorted
|
|
52
|
+
// schedule; each press holds from its `frame` for `holdFrames` frames.
|
|
53
|
+
// frame({op:'stepInstruction'}) — execute exactly ONE CPU instruction and stop.
|
|
54
|
+
// Exported so the `frame` router (frame.js) can call it; takes sessionKey.
|
|
55
|
+
export async function stepInstructionCore(sessionKey) {
|
|
56
|
+
const host = getHost(sessionKey);
|
|
57
|
+
if (!host.pcBreakSupported || !host.pcBreakSupported()) {
|
|
58
|
+
return jsonContent({
|
|
59
|
+
stepped: false, notSupported: true,
|
|
60
|
+
note: "This core build has no single-step (shipped on all 14 platforms as of 0.5.0 — update the core package if you see this).",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const r = host.stepInstruction();
|
|
64
|
+
return attachObserverFrame(jsonContent({
|
|
65
|
+
stepped: true,
|
|
66
|
+
pc: r.pc != null ? "$" + r.pc.toString(16).toUpperCase() : null,
|
|
67
|
+
pcRaw: r.pc,
|
|
68
|
+
note: "CPU is frozen one instruction later. cpu({op:'read'}) to read registers; frame({op:'stepInstruction'}) again to keep stepping.",
|
|
69
|
+
}), host);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function makePressDriver(host, presses) {
|
|
73
|
+
let applied = 0; // how many scheduled presses actually got a frame
|
|
74
|
+
let lastSet = null; // last setInput payload we pushed (to avoid churn)
|
|
75
|
+
const platform = host.status?.platform;
|
|
76
|
+
return {
|
|
77
|
+
applied: () => applied,
|
|
78
|
+
applyForFrame(i) {
|
|
79
|
+
// Buttons whose [frame, frame+holdFrames) window covers frame i.
|
|
80
|
+
const held = presses.filter((p) => i >= p.frame && i < p.frame + (p.holdFrames ?? 2));
|
|
81
|
+
// Build a 2-port setInput payload from the held buttons.
|
|
82
|
+
const ports = [{}, {}];
|
|
83
|
+
for (const p of held) {
|
|
84
|
+
const resolved = resolveButtonAlias(p.button, platform);
|
|
85
|
+
ports[p.port ?? 0][resolved] = true;
|
|
86
|
+
}
|
|
87
|
+
const key = JSON.stringify(ports);
|
|
88
|
+
if (key !== lastSet) { host.setInput({ ports }); lastSet = key; }
|
|
89
|
+
// Count each scheduled press once, on the first frame it's actually held.
|
|
90
|
+
for (const p of held) { if (p.frame === i) applied++; }
|
|
91
|
+
},
|
|
92
|
+
finish() {
|
|
93
|
+
if (lastSet !== null && lastSet !== "[{},{}]") host.setInput({ ports: [{}, {}] });
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Single source of truth: the same canonical region vocabulary readMemory
|
|
99
|
+
// uses (host/types.js). Previously this was a hand-maintained list that had
|
|
100
|
+
// drifted — it carried DEAD Genesis `md_*` names (which throw on read) and
|
|
101
|
+
// was MISSING nes_apu_regs / genesis_* / c64_*, so you couldn't watch the
|
|
102
|
+
// hardware-register regions readMemory could already read. Deriving from the
|
|
103
|
+
// host map means new regions flow through automatically and the two tools can
|
|
104
|
+
// never disagree again.
|
|
105
|
+
const MEMORY_REGIONS = /** @type {[string, ...string[]]} */ (Object.keys(MemoryRegionToRetro));
|
|
106
|
+
|
|
107
|
+
function tryGetPC(host) {
|
|
108
|
+
try {
|
|
109
|
+
const platform = host.status?.platform;
|
|
110
|
+
if (!platform) return null;
|
|
111
|
+
const cpu = getCPUState(host, platform);
|
|
112
|
+
if (cpu && typeof cpu.pc === "number") return cpu.pc;
|
|
113
|
+
return null;
|
|
114
|
+
} catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function hexPC(pc) {
|
|
120
|
+
if (pc == null) return null;
|
|
121
|
+
return "$" + pc.toString(16).toUpperCase().padStart(4, "0");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function snap(host, region, offset, length) {
|
|
125
|
+
return Array.from(host.readMemory(region, offset, length));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function diffSnapshots(before, after, baseOffset, label) {
|
|
129
|
+
const changes = [];
|
|
130
|
+
for (let i = 0; i < before.length; i++) {
|
|
131
|
+
if (before[i] !== after[i]) {
|
|
132
|
+
changes.push({
|
|
133
|
+
...(label ? { label } : {}),
|
|
134
|
+
offset: baseOffset + i,
|
|
135
|
+
offsetHex: "0x" + (baseOffset + i).toString(16).toUpperCase().padStart(4, "0"),
|
|
136
|
+
before: before[i],
|
|
137
|
+
after: after[i],
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return changes;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Edge classifier — a single byte's transition relative to its previous value.
|
|
145
|
+
// "reset" is the canonical music-driver signal: a countdown counter that
|
|
146
|
+
// reloads (jumps UP) marks a note onset. Filtering to resets turns a 7000-event
|
|
147
|
+
// decrement stream into the ~few-hundred-event note list directly.
|
|
148
|
+
function edgeMatches(onChange, before, after) {
|
|
149
|
+
switch (onChange) {
|
|
150
|
+
case "increase": return after > before;
|
|
151
|
+
case "decrease": return after < before;
|
|
152
|
+
case "reset": return after > before; // counter reload = jump up
|
|
153
|
+
case "any":
|
|
154
|
+
default: return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function valueMatches(valueFilter, after) {
|
|
159
|
+
if (!valueFilter) return true;
|
|
160
|
+
if (valueFilter.min != null && after < valueFilter.min) return false;
|
|
161
|
+
if (valueFilter.max != null && after > valueFilter.max) return false;
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Downsample an array to at most `n` evenly-spaced elements, ALWAYS keeping the
|
|
166
|
+
// first and last (so a value-vs-frame curve still spans the whole window). For
|
|
167
|
+
// n>=length returns the array unchanged; for n<=1 returns just the last point.
|
|
168
|
+
function downsample(arr, n) {
|
|
169
|
+
const len = arr.length;
|
|
170
|
+
if (len <= n) return arr;
|
|
171
|
+
if (n <= 1) return [arr[len - 1]];
|
|
172
|
+
const out = [];
|
|
173
|
+
const step = (len - 1) / (n - 1);
|
|
174
|
+
for (let i = 0; i < n; i++) out.push(arr[Math.round(i * step)]);
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function registerWatchMemoryTools(server, z, sessionKey) {
|
|
179
|
+
const rangeShape = z.object({
|
|
180
|
+
region: z.enum(MEMORY_REGIONS),
|
|
181
|
+
offset: z.number().int().min(0),
|
|
182
|
+
length: z.number().int().min(1).max(4096).default(1),
|
|
183
|
+
label: z.string().optional().describe("Name echoed on every event from this range — tells disjoint ranges apart in one stream."),
|
|
184
|
+
// Per-range overrides of the call-wide filters. The whole point: in a
|
|
185
|
+
// multi-range watch, keep EVERY transition of a slow state byte while
|
|
186
|
+
// sampling/suppressing a fast free-running counter in the SAME pass.
|
|
187
|
+
onChange: z.enum(["any", "increase", "decrease", "reset"]).optional().describe("Per-range edge filter; overrides the call-wide `onChange` for THIS range only."),
|
|
188
|
+
sampleEvery: z.number().int().min(1).optional().describe("Per-range downsample: keep every Nth change from THIS range (e.g. 8 to thin a noisy counter while other ranges stay full)."),
|
|
189
|
+
valueFilter: z.object({ min: z.number().int().min(0).max(255).optional(), max: z.number().int().min(0).max(255).optional() }).optional().describe("Per-range value window; overrides the call-wide `valueFilter` for THIS range."),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// watch({on:mem|range|pc}) LOG-ALL. on:mem=watchMem (the power tool below),
|
|
193
|
+
// on:range=wRange, on:pc=wLogPC.
|
|
194
|
+
async function watchMem({ region, offset = 0, length = 1, ranges, frames = 600, stopOnFirst = false, onChange = "any", valueFilter, maxEvents = 256, format = "events", sampleEvery = 1, groupByPC = false, outputPath, pressDuring, cheatLabels }) {
|
|
195
|
+
const host = getHost(sessionKey);
|
|
196
|
+
|
|
197
|
+
// Normalize to a list of ranges. Single-range mode requires `region`.
|
|
198
|
+
const watchRanges = (ranges && ranges.length)
|
|
199
|
+
? ranges.map((r) => ({ length: 1, ...r }))
|
|
200
|
+
: (() => {
|
|
201
|
+
if (!region) throw new Error("watchMemory: pass `region` (single-range) or `ranges` (multi-range).");
|
|
202
|
+
return [{ region, offset, length }];
|
|
203
|
+
})();
|
|
204
|
+
|
|
205
|
+
// Optional: auto-label watched RAM addresses from the cheat DB. Builds an
|
|
206
|
+
// address→desc map from the matched game's RAM cheats and fills in `label`
|
|
207
|
+
// for any range whose CPU address lines up (system_ram offset == address)
|
|
208
|
+
// and that the caller didn't already label. Free semantic names; PROBABLE
|
|
209
|
+
// match (see gameCheats) — labels are strong hints, not gospel.
|
|
210
|
+
let cheatLabelInfo;
|
|
211
|
+
if (cheatLabels) {
|
|
212
|
+
try {
|
|
213
|
+
const idMod = await import("../../rom-id/identifier.js");
|
|
214
|
+
const { lookupCheats } = await import("../../cheats/lookup.js");
|
|
215
|
+
const id = await idMod.identifyFile(cheatLabels).catch(() => null);
|
|
216
|
+
const res = await lookupCheats({ platform: id?.platform, fileName: path.basename(cheatLabels), romName: id?.title || undefined });
|
|
217
|
+
if (res.matched) {
|
|
218
|
+
const addrToDesc = new Map();
|
|
219
|
+
for (const e of res.entries) {
|
|
220
|
+
for (const p of (e.parts || [])) {
|
|
221
|
+
if (p && p.kind === "ram" && !addrToDesc.has(p.address)) addrToDesc.set(p.address, e.desc);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
for (const r of watchRanges) {
|
|
225
|
+
if (r.label) continue;
|
|
226
|
+
// Only RAM-class regions where offset maps 1:1 to CPU address.
|
|
227
|
+
if (!/(^system_ram$|_ram$|_wram$|^gb_hram$)/.test(r.region)) continue;
|
|
228
|
+
const desc = addrToDesc.get(r.offset);
|
|
229
|
+
if (desc) r.label = desc;
|
|
230
|
+
}
|
|
231
|
+
cheatLabelInfo = { matched: true, game: res.game, confidence: res.confidence, labeled: watchRanges.filter((r) => r.label).length };
|
|
232
|
+
} else {
|
|
233
|
+
cheatLabelInfo = { matched: false };
|
|
234
|
+
}
|
|
235
|
+
} catch { cheatLabelInfo = { matched: false }; }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
239
|
+
const pressDriver = makePressDriver(host, presses);
|
|
240
|
+
const startFrame = host.status.frameCount;
|
|
241
|
+
|
|
242
|
+
// Per-range previous snapshots.
|
|
243
|
+
let prevs = watchRanges.map((r) => snap(host, r.region, r.offset, r.length));
|
|
244
|
+
const rangeSample = new Array(watchRanges.length).fill(0); // per-range sampleEvery counters
|
|
245
|
+
|
|
246
|
+
const preview = []; // bounded inline events
|
|
247
|
+
let totalMatched = 0; // ALL filter-passing events (file-backed)
|
|
248
|
+
let sampleCounter = 0; // for sampleEvery: keep every Nth match
|
|
249
|
+
let truncated = false; // inline preview hit maxEvents
|
|
250
|
+
let stoppedEarly = false;
|
|
251
|
+
const fileLines = []; // NDJSON lines when outputPath set
|
|
252
|
+
// groupByPC accumulator: pc -> {hits, firstFrame, lastFrame, offsets:Set}.
|
|
253
|
+
// Collapses "which instructions touched this byte" — the canonical
|
|
254
|
+
// "find the hot-path writer" question — into one row per PC regardless of
|
|
255
|
+
// how many thousands of times each fired.
|
|
256
|
+
const byPc = groupByPC ? new Map() : null;
|
|
257
|
+
// format:"series" accumulator: offsetHex -> {offset, offsetHex, label,
|
|
258
|
+
// region, frames:[], values:[]}. The compact value-vs-frame curve, with
|
|
259
|
+
// the repeated boilerplate hoisted into the per-offset header (set once).
|
|
260
|
+
const seriesMap = format === "series" ? new Map() : null;
|
|
261
|
+
|
|
262
|
+
const pushEvent = (ev) => {
|
|
263
|
+
totalMatched++;
|
|
264
|
+
// sampleEvery: keep only every Nth filter-passing change (1 = all).
|
|
265
|
+
if (sampleEvery > 1) {
|
|
266
|
+
const keep = (sampleCounter % sampleEvery) === 0;
|
|
267
|
+
sampleCounter++;
|
|
268
|
+
if (!keep) return;
|
|
269
|
+
}
|
|
270
|
+
if (seriesMap) {
|
|
271
|
+
const key = ev.offsetHex ?? String(ev.offset);
|
|
272
|
+
let s = seriesMap.get(key);
|
|
273
|
+
if (!s) {
|
|
274
|
+
s = { offset: ev.offset, offsetHex: ev.offsetHex, region: ev.region, frames: [], values: [] };
|
|
275
|
+
if (ev.label != null) s.label = ev.label;
|
|
276
|
+
seriesMap.set(key, s);
|
|
277
|
+
}
|
|
278
|
+
s.frames.push(ev.frame);
|
|
279
|
+
s.values.push(ev.after);
|
|
280
|
+
}
|
|
281
|
+
if (byPc) {
|
|
282
|
+
const key = ev.pc ?? "(unknown)";
|
|
283
|
+
let g = byPc.get(key);
|
|
284
|
+
if (!g) { g = { pc: key, hits: 0, firstFrame: ev.frame, lastFrame: ev.frame, offsets: new Set() }; byPc.set(key, g); }
|
|
285
|
+
g.hits++;
|
|
286
|
+
g.lastFrame = ev.frame;
|
|
287
|
+
g.offsets.add(ev.offsetHex ?? ev.offset);
|
|
288
|
+
}
|
|
289
|
+
if (outputPath) fileLines.push(JSON.stringify(ev));
|
|
290
|
+
// When grouping, the per-event preview is redundant with the summary —
|
|
291
|
+
// keep only a tiny sample for context (the byPC[] rows are the answer;
|
|
292
|
+
// a 30-event watch shouldn't dump ~360 lines of raw events too).
|
|
293
|
+
const cap = byPc ? Math.min(maxEvents, 8) : maxEvents;
|
|
294
|
+
if (preview.length < cap) preview.push(ev);
|
|
295
|
+
else { truncated = true; }
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
outer:
|
|
299
|
+
for (let i = 0; i < frames; i++) {
|
|
300
|
+
// Set held-button state for this frame BEFORE stepping (the loop owns
|
|
301
|
+
// stepFrames; the driver only calls setInput).
|
|
302
|
+
pressDriver.applyForFrame(i);
|
|
303
|
+
host.stepFrames(1);
|
|
304
|
+
const frameAbs = startFrame + i + 1;
|
|
305
|
+
let pcCached;
|
|
306
|
+
const pcOnce = () => (pcCached !== undefined ? pcCached : (pcCached = tryGetPC(host)));
|
|
307
|
+
|
|
308
|
+
for (let ri = 0; ri < watchRanges.length; ri++) {
|
|
309
|
+
const r = watchRanges[ri];
|
|
310
|
+
const cur = snap(host, r.region, r.offset, r.length);
|
|
311
|
+
const changes = diffSnapshots(prevs[ri], cur, r.offset, r.label);
|
|
312
|
+
prevs[ri] = cur;
|
|
313
|
+
// Per-range filter overrides fall back to the call-wide values.
|
|
314
|
+
const rOnChange = r.onChange ?? onChange;
|
|
315
|
+
const rValueFilter = r.valueFilter ?? valueFilter;
|
|
316
|
+
const rSampleEvery = r.sampleEvery ?? 1;
|
|
317
|
+
for (const c of changes) {
|
|
318
|
+
if (!edgeMatches(rOnChange, c.before, c.after)) continue;
|
|
319
|
+
if (!valueMatches(rValueFilter, c.after)) continue;
|
|
320
|
+
// Per-range downsample (independent of the call-wide sampleEvery,
|
|
321
|
+
// which still applies globally inside pushEvent).
|
|
322
|
+
if (rSampleEvery > 1) {
|
|
323
|
+
rangeSample[ri] = (rangeSample[ri] ?? 0) + 1;
|
|
324
|
+
if ((rangeSample[ri] - 1) % rSampleEvery !== 0) continue;
|
|
325
|
+
}
|
|
326
|
+
const pc = pcOnce();
|
|
327
|
+
pushEvent({
|
|
328
|
+
frame: frameAbs,
|
|
329
|
+
frameRelative: i + 1,
|
|
330
|
+
region: r.region,
|
|
331
|
+
...c,
|
|
332
|
+
pc: hexPC(pc),
|
|
333
|
+
pcRaw: pc,
|
|
334
|
+
});
|
|
335
|
+
if (stopOnFirst) { stoppedEarly = true; break outer; }
|
|
336
|
+
// Without a file, once the inline preview is full there's no point
|
|
337
|
+
// continuing — EXCEPT when grouping (byPC[] needs every event) or in
|
|
338
|
+
// series mode (the curve needs every point before its own downsample).
|
|
339
|
+
if (!outputPath && !byPc && !seriesMap && truncated) break outer;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
pressDriver.finish(); // release any still-held buttons
|
|
344
|
+
|
|
345
|
+
// Build the grouped-by-PC summary (sorted by hit count, descending).
|
|
346
|
+
const byPCSummary = byPc
|
|
347
|
+
? Array.from(byPc.values())
|
|
348
|
+
.sort((a, b) => b.hits - a.hits)
|
|
349
|
+
.map((g) => ({ pc: g.pc, hits: g.hits, firstFrame: g.firstFrame, lastFrame: g.lastFrame, offsets: Array.from(g.offsets) }))
|
|
350
|
+
: undefined;
|
|
351
|
+
|
|
352
|
+
const base = {
|
|
353
|
+
framesStepped: stoppedEarly ? undefined : frames,
|
|
354
|
+
watched: watchRanges,
|
|
355
|
+
onChange,
|
|
356
|
+
valueFilter: valueFilter ?? null,
|
|
357
|
+
eventCount: totalMatched,
|
|
358
|
+
...(byPCSummary ? { byPC: byPCSummary, distinctPCs: byPCSummary.length } : {}),
|
|
359
|
+
// When the caller scheduled input, ALWAYS report what landed — so a
|
|
360
|
+
// press that never registered is visible, not a silent eventCount:0.
|
|
361
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
362
|
+
...(cheatLabelInfo ? { cheatLabels: cheatLabelInfo } : {}),
|
|
363
|
+
stoppedEarly,
|
|
364
|
+
truncated,
|
|
365
|
+
note: totalMatched === 0
|
|
366
|
+
? "No matching changes in the watched window. Try (a) onChange:'any' to confirm the byte moves at all, (b) longer `frames`, (c) `pressDuring` to drive the game past the event, (d) a different region/offset. If the byte never moves even with onChange:'any', this region may be REBUILT as a block (sprite/OAM shadow, display list, VRAM) rather than written in place — watch the SOURCE struct the copy/DMA reads from instead (find it with searchValue)."
|
|
367
|
+
: (tryGetPC(host) == null ? "PC not available for this platform (getCPUState returned no pc field)." : undefined),
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
if (outputPath) {
|
|
371
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
372
|
+
await writeFile(outputPath, fileLines.length ? fileLines.join("\n") + "\n" : "");
|
|
373
|
+
return jsonContent({
|
|
374
|
+
...base,
|
|
375
|
+
path: outputPath,
|
|
376
|
+
format: "ndjson",
|
|
377
|
+
previewCount: preview.length,
|
|
378
|
+
preview,
|
|
379
|
+
previewNote: truncated
|
|
380
|
+
? `Inline preview capped at ${maxEvents} of ${totalMatched} events; the COMPLETE log is in the file.`
|
|
381
|
+
: "All events fit inline AND are in the file.",
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// format:"series" — compact columnar value-vs-frame curve per offset.
|
|
386
|
+
// maxEvents caps SAMPLES PER OFFSET by DOWNSAMPLING (evenly-spaced subset
|
|
387
|
+
// that always keeps the first and last point) rather than truncating, so
|
|
388
|
+
// the curve spans the whole window in one call.
|
|
389
|
+
if (seriesMap) {
|
|
390
|
+
let anyDownsampled = false;
|
|
391
|
+
const series = Array.from(seriesMap.values()).map((s) => {
|
|
392
|
+
const total = s.frames.length;
|
|
393
|
+
let { frames: fr, values: va } = s;
|
|
394
|
+
if (total > maxEvents) {
|
|
395
|
+
anyDownsampled = true;
|
|
396
|
+
fr = downsample(fr, maxEvents);
|
|
397
|
+
va = downsample(va, maxEvents);
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
offset: s.offset, offsetHex: s.offsetHex, region: s.region,
|
|
401
|
+
...(s.label != null ? { label: s.label } : {}),
|
|
402
|
+
points: fr.length, totalChanges: total,
|
|
403
|
+
...(total > maxEvents ? { downsampledFrom: total } : {}),
|
|
404
|
+
frames: fr, values: va,
|
|
405
|
+
};
|
|
406
|
+
});
|
|
407
|
+
return jsonContent({
|
|
408
|
+
...base,
|
|
409
|
+
format: "series",
|
|
410
|
+
...(sampleEvery > 1 ? { sampleEvery } : {}),
|
|
411
|
+
series,
|
|
412
|
+
...(anyDownsampled
|
|
413
|
+
? { seriesNote: `One or more offsets had >maxEvents (${maxEvents}) changes and were DOWNSAMPLED to an evenly-spaced subset spanning the full window (first+last kept). Raise maxEvents or lower sampleEvery for more resolution; use outputPath for every raw delta.` }
|
|
414
|
+
: {}),
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return jsonContent({ ...base, events: preview, ...(sampleEvery > 1 ? { sampleEvery } : {}) });
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// breakpoint({on:write|read|pc}) STOP-on-first. on:write precision:exact=bpFindWriter
|
|
422
|
+
// (core watchpoint, true PC under IRQ), precision:sampled=bpRunUntilWrite (frame PC).
|
|
423
|
+
async function bpFindWriter({ address, maxFrames = 600, pressDuring }) {
|
|
424
|
+
const host = getHost(sessionKey);
|
|
425
|
+
if (!host.watchpointSupported || !host.watchpointSupported()) {
|
|
426
|
+
return jsonContent({
|
|
427
|
+
found: false, notSupported: true, address: "$" + address.toString(16).toUpperCase(),
|
|
428
|
+
note: "This core build has no instruction-level write watchpoint (shipped on all 14 platforms — update the core package if you see this; only PC Engine lacked it before 0.6.0). " +
|
|
429
|
+
"Use watchMemory/runUntilWrite here — their pc is frame-sampled, so cross-check the value trace.",
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
host.setWatchpoint(address, true);
|
|
433
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
434
|
+
const pressDriver = makePressDriver(host, presses);
|
|
435
|
+
let result = null;
|
|
436
|
+
for (let i = 0; i < maxFrames; i++) {
|
|
437
|
+
pressDriver.applyForFrame(i);
|
|
438
|
+
host.stepFrames(1);
|
|
439
|
+
const w = host.getWatchpoint();
|
|
440
|
+
if (w.hits > 0) { result = { ...w, framesStepped: i + 1 }; break; }
|
|
441
|
+
}
|
|
442
|
+
pressDriver.finish();
|
|
443
|
+
host.setWatchpoint(address, false); // disarm
|
|
444
|
+
if (!result) {
|
|
445
|
+
return jsonContent({
|
|
446
|
+
found: false, address: "$" + address.toString(16).toUpperCase(), framesStepped: maxFrames,
|
|
447
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
448
|
+
note: "No per-byte CPU write to that address within maxFrames. Two common reasons: " +
|
|
449
|
+
"(1) the event didn't fire — increase maxFrames or drive the game with pressDuring to trigger it. " +
|
|
450
|
+
"(2) this region is rebuilt as a BLOCK rather than written field-by-field — sprite/OAM shadow tables, " +
|
|
451
|
+
"display lists, and VRAM are typically bulk-copied (memcpy/loop) or DMA'd from a SOURCE struct elsewhere, " +
|
|
452
|
+
"so no single instruction writes this exact byte. In that case the address you want is the SOURCE: watch " +
|
|
453
|
+
"the struct the copy reads from (find it with searchValue on the live value), or for graphics trace the " +
|
|
454
|
+
"DMA/copy source (Genesis VRAM DMA source is in VDP regs). 'Address is wrong' is usually case (2), not a bad address.",
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
// When the core reports a PRG-ROM offset for the PC (fceumm/NES), it
|
|
458
|
+
// disambiguates the BANK — turn it into the iNES bank index + the prg.bin
|
|
459
|
+
// offset so disassembleRom can target the exact bank, no $FF-padding from
|
|
460
|
+
// the wrong (fixed) bank on a banked mapper.
|
|
461
|
+
const prgOffset = result.prgOffset;
|
|
462
|
+
const bankInfo = (prgOffset != null)
|
|
463
|
+
? { prgOffset: "0x" + prgOffset.toString(16).toUpperCase(), bank: Math.floor(prgOffset / 0x4000) }
|
|
464
|
+
: null;
|
|
465
|
+
return attachObserverFrame(jsonContent({
|
|
466
|
+
found: true,
|
|
467
|
+
address: "$" + address.toString(16).toUpperCase(),
|
|
468
|
+
pc: result.lastPC != null ? "$" + result.lastPC.toString(16).toUpperCase() : null,
|
|
469
|
+
pcRaw: result.lastPC,
|
|
470
|
+
value: "0x" + result.lastValue.toString(16).toUpperCase().padStart(2, "0"),
|
|
471
|
+
hits: result.hits,
|
|
472
|
+
framesStepped: result.framesStepped,
|
|
473
|
+
...(bankInfo ? bankInfo : {}),
|
|
474
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
475
|
+
note: "pc is the EXACT writing instruction (captured in the CPU write path), not a frame sample. " +
|
|
476
|
+
(bankInfo
|
|
477
|
+
? `pc is in PRG bank ${bankInfo.bank} (prg offset ${bankInfo.prgOffset}) — disassembleRom({ startAddress: ${result.lastPC != null ? "0x" + result.lastPC.toString(16) : "pc"}, bank: ${bankInfo.bank} }) targets the exact bank (no fixed-bank $FF padding).`
|
|
478
|
+
: `disassembleRom({ startAddress: ${result.lastPC != null ? "0x" + result.lastPC.toString(16) : "pc"} }) to see it. On a banked mapper a $8000-$BFFF pc may be in a switchable bank — pass the right \`bank\`.`),
|
|
479
|
+
}), host);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async function bpRunUntilWrite({ region, offset, length = 1, maxFrames = 600, pressDuring }) {
|
|
483
|
+
const host = getHost(sessionKey);
|
|
484
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
485
|
+
const pressDriver = makePressDriver(host, presses);
|
|
486
|
+
let prev = snap(host, region, offset, length);
|
|
487
|
+
const startFrame = host.status.frameCount;
|
|
488
|
+
|
|
489
|
+
for (let i = 0; i < maxFrames; i++) {
|
|
490
|
+
// Hold scheduled input via setInput before stepping (loop owns stepFrames).
|
|
491
|
+
pressDriver.applyForFrame(i);
|
|
492
|
+
host.stepFrames(1);
|
|
493
|
+
const cur = snap(host, region, offset, length);
|
|
494
|
+
const changes = diffSnapshots(prev, cur, offset);
|
|
495
|
+
if (changes.length > 0) {
|
|
496
|
+
const pc = tryGetPC(host);
|
|
497
|
+
const frameAbs = startFrame + i + 1;
|
|
498
|
+
pressDriver.finish();
|
|
499
|
+
return attachObserverFrame(jsonContent({
|
|
500
|
+
written: true,
|
|
501
|
+
frame: frameAbs,
|
|
502
|
+
frameRelative: i + 1,
|
|
503
|
+
changes,
|
|
504
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
505
|
+
pc: hexPC(pc),
|
|
506
|
+
pcRaw: pc,
|
|
507
|
+
// NOTE: this PC is sampled at the frame boundary AFTER the write, not
|
|
508
|
+
// captured at the writing instruction. For NMI/IRQ-driven writes
|
|
509
|
+
// (the common case on NES/GB) it is usually the interrupted
|
|
510
|
+
// main-thread PC (often an idle loop), NOT the writer. Treat it as a
|
|
511
|
+
// lead, and confirm against the value trace / a manual disasm.
|
|
512
|
+
pcCaveat: "pc is a frame-boundary sample, not the writing instruction; for ISR-driven writes it is typically the interrupted main-thread PC (e.g. an idle loop), not the code that wrote the byte.",
|
|
513
|
+
hint: pc != null
|
|
514
|
+
? `disassembleRom near ${hexPC(pc)} is a STARTING point — but if this ROM writes from an NMI/IRQ handler, ${hexPC(pc)} is likely the interrupted idle loop, not the writer. Cross-check with the value trace.`
|
|
515
|
+
: "PC was not available — check that getCPUState is wired for this platform.",
|
|
516
|
+
}), host);
|
|
517
|
+
}
|
|
518
|
+
prev = cur;
|
|
519
|
+
}
|
|
520
|
+
pressDriver.finish();
|
|
521
|
+
return jsonContent({
|
|
522
|
+
written: false,
|
|
523
|
+
framesStepped: maxFrames,
|
|
524
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
525
|
+
note: "Target byte was not written within maxFrames. Try increasing maxFrames or driving the game with pressDuring.",
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
async function bpRunUntilPC({ address, maxFrames = 600, pressDuring }) {
|
|
530
|
+
const host = getHost(sessionKey);
|
|
531
|
+
if (!host.pcBreakSupported || !host.pcBreakSupported()) {
|
|
532
|
+
return jsonContent({
|
|
533
|
+
hit: false, notSupported: true, address: "$" + address.toString(16).toUpperCase(),
|
|
534
|
+
note: "This core build has no PC breakpoint (shipped on all 14 platforms as of 0.5.0 — update the core package if you see this). " +
|
|
535
|
+
"Interim: use runUntilWrite/findWriter to anchor on a write, or stepFrames + getCPUState sampling.",
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
539
|
+
const pressDriver = makePressDriver(host, presses);
|
|
540
|
+
host.setPCBreak(address, true, false);
|
|
541
|
+
let hit = false, framesRun = 0, last = null;
|
|
542
|
+
try {
|
|
543
|
+
for (let i = 0; i < maxFrames; i++) {
|
|
544
|
+
pressDriver.applyForFrame(i);
|
|
545
|
+
host.stepFrames(1);
|
|
546
|
+
framesRun++;
|
|
547
|
+
const st = host.getPCBreak(false);
|
|
548
|
+
if (st.hit) { hit = true; last = st; break; }
|
|
549
|
+
}
|
|
550
|
+
} finally {
|
|
551
|
+
pressDriver.finish();
|
|
552
|
+
host.setPCBreak(0, false, false); // disarm
|
|
553
|
+
}
|
|
554
|
+
if (!hit) {
|
|
555
|
+
return attachObserverFrame(jsonContent({
|
|
556
|
+
hit: false, address: "$" + address.toString(16).toUpperCase(), framesRun,
|
|
557
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
558
|
+
note: "PC never reached that address within maxFrames. Either the code path didn't execute (drive it with pressDuring " +
|
|
559
|
+
"to reach the right game state), or the address isn't an instruction boundary (a mid-instruction address never matches REG_PC).",
|
|
560
|
+
}), host);
|
|
561
|
+
}
|
|
562
|
+
const fin = host.getPCBreak(true); // clear hit
|
|
563
|
+
return attachObserverFrame(jsonContent({
|
|
564
|
+
hit: true,
|
|
565
|
+
address: "$" + address.toString(16).toUpperCase(),
|
|
566
|
+
pc: last.lastPC != null ? "$" + last.lastPC.toString(16).toUpperCase() : null,
|
|
567
|
+
pcRaw: last.lastPC,
|
|
568
|
+
frame: host.status.frameCount,
|
|
569
|
+
framesRun,
|
|
570
|
+
hits: fin.hits,
|
|
571
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
572
|
+
note: "CPU is FROZEN at this instruction. Call cpu({op:'read'}) to read all registers at this exact " +
|
|
573
|
+
"moment (the value you want — e.g. an address register holding a source pointer — is live now), then memory({op:'read'/'readCart'}) " +
|
|
574
|
+
"at that pointer. frame({op:'stepInstruction'}) to single-step, or frame({op:'step'})/host({op:'resume'}) to continue.",
|
|
575
|
+
}), host);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
async function bpRunUntilRead({ address, maxFrames = 600, pressDuring }) {
|
|
579
|
+
const host = getHost(sessionKey);
|
|
580
|
+
if (!host.readWatchSupported || !host.readWatchSupported()) {
|
|
581
|
+
return jsonContent({
|
|
582
|
+
hit: false, notSupported: true, address: "$" + address.toString(16).toUpperCase(),
|
|
583
|
+
note: "This core build has no read watchpoint (shipped on all 14 platforms as of 0.5.0 — update the core package if you see this).",
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
587
|
+
const pressDriver = makePressDriver(host, presses);
|
|
588
|
+
host.setReadWatch(address, true);
|
|
589
|
+
let hit = false, framesRun = 0, last = null;
|
|
590
|
+
try {
|
|
591
|
+
for (let i = 0; i < maxFrames; i++) {
|
|
592
|
+
pressDriver.applyForFrame(i);
|
|
593
|
+
host.stepFrames(1);
|
|
594
|
+
framesRun++;
|
|
595
|
+
const st = host.getReadWatch(false);
|
|
596
|
+
if (st.hits > 0) { hit = true; last = st; break; }
|
|
597
|
+
}
|
|
598
|
+
} finally {
|
|
599
|
+
pressDriver.finish();
|
|
600
|
+
host.setReadWatch(0, false);
|
|
601
|
+
}
|
|
602
|
+
if (!hit) {
|
|
603
|
+
return jsonContent({
|
|
604
|
+
hit: false, address: "$" + address.toString(16).toUpperCase(), framesRun,
|
|
605
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
606
|
+
note: "Address was not read within maxFrames. Drive the game to the state that reads it (pressDuring), or increase maxFrames.",
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
const fin = host.getReadWatch(true);
|
|
610
|
+
return attachObserverFrame(jsonContent({
|
|
611
|
+
hit: true,
|
|
612
|
+
address: "$" + address.toString(16).toUpperCase(),
|
|
613
|
+
pc: last.lastPC != null ? "$" + last.lastPC.toString(16).toUpperCase() : null,
|
|
614
|
+
pcRaw: last.lastPC,
|
|
615
|
+
value: "0x" + (last.lastValue & 0xFF).toString(16).toUpperCase().padStart(2, "0"),
|
|
616
|
+
frame: host.status.frameCount,
|
|
617
|
+
framesRun,
|
|
618
|
+
hits: fin.hits,
|
|
619
|
+
...(presses.length ? { pressesScheduled: presses.length, pressesApplied: pressDriver.applied() } : {}),
|
|
620
|
+
note: "pc is the EXACT instruction that read this address. disasm({ target:'rom', startAddress: pc }) to see it.",
|
|
621
|
+
}), host);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
server.tool(
|
|
625
|
+
"breakpoint",
|
|
626
|
+
"STOP-on-first dynamic breakpoints — run until a condition hits, then stop. One tool keyed by `on`. (For LOG-ALL " +
|
|
627
|
+
"coverage over many frames use `watch`; for a value-predicate closure use `runUntil`.)\n" +
|
|
628
|
+
"• on:'write' — break when a CPU `address` is written. **`precision` is the key axis here:**\n" +
|
|
629
|
+
" – precision:'exact' (default) — arms a core-level WRITE WATCHPOINT and returns the writing instruction's PC " +
|
|
630
|
+
"captured INSIDE the CPU write path — **correct even for NMI/IRQ-driven writes** (where a frame sample is just the idle loop). " +
|
|
631
|
+
"The precise answer to 'which code wrote $XX?'. On banked NES mappers it also reports the prg bank.\n" +
|
|
632
|
+
" – precision:'sampled' — the cheap wrapper: steps until a memory `region`/`offset` byte changes and returns the PC " +
|
|
633
|
+
"**sampled at the frame boundary**. **CAVEAT: that PC is NOT the writing instruction — under interrupts it's usually the " +
|
|
634
|
+
"interrupted main-thread PC (an idle loop), a LIE. Use 'exact' when you need the real writer.**\n" +
|
|
635
|
+
"• on:'read' — break when the CPU READS `address` (the read-side mirror of on:'write' exact): the EXACT instruction PC that " +
|
|
636
|
+
"read the byte. Finds who CONSUMES a value. Does NOT freeze mid-frame — records the PC and finishes the frame.\n" +
|
|
637
|
+
"• on:'pc' — break when the PC reaches `address`, freezing the CPU EXACTLY at that instruction (a real execution breakpoint). " +
|
|
638
|
+
"**The RE primitive for 'read the register at this instruction': break, then cpu({op:'read'}) the live register file** " +
|
|
639
|
+
"(e.g. break at a decoder's `move.b (a0),d0` and read A0 = the source address). After a hit the CPU stays FROZEN mid-frame — " +
|
|
640
|
+
"inspect, then frame({op:'step'/'stepInstruction'}) to continue. (on:'read'/'write' finish the frame; on:'pc' freezes.)\n" +
|
|
641
|
+
"All supported on every CPU core; out-of-date core packages return notSupported.",
|
|
642
|
+
{
|
|
643
|
+
on: z.enum(["write", "read", "pc"])
|
|
644
|
+
.describe("write=break on a write to address (precision:exact=true writer PC / sampled=frame PC, a lie under IRQ); read=break on a read (exact PC, who consumes it); pc=break when PC reaches address (freezes mid-instruction)."),
|
|
645
|
+
precision: z.enum(["exact", "sampled"]).default("exact")
|
|
646
|
+
.describe("on:'write' ONLY. exact=core watchpoint, the real writing instruction PC even under interrupts (uses `address`). sampled=cheap frame-boundary PC (uses region/offset/length) — NOT the writer under IRQ. Ignored for on:read/pc (always exact)."),
|
|
647
|
+
address: z.number().int().min(0).optional().describe("on:'write' exact / on:'read' / on:'pc' — CPU address to break on (write target, read target, or instruction boundary). Required for those."),
|
|
648
|
+
region: z.enum(MEMORY_REGIONS).optional().describe("on:'write' precision:'sampled' — region whose byte to watch for change."),
|
|
649
|
+
offset: z.number().int().min(0).optional().describe("on:'write' precision:'sampled' — offset within the region."),
|
|
650
|
+
length: z.number().int().min(1).max(4096).default(1).describe("on:'write' precision:'sampled' — bytes to watch from offset."),
|
|
651
|
+
maxFrames: z.number().int().min(1).max(1_000_000).default(600).describe("Max frames to run while waiting for the condition."),
|
|
652
|
+
pressDuring: z.array(z.object({
|
|
653
|
+
frame: z.number().int().min(0),
|
|
654
|
+
button: z.string(),
|
|
655
|
+
port: z.number().int().min(0).max(3).default(0),
|
|
656
|
+
holdFrames: z.number().int().min(1).default(2),
|
|
657
|
+
})).optional().describe("Schedule input while waiting (drive the game to the state that triggers the condition)."),
|
|
658
|
+
},
|
|
659
|
+
safeTool(async (args) => {
|
|
660
|
+
switch (args.on) {
|
|
661
|
+
case "write": {
|
|
662
|
+
if (args.precision === "sampled") {
|
|
663
|
+
if (!args.region || args.offset == null) throw new Error("breakpoint({on:'write', precision:'sampled'}): `region` and `offset` are required.");
|
|
664
|
+
return await bpRunUntilWrite(args);
|
|
665
|
+
}
|
|
666
|
+
if (args.address == null) throw new Error("breakpoint({on:'write', precision:'exact'}): `address` is required.");
|
|
667
|
+
return await bpFindWriter(args);
|
|
668
|
+
}
|
|
669
|
+
case "read": {
|
|
670
|
+
if (args.address == null) throw new Error("breakpoint({on:'read'}): `address` is required.");
|
|
671
|
+
return await bpRunUntilRead(args);
|
|
672
|
+
}
|
|
673
|
+
case "pc": {
|
|
674
|
+
if (args.address == null) throw new Error("breakpoint({on:'pc'}): `address` is required.");
|
|
675
|
+
return await bpRunUntilPC(args);
|
|
676
|
+
}
|
|
677
|
+
default: throw new Error(`breakpoint: unknown on '${args.on}'`);
|
|
678
|
+
}
|
|
679
|
+
}),
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
// stepInstruction folded into frame({op:'stepInstruction'}) (frame.js, which
|
|
683
|
+
// imports stepInstructionCore). Nothing registered here.
|
|
684
|
+
|
|
685
|
+
// ── register write/read + callSubroutine / decompressWith (item 1) ──────────
|
|
686
|
+
// reg-id convention (m68k family): 0..7=D0..D7, 8..15=A0..A7, 16=PC, 17=SR, 18=SP.
|
|
687
|
+
|
|
688
|
+
// cpu({op:read|setReg|call|decompress}) router. op:read -> getCPUStateCore
|
|
689
|
+
// (platform-tools.js). The other 3 are closure impls below (they need the
|
|
690
|
+
// per-session host). regSchema is shared by the call op.
|
|
691
|
+
const regSchema = z.record(z.string(), z.number().int()).optional().describe(
|
|
692
|
+
"op:call — registers to set before the call, keyed by romdev reg-id (m68k: 0-7=D0-D7, 8-15=A0-A7, 16=PC, 17=SR, 18=SP). " +
|
|
693
|
+
"e.g. {\"8\":2863118} sets A0. PC is set from the `pc` arg, not here.");
|
|
694
|
+
|
|
695
|
+
async function cpuSetReg({ regId, value }) {
|
|
696
|
+
const host = getHost(sessionKey);
|
|
697
|
+
if (!host.setRegSupported || !host.setRegSupported()) {
|
|
698
|
+
return jsonContent({ notSupported: true, note: "This core build has no register-write (shipped on all 14 platforms as of 0.6.0 — update the core package if you see this)." });
|
|
699
|
+
}
|
|
700
|
+
host.setReg(regId, value >>> 0);
|
|
701
|
+
const now = host.getReg(regId);
|
|
702
|
+
return jsonContent({ regId, value: "0x" + (now >>> 0).toString(16).toUpperCase(), valueRaw: now });
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async function cpuCall({ pc, regs, sentinelPC = 0, stopAtPC, presetMemory, maxFrames = 600, maxInstructions, sandbox = false }) {
|
|
706
|
+
const host = getHost(sessionKey);
|
|
707
|
+
if (!host.setRegSupported || !host.setRegSupported()) {
|
|
708
|
+
return jsonContent({ returned: false, notSupported: true,
|
|
709
|
+
note: "This core build has no register-write (shipped on all 14 platforms as of 0.6.0 — update the core package). cpu({op:'call'}) needs it." });
|
|
710
|
+
}
|
|
711
|
+
const numRegs = {};
|
|
712
|
+
for (const [k, v] of Object.entries(regs ?? {})) numRegs[Number(k)] = v >>> 0;
|
|
713
|
+
const r = host.callSubroutine({
|
|
714
|
+
pc, regs: numRegs, sentinelPC, stopAtPC,
|
|
715
|
+
presetMemory: (presetMemory ?? []).map((m) => ({ addr: m.addr, hex: m.hex })),
|
|
716
|
+
maxFrames, ...(maxInstructions ? { maxInstructions } : {}), sandbox,
|
|
717
|
+
});
|
|
718
|
+
const note = r.returned
|
|
719
|
+
? "Routine RETURNED. readMemory the buffer it wrote (e.g. the decompressor's A1 dest) now — sandbox:false leaves it live. (regs by reg-id: m68k 8=A0,9=A1,0=D0.)"
|
|
720
|
+
: r.watchdog
|
|
721
|
+
? "WATCHDOG tripped (ran the instruction budget without returning) — almost always a wrong entry setup, not a long routine. Check finalPC (where it's spinning) + finalRegs (is A0 where you set it, or did it walk off?). Common fixes: correct A0 to the real block start (with its length header), add a presetMemory the codec reads, or pass a WRAPPER entryPC that sets up dest. Raise maxInstructions only if you're sure it's legitimately huge."
|
|
722
|
+
: r.stoppedAtPC
|
|
723
|
+
? `Stopped at ${r.stoppedAtPC} (your stopAtPC) with PARTIAL output — readMemory the dst to see what's been written so far.`
|
|
724
|
+
: "Did not return within maxFrames AND the watchdog didn't trip — this usually means the entry FELL BACK INTO THE GAME (a wrapper PC with a wrong source, so it never reaches the sentinel) and the game is just free-running. finalPC is inside the main loop, not your routine. Re-check the entry PC (use the routine body, not a wrapper) and the source regs; or lower maxInstructions to fail fast while probing. Bump maxFrames/maxInstructions only if you're sure it's a legitimately huge decompress.";
|
|
725
|
+
return jsonContent({
|
|
726
|
+
returned: r.returned, framesRun: r.framesRun, sandbox,
|
|
727
|
+
...(r.watchdog ? { watchdog: true, reason: r.reason } : {}),
|
|
728
|
+
...(r.stoppedAtPC ? { stoppedAtPC: r.stoppedAtPC } : {}),
|
|
729
|
+
...(r.finalPC ? { finalPC: r.finalPC } : {}),
|
|
730
|
+
...(r.finalRegs ? { finalRegs: r.finalRegs } : {}),
|
|
731
|
+
note,
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
async function cpuDecompress({ entryPC, sourceAddress, destAddress, maxFrames = 600 }) {
|
|
736
|
+
const host = getHost(sessionKey);
|
|
737
|
+
if (!host.setRegSupported || !host.setRegSupported()) {
|
|
738
|
+
return jsonContent({ returned: false, notSupported: true,
|
|
739
|
+
note: "This core build has no register-write (shipped on all 14 platforms as of 0.6.0 — update the core package). decompressWith needs it." });
|
|
740
|
+
}
|
|
741
|
+
const regs = { 8: sourceAddress >>> 0 };
|
|
742
|
+
if (destAddress !== undefined) regs[9] = destAddress >>> 0;
|
|
743
|
+
const r = host.callSubroutine({ pc: entryPC, regs, sentinelPC: 0, maxFrames, sandbox: false });
|
|
744
|
+
return jsonContent({
|
|
745
|
+
returned: r.returned, framesRun: r.framesRun,
|
|
746
|
+
...(destAddress !== undefined ? { destAddress: "$" + (destAddress >>> 0).toString(16).toUpperCase() } : {}),
|
|
747
|
+
note: r.returned
|
|
748
|
+
? `Decompressor returned. readMemory at ${destAddress !== undefined ? "$" + (destAddress >>> 0).toString(16).toUpperCase() : "the routine's dest"} to get the decompressed bytes (the live core ran the game's own codec — no codec reimplementation needed).`
|
|
749
|
+
: "Decompressor did NOT return within maxFrames. Confirm entryPC is the routine start, A0=source is right, and bump maxFrames. (Some codecs expect more setup regs — use cpu({op:'call'}) with the full regs map.)",
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
server.tool(
|
|
754
|
+
"cpu",
|
|
755
|
+
"Read or drive a CPU, one tool keyed by `op`.\n" +
|
|
756
|
+
"OP CHEAT-SHEET (the params each op uses): " +
|
|
757
|
+
"read → {cpu?, platform?}; " +
|
|
758
|
+
"setReg → {regId, value}; " +
|
|
759
|
+
"call → {pc, regs?, sandbox?, maxInstructions?, sentinelPC?, stopAtPC?, presetMemory?, maxFrames?}; " +
|
|
760
|
+
"decompress → {entryPC, sourceAddress, destAddress?, maxFrames?}.\n" +
|
|
761
|
+
"• op:'read' — read a CPU's {pc, registers, flags, sp}. Main CPU wired for all 14 tier-1 systems (nes, snes, " +
|
|
762
|
+
"genesis, sms, gg, gb, gbc, atari2600, atari7800, c64, lynx, gba (ARM7TDMI: 16 gprs + cpsr/spsr + execPc for " +
|
|
763
|
+
"pipeline prefetch), pce, msx). Secondary CPUs via `cpu`: 'spc700' (SNES audio — 'stuck in IPL' vs 'running' vs " +
|
|
764
|
+
"'crashed'), 'z80' (Genesis sound — held in reset until the 68k releases it via $A11100, so a fresh boot reads all-zero).\n" +
|
|
765
|
+
"• op:'setReg' — write a single register by romdev reg-id (the inverse of op:'read'). **m68k reg-ids: 0-7=D0-D7, " +
|
|
766
|
+
"8-15=A0-A7, 16=PC, 17=SR, 18=SP.** Returns the value read back. notSupported where the core lacks register-write.\n" +
|
|
767
|
+
"• op:'call' — drive the ROM's OWN subroutine and run until it returns — the RE primitive for compressed assets. Set " +
|
|
768
|
+
"up the CPU (`regs` by reg-id, PC=`pc`), push a sentinel return, run until RTS. **SANDBOXED off by default so the dst " +
|
|
769
|
+
"buffer it wrote stays live for memory({op:'read'}).** Classic use: drive a decompressor (A0=source, A1=dest) then read " +
|
|
770
|
+
"the dst. **NEVER HANGS: an instruction WATCHDOG (`maxInstructions`) force-stops a runaway and returns PROGRESS — " +
|
|
771
|
+
"finalPC + finalRegs + watchdog:true — so you can tell 'wrong A0' from 'needs a preset' from 'legitimately long'.** " +
|
|
772
|
+
"`stopAtPC` halts mid-routine for partial output; `presetMemory` for codecs that read a global from RAM first.\n" +
|
|
773
|
+
"• op:'decompress' — convenience wrapper over op:'call' for the common decompressor shape: call `entryPC` with " +
|
|
774
|
+
"A0=`sourceAddress` (and optionally A1=`destAddress`), run until it returns, then read `destAddress`. For the " +
|
|
775
|
+
"NBA-Jam-style 'name + portrait are LZ-compressed' wall: point it at the game's own decompressor.",
|
|
776
|
+
{
|
|
777
|
+
op: z.enum(["read", "setReg", "call", "decompress"])
|
|
778
|
+
.describe("read=CPU registers/flags; setReg=write one register; call=drive a subroutine until it returns; decompress=call shortcut (A0=source, A1=dest)."),
|
|
779
|
+
// read
|
|
780
|
+
platform: z.string().optional().describe("op:read — override platform; defaults to the loaded ROM."),
|
|
781
|
+
cpu: z.enum(["main", "spc700", "z80"]).default("main").describe("op:read — which CPU: main (primary), spc700 (SNES audio), z80 (Genesis sound)."),
|
|
782
|
+
// setReg
|
|
783
|
+
regId: z.number().int().min(0).max(31).optional().describe("op:setReg — romdev reg-id (m68k: 0-7=D, 8-15=A, 16=PC, 17=SR, 18=SP)."),
|
|
784
|
+
value: z.number().int().optional().describe("op:setReg — 32-bit value to write."),
|
|
785
|
+
// call
|
|
786
|
+
pc: z.number().int().min(0).optional().describe("op:call — entry PC of the subroutine (may be a WRAPPER that sets up regs then tail-calls; sentinel-return is detected from the final RTS regardless)."),
|
|
787
|
+
regs: regSchema,
|
|
788
|
+
sentinelPC: z.number().int().min(0).default(0).describe("op:call — return address pushed on the stack; run stops when PC reaches it. Default 0 (vector area); override if it collides with real code."),
|
|
789
|
+
stopAtPC: z.number().int().min(0).optional().describe("op:call — STOP when PC reaches this address and return the partial output instead of waiting for the sentinel return."),
|
|
790
|
+
presetMemory: z.array(z.object({
|
|
791
|
+
addr: z.number().int().min(0).describe("CPU address to write before the call."),
|
|
792
|
+
hex: z.string().describe("Bytes as hex (e.g. '00FF')."),
|
|
793
|
+
})).optional().describe("op:call — memory writes applied before the call (codecs that read a global from RAM, not just registers)."),
|
|
794
|
+
maxFrames: z.number().int().min(1).max(100000).default(600).describe("op:call/decompress — frame cap (the outer bound)."),
|
|
795
|
+
maxInstructions: z.number().int().min(1000).optional().describe("op:call — instruction watchdog budget (the REAL cap; default ~maxFrames*500k). Raise for a huge decompress; lower to fail fast while probing the right A0."),
|
|
796
|
+
sandbox: z.boolean().default(false).describe("op:call — snapshot+restore core state around the call (default FALSE — you want the dst buffer left live to read). True leaves the live game untouched."),
|
|
797
|
+
// decompress
|
|
798
|
+
entryPC: z.number().int().min(0).optional().describe("op:decompress — decompressor entry PC."),
|
|
799
|
+
sourceAddress: z.number().int().min(0).optional().describe("op:decompress — compressed-source address → A0 (reg-id 8 on m68k)."),
|
|
800
|
+
destAddress: z.number().int().min(0).optional().describe("op:decompress — destination buffer address → A1 (reg-id 9). Omit if the routine picks its own dest."),
|
|
801
|
+
},
|
|
802
|
+
safeTool(async (args) => {
|
|
803
|
+
switch (args.op) {
|
|
804
|
+
case "read": return await getCPUStateCore(args);
|
|
805
|
+
case "setReg": {
|
|
806
|
+
if (args.regId == null || args.value == null) throw new Error("cpu({op:'setReg'}): `regId` and `value` are required.");
|
|
807
|
+
return await cpuSetReg(args);
|
|
808
|
+
}
|
|
809
|
+
case "call": {
|
|
810
|
+
if (args.pc == null) throw new Error("cpu({op:'call'}): `pc` (entry PC) is required.");
|
|
811
|
+
return await cpuCall(args);
|
|
812
|
+
}
|
|
813
|
+
case "decompress": {
|
|
814
|
+
if (args.entryPC == null || args.sourceAddress == null) throw new Error("cpu({op:'decompress'}): `entryPC` and `sourceAddress` are required.");
|
|
815
|
+
return await cpuDecompress(args);
|
|
816
|
+
}
|
|
817
|
+
default: throw new Error(`cpu: unknown op '${args.op}'`);
|
|
818
|
+
}
|
|
819
|
+
}),
|
|
820
|
+
);
|
|
821
|
+
|
|
822
|
+
// ── Range watch + coverage trace (item 2, discovery) ────────────────────────
|
|
823
|
+
|
|
824
|
+
async function wRange({ start, end, kind = "both", frames = 120, pressDuring, limit = 200 }) {
|
|
825
|
+
const host = getHost(sessionKey);
|
|
826
|
+
if (!host.rangeWatchSupported || !host.rangeWatchSupported()) {
|
|
827
|
+
return jsonContent({ notSupported: true, events: [],
|
|
828
|
+
note: "This core build has no range watch (shipped on all 14 platforms as of 0.6.0 — update the core package). Use breakpoint({on:'write'/'read'}) for a single address." });
|
|
829
|
+
}
|
|
830
|
+
if (end < start) throw new Error("watch({on:'range'}): end must be >= start.");
|
|
831
|
+
// pressDuring is driven inside the frame loop; watchRange's host method owns
|
|
832
|
+
// stepping, so for now apply presses up front if any (simple: hold for the run).
|
|
833
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
834
|
+
const pressDriver = makePressDriver(host, presses);
|
|
835
|
+
if (presses.length) pressDriver.applyForFrame(0);
|
|
836
|
+
const r = host.watchRange(start, end, kind, frames);
|
|
837
|
+
pressDriver.finish();
|
|
838
|
+
const events = r.events.slice(0, limit).map((e) => ({
|
|
839
|
+
pc: "$" + e.pc.toString(16).toUpperCase(),
|
|
840
|
+
address: "$" + e.address.toString(16).toUpperCase(),
|
|
841
|
+
value: "0x" + e.value.toString(16).toUpperCase().padStart(2, "0"),
|
|
842
|
+
}));
|
|
843
|
+
// distinct PCs are the actionable summary
|
|
844
|
+
const distinctPCs = [...new Set(r.events.map((e) => e.pc))].slice(0, 64)
|
|
845
|
+
.map((p) => "$" + p.toString(16).toUpperCase());
|
|
846
|
+
return attachObserverFrame(jsonContent({
|
|
847
|
+
range: "$" + start.toString(16).toUpperCase() + "..$" + end.toString(16).toUpperCase(),
|
|
848
|
+
kind, total: r.total, returned: events.length, truncated: r.truncated,
|
|
849
|
+
distinctPCs, events,
|
|
850
|
+
note: "distinctPCs is the actionable summary — each is a routine that touches this range; disasm({target:'rom'}) one to identify the renderer/reader. " +
|
|
851
|
+
(r.truncated ? "TRUNCATED: more events than the buffer held — narrow `start..end` or `frames` for the full set." : ""),
|
|
852
|
+
}), host);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
async function wLogPC({ start, end, frames = 120, pressDuring, limit = 512 }) {
|
|
856
|
+
const host = getHost(sessionKey);
|
|
857
|
+
if (!host.rangeWatchSupported || !host.rangeWatchSupported()) {
|
|
858
|
+
return jsonContent({ notSupported: true, pcs: [],
|
|
859
|
+
note: "This core build has no coverage trace (shipped on all 14 platforms as of 0.6.0 — update the core package)." });
|
|
860
|
+
}
|
|
861
|
+
if (end < start) throw new Error("watch({on:'pc'}): end must be >= start.");
|
|
862
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
863
|
+
const pressDriver = makePressDriver(host, presses);
|
|
864
|
+
if (presses.length) pressDriver.applyForFrame(0);
|
|
865
|
+
const r = host.logPCRange(start, end, frames);
|
|
866
|
+
pressDriver.finish();
|
|
867
|
+
const pcs = r.pcs.slice(0, limit).map((p) => "$" + p.toString(16).toUpperCase());
|
|
868
|
+
return attachObserverFrame(jsonContent({
|
|
869
|
+
window: "$" + start.toString(16).toUpperCase() + "..$" + end.toString(16).toUpperCase(),
|
|
870
|
+
distinct: r.distinct, total: r.total, returned: pcs.length, truncated: r.truncated,
|
|
871
|
+
pcs,
|
|
872
|
+
note: "Each PC is code that EXECUTED in this window. disasm({target:'rom'}) them to find the routine you're hunting. " +
|
|
873
|
+
(r.truncated ? "TRUNCATED — narrow the window for the full distinct set." : ""),
|
|
874
|
+
}), host);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
server.tool(
|
|
878
|
+
"watch",
|
|
879
|
+
"LOG-ALL dynamic tracing — run N frames and log EVERY hit (not stop-on-first; for stop-on-first use `breakpoint`). One tool keyed by `on`.\n" +
|
|
880
|
+
"• on:'mem' — the power tool: answer 'what code is touching this RAM byte?' OR extract a frame-accurate event timeline (music-driver note onsets, physics arcs). Reports every frame that changed a watched byte as {frame,offset,before,after,pc}. " +
|
|
881
|
+
"Extras: `ranges:[{region,offset,length,label}]` watches MANY disjoint regions in ONE pass (identical frames); `onChange:'reset'|'increase'|'decrease'|'any'` edge filter (reset = counter-reload = the note-onset signal); `valueFilter:{min,max}`; `format:'series'` = compact columnar value-vs-frame curve (~10× smaller for a ramp); `sampleEvery`; `groupByPC` (collapse by sampled PC); `cheatLabels` (auto-name addresses from the cheat DB); `outputPath` streams all events as NDJSON; `stopOnFirst` exits on the first match. " +
|
|
882
|
+
"**CAVEAT: frame-level, not instruction-level (last value per frame); the sampled `pc` is a frame-boundary sample — for ISR-driven writes use breakpoint({on:'write', precision:'exact'}) for the real writer.**\n" +
|
|
883
|
+
"• on:'range' — DISCOVERY: log EVERY instruction that reads or writes ANYWHERE in [start,end]. The fix for 'I don't know which PC touches this'. Returns {pc,address,value}[] + the actionable distinctPCs. (Ring-buffered: `truncated:true` if it overflows.)\n" +
|
|
884
|
+
"• on:'pc' — DISCOVERY (coverage trace): record every DISTINCT PC executed within [start,end] — 'what code runs here?'. Log execution in the bank where you suspect the renderer lives during the moment it draws, then disassemble the PCs.",
|
|
885
|
+
{
|
|
886
|
+
on: z.enum(["mem", "range", "pc"])
|
|
887
|
+
.describe("mem=watch a RAM byte/ranges for value changes over frames (the power tool); range=log every read/write PC in [start,end]; pc=coverage trace of distinct PCs executed in [start,end]."),
|
|
888
|
+
// on:'mem'
|
|
889
|
+
region: z.enum(MEMORY_REGIONS).optional().describe("on:'mem' single-range — the region to watch (same canonical set memory uses, incl. nes_apu_regs, genesis_ym2612, c64_sid_regs). Omit when using `ranges`."),
|
|
890
|
+
offset: z.number().int().min(0).default(0).describe("on:'mem' single-range — first byte of the watched range."),
|
|
891
|
+
length: z.number().int().min(1).max(4096).default(1).describe("on:'mem' single-range — bytes to watch (default 1)."),
|
|
892
|
+
ranges: z.array(rangeShape).min(1).max(16).optional().describe("on:'mem' — watch several disjoint ranges in one pass (region/offset/length ignored). Each event carries its range's `label`; each range may OVERRIDE call-wide `onChange`/`sampleEvery`/`valueFilter` (keep a slow state byte while suppressing a noisy counter in the same pass)."),
|
|
893
|
+
onChange: z.enum(["any", "increase", "decrease", "reset"]).default("any").describe("on:'mem' edge filter. 'any' (default); 'increase'/'decrease' directional; 'reset' = value jumped UP (counter reload — the note-onset signal)."),
|
|
894
|
+
valueFilter: z.object({ min: z.number().int().min(0).max(255).optional(), max: z.number().int().min(0).max(255).optional() }).optional().describe("on:'mem' — keep only changes whose NEW value is within [min,max]."),
|
|
895
|
+
maxEvents: z.number().int().min(1).max(100_000).default(256).describe("on:'mem' — cap RETURNED events (outputPath gets ALL). With format:'series' caps SAMPLES PER OFFSET and downsamples to span the full window."),
|
|
896
|
+
format: z.enum(["events", "series"]).default("events").describe("on:'mem' — 'events' (verbose per change) or 'series' (compact columnar frames[]/values[] curve, ~10× smaller for a ramp; drops pc)."),
|
|
897
|
+
sampleEvery: z.number().int().min(1).default(1).describe("on:'mem' — keep only every Nth filter-passing change (trend, not every delta)."),
|
|
898
|
+
groupByPC: z.boolean().default(false).describe("on:'mem' — collapse events by sampled PC into byPC[]. CAVEAT: that PC is frame-boundary-sampled, NOT the writer under interrupts — use breakpoint({on:'write', precision:'exact'}) for the EXACT writer."),
|
|
899
|
+
cheatLabels: z.string().optional().describe("on:'mem' — absolute path to the loaded ROM; auto-annotate watched RAM-region addresses (system_ram/*_ram/*_wram/gb_hram) from the bundled cheat DB (a PROBABLE match — strong hints, not gospel)."),
|
|
900
|
+
stopOnFirst: z.boolean().default(false).describe("on:'mem' — stop on the first filter-passing change instead of running the full duration. (For a true stop-on-first breakpoint, prefer the `breakpoint` tool.)"),
|
|
901
|
+
// on:'range'
|
|
902
|
+
kind: z.enum(["read", "write", "both"]).default("both").describe("on:'range' — watch reads, writes, or both."),
|
|
903
|
+
// on:'range' / on:'pc' window
|
|
904
|
+
start: z.number().int().min(0).optional().describe("on:'range'/'pc' — low CPU address of the window."),
|
|
905
|
+
end: z.number().int().min(0).optional().describe("on:'range'/'pc' — high CPU address (inclusive)."),
|
|
906
|
+
// shared
|
|
907
|
+
frames: z.number().int().min(1).max(1_000_000).default(600).describe("Frames to run while logging (default 600). on:'range'/'pc' windows are usually short (~120) — pass a smaller value to keep the ring buffer from overflowing."),
|
|
908
|
+
limit: z.number().int().min(1).max(4000).default(200).describe("on:'range'/'pc' — max events/PCs returned (default 200; full count is in `total`)."),
|
|
909
|
+
outputPath: z.string().optional().describe("on:'mem' — stream every filter-passing event to this path as NDJSON + return a compact summary. Use for long watches so the full log never enters your context."),
|
|
910
|
+
pressDuring: z.array(z.object({
|
|
911
|
+
frame: z.number().int().min(0),
|
|
912
|
+
button: z.string(),
|
|
913
|
+
port: z.number().int().min(0).max(3).default(0),
|
|
914
|
+
holdFrames: z.number().int().min(1).default(2),
|
|
915
|
+
})).optional().describe("Schedule input while watching (drive the game to the state that touches the watched bytes/range)."),
|
|
916
|
+
},
|
|
917
|
+
safeTool(async (args) => {
|
|
918
|
+
switch (args.on) {
|
|
919
|
+
case "mem": return await watchMem(args);
|
|
920
|
+
case "range": {
|
|
921
|
+
if (args.start == null || args.end == null) throw new Error("watch({on:'range'}): `start` and `end` are required.");
|
|
922
|
+
return await wRange({ ...args, frames: args.frames ?? 120, limit: args.limit ?? 200 });
|
|
923
|
+
}
|
|
924
|
+
case "pc": {
|
|
925
|
+
if (args.start == null || args.end == null) throw new Error("watch({on:'pc'}): `start` and `end` are required.");
|
|
926
|
+
return await wLogPC({ ...args, frames: args.frames ?? 120, limit: args.limit ?? 512 });
|
|
927
|
+
}
|
|
928
|
+
default: throw new Error(`watch: unknown on '${args.on}'`);
|
|
929
|
+
}
|
|
930
|
+
}),
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
// ── dmaTrace (item 3, Genesis only) ─────────────────────────────────────────
|
|
934
|
+
// precision:exact = dmaExact (watchDma, per-DMA core log), precision:sampled =
|
|
935
|
+
// traceVramSourceCore (frame-sampled, dest-agnostic).
|
|
936
|
+
async function dmaExact({ frames = 120, vramDest, destWindow = 0x40, dedupe = true, sourceFilter = "all", pressDuring, romPreviewBytes = 0, limit = 200 }) {
|
|
937
|
+
const host = getHost(sessionKey);
|
|
938
|
+
if (!host.dmaWatchSupported || !host.dmaWatchSupported()) {
|
|
939
|
+
return jsonContent({ notSupported: true, dmas: [],
|
|
940
|
+
note: "dmaTrace is Genesis-only (VDP DMA). On other platforms use breakpoint({on:'write'}) (CPU writes) or the platform's source tracer." });
|
|
941
|
+
}
|
|
942
|
+
const presses = (pressDuring ?? []).slice().sort((a, b) => a.frame - b.frame);
|
|
943
|
+
const pressDriver = makePressDriver(host, presses);
|
|
944
|
+
if (presses.length) pressDriver.applyForFrame(0);
|
|
945
|
+
const r = host.watchDma(frames);
|
|
946
|
+
pressDriver.finish();
|
|
947
|
+
let rom = null;
|
|
948
|
+
if (romPreviewBytes > 0) { try { rom = host.getCartRom(); } catch { /* no preview */ } }
|
|
949
|
+
// VDP code low bits: 1=VRAM, 3=CRAM, 5=VSRAM (write codes). Decode the target.
|
|
950
|
+
const targetOf = (code) => { const c = code & 0x0F; return c === 1 ? "VRAM" : c === 3 ? "CRAM" : c === 5 ? "VSRAM" : "VRAM?"; };
|
|
951
|
+
// Genesis 68k bus: ROM is the low address space (< $400000 typically), work
|
|
952
|
+
// RAM is $E00000-$FFFFFF. A DMA `source` is a 68k byte address — split on the
|
|
953
|
+
// RAM window so 'rom-only' drops the RAM→VRAM sprite/scroll refresh.
|
|
954
|
+
const isRam = (src) => (src >>> 0) >= 0xE00000;
|
|
955
|
+
let dmas = r.dmas;
|
|
956
|
+
if (vramDest !== undefined) dmas = dmas.filter((d) => Math.abs((d.vramDest >>> 0) - vramDest) <= destWindow);
|
|
957
|
+
if (sourceFilter === "rom-only") dmas = dmas.filter((d) => !isRam(d.source));
|
|
958
|
+
else if (sourceFilter === "ram-only") dmas = dmas.filter((d) => isRam(d.source));
|
|
959
|
+
let collapsedCount = 0;
|
|
960
|
+
if (dedupe) {
|
|
961
|
+
const seen = new Map();
|
|
962
|
+
for (const d of dmas) {
|
|
963
|
+
const k = `${d.vramDest >>> 0}:${d.source >>> 0}:${d.lengthWords}:${d.code}`;
|
|
964
|
+
if (seen.has(k)) { seen.get(k).occurrences++; collapsedCount++; }
|
|
965
|
+
else seen.set(k, { ...d, occurrences: 1 });
|
|
966
|
+
}
|
|
967
|
+
dmas = [...seen.values()];
|
|
968
|
+
}
|
|
969
|
+
const totalDistinct = dmas.length;
|
|
970
|
+
const out = dmas.slice(0, limit).map((d) => {
|
|
971
|
+
const o = {
|
|
972
|
+
vramDest: "$" + (d.vramDest >>> 0).toString(16).toUpperCase(),
|
|
973
|
+
source: "0x" + (d.source >>> 0).toString(16).toUpperCase(),
|
|
974
|
+
lengthWords: d.lengthWords, lengthBytes: d.lengthWords * 2,
|
|
975
|
+
target: targetOf(d.code),
|
|
976
|
+
from: isRam(d.source) ? "RAM" : "ROM",
|
|
977
|
+
...(dedupe ? { occurrences: d.occurrences } : {}),
|
|
978
|
+
};
|
|
979
|
+
if (rom && rom.bytes && !isRam(d.source) && (d.source >>> 0) < rom.bytes.length) {
|
|
980
|
+
const a = d.source >>> 0, e = Math.min(a + romPreviewBytes, rom.bytes.length);
|
|
981
|
+
o.romPreview = Array.from(rom.bytes.subarray(a, e), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
982
|
+
}
|
|
983
|
+
return o;
|
|
984
|
+
});
|
|
985
|
+
return attachObserverFrame(jsonContent({
|
|
986
|
+
totalEvents: r.total, distinctDmas: totalDistinct, returned: out.length,
|
|
987
|
+
...(dedupe && collapsedCount ? { collapsed: collapsedCount } : {}),
|
|
988
|
+
...(r.truncated ? { coreBufferTruncated: true } : {}),
|
|
989
|
+
...(vramDest !== undefined ? { filteredToVramDest: "$" + vramDest.toString(16).toUpperCase(), destWindow } : {}),
|
|
990
|
+
...(sourceFilter !== "all" ? { sourceFilter } : {}),
|
|
991
|
+
dmas: out,
|
|
992
|
+
note: "`source` is the 68k byte address the tiles were copied from — for a ROM source (`from:ROM`) edit the tiles THERE. " +
|
|
993
|
+
"dedupe collapses the per-frame refresh; sourceFilter:'rom-only' drops the RAM→VRAM sprite/scroll noise (use it to find a cart-ROM asset DMA). " +
|
|
994
|
+
(totalDistinct > limit ? `Showing ${out.length}/${totalDistinct} distinct — raise limit or narrow vramDest.` : ""),
|
|
995
|
+
}), host);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
server.tool(
|
|
999
|
+
"dmaTrace",
|
|
1000
|
+
"GENESIS ONLY — trace mem→VDP DMAs (the answer to 'this name/portrait/logo is a pre-rendered bitmap DMA'd into VRAM — " +
|
|
1001
|
+
"WHERE in ROM?', which breakpoint({on:'write'}) can't catch). Keyed by `precision`.\n" +
|
|
1002
|
+
"• precision:'exact' (default) — log every mem→VDP DMA with its VRAM DESTINATION, ROM SOURCE, length, and code. " +
|
|
1003
|
+
"Filter by `vramDest` (±`destWindow`) to find the exact source of a specific tile. `dedupe` collapses the per-frame " +
|
|
1004
|
+
"refresh (7000 events → a handful); `sourceFilter:'rom-only'` drops the RAM→VRAM sprite/scroll noise. " +
|
|
1005
|
+
"**Catches a second DMA in the same frame that the sampled mode misses.**\n" +
|
|
1006
|
+
"• precision:'sampled' — the cheap frame-sampled tracer: reads the VDP DMA source registers ($15-$17) once per frame " +
|
|
1007
|
+
"and logs each DISTINCT mem→VRAM source as a ROM byte offset. **HONEST LIMIT: two DMAs in the SAME frame may show only " +
|
|
1008
|
+
"one source — narrow the window around when the graphic appears. dest-agnostic (no vramDest filter).**",
|
|
1009
|
+
{
|
|
1010
|
+
precision: z.enum(["exact", "sampled"]).default("exact")
|
|
1011
|
+
.describe("exact=per-DMA core log with VRAM dest + ROM source (catches same-frame DMAs); sampled=frame-sampled source-register read (cheaper, may miss two DMAs in one frame, dest-agnostic)."),
|
|
1012
|
+
frames: z.number().int().min(1).max(6000).default(120).describe("Frames to step while tracing (default 120 ≈ 2s)."),
|
|
1013
|
+
pressDuring: z.array(z.object({
|
|
1014
|
+
frame: z.number().int().min(0),
|
|
1015
|
+
button: z.string(),
|
|
1016
|
+
port: z.number().int().min(0).max(3).default(0),
|
|
1017
|
+
holdFrames: z.number().int().min(1).default(2),
|
|
1018
|
+
})).optional().describe("Drive input to the screen that uploads the graphic."),
|
|
1019
|
+
romPreviewBytes: z.number().int().min(0).max(64).default(0).describe("Bytes of the ROM source to preview per DMA (exact default 0; sampled default 16)."),
|
|
1020
|
+
// precision:'exact' only
|
|
1021
|
+
vramDest: z.number().int().min(0).optional().describe("precision:'exact' — keep only DMAs whose VRAM destination is within ±`destWindow` of this address."),
|
|
1022
|
+
destWindow: z.number().int().min(0).default(0x40).describe("precision:'exact' — match window around vramDest (default 64 bytes ≈ 1 tile)."),
|
|
1023
|
+
dedupe: z.boolean().default(true).describe("precision:'exact' — collapse identical DMAs (same dest+source+length+code) to one entry with an `occurrences` count (default on)."),
|
|
1024
|
+
sourceFilter: z.enum(["all", "rom-only", "ram-only"]).default("all").describe("precision:'exact' — 'rom-only' drops the RAM→VRAM per-frame refresh noise; 'ram-only' keeps only it."),
|
|
1025
|
+
limit: z.number().int().min(1).max(2000).default(200).describe("precision:'exact' — max DMA entries to return (after dedupe/filter)."),
|
|
1026
|
+
// precision:'sampled' only
|
|
1027
|
+
minLengthBytes: z.number().int().min(0).max(65536).default(0).describe("precision:'sampled' — ignore DMAs shorter than this many bytes (filters tiny scroll/sprite updates so graphic uploads stand out)."),
|
|
1028
|
+
},
|
|
1029
|
+
safeTool(async (args) => {
|
|
1030
|
+
if (args.precision === "sampled") {
|
|
1031
|
+
return await traceVramSourceCore({ ...args, romPreviewBytes: args.romPreviewBytes || 16, sessionKey });
|
|
1032
|
+
}
|
|
1033
|
+
return await dmaExact(args);
|
|
1034
|
+
}),
|
|
1035
|
+
);
|
|
1036
|
+
}
|