romdevtools 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/AGENTS.md +56 -44
  2. package/CHANGELOG.md +355 -0
  3. package/README.md +4 -4
  4. package/examples/README.md +7 -7
  5. package/examples/atari2600/templates/platformer.asm +1227 -325
  6. package/examples/atari2600/templates/puzzle.asm +1056 -0
  7. package/examples/atari2600/templates/racing.asm +909 -257
  8. package/examples/atari2600/templates/shmup.asm +1035 -218
  9. package/examples/atari2600/templates/sports.asm +1143 -229
  10. package/examples/atari7800/templates/hello_sprite.c +8 -4
  11. package/examples/atari7800/templates/platformer.c +991 -152
  12. package/examples/atari7800/templates/puzzle.c +1091 -145
  13. package/examples/atari7800/templates/racing.c +949 -118
  14. package/examples/atari7800/templates/shmup.c +812 -130
  15. package/examples/atari7800/templates/sports.c +820 -181
  16. package/examples/c64/templates/platformer.c +876 -157
  17. package/examples/c64/templates/puzzle.c +881 -143
  18. package/examples/c64/templates/racing.c +873 -88
  19. package/examples/c64/templates/shmup.c +762 -154
  20. package/examples/c64/templates/sports.c +755 -95
  21. package/examples/gb/templates/platformer.c +841 -175
  22. package/examples/gb/templates/puzzle.c +1094 -176
  23. package/examples/gb/templates/racing.c +761 -169
  24. package/examples/gb/templates/shmup.c +679 -169
  25. package/examples/gb/templates/sports.c +790 -153
  26. package/examples/gba/templates/platformer.c +624 -169
  27. package/examples/gba/templates/puzzle.c +535 -207
  28. package/examples/gba/templates/racing.c +513 -196
  29. package/examples/gba/templates/shmup.c +565 -168
  30. package/examples/gba/templates/sports.c +454 -162
  31. package/examples/gbc/templates/platformer.c +944 -176
  32. package/examples/gbc/templates/puzzle.c +1131 -177
  33. package/examples/gbc/templates/racing.c +891 -175
  34. package/examples/gbc/templates/shmup.c +827 -179
  35. package/examples/gbc/templates/sports.c +870 -156
  36. package/examples/genesis/templates/platformer.c +747 -129
  37. package/examples/genesis/templates/puzzle.c +702 -208
  38. package/examples/genesis/templates/racing.c +728 -193
  39. package/examples/genesis/templates/shmup.c +535 -142
  40. package/examples/genesis/templates/shmup_2p.c +13 -1
  41. package/examples/genesis/templates/sports.c +495 -158
  42. package/examples/gg/templates/platformer.c +883 -214
  43. package/examples/gg/templates/puzzle.c +906 -181
  44. package/examples/gg/templates/racing.c +919 -160
  45. package/examples/gg/templates/shmup.c +716 -177
  46. package/examples/gg/templates/sports.c +735 -128
  47. package/examples/lynx/templates/platformer.c +604 -50
  48. package/examples/lynx/templates/puzzle.c +533 -130
  49. package/examples/lynx/templates/racing.c +538 -102
  50. package/examples/lynx/templates/shmup.c +461 -122
  51. package/examples/lynx/templates/sports.c +496 -69
  52. package/examples/msx/platformer/main.c +648 -159
  53. package/examples/msx/puzzle/main.c +750 -185
  54. package/examples/msx/racing/main.c +669 -177
  55. package/examples/msx/shmup/main.c +460 -177
  56. package/examples/msx/sports/main.c +591 -124
  57. package/examples/nes/templates/platformer.c +586 -160
  58. package/examples/nes/templates/puzzle.c +603 -222
  59. package/examples/nes/templates/racing.c +505 -197
  60. package/examples/nes/templates/shmup.c +339 -144
  61. package/examples/nes/templates/sports.c +341 -182
  62. package/examples/pce/platformer/main.c +875 -204
  63. package/examples/pce/puzzle/main.c +797 -216
  64. package/examples/pce/racing/main.c +782 -206
  65. package/examples/pce/shmup/main.c +638 -211
  66. package/examples/pce/sports/main.c +585 -167
  67. package/examples/porting-across-platforms/README.md +1 -1
  68. package/examples/sms/templates/platformer.c +765 -176
  69. package/examples/sms/templates/puzzle.c +783 -177
  70. package/examples/sms/templates/racing.c +812 -133
  71. package/examples/sms/templates/shmup.c +601 -148
  72. package/examples/sms/templates/shmup_2p.c +17 -1
  73. package/examples/sms/templates/sports.c +633 -121
  74. package/examples/snes/templates/music_demo.c +7 -0
  75. package/examples/snes/templates/platformer-data.asm +123 -24
  76. package/examples/snes/templates/platformer-hdr.asm +57 -0
  77. package/examples/snes/templates/platformer.c +587 -149
  78. package/examples/snes/templates/puzzle-data.asm +116 -21
  79. package/examples/snes/templates/puzzle-hdr.asm +57 -0
  80. package/examples/snes/templates/puzzle.c +632 -185
  81. package/examples/snes/templates/racing-data.asm +390 -32
  82. package/examples/snes/templates/racing-hdr.asm +57 -0
  83. package/examples/snes/templates/racing.c +807 -177
  84. package/examples/snes/templates/shmup-data.asm +87 -29
  85. package/examples/snes/templates/shmup-hdr.asm +57 -0
  86. package/examples/snes/templates/shmup.c +459 -180
  87. package/examples/snes/templates/sports-data.asm +48 -2
  88. package/examples/snes/templates/sports-hdr.asm +57 -0
  89. package/examples/snes/templates/sports.c +414 -156
  90. package/package.json +12 -12
  91. package/src/cores/wasm/bluemsx_libretro.js +1 -1
  92. package/src/cores/wasm/bluemsx_libretro.wasm +0 -0
  93. package/src/cores/wasm/fceumm_libretro.js +1 -1
  94. package/src/cores/wasm/fceumm_libretro.wasm +0 -0
  95. package/src/cores/wasm/gambatte_libretro.js +1 -1
  96. package/src/cores/wasm/gambatte_libretro.wasm +0 -0
  97. package/src/cores/wasm/geargrafx_libretro.js +1 -1
  98. package/src/cores/wasm/geargrafx_libretro.wasm +0 -0
  99. package/src/cores/wasm/genesis_plus_gx_libretro.js +1 -1
  100. package/src/cores/wasm/genesis_plus_gx_libretro.wasm +0 -0
  101. package/src/cores/wasm/handy_libretro.js +1 -1
  102. package/src/cores/wasm/handy_libretro.wasm +0 -0
  103. package/src/cores/wasm/mgba_libretro.js +1 -1
  104. package/src/cores/wasm/mgba_libretro.wasm +0 -0
  105. package/src/cores/wasm/prosystem_libretro.js +1 -1
  106. package/src/cores/wasm/prosystem_libretro.wasm +0 -0
  107. package/src/cores/wasm/snes9x_libretro.js +1 -1
  108. package/src/cores/wasm/snes9x_libretro.wasm +0 -0
  109. package/src/cores/wasm/stella2014_libretro.js +1 -1
  110. package/src/cores/wasm/stella2014_libretro.wasm +0 -0
  111. package/src/cores/wasm/vice_x64_libretro.js +1 -1
  112. package/src/cores/wasm/vice_x64_libretro.wasm +0 -0
  113. package/src/host/LibretroHost.js +304 -11
  114. package/src/http/tool-registry.js +11 -11
  115. package/src/mcp/server.js +6 -0
  116. package/src/mcp/tools/cheats.js +2 -1
  117. package/src/mcp/tools/disasm-rebuild.js +315 -65
  118. package/src/mcp/tools/disasm.js +149 -28
  119. package/src/mcp/tools/find-references.js +216 -51
  120. package/src/mcp/tools/frame.js +14 -6
  121. package/src/mcp/tools/index.js +18 -4
  122. package/src/mcp/tools/input.js +31 -7
  123. package/src/mcp/tools/lifecycle.js +6 -4
  124. package/src/mcp/tools/memory.js +208 -39
  125. package/src/mcp/tools/platform-docs.js +1 -1
  126. package/src/mcp/tools/playtest.js +56 -4
  127. package/src/mcp/tools/preview-tile.js +6 -2
  128. package/src/mcp/tools/project.js +1114 -120
  129. package/src/mcp/tools/rom-id.js +5 -1
  130. package/src/mcp/tools/run-until.js +4 -2
  131. package/src/mcp/tools/snippets.js +6 -6
  132. package/src/mcp/tools/sprite-pipeline.js +14 -2
  133. package/src/mcp/tools/state.js +2 -1
  134. package/src/mcp/tools/tile-inspect.js +8 -1
  135. package/src/mcp/tools/toolchain.js +55 -11
  136. package/src/mcp/tools/watch-memory.js +145 -27
  137. package/src/observer/bus.js +73 -0
  138. package/src/observer/livestream.html +4 -2
  139. package/src/observer/tool-wrap.js +17 -14
  140. package/src/platforms/_guides/ROMHACKING_PLAYBOOK.md +64 -17
  141. package/src/platforms/atari2600/MENTAL_MODEL.md +5 -1
  142. package/src/platforms/atari2600/TROUBLESHOOTING.md +40 -0
  143. package/src/platforms/atari7800/MENTAL_MODEL.md +32 -11
  144. package/src/platforms/atari7800/TROUBLESHOOTING.md +5 -5
  145. package/src/platforms/c64/MENTAL_MODEL.md +11 -4
  146. package/src/platforms/c64/TROUBLESHOOTING.md +13 -0
  147. package/src/platforms/gb/MENTAL_MODEL.md +19 -4
  148. package/src/platforms/gb/TROUBLESHOOTING.md +101 -6
  149. package/src/platforms/gb/lib/c/README.md +10 -11
  150. package/src/platforms/gb/lib/c/gb_crt0.s +27 -3
  151. package/src/platforms/gb/lib/c/patch-header.js +19 -6
  152. package/src/platforms/gba/MENTAL_MODEL.md +4 -4
  153. package/src/platforms/gba/TROUBLESHOOTING.md +3 -3
  154. package/src/platforms/gba/lib/c/gba_sfx.c +40 -0
  155. package/src/platforms/gba/lib/c/gba_sfx.h +10 -0
  156. package/src/platforms/gbc/MENTAL_MODEL.md +16 -4
  157. package/src/platforms/gbc/TROUBLESHOOTING.md +24 -3
  158. package/src/platforms/gbc/UPSTREAM_SOURCES.md +1 -1
  159. package/src/platforms/gbc/lib/c/README.md +10 -11
  160. package/src/platforms/gbc/lib/c/font.h +43 -0
  161. package/src/platforms/gbc/lib/c/gb_crt0.s +26 -3
  162. package/src/platforms/gbc/lib/c/patch-header.js +19 -6
  163. package/src/platforms/genesis/MENTAL_MODEL.md +43 -9
  164. package/src/platforms/genesis/TROUBLESHOOTING.md +2 -2
  165. package/src/platforms/genesis/lib/c/genesis_sfx.c +37 -0
  166. package/src/platforms/genesis/lib/c/genesis_sfx.h +1 -0
  167. package/src/platforms/gg/MENTAL_MODEL.md +4 -4
  168. package/src/platforms/gg/TROUBLESHOOTING.md +14 -18
  169. package/src/platforms/gg/UPSTREAM_SOURCES.md +1 -1
  170. package/src/platforms/gg/lib/c/gg_crt0.s +14 -2
  171. package/src/platforms/gg/lib/c/joypad_read.c +29 -0
  172. package/src/platforms/lynx/MENTAL_MODEL.md +1 -1
  173. package/src/platforms/lynx/TROUBLESHOOTING.md +3 -3
  174. package/src/platforms/lynx/lib/c/lynx_sfx.c +38 -2
  175. package/src/platforms/lynx/lib/c/lynx_sfx.h +1 -0
  176. package/src/platforms/msx/MENTAL_MODEL.md +11 -5
  177. package/src/platforms/msx/TROUBLESHOOTING.md +21 -0
  178. package/src/platforms/msx/lib/c/msx_crt0.s +27 -0
  179. package/src/platforms/msx/lib/c/msx_hw.h +3 -0
  180. package/src/platforms/msx/lib/c/msx_vdp.c +70 -0
  181. package/src/platforms/nes/MENTAL_MODEL.md +12 -5
  182. package/src/platforms/nes/lib/c/nes_runtime.c +190 -34
  183. package/src/platforms/nes/lib/c/nes_runtime.h +35 -0
  184. package/src/platforms/pce/MENTAL_MODEL.md +14 -5
  185. package/src/platforms/pce/TROUBLESHOOTING.md +9 -0
  186. package/src/platforms/pce/lib/c/pce_hw.h +13 -1
  187. package/src/platforms/pce/lib/c/pce_sound.c +22 -0
  188. package/src/platforms/pce/lib/c/pce_video.c +32 -0
  189. package/src/platforms/sms/MENTAL_MODEL.md +11 -6
  190. package/src/platforms/sms/TROUBLESHOOTING.md +6 -0
  191. package/src/platforms/sms/lib/c/sms_crt0.s +14 -2
  192. package/src/platforms/snes/MENTAL_MODEL.md +7 -2
  193. package/src/platforms/snes/TROUBLESHOOTING.md +40 -1
  194. package/src/playtest/playtest.js +73 -3
  195. package/src/toolchains/cc65/presets/nes/chr-ram-runtime.cfg +13 -8
  196. package/src/toolchains/cc65/presets/nes/chr-ram-runtime.crt0.s +58 -5
  197. package/src/toolchains/cc65/presets/nes/chr-rom.crt0.s +52 -3
  198. package/src/toolchains/cc65/presets/pce/rom32k.cfg +52 -0
  199. package/src/toolchains/index.js +64 -19
