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,986 @@
1
+ ---
2
+ recipe: sprite-multiplex-game
3
+ toolchain: kickassembler
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [sprite_multiplex_game]
7
+ file_formats: [PRG]
8
+ uses_registers: [D000, D001, D010, D011, D012, D015, D017, D019, D01A, D01B, D01C, D01D, D020, D021, D027, DC0D, DD04, DD05, DD06, DD07, DD0D, DD0E, DD0F]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # KickAssembler — Game Sprite Multiplexer With Its Own Timings
15
+
16
+ ## Synopsis
17
+
18
+ Twenty-four actors move on their own paths and are shown with eight
19
+ hardware sprites. The main loop sorts them by Y every frame with an
20
+ insertion sort that keeps last frame's order, builds the sorted sprite
21
+ table into the half the IRQs are not reading, and marks it ready. A frame
22
+ IRQ at line 252 swaps the halves and writes the first eight sprites; zone
23
+ IRQs further down reuse the slots, each zone writing every sprite whose Y
24
+ is within four lines of its first. When a zone ends so close to the next
25
+ one that the raster is already within three lines of it, the handler runs
26
+ the next zone at once instead of returning. The program times its own
27
+ sort, build and IRQs with the two CIA2 timers and prints them in the top
28
+ four text rows, with a count of the times and frames the late guard fired.
29
+ Use it as the display half of a game with more than eight moving objects.
30
+ The technique is `sprite_multiplex_game` in `docs/techniques/sprite.md`.
31
+
32
+ Verified in VICE x64sc 3.10 on PAL and NTSC, measured with PIL: every one
33
+ of the 24 actors shows in its own column in both pinned shots and all 16
34
+ swept shots. In the pinned shots each is one whole 21-line box. In 9
35
+ swept shots some boxes are split at the line where the exit screenshot
36
+ cut the frame.
37
+
38
+ ## Source
39
+
40
+ ```asm
41
+ // sprite-multiplex-game.asm
42
+ // A game-style sprite multiplexer: 24 actors on independent paths, sorted
43
+ // by Y every frame with a persistent insertion sort, built into one half
44
+ // of a double-buffered sorted table while the IRQs show the other half,
45
+ // and displayed through zone IRQs that each set up one or more sprites.
46
+ // The program times its own sort and its own IRQs with the two CIA2
47
+ // timers and prints the figures in the top four text rows.
48
+ //
49
+ // Each actor has its own X column (X = 24 + 13*i), so a missing actor is
50
+ // an empty column. Actors 18-23 are past X=255 and need $D010.
51
+ //
52
+ // Region: both. KERNAL and BASIC are banked out; the IRQ vector is $FFFE.
53
+
54
+ .const N = 24 // actors
55
+ .const BUF = 32 // offset of sorted buffer 1 (a multiple of 8)
56
+ .const MIN_GAP = 21 // a reused slot's next Y must be >= its last Y + 21
57
+ .const JOIN = 4 // sprites within 4 lines of a zone's first join it
58
+ .const LEAD = 3 // zone IRQ line = first Y - LEAD - sprites in zone
59
+ .const MARGIN = 3 // late guard: next line - 3 already reached? run it now
60
+ .const BOTTOM = 252 // frame IRQ: swap buffers, write the first eight
61
+ .const TOP_Y = 90 // path range 90..228; a sprite at Y draws Y+1..Y+21
62
+
63
+ .const SCREEN = $0400
64
+ .const PTRS = $07f8
65
+
66
+ // zero page
67
+ .label save_a = $02
68
+ .label save_x = $03
69
+ .label save_y = $04
70
+ .label cra_save = $05
71
+ .label next_hnd = $06 // 2 bytes: body the next IRQ runs
72
+ .label zidx = $08
73
+ .label zlast = $09
74
+ .label zend_tmp = $0a
75
+ .label front_off = $0b // 0 or BUF: the half the IRQs read
76
+ .label ready = $0c // main loop sets 1 when the back half is built
77
+ .label late_flag = $0d
78
+ .label late_total = $0e // 2 bytes: times the guard fell through
79
+ .label late_frms = $10 // 2 bytes: frames with at least one fall-through
80
+ .label missed = $12 // 2 bytes: frames shown twice (build not ready)
81
+ .label frames = $14 // 2 bytes
82
+ .label irq_cyc = $16 // 2 bytes: CIA2 timer B, multiplexer IRQs, one frame
83
+ .label sort_cyc = $18 // 2 bytes: CIA2 timer A, sort of the last frame
84
+ .label sort_max = $1a // 2 bytes
85
+ .label calib = $1c // 2 bytes: timer count of an empty start/stop
86
+ .label t_stable = $1e // 2 bytes: startup, sort of an already sorted order
87
+ .label t_shuf = $20 // 2 bytes: startup, order i*7 mod 24
88
+ .label t_rev = $22 // 2 bytes: startup, reversed order
89
+ .label bo = $24 // build: back half offset
90
+ .label acc = $25 // build: next accepted index (absolute)
91
+ .label bk = $26
92
+ .label by = $27
93
+ .label d010run = $28
94
+ .label rejects = $29
95
+ .label zw = $2a
96
+ .label ybase = $2b
97
+ .label ylim = $2c
98
+ .label zn = $2d
99
+ .label key = $2e
100
+ .label cand = $2f
101
+ .label s_i = $30
102
+ .label n16 = $31 // 2 bytes
103
+ .label tmp = $33
104
+ .label digit = $34
105
+ .label dst = $35 // 2 bytes
106
+ .label t_build = $37 // 2 bytes: startup, one build of the sorted half
107
+ .label pflip = $39
108
+
109
+ BasicUpstart2(start)
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // Setup
113
+ // ---------------------------------------------------------------------------
114
+ * = $0820
115
+ start:
116
+ sei
117
+ lda #$7f
118
+ sta $dc0d // no CIA1 interrupts
119
+ sta $dd0d // no CIA2 NMIs from the timers used as counters
120
+ lda $dc0d
121
+ lda $dd0d
122
+ lda #$35 // KERNAL and BASIC out, I/O in
123
+ sta $01
124
+ lda #<irq_entry
125
+ sta $fffe
126
+ lda #>irq_entry
127
+ sta $ffff
128
+ lda #<nmi
129
+ sta $fffa
130
+ lda #>nmi
131
+ sta $fffb
132
+
133
+ ldx #0
134
+ !: lda #$20
135
+ sta SCREEN, x
136
+ sta SCREEN + $100, x
137
+ sta SCREEN + $200, x
138
+ sta SCREEN + $2e8, x
139
+ lda #1
140
+ sta $d800, x
141
+ sta $d900, x
142
+ sta $da00, x
143
+ sta $dae8, x
144
+ inx
145
+ bne !-
146
+ ldx #0
147
+ !: lda labels, x
148
+ sta SCREEN, x
149
+ inx
150
+ cpx #160
151
+ bne !-
152
+
153
+ lda #0
154
+ sta $d020
155
+ sta $d021
156
+ sta $d017
157
+ sta $d01d
158
+ sta $d01c
159
+ sta $d01b
160
+
161
+ ldx #$2f // clear the zero-page variables
162
+ lda #0
163
+ !: sta $02, x
164
+ dex
165
+ bpl !-
166
+
167
+ // CIA2 timers as cycle counters: latch $FFFF, loaded, stopped.
168
+ lda #$ff
169
+ sta $dd04
170
+ sta $dd05
171
+ sta $dd06
172
+ sta $dd07
173
+ lda #$10
174
+ sta $dd0e
175
+ sta $dd0f
176
+
177
+ // Calibration: the count of a start immediately followed by a stop.
178
+ lda #$11
179
+ sta $dd0e
180
+ lda #$00
181
+ sta $dd0e
182
+ jsr read_a
183
+ lda n16
184
+ sta calib
185
+ lda n16 + 1
186
+ sta calib + 1
187
+
188
+ // Startup sort timings, IRQs off, screen and sprites off: with DEN
189
+ // clear when line $30 passes there are no badlines, so the timer
190
+ // counts only the CPU's own cycles.
191
+ lda #$0b
192
+ sta $d011
193
+ lda #0
194
+ sta $d015
195
+ !: lda $d012
196
+ bne !-
197
+ !: lda $d012
198
+ cmp #60
199
+ bne !-
200
+ ldx #N - 1
201
+ !: txa
202
+ sta order, x
203
+ dex
204
+ bpl !-
205
+ jsr move_actors
206
+ jsr sort // untimed: now sorted
207
+ jsr timed_sort // already sorted
208
+ lda n16
209
+ sta t_stable
210
+ lda n16 + 1
211
+ sta t_stable + 1
212
+
213
+ ldx #0 // order = i*7 mod 24
214
+ lda #0
215
+ !: sta order, x
216
+ clc
217
+ adc #7
218
+ cmp #N
219
+ bcc no_wrap
220
+ sbc #N
221
+ no_wrap:
222
+ inx
223
+ cpx #N
224
+ bne !-
225
+ jsr timed_sort
226
+ lda n16
227
+ sta t_shuf
228
+ lda n16 + 1
229
+ sta t_shuf + 1
230
+
231
+ ldx #0 // reverse the sorted order
232
+ ldy #N - 1
233
+ !: lda order, y
234
+ sta tmp_order, x
235
+ dey
236
+ inx
237
+ cpx #N
238
+ bne !-
239
+ ldx #N - 1
240
+ !: lda tmp_order, x
241
+ sta order, x
242
+ dex
243
+ bpl !-
244
+ jsr timed_sort
245
+ lda n16
246
+ sta t_rev
247
+ lda n16 + 1
248
+ sta t_rev + 1
249
+
250
+ // First frame: build half 0, show it, arm the frame IRQ.
251
+ lda #BUF // so that build's back half is 0
252
+ sta front_off
253
+ lda #$11 // timed like the sorts: screen still off
254
+ sta $dd0e
255
+ jsr build
256
+ lda #$00
257
+ sta $dd0e
258
+ jsr read_a
259
+ lda n16
260
+ sta t_build
261
+ lda n16 + 1
262
+ sta t_build + 1
263
+ lda #0
264
+ sta front_off
265
+ lda #<bottom_body
266
+ sta next_hnd
267
+ lda #>bottom_body
268
+ sta next_hnd + 1
269
+ jsr print_fixed
270
+ lda #$ff
271
+ sta $d015
272
+ lda #$1b
273
+ sta $d011 // screen on; bit 8 of the raster compare = 0
274
+ lda #BOTTOM
275
+ sta $d012
276
+ lda #$01
277
+ sta $d01a
278
+ sta $d019
279
+ cli
280
+
281
+ // ---------------------------------------------------------------------------
282
+ // Main loop: one pass per displayed frame.
283
+ // ---------------------------------------------------------------------------
284
+ main:
285
+ !: lda ready // wait until the frame IRQ took the last build
286
+ bne !-
287
+ jsr move_actors
288
+ lda #$11 // load $FFFF and start timer A
289
+ sta $dd0e
290
+ jsr sort
291
+ lda #$00
292
+ sta $dd0e // stop
293
+ jsr read_a
294
+ lda n16
295
+ sta sort_cyc
296
+ lda n16 + 1
297
+ sta sort_cyc + 1
298
+ cmp sort_max + 1 // keep the largest
299
+ bcc not_max
300
+ bne new_max
301
+ lda n16
302
+ cmp sort_max
303
+ bcc not_max
304
+ new_max:
305
+ lda n16
306
+ sta sort_max
307
+ lda n16 + 1
308
+ sta sort_max + 1
309
+ not_max:
310
+ jsr build
311
+ lda #1
312
+ sta ready
313
+ jsr print_stats
314
+ jmp main
315
+
316
+ timed_sort:
317
+ lda #$11
318
+ sta $dd0e
319
+ jsr sort
320
+ lda #$00
321
+ sta $dd0e
322
+ // fall through
323
+ // read_a: n16 = $FFFF - timer A - calib, then reload the latch.
324
+ read_a:
325
+ lda #$ff
326
+ sec
327
+ sbc $dd04
328
+ sta n16
329
+ lda #$ff
330
+ sbc $dd05
331
+ sta n16 + 1
332
+ lda n16
333
+ sec
334
+ sbc calib
335
+ sta n16
336
+ lda n16 + 1
337
+ sbc calib + 1
338
+ sta n16 + 1
339
+ lda #$10
340
+ sta $dd0e
341
+ rts
342
+
343
+ // ---------------------------------------------------------------------------
344
+ // Actors follow a 256-entry path table at their own phase and speed.
345
+ // ---------------------------------------------------------------------------
346
+ move_actors:
347
+ ldx #N - 1
348
+ !: lda phase, x
349
+ clc
350
+ adc speed, x
351
+ sta phase, x
352
+ tay
353
+ lda path, y
354
+ sta act_y, x
355
+ dex
356
+ bpl !-
357
+ rts
358
+
359
+ // ---------------------------------------------------------------------------
360
+ // Persistent insertion sort: order[] keeps last frame's order, so an
361
+ // element already in place costs one compare. Ties keep their order.
362
+ // ---------------------------------------------------------------------------
363
+ .align $100 // both loop branches stay inside one page
364
+ sort:
365
+ ldx #1
366
+ s_loop:
367
+ ldy order, x
368
+ lda act_y, y
369
+ ldy order - 1, x
370
+ cmp act_y, y
371
+ bcs s_next // y[order[i]] >= y[order[i-1]]: in place
372
+ sta key
373
+ lda order, x
374
+ sta cand
375
+ stx s_i
376
+ s_shift:
377
+ lda order - 1, x
378
+ sta order, x
379
+ dex
380
+ beq s_place
381
+ ldy order - 1, x
382
+ lda act_y, y
383
+ cmp key
384
+ beq s_place
385
+ bcs s_shift // still greater than the key: keep shifting
386
+ s_place:
387
+ lda cand
388
+ sta order, x
389
+ ldx s_i
390
+ s_next:
391
+ inx
392
+ cpx #N
393
+ bne s_loop
394
+ rts
395
+
396
+ // ---------------------------------------------------------------------------
397
+ // Build the back half: accept or reject each sorted actor, precalculate
398
+ // $D010, then group sprites 8.. into zones.
399
+ // ---------------------------------------------------------------------------
400
+ build:
401
+ lda front_off
402
+ eor #BUF
403
+ sta bo
404
+ sta acc
405
+ lda #0
406
+ sta d010run
407
+ sta rejects
408
+ ldx #0
409
+ b_loop:
410
+ stx bk
411
+ ldy order, x
412
+ lda act_y, y
413
+ sta by
414
+ ldx acc
415
+ txa
416
+ sec
417
+ sbc bo
418
+ cmp #8
419
+ bcc b_accept // the first eight always fit
420
+ lda by
421
+ sec
422
+ sbc sy - 8, x // gap to the last sprite this slot showed
423
+ cmp #MIN_GAP
424
+ bcc b_reject
425
+ b_accept:
426
+ lda by
427
+ sta sy, x
428
+ lda act_x, y
429
+ sta sx, x
430
+ lda act_ptr, y
431
+ sta sptr, x
432
+ lda act_col, y
433
+ sta scol, x
434
+ lda act_xh, y
435
+ beq b_clear
436
+ lda d010run
437
+ ora bitm, x
438
+ jmp b_store
439
+ b_clear:
440
+ lda bitm, x
441
+ eor #$ff
442
+ and d010run
443
+ b_store:
444
+ sta d010run
445
+ sta sd010, x
446
+ inx
447
+ stx acc
448
+ jmp b_next
449
+ b_reject:
450
+ inc rejects
451
+ b_next:
452
+ ldx bk
453
+ inx
454
+ cpx #N
455
+ bne b_loop
456
+
457
+ lda bo // zones over accepted sprites 8..acc-1
458
+ sta zw
459
+ clc
460
+ adc #8
461
+ tax
462
+ z_loop:
463
+ cpx acc
464
+ bcs z_done
465
+ ldy zw
466
+ txa
467
+ sta zstart, y
468
+ lda sy, x
469
+ sta ybase
470
+ clc
471
+ adc #JOIN
472
+ sta ylim
473
+ lda #0
474
+ sta zn
475
+ z_in:
476
+ inx
477
+ inc zn
478
+ cpx acc
479
+ bcs z_close
480
+ lda sy, x
481
+ cmp ylim
482
+ bcc z_in
483
+ beq z_in
484
+ z_close:
485
+ txa
486
+ sta zend, y
487
+ lda ybase
488
+ sec
489
+ sbc #LEAD
490
+ sbc zn
491
+ sta zline, y
492
+ inc zw
493
+ jmp z_loop
494
+ z_done:
495
+ ldy bo
496
+ lda zw
497
+ sta zlast_b, y
498
+ lda rejects
499
+ sta rej_b, y
500
+ rts
501
+
502
+ // ---------------------------------------------------------------------------
503
+ // IRQ. Entry pauses timer A (so an IRQ during the sort is not counted as
504
+ // sort time, apart from the cycles before the pause) and runs timer B,
505
+ // which adds up the multiplexer's IRQ time over one frame.
506
+ // ---------------------------------------------------------------------------
507
+ irq_entry:
508
+ sta save_a
509
+ lda $dd0e
510
+ and #$01
511
+ sta cra_save
512
+ lda #$00
513
+ sta $dd0e // pause the sort timer
514
+ lda #$01
515
+ sta $dd0f // run the IRQ timer
516
+ cld // binary arithmetic below, whatever was running
517
+ stx save_x
518
+ sty save_y
519
+ dispatch:
520
+ jmp (next_hnd)
521
+
522
+ // Zone body: write every sprite of zone zidx, Y first.
523
+ zone_body:
524
+ ldx zidx
525
+ lda zend, x
526
+ sta zend_tmp
527
+ ldy zstart, x
528
+ zl:
529
+ ldx slot2, y
530
+ lda sy, y
531
+ sta $d001, x
532
+ lda sx, y
533
+ sta $d000, x
534
+ ldx slot, y
535
+ lda sptr, y
536
+ sta PTRS, x
537
+ lda scol, y
538
+ sta $d027, x
539
+ lda sd010, y
540
+ sta $d010
541
+ iny
542
+ cpy zend_tmp
543
+ bne zl
544
+ ldx zidx
545
+ inx
546
+ stx zidx
547
+ cpx zlast
548
+ beq z_to_bottom
549
+ lda zline, x
550
+ jmp schedule
551
+ z_to_bottom:
552
+ lda #<bottom_body
553
+ sta next_hnd
554
+ lda #>bottom_body
555
+ sta next_hnd + 1
556
+ lda #BOTTOM
557
+ // fall through
558
+
559
+ // schedule: A = next line. If the raster is already within MARGIN lines
560
+ // of it, run the next body now instead of returning and waiting a frame.
561
+ schedule:
562
+ sta $d012
563
+ sec
564
+ sbc #MARGIN
565
+ cmp $d012
566
+ bcs on_time
567
+ inc late_total
568
+ bne !+
569
+ inc late_total + 1
570
+ !: lda #1
571
+ sta late_flag
572
+ jmp dispatch
573
+ on_time:
574
+ lda #$01
575
+ sta $d019
576
+ irq_exit:
577
+ ldy save_y
578
+ ldx save_x
579
+ lda #$00
580
+ sta $dd0f // stop the IRQ timer
581
+ lda cra_save
582
+ sta $dd0e // resume the sort timer if it was running
583
+ lda save_a
584
+ nmi:
585
+ rti
586
+
587
+ // Frame body at line BOTTOM: swap halves if a build is ready, write the
588
+ // first eight sprites of the shown half, arm the first zone.
589
+ bottom_body:
590
+ lda ready
591
+ beq no_swap
592
+ lda front_off
593
+ eor #BUF
594
+ sta front_off
595
+ lda #0
596
+ sta ready
597
+ jmp swapped
598
+ no_swap:
599
+ inc missed
600
+ bne swapped
601
+ inc missed + 1
602
+ swapped:
603
+ ldy front_off
604
+ .for (var s = 0; s < 8; s++) {
605
+ lda sy + s, y
606
+ sta $d001 + s * 2
607
+ lda sx + s, y
608
+ sta $d000 + s * 2
609
+ lda sptr + s, y
610
+ sta PTRS + s
611
+ lda scol + s, y
612
+ sta $d027 + s
613
+ }
614
+ lda sd010 + 7, y
615
+ sta $d010
616
+ sty zidx
617
+ lda zlast_b, y
618
+ sta zlast
619
+ inc frames
620
+ bne !+
621
+ inc frames + 1
622
+ !: lda late_flag
623
+ beq !+
624
+ inc late_frms
625
+ bne !+
626
+ inc late_frms + 1
627
+ !: lda #0
628
+ sta late_flag
629
+ sta $dd0f // stop timer B and read one frame's IRQ time
630
+ lda #$ff
631
+ sec
632
+ sbc $dd06
633
+ sta irq_cyc
634
+ lda #$ff
635
+ sbc $dd07
636
+ sta irq_cyc + 1
637
+ lda #$10
638
+ sta $dd0f // reload $FFFF, stopped
639
+ ldx zidx
640
+ cpx zlast
641
+ beq only_eight
642
+ lda #<zone_body
643
+ sta next_hnd
644
+ lda #>zone_body
645
+ sta next_hnd + 1
646
+ lda zline, x
647
+ jmp arm
648
+ only_eight:
649
+ lda #BOTTOM
650
+ arm:
651
+ sta $d012 // next frame: no late check across the wrap
652
+ jmp on_time
653
+
654
+ // ---------------------------------------------------------------------------
655
+ // Statistics, printed by the main loop after each build.
656
+ // ---------------------------------------------------------------------------
657
+ .macro Print(v, col) {
658
+ lda v
659
+ sta n16
660
+ lda v + 1
661
+ sta n16 + 1
662
+ lda #<(SCREEN + col)
663
+ sta dst
664
+ lda #>(SCREEN + col)
665
+ sta dst + 1
666
+ jsr pr16
667
+ }
668
+
669
+ // The figures fixed at startup are printed once; the live ones in two
670
+ // halves on alternate frames, so printing does not crowd out the build.
671
+ print_fixed:
672
+ Print(t_build, 35)
673
+ Print(t_stable, 40 + 7)
674
+ Print(t_shuf, 40 + 18)
675
+ Print(t_rev, 40 + 28)
676
+ Print(calib, 120 + 30)
677
+ rts
678
+
679
+ print_stats:
680
+ inc pflip
681
+ lda pflip
682
+ and #1
683
+ beq print_a
684
+ Print(late_total, 80 + 5)
685
+ Print(late_frms, 80 + 16)
686
+ Print(frames, 120 + 7)
687
+ Print(missed, 120 + 20)
688
+ rts
689
+ print_a:
690
+ Print(sort_cyc, 5)
691
+ Print(sort_max, 15)
692
+ Print(irq_cyc, 25)
693
+ ldy bo // zones and rejects of the half just built
694
+ lda zlast_b, y
695
+ sec
696
+ sbc bo
697
+ sta n16
698
+ lda #0
699
+ sta n16 + 1
700
+ lda #<(SCREEN + 80 + 25)
701
+ sta dst
702
+ lda #>(SCREEN + 80 + 25)
703
+ sta dst + 1
704
+ jsr pr16
705
+ ldy bo
706
+ lda rej_b, y
707
+ sta n16
708
+ lda #0
709
+ sta n16 + 1
710
+ lda #<(SCREEN + 80 + 34)
711
+ sta dst
712
+ lda #>(SCREEN + 80 + 34)
713
+ sta dst + 1
714
+ // fall through
715
+
716
+ // pr16: n16 as five decimal digits at (dst).
717
+ pr16:
718
+ ldy #0
719
+ ldx #0
720
+ d_loop:
721
+ lda #$30 // screen code of '0'
722
+ sta digit
723
+ d_sub:
724
+ lda n16
725
+ sec
726
+ sbc p10lo, x
727
+ sta tmp
728
+ lda n16 + 1
729
+ sbc p10hi, x
730
+ bcc d_out
731
+ sta n16 + 1
732
+ lda tmp
733
+ sta n16
734
+ inc digit
735
+ jmp d_sub
736
+ d_out:
737
+ lda digit
738
+ sta (dst), y
739
+ iny
740
+ inx
741
+ cpx #5
742
+ bne d_loop
743
+ rts
744
+
745
+ p10lo: .byte <10000, <1000, <100, <10, <1
746
+ p10hi: .byte >10000, >1000, >100, >10, >1
747
+
748
+ labels:
749
+ .text "sort max irq bld "
750
+ .text "stable shuf rev "
751
+ .text "late lfrm zn rj "
752
+ .text "frames missed cal "
753
+
754
+ // ---------------------------------------------------------------------------
755
+ // Tables
756
+ // ---------------------------------------------------------------------------
757
+ * = $1000 "tables"
758
+ path: .fill 256, TOP_Y + round(69 + 69 * sin(toRadians(i * 360 / 256)))
759
+ act_y: .fill N, 0
760
+ act_x: .fill N, (24 + 13 * i) & $ff
761
+ act_xh: .fill N, (24 + 13 * i) >> 8
762
+ act_col: .fill N, 1 + mod(i, 15)
763
+ act_ptr: .fill N, $2000 / 64
764
+ phase: .fill N, mod(i * 45, 256)
765
+ speed: .fill N, (i & 3) == 3 ? $fe : 1 + (i & 3)
766
+ order: .fill N, i
767
+ tmp_order: .fill N, 0
768
+
769
+ * = $1200 "sorted halves"
770
+ sy: .fill 64, 0
771
+ sx: .fill 64, 0
772
+ sptr: .fill 64, 0
773
+ scol: .fill 64, 0
774
+ sd010: .fill 64, 0
775
+ zstart: .fill 64, 0
776
+ zend: .fill 64, 0
777
+ zline: .fill 64, 0
778
+ zlast_b: .fill 64, 0
779
+ rej_b: .fill 64, 0
780
+ slot: .fill 64, i & 7
781
+ slot2: .fill 64, (i & 7) * 2
782
+ bitm: .fill 64, 1 << (i & 7)
783
+
784
+ // One shape: an 8-pixel-wide, 21-line block in the sprite's left byte.
785
+ * = $2000 "sprite"
786
+ .fill 21, [$ff, $00, $00]
787
+ .byte 0
788
+ ```
789
+
790
+ ## Build
791
+
792
+ ```bash
793
+ java -jar KickAss.jar sprite-multiplex-game.asm -o sprite-multiplex-game.prg -showmem
794
+ ```
795
+
796
+ `-showmem` prints code at $0820–$0EAA, the actor and path tables at
797
+ $1000–$11D7, the two sorted halves and the slot tables at $1200–$153F and
798
+ the sprite shape at $2000. The sort is aligned to a page (`.align $100`),
799
+ which is why the code segment has a gap.
800
+
801
+ ## Expected output
802
+
803
+ A black screen. The top four text rows, in white:
804
+
805
+ ```text
806
+ SORT 00750 MAX 01411 IRQ 02764 BLD 03815
807
+ STABLE 00611 SHUF 05228 REV 08783
808
+ LATE 00370 LFRM 00249 ZN 00010 RJ 00000
809
+ FRAMES 00309 MISSED 00001 CAL 00005
810
+ ```
811
+
812
+ That is the PAL screenshot at 9,100,000 cycles. The NTSC one reads SORT
813
+ 815, MAX 1,411, IRQ 2,608, LATE 369, LFRM 266, ZN 10, RJ 0, FRAMES 346,
814
+ MISSED 0, and the same five startup figures. The fields are:
815
+
816
+ | Field | What it counts |
817
+ |---|---|
818
+ | SORT, MAX | Cycles of this frame's sort call, and the largest so far (CIA2 timer A). |
819
+ | IRQ | Cycles inside the multiplexer IRQs over one frame (CIA2 timer B), from the timer-start write to the timer-stop write of each IRQ. |
820
+ | BLD | One build of a sorted half, timed at startup. |
821
+ | STABLE, SHUF, REV | The sort at startup on an order already sorted, on the order i×7 mod 24, and on the sorted order reversed. |
822
+ | LATE, LFRM | Times the late guard ran the next zone at once, and frames in which it did so at least once. |
823
+ | ZN, RJ | Zones and rejected actors in the half just built. |
824
+ | FRAMES, MISSED | Frame IRQs so far, and frames shown twice because the build was not ready. |
825
+ | CAL | Timer count of a start write followed at once by a stop write; every timed figure has it subtracted. |
826
+
827
+ Below the text, 24 boxes, 8 pixels wide and 21 lines tall, one per
828
+ column at sprite X = 24 + 13 × i, in colours 1–15 repeating. Actors 18–23
829
+ sit past X = 255 and need their $D010 bit. The boxes rise and fall on a
830
+ sine at different speeds and phases, so they overtake one another in Y
831
+ and the sort has work to do.
832
+
833
+ Screenshots from the VICE runs this page describes:
834
+ `screenshots/sprite-multiplex-game.png` (PAL) and
835
+ `screenshots/sprite-multiplex-game-ntsc.png` (NTSC), both at
836
+ 9,100,000 cycles. Each command was run twice and gave identical bytes.
837
+
838
+ ## Why this works
839
+
840
+ ### What was measured
841
+
842
+ The text rows were decoded from the screenshots by matching each 8×8 cell
843
+ against the character ROM (`chargen-901225-01.bin`). The sprite check
844
+ walked each actor's column at screenshot x = 35 + 13 × i and recorded each
845
+ lit run (PAL row = raster line − 16, NTSC row = line − 28).
846
+
847
+ | Claim | Result | Rung |
848
+ |---|---|---|
849
+ | Every actor is drawn | 24 of 24 columns hold a box in both pinned shots and in 16 swept shots (PAL and NTSC, 8.1 to 9.5 million cycles, 200,000 apart) | measured in VICE x64sc |
850
+ | Boxes are whole | Pinned shots: every box is 21 lines, 8 pixels, one colour. In 9 of the 16 swept shots, 2 to 4 boxes were 18 to 26 lines long or had a 1-line fragment beside them, because the exit screenshot cut the frame there (the mid-frame effect in `docs/runtime/vice-reference.md`). The beam line at exit, (cycles mod 19,656) / 63 on PAL and (cycles mod 17,095) / 65 on NTSC, lies inside the split boxes' lines in all 9 of those shots and outside sprite lines 91 to 249 in the 7 clean ones. PAL reruns at 8,519,656 and 8,539,312 cycles (beam at line 136) split boxes at 136 again; 8,509,828 and 8,529,484 (beam at line 292) were clean | measured; the cut line predicted by arithmetic and confirmed by runs one frame apart |
851
+ | Sort, order already sorted | 611 cycles for 24 actors, JSR and RTS included. The listing gives JSR 6 + `ldx #1` 2 + 26 per compare × 23 − 1 (the last `bne` not taken) + RTS 6 = 611, which matches the measurement | measured, and arithmetic agrees |
852
+ | Same sort straddling a page | 656 cycles: both loop branches crossed a page and took 28 per compare. Hence `.align $100` | measured |
853
+ | Sort, shuffled (i×7 mod 24) | 5,228 cycles | measured |
854
+ | Sort, reversed | 8,783 cycles: 276 moves, about 29.6 cycles per place an element moves | measured |
855
+ | Sort in the running game | 611 to 953 cycles in the 16 swept shots (PAL and NTSC, 8.1 to 9.5 million cycles); largest 1,411 in the first 257 to 370 frames of each | measured |
856
+ | Build of one sorted half | 3,815 cycles | measured |
857
+ | IRQ time per frame | 2,201 to 2,764 cycles in the same 16 shots, with 7 to 13 zones built (10 in the pinned shot) | measured |
858
+ | IRQ time the timer does not see | 31 cycles before the start write (7 for the interrupt, 24 of prologue) and 16 after the stop write, per IRQ taken | arithmetic from the listing |
859
+ | Late guard | Fired 370 times in 309 PAL frames, in 249 of them; 369 times in 346 NTSC frames, in 266 of them | measured |
860
+ | Late guard overshoot | A probe build recorded the raster on the fall-through path: at most 5 lines past line − 3, so at most 2 lines past the scheduled line and at least 2 lines before the zone's first Y (PAL, 309 frames). An 8-sprite zone under full sprite DMA on a badline was not measured | measured in VICE x64sc |
861
+ | Late guard removed | A build with `bcs on_time` changed to `jmp on_time` showed 11 of 24 boxes in 2 of the 16 swept shots (9,300,000 cycles, PAL and NTSC) and 24 in the other 14 | measured |
862
+ | Printing load | Printing all twelve figures every frame left MISSED at 13 of about 260 PAL frames and 66 of about 290 NTSC frames; printing the five startup figures once and the live ones half at a time brought it to 0 or 1 | measured |
863
+
864
+ The startup timings run with IRQs off, sprites off and $D011 = $0B. DEN
865
+ is clear when line $30 passes, so there are no badlines and the timer
866
+ counts only the CPU's own cycles. With the screen and sprites on, the
867
+ already-sorted figure read 742.
868
+
869
+ ### The sort keeps last frame's order
870
+
871
+ `order[]` is never reset. Each frame starts from the order the last frame
872
+ ended with, so an actor that has not passed a neighbour costs one compare:
873
+ `ldy order,x / lda act_y,y / ldy order-1,x / cmp act_y,y / bcs`, 26
874
+ cycles with the loop control. An actor that has passed k neighbours is
875
+ shifted k places at about 29.6 cycles a place. On paths that move 1 to 3
876
+ lines a frame that is a few hundred cycles above the sorted figure. A
877
+ reversed order is the worst case, 8,783 cycles, about 45 % of a PAL frame
878
+ on the sort alone. Ties stop the shift (`beq s_place`), so equal Ys keep
879
+ their order and do not swap back and forth from frame to frame.
880
+
881
+ ### Two halves, one flag
882
+
883
+ The sorted tables `sy`, `sx`, `sptr`, `scol` and `sd010` are 64 bytes
884
+ each: half 0 at offset 0 and half 1 at offset 32. The IRQs read the half
885
+ at `front_off`; the main loop builds the other. The main loop waits until
886
+ `ready` is 0, builds, then sets `ready`. The frame IRQ swaps only when
887
+ `ready` is 1. The main loop therefore never writes a half the IRQs are
888
+ reading, and a late build shows the old half again (MISSED) instead of a
889
+ half-written table. The unsorted actor tables are not doubled; only the
890
+ main loop touches them.
891
+
892
+ ### Rejecting the ninth sprite
893
+
894
+ A sorted entry at accepted position a ≥ 8 goes to slot a mod 8, which last
895
+ showed entry a − 8. `build` rejects the actor when its Y is less than 21
896
+ lines below that entry's Y and counts it in RJ. Twenty-one is the gap the
897
+ hardware needs: `docs/pitfalls/sprite.md` (`sprite_dma_overflow`) measured
898
+ a slot at Y = 100 rewritten to Y = 120 never reappearing, while Y = 121
899
+ did. A variant with the path squeezed into 50 lines showed RJ = 3 and 20
900
+ of 24 boxes in one PAL shot.
901
+
902
+ ### Zones
903
+
904
+ Sprites 8 onward are grouped: a zone starts at the first unwritten sprite
905
+ and takes every following sprite whose Y is at most 4 lines lower. The
906
+ zone's IRQ line is its first Y − 3 − n, where n is its sprite count. The
907
+ writes cost about 60 cycles a sprite (arithmetic from the loop), about one
908
+ line, and Y is written first. A zone can hold at most eight sprites:
909
+ two sprites within 4 lines cannot share a slot, since accepted entries in
910
+ one slot are at least 21 lines apart. The same fact means the slot's
911
+ previous sprite started at least 17 lines above the zone's first Y, so the
912
+ IRQ line (at most 11 lines above it) is always after that start.
913
+
914
+ What the zone does not wait for is the end of the previous sprite. If the
915
+ new sprite is exactly 21 lines below the old one, the new X, colour and
916
+ pointer land while the old sprite still has its last few lines to draw.
917
+ In the squeezed variant, 1- to 3-line stubs in another actor's colour
918
+ appeared next to some boxes; that is this effect. Writing Y last and
919
+ firing the IRQ just below the old sprite avoids it, at the cost of
920
+ dropping the new sprite when the IRQ is late (Cadaver, sprite.html,
921
+ section 2.4.2).
922
+
923
+ ### The late guard
924
+
925
+ At the end of every zone the handler stores the next zone's line in
926
+ $D012, subtracts 3 and compares with $D012. If the raster has already
927
+ reached that point it jumps straight to the next zone's body, skipping
928
+ the exit, the acknowledge and the next entry. Without the guard, an IRQ
929
+ line written after the raster has passed it does not fire until the
930
+ next frame, and every zone after it that frame is lost: 11 of 24 boxes in
931
+ 2 of the 16 swept shots of the variant above. The acknowledge ($D019 = $01) is written only on the
932
+ on-time path, after the guard, so a compare that matched during a
933
+ fall-through does not raise a second IRQ. Cadaver found that a margin of
934
+ 2 lines still flickered in rare cases and uses 3 (not measured here).
935
+ The frame IRQ does not use the guard: its next line is in the next
936
+ frame, and any compare with the current raster would call it late.
937
+
938
+ ### $D010 is precalculated
939
+
940
+ `build` keeps a running $D010 value and stores, with every sorted entry,
941
+ the $D010 byte as it must be after that entry is written. The IRQ writes
942
+ one precomputed byte instead of reading, masking and setting a bit. The
943
+ frame IRQ writes the byte stored with entry 7.
944
+
945
+ ### The timers
946
+
947
+ CIA2 timer A times the sort and B adds up IRQ time. Both latch $FFFF.
948
+ Writing $11 to a control register loads $FFFF and starts the timer;
949
+ writing $00 stops it; the elapsed count is $FFFF minus the timer, less
950
+ CAL. The IRQ prologue reads timer A's control register, keeps its start
951
+ bit, and stops it, then starts timer B; the epilogue stops B and writes
952
+ A's saved start bit back. A stopped timer restarts from its current count,
953
+ so an IRQ that lands during the sort adds only its first 25 or so cycles
954
+ to SORT. In this program the sort runs in the lower border after the
955
+ frame IRQ, where no zone IRQ fires. CIA2's interrupt mask is cleared so
956
+ the timers cannot raise an NMI. The prologue clears the decimal flag
957
+ before any arithmetic.
958
+
959
+ ### Where the time goes
960
+
961
+ Per PAL frame in the pinned shot: sort 750, build about 3,815, IRQs 2,764
962
+ plus about 47 per IRQ taken. The build copies five bytes for every actor
963
+ so the IRQ indexes one set of tables; it is the largest item. The main
964
+ loop also runs `move_actors` and prints, and the VIC takes its badline and
965
+ sprite cycles. Printing all twelve figures every frame was enough to
966
+ overrun on NTSC (MISSED 66 of about 290), which is why the live figures
967
+ are printed half at a time.
968
+
969
+ ### Region
970
+
971
+ `region: both`. Every IRQ line is between 79 and 252, inside PAL's 312
972
+ and NTSC's 263 lines, so $D011 bit 7 stays 0. Sprite Ys run from 90 to
973
+ 228; the last sprite line is 249, before the frame IRQ at 252. Lines 256
974
+ and later on PAL compare as 0 to 55 in the low byte, below every sprite Y
975
+ used here. The pinned run uses the same cycle count on both models.
976
+
977
+ ### Sources
978
+
979
+ Facts, not code, from: Cadaver, "Sprite multiplexing",
980
+ https://cadaver.github.io/rants/sprite.html (continuous insertion sort,
981
+ the 21-line rejection, double-buffered sorted tables, precalculated
982
+ $D010, the late-IRQ check with a 3-line margin); Falco Paul in Cadaver's
983
+ "Speculative sprite sorting methods",
984
+ https://cadaver.github.io/rants/sorting.html (bucket and hybrid sorts);
985
+ cadaver/c64gameframework, https://github.com/cadaver/c64gameframework
986
+ (`screen.s`, `raster.s`; MIT), read for names and structure only.