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,1714 @@
1
+ ---
2
+ chip: VIC-II
3
+ ---
4
+
5
+ # VIC-II Hardware Reference
6
+
7
+ ## Overview
8
+
9
+ The VIC-II (Video Interface Chip II, MOS 6567/6569/8562/8565) is the
10
+ display generator of the Commodore 64. It produces a composite-video signal
11
+ 40 columns wide by 25 rows tall, with eight hardware sprites, four
12
+ selectable display modes, a per-cell color attribute system, and a raster
13
+ counter that can interrupt the CPU at any visible scanline. Almost every
14
+ visual trick the C64 is known for — smooth scrolling, FLD/FLI, sprite
15
+ multiplexing, side borders open, 64-pixel-tall character cells — leans on
16
+ its tight, documented coupling between the chip and the 6510 CPU bus.
17
+
18
+ The VIC-II shares the bus with the 6510. During each PAL raster line the
19
+ chip takes the bus for itself on the first half of every cycle (phi1) to
20
+ fetch pixel data and on roughly five extra cycles for sprite DMA, while
21
+ the CPU is allowed to run on the second half (phi2). Once per text row —
22
+ 25 times every frame, every eighth raster line (51, 59, ..., 243 with the
23
+ default YSCROLL = 3; measured in VICE x64sc on PAL and NTSC alike) — the
24
+ chip needs an entire row of character pointers from screen RAM and steals
25
+ 40 consecutive cycles from the CPU: the *badline*. (An earlier revision of
26
+ this page said "eight times"; eight is the spacing in lines, not the
27
+ count.) This single quirk is responsible for most of the cycle-exact
28
+ discipline a C64 demo coder lives by. See the
29
+ [Raster system](#raster-system) section.
30
+
31
+ ### Chip variants
32
+
33
+ The VIC-II shipped in four primary variants. The PAL parts have an extra
34
+ line of vertical resolution and a slower system clock; the NTSC parts run
35
+ faster but have less vertical real estate. The HMOS-II "8000-series"
36
+ revisions are functionally identical to the original NMOS parts in the
37
+ common cases but differ in DC characteristics, color shades, and a handful
38
+ of timing edges that only matter to demo coders.
39
+
40
+ | Variant | Region | Process | Lines/frame | Cycles/line | Master clock | System (phi2) |
41
+ |---------|--------|---------|-------------|-------------|--------------|---------------|
42
+ | 6569 | PAL | NMOS | 312 | 63 | 17.734472 MHz / 18 | 0.985 MHz |
43
+ | 6567 R56A | NTSC | NMOS | 262 | 64 | 14.318181 MHz / 14 | 1.022 MHz |
44
+ | 6567 R8 / R9 | NTSC | NMOS | 263 | 65 | 14.318181 MHz / 14 | 1.022 MHz |
45
+ | 8565 | PAL | HMOS-II | 312 | 63 | 17.734472 MHz / 18 | 0.985 MHz |
46
+ | 8562 | NTSC | HMOS-II | 263 | 65 | 14.318181 MHz / 14 | 1.022 MHz |
47
+
48
+ Notes on variants:
49
+
50
+ - 6569 PAL machines run at 50.125 Hz refresh; the 6567 NTSC at ~59.83 Hz.
51
+ - The 6567 R56A is rare — it has only 262 lines and 64 cycles per line,
52
+ one fewer than the more common R8. Most NTSC C64s use R8.
53
+ - 8565 (PAL) / 8562 (NTSC) are the late-model HMOS-II parts found in the
54
+ C64C. The C128 does not carry them: its VIC is the VIC-IIe (MOS 8564 /
55
+ 8566), a different chip with extra registers at $D02F–$D030 — see the
56
+ $D02F entry below. (An earlier revision of this page listed the C128
57
+ alongside the C64C here, contradicting its own $D02F entry.)
58
+ They are pin-compatible with the 6569/6567 but produce slightly different
59
+ colors (notably grays and reds) and have sharper color transitions on
60
+ composite. Some sprite-crunch and color-DMA edge cases differ.
61
+ - All variants share the same register map and the same 47 documented
62
+ registers at $D000–$D02E plus a 48th unused address $D02F.
63
+
64
+ ### What this chip does for software
65
+
66
+ - Generates the picture: characters, bitmaps, or a mix of modes.
67
+ - Provides eight 24×21 hardware sprites with optional 2×/1×/×1 expansion,
68
+ multicolor mode, and per-sprite-pair priority.
69
+ - Drives the IRQ line on configurable conditions (raster match, sprite
70
+ collisions, light pen, sprite/background collisions).
71
+ - Owns 16 KB of address space (the VIC bank), selected by CIA2 port A.
72
+ - Reads color attributes from a dedicated 1024×4-bit Color RAM at $D800.
73
+
74
+ The CPU sees the VIC-II as a 64-byte register window at $D000–$D03F. The
75
+ last 17 addresses ($D02F–$D03F) are unimplemented: they read $FF and
76
+ ignore writes (measured in VICE x64sc; an earlier version of this page
77
+ called them images of $D000–$D00F, which they are not). The Color RAM at
78
+ $D800–$DBFF is logically
79
+ part of the VIC subsystem even though it is implemented in a separate
80
+ 2114-family static RAM.
81
+
82
+ ## Quick reference
83
+
84
+ All 47 documented registers plus the one unused address are listed below.
85
+ Each register has a full H3 entry later in the document with bit layout
86
+ and behavioral notes.
87
+
88
+ | Addr | Dec | Name | Description | Access |
89
+ |-------|-------|--------|--------------------------------------|--------|
90
+ | $D000 | 53248 | M0X | Sprite 0 X position (low 8 bits) | RW |
91
+ | $D001 | 53249 | M0Y | Sprite 0 Y position | RW |
92
+ | $D002 | 53250 | M1X | Sprite 1 X position (low 8 bits) | RW |
93
+ | $D003 | 53251 | M1Y | Sprite 1 Y position | RW |
94
+ | $D004 | 53252 | M2X | Sprite 2 X position (low 8 bits) | RW |
95
+ | $D005 | 53253 | M2Y | Sprite 2 Y position | RW |
96
+ | $D006 | 53254 | M3X | Sprite 3 X position (low 8 bits) | RW |
97
+ | $D007 | 53255 | M3Y | Sprite 3 Y position | RW |
98
+ | $D008 | 53256 | M4X | Sprite 4 X position (low 8 bits) | RW |
99
+ | $D009 | 53257 | M4Y | Sprite 4 Y position | RW |
100
+ | $D00A | 53258 | M5X | Sprite 5 X position (low 8 bits) | RW |
101
+ | $D00B | 53259 | M5Y | Sprite 5 Y position | RW |
102
+ | $D00C | 53260 | M6X | Sprite 6 X position (low 8 bits) | RW |
103
+ | $D00D | 53261 | M6Y | Sprite 6 Y position | RW |
104
+ | $D00E | 53262 | M7X | Sprite 7 X position (low 8 bits) | RW |
105
+ | $D00F | 53263 | M7Y | Sprite 7 Y position | RW |
106
+ | $D010 | 53264 | MSIGX | Sprite X position MSBs (bit 8) | RW |
107
+ | $D011 | 53265 | SCROLY | Screen control register 1 / Y scroll | RW |
108
+ | $D012 | 53266 | RASTER | Raster line counter / compare | RW |
109
+ | $D013 | 53267 | LPENX | Light pen X position (latched) | R |
110
+ | $D014 | 53268 | LPENY | Light pen Y position (latched) | R |
111
+ | $D015 | 53269 | SPENA | Sprite enable | RW |
112
+ | $D016 | 53270 | SCROLX | Screen control register 2 / X scroll | RW |
113
+ | $D017 | 53271 | YXPAND | Sprite Y expansion | RW |
114
+ | $D018 | 53272 | VMCSB | Memory pointers (video matrix / char)| RW |
115
+ | $D019 | 53273 | VICIRQ | Interrupt status / latch | RW |
116
+ | $D01A | 53274 | IRQMSK | Interrupt mask / enable | RW |
117
+ | $D01B | 53275 | SPBGPR | Sprite-to-background priority | RW |
118
+ | $D01C | 53276 | SPMC | Sprite multicolor enable | RW |
119
+ | $D01D | 53277 | XXPAND | Sprite X expansion | RW |
120
+ | $D01E | 53278 | SPSPCL | Sprite-sprite collision | R |
121
+ | $D01F | 53279 | SPBGCL | Sprite-background collision | R |
122
+ | $D020 | 53280 | EXTCOL | Border color | RW |
123
+ | $D021 | 53281 | BGCOL0 | Background color 0 | RW |
124
+ | $D022 | 53282 | BGCOL1 | Background color 1 (MCM/ECM) | RW |
125
+ | $D023 | 53283 | BGCOL2 | Background color 2 (MCM/ECM) | RW |
126
+ | $D024 | 53284 | BGCOL3 | Background color 3 (ECM only) | RW |
127
+ | $D025 | 53285 | SPMC0 | Sprite multicolor shared 0 | RW |
128
+ | $D026 | 53286 | SPMC1 | Sprite multicolor shared 1 | RW |
129
+ | $D027 | 53287 | SP0COL | Sprite 0 individual color | RW |
130
+ | $D028 | 53288 | SP1COL | Sprite 1 individual color | RW |
131
+ | $D029 | 53289 | SP2COL | Sprite 2 individual color | RW |
132
+ | $D02A | 53290 | SP3COL | Sprite 3 individual color | RW |
133
+ | $D02B | 53291 | SP4COL | Sprite 4 individual color | RW |
134
+ | $D02C | 53292 | SP5COL | Sprite 5 individual color | RW |
135
+ | $D02D | 53293 | SP6COL | Sprite 6 individual color | RW |
136
+ | $D02E | 53294 | SP7COL | Sprite 7 individual color | RW |
137
+ | $D02F | 53295 | — | Unused — reads $FF, writes ignored | R |
138
+
139
+ Addresses $D02F–$D03F are unused and read $FF. The 64-byte window is
140
+ repeated 16 times across $D000–$D3FF (15 further images at $D040–$D3FF).
141
+ Code should never rely on the mirrors — they are an accident of incomplete
142
+ address decoding.
143
+
144
+ ### Color RAM and the wider VIC address window
145
+
146
+ | Range | Length | Description |
147
+ |---------------|--------|------------------------------------------|
148
+ | $D000–$D02E | 47 B | VIC-II registers |
149
+ | $D02F–$D03F | 17 B | Unused — read $FF, writes ignored |
150
+ | $D040–$D3FF | 960 B | 15 further mirrors of $D000–$D03F |
151
+ | $D800–$DBFF | 1024 B | Color RAM (4 bits per cell, upper nibble reads as garbage) |
152
+
153
+ The Color RAM is described in detail in [Color RAM](#color-ram).
154
+
155
+ ## Register reference
156
+
157
+ Each register address in $D000–$D02F gets its own H3 below in the canonical
158
+ conventions format. Bit fields are described inline. Where reset behavior
159
+ differs from "cleared to 0 on reset", that is called out explicitly.
160
+
161
+ ### $D000 — M0X — Sprite 0 X position (RW)
162
+
163
+ **Chip:** VIC-II
164
+
165
+ Low 8 bits of sprite 0 horizontal position. Bit 8 of the X position lives
166
+ in $D010 bit 0. Coordinate space is 0–511 with the visible display roughly
167
+ spanning 24..343 in non-CSEL-trimmed mode; X = 0 is well off the left edge
168
+ of the visible screen. Write at any time — the new position takes effect
169
+ the next time the sprite's DMA fetch occurs.
170
+
171
+ ### $D001 — M0Y — Sprite 0 Y position (RW)
172
+
173
+ **Chip:** VIC-II
174
+
175
+ Sprite 0 vertical position (8 bits, 0–255). The register holds the raster
176
+ line on which the sprite's DMA is switched on; its first pixel row is
177
+ displayed on the NEXT line, so the sprite occupies raster lines
178
+ Y + 1 .. Y + 21 (Y + 1 .. Y + 42 if vertically expanded via $D017). Y = 50
179
+ therefore puts the top of the sprite on line 51, the first line of the
180
+ 25-row text display, and Y = 249 shows a single row on line 250 before the
181
+ lower border covers the rest. An earlier revision of this entry said
182
+ Y .. Y + 20, one line too high. Measured in VICE x64sc 3.10 on the PAL
183
+ C64C (VIC-II 8565, VICE's default) and NTSC 6567R8 models (an earlier version said the VICE PAL run was a 6569; `x64sc -default` is the C64C: 8565, 8580, 8521); the DMA-on-line-Y / display-on-line-Y+1
184
+ mechanism is from Bauer's VIC article, not measured here.
185
+
186
+ ### $D002 — M1X — Sprite 1 X position (RW)
187
+
188
+ **Chip:** VIC-II
189
+
190
+ Sprite 1 horizontal position, low 8 bits. MSB in $D010 bit 1.
191
+
192
+ ### $D003 — M1Y — Sprite 1 Y position (RW)
193
+
194
+ **Chip:** VIC-II
195
+
196
+ Sprite 1 vertical position.
197
+
198
+ ### $D004 — M2X — Sprite 2 X position (RW)
199
+
200
+ **Chip:** VIC-II
201
+
202
+ Sprite 2 horizontal position, low 8 bits. MSB in $D010 bit 2.
203
+
204
+ ### $D005 — M2Y — Sprite 2 Y position (RW)
205
+
206
+ **Chip:** VIC-II
207
+
208
+ Sprite 2 vertical position.
209
+
210
+ ### $D006 — M3X — Sprite 3 X position (RW)
211
+
212
+ **Chip:** VIC-II
213
+
214
+ Sprite 3 horizontal position, low 8 bits. MSB in $D010 bit 3.
215
+
216
+ ### $D007 — M3Y — Sprite 3 Y position (RW)
217
+
218
+ **Chip:** VIC-II
219
+
220
+ Sprite 3 vertical position.
221
+
222
+ ### $D008 — M4X — Sprite 4 X position (RW)
223
+
224
+ **Chip:** VIC-II
225
+
226
+ Sprite 4 horizontal position, low 8 bits. MSB in $D010 bit 4.
227
+
228
+ ### $D009 — M4Y — Sprite 4 Y position (RW)
229
+
230
+ **Chip:** VIC-II
231
+
232
+ Sprite 4 vertical position.
233
+
234
+ ### $D00A — M5X — Sprite 5 X position (RW)
235
+
236
+ **Chip:** VIC-II
237
+
238
+ Sprite 5 horizontal position, low 8 bits. MSB in $D010 bit 5.
239
+
240
+ ### $D00B — M5Y — Sprite 5 Y position (RW)
241
+
242
+ **Chip:** VIC-II
243
+
244
+ Sprite 5 vertical position.
245
+
246
+ ### $D00C — M6X — Sprite 6 X position (RW)
247
+
248
+ **Chip:** VIC-II
249
+
250
+ Sprite 6 horizontal position, low 8 bits. MSB in $D010 bit 6.
251
+
252
+ ### $D00D — M6Y — Sprite 6 Y position (RW)
253
+
254
+ **Chip:** VIC-II
255
+
256
+ Sprite 6 vertical position.
257
+
258
+ ### $D00E — M7X — Sprite 7 X position (RW)
259
+
260
+ **Chip:** VIC-II
261
+
262
+ Sprite 7 horizontal position, low 8 bits. MSB in $D010 bit 7.
263
+
264
+ ### $D00F — M7Y — Sprite 7 Y position (RW)
265
+
266
+ **Chip:** VIC-II
267
+
268
+ Sprite 7 vertical position.
269
+
270
+ ### $D010 — MSIGX — Sprite X position MSBs (RW)
271
+
272
+ **Chip:** VIC-II
273
+
274
+ Bit 8 of each sprite's X coordinate. Read-modify-write to move a single
275
+ sprite across the X=255 boundary.
276
+
277
+ | Bit | Name | Description |
278
+ |-----|------|--------------------------------------|
279
+ | 7 | M7X8 | Sprite 7 X position MSB |
280
+ | 6 | M6X8 | Sprite 6 X position MSB |
281
+ | 5 | M5X8 | Sprite 5 X position MSB |
282
+ | 4 | M4X8 | Sprite 4 X position MSB |
283
+ | 3 | M3X8 | Sprite 3 X position MSB |
284
+ | 2 | M2X8 | Sprite 2 X position MSB |
285
+ | 1 | M1X8 | Sprite 1 X position MSB |
286
+ | 0 | M0X8 | Sprite 0 X position MSB |
287
+
288
+ When you want to position a sprite at X = 320 (center-ish), write $40 to
289
+ the sprite's low-byte X register and OR the corresponding bit into $D010.
290
+
291
+ ### $D011 — SCROLY — Screen control register 1 (RW)
292
+
293
+ **Chip:** VIC-II
294
+
295
+ The most-poked register on the C64. Combines the Y-scroll fine offset,
296
+ display geometry, the master enable, the mode bits, and the raster compare
297
+ MSB.
298
+
299
+ | Bit | Name | Description |
300
+ |-----|-------|----------------------------------------------------|
301
+ | 7 | RST8 | Bit 8 of the raster compare value (read: raster bit 8) |
302
+ | 6 | ECM | Extended background color mode enable |
303
+ | 5 | BMM | Bitmap mode enable |
304
+ | 4 | DEN | Display enable (must be set on raster line $30 to allow badlines for the frame) |
305
+ | 3 | RSEL | Row select: 1 = 25 rows / 200 px tall, 0 = 24 rows / 192 px |
306
+ | 2-0 | YSCROLL | Vertical fine scroll, 0–7 lines |
307
+
308
+ Reading $D011 returns the *current* raster line's bit 8 in bit 7 (it is
309
+ not the value last written; it is overlaid with the live raster MSB). To
310
+ program a raster IRQ at line ≥ 256, set $D012 to (line & $FF), read
311
+ $D011, clear bit 7, OR in ((line >> 8) & 1) << 7, and write it back.
312
+
313
+ DEN must be set at some point during raster line $30 (decimal 48) for
314
+ badlines to be enabled for the frame. The chip accepts the bit on any cycle
315
+ of that line (Bauer §3.5, not measured cycle-by-cycle here); in VICE x64sc
316
+ a write landing anywhere from about cycle 18 to cycle 57 of line $30 still
317
+ enabled every badline of the frame, and the same write on line $31 enabled
318
+ none. An earlier version of this page said DEN had to be 1 during cycle 14
319
+ specifically. Holding DEN clear for the whole of line $30 removes every
320
+ badline of that frame. Clearing DEN does not show the background colour:
321
+ the vertical border flip-flop is reset only if DEN is set at cycle 63 of
322
+ the top comparison line (51 with RSEL = 1, 55 with RSEL = 0), so with DEN
323
+ clear across that line the border colour ($D020) covers the whole screen,
324
+ sprites hidden under it — measured in VICE x64sc; an earlier version of
325
+ this page said the interior turned to the background colour. The two
326
+ samples are independent: DEN clear on line $30 but set again before line
327
+ 51 gives a frame with no badlines whose window still opens on idle-state
328
+ graphics (BGCOL0 where $3FFF is 0, sprites visible); DEN set on line $30
329
+ but clear across line 51 gives a frame with badlines whose window never
330
+ opens. Clearing DEN after line $30 does not stop the remaining badlines
331
+ of that frame, and clearing it after line 51 has no effect at all until
332
+ the next frame — display state, border and sprites all continue
333
+ (measured in VICE x64sc).
334
+
335
+ YSCROLL = 3 is the default; the kernel boot screen uses this. The badline
336
+ condition is "current raster ≥ $30, ≤ $F7, and bottom 3 bits == YSCROLL,
337
+ and DEN was set on line $30". Changing YSCROLL therefore shifts every
338
+ badline by the corresponding number of lines.
339
+
340
+ ### $D012 — RASTER — Raster line counter / compare (RW)
341
+
342
+ **Chip:** VIC-II
343
+
344
+ Reading returns the low 8 bits of the current raster line; the high bit
345
+ lives in $D011 bit 7. Writing programs the *compare* value for raster
346
+ interrupts (low 8 bits); the MSB to compare lives in $D011 bit 7.
347
+
348
+ The raster line counter increments at the start of cycle 1 of each line
349
+ except for line 0, where it increments one cycle later — this is the
350
+ single "wrong-by-one-cycle" timing quirk that occasionally bites tightly
351
+ written stable-raster code. See the [Raster system](#raster-system).
352
+
353
+ PAL line range: 0..311. NTSC R8 line range: 0..262. NTSC R56A: 0..261.
354
+
355
+ ### $D013 — LPENX — Light pen X position (R)
356
+
357
+ **Chip:** VIC-II
358
+
359
+ X coordinate latched the last time the LP pin (CIA1 PB4) went low. Value
360
+ is X/2; the chip's horizontal counter divided by 2 to fit 8 bits. The
361
+ light pen latch fires *once per frame*; reads after the first latch return
362
+ the same value until the next vertical blanking interval. With no light
363
+ pen attached this register reflects whatever spurious LP events the
364
+ joystick fire button on port 1 caused (joystick fire on port 1 is tied to
365
+ the LP pin).
366
+
367
+ ### $D014 — LPENY — Light pen Y position (R)
368
+
369
+ **Chip:** VIC-II
370
+
371
+ Y coordinate latched at the same instant as $D013. Full 8-bit raster line
372
+ number; the latch only captures the bottom 8 bits so lines ≥ 256 wrap.
373
+
374
+ ### $D015 — SPENA — Sprite enable (RW)
375
+
376
+ **Chip:** VIC-II
377
+
378
+ Per-sprite enable. Bit n enables sprite n. A disabled sprite still has its
379
+ DMA pointer fetched (one p-access per line), but the three s-accesses are
380
+ skipped, freeing the CPU to use those cycles. Clearing this register
381
+ disables all eight sprites simultaneously.
382
+
383
+ | Bit | Name | Description |
384
+ |-----|------|-----------------------|
385
+ | 7-0 | Mn E | Sprite n enable (bit n)|
386
+
387
+ ### $D016 — SCROLX — Screen control register 2 (RW)
388
+
389
+ **Chip:** VIC-II
390
+
391
+ The X-scroll, column-select, and MCM toggle live here. Bits 6 and 7 read
392
+ back as 1 on every variant — they are unimplemented in this register
393
+ even though some sources include them in masks.
394
+
395
+ | Bit | Name | Description |
396
+ |-----|-------|---------------------------------------------------|
397
+ | 7,6 | — | Unused (always read 1) |
398
+ | 5 | RES | Hardware reset of VIC-II video shift register (reserved; never works as intended on production chips) |
399
+ | 4 | MCM | Multicolor mode enable |
400
+ | 3 | CSEL | Column select: 1 = 40 cols / 320 px wide, 0 = 38 cols / 304 px |
401
+ | 2-0 | XSCROLL | Horizontal fine scroll, 0–7 pixels |
402
+
403
+ Setting CSEL = 0 narrows the window from X 24–343 to X 31–334, 16 pixels
404
+ in all: 7 extra border pixels on the left and 9 on the right (measured in
405
+ VICE x64sc; an earlier version of this page said 8 on each side). Those
406
+ two strips are where the *border* is drawn but the chip's display
407
+ sequencer never starts; this is the side-borders-open exploit's foothold.
408
+
409
+ ### $D017 — YXPAND — Sprite Y expansion (RW)
410
+
411
+ **Chip:** VIC-II
412
+
413
+ Per-sprite vertical 2× expansion. When bit n is set, sprite n renders each
414
+ of its 21 lines twice for a total of 42 visible lines. The expansion
415
+ *toggle* flag is internal; if you clear $D017 on the raster line that the
416
+ chip would normally apply the toggle, the famous "sprite crunch" bug
417
+ fires — see [Pitfalls](#pitfalls).
418
+
419
+ | Bit | Name | Description |
420
+ |-----|------|-----------------------|
421
+ | 7-0 | Mn YE| Sprite n Y expansion |
422
+
423
+ ### $D018 — VMCSB — Memory pointers (RW)
424
+
425
+ **Chip:** VIC-II
426
+
427
+ Selects, within the current VIC bank, the base addresses of the video
428
+ matrix and either the character generator (text modes) or bitmap (bitmap
429
+ modes).
430
+
431
+ | Bit | Name | Description |
432
+ |-----|-------|----------------------------------------------------|
433
+ | 7-4 | VM | Video matrix base / 1024 within the VIC bank (bits 0–3 of pointer) |
434
+ | 3-1 | CB | In text mode: character generator base / 2048. In bitmap mode: bit 2 selects $0000 or $2000 within the bank |
435
+ | 0 | — | Unused (reads 1) |
436
+
437
+ Computed addresses inside the VIC bank:
438
+
439
+ ```
440
+ video matrix base = (VM3..VM0) * $0400 ; 16 possible positions
441
+ char base (text) = (CB2..CB0) * $0800 ; 8 possible positions
442
+ bitmap base = (CB2) * $2000 ; 2 possible positions
443
+ ```
444
+
445
+ The default kernal screen is at $0400 (VM = %0001 = 1) with charrom
446
+ shadowed at $1000 (CB = %010 = 2) in bank 0.
447
+
448
+ Important: the character generator ROM only appears mirrored into VIC
449
+ banks 0 and 2 at addresses $1000–$1FFF and $9000–$9FFF respectively. In
450
+ banks 1 and 3 you must place your own character set in RAM. See
451
+ [Memory access](#memory-access).
452
+
453
+ ### $D019 — VICIRQ — Interrupt status / latch (RW)
454
+
455
+ **Chip:** VIC-II
456
+
457
+ Latched IRQ source flags. Bits 7 and 4–6 ordinarily read 0/1 depending
458
+ on chip state. To acknowledge an IRQ you write a 1 to the corresponding
459
+ latch bit (this is the canonical "write to clear" pattern).
460
+
461
+ | Bit | Name | Description |
462
+ |-----|------|---------------------------------------------------|
463
+ | 7 | IRQ | 1 = at least one enabled source is pending (IRQ line asserted) |
464
+ | 6-4 | — | Unused, read 1 |
465
+ | 3 | ILP | Light pen latch fired |
466
+ | 2 | IMMC | Sprite-sprite collision latched |
467
+ | 1 | IMBC | Sprite-background collision latched |
468
+ | 0 | IRST | Raster compare matched |
469
+
470
+ Acknowledging is mandatory: until you clear the latch bit, the chip will
471
+ continue asserting IRQ at the start of every cycle.
472
+
473
+ ### $D01A — IRQMSK — Interrupt mask / enable (RW)
474
+
475
+ **Chip:** VIC-II
476
+
477
+ Per-source IRQ enable. Mirrors the layout of $D019 bits 3–0. Setting a bit
478
+ allows the corresponding latch in $D019 to assert the IRQ output.
479
+
480
+ | Bit | Name | Description |
481
+ |-----|------|--------------------------------------|
482
+ | 7-4 | — | Unused |
483
+ | 3 | ELP | Enable light pen IRQ |
484
+ | 2 | EMMC | Enable sprite-sprite collision IRQ |
485
+ | 1 | EMBC | Enable sprite-background collision IRQ |
486
+ | 0 | ERST | Enable raster IRQ |
487
+
488
+ Reset value is 0 (all disabled), and the KERNAL leaves it there: its VIC
489
+ init table ($ECB9, copied to $D000–$D02E by the loop at $E5A8) writes $00
490
+ to $D01A, and nothing else in the KERNAL writes the register — after boot
491
+ it reads $F0 (measured in VICE x64sc; bits 7–4 read as 1). The system tick
492
+ is CIA1 timer A ($FDDD loads $4025 PAL / $4295 NTSC, $FF6E enables it with
493
+ $81 → $DC0D), not a raster IRQ. The compare line the KERNAL does leave is
494
+ 311 ($D011 = $9B, $D012 = $37), which CINT uses once to tell PAL from NTSC
495
+ through the $D019 latch. (An earlier version of this page said the KERNAL
496
+ enabled a raster IRQ at line 0 for the tick; it does not.)
497
+
498
+ ### $D01B — SPBGPR — Sprite-to-background priority (RW)
499
+
500
+ **Chip:** VIC-II
501
+
502
+ Per-sprite priority versus foreground pixels. Bit n = 0: sprite n appears
503
+ in front of foreground graphics (the default). Bit n = 1: sprite n appears
504
+ *behind* foreground pixels but still in front of background pixels.
505
+
506
+ | Bit | Name | Description |
507
+ |-----|-------|------------------------------------------|
508
+ | 7-0 | Mn DP | Sprite n data priority |
509
+
510
+ Sprite-vs-sprite priority is fixed: sprite 0 is always in front of sprite
511
+ 1, sprite 1 in front of sprite 2, etc. (lower index wins).
512
+
513
+ ### $D01C — SPMC — Sprite multicolor enable (RW)
514
+
515
+ **Chip:** VIC-II
516
+
517
+ Per-sprite multicolor mode toggle.
518
+
519
+ | Bit | Name | Description |
520
+ |-----|-------|------------------------------------------|
521
+ | 7-0 | Mn MC | Sprite n multicolor enable |
522
+
523
+ When set, the sprite is rendered at half the horizontal resolution (12×21
524
+ double-wide pixels) with 4 colors instead of 24×21 with 2 colors. Color
525
+ mapping for multicolor sprites:
526
+
527
+ | 2-bit pattern | Color source |
528
+ |---------------|-------------------------------------------|
529
+ | %00 | Transparent |
530
+ | %01 | $D025 (sprite multicolor 0, shared) |
531
+ | %10 | $D027 + n (sprite n individual color) |
532
+ | %11 | $D026 (sprite multicolor 1, shared) |
533
+
534
+ ### $D01D — XXPAND — Sprite X expansion (RW)
535
+
536
+ **Chip:** VIC-II
537
+
538
+ Per-sprite horizontal 2× expansion. When bit n is set, sprite n is drawn
539
+ 48 pixels wide instead of 24. Combined with Y expansion you get 48×42
540
+ sprites that still cost only 64 bytes of sprite data plus DMA.
541
+
542
+ | Bit | Name | Description |
543
+ |-----|------|-----------------------|
544
+ | 7-0 | Mn XE| Sprite n X expansion |
545
+
546
+ ### $D01E — SPSPCL — Sprite-sprite collision (R)
547
+
548
+ **Chip:** VIC-II
549
+
550
+ Sprite-versus-sprite collision flags, latched. Bit n is set when any
551
+ non-transparent pixel of sprite n overlapped any non-transparent pixel of
552
+ any other sprite since the last read. Reading clears all bits in this
553
+ register (read-to-clear, *not* write-to-clear, unlike $D019).
554
+
555
+ If only one bit is set, no collision occurred — that bit would only set in
556
+ the presence of a second sprite. Typically you read this once per frame
557
+ and inspect for any nonzero value.
558
+
559
+ ### $D01F — SPBGCL — Sprite-background collision (R)
560
+
561
+ **Chip:** VIC-II
562
+
563
+ Sprite-versus-foreground collision flags, latched. Bit n is set when any
564
+ non-transparent pixel of sprite n overlapped a foreground pixel of the
565
+ display: a 1 bit with MCM clear, or bit pair 10 or 11 with MCM set (pair 01
566
+ counts as background even though it is drawn in `$D022` or a screen RAM
567
+ colour; Bauer's VIC-II article, section 3.8.2; see "Priority" below).
568
+ Read-to-clear. Border and overscan pixels do not
569
+ count as foreground.
570
+
571
+ ### $D020 — EXTCOL — Border color (RW)
572
+
573
+ **Chip:** VIC-II
574
+
575
+ Color register for the screen border. Only the low 4 bits matter; the
576
+ upper 4 bits read as 1. Border color can be changed mid-line for stripe
577
+ effects.
578
+
579
+ | Bit | Description |
580
+ |-----|------------------------------------------|
581
+ | 7-4 | Unused, read 1 |
582
+ | 3-0 | Border color index, 0–15 |
583
+
584
+ ### $D021 — BGCOL0 — Background color 0 (RW)
585
+
586
+ **Chip:** VIC-II
587
+
588
+ The primary background color used in standard text, multicolor text,
589
+ multicolor bitmap, and (alongside three other regs) ECM modes. In
590
+ multicolor sprite mode this is *not* the sprite background — sprite
591
+ transparency is implicit. Bits 7–4 read 1.
592
+
593
+ ### $D022 — BGCOL1 — Background color 1 (RW)
594
+
595
+ **Chip:** VIC-II
596
+
597
+ Used in multicolor text mode as the %01 color, in ECM as one of four
598
+ background colors selected by character code bits 6–7, and in multicolor
599
+ bitmap as the %01 color.
600
+
601
+ ### $D023 — BGCOL2 — Background color 2 (RW)
602
+
603
+ **Chip:** VIC-II
604
+
605
+ Used in multicolor text mode as the %10 color, and in ECM/multicolor
606
+ bitmap analogously.
607
+
608
+ ### $D024 — BGCOL3 — Background color 3 (RW)
609
+
610
+ **Chip:** VIC-II
611
+
612
+ Fourth ECM background color. Unused in standard text and multicolor
613
+ bitmap. In multicolor text mode this register is irrelevant — the %11
614
+ color comes from the per-cell Color RAM nibble.
615
+
616
+ ### $D025 — SPMC0 — Sprite multicolor 0 (RW)
617
+
618
+ **Chip:** VIC-II
619
+
620
+ Shared sprite multicolor #0. Used by every sprite that has $D01C bit n
621
+ set, as the %01 pixel color. Bits 7–4 read 1.
622
+
623
+ ### $D026 — SPMC1 — Sprite multicolor 1 (RW)
624
+
625
+ **Chip:** VIC-II
626
+
627
+ Shared sprite multicolor #1. Used as the %11 pixel color in multicolor
628
+ sprites.
629
+
630
+ ### $D027 — SP0COL — Sprite 0 color (RW)
631
+
632
+ **Chip:** VIC-II
633
+
634
+ Sprite 0 individual color. In hires sprite mode this is the only non-
635
+ transparent color. In multicolor sprite mode this is the %10 color.
636
+
637
+ ### $D028 — SP1COL — Sprite 1 color (RW)
638
+
639
+ **Chip:** VIC-II
640
+
641
+ Sprite 1 individual color.
642
+
643
+ ### $D029 — SP2COL — Sprite 2 color (RW)
644
+
645
+ **Chip:** VIC-II
646
+
647
+ Sprite 2 individual color.
648
+
649
+ ### $D02A — SP3COL — Sprite 3 color (RW)
650
+
651
+ **Chip:** VIC-II
652
+
653
+ Sprite 3 individual color.
654
+
655
+ ### $D02B — SP4COL — Sprite 4 color (RW)
656
+
657
+ **Chip:** VIC-II
658
+
659
+ Sprite 4 individual color.
660
+
661
+ ### $D02C — SP5COL — Sprite 5 color (RW)
662
+
663
+ **Chip:** VIC-II
664
+
665
+ Sprite 5 individual color.
666
+
667
+ ### $D02D — SP6COL — Sprite 6 color (RW)
668
+
669
+ **Chip:** VIC-II
670
+
671
+ Sprite 6 individual color.
672
+
673
+ ### $D02E — SP7COL — Sprite 7 color (RW)
674
+
675
+ **Chip:** VIC-II
676
+
677
+ Sprite 7 individual color.
678
+
679
+ ### $D02F — UNUSED — Unused, reads $FF (R)
680
+
681
+ **Chip:** VIC-II
682
+
683
+ This address is unimplemented on the VIC-II. It always reads $FF and
684
+ silently ignores writes. The MOS 8564 / 8566 VIC-IIe (C128 only)
685
+ implements it as the extra-keyboard row-select register (K0–K2 in bits
686
+ 0–2, the upper bits read back as 1; the C128 KERNAL's keyboard scanner
687
+ drives it alongside CIA 1 port A and reads the rows back on CIA 1 port B)
688
+ and implements $D030 as the 2 MHz / test register (bit 0 = 2 MHz, which is
689
+ what BASIC 7.0's FAST and SLOW write). An earlier revision of this page
690
+ called $D02F a "mode-control register (50/60 Hz, fast-mode)"; that was
691
+ wrong — fast mode is $D030 bit 0, and the C128 ROM writes $D02F only from
692
+ its keyboard scanner. Measured in VICE x128 and read from the C128 ROMs
693
+ (318020-05 keyboard scan at $C56B–$C597; BASIC 7.0 FAST/SLOW at
694
+ $77B3/$77C4). On the C64's VIC-II proper both addresses are dead silicon.
695
+
696
+ ## Display modes
697
+
698
+ The VIC-II's display sequencer can run in one of four combinations of two
699
+ mode bits ECM ($D011 bit 6) and BMM ($D011 bit 5), each in either single-
700
+ color or multicolor (MCM = $D016 bit 4). That gives eight combinations —
701
+ but only six are "legal" (well-documented and useful); the other two are
702
+ the so-called *illegal* or *invalid* modes that produce solid color
703
+ output, useful only as oddities.
704
+
705
+ | BMM | ECM | MCM | Mode name |
706
+ |-----|-----|-----|----------------------------|
707
+ | 0 | 0 | 0 | Standard text mode |
708
+ | 0 | 0 | 1 | Multicolor text mode |
709
+ | 0 | 1 | 0 | Extended color text mode (ECM) |
710
+ | 0 | 1 | 1 | Invalid (ECM + MCM text) — output is black |
711
+ | 1 | 0 | 0 | Standard bitmap mode (hires) |
712
+ | 1 | 0 | 1 | Multicolor bitmap mode |
713
+ | 1 | 1 | 0 | Invalid (ECM bitmap) — output is black |
714
+ | 1 | 1 | 1 | Invalid (ECM + MCM bitmap) — output is black |
715
+
716
+ In all cases the chip outputs 320×200 pixels of content within the
717
+ RSEL = 1, CSEL = 1 window. Multicolor modes effectively halve horizontal
718
+ resolution to 160×200 pixels.
719
+
720
+ ### Standard text mode (ECM=0, BMM=0, MCM=0)
721
+
722
+ The default. 40 columns × 25 rows of 8×8 character cells, each cell drawn
723
+ from a 2K character generator pointed to by $D018 bits 3–1. Each character
724
+ cell has two colors:
725
+
726
+ - **Background**: $D021 (BGCOL0), global.
727
+ - **Foreground**: the low 4 bits of the matching Color RAM byte at
728
+ $D800 + (row × 40) + col.
729
+
730
+ Character codes are 8-bit values stored in the video matrix (default
731
+ $0400–$07E7). The character generator is its own 4 KB ROM (901225 —
732
+ separate from the 8 KB KERNAL ROM), which the CPU can read at $D000–$DFFF
733
+ only while CHAREN ($01 bit 2) is 0. The VIC never sees it at that address:
734
+ it appears to the VIC at $1000–$1FFF in bank 0 and $9000–$9FFF in bank 2,
735
+ and nowhere in banks 1 and 3. The default $D018 = $14 (CB = 2) therefore
736
+ selects the uppercase/graphics set from its first 2 KB; CB = 3
737
+ ($D018 = $16) selects the lowercase/uppercase set from its second 2 KB. An
738
+ earlier revision of this paragraph called it "the KERNAL ROM character set
739
+ at $D000 in VIC bank 0/2": $D000 is a CPU-side address the VIC cannot
740
+ form, and pointing the VIC at CPU $D000 (bank 3, CB = 2) reads RAM —
741
+ measured in VICE x64sc (default C64C model, VIC-II 8565), not on a bench.
742
+
743
+ Cell address inside the character generator:
744
+
745
+ ```
746
+ cell_addr = char_base + (char_code * 8) + row_within_cell
747
+ ```
748
+
749
+ The chip fetches one character pointer (c-access) per cell during the
750
+ badline of each text row, caches it in an internal 40×12-bit row buffer,
751
+ and then performs eight g-accesses per cell over the next eight raster
752
+ lines to read the pixel data.
753
+
754
+ ### Multicolor text mode (ECM=0, BMM=0, MCM=1)
755
+
756
+ Same character matrix and same character generator as standard text mode.
757
+ The interpretation of cells depends on the color RAM nibble.
758
+
759
+ If the high color RAM bit (bit 3) is **clear**, the cell renders exactly
760
+ like standard text mode (high resolution, 2-color, foreground = color RAM
761
+ bits 0–2).
762
+
763
+ If the high bit is **set**, the cell renders as multicolor: 4×8 double-
764
+ wide pixels with this color map:
765
+
766
+ | Bit pattern | Color source |
767
+ |-------------|-------------------------------------------|
768
+ | %00 | $D021 (BGCOL0) |
769
+ | %01 | $D022 (BGCOL1) |
770
+ | %10 | $D023 (BGCOL2) |
771
+ | %11 | Color RAM bits 0–2 (foreground) |
772
+
773
+ This means in multicolor text mode you only get 8 possible foreground
774
+ colors per cell (colors 0–7), not the full 16. Demo coders sometimes
775
+ combine multicolor and standard text by carefully choosing which color RAM
776
+ high-bits to set on which cells.
777
+
778
+ ### Extended color mode (ECM) text (ECM=1, BMM=0, MCM=0)
779
+
780
+ Each character cell still has 8×8 hi-res pixels, but the top two bits of
781
+ the character code are used to select one of four background colors,
782
+ leaving only 64 distinct glyph codes:
783
+
784
+ | Char code bits 7–6 | Background |
785
+ |--------------------|-------------------|
786
+ | %00 (0–63) | $D021 (BGCOL0) |
787
+ | %01 (64–127) | $D022 (BGCOL1) |
788
+ | %10 (128–191) | $D023 (BGCOL2) |
789
+ | %11 (192–255) | $D024 (BGCOL3) |
790
+
791
+ Foreground color still comes from Color RAM. Useful in games for cheap
792
+ per-region background coloring; downside is the loss of 192 of the 256
793
+ glyphs.
794
+
795
+ ### Standard bitmap mode (ECM=0, BMM=1, MCM=0)
796
+
797
+ 8000 bytes (320×200/8) of bitmap data with per-8×8-cell foreground/
798
+ background colors stored in the video matrix.
799
+
800
+ - Bitmap base: $0000 or $2000 within the VIC bank, selected by $D018 bit 3.
801
+ - Video matrix base: any 1K boundary in the VIC bank, selected by $D018
802
+ bits 7–4.
803
+
804
+ Each video matrix byte holds two color nibbles for one 8×8 cell:
805
+
806
+ | Bits | Use |
807
+ |------|--------------------------------------|
808
+ | 7-4 | Foreground color (set bits in bitmap)|
809
+ | 3-0 | Background color (clear bits) |
810
+
811
+ Color RAM is not used in hires bitmap mode. Pixel addresses inside the
812
+ bitmap:
813
+
814
+ ```
815
+ byte_addr = bitmap_base + (cell_row * 320) + (cell_col * 8) + row_in_cell
816
+ ```
817
+
818
+ ### Multicolor bitmap mode (ECM=0, BMM=1, MCM=1)
819
+
820
+ Same bitmap addressing as hires bitmap; same video matrix layout for two
821
+ colors per cell; *plus* the Color RAM nibble for a third per-cell color;
822
+ plus $D021 BGCOL0 as the shared fourth color.
823
+
824
+ | Bit pattern | Color source |
825
+ |-------------|-------------------------------------------|
826
+ | %00 | $D021 (BGCOL0) |
827
+ | %01 | Video matrix byte high nibble |
828
+ | %10 | Video matrix byte low nibble |
829
+ | %11 | Color RAM low nibble |
830
+
831
+ Horizontal resolution drops to 160 double-wide pixels. The vast majority
832
+ of "C64 paintings" you have ever seen are multicolor bitmap.
833
+
834
+ ### Illegal display modes
835
+
836
+ Setting ECM+MCM together, or BMM+ECM together, puts the chip into an
837
+ "invalid" mode. The display sequencer still runs, but the pixel data
838
+ output is forced to black. Collisions and sprites still function. Demo
839
+ coders sometimes flip into invalid mode briefly to blank the display
840
+ without touching DEN (a DEN clear only blanks the frame if it is clear on
841
+ line $30 and line 51, which also removes the frame's badlines and hides
842
+ the sprites under the border; sprite DMA and collisions are unaffected by
843
+ DEN either way — measured in VICE x64sc).
844
+
845
+ ### Mode-switch timing
846
+
847
+ The mode bits ECM, BMM, MCM are sampled by the display sequencer every
848
+ cycle. Switching modes mid-line therefore changes pixels mid-row at
849
+ character-cell boundaries. This is the foundation of FLI (Flexible Line
850
+ Interpretation), AGSP, and other "extra colors" tricks. The trick is that
851
+ the c-accesses for the *next* line happen during cycles 15–54 of the
852
+ previous badline, so a mode switch on cycle 14 of the current line affects
853
+ pixel rendering immediately.
854
+
855
+ ## Sprites
856
+
857
+ The VIC-II provides eight hardware sprites. Each sprite is 24×21 pixels
858
+ in hires mode or 12×21 (double-width) in multicolor mode, with optional
859
+ 2× horizontal and/or 2× vertical expansion. Sprites are independent of
860
+ text/bitmap modes; the same eight sprites are available regardless.
861
+
862
+ ### Sprite data layout
863
+
864
+ Each sprite consumes 63 bytes of memory plus 1 byte of padding (total 64).
865
+ The 63 bytes form a 24-pixel-wide, 21-line image:
866
+
867
+ ```
868
+ byte 0 byte 1 byte 2 <- first scanline of sprite
869
+ byte 3 byte 4 byte 5 <- second scanline
870
+ ...
871
+ byte 60 byte 61 byte 62 <- 21st scanline
872
+ byte 63 unused
873
+ ```
874
+
875
+ In hires mode each bit is a pixel: 1 = sprite color from $D027 + n, 0 =
876
+ transparent. In multicolor mode each pair of bits is a pixel (12 pixels
877
+ per line) using the color map under [$D01C](#d01c--spmc--sprite-multicolor-enable-rw).
878
+
879
+ ### Sprite pointers
880
+
881
+ Each enabled sprite reads a pointer byte once per raster line from the
882
+ last 8 bytes of the video matrix. The pointer × 64 is the address (inside
883
+ the VIC bank) where the sprite's 63 bytes of pixel data begin.
884
+
885
+ ```
886
+ pointer_addr = video_matrix_base + $3F8 + sprite_index
887
+ sprite_data_addr = (pointer_value) * 64
888
+ ```
889
+
890
+ So with the default screen at $0400, the eight pointer bytes live at
891
+ $07F8–$07FF. Writing a pointer of $80 places the sprite data at
892
+ $80 × 64 = $2000.
893
+
894
+ ### Positioning
895
+
896
+ X is 9-bit (0–511) split between $D000+2n and $D010 bit n. Y is 8-bit
897
+ (0–255) in $D001+2n. The visible 200-line display occupies Y = 50 (top of
898
+ character row 0) through Y = 249 inclusive, with Y = 250 the first value
899
+ whose top row falls in the lower border (raster line 251; raster line 250
900
+ itself is the last display line). To place a sprite on top of character
901
+ row r,
902
+ column c (cell coordinates), the formula is:
903
+
904
+ ```
905
+ sprite_X = 24 + c * 8 ; offset 24 because X = 0 is well off-screen
906
+ sprite_Y = 50 + r * 8
907
+ ```
908
+
909
+ ### Expansion
910
+
911
+ `$D017` and `$D01D` toggle vertical and horizontal 2× expansion per
912
+ sprite. The expansion takes effect immediately on the X axis (next pixel
913
+ shifted is doubled), but on Y axis the chip uses an internal "expansion
914
+ flip-flop" that toggles each line — changing $D017 mid-line can confuse
915
+ the flip-flop and cause "sprite crunch" (variable-height sprites used in
916
+ some demos and unintentionally in some bugs).
917
+
918
+ ### Multicolor
919
+
920
+ Setting bit n in $D01C makes sprite n multicolor: 12-pixel horizontal
921
+ resolution, 4-color (one transparent, plus three pickable). See the
922
+ [$D01C](#d01c--spmc--sprite-multicolor-enable-rw) entry for the color map.
923
+
924
+ ### Priority
925
+
926
+ Sprite-sprite priority is fixed: index 0 wins over 1, 1 over 2, etc. So
927
+ sprite 0 always renders in front of sprite 7 when they overlap.
928
+
929
+ Sprite-background priority is per-sprite via $D01B. When bit n = 0
930
+ (default), sprite n appears in front of foreground graphics. When bit
931
+ n = 1, sprite n appears *behind* foreground but still in front of
932
+ background.
933
+
934
+ In effect each pixel has these layers from back to front:
935
+
936
+ ```
937
+ background <- [sprites with $D01B bit set] <- foreground <- [sprites with $D01B bit clear] <- border
938
+ ```
939
+
940
+ The border is the front-most layer: it hides sprites unless it is opened
941
+ (measured in VICE x64sc; an earlier version of this page drew it at the
942
+ back).
943
+
944
+ "Background" for sprite priority and for `$D01F` is decided by the pixel's
945
+ bit pattern, not its colour register. With MCM clear (standard text, ECM,
946
+ standard bitmap), a 0 bit is background and a 1 bit is foreground. With MCM
947
+ set (multicolour text cells and multicolour bitmap), bit pairs 00 and 01 are
948
+ background and 10 and 11 are foreground, whatever colour 01 draws in
949
+ (`$D022` in multicolour text, the screen RAM high nibble in multicolour
950
+ bitmap). A sprite with its `$D01B` bit clear is drawn over all of these; with
951
+ the bit set, 00 and 01 pixels show the sprite through. Measured in VICE
952
+ x64sc in multicolour text by the `oscar64/mixed-fighters` recipe (pair 01
953
+ showed the sprite, pairs 10 and 11 covered it); Bauer's VIC-II article,
954
+ section 3.8.2, gives the same table
955
+ (http://www.zimmers.net/cbmpics/cbm/c64/vic-ii.txt). An earlier version of
956
+ this paragraph defined background as the pixels drawn in `$D021` (and
957
+ BGCOL1-3 in multicolour bitmap or ECM), which counted `$D022` pixels in
958
+ multicolour text as foreground and named the wrong source for bitmap
959
+ colour 01.
960
+
961
+ ### Collisions
962
+
963
+ Two collision registers latch at pixel-by-pixel resolution:
964
+
965
+ - **$D01E**: any non-transparent pixel of sprite n overlaps a non-
966
+ transparent pixel of any other sprite.
967
+ - **$D01F**: any non-transparent pixel of sprite n overlaps a foreground
968
+ pixel of the background graphics.
969
+
970
+ Each is read-to-clear. If the corresponding IRQ enable bit in $D01A is
971
+ set, the first collision per latch interval also triggers an IRQ via
972
+ $D019. Border pixels and the screen blanking area do not generate
973
+ collisions.
974
+
975
+ A subtle gotcha: the *latch interval* spans from the previous read to the
976
+ current read. If you do not read the register at all during a frame, a
977
+ collision that happens and then resolves is lost.
978
+
979
+ ### Sprite DMA
980
+
981
+ For each sprite that is enabled or in the middle of its 21-line render,
982
+ the VIC-II steals additional cycles from the CPU on its raster lines. The
983
+ exact pattern:
984
+
985
+ 1. One **p-access** (pointer fetch) per raster line, always, regardless of
986
+ enable state, on cycles 58, 60, 62, 1, 3, 5, 7, 9 for sprites 0–7 on
987
+ PAL — measured in VICE x64sc on its default C64C model, VIC-II 8565 (an
988
+ earlier version said 6569): with sprites 0..k active the CPU
989
+ resumes two cycles after sprite k's slot (60, 1, 3, 9, 11 for
990
+ k = 0, 2, 3, 6, 7). On the 65-cycle 6567R8 the slots are 60, 62, 64,
991
+ 1, 3, 5, 7, 9 (from Bauer's tables; only the relative structure —
992
+ eight contiguous two-cycle slots ending on cycle 10 — was reproduced
993
+ here). An earlier version of this page listed 58, 60, 62, 64, 1, 3, 5,
994
+ 7, which puts a cycle 64 on a 63-cycle line and sprite 7 two cycles
995
+ early.
996
+ 2. Three **s-accesses** (sprite data fetch) per raster line, but only when
997
+ that sprite's render row is active. These follow each sprite's
998
+ p-access slot.
999
+
1000
+ With all eight sprites active the chip steals 3 (BA lead-in before
1001
+ sprite 0, usable only for write cycles) + 8 × 2 (two bus cycles of
1002
+ s-accesses per sprite; the p-access is a phi1 access and costs the CPU
1003
+ nothing) = up to 19 cycles per line on top of any badline overhead,
1004
+ leaving the CPU ~44 of the 63 PAL cycles (~46 of 65 on NTSC). An earlier
1005
+ version of this page wrote the sum as (8 × 2 + 8 × 1), which is 24 and
1006
+ counted the free p-access as a stolen cycle; the 19 is measured in VICE
1007
+ x64sc (399 cycles over the 21 DMA lines of eight sprites, 105 for one
1008
+ sprite, 210 for sprites 0 and 7 as two separate BA groups). This is why
1009
+ "full-screen multiplexers" of more
1010
+ than 8 sprites have to do their pointer rewrites during specific cycle
1011
+ windows.
1012
+
1013
+ The VIC-II asserts BA (Bus Available) low three cycles before each sprite
1014
+ fetch. The CPU then completes its current memory cycle and releases the
1015
+ bus on the next read cycle. Write cycles are not blocked by BA, so the
1016
+ CPU continues to execute write instructions for up to three additional
1017
+ cycles before the chip actually steals the bus.
1018
+
1019
+ ### Number-of-sprites limits
1020
+
1021
+ A single VIC-II shows eight sprites *per scanline*. The classic
1022
+ multiplexer technique reuses sprites across vertical bands by rewriting
1023
+ their Y position and pointer during the lines between bands; modern
1024
+ multiplexer routines achieve 16–24 sprites per frame routinely.
1025
+
1026
+ The hardware does not enforce any limit beyond "8 simultaneous"; if you
1027
+ move a sprite while it is rendering, the display will show the new value
1028
+ on the next line it is fetched, which is what makes multiplexing work.
1029
+
1030
+ ## Raster system
1031
+
1032
+ The VIC-II's raster engine ticks once per character pixel column with
1033
+ high precision, and its interaction with the CPU bus is fully
1034
+ deterministic. Everything in this section is the foundation of stable
1035
+ rasters, hardware scrolling, FLD/FLI/CRT effects, and sprite multiplexing.
1036
+
1037
+ ### Raster line counter
1038
+
1039
+ `$D012` holds the low 8 bits of the current line; bit 7 of $D011 holds
1040
+ bit 8. The counter increments at the start of cycle 1 of each raster line
1041
+ *except* line 0, where it ticks one cycle later — this off-by-one quirk
1042
+ is documented in Bauer's article and is why some stable-raster code
1043
+ double-checks the counter on the cycle after it expects an increment.
1044
+
1045
+ Line numbering on a PAL 6569:
1046
+
1047
+ | Line range | Region |
1048
+ |------------|-------------------------------------------------|
1049
+ | 0..15 | Top border (with VBI) |
1050
+ | 16..50 | Top border |
1051
+ | 51..250 | Visible 25-row display window (RSEL = 1) |
1052
+ | 55..246 | Visible 24-row display window (RSEL = 0) |
1053
+ | 251..299 | Bottom border |
1054
+ | 300..311 | Bottom border (with VBI) |
1055
+
1056
+ NTSC line numbering is similar but with fewer lines below 0 and a
1057
+ different total (262 or 263).
1058
+
1059
+ ### Raster IRQ
1060
+
1061
+ Write the desired compare line into $D012 (low 8 bits) and into $D011
1062
+ bit 7 (bit 8), enable raster IRQ in $D01A bit 0, and the chip will pull
1063
+ its IRQ output low at the start of cycle 1 of that line (cycle 2 for
1064
+ line 0). The CPU sees this as a normal 6502/6510 IRQ and vectors via
1065
+ ($FFFE/$FFFF) or via $0314/$0315 if the KERNAL IRQ handler at $EA31 is
1066
+ in place.
1067
+
1068
+ You **must** acknowledge by writing 1 to bit 0 of $D019, or the IRQ will
1069
+ re-fire as soon as you RTI.
1070
+
1071
+ Two-byte raster compare write sequence (canonical):
1072
+
1073
+ ```
1074
+ lda #target_line_lo
1075
+ sta $d012
1076
+ lda $d011
1077
+ and #$7f
1078
+ ora #(target_line_hi_bit << 7)
1079
+ sta $d011
1080
+ ```
1081
+
1082
+ Do not skip the second step, even for target lines below 256. The KERNAL's
1083
+ VIC init (the table at $ECB9, copied to $D000–$D02E by $E5A0 during CINT)
1084
+ writes $9B to $D011, so after boot RST8 = 1 and the compare value is $137.
1085
+ A program that writes only $D012 gets its interrupt on line target+256 if
1086
+ that line exists — PAL lines 256..311, i.e. targets 0..55 — and otherwise
1087
+ never. Measured in VICE x64sc 3.10: with $D011 untouched, $D012 = $64 gave
1088
+ 0 IRQs in 20 frames on both PAL and NTSC; $D012 = $30 gave one IRQ per
1089
+ frame at line $130 (304) on PAL and none on NTSC; after
1090
+ `lda $d011 / and #$7f / sta $d011` the $64 target fired once per frame at
1091
+ line 100 on both. Always do the read-modify-write above. (An earlier
1092
+ version of this page said the step could be skipped below 256 because
1093
+ bit 7 "should already be 0"; it is 1 after boot.)
1094
+
1095
+ ### Badlines
1096
+
1097
+ A badline is a raster line on which the chip must perform 40 c-accesses
1098
+ (character pointer + Color RAM fetches) to load the next row's video
1099
+ matrix into its internal row buffer. The condition is:
1100
+
1101
+ ```
1102
+ ($30 <= raster <= $F7) AND (raster & 7 == YSCROLL) AND DEN was set on $30
1103
+ ```
1104
+
1105
+ PAL line $30 is decimal 48; $F7 is 247. With the default YSCROLL = 3 this
1106
+ means badlines occur on lines 51, 59, 67, ..., 243 — exactly every 8
1107
+ lines, once per character row.
1108
+
1109
+ On a badline the chip pulls BA low at cycle 12 to warn the CPU, then
1110
+ takes the bus from cycle 15 through cycle 54. Total stolen cycles: 40,
1111
+ plus up to 3 cycles of CPU "tail" before BA actually takes hold (because
1112
+ the CPU finishes its current read instruction). Effective CPU budget on a
1113
+ badline: 63 - 43 = 20 cycles on PAL.
1114
+
1115
+ You can *prevent* badlines for a whole frame by keeping DEN ($D011 bit 4)
1116
+ clear for the whole of raster line $30 (48); setting it on any cycle of
1117
+ that line re-enables them (an earlier version said "before cycle 14"). The
1118
+ chip then stays in idle state for the frame; the screen shows the border
1119
+ colour ($D020) if DEN is still clear at cycle 63 of line 51 — the vertical
1120
+ border flip-flop is never reset — or the idle-state $3FFF picture (BGCOL0
1121
+ / idle-state graphics) if DEN was set again before line 51. Measured in
1122
+ VICE x64sc; an earlier version of this page said the display turns to
1123
+ BGCOL0. Clearing DEN after line $30 does not stop the remaining badlines
1124
+ of that frame.
1125
+
1126
+ You can *shift* badlines by changing YSCROLL, or *delay one badline*
1127
+ by changing YSCROLL on the badline immediately before; this is the
1128
+ foundation of FLD (Flexible Line Distance) and other vertical-stretch
1129
+ tricks.
1130
+
1131
+ ### c-access, g-access, p-access, s-access
1132
+
1133
+ Four kinds of memory accesses the chip can perform:
1134
+
1135
+ | Access | When | What is read |
1136
+ |--------|---------------------------------------|----------------------------|
1137
+ | c | Cycles 15–54 of every badline | Char pointer + color RAM nibble (12-bit) |
1138
+ | g | Cycles 16–55 of every visible line | 8 bits of pixel data (char gen or bitmap) |
1139
+ | p | Cycles 58, 60, 62, 1, 3, 5, 7, 9 (PAL); 60, 62, 64, 1, 3, 5, 7, 9 (6567R8) | Sprite pointer byte |
1140
+ | s | After each p, when sprite is active | 3 bytes of sprite pixel data |
1141
+
1142
+ The c- and g-accesses are pipelined so that the c-access on badline N
1143
+ fetches the row that will be g-rendered on lines N+1..N+8 (or N..N+7 in
1144
+ some sources depending on which line is "first"). The internal video
1145
+ matrix latch holds these 40 12-bit entries until the next badline.
1146
+
1147
+ ### Idle vs display state
1148
+
1149
+ The chip distinguishes two operating states:
1150
+
1151
+ - **Display state**: the c-access pipeline has data, g-accesses fetch from
1152
+ char gen or bitmap, and pixel output reflects the video matrix. Entered
1153
+ when a badline occurs and the chip is in the visible Y range.
1154
+ - **Idle state**: c-accesses are skipped, the video matrix latch is
1155
+ zeroed out (so all cells read as 0), and g-accesses fetch from a fixed
1156
+ address ($3FFF, or $39FF if ECM is set). Pixel output is black
1157
+ (or whatever bit pattern is at $3FFF, with the current foreground/
1158
+ background colors).
1159
+
1160
+ The chip is in idle state whenever no badline has loaded the row buffer:
1161
+ outside the display Y range, or for the whole frame when DEN was clear on
1162
+ raster line $30. DEN itself is not consulted by the idle/display logic.
1163
+ Clearing DEN later in the frame changes nothing for the rest of that
1164
+ frame — badlines, display state, border and sprites all continue
1165
+ (measured in VICE x64sc: DEN cleared on line 100, window fully displayed
1166
+ and the badline count between lines 104 and 200 unchanged, 12 of 12). An
1167
+ earlier version of this section said clearing DEN entered idle state. It
1168
+ re-enters display state on the next badline.
1169
+
1170
+ The "$3FFF phantom pixels" picture is a whole-frame effect, not a
1171
+ mid-frame strip: it appears when DEN is clear on line $30 (no badlines, so
1172
+ the frame never leaves idle state) but set again by line 51 (so the
1173
+ vertical border opens); the window then shows the byte at $3FFF ($39FF
1174
+ with ECM) in colour 0 over $D021 on every line.
1175
+
1176
+ ### Light pen latch
1177
+
1178
+ Pulling the LP pin (CIA1 PB4, also tied to joystick port 1 fire button)
1179
+ low latches the current X (÷ 2) into $D013 and Y into $D014. The latch
1180
+ fires *once per frame*; subsequent LP edges in the same frame are ignored.
1181
+ On PAL the latch is reset at the start of line 0; on NTSC at line 0 of
1182
+ the next frame.
1183
+
1184
+ ### Stable raster technique
1185
+
1186
+ To synchronize execution to a known cycle within a known raster line:
1187
+
1188
+ 1. Set up a raster IRQ at the target line.
1189
+ 2. In the IRQ handler, immediately write a *second* raster IRQ for
1190
+ line + 1 and acknowledge the current one.
1191
+ 3. Pad the handler with NOPs so that the worst-case IRQ entry latency is
1192
+ absorbed. The 6510 recognises an IRQ only at the end of the instruction
1193
+ it is executing, and that instruction can be 2–7 cycles long, so the
1194
+ latency varies over a window of 0–6 cycles (seven possible entry
1195
+ timings; an earlier version of this page said 5, which is the 7−2
1196
+ subtraction and undercounts by one — measured in VICE x64sc: a sled of
1197
+ 7-cycle INC abs,X gives exactly seven distinct entry cycles).
1198
+ Undocumented 8-cycle read-modify-write opcodes such as SLO (zp),Y widen
1199
+ the window to 0–7.
1200
+ 4. After the second IRQ fires, you know exactly which cycle of which line
1201
+ you are on.
1202
+
1203
+ Most demo coders use the "double-IRQ" technique above as the foundation
1204
+ of every effect that needs cycle accuracy (border opening, FLI, sprite
1205
+ multiplexer rasters).
1206
+
1207
+ ## Color RAM
1208
+
1209
+ The Color RAM is a 1024-nibble (1024 × 4-bit) static RAM at $D800–$DBFF,
1210
+ backing the per-cell foreground/attribute color in text and multicolor
1211
+ bitmap modes.
1212
+
1213
+ ### Layout
1214
+
1215
+ The 1000 cells of the 40×25 character matrix map directly to the first
1216
+ 1000 nibbles of Color RAM:
1217
+
1218
+ ```
1219
+ color_addr = $D800 + (row * 40) + col
1220
+ ```
1221
+
1222
+ The remaining 24 nibbles ($DBE8–$DBFF) are not used by the display but
1223
+ the RAM is fully readable and writable. Some software uses these 24 cells
1224
+ as "free" 4-bit-per-cell storage.
1225
+
1226
+ ### Reads return only 4 bits
1227
+
1228
+ The Color RAM chip only stores 4 bits per cell. Reading $D800+n returns
1229
+ the low nibble in bits 0–3; the upper 4 bits read whatever happens to be
1230
+ on the bus at that moment (typically the high nibble of the most recently
1231
+ fetched byte). Always AND with $0F when reading Color RAM.
1232
+
1233
+ Writes only honor the low 4 bits; the upper 4 bits are discarded by the
1234
+ hardware.
1235
+
1236
+ ### Color values
1237
+
1238
+ Each nibble encodes one of 16 colors:
1239
+
1240
+ | Value | Color | Value | Color |
1241
+ |-------|--------------|-------|-------------|
1242
+ | 0 | Black | 8 | Orange |
1243
+ | 1 | White | 9 | Brown |
1244
+ | 2 | Red | 10 | Light red |
1245
+ | 3 | Cyan | 11 | Dark grey |
1246
+ | 4 | Purple | 12 | Medium grey |
1247
+ | 5 | Green | 13 | Light green |
1248
+ | 6 | Blue | 14 | Light blue |
1249
+ | 7 | Yellow | 15 | Light grey |
1250
+
1251
+ The 8565/8562 produce subtly different shades, particularly for grays
1252
+ and reds, due to differences in the HMOS-II color encoder.
1253
+
1254
+ ### Use across display modes
1255
+
1256
+ | Mode | Color RAM use |
1257
+ |-----------------------|--------------------------------------------|
1258
+ | Standard text | Foreground color, 16 colors |
1259
+ | Multicolor text | If bit 3 set: %11 color (8 colors); else hires foreground (8 colors) |
1260
+ | Extended color mode | Foreground color, 16 colors |
1261
+ | Standard bitmap (hires)| Not used |
1262
+ | Multicolor bitmap | %11 color (16 colors) |
1263
+
1264
+ ### Initialization gotcha
1265
+
1266
+ Color RAM contents are random on power-on. The KERNAL clears it to the
1267
+ current `$0286` (text color) value during reset, but if you take over
1268
+ before the KERNAL clear runs you may see colorful garbage where you
1269
+ expected color 0 (black on black).
1270
+
1271
+ ### Sprite color registers
1272
+
1273
+ Note that the per-sprite color registers ($D027–$D02E) and the shared
1274
+ sprite multicolor registers ($D025, $D026) live in the VIC-II register
1275
+ space, *not* in Color RAM. Color RAM affects backgrounds and characters
1276
+ only; sprite colors are programmed directly.
1277
+
1278
+ ## Memory access
1279
+
1280
+ The VIC-II reads memory through a 16 KB address window called the *VIC
1281
+ bank*. The chip itself only generates 14 bits of address (A0–A13); the
1282
+ upper 2 bits come from CIA2 port A.
1283
+
1284
+ ### VIC bank selection (via CIA2 $DD00)
1285
+
1286
+ CIA2 port A bits 0–1 are inverted and used as the high 2 bits of every
1287
+ VIC-II memory access. Writing %xx to bits 0–1 sets the VIC bank as:
1288
+
1289
+ | CIA2 $DD00 bits 1–0 | VIC bank | Address range |
1290
+ |---------------------|----------|----------------|
1291
+ | %11 | 0 | $0000–$3FFF |
1292
+ | %10 | 1 | $4000–$7FFF |
1293
+ | %01 | 2 | $8000–$BFFF |
1294
+ | %00 | 3 | $C000–$FFFF |
1295
+
1296
+ The default after RESET is bank 0 ($0000–$3FFF), placing the screen at
1297
+ $0400 and the character generator ROM at $1000.
1298
+
1299
+ To change banks, also set CIA2 data direction register $DD02 bits 0–1 to
1300
+ 1 (output). The KERNAL does this at boot.
1301
+
1302
+ ### Character ROM shadowing
1303
+
1304
+ The character generator ROM at $D000–$DFFF in CPU address space appears
1305
+ shadowed at $1000–$1FFF in VIC banks 0 and 2, and at $9000–$9FFF in VIC
1306
+ banks 1 and 3 — no, that's not right. Actually: the character ROM
1307
+ appears at $1000–$1FFF inside VIC banks 0 and 2 only. In VIC banks 1 and
1308
+ 3 the chip sees RAM at those addresses.
1309
+
1310
+ | VIC bank | $1000–$1FFF region sees |
1311
+ |----------|--------------------------|
1312
+ | 0 | Character ROM |
1313
+ | 1 | RAM at $5000–$5FFF |
1314
+ | 2 | Character ROM |
1315
+ | 3 | RAM at $D000–$DFFF (which is I/O from the CPU's view) |
1316
+
1317
+ This shadowing is independent of the CPU's view: the CPU sees $D000–$DFFF
1318
+ as I/O (or character ROM, or RAM, depending on $01 banking), while the
1319
+ VIC-II *always* sees character ROM at $1000–$1FFF in banks 0 and 2.
1320
+
1321
+ In banks 1 and 3 you must place a character set in RAM at one of the 8
1322
+ possible character base positions inside the bank.
1323
+
1324
+ ### Video matrix and char base inside the bank ($D018)
1325
+
1326
+ `$D018` selects, within the 16 KB VIC bank, the position of the video
1327
+ matrix (1 KB) and the character generator (2 KB):
1328
+
1329
+ ```
1330
+ video_matrix_offset = VM_bits * $0400
1331
+ char_base_offset = CB_bits * $0800
1332
+ ```
1333
+
1334
+ with VM_bits in 0..15 and CB_bits in 0..7. For example, $D018 = $14
1335
+ (binary 0001 0100) puts VM at $0400 and CB at $1000 — the default.
1336
+
1337
+ In bitmap mode bit CB2 (the high bit of the 3-bit CB field) selects
1338
+ between $0000 and $2000 as the bitmap base. The low two CB bits are
1339
+ ignored.
1340
+
1341
+ ### What if the VIC-II reads $D000–$DFFF?
1342
+
1343
+ Inside the C64, $D000–$DFFF is the I/O area for the CPU, but the VIC-II
1344
+ itself does not see "I/O" — it sees RAM (the 1K backing RAM behind the
1345
+ I/O space, sometimes called the "shadow RAM"). So in bank 3, addresses
1346
+ $D000–$DFFF from the VIC's perspective are simply 4K of RAM that the CPU
1347
+ cannot normally reach (unless I/O is banked out via $01). This is a
1348
+ useful place to store sprite data or character sets that the CPU never
1349
+ touches.
1350
+
1351
+ ### Address translation summary
1352
+
1353
+ ```
1354
+ vic_address = (NOT CIA2_PRA[1:0]) << 14 | vic_internal_14bit_addr
1355
+ ```
1356
+
1357
+ When designing a memory layout: choose a VIC bank first (CIA2 $DD00),
1358
+ then within that 16 KB place the video matrix (VM × 1 KB), char gen or
1359
+ bitmap (CB × 2 KB or CB2 × 8 KB), sprite data (any 64-byte boundary),
1360
+ and finally the sprite pointer table at video_matrix + $3F8.
1361
+
1362
+ ## Programming patterns
1363
+
1364
+ This section collects the canonical idioms that appear in nearly every
1365
+ C64 program that touches the VIC-II.
1366
+
1367
+ ### Reading the current raster line
1368
+
1369
+ ```
1370
+ ; spin until a specific raster is reached (line < 256)
1371
+ wait:
1372
+ lda $d012
1373
+ cmp #target_line
1374
+ bne wait
1375
+ ```
1376
+
1377
+ For target lines ≥ 256, also check $D011 bit 7:
1378
+
1379
+ ```
1380
+ wait_hi:
1381
+ lda $d011
1382
+ and #$80
1383
+ beq wait_hi ; wait until raster MSB is 1
1384
+ lda $d012
1385
+ cmp #(target - 256)
1386
+ bne wait_hi
1387
+ ```
1388
+
1389
+ ### Programming a raster IRQ
1390
+
1391
+ ```
1392
+ sei
1393
+ lda #<irq_handler
1394
+ sta $0314
1395
+ lda #>irq_handler
1396
+ sta $0315
1397
+
1398
+ lda #target_line_lo
1399
+ sta $d012
1400
+ lda $d011
1401
+ and #$7f
1402
+ ora #(target_line_hi_bit * $80)
1403
+ sta $d011
1404
+
1405
+ lda #$01 ; enable raster IRQ only
1406
+ sta $d01a
1407
+ lda #$7f ; mask all CIA IRQs to avoid jitter
1408
+ sta $dc0d
1409
+ sta $dd0d
1410
+ lda $dc0d ; ack any pending CIA IRQ
1411
+ lda $dd0d
1412
+ cli
1413
+
1414
+ irq_handler:
1415
+ pha
1416
+ txa
1417
+ pha
1418
+ tya
1419
+ pha
1420
+ lda #$01
1421
+ sta $d019 ; ack raster IRQ
1422
+ ; ... do work ...
1423
+ pla
1424
+ tay
1425
+ pla
1426
+ tax
1427
+ pla
1428
+ rti
1429
+ ```
1430
+
1431
+ ### Double-IRQ stable raster
1432
+
1433
+ The single-IRQ approach above has up to 6 cycles of jitter (seven possible
1434
+ entry timings; 7 only if 8-cycle undocumented opcodes are in the
1435
+ interrupted code) due to the 6510's variable instruction length when an
1436
+ IRQ fires. The double-IRQ trick removes that jitter:
1437
+
1438
+ ```
1439
+ irq1:
1440
+ ; first IRQ: schedule second IRQ on next line and rti immediately
1441
+ lda #<irq2
1442
+ sta $0314
1443
+ lda #>irq2
1444
+ sta $0315
1445
+ inc $d012 ; raster + 1
1446
+ lda #$01
1447
+ sta $d019 ; ack
1448
+ tsx
1449
+ cli
1450
+ nop
1451
+ nop
1452
+ nop
1453
+ nop
1454
+ nop
1455
+ nop
1456
+ nop
1457
+ nop ; waste max-cycle window
1458
+ irq2:
1459
+ txs ; restore stack
1460
+ lda #<irq1 ; reschedule irq1 for the original line
1461
+ sta $0314
1462
+ lda #>irq1
1463
+ sta $0315
1464
+ lda #original_lo
1465
+ sta $d012
1466
+ lda #$01
1467
+ sta $d019
1468
+ ; now we are at a known cycle of a known line
1469
+ ; ... cycle-exact effect code ...
1470
+ jmp $ea81 ; or rti through KERNAL
1471
+ ```
1472
+
1473
+ ### Setting up a screen + character set in bank 1
1474
+
1475
+ ```
1476
+ ; switch CIA2 DDR + PRA to put VIC on bank 1
1477
+ lda $dd02
1478
+ ora #$03
1479
+ sta $dd02
1480
+ lda $dd00
1481
+ and #$fc
1482
+ ora #$02 ; bits 1..0 = %10 -> bank 1
1483
+ sta $dd00
1484
+
1485
+ ; place video matrix at $4400 (VM = %0001), charset at $5000 (CB = %100)
1486
+ lda #(%0001_0000 | %0000_1000 | %0) ; VM=1, CB=4
1487
+ sta $d018 ; final value $18
1488
+ ```
1489
+
1490
+ (Comment for clarity; the actual value would be $18.)
1491
+
1492
+ ### Building a sprite
1493
+
1494
+ ```
1495
+ ; copy 63 bytes of sprite data to $2000
1496
+ ; set sprite pointer 0 to $2000 / 64 = $80
1497
+ lda #$80
1498
+ sta $07f8 ; sprite pointer 0, assuming screen at $0400
1499
+
1500
+ ; enable sprite 0
1501
+ lda #$01
1502
+ sta $d015
1503
+
1504
+ ; position it on top-left of display
1505
+ lda #24+0
1506
+ sta $d000
1507
+ lda #50+0
1508
+ sta $d001
1509
+ lda $d010
1510
+ and #$fe
1511
+ sta $d010
1512
+
1513
+ ; color it white
1514
+ lda #$01
1515
+ sta $d027
1516
+ ```
1517
+
1518
+ ### Smooth scrolling with YSCROLL
1519
+
1520
+ For vertical fine-scroll, change YSCROLL each frame and shift the
1521
+ screen RAM up by one row every 8 frames:
1522
+
1523
+ ```
1524
+ scroll_step:
1525
+ dec yscroll_var
1526
+ bpl scroll_done
1527
+ lda #7
1528
+ sta yscroll_var
1529
+ jsr shift_screen_up_one_row
1530
+ scroll_done:
1531
+ lda $d011
1532
+ and #$f8
1533
+ ora yscroll_var
1534
+ sta $d011
1535
+ rts
1536
+ ```
1537
+
1538
+ XSCROLL via $D016 works identically for horizontal scrolling.
1539
+
1540
+ ### Switching display modes safely
1541
+
1542
+ To switch between modes without flicker:
1543
+
1544
+ 1. Wait for the VBI (raster ≥ 250).
1545
+ 2. Write the new $D011 and $D016 values.
1546
+ 3. Update $D018 if char base or VM moved.
1547
+ 4. Update $DD00 if VIC bank changed.
1548
+
1549
+ Mid-frame mode switches are valid but produce visible seams; useful for
1550
+ splitscreen effects (text status bar + bitmap play area) when timed to a
1551
+ raster IRQ.
1552
+
1553
+ ## Detailed timing reference
1554
+
1555
+ ### PAL cycle map of a non-badline raster line (6569)
1556
+
1557
+ ```
1558
+ cycle bus master access type
1559
+ 1 VIC p1 (sprite 3 pointer)
1560
+ 2 CPU phi2
1561
+ 3 VIC p2 (sprite 4 pointer)
1562
+ 4 CPU
1563
+ 5 VIC p3 (sprite 5 pointer)
1564
+ 6 CPU
1565
+ 7 VIC p4 (sprite 6 pointer)
1566
+ 8 CPU
1567
+ 9 VIC p7 (sprite 7 pointer); 9-10 s-accesses if active
1568
+ 11 CPU ; CPU runs freely if no badline
1569
+ ...
1570
+ 55 VIC g-access (last one of line)
1571
+ 56 CPU
1572
+ 57 VIC refresh
1573
+ 58 VIC p0 (sprite 0 pointer)
1574
+ 59 CPU
1575
+ 60 VIC p1 (sprite 1 pointer)
1576
+ 61 CPU
1577
+ 62 VIC p2 (sprite 2 pointer)
1578
+ 63 CPU ; last cycle of line on PAL
1579
+ ```
1580
+
1581
+ This is a simplified picture; the exact cycle each access happens on is
1582
+ documented in Bauer's article appendix.
1583
+
1584
+ ### PAL badline (40 stolen cycles)
1585
+
1586
+ ```
1587
+ cycle bus master notes
1588
+ 1-11 alternating
1589
+ 12 VIC sets BA low ; CPU has up to 3 more cycles to finish writes
1590
+ 13-14 CPU may finish writes
1591
+ 15 VIC takes bus ; first c-access
1592
+ 16-54 VIC ; 40 c-accesses total
1593
+ 55 CPU returns
1594
+ 56-63 alternating
1595
+ ```
1596
+
1597
+ Net effect: CPU loses 40-43 cycles depending on whether it was reading
1598
+ or writing when BA went low.
1599
+
1600
+ ### Y range visibility on PAL
1601
+
1602
+ | Y position | What you see |
1603
+ |-------------|-------------------------------------------|
1604
+ | 0–50 | Top border |
1605
+ | 51–250 | 25-row text display (RSEL = 1) |
1606
+ | 55–246 | 24-row text display (RSEL = 0) |
1607
+ | 251–311 | Bottom border |
1608
+ | 300–311 | Vertical blanking (no video output) |
1609
+
1610
+ A sprite's first row appears on the line AFTER its Y register value, so
1611
+ Y = 50 puts its top edge on line 51, the first line of the visible
1612
+ display, and the sprite Y range that lands inside the 25-row window is
1613
+ 50–249.
1614
+
1615
+ ### Effective CPU cycles per second
1616
+
1617
+ ```
1618
+ PAL 6569: 63 cycles/line * 312 lines * 50 Hz = 982,800 cycles/s nominal
1619
+ NTSC 6567: 65 cycles/line * 263 lines * ~60 Hz = 1,025,700 cycles/s nominal
1620
+ ```
1621
+
1622
+ Subtract 25 badlines × 40 stolen cycles × 50 Hz = 50,000 cycles/s for a
1623
+ typical text frame; the CPU effectively gets ~933,000 cycles/s on PAL.
1624
+ Sprites can subtract another 50–100K cycles/s if used heavily.
1625
+
1626
+ ## Pitfalls
1627
+
1628
+ - **Badline cycle steal**: any raster line where (raster ≥ $30 AND
1629
+ raster ≤ $F7 AND raster & 7 == YSCROLL AND DEN was set on line $30)
1630
+ steals 40-43 CPU cycles. A worst-case PAL line with 8 sprites and a
1631
+ badline leaves the CPU one guaranteed cycle — 43 + 19 = 62 of 63 stolen,
1632
+ measured in VICE x64sc (an earlier version of this bullet said ~14, which
1633
+ disagreed with this page's own 19-cycle sprite figure). See
1634
+ [raster-and-badline.md](../pitfalls/raster-and-badline.md)
1635
+ (`badline_cycle_loss`, `vic_bus_takeover_on_dma`).
1636
+ - **$D012 raster wrap**: comparing $D012 against ≥ 256 requires combining
1637
+ with $D011 bit 7. Forgetting the MSB makes raster IRQs misfire at
1638
+ line N mod 256 instead of line N. See
1639
+ [raster-and-badline.md](../pitfalls/raster-and-badline.md) (`d012_wrap_around`).
1640
+ - **Color RAM high nibble garbage**: reading $D800+n returns garbage in
1641
+ bits 4–7 — the byte the VIC fetched in the preceding phi1 cycle, not
1642
+ the address high byte. Always mask with #$0F. See
1643
+ [c64-registers-reference.md](c64-registers-reference.md) (Color RAM).
1644
+ - **Sprite DMA timing**: each sprite steals 2 bus cycles per line while
1645
+ its DMA is on (the two phi2 s-accesses; the p-access and the third
1646
+ s-access are phi1), plus 3 cycles of BA lead-in per contiguous group
1647
+ of active slots. Worst-case 19 stolen cycles on top of any badline. See
1648
+ [raster-and-badline.md](../pitfalls/raster-and-badline.md)
1649
+ (`vic_bus_takeover_on_dma`).
1650
+ - **Sprite crunch**: clearing a Y-expand bit ($D017) on one particular
1651
+ cycle (cycle 15 in VICE's PAL numbering, just before the cycle-16
1652
+ MCBASE step) of one of the sprite's display lines after the first
1653
+ changes the sprite's remaining length once, by a data-dependent amount
1654
+ — every crunch measured in VICE x64sc lengthened the sprite, by 4 to 21
1655
+ lines (an earlier version of this bullet said it shortened the sprite to
1656
+ ≤ 21 lines). Used intentionally for tricks; bites unwary multiplexer
1657
+ code. See [sprite.md](../pitfalls/sprite.md)
1658
+ (`sprite_y_expand_double_register_write`) and
1659
+ `sprite_y_stretch_glitch` in `techniques/sprite.md`.
1660
+ - **DEN must be set on line $30 (48)**: if $D011 bit 4 is clear for all
1661
+ of line 48, badlines are inhibited for the entire frame — a write
1662
+ setting it on any cycle of that line is enough to enable them (an
1663
+ earlier version of this bullet said "before cycle 14"); many effects
1664
+ rely on badlines firing, and you may not notice for a frame why the
1665
+ display has gone idle.
1666
+ - **$D011 read overlay**: reading $D011 returns the live raster MSB in
1667
+ bit 7, not the value you last wrote. To preserve other bits when
1668
+ writing raster targets, write the same bits you want; do not
1669
+ read-modify-write naively.
1670
+ - **$D019 acknowledgment**: IRQ latch bits in $D019 must be cleared by
1671
+ writing 1 (not 0) to the bit. Forgetting causes the IRQ handler to
1672
+ immediately re-enter.
1673
+ - **$D01E / $D01F read-to-clear**: collision registers clear when read,
1674
+ unlike $D019 which clears on write. Reading them in a debugger
1675
+ destroys live state.
1676
+ - **VIC bank vs CPU view**: the VIC-II's view of memory is independent
1677
+ of the CPU's $01 banking. Placing data at $D000–$DFFF and pointing
1678
+ the VIC at bank 3 makes it visible to the chip but not to the CPU
1679
+ (without further $01 manipulation).
1680
+ - **Character ROM only in banks 0 and 2**: in VIC banks 1 and 3 you must
1681
+ copy or generate a character set in RAM. Default PETSCII display will
1682
+ show garbage if you switch to bank 1 or 3 without preparing a charset.
1683
+ - **Sprite pointer location**: the eight sprite pointers always live at
1684
+ video_matrix_base + $3F8 inside the current VIC bank, *not* at a fixed
1685
+ CPU address. Moving the screen also moves the sprite pointer table.
1686
+ - **Mid-line mode switches**: ECM, BMM, MCM are sampled every cycle.
1687
+ Mid-line switches change pixels at character-cell boundaries; used for
1688
+ FLI, but a stray write during a badline can rewrite the row buffer in
1689
+ unexpected ways.
1690
+ - **NTSC R56A oddity**: the rare 6567 R56A NTSC chip has 262 lines and
1691
+ 64 cycles/line instead of the more common R8's 263/65. Code that
1692
+ hard-codes "65 cycles per line on NTSC" miscounts on the R56A.
1693
+ - **HMOS-II color differences**: 8565/8562 chips produce different shades
1694
+ for some colors (notably greys and reds). Pixel-exact graphics that
1695
+ rely on specific colors may look different on later C64C machines.
1696
+ - **$D02F unused**: writes to $D02F are silently ignored on the C64's
1697
+ VIC-II proper. The 8564/8566 VIC-IIe in the C128 uses this address as
1698
+ the extra-keyboard row select (K0–K2) and $D030 as the 2 MHz / test
1699
+ register (previously misdescribed here as a mode-control register); on
1700
+ the C64 both are dead.
1701
+
1702
+ ## Sources
1703
+
1704
+ - Christian Bauer, *The MOS 6567/6569 video controller (VIC-II) and its
1705
+ application in the Commodore 64*, July 1996. https://www.cebix.net/VIC-Article.txt
1706
+ - "VIC", C64-Wiki. https://www.c64-wiki.com/wiki/VIC
1707
+ - "Page 208-211" (VIC-II register list), C64-Wiki.
1708
+ https://www.c64-wiki.com/wiki/Page_208-211
1709
+ - Dustlayer, "VIC-II" tutorial series. https://www.dustlayer.com/vic-ii
1710
+ - "VIC-II", Codebase 64. https://codebase64.org/doku.php?id=base:vicii
1711
+ - Codebase 64 articles on stable rasters, sprite multiplexing, badline
1712
+ abuse, and the various display-mode tricks referenced above.
1713
+
1714
+ <!-- doc-type: hardware-reference -->