@@ -1,6 +1,230 @@
1
- ; ── racing-data.asm — font + player car + enemy car tiles ─────────
1
+ ; ── racing-data.asm — EMBER CIRCUIT's assembly half ──────────────────────────
2
+ ;
3
+ ; What lives here (and why it can't live in racing.c):
4
+ ; 1. The Mode 7 HDMA tables, in a RAMSECTION pinned to WRAM BANK $7E.
5
+ ; tcc-65816 puts C globals in bank $7F — but an HDMA channel's A1Bx bank
6
+ ; byte + the table address must be known exactly, so the tables live here
7
+ ; where WE pick the bank. racing.c reaches them as plain externs.
8
+ ; 2. m7_build — the per-frame matrix-table builder. 168 multiplies per frame
9
+ ; is far beyond tcc-compiled C (software 16-bit mul ≈ 200+ cycles); this
10
+ ; uses the S-CPU's 8x8 hardware multiplier ($4202/$4203 → $4216, 8-cycle
11
+ ; latency) and finishes in ~30% of a frame.
12
+ ; 3. sram_read16/sram_write16 — battery SRAM accessors. SRAM sits at
13
+ ; $70:0000 (declared in hdr.asm — see racing-hdr.asm), reachable only
14
+ ; with long (24-bit) addressing, which tcc C pointers don't emit.
15
+ ; 4. Font + car sprite tiles (rodata).
16
+ ;
17
+ ; Section names must stay unique vs snes_sfx_data.asm (also linked in).
18
+
2
19
  .include "hdr.asm"
