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,881 @@
1
+ ---
2
+ recipe: own-keyscan
3
+ toolchain: kickassembler
4
+ output_format: PRG
5
+ region: both
6
+ techniques: [irq_keyboard_own_scan]
7
+ file_formats: [PRG]
8
+ uses_registers: [DC00, DC01, DC02, DC03, DC04, DC05, DC0D, DC0E, D011, D012, D019, D01A, D020, D021]
9
+ uses_kernal: []
10
+ ---
11
+
12
+ <!-- doc-type: recipe -->
13
+
14
+ # KickAssembler — Scan the keyboard matrix from your own raster IRQ, with edges, ages and a timed scan
15
+
16
+ ## Synopsis
17
+
18
+ Masks the CIA1 interrupts so the KERNAL jiffy IRQ and its SCNKEY stop,
19
+ takes `$0314` with a raster IRQ on line 250, and in that IRQ walks one
20
+ low bit across the eight columns of `$DC00`, reading the rows from
21
+ `$DC01` into an eight-byte matrix image. It keeps last frame's image,
22
+ derives the pressed and released sets per column by XOR, ages four
23
+ watched keys (SPACE, Z, C, B: 0 up, 1 pressed this frame, N held N
24
+ frames), counts press events and auto-repeat events, writes `$FF` back
25
+ to `$DC00` and reads it as a joystick 2 poll would, and times the scan
26
+ with CIA1 Timer A around the scan, the read-back, the edge pass and
27
+ the ageing. Before the IRQ starts it runs the same age routine
28
+ over a compiled-in sequence of eight matrix images and counts
29
+ mismatches against an expected table. Verdict: `$02FF` = `$01` and a
30
+ green border when the synthetic sequence matched, no live frame read a
31
+ dirty matrix, `$DC00` read back high on every line but port 2's fire,
32
+ and the net cost is 700 to 1000 ticks; `$02` and red otherwise. The
33
+ technique is `irq_keyboard_own_scan` in `techniques/input.md`.
34
+
35
+ No key is pressed in the pinned run. VICE's `-keybuf` fills the KERNAL
36
+ buffer at `$0277`, which this program never reads, and the headless
37
+ build has no host keyboard. What the pinned run drives is port 2's fire
38
+ line, through VICE's own autofire (`-joydev2 2 -joystick2autofire
39
+ -joystick2autofiremode 1 -joystick2autofirespeed 5`): PA4 goes low five
40
+ times a second with nothing pressed on the host. The scan must not see
41
+ that as a key, and the `$DC00` read-back must. A second run, not
42
+ pinned, moves the autofire to port 1 from the monitor after the program
43
+ has started, which grounds row line PB4 and lets the matrix, the edge
44
+ sets and the age counters be watched on a driven input. Both are
45
+ described under Expected output.
46
+
47
+ ## Source
48
+
49
+ ```asm
50
+ // own-keyscan.asm
51
+ // A raster IRQ that scans the keyboard matrix itself, once a frame, with
52
+ // the KERNAL jiffy IRQ switched off. It keeps this frame's and last frame's
53
+ // eight-byte matrix image, derives the pressed and released sets by XOR,
54
+ // keeps a per-key age counter for four keys (0 = up, 1 = pressed this
55
+ // frame, N = held N frames), counts press events and auto-repeat events,
56
+ // times the eight-column scan with CIA1 Timer A, and checks the age logic
57
+ // against a compiled-in sequence of matrix images before the IRQ starts.
58
+ // Verdict: $02FF = $01 and a green border when the synthetic sequence
59
+ // matched, the scan cost is inside the window and $DC00 reads $FF after
60
+ // the restore; $02 and red otherwise.
61
+ .encoding "screencode_upper"
62
+
63
+ .const SCREEN = $0400
64
+ .const RESULT = $02ff
65
+ .const IRQ_LINE = 250 // below the display: no badline inside the scan
66
+ .const NKEYS = 4
67
+ .const REPEAT_AT = 4 // first repeat event when a key has been held this many frames
68
+ .const REPEAT_MSK = 1 // then every 2 frames: (age - REPEAT_AT) & 1 == 0
69
+ .const NSYN = 8 // frames in the synthetic sequence
70
+ .const NCHK = 5 // bytes checked per synthetic frame
71
+ .const COST_LO = 700 // pass window for the net cost, Timer A ticks, inclusive
72
+ .const COST_HI = 1000 // (an earlier build compared a byte against 281, which the
73
+ // assembler truncates to 25, and every run read red)
74
+
75
+ .const zp_row = $fb // screen pointer for the printers
76
+ .const zp_tmp = $fd
77
+ .const zp_i = $02 // a free zero-page byte; $FE would be zp_tmp's high byte
78
+ .const zp_col = $f9 // the IRQ's column mask; the main loop never touches it
79
+ .const zp_x = $f7 // column counter for the eight-byte printer
80
+
81
+ BasicUpstart2(start)
82
+
83
+ * = $0900 "code"
84
+
85
+ start:
86
+ sei
87
+ lda #$7f
88
+ sta $dc0d // mask every CIA1 interrupt: the jiffy IRQ and its SCNKEY stop here
89
+ lda $dc0d // acknowledge anything pending
90
+ lda #$ff
91
+ sta $dc02 // port A output: column drive (IOINIT's value, set again on purpose)
92
+ lda #$00
93
+ sta $dc03 // port B input: row sense
94
+ lda #$ff
95
+ sta $dc00 // no column selected
96
+ sta prev // last frame's image starts empty
97
+ sta prev+1
98
+ sta prev+2
99
+ sta prev+3
100
+ sta prev+4
101
+ sta prev+5
102
+ sta prev+6
103
+ sta prev+7
104
+ lda #$00
105
+ sta $d020
106
+ sta $d021
107
+ jsr clear_screen
108
+ jsr draw_labels
109
+
110
+ // --- part A: the age logic on a compiled-in sequence of matrix images ---
111
+ lda #0
112
+ sta syn_bad
113
+ sta zp_i
114
+ synloop:
115
+ lda zp_i
116
+ asl
117
+ asl
118
+ asl // frame * 8
119
+ tax
120
+ ldy #0
121
+ copysyn:
122
+ lda syn_frames,x
123
+ sta cur,y
124
+ inx
125
+ iny
126
+ cpy #8
127
+ bne copysyn
128
+ jsr update_keys // the same routine the IRQ runs
129
+ lda zp_i
130
+ asl
131
+ asl
132
+ adc zp_i // frame * 5
133
+ tax
134
+ lda ages
135
+ cmp syn_expect,x
136
+ bne synfail
137
+ lda ages+2
138
+ cmp syn_expect+1,x
139
+ bne synfail
140
+ lda repeats
141
+ cmp syn_expect+2,x
142
+ bne synfail
143
+ lda pressed+7
144
+ cmp syn_expect+3,x
145
+ bne synfail
146
+ lda released+7
147
+ cmp syn_expect+4,x
148
+ beq synok
149
+ synfail:
150
+ inc syn_bad
151
+ synok:
152
+ inc zp_i
153
+ lda zp_i
154
+ cmp #NSYN
155
+ bne synloop
156
+
157
+ // reset every counter the synthetic pass touched, so the live run starts clean
158
+ ldx #0
159
+ txa
160
+ clrstate:
161
+ sta ages,x
162
+ sta presses,x
163
+ sta repeats,x
164
+ inx
165
+ cpx #NKEYS
166
+ bne clrstate
167
+ lda #$ff
168
+ ldx #0
169
+ clrimg:
170
+ sta prev,x
171
+ sta cur,x
172
+ inx
173
+ cpx #8
174
+ bne clrimg
175
+ lda #0
176
+ sta pressed+7
177
+ sta released+7
178
+
179
+ // --- part B: install the raster IRQ ---------------------------------------
180
+ lda #<irq
181
+ sta $0314
182
+ lda #>irq
183
+ sta $0315
184
+ lda #IRQ_LINE
185
+ sta $d012
186
+ lda $d011
187
+ and #$7f
188
+ sta $d011
189
+ lda #$01
190
+ sta $d01a
191
+ sta $d019
192
+ lda #0
193
+ sta frames
194
+ cli
195
+
196
+ // --- main loop: show what the IRQ measured --------------------------------
197
+ main:
198
+ lda frames
199
+ cmp #100
200
+ bcc main // let the scan settle for 100 frames before judging
201
+
202
+ // matrix image, row 2
203
+ ldy #2
204
+ ldx #8
205
+ lda #<cur
206
+ sta zp_tmp
207
+ lda #>cur
208
+ sta zp_tmp+1
209
+ jsr print_bytes8
210
+ // pressed set, row 3; released set, row 4
211
+ ldy #3
212
+ ldx #8
213
+ lda #<pressed
214
+ sta zp_tmp
215
+ lda #>pressed
216
+ sta zp_tmp+1
217
+ jsr print_bytes8
218
+ ldy #4
219
+ ldx #8
220
+ lda #<released
221
+ sta zp_tmp
222
+ lda #>released
223
+ sta zp_tmp+1
224
+ jsr print_bytes8
225
+
226
+ // per-key lines: age, presses, repeats
227
+ ldx #0
228
+ keyline:
229
+ txa
230
+ pha
231
+ stx zp_i
232
+ txa
233
+ clc
234
+ adc #7
235
+ tay // rows 7..10
236
+ lda ages,x
237
+ ldx #8
238
+ jsr print_hex
239
+ ldx zp_i
240
+ lda presses,x
241
+ ldy zp_i
242
+ iny
243
+ iny
244
+ iny
245
+ iny
246
+ iny
247
+ iny
248
+ iny
249
+ ldx #13
250
+ jsr print_hex
251
+ ldx zp_i
252
+ lda repeats,x
253
+ ldy zp_i
254
+ iny
255
+ iny
256
+ iny
257
+ iny
258
+ iny
259
+ iny
260
+ iny
261
+ ldx #18
262
+ jsr print_hex
263
+ pla
264
+ tax
265
+ inx
266
+ cpx #NKEYS
267
+ bne keyline
268
+
269
+ // scan cost, frames, $DC00 read-back, synthetic mismatches
270
+ lda net+1
271
+ ldy #12
272
+ ldx #8
273
+ jsr print_hex
274
+ lda net
275
+ ldy #12
276
+ ldx #10
277
+ jsr print_hex
278
+ lda cost+1
279
+ ldy #12
280
+ ldx #14
281
+ jsr print_hex
282
+ lda cost
283
+ ldy #12
284
+ ldx #16
285
+ jsr print_hex
286
+ lda cost0+1
287
+ ldy #12
288
+ ldx #20
289
+ jsr print_hex
290
+ lda cost0
291
+ ldy #12
292
+ ldx #22
293
+ jsr print_hex
294
+ lda frames
295
+ ldy #13
296
+ ldx #8
297
+ jsr print_hex
298
+ lda dc00_back
299
+ ldy #14
300
+ ldx #8
301
+ jsr print_hex
302
+ lda syn_bad
303
+ ldy #15
304
+ ldx #8
305
+ jsr print_hex
306
+ lda fire_seen
307
+ ldy #16
308
+ ldx #8
309
+ jsr print_hex
310
+ lda dirty
311
+ ldy #17
312
+ ldx #8
313
+ jsr print_hex
314
+
315
+ // verdict
316
+ lda syn_bad
317
+ bne fail
318
+ lda dirty
319
+ bne fail
320
+ lda dc00_back
321
+ ora #$10 // port 2's fire line may be low; every other bit must read high
322
+ cmp #$ff
323
+ bne fail
324
+ lda net+1
325
+ cmp #>COST_LO
326
+ bcc fail
327
+ bne nothi_lo
328
+ lda net
329
+ cmp #<COST_LO
330
+ bcc fail
331
+ nothi_lo:
332
+ lda net+1
333
+ cmp #>COST_HI
334
+ bcc costok
335
+ bne fail
336
+ lda net
337
+ cmp #<COST_HI+1
338
+ bcs fail
339
+ costok:
340
+ lda #$01
341
+ sta RESULT
342
+ lda #$05
343
+ sta $d020
344
+ jmp main
345
+ fail:
346
+ lda #$02
347
+ sta RESULT
348
+ lda #$02
349
+ sta $d020
350
+ jmp main
351
+
352
+ // --- the IRQ: scan, derive, age, time ------------------------------------
353
+ irq:
354
+ cld // D is not cleared on entry; arithmetic below
355
+ lda #$01
356
+ sta $d019 // acknowledge the raster interrupt
357
+ inc frames
358
+
359
+ lda #$00
360
+ sta $dc0e // stop Timer A while the latch is loaded (it is CIA1's, the jiffy clock: masked above)
361
+ lda #$ff
362
+ sta $dc04
363
+ sta $dc05 // latch = $FFFF
364
+ lda #$11
365
+ sta $dc0e // start, force load, continuous; ticks at the CPU clock
366
+ timed_start:
367
+
368
+ ldx #0
369
+ lda #$fe
370
+ sta zp_col
371
+ scan:
372
+ lda zp_col
373
+ sta $dc00 // one column low, seven high
374
+ lda $dc01 // bit r clear = key (column x, row r) down
375
+ sta cur,x
376
+ sec
377
+ rol zp_col // walk the zero bit up: $FE, $FD, ... $7F
378
+ inx
379
+ cpx #8
380
+ bne scan
381
+ lda #$ff
382
+ sta $dc00 // restore: no column selected, so a joystick 2 read is clean
383
+
384
+ lda $dc00
385
+ sta dc00_back // what a joystick 2 poll would see now
386
+ jsr update_keys // edges for eight columns, ages for four keys
387
+
388
+ scan_end:
389
+ lda #$00
390
+ sta $dc0e // stop, then read: cost = $FFFF - Timer A
391
+ sec
392
+ lda #$ff
393
+ sbc $dc04
394
+ sta cost
395
+ lda #$ff
396
+ sbc $dc05
397
+ sta cost+1
398
+
399
+ lda dc00_back
400
+ and #$10
401
+ bne nofire
402
+ inc fire_seen // frames in which port 2's fire line was low at this read
403
+ nofire:
404
+ ldx #0
405
+ lda #$ff
406
+ chkclean:
407
+ and cur,x
408
+ inx
409
+ cpx #8
410
+ bne chkclean
411
+ cmp #$ff
412
+ beq clean
413
+ inc dirty // frames in which any matrix byte was not $FF
414
+ clean:
415
+
416
+ lda #$ff
417
+ sta $dc04
418
+ sta $dc05
419
+ lda #$11
420
+ sta $dc0e // the same bracket around nothing: the start and stop stores' own share
421
+ lda #$00
422
+ sta $dc0e
423
+ sec
424
+ lda #$ff
425
+ sbc $dc04
426
+ sta cost0
427
+ lda #$ff
428
+ sbc $dc05
429
+ sta cost0+1
430
+
431
+ sec
432
+ lda cost
433
+ sbc cost0
434
+ sta net
435
+ lda cost+1
436
+ sbc cost0+1
437
+ sta net+1 // net = scan, read-back, edges and ages
438
+
439
+ jmp $ea81 // KERNAL's bare exit: pull Y, X, A and RTI; no SCNKEY, no cursor
440
+
441
+ // update_keys: from cur and prev derive pressed (1 -> 0 edges) and released
442
+ // (0 -> 1 edges) per column, age the four watched keys, then prev = cur.
443
+ update_keys:
444
+ ldx #0
445
+ edges:
446
+ lda prev,x
447
+ eor cur,x // bits that changed
448
+ sta zp_col
449
+ and prev,x // changed and was 1 (up): now down
450
+ sta pressed,x
451
+ lda zp_col
452
+ and cur,x // changed and is 1 (up): was down
453
+ sta released,x
454
+ lda cur,x
455
+ sta prev,x
456
+ inx
457
+ cpx #8
458
+ bne edges
459
+
460
+ ldx #0
461
+ agekeys:
462
+ ldy key_col,x
463
+ lda cur,y
464
+ and key_bit,x
465
+ bne keyup
466
+ lda ages,x
467
+ cmp #$ff
468
+ beq agesat // hold at 255
469
+ inc ages,x
470
+ agesat:
471
+ lda ages,x
472
+ cmp #1
473
+ bne notnew
474
+ inc presses,x // age 1 = pressed this frame
475
+ notnew:
476
+ lda ages,x
477
+ cmp #REPEAT_AT
478
+ bcc nextkey
479
+ sec
480
+ sbc #REPEAT_AT
481
+ and #REPEAT_MSK
482
+ bne nextkey
483
+ inc repeats,x // held REPEAT_AT frames, then every second frame
484
+ jmp nextkey
485
+ keyup:
486
+ lda #0
487
+ sta ages,x
488
+ nextkey:
489
+ inx
490
+ cpx #NKEYS
491
+ bne agekeys
492
+ rts
493
+
494
+ // --- printers ----------------------------------------------------------
495
+ // print_bytes8: eight hex bytes from (zp_tmp) at row Y, column X
496
+ print_bytes8:
497
+ sty zp_i
498
+ stx zp_x
499
+ ldy #0
500
+ pb8:
501
+ tya
502
+ pha
503
+ lda (zp_tmp),y
504
+ ldy zp_i
505
+ ldx zp_x
506
+ jsr print_hex
507
+ inc zp_x
508
+ inc zp_x
509
+ inc zp_x
510
+ pla
511
+ tay
512
+ iny
513
+ cpy #8
514
+ bne pb8
515
+ rts
516
+
517
+ // print_hex: A as two hex digits at row Y, column X (clobbers A, X, Y)
518
+ print_hex:
519
+ pha
520
+ jsr set_row
521
+ txa
522
+ tay // Y = column
523
+ pla
524
+ pha
525
+ lsr
526
+ lsr
527
+ lsr
528
+ lsr
529
+ tax
530
+ lda hexdigits,x
531
+ sta (zp_row),y
532
+ pla
533
+ and #$0f
534
+ tax
535
+ lda hexdigits,x
536
+ iny
537
+ sta (zp_row),y
538
+ rts
539
+
540
+ set_row:
541
+ lda row_lo,y
542
+ sta zp_row
543
+ lda row_hi,y
544
+ sta zp_row+1
545
+ rts
546
+
547
+ clear_screen:
548
+ ldx #0
549
+ lda #$20
550
+ clr:
551
+ sta SCREEN,x
552
+ sta SCREEN+$100,x
553
+ sta SCREEN+$200,x
554
+ sta SCREEN+$300,x
555
+ inx
556
+ bne clr
557
+ ldx #0
558
+ lda #$01
559
+ col:
560
+ sta $d800,x
561
+ sta $d900,x
562
+ sta $da00,x
563
+ sta $db00,x
564
+ inx
565
+ bne col
566
+ rts
567
+
568
+ draw_labels:
569
+ ldx #0 // index into the label text
570
+ stx zp_i // label number
571
+ lbl:
572
+ ldy zp_i
573
+ lda label_row,y
574
+ cmp #$ff
575
+ beq lbldone
576
+ tay
577
+ jsr set_row
578
+ ldy #0
579
+ lblchr:
580
+ lda labels,x
581
+ beq lblend
582
+ sta (zp_row),y
583
+ iny
584
+ inx
585
+ bne lblchr
586
+ lblend:
587
+ inx
588
+ inc zp_i
589
+ jmp lbl
590
+ lbldone:
591
+ rts
592
+
593
+ // --- data -----------------------------------------------------------------
594
+ hexdigits:
595
+ .text "0123456789ABCDEF"
596
+
597
+ row_lo:
598
+ .fill 25, <(SCREEN + i * 40)
599
+ row_hi:
600
+ .fill 25, >(SCREEN + i * 40)
601
+
602
+ // the four watched keys: column, row bit
603
+ key_col:
604
+ .byte 7, 1, 2, 3 // SPACE, Z, C, B: all row 4, so port 1's fire line holds all four
605
+ key_bit:
606
+ .byte $10, $10, $10, $10
607
+
608
+ // synthetic matrix images, eight bytes a frame, $FF = nothing in that column
609
+ syn_frames:
610
+ .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ef // 1: SPACE down
611
+ .byte $ff,$ff,$ef,$ff,$ff,$ff,$ff,$ef // 2: SPACE and C down
612
+ .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ef // 3: C up
613
+ .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ef // 4: SPACE held 4 frames: first repeat
614
+ .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ef // 5: held 5
615
+ .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ef // 6: held 6: second repeat
616
+ .byte $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff // 7: all up
617
+ .byte $ff,$ef,$ff,$ef,$ff,$ff,$ff,$ff // 8: Z and B down
618
+ // expected after each frame: ages[0] (SPACE), ages[2] (C), repeats[0], pressed[7], released[7]
619
+ syn_expect:
620
+ .byte 1, 0, 0, $10, $00
621
+ .byte 2, 1, 0, $00, $00
622
+ .byte 3, 0, 0, $00, $00
623
+ .byte 4, 0, 1, $00, $00
624
+ .byte 5, 0, 1, $00, $00
625
+ .byte 6, 0, 2, $00, $00
626
+ .byte 0, 0, 2, $00, $10
627
+ .byte 0, 0, 2, $00, $00
628
+
629
+ label_row:
630
+ .byte 0, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, $ff
631
+ labels:
632
+ .text "OWN KEYSCAN IN THE RASTER IRQ"
633
+ .byte 0
634
+ .text "MATRIX"
635
+ .byte 0
636
+ .text "PRESS"
637
+ .byte 0
638
+ .text "RELS"
639
+ .byte 0
640
+ .text "KEY AGE PRS RPT"
641
+ .byte 0
642
+ .text "SPACE"
643
+ .byte 0
644
+ .text "Z"
645
+ .byte 0
646
+ .text "C"
647
+ .byte 0
648
+ .text "B"
649
+ .byte 0
650
+ .text " NET RAW BASE"
651
+ .byte 0
652
+ .text "COST"
653
+ .byte 0
654
+ .text "FRAMES"
655
+ .byte 0
656
+ .text "DC00"
657
+ .byte 0
658
+ .text "SYNBAD"
659
+ .byte 0
660
+ .text "FIRE"
661
+ .byte 0
662
+ .text "DIRTY"
663
+ .byte 0
664
+
665
+ cur: .fill 8, $ff
666
+ prev: .fill 8, $ff
667
+ pressed: .fill 8, 0
668
+ released: .fill 8, 0
669
+ ages: .fill NKEYS, 0
670
+ presses: .fill NKEYS, 0
671
+ repeats: .fill NKEYS, 0
672
+ cost: .word 0
673
+ cost0: .word 0
674
+ net: .word 0
675
+ frames: .byte 0
676
+ fire_seen: .byte 0
677
+ dirty: .byte 0
678
+ dc00_back: .byte 0
679
+ syn_bad: .byte 0
680
+ ```
681
+
682
+ ## Build
683
+
684
+ ```bash
685
+ java -jar $KICKASS_JAR own-keyscan.asm -o own-keyscan.prg
686
+ ```
687
+
688
+ Run headless, pinned (exit status 1 on the cycle limit is normal):
689
+
690
+ ```bash
691
+ x64sc -default -warp +sound +autostart-delay-random -autostartprgmode 1 \
692
+ -limitcycles 6000000 \
693
+ -joydev2 2 -joystick2autofire -joystick2autofiremode 1 -joystick2autofirespeed 5 \
694
+ -exitscreenshot own-keyscan.png -autostart own-keyscan.prg
695
+ ```
696
+
697
+ Add `-model ntsc` for the NTSC picture.
698
+
699
+ ## Expected output
700
+
701
+ Black screen, white text, green border. Measured in VICE x64sc 3.10
702
+ with the char-ROM decoder over the exit screenshot; two runs per model
703
+ gave byte-identical PNGs (`screenshots/own-keyscan.png`,
704
+ `screenshots/own-keyscan-ntsc.png`).
705
+
706
+ ```text
707
+ OWN KEYSCAN IN THE RASTER IRQ
708
+
709
+ MATRIX FF FF FF FF FF FF FF FF
710
+ PRESS 00 00 00 00 00 00 00 00
711
+ RELS 00 00 00 00 00 00 00 00
712
+
713
+ KEY AGE PRS RPT
714
+ SPACE 00 00 00
715
+ Z 00 00 00
716
+ C 00 00 00
717
+ B 00 00 00
718
+ NET RAW BASE
719
+ COST 030D 0312 0005
720
+ FRAMES 98
721
+ DC00 EF
722
+ SYNBAD 00
723
+ FIRE 4D
724
+ DIRTY 00
725
+ ```
726
+
727
+ Line by line:
728
+
729
+ - `MATRIX` is this frame's image, column 0 to 7. `$FF` in every column
730
+ is the empty matrix: no switch closed, and the port 2 fire line held
731
+ low on PA4 (a column line) does not show, because a grounded column
732
+ with no key pressed pulls no row down.
733
+ - `PRESS` and `RELS` are the edge sets for the same eight columns, bit
734
+ r set where key (column, row r) went down or came up this frame.
735
+ - `AGE`, `PRS`, `RPT`: the age counter, the count of press events (age
736
+ reached 1) and the count of repeat events (age reached 4, then every
737
+ second frame) for the four watched keys. All zero: nothing pressed.
738
+ - `COST`: `NET` is the handler's work with the matrix empty, 781
739
+ cycles (`$030D`): the eight-column scan, the `$FF` restore and
740
+ read-back, the edge pass over eight columns and the ageing of four
741
+ keys. `RAW` is the timed bracket, 786, and `BASE` is the same bracket
742
+ around nothing, 5. Timer A is CIA1's and ticks at the CPU clock; the
743
+ same figure on PAL and NTSC. With all four watched keys held the net
744
+ is 945 (`$03B1`, the port 1 run below): a held key takes the longer
745
+ ageing path, 41 cycles more each.
746
+ - `FRAMES`: IRQs since the handler was installed, `$98` = 152 on PAL
747
+ and `$A9` = 169 on NTSC at 6,000,000 cycles.
748
+ - `DC00`: the read-back after the `$FF` restore, at the instant of the
749
+ last IRQ. `$EF` is bit 4 low: port 2's fire, asserted by the autofire
750
+ at that moment. It alternates with `$FF` from frame to frame; the
751
+ exit lands on `$EF` at this cycle count on both models.
752
+ - `SYNBAD`: mismatches between the synthetic sequence's results and
753
+ the expected table, 0 of 40 bytes.
754
+ - `FIRE`: frames in which the read-back had bit 4 low, `$4D` = 77 of
755
+ 152 on PAL, `$55` = 85 of 169 on NTSC. Five presses a second, half
756
+ the frames down.
757
+ - `DIRTY`: frames in which any matrix byte was not `$FF`, 0. The port 2
758
+ line never leaked into the matrix image.
759
+
760
+ ### What was pressed, and what was not
761
+
762
+ Pressed: nothing on the keyboard. The pinned run asserts port 2's fire
763
+ line through VICE's autofire, with `-joydev2 2` (keyset 1) as the
764
+ device so the port has a joystick attached; the keyset itself is never
765
+ touched. No row line is ever driven in the pinned run, so the matrix,
766
+ edge and age columns show the empty case only, and the age logic's
767
+ evidence is the synthetic sequence.
768
+
769
+ Port 1 autofire from the command line is not usable: its fire line is
770
+ row 4, the KERNAL scanner reads it as R-SHIFT then SPACE and types
771
+ shift-spaces during boot, and VICE's autostart never sees the READY it
772
+ waits for (tried at 1 and 5 presses a second, with keyset 1 and with no
773
+ device; the boot screen was still up at the cycle limit every time).
774
+ The way round is to switch it on after the program has masked CIA1, from
775
+ a monitor breakpoint at `$0900`:
776
+
777
+ ```text
778
+ break 0900
779
+ command 1 "resourceset \"JoyDevice1\" \"2\" ; resourceset \"JoyStick1AutoFire\" \"1\" ; resourceset \"JoyStick1AutoFireMode\" \"1\" ; resourceset \"JoyStick1AutoFireSpeed\" \"5\" ; delete 1 ; z"
780
+ ```
781
+
782
+ (`;` separates monitor commands; `|` is refused with "Unexpected
783
+ token".) Run with `-moncommands that-file` and the pinned flags removed.
784
+ Measured in VICE x64sc 3.10, PAL, 6,000,000 cycles:
785
+
786
+ ```text
787
+ MATRIX EF EF EF EF EF EF EF EF
788
+ PRESS 00 00 00 00 00 00 00 00
789
+ RELS 00 00 00 00 00 00 00 00
790
+ SPACE 04 10 0F
791
+ Z 04 10 0F
792
+ C 04 10 0F
793
+ B 04 10 0F
794
+ COST 03B1 03B6 0005
795
+ DC00 FF
796
+ DIRTY 4D
797
+ ```
798
+
799
+ Row 4 reads low in all eight columns while PB4 is grounded, which is the
800
+ "a port 1 direction is a row of keys" effect from `keyboard_matrix_scan`
801
+ seen from the other side: F1, Z, C, B, M, `.`, R-SHIFT and SPACE all
802
+ appear held. The four watched keys are all on row 4, so all four show
803
+ 16 press events and 15 repeat events over 152 frames with age 4 at
804
+ exit, and the net cost rises to 945. Five presses a second is one press per ten frames,
805
+ five frames held: one press event and one repeat event (at age 4) per
806
+ cycle, and 152 / 10 rounds to the 16 and 15 seen. `DIRTY` is 77 of
807
+ 152, the held half. The verdict is red in that run, by design: a dirty
808
+ matrix fails it, and the run exists to show a dirty matrix. The exit
809
+ screenshot of that run is not committed; the figures above are from
810
+ it.
811
+
812
+ ## Why this works
813
+
814
+ **Killing the KERNAL scan.** `$DC0D` = `$7F` clears every CIA1
815
+ interrupt mask, so Timer A's underflow no longer reaches the CPU and
816
+ the jiffy IRQ, with SCNKEY inside it, stops. Nothing else is needed:
817
+ SCNKEY is only ever called from that handler. The raster IRQ goes
818
+ through the KERNAL's `$FF48` entry and `$0314`, so registers are pushed
819
+ for us and the handler leaves through `$EA81`, the six bytes `PLA TAY
820
+ PLA TAX PLA RTI` (read from the ROM image). `$EA7E` is `LDA $DC0D` then
821
+ those six bytes, a bare exit that also acknowledges CIA1, and `$EA7B`
822
+ is `JSR $EA87`, the SCNKEY call itself, followed by the two: jumping to
823
+ `$EA7B` runs the KERNAL scan and skips only the cursor blink and tape
824
+ motor code above it. A program that keeps the KERNAL IRQ and adds its
825
+ own scan therefore leaves through `$EA7E` or `$EA81`, never `$EA7B`.
826
+
827
+ **The scan.** With `$DC02` = `$FF` and `$DC03` = `$00`, the eight
828
+ stores of a walking zero to `$DC00` each drive one column low, and the
829
+ read of `$DC01` that follows sees a 0 in row r only for a closed
830
+ switch in that column. `SEC` then `ROL` moves the zero up a bit a time
831
+ and shifts a 1 in at the bottom: `$FE`, `$FD`, `$FB` … `$7F`. The
832
+ final `$FF` store deselects every column, so a joystick 2 read of
833
+ `$DC00` afterwards sees only the port's own switches; the KERNAL leaves
834
+ `$7F` instead, which is why `hardware/c64-memory-map.md`'s STOP-key
835
+ test works and why a port 2 poll after SCNKEY can see column 7's keys.
836
+
837
+ **Edges by XOR.** `prev EOR cur` is the set of bits that changed;
838
+ `AND prev` keeps those that were 1 (up) and so are now down, the
839
+ pressed set; `AND cur` keeps those now 1, the released set. Eight
840
+ bytes, three operations each, no branches.
841
+
842
+ **Ages.** A key's age is 0 while up, and counts up from 1 each frame it
843
+ is down, saturating at 255. Age 1 is the press event, so no separate
844
+ edge test is needed for the watched keys; the repeat rule (age is
845
+ REPEAT_AT, or past it by an even count) gives a delayed auto-repeat
846
+ from the same byte. A contact bounce that opens the switch for one
847
+ scan resets the age and fires a second press event next frame, which
848
+ `keyboard_matrix_scan` explains is the accepted cost of a once-a-frame
849
+ scan.
850
+
851
+ **The timer.** Timer A is stopped, its latch set to `$FFFF`, then
852
+ started with force load in continuous mode; after the ageing it is
853
+ stopped again and read. `$FFFF` minus the count is the elapsed ticks.
854
+ The same bracket around nothing reads 5, the stores' own share, and
855
+ the difference is the handler's work: 781 empty, 945 with four keys
856
+ held. Of the 781, the scan itself is 252, measured by an earlier build
857
+ of this listing that stopped the timer straight after the `$FF`
858
+ restore, and that agrees with the instruction arithmetic (7 to set up,
859
+ eight passes of 30 with the last branch not taken, 6 to restore). An
860
+ earlier build restarted a still-running
861
+ one-shot timer with a force load and no stop, and read 509 where the
862
+ monitor's cycle counter said 252 between the start store and the read;
863
+ the monitor's own peek of `$DC04/$DC05` at that point said `$FF05`,
864
+ 250 elapsed, disagreeing with what the CPU's read returned. Stopping
865
+ the timer before loading the latch, as `mouse-1351-read.md` does,
866
+ removed the discrepancy; why the running restart misreads in VICE was
867
+ not established here.
868
+
869
+ **The verdict window.** 700 to 1000 covers the empty matrix and all
870
+ four keys held with margin on both sides; a build before it compared a
871
+ single byte against 281, which the assembler truncates to 25, and read
872
+ red on every run with a correct 252.
873
+
874
+ **Why the synthetic sequence.** The age routine is the same code on
875
+ both paths: part A copies each table image into `cur` and calls
876
+ `update_keys`, exactly as the IRQ does with a live image. The sequence
877
+ covers a press, a second key in another column joining and leaving,
878
+ the first repeat at age 4 and the second at 6, a release, and two
879
+ keys down at once. The
880
+ expected table checks two ages, the repeat count and column 7's two
881
+ edge sets after every frame, forty bytes in all.