c64-kb 0.17.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 (970) hide show
  1. package/CHANGELOG.md +2082 -0
  2. package/LICENSE +29 -0
  3. package/README.md +559 -0
  4. package/VERSION +25 -0
  5. package/dist/cli/setup.js +66 -0
  6. package/dist/cli/setup.js.map +1 -0
  7. package/dist/cli-memorize-audit.js +97 -0
  8. package/dist/cli-memorize-audit.js.map +1 -0
  9. package/dist/cli.js +335 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.js +83 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/context.js +53 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/domain/budget-notes.js +104 -0
  16. package/dist/domain/budget-notes.js.map +1 -0
  17. package/dist/domain/budget.js +417 -0
  18. package/dist/domain/budget.js.map +1 -0
  19. package/dist/domain/game-design.js +77 -0
  20. package/dist/domain/game-design.js.map +1 -0
  21. package/dist/domain/timing.js +39 -0
  22. package/dist/domain/timing.js.map +1 -0
  23. package/dist/graph/apply.js +132 -0
  24. package/dist/graph/apply.js.map +1 -0
  25. package/dist/graph/claims.js +231 -0
  26. package/dist/graph/claims.js.map +1 -0
  27. package/dist/graph/extract/archetype.js +118 -0
  28. package/dist/graph/extract/archetype.js.map +1 -0
  29. package/dist/graph/extract/common.js +69 -0
  30. package/dist/graph/extract/common.js.map +1 -0
  31. package/dist/graph/extract/failure.js +37 -0
  32. package/dist/graph/extract/failure.js.map +1 -0
  33. package/dist/graph/extract/game-design.js +189 -0
  34. package/dist/graph/extract/game-design.js.map +1 -0
  35. package/dist/graph/extract/hardware.js +124 -0
  36. package/dist/graph/extract/hardware.js.map +1 -0
  37. package/dist/graph/extract/pitfall.js +62 -0
  38. package/dist/graph/extract/pitfall.js.map +1 -0
  39. package/dist/graph/extract/raster-band.js +56 -0
  40. package/dist/graph/extract/raster-band.js.map +1 -0
  41. package/dist/graph/extract/recipe.js +71 -0
  42. package/dist/graph/extract/recipe.js.map +1 -0
  43. package/dist/graph/extract/technique-entities.js +180 -0
  44. package/dist/graph/extract/technique-entities.js.map +1 -0
  45. package/dist/graph/extract/technique.js +179 -0
  46. package/dist/graph/extract/technique.js.map +1 -0
  47. package/dist/graph/extract/toolchain.js +67 -0
  48. package/dist/graph/extract/toolchain.js.map +1 -0
  49. package/dist/graph/extract/types.js +3 -0
  50. package/dist/graph/extract/types.js.map +1 -0
  51. package/dist/graph/extract/vocabulary.js +65 -0
  52. package/dist/graph/extract/vocabulary.js.map +1 -0
  53. package/dist/graph/extract.js +43 -0
  54. package/dist/graph/extract.js.map +1 -0
  55. package/dist/graph/kernal-clobbers.js +64 -0
  56. package/dist/graph/kernal-clobbers.js.map +1 -0
  57. package/dist/graph/machine-variants.js +208 -0
  58. package/dist/graph/machine-variants.js.map +1 -0
  59. package/dist/ingest/files.js +99 -0
  60. package/dist/ingest/files.js.map +1 -0
  61. package/dist/ingest/passes.js +104 -0
  62. package/dist/ingest/passes.js.map +1 -0
  63. package/dist/ingest/points.js +50 -0
  64. package/dist/ingest/points.js.map +1 -0
  65. package/dist/ingest/report.js +140 -0
  66. package/dist/ingest/report.js.map +1 -0
  67. package/dist/ingest/tally.js +81 -0
  68. package/dist/ingest/tally.js.map +1 -0
  69. package/dist/ingest/verified-on.js +43 -0
  70. package/dist/ingest/verified-on.js.map +1 -0
  71. package/dist/ingest.js +135 -0
  72. package/dist/ingest.js.map +1 -0
  73. package/dist/schemas/cost-basis.js +5 -0
  74. package/dist/schemas/cost-basis.js.map +1 -0
  75. package/dist/schemas/machine-variant.js +25 -0
  76. package/dist/schemas/machine-variant.js.map +1 -0
  77. package/dist/schemas/plan-budget.js +121 -0
  78. package/dist/schemas/plan-budget.js.map +1 -0
  79. package/dist/schemas/tool-outputs.js +526 -0
  80. package/dist/schemas/tool-outputs.js.map +1 -0
  81. package/dist/server/define-tool.js +52 -0
  82. package/dist/server/define-tool.js.map +1 -0
  83. package/dist/server/defined-only.js +9 -0
  84. package/dist/server/defined-only.js.map +1 -0
  85. package/dist/server/tools-briefings.js +70 -0
  86. package/dist/server/tools-briefings.js.map +1 -0
  87. package/dist/server/tools-lookup.js +180 -0
  88. package/dist/server/tools-lookup.js.map +1 -0
  89. package/dist/server/tools-maintenance.js +116 -0
  90. package/dist/server/tools-maintenance.js.map +1 -0
  91. package/dist/server/tools-pitfalls.js +89 -0
  92. package/dist/server/tools-pitfalls.js.map +1 -0
  93. package/dist/server/tools-recipes.js +296 -0
  94. package/dist/server/tools-recipes.js.map +1 -0
  95. package/dist/server/tools-runtime.js +48 -0
  96. package/dist/server/tools-runtime.js.map +1 -0
  97. package/dist/server/tools.js +43 -0
  98. package/dist/server/tools.js.map +1 -0
  99. package/dist/server.js +95 -0
  100. package/dist/server.js.map +1 -0
  101. package/dist/services/analytics/schema.js +78 -0
  102. package/dist/services/analytics/schema.js.map +1 -0
  103. package/dist/services/analytics/statements.js +99 -0
  104. package/dist/services/analytics/statements.js.map +1 -0
  105. package/dist/services/analytics.js +195 -0
  106. package/dist/services/analytics.js.map +1 -0
  107. package/dist/services/bm25.js +158 -0
  108. package/dist/services/bm25.js.map +1 -0
  109. package/dist/services/chunker.js +81 -0
  110. package/dist/services/chunker.js.map +1 -0
  111. package/dist/services/embeddings.js +58 -0
  112. package/dist/services/embeddings.js.map +1 -0
  113. package/dist/services/falkor/base.js +85 -0
  114. package/dist/services/falkor/base.js.map +1 -0
  115. package/dist/services/falkor/links.js +361 -0
  116. package/dist/services/falkor/links.js.map +1 -0
  117. package/dist/services/falkor/nodes.js +183 -0
  118. package/dist/services/falkor/nodes.js.map +1 -0
  119. package/dist/services/falkor/params.js +45 -0
  120. package/dist/services/falkor/params.js.map +1 -0
  121. package/dist/services/falkor/schema.js +77 -0
  122. package/dist/services/falkor/schema.js.map +1 -0
  123. package/dist/services/falkor.js +100 -0
  124. package/dist/services/falkor.js.map +1 -0
  125. package/dist/services/qdrant.js +238 -0
  126. package/dist/services/qdrant.js.map +1 -0
  127. package/dist/services/versions.js +73 -0
  128. package/dist/services/versions.js.map +1 -0
  129. package/dist/services/vice-bin.js +51 -0
  130. package/dist/services/vice-bin.js.map +1 -0
  131. package/dist/tools/briefings/archetype.js +174 -0
  132. package/dist/tools/briefings/archetype.js.map +1 -0
  133. package/dist/tools/briefings/budget.js +177 -0
  134. package/dist/tools/briefings/budget.js.map +1 -0
  135. package/dist/tools/briefings/build-order.js +135 -0
  136. package/dist/tools/briefings/build-order.js.map +1 -0
  137. package/dist/tools/briefings/build.js +185 -0
  138. package/dist/tools/briefings/build.js.map +1 -0
  139. package/dist/tools/briefings/discovery.js +290 -0
  140. package/dist/tools/briefings/discovery.js.map +1 -0
  141. package/dist/tools/briefings/plan-pitfalls.js +69 -0
  142. package/dist/tools/briefings/plan-pitfalls.js.map +1 -0
  143. package/dist/tools/briefings/render.js +151 -0
  144. package/dist/tools/briefings/render.js.map +1 -0
  145. package/dist/tools/briefings/rows.js +41 -0
  146. package/dist/tools/briefings/rows.js.map +1 -0
  147. package/dist/tools/briefings/toolchain.js +63 -0
  148. package/dist/tools/briefings/toolchain.js.map +1 -0
  149. package/dist/tools/briefings/why-proposed.js +69 -0
  150. package/dist/tools/briefings/why-proposed.js.map +1 -0
  151. package/dist/tools/briefings.js +44 -0
  152. package/dist/tools/briefings.js.map +1 -0
  153. package/dist/tools/feedback.js +97 -0
  154. package/dist/tools/feedback.js.map +1 -0
  155. package/dist/tools/hydrate.js +75 -0
  156. package/dist/tools/hydrate.js.map +1 -0
  157. package/dist/tools/intelligence.js +67 -0
  158. package/dist/tools/intelligence.js.map +1 -0
  159. package/dist/tools/lint/asm-decimal.js +86 -0
  160. package/dist/tools/lint/asm-decimal.js.map +1 -0
  161. package/dist/tools/lint/asm-rules.js +221 -0
  162. package/dist/tools/lint/asm-rules.js.map +1 -0
  163. package/dist/tools/lint/asm-shared.js +3 -0
  164. package/dist/tools/lint/asm-shared.js.map +1 -0
  165. package/dist/tools/lint/c-rules.js +215 -0
  166. package/dist/tools/lint/c-rules.js.map +1 -0
  167. package/dist/tools/lint/text.js +122 -0
  168. package/dist/tools/lint/text.js.map +1 -0
  169. package/dist/tools/lint/types.js +40 -0
  170. package/dist/tools/lint/types.js.map +1 -0
  171. package/dist/tools/lint.js +76 -0
  172. package/dist/tools/lint.js.map +1 -0
  173. package/dist/tools/memorization-mcp.js +111 -0
  174. package/dist/tools/memorization-mcp.js.map +1 -0
  175. package/dist/tools/pitfalls/bm25.js +53 -0
  176. package/dist/tools/pitfalls/bm25.js.map +1 -0
  177. package/dist/tools/pitfalls/format.js +58 -0
  178. package/dist/tools/pitfalls/format.js.map +1 -0
  179. package/dist/tools/pitfalls/graph.js +124 -0
  180. package/dist/tools/pitfalls/graph.js.map +1 -0
  181. package/dist/tools/pitfalls.js +134 -0
  182. package/dist/tools/pitfalls.js.map +1 -0
  183. package/dist/tools/prompts.js +81 -0
  184. package/dist/tools/prompts.js.map +1 -0
  185. package/dist/tools/query/compatibility/closure.js +62 -0
  186. package/dist/tools/query/compatibility/closure.js.map +1 -0
  187. package/dist/tools/query/compatibility/facts.js +28 -0
  188. package/dist/tools/query/compatibility/facts.js.map +1 -0
  189. package/dist/tools/query/compatibility/fetch.js +164 -0
  190. package/dist/tools/query/compatibility/fetch.js.map +1 -0
  191. package/dist/tools/query/compatibility/hard-rules.js +159 -0
  192. package/dist/tools/query/compatibility/hard-rules.js.map +1 -0
  193. package/dist/tools/query/compatibility/index.js +27 -0
  194. package/dist/tools/query/compatibility/index.js.map +1 -0
  195. package/dist/tools/query/compatibility/kernal-zp-rule.js +90 -0
  196. package/dist/tools/query/compatibility/kernal-zp-rule.js.map +1 -0
  197. package/dist/tools/query/compatibility/render.js +106 -0
  198. package/dist/tools/query/compatibility/render.js.map +1 -0
  199. package/dist/tools/query/compatibility/rules.js +337 -0
  200. package/dist/tools/query/compatibility/rules.js.map +1 -0
  201. package/dist/tools/query/compatibility/unit-rules.js +253 -0
  202. package/dist/tools/query/compatibility/unit-rules.js.map +1 -0
  203. package/dist/tools/query/game-design.js +83 -0
  204. package/dist/tools/query/game-design.js.map +1 -0
  205. package/dist/tools/query/lookups.js +220 -0
  206. package/dist/tools/query/lookups.js.map +1 -0
  207. package/dist/tools/query/plan-budget.js +266 -0
  208. package/dist/tools/query/plan-budget.js.map +1 -0
  209. package/dist/tools/query/recipes.js +214 -0
  210. package/dist/tools/query/recipes.js.map +1 -0
  211. package/dist/tools/query/retrieval.js +128 -0
  212. package/dist/tools/query/retrieval.js.map +1 -0
  213. package/dist/tools/query/shared.js +121 -0
  214. package/dist/tools/query/shared.js.map +1 -0
  215. package/dist/tools/query/techniques.js +331 -0
  216. package/dist/tools/query/techniques.js.map +1 -0
  217. package/dist/tools/query/timing.js +106 -0
  218. package/dist/tools/query/timing.js.map +1 -0
  219. package/dist/tools/query/types.js +11 -0
  220. package/dist/tools/query/types.js.map +1 -0
  221. package/dist/tools/query.js +21 -0
  222. package/dist/tools/query.js.map +1 -0
  223. package/dist/tools/resources.js +186 -0
  224. package/dist/tools/resources.js.map +1 -0
  225. package/dist/tools/run-game.js +249 -0
  226. package/dist/tools/run-game.js.map +1 -0
  227. package/dist/tools/selfimprovement.js +367 -0
  228. package/dist/tools/selfimprovement.js.map +1 -0
  229. package/docker-compose.yml +35 -0
  230. package/docs/ARCHITECTURE.md +164 -0
  231. package/docs/CONVENTIONS-archetypes.md +158 -0
  232. package/docs/CONVENTIONS-failures.md +46 -0
  233. package/docs/CONVENTIONS-game-designs.md +75 -0
  234. package/docs/CONVENTIONS-hardware-reference.md +184 -0
  235. package/docs/CONVENTIONS-pitfalls.md +91 -0
  236. package/docs/CONVENTIONS-recipes.md +106 -0
  237. package/docs/CONVENTIONS-techniques.md +309 -0
  238. package/docs/CONVENTIONS-toolchain-reference.md +89 -0
  239. package/docs/ONTOLOGY.md +655 -0
  240. package/docs/art/art-production-reference.md +157 -0
  241. package/docs/art/asset-pipelines.md +586 -0
  242. package/docs/c64-failure-patterns.md +693 -0
  243. package/docs/demo-design/demo-composition.md +349 -0
  244. package/docs/demo-design/demo-design-philosophy.md +320 -0
  245. package/docs/demo-design/intro-cracktro-patterns.md +435 -0
  246. package/docs/figures/ctm-spd-embed-probe.png +0 -0
  247. package/docs/figures/dot-flag-mid-5000000.png +0 -0
  248. package/docs/figures/dot-flag-no-erase-12000000.png +0 -0
  249. package/docs/figures/edges.json +1 -0
  250. package/docs/figures/fig6-architecture.png +0 -0
  251. package/docs/figures/fig7-ontology.png +0 -0
  252. package/docs/figures/screen-dissolve-mid-frame25.png +0 -0
  253. package/docs/figures/screen-dissolve-wipe-frame25.png +0 -0
  254. package/docs/figures/spindle-two-parts-part1.png +0 -0
  255. package/docs/figures/spindle-two-parts-part2.png +0 -0
  256. package/docs/figures/starters/action-puzzle.png +0 -0
  257. package/docs/figures/starters/adventure.png +0 -0
  258. package/docs/figures/starters/beat-em-up.png +0 -0
  259. package/docs/figures/starters/demo.png +0 -0
  260. package/docs/figures/starters/platformer.png +0 -0
  261. package/docs/figures/starters/shmup-vertical.png +0 -0
  262. package/docs/figures/tape-kernal-master-ntsc.png +0 -0
  263. package/docs/figures/tape-kernal-master-pal.png +0 -0
  264. package/docs/figures/tape-turbo-loader-ntsc.png +0 -0
  265. package/docs/figures/tape-turbo-loader-pal.png +0 -0
  266. package/docs/figures/tape-turbo-master-ntsc.png +0 -0
  267. package/docs/figures/tape-turbo-master-pal.png +0 -0
  268. package/docs/figures/tech-tech-pad2-12000000.png +0 -0
  269. package/docs/figures/tech-tech-pad4-12000000.png +0 -0
  270. package/docs/figures/tech-tech-seven-12000000.png +0 -0
  271. package/docs/figures/twister-mid-5000000.png +0 -0
  272. package/docs/figures/twister-straight-12000000.png +0 -0
  273. package/docs/figures/vector-balls-nosort-ntsc.png +0 -0
  274. package/docs/figures/vector-balls-nosort.png +0 -0
  275. package/docs/formats/c64-file-formats.md +1212 -0
  276. package/docs/formats/iec-disk-reference.md +754 -0
  277. package/docs/game-design/c64-game-archetypes.md +273 -0
  278. package/docs/game-design/designs/falling-blocks.md +54 -0
  279. package/docs/game-design/designs/platformer-scaffold.md +48 -0
  280. package/docs/game-design/designs/simple-shmup.md +27 -0
  281. package/docs/game-design/enemy-behaviour-and-difficulty.md +349 -0
  282. package/docs/game-design/game-design-patterns.md +1189 -0
  283. package/docs/game-design/game-structure.md +354 -0
  284. package/docs/game-design/production-planning.md +349 -0
  285. package/docs/game-design/reference-game-sources.md +90 -0
  286. package/docs/hardware/6502-illegal-opcodes.md +1353 -0
  287. package/docs/hardware/6510-cpu-reference.md +2112 -0
  288. package/docs/hardware/c64-memory-map.md +3184 -0
  289. package/docs/hardware/c64-registers-reference.md +996 -0
  290. package/docs/hardware/cia-reference.md +1281 -0
  291. package/docs/hardware/kernal-routines-reference.md +1836 -0
  292. package/docs/hardware/pal-ntsc-reference.md +813 -0
  293. package/docs/hardware/sid-reference.md +1137 -0
  294. package/docs/hardware/vic-ii-reference.md +1714 -0
  295. package/docs/music/music-production-reference.md +403 -0
  296. package/docs/pitfalls/banking.md +1067 -0
  297. package/docs/pitfalls/cia.md +1147 -0
  298. package/docs/pitfalls/cpu.md +874 -0
  299. package/docs/pitfalls/input.md +282 -0
  300. package/docs/pitfalls/kernal-and-io.md +1615 -0
  301. package/docs/pitfalls/loader.md +1191 -0
  302. package/docs/pitfalls/logic.md +94 -0
  303. package/docs/pitfalls/maths.md +187 -0
  304. package/docs/pitfalls/raster-and-badline.md +721 -0
  305. package/docs/pitfalls/region-timing.md +660 -0
  306. package/docs/pitfalls/scroll.md +207 -0
  307. package/docs/pitfalls/sid.md +738 -0
  308. package/docs/pitfalls/sprite.md +979 -0
  309. package/docs/pitfalls/text-mode-render.md +1172 -0
  310. package/docs/recipes/cc65/cartridge-8k.md +398 -0
  311. package/docs/recipes/cc65/hello-world-conio.md +76 -0
  312. package/docs/recipes/cc65/memory-layout.md +312 -0
  313. package/docs/recipes/cc65/screenshots/README.md +14 -0
  314. package/docs/recipes/cc65/screenshots/cartridge-8k-ntsc.png +0 -0
  315. package/docs/recipes/cc65/screenshots/cartridge-8k.png +0 -0
  316. package/docs/recipes/cc65/screenshots/hello-world-conio.png +0 -0
  317. package/docs/recipes/cc65/screenshots/memory-layout-ntsc.png +0 -0
  318. package/docs/recipes/cc65/screenshots/memory-layout.png +0 -0
  319. package/docs/recipes/kickassembler/basic-float-calls.md +578 -0
  320. package/docs/recipes/kickassembler/basic-wedge.md +398 -0
  321. package/docs/recipes/kickassembler/big-font-scroller.md +620 -0
  322. package/docs/recipes/kickassembler/charset-copy-rom-to-ram.md +623 -0
  323. package/docs/recipes/kickassembler/cia-revision-detect.md +366 -0
  324. package/docs/recipes/kickassembler/colour-cycling.md +343 -0
  325. package/docs/recipes/kickassembler/colour-fade.md +303 -0
  326. package/docs/recipes/kickassembler/compare-16bit-signed.md +1007 -0
  327. package/docs/recipes/kickassembler/cracktro-template.md +526 -0
  328. package/docs/recipes/kickassembler/crt-banked.md +276 -0
  329. package/docs/recipes/kickassembler/dos-error-codes.md +466 -0
  330. package/docs/recipes/kickassembler/dot-flag.md +576 -0
  331. package/docs/recipes/kickassembler/drive-job-queue.md +667 -0
  332. package/docs/recipes/kickassembler/drive-via-probe.md +690 -0
  333. package/docs/recipes/kickassembler/dycp-scroller.md +568 -0
  334. package/docs/recipes/kickassembler/dypp-sprite-scroller.md +681 -0
  335. package/docs/recipes/kickassembler/dysp.md +670 -0
  336. package/docs/recipes/kickassembler/easyflash-save.md +800 -0
  337. package/docs/recipes/kickassembler/eight-way-scroll.md +1484 -0
  338. package/docs/recipes/kickassembler/file-io-roundtrip.md +546 -0
  339. package/docs/recipes/kickassembler/fire-effect.md +420 -0
  340. package/docs/recipes/kickassembler/fld.md +414 -0
  341. package/docs/recipes/kickassembler/fli-image.md +336 -0
  342. package/docs/recipes/kickassembler/four-player-read.md +672 -0
  343. package/docs/recipes/kickassembler/headless-verify.md +228 -0
  344. package/docs/recipes/kickassembler/hello-world.md +98 -0
  345. package/docs/recipes/kickassembler/high-score-insert.md +660 -0
  346. package/docs/recipes/kickassembler/hires-plot-line.md +723 -0
  347. package/docs/recipes/kickassembler/irq-chain.md +316 -0
  348. package/docs/recipes/kickassembler/irq-owns-port.md +668 -0
  349. package/docs/recipes/kickassembler/isometric-room.md +1145 -0
  350. package/docs/recipes/kickassembler/light-pen-read.md +926 -0
  351. package/docs/recipes/kickassembler/logic-rate-decoupling.md +670 -0
  352. package/docs/recipes/kickassembler/mci-interlace.md +543 -0
  353. package/docs/recipes/kickassembler/memory-layout.md +277 -0
  354. package/docs/recipes/kickassembler/mouse-1351-read.md +801 -0
  355. package/docs/recipes/kickassembler/nmi-timer-tick.md +562 -0
  356. package/docs/recipes/kickassembler/own-keyscan.md +881 -0
  357. package/docs/recipes/kickassembler/paddle-read.md +751 -0
  358. package/docs/recipes/kickassembler/palette-cells.md +219 -0
  359. package/docs/recipes/kickassembler/pseudo-3d-road.md +930 -0
  360. package/docs/recipes/kickassembler/pwm-digi.md +463 -0
  361. package/docs/recipes/kickassembler/raster-bars.md +264 -0
  362. package/docs/recipes/kickassembler/reu-dma.md +1019 -0
  363. package/docs/recipes/kickassembler/runtime-relocation.md +743 -0
  364. package/docs/recipes/kickassembler/screen-dissolve.md +545 -0
  365. package/docs/recipes/kickassembler/screen-wipe.md +408 -0
  366. package/docs/recipes/kickassembler/screenshots/README.md +72 -0
  367. package/docs/recipes/kickassembler/screenshots/basic-float-calls-ntsc.png +0 -0
  368. package/docs/recipes/kickassembler/screenshots/basic-float-calls.png +0 -0
  369. package/docs/recipes/kickassembler/screenshots/basic-wedge-ntsc.png +0 -0
  370. package/docs/recipes/kickassembler/screenshots/basic-wedge.png +0 -0
  371. package/docs/recipes/kickassembler/screenshots/big-font-scroller-ntsc.png +0 -0
  372. package/docs/recipes/kickassembler/screenshots/big-font-scroller.png +0 -0
  373. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram-ntsc.png +0 -0
  374. package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram.png +0 -0
  375. package/docs/recipes/kickassembler/screenshots/cia-revision-detect-ntsc.png +0 -0
  376. package/docs/recipes/kickassembler/screenshots/cia-revision-detect.png +0 -0
  377. package/docs/recipes/kickassembler/screenshots/colour-cycling-ntsc.png +0 -0
  378. package/docs/recipes/kickassembler/screenshots/colour-cycling.png +0 -0
  379. package/docs/recipes/kickassembler/screenshots/colour-fade-ntsc.png +0 -0
  380. package/docs/recipes/kickassembler/screenshots/colour-fade.png +0 -0
  381. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed-ntsc.png +0 -0
  382. package/docs/recipes/kickassembler/screenshots/compare-16bit-signed.png +0 -0
  383. package/docs/recipes/kickassembler/screenshots/cracktro-template.png +0 -0
  384. package/docs/recipes/kickassembler/screenshots/crt-banked-ntsc.png +0 -0
  385. package/docs/recipes/kickassembler/screenshots/crt-banked.png +0 -0
  386. package/docs/recipes/kickassembler/screenshots/dos-error-codes-ntsc.png +0 -0
  387. package/docs/recipes/kickassembler/screenshots/dos-error-codes.png +0 -0
  388. package/docs/recipes/kickassembler/screenshots/dot-flag-ntsc.png +0 -0
  389. package/docs/recipes/kickassembler/screenshots/dot-flag.png +0 -0
  390. package/docs/recipes/kickassembler/screenshots/drive-job-queue-ntsc.png +0 -0
  391. package/docs/recipes/kickassembler/screenshots/drive-job-queue.png +0 -0
  392. package/docs/recipes/kickassembler/screenshots/drive-via-probe-ntsc.png +0 -0
  393. package/docs/recipes/kickassembler/screenshots/drive-via-probe.png +0 -0
  394. package/docs/recipes/kickassembler/screenshots/dycp-scroller-ntsc.png +0 -0
  395. package/docs/recipes/kickassembler/screenshots/dycp-scroller.png +0 -0
  396. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller-ntsc.png +0 -0
  397. package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller.png +0 -0
  398. package/docs/recipes/kickassembler/screenshots/dysp-ntsc.png +0 -0
  399. package/docs/recipes/kickassembler/screenshots/dysp.png +0 -0
  400. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc-run2.png +0 -0
  401. package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc.png +0 -0
  402. package/docs/recipes/kickassembler/screenshots/easyflash-save-run2.png +0 -0
  403. package/docs/recipes/kickassembler/screenshots/easyflash-save.png +0 -0
  404. package/docs/recipes/kickassembler/screenshots/eight-way-scroll-ntsc.png +0 -0
  405. package/docs/recipes/kickassembler/screenshots/eight-way-scroll.png +0 -0
  406. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip-ntsc.png +0 -0
  407. package/docs/recipes/kickassembler/screenshots/file-io-roundtrip.png +0 -0
  408. package/docs/recipes/kickassembler/screenshots/fire-effect-ntsc.png +0 -0
  409. package/docs/recipes/kickassembler/screenshots/fire-effect.png +0 -0
  410. package/docs/recipes/kickassembler/screenshots/fld-ntsc.png +0 -0
  411. package/docs/recipes/kickassembler/screenshots/fld.png +0 -0
  412. package/docs/recipes/kickassembler/screenshots/fli-image.png +0 -0
  413. package/docs/recipes/kickassembler/screenshots/four-player-read-ntsc.png +0 -0
  414. package/docs/recipes/kickassembler/screenshots/four-player-read.png +0 -0
  415. package/docs/recipes/kickassembler/screenshots/headless-verify-ntsc.png +0 -0
  416. package/docs/recipes/kickassembler/screenshots/headless-verify.png +0 -0
  417. package/docs/recipes/kickassembler/screenshots/hello-world.png +0 -0
  418. package/docs/recipes/kickassembler/screenshots/high-score-insert-ntsc.png +0 -0
  419. package/docs/recipes/kickassembler/screenshots/high-score-insert.png +0 -0
  420. package/docs/recipes/kickassembler/screenshots/hires-plot-line-ntsc.png +0 -0
  421. package/docs/recipes/kickassembler/screenshots/hires-plot-line.png +0 -0
  422. package/docs/recipes/kickassembler/screenshots/irq-chain-ntsc.png +0 -0
  423. package/docs/recipes/kickassembler/screenshots/irq-chain.png +0 -0
  424. package/docs/recipes/kickassembler/screenshots/irq-owns-port-ntsc.png +0 -0
  425. package/docs/recipes/kickassembler/screenshots/irq-owns-port.png +0 -0
  426. package/docs/recipes/kickassembler/screenshots/isometric-room-ntsc.png +0 -0
  427. package/docs/recipes/kickassembler/screenshots/isometric-room.png +0 -0
  428. package/docs/recipes/kickassembler/screenshots/light-pen-read-ntsc.png +0 -0
  429. package/docs/recipes/kickassembler/screenshots/light-pen-read.png +0 -0
  430. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling-ntsc.png +0 -0
  431. package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling.png +0 -0
  432. package/docs/recipes/kickassembler/screenshots/mci-interlace-average.png +0 -0
  433. package/docs/recipes/kickassembler/screenshots/mci-interlace-frame-b.png +0 -0
  434. package/docs/recipes/kickassembler/screenshots/mci-interlace-ntsc.png +0 -0
  435. package/docs/recipes/kickassembler/screenshots/mci-interlace.png +0 -0
  436. package/docs/recipes/kickassembler/screenshots/memory-layout-ntsc.png +0 -0
  437. package/docs/recipes/kickassembler/screenshots/memory-layout.png +0 -0
  438. package/docs/recipes/kickassembler/screenshots/mouse-1351-read-ntsc.png +0 -0
  439. package/docs/recipes/kickassembler/screenshots/mouse-1351-read.png +0 -0
  440. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick-ntsc.png +0 -0
  441. package/docs/recipes/kickassembler/screenshots/nmi-timer-tick.png +0 -0
  442. package/docs/recipes/kickassembler/screenshots/own-keyscan-ntsc.png +0 -0
  443. package/docs/recipes/kickassembler/screenshots/own-keyscan.png +0 -0
  444. package/docs/recipes/kickassembler/screenshots/paddle-read-ntsc.png +0 -0
  445. package/docs/recipes/kickassembler/screenshots/paddle-read.png +0 -0
  446. package/docs/recipes/kickassembler/screenshots/palette-cells-ntsc.png +0 -0
  447. package/docs/recipes/kickassembler/screenshots/palette-cells.png +0 -0
  448. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road-ntsc.png +0 -0
  449. package/docs/recipes/kickassembler/screenshots/pseudo-3d-road.png +0 -0
  450. package/docs/recipes/kickassembler/screenshots/pwm-digi-ntsc.png +0 -0
  451. package/docs/recipes/kickassembler/screenshots/pwm-digi.png +0 -0
  452. package/docs/recipes/kickassembler/screenshots/raster-bars.png +0 -0
  453. package/docs/recipes/kickassembler/screenshots/reu-dma-ntsc.png +0 -0
  454. package/docs/recipes/kickassembler/screenshots/reu-dma.png +0 -0
  455. package/docs/recipes/kickassembler/screenshots/runtime-relocation-ntsc.png +0 -0
  456. package/docs/recipes/kickassembler/screenshots/runtime-relocation.png +0 -0
  457. package/docs/recipes/kickassembler/screenshots/screen-dissolve-ntsc.png +0 -0
  458. package/docs/recipes/kickassembler/screenshots/screen-dissolve.png +0 -0
  459. package/docs/recipes/kickassembler/screenshots/screen-wipe-ntsc.png +0 -0
  460. package/docs/recipes/kickassembler/screenshots/screen-wipe.png +0 -0
  461. package/docs/recipes/kickassembler/screenshots/scroll-panel-split-ntsc.png +0 -0
  462. package/docs/recipes/kickassembler/screenshots/scroll-panel-split.png +0 -0
  463. package/docs/recipes/kickassembler/screenshots/sfx-in-player-ntsc.png +0 -0
  464. package/docs/recipes/kickassembler/screenshots/sfx-in-player.png +0 -0
  465. package/docs/recipes/kickassembler/screenshots/shadebobs-ntsc.png +0 -0
  466. package/docs/recipes/kickassembler/screenshots/shadebobs.png +0 -0
  467. package/docs/recipes/kickassembler/screenshots/sideborder-open.png +0 -0
  468. package/docs/recipes/kickassembler/screenshots/sine-scroller.png +0 -0
  469. package/docs/recipes/kickassembler/screenshots/sine-table-runtime-ntsc.png +0 -0
  470. package/docs/recipes/kickassembler/screenshots/sine-table-runtime.png +0 -0
  471. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted-ntsc.png +0 -0
  472. package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted.png +0 -0
  473. package/docs/recipes/kickassembler/screenshots/speedcode-generator-ntsc.png +0 -0
  474. package/docs/recipes/kickassembler/screenshots/speedcode-generator.png +0 -0
  475. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller-ntsc.png +0 -0
  476. package/docs/recipes/kickassembler/screenshots/sprite-border-scroller.png +0 -0
  477. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip-ntsc.png +0 -0
  478. package/docs/recipes/kickassembler/screenshots/sprite-cache-flip.png +0 -0
  479. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-24.png +0 -0
  480. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game-ntsc.png +0 -0
  481. package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game.png +0 -0
  482. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes-ntsc.png +0 -0
  483. package/docs/recipes/kickassembler/screenshots/sprite-priority-classes.png +0 -0
  484. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain-ntsc.png +0 -0
  485. package/docs/recipes/kickassembler/screenshots/sprite-sine-chain.png +0 -0
  486. package/docs/recipes/kickassembler/screenshots/sprite-stretcher-ntsc.png +0 -0
  487. package/docs/recipes/kickassembler/screenshots/sprite-stretcher.png +0 -0
  488. package/docs/recipes/kickassembler/screenshots/sprites-only-screen-ntsc.png +0 -0
  489. package/docs/recipes/kickassembler/screenshots/sprites-only-screen.png +0 -0
  490. package/docs/recipes/kickassembler/screenshots/sqrt-atan2-ntsc.png +0 -0
  491. package/docs/recipes/kickassembler/screenshots/sqrt-atan2.png +0 -0
  492. package/docs/recipes/kickassembler/screenshots/stable-raster-irq-control.png +0 -0
  493. package/docs/recipes/kickassembler/screenshots/stable-raster-irq.png +0 -0
  494. package/docs/recipes/kickassembler/screenshots/tech-tech-ntsc.png +0 -0
  495. package/docs/recipes/kickassembler/screenshots/tech-tech.png +0 -0
  496. package/docs/recipes/kickassembler/screenshots/tod-alarm-ntsc.png +0 -0
  497. package/docs/recipes/kickassembler/screenshots/tod-alarm.png +0 -0
  498. package/docs/recipes/kickassembler/screenshots/topbottom-border-open.png +0 -0
  499. package/docs/recipes/kickassembler/screenshots/twister-ntsc.png +0 -0
  500. package/docs/recipes/kickassembler/screenshots/twister.png +0 -0
  501. package/docs/recipes/kickassembler/screenshots/unit-test-driver-ntsc.png +0 -0
  502. package/docs/recipes/kickassembler/screenshots/unit-test-driver.png +0 -0
  503. package/docs/recipes/kickassembler/screenshots/vector-balls-ntsc.png +0 -0
  504. package/docs/recipes/kickassembler/screenshots/vector-balls.png +0 -0
  505. package/docs/recipes/kickassembler/screenshots/wireframe-ships-ntsc.png +0 -0
  506. package/docs/recipes/kickassembler/screenshots/wireframe-ships.png +0 -0
  507. package/docs/recipes/kickassembler/scroll-panel-split.md +381 -0
  508. package/docs/recipes/kickassembler/sfx-in-player.md +907 -0
  509. package/docs/recipes/kickassembler/shadebobs.md +522 -0
  510. package/docs/recipes/kickassembler/sideborder-open.md +338 -0
  511. package/docs/recipes/kickassembler/sine-scroller.md +321 -0
  512. package/docs/recipes/kickassembler/sine-table-runtime.md +815 -0
  513. package/docs/recipes/kickassembler/software-sprite-preshifted.md +725 -0
  514. package/docs/recipes/kickassembler/speedcode-generator.md +606 -0
  515. package/docs/recipes/kickassembler/sprite-border-scroller.md +696 -0
  516. package/docs/recipes/kickassembler/sprite-cache-flip.md +1071 -0
  517. package/docs/recipes/kickassembler/sprite-multiplex-24.md +326 -0
  518. package/docs/recipes/kickassembler/sprite-multiplex-game.md +986 -0
  519. package/docs/recipes/kickassembler/sprite-priority-classes.md +463 -0
  520. package/docs/recipes/kickassembler/sprite-sine-chain.md +338 -0
  521. package/docs/recipes/kickassembler/sprite-stretcher.md +501 -0
  522. package/docs/recipes/kickassembler/sprites-only-screen.md +550 -0
  523. package/docs/recipes/kickassembler/sqrt-atan2.md +1014 -0
  524. package/docs/recipes/kickassembler/stable-raster-irq.md +360 -0
  525. package/docs/recipes/kickassembler/tape-turbo-loader.md +875 -0
  526. package/docs/recipes/kickassembler/tech-tech.md +679 -0
  527. package/docs/recipes/kickassembler/tod-alarm.md +754 -0
  528. package/docs/recipes/kickassembler/topbottom-border-open.md +407 -0
  529. package/docs/recipes/kickassembler/twister.md +518 -0
  530. package/docs/recipes/kickassembler/unit-test-driver.md +314 -0
  531. package/docs/recipes/kickassembler/vector-balls.md +545 -0
  532. package/docs/recipes/kickassembler/wireframe-ships.md +2324 -0
  533. package/docs/recipes/oscar64/actor-activation-window.md +807 -0
  534. package/docs/recipes/oscar64/adventure-engine.md +1094 -0
  535. package/docs/recipes/oscar64/attract-replay.md +465 -0
  536. package/docs/recipes/oscar64/beat-em-up-lanes.md +563 -0
  537. package/docs/recipes/oscar64/bfs-distance-map.md +723 -0
  538. package/docs/recipes/oscar64/bitmap-koala-viewer.md +355 -0
  539. package/docs/recipes/oscar64/car-contact.md +950 -0
  540. package/docs/recipes/oscar64/cave-scan.md +609 -0
  541. package/docs/recipes/oscar64/char-bullets.md +477 -0
  542. package/docs/recipes/oscar64/charset-animation.md +383 -0
  543. package/docs/recipes/oscar64/charset-parallax.md +401 -0
  544. package/docs/recipes/oscar64/destructible-terrain.md +1099 -0
  545. package/docs/recipes/oscar64/difficulty-tables.md +654 -0
  546. package/docs/recipes/oscar64/dig-and-guards.md +975 -0
  547. package/docs/recipes/oscar64/directory-reader.md +535 -0
  548. package/docs/recipes/oscar64/divide-check.md +581 -0
  549. package/docs/recipes/oscar64/double-buffer-nomirror.md +205 -0
  550. package/docs/recipes/oscar64/double-buffer.md +255 -0
  551. package/docs/recipes/oscar64/falling-blocks.md +874 -0
  552. package/docs/recipes/oscar64/fixed-point-jump-velocity.md +289 -0
  553. package/docs/recipes/oscar64/fixed-point-jump.md +210 -0
  554. package/docs/recipes/oscar64/flip-screen-rooms.md +793 -0
  555. package/docs/recipes/oscar64/frame-sync-loop-overrun.md +214 -0
  556. package/docs/recipes/oscar64/frame-sync-loop.md +254 -0
  557. package/docs/recipes/oscar64/game-tree-search.md +743 -0
  558. package/docs/recipes/oscar64/ghost-targeting.md +867 -0
  559. package/docs/recipes/oscar64/headless-verify.md +345 -0
  560. package/docs/recipes/oscar64/hello-world.md +83 -0
  561. package/docs/recipes/oscar64/high-score-persist.md +772 -0
  562. package/docs/recipes/oscar64/iffl-kernal-skip.md +421 -0
  563. package/docs/recipes/oscar64/joystick-input.md +358 -0
  564. package/docs/recipes/oscar64/lane-pursuit.md +1028 -0
  565. package/docs/recipes/oscar64/level-rle-decoder.md +620 -0
  566. package/docs/recipes/oscar64/lfsr-random-seed2.md +338 -0
  567. package/docs/recipes/oscar64/lfsr-random.md +403 -0
  568. package/docs/recipes/oscar64/load-asset-runtime.md +492 -0
  569. package/docs/recipes/oscar64/memory-layout.md +232 -0
  570. package/docs/recipes/oscar64/mixed-fighters.md +781 -0
  571. package/docs/recipes/oscar64/multi-sprite-object.md +533 -0
  572. package/docs/recipes/oscar64/nav-area-pathfinding.md +881 -0
  573. package/docs/recipes/oscar64/object-pool.md +572 -0
  574. package/docs/recipes/oscar64/pal-ntsc-detect.md +257 -0
  575. package/docs/recipes/oscar64/password-state.md +532 -0
  576. package/docs/recipes/oscar64/per-frame-hitbox.md +651 -0
  577. package/docs/recipes/oscar64/petscii-screen-codes.md +428 -0
  578. package/docs/recipes/oscar64/platformer-scaffold.md +1467 -0
  579. package/docs/recipes/oscar64/print-number.md +367 -0
  580. package/docs/recipes/oscar64/raster-bars.md +239 -0
  581. package/docs/recipes/oscar64/raster-profile-bars.md +404 -0
  582. package/docs/recipes/oscar64/rel-side-sectors.md +391 -0
  583. package/docs/recipes/oscar64/relative-file-records.md +378 -0
  584. package/docs/recipes/oscar64/save-load-seq-file.md +365 -0
  585. package/docs/recipes/oscar64/screenshots/README.md +99 -0
  586. package/docs/recipes/oscar64/screenshots/actor-activation-window-ntsc.png +0 -0
  587. package/docs/recipes/oscar64/screenshots/actor-activation-window.png +0 -0
  588. package/docs/recipes/oscar64/screenshots/adventure-engine-ntsc.png +0 -0
  589. package/docs/recipes/oscar64/screenshots/adventure-engine.png +0 -0
  590. package/docs/recipes/oscar64/screenshots/attract-replay-ntsc.png +0 -0
  591. package/docs/recipes/oscar64/screenshots/attract-replay.png +0 -0
  592. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes-ntsc.png +0 -0
  593. package/docs/recipes/oscar64/screenshots/beat-em-up-lanes.png +0 -0
  594. package/docs/recipes/oscar64/screenshots/bfs-distance-map-ntsc.png +0 -0
  595. package/docs/recipes/oscar64/screenshots/bfs-distance-map.png +0 -0
  596. package/docs/recipes/oscar64/screenshots/bitmap-koala-viewer.png +0 -0
  597. package/docs/recipes/oscar64/screenshots/car-contact-ntsc.png +0 -0
  598. package/docs/recipes/oscar64/screenshots/car-contact.png +0 -0
  599. package/docs/recipes/oscar64/screenshots/cave-scan-ntsc.png +0 -0
  600. package/docs/recipes/oscar64/screenshots/cave-scan.png +0 -0
  601. package/docs/recipes/oscar64/screenshots/char-bullets-ntsc.png +0 -0
  602. package/docs/recipes/oscar64/screenshots/char-bullets.png +0 -0
  603. package/docs/recipes/oscar64/screenshots/charset-animation-ntsc.png +0 -0
  604. package/docs/recipes/oscar64/screenshots/charset-animation.png +0 -0
  605. package/docs/recipes/oscar64/screenshots/charset-parallax-ntsc.png +0 -0
  606. package/docs/recipes/oscar64/screenshots/charset-parallax.png +0 -0
  607. package/docs/recipes/oscar64/screenshots/destructible-terrain-ntsc.png +0 -0
  608. package/docs/recipes/oscar64/screenshots/destructible-terrain.png +0 -0
  609. package/docs/recipes/oscar64/screenshots/difficulty-tables-ntsc.png +0 -0
  610. package/docs/recipes/oscar64/screenshots/difficulty-tables.png +0 -0
  611. package/docs/recipes/oscar64/screenshots/dig-and-guards-ntsc.png +0 -0
  612. package/docs/recipes/oscar64/screenshots/dig-and-guards.png +0 -0
  613. package/docs/recipes/oscar64/screenshots/directory-reader-ntsc.png +0 -0
  614. package/docs/recipes/oscar64/screenshots/directory-reader.png +0 -0
  615. package/docs/recipes/oscar64/screenshots/divide-check-ntsc.png +0 -0
  616. package/docs/recipes/oscar64/screenshots/divide-check.png +0 -0
  617. package/docs/recipes/oscar64/screenshots/double-buffer-nomirror.png +0 -0
  618. package/docs/recipes/oscar64/screenshots/double-buffer-ntsc.png +0 -0
  619. package/docs/recipes/oscar64/screenshots/double-buffer.png +0 -0
  620. package/docs/recipes/oscar64/screenshots/falling-blocks-ntsc.png +0 -0
  621. package/docs/recipes/oscar64/screenshots/falling-blocks.png +0 -0
  622. package/docs/recipes/oscar64/screenshots/fixed-point-jump-ntsc.png +0 -0
  623. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity-ntsc.png +0 -0
  624. package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity.png +0 -0
  625. package/docs/recipes/oscar64/screenshots/fixed-point-jump.png +0 -0
  626. package/docs/recipes/oscar64/screenshots/flip-screen-rooms-ntsc.png +0 -0
  627. package/docs/recipes/oscar64/screenshots/flip-screen-rooms.png +0 -0
  628. package/docs/recipes/oscar64/screenshots/frame-sync-loop-ntsc.png +0 -0
  629. package/docs/recipes/oscar64/screenshots/frame-sync-loop-overrun.png +0 -0
  630. package/docs/recipes/oscar64/screenshots/frame-sync-loop.png +0 -0
  631. package/docs/recipes/oscar64/screenshots/game-tree-search-ntsc.png +0 -0
  632. package/docs/recipes/oscar64/screenshots/game-tree-search.png +0 -0
  633. package/docs/recipes/oscar64/screenshots/ghost-targeting-ntsc.png +0 -0
  634. package/docs/recipes/oscar64/screenshots/ghost-targeting.png +0 -0
  635. package/docs/recipes/oscar64/screenshots/headless-verify-ntsc.png +0 -0
  636. package/docs/recipes/oscar64/screenshots/headless-verify.png +0 -0
  637. package/docs/recipes/oscar64/screenshots/hello-world.png +0 -0
  638. package/docs/recipes/oscar64/screenshots/high-score-persist-ntsc.png +0 -0
  639. package/docs/recipes/oscar64/screenshots/high-score-persist.png +0 -0
  640. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip-ntsc.png +0 -0
  641. package/docs/recipes/oscar64/screenshots/iffl-kernal-skip.png +0 -0
  642. package/docs/recipes/oscar64/screenshots/joystick-input-ntsc.png +0 -0
  643. package/docs/recipes/oscar64/screenshots/joystick-input.png +0 -0
  644. package/docs/recipes/oscar64/screenshots/lane-pursuit-ntsc.png +0 -0
  645. package/docs/recipes/oscar64/screenshots/lane-pursuit.png +0 -0
  646. package/docs/recipes/oscar64/screenshots/level-rle-decoder-ntsc.png +0 -0
  647. package/docs/recipes/oscar64/screenshots/level-rle-decoder.png +0 -0
  648. package/docs/recipes/oscar64/screenshots/lfsr-random-ntsc.png +0 -0
  649. package/docs/recipes/oscar64/screenshots/lfsr-random-seed2.png +0 -0
  650. package/docs/recipes/oscar64/screenshots/lfsr-random.png +0 -0
  651. package/docs/recipes/oscar64/screenshots/load-asset-runtime-ntsc.png +0 -0
  652. package/docs/recipes/oscar64/screenshots/load-asset-runtime.png +0 -0
  653. package/docs/recipes/oscar64/screenshots/memory-layout-ntsc.png +0 -0
  654. package/docs/recipes/oscar64/screenshots/memory-layout.png +0 -0
  655. package/docs/recipes/oscar64/screenshots/mixed-fighters-ntsc.png +0 -0
  656. package/docs/recipes/oscar64/screenshots/mixed-fighters.png +0 -0
  657. package/docs/recipes/oscar64/screenshots/multi-sprite-object-ntsc.png +0 -0
  658. package/docs/recipes/oscar64/screenshots/multi-sprite-object.png +0 -0
  659. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding-ntsc.png +0 -0
  660. package/docs/recipes/oscar64/screenshots/nav-area-pathfinding.png +0 -0
  661. package/docs/recipes/oscar64/screenshots/object-pool-ntsc.png +0 -0
  662. package/docs/recipes/oscar64/screenshots/object-pool.png +0 -0
  663. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-ntsc.png +0 -0
  664. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-oldntsc.png +0 -0
  665. package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-pal.png +0 -0
  666. package/docs/recipes/oscar64/screenshots/password-state-ntsc.png +0 -0
  667. package/docs/recipes/oscar64/screenshots/password-state.png +0 -0
  668. package/docs/recipes/oscar64/screenshots/per-frame-hitbox-ntsc.png +0 -0
  669. package/docs/recipes/oscar64/screenshots/per-frame-hitbox.png +0 -0
  670. package/docs/recipes/oscar64/screenshots/petscii-screen-codes-ntsc.png +0 -0
  671. package/docs/recipes/oscar64/screenshots/petscii-screen-codes.png +0 -0
  672. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64-ntsc.png +0 -0
  673. package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64.png +0 -0
  674. package/docs/recipes/oscar64/screenshots/platformer-scaffold-ntsc.png +0 -0
  675. package/docs/recipes/oscar64/screenshots/platformer-scaffold.png +0 -0
  676. package/docs/recipes/oscar64/screenshots/print-number-ntsc.png +0 -0
  677. package/docs/recipes/oscar64/screenshots/print-number.png +0 -0
  678. package/docs/recipes/oscar64/screenshots/raster-bars.png +0 -0
  679. package/docs/recipes/oscar64/screenshots/raster-profile-bars-ntsc.png +0 -0
  680. package/docs/recipes/oscar64/screenshots/raster-profile-bars.png +0 -0
  681. package/docs/recipes/oscar64/screenshots/rel-side-sectors-ntsc.png +0 -0
  682. package/docs/recipes/oscar64/screenshots/rel-side-sectors.png +0 -0
  683. package/docs/recipes/oscar64/screenshots/relative-file-records-ntsc.png +0 -0
  684. package/docs/recipes/oscar64/screenshots/relative-file-records.png +0 -0
  685. package/docs/recipes/oscar64/screenshots/save-load-seq-file-ntsc.png +0 -0
  686. package/docs/recipes/oscar64/screenshots/save-load-seq-file.png +0 -0
  687. package/docs/recipes/oscar64/screenshots/seeded-level-fill-ntsc.png +0 -0
  688. package/docs/recipes/oscar64/screenshots/seeded-level-fill.png +0 -0
  689. package/docs/recipes/oscar64/screenshots/sfx-engine-ntsc.png +0 -0
  690. package/docs/recipes/oscar64/screenshots/sfx-engine.png +0 -0
  691. package/docs/recipes/oscar64/screenshots/sid-music-player.png +0 -0
  692. package/docs/recipes/oscar64/screenshots/simple-shmup.png +0 -0
  693. package/docs/recipes/oscar64/screenshots/slope-collision-ntsc.png +0 -0
  694. package/docs/recipes/oscar64/screenshots/slope-collision.png +0 -0
  695. package/docs/recipes/oscar64/screenshots/soft-scroll-h.png +0 -0
  696. package/docs/recipes/oscar64/screenshots/sprite-animation-table-ntsc.png +0 -0
  697. package/docs/recipes/oscar64/screenshots/sprite-animation-table.png +0 -0
  698. package/docs/recipes/oscar64/screenshots/sprite-multiplex-8.png +0 -0
  699. package/docs/recipes/oscar64/screenshots/stable-raster-irq.png +0 -0
  700. package/docs/recipes/oscar64/screenshots/text-input-ntsc.png +0 -0
  701. package/docs/recipes/oscar64/screenshots/text-input.png +0 -0
  702. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-gameover.png +0 -0
  703. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-notrail-control.png +0 -0
  704. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ntsc.png +0 -0
  705. package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ungated-control.png +0 -0
  706. package/docs/recipes/oscar64/screenshots/text-overlay-playfield.png +0 -0
  707. package/docs/recipes/oscar64/screenshots/text-window-menu-ntsc.png +0 -0
  708. package/docs/recipes/oscar64/screenshots/text-window-menu.png +0 -0
  709. package/docs/recipes/oscar64/screenshots/tile-grid-collision-ntsc.png +0 -0
  710. package/docs/recipes/oscar64/screenshots/tile-grid-collision.png +0 -0
  711. package/docs/recipes/oscar64/screenshots/tile-map-render-ntsc.png +0 -0
  712. package/docs/recipes/oscar64/screenshots/tile-map-render.png +0 -0
  713. package/docs/recipes/oscar64/screenshots/two-player-ntsc.png +0 -0
  714. package/docs/recipes/oscar64/screenshots/two-player.png +0 -0
  715. package/docs/recipes/oscar64/screenshots/two-word-parser-ntsc.png +0 -0
  716. package/docs/recipes/oscar64/screenshots/two-word-parser.png +0 -0
  717. package/docs/recipes/oscar64/screenshots/vehicle-control-ntsc.png +0 -0
  718. package/docs/recipes/oscar64/screenshots/vehicle-control.png +0 -0
  719. package/docs/recipes/oscar64/screenshots/wave-director-ntsc.png +0 -0
  720. package/docs/recipes/oscar64/screenshots/wave-director.png +0 -0
  721. package/docs/recipes/oscar64/seeded-level-fill.md +364 -0
  722. package/docs/recipes/oscar64/sfx-engine.md +514 -0
  723. package/docs/recipes/oscar64/sid-music-player.md +441 -0
  724. package/docs/recipes/oscar64/simple-shmup.md +1000 -0
  725. package/docs/recipes/oscar64/slope-collision.md +610 -0
  726. package/docs/recipes/oscar64/soft-scroll-h.md +261 -0
  727. package/docs/recipes/oscar64/sprite-animation-table.md +671 -0
  728. package/docs/recipes/oscar64/sprite-multiplex-8.md +314 -0
  729. package/docs/recipes/oscar64/stable-raster-irq.md +236 -0
  730. package/docs/recipes/oscar64/text-input.md +274 -0
  731. package/docs/recipes/oscar64/text-overlay-playfield.md +617 -0
  732. package/docs/recipes/oscar64/text-window-menu.md +551 -0
  733. package/docs/recipes/oscar64/tile-grid-collision.md +563 -0
  734. package/docs/recipes/oscar64/tile-map-render.md +395 -0
  735. package/docs/recipes/oscar64/two-player.md +528 -0
  736. package/docs/recipes/oscar64/two-word-parser.md +510 -0
  737. package/docs/recipes/oscar64/vehicle-control.md +771 -0
  738. package/docs/recipes/oscar64/wave-director.md +787 -0
  739. package/docs/recipes/runs.json +1606 -0
  740. package/docs/runtime/sim6502-reference.md +466 -0
  741. package/docs/runtime/vice-mcp-reference.md +351 -0
  742. package/docs/runtime/vice-reference.md +1393 -0
  743. package/docs/techniques/bitmap-modes.md +685 -0
  744. package/docs/techniques/cpu-cycle-tricks.md +1570 -0
  745. package/docs/techniques/effects-vector-3d.md +1431 -0
  746. package/docs/techniques/file-io.md +1427 -0
  747. package/docs/techniques/input.md +1072 -0
  748. package/docs/techniques/loaders-packers.md +768 -0
  749. package/docs/techniques/logic.md +3091 -0
  750. package/docs/techniques/maths.md +1524 -0
  751. package/docs/techniques/memory-banking.md +1686 -0
  752. package/docs/techniques/music-sid.md +1144 -0
  753. package/docs/techniques/raster.md +1543 -0
  754. package/docs/techniques/scroll.md +1292 -0
  755. package/docs/techniques/sprite.md +2566 -0
  756. package/docs/techniques/text-mode-render.md +717 -0
  757. package/docs/techniques/text.md +1095 -0
  758. package/docs/techniques/transitions.md +405 -0
  759. package/docs/toolchains/cartconv-reference.md +262 -0
  760. package/docs/toolchains/cc1541-reference.md +316 -0
  761. package/docs/toolchains/cc65-reference.md +667 -0
  762. package/docs/toolchains/error-sources/cc65/README.md +1 -0
  763. package/docs/toolchains/error-sources/cc65/missing-setcpu.s +4 -0
  764. package/docs/toolchains/error-sources/cc65/range-error.s +4 -0
  765. package/docs/toolchains/error-sources/cc65/segment-overflow.c +6 -0
  766. package/docs/toolchains/error-sources/cc65/unresolved-external.c +6 -0
  767. package/docs/toolchains/error-sources/kickassembler/README.md +1 -0
  768. package/docs/toolchains/error-sources/kickassembler/branch-out-of-range.asm +4 -0
  769. package/docs/toolchains/error-sources/kickassembler/failed-assert.asm +3 -0
  770. package/docs/toolchains/error-sources/kickassembler/flat-lib.asm +4 -0
  771. package/docs/toolchains/error-sources/kickassembler/import-source-no-namespace.asm +5 -0
  772. package/docs/toolchains/error-sources/kickassembler/macro-without-parentheses.asm +6 -0
  773. package/docs/toolchains/error-sources/kickassembler/memory-block-overlap.asm +4 -0
  774. package/docs/toolchains/error-sources/kickassembler/symbol-clash-lib.asm +5 -0
  775. package/docs/toolchains/error-sources/kickassembler/symbol-clash-main.asm +6 -0
  776. package/docs/toolchains/error-sources/kickassembler/unknown-symbol.asm +4 -0
  777. package/docs/toolchains/error-sources/oscar64/README.md +1 -0
  778. package/docs/toolchains/error-sources/oscar64/asm-addressing-mode.c +7 -0
  779. package/docs/toolchains/error-sources/oscar64/region-overflow.c +6 -0
  780. package/docs/toolchains/error-sources/oscar64/undefined-extern-var.c +5 -0
  781. package/docs/toolchains/error-sources/oscar64/undefined-extern.c +6 -0
  782. package/docs/toolchains/error-sources/oscar64/unknown-vic-field.c +6 -0
  783. package/docs/toolchains/error-sources/oscar64/void-main.c +3 -0
  784. package/docs/toolchains/kickassembler-reference.md +1020 -0
  785. package/docs/toolchains/memory-layout-planning.md +362 -0
  786. package/docs/toolchains/oscar64-headers-reference.md +583 -0
  787. package/docs/toolchains/oscar64-reference.md +892 -0
  788. package/docs/toolchains/petcat-reference.md +290 -0
  789. package/docs/toolchains/png2prg.md +188 -0
  790. package/docs/toolchains/release-disk.md +314 -0
  791. package/docs/toolchains/sidreloc.md +236 -0
  792. package/docs/toolchains/spindle-reference.md +487 -0
  793. package/docs/toolchains/tape-mastering.md +592 -0
  794. package/docs/toolchains/unit-testing-6502.md +281 -0
  795. package/docs/workflow/agent-harness.md +478 -0
  796. package/package.json +105 -0
  797. package/templates/_harness/CLAUDE.md.template +91 -0
  798. package/templates/_harness/PLAN.md.template +72 -0
  799. package/templates/_harness/check.py +442 -0
  800. package/templates/_harness/claude/settings.json +17 -0
  801. package/templates/_harness/gen-asm-header.py +96 -0
  802. package/templates/_harness/harness.mk +273 -0
  803. package/templates/_harness/hooks/plan-gate.py +185 -0
  804. package/templates/_harness/meter/frame_meter.asm +311 -0
  805. package/templates/_harness/meter/frame_meter.c +155 -0
  806. package/templates/_harness/meter/frame_meter.h +80 -0
  807. package/templates/_harness/zp-used.py +104 -0
  808. package/templates/action-puzzle/.claude/settings.json +17 -0
  809. package/templates/action-puzzle/.mcp.json +10 -0
  810. package/templates/action-puzzle/CLAUDE.md +120 -0
  811. package/templates/action-puzzle/Makefile +125 -0
  812. package/templates/action-puzzle/PLAN.md +388 -0
  813. package/templates/action-puzzle/README.md +240 -0
  814. package/templates/action-puzzle/expect.json +25 -0
  815. package/templates/action-puzzle/src/cave.c +280 -0
  816. package/templates/action-puzzle/src/cave.h +80 -0
  817. package/templates/action-puzzle/src/gen_autopilot.h +20 -0
  818. package/templates/action-puzzle/src/gen_caves.h +59 -0
  819. package/templates/action-puzzle/src/gen_notes.h +16 -0
  820. package/templates/action-puzzle/src/hiscore.c +152 -0
  821. package/templates/action-puzzle/src/hiscore.h +41 -0
  822. package/templates/action-puzzle/src/level.c +64 -0
  823. package/templates/action-puzzle/src/level.h +24 -0
  824. package/templates/action-puzzle/src/main.c +599 -0
  825. package/templates/action-puzzle/src/render.c +239 -0
  826. package/templates/action-puzzle/src/render.h +31 -0
  827. package/templates/action-puzzle/src/sound.c +158 -0
  828. package/templates/action-puzzle/src/sound.h +22 -0
  829. package/templates/action-puzzle/tools/disk_check.py +77 -0
  830. package/templates/action-puzzle/tools/drive.py +106 -0
  831. package/templates/action-puzzle/tools/gen.py +454 -0
  832. package/templates/action-puzzle/tools/model_check.py +49 -0
  833. package/templates/action-puzzle/tools/verdict_codes.py +24 -0
  834. package/templates/adventure/.claude/settings.json +17 -0
  835. package/templates/adventure/.mcp.json +10 -0
  836. package/templates/adventure/CLAUDE.md +118 -0
  837. package/templates/adventure/Makefile +113 -0
  838. package/templates/adventure/PLAN.md +396 -0
  839. package/templates/adventure/README.md +277 -0
  840. package/templates/adventure/expect.json +25 -0
  841. package/templates/adventure/src/engine.c +543 -0
  842. package/templates/adventure/src/engine.h +48 -0
  843. package/templates/adventure/src/gen_script.h +141 -0
  844. package/templates/adventure/src/gen_world.h +511 -0
  845. package/templates/adventure/src/main.c +439 -0
  846. package/templates/adventure/src/picture.c +83 -0
  847. package/templates/adventure/src/picture.h +16 -0
  848. package/templates/adventure/src/save.c +159 -0
  849. package/templates/adventure/src/save.h +25 -0
  850. package/templates/adventure/src/sound.c +71 -0
  851. package/templates/adventure/src/sound.h +16 -0
  852. package/templates/adventure/src/text.c +349 -0
  853. package/templates/adventure/src/text.h +40 -0
  854. package/templates/adventure/tools/disk_check.py +128 -0
  855. package/templates/adventure/tools/drive.py +119 -0
  856. package/templates/adventure/tools/gen.py +1033 -0
  857. package/templates/adventure/tools/world.py +356 -0
  858. package/templates/beat-em-up/.claude/settings.json +17 -0
  859. package/templates/beat-em-up/.mcp.json +10 -0
  860. package/templates/beat-em-up/CLAUDE.md +136 -0
  861. package/templates/beat-em-up/Makefile +96 -0
  862. package/templates/beat-em-up/PLAN.md +502 -0
  863. package/templates/beat-em-up/README.md +315 -0
  864. package/templates/beat-em-up/expect-gameover.json +8 -0
  865. package/templates/beat-em-up/expect.json +29 -0
  866. package/templates/beat-em-up/src/anim.c +70 -0
  867. package/templates/beat-em-up/src/art.c +344 -0
  868. package/templates/beat-em-up/src/autopilot.h +154 -0
  869. package/templates/beat-em-up/src/brute.c +273 -0
  870. package/templates/beat-em-up/src/enemy.c +281 -0
  871. package/templates/beat-em-up/src/engine.asm +512 -0
  872. package/templates/beat-em-up/src/fighter.c +384 -0
  873. package/templates/beat-em-up/src/game.h +269 -0
  874. package/templates/beat-em-up/src/hud.c +135 -0
  875. package/templates/beat-em-up/src/main.c +341 -0
  876. package/templates/beat-em-up/src/sound.c +44 -0
  877. package/templates/beat-em-up/src/street.c +93 -0
  878. package/templates/beat-em-up/src/verdict.h +523 -0
  879. package/templates/beat-em-up/src/view.c +362 -0
  880. package/templates/beat-em-up/tools/drive.py +105 -0
  881. package/templates/beat-em-up/tools/flickercheck.py +273 -0
  882. package/templates/demo/.claude/settings.json +17 -0
  883. package/templates/demo/.mcp.json +10 -0
  884. package/templates/demo/CLAUDE.md +129 -0
  885. package/templates/demo/Makefile +66 -0
  886. package/templates/demo/PLAN.md +401 -0
  887. package/templates/demo/README.md +322 -0
  888. package/templates/demo/expect.json +945 -0
  889. package/templates/demo/src/config.asm +80 -0
  890. package/templates/demo/src/framework.asm +390 -0
  891. package/templates/demo/src/main.asm +139 -0
  892. package/templates/demo/src/music.asm +197 -0
  893. package/templates/demo/src/part_main.asm +279 -0
  894. package/templates/demo/src/part_title.asm +79 -0
  895. package/templates/demo/src/parts.asm +43 -0
  896. package/templates/demo/src/tables.asm +73 -0
  897. package/templates/demo/src/verdict.asm +179 -0
  898. package/templates/demo/tools/audio.py +80 -0
  899. package/templates/demo/tools/gen_expect.py +167 -0
  900. package/templates/demo/tools/probe.py +95 -0
  901. package/templates/hello/.claude/settings.json +17 -0
  902. package/templates/hello/.mcp.json +10 -0
  903. package/templates/hello/CLAUDE.md +100 -0
  904. package/templates/hello/Makefile +38 -0
  905. package/templates/hello/PLAN.md +200 -0
  906. package/templates/hello/expect.json +20 -0
  907. package/templates/hello/src/main.c +161 -0
  908. package/templates/hello/src/sprite.asm +27 -0
  909. package/templates/hello-kick/.claude/settings.json +17 -0
  910. package/templates/hello-kick/.mcp.json +10 -0
  911. package/templates/hello-kick/CLAUDE.md +100 -0
  912. package/templates/hello-kick/Makefile +17 -0
  913. package/templates/hello-kick/PLAN.md +199 -0
  914. package/templates/hello-kick/expect.json +20 -0
  915. package/templates/hello-kick/src/main.asm +233 -0
  916. package/templates/platformer/.claude/settings.json +17 -0
  917. package/templates/platformer/.mcp.json +10 -0
  918. package/templates/platformer/CLAUDE.md +125 -0
  919. package/templates/platformer/Makefile +86 -0
  920. package/templates/platformer/PLAN.md +360 -0
  921. package/templates/platformer/README.md +277 -0
  922. package/templates/platformer/expect.json +32 -0
  923. package/templates/platformer/src/actors.c +289 -0
  924. package/templates/platformer/src/anim.c +51 -0
  925. package/templates/platformer/src/art.c +212 -0
  926. package/templates/platformer/src/autopilot.h +30 -0
  927. package/templates/platformer/src/engine.asm +253 -0
  928. package/templates/platformer/src/game.h +248 -0
  929. package/templates/platformer/src/hud.c +90 -0
  930. package/templates/platformer/src/level.c +184 -0
  931. package/templates/platformer/src/main.c +306 -0
  932. package/templates/platformer/src/player.c +268 -0
  933. package/templates/platformer/src/sound.c +42 -0
  934. package/templates/platformer/src/verdict.h +206 -0
  935. package/templates/platformer/src/view.c +331 -0
  936. package/templates/platformer/stage-expect.json +6 -0
  937. package/templates/platformer/tools/drive.py +112 -0
  938. package/templates/platformer/tools/tearcheck.py +229 -0
  939. package/templates/shmup-vertical/.claude/settings.json +17 -0
  940. package/templates/shmup-vertical/.mcp.json +10 -0
  941. package/templates/shmup-vertical/CLAUDE.md +137 -0
  942. package/templates/shmup-vertical/Makefile +131 -0
  943. package/templates/shmup-vertical/PLAN.md +569 -0
  944. package/templates/shmup-vertical/README.md +189 -0
  945. package/templates/shmup-vertical/expect.json +38 -0
  946. package/templates/shmup-vertical/src/bullets.c +158 -0
  947. package/templates/shmup-vertical/src/bullets.h +35 -0
  948. package/templates/shmup-vertical/src/display.c +239 -0
  949. package/templates/shmup-vertical/src/display.h +40 -0
  950. package/templates/shmup-vertical/src/game.h +85 -0
  951. package/templates/shmup-vertical/src/glyph.asm +358 -0
  952. package/templates/shmup-vertical/src/hiscore.c +141 -0
  953. package/templates/shmup-vertical/src/hiscore.h +16 -0
  954. package/templates/shmup-vertical/src/hit.asm +180 -0
  955. package/templates/shmup-vertical/src/hitbox.c +59 -0
  956. package/templates/shmup-vertical/src/hitbox.h +25 -0
  957. package/templates/shmup-vertical/src/kernel.asm +330 -0
  958. package/templates/shmup-vertical/src/level.c +174 -0
  959. package/templates/shmup-vertical/src/level.h +27 -0
  960. package/templates/shmup-vertical/src/main.c +824 -0
  961. package/templates/shmup-vertical/src/mux.asm +321 -0
  962. package/templates/shmup-vertical/src/sound.asm +255 -0
  963. package/templates/shmup-vertical/src/step.asm +169 -0
  964. package/templates/shmup-vertical/src/waves.c +195 -0
  965. package/templates/shmup-vertical/src/waves.h +33 -0
  966. package/templates/shmup-vertical/stage-expect.json +6 -0
  967. package/templates/shmup-vertical/tools/drive.py +152 -0
  968. package/templates/shmup-vertical/tools/joytest.py +159 -0
  969. package/templates/shmup-vertical/tools/meter.py +15 -0
  970. package/templates/shmup-vertical/tools/phases.py +73 -0
