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,738 @@
1
+ ---
2
+ category: sid
3
+ ---
4
+
5
+ <!-- doc-type: pitfall-reference -->
6
+
7
+ # SID Pitfalls
8
+
9
+ The MOS 6581/8580 SID chip has a register interface that looks
10
+ straightforward on paper but hides several hardware-level traps that
11
+ catch even experienced composers and coders. These pitfalls fall into
12
+ two clusters: the write-only nature of the entire register bank
13
+ (which forces a shadow-RAM discipline on all SID code), and the
14
+ substantial behavioral differences between the two SID revisions
15
+ (which means a song or digi routine calibrated on a 6581 can fail
16
+ audibly on an 8580, or vice versa). The ADSR-reset bug and the voice-3
17
+ silent-bit divergence are both in the second cluster, and both have
18
+ safe workarounds that are easy to apply once you understand the
19
+ underlying mechanism. SID replacements that do not emulate the read side (the
20
+ SwinSID) are a separate case: `sid_replacement_d41b_unreadable`.
21
+
22
+ All pitfalls in this document apply equally to PAL and NTSC
23
+ systems; none of them are timing-region-specific. The filter cutoff
24
+ curve pitfall is the most musically impactful and deserves particular
25
+ attention when writing cross-compatible SID music.
26
+
27
+ ---
28
+
29
+ ## sid_write_only_registers — All SID registers $D400-$D418 are write-only; reads return garbage
30
+
31
+ **Severity:** medium
32
+ **Region:** both
33
+ **Triggered by registers:** D400, D404, D40B, D412, D418
34
+ **Triggered by techniques:** sfx_engine_beside_music, sidfx_layered_chip, sfx_in_player, digi_4bit, sidasid_emulation_notes
35
+
36
+ ### Symptom
37
+
38
+ Code that reads a SID control register expecting to see what was
39
+ previously written instead gets corrupted data — the last byte
40
+ written to (or read from) the SID, not the register's value (an
41
+ earlier version of this sentence said "the high byte of the read
42
+ address, the last byte the VIC-II fetched, or floating-bus noise";
43
+ neither of the first two ever appears). A read-modify-write pattern like "set bit 3 of
44
+ $D418 without touching the other bits" silently destroys the filter
45
+ mode and volume settings if no shadow register is maintained.
46
+ The failure mode is usually silent (the wrong register value takes
47
+ effect immediately, but there is no error signal) or manifests as
48
+ audio glitches: a filter sweep that jumps to the wrong cutoff, a
49
+ volume register that changes the master volume mid-note, or a voice
50
+ control register that clears the GATE bit unintentionally.
51
+
52
+ ### Mechanism
53
+
54
+ The SID chip ($D400-$D41F) exposes 25 write-only registers at
55
+ $D400-$D418 (an earlier version of this sentence said 29; $D418 −
56
+ $D400 + 1 = 25, the same count the Fix below uses), followed by four
57
+ read-only registers at $D419-$D41C. The SID has no read path for
58
+ these registers. A read does not float the bus: the chip drives it
59
+ with the byte it last held — the last value written to any of its 32
60
+ addresses ($D400-$D41F and every mirror through $D7FF) or the last
61
+ value read from $D419-$D41C. That byte decays to $00 after roughly
62
+ 7k cycles on a 6581 and roughly 660k cycles on an 8580 (measured in
63
+ VICE 3.10 reSID with the SID being clocked; real chips also decay but
64
+ were not measured here — see sid-reference.md). It is not the address
65
+ high byte and not a VIC-II fetch, which is what an earlier version of
66
+ this paragraph said; either way it is not register state and must
67
+ never be used as such. (For testers: in VICE, a run with sound
68
+ disabled (`+sound`) returns $00 from these reads via a fallback path
69
+ and does not emulate this behaviour, and with the dummy driver or
70
+ warp mode the held byte never fades.)
71
+
72
+ The four read-only registers ($D419-$D41C) are a completely different
73
+ story: POTX ($D419) and POTY ($D41A) return real paddle A/D values;
74
+ RANDOM ($D41B) returns the upper 8 bits of voice 3's oscillator
75
+ accumulator; ENV3 ($D41C) returns voice 3's current envelope level.
76
+ These are the only SID addresses where reads are meaningful.
77
+
78
+ ### Fix
79
+
80
+ Maintain a complete shadow copy of the SID write registers in RAM.
81
+ The shadow is the single source of truth for register state. To
82
+ modify any SID register:
83
+
84
+ 1. Read the shadow RAM location.
85
+ 2. Apply the bit-level change to the shadow.
86
+ 3. Write the modified shadow value to both the shadow location and the
87
+ real SID register.
88
+
89
+ Never read back from the SID hardware to determine the current state.
90
+ The shadow RAM write and the hardware write must stay in lock-step;
91
+ mixing in any hardware reads is the source of the bug.
92
+
93
+ Recommended layout: a contiguous block of 25 bytes in RAM you own,
94
+ mapped 1:1 to the SID register layout. Under BASIC/KERNAL the free
95
+ zero page is only $02 and $FB-$FE, so a 25-byte shadow cannot live
96
+ there; $033C-$03FB is the cassette buffer, free only when tape I/O is
97
+ not in use, or use any RAM above your program. An earlier version of
98
+ this paragraph recommended `$C5` through `$DD` — that block is the
99
+ KERNAL's keyboard and screen-editor state ($C5 LSTX, $C6 NDX, $CB-$CD
100
+ key/cursor, $D1-$D6 screen line and cursor, $D9-$F2 the line link
101
+ table; see c64-memory-map.md), and a shadow there corrupts the
102
+ keyboard scan and screen editor on every IRQ. No "SID player
103
+ convention" places a shadow there.
104
+
105
+ ### Worked example
106
+
107
+ ```asm
108
+ ; WRONG: read-modify-write directly on hardware register
109
+ ; This reads garbage from $D418 and sets an incorrect value.
110
+ lda $D418 ; BUG: returns the SID's last-held bus byte, not this register
111
+ ora #$0F ; intended: set volume to 15, keep filter bits
112
+ sta $D418 ; writes garbage|0x0F — wrong filter mode likely set
113
+
114
+ ; CORRECT: shadow-RAM pattern
115
+ ; Declare shadow at top of file:
116
+ ; shadow_d418: .byte 0 ; in RAM you own, e.g. $0340 (not zero page unless you own it)
117
+ ;
118
+ lda shadow_d418 ; read from RAM shadow — always coherent
119
+ ora #$0F ; set volume bits to 15, preserve filter/3OFF bits
120
+ sta shadow_d418 ; update shadow
121
+ sta $D418 ; write to hardware
122
+
123
+ ; Bit-clear variant (e.g. clear the LP filter mode bit 4):
124
+ lda shadow_d418
125
+ and #%11101111 ; clear LP bit
126
+ sta shadow_d418
127
+ sta $D418
128
+
129
+ ; Full three-voice control register update using shadows:
130
+ ; shadow_d404: .byte 0
131
+ ; shadow_d40b: .byte 0
132
+ ; shadow_d412: .byte 0
133
+ ;
134
+ ; To gate all three voices off:
135
+ lda shadow_d404
136
+ and #$FE ; clear bit 0 (GATE)
137
+ sta shadow_d404
138
+ sta $D404
139
+
140
+ lda shadow_d40b
141
+ and #$FE
142
+ sta shadow_d40b
143
+ sta $D40B
144
+
145
+ lda shadow_d412
146
+ and #$FE
147
+ sta shadow_d412
148
+ sta $D412
149
+ ```
150
+
151
+ ### Cross-references
152
+
153
+ - Registers: D400, D404, D40B, D412, D418
154
+ - Technique: `sid_voice_setup` — covers the full register layout per voice
155
+ - Read-only registers for legitimate reads: $D419 (POTX), $D41A (POTY),
156
+ $D41B (RANDOM/OSC3), $D41C (ENV3)
157
+
158
+ ---
159
+
160
+ ## sid_filter_chip_variation — 6581 vs 8580 filter cutoff and resonance differ wildly; same patch sounds different on each chip
161
+
162
+ **Severity:** high
163
+ **Region:** both
164
+ **Triggered by registers:** D415, D416, D417, D418
165
+ **Triggered by techniques:** sid_filter_routing, sid_8580_vs_6581_differences, sidasid_emulation_notes
166
+
167
+ ### Symptom
168
+
169
+ A SID music patch that sounds bright and resonant on a 6581 system
170
+ comes out dull and flat on an 8580. A filter sweep that sounds
171
+ evenly-stepped across the frequency range on an 8580 sounds
172
+ compressed at the low end and widely-spaced at the high end on a
173
+ 6581. Two 6581 boards of the same chip revision may produce
174
+ noticeably different filter sounds from the same register values.
175
+ The problem is invisible in code review — the register writes are
176
+ correct — but audible immediately on mismatched hardware.
177
+
178
+ ### Mechanism
179
+
180
+ The 6581 and 8580 implement the same filter architecture (11-bit
181
+ cutoff, 4-bit resonance, shared LP/BP/HP modes) but use fundamentally
182
+ different analog circuit designs for the cutoff cell.
183
+
184
+ **6581 filter — non-linear and chip-variable.** The 6581 filter is a
185
+ switched-capacitor design. The relationship between the 11-bit cutoff
186
+ register value and the resulting cutoff frequency in Hz is
187
+ non-linear — roughly sigmoidal on a logarithmic frequency scale.
188
+ The low end of the register range (roughly $D416 = $00-$30) produces
189
+ almost no frequency change; the mid-range ($40-$A0) sweeps across
190
+ most of the audible spectrum; the upper range ($A0-$FF) compresses
191
+ back. Additionally, the curve varies substantially between individual
192
+ 6581 chips from different manufacturing batches. The same $D416 value
193
+ of $60 may produce a cutoff of 800 Hz on one 6581 and 1200 Hz on
194
+ another from a different batch. This inter-chip variation is inherent
195
+ to the analog design and cannot be corrected in software without
196
+ chip-specific calibration.
197
+
198
+ **8580 filter — linear and consistent.** The 8580 redesigned the
199
+ filter cell for a near-linear cutoff response. A $D416 value of $80
200
+ is roughly half the nominal maximum cutoff (an earlier version said
201
+ $40, which is a quarter of the register's range); a sweep of $D416 from
202
+ $00 to $FF produces a perceptually even frequency sweep. The curve
203
+ is consistent between 8580 chips.
204
+
205
+ **Resonance.** The 4-bit resonance (RESON, $D417 bits 7-4) controls
206
+ Q differently between chip revisions. At RES=12-15, the 6581 often
207
+ distorts audibly — a characteristic "gritty" resonance that scene SID
208
+ musicians frequently exploit. The 8580 at RES=15 can self-oscillate
209
+ cleanly around the cutoff frequency, producing a sine-like tone that
210
+ is useful as a "fourth voice." A patch tuned at RES=15 for a specific
211
+ 6581 timbre typically sounds clean and different on 8580.
212
+
213
+ ### Fix
214
+
215
+ There is no single software fix that makes the same patch sound
216
+ identical on both chips. The standard approaches are:
217
+
218
+ **Per-chip cutoff tables.** Ship two cutoff frequency tables, one
219
+ calibrated for 6581 and one for 8580. At startup, detect the chip
220
+ revision (see the $D41B detection method below, and
221
+ `sid_8580_vs_6581_differences`) and select the appropriate
222
+ table. GoatTracker implements this with its "chip-select" toggle that
223
+ exports per-chip filter tuning. SidFactory II has similar per-chip
224
+ compensation.
225
+
226
+ **Target one chip explicitly.** For scene-quality demos or game
227
+ music, choose a target chip and tune all filter patches against that
228
+ chip. Document the target in the .SID header's 16-bit big-endian
229
+ flags word at $76-$77: bits 4-5 of byte $77 give the first SID's
230
+ model (00=unknown, 01=6581, 10=8580, 11=either); bits 0-1 are the
231
+ MUS-data and PlaySID/BASIC flags and bits 2-3 the video standard, so
232
+ mask `byte[$77] >> 4 & 3`, not `& 3` (an earlier version of this
233
+ sentence put the model in bits 0-1, which would classify MUS files as
234
+ 6581). See formats/c64-file-formats.md. Accept that the other chip
235
+ will sound different.
236
+
237
+ **Use filter-independent timbres.** Unfiltered voices (FILT bits
238
+ clear in $D417) pass straight to the volume DAC and are not subject
239
+ to cutoff curve differences. For cross-compatible patches, minimize
240
+ filter use or use the filter only for broad tonal shaping rather than
241
+ a precise tuned-resonance effect.
242
+
243
+ **Chip detection at runtime.** The filter cannot be observed from
244
+ software: the only readable voice-3 registers are $D41B (OSC3) and
245
+ $D41C (ENV3), and both sit before the filter in the signal path (see
246
+ sid-reference.md, Filter signal flow), so no cutoff, mode or routing
247
+ write changes what they return. An earlier version of this section
248
+ proposed reading ENV3 through the filter, which cannot work — $D41B
249
+ and $D41C sit before the filter; run in VICE reSID, ENV3 read $FF
250
+ with cutoff $00, cutoff $FF, FILT3 = 0 and 3OFF = 1 alike on both chip
251
+ models, and the deleted listing returned "8580-like" on both chips by
252
+ its own comment (its value was just how far a rate-0 attack had got in
253
+ the ~1,000-cycle settle loop). That listing was also self-inconsistent:
254
+ its header comment named the same flag state for both chips and its
255
+ carry sense was the inverse of its own prose. Anyone who copied it got
256
+ both the mechanism and the branch wrong.
257
+
258
+ The standard detection routine uses $D41B instead: write $FF to
259
+ $D412, $D40E and $D40F, then write $20 to $D412 (sawtooth, TEST and
260
+ GATE cleared) and read $D41B immediately. The value differs between
261
+ revisions because the two chips reset and restart the accumulator
262
+ differently — measured in VICE x64sc reSID, `-sidmodel 0` returns 3
263
+ and `-sidmodel 1` returns 2; real-hardware values are unverified here,
264
+ treat them as the same. Detection is imprecise (some SIDs answer
265
+ ambiguously) — use it only to select between precomputed cutoff
266
+ tables, and offer a settings toggle as the fallback. When testing this
267
+ in headless VICE, the $D41B/$D41C reads are only meaningful with a
268
+ real sound sink (`-sound -sounddev wav -soundarg out.wav`); the usual
269
+ `+sound` invocation returns meaningless values and would make the
270
+ detection look non-deterministic (see `sidasid_emulation_notes` in
271
+ music-sid).
272
+
273
+ ### Worked example
274
+
275
+ ```asm
276
+ ; SID music player with per-chip filter table selection
277
+ ; shadow_d416 and shadow_d417 are maintained throughout playback
278
+
279
+ chip_is_8580: .byte 0 ; 0 = 6581, 1 = 8580
280
+
281
+ ; Filter cutoff tables (simplified; real tables have 64 or more entries)
282
+ cutoff_tbl_6581:
283
+ ; These values are pre-mapped to produce evenly-spaced Hz steps
284
+ ; on an average 6581 (they cluster in the $30-$A0 range)
285
+ .byte $10, $1A, $26, $34, $44, $58, $6C, $82, $96, $AA, $BC, $CC
286
+
287
+ cutoff_tbl_8580:
288
+ ; 8580 is linear, so these are evenly spaced $00-$FF
289
+ .byte $15, $2A, $40, $55, $6A, $80, $95, $AA, $BF, $D5, $EA, $FF
290
+
291
+ ; In the play routine, set cutoff using the appropriate table:
292
+ set_cutoff:
293
+ ; A = note/step index into the cutoff table
294
+ tay
295
+ lda chip_is_8580
296
+ bne use_8580
297
+ lda cutoff_tbl_6581,y
298
+ jmp write_cutoff
299
+ use_8580:
300
+ lda cutoff_tbl_8580,y
301
+ write_cutoff:
302
+ sta shadow_d416
303
+ sta $D416
304
+ rts
305
+ ```
306
+
307
+ ### Cross-references
308
+
309
+ - Registers: D415, D416, D417, D418
310
+ - Technique: `sid_filter_routing` — full filter setup and mode documentation
311
+ - Technique: `sid_8580_vs_6581_differences` — chip revision differences overview
312
+
313
+ ---
314
+
315
+ ## sid_adsr_bug_8580 — 8580 ADSR-reset bug on hard restart; the rate-counter wrap is ~33 ms on both chips
316
+
317
+ **Severity:** high
318
+ **Region:** both
319
+ **Triggered by registers:** D404, D40B, D412
320
+ **Triggered by techniques:** digi_8bit_hard_restart, sid_8580_vs_6581_differences, sfx_in_player, goattracker_player_api
321
+
322
+ ### Symptom
323
+
324
+ A hard restart that behaves on a 6581 leaves an 8580 voice holding
325
+ its level for a moment before the attack starts (the 8580 reset-path
326
+ difference below), and on either chip a note whose AD/SR nibbles were
327
+ lowered while the rate counter had already passed the new period
328
+ starts up to 33 ms late (the rate-counter wrap). The effect is most
329
+ audible on fast-changing note sequences (arpeggios). An earlier version
330
+ of this Symptom also described digi samples coming out "louder, quieter,
331
+ or with a shifted peak on 8580" and players with "envelope timing drift
332
+ on the other chip"; both rested on a per-chip attack-step difference
333
+ that the Mechanism below withdraws — none has been measured.
334
+
335
+ ### Mechanism
336
+
337
+ Both the 6581 and 8580 share an ADSR bug rooted in the design of
338
+ the 15-bit envelope rate counter. The bug triggers when the CPU
339
+ writes a new (smaller) rate value to $D405 or $D406 at a time when
340
+ the envelope's internal 15-bit rate counter has already counted past
341
+ the new target threshold for the current phase. In that case the
342
+ counter must wrap through its full 15-bit range (0-32767 steps)
343
+ before the envelope generator reads the new rate and produces the
344
+ next envelope increment. At PAL clock (985248 Hz), a full 15-bit
345
+ wrap takes up to 32768 cycles — approximately 33 milliseconds.
346
+
347
+ The wrap length does not depend on the chip or on the new rate: it
348
+ is up to 32768 cycles (~33 ms at PAL) on both the 6581 and the 8580,
349
+ because the 15-bit counter must come back round to the new compare
350
+ value however small that value is (measured in VICE reSID: writing
351
+ attack 0 after the counter had run 5,120 cycles stalled the envelope
352
+ 27,627 cycles on the 6581 model and 27,240 on the 8580; writing
353
+ attack 1 instead gave 27,173 / 27,350; the rate-0 attack itself takes
354
+ ~2,280 cycles, which is where the 2 ms figure belongs). An earlier
355
+ version of this paragraph said the 6581's wrap at rate 0 was "close
356
+ to the 2 ms attack time" — that confused the attack duration with the
357
+ wrap. Hard restart works by writing AD/SR = 0 two frames before the
358
+ gate: 2 × 19,705 = 39,410 cycles covers the worst-case wrap, one
359
+ frame (19,705) does not.
360
+
361
+ **8580 behavior and the reset bug.** The 8580 introduced an internal
362
+ difference in the envelope reset path. On hard restart — where the
363
+ code writes AD=0 and SR=0 then clears GATE — the 8580's envelope
364
+ can enter an intermediate "hold at level" state caused by the reset
365
+ bug before it begins the release phase. At rate 0 the envelope steps
366
+ roughly every 9 φ2 cycles on either chip (2 ms / 256 steps = 7.7 µs
367
+ by the datasheet; measured in VICE reSID, 6581 and 8580 models, the
368
+ 255 steps to peak take about 2,100-2,300 cycles ≈ 2.1-2.3 ms, with
369
+ the two models within half a cycle per step of each other). An
370
+ earlier version said ~15 cycles on the 6581 and 17 on the 8580 and
371
+ attributed the 17 to a silicon measurement; neither number came from
372
+ a measurement, and the quoted formula did not evaluate to 15.
373
+
374
+ **Hard-restart digi (digi_8bit_hard_restart) cross-chip impact.**
375
+ The Hermit-style hard-restart digi technique depends on the voice's
376
+ envelope reaching a known level within a precisely-timed window. No
377
+ per-chip rate-0 step difference has been measured (in reSID the two
378
+ models reach peak within the same poll count), so an earlier version
379
+ of this paragraph, which derived a systematic 1-3 count envelope
380
+ offset on the 8580 from a slower attack step, rested on a premise
381
+ that has been withdrawn. Digi routines do drift between real chips,
382
+ but for other reasons — DC offset, the volume DAC's mixing
383
+ nonlinearity and the filter — not from the attack step rate.
384
+
385
+ ### Fix
386
+
387
+ **Always use a hard-restart sequence.** Both chip revisions benefit
388
+ from a two-frame hard restart. The one shown in the worked example
389
+ below is the **test-bit restart** variant listed under hard-restart
390
+ variants in sid-reference.md: one frame with AD=0/SR=0 and GATE
391
+ cleared, one frame with the TEST bit set (GATE still clear) to lock
392
+ the oscillator, then the real note gate on the third frame, so the
393
+ note frame supplies the 0→1 GATE edge and the attack begins from
394
+ zero. The "Classic" form that sid-reference.md and music-sid.md show
395
+ is a different sequence: SR = $F0 (not 0) on the first frame and $09
396
+ = TEST+GATE on the middle frame, so the envelope is already gated at
397
+ the note frame (ENV3 $FF before and after the note-frame write in
398
+ reSID) and that write does not start a fresh attack. An earlier
399
+ version of this entry presented the test-bit form as "the full
400
+ hard-restart sequence" without distinguishing it from the classic
401
+ one. Do not mix the two: with AD=0/SR=0 on frame 1, a $09 middle
402
+ frame would let the envelope decay to zero during the TEST+GATE frame
403
+ and, because a GATE-held write does not retrigger the attack
404
+ (measured in VICE reSID), the note frame would play silently. Either
405
+ form forces the rate counter through its wrap before the new note
406
+ begins.
407
+
408
+ **Do not pick an attack rate for cross-chip consistency without
409
+ measuring it.** No source supports rate 1 being more consistent
410
+ between revisions than rate 0 (an earlier version of this paragraph
411
+ said it was). In VICE reSID both rates jitter by the rate counter's
412
+ phase at gate-on and neither shows a systematic 6581/8580 difference:
413
+ the rate-0 attack reached $FF in 2,080-2,300 cycles and the rate-1
414
+ attack in 7,460-8,070 cycles on both chip models (x64sc, `-sound
415
+ -sounddev wav`, 16 trials per rate; runs made with `+sound` return
416
+ meaningless ENV3 values, see music-sid). What does change the rate-0
417
+ time is the ADSR delay bug: lowering the attack nibble while the rate
418
+ counter has passed the new period cost one trial 33 ms (the full
419
+ 15-bit wrap), which is why the hard-restart sequence above matters
420
+ more than the rate you choose.
421
+
422
+ **Chip-detect then branch.** Detect the SID revision at startup (see
423
+ the $D41B method in `sid_filter_chip_variation` above, or
424
+ `sid_8580_vs_6581_differences`) if you need per-chip filter tables.
425
+ An earlier version of this section followed with a listing of
426
+ per-chip digi timing constants (`.byte 15` for the 6581, `.byte 17
427
+ ; empirically measured on 8580 silicon` for the 8580); neither value
428
+ came from a measurement, the only measured figure is one number for
429
+ both chips (~9 cycles per attack step at rate 0, VICE reSID), and the
430
+ listing has been removed rather than corrected — do not keep a
431
+ per-chip constant.
432
+
433
+ **For music (not digi):** the standard hard restart is sufficient
434
+ for music playback on both revisions. Only digi routines that
435
+ require sub-millisecond envelope-level precision need to care about
436
+ the attack step timing at all, and no per-chip difference in it has
437
+ been measured.
438
+
439
+ ### Worked example
440
+
441
+ ```asm
442
+ ; Test-bit hard restart (sid-reference.md's "Test-bit restart" variant,
443
+ ; not the "Classic" SR=$F0 / $09 form) with explicit cycle-count comments
444
+ ; Applied to voice 1 two frames before the new note
445
+
446
+ ; FRAME N-2: disable ADSR, gate off
447
+ hard_restart_frame1:
448
+ lda #$00
449
+ sta $D405 ; AD1 = 0 (fastest attack/decay) [4 cycles]
450
+ sta $D406 ; SR1 = 0 (no sustain, fastest release) [4 cycles]
451
+ lda shadow_d404
452
+ and #$FE ; clear GATE bit [2 cycles]
453
+ sta shadow_d404
454
+ sta $D404 ; voice 1: waveform preserved, GATE=0 [4 cycles]
455
+ ; envelope now begins release from current level
456
+ rts
457
+
458
+ ; FRAME N-1: set TEST bit to lock oscillator at zero phase
459
+ hard_restart_frame2:
460
+ lda shadow_d404
461
+ and #$FE ; ensure GATE still clear
462
+ ora #$08 ; set TEST bit (bit 3)
463
+ sta shadow_d404
464
+ sta $D404 ; oscillator locked at zero DC [4 cycles]
465
+ ; GATE stays clear here (test-bit variant): the note frame
466
+ ; supplies the 0->1 GATE edge. The classic form writes $09
467
+ ; (TEST+GATE) instead, but only with SR=$F0 on frame 1.
468
+ rts
469
+
470
+ ; FRAME N (note frame): release TEST, set real waveform + GATE
471
+ hard_restart_note:
472
+ ; X = ADSR attack/decay byte for this note
473
+ ; Y = ADSR sustain/release byte for this note
474
+ ; A = waveform + GATE byte for this note
475
+ stx $D405 ; real attack/decay
476
+ sty $D406 ; real sustain/release
477
+ sta shadow_d404
478
+ sta $D404 ; clears TEST, sets waveform, sets GATE
479
+ ; Attack begins from zero; oscillator released from phase-zero lock
480
+ ; attack steps every ~9 cycles at rate 0 (VICE reSID, both models)
481
+ rts
482
+ ```
483
+
484
+ An earlier version of this listing ended with a
485
+ `compute_digi_irq_interval` routine returning 15 for the 6581 and 17
486
+ for the 8580 as "cycles per attack step"; neither figure was measured
487
+ and the two chips show no difference in reSID, so it has been removed.
488
+
489
+ ### Cross-references
490
+
491
+ - Registers: D404, D40B, D412 (VCREG for all three voices — hard restart
492
+ applies to whichever voice is being gated)
493
+ - Technique: `digi_8bit_hard_restart` — the hard-restart digi family and
494
+ the measured rate-0 envelope timing (9 φ2 cycles per attack step in
495
+ reSID on both chip models; the exact Hermit/Mahoney register sequences
496
+ are not documented in this knowledge base — an earlier version of this
497
+ line promised "full Hermit/Mahoney digi routine documentation")
498
+ - Pitfall: `sid_write_only_registers` — always use shadow for D404 read-modify-write
499
+
500
+ ---
501
+
502
+ ## sid_voice3_disable_silent_bit — Bit 7 of $D418 silences voice 3 on 6581 but not all 8580 revisions; relying on it for muted melodic tricks is fragile
503
+
504
+ **Severity:** medium
505
+ **Region:** both
506
+ **Triggered by registers:** D418
507
+ **Triggered by techniques:** sid_voice_setup, lfsr_random
508
+
509
+ ### Symptom
510
+
511
+ Code that configures voice 3 as a silent LFO or random-number source
512
+ by setting $D418 bit 7 (the "3OFF" bit) hears voice 3 leaking
513
+ audibly on some 8580 boards. The leak is a faint but perceptible
514
+ tone or noise — particularly noticeable in quiet passages. Conversely,
515
+ a "muted melodic" arrangement that intentionally plays a pitched
516
+ voice 3 melody silenced via bit 7 (a known trick on 6581 for adding
517
+ a silent modulator voice) fails on certain 8580 revisions where the
518
+ voice is clearly audible.
519
+
520
+ ### Mechanism
521
+
522
+ Bit 7 of $D418 (SIGVOL) is documented as "3OFF: disconnect voice 3
523
+ from audio output." The mechanism differs between chip revisions.
524
+
525
+ **6581 behavior.** On the 6581, the 3OFF bit reliably disconnects
526
+ voice 3 from the mixer that feeds the volume DAC. Voice 3's
527
+ oscillator and envelope continue running normally — the oscillator
528
+ output is still visible at $D41B (RANDOM/OSC3) and the envelope at
529
+ $D41C (ENV3) — but no audio from voice 3 reaches the output pin.
530
+ This is the basis for the classic pattern of using voice 3 as a free
531
+ LFO or random source without its sound being audible.
532
+
533
+ **8580 behavior — filter routing caveat applies to both chips.**
534
+ If voice 3 has its FILT3 bit set in $D417 (routing it through the
535
+ filter), then $D418 bit 7 does NOT silence it on either chip.
536
+ The 3OFF bit only disconnects the bypass path (the direct route from
537
+ the envelope output to the volume DAC that bypasses the filter). A
538
+ filtered voice 3 still sends its post-filter signal to the DAC
539
+ regardless of bit 7. This behavior is consistent between 6581 and
540
+ 8580 — it is simply not always understood.
541
+
542
+ **8580 revision differences on the bypass path.** On 8580 chips
543
+ manufactured after approximately 1990 (typically the R5 revision and
544
+ later), the 3OFF bit's implementation was revised as part of broader
545
+ cost-reduction changes. The bit was originally undocumented and was
546
+ added for the "voice 3 as LFO" use case that had emerged in the C64
547
+ development community. Some 8580 R5 revisions implement 3OFF by
548
+ cutting the voice 3 output from the bypass summing node but do not
549
+ fully isolate the signal path, leaving a small residual. The bleed
550
+ is typically below -40 dB relative to a full-volume voice, but at
551
+ high master volume (VOL=15) and in quiet musical contexts it is
552
+ audible.
553
+
554
+ A secondary mechanism: voice 3 routed through the filter (FILT3=1 in
555
+ $D417) is entirely unaffected by 3OFF on any chip revision. Code
556
+ that sets FILT3 and 3OFF simultaneously and expects silence will hear
557
+ voice 3 through the filter on all chip revisions. This is by far the
558
+ more common source of the symptom compared to the 8580 R5 revision
559
+ bypass issue.
560
+
561
+ ### Fix
562
+
563
+ **Do not rely solely on $D418 bit 7 for silence.** The safe approach
564
+ for voice 3 used as an LFO or modulation source is:
565
+
566
+ 1. Clear FILT3 in $D417 (voice 3 bypasses the filter; bit 7 then
567
+ works as intended on 6581 and most 8580s).
568
+ 2. Set the voice 3 sustain level to 0 (SUSTAIN nibble of $D414
569
+ = 0). With sustain at zero, the envelope decays to zero after
570
+ the attack and decay phases and then holds at zero. Even if
571
+ the bypass bleed reaches the output on some 8580 R5 chips,
572
+ zero envelope means zero audio.
573
+ 3. Optionally, set $D418 bit 7 as well for belt-and-suspenders
574
+ protection on 6581 (where the bit works reliably).
575
+
576
+ For the voice-3-as-LFO pattern ($D41B read each frame), the
577
+ oscillator continues running at zero envelope perfectly well.
578
+ ENV3 ($D41C) is the envelope itself — if sustain=0, ENV3 reads
579
+ zero during the sustain phase, which means ENV3-as-LFO only
580
+ provides signal during the attack and decay portions of the
581
+ envelope. For a sustained LFO, use the oscillator output ($D41B,
582
+ set voice 3 to TRI or SAW waveform) rather than the envelope output.
583
+
584
+ ### Worked example
585
+
586
+ ```asm
587
+ ; FRAGILE: relies only on $D418 bit 7 — fails on 8580 R5 if FILT3 is set,
588
+ ; and may have subtle bleed on late 8580 revisions
589
+
590
+ ; This sets 3OFF but forgets to clear FILT3:
591
+ lda shadow_d417
592
+ ora #$04 ; FILT3 = 1 (voice 3 through filter) -- MISTAKE
593
+ sta shadow_d417
594
+ sta $D417
595
+
596
+ lda shadow_d418
597
+ ora #$80 ; 3OFF = 1 -- doesn't silence filtered voice 3!
598
+ sta shadow_d418
599
+ sta $D418
600
+
601
+ ; Result: voice 3 still audible on ALL chip revisions because FILT3 overrides 3OFF.
602
+
603
+ ; ---------------------------------------------------------------
604
+
605
+ ; SAFE: sustain-zero + clear FILT3 approach, works on all chips
606
+
607
+ ; Voice 3 as triangle LFO source — silent on all revisions:
608
+ init_voice3_lfo:
609
+ lda #$10 ; low frequency: slow LFO sweep
610
+ sta $D40E ; FRELO3
611
+ lda #$00
612
+ sta $D40F ; FREHI3
613
+
614
+ lda #$00 ; fastest attack, fastest decay
615
+ sta $D413 ; ATDCY3
616
+ lda #$00 ; sustain 0 — envelope goes to zero after decay
617
+ sta $D414 ; SUREL3: sustain nibble=0, release rate=0
618
+
619
+ lda #$11 ; TRI waveform + GATE on
620
+ sta shadow_d412
621
+ sta $D412 ; voice 3 oscillator starts running
622
+
623
+ ; Clear FILT3 (remove voice 3 from filter path)
624
+ lda shadow_d417
625
+ and #%11111011 ; clear bit 2 (FILT3)
626
+ sta shadow_d417
627
+ sta $D417
628
+
629
+ ; Now set 3OFF for belt-and-suspenders on 6581
630
+ lda shadow_d418
631
+ ora #$80 ; 3OFF = 1
632
+ sta shadow_d418
633
+ sta $D418
634
+
635
+ ; Result: voice 3 oscillator runs (readable at $D41B), envelope at 0,
636
+ ; FILT3 clear so 3OFF is effective, sustain=0 so even if bypass bleeds
637
+ ; the audio amplitude is zero. Safe on all chip revisions.
638
+ rts
639
+
640
+ ; Using the LFO value each frame (e.g. in raster IRQ):
641
+ lfo_tick:
642
+ lda $D41B ; read OSC3 — triangle LFO value 0-255 cycling
643
+ lsr a ; scale down for pulse-width modulation
644
+ lsr a
645
+ sta shadow_d403
646
+ sta $D403 ; write to voice 1 PWHI — modulate pulse width
647
+ rts
648
+ ```
649
+
650
+ ### Cross-references
651
+
652
+ - Register: D418 (bit 7 = 3OFF, bits 4-0 = filter mode and volume)
653
+ - Register: D417 (bit 2 = FILT3 — must be clear for 3OFF to work)
654
+ - Technique: `sid_voice_setup` — full voice 3 LFO and modulation patterns
655
+ - Technique: `sid_filter_routing` — filter voice routing and the FILT3 interaction
656
+
657
+ ---
658
+
659
+ ## sid_replacement_d41b_unreadable — Some SID replacements cannot read back $D41B; a random seed from it can become constant or low-entropy
660
+
661
+ **Severity:** medium
662
+ **Region:** both
663
+ **Triggered by registers:** D41B
664
+ **Triggered by techniques:** lfsr_random, sid_8580_vs_6581_differences
665
+
666
+ ### Symptom
667
+
668
+ A game seeded from SID voice 3 noise plays the same "random" sequence
669
+ on every run, or its enemies, spawns and level layouts never vary, on a
670
+ machine fitted with a SID replacement. The same program varies on a
671
+ real 6581 or 8580. Chip-detection code that reads `$D41B` reports the
672
+ wrong chip or none. Nothing here was run on such hardware; this page
673
+ has no instrument for it (rung 4, from the sources below).
674
+
675
+ ### Mechanism
676
+
677
+ The seeding pattern in `lfsr_random` sets voice 3 to noise at frequency
678
+ `$FFFF` and reads the oscillator output at `$D41B` twice. On a real SID
679
+ the register changes on every read. SID replacements are
680
+ microcontrollers or FPGAs that emulate the chip, and not all of them
681
+ emulate the read side:
682
+
683
+ - **SwinSID.** C64-Wiki: "SwinSID does not support reading registers",
684
+ and games that "read from $D41B to generate random numbers" (it names
685
+ Fort Apocalypse, Uridium, Pirates! and Paradroid) "behave strangely".
686
+ Paddles and mice do not work either, because SwinSID has no
687
+ analogue-to-digital converter for `$D419`/`$D41A`.
688
+ - **SwinSID Nano.** The SIDDetector-II README says its `$D41B` does move,
689
+ but only at about 44 kHz, so back-to-back reads can return the same
690
+ value; SIDDetector-II uses exactly that to tell it from a real SID.
691
+ C64-Wiki names the SwinSID Nano as the SwinSID it describes, so the two
692
+ sources disagree about whether its read moves at all.
693
+ - **No SID, or an Ultimate II+ with its virtual SID off.** The same README
694
+ reports bus noise at about 44 kHz from the cartridge, which SIDDetector-II
695
+ cannot tell from a SwinSID Nano.
696
+ - **ARMSID, SwinSID Ultimate and others** echo written values in their
697
+ voice-3 read registers when sent an identification string (SIDDetector-II
698
+ README); what they return at `$D41B` during normal play is not stated
699
+ there.
700
+
701
+ Where the read does not move, or moves slowly, the two reads can give
702
+ the same bytes on every run and the seed can be constant or low-entropy;
703
+ an undriven read may also return open-bus data. This is an inference from
704
+ the sources (rung 4), not something C64-Wiki states. `$D41B`-based chip detection
705
+ (`sid_8580_vs_6581_differences`, "Chip detection at runtime") fails for
706
+ the same reason.
707
+
708
+ ### Fix
709
+
710
+ Do not make `$D41B` the only source of the seed. XOR in CIA1 timer A
711
+ (`$DC04/$DC05`) and, better, the frame count until the player's first
712
+ fire press; `lfsr_random` in `techniques/maths.md` already describes
713
+ both. The recipe's own check can also detect the problem: it counts how
714
+ many of 255 consecutive `$D41B` read pairs differ (255 in VICE). A count
715
+ far below 255 means the SID read is not moving and the seed should come
716
+ from the other sources (an inference from the sources above, not
717
+ measured here). Keep the zero check from `lfsr_zero_state_lockup`: a bus
718
+ that reads `$00` gives a zero seed.
719
+
720
+ Recipes that seed from `$D41B` alone: `recipes/oscar64/lfsr-random.md`
721
+ (it also prints the CIA timer but does not mix it into the seed) and
722
+ `recipes/oscar64/platformer-scaffold.md` (two `sid.random` reads, then
723
+ the zero check). Both can give a constant or low-entropy seed on a SwinSID (rung 4).
724
+
725
+ ### Cross-references
726
+
727
+ - Technique `lfsr_random` — seeding from SID, CIA timer and player input
728
+ - Technique `sid_8580_vs_6581_differences` — `$D41B` chip detection
729
+ - Pitfall `lfsr_zero_state_lockup` (`pitfalls/cpu.md`) — the zero seed
730
+ - Register `$D41B` (OSC3) — `../hardware/sid-reference.md`
731
+
732
+ **Sources.** C64-Wiki, "SwinSID": https://www.c64-wiki.com/wiki/SwinSID.
733
+ SIDDetector-II README (steps "SwinSID Nano" and "ARMSID / ARM2SID / Swinsid
734
+ Ultimate"): https://github.com/MichaelTroelsen/SIDDetector-II.
735
+
736
+ ---
737
+
738
+ *Cross-references: [docs/hardware/sid-reference.md](../hardware/sid-reference.md) for the complete SID register map, ADSR table, and hard-restart programming patterns. [docs/techniques/music-sid.md](../techniques/music-sid.md) for sid_voice_setup, sid_filter_routing, sid_8580_vs_6581_differences, and digi_8bit_hard_restart technique documentation.*