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,685 @@
1
+ ---
2
+ category: bitmap
3
+ chip: VIC-II
4
+ ---
5
+
6
+ <!-- doc-type: technique-reference -->
7
+
8
+ # Bitmap Modes
9
+
10
+ The VIC-II supports two hardware bitmap modes — standard hires and multicolor — each with its own memory layout, color resolution, and practical constraints. On top of these two fundamental modes, the scene has developed several scanline-switching techniques (FLI, AFLI, IFLI) that exploit the chip's internal video-matrix pipeline to push color fidelity far beyond what the hardware naively supports. This document covers the techniques in the bitmap family, from the simplest mode enable, a pixel plot and a line, through the most demanding interlaced scanline-switcher.
11
+
12
+ Understanding the bitmap modes thoroughly is a prerequisite before attempting FLI variants. The FLI family builds entirely on the standard bitmap addressing described here; a mistake in the memory layout will manifest as wrong colors in an FLI image just as much as in a plain bitmap.
13
+
14
+ ---
15
+
16
+ ## standard_bitmap — Standard bitmap mode
17
+
18
+ **Complexity:** low
19
+ **Region:** both
20
+ **Uses registers:** D011, D018
21
+ **Uses kernal:** (none)
22
+
23
+ ### Why
24
+
25
+ The default character mode gives only 40x25 cells with two colors per cell drawn from a shared character generator. Bitmap mode breaks that constraint: every one of the 64,000 pixels in the 320x200 display window is individually addressable in one of two colors chosen independently for each 8x8 cell. This is the foundation of all full-screen painted or rendered graphics on the C64.
26
+
27
+ ### How
28
+
29
+ Enable standard bitmap mode by setting bit 5 (BMM) of $D011 to 1. The VIC-II's display sequencer then treats the video data as raw pixel bits rather than character indices.
30
+
31
+ Two separate memory areas are required within the current 16 KB VIC bank:
32
+
33
+ - **Bitmap data**: 8000 bytes (320x200 / 8) arranged as 25 rows of 40 cells, each cell occupying 8 consecutive bytes (one byte per scanline within the cell). The base address is controlled by $D018 bit 3 (CB2): 0 places the bitmap at offset $0000 in the bank, 1 places it at $2000.
34
+ - **Screen RAM (video matrix)**: 1000 bytes at any 1 KB boundary within the VIC bank, selected by $D018 bits 7-4. Each screen RAM byte encodes the two colors for one 8x8 cell — the high nibble is the foreground color (set bits in bitmap), the low nibble is the background color (clear bits).
35
+
36
+ Color RAM ($D800-$DBFF) is not read in standard bitmap mode.
37
+
38
+ The cell layout inside the bitmap is row-major: cell (col, row) starts at byte offset `(row * 40 + col) * 8` within the bitmap area. Bit 7 of each bitmap byte is the leftmost pixel in that scanline row of the cell.
39
+
40
+ To set up a standard bitmap:
41
+ 1. Write the screen RAM with color nibbles for all 1000 cells.
42
+ 2. Write pixel data into the 8000-byte bitmap area.
43
+ 3. Write $D018 with the correct VM (screen RAM) and CB (bitmap base) nibbles.
44
+ 4. Set $D011 bit 5 to 1.
45
+
46
+ ### Why it works
47
+
48
+ In standard text mode the chip's g-access fetches a byte from the character generator ROM or RAM. In bitmap mode the same g-access mechanism reads sequentially from the 8000-byte bitmap area instead — the chip simply treats the bitmap as a 40x25x8 character set in which every character has a unique glyph. The per-cell two-color attribute lives in the video matrix (screen RAM), which the chip fetches on each badline exactly as it does in text mode. The only difference is which pixel source the chip reads on g-access cycles.
49
+
50
+ ### Variations
51
+
52
+ **Split-screen hires/text**: program a raster IRQ to toggle $D011 bit 5 at the desired scanline boundary. This gives a bitmap area above and a text area below (or vice versa) within the same frame. Remember to update $D018 if the screen RAM positions differ between the two halves.
53
+
54
+ **Two-bitmap pages**: keep two 8000-byte areas at $0000 and $2000 in the VIC bank and alternate $D018 bit 3 each frame for double-buffering. Allows one page to be drawn while the other is displayed, eliminating partial-frame tearing.
55
+
56
+ **Single-colour full bitmap**: fill every screen RAM byte with the same value whose two nibbles differ (e.g. $10 = white ink on black), so the whole 320x200 area is one two-colour canvas; then the bitmap bits alone draw the picture. (Equal nibbles make ink and paper the same colour and the drawing disappears — an earlier version of this paragraph said to make them equal. Measured in VICE x64sc: screen byte $12 renders bitmap $FF white and $00 red.)
57
+
58
+ ### Cycle budget
59
+
60
+ Standard bitmap mode does not change the cycle budget versus text mode. Badlines still occur on the same schedule (every 8 visible lines, wherever YSCROLL aligns them), each costing 40-43 CPU cycles. With no sprites active, a non-badline gives the CPU all 63 PAL cycles (65 NTSC).
61
+
62
+ Drawing into the bitmap from the main program is safe in the vertical blank or in the overscan region. Modifying bitmap bytes while those cells are being rendered produces visible tearing.
63
+
64
+ ### Recipes
65
+
66
+ - `recipes/kickassembler/hires-plot-line.md` — the hires setup ($D018 = $18, $D016 = $08, $D011 = $3B) with screen RAM set to white on black, then plots and lines into it.
67
+ - `recipes/oscar64/bitmap-koala-viewer.md` sets up $D018 and BMM for the multicolour case; the hires setup differs only in $D016.
68
+
69
+ ---
70
+
71
+ ## hires_plot — Set one pixel in a hires bitmap through a row table and a mask table
72
+
73
+ **Complexity:** low
74
+ **Region:** both
75
+ **Uses registers:** D011, D016, D018
76
+ **Uses kernal:** (none)
77
+ **Requires:** standard_bitmap
78
+ **Cost:** cycles_per_frame=63
79
+ **Cost basis:** measured-vice
80
+
81
+ ### Why
82
+
83
+ A hires bitmap is 8000 bytes laid out cell by cell, not scanline by scanline, so the byte that holds pixel (x, y) is not `y * 40 + x / 8`. Working the address out from scratch on each plot means a multiply by 320; a plot is the inner step of every line, circle and fill routine, so it has to be a table lookup and a handful of adds.
84
+
85
+ ### How
86
+
87
+ Two tables, built at assembly time:
88
+
89
+ - A row address table with one 16-bit entry per y from 0 to 199: `BITMAP + (y / 8) * 320 + (y & 7)`. That is the address of the leftmost byte on scanline y. Store low bytes in one table and high bytes in another so each is indexed by y in one instruction.
90
+ - A mask table with one byte per x & 7: `$80, $40, $20, $10, $08, $04, $02, $01`. Bit 7 is the leftmost pixel of a byte.
91
+
92
+ The plot, with x in 16 bits because it reaches 319:
93
+
94
+ 1. Take `x & $F8`. That is the column times eight, which is also the byte offset of that column's cell within the row, because each cell is eight bytes.
95
+ 2. Add it to the row table's low byte for y; add x's high byte to the row table's high byte with the carry. The result is the address of the byte holding the pixel.
96
+ 3. Read the byte, `ORA` the mask for `x & 7`, write it back.
97
+
98
+ ```text
99
+ ldy y
100
+ lda x_lo
101
+ and #$f8
102
+ clc
103
+ adc row_lo,y
104
+ sta ptr
105
+ lda row_hi,y
106
+ adc x_hi
107
+ sta ptr + 1
108
+ lda x_lo
109
+ and #$07
110
+ tax
111
+ lda mask,x
112
+ ldy #0
113
+ ora (ptr),y
114
+ sta (ptr),y
115
+ ```
116
+
117
+ Put each row table in its own page (`.align $100` in KickAssembler). `LDA abs,Y` costs one cycle more when the index carries into the next page; with the tables unaligned, the recipe's plot measured 65 cycles at y = 199 instead of 63.
118
+
119
+ ### Why it works
120
+
121
+ The VIC-II fetches the bitmap in the same order it fetches a character set: on each badline it reads 40 screen RAM bytes, and on the eight lines that follow it reads one byte per cell per line, walking eight bytes per cell. So the eight bytes of a cell are consecutive, a row of 40 cells is 320 consecutive bytes, and the address arithmetic above is the fetch order inverted. `$D018` bit 3 chooses `$0000` or `$2000` within the VIC bank as the base; `$D011` bit 5 turns bitmap mode on; `$D016` bit 4 clear keeps it hires, one bit per pixel. Screen RAM supplies the ink and paper nibbles per cell and is not touched by the plot, so a canvas of one ink colour is set up once.
122
+
123
+ ### Variations
124
+
125
+ **Multicolour plot.** In multicolour bitmap mode a pixel is two bits wide and x runs 0 to 159. The byte is `row + (x & $FC) * 2`, which is the column times eight; the doubling can carry out of the low byte for x of 128 and above, so add it in 16 bits or use a 40-entry column table. The mask table has four entries, `$C0, $30, $0C, $03`, indexed by `x & 3`, and the colour value is shifted into the same two bits. Clear with `AND` of the inverted mask, then `ORA` the shifted colour, so a plot can set any of the four colours and not just turn a bit on.
126
+
127
+ **Erase list.** An animated shape drawn with plots is cheapest to remove by replaying its own plots with `AND` of the inverted mask (an `unplot`). Record each plotted address and mask in a list as the shape is drawn; clearing the whole 8000 bytes costs about 8 cycles a byte, an erase list costs one `unplot` per pixel.
128
+
129
+ **Plot without the high byte.** A routine that only ever plots x below 256 can drop `x_hi` and the second `adc`; the mask and row tables are unchanged.
130
+
131
+ ### Cycle budget
132
+
133
+ 63 cycles for `jsr` and `rts` included, with both tables page-aligned, measured with CIA1 timer A in the `hires-plot-line` recipe with the display blanked; the instruction table gives the same 63. With the display on, a badline under the plot adds 40 to 43 cycles on the CIA's count without making the plot slower. Nothing here depends on the raster position; drawing is safe while the cells being written are not being fetched.
134
+
135
+ ### Recipes
136
+
137
+ - `recipes/kickassembler/hires-plot-line.md` — the tables, the plot, timed, and 2,056 pixels counted back out of the bitmap.
138
+
139
+ ---
140
+
141
+ ## bresenham_line — Straight line by Bresenham's error term, all eight octants
142
+
143
+ **Complexity:** medium
144
+ **Region:** both
145
+ **Uses kernal:** (none)
146
+ **Requires:** hires_plot
147
+ **Cost:** cycles_per_frame=43606
148
+ **Cost basis:** measured-vice
149
+
150
+ ### Why
151
+
152
+ A line between two pixels has one pixel per step along its longer axis, and the shorter axis moves a fraction of a pixel per step. Keeping that fraction as a fixed-point value works but costs a 16-bit add per step and a division at setup. Bresenham's form keeps an integer error term whose sign says when the minor axis is due to move, needs no division, and every pixel it picks is the one nearest the ideal line.
153
+
154
+ ### How
155
+
156
+ Given (x0, y0) to (x1, y1):
157
+
158
+ 1. `dx = |x1 - x0|`, `dy = |y1 - y0|`, and a step of +1 or -1 for each axis from the signs. x needs 16 bits on a 320-wide bitmap; y fits 8, but a difference of two y values reaches -199, so take it in 16 bits too or sign-extend with care.
159
+ 2. The major axis is the one with the larger delta. Two loops, one for each, are simpler and faster than one loop that swaps roles.
160
+ 3. Error term `err = 2 * minor - major`, kept in 16 bits with the doubled deltas precomputed.
161
+ 4. Loop `major + 1` times: plot; if the count is spent, stop; if `err >= 0`, step the minor axis and `err -= 2 * major`; then `err += 2 * minor` and step the major axis.
162
+
163
+ The sign test is `LDA err_hi : BMI skip`. The term stays within about -640 to +640 for any line on this screen, so bit 7 of the high byte is the true sign and no overflow case arises. The count is `major`, tested for zero before decrementing, so the last pixel is the end point in every octant and the count of pixels is `max(dx, dy) + 1`.
164
+
165
+ ```text
166
+ shallow_loop:
167
+ jsr plot
168
+ lda n : ora n + 1 : beq done
169
+ (n = n - 1)
170
+ lda err + 1
171
+ bmi no_y
172
+ (y = y + sy ; err = err - dx2)
173
+ no_y:
174
+ (err = err + dy2 ; x = x + sx)
175
+ jmp shallow_loop
176
+ ```
177
+
178
+ ### Why it works
179
+
180
+ The error term is twice the signed distance between the ideal line and the pixel just plotted, measured along the minor axis in units of a pixel. Doubling keeps the half-pixel threshold an integer. Each major step moves the ideal line `minor / major` of a pixel, so adding `2 * minor` to a term that was scaled by `major` is that move; when the term reaches zero the ideal line has passed the half-way point, the minor axis steps, and subtracting `2 * major` recentres the term on the new pixel. Because only the sign is ever tested and the term is bounded by the deltas, 16 bits are enough and the test is one branch on one byte.
181
+
182
+ ### Variations
183
+
184
+ **Clipped line.** Test each end point against 0 to 319 and 0 to 199 before drawing. A line with both ends inside never leaves the screen, because Bresenham's pixels lie between its end points on both axes. For a line with an end outside, clip the end point to the edge first (Cohen-Sutherland style code, not on this page) rather than testing every pixel; a per-pixel test doubles the loop cost.
185
+
186
+ **Erase list.** Record each pixel's address and mask as the line is drawn and replay the list with `AND` to remove it; see the erase-list variation of `hires_plot`.
187
+
188
+ **8-bit error term.** When the larger delta is below 64 the term and the doubled deltas fit a signed byte: the term stays within twice the major delta, so 126 at most, and the two 16-bit adds become one 8-bit add each, saving about 12 cycles a step. A line whose larger delta is 64 or more overflows the byte and the sign test then reads the wrong way (`pitfalls/cpu.md`, `signed_compare_bmi_overflow`); guard the setup, do not assume the caller did.
189
+
190
+ ### Cycle budget
191
+
192
+ Measured with CIA1 timer A in the `hires-plot-line` recipe, display blanked, VICE x64sc, identical on PAL and NTSC: 214 cycles for a one-pixel line (setup, first plot, exit test) and 43,606 for the 320-pixel flat line along the bottom row, the longest line the screen holds. A sweep of flat lines from 2 to 320 pixels fits 214 + 136 per further pixel, plus 4 when the step count's low byte passes zero and 4 when x crosses 255. The 136 is 63 for the plot and 73 for the step, by the instruction table. A steep line costs the same step less the `jsr step_x`, about 130, when its major axis is y. Both figures are for the recipe's layout: the same loop with its `bne` sitting on `$0AFC` and its target on `$0B00` measured 43,925, one cycle more per step (`pitfalls/cpu.md`, `branch_page_cross_extra_cycle`). A frame of 19,656 PAL cycles holds about 140 pixels of line drawn this way; a game that draws more than that per frame unrolls the plot into the loop or draws across frames.
193
+
194
+ ### Recipes
195
+
196
+ - `recipes/kickassembler/hires-plot-line.md` — eleven lines in every direction, the longest one timed, and the set-bit count checked against the endpoints.
197
+
198
+ ---
199
+
200
+ ## multicolor_bitmap — Multicolor bitmap (MCM)
201
+
202
+ **Complexity:** low
203
+ **Region:** both
204
+ **Uses registers:** D011, D016, D018
205
+ **Uses kernal:** (none)
206
+
207
+ ### Why
208
+
209
+ Standard bitmap mode gives 320x200 pixel resolution with only two colors per 8x8 cell. Many full-screen paintings require more than two colors per cell. Multicolor bitmap trades horizontal resolution for additional colors: each 8x8 cell gets four independent colors, at the cost of halving horizontal resolution to 160x200 (each displayed pixel is two bits wide).
210
+
211
+ The overwhelming majority of "C64 art" seen online — artwork from Koala Painter, Advanced Art Studio, PETSCII editors set to bitmap mode — is multicolor bitmap.
212
+
213
+ ### How
214
+
215
+ Enable multicolor bitmap by setting both bit 5 of $D011 (BMM) and bit 4 of $D016 (MCM) to 1.
216
+
217
+ The same 8000-byte bitmap and 1000-byte screen RAM areas are used as in standard bitmap mode, with identical addressing. The chip now interprets each byte of bitmap data as four 2-bit pixels instead of eight 1-bit pixels.
218
+
219
+ Each 2-bit pattern in a bitmap byte maps to a color source:
220
+
221
+ | Pattern | Color source |
222
+ |---------|-------------|
223
+ | %00 | $D021 (BGCOL0) — shared global background |
224
+ | %01 | Screen RAM high nibble (per-cell) |
225
+ | %10 | Screen RAM low nibble (per-cell) |
226
+ | %11 | Color RAM nibble at matching cell position (per-cell) |
227
+
228
+ This gives three per-cell colors plus one global shared background, for a total of four colors per cell. The Color RAM nibble (%11 color) is read from $D800 indexed by cell position, same as in multicolor text mode.
229
+
230
+ Because each pixel is two bits, each pixel row is still 40 bytes, one per cell, but each byte now yields four double-wide pixels, so a row is 160 pixels and the bitmap remains 8000 bytes — byte layout is unchanged, only interpretation differs. (An earlier version described this as "40 cells x 4 bytes per horizontal tile", which is not the layout.)
231
+
232
+ ### Why it works
233
+
234
+ The multicolor bit in $D016 changes how the chip interprets the pixel shift register during g-access rendering. Instead of emitting one bit per pixel clock (hires: eight 1-clock pixels per byte), the chip takes two bits every second pixel clock and holds each 2-bit pair on the output for two clocks (four 2-clock pixels per byte). A byte still lasts the eight clocks of its cell — measured in VICE x64sc, the four pairs of one byte span the full 8-pixel cell width; an earlier version said "4 clocks per byte". The two-bit pattern is decoded through the four-entry color lookup described above. All other chip mechanics — badlines, video matrix fetches, memory banking — are unchanged.
235
+
236
+ ### Variations
237
+
238
+ **Mixed hires/multicolor bitmap**: you cannot mix per-cell within a single bitmap frame using only these two mode bits. However, you can do a full-frame mode switch via raster IRQ between a hires region and a multicolor region.
239
+
240
+ **Programmatic color cycling**: write new values to $D021 or to screen RAM/Color RAM bytes during the vertical blank each frame. Changing $D021 shifts the %00 color across the entire bitmap simultaneously, a cheap way to animate background tones or produce global color washes.
241
+
242
+ **Koala-format integration**: Koala Painter's .kla file format encodes a multicolor bitmap image directly as bitmap data + screen RAM + Color RAM + $D021 value. See `koala_format` below for load and display procedures.
243
+
244
+ ### Cycle budget
245
+
246
+ Multicolor bitmap mode has the same CPU cycle budget as standard bitmap mode. Badlines, sprite DMA, and VBI overhead are identical. There is no extra cost for the MCM pixel decoding — it is done entirely in VIC-II hardware.
247
+
248
+ ### Recipes
249
+
250
+ - `recipes/oscar64/bitmap-koala-viewer.md` — set up multicolor bitmap, populate screen/color RAM, display a static image.
251
+
252
+ ---
253
+
254
+ ## ecm_mode — Extended Color Mode (text only)
255
+
256
+ **Complexity:** low
257
+ **Region:** both
258
+ **Uses registers:** D011, D022, D023, D024
259
+ **Uses kernal:** (none)
260
+
261
+ ### Why
262
+
263
+ Standard text mode gives each character cell one foreground color and one global background color ($D021). For games that need distinct background regions — sky, ground, water — changing $D021 globally is too coarse. Extended Color Mode (ECM) allows four different background colors selectable per character cell, at the cost of reducing the usable character set from 256 to 64 glyphs.
264
+
265
+ ECM is a text mode, not a bitmap mode, but it belongs in this document because it shares the $D011 control register with the bitmap modes and is part of the full mode-bit matrix that technique writers must understand.
266
+
267
+ ### How
268
+
269
+ Enable ECM by setting bit 6 of $D011 to 1. BMM (bit 5) must remain 0; setting both ECM and BMM simultaneously produces one of the VIC-II's invalid (all-black) modes.
270
+
271
+ The top two bits of each character code byte in screen RAM are repurposed as a background selector rather than part of the glyph index. This means only character codes 0-63 address distinct glyphs; codes 64-127, 128-191, and 192-255 all display one of the 64 base glyphs but with a different background color:
272
+
273
+ | Code bits 7-6 | Background register |
274
+ |--------------|---------------------|
275
+ | %00 (codes 0-63) | $D021 (BGCOL0) |
276
+ | %01 (codes 64-127) | $D022 (BGCOL1) |
277
+ | %10 (codes 128-191) | $D023 (BGCOL2) |
278
+ | %11 (codes 192-255) | $D024 (BGCOL3) |
279
+
280
+ Foreground color for each cell still comes from Color RAM as in standard text mode. Sprite behavior, scroll registers, and all other VIC-II facilities work identically.
281
+
282
+ ### Why it works
283
+
284
+ The VIC-II character decoder reads the character pointer from the video matrix (c-access), passes the low 6 bits to the character generator for the glyph fetch (g-access), and uses bits 6-7 of the pointer to select which of the four background color registers drives the cell's background pixels. The character generator still has 64 rows of 8 bytes each; bits 6-7 never reach the address bus on glyph lookup.
285
+
286
+ ### Variations
287
+
288
+ **Platform game zones**: use codes 0-63 for sky-colored background, 64-127 for earth-colored cells, 128-191 for cave cells. The glyphs can be the same 64 tiles — only their background tint changes. This gives a cheap color-region effect with minimal code.
289
+
290
+ **ECM + sprite overlay**: since sprites render over the ECM background exactly as in text mode, a sprite-based player character requires no special handling. The ECM background acts as a colored playing field.
291
+
292
+ ### Cycle budget
293
+
294
+ ECM is a text mode; the cycle budget is identical to standard text mode. No additional register writes are needed per frame unless background colors need to change. Switching between ECM and standard text requires only a write to $D011.
295
+
296
+ ### Recipes
297
+
298
+ - No recipe yet for ECM zones.
299
+
300
+ ---
301
+
302
+ ## mcm_text — Multicolor Char Mode
303
+
304
+ **Complexity:** low
305
+ **Region:** both
306
+ **Uses registers:** D016, D018, D021, D022, D023
307
+ **Uses kernal:** (none)
308
+
309
+ ### Why
310
+
311
+ Standard text mode gives 8x8 hires character cells with two colors each. Sometimes you want per-cell multicolor character graphics — sprites are limited to 8 and are expensive in terms of DMA cycles; a custom character set with 4-color glyphs can render complex repeating graphics cheaply. Multicolor character mode gives 4x8 effective resolution per character cell (double-wide pixels) with four colors, three of which can be shared across all cells or chosen globally.
312
+
313
+ ### How
314
+
315
+ Enable multicolor character mode by setting bit 4 of $D016 (MCM) to 1. BMM ($D011 bit 5) must be 0.
316
+
317
+ The color assignment per cell depends on bit 3 of the Color RAM nibble for that cell:
318
+
319
+ - If Color RAM bit 3 is **0**, the cell renders as a standard hires character — 8x8, two colors (foreground = Color RAM bits 0-2, background = $D021). MCM has no effect on this cell.
320
+ - If Color RAM bit 3 is **1**, the cell renders as multicolor: 4x8 double-wide pixels, four colors:
321
+
322
+ | Pattern | Color source |
323
+ |---------|-------------|
324
+ | %00 | $D021 (BGCOL0) |
325
+ | %01 | $D022 (BGCOL1) |
326
+ | %10 | $D023 (BGCOL2) |
327
+ | %11 | Color RAM bits 0-2 (per-cell, 8 colors only) |
328
+
329
+ The glyph data is fetched from the character generator normally; the chip only changes how it interprets the bit patterns. Custom character sets work identically to text mode — set $D018 bits 3-1 to the desired character generator base, and populate that RAM with 8 bytes per glyph.
330
+
331
+ Note that %11 pattern in MCM text uses only the low 3 bits of Color RAM, giving 8 foreground choices (not 16). This contrasts with multicolor bitmap mode, where %11 uses all 4 Color RAM bits for 16 choices.
332
+
333
+ $D025/$D026 (sprite multicolour 0/1) were formerly listed in the Uses registers line because setup routines often write them alongside; they play no part in character MCM (measured in VICE x64sc: an MCM cell with $D025/$D026 set to distinct colours rendered only $D021/$D022/$D023/Colour-RAM) and have been removed from the Uses line.
334
+
335
+ ### Why it works
336
+
337
+ In the chip's pixel rendering path, the MCM bit in $D016 selects whether to clock the output shift register at 1 bit per clock (hires) or 2 bits per clock (multicolor). The per-cell opt-in through Color RAM bit 3 means the chip must check that bit every cell during rendering. The character generator fetch is otherwise unchanged — the same 8 bytes are read; the bit-pair interpretation happens in the output shift register, not the character generator.
338
+
339
+ ### Variations
340
+
341
+ **Mixed hires/multicolor cells**: set Color RAM bit 3 selectively so some cells render hires and others render multicolor. This allows a mix of fine-detail character graphics and color-rich multicolor ones in the same 40x25 grid.
342
+
343
+ **Animation through charset swaps**: switch $D018 bits 3-1 during the vertical blank to point to an alternate character set, giving full-screen character animation at 50/60 Hz without touching individual screen RAM bytes.
344
+
345
+ ### Cycle budget
346
+
347
+ MCM text mode has the same cycle budget as standard text mode. No per-frame overhead beyond the initial setup writes.
348
+
349
+ ### Recipes
350
+
351
+ - No recipe yet for a multicolour character set.
352
+
353
+ ---
354
+
355
+ ## fli_image — FLI (Flexible Line Interpretation)
356
+
357
+ **Complexity:** scene-tier
358
+ **Region:** PAL
359
+ **Uses registers:** D011, D018, D016
360
+ **Uses kernal:** (none)
361
+ **Demands:** cpu_every_line, constant_sprite_set
362
+ **Requires:** stable_raster_irq, multicolor_bitmap, vic_bank_select
363
+ **Raster band:** 45-251 (the fli-image recipe's first IRQ is on line 45; its last FLI line is 250 and the handler exits near cycle 50 of line 251)
364
+ **Cost:** cycles_per_line=63, lines_active=207, cycles_per_frame=13041, bytes_code=3488, bytes_data=16001, irq_slots=1
365
+ **Cost basis:** arithmetic
366
+ **Cost measured on:** kickassembler-fli-image
367
+ **Cost includes:** stable_raster_irq, double_irq
368
+ **Claims:** vic_raster_irq (owns), cia2_vic_bank (owns)
369
+ **Claims basis:** derived-listing
370
+
371
+ ### Why
372
+
373
+ Multicolor bitmap mode gives 160x200 pixels with only four colors per 8x8 cell. The constraint is that the VIC-II reuses the same screen RAM row for all 8 scanlines that make up one character row, meaning the per-cell color palette repeats 8 times vertically. An image with rich vertical color variation — a gradient, a portrait, a landscape — must compress 8 vertical pixels of color choice into a single screen RAM byte.
374
+
375
+ FLI (Flexible Line Interpretation) breaks this constraint by re-uploading new screen RAM values to the chip on every scanline. The result is that each of the 200 visible scanlines effectively has its own per-cell color palette. A multicolor FLI image has 160x200 pixels with up to 8000 unique color combinations (one per cell-per-line), versus MCM's 1000 cell palettes shared 8 lines each.
376
+
377
+ ### How
378
+
379
+ FLI makes *every* display line a badline. The chip only reloads its 40-entry
380
+ colour latch on a badline, and a badline is any line where `(line & 7) ==
381
+ YSCROLL`; so on each line the code writes YSCROLL = line & 7 into $D011, and
382
+ before that writes $D018 to point at the screen page that holds this line's
383
+ colours. Two writes per line, 200 lines, from one stable raster entry at the
384
+ top of the frame; there are no per-line interrupts, and could not be, since
385
+ a badline leaves the CPU 20 cycles.
386
+
387
+ The full FLI setup:
388
+
389
+ 1. Eight 1 KB screen RAM pages in the same 16 KB VIC bank as the bitmap
390
+ (line `l` uses page `l & 7`), each pre-filled with that line's colour
391
+ nibbles. With the bitmap at offset $2000 the eight screens fill offsets
392
+ $0000-$1FFF, and in banks 0 and 2 the VIC sees the character ROM at
393
+ offsets $1000-$1FFF (`memory-banking.md`, `../hardware/c64-memory-map.md`),
394
+ so this layout needs bank 1 or 3, selected through `$DD00`
395
+ (`vic_bank_select`). An earlier version said only that bank 0 was
396
+ crowded and that FLI displays "usually" live in bank 1 or 3.
397
+ 2. The 8000-byte multicolor bitmap at offset $2000 in the bank; $D016 with
398
+ MCM set.
399
+ 3. A stable raster IRQ (double IRQ) a few lines above the display, then a
400
+ delay to the first display line, which is a natural badline and stalls
401
+ the CPU to cycle 55 whatever the delay's exact length was.
402
+ 4. For each line from the second to the last, unrolled: `LDA #page / STA
403
+ $D018 / LDA #$38|(line&7) / STA $D011`, padded so the $D011 write's
404
+ badline condition arises on cycle 15. The CPU then stalls until cycle 55,
405
+ which is what makes each line's block start on the same cycle as the
406
+ last without any counting of the stall itself.
407
+
408
+ Why cycle 15 and not earlier: in cycle 14 the VIC resets its row counter RC
409
+ to 0 if the badline condition holds *in that cycle*. A condition already
410
+ true in cycle 14 on every line would keep RC at 0 and display the first
411
+ line of the first character row forever. With the previous line's YSCROLL
412
+ still in the register during cycle 14, the condition is false there, RC
413
+ counts normally and the rows advance; the write on 15 then triggers the
414
+ c-accesses late. Why not later: c-accesses start three cycles after BA
415
+ drops and skip the columns whose slot has passed, and those columns read
416
+ $FF. Cycle 15 loses three columns; every cycle later loses one more.
417
+
418
+ That is the FLI bug: the three leftmost character columns of every line
419
+ show colour $F in both nibbles, light grey (in multicolour mode, both the
420
+ %01 and %10 pixels). It is intrinsic to the method on the 6569 and the
421
+ 6567; FLI pictures cover it with sprites, a border, or content that does
422
+ not mind.
423
+
424
+ The colour resolution is 160x200 with four colours per 4x1 cell-line
425
+ (background, two from the line's screen page, one from Colour RAM, which is
426
+ not paged and stays per 8x8 cell), for 8000 distinct colour sets instead of
427
+ 1000.
428
+
429
+ ### Why it works
430
+
431
+ The VIC-II's c-access mechanism fetches 40 screen RAM bytes into an internal 40x12-bit latch during cycles 15-54 of each badline, and uses that latch for every line until the next badline. The address it fetches from is whatever $D018's VM bits say at the moment of each c-access. FLI forces a badline on every line and has $D018 already pointing at the line's page when the condition arises, so every line's latch is filled from a different page. The badline condition is evaluated every cycle, not only at the start of the line, which is what allows the code to *create* one mid-line with a $D011 write.
432
+
433
+ The stable raster entry is needed once, at the top: after that the natural badline on the first display line and the forced badlines on every line after it re-phase the CPU to cycle 55 each time, so the per-line code is straight-line and self-timing. Measured in VICE for `recipes/kickassembler/fli-image.md`: with the $D011 write placed for cycle 15 the picture shows three grey columns; one cycle later the grey band is a column to the right and column 0 keeps a stale colour; one cycle earlier the display repeats a row.
434
+
435
+ ### Variations
436
+
437
+ **Eight pages, not "reduced"**: an earlier version listed the eight-page layout here as a "reduced-bank" variation of a 200-page baseline; there was no such baseline. Eight pages is not a reduction of anything: a line needs 40 colour bytes, 200 lines need 8000, and eight 1 KB pages hold exactly that with page p, row r serving line 8r+p. Eight is also all that fits, since the pages must share the 16 KB VIC bank with the 8 KB bitmap and $D018's VM nibble reaches only 16 pages in a bank. The page is chosen by $D018, not by YSCROLL; YSCROLL only decides which line becomes a badline.
438
+
439
+ **FLI with static bitmap**: the bitmap data itself does not change per scanline. Only screen RAM rotates. This allows the bitmap to carry shape information while screen RAM carries the color information, making them independently editable in tools.
440
+
441
+ **Sprite overlay on FLI**: sprites are not affected by $D018 changes. Sprites render normally on top of or behind the FLI bitmap according to $D01B priority bits. This means a FLI background can coexist with sprite-based characters.
442
+
443
+ ### Cycle budget (PAL)
444
+
445
+ FLI on PAL, per display line:
446
+
447
+ - VIC bus: 40 cycles (15-54), BA low from 12.
448
+ - `LDA # / STA $D018 / LDA # / STA $D011`: 12 cycles, the last write on 15.
449
+ - Padding between the end of one line's stall (cycle 55) and the next
450
+ block: 11 cycles.
451
+ - Left for anything else: nothing. Sprites active in the FLI region would
452
+ add their own bus cycles and move the stall; music and logic run in the
453
+ 112 border lines.
454
+
455
+ The Cost line charges the whole band: lines 45 to 251 are 207 lines, and
456
+ 207 × 63 = 13,041 cycles a frame (arithmetic from the band). An earlier
457
+ Cost line said `lines_active=200` and 12,600: it counted the 200 FLI
458
+ lines, not the band the handler holds from its first IRQ to its exit.
459
+ The stable entry (`stable_raster_irq` by a double IRQ, step 3 above)
460
+ runs inside the band, so the Cost includes line names both and a budget
461
+ does not add them again.
462
+
463
+ The byte figures are KickAssembler 5.25's `-showmem` for the recipe
464
+ listing: code $0900-$169F is 3,488 bytes, and data is the one-byte
465
+ `saved_sp`, eight 1,000-byte screen pages and the 8,000-byte bitmap,
466
+ 16,001 bytes. An earlier Cost line said `bytes_code=3277` and
467
+ `bytes_data=16384`, which are 3.2 KB and 16 KB multiplied by 1,024, not
468
+ the segments, and its basis said `estimated`; every figure on the line is
469
+ now arithmetic or read off the listing, so the basis is `arithmetic`.
470
+
471
+ Code size: 16 bytes per line unrolled, 3.2 KB for 200 lines. The old
472
+ figure of "25-30 cycles per line" for an IRQ-per-line handler described
473
+ something that does not fit in a badline and was never run.
474
+
475
+ On NTSC the block structure is unchanged: the c-accesses still occupy cycles 15-54, the stall still ends on cycle 55 and the $D011 write must still land on cycle 15, so each line's padding grows by the line's extra cycles — `LINE_PAD` 13 on the 6567R8 (65 cycles) and 12 on the 6567R56A (64), instead of the recipe's 11. The entry delay spans three lines and grows the same way (`ENTRY_PAD` 204 on the 6567R8); with the PAL value the first two or three FLI lines come out wrong. Measured in VICE x64sc `-model ntsc` / `-model oldntsc`: with the PAL padding one grey column appears on the 6567R8; with 13 (12 on the R56A) the same three as PAL, and with the entry delay also lengthened the picture matches PAL line for line. (An earlier version of this paragraph spoke of "badline onset relative to IRQ fire"; there is no per-line IRQ in the method, so that named nothing.)
476
+
477
+ ### Recipes
478
+
479
+ - `recipes/kickassembler/fli-image.md` — full FLI display engine with stable raster, page rotation, and bitmap layout.
480
+
481
+ ---
482
+
483
+ ## afli_image — AFLI (Advanced FLI)
484
+
485
+ **Complexity:** scene-tier
486
+ **Region:** PAL
487
+ **Uses registers:** D011, D018
488
+ **Uses kernal:** (none)
489
+ **Demands:** cpu_every_line, constant_sprite_set
490
+ **Requires:** fli_image
491
+ **Raster band:** 45-251 (fli_image's engine, which How says this reuses unchanged)
492
+
493
+ ### Why
494
+
495
+ AFLI is hires FLI: the FLI trick applied to standard bitmap mode instead of multicolour. Plain hires gives 320x200 pixels but only two colours per 8x8 cell, both from the cell's screen RAM byte. Re-fetching screen RAM on every line, exactly as `fli_image` does, shrinks the attribute cell to 8x1: every line of every cell gets its own foreground and background pair. Each cell stays two-colour; dithering between adjacent pairs simulates more, and the result reads like 16-colour dithered PC graphics (`art/art-production-reference.md`, "AFLI — Advanced FLI (Hires FLI)", agrees and does not cite this page).
496
+
497
+ An earlier version of this section described AFLI as multicolour FLI plus a second 8 KB bitmap whose CB bit was toggled per line, giving "interleaved two-plane pixels". That was wrong: there is one bitmap, the mode is hires, and $D016's MCM bit stays clear. Its memory budget was also impossible — two 8 KB bitmaps at $0000 and $2000 fill a 16 KB VIC bank, leaving no room for the eight screen pages the same text required.
498
+
499
+ ### How
500
+
501
+ Layout: eight 1 KB screen pages at bank+$0000..$1FFF (line `l` uses page `l & 7`) and the 8000-byte hires bitmap at bank+$2000 — exactly the `fli_image` layout, 16 KB in total. Set BMM ($D011 bit 5) and leave MCM ($D016 bit 4) clear; the CB bit of $D018 is 1 throughout, only the VM nibble changes per line.
502
+
503
+ The per-line engine is `fli_image`'s, unchanged: one stable raster entry at the top of the frame, then an unrolled `LDA #page / STA $D018 / LDA #$38|(line&7) / STA $D011` block per line, the $D011 write making the badline condition true on cycle 15, the CPU stalled to cycle 55 on every line. Colour RAM is fetched by the c-access but not used in hires bitmap mode, so both colours of every 8x1 cell come from the line's screen page (high nibble foreground, low nibble background).
504
+
505
+ Koala Painter files are multicolour and are not AFLI source; AFLI pictures come from hires-FLI editors or converters that emit a hires bitmap plus eight screen pages.
506
+
507
+ ### Why it works
508
+
509
+ The VIC-II fills its 40-entry colour latch from the video matrix only on a badline, and in hires bitmap mode the two colours of a cell are the two nibbles of that latch entry. Forcing a badline on every line with $D018 already pointing at that line's page (see `fli_image`, "Why it works") refills the latch from a different page each line, so the two-colour attribute changes every line while the bitmap bit for line `l` of a cell is still read from its fixed place, `(row*320 + col*8 + (l & 7))`. The FLI bug is present as in multicolour FLI: the three leftmost columns of every line read $FF from the video matrix and show colour $F on colour $F, light grey.
510
+
511
+ ### Variations
512
+
513
+ **AFLI for portraits**: the technique is particularly effective for human faces and gradients where vertical colour resolution is most perceptually significant.
514
+
515
+ **Hires IFLI**: two AFLI frames alternated at frame rate, i.e. two bitmaps and two sets of eight screen pages (32 KB across two VIC banks); see `ifli_image`.
516
+
517
+ ### Cycle budget (PAL)
518
+
519
+ The cycle budget is identical to `fli_image`: two writes per line (`STA $D018`, `STA $D011`), the $D011 write making the badline condition true on cycle 15, nothing left over — the $D018 value carries more bits but the instruction costs the same four cycles. An earlier version said AFLI adds 2-4 cycles per line and that the write lands "before cycle 15"; neither is right. The 63-cycle line is 40 VIC bus + 12 block + 11 padding, so there is no slack, and a write effective on cycle 14 resets RC: measured in VICE x64sc (PAL) with the fli-image listing's bitmap rows alternating $55/$00, `LINE_PAD` 10 shows every line drawing bitmap row 0 and only two grey columns, `LINE_PAD` 11 shows the rows advancing and three grey columns.
520
+
521
+ ---
522
+
523
+ ## ifli_image — IFLI (Interlaced FLI)
524
+
525
+ **Complexity:** scene-tier
526
+ **Region:** PAL
527
+ **Uses registers:** D011, D018
528
+ **Uses kernal:** (none)
529
+ **Demands:** cpu_every_line, constant_sprite_set
530
+ **Requires:** fli_image
531
+ **Raster band:** 45-251 (fli_image's per-line engine only; the page does not say on which line the image swap runs)
532
+
533
+ ### Why
534
+
535
+ Even with FLI providing per-scanline color variation, the horizontal pixel resolution of multicolor bitmap remains 160 pixels. IFLI (Interlaced FLI) pushes effective resolution to 320x200 by rendering two different FLI frames on alternating PAL frames and relying on the display's phosphor persistence to blend them. The viewer perceives an image with more horizontal detail than either frame alone provides.
536
+
537
+ IFLI images are some of the highest-quality C64 artwork in the demoscene. The technique requires two complete, independently prepared FLI images and a precise frame-alternating engine.
538
+
539
+ ### How
540
+
541
+ IFLI requires two complete FLI images — each with its own 8000-byte bitmap and its own eight screen RAM pages — stored in memory simultaneously. Colour RAM is single and shared: there is one 1 KB at $D800, read by the VIC-II over its own bus regardless of $D018 or $DD00, and rewriting it between frames (1,000 bytes, at least 8,000 cycles) does not fit in the roughly 7,000-cycle PAL vertical blank the FLI engine leaves free. The %11 colour of each cell is therefore the same in both sub-frames, and IFLI image formats store a single Colour RAM block. (An earlier version of this sentence gave each sub-frame "a Color RAM state", contradicting the cycle budget below.) On even PAL frames, image A is displayed; on odd frames, image B. Alternating at 50 Hz with PAL phosphor persistence, the human eye integrates the two images.
542
+
543
+ The frame alternation is driven by a vertical blank IRQ (or a top-of-frame raster IRQ) that swaps the bank layout or bitmap/screen RAM addresses pointed to by $D018. Within each frame, the per-line FLI write block runs exactly as described in `fli_image`.
544
+
545
+ The two images are typically prepared as slightly horizontally-offset variants of the same source — image B shifted one pixel left or right relative to image A. The overlap creates the perception of 320-wide content. Preparing an IFLI pair from source art is a non-trivial image processing task; dedicated tools (IFLI converters) handle this.
546
+
547
+ ### Why it works
548
+
549
+ The VIC-II's output is a composite video signal. On a real CRT display, each scanline's phosphors retain charge for a fraction of a frame. When two similar images alternate at 50 Hz, the eye blends them in both spatial and temporal dimensions. The 160-pixel-wide multicolor pixels of each sub-frame appear to blend with the offset pixels of the opposite frame, creating the illusion of 320-pixel hires color content.
550
+
551
+ This does not work at the pixel buffer level — both frames are full multicolor bitmap images with the same 160x200 pixel grid. The resolution improvement is entirely perceptual, a property of the human visual system and the CRT. IFLI images do not look the same on LCD monitors without post-processing; dedicated IFLI-aware emulator display modes apply a blending filter to simulate the CRT integration.
552
+
553
+ ### Variations
554
+
555
+ **IFLI on NTSC**: the two sub-frames alternate at 30 Hz (60 Hz frame rate) instead of PAL's 25 Hz. The engine is the same; what differs is the per-line cycle count (65 vs 63), which lengthens the per-line padding by two cycles and needs its own cycle counting — see the NTSC note under `fli_image`. An earlier version of this paragraph said 30 Hz flickers *more* because it is "closer to the flicker-fusion threshold"; that mechanism was inverted (the threshold is the rate above which flicker is no longer seen, so being nearer to it from below means less visible flicker, not more) and nothing in this repo measures either standard. How visible the flicker is on PAL or NTSC is a display and viewer question, not measured here.
556
+
557
+ **Hires IFLI**: two hires-FLI (`afli_image`) frames alternated, i.e. two bitmaps and two sets of eight screen pages (32 KB across two VIC banks), doubling the effective colour resolution of the 8x1 cells. (An earlier version called this "IFLI with AFLI basis" and spoke of "four complete image planes"; it is two.)
558
+
559
+ **Single-frame IFLI display**: some demo effects display an IFLI pair for a fixed number of frames then freeze on one sub-frame, useful for a zooming-in effect where the image appears to sharpen as it holds.
560
+
561
+ ### Cycle budget (PAL)
562
+
563
+ IFLI's per-frame cycle budget is the same as FLI: one stable raster entry per frame and an unrolled two-write block per line — there is no per-line IRQ, and could not be (see `fli_image`; an earlier version of this sentence said "one stable raster IRQ per scanline"). The extra work is a handful of writes at the top of each frame to switch to the other image: since one FLI image (eight 1 KB screen pages plus an 8000-byte bitmap) fills a 16 KB VIC bank, the two images live in two banks and the swap is a $DD00 bank write, with the same unrolled $D018/$D011 block serving both. That is a few dozen cycles in the border lines.
564
+
565
+ The real cost of IFLI is not cycles but memory: two complete FLI images occupy roughly 2 x (8000 + 8 x 1000) = 32,000 bytes of VIC-accessible RAM, plus Color RAM, which is a fixed 1 KB at $D800 and shared between both sub-frames.
566
+
567
+ ---
568
+
569
+ ## mci_interlace_bitmap — MCI (Multicolour Interlace): two multicolour bitmaps alternated with a half-pixel shift
570
+
571
+ **Complexity:** medium
572
+ **Region:** both
573
+ **Uses registers:** D011, D012, D016, D018, DD00
574
+ **Uses kernal:** (none)
575
+ **Requires:** multicolor_bitmap, frame_sync_loop
576
+ **Cost:** cycles_per_frame=50, bytes_data=18000
577
+ **Cost basis:** measured-vice
578
+ **Cost measured on:** kickassembler-mci-interlace
579
+
580
+ ### Why
581
+
582
+ A multicolour bitmap has 160 pixels across, each two hires pixels wide, and four colours per cell. Showing two different multicolour bitmaps on alternate frames, with the second moved one hires pixel to the right, gives a display with any persistence a picture whose colour changes every hires pixel: twice the horizontal colour resolution of one frame, from plain multicolour bitmap hardware and a three-store switch each frame. The price is that each frame is shown at half the frame rate, 25 Hz on PAL and 30 Hz on NTSC, so wherever the two frames differ the picture flickers; how visible that is on a given display and to a given viewer is not measured here. MCI is the flat-bitmap member of the family whose per-line member is `ifli_image`.
583
+
584
+ ### How
585
+
586
+ Two multicolour bitmaps with their own screens, one per frame. They do not fit in one VIC bank: two 8000-byte bitmaps and two 1000-byte screens are 18,000 bytes and a bank is 16,384, so frame A lives in one bank and frame B in another (the recipe uses bank 1 for A, bitmap $6000 and screen $5C00, $D018 = $78, and bank 0 for B, bitmap $2000 and screen $0400, $D018 = $18; bank 0's character ROM shadow at $1000 to $1FFF touches neither). Colour RAM is one 1 KB block at $D800, read by the VIC-II whatever bank or $D018 is selected, so the %11 colour of every cell is the same in both frames; a converter preparing an MCI pair has two screen nibbles per cell per frame but one colour RAM nibble per cell for both, and the background $D021 is likewise one value unless it is changed in the blank as well.
587
+
588
+ Once per frame, below the display (`frame_sync_loop` on raster line 251, which is past the 200-line window on both models), the loop stores $DD00 for the bank, $D018 for the screen and bitmap, and $D016 whole: $D8 on even frames (MCM on, 40 columns, XSCROLL 0) and $D9 on odd frames (XSCROLL 1). XSCROLL moves the display in hires pixels and a multicolour pixel is two of them, so the odd frame is half a multicolour pixel to the right. The switch is made inside one raster line and the loop then waits for $D012 to leave that line, because a switch shorter than a line would otherwise match the same line twice and swap twice in one frame.
589
+
590
+ Measured in VICE x64sc on the `mci-interlace` recipe, which draws its own test card (eight two-colour bands with the colours swapped between the frames, and one diagonal at the same multicolour position in both bitmaps): the diagonal sits on columns 190 and 191 at row 134 in frame A and on 191 and 192 in frame B, one hires pixel apart at every measured row; with XSCROLL left at 0 on both frames (the control build) the two diagonals coincide at 190 and 191 and only the band colours alternate, a blend without the resolution gain. The pixel average of the two frames puts four distinct columns, pure colour, blend, the other pure colour, blend, where one frame has two; the numbers are on the recipe page. With XSCROLL 1 in 40-column mode the leftmost hires column shows the background colour, so frame B's column 32 is black on every row.
591
+
592
+ ### Why it works
593
+
594
+ The VIC-II fetches its bitmap and screen bytes from whichever 16 KB the $DD00 bits and $D018 name at the moment of the fetch, so a bank and pointer change made in the vertical blank takes effect cleanly on the next field with no copying; the two frames are both complete pictures in memory all the time. XSCROLL delays the start of pixel output by up to seven hires clocks for the whole display, and in multicolour mode the shift register still emits its pairs two clocks wide, so a shift of one clock puts frame B's pixel boundaries exactly between frame A's. On a display with persistence, or in the eye, the two fields add, and each hires column of the sum carries either one frame's colour where the two agree or the mean of the two where they differ. That is the same perceptual mechanism as `ifli_image`, which adds the per-line colour changes of FLI to it; MCI keeps the plain 8x8 cell colour limits and gets its gain from the alternation alone. The improvement is not in the frame buffer: each field is still a 160-pixel-wide multicolour picture, and VICE's exit screenshot shows one field at a time.
595
+
596
+ ### Cycle budget
597
+
598
+ Measured with CIA1 timer A on the recipe, the same on PAL and NTSC: 34 cycles on the even frame and 32 on the odd from the timer start after the $D012 match to the read after the last of the three stores (the even path takes a `jmp` the odd path does not), plus 16 from the match to the timer start by the instruction table, so 50 cycles from the raster match to the last store. With the two polls of $D012 the loop is under two raster lines a frame and the rest of the frame is free for other work. Memory, not time, is the cost: 18,000 bytes of bitmaps and screens in two VIC banks, plus the shared 1 KB of colour RAM.
599
+
600
+ ### Variations
601
+
602
+ **IFLI.** The per-line cousin: two FLI pictures alternated the same way, with eight screen pages per frame and a stable raster engine rewriting $D018 every line; see `ifli_image`. It needs two banks for the same reason MCI does, and inherits FLI's cpu_every_line demand, where MCI leaves the frame free.
603
+
604
+ **Switch on a raster line inside the frame.** Making the bank and $D018 change at a line inside the display instead of below it gives a picture whose upper part is one frame and lower part the other for that field, so the interlaced region can be confined to a band of lines and the rest of the screen held static and flicker-free; the switch line must then be the same every frame, in the border of the line, or the join tears.
605
+
606
+ **Same bitmap, shifted.** Alternating one bitmap with itself, XSCROLL 0 and 1 on alternate frames, blends each multicolour pixel with its neighbour and reads as a soft 320-wide picture with no second bitmap and no second bank; the colour count does not rise, only the edges smear, and the flicker is confined to colour boundaries.
607
+
608
+ ### Pitfalls
609
+
610
+ - `d016_unmasked_rmw_clobbers_csel_mcm` (`pitfalls/scroll.md`): the switch writes $D016 whole every frame; write it from a constant that carries MCM and CSEL, as the recipe does, not from the XSCROLL value alone.
611
+ - `vic_bank_visibility_collision` (`pitfalls/banking.md`): each frame's bitmap and screen must be inside the bank that frame selects, and the two banks are switched with $DD00 every frame; a bitmap or screen placed in the other bank, or a pair that does not fit in one, shows garbage on that frame only, which flickers at 25 Hz and reads as a timing fault.
612
+
613
+ ### Recipes
614
+
615
+ - `recipes/kickassembler/mci-interlace.md` — two banks, a self-drawn test card, the half-pixel measured against a control, the frame-loop cost timed, and a PIL average of the two fields.
616
+
617
+ ---
618
+
619
+ ## koala_format — Koala Painter format load and display
620
+
621
+ **Complexity:** low
622
+ **Region:** both
623
+ **Uses registers:** D011, D016, D018, D021
624
+ **Uses kernal:** (none)
625
+
626
+ ### Why
627
+
628
+ Koala Painter (1984) was the dominant C64 painting tool throughout the 1980s and into the 1990s. Its file format became the de facto interchange format for C64 multicolor bitmap images. An enormous corpus of C64 artwork survives in .kla format. Any program or demo that needs to display arbitrary C64 artwork must be able to parse and display Koala files.
629
+
630
+ Beyond historical importance, the Koala format is also the most compact and direct representation of a multicolor bitmap image. Understanding it means understanding the precise relationship between bitmap data, screen RAM, Color RAM, and the background color register.
631
+
632
+ ### How
633
+
634
+ A Koala Painter file has the following structure:
635
+
636
+ | Offset | Size | Content |
637
+ |--------|------|---------|
638
+ | 0x0000 | 2 | Load address, little-endian (typically $6000 or $0000) |
639
+ | 0x0002 | 8000 | Bitmap data, 320x200 / 8 bytes |
640
+ | 0x1F42 | 1000 | Screen RAM (video matrix), 40x25 color nibbles |
641
+ | 0x232A | 1000 | Color RAM, 40x25 color nibbles |
642
+ | 0x2712 | 1 | Background color ($D021 value) |
643
+
644
+ Total file size: 10003 bytes (with 2-byte load address) or 10001 bytes (raw, some variants omit the load address).
645
+
646
+ The load address at offset 0 is a standard C64 PRG-format header — two bytes little-endian indicating where the file should be loaded in CPU address space. Koala Painter itself loads the file to $6000, placing bitmap at $6000, screen RAM at $7F40, Color RAM at $8328, and background byte at $8710. These addresses are commonly used by display loaders to avoid the need to parse the header.
647
+
648
+ **Display procedure**:
649
+
650
+ 1. Copy the 8000-byte bitmap to the desired bitmap location in the VIC bank (typically $2000 or $6000).
651
+ 2. Copy the 1000-byte screen RAM segment to the VIC bank's video matrix location.
652
+ 3. Copy the 1000-byte Color RAM segment to $D800.
653
+ 4. Read the single background color byte and write it to $D021.
654
+ 5. Update $D018 to point the VIC at the bitmap and video matrix locations.
655
+ 6. Set $D011 bit 5 (BMM) and $D016 bit 4 (MCM) to enable multicolor bitmap mode.
656
+
657
+ ### Why it works
658
+
659
+ The Koala format is a direct serialization of the three memory regions that multicolor bitmap mode reads during rendering. The bitmap data feeds g-accesses directly; screen RAM feeds c-accesses on badlines; Color RAM is read separately by the chip at cycle granularity as $D800 + cell_offset. The background byte goes to $D021, which the chip reads for the %00 color on every rendered pixel. Placing these exactly as the format specifies and enabling the two mode bits produces the image immediately.
660
+
661
+ The VIC bank and $D018 pointer configuration determines where in the 64 KB address space the chip looks. If loading to $6000 (within VIC bank 1, CIA2 $DD00 bits = %10), the bitmap is at bank-offset $2000, placing $D018 CB2 = 1. The screen data at $7F40 is at bank-offset $3F40, which is not on a 1 KB boundary ($3F40 mod $400 = $340), so no $D018 VM value can point the VIC at it in place; the nearest page, VM = %1111, is $7C00. The offset $1F40 is itself $340 past a 1 KB boundary, so no 8 KB-aligned load address puts both the bitmap and the screen block where $D018 can reach them. The bitmap can stay at $6000 (bank 1, CB = 1), but the screen block must be copied to a 1 KB-aligned page in the same bank that does not overlap the bitmap ($4000-$5C00, i.e. VM = %0000-%0111), and Color RAM to $D800 in any case. Most display loaders simply copy all three blocks to a clean layout, as below. (An earlier version said the screen offset "rounds to $3C00"; it does not round, and the page at $7C00 holds no Koala data.)
662
+
663
+ For Oscar64 programs, the recommended approach is to copy the Koala bitmap to $2000 in bank 0 (VIC offset $2000), screen RAM to $0400 (VIC offset $0400), and Color RAM directly to $D800, then set $D018 = $18 (VM = 1 = $0400, CB = bit 3 = 1 = $2000 bitmap). This keeps the VIC configuration simple and predictable.
664
+
665
+ ### Variations
666
+
667
+ **Streaming from disk**: load the Koala file in the background using a turbo loader while displaying a placeholder screen, then swap in the bitmap on a VBI boundary. The Koala layout is sequential enough that the copy sequence is also the disk read order.
668
+
669
+ **Koala animation**: $D018 can only place a bitmap at offset $0000 or $2000 of the current 16 KB bank (bit 3; bits 1-2 are ignored in bitmap mode — measured in VICE x64sc), and two 8000-byte bitmaps leave only two 192-byte gaps, neither a 1 KB-aligned block for a second screen RAM page, so two complete frames do not fit one bank. In practice each resident frame lives in its own VIC bank (bitmap at offset $2000 in banks 0 and 2 to avoid the character ROM shadow at $1000-$1FFF/$9000-$9FFF), selected by $DD00 bits 0-1 and $D018 together — at most four frames resident at once. $D018/$DD00 redirect only the bitmap and video matrix: each frame's 1,000-byte Colour RAM block must still be copied to $D800 (about 8,000 cycles unrolled, LDA abs/STA abs) and its background byte written to $D021. With frames resident the flip itself is cheap; loading from disk is the limit, which is where the practical 6-10 fps comes from. (Earlier text said several frames could be flipped by $D018 alone.)
670
+
671
+ **Koala + sprite overlay**: because sprites are independent of bitmap mode, a Koala image can serve as a full-screen background with sprite-based animated foreground elements. Set $D01B appropriately for depth ordering.
672
+
673
+ **Paletted color shift**: write a different value to $D021 each frame without touching the bitmap or screen RAM. This shifts the background tone of the entire image, producing a cheap palette animation that works on any Koala image. Similarly, writing to screen RAM nibbles mid-frame or between frames alters the per-cell %01/%10 colors.
674
+
675
+ ### Cycle budget
676
+
677
+ Koala display is not cycle-sensitive once the mode is enabled, but the copy is not small. Measured in VICE x64sc (PAL, CIA timer, screen blanked): a basic indexed page loop (LDA abs,X / STA abs,X / INX / BNE, 14 cycles per byte) copies the 10,000 bytes in about 140,000 cycles, and a fully unrolled LDA abs / STA abs copy costs 8 cycles per byte, 80,000 cycles for the whole image (and 60 KB of code, so in practice a partially unrolled loop lands between the two). With the screen on, badline DMA adds roughly 6 % more. That is four to seven PAL frames of 19,656 cycles; it does not fit the 7,056-cycle vertical border (112 lines x 63, lines 0-50 and 251-311). Copy before enabling BMM, or with the screen blanked (DEN = 0), and only then set $D018/$D011/$D016. Only the bitmap can be displayed in place: a file loaded at $6000 puts it at an 8 KB-aligned offset in bank 1, but the screen RAM that follows at +$1F40 is never 1 KB-aligned when the bitmap is 8 KB-aligned, and Color RAM must always be copied to $D800. An earlier version of this page gave 10,000-12,000 cycles for the copy and a 3,900-cycle VBI window; both were wrong.
678
+
679
+ For real-time conversion from disk, the raw data rate of the 1541 (approximately 300 bytes/second with standard KERNAL I/O, or 4000-6000 bytes/second with a turbo loader) dominates the timing. Full Koala loads via standard KERNAL take approximately 33 seconds; turbo-loaded Koala files load in under 3 seconds.
680
+
681
+ ### Recipes
682
+
683
+ - `recipes/oscar64/bitmap-koala-viewer.md` — embed a .kla file, copy it to display RAM, enable multicolor bitmap mode.
684
+
685
+ <!-- doc-type: technique-reference -->