3
20
 
21
+ ; ── HARDWARE IDIOM (load-bearing — reshape gameplay around this; see TROUBLESHOOTING) ──
22
+ ; The double-buffered HDMA tables. HDMA reads these DURING active display —
23
+ ; rewriting the table the beam is walking shears the ground mid-frame. So:
24
+ ; two copies of each; racing.c builds into the back buffer while HDMA walks
25
+ ; the front, and flips by rewriting A1Tx during vblank.
26
+ ;
27
+ ; Table grammar (walked by hardware, one entry header per batch of lines):
28
+ ; [count 1-127][data] = write data once, hold it for <count> lines
29
+ ; [count|$80] [data...] = REPEAT: fresh data EVERY line for count&$7F lines
30
+ ; [0] = end of table (last value persists to frame bottom)
31
+ ; We use plain 2-line hold entries (84 entries x 2 lines = 168 road lines):
32
+ ; half the multiplies of per-line repeat mode, visually identical.
33
+ ;
34
+ ; AB/CD layout (matrix channels, transfer mode 3 → $211B,$211B,$211C,$211C):
35
+ ; [0] = 56 hold the identity matrix through the mode-1 HUD strip
36
+ ; [1-4] = A=$0100, B=0 (identity — these lines are text, matrix unused)
37
+ ; [5..] = 84 x { count=2, Alo, Ahi, Blo, Bhi } ← m7_build rewrites data
38
+ ; [425] = 0 terminator
39
+ ; m7_cdN MUST sit exactly 426 bytes after m7_abN: m7_build stores the CD
40
+ ; (M7C/M7D) halves through the same index register at offset +426/+428.
41
+ ;
42
+ ; VOFS layout (mode 2 → $210E,$210E): [56][0,0] then 84 x {2, lo, hi}, [0].
43
+ ; The VOFS value steps -2 per entry = -1 per scanline (see racing.c for the
44
+ ; camera math that makes that constant slope correct at every zoom).
45
+ .RAMSECTION "mode7_tables" BANK $7E SLOT 2
46
+ m7_ab0 dsb 426 ; matrix A/B table, buffer 0
47
+ m7_cd0 dsb 426 ; matrix C/D table, buffer 0 (= m7_ab0 + 426, load-bearing)
48
+ m7_ab1 dsb 426 ; buffer 1
49
+ m7_cd1 dsb 426
50
+ m7_vo0 dsb 256 ; M7VOFS table, buffer 0
51
+ m7_vo1 dsb 256
52
+ lam8_tab dsb 84 ; per-band zoom λ>>3 (max 184, fits the 8x8 multiplier)
53
+ hdma_mode_tab dsb 8 ; BGMODE split table (static after boot)
54
+ hdma_hofs_tab dsb 8 ; M7HOFS table (racing.c patches bytes [4],[5] in vblank)
55
+ m7_cos dsb 1 ; inputs to m7_build, written by racing.c each frame:
56
+ m7_sin dsb 1 ; heading cos/sin, signed, 64 = 1.0
57
+ m7_dst dsb 2 ; back-buffer AB table, address of first entry
58
+ m7_vdst dsb 2 ; back-buffer VOFS table, address of first entry
59
+ m7_vstart dsb 2 ; VOFS value for the first road line
60
+ m7_cabs dsb 1 ; m7_build scratch: |cos|, |sin|, sign flags, products
61
+ m7_sabs dsb 1
62
+ m7_cneg dsb 2
63
+ m7_sneg dsb 2
64
+ m7_pc dsb 2
65
+ m7_ps dsb 2
66
+ telem dsb 16 ; headless-test telemetry block (see racing.c)
67
+ .ENDS
68
+
69
+ .SECTION ".racing_asm" SUPERFREE
70
+
71
+ ; ── HARDWARE IDIOM (load-bearing — reshape gameplay around this; see TROUBLESHOOTING) ──
72
+ ; void m7_build(void) — rebuild the BACK buffer's 84 matrix entries + VOFS
73
+ ; column from m7_cos/m7_sin/m7_dst/m7_vdst/m7_vstart (racing.c sets all five
74
+ ; first). Per entry: two hardware multiplies
75
+ ; value = (λ>>3) x |trig| → $4216, then >>3 → 8.8 fixed point
76
+ ; λ is 8.8 zoom (so λ>>3 is 5.3, ≤184); trig is 64=1.0 (1.6); the product is
77
+ ; 6.9, and >>3 lands it in the 8.8 the M7x registers expect. Quantizing λ to
78
+ ; 8 bits costs ≤3% scale error on the nearest rows — invisible, and it turns
79
+ ; a 16x16 software multiply into one 8-cycle hardware one.
80
+ ; Matrix written per band: A = λcosθ B = -λsinθ C = λsinθ D = λcosθ
81
+ ; (the standard 2D rotation, scaled per scanline-band — that's all Mode 7 is).
82
+ m7_build:
83
+ php
84
+ phb
85
+ sep #$20
86
+ lda #$7E
87
+ pha
88
+ plb ; DBR = $7E → every .w absolute below hits WRAM
89
+
90
+ ; split cos/sin into |value| + 16-bit negate flag
91
+ stz.w m7_cneg
92
+ stz.w m7_cneg + 1
93
+ stz.w m7_sneg
94
+ stz.w m7_sneg + 1
95
+ lda.w m7_cos
96
+ bpl @cpos
97
+ eor #$FF
98
+ inc a
99
+ inc.w m7_cneg
100
+ @cpos:
101
+ sta.w m7_cabs
102
+ lda.w m7_sin
103
+ bpl @spos
104
+ eor #$FF
105
+ inc a
106
+ inc.w m7_sneg
107
+ @spos:
108
+ sta.w m7_sabs
109
+
110
+ rep #$30
111
+ ldx.w m7_dst ; X → first AB entry's count byte
112
+ ldy.w #0 ; Y = entry index 0..83 (also indexes lam8_tab)
113
+ @entry:
114
+ ; Pc = (lam8[y] * |cos|) >> 3, negated if cos was negative
115
+ sep #$20
116
+ lda.w lam8_tab,y
117
+ sta.l $004202 ; multiplicand
118
+ lda.w m7_cabs
119
+ sta.l $004203 ; multiplier — starts the 8-cycle multiply
120
+ rep #$20
121
+ nop ; rep(3) + nop+nop(4) + lda.l setup ≥ the 8-cycle
122
+ nop ; result latency — NEVER read $4216 sooner
123
+ lda.l $004216
124
+ lsr a
125
+ lsr a
126
+ lsr a
127
+ sta.w m7_pc
128
+ lda.w m7_cneg
129
+ beq @pcok
130
+ lda.w #0
131
+ sec
132
+ sbc.w m7_pc
133
+ sta.w m7_pc
134
+ @pcok:
135
+ ; Ps = (lam8[y] * |sin|) >> 3, negated if sin was negative
136
+ sep #$20
137
+ lda.w lam8_tab,y
138
+ sta.l $004202
139
+ lda.w m7_sabs
140
+ sta.l $004203
141
+ rep #$20
142
+ nop
143
+ nop
144
+ lda.l $004216
145
+ lsr a
146
+ lsr a
147
+ lsr a
148
+ sta.w m7_ps
149
+ lda.w m7_sneg
150
+ beq @psok
151
+ lda.w #0
152
+ sec
153
+ sbc.w m7_ps
154
+ sta.w m7_ps
155
+ @psok:
156
+ ; store the band's matrix: AB entry data at 1,x — CD twin at +426
157
+ lda.w m7_pc
158
+ sta.w $0001,x ; M7A = λcosθ
159
+ sta.w $01AD,x ; M7D = λcosθ ($1AD = 429 = 426 + 3)
160
+ lda.w m7_ps
161
+ sta.w $01AB,x ; M7C = λsinθ ($1AB = 427 = 426 + 1)
162
+ lda.w #0
163
+ sec
164
+ sbc.w m7_ps
165
+ sta.w $0003,x ; M7B = -λsinθ
166
+ txa
167
+ clc
168
+ adc.w #5 ; next entry (count byte + 4 data bytes)
169
+ tax
170
+ iny
171
+ cpy.w #84
172
+ bne @entry
173
+
174
+ ; VOFS column: linear ramp, -2 per 2-line band (-1 per scanline)
175
+ ldx.w m7_vdst
176
+ lda.w m7_vstart
177
+ ldy.w #84
178
+ @vrow:
179
+ sta.w $0001,x
180
+ dec a
181
+ dec a
182
+ inx
183
+ inx
184
+ inx
185
+ dey
186
+ bne @vrow
187
+
188
+ plb
189
+ plp
190
+ rtl
191
+
192
+ ; ── HARDWARE IDIOM (load-bearing) — battery SRAM accessors ──────────────────
193
+ ; SRAM is mapped at $70:0000 (LoROM, SRAMSIZE $01 in racing-hdr.asm = 2 KB).
194
+ ; Long addressing only — there is no SRAM mirror in the program banks, which
195
+ ; is why these are asm and not C. tcc calling convention: u16 arg at 5,s
196
+ ; (after the 4-byte rtl frame), second arg at 7,s; u16 return in tcc__r0.
197
+
198
+ ; u16 sram_read16(u16 offset)
199
+ sram_read16:
200
+ php
201
+ rep #$30
202
+ lda 5,s ; offset
203
+ tax
204
+ sep #$20
205
+ lda.l $700000,x
206
+ sta.w tcc__r0
207
+ lda.l $700001,x
208
+ sta.w tcc__r0 + 1
209
+ plp
210
+ rtl
211
+
212
+ ; void sram_write16(u16 offset, u16 value)
213
+ sram_write16:
214
+ php
215
+ rep #$30
216
+ lda 5,s ; offset
217
+ tax
218
+ lda 7,s ; value
219
+ sep #$20
220
+ sta.l $700000,x ; low byte
221
+ xba
222
+ sta.l $700001,x ; high byte
223
+ plp
224
+ rtl
225
+
226
+ .ENDS
227
+
4
228
  .section ".rodata1" superfree
5
229
 
6
230
  tilfont:
@@ -307,47 +531,181 @@ palfont:
307
531
  .db $00, $00, $00, $00, $00, $00, $00, $00
308
532
  .db $00, $00
309
533
 
534
+ palsprite:
535
+ .db $00, $00 ; 0 transparent
536
+ .db $FF, $7F ; 1 white (cockpit stripe)
537
+ .db $1F, $00 ; 2 red (body)
538
+ .db $10, $00 ; 3 dark red (shading)
539
+ .db $C6, $18 ; 4 dark grey (tires)
540
+ .db $CE, $39 ; 5 grey
541
+ .db $00, $00, $00, $00, $00, $00, $00, $00
542
+ .db $00, $00, $00, $00, $00, $00, $00, $00
543
+ .db $00, $00, $00, $00
544
+
310
545
  tilsprite:
311
- ; Tile 0 player car (colour 1)
312
- .db $3C, $00, $7E, $00, $42, $00, $7E, $00
313
- .db $7E, $00, $42, $00, $7E, $00, $66, $00
546
+ ; The car, 16x16, as OBJ-page tiles. SNES large (16x16) sprites fetch tiles
547
+ ; n, n+1, n+16, n+17 from a 16-tile-wide page — so the four quadrants sit at
548
+ ; page positions 0, 1, 16, 17 with blank tiles padding the rest of each row.
549
+ ; 4bpp: per tile 32 bytes = rows 0-7 plane0/plane1 pairs, then plane2/plane3.
550
+ ; tile 0 - car top-left
551
+ .db $00, $03, $00, $07, $03, $04, $03, $04
552
+ .db $00, $0F, $01, $0F, $03, $1F, $03, $1F
553
+ .db $00, $00, $00, $00, $00, $00, $C0, $00
554
+ .db $C0, $00, $F0, $00, $20, $00, $00, $00
555
+ ; tile 1 - car top-right
556
+ .db $00, $C0, $00, $E0, $00, $E0, $00, $E0
557
+ .db $00, $F0, $80, $F0, $C0, $F8, $C0, $F8
558
+ .db $00, $00, $00, $00, $00, $00, $03, $00
559
+ .db $03, $00, $0F, $00, $00, $00, $00, $00
560
+ ; tile 2 - blank
314
561
  .db $00, $00, $00, $00, $00, $00, $00, $00
315
562
  .db $00, $00, $00, $00, $00, $00, $00, $00
316
- ; Tile 1 — enemy car (colour 2)
317
- .db $00, $3C, $00, $7E, $00, $42, $00, $7E
318
- .db $00, $7E, $00, $42, $00, $7E, $00, $66
319
563
  .db $00, $00, $00, $00, $00, $00, $00, $00
320
564
  .db $00, $00, $00, $00, $00, $00, $00, $00
321
-
322
- palsprite:
323
- .db $00, $00 ; 0 transparent
324
- .db $FF, $7F ; 1 white (player)
325
- .db $00, $7C ; 2 red (enemy)
565
+ ; tile 3 - blank
326
566
  .db $00, $00, $00, $00, $00, $00, $00, $00
327
567
  .db $00, $00, $00, $00, $00, $00, $00, $00
328
568
  .db $00, $00, $00, $00, $00, $00, $00, $00
329
569
  .db $00, $00, $00, $00, $00, $00, $00, $00
330
-
331
- ; ── Background wallpaper (one 8x8 4bpp tile, 4 solid colour quadrants) ──
332
- ; Tiled across BG1 it paints the whole screen in four muted colours so the
333
- ; playfield never reads as a flat/blank backdrop. Quadrant->colour: TL=1,
334
- ; TR=2, BL=3, BR=4. 4bpp plane order: bytes 0-15 = rows 0-7 plane0/plane1
335
- ; pairs, bytes 16-31 = rows 0-7 plane2/plane3 pairs.
336
- tilbg:
337
- .db $F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F ; rows 0-3: p0=left p1=right
338
- .db $F0, $F0, $F0, $F0, $F0, $F0, $F0, $F0 ; rows 4-7: p0+p1 = left
339
- .db $00, $00, $00, $00, $00, $00, $00, $00 ; rows 0-3: p2/p3 = 0
340
- .db $0F, $00, $0F, $00, $0F, $00, $0F, $00 ; rows 4-7: p2 = right
341
-
342
- palbg:
343
- ; 16-colour BG palette; only 1-4 used (the four wallpaper quadrant tones).
344
- .db $00, $00 ; 0 unused (BG fully opaque)
345
- .db $C4, $30 ; 1 dark blue
346
- .db $42, $29 ; 2 dark teal
347
- .db $88, $30 ; 3 dark purple
348
- .db $C6, $24 ; 4 dark slate
570
+ ; tile 4 - blank
571
+ .db $00, $00, $00, $00, $00, $00, $00, $00
572
+ .db $00, $00, $00, $00, $00, $00, $00, $00
573
+ .db $00, $00, $00, $00, $00, $00, $00, $00
574
+ .db $00, $00, $00, $00, $00, $00, $00, $00
575
+ ; tile 5 - blank
576
+ .db $00, $00, $00, $00, $00, $00, $00, $00
577
+ .db $00, $00, $00, $00, $00, $00, $00, $00
578
+ .db $00, $00, $00, $00, $00, $00, $00, $00
579
+ .db $00, $00, $00, $00, $00, $00, $00, $00
580
+ ; tile 6 - blank
581
+ .db $00, $00, $00, $00, $00, $00, $00, $00
582
+ .db $00, $00, $00, $00, $00, $00, $00, $00
583
+ .db $00, $00, $00, $00, $00, $00, $00, $00
584
+ .db $00, $00, $00, $00, $00, $00, $00, $00
585
+ ; tile 7 - blank
586
+ .db $00, $00, $00, $00, $00, $00, $00, $00
587
+ .db $00, $00, $00, $00, $00, $00, $00, $00
588
+ .db $00, $00, $00, $00, $00, $00, $00, $00
589
+ .db $00, $00, $00, $00, $00, $00, $00, $00
590
+ ; tile 8 - blank
591
+ .db $00, $00, $00, $00, $00, $00, $00, $00
592
+ .db $00, $00, $00, $00, $00, $00, $00, $00
593
+ .db $00, $00, $00, $00, $00, $00, $00, $00
594
+ .db $00, $00, $00, $00, $00, $00, $00, $00
595
+ ; tile 9 - blank
596
+ .db $00, $00, $00, $00, $00, $00, $00, $00
597
+ .db $00, $00, $00, $00, $00, $00, $00, $00
598
+ .db $00, $00, $00, $00, $00, $00, $00, $00
599
+ .db $00, $00, $00, $00, $00, $00, $00, $00
600
+ ; tile 10 - blank
601
+ .db $00, $00, $00, $00, $00, $00, $00, $00
602
+ .db $00, $00, $00, $00, $00, $00, $00, $00
603
+ .db $00, $00, $00, $00, $00, $00, $00, $00
604
+ .db $00, $00, $00, $00, $00, $00, $00, $00
605
+ ; tile 11 - blank
606
+ .db $00, $00, $00, $00, $00, $00, $00, $00
607
+ .db $00, $00, $00, $00, $00, $00, $00, $00
608
+ .db $00, $00, $00, $00, $00, $00, $00, $00
609
+ .db $00, $00, $00, $00, $00, $00, $00, $00
610
+ ; tile 12 - blank
611
+ .db $00, $00, $00, $00, $00, $00, $00, $00
612
+ .db $00, $00, $00, $00, $00, $00, $00, $00
613
+ .db $00, $00, $00, $00, $00, $00, $00, $00
614
+ .db $00, $00, $00, $00, $00, $00, $00, $00
615
+ ; tile 13 - blank
616
+ .db $00, $00, $00, $00, $00, $00, $00, $00
617
+ .db $00, $00, $00, $00, $00, $00, $00, $00
618
+ .db $00, $00, $00, $00, $00, $00, $00, $00
619
+ .db $00, $00, $00, $00, $00, $00, $00, $00
620
+ ; tile 14 - blank
621
+ .db $00, $00, $00, $00, $00, $00, $00, $00
622
+ .db $00, $00, $00, $00, $00, $00, $00, $00
623
+ .db $00, $00, $00, $00, $00, $00, $00, $00
624
+ .db $00, $00, $00, $00, $00, $00, $00, $00
625
+ ; tile 15 - blank
626
+ .db $00, $00, $00, $00, $00, $00, $00, $00
627
+ .db $00, $00, $00, $00, $00, $00, $00, $00
628
+ .db $00, $00, $00, $00, $00, $00, $00, $00
629
+ .db $00, $00, $00, $00, $00, $00, $00, $00
630
+ ; tile 16 - car bottom-left
631
+ .db $01, $1F, $01, $0F, $01, $0F, $01, $1F
632
+ .db $00, $0F, $03, $1F, $07, $0F, $07, $07
633
+ .db $00, $00, $00, $00, $C0, $00, $C0, $00
634
+ .db $F0, $00, $20, $00, $00, $00, $00, $00
635
+ ; tile 17 - car bottom-right
636
+ .db $80, $F8, $80, $F0, $80, $F0, $80, $F8
637
+ .db $00, $F0, $C0, $F8, $E0, $F0, $E0, $E0
638
+ .db $00, $00, $00, $00, $03, $00, $03, $00
639
+ .db $0F, $00, $00, $00, $00, $00, $00, $00
640
+ ; tile 18 - blank
641
+ .db $00, $00, $00, $00, $00, $00, $00, $00
642
+ .db $00, $00, $00, $00, $00, $00, $00, $00
643
+ .db $00, $00, $00, $00, $00, $00, $00, $00
644
+ .db $00, $00, $00, $00, $00, $00, $00, $00
645
+ ; tile 19 - blank
646
+ .db $00, $00, $00, $00, $00, $00, $00, $00
647
+ .db $00, $00, $00, $00, $00, $00, $00, $00
648
+ .db $00, $00, $00, $00, $00, $00, $00, $00
649
+ .db $00, $00, $00, $00, $00, $00, $00, $00
650
+ ; tile 20 - blank
651
+ .db $00, $00, $00, $00, $00, $00, $00, $00
652
+ .db $00, $00, $00, $00, $00, $00, $00, $00
653
+ .db $00, $00, $00, $00, $00, $00, $00, $00
654
+ .db $00, $00, $00, $00, $00, $00, $00, $00
655
+ ; tile 21 - blank
656
+ .db $00, $00, $00, $00, $00, $00, $00, $00
657
+ .db $00, $00, $00, $00, $00, $00, $00, $00
658
+ .db $00, $00, $00, $00, $00, $00, $00, $00
659
+ .db $00, $00, $00, $00, $00, $00, $00, $00
660
+ ; tile 22 - blank
661
+ .db $00, $00, $00, $00, $00, $00, $00, $00
662
+ .db $00, $00, $00, $00, $00, $00, $00, $00
663
+ .db $00, $00, $00, $00, $00, $00, $00, $00
664
+ .db $00, $00, $00, $00, $00, $00, $00, $00
665
+ ; tile 23 - blank
666
+ .db $00, $00, $00, $00, $00, $00, $00, $00
667
+ .db $00, $00, $00, $00, $00, $00, $00, $00
668
+ .db $00, $00, $00, $00, $00, $00, $00, $00
669
+ .db $00, $00, $00, $00, $00, $00, $00, $00
670
+ ; tile 24 - blank
671
+ .db $00, $00, $00, $00, $00, $00, $00, $00
672
+ .db $00, $00, $00, $00, $00, $00, $00, $00
673
+ .db $00, $00, $00, $00, $00, $00, $00, $00
674
+ .db $00, $00, $00, $00, $00, $00, $00, $00
675
+ ; tile 25 - blank
676
+ .db $00, $00, $00, $00, $00, $00, $00, $00
677
+ .db $00, $00, $00, $00, $00, $00, $00, $00
678
+ .db $00, $00, $00, $00, $00, $00, $00, $00
679
+ .db $00, $00, $00, $00, $00, $00, $00, $00
680
+ ; tile 26 - blank
681
+ .db $00, $00, $00, $00, $00, $00, $00, $00
682
+ .db $00, $00, $00, $00, $00, $00, $00, $00
683
+ .db $00, $00, $00, $00, $00, $00, $00, $00
684
+ .db $00, $00, $00, $00, $00, $00, $00, $00
685
+ ; tile 27 - blank
686
+ .db $00, $00, $00, $00, $00, $00, $00, $00
687
+ .db $00, $00, $00, $00, $00, $00, $00, $00
688
+ .db $00, $00, $00, $00, $00, $00, $00, $00
689
+ .db $00, $00, $00, $00, $00, $00, $00, $00
690
+ ; tile 28 - blank
691
+ .db $00, $00, $00, $00, $00, $00, $00, $00
692
+ .db $00, $00, $00, $00, $00, $00, $00, $00
693
+ .db $00, $00, $00, $00, $00, $00, $00, $00
694
+ .db $00, $00, $00, $00, $00, $00, $00, $00
695
+ ; tile 29 - blank
696
+ .db $00, $00, $00, $00, $00, $00, $00, $00
697
+ .db $00, $00, $00, $00, $00, $00, $00, $00
698
+ .db $00, $00, $00, $00, $00, $00, $00, $00
699
+ .db $00, $00, $00, $00, $00, $00, $00, $00
700
+ ; tile 30 - blank
701
+ .db $00, $00, $00, $00, $00, $00, $00, $00
702
+ .db $00, $00, $00, $00, $00, $00, $00, $00
703
+ .db $00, $00, $00, $00, $00, $00, $00, $00
704
+ .db $00, $00, $00, $00, $00, $00, $00, $00
705
+ ; tile 31 - blank
706
+ .db $00, $00, $00, $00, $00, $00, $00, $00
707
+ .db $00, $00, $00, $00, $00, $00, $00, $00
349
708
  .db $00, $00, $00, $00, $00, $00, $00, $00
350
709
  .db $00, $00, $00, $00, $00, $00, $00, $00
351
- .db $00, $00, $00, $00, $00, $00
352
710
 
353
711
  .ends
@@ -0,0 +1,57 @@
1
+ ;==LoRom== racing hdr.asm — PROJECT OVERRIDE of PVSnesLib's stock header
2
+ ;
3
+ ; Why this file exists: the stock include/hdr.asm declares CARTRIDGETYPE $00
4
+ ; (ROM only) and SRAMSIZE $00. The SNES cart header is the ONLY place battery
5
+ ; SRAM gets declared — snes9x (and real flash carts) size the save RAM from
6
+ ; these two bytes. Delete this file and the build still succeeds, the game
7
+ ; still runs, and saves silently stop existing: sram_read16/sram_write16 hit
8
+ ; open bus at $70:0000 and the "best time" never survives a power cycle.
9
+ ;
10
+ ; Everything except CARTRIDGETYPE/SRAMSIZE/NAME is byte-identical to the
11
+ ; stock header — the memory map and vectors MUST match what PVSnesLib's
12
+ ; crt0/libs were assembled against, or wlalink places sections inconsistently.
13
+
14
+ .MEMORYMAP ; Begin describing the system architecture.
15
+ SLOTSIZE $8000 ; ROM slot is $8000 bytes (LoROM 32K banks).
16
+ DEFAULTSLOT 0
17
+ SLOT 0 $8000 ; ROM
18
+ SLOT 1 $0 $2000 ; low WRAM mirror (tcc registers live at $0000)
19
+ SLOT 2 $2000 $E000 ; WRAM $2000-$FFFF (our HDMA tables land here)
20
+ SLOT 3 $0 $10000 ; bank $7F WRAM (tcc C globals)
21
+ .ENDME
22
+
23
+ .ROMBANKSIZE $8000 ; 32 KByte ROM banks
24
+ .ROMBANKS 8 ; 2 Mbits (256 KB) — matches PVSnesLib stock
25
+
26
+ .SNESHEADER
27
+ ID "SNES"
28
+
29
+ NAME "EMBER CIRCUIT " ; Program Title - 21 bytes, space-padded.
30
+ ; "123456789012345678901"
31
+
32
+ SLOWROM
33
+ LOROM
34
+
35
+ CARTRIDGETYPE $02 ; $02 = ROM + SRAM + battery ← THE SAVE SWITCH
36
+ ROMSIZE $08 ; $08 = 2 Mbits
37
+ SRAMSIZE $01 ; $01 = 2 KB SRAM, mapped at $70:0000-$07FF
38
+ COUNTRY $01 ; $01 = U.S.
39
+ LICENSEECODE $00
40
+ VERSION $00
41
+ .ENDSNES
42
+
43
+ .SNESNATIVEVECTOR ; Native Mode interrupt vector table
44
+ COP EmptyHandler
45
+ BRK EmptyHandler
46
+ ABORT EmptyHandler
47
+ NMI VBlank ; PVSnesLib's vblank.asm handler
48
+ IRQ EmptyHandler
49
+ .ENDNATIVEVECTOR
50
+
51
+ .SNESEMUVECTOR ; Emulation Mode interrupt vector table
52
+ COP EmptyHandler
53
+ ABORT EmptyHandler
54
+ NMI EmptyHandler
55
+ RESET tcc__start ; PVSnesLib crt0 entry
56
+ IRQBRK EmptyHandler
57
+ .ENDEMUVECTOR