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,1281 @@
1
+ # CIA Reference (MOS 6526 — CIA1 and CIA2)
2
+
3
+ ## Overview
4
+
5
+ The Commodore 64 contains two MOS Technology 6526 Complex Interface Adapter
6
+ (CIA) chips. They are physically and electrically identical — the same mask,
7
+ the same datasheet, the same 16-register interface. What differs is *where*
8
+ each chip is wired into the C64 motherboard, *what* its pins connect to, and
9
+ *which* CPU interrupt line its IRQ output drives.
10
+
11
+ - **CIA1** lives at `$DC00-$DC0F` (with the rest of page `$DC00-$DCFF` being
12
+ 16-byte mirrors of the same registers). CIA1 is the user-input chip:
13
+ keyboard matrix, control-port 1 and 2 (joysticks, paddles, light pen),
14
+ and the paddle-fire button lines. Its `/IRQ` output pin drives the 6510
15
+ `/IRQ` line. CIA1 also generates the KERNAL jiffy interrupt — about
16
+ 60 Hz on BOTH PAL and NTSC machines, not once per frame — that drives
17
+ the KERNAL `IRQ` handler and the TI/TI$ jiffy clock. (An earlier
18
+ version of this page said 50 Hz on PAL; the ROM and a VICE x64sc
19
+ measurement say otherwise — see `$DC04`.)
20
+ - **CIA2** lives at `$DD00-$DD0F` (with `$DD00-$DDFF` again being 16-byte
21
+ mirrors). CIA2 is the system-interface chip: it picks the 16 KiB VIC-II
22
+ bank (bits 0-1 of port A), drives the serial-IEC bus (disk drive,
23
+ printer) on port A bits 3-7, drives the RS-232 user-port lines, and
24
+ exposes the user-port PB pins. Its `/IRQ` output pin drives the 6510
25
+ `/NMI` line, which the keyboard's `RESTORE` key also pulls low through
26
+ its own one-shot (one half of the 556 dual timer at U20 on the 1982-86
27
+ boards; this page used to give the pulse as "100 ms", a figure that is
28
+ not measured here).
29
+
30
+ The naming is unfortunate: from the 6526's point of view both chips
31
+ generate IRQs — the chip has no idea one of its IRQ outputs is wired to
32
+ the CPU's NMI line. Code that programs CIA2's interrupt-control register
33
+ (`$DD0D`) must remember it is enabling NMIs, not IRQs.
34
+
35
+ Both chips share the same internal layout:
36
+
37
+ - Two 8-bit parallel I/O ports (port A on pins PA0-PA7, port B on pins
38
+ PB0-PB7), each with an independent data-direction register (DDR).
39
+ - Two 16-bit down-counting timers, Timer A and Timer B. Each timer can
40
+ count system phi-2 clocks, rising (positive) edges on the CNT pin,
41
+ Timer A underflows (Timer B only), or Timer A underflows while CNT is
42
+ high (Timer B only). An earlier revision of this bullet said falling
43
+ edges; the CRA/CRB tables and the Count-modes section below were
44
+ already right. The polarity is the 6526 datasheet's, not measured
45
+ here: CNT is a user-port pin, and VICE does not count edges the CIA
46
+ itself puts out in SP-output mode.
47
+ - A 24-bit BCD time-of-day (TOD) clock with hours/minutes/seconds/tenths,
48
+ plus an alarm register that fires on match.
49
+ - An 8-bit synchronous serial shift register (SDR/SP), clocked by CNT.
50
+ The C64 KERNAL uses it on neither chip — its RS-232 driver is
51
+ bit-banged (see `$DD0C`).
52
+ - A single interrupt-control register that masks five interrupt sources
53
+ (Timer A underflow, Timer B underflow, TOD alarm match, serial register
54
+ full/empty, FLAG pin transition) and aggregates them into the chip's
55
+ single `/IRQ` output pin.
56
+
57
+ This document covers both chips in one file because they are the same chip
58
+ with different jobs. Every register section is tagged with
59
+ `**Chip:** CIA1` or `**Chip:** CIA2` so the entity extractor in
60
+ `src/graph/extract.ts` can disambiguate registers that share a name (e.g.
61
+ both chips have a "Data Port A" but at different addresses, with different
62
+ external wiring).
63
+
64
+ ### IRQ vs NMI — the critical distinction
65
+
66
+ The 6510 has two interrupt pins, `/IRQ` (maskable) and `/NMI`
67
+ (non-maskable). The 6526 has no idea which of the two it is wired to.
68
+
69
+ | CIA | Address | CPU pin driven | Vector RAM addr | Typical user |
70
+ |------|---------------|----------------|-----------------|-----------------------------------------|
71
+ | CIA1 | `$DC00-$DC0F` | `/IRQ` | `$0314-$0315` | KERNAL 60 Hz jiffy IRQ, keyboard scan |
72
+ | CIA2 | `$DD00-$DD0F` | `/NMI` | `$0318-$0319` | RESTORE key, RS-232 timing |
73
+
74
+ `/IRQ` is maskable with the 6502 `I` flag (`SEI`/`CLI`). `/NMI` is
75
+ **not** maskable — when CIA2's `/IRQ` output goes low, the CPU will
76
+ service an NMI as soon as it finishes the current instruction, regardless
77
+ of `I`. The only way to "mask" an NMI from CIA2 is to disable the
78
+ interrupt-source bits in `$DD0D`.
79
+
80
+ The `RESTORE` key is wired to the CPU's `/NMI` pin *in parallel* with
81
+ CIA2's `/IRQ` output, through a one-shot — one half of the 556 dual
82
+ timer at U20 on the 1982-86 boards (this page used to say "a 555"). This
83
+ means pressing `RESTORE` will fire `/NMI` even with all CIA2 interrupts
84
+ disabled, and any code that uses CIA2 to generate NMIs must coexist
85
+ with the RESTORE wiring.
86
+
87
+ ## CIA1 quick reference
88
+
89
+ CIA1 occupies `$DC00-$DC0F` with 16-byte mirrors filling the rest of
90
+ `$DC00-$DCFF`. Reads and writes to `$DC10`, `$DC20`, ... `$DCF0` access
91
+ the same registers as `$DC00`.
92
+
93
+ | Addr | Name | R/W | Function |
94
+ |---------|----------|-----|---------------------------------------------------------|
95
+ | `$DC00` | `DC00` | RW | Data port A — keyboard matrix col, joystick 2 pins |
96
+ | `$DC01` | `DC01` | RW | Data port B — keyboard matrix row, joystick 1 pins |
97
+ | `$DC02` | `DC02` | RW | Data direction register A (0=input, 1=output) |
98
+ | `$DC03` | `DC03` | RW | Data direction register B (0=input, 1=output) |
99
+ | `$DC04` | `DC04` | RW | Timer A low byte (write = latch, read = current) |
100
+ | `$DC05` | `DC05` | RW | Timer A high byte (write = latch, read = current) |
101
+ | `$DC06` | `DC06` | RW | Timer B low byte (write = latch, read = current) |
102
+ | `$DC07` | `DC07` | RW | Timer B high byte (write = latch, read = current) |
103
+ | `$DC08` | `DC08` | RW | Time-of-day tenths of a second (BCD) |
104
+ | `$DC09` | `DC09` | RW | Time-of-day seconds (BCD) |
105
+ | `$DC0A` | `DC0A` | RW | Time-of-day minutes (BCD) |
106
+ | `$DC0B` | `DC0B` | RW | Time-of-day hours (BCD, bit 7 = AM/PM) |
107
+ | `$DC0C` | `DC0C` | RW | Serial shift register (SDR) |
108
+ | `$DC0D` | `DC0D` | RW | Interrupt-control register (drives 6510 /IRQ) |
109
+ | `$DC0E` | `DC0E` | RW | Control register A — Timer A mode |
110
+ | `$DC0F` | `DC0F` | RW | Control register B — Timer B mode |
111
+
112
+ ## CIA2 quick reference
113
+
114
+ CIA2 occupies `$DD00-$DD0F` with 16-byte mirrors filling `$DD00-$DDFF`.
115
+
116
+ | Addr | Name | R/W | Function |
117
+ |---------|----------|-----|----------------------------------------------------------|
118
+ | `$DD00` | `DD00` | RW | Data port A — VIC bank (0-1), serial bus (3-7), RS-232 |
119
+ | `$DD01` | `DD01` | RW | Data port B — user-port PB lines, RS-232 data |
120
+ | `$DD02` | `DD02` | RW | Data direction register A |
121
+ | `$DD03` | `DD03` | RW | Data direction register B |
122
+ | `$DD04` | `DD04` | RW | Timer A low byte |
123
+ | `$DD05` | `DD05` | RW | Timer A high byte |
124
+ | `$DD06` | `DD06` | RW | Timer B low byte |
125
+ | `$DD07` | `DD07` | RW | Timer B high byte |
126
+ | `$DD08` | `DD08` | RW | Time-of-day tenths (BCD) |
127
+ | `$DD09` | `DD09` | RW | Time-of-day seconds (BCD) |
128
+ | `$DD0A` | `DD0A` | RW | Time-of-day minutes (BCD) |
129
+ | `$DD0B` | `DD0B` | RW | Time-of-day hours (BCD) |
130
+ | `$DD0C` | `DD0C` | RW | Serial shift register (unused by the KERNAL) |
131
+ | `$DD0D` | `DD0D` | RW | Interrupt-control register (drives 6510 /NMI) |
132
+ | `$DD0E` | `DD0E` | RW | Control register A — Timer A mode |
133
+ | `$DD0F` | `DD0F` | RW | Control register B — Timer B mode |
134
+
135
+ ## CIA1 register details
136
+
137
+ ### $DC00 — DC00 — Data Port A (RW)
138
+
139
+ **Chip:** CIA1
140
+
141
+ Data port A. Output pins are PA0-PA7. On the C64 these pins are wired to:
142
+
143
+ - The keyboard matrix **column drive** (PA0-PA7 drive columns 0-7).
144
+ - Control port 2 ("joy 2"): joystick directions, fire button, paddle
145
+ switches share PA0-PA4 with the keyboard columns.
146
+ - Paddle-X / paddle-Y selection (bits 6-7) which the SID's POTX/POTY
147
+ ADC reads.
148
+
149
+ | Bit | Function |
150
+ |-----|----------------------------------------------------------------|
151
+ | 0 | Keyboard column 0 drive / joy2 UP |
152
+ | 1 | Keyboard column 1 drive / joy2 DOWN |
153
+ | 2 | Keyboard column 2 drive / joy2 LEFT |
154
+ | 3 | Keyboard column 3 drive / joy2 RIGHT |
155
+ | 4 | Keyboard column 4 drive / joy2 FIRE |
156
+ | 5 | Keyboard column 5 drive |
157
+ | 6 | Keyboard column 6 drive / paddle select bit 0 |
158
+ | 7 | Keyboard column 7 drive / paddle select bit 1 |
159
+
160
+ To scan a column, clear the chosen column's bit in `$DC00` and set the
161
+ other seven (the KERNAL walks `$FE`, `$FD`, ... `$7F`), then read
162
+ `$DC01` to see which rows were pulled low.
163
+ The control-port 2 joystick is wired in parallel with the column lines,
164
+ so a pushed direction grounds PA0-PA4 externally. On its own that
165
+ produces no phantom key: the KERNAL scanner's no-key test writes `$00`
166
+ to `$DC00` and reads `$DC01`, and nothing on port A can lower a row line
167
+ unless a key is closed. (An earlier version said joy 2 up read as a
168
+ phantom INST/DEL; corrected from the SCNKEY code at `$EA87-$EADD` and
169
+ measured in VICE x64sc.)
170
+
171
+ ### $DC01 — DC01 — Data Port B (RW)
172
+
173
+ **Chip:** CIA1
174
+
175
+ Data port B. Pins PB0-PB7. On the C64:
176
+
177
+ - Keyboard matrix **row read** (PB0-PB7 read rows 0-7).
178
+ - Control port 1 ("joy 1"): joy1 directions and fire share PB0-PB4
179
+ with the keyboard rows.
180
+ - Timer A and Timer B can optionally drive PB6/PB7 as output (see the
181
+ PBON bit of `$DC0E`/`$DC0F`).
182
+ - Light-pen trigger: bit 4 connects to the VIC-II `/LP` line via the
183
+ control-port 1 fire-button pin.
184
+
185
+ | Bit | Function |
186
+ |-----|----------------------------------------------------------------|
187
+ | 0 | Keyboard row 0 read / joy1 UP |
188
+ | 1 | Keyboard row 1 read / joy1 DOWN |
189
+ | 2 | Keyboard row 2 read / joy1 LEFT |
190
+ | 3 | Keyboard row 3 read / joy1 RIGHT |
191
+ | 4 | Keyboard row 4 read / joy1 FIRE / light pen trigger |
192
+ | 5 | Keyboard row 5 read |
193
+ | 6 | Keyboard row 6 read / Timer A PBON output (if enabled) |
194
+ | 7 | Keyboard row 7 read / Timer B PBON output (if enabled) |
195
+
196
+ Reading `$DC01` gives `1` for rows that are pulled high (no key pressed,
197
+ joystick not in that direction) and `0` for rows pulled low through
198
+ either the matrix or the joystick switches.
199
+
200
+ ### $DC02 — DC02 — Data Direction Register A (RW)
201
+
202
+ **Chip:** CIA1
203
+
204
+ Data-direction register for port A. Each bit controls the direction of
205
+ the corresponding port-A pin:
206
+
207
+ - `0` = pin is input (high-impedance, internally pulled up)
208
+ - `1` = pin is output (driven by the corresponding bit of `$DC00`)
209
+
210
+ IOINIT (`$FDA3`; the store is `STX $DC02` at `$FDC8` with X = `$FF`)
211
+ sets `$DC02` to `$FF` — at reset, again on RUN/STOP+RESTORE (the NMI
212
+ handler calls IOINIT at `$FE69`), and whenever `$FF84` is called. The
213
+ keyboard scanner (SCNKEY, `$EA87`) relies on that and only ever writes
214
+ `$DC00`; it never touches a DDR, so if you clear `$DC02` to read
215
+ joystick 2 you must restore `$FF` yourself — the jiffy scan will not.
216
+ The chip's own reset leaves the DDR at `$00` (all input): measured in
217
+ VICE x64sc 3.10 from a cartridge cold start, which the RESET entry runs
218
+ before IOINIT. An earlier version of this page said the scanner set
219
+ `$DC02` and that `$FF` was the reset default; both were the KERNAL's
220
+ doing.
221
+
222
+ ### $DC03 — DC03 — Data Direction Register B (RW)
223
+
224
+ **Chip:** CIA1
225
+
226
+ Data-direction register for port B. The KERNAL keyboard scanner sets
227
+ this to `$00` so PB0-PB7 are all inputs (rows being read). After
228
+ RESET the default is `$00`.
229
+
230
+ Note: if you enable Timer A or Timer B output to PB6/PB7 via the PBON
231
+ bit of `$DC0E`/`$DC0F`, those bits of `$DC03` are forced to output
232
+ regardless of what you write here.
233
+
234
+ ### $DC04 — DC04 — Timer A Low Byte (RW)
235
+
236
+ **Chip:** CIA1
237
+
238
+ Timer A is a 16-bit down counter. `$DC04` is its low byte.
239
+
240
+ - **Write**: writes go to the 16-bit *latch*, not the counter. The
241
+ counter is reloaded from the latch on underflow or when the LOAD bit
242
+ of `$DC0E` is set.
243
+ - **Read**: reads return the *current counter value*, not the latch.
244
+
245
+ Reading `$DC04` and `$DC05` to capture a 16-bit timer value is racy
246
+ because the counter decrements between the two byte reads. The standard
247
+ trick is: stop Timer A with `STA $DC0E` (clear START bit), then read,
248
+ then restart.
249
+
250
+ After RESET the latch is `$FFFF`.
251
+
252
+ The KERNAL programs CIA1 Timer A for the jiffy IRQ from the code at
253
+ `$FDDD` (inside IOINIT, and entered again from the tail of CINT at
254
+ `$FF5B` once it has set the PAL/NTSC flag at `$02A6`, which is the write
255
+ that sticks: 1 = PAL, 0 = NTSC). It writes the latch `$4025` on PAL
256
+ (period 16,422 cycles; 985,248 / 16,422 = 59.996 Hz) and `$4295` on
257
+ NTSC (period 17,046 cycles; 1,022,727 / 17,046 = 59.998 Hz) — so one
258
+ jiffy is 1/60 s in both regions and only the VIC frame rate differs. An
259
+ earlier version of this page had the two values swapped and said the
260
+ timer matched the frame rate. Values read from kernal-901227-03.bin at
261
+ `$FDDD-$FDF6` and confirmed in VICE x64sc by reading the latch back
262
+ (stop + LOAD strobe) and by counting 299 jiffies in 250 PAL frames; the
263
+ +1 in the period is the 6526's count-to-zero-then-reload behaviour, not
264
+ measured separately here.
265
+
266
+ ### $DC05 — DC05 — Timer A High Byte (RW)
267
+
268
+ **Chip:** CIA1
269
+
270
+ Timer A high byte. Same semantics as `$DC04`: writes set the latch,
271
+ reads return the current counter.
272
+
273
+ Writing the *high* byte while Timer A is stopped also force-loads the
274
+ counter from the latch (this is a 6526 quirk — useful for setting up a
275
+ new value without an explicit LOAD).
276
+
277
+ ### $DC06 — DC06 — Timer B Low Byte (RW)
278
+
279
+ **Chip:** CIA1
280
+
281
+ Timer B low byte. Same semantics as Timer A's `$DC04`. Writes go to the
282
+ latch, reads return the counter.
283
+
284
+ CIA1 Timer B is free for application use only while no KERNAL
285
+ serial-bus or tape I/O is running. Every byte the KERNAL sends on the
286
+ IEC bus (LISTEN/TALK command bytes, secondary addresses, CIOUT data)
287
+ ends with `LDA #$04 / STA $DC07 / LDA #$19 / STA $DC0F` at `$ED92` and a
288
+ poll of `$DC0D` bit 1 at `$ED9F` (the listener-acknowledge timeout), and
289
+ every byte ACPTR receives starts with the same sequence using `#$01` at
290
+ `$EE20`, polled at `$EE30` (the EOI timeout). Only the high latch byte
291
+ is written; the low byte is whatever was there before (`$FF` from reset
292
+ — IOINIT never touches `$DC06` — so the one-shots are `$04FF` and
293
+ `$01FF` cycles, about 1.3 ms and 0.5 ms, not `$0400`/`$0100`). CRB is
294
+ rewritten wholesale to `$19`: a continuous timer becomes one-shot and
295
+ stops after its next underflow, PBON, OUTMODE, INMODE and the ALARM
296
+ select are cleared, and the `$DC0D` reads discard every pending CIA1
297
+ flag, not just Timer B's. Measured in VICE x64sc with a true-emulated
298
+ 1541: a Timer B programmed to `$1234`, continuous and running, read back
299
+ CRB = `$08` (one-shot, stopped), counter `$0434` and `$DC0D` bit 1
300
+ pending after a single KERNAL TALK/TKSA/ACPTR/UNTLK. The tape code owns
301
+ the timer outright: tape write runs on Timer B underflow interrupts
302
+ (mask `$82` written at `$F87A`; half-pulse latches `$0060`/`$00B0` set
303
+ at `$FBB1-$FBBC`) and tape read measures pulse widths on it at `$F92C`
304
+ and restarts it from a `$FFFF` latch at `$F93D-$F945`. A music or
305
+ raster timer on CIA1 Timer B does not survive a KERNAL LOAD or SAVE
306
+ over IEC or tape. (An earlier version of this page said the KERNAL
307
+ never used it; read from kernal-901227-03.bin and measured in VICE.)
308
+
309
+ ### $DC07 — DC07 — Timer B High Byte (RW)
310
+
311
+ **Chip:** CIA1
312
+
313
+ Timer B high byte. Writes to the latch; reads from the counter.
314
+
315
+ ### $DC08 — DC08 — Time-of-Day Tenths (RW)
316
+
317
+ **Chip:** CIA1
318
+
319
+ Time-of-day clock — tenths of a second, encoded in 4-bit BCD. Only
320
+ bits 0-3 are used; bits 4-7 read zero.
321
+
322
+ The TOD clock is driven by the **TOD pin** on the 6526, which on the
323
+ C64 is wired to the AC mains 50 Hz (PAL) or 60 Hz (NTSC) line via the
324
+ power supply. The CRA bit 7 of `$DC0E` selects 50 Hz vs 60 Hz division.
325
+
326
+ **Reading `$DC0B` (hours) latches** all four TOD registers
327
+ (`$DC08`-`$DC0B`) so a multi-byte read sees a coherent time; the latch
328
+ is released by reading `$DC08` (tenths). Read order: hours, minutes,
329
+ seconds, tenths. The counter keeps running underneath the latch, so a
330
+ read of tenths after a long-held latch jumps straight to the live time.
331
+ (An earlier version of this page had the two registers swapped;
332
+ measured in VICE x64sc; the probe is in `pitfalls/cia.md`,
333
+ `tod_read_order_latch`.)
334
+
335
+ **Writes** go to the running clock when the ALARM bit of `$DC0F` is 0
336
+ and to the alarm when it is 1. With ALARM = 0, writing `$DC0B` (hours)
337
+ STOPS the clock so all four registers can be set coherently, and writing
338
+ `$DC08` (tenths) restarts it; set hours, minutes, seconds, tenths in
339
+ that order — a clock whose tenths are never written stays stopped
340
+ (VICE's TOD is stopped at power-up until the first tenths write). With
341
+ ALARM = 1 the same four writes program the alarm and leave the clock
342
+ running; there is no separate arming step, the alarm compare is always
343
+ live. (An earlier version of this page said the hours write started the
344
+ clock; measured in VICE x64sc.)
345
+
346
+ ### $DC09 — DC09 — Time-of-Day Seconds (RW)
347
+
348
+ **Chip:** CIA1
349
+
350
+ Seconds, BCD. Bits 0-3 are the units digit, bits 4-6 are the tens
351
+ digit (0-5). Bit 7 reads zero.
352
+
353
+ ### $DC0A — DC0A — Time-of-Day Minutes (RW)
354
+
355
+ **Chip:** CIA1
356
+
357
+ Minutes, BCD. Bits 0-3 = units, bits 4-6 = tens (0-5), bit 7 = 0.
358
+
359
+ ### $DC0B — DC0B — Time-of-Day Hours (RW)
360
+
361
+ **Chip:** CIA1
362
+
363
+ Hours, BCD. Bits 0-3 = units, bit 4 = tens digit (0 or 1), bits 5-6 = 0,
364
+ bit 7 = AM/PM flag (0 = AM, 1 = PM).
365
+
366
+ Writing `$DC0B` with `$DC0F` bit 7 = 0 stops the clock; it does not run
367
+ again until `$DC08` (tenths) is written. With bit 7 = 1 the write sets
368
+ the alarm hours and the clock keeps running (measured in VICE x64sc;
369
+ this page used to say the hours write started the clock).
370
+
371
+ Reading `$DC0B` latches all four TOD registers; the latch is released
372
+ by a later read of `$DC08` (tenths). If you peek at the hours and never
373
+ read tenths, every subsequent TOD read returns the frozen value.
374
+ (Previously stated the other way round; measured in VICE x64sc.)
375
+
376
+ ### $DC0C — DC0C — Serial Shift Register (RW)
377
+
378
+ **Chip:** CIA1
379
+
380
+ 8-bit synchronous serial shift register. Clock comes from CNT, data
381
+ from SP. Direction (input/output) is selected by the SPMODE bit of
382
+ `$DC0E`.
383
+
384
+ CIA1's SDR is **not used by the KERNAL**. Its SP1 and CNT1 pins do
385
+ reach the user port (pins 5 and 4, beside CIA2's SP2/CNT2 on 7 and 6 —
386
+ the C64 user-port pinout, not measured here), so third-party hardware
387
+ can drive it. An earlier version of this page said the pins had no
388
+ external wiring.
389
+
390
+ After a full byte has been shifted in or out, the SDR bit of the ICR
391
+ (`$DC0D` bit 3) goes high.
392
+
393
+ ### $DC0D — DC0D — Interrupt Control Register (RW)
394
+
395
+ **Chip:** CIA1
396
+
397
+ Five interrupt sources, one summary flag. Reads and writes use
398
+ different bit layouts.
399
+
400
+ **Read** of `$DC0D`: returns pending interrupt flags, then **clears all
401
+ flags as a side effect** and de-asserts `/IRQ`.
402
+
403
+ | Bit | Read meaning |
404
+ |-----|----------------------------------------------------|
405
+ | 0 | Timer A underflow occurred |
406
+ | 1 | Timer B underflow occurred |
407
+ | 2 | TOD alarm matched |
408
+ | 3 | Serial shift register full/empty |
409
+ | 4 | FLAG pin transition (negative edge) |
410
+ | 5-6 | always 0 |
411
+ | 7 | IRQ — set if any of bits 0-4 are set AND its mask |
412
+
413
+ **Write** to `$DC0D`: sets or clears interrupt-enable mask bits.
414
+
415
+ | Bit | Write meaning |
416
+ |-----|---------------------------------------------------------------|
417
+ | 0 | Enable/disable Timer A underflow IRQ |
418
+ | 1 | Enable/disable Timer B underflow IRQ |
419
+ | 2 | Enable/disable TOD alarm IRQ |
420
+ | 3 | Enable/disable serial shift IRQ |
421
+ | 4 | Enable/disable FLAG-pin IRQ |
422
+ | 5-6 | reserved (write 0) |
423
+ | 7 | SET/CLEAR — `1` = bits 0-4 *set* selected masks; |
424
+ | | `0` = bits 0-4 *clear* selected masks |
425
+
426
+ Idiom: to enable Timer A IRQ only, write `%10000001` = `$81`.
427
+ To disable Timer A IRQ only, write `%00000001` = `$01`.
428
+
429
+ When `/IRQ` is asserted by CIA1, the 6510's `/IRQ` pin goes low. With
430
+ `I` clear, this jumps through the IRQ vector at `$FFFE-$FFFF` (which
431
+ in KERNAL ROM mode points at `$FF48`, the KERNAL IRQ handler, which
432
+ in turn calls the indirect vector at `$0314-$0315`).
433
+
434
+ A custom IRQ handler **must** read `$DC0D` to acknowledge — otherwise
435
+ the chip will keep `/IRQ` asserted and the handler will re-enter
436
+ immediately after `RTI`.
437
+
438
+ ### $DC0E — DC0E — Control Register A (Timer A) (RW)
439
+
440
+ **Chip:** CIA1
441
+
442
+ Controls Timer A.
443
+
444
+ | Bit | Name | Function |
445
+ |-----|------------|---------------------------------------------------------|
446
+ | 0 | START | 1 = start Timer A counting, 0 = stop |
447
+ | 1 | PBON | 1 = drive Timer A output (toggle or pulse) to PB6 |
448
+ | 2 | OUTMODE | 0 = pulse PB6 for one cycle; 1 = toggle PB6 on underflow|
449
+ | 3 | RUNMODE | 0 = continuous (auto-reload); 1 = one-shot (stop) |
450
+ | 4 | LOAD | 1 = strobe: force-load counter from latch (no storage) |
451
+ | 5 | INMODE | 0 = count phi-2 clocks; 1 = count CNT positive edges |
452
+ | 6 | SPMODE | 0 = SDR input; 1 = SDR output (Timer A clocks SP) |
453
+ | 7 | TODIN | 0 = TOD counts 60 Hz; 1 = TOD counts 50 Hz |
454
+
455
+ The KERNAL never sets TODIN. IOINIT (`$FDAE`) writes `$08` to `$DC0E`,
456
+ `$DC0F`, `$DD0E` and `$DD0F` on every machine; the jiffy-timer tail at
457
+ `$FF6E` then rewrites `$DC0E` as (`$DC0E` AND `$80`) OR `$11`, which
458
+ keeps the 0 IOINIT put there. So after boot `$DC0E` reads `$01` and
459
+ `$DD0E` reads `$08` on PAL and NTSC alike, and both TOD clocks are in
460
+ 60 Hz mode even on a PAL C64. A PAL program that wants a correct TOD
461
+ must set bit 7 itself, and must do it read-modify-write
462
+ (`LDA $DC0E : ORA #$80 : STA $DC0E`) because a plain store would clear
463
+ bit 0 and stop the Timer A jiffy IRQ that drives the keyboard scan. Left
464
+ at 0 on a 50 Hz supply the clock counts 5/6 of real time (measured in
465
+ VICE x64sc: 4.1 s on the TOD for 4.9 s elapsed); the mirror case,
466
+ TODIN = 1 on an NTSC machine, runs 6/5 fast. (An earlier version said
467
+ the KERNAL set this bit by region; read from kernal-901227-03.bin
468
+ `$FDAE`/`$FF6E` and confirmed in VICE x64sc on both models.)
469
+
470
+ LOAD is a write-only strobe; reading bit 4 always returns 0.
471
+
472
+ ### $DC0F — DC0F — Control Register B (Timer B) (RW)
473
+
474
+ **Chip:** CIA1
475
+
476
+ Controls Timer B.
477
+
478
+ | Bit | Name | Function |
479
+ |-----|------------|----------------------------------------------------------|
480
+ | 0 | START | 1 = start Timer B counting |
481
+ | 1 | PBON | 1 = drive Timer B output to PB7 |
482
+ | 2 | OUTMODE | 0 = pulse PB7 once; 1 = toggle PB7 |
483
+ | 3 | RUNMODE | 0 = continuous; 1 = one-shot |
484
+ | 4 | LOAD | 1 = strobe: force-load counter from latch |
485
+ | 5-6 | INMODE | 00 = phi-2; 01 = rising CNT edges; 10 = Timer A underflows; |
486
+ | | | 11 = Timer A underflows gated by CNT high |
487
+ | 7 | ALARM | 0 = TOD writes set clock; 1 = TOD writes set alarm |
488
+
489
+ The INMODE `10` setting (count Timer A underflows) lets you chain
490
+ the two timers into a 32-bit timer. Set Timer A as the low 16 bits,
491
+ Timer B as the high 16 bits, and Timer B will tick once per Timer A
492
+ underflow — giving a period of up to 2^32 phi-2 cycles, roughly
493
+ 4300 seconds at 1 MHz.
494
+
495
+ ## CIA2 register details
496
+
497
+ ### $DD00 — DD00 — Data Port A — VIC bank + IEC (RW)
498
+
499
+ **Chip:** CIA2
500
+
501
+ CIA2's port A is the most heavily multiplexed register on the C64.
502
+ Bits 0-1 select the VIC-II's 16 KiB bank. Bits 3-7 drive (or read)
503
+ the serial-IEC bus to the disk drive and printer. Bit 2 is the
504
+ RS-232 TXD output on the user port.
505
+
506
+ | Bit | Direction | Function |
507
+ |-----|-----------|-----------------------------------------------------------|
508
+ | 0 | Output | VA14 — VIC bank select bit 0 (inverted: see below) |
509
+ | 1 | Output | VA15 — VIC bank select bit 1 (inverted) |
510
+ | 2 | Output | User-port RS-232 TXD (transmit data) |
511
+ | 3 | Output | Serial IEC ATN OUT (drive ATN low) |
512
+ | 4 | Output | Serial IEC CLK OUT |
513
+ | 5 | Output | Serial IEC DATA OUT |
514
+ | 6 | Input | Serial IEC CLK IN (sensed from bus) |
515
+ | 7 | Input | Serial IEC DATA IN (sensed from bus) |
516
+
517
+ **VIC bank selection (bits 0-1):**
518
+
519
+ These two bits are *inverted* on the way to VA14/VA15. The mapping is:
520
+
521
+ | Bits 1-0 | Bank | VIC sees |
522
+ |----------|------|-------------------------|
523
+ | `11` | 0 | `$0000-$3FFF` |
524
+ | `10` | 1 | `$4000-$7FFF` |
525
+ | `01` | 2 | `$8000-$BFFF` |
526
+ | `00` | 3 | `$C000-$FFFF` |
527
+
528
+ After RESET both bits are `1`, so the VIC sees bank 0 (`$0000-$3FFF`).
529
+ The KERNAL leaves the default at bank 0. Bank 1 and bank 3 do *not* see
530
+ character ROM (it only appears at `$1000-$1FFF` and `$9000-$9FFF`); to
531
+ use custom charsets in banks 1 or 3, copy the ROM character set to RAM
532
+ first.
533
+
534
+ The IEC input bits (6, 7) are *not* inverted at the register: bit 6
535
+ (CLK IN) and bit 7 (DATA IN) read `1` when the line is high (released)
536
+ and `0` when this C64 or any device is pulling it low. Only the output
537
+ side is inverted: writing `1` to bits 3, 4, 5 pulls ATN/CLK/DATA low
538
+ (the KERNAL's CLKLO at `$EE8E` is `ORA #$10`, CLKHI at `$EE85` is
539
+ `AND #$EF`). The KERNAL relies on the input polarity: LISTEN's
540
+ device-not-present test at `$ED47` is `BCS` on bit 7 after `ASL` (DATA
541
+ still high after releasing it under ATN = nobody home), and ACPTR at
542
+ `$EE1B` waits for bit 6 = 1, the talker releasing CLK. Measured in VICE
543
+ x64sc: with all three outputs released `$DD00` reads `$C7`; setting
544
+ bit 5 makes bit 7 read `0`; with a 1541 attached and ATN asserted the
545
+ drive pulls DATA and bit 7 reads `0`. After boot it reads `$97` because
546
+ the KERNAL leaves CLK OUT (bit 4) set, so bit 6 is `0` while the C64
547
+ holds CLK low. (An earlier version of this page had the inputs inverted
548
+ as well as the outputs.)
549
+
550
+ ### $DD01 — DD01 — Data Port B — user port (RW)
551
+
552
+ **Chip:** CIA2
553
+
554
+ Port B is wired to the C64 user port (the rear edge connector), pins
555
+ C-L. These are general-purpose I/O pins commonly used for:
556
+
557
+ - RS-232 receive data (bit 0 is RXD)
558
+ - RS-232 modem-control signals (RTS, DTR, RI, DCD, CTS, DSR)
559
+ - User-port parallel cables (1541 fastloaders, 1571 burst mode)
560
+ - Hardware MIDI interfaces
561
+ - Centronics printer cables
562
+
563
+ The KERNAL RS-232 driver uses CIA2 Timer A as the transmit bit-clock
564
+ and Timer B as the receive bit-clock, bit-banging TXD on `$DD00` bit 2
565
+ and sampling RXD on `$DD01` bit 0 (`$FED6`).
566
+
567
+ After RESET all bits are inputs (`$DD03` = `$00`).
568
+
569
+ ### $DD02 — DD02 — Data Direction Register A (RW)
570
+
571
+ **Chip:** CIA2
572
+
573
+ DDR for CIA2 port A. The KERNAL sets this to `$3F` so that bits 0-5
574
+ are outputs (VIC bank, RS-232 TXD, IEC ATN/CLK/DATA OUT) and bits 6-7
575
+ are inputs (IEC CLK IN, IEC DATA IN).
576
+
577
+ If you accidentally clear `$DD02` to `$00`, the VIC bank-select bits
578
+ become inputs and the VIC will see whatever the bus floats to —
579
+ typically `$3FFF` lines all-high, putting the VIC in bank 0. More
580
+ importantly, writing to `$DD00` then has no effect until you restore
581
+ the DDR.
582
+
583
+ ### $DD03 — DD03 — Data Direction Register B (RW)
584
+
585
+ **Chip:** CIA2
586
+
587
+ DDR for CIA2 port B (user port). After RESET this is `$00` (all input).
588
+ RS-232 transmit code sets specific bits to output as needed.
589
+
590
+ ### $DD04 — DD04 — Timer A Low Byte (RW)
591
+
592
+ **Chip:** CIA2
593
+
594
+ Timer A low byte. Same semantics as CIA1's `$DC04`: writes to latch,
595
+ reads from counter.
596
+
597
+ The KERNAL uses CIA2 Timer A as the RS-232 bit-rate generator. When
598
+ RS-232 is not in use, Timer A is free for application timing.
599
+
600
+ ### $DD05 — DD05 — Timer A High Byte (RW)
601
+
602
+ **Chip:** CIA2
603
+
604
+ Timer A high byte.
605
+
606
+ ### $DD06 — DD06 — Timer B Low Byte (RW)
607
+
608
+ **Chip:** CIA2
609
+
610
+ Timer B low byte.
611
+
612
+ ### $DD07 — DD07 — Timer B High Byte (RW)
613
+
614
+ **Chip:** CIA2
615
+
616
+ Timer B high byte.
617
+
618
+ ### $DD08 — DD08 — Time-of-Day Tenths (RW)
619
+
620
+ **Chip:** CIA2
621
+
622
+ CIA2 has a fully independent TOD clock from CIA1's. It is driven by the
623
+ same AC mains line through the same TOD pin, so both clocks tick at the
624
+ same external rate, but they can hold different values.
625
+
626
+ CIA2's TOD is largely unused by the C64 KERNAL.
627
+
628
+ ### $DD09 — DD09 — Time-of-Day Seconds (RW)
629
+
630
+ **Chip:** CIA2
631
+
632
+ Seconds, BCD.
633
+
634
+ ### $DD0A — DD0A — Time-of-Day Minutes (RW)
635
+
636
+ **Chip:** CIA2
637
+
638
+ Minutes, BCD.
639
+
640
+ ### $DD0B — DD0B — Time-of-Day Hours (RW)
641
+
642
+ **Chip:** CIA2
643
+
644
+ Hours, BCD with AM/PM in bit 7.
645
+
646
+ ### $DD0C — DD0C — Serial Shift Register (RW)
647
+
648
+ **Chip:** CIA2
649
+
650
+ CIA2's SDR. The KERNAL never touches either CIA's shift register —
651
+ there is no reference to `$DC0C` or `$DD0C` anywhere in the 901227-03
652
+ KERNAL or 901226-01 BASIC ROMs (byte census, any alignment). KERNAL
653
+ RS-232 is bit-banged under NMI: CIA2 Timer A paces transmit on PA2
654
+ (`$F047` writes `$11` to `$DD0E`), the FLAG input catches the start bit
655
+ (`$EF7E` writes `$90` to `$DD0D`), and Timer B paces receive sampling
656
+ of PB0 (`$FED6`: `LDA $DD01 / AND #$01 / STA $A7`; `$FEF1`/`$FF13`
657
+ write `$11` to `$DD0F`). There is no "high-speed synchronous" RS-232
658
+ mode in the KERNAL. The SP2/CNT2 pins reach the user port, so
659
+ third-party serial hardware and drivers can use the SDR; for
660
+ KERNAL-only code it is free. (An earlier version of this section said
661
+ the KERNAL used the SDR in shift-in mode for a synchronous RS-232
662
+ receive; it does not — read from kernal-901227-03.bin.)
663
+
664
+ ### $DD0D — DD0D — Interrupt Control Register (drives /NMI) (RW)
665
+
666
+ **Chip:** CIA2
667
+
668
+ Same bit layout as CIA1's `$DC0D`. The crucial difference is that
669
+ CIA2's `/IRQ` output is wired to the 6510's `/NMI` pin, **not** `/IRQ`.
670
+
671
+ | Bit | Read meaning | Write meaning |
672
+ |-----|---------------------------------------------------|----------------------------|
673
+ | 0 | Timer A underflow occurred | Mask Timer A NMI |
674
+ | 1 | Timer B underflow occurred | Mask Timer B NMI |
675
+ | 2 | TOD alarm matched | Mask TOD-alarm NMI |
676
+ | 3 | Serial shift register full/empty | Mask SDR NMI |
677
+ | 4 | FLAG pin transition | Mask FLAG NMI |
678
+ | 5-6 | always 0 | reserved (write 0) |
679
+ | 7 | NMI summary flag (any enabled bit 0-4 set) | SET/CLEAR direction |
680
+
681
+ The chip itself still calls it an "IRQ" in datasheet language. The
682
+ NMI/IRQ distinction is purely a function of which CPU pin the output
683
+ is wired to — see Overview.
684
+
685
+ Reading `$DD0D` clears all pending NMI flags and de-asserts the chip's
686
+ output pin. An NMI handler **must** read `$DD0D` (or otherwise
687
+ acknowledge) before `RTI`; otherwise `/NMI` stays low and, because the
688
+ 6510 takes NMI on a falling edge only, no further CIA2 NMI — and no
689
+ RESTORE press — can be taken until something reads `$DD0D`. (An
690
+ earlier version of this page said the handler would re-enter on `RTI`;
691
+ that is the IRQ symptom, not the NMI one. Measured in VICE x64sc 3.10:
692
+ CIA2 Timer A one-shot NMI with a handler that never reads `$DD0D` —
693
+ entered once; a second underflow while `/NMI` stayed low produced no
694
+ NMI; one `LDA $DD0D` and the next underflow produced one. See
695
+ Pitfalls.)
696
+
697
+ The KERNAL initializes `$DD0D` to `$7F` (clear all masks) followed by
698
+ no explicit enables, leaving CIA2 NMIs disabled by default.
699
+
700
+ ### $DD0E — DD0E — Control Register A (Timer A) (RW)
701
+
702
+ **Chip:** CIA2
703
+
704
+ Same bit layout as CIA1's `$DC0E`. Same notes about the LOAD strobe and
705
+ TODIN frequency. The KERNAL leaves CIA2's TODIN at 0 as well — IOINIT
706
+ writes `$08` here and nothing later touches bit 7 (the only other
707
+ KERNAL writes, `$F030`/`$F049` in the RS-232 code, store `$10`/`$11`)
708
+ — so a PAL program using CIA2's TOD must OR in bit 7 itself. (An
709
+ earlier version said the KERNAL set it by region.)
710
+
711
+ ### $DD0F — DD0F — Control Register B (Timer B) (RW)
712
+
713
+ **Chip:** CIA2
714
+
715
+ Same bit layout as CIA1's `$DC0F`. Same INMODE choices (phi-2 / CNT /
716
+ Timer A underflows / Timer A + CNT gated). Same ALARM bit selecting
717
+ between writing the clock vs writing the alarm.
718
+
719
+ ## Keyboard scanning (CIA1 ports A/B)
720
+
721
+ The C64 keyboard is an 8x8 matrix of 64 key switches. Two extra
722
+ non-matrix switches (`RESTORE` to NMI, `SHIFT LOCK` mechanically tied
723
+ to LEFT-SHIFT) exist outside the matrix.
724
+
725
+ Technique: scanning the matrix from a program without the KERNAL, and
726
+ why a main-loop scan interferes with joystick port 1, is
727
+ `keyboard_matrix_scan` in `techniques/input.md`.
728
+
729
+ **Wiring:**
730
+
731
+ - CIA1 port A (`$DC00`) drives the 8 *columns* (output, all `1`s except
732
+ the column being scanned, which is `0`).
733
+ - CIA1 port B (`$DC01`) reads the 8 *rows* (input with internal pull-ups
734
+ to `1`). A pressed key in the active column pulls its row to `0`.
735
+
736
+ The KERNAL keyboard scanner runs once per jiffy interrupt (about 60 Hz
737
+ on both PAL and NTSC — see `$DC04`). A minimal scanner in the KERNAL's
738
+ style (the ROM's SCNKEY sets the DDRs nowhere; IOINIT did that at
739
+ boot):
740
+
741
+ ```asm
742
+ LDA #$FF
743
+ STA $DC02 ; port A = output
744
+ LDA #$00
745
+ STA $DC03 ; port B = input
746
+ LDX #$00
747
+ loop: LDA col_mask,X ; one zero-bit walking across $FE..$7F
748
+ STA $DC00 ; drive that column low
749
+ LDA $DC01 ; read rows
750
+ STA matrix,X ; save row bits
751
+ INX
752
+ CPX #$08
753
+ BNE loop
754
+ ```
755
+
756
+ The classic full-matrix layout (column, row 0..7):
757
+
758
+ | Col | Row 0 | Row 1 | Row 2 | Row 3 | Row 4 | Row 5 | Row 6 | Row 7 |
759
+ |-----|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
760
+ | 0 | INST/DEL | RETURN | CRSR L/R | F7/F8 | F1/F2 | F3/F4 | F5/F6 | CRSR U/D |
761
+ | 1 | 3 # | W | A | 4 $ | Z | S | E | L-SHIFT |
762
+ | 2 | 5 % | R | D | 6 & | C | F | T | X |
763
+ | 3 | 7 ' | Y | G | 8 ( | B | H | U | V |
764
+ | 4 | 9 ) | I | J | 0 | M | K | O | N |
765
+ | 5 | + | P | L | - | . > | : [ | @ | , < |
766
+ | 6 | £ | * | ; ] | CLR/HOME | R-SHIFT | = | UP-ARROW | / ? |
767
+ | 7 | 1 ! | LEFT-ARROW| CTRL | 2 " | SPACE | C= | Q | RUN/STOP |
768
+
769
+ **Detecting "no key pressed"**: with all columns driven low (write `$00`
770
+ to `$DC00`) and DDR-A = `$FF`, read `$DC01` and check for `$FF`.
771
+
772
+ **Detecting multiple key combinations**: scan column by column and OR
773
+ the result. Standard caveat: three keys whose row+column rectangle forms
774
+ a triangle produce a "ghost" reading on the fourth corner — there are
775
+ no diodes in the matrix.
776
+
777
+ **Joystick interference**: Joystick 2 alone cannot make the KERNAL type
778
+ anything: its lines are columns, and the scanner's no-key test
779
+ (`$DC00` = `$00`, `$DC01` == `$FF`) looks only at rows. Measured in
780
+ VICE x64sc 3.10 with PA0, and then PA0-PA4, held low through six
781
+ seconds of scanning: SFDX stays `$40`, the buffer stays empty. It is
782
+ joystick 1, on the row lines PB0-PB4, that the scanner mistakes for
783
+ keys — and not quite as folklore has it. The column loop
784
+ (`$EAA3-$EADA`) walks `$DC00` from `$FE` to `$7F` and keeps the LAST
785
+ matching matrix index (`$EAC9`: `STY $CB`), then makes one more pass
786
+ with `$DC00` = `$FF` (the mask is rotated with carry set and
787
+ `BNE $EAA8` is taken) that tests row 0 once more at index 64 — the
788
+ tables' 65th entry, `$FF`, "no key". A real key cannot appear there
789
+ because no column is selected; a joystick-grounded row does. With the
790
+ default tables: UP is swallowed (index 64 → no key); DOWN types
791
+ LEFT-ARROW (`$5F`); LEFT lands on CTRL (col 7, row 2), which the
792
+ scanner treats as a modifier (`$028D` = 4), so the key kept is `;`
793
+ (col 6) read through the CTRL table: `$1D`, cursor right; RIGHT types
794
+ `2`; FIRE passes R-SHIFT (col 6, row 4) before SPACE, so SHFLAG = 1 and
795
+ the shifted table gives `$A0`, shift-space, which prints blank — the
796
+ "joystick in port 1 types spaces" effect. All five measured in VICE
797
+ x64sc 3.10 by holding the single port-B line low while the KERNAL
798
+ scanner ran. Joystick 2 held while a real key on rows 1-7 of column 0
799
+ is pressed makes that key read as its column-7 neighbour (RETURN reads
800
+ as LEFT-ARROW), because the grounded column shows in every column pass;
801
+ from the code, not measured. Games read `$DC00`/`$DC01` directly and
802
+ keep the KERNAL scanner out of the way during play.
803
+
804
+ ## Joystick reading (CIA1 port A = joy2, port B = joy1)
805
+
806
+ The C64 has two control ports (the DE-9 connectors on the right side of
807
+ the case). Each port has 5 active-low switch lines (up, down, left,
808
+ right, fire) plus two analog "potentiometer" lines.
809
+
810
+ Technique: turning the port byte into press events, held frames and
811
+ delayed auto-repeat is `joystick_edge_detect` and `joystick_autorepeat`
812
+ in `techniques/input.md`, with the recipe
813
+ `recipes/oscar64/joystick-input.md`.
814
+
815
+ - **Joy 2** (control port 2) → CIA1 port A, bits 0-4.
816
+ - **Joy 1** (control port 1) → CIA1 port B, bits 0-4.
817
+
818
+ Yes, port 1 is on CIA1 port *B*. This crossed wiring is the most
819
+ common surprise for new C64 developers.
820
+
821
+ **Bit assignments** (both ports use the same bit layout, just on
822
+ different CIA1 ports):
823
+
824
+ | Bit | Direction |
825
+ |-----|-----------|
826
+ | 0 | UP |
827
+ | 1 | DOWN |
828
+ | 2 | LEFT |
829
+ | 3 | RIGHT |
830
+ | 4 | FIRE |
831
+ | 5 | (unused — analog POT-Y on the port pin, not in this bit) |
832
+ | 6 | (analog POT-X on the port pin, not in this bit) |
833
+ | 7 | (unused) |
834
+
835
+ To read joy 2:
836
+
837
+ ```asm
838
+ LDA $DC00 ; joy 2: bits 0-4, 0 = pressed (UP, DOWN, LEFT, RIGHT, FIRE)
839
+ AND #$1F ; idle reads $7F, not $FF: bit 7 is the KERNAL's column-7 drive
840
+ ```
841
+
842
+ No DDR change is needed. The KERNAL leaves `$DC02` = `$FF` and `$DC00` =
843
+ `$7F` between scans (IOINIT `$FDC8`, SCNKEY exit `$EB42`), the CIA
844
+ returns the pin level rather than the output latch, and a closed switch
845
+ holds a pin low whether or not it is configured as an output (measured
846
+ in VICE x64sc with an external device on control port 2: the same bytes
847
+ read under DDR = `$FF`/PRA = `$7F` as under DDR = `$00`). An earlier
848
+ revision of this section wrote `$00` to `$DC02` "so the joystick can
849
+ pull lines low"; that was the wrong reason.
850
+
851
+ To read joy 1:
852
+
853
+ ```asm
854
+ LDA $DC01 ; port B is already input by default
855
+ ; bit 0 = 0 means UP, etc.
856
+ ```
857
+
858
+ If you do change `$DC02`, restore `$FF` before the next jiffy IRQ.
859
+ SCNKEY never rewrites the DDR (the only writes in the KERNAL are
860
+ IOINIT's), so with `$DC02` = `$00` no column is ever driven low, `$DC01`
861
+ reads `$FF` on every pass, and the keyboard — RUN/STOP included, which
862
+ UDTIM tests through the same port — is dead until something writes
863
+ `$FF` back.
864
+
865
+ **Paddles** (POT-X / POT-Y) are read through the SID chip's
866
+ `$D419`/`$D41A` registers. CIA1 port A bits 6-7 select which of the
867
+ two paddle pairs (port 1 or port 2) the SID samples. Setting bits 6-7
868
+ of `$DC00` to `01` selects paddle pair 1; `10` selects pair 2.
869
+
870
+ ## Timer A / Timer B
871
+
872
+ Both CIAs have identical Timer A and Timer B blocks. Each is a 16-bit
873
+ down counter with a 16-bit reload latch.
874
+
875
+ ### Count modes (input source)
876
+
877
+ **Timer A** has two count modes, selected by bit 5 of CRA (`$DC0E`
878
+ or `$DD0E`):
879
+
880
+ - `0`: count system phi-2 clocks (~1 MHz on a stock C64 — slightly
881
+ different PAL/NTSC).
882
+ - `1`: count rising edges on the CNT pin.
883
+
884
+ **Timer B** has four count modes, selected by bits 5-6 of CRB:
885
+
886
+ - `00`: count phi-2 clocks.
887
+ - `01`: count rising edges on the CNT pin.
888
+ - `10`: count Timer A underflows.
889
+ - `11`: count Timer A underflows while CNT is high.
890
+
891
+ Mode `10` enables 32-bit cascade: Timer A is the low 16 bits, Timer B
892
+ is the high 16 bits.
893
+
894
+ ### Run modes (what happens on underflow)
895
+
896
+ Bit 3 of CRA/CRB controls run mode:
897
+
898
+ - `0` continuous: counter reloads from latch and keeps counting.
899
+ - `1` one-shot: counter reloads from latch, START bit is cleared, the
900
+ timer stops.
901
+
902
+ ### Output to port B
903
+
904
+ Bit 1 (PBON) of CRA/CRB enables driving Timer A output to PB6 or Timer B
905
+ output to PB7. The driven bit of `$DC03`/`$DD03` is forced to output
906
+ mode regardless of what you wrote. Bit 2 (OUTMODE) picks pulse vs
907
+ toggle:
908
+
909
+ - OUTMODE = 0: PB6/PB7 *pulses* for one phi-2 cycle on each underflow.
910
+ - OUTMODE = 1: PB6/PB7 *toggles* on each underflow.
911
+
912
+ This is most often used on CIA1 to generate a tone at a precise
913
+ frequency, but the C64 doesn't route PB6/PB7 to anything audible by
914
+ default — the cassette port writes a pulse train to record bytes, but
915
+ that's CASS WRITE on the 6510 itself, not the CIA.
916
+
917
+ ### IRQ / NMI on underflow
918
+
919
+ When a timer underflows, the corresponding bit in `$DC0D` / `$DD0D`
920
+ goes high. If that bit's mask is set (via a write to `$DC0D` /
921
+ `$DD0D` with bit 7 = 1), the chip asserts `/IRQ`:
922
+
923
+ - CIA1 → 6510 `/IRQ` (maskable).
924
+ - CIA2 → 6510 `/NMI` (non-maskable).
925
+
926
+ ### Reading a running timer
927
+
928
+ Reads of timer low/high return the *current counter*, not the latch.
929
+ The counter is decrementing one count per phi-2 cycle (in phi-2 mode),
930
+ so reading the low byte and then the high byte will sometimes catch a
931
+ borrow in between, giving a value one tick off.
932
+
933
+ Standard idioms:
934
+
935
+ 1. **Stop, read, restart**: `LDA $DC0E / AND #$FE / STA $DC0E` to stop,
936
+ `LDA $DC04 / LDX $DC05`, then `LDA $DC0E / ORA #$01 / STA $DC0E` to
937
+ restart. Loses a few cycles of count.
938
+ 2. **Read high, read low, read high**: if the second high read matches
939
+ the first, the low read was valid. Otherwise retry.
940
+ 3. There is no atomic two-byte timer read on the 6526. (An earlier
941
+ version of this list said the 6526A revision added one; no datasheet
942
+ on this machine supports that, and the claim is withdrawn.)
943
+
944
+ ### Setting up a timer IRQ
945
+
946
+ ```asm
947
+ SEI
948
+ LDA #<period
949
+ STA $DC04
950
+ LDA #>period
951
+ STA $DC05 ; latch period
952
+ LDA #$11 ; START=1, PBON=0, RUNMODE=0 (continuous), LOAD=1
953
+ STA $DC0E ; LOAD + START Timer A
954
+ LDA #$81 ; SET mask, enable Timer A
955
+ STA $DC0D ; enable Timer A IRQ
956
+ CLI
957
+ ```
958
+
959
+ The LOAD strobe (bit 4) forces the counter to reload from the latch
960
+ without waiting for the next underflow — useful on initial setup.
961
+
962
+ ## IRQ/NMI control ($DC0D → IRQ, $DD0D → NMI)
963
+
964
+ The two ICRs share a bit layout but drive different CPU pins. The
965
+ sections above for `$DC0D` and `$DD0D` cover the bit details. Here's the
966
+ operational rules:
967
+
968
+ ### Acknowledgement
969
+
970
+ **An interrupt handler MUST read its CIA's `$xx0D` to acknowledge.**
971
+ The 6526 latches an asserted `/IRQ` line; it stays low until the ICR
972
+ read clears the flags. For CIA1, on the level-sensitive `/IRQ` pin, an
973
+ `RTI` without reading the ICR means the CPU immediately re-enters the
974
+ handler (measured in VICE x64sc 3.10: a CIA1 Timer B one-shot with a
975
+ `$0314` handler that never read `$DC0D` was entered 100 times, the cap
976
+ at which the handler finally acked).
977
+
978
+ A CIA2 NMI handler must read `$DD0D` too, but the failure mode is
979
+ silence, not re-entry: the 6510 takes NMI on a falling edge, so a line
980
+ left low cannot produce another one. Measured in the same run: CIA2
981
+ Timer A one-shot NMI with a handler that never reads `$DD0D` — entered
982
+ once; a second underflow while `/NMI` stayed low produced no NMI; one
983
+ `LDA $DD0D` and the next underflow produced one; in continuous mode 1
984
+ entry without ack against 99 with ack in the same window. (An earlier
985
+ version of this section said NMIs re-entered like IRQs and that RESTORE
986
+ needed separate handling — see Pitfalls.)
987
+
988
+ ### Mask-write semantics
989
+
990
+ The SET/CLEAR bit (bit 7) of a write decides whether the 1-bits in
991
+ bits 0-4 *set* or *clear* the mask:
992
+
993
+ - `STA $DC0D` with `A = $81`: enable Timer A interrupt.
994
+ - `STA $DC0D` with `A = $01`: disable Timer A interrupt.
995
+ - `STA $DC0D` with `A = $7F`: disable ALL interrupts.
996
+
997
+ A common bug is forgetting the SET/CLEAR bit, e.g. writing `$01`
998
+ intending to enable Timer A but actually disabling it.
999
+
1000
+ ### IRQ vector (CIA1)
1001
+
1002
+ CIA1's `/IRQ` reaches the 6510 `/IRQ` pin. With KERNAL ROM mapped in,
1003
+ the CPU jumps through `$FFFE-$FFFF` to `$FF48`, which:
1004
+
1005
+ 1. Pushes A, X, Y.
1006
+ 2. `TSX / LDA $0104,X / AND #$10` — reads the status byte pushed by the
1007
+ interrupt and tests the B flag; a BRK goes through `($0316)`, a
1008
+ hardware IRQ through `($0314)`. (`$01` is the 6510 port and is not
1009
+ involved; an earlier version of this page said `$FF48` read it.)
1010
+ 3. For IRQ, jumps through `($0314)` (default = `$EA31`, the KERNAL
1011
+ IRQ handler that scans keyboard and updates the jiffy clock).
1012
+ 4. KERNAL handler ends by reading `$DC0D` and `RTI`.
1013
+
1014
+ To install a custom IRQ, replace `$0314-$0315` with your handler's
1015
+ address. Your handler must read `$DC0D` to ack, then either chain to
1016
+ `$EA31` for full KERNAL services or `JMP $EA81` to skip the keyboard
1017
+ scan and just `RTI`.
1018
+
1019
+ ### NMI vector (CIA2 + RESTORE)
1020
+
1021
+ CIA2's `/IRQ` and the RESTORE key both reach the 6510 `/NMI` pin. The
1022
+ CPU jumps through `$FFFA-$FFFB` to `$FE43`, which is only
1023
+ `SEI / JMP ($0318)` — nothing is pushed there. The default `($0318)`
1024
+ target is `$FE47`, and that is where the register saves live (read from
1025
+ kernal-901227-03.bin at `$FE43`: `78 6C 18 03 48 8A 48 98 48`):
1026
+
1027
+ 1. `$FE47`: pushes A, X, Y (`PHA / TXA / PHA / TYA / PHA`) — after the
1028
+ vector, not before it, which is exactly why a bare `RTI` at `$0318`
1029
+ is valid.
1030
+ 2. Writes `$7F` to `$DD0D` (disable every CIA2 source) and reads
1031
+ `$DD0D` into Y, clearing the pending flags.
1032
+ 3. `BMI $FE72`: if a CIA2 source was pending, runs the RS-232 code (if
1033
+ an enabled CIA2 source — Timer A for transmit, Timer B or FLAG for
1034
+ receive — is pending; `$FE72` tests ICR bits 0, 1 and 4 only, never
1035
+ the SDR bit 3). RESTORE alone falls through the RS-232 dispatcher at
1036
+ `$FE72` with no enabled bit set, rewrites `$DD0D` from the enable
1037
+ mirror at `$02A1`, restores Y, X, A and `RTI`s (`$FEBC-$FEC1`).
1038
+ 4. Otherwise `JSR $FD02` (cartridge check: compares `$8004-$8008` with
1039
+ `CBM80`); if a cartridge answers, `JMP ($8002)`.
1040
+ 5. `JSR $F6BC` (UDTIM, which is what samples the keyboard row that
1041
+ `$FFE1` then reads from `$91`), then `JSR $FFE1` (STOP test); if STOP
1042
+ is not held, restore the registers and `RTI`.
1043
+ 6. RUN/STOP + RESTORE: `JSR $FD15` (RESTOR), `JSR $FDA3` (IOINIT),
1044
+ `JSR $E518` (CINT), `JMP ($A002)` — the BASIC warm-start vector.
1045
+
1046
+ There is no BRK test anywhere in it. (An earlier version of this page
1047
+ said `$FE43` saved A/X/Y before jumping through `($0318)`, that the
1048
+ handler checked for BRK first, and that the RS-232 code ran when the
1049
+ SDR triggered; a `$0318` handler written to that description would pull
1050
+ three registers nothing had pushed. Read from kernal-901227-03.bin
1051
+ `$FE43-$FEC1`.)
1052
+
1053
+ To install a custom NMI, replace `$0318-$0319`. Your NMI handler must
1054
+ read `$DD0D` to acknowledge a CIA2 NMI. A RESTORE press is one falling
1055
+ edge on `/NMI`, so one NMI, however long the pulse; there is nothing in
1056
+ the CIA to acknowledge for it, and the pulse width itself is not
1057
+ measured here. (Earlier text said the 555 held `/NMI` low for ~100 ms
1058
+ and that this needed handling; see Pitfalls for what a held-low line
1059
+ actually does.)
1060
+
1061
+ **Disabling RESTORE.** It cannot be done in `$DD0D`: the key's pulse never
1062
+ passes through the CIA, and the KERNAL handler above recognises RESTORE
1063
+ precisely by finding *no* CIA2 flag after its `LDY $DD0D` (the branch is
1064
+ `BMI` at `$FE54`, from the ROM bytes). Two things work: point `$0318` at a
1065
+ handler that ends in `RTI`, or hold an unacknowledged CIA2 NMI so `/NMI`
1066
+ never returns high — the 6510's NMI input is edge-triggered, so a line held
1067
+ low is not re-entered (the "NMI lock": measured in VICE x64sc 3.10, a
1068
+ second Timer A underflow with `/NMI` already low produced no second NMI;
1069
+ the key itself was not pressed in that run, so its case follows from the
1070
+ edge-triggered input rather than from a measurement). Both, with their
1071
+ costs and the RUN/STOP detail, are in `pitfalls/kernal-and-io.md` →
1072
+ `restore_nmi_not_maskable`.
1073
+
1074
+ ## VIC bank selection (CIA2 port A bits 0-1)
1075
+
1076
+ The VIC-II has a 14-bit address bus (16 KiB) but the C64 has 64 KiB of
1077
+ RAM. CIA2 port A bits 0-1 select which 16 KiB *bank* the VIC sees.
1078
+
1079
+ The bits are **inverted** between CIA2 and the VIC:
1080
+
1081
+ | `$DD00` bits 1-0 | VIC sees | Char ROM available? |
1082
+ |------------------|----------------|---------------------|
1083
+ | `11` | `$0000-$3FFF` | Yes — at `$1000-$1FFF` |
1084
+ | `10` | `$4000-$7FFF` | No (RAM only) |
1085
+ | `01` | `$8000-$BFFF` | Yes — at `$9000-$9FFF` |
1086
+ | `00` | `$C000-$FFFF` | No (RAM only) |
1087
+
1088
+ After RESET, both bits are `1`, so the VIC sees bank 0 (`$0000-$3FFF`)
1089
+ and the screen RAM at `$0400` is in the default location.
1090
+
1091
+ To switch the VIC to bank 1 while preserving the other port-A bits:
1092
+
1093
+ ```asm
1094
+ LDA $DD00
1095
+ AND #$FC ; clear bits 0-1
1096
+ ORA #$02 ; set bit 1, clear bit 0 (binary 10)
1097
+ STA $DD00
1098
+ ```
1099
+
1100
+ Then update `$D018` (VIC memory pointers) to tell the VIC where in the
1101
+ new 16 KiB bank to find screen RAM and the character set.
1102
+
1103
+ **Why the inversion?** It's a circuit-design optimization: bits 0-1 of
1104
+ CIA2 PA are inverted by the buffers between CIA2 and the VIC's
1105
+ VA14/VA15 inputs. The effect is that after reset (when CIA2 PA is `$FF`
1106
+ and bits 0-1 are high), the VIC sees bank 0. The all-high reset state
1107
+ of an open-collector / TTL bus matches the "no special change" default
1108
+ that makes screen RAM appear at `$0400` out of the box.
1109
+
1110
+ **Character ROM caveat**: the character ROM is mirrored only into VIC
1111
+ banks 0 and 2 (where addresses `$x000-$x1FFF` of the VIC's view map to
1112
+ the C64's `$D000-$DFFF` I/O area, which when accessed by the VIC
1113
+ returns the character ROM). In banks 1 and 3, the VIC sees pure RAM at
1114
+ that range. To use a custom charset in bank 1 or 3, copy the char ROM
1115
+ to RAM in the new bank first.
1116
+
1117
+ ## Serial bus (CIA2 port A bits 3-7)
1118
+
1119
+ The C64's serial-IEC bus is a 4-wire (plus ground) bus carrying ATN,
1120
+ CLOCK, DATA, and SRQ. ATN/CLOCK/DATA each have one driver per device
1121
+ plus a pull-up to +5V — a device drives the line by pulling it to
1122
+ ground (open-collector), and the line reads "high" when no device is
1123
+ pulling.
1124
+
1125
+ **CIA2 PA bit assignments for IEC:**
1126
+
1127
+ | Bit | Direction | IEC role |
1128
+ |-----|-----------|--------------------------------|
1129
+ | 3 | Output | ATN OUT (1 = drive ATN low) |
1130
+ | 4 | Output | CLK OUT (1 = drive CLK low) |
1131
+ | 5 | Output | DATA OUT (1 = drive DATA low) |
1132
+ | 6 | Input | CLK IN (0 = CLK pulled low by some device, 1 = released) |
1133
+ | 7 | Input | DATA IN (0 = DATA pulled low by some device, 1 = released) |
1134
+
1135
+ Note the asymmetry: writing `1` to bit 3 pulls ATN to ground, but
1136
+ reading `1` from bit 6 means CLK is *released* (high); reading `0`
1137
+ means it is being held low, either by this C64 or by a peripheral.
1138
+ (An earlier version of this table had the inputs inverted too — see
1139
+ `$DD00`.)
1140
+
1141
+ **ATN** (attention) is the talker/listener-select line. The C64
1142
+ pulls ATN low to broadcast a command (e.g. "drive 8, talk channel 0"),
1143
+ all devices listen, then C64 releases ATN and the talker starts
1144
+ clocking out data.
1145
+
1146
+ **Slow loader** (KERNAL-default IEC): software-driven on every bit,
1147
+ roughly 300–400 bytes per second on a 1541, about 2.5 ms per byte end
1148
+ to end — measured in VICE x64sc with true drive emulation, where an
1149
+ 8,002-byte KERNAL LOAD took 20.1 M PAL cycles (20.4 s, ~390 bytes/s),
1150
+ the same range the loader and IEC pages use. An earlier revision of
1151
+ this page said ~50 bytes per second, which its own 400 µs-per-bit
1152
+ figure contradicted. A 50 KB part takes over two minutes. Most
1153
+ games and demos replace the KERNAL loader with a fastloader that
1154
+ uses Timer A on CIA1 or CIA2 to pace high-speed bit transfers,
1155
+ either by reusing CLK/DATA in non-standard timing or by adding new
1156
+ wires through the serial port's extra pins.
1157
+
1158
+ **Fastloaders** typically take over the IRQ vector or NMI vector,
1159
+ saturate the bus with a custom 2-bit-per-clock protocol, and require
1160
+ matching code in the 1541 disk drive's 6502. Examples: JiffyDOS, Final
1161
+ Cartridge III, Action Replay, EXOS, Krill's loader.
1162
+
1163
+ The SRQ line is not used by the standard C64 KERNAL.
1164
+
1165
+ ## Pitfalls
1166
+
1167
+ - **CIA1 vs CIA2 confusion**: both chips have the same register layout,
1168
+ but `$DC00` is keyboard/joystick (drives IRQ) and `$DD00` is VIC
1169
+ bank/IEC (drives NMI). Mixing them up is the most common CIA bug —
1170
+ e.g. writing the VIC bank to `$DC00`, or enabling a "Timer A IRQ" on
1171
+ `$DD0D` when you wanted CIA1 (you'll get an NMI instead, which won't
1172
+ be masked by `SEI`).
1173
+ - **Timer latch order**: writing the low byte of a timer (`$DC04`,
1174
+ `$DC06`, `$DD04`, `$DD06`) only updates the latch's low byte; the
1175
+ counter is not reloaded until you write the high byte (which loads
1176
+ the counter from the latch if the timer is stopped) or strobe LOAD
1177
+ via bit 4 of the CRA/CRB. Writing high then low does NOT load the
1178
+ counter — you must finish with the high byte or with a LOAD strobe.
1179
+ - **An un-acknowledged CIA2 NMI silences NMI**: the hazard is lost
1180
+ NMIs, not re-entry. The 6510 takes NMI on a falling edge; a CIA2 NMI
1181
+ handler that returns without reading `$DD0D` leaves `/NMI` low, and
1182
+ no later CIA2 event can produce another edge until something reads
1183
+ the ICR. Measured in VICE x64sc 3.10: CIA2 Timer A one-shot NMI with a
1184
+ handler that never reads `$DD0D` — entered once; a second underflow
1185
+ while `/NMI` stayed low produced no NMI; one `LDA $DD0D` and the next
1186
+ underflow produced one; in continuous mode 1 entry without ack
1187
+ against 99 with ack in the same window. The demo trick to kill
1188
+ RESTORE is exactly this: fire a CIA2 Timer A one-shot NMI into a
1189
+ handler that never reads `$DD0D`, and the line stays low. RESTORE
1190
+ itself was not measured here (VICE headless cannot press it); that a
1191
+ held-low CIA2 line also swallows RESTORE presses is the standard
1192
+ scene trick and follows from the shared pin, not a measurement. The
1193
+ other option, pointing `$0318` at an `RTI`, still *takes* the NMI —
1194
+ the 7-cycle interrupt sequence, `SEI`, `JMP ($0318)` and the `RTI`,
1195
+ about 20 cycles of jitter per press with the ROM in; with the KERNAL
1196
+ banked out it is `$FFFA/$FFFB` that must point at the `RTI` — whereas
1197
+ the held-low trick prevents the interrupt from being taken at all.
1198
+ (An earlier version of this bullet described NMI re-entrancy on a
1199
+ ~100 ms RESTORE pulse and offered `LDA #$00 / STA $DD0E` or counting
1200
+ out the pulse with Timer A as workarounds; the mechanism was the IRQ
1201
+ one, and neither workaround touches the ICR — measured: that handler
1202
+ leaves the line low and the next event is still lost.)
1203
+ The dispatch table, the 20-cycle cost and the lock, measured, are in
1204
+ `pitfalls/kernal-and-io.md` → `restore_nmi_not_maskable`.
1205
+ - **Reading a running timer gives torn values**: low byte decrements
1206
+ between the two-byte read. Stop the timer before reading, or use the
1207
+ read-high / read-low / re-read-high consistency loop. (An earlier
1208
+ version of this bullet said the 6526A added a latched-read mode; it
1209
+ is withdrawn, unsupported by anything on this machine.)
1210
+ - **Forgetting to acknowledge an IRQ**: a custom IRQ handler must read
1211
+ `$DC0D` (CIA1) or `$DD0D` (CIA2) to clear the pending flags and
1212
+ release the `/IRQ`/`/NMI` line. Without this a CIA1 `/IRQ` handler
1213
+ will re-enter immediately after `RTI` and the CPU will appear to hang
1214
+ in the handler; for CIA2 the symptom is the opposite: NMIs stop
1215
+ arriving (see the bullet above). (Earlier text gave the re-entry
1216
+ symptom for both chips.)
1217
+ - **ICR write SET/CLEAR confusion**: bit 7 of an ICR write is the
1218
+ SET/CLEAR control bit, not an interrupt-enable. `STA $DC0D` with
1219
+ `A = $01` *disables* Timer A IRQ; you want `$81` to enable it. A
1220
+ common pattern that confuses this is "write `$7F` to mask all" — `$7F`
1221
+ has bit 7 = 0 (CLEAR), bits 0-6 = 1 (every source) → "clear masks for
1222
+ all sources" → disable all. Conversely `$FF` would *enable* all
1223
+ sources.
1224
+ - **Keyboard scan vs joystick 1**: the KERNAL scanner reads rows; a
1225
+ joystick in port 1 grounds row lines and is decoded as keys — DOWN as
1226
+ LEFT-ARROW, LEFT as CTRL+; (cursor right), RIGHT as `2`, FIRE as
1227
+ shift-space; UP is swallowed by the scanner's final no-column pass.
1228
+ Joystick 2 alone types nothing, but held together with a column-0 key
1229
+ it moves that key to column 7 (RETURN reads as LEFT-ARROW). If your
1230
+ program uses the KERNAL scanner and a joystick, read the joystick
1231
+ from a raster or timer interrupt with the scanner disabled, or clear
1232
+ the buffer. (Earlier text blamed joy 2 for a phantom INST/DEL and
1233
+ said the contention could stress the CIA on early boards; wrong port
1234
+ and wrong key — see the SCNKEY reading in the keyboard section — and
1235
+ the electrical claim has no source in this repo, so it is dropped.)
1236
+ - **VIC bank bits are inverted**: setting `$DD00` bits 1-0 to `00`
1237
+ selects bank 3 (`$C000-$FFFF`), not bank 0. The bit-to-bank table is
1238
+ in the VIC bank section.
1239
+ - **DDR before data**: writing `$DD00` to change VIC bank has no effect
1240
+ if `$DD02` doesn't have bits 0-1 set to output. After RESET the
1241
+ KERNAL sets `$DD02 = $3F` which covers VIC bank + IEC outputs, but
1242
+ if your code clobbered `$DD02` you must restore it.
1243
+ - **TOD pin needs AC mains**: the TOD clock counts the 50/60 Hz AC
1244
+ zero-crossing from the C64's power supply. In emulators that don't
1245
+ emulate the mains line (most), the TOD clock is faked from phi-2 or
1246
+ doesn't tick at all. Don't rely on TOD for precise wall-clock timing
1247
+ in cross-emulator code.
1248
+ - **TOD latch on read**: reading `$DC0B` (or `$DD0B`, hours) latches
1249
+ all four TOD registers so a multi-byte read is coherent; reading
1250
+ `$DC08` (tenths) releases it. If you read hours and then never read
1251
+ tenths, the TOD registers appear frozen on subsequent reads while the
1252
+ clock keeps counting underneath (earlier text had tenths latching and
1253
+ hours releasing; measured in VICE x64sc, PAL and NTSC). The probe and the write-side twin —
1254
+ hours-write stops the clock, tenths-write starts it — are in
1255
+ `pitfalls/cia.md` (`tod_read_order_latch`).
1256
+ - **TOD BCD**: TOD registers are BCD-encoded. Code that increments
1257
+ them via `INC` will produce invalid BCD digits (e.g. `$09` + 1 =
1258
+ `$0A`, not `$10`). Either write decoded values or use ADC with the
1259
+ decimal-mode flag.
1260
+ - **CIA chip revision differences**: original 6526 and the later 6526A
1261
+ / 8521 have subtly different behavior on edge cases: latch loading
1262
+ timing, TOD start glitch, and serial-shift-register synchronization.
1263
+ Demoscene code that exploits cycle-exact CIA behavior may break on a
1264
+ different chip revision. The "Lorenz CIA test suite" is the gold
1265
+ standard for testing whether your emulator or replacement chip
1266
+ matches a real 6526.
1267
+ - **NMI cannot be masked by SEI**: `SEI` masks the 6510 `/IRQ` line,
1268
+ not `/NMI`. Code that disables CIA1 IRQs with `SEI` to do a
1269
+ time-critical operation can still be interrupted by a CIA2 NMI or a
1270
+ RESTORE press. To truly disable all interrupts, mask CIA2's ICR
1271
+ (`STA $DD0D` with `A = $7F`) AND set `I` AND ideally point
1272
+ `($0318)` at a `RTI` to absorb a RESTORE NMI.
1273
+ - **The "all-output trick" on $DC02**: setting `$DC02 = $FF` and
1274
+ `$DC00 = $00` drives all eight keyboard columns low. Reading
1275
+ `$DC01` then returns the OR of every pressed-key row — useful for
1276
+ fast "any key pressed?" tests but doesn't tell you *which* key.
1277
+ - **Joystick port 1 is on port B, port 2 is on port A**: this is the
1278
+ most-warned pitfall in C64 game-dev tutorials, and yet every new C64
1279
+ coder gets bitten by it. Joy 2 on `$DC00`, joy 1 on `$DC01`.
1280
+
1281
+ <!-- doc-type: hardware-reference -->