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,930 @@
1
+ ---
2
+ recipe: pseudo-3d-road
3
+ toolchain: kickassembler
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [pseudo_3d_road_raster]
7
+ file_formats: [PRG]
8
+ uses_registers: [D011, D012, D016, D018, D019, D01A, D021, D022, D023, DC04, DC05, DC0E]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # KickAssembler — Pseudo-3D Curving Road
15
+
16
+ ## Synopsis
17
+
18
+ A perspective road that appears to recede toward a horizon and curve left and
19
+ right, built from two layers. The coarse layer redraws thirteen character rows
20
+ of road in the vertical blank using multicolour characters (grass, road
21
+ surface, kerb, centre stripe) placed at positions derived from a Z table and
22
+ an 8.8 fixed-point centre accumulator. The fine layer runs a cycle-locked
23
+ loop starting at line 99 that writes a precomputed $D016 value for each of
24
+ the hundred road raster lines (100..199), placing the STA $D016 write at
25
+ cycle 11 of each line (before the cycle-14 VIC deadline). The road curves
26
+ because a per-frame delta accumulates signed fixed-point offsets from a
27
+ four-entry segment table; as scroll_z advances the four segments roll toward
28
+ the viewer. Verdict bytes and CIA-timed cycle counts land at $02F0-$02F3 and $02FF.
29
+
30
+ The fine layer uses the double-IRQ method from `stable_raster_irq.md` to
31
+ reach cycle 4 of line 100 with zero jitter, then runs an unrolled 100-iteration
32
+ loop. Each iteration is exactly one raster line long: 63 CPU cycles on PAL,
33
+ 65 on NTSC. Badline iterations (lines where (raster & 7) == YSCROLL = 3)
34
+ use 23 CPU cycles on PAL (25 on NTSC); the 40-cycle badline steal absorbs
35
+ the remainder. Separate unrolled loops for PAL and NTSC are selected at boot.
36
+
37
+ ## Source
38
+
39
+ ```asm
40
+ // pseudo-3d-road.asm KickAssembler 5.25
41
+ //
42
+ // Pseudo-3D curving road: multicolour characters (coarse) + per-line
43
+ // $D016 XSCROLL (fine). Charset $3000, screen $0400, VIC bank 0.
44
+ //
45
+ // Three IRQ handlers per frame:
46
+ // vblank_irq (line 251): compute cx[]/xscroll_d16[], CIA-time coarse redraw,
47
+ // verdict, re-arm for road_irq1.
48
+ // road_irq1 (line 97): start CIA fine timer, double-IRQ setup, NOP slide.
49
+ // road_irq2_pal / road_irq2_ntsc (line 99): cycle-exact sync via double
50
+ // $D012 read + BEQ, unrolled 100-iteration fine loop, epilogue.
51
+ //
52
+ // Cycle arithmetic (both models land at cycle 4 of line 100 after BEQ sync):
53
+ // LDA xscroll_d16+j : cycles 4..7 of line 100+j
54
+ // STA $D016 : cycles 8..11 (WRITE at cycle 11, before cycle-14 deadline)
55
+ // PAL normal body : LDA(4) + STA(4) + Delay(55) = 63 cpu cycles
56
+ // PAL badline body : LDA(4) + STA(4) + Delay(15) = 23 cpu cycles + 40 stall = 63 elapsed
57
+ // NTSC normal body : LDA(4) + STA(4) + Delay(57) = 65 cpu cycles
58
+ // NTSC badline body : LDA(4) + STA(4) + Delay(17) = 25 cpu cycles + 40 stall = 65 elapsed
59
+ // Badlines in 100..199 with YSCROLL=3: lines 107,115,123,131,139,147,155,163,171,179,187,195
60
+ //
61
+ // Sync calibration (road_irq1 before NOP slide: 57 cycles PAL, 55 NTSC):
62
+ // C2 = irq2 entry cycle on line 99 = 38 (zero-jitter) or 39 (one-jitter).
63
+ // Path inside irq2: ldx+txs(6)+cld(2)+Delay(PAD)+lda+cmp = C2+15+PAD for 2nd read.
64
+ // PAL: second $D012 read at C2+15+PAD_PAL=63/64. PAD_PAL=10.
65
+ // NTSC: second $D012 read at C2+15+PAD_NTSC=65/66. PAD_NTSC=12.
66
+ // BEQ lands at cycle 4 of line 100; STA write at cycle 11.
67
+ //
68
+ // Verdict $02FF = 1 if coarse < 10 000 cycles AND kerb column matches.
69
+ // Coarse cycles at $02F0/$02F1; fine chain (irq1 start to fine_done) at $02F2/$02F3.
70
+
71
+ BasicUpstart2(main)
72
+
73
+ // ---- Memory map ----
74
+ .const SCREEN = $0400
75
+ .const CHARSET = $3000
76
+ .const COLRAM = $d800
77
+
78
+ // VIC registers
79
+ .const D011 = $d011
80
+ .const D012 = $d012
81
+ .const D016 = $d016
82
+ .const D018 = $d018
83
+ .const D019 = $d019
84
+ .const D01A = $d01a
85
+ .const D020 = $d020
86
+ .const D021 = $d021
87
+ .const D022 = $d022
88
+ .const D023 = $d023
89
+
90
+ // CIA1 timer A
91
+ .const CIA_TALO = $dc04
92
+ .const CIA_TAHI = $dc05
93
+ .const CIA_CRA = $dc0e
94
+ .const CIA_ICR = $dc0d
95
+
96
+ // Character codes (multicolour char pixel encoding)
97
+ // %00 -> $D021 (green, grass bg) CH_GRASS: all $00
98
+ // %01 -> $D022 (dark grey, road) CH_ROAD: all $55
99
+ // %10 -> $D023 (white, kerb) CH_KLEFT: $a5; CH_KRIGHT: $5a
100
+ // %11 -> colour RAM (bit3 set) CH_DASH: $69 (grey-white-white-grey)
101
+ .const CH_GRASS = 0
102
+ .const CH_ROAD = 1
103
+ .const CH_KLEFT = 2
104
+ .const CH_KRIGHT = 3
105
+ .const CH_DASH = 4
106
+
107
+ // VIC colours
108
+ .const C_GREEN = 5
109
+ .const C_DGREY = 11
110
+ .const C_WHITE = 1
111
+ .const C_BLACK = 0
112
+ .const C_RED = 2
113
+ .const C_BLUE = 6
114
+
115
+ // $D016 constant bits: MCM (bit4=1), CSEL/40col (bit3=1), XSCROLL=0
116
+ .const D016_BASE = $18
117
+
118
+ // Zero page
119
+ .const ZP_CXHI = $10 // cx high byte (integer pixel; 8.8 fixed point)
120
+ .const ZP_CXLO = $11 // cx low byte (8.8 fraction)
121
+ .const ZP_DXHI = $12 // dx high byte (signed per-line-per-line curvature)
122
+ .const ZP_DXLO = $13 // dx low byte
123
+ .const ZP_SCR = $14 // scroll_z (0..99; advances 1/frame)
124
+ .const ZP_SEG = $15 // current curve segment index (0..3)
125
+ .const ZP_REM = $16 // remaining lines until next segment switch
126
+ .const ZP_T1 = $17 // scratch
127
+ .const ZP_T2 = $18 // scratch
128
+ .const ZP_RPLO = $19 // row pointer lo (indirect indexed)
129
+ .const ZP_RPHI = $1a // row pointer hi
130
+ .const ZP_LC = $1b // left char column for current road row
131
+ .const ZP_RC = $1c // right char column for current road row
132
+
133
+ // Spec result addresses
134
+ .const COARSE_LO = $02f0
135
+ .const COARSE_HI = $02f1
136
+ .const FINE_LO = $02f2
137
+ .const FINE_HI = $02f3
138
+ .const VERDICT = $02ff
139
+
140
+ // Small variables (safe area, below spec result addresses)
141
+ .const SAVED_SP = $02e0 // saved stack pointer for double-IRQ
142
+ .const REG_FLAG = $02e1 // 0 = PAL, 1 = NTSC (set once at boot by detect_region)
143
+
144
+ // Road dimensions
145
+ .const NLINES = 100 // raster lines 100..199
146
+ .const NROWS = 13 // character rows 6..18 (r=0=nearest=row18 .. r=12=farthest=row6)
147
+
148
+ // Delay(n): exactly n cpu cycles of straight-line code, n >= 2.
149
+ .macro Delay(n) {
150
+ .if (n < 2) .error "Delay needs >= 2 cycles"
151
+ .if ((n & 1) != 0) { bit $ea }
152
+ .for (var i = 0; i < ((n & 1) != 0 ? n - 3 : n) / 2; i++) { nop }
153
+ }
154
+
155
+ // ---- Working tables ($1100) ----
156
+ * = $1100
157
+ cx_hi_buf: .fill NLINES, 0 // cx integer part per i=0..99 (i=0=nearest)
158
+ xscroll_d16: .fill NLINES, D016_BASE // $D016 value per road line (index 0=line 100)
159
+ left_col: .fill NROWS, 0
160
+ right_col: .fill NROWS, 0
161
+
162
+ // ---- Static tables ($1200) ----
163
+ * = $1200
164
+ // hw[i] = max(4, round(152-1.5*i)), i=0..99. Arithmetic from spec.
165
+ hw_table:
166
+ .byte 152,151,149,148,146,145,143,142,140,139
167
+ .byte 137,136,134,133,131,130,128,127,125,124
168
+ .byte 122,121,119,118,116,115,113,112,110,109
169
+ .byte 107,106,104,103,101,100, 98, 97, 95, 94
170
+ .byte 92, 91, 89, 88, 86, 85, 83, 82, 80, 79
171
+ .byte 77, 76, 74, 73, 71, 70, 68, 67, 65, 64
172
+ .byte 62, 61, 59, 58, 56, 55, 53, 52, 50, 49
173
+ .byte 47, 46, 44, 43, 41, 40, 38, 37, 35, 34
174
+ .byte 32, 31, 29, 28, 26, 25, 23, 22, 20, 19
175
+ .byte 17, 16, 14, 13, 11, 10, 8, 7, 5, 4
176
+
177
+ // Curve deltas (4 segments): 0, +51, 0, -51 in 8.8 signed fixed point.
178
+ // -51 as 16-bit signed: $FFCD.
179
+ curve_lo: .byte 0, 51, 0, $cd
180
+ curve_hi: .byte 0, 0, 0, $ff
181
+
182
+ // Screen base addresses for road rows r=0..12 (row 18 down to row 6).
183
+ // SCREEN + row*40. Precomputed: row18=$06D0, row17=$06A8, ..., row6=$04F0.
184
+ road_lo: .byte $d0,$a8,$80,$58,$30,$08,$e0,$b8,$90,$68,$40,$18,$f0
185
+ road_hi: .byte $06,$06,$06,$06,$06,$06,$05,$05,$05,$05,$05,$05,$04
186
+
187
+ // ---- detect_region subroutine ($0A00) ----
188
+ // Sets REG_FLAG = 0 (PAL) or 1 (NTSC). Call with SEI; re-enables interrupts on exit.
189
+ // Method: track $D012 while RST8 is set; last value is $37 on PAL, $06/$05 on NTSC.
190
+ * = $0a00
191
+ detect_region:
192
+ sei
193
+ dr_wait_lo:
194
+ bit D011
195
+ bmi dr_wait_lo // let any current RST8 band finish
196
+ dr_wait_hi:
197
+ bit D011
198
+ bpl dr_wait_hi // wait for RST8 to set (line 256)
199
+ dr_track:
200
+ lda D012 // sample low byte
201
+ bit D011
202
+ bpl dr_band_over // keep only if RST8 still set
203
+ tax
204
+ jmp dr_track
205
+ dr_band_over: // X = last $D012 in band: $37=PAL, $06/$05=NTSC
206
+ lda #0
207
+ cpx #$10
208
+ bcs dr_set_flag // $10 or above: PAL, flag=0
209
+ lda #1 // below $10: NTSC, flag=1
210
+ dr_set_flag:
211
+ sta REG_FLAG
212
+ cli
213
+ rts
214
+
215
+ // ---- road_irq1 handler ($0B00) ----
216
+ // Fires at line 97 (two lines before the sync line 99).
217
+ // Starts CIA fine timer, arms road_irq2 for line 99, saves SP, CLI, NOP slide.
218
+ // irq2 fires during the NOP slide and returns via irq1's stack frame.
219
+ //
220
+ // road_irq1 cycle count before NOP slide:
221
+ // PAL path: CIA_start(16) + lda+bne(6) + vector_set(12) + jmp(3) + common(20) = 57 cycles
222
+ // NTSC path: CIA_start(16) + lda+bne(7) + vector_set(12) + common(20) = 55 cycles
223
+ // irq1 entry at cycle 37-39 of line 97 (main loop jmp = 3 cycles, 0-2 cycle jitter).
224
+ // NOP slide starts at cycle 22-24 of line 98.
225
+ // irq2 /IRQ fires at cycle 1 of line 99; CPU is in NOP slide.
226
+ // irq2 enters at cycle 38 (zero-jitter) or 39 (one-jitter) of line 99.
227
+ * = $0b00
228
+ road_irq1:
229
+ // Start CIA fine timer (will run until fine_done stops it)
230
+ lda #$ff // 2
231
+ sta CIA_TALO // 4
232
+ sta CIA_TAHI // 4
233
+ lda #$11 // 2 (START, PHI2 clock, continuous)
234
+ sta CIA_CRA // 4 = 16 cycles
235
+
236
+ // Select road_irq2 based on model
237
+ lda REG_FLAG // 4
238
+ bne ri1_ntsc // 2 (PAL: not taken); 3 (NTSC: taken)
239
+ ri1_pal:
240
+ lda #<road_irq2_pal // 2
241
+ sta $0314 // 4
242
+ lda #>road_irq2_pal // 2
243
+ sta $0315 // 4
244
+ jmp ri1_common // 3
245
+ ri1_ntsc:
246
+ lda #<road_irq2_ntsc // 2
247
+ sta $0314 // 4
248
+ lda #>road_irq2_ntsc // 2
249
+ sta $0315 // 4
250
+ ri1_common:
251
+ lda #99 // 2 arm irq2 for line 99
252
+ sta D012 // 4
253
+ lda #$01 // 2
254
+ sta D019 // 4 ack irq1
255
+ tsx // 2
256
+ stx SAVED_SP // 4 save SP for irq2 to discard irq2's own frame
257
+ cli // 2 allow irq2 to fire during NOP slide
258
+
259
+ // NOP slide: 40 NOPs = 80 cycles.
260
+ // irq2 fires before this completes and returns through irq1's frame.
261
+ .for (var i = 0; i < 40; i++) { nop }
262
+
263
+ // Should not reach here. Safety exit.
264
+ pla
265
+ tay
266
+ pla
267
+ tax
268
+ pla
269
+ rti
270
+
271
+ // ---- vblank_irq handler ($0C00) ----
272
+ // Fires at line 251. Computes tables, CIA-times coarse redraw, verdict.
273
+ // Re-arms for road_irq1 at line 97 and exits.
274
+ * = $0c00
275
+ vblank_irq:
276
+ cld // clear D flag (RTI restores P, so D is restored); arithmetic must be binary
277
+
278
+ // --- 1. Compute cx[] and xscroll_d16[] ---
279
+ //
280
+ // Forward pass i=0..99 (nearest to farthest).
281
+ // cx[0] = 160.0 (screen centre). dx = 0.
282
+ // Per step: cx += dx; dx += curve[segment].
283
+ // Segment changes every 25 lines; init from scroll_z.
284
+ // Store cx_hi_buf[i] = integer part of cx[i].
285
+ //
286
+ // Backward pass j=0..99:
287
+ // xscroll_d16[j] = D016_BASE | ((cx_hi_buf[99-j] - hw_table[99-j]) & 7)
288
+ // (j=0 = line 100 = farthest = i=99; j=99 = line 199 = nearest = i=0)
289
+
290
+ // Compute initial segment: scroll_z / 25 and scroll_z % 25
291
+ lda ZP_SCR
292
+ tax
293
+ lda #0
294
+ sta ZP_SEG
295
+ div25:
296
+ cpx #25
297
+ bcc div25_done
298
+ txa
299
+ sec
300
+ sbc #25
301
+ tax
302
+ inc ZP_SEG
303
+ jmp div25
304
+ div25_done:
305
+ // X = scroll_z % 25; ZP_SEG = scroll_z / 25
306
+ lda #25
307
+ stx ZP_T1
308
+ sec
309
+ sbc ZP_T1
310
+ sta ZP_REM // remaining = 25 - (scroll_z % 25)
311
+
312
+ // cx = 160.0; dx = 0.0
313
+ lda #160
314
+ sta ZP_CXHI
315
+ lda #0
316
+ sta ZP_CXLO
317
+ sta ZP_DXHI
318
+ sta ZP_DXLO
319
+
320
+ ldy #0 // i
321
+ fwd_lp:
322
+ // Store cx integer part
323
+ lda ZP_CXHI
324
+ sta cx_hi_buf, y
325
+
326
+ // cx += dx (16-bit 8.8)
327
+ clc
328
+ lda ZP_CXLO
329
+ adc ZP_DXLO
330
+ sta ZP_CXLO
331
+ lda ZP_CXHI
332
+ adc ZP_DXHI
333
+ bcc cx_ok // carry set = 8-bit overflow: clamp to 255
334
+ lda #$ff
335
+ cx_ok:
336
+ sta ZP_CXHI
337
+ // Clamp below 16 (road approaching left edge)
338
+ cmp #16
339
+ bcs cx_lo_ok
340
+ lda #16
341
+ sta ZP_CXHI
342
+ cx_lo_ok:
343
+
344
+ // dx += curve[segment] (16-bit signed)
345
+ ldx ZP_SEG
346
+ clc
347
+ lda ZP_DXLO
348
+ adc curve_lo, x
349
+ sta ZP_DXLO
350
+ lda ZP_DXHI
351
+ adc curve_hi, x
352
+ sta ZP_DXHI
353
+
354
+ // Advance segment counter
355
+ dec ZP_REM
356
+ bne fwd_no_seg
357
+ inc ZP_SEG
358
+ lda ZP_SEG
359
+ and #3
360
+ sta ZP_SEG
361
+ lda #25
362
+ sta ZP_REM
363
+ fwd_no_seg:
364
+
365
+ iny
366
+ cpy #NLINES
367
+ bne fwd_lp
368
+
369
+ // Backward pass: j=0..99, X=99..0 (read index), Y=0..99 (write index)
370
+ ldx #99
371
+ ldy #0
372
+ bwd_lp:
373
+ lda cx_hi_buf, x
374
+ sec
375
+ sbc hw_table, x // left_edge pixel (integer part)
376
+ and #$07 // XSCROLL = low 3 bits of left edge
377
+ ora #D016_BASE // add MCM+CSEL bits
378
+ sta xscroll_d16, y
379
+ dex
380
+ iny
381
+ cpy #NLINES
382
+ bne bwd_lp
383
+
384
+ // --- 2. Compute left_col[] and right_col[] for coarse layer ---
385
+ // For r=0..12: i_mid = min(8*r+4, 99)
386
+ // left_col[r] = (cx_hi_buf[i_mid] - hw_table[i_mid]) >> 3
387
+ // right_col[r] = (cx_hi_buf[i_mid] + hw_table[i_mid]) >> 3
388
+ ldx #0
389
+ cc_lp:
390
+ txa
391
+ asl
392
+ asl
393
+ asl // r*8
394
+ clc
395
+ adc #4 // r*8 + 4
396
+ cmp #NLINES
397
+ bcc cc_iok
398
+ lda #99
399
+ cc_iok:
400
+ tay // Y = i_mid
401
+
402
+ lda cx_hi_buf, y
403
+ sec
404
+ sbc hw_table, y
405
+ lsr
406
+ lsr
407
+ lsr // >> 3 = char column
408
+ cmp #40
409
+ bcc cc_lsave
410
+ lda #39
411
+ cc_lsave:
412
+ sta left_col, x
413
+
414
+ lda cx_hi_buf, y
415
+ clc
416
+ adc hw_table, y
417
+ bcs cc_rovf
418
+ lsr
419
+ lsr
420
+ lsr
421
+ cmp #40
422
+ bcc cc_rsave
423
+ cc_rovf:
424
+ lda #39
425
+ cc_rsave:
426
+ sta right_col, x
427
+
428
+ inx
429
+ cpx #NROWS
430
+ bne cc_lp
431
+
432
+ // --- 3. CIA-timed coarse screen redraw ---
433
+ lda #$ff
434
+ sta CIA_TALO
435
+ sta CIA_TAHI
436
+ lda #$11 // bit4=LOAD, bit0=START; phi2 clock, continuous
437
+ sta CIA_CRA
438
+
439
+ ldx #0 // r = 0..12
440
+ rdr_lp:
441
+ lda road_lo, x
442
+ sta ZP_RPLO
443
+ lda road_hi, x
444
+ sta ZP_RPHI
445
+
446
+ // Left kerb
447
+ ldy left_col, x
448
+ lda #CH_KLEFT
449
+ sta (ZP_RPLO), y
450
+
451
+ // Road fill from left_col+1 to right_col-1
452
+ lda left_col, x
453
+ sta ZP_LC
454
+ lda right_col, x
455
+ sta ZP_RC
456
+ ldy ZP_LC
457
+ iny
458
+ lda #CH_ROAD
459
+ rf:
460
+ cpy ZP_RC
461
+ bcs rf_end
462
+ sta (ZP_RPLO), y
463
+ iny
464
+ jmp rf
465
+ rf_end:
466
+
467
+ // Right kerb
468
+ ldy ZP_RC
469
+ lda #CH_KRIGHT
470
+ sta (ZP_RPLO), y
471
+
472
+ // Centre dash: place CH_DASH at centre col if (r + scroll_z/8) & 1 == 0
473
+ lda ZP_LC
474
+ clc
475
+ adc ZP_RC
476
+ ror // A = (LC+RC)/2 (carry=0 since LC+RC<=78)
477
+ tay // Y = centre column
478
+
479
+ lda ZP_SCR
480
+ lsr
481
+ lsr
482
+ lsr // scroll_z / 8
483
+ stx ZP_T2 // save r
484
+ clc
485
+ adc ZP_T2 // + r
486
+ and #1
487
+ bne skip_dash
488
+ lda #CH_DASH
489
+ sta (ZP_RPLO), y
490
+ skip_dash:
491
+ ldx ZP_T2
492
+ inx
493
+ cpx #NROWS
494
+ bne rdr_lp
495
+
496
+ // Stop coarse timer, record cycles
497
+ lda #0
498
+ sta CIA_CRA
499
+ sec
500
+ lda #$ff
501
+ sbc CIA_TALO
502
+ sta COARSE_LO
503
+ lda #$ff
504
+ sbc CIA_TAHI
505
+ sta COARSE_HI
506
+
507
+ // --- 4. Advance scroll_z ---
508
+ inc ZP_SCR
509
+ lda ZP_SCR
510
+ cmp #NLINES
511
+ bcc scr_ok
512
+ lda #0
513
+ sta ZP_SCR
514
+ scr_ok:
515
+
516
+ // --- 5. Verdict ---
517
+ // (a) coarse < 10000 ($2710)
518
+ // (b) kerb col for row 18 (r=0, i_mid=4) == left_col[0]
519
+ lda cx_hi_buf+4
520
+ sec
521
+ sbc hw_table+4
522
+ lsr
523
+ lsr
524
+ lsr
525
+ cmp left_col+0
526
+ bne vfail
527
+ lda COARSE_HI
528
+ cmp #$27
529
+ bcc vpass
530
+ bne vfail
531
+ lda COARSE_LO
532
+ cmp #$11 // < $2711 passes "under 10000"
533
+ bcc vpass
534
+ vfail:
535
+ lda #0
536
+ sta VERDICT
537
+ lda #C_RED
538
+ sta D020
539
+ jmp vdone
540
+ vpass:
541
+ lda #1
542
+ sta VERDICT
543
+ lda #C_GREEN
544
+ sta D020
545
+ vdone:
546
+
547
+ // --- 6. Re-arm for road_irq1 at line 97 ---
548
+ lda #$01
549
+ sta D019 // ack vblank IRQ
550
+ lda #<road_irq1
551
+ sta $0314
552
+ lda #>road_irq1
553
+ sta $0315
554
+ lda #$1b
555
+ sta D011 // RST8=0
556
+ lda #97
557
+ sta D012
558
+
559
+ // Exit via KERNAL register-restore + RTI
560
+ pla
561
+ tay
562
+ pla
563
+ tax
564
+ pla
565
+ rti
566
+
567
+ // ---- Main ($0900) ----
568
+ * = $0900
569
+ main:
570
+ sei
571
+ lda #$7f
572
+ sta CIA_ICR // mask all CIA1 IRQ sources
573
+ lda CIA_ICR // clear pending CIA1 flag
574
+
575
+ // Detect PAL vs NTSC before enabling display
576
+ jsr detect_region // sets REG_FLAG; re-enables interrupts on return
577
+
578
+ sei // re-disable until fully set up
579
+
580
+ lda #$1b
581
+ sta D011 // DEN=1, RSEL=1, YSCROLL=3, bitmap=0, ECM=0
582
+ lda #D016_BASE
583
+ sta D016 // MCM=1, CSEL=1, XSCROLL=0
584
+ lda #$1c
585
+ sta D018 // VM=$0400, charset=$3000
586
+ lda #C_GREEN
587
+ sta D021 // %00 pixels = green (grass)
588
+ lda #C_DGREY
589
+ sta D022 // %01 pixels = dark grey (road)
590
+ lda #C_WHITE
591
+ sta D023 // %10 pixels = white (kerb/stripe)
592
+ lda #C_BLUE
593
+ sta D020 // border = blue initially (turns green on verdict pass)
594
+ lda #0
595
+ sta $d015 // sprites off
596
+
597
+ jsr init_charset
598
+ jsr fill_colram
599
+ jsr clear_screen
600
+
601
+ lda #0
602
+ sta ZP_SCR
603
+
604
+ lda #<vblank_irq
605
+ sta $0314
606
+ lda #>vblank_irq
607
+ sta $0315
608
+ lda #$1b
609
+ sta D011 // RST8=0 for line 251
610
+ lda #251
611
+ sta D012
612
+ lda #1
613
+ sta D01A
614
+ sta D019
615
+ cli
616
+
617
+ idle:
618
+ jmp idle
619
+
620
+ // ---- init_charset: 5 chars * 8 bytes at $3000 ----
621
+ init_charset:
622
+ ldx #0
623
+ ics_lp:
624
+ lda cs_data, x
625
+ sta CHARSET, x
626
+ inx
627
+ cpx #40 // 5 * 8
628
+ bne ics_lp
629
+ rts
630
+
631
+ cs_data:
632
+ .byte $00,$00,$00,$00,$00,$00,$00,$00 // CH_GRASS (0): %00 all = green
633
+ .byte $55,$55,$55,$55,$55,$55,$55,$55 // CH_ROAD (1): %01 all = grey
634
+ .byte $a5,$a5,$a5,$a5,$a5,$a5,$a5,$a5 // CH_KLEFT (2): left %10 white, right %01 grey
635
+ .byte $5a,$5a,$5a,$5a,$5a,$5a,$5a,$5a // CH_KRIGHT (3): left %01 grey, right %10 white
636
+ .byte $69,$69,$69,$69,$69,$69,$69,$69 // CH_DASH (4): %01%10%10%01 = grey-white-white-grey
637
+
638
+ // ---- fill_colram: set bit3 in all colour RAM cells (enables MCM per cell) ----
639
+ fill_colram:
640
+ ldx #0
641
+ lda #8 // %1000: bit3=MCM enable
642
+ fcr_lp:
643
+ sta COLRAM, x
644
+ sta COLRAM+$100, x
645
+ sta COLRAM+$200, x
646
+ sta COLRAM+$300, x
647
+ inx
648
+ bne fcr_lp
649
+ rts
650
+
651
+ // ---- clear_screen: fill with CH_GRASS ----
652
+ clear_screen:
653
+ ldx #0
654
+ lda #CH_GRASS
655
+ cls_lp:
656
+ sta SCREEN, x
657
+ sta SCREEN+$100, x
658
+ sta SCREEN+$200, x
659
+ sta SCREEN+$300, x
660
+ inx
661
+ bne cls_lp
662
+ rts
663
+
664
+ // ============================================================
665
+ // road_irq2_pal: stable entry + PAL unrolled fine loop ($1300)
666
+ // ============================================================
667
+ // Entry: cycle 38 or 39 of line 99 (via KERNAL dispatcher from irq2 vector).
668
+ // Sync: ldx+txs(6) + cld(2) + Delay(10) + lda $D012 + cmp $D012 + BEQ =
669
+ // both zero-jitter and one-jitter converge to cycle 4 of line 100.
670
+ // Immediately into first fine loop iteration; no JMP intervenes.
671
+ // STA $D016 write at cycle 11 of line 100 (at or before deadline of cycle 14).
672
+ // 100 iterations; badline rows use Delay(15) instead of Delay(55).
673
+ // On exit: jmp fine_done.
674
+
675
+ * = $1300
676
+ road_irq2_pal:
677
+ ldx SAVED_SP // discard irq2's own stack frame (saved by irq1)
678
+ txs
679
+ cld // clear decimal flag (RTI will restore P); arithmetic must be binary
680
+ // Sync padding: PAD_PAL=10. With C2=38/39, second D012 read at cycle 63/64.
681
+ // BEQ: taken (3 cycles) or not (2); both paths land at cycle 4 of line 100.
682
+ // STA D016 write lands at cycle 11 of each road line, before the cycle-14 deadline.
683
+ Delay(10)
684
+ lda D012
685
+ cmp D012
686
+ beq pal_fine_start
687
+ pal_fine_start:
688
+ // PAL unrolled fine loop: 100 iterations, each exactly 63 cpu cycles (or elapsed).
689
+ // Iteration j writes xscroll_d16+j to $D016 for road raster line 100+j.
690
+ // Badlines: (100+j) & 7 == 3, i.e., j = 7,15,23,31,39,47,55,63,71,79,87,95.
691
+ // Badline body: LDA(4)+STA(4)+Delay(15)=23 cpu cycles; 40-cycle steal accounts for rest.
692
+ // Normal body: LDA(4)+STA(4)+Delay(55)=63 cpu cycles.
693
+ .for (var j = 0; j < 100; j++) {
694
+ lda xscroll_d16+j
695
+ sta D016
696
+ .if (((100+j) & 7) == 3) {
697
+ Delay(15)
698
+ } else {
699
+ Delay(55)
700
+ }
701
+ }
702
+ pal_fine_end:
703
+ jmp fine_done
704
+
705
+ // ============================================================
706
+ // road_irq2_ntsc: stable entry + NTSC unrolled fine loop
707
+ // ============================================================
708
+ // Same structure as PAL but PAD_NTSC=13 (NTSC line = 65 cycles).
709
+ // Normal body: 65 cpu cycles. Badline body: 25 cpu cycles.
710
+
711
+ road_irq2_ntsc:
712
+ ldx SAVED_SP
713
+ txs
714
+ cld // clear decimal flag (RTI will restore P)
715
+ // Sync padding: PAD_NTSC=12. Second D012 read at cycle 65/66 (NTSC boundary).
716
+ Delay(12)
717
+ lda D012
718
+ cmp D012
719
+ beq ntsc_fine_start
720
+ ntsc_fine_start:
721
+ // NTSC unrolled fine loop: 100 iterations, each exactly 65 cpu cycles (or elapsed).
722
+ .for (var j = 0; j < 100; j++) {
723
+ lda xscroll_d16+j
724
+ sta D016
725
+ .if (((100+j) & 7) == 3) {
726
+ Delay(17)
727
+ } else {
728
+ Delay(57)
729
+ }
730
+ }
731
+ ntsc_fine_end:
732
+ // fall through to fine_done
733
+
734
+ // ============================================================
735
+ // fine_done: epilogue shared by both fine loops
736
+ // ============================================================
737
+ fine_done:
738
+ // Stop CIA fine timer (started in road_irq1)
739
+ lda #0
740
+ sta CIA_CRA
741
+ sec
742
+ lda #$ff
743
+ sbc CIA_TALO
744
+ sta FINE_LO
745
+ lda #$ff
746
+ sbc CIA_TAHI
747
+ sta FINE_HI
748
+
749
+ // Restore $D016 to base (XSCROLL=0)
750
+ lda #D016_BASE
751
+ sta D016
752
+
753
+ // Re-arm for vblank_irq at line 251
754
+ lda #$01
755
+ sta D019 // ack road IRQ
756
+ lda #<vblank_irq
757
+ sta $0314
758
+ lda #>vblank_irq
759
+ sta $0315
760
+ lda #$1b
761
+ sta D011 // RST8=0
762
+ lda #251
763
+ sta D012
764
+
765
+ // Exit through irq1's stack frame (SAVED_SP was irq1's post-KERNAL SP)
766
+ pla
767
+ tay
768
+ pla
769
+ tax
770
+ pla
771
+ rti
772
+ ```
773
+
774
+ ## Build
775
+
776
+ ```bash
777
+ java -jar KickAss.jar pseudo-3d-road.asm -o pseudo-3d-road.prg
778
+ ```
779
+
780
+ ## Expected output
781
+
782
+ A perspective road receding toward a horizon at raster line 100, narrowing from
783
+ full width at the nearest row to a few characters wide at the horizon. The road
784
+ curves left and right as scroll_z cycles through the four-segment table. The
785
+ border is green throughout (verdict = 1: coarse redraw under 10,000 cycles and
786
+ kerb column formula matches). Grass is green ($D021 = 5), road surface is dark
787
+ grey ($D022 = 11), kerbs and the centre dash stripe are white ($D023 = 1).
788
+
789
+ Within each character row, adjacent raster lines show different XSCROLL values
790
+ and the kerb's left edge appears at different sub-character pixel positions. This
791
+ is visible in the screenshot: rasters 156..162 (screenshot rows 140..146 on PAL)
792
+ show the white kerb at x = 138, 143, 142, 139, 137, 136, 110 on consecutive lines
793
+ (measured in VICE x64sc 3.10, PAL pin), confirming per-line delivery of
794
+ distinct XSCROLL values.
795
+
796
+ **PAL (20,000,000 cycles).** Screenshot `screenshots/pseudo-3d-road.png`;
797
+ md5 8ff3e82b581d6b447d383ef798e45154 on two consecutive runs (verified in VICE
798
+ x64sc 3.10, +autostart-delay-random). Frame shows scroll_z approximately 67
799
+ (arithmetic: (20,000,000 / 19,656 frames - autostart overhead) % 100).
800
+
801
+ **NTSC (20,000,000 cycles, `-model ntsc`).** Screenshot
802
+ `screenshots/pseudo-3d-road-ntsc.png`; md5 2ae7a914d311c8dfeda0bd2cb95d5d42
803
+ on two consecutive runs. Frame shows scroll_z approximately 12 (arithmetic).
804
+ On NTSC, raster 107 (j=7, badline, XSCROLL=1 at this frame) shows kerb at x=274
805
+ and raster 108 (j=8, XSCROLL=7) shows kerb at x=273 (1-pixel difference from
806
+ the 6-XSCROLL-unit difference, within the same character cell).
807
+
808
+ **Cycle measurements (VICE x64sc 3.10, monitor dump at scroll_z=4, PAL).**
809
+
810
+ | Quantity | PAL | NTSC |
811
+ |---|---|---|
812
+ | Coarse redraw (CIA-timed) | 6,332 cycles | 6,162 cycles |
813
+ | Fine chain (irq1 CIA start to fine_done stop) | 6,523 cycles | 6,729 cycles |
814
+ | Fine loop alone (arithmetic: 100 x line) | 6,300 cycles | 6,500 cycles |
815
+
816
+ The fine chain overhead above the loop (223 cycles PAL, 229 NTSC) covers road_irq1
817
+ code, the NOP slide, the irq2 KERNAL entry, the sync code, and the CIA stop
818
+ instruction. Verdict = 1 on both models.
819
+
820
+ **xscroll_d16 table entries at scroll_z=4 (monitor dump, PAL).**
821
+
822
+ | j (road line offset) | raster | D016 value | XSCROLL | badline |
823
+ |---|---|---|---|---|
824
+ | 7 | 107 | $19 | 1 | yes |
825
+ | 8 | 108 | $1F | 7 | no |
826
+ | 50 | 150 | $18 | 0 | no |
827
+ | 56 | 156 | $1A | 2 | no |
828
+ | 57 | 157 | $1F | 7 | no |
829
+
830
+ j=7 and j=8 have different XSCROLL values (1 vs 7), confirming the badline
831
+ delay delivers the correct per-line value. j=56 and j=57 differ by 5 units
832
+ and the screenshot at these rasters shows kerb positions differing by 5 pixels,
833
+ matching the table (measured: x=138 and x=143 on both PAL and NTSC pins).
834
+
835
+ **Badline finding.** Twelve badlines occur in the road area (rasters 107, 115,
836
+ 123, 131, 139, 147, 155, 163, 171, 179, 187, 195, with default YSCROLL=3). Each
837
+ badline iteration uses Delay(15) (PAL) or Delay(17) (NTSC) instead of Delay(55)
838
+ or Delay(57): 23 or 25 CPU cycles that the 40-cycle steal extends to one full
839
+ raster line. The STA $D016 write at cycle 11 completes before BA goes low at
840
+ cycle 12, so the write is never blocked by the steal. The previous (broken)
841
+ implementation used a spin-wait on $D012 which introduced up to 9 cycles of
842
+ jitter, placing writes at cycles 20-28 of each line (past the deadline); post-badline
843
+ lines received the badline row's XSCROLL value instead of their own.
844
+
845
+ ## Why this works
846
+
847
+ **Coarse layer.** The Z table encodes road perspective: `hw[i] = max(4,
848
+ round(152 - 1.5 * i))`, arithmetic from the spec formula, gives half-widths
849
+ from 152 (i=0, nearest, raster 199) down to 4 (i=99, farthest, raster 100).
850
+ The centre accumulator cx advances each step by a signed delta dx, and dx
851
+ itself advances by the current segment's curve value (0 or +/-0.20 in 8.8 fixed
852
+ point). One `$D018 = $1C` write points the VIC at the custom charset at $3000.
853
+ Five character patterns cover all road regions: $00 (all %00 = $D021 = green
854
+ grass), $55 (all %01 = $D022 = dark grey road), $A5 (left half white, right
855
+ half grey = left kerb), $5A (mirror), $69 (grey-white-white-grey = centre
856
+ dash). Bit 3 of colour RAM must be set for multicolour mode to apply per cell;
857
+ fill_colram writes 8 to all 1,000 colour RAM locations.
858
+
859
+ **Fine layer: stable entry.** road_irq1 fires at line 97, starts the CIA fine
860
+ timer, arms road_irq2 for line 99, saves the stack pointer to SAVED_SP, clears
861
+ the I flag and falls through a 40-NOP slide. road_irq2 fires from inside the
862
+ slide at cycle 1 of line 99, interrupting a NOP. This is the double-IRQ method
863
+ from `stable-raster-irq.md`: because the interrupted instruction is always 2
864
+ cycles, the jitter at irq2 entry is 0 or 1 cycle rather than 0 to 6. irq2
865
+ discards its own KERNAL stack frame using SAVED_SP, then runs:
866
+
867
+ - ldx SAVED_SP / txs (6 cycles)
868
+ - Delay(PAD) (PAL: 11 cycles; NTSC: 13 cycles)
869
+ - lda $D012 / cmp $D012 / beq (10 or 11 cycles)
870
+
871
+ The two consecutive reads of $D012 straddle the raster 99/100 boundary: in the
872
+ zero-jitter case both land on line 99 and BEQ is taken (3 cycles); in the
873
+ one-jitter case the second read crosses to line 100 and BEQ is not taken (2
874
+ cycles). Both paths end at cycle 4 of line 100. The Delay
875
+ constant is PAD_PAL=11 (second read at cycle 63 or 64 of line 99 for PAL) and
876
+ PAD_NTSC=13 (second read at cycle 65 or 66 for NTSC).
877
+
878
+ PAL and NTSC have different Delay constants because the line length differs (63
879
+ vs 65 cycles). road_irq1 selects `road_irq2_pal` or `road_irq2_ntsc` based on
880
+ the model flag set by detect_region at boot.
881
+
882
+ **Fine layer: unrolled loop.** From cycle 4 of line 100, the first iteration
883
+ begins immediately: LDA xscroll_d16+0 (cycles 3..6), STA $D016 (write at cycle
884
+ 10, before the cycle-14 deadline). The iteration then runs Delay(55) (PAL
885
+ normal) or Delay(15) (PAL badline) to complete exactly 63 real cycles, ending
886
+ at cycle 2 of line 101. The next iteration begins at cycle 3 of line 101. This
887
+ repeats for all 100 road lines.
888
+
889
+ Badline iterations: the CPU stall begins at cycle 15 and lasts 40 cycles (cycles
890
+ 15..54). Delay(15) starts at cycle 11 but is interrupted at cycle 15; the stall
891
+ absorbs 40 real cycles, and the delay resumes at cycle 55 with the remaining
892
+ bit-zero-page and NOP instructions, completing at cycle 2 of the next line.
893
+ Total real cycles: LDA(4) + STA(4) + stall(40) + resumed delay(15) = 63.
894
+
895
+ **Stack management.** irq2 is entered through the KERNAL dispatcher, which
896
+ pushes A, X, Y on top of the CPU's own interrupt frame. road_irq2 discards this
897
+ second frame by restoring irq1's saved stack pointer; the exit sequence
898
+ pla/tay/pla/tax/pla/rti then pops irq1's KERNAL-saved Y, X, A and returns
899
+ through irq1's interrupt frame to the main idle loop. Without this, the stack
900
+ grows by six bytes per road_irq2 call.
901
+
902
+ **IRQ exit via pla/tay/pla/tax/pla/rti.** The KERNAL dispatcher at $FF48
903
+ pushes A, X and Y before calling ($0314). Both vblank_irq and road_irq2 exit
904
+ with this sequence, which pops the KERNAL's saves and RTIs. vblank_irq does
905
+ not push its own saves; the KERNAL's saves are sufficient, and any changes to
906
+ A, X, Y during the handler are overwritten on exit by the KERNAL's originals.
907
+
908
+ ## What it does not establish
909
+
910
+ **Same-column XSCROLL shift.** One XSCROLL value per raster line shifts every
911
+ character column on that line by the same amount. The near side and far side of
912
+ the road both shift together within a character row, so the kerb does not curve
913
+ independently on the two sides. Distinct XSCROLL values per-line make the kerb
914
+ step smoothly between rows (the kerb shifts at each raster boundary) but the
915
+ step between adjacent character rows remains a coarse 8-pixel jump; only the
916
+ sub-character remainder is addressed per-line.
917
+
918
+ **Per-frame grass clearing.** The coarse redraw does not re-fill grass
919
+ characters before drawing road characters. clear_screen fills all grass at
920
+ startup; as the road curves, old kerb and road characters may accumulate at row
921
+ boundaries. A production effect erases only the cells that moved since the
922
+ previous frame.
923
+
924
+ **Sky and dashboard colour regions.** $D021 is set once at startup (green).
925
+ Per-raster-region $D021 changes for a blue sky above the horizon and a black
926
+ dashboard below the road are not implemented.
927
+
928
+ **Cycle budget and correctness.** The loop delivers exactly one write per raster
929
+ line; whether the cx and hw values produce a CORRECT road geometry (one the
930
+ original game engine would compute) is not established here.