@@ -0,0 +1,907 @@
1
+ ---
2
+ recipe: sfx-in-player
3
+ toolchain: kickassembler
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [sfx_in_player]
7
+ file_formats: [PRG]
8
+ uses_registers: [D011, D012, D020, D021, D400, D401, D402, D403, D404, D405, D406, D407, D408, D409, D40A, D40B, D40C, D40D, D40E, D40F, D410, D411, D412, D413, D414, D415, D416, D417, D418, DC04, DC05, DC0D, DC0E, DD0D]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # KickAssembler — Sound effects inside the music player, with voice stealing and hand-back
15
+
16
+ ## Synopsis
17
+
18
+ A three-voice music player of its own, with a sound-effect entry point
19
+ built in. An effect takes one voice for its length. Requests are queued, so
20
+ at most one effect starts per frame and the higher effect number wins; an
21
+ effect cannot cut a higher-numbered one already on its voice. When an
22
+ effect ends, the player re-applies the music voice's instrument (AD, SR,
23
+ pulse width, waveform and gate) on that same frame. The player writes into
24
+ a 25-byte shadow of the SID and copies the whole shadow to `$D400`-`$D418`
25
+ once per frame ("ghost registers"). A script requests effects on fixed
26
+ frames, so the run needs no input. The program logs which voices an effect
27
+ owned on each of 120 frames, compares the log with an expected table, reads
28
+ the shadow on the frames around every hand-back, times each play call with
29
+ CIA1 timer A, and prints PASS or FAIL. The technique is `sfx_in_player` in
30
+ `techniques/music-sid.md`.
31
+
32
+ ## Source
33
+
34
+ ```asm
35
+ // sfx-in-player.asm: sound effects run inside a three-voice music player.
36
+ // The player keeps a 25-byte shadow of the SID ("ghost registers"), writes
37
+ // music or effect values into it per voice, and copies all 25 bytes to
38
+ // $D400-$D418 once per frame, $18 down to $00. An effect takes one voice for
39
+ // its length; a request is queued so at most one effect starts per frame and
40
+ // the higher effect number wins; an effect cannot cut a higher one already
41
+ // playing on its voice. When an effect ends the player re-applies the
42
+ // music voice's AD, SR, pulse width and control from its instrument.
43
+ // A script requests effects on fixed frames. The program logs which voices
44
+ // an effect owned on each of 120 frames, checks the log against an
45
+ // expected table, reads the shadow on the frames around each hand-back,
46
+ // times every play call with CIA1 timer A, and prints PASS or FAIL.
47
+ // Build: java -jar KickAss.jar sfx-in-player.asm -o sfx-in-player.prg
48
+
49
+ BasicUpstart2(start)
50
+
51
+ .encoding "screencode_upper"
52
+
53
+ .const SCREEN = $0400
54
+ .const LINE = 251 // below the display: no badlines, no sprites
55
+ .const NFRAMES = 120 // frames logged and checked
56
+ .label fxptr = $fb // zero-page pointer to the running effect
57
+ .label patptr = $fd // zero-page pointer to a voice's pattern
58
+
59
+ * = $0810
60
+
61
+ start:
62
+ sei
63
+ lda #$7f
64
+ sta $dc0d // no CIA interrupts: timer A is the stopwatch
65
+ sta $dd0d
66
+ lda $dc0d
67
+ lda $dd0d
68
+ lda #0
69
+ sta $d020
70
+ sta $d021
71
+ ldx #0
72
+ clr:
73
+ lda #$20
74
+ sta SCREEN,x
75
+ sta SCREEN + $100,x
76
+ sta SCREEN + $200,x
77
+ sta SCREEN + $2e8,x
78
+ lda #1
79
+ sta $d800,x
80
+ sta $d900,x
81
+ sta $da00,x
82
+ sta $dae8,x
83
+ inx
84
+ bne clr
85
+ ldx #0
86
+ lab:
87
+ lda labels,x
88
+ sta SCREEN,x
89
+ lda labels + $100,x
90
+ sta SCREEN + $100,x
91
+ inx
92
+ bne lab
93
+
94
+ jsr music_init
95
+ jsr calibrate
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // Frame loop: script, timed play, log, checks. No interrupts.
99
+ // ---------------------------------------------------------------------------
100
+ frameloop:
101
+ jsr waitline
102
+ inc frame
103
+ jsr script
104
+ ldx #2 // mask of effect voices before play
105
+ jsr fxmask
106
+ sta maskbefore
107
+ jsr timed_play
108
+ ldx #2 // count effects on their first frame:
109
+ cnt1: // header and one row read, position 5
110
+ lda sfxnum,x
111
+ beq cnt2
112
+ lda sfxpos,x
113
+ cmp #5
114
+ bne cnt2
115
+ inc starts
116
+ cnt2:
117
+ dex
118
+ bpl cnt1
119
+ ldx #2
120
+ jsr fxmask
121
+ ldy frame
122
+ sta log - 1,y // frame 1 goes to log+0
123
+ ora maskbefore // an effect ran or handed back this frame
124
+ beq idlecat
125
+ lda cost + 1 // effect frame: keep the maximum
126
+ cmp fxmax + 1
127
+ bcc catdone
128
+ bne fxnew
129
+ lda cost
130
+ cmp fxmax
131
+ bcc catdone
132
+ fxnew:
133
+ lda cost
134
+ sta fxmax
135
+ lda cost + 1
136
+ sta fxmax + 1
137
+ lda frame
138
+ sta fxat
139
+ jmp catdone
140
+ idlecat:
141
+ lda cost + 1 // music-only frame: keep the maximum
142
+ cmp idmax + 1
143
+ bcc catdone
144
+ bne idnew
145
+ lda cost
146
+ cmp idmax
147
+ bcc catdone
148
+ idnew:
149
+ lda cost
150
+ sta idmax
151
+ lda cost + 1
152
+ sta idmax + 1
153
+ lda frame
154
+ sta idat
155
+ catdone:
156
+ lda cost + 1 // any frame: keep the minimum
157
+ cmp mnmin + 1
158
+ bcc mnnew
159
+ bne mndone
160
+ lda cost
161
+ cmp mnmin
162
+ bcs mndone
163
+ mnnew:
164
+ lda cost
165
+ sta mnmin
166
+ lda cost + 1
167
+ sta mnmin + 1
168
+ lda frame
169
+ sta mnat
170
+ mndone:
171
+ jsr checks
172
+ lda frame
173
+ cmp #NFRAMES
174
+ beq alldone
175
+ jmp frameloop
176
+ alldone:
177
+ jsr report
178
+ idle: // music keeps playing; the screen is final
179
+ jsr waitline
180
+ jsr play
181
+ jmp idle
182
+
183
+ waitline:
184
+ lda $d011
185
+ bmi waitline
186
+ lda $d012
187
+ cmp #LINE
188
+ bne waitline
189
+ rts
190
+
191
+ // A = mask of voices (bit 0 = voice 1) an effect owns; X = 2 on entry
192
+ fxmask:
193
+ lda #0
194
+ sta mtmp
195
+ fxm1:
196
+ lda sfxnum,x
197
+ cmp #1 // carry set if an effect owns voice X
198
+ rol mtmp
199
+ dex
200
+ bpl fxm1
201
+ lda mtmp // voice 3 rolled in first, ends in bit 2
202
+ rts
203
+
204
+ // ---------------------------------------------------------------------------
205
+ // Stopwatch: CIA1 timer A, one-shot from $FFFF.
206
+ // ---------------------------------------------------------------------------
207
+ calibrate:
208
+ lda #$ff
209
+ sta $dc04
210
+ sta $dc05
211
+ lda #%00011001 // force load, one-shot, start
212
+ sta $dc0e
213
+ lda #0
214
+ sta $dc0e // stop
215
+ sec
216
+ lda #$ff
217
+ sbc $dc04
218
+ sta calib
219
+ lda #$ff
220
+ sbc $dc05
221
+ sta calib + 1
222
+ rts
223
+
224
+ timed_play:
225
+ lda #$ff
226
+ sta $dc04
227
+ sta $dc05
228
+ lda #%00011001
229
+ sta $dc0e
230
+ jsr play
231
+ lda #0
232
+ sta $dc0e
233
+ sec
234
+ lda #$ff
235
+ sbc $dc04
236
+ sta cost
237
+ lda #$ff
238
+ sbc $dc05
239
+ sta cost + 1
240
+ sec // less the stopwatch's own start/stop
241
+ lda cost
242
+ sbc calib
243
+ sta cost
244
+ lda cost + 1
245
+ sbc calib + 1
246
+ sta cost + 1
247
+ rts
248
+
249
+ // ---------------------------------------------------------------------------
250
+ // Script: effect requests on fixed frames (the autopilot).
251
+ // ---------------------------------------------------------------------------
252
+ script:
253
+ ldx sidx
254
+ lda scframe,x
255
+ cmp frame
256
+ bne scdone
257
+ lda scfx,x
258
+ jsr sfx_request
259
+ inc sidx
260
+ jmp script // two requests may share a frame
261
+ scdone:
262
+ rts
263
+
264
+ // ===========================================================================
265
+ // The player
266
+ // ===========================================================================
267
+
268
+ // SFX entry point. A = effect number 1-4; a higher number wins.
269
+ // Only one request per frame survives to the player.
270
+ sfx_request:
271
+ cmp pending
272
+ bcc srdrop
273
+ ldy pending
274
+ beq srstore
275
+ inc dropped // a lower request queued this frame is lost
276
+ srstore:
277
+ sta pending
278
+ rts
279
+ srdrop:
280
+ inc dropped
281
+ rts
282
+
283
+ music_init:
284
+ ldx #2
285
+ mi1:
286
+ lda #0
287
+ sta mtimer,x
288
+ sta mseq,x
289
+ sta sfxnum,x
290
+ sta restore,x
291
+ dex
292
+ bpl mi1
293
+ ldx #$18
294
+ mi2:
295
+ lda #0
296
+ sta ghost,x
297
+ dex
298
+ bpl mi2
299
+ lda #$0f
300
+ sta ghost + $18 // volume 15, no filter
301
+ rts
302
+
303
+ play:
304
+ ldy pending // start the queued effect, if any
305
+ beq plvoices
306
+ ldx fxvoice,y
307
+ tya
308
+ cmp sfxnum,x
309
+ bcs pltake // same or higher than the one playing: take
310
+ inc refused
311
+ jmp plclear
312
+ pltake:
313
+ sta sfxnum,x
314
+ lda #0
315
+ sta sfxpos,x
316
+ plclear:
317
+ lda #0
318
+ sta pending
319
+ plvoices:
320
+ ldx #2
321
+ plv:
322
+ jsr voice
323
+ dex
324
+ bpl plv
325
+ ldx #$18 // ghost copy: every register, once per frame
326
+ plcopy:
327
+ lda ghost,x
328
+ sta $d400,x
329
+ dex
330
+ bpl plcopy
331
+ rts
332
+
333
+ // One voice. X = voice 0-2. The music advances every frame, owned or not.
334
+ voice:
335
+ lda voff,x
336
+ sta vo
337
+ lda #0
338
+ sta noteinit
339
+ lda mtimer,x
340
+ bne vgate
341
+ inc noteinit // first frame of a note: fetch it
342
+ lda patlo,x
343
+ sta patptr
344
+ lda pathi,x
345
+ sta patptr + 1
346
+ ldy mseq,x
347
+ lda (patptr),y
348
+ cmp #$ff
349
+ bne vnote
350
+ ldy #0 // end of pattern: loop
351
+ lda (patptr),y
352
+ vnote:
353
+ iny
354
+ sta ntmp
355
+ tya
356
+ sta mseq,x
357
+ ldy ntmp
358
+ lda freqlo,y
359
+ sta mflo,x
360
+ lda freqhi,y
361
+ sta mfhi,x
362
+ vgate:
363
+ lda mtimer,x // gate off on a note's first and last frame
364
+ beq vgoff
365
+ clc
366
+ adc #1
367
+ cmp idur,x
368
+ beq vgoff
369
+ lda iwave,x
370
+ ora #1
371
+ bne vgset
372
+ vgoff:
373
+ lda iwave,x
374
+ vgset:
375
+ sta mctrl,x
376
+ inc mtimer,x
377
+ lda mtimer,x
378
+ cmp idur,x
379
+ bne vowner
380
+ lda #0
381
+ sta mtimer,x
382
+ vowner:
383
+ lda sfxnum,x
384
+ bne veffect
385
+ vmusic:
386
+ ldy vo
387
+ lda restore,x // hand-back frame or note start: instrument
388
+ ora noteinit
389
+ beq vfc
390
+ lda #0
391
+ sta restore,x
392
+ lda iad,x
393
+ sta ghost + 5,y
394
+ lda isr,x
395
+ sta ghost + 6,y
396
+ lda ipw,x
397
+ sta ghost + 3,y
398
+ lda #0
399
+ sta ghost + 2,y
400
+ vfc:
401
+ lda mflo,x
402
+ sta ghost + 0,y
403
+ lda mfhi,x
404
+ sta ghost + 1,y
405
+ lda mctrl,x
406
+ sta ghost + 4,y
407
+ rts
408
+
409
+ // Effect data: AD, SR, pulse high, then rows of (control, freq high),
410
+ // one row per frame, ended by a control byte of 0.
411
+ veffect:
412
+ stx vidx
413
+ ldy sfxnum,x
414
+ lda fxlo,y
415
+ sta fxptr
416
+ lda fxhi,y
417
+ sta fxptr + 1
418
+ ldy sfxpos,x
419
+ ldx vo
420
+ cpy #0
421
+ bne vrow
422
+ lda (fxptr),y // first frame: the effect's envelope and pulse
423
+ sta ghost + 5,x
424
+ iny
425
+ lda (fxptr),y
426
+ sta ghost + 6,x
427
+ iny
428
+ lda (fxptr),y
429
+ sta ghost + 3,x
430
+ lda #0
431
+ sta ghost + 2,x
432
+ iny
433
+ vrow:
434
+ lda (fxptr),y
435
+ beq vend
436
+ sta ghost + 4,x
437
+ iny
438
+ lda (fxptr),y
439
+ sta ghost + 1,x
440
+ lda #0
441
+ sta ghost + 0,x
442
+ iny
443
+ tya
444
+ ldx vidx
445
+ sta sfxpos,x
446
+ rts
447
+ vend:
448
+ ldx vidx // effect over: hand the voice back this frame
449
+ lda #0
450
+ sta sfxnum,x
451
+ lda #1
452
+ sta restore,x
453
+ jmp vmusic
454
+
455
+ // ===========================================================================
456
+ // Checks
457
+ // ===========================================================================
458
+
459
+ // Around each hand-back: on the effect's last frame the shadow holds the
460
+ // effect's AD and SR; on the next frame it holds the instrument's AD, SR,
461
+ // pulse high and waveform with GATE set (the music note is mid-note).
462
+ checks:
463
+ ldx cidx
464
+ lda ckframe,x
465
+ cmp frame
466
+ bne ckdone
467
+ ldy ckvoice,x
468
+ lda voff,y
469
+ tay // Y = ghost offset
470
+ lda cktype,x
471
+ bne ckback
472
+ lda ckfx,x // owned: compare with the effect header
473
+ tax
474
+ lda fxlo,x
475
+ sta fxptr
476
+ lda fxhi,x
477
+ sta fxptr + 1
478
+ lda ghost + 5,y
479
+ sta ctmp
480
+ lda ghost + 6,y
481
+ ldy #1
482
+ cmp (fxptr),y
483
+ bne ckfail
484
+ lda ctmp
485
+ dey
486
+ cmp (fxptr),y
487
+ bne ckfail
488
+ jmp ckpass
489
+ ckback:
490
+ ldx cidx
491
+ lda ckvoice,x
492
+ tax // X = voice
493
+ lda ghost + 5,y
494
+ cmp iad,x
495
+ bne ckfail
496
+ lda ghost + 6,y
497
+ cmp isr,x
498
+ bne ckfail
499
+ lda ghost + 3,y
500
+ cmp ipw,x
501
+ bne ckfail
502
+ ldy cidx // type 1 wants GATE set, type 2 clear
503
+ lda cktype,y
504
+ and #1
505
+ ldy voff,x // Y = ghost offset again
506
+ ora iwave,x
507
+ cmp ghost + 4,y
508
+ bne ckfail
509
+ ckpass:
510
+ inc ckok
511
+ ckfail:
512
+ inc cidx
513
+ ckdone:
514
+ rts
515
+
516
+ // ===========================================================================
517
+ // Report
518
+ // ===========================================================================
519
+ report:
520
+ ldx #0 // mask log, rows 2 to 4
521
+ rp1:
522
+ lda log,x
523
+ ora #$30
524
+ sta SCREEN + 2 * 40,x
525
+ inx
526
+ cpx #NFRAMES
527
+ bne rp1
528
+
529
+ ldx #0 // compare the log with the expected runs
530
+ ldy #0
531
+ rp2:
532
+ lda exprun,y // run length, 0 ends
533
+ beq rp4
534
+ sta rtmp
535
+ lda exprun + 1,y
536
+ rp3:
537
+ cmp log,x
538
+ bne rpbad
539
+ inx
540
+ dec rtmp
541
+ bne rp3
542
+ iny
543
+ iny
544
+ jmp rp2
545
+ rpbad:
546
+ inc logbad
547
+ rp4:
548
+ cpx #NFRAMES
549
+ beq rp5
550
+ inc logbad
551
+ rp5:
552
+ lda #<(SCREEN + 5 * 40 + 7)
553
+ ldx #>(SCREEN + 5 * 40 + 7)
554
+ ldy starts
555
+ jsr puthex
556
+ lda #<(SCREEN + 5 * 40 + 18)
557
+ ldx #>(SCREEN + 5 * 40 + 18)
558
+ ldy refused
559
+ jsr puthex
560
+ lda #<(SCREEN + 5 * 40 + 29)
561
+ ldx #>(SCREEN + 5 * 40 + 29)
562
+ ldy dropped
563
+ jsr puthex
564
+ lda #<(SCREEN + 6 * 40 + 16)
565
+ ldx #>(SCREEN + 6 * 40 + 16)
566
+ ldy ckok
567
+ jsr puthex
568
+ lda #<(SCREEN + 7 * 40 + 16)
569
+ ldx #>(SCREEN + 7 * 40 + 16)
570
+ ldy idmax + 1
571
+ jsr puthex
572
+ lda #<(SCREEN + 7 * 40 + 18)
573
+ ldx #>(SCREEN + 7 * 40 + 18)
574
+ ldy idmax
575
+ jsr puthex
576
+ lda #<(SCREEN + 7 * 40 + 31)
577
+ ldx #>(SCREEN + 7 * 40 + 31)
578
+ ldy idat
579
+ jsr puthex
580
+ lda #<(SCREEN + 8 * 40 + 16)
581
+ ldx #>(SCREEN + 8 * 40 + 16)
582
+ ldy fxmax + 1
583
+ jsr puthex
584
+ lda #<(SCREEN + 8 * 40 + 18)
585
+ ldx #>(SCREEN + 8 * 40 + 18)
586
+ ldy fxmax
587
+ jsr puthex
588
+ lda #<(SCREEN + 8 * 40 + 31)
589
+ ldx #>(SCREEN + 8 * 40 + 31)
590
+ ldy fxat
591
+ jsr puthex
592
+ lda #<(SCREEN + 9 * 40 + 16)
593
+ ldx #>(SCREEN + 9 * 40 + 16)
594
+ ldy mnmin + 1
595
+ jsr puthex
596
+ lda #<(SCREEN + 9 * 40 + 18)
597
+ ldx #>(SCREEN + 9 * 40 + 18)
598
+ ldy mnmin
599
+ jsr puthex
600
+ lda #<(SCREEN + 9 * 40 + 31)
601
+ ldx #>(SCREEN + 9 * 40 + 31)
602
+ ldy mnat
603
+ jsr puthex
604
+ lda #<(SCREEN + 10 * 40 + 16)
605
+ ldx #>(SCREEN + 10 * 40 + 16)
606
+ ldy calib + 1
607
+ jsr puthex
608
+ lda #<(SCREEN + 10 * 40 + 18)
609
+ ldx #>(SCREEN + 10 * 40 + 18)
610
+ ldy calib
611
+ jsr puthex
612
+
613
+ lda logbad // verdict
614
+ bne rpfail
615
+ lda ckok
616
+ cmp #8
617
+ bne rpfail
618
+ lda starts
619
+ cmp #5
620
+ bne rpfail
621
+ lda refused
622
+ cmp #1
623
+ bne rpfail
624
+ lda dropped
625
+ cmp #1
626
+ bne rpfail
627
+ ldx #3
628
+ rppass:
629
+ lda passtxt,x
630
+ sta SCREEN + 11 * 40 + 7,x
631
+ dex
632
+ bpl rppass
633
+ lda #5 // green border: PASS
634
+ sta $d020
635
+ rts
636
+ rpfail:
637
+ ldx #3
638
+ rpf1:
639
+ lda failtxt,x
640
+ sta SCREEN + 11 * 40 + 7,x
641
+ dex
642
+ bpl rpf1
643
+ lda #2 // red border: FAIL
644
+ sta $d020
645
+ rts
646
+
647
+ // Y = byte, A/X = screen address: two hex digits
648
+ puthex:
649
+ sta patptr
650
+ stx patptr + 1
651
+ tya
652
+ pha
653
+ lsr
654
+ lsr
655
+ lsr
656
+ lsr
657
+ tax
658
+ lda hexdig,x
659
+ ldy #0
660
+ sta (patptr),y
661
+ pla
662
+ and #$0f
663
+ tax
664
+ lda hexdig,x
665
+ ldy #1
666
+ sta (patptr),y
667
+ rts
668
+
669
+ // ===========================================================================
670
+ // Data
671
+ // ===========================================================================
672
+ voff: .byte 0, 7, 14
673
+ iwave: .byte $40, $20, $40 // pulse, saw, pulse
674
+ iad: .byte $08, $0a, $22
675
+ isr: .byte $a6, $80, $b8
676
+ ipw: .byte $08, $04, $06 // pulse width high nybble
677
+ idur: .byte 8, 16, 12 // frames per note
678
+ patlo: .byte <pat1, <pat2, <pat3
679
+ pathi: .byte >pat1, >pat2, >pat3
680
+ pat1: .byte 12, 16, 19, 16, 14, 17, 21, 17, $ff
681
+ pat2: .byte 0, 0, 5, 7, $ff
682
+ pat3: .byte 19, 21, 23, 21, $ff
683
+
684
+ // 24 semitones from C-3, PAL clock: f * 16777216 / 985248
685
+ .const K = 16777216 / 985248
686
+ freqlo: .fill 24, <round(K * 130.81 * pow(2, i / 12))
687
+ freqhi: .fill 24, >round(K * 130.81 * pow(2, i / 12))
688
+
689
+ // Effect number n: voice and data. Entry 0 is unused.
690
+ fxvoice: .byte 0, 2, 2, 2, 0
691
+ fxlo: .byte 0, <fx1, <fx2, <fx3, <fx4
692
+ fxhi: .byte 0, >fx1, >fx2, >fx3, >fx4
693
+ fx1: .byte $00, $f0, $02 // 10 frames, falling blip
694
+ .for (var r = 0; r < 9; r++) { .byte $41, $30 - r * 3 }
695
+ .byte $40, $08, 0
696
+ fx2: .byte $0c, $00, $08 // 40 frames, noise
697
+ .for (var r = 0; r < 39; r++) { .byte $81, $28 - (r >> 1) }
698
+ .byte $80, $10, 0
699
+ fx3: .byte $00, $c9, $03 // 20 frames, rising
700
+ .for (var r = 0; r < 19; r++) { .byte $41, $10 + r * 2 }
701
+ .byte $40, $38, 0
702
+ fx4: .byte $05, $50, $0c // 10 frames, voice 1
703
+ .for (var r = 0; r < 9; r++) { .byte $11, $20 + r * 4 }
704
+ .byte $10, $40, 0
705
+
706
+ // Script: frame, effect. Frame 0 ends it.
707
+ scframe: .byte 20, 30, 49, 49, 81, 87, 97, 0
708
+ scfx: .byte 2, 1, 1, 3, 4, 1, 4, 0
709
+
710
+ // Checks: frame, voice, type, effect for type 0. Type 0: the effect owns
711
+ // the voice. Type 1: hand-back mid-note, GATE set. Type 2: hand-back on a
712
+ // note's first frame, GATE clear.
713
+ ckframe: .byte 68, 69, 90, 91, 96, 97, 106, 107, 0
714
+ ckvoice: .byte 2, 2, 0, 0, 2, 2, 0, 0
715
+ cktype: .byte 0, 1, 0, 1, 0, 2, 0, 1
716
+ ckfx: .byte 3, 0, 4, 0, 1, 0, 4, 0
717
+
718
+ // Expected mask log as runs of (length, mask), written from the script,
719
+ // not from the player: bit 0 voice 1, bit 2 voice 3.
720
+ exprun: .byte 19, 0, 49, 4, 12, 0, 6, 1, 4, 5, 6, 4, 10, 1, 14, 0, 0
721
+
722
+ hexdig: .text "0123456789ABCDEF"
723
+ passtxt: .text "PASS"
724
+ failtxt: .text "FAIL"
725
+
726
+ labels:
727
+ .text "SFX INSIDE THE PLAYER: VOICE STEALING " // row 0
728
+ .text "EFFECT VOICES PER FRAME, FRAMES 1-120: " // row 1
729
+ .text " " // row 2
730
+ .text " " // row 3
731
+ .text " " // row 4
732
+ .text "STARTS REFUSED DROPPED " // row 5
733
+ .text "HANDBACK CHECKS OF 08 " // row 6
734
+ .text "PLAY IDLE MAX $ AT FRAME $ " // row 7
735
+ .text "PLAY FX MAX $ AT FRAME $ " // row 8
736
+ .text "PLAY MIN $ AT FRAME $ " // row 9
737
+ .text "STOPWATCH $ " // row 10
738
+ .text "RESULT " // row 11
739
+ .fill 512 - 12 * 40, $20
740
+
741
+ // Variables
742
+ frame: .byte 0
743
+ sidx: .byte 0
744
+ cidx: .byte 0
745
+ pending: .byte 0
746
+ refused: .byte 0
747
+ dropped: .byte 0
748
+ starts: .byte 0
749
+ ckok: .byte 0
750
+ logbad: .byte 0
751
+ maskbefore: .byte 0
752
+ mtmp: .byte 0
753
+ ntmp: .byte 0
754
+ ctmp: .byte 0
755
+ rtmp: .byte 0
756
+ vo: .byte 0
757
+ vidx: .byte 0
758
+ noteinit: .byte 0
759
+ cost: .word 0
760
+ calib: .word 0
761
+ idmax: .word 0
762
+ idat: .byte 0
763
+ fxmax: .word 0
764
+ fxat: .byte 0
765
+ mnmin: .word $ffff
766
+ mnat: .byte 0
767
+ mtimer: .fill 3, 0
768
+ mseq: .fill 3, 0
769
+ mflo: .fill 3, 0
770
+ mfhi: .fill 3, 0
771
+ mctrl: .fill 3, 0
772
+ sfxnum: .fill 3, 0
773
+ sfxpos: .fill 3, 0
774
+ restore: .fill 3, 0
775
+ ghost: .fill 25, 0
776
+ log: .fill NFRAMES, 0
777
+ ```
778
+
779
+ ## Build
780
+
781
+ ```bash
782
+ java -jar KickAss.jar sfx-in-player.asm -o sfx-in-player.prg
783
+ ```
784
+
785
+ Built with KickAssembler 5.25. Code and data occupy `$0810`-`$110A`. From
786
+ the symbol file: the player's code (`sfx_request` to the end of `veffect`)
787
+ is 371 bytes, and its tables, patterns, frequency table and four effects
788
+ are 282 bytes. The shadow is 25 bytes and the per-voice state 24.
789
+
790
+ ## Expected output
791
+
792
+ Every figure below was measured in VICE x64sc 3.10 (rung 1) from the exit
793
+ screenshot of the pinned run at 8,000,000 cycles, text decoded against the
794
+ `chargen-901225-01.bin` glyphs with PIL. Two runs per model gave
795
+ byte-identical PNGs. `+sound` is off: every claim is register-level, what
796
+ the player put in the shadow and so in the SID. Nobody has listened to it.
797
+
798
+ ```text
799
+ x64sc -default -warp +sound +autostart-delay-random -autostartprgmode 1 \
800
+ -limitcycles 8000000 [-model ntsc] -exitscreenshot out.png \
801
+ -autostart sfx-in-player.prg
802
+ ```
803
+
804
+ PAL (`screenshots/sfx-in-player.png`) and NTSC
805
+ (`screenshots/sfx-in-player-ntsc.png`) show the same text:
806
+
807
+ ```text
808
+ SFX INSIDE THE PLAYER: VOICE STEALING
809
+ EFFECT VOICES PER FRAME, FRAMES 1-120:
810
+ 0000000000000000000444444444444444444444
811
+ 4444444444444444444444444444000000000000
812
+ 1111115555444444111111111100000000000000
813
+ STARTS 05 REFUSED 01 DROPPED 01
814
+ HANDBACK CHECKS 08 OF 08
815
+ PLAY IDLE MAX $0422 AT FRAME $01
816
+ PLAY FX MAX $04B0 AT FRAME $61
817
+ PLAY MIN $0306 AT FRAME $02
818
+ STOPWATCH $0005
819
+ RESULT PASS
820
+ ```
821
+
822
+ The border is green (PASS; red would be FAIL).
823
+
824
+ **The log.** One digit per frame, frames 1 to 120: bit 0 set means an
825
+ effect owns voice 1, bit 2 voice 3. The script's requests and what the log
826
+ shows:
827
+
828
+ | Frame | Request | Result in the log |
829
+ |---|---|---|
830
+ | 20 | effect 2 (voice 3, 40 rows) | voice 3 taken: `4` from frame 20 |
831
+ | 30 | effect 1 (voice 3) | refused: effect 2 is higher. `REFUSED 01` |
832
+ | 49 | effect 1, then effect 3, same frame | the queue keeps 3 and drops 1 (`DROPPED 01`); 3 cuts 2 |
833
+ | 69 | (none) | effect 3's 20 rows are over: voice 3 handed back, `0` |
834
+ | 81 | effect 4 (voice 1, 10 rows) | `1` |
835
+ | 87 | effect 1 (voice 3, 10 rows) | both voices: `5` |
836
+ | 91 | (none) | effect 4 ends, voice 1 handed back: `4` |
837
+ | 97 | effect 4 again (voice 1) | voice 3 handed back and voice 1 taken on the same frame: `1` |
838
+ | 107 | (none) | voice 1 handed back: `0` to frame 120 |
839
+
840
+ The program compares the log with a table of runs written from this
841
+ script, not from the player (`exprun`). `STARTS 05` counts effects that got
842
+ a voice (2, 3, 4, 1, 4), found after each call as a voice whose effect
843
+ position is 5, the header and one row.
844
+
845
+ **Hand-back checks.** On the last frame of each of the four effects the
846
+ shadow's AD and SR equal the effect's header (4 checks). On the next frame
847
+ they equal the instrument's AD, SR and pulse high byte, and the control
848
+ byte equals the instrument's waveform with GATE set (frames 69, 91 and
849
+ 107, all mid-note) or clear (frame 97, where voice 3's next note starts
850
+ and the player holds GATE off for one frame).
851
+
852
+ A harness build with the one store that sets `restore` changed to store 0
853
+ (not this listing) ran the same way: `HANDBACK CHECKS 05 OF 08`, FAIL. The
854
+ three mid-note hand-backs failed and the frame-97 one passed, because the
855
+ player writes AD, SR and pulse on every note start anyway. Without the
856
+ restore, the music voice keeps the effect's envelope and pulse width until
857
+ its next note.
858
+
859
+ **Cycles.** Hex, net of the stopwatch's own 5 cycles; the same on PAL and
860
+ NTSC, because the play call runs from raster line 251, below the badlines,
861
+ with no sprites on.
862
+
863
+ | Row | Cycles | Frame | What ran |
864
+ |---|---|---|---|
865
+ | `PLAY IDLE MAX` | 1,058 | 1 | no effect; a note starts on all three voices |
866
+ | `PLAY FX MAX` | 1,200 | 97 | a note starts on all three voices, voice 3 is handed back with its instrument re-applied, and effect 4 starts on voice 1 with its header |
867
+ | `PLAY MIN` | 774 | 2 | no effect, no note start |
868
+
869
+ Frame 97 is the worst frame the script builds on purpose: every
870
+ per-voice path that costs extra, on one frame. 351 cycles of every figure
871
+ are the shadow copy (25 × 14 − 1 + 2, from the instruction table; `ghost`
872
+ does not cross a page). The demonstration's counters are outside the
873
+ timed call, except `inc refused` (6 cycles), which runs only on a refused
874
+ frame. An earlier layout of this listing, with a counter inside `play`,
875
+ measured 1,055, 1,203 and 773: moving code shifts page crossings in the
876
+ indexed loads, and the figures move by a few cycles with it.
877
+
878
+ ## Why this works
879
+
880
+ **The player advances the music on every voice, every frame.** An effect
881
+ stops the voice's writes to the shadow, not its sequencer. `voice` fetches
882
+ notes and works out the gate for the music whether or not an effect owns
883
+ the voice; `vowner` then picks who writes. The tune stays in time, and at
884
+ hand-back the music's frequency and gate are already the ones for that
885
+ frame.
886
+
887
+ **Hand-back re-applies the instrument.** This player writes AD, SR and
888
+ pulse width only on a note's first frame, as most players do, to save
889
+ cycles. The effect overwrote them. So `vend` sets `restore` and jumps into
890
+ the music path, which rewrites all three from the instrument table on the
891
+ same frame. The effect's last row clears GATE, so the music's GATE on the
892
+ next frame is a 0-to-1 edge and a fresh attack with the music's envelope.
893
+
894
+ **One start per frame.** `sfx_request` only compares and stores: the
895
+ higher number stays in `pending`. The player takes it at the top of the
896
+ next `play`. Two requests in one frame cost one voice, not two.
897
+
898
+ **Ghost registers.** Nothing writes the SID but the copy loop at the end of
899
+ `play`, `$18` down to `$00`: for each voice SR, AD, control, pulse,
900
+ frequency. Every register is written every frame, in the same order, and
901
+ a voice's seven writes land within 98 cycles (7 × 14, arithmetic) whatever
902
+ path the player took. When they land in the frame still moves with the
903
+ player's length, 774 to 1,200 cycles here; copying first and computing
904
+ second fixes that too (see the technique). The SID's
905
+ registers are write-only (`pitfalls/sid.md`, `sid_write_only_registers`),
906
+ so the shadow is also the only place a program can read what it last
907
+ wrote; the checks read it.