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.
- package/CHANGELOG.md +2082 -0
- package/LICENSE +29 -0
- package/README.md +559 -0
- package/VERSION +25 -0
- package/dist/cli/setup.js +66 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli-memorize-audit.js +97 -0
- package/dist/cli-memorize-audit.js.map +1 -0
- package/dist/cli.js +335 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +83 -0
- package/dist/config.js.map +1 -0
- package/dist/context.js +53 -0
- package/dist/context.js.map +1 -0
- package/dist/domain/budget-notes.js +104 -0
- package/dist/domain/budget-notes.js.map +1 -0
- package/dist/domain/budget.js +417 -0
- package/dist/domain/budget.js.map +1 -0
- package/dist/domain/game-design.js +77 -0
- package/dist/domain/game-design.js.map +1 -0
- package/dist/domain/timing.js +39 -0
- package/dist/domain/timing.js.map +1 -0
- package/dist/graph/apply.js +132 -0
- package/dist/graph/apply.js.map +1 -0
- package/dist/graph/claims.js +231 -0
- package/dist/graph/claims.js.map +1 -0
- package/dist/graph/extract/archetype.js +118 -0
- package/dist/graph/extract/archetype.js.map +1 -0
- package/dist/graph/extract/common.js +69 -0
- package/dist/graph/extract/common.js.map +1 -0
- package/dist/graph/extract/failure.js +37 -0
- package/dist/graph/extract/failure.js.map +1 -0
- package/dist/graph/extract/game-design.js +189 -0
- package/dist/graph/extract/game-design.js.map +1 -0
- package/dist/graph/extract/hardware.js +124 -0
- package/dist/graph/extract/hardware.js.map +1 -0
- package/dist/graph/extract/pitfall.js +62 -0
- package/dist/graph/extract/pitfall.js.map +1 -0
- package/dist/graph/extract/raster-band.js +56 -0
- package/dist/graph/extract/raster-band.js.map +1 -0
- package/dist/graph/extract/recipe.js +71 -0
- package/dist/graph/extract/recipe.js.map +1 -0
- package/dist/graph/extract/technique-entities.js +180 -0
- package/dist/graph/extract/technique-entities.js.map +1 -0
- package/dist/graph/extract/technique.js +179 -0
- package/dist/graph/extract/technique.js.map +1 -0
- package/dist/graph/extract/toolchain.js +67 -0
- package/dist/graph/extract/toolchain.js.map +1 -0
- package/dist/graph/extract/types.js +3 -0
- package/dist/graph/extract/types.js.map +1 -0
- package/dist/graph/extract/vocabulary.js +65 -0
- package/dist/graph/extract/vocabulary.js.map +1 -0
- package/dist/graph/extract.js +43 -0
- package/dist/graph/extract.js.map +1 -0
- package/dist/graph/kernal-clobbers.js +64 -0
- package/dist/graph/kernal-clobbers.js.map +1 -0
- package/dist/graph/machine-variants.js +208 -0
- package/dist/graph/machine-variants.js.map +1 -0
- package/dist/ingest/files.js +99 -0
- package/dist/ingest/files.js.map +1 -0
- package/dist/ingest/passes.js +104 -0
- package/dist/ingest/passes.js.map +1 -0
- package/dist/ingest/points.js +50 -0
- package/dist/ingest/points.js.map +1 -0
- package/dist/ingest/report.js +140 -0
- package/dist/ingest/report.js.map +1 -0
- package/dist/ingest/tally.js +81 -0
- package/dist/ingest/tally.js.map +1 -0
- package/dist/ingest/verified-on.js +43 -0
- package/dist/ingest/verified-on.js.map +1 -0
- package/dist/ingest.js +135 -0
- package/dist/ingest.js.map +1 -0
- package/dist/schemas/cost-basis.js +5 -0
- package/dist/schemas/cost-basis.js.map +1 -0
- package/dist/schemas/machine-variant.js +25 -0
- package/dist/schemas/machine-variant.js.map +1 -0
- package/dist/schemas/plan-budget.js +121 -0
- package/dist/schemas/plan-budget.js.map +1 -0
- package/dist/schemas/tool-outputs.js +526 -0
- package/dist/schemas/tool-outputs.js.map +1 -0
- package/dist/server/define-tool.js +52 -0
- package/dist/server/define-tool.js.map +1 -0
- package/dist/server/defined-only.js +9 -0
- package/dist/server/defined-only.js.map +1 -0
- package/dist/server/tools-briefings.js +70 -0
- package/dist/server/tools-briefings.js.map +1 -0
- package/dist/server/tools-lookup.js +180 -0
- package/dist/server/tools-lookup.js.map +1 -0
- package/dist/server/tools-maintenance.js +116 -0
- package/dist/server/tools-maintenance.js.map +1 -0
- package/dist/server/tools-pitfalls.js +89 -0
- package/dist/server/tools-pitfalls.js.map +1 -0
- package/dist/server/tools-recipes.js +296 -0
- package/dist/server/tools-recipes.js.map +1 -0
- package/dist/server/tools-runtime.js +48 -0
- package/dist/server/tools-runtime.js.map +1 -0
- package/dist/server/tools.js +43 -0
- package/dist/server/tools.js.map +1 -0
- package/dist/server.js +95 -0
- package/dist/server.js.map +1 -0
- package/dist/services/analytics/schema.js +78 -0
- package/dist/services/analytics/schema.js.map +1 -0
- package/dist/services/analytics/statements.js +99 -0
- package/dist/services/analytics/statements.js.map +1 -0
- package/dist/services/analytics.js +195 -0
- package/dist/services/analytics.js.map +1 -0
- package/dist/services/bm25.js +158 -0
- package/dist/services/bm25.js.map +1 -0
- package/dist/services/chunker.js +81 -0
- package/dist/services/chunker.js.map +1 -0
- package/dist/services/embeddings.js +58 -0
- package/dist/services/embeddings.js.map +1 -0
- package/dist/services/falkor/base.js +85 -0
- package/dist/services/falkor/base.js.map +1 -0
- package/dist/services/falkor/links.js +361 -0
- package/dist/services/falkor/links.js.map +1 -0
- package/dist/services/falkor/nodes.js +183 -0
- package/dist/services/falkor/nodes.js.map +1 -0
- package/dist/services/falkor/params.js +45 -0
- package/dist/services/falkor/params.js.map +1 -0
- package/dist/services/falkor/schema.js +77 -0
- package/dist/services/falkor/schema.js.map +1 -0
- package/dist/services/falkor.js +100 -0
- package/dist/services/falkor.js.map +1 -0
- package/dist/services/qdrant.js +238 -0
- package/dist/services/qdrant.js.map +1 -0
- package/dist/services/versions.js +73 -0
- package/dist/services/versions.js.map +1 -0
- package/dist/services/vice-bin.js +51 -0
- package/dist/services/vice-bin.js.map +1 -0
- package/dist/tools/briefings/archetype.js +174 -0
- package/dist/tools/briefings/archetype.js.map +1 -0
- package/dist/tools/briefings/budget.js +177 -0
- package/dist/tools/briefings/budget.js.map +1 -0
- package/dist/tools/briefings/build-order.js +135 -0
- package/dist/tools/briefings/build-order.js.map +1 -0
- package/dist/tools/briefings/build.js +185 -0
- package/dist/tools/briefings/build.js.map +1 -0
- package/dist/tools/briefings/discovery.js +290 -0
- package/dist/tools/briefings/discovery.js.map +1 -0
- package/dist/tools/briefings/plan-pitfalls.js +69 -0
- package/dist/tools/briefings/plan-pitfalls.js.map +1 -0
- package/dist/tools/briefings/render.js +151 -0
- package/dist/tools/briefings/render.js.map +1 -0
- package/dist/tools/briefings/rows.js +41 -0
- package/dist/tools/briefings/rows.js.map +1 -0
- package/dist/tools/briefings/toolchain.js +63 -0
- package/dist/tools/briefings/toolchain.js.map +1 -0
- package/dist/tools/briefings/why-proposed.js +69 -0
- package/dist/tools/briefings/why-proposed.js.map +1 -0
- package/dist/tools/briefings.js +44 -0
- package/dist/tools/briefings.js.map +1 -0
- package/dist/tools/feedback.js +97 -0
- package/dist/tools/feedback.js.map +1 -0
- package/dist/tools/hydrate.js +75 -0
- package/dist/tools/hydrate.js.map +1 -0
- package/dist/tools/intelligence.js +67 -0
- package/dist/tools/intelligence.js.map +1 -0
- package/dist/tools/lint/asm-decimal.js +86 -0
- package/dist/tools/lint/asm-decimal.js.map +1 -0
- package/dist/tools/lint/asm-rules.js +221 -0
- package/dist/tools/lint/asm-rules.js.map +1 -0
- package/dist/tools/lint/asm-shared.js +3 -0
- package/dist/tools/lint/asm-shared.js.map +1 -0
- package/dist/tools/lint/c-rules.js +215 -0
- package/dist/tools/lint/c-rules.js.map +1 -0
- package/dist/tools/lint/text.js +122 -0
- package/dist/tools/lint/text.js.map +1 -0
- package/dist/tools/lint/types.js +40 -0
- package/dist/tools/lint/types.js.map +1 -0
- package/dist/tools/lint.js +76 -0
- package/dist/tools/lint.js.map +1 -0
- package/dist/tools/memorization-mcp.js +111 -0
- package/dist/tools/memorization-mcp.js.map +1 -0
- package/dist/tools/pitfalls/bm25.js +53 -0
- package/dist/tools/pitfalls/bm25.js.map +1 -0
- package/dist/tools/pitfalls/format.js +58 -0
- package/dist/tools/pitfalls/format.js.map +1 -0
- package/dist/tools/pitfalls/graph.js +124 -0
- package/dist/tools/pitfalls/graph.js.map +1 -0
- package/dist/tools/pitfalls.js +134 -0
- package/dist/tools/pitfalls.js.map +1 -0
- package/dist/tools/prompts.js +81 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/query/compatibility/closure.js +62 -0
- package/dist/tools/query/compatibility/closure.js.map +1 -0
- package/dist/tools/query/compatibility/facts.js +28 -0
- package/dist/tools/query/compatibility/facts.js.map +1 -0
- package/dist/tools/query/compatibility/fetch.js +164 -0
- package/dist/tools/query/compatibility/fetch.js.map +1 -0
- package/dist/tools/query/compatibility/hard-rules.js +159 -0
- package/dist/tools/query/compatibility/hard-rules.js.map +1 -0
- package/dist/tools/query/compatibility/index.js +27 -0
- package/dist/tools/query/compatibility/index.js.map +1 -0
- package/dist/tools/query/compatibility/kernal-zp-rule.js +90 -0
- package/dist/tools/query/compatibility/kernal-zp-rule.js.map +1 -0
- package/dist/tools/query/compatibility/render.js +106 -0
- package/dist/tools/query/compatibility/render.js.map +1 -0
- package/dist/tools/query/compatibility/rules.js +337 -0
- package/dist/tools/query/compatibility/rules.js.map +1 -0
- package/dist/tools/query/compatibility/unit-rules.js +253 -0
- package/dist/tools/query/compatibility/unit-rules.js.map +1 -0
- package/dist/tools/query/game-design.js +83 -0
- package/dist/tools/query/game-design.js.map +1 -0
- package/dist/tools/query/lookups.js +220 -0
- package/dist/tools/query/lookups.js.map +1 -0
- package/dist/tools/query/plan-budget.js +266 -0
- package/dist/tools/query/plan-budget.js.map +1 -0
- package/dist/tools/query/recipes.js +214 -0
- package/dist/tools/query/recipes.js.map +1 -0
- package/dist/tools/query/retrieval.js +128 -0
- package/dist/tools/query/retrieval.js.map +1 -0
- package/dist/tools/query/shared.js +121 -0
- package/dist/tools/query/shared.js.map +1 -0
- package/dist/tools/query/techniques.js +331 -0
- package/dist/tools/query/techniques.js.map +1 -0
- package/dist/tools/query/timing.js +106 -0
- package/dist/tools/query/timing.js.map +1 -0
- package/dist/tools/query/types.js +11 -0
- package/dist/tools/query/types.js.map +1 -0
- package/dist/tools/query.js +21 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/tools/resources.js +186 -0
- package/dist/tools/resources.js.map +1 -0
- package/dist/tools/run-game.js +249 -0
- package/dist/tools/run-game.js.map +1 -0
- package/dist/tools/selfimprovement.js +367 -0
- package/dist/tools/selfimprovement.js.map +1 -0
- package/docker-compose.yml +35 -0
- package/docs/ARCHITECTURE.md +164 -0
- package/docs/CONVENTIONS-archetypes.md +158 -0
- package/docs/CONVENTIONS-failures.md +46 -0
- package/docs/CONVENTIONS-game-designs.md +75 -0
- package/docs/CONVENTIONS-hardware-reference.md +184 -0
- package/docs/CONVENTIONS-pitfalls.md +91 -0
- package/docs/CONVENTIONS-recipes.md +106 -0
- package/docs/CONVENTIONS-techniques.md +309 -0
- package/docs/CONVENTIONS-toolchain-reference.md +89 -0
- package/docs/ONTOLOGY.md +655 -0
- package/docs/art/art-production-reference.md +157 -0
- package/docs/art/asset-pipelines.md +586 -0
- package/docs/c64-failure-patterns.md +693 -0
- package/docs/demo-design/demo-composition.md +349 -0
- package/docs/demo-design/demo-design-philosophy.md +320 -0
- package/docs/demo-design/intro-cracktro-patterns.md +435 -0
- package/docs/figures/ctm-spd-embed-probe.png +0 -0
- package/docs/figures/dot-flag-mid-5000000.png +0 -0
- package/docs/figures/dot-flag-no-erase-12000000.png +0 -0
- package/docs/figures/edges.json +1 -0
- package/docs/figures/fig6-architecture.png +0 -0
- package/docs/figures/fig7-ontology.png +0 -0
- package/docs/figures/screen-dissolve-mid-frame25.png +0 -0
- package/docs/figures/screen-dissolve-wipe-frame25.png +0 -0
- package/docs/figures/spindle-two-parts-part1.png +0 -0
- package/docs/figures/spindle-two-parts-part2.png +0 -0
- package/docs/figures/starters/action-puzzle.png +0 -0
- package/docs/figures/starters/adventure.png +0 -0
- package/docs/figures/starters/beat-em-up.png +0 -0
- package/docs/figures/starters/demo.png +0 -0
- package/docs/figures/starters/platformer.png +0 -0
- package/docs/figures/starters/shmup-vertical.png +0 -0
- package/docs/figures/tape-kernal-master-ntsc.png +0 -0
- package/docs/figures/tape-kernal-master-pal.png +0 -0
- package/docs/figures/tape-turbo-loader-ntsc.png +0 -0
- package/docs/figures/tape-turbo-loader-pal.png +0 -0
- package/docs/figures/tape-turbo-master-ntsc.png +0 -0
- package/docs/figures/tape-turbo-master-pal.png +0 -0
- package/docs/figures/tech-tech-pad2-12000000.png +0 -0
- package/docs/figures/tech-tech-pad4-12000000.png +0 -0
- package/docs/figures/tech-tech-seven-12000000.png +0 -0
- package/docs/figures/twister-mid-5000000.png +0 -0
- package/docs/figures/twister-straight-12000000.png +0 -0
- package/docs/figures/vector-balls-nosort-ntsc.png +0 -0
- package/docs/figures/vector-balls-nosort.png +0 -0
- package/docs/formats/c64-file-formats.md +1212 -0
- package/docs/formats/iec-disk-reference.md +754 -0
- package/docs/game-design/c64-game-archetypes.md +273 -0
- package/docs/game-design/designs/falling-blocks.md +54 -0
- package/docs/game-design/designs/platformer-scaffold.md +48 -0
- package/docs/game-design/designs/simple-shmup.md +27 -0
- package/docs/game-design/enemy-behaviour-and-difficulty.md +349 -0
- package/docs/game-design/game-design-patterns.md +1189 -0
- package/docs/game-design/game-structure.md +354 -0
- package/docs/game-design/production-planning.md +349 -0
- package/docs/game-design/reference-game-sources.md +90 -0
- package/docs/hardware/6502-illegal-opcodes.md +1353 -0
- package/docs/hardware/6510-cpu-reference.md +2112 -0
- package/docs/hardware/c64-memory-map.md +3184 -0
- package/docs/hardware/c64-registers-reference.md +996 -0
- package/docs/hardware/cia-reference.md +1281 -0
- package/docs/hardware/kernal-routines-reference.md +1836 -0
- package/docs/hardware/pal-ntsc-reference.md +813 -0
- package/docs/hardware/sid-reference.md +1137 -0
- package/docs/hardware/vic-ii-reference.md +1714 -0
- package/docs/music/music-production-reference.md +403 -0
- package/docs/pitfalls/banking.md +1067 -0
- package/docs/pitfalls/cia.md +1147 -0
- package/docs/pitfalls/cpu.md +874 -0
- package/docs/pitfalls/input.md +282 -0
- package/docs/pitfalls/kernal-and-io.md +1615 -0
- package/docs/pitfalls/loader.md +1191 -0
- package/docs/pitfalls/logic.md +94 -0
- package/docs/pitfalls/maths.md +187 -0
- package/docs/pitfalls/raster-and-badline.md +721 -0
- package/docs/pitfalls/region-timing.md +660 -0
- package/docs/pitfalls/scroll.md +207 -0
- package/docs/pitfalls/sid.md +738 -0
- package/docs/pitfalls/sprite.md +979 -0
- package/docs/pitfalls/text-mode-render.md +1172 -0
- package/docs/recipes/cc65/cartridge-8k.md +398 -0
- package/docs/recipes/cc65/hello-world-conio.md +76 -0
- package/docs/recipes/cc65/memory-layout.md +312 -0
- package/docs/recipes/cc65/screenshots/README.md +14 -0
- package/docs/recipes/cc65/screenshots/cartridge-8k-ntsc.png +0 -0
- package/docs/recipes/cc65/screenshots/cartridge-8k.png +0 -0
- package/docs/recipes/cc65/screenshots/hello-world-conio.png +0 -0
- package/docs/recipes/cc65/screenshots/memory-layout-ntsc.png +0 -0
- package/docs/recipes/cc65/screenshots/memory-layout.png +0 -0
- package/docs/recipes/kickassembler/basic-float-calls.md +578 -0
- package/docs/recipes/kickassembler/basic-wedge.md +398 -0
- package/docs/recipes/kickassembler/big-font-scroller.md +620 -0
- package/docs/recipes/kickassembler/charset-copy-rom-to-ram.md +623 -0
- package/docs/recipes/kickassembler/cia-revision-detect.md +366 -0
- package/docs/recipes/kickassembler/colour-cycling.md +343 -0
- package/docs/recipes/kickassembler/colour-fade.md +303 -0
- package/docs/recipes/kickassembler/compare-16bit-signed.md +1007 -0
- package/docs/recipes/kickassembler/cracktro-template.md +526 -0
- package/docs/recipes/kickassembler/crt-banked.md +276 -0
- package/docs/recipes/kickassembler/dos-error-codes.md +466 -0
- package/docs/recipes/kickassembler/dot-flag.md +576 -0
- package/docs/recipes/kickassembler/drive-job-queue.md +667 -0
- package/docs/recipes/kickassembler/drive-via-probe.md +690 -0
- package/docs/recipes/kickassembler/dycp-scroller.md +568 -0
- package/docs/recipes/kickassembler/dypp-sprite-scroller.md +681 -0
- package/docs/recipes/kickassembler/dysp.md +670 -0
- package/docs/recipes/kickassembler/easyflash-save.md +800 -0
- package/docs/recipes/kickassembler/eight-way-scroll.md +1484 -0
- package/docs/recipes/kickassembler/file-io-roundtrip.md +546 -0
- package/docs/recipes/kickassembler/fire-effect.md +420 -0
- package/docs/recipes/kickassembler/fld.md +414 -0
- package/docs/recipes/kickassembler/fli-image.md +336 -0
- package/docs/recipes/kickassembler/four-player-read.md +672 -0
- package/docs/recipes/kickassembler/headless-verify.md +228 -0
- package/docs/recipes/kickassembler/hello-world.md +98 -0
- package/docs/recipes/kickassembler/high-score-insert.md +660 -0
- package/docs/recipes/kickassembler/hires-plot-line.md +723 -0
- package/docs/recipes/kickassembler/irq-chain.md +316 -0
- package/docs/recipes/kickassembler/irq-owns-port.md +668 -0
- package/docs/recipes/kickassembler/isometric-room.md +1145 -0
- package/docs/recipes/kickassembler/light-pen-read.md +926 -0
- package/docs/recipes/kickassembler/logic-rate-decoupling.md +670 -0
- package/docs/recipes/kickassembler/mci-interlace.md +543 -0
- package/docs/recipes/kickassembler/memory-layout.md +277 -0
- package/docs/recipes/kickassembler/mouse-1351-read.md +801 -0
- package/docs/recipes/kickassembler/nmi-timer-tick.md +562 -0
- package/docs/recipes/kickassembler/own-keyscan.md +881 -0
- package/docs/recipes/kickassembler/paddle-read.md +751 -0
- package/docs/recipes/kickassembler/palette-cells.md +219 -0
- package/docs/recipes/kickassembler/pseudo-3d-road.md +930 -0
- package/docs/recipes/kickassembler/pwm-digi.md +463 -0
- package/docs/recipes/kickassembler/raster-bars.md +264 -0
- package/docs/recipes/kickassembler/reu-dma.md +1019 -0
- package/docs/recipes/kickassembler/runtime-relocation.md +743 -0
- package/docs/recipes/kickassembler/screen-dissolve.md +545 -0
- package/docs/recipes/kickassembler/screen-wipe.md +408 -0
- package/docs/recipes/kickassembler/screenshots/README.md +72 -0
- package/docs/recipes/kickassembler/screenshots/basic-float-calls-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/basic-float-calls.png +0 -0
- package/docs/recipes/kickassembler/screenshots/basic-wedge-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/basic-wedge.png +0 -0
- package/docs/recipes/kickassembler/screenshots/big-font-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/big-font-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/charset-copy-rom-to-ram.png +0 -0
- package/docs/recipes/kickassembler/screenshots/cia-revision-detect-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/cia-revision-detect.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-cycling-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-cycling.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-fade-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/colour-fade.png +0 -0
- package/docs/recipes/kickassembler/screenshots/compare-16bit-signed-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/compare-16bit-signed.png +0 -0
- package/docs/recipes/kickassembler/screenshots/cracktro-template.png +0 -0
- package/docs/recipes/kickassembler/screenshots/crt-banked-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/crt-banked.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dos-error-codes-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dos-error-codes.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dot-flag-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dot-flag.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-job-queue-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-job-queue.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-via-probe-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/drive-via-probe.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dycp-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dycp-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dypp-sprite-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dysp-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/dysp.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc-run2.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save-run2.png +0 -0
- package/docs/recipes/kickassembler/screenshots/easyflash-save.png +0 -0
- package/docs/recipes/kickassembler/screenshots/eight-way-scroll-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/eight-way-scroll.png +0 -0
- package/docs/recipes/kickassembler/screenshots/file-io-roundtrip-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/file-io-roundtrip.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fire-effect-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fire-effect.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fld-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fld.png +0 -0
- package/docs/recipes/kickassembler/screenshots/fli-image.png +0 -0
- package/docs/recipes/kickassembler/screenshots/four-player-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/four-player-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/headless-verify-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/headless-verify.png +0 -0
- package/docs/recipes/kickassembler/screenshots/hello-world.png +0 -0
- package/docs/recipes/kickassembler/screenshots/high-score-insert-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/high-score-insert.png +0 -0
- package/docs/recipes/kickassembler/screenshots/hires-plot-line-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/hires-plot-line.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-chain-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-chain.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-owns-port-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/irq-owns-port.png +0 -0
- package/docs/recipes/kickassembler/screenshots/isometric-room-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/isometric-room.png +0 -0
- package/docs/recipes/kickassembler/screenshots/light-pen-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/light-pen-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/logic-rate-decoupling.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace-average.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace-frame-b.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mci-interlace.png +0 -0
- package/docs/recipes/kickassembler/screenshots/memory-layout-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/memory-layout.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mouse-1351-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/mouse-1351-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/nmi-timer-tick-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/nmi-timer-tick.png +0 -0
- package/docs/recipes/kickassembler/screenshots/own-keyscan-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/own-keyscan.png +0 -0
- package/docs/recipes/kickassembler/screenshots/paddle-read-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/paddle-read.png +0 -0
- package/docs/recipes/kickassembler/screenshots/palette-cells-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/palette-cells.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pseudo-3d-road-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pseudo-3d-road.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pwm-digi-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/pwm-digi.png +0 -0
- package/docs/recipes/kickassembler/screenshots/raster-bars.png +0 -0
- package/docs/recipes/kickassembler/screenshots/reu-dma-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/reu-dma.png +0 -0
- package/docs/recipes/kickassembler/screenshots/runtime-relocation-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/runtime-relocation.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-dissolve-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-dissolve.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-wipe-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/screen-wipe.png +0 -0
- package/docs/recipes/kickassembler/screenshots/scroll-panel-split-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/scroll-panel-split.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sfx-in-player-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sfx-in-player.png +0 -0
- package/docs/recipes/kickassembler/screenshots/shadebobs-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/shadebobs.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sideborder-open.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sine-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sine-table-runtime-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sine-table-runtime.png +0 -0
- package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/software-sprite-preshifted.png +0 -0
- package/docs/recipes/kickassembler/screenshots/speedcode-generator-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/speedcode-generator.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-border-scroller-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-border-scroller.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-cache-flip-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-cache-flip.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-multiplex-24.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-multiplex-game.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-priority-classes-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-priority-classes.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-sine-chain-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-sine-chain.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-stretcher-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprite-stretcher.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprites-only-screen-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sprites-only-screen.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sqrt-atan2-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/sqrt-atan2.png +0 -0
- package/docs/recipes/kickassembler/screenshots/stable-raster-irq-control.png +0 -0
- package/docs/recipes/kickassembler/screenshots/stable-raster-irq.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tech-tech-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tech-tech.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tod-alarm-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/tod-alarm.png +0 -0
- package/docs/recipes/kickassembler/screenshots/topbottom-border-open.png +0 -0
- package/docs/recipes/kickassembler/screenshots/twister-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/twister.png +0 -0
- package/docs/recipes/kickassembler/screenshots/unit-test-driver-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/unit-test-driver.png +0 -0
- package/docs/recipes/kickassembler/screenshots/vector-balls-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/vector-balls.png +0 -0
- package/docs/recipes/kickassembler/screenshots/wireframe-ships-ntsc.png +0 -0
- package/docs/recipes/kickassembler/screenshots/wireframe-ships.png +0 -0
- package/docs/recipes/kickassembler/scroll-panel-split.md +381 -0
- package/docs/recipes/kickassembler/sfx-in-player.md +907 -0
- package/docs/recipes/kickassembler/shadebobs.md +522 -0
- package/docs/recipes/kickassembler/sideborder-open.md +338 -0
- package/docs/recipes/kickassembler/sine-scroller.md +321 -0
- package/docs/recipes/kickassembler/sine-table-runtime.md +815 -0
- package/docs/recipes/kickassembler/software-sprite-preshifted.md +725 -0
- package/docs/recipes/kickassembler/speedcode-generator.md +606 -0
- package/docs/recipes/kickassembler/sprite-border-scroller.md +696 -0
- package/docs/recipes/kickassembler/sprite-cache-flip.md +1071 -0
- package/docs/recipes/kickassembler/sprite-multiplex-24.md +326 -0
- package/docs/recipes/kickassembler/sprite-multiplex-game.md +986 -0
- package/docs/recipes/kickassembler/sprite-priority-classes.md +463 -0
- package/docs/recipes/kickassembler/sprite-sine-chain.md +338 -0
- package/docs/recipes/kickassembler/sprite-stretcher.md +501 -0
- package/docs/recipes/kickassembler/sprites-only-screen.md +550 -0
- package/docs/recipes/kickassembler/sqrt-atan2.md +1014 -0
- package/docs/recipes/kickassembler/stable-raster-irq.md +360 -0
- package/docs/recipes/kickassembler/tape-turbo-loader.md +875 -0
- package/docs/recipes/kickassembler/tech-tech.md +679 -0
- package/docs/recipes/kickassembler/tod-alarm.md +754 -0
- package/docs/recipes/kickassembler/topbottom-border-open.md +407 -0
- package/docs/recipes/kickassembler/twister.md +518 -0
- package/docs/recipes/kickassembler/unit-test-driver.md +314 -0
- package/docs/recipes/kickassembler/vector-balls.md +545 -0
- package/docs/recipes/kickassembler/wireframe-ships.md +2324 -0
- package/docs/recipes/oscar64/actor-activation-window.md +807 -0
- package/docs/recipes/oscar64/adventure-engine.md +1094 -0
- package/docs/recipes/oscar64/attract-replay.md +465 -0
- package/docs/recipes/oscar64/beat-em-up-lanes.md +563 -0
- package/docs/recipes/oscar64/bfs-distance-map.md +723 -0
- package/docs/recipes/oscar64/bitmap-koala-viewer.md +355 -0
- package/docs/recipes/oscar64/car-contact.md +950 -0
- package/docs/recipes/oscar64/cave-scan.md +609 -0
- package/docs/recipes/oscar64/char-bullets.md +477 -0
- package/docs/recipes/oscar64/charset-animation.md +383 -0
- package/docs/recipes/oscar64/charset-parallax.md +401 -0
- package/docs/recipes/oscar64/destructible-terrain.md +1099 -0
- package/docs/recipes/oscar64/difficulty-tables.md +654 -0
- package/docs/recipes/oscar64/dig-and-guards.md +975 -0
- package/docs/recipes/oscar64/directory-reader.md +535 -0
- package/docs/recipes/oscar64/divide-check.md +581 -0
- package/docs/recipes/oscar64/double-buffer-nomirror.md +205 -0
- package/docs/recipes/oscar64/double-buffer.md +255 -0
- package/docs/recipes/oscar64/falling-blocks.md +874 -0
- package/docs/recipes/oscar64/fixed-point-jump-velocity.md +289 -0
- package/docs/recipes/oscar64/fixed-point-jump.md +210 -0
- package/docs/recipes/oscar64/flip-screen-rooms.md +793 -0
- package/docs/recipes/oscar64/frame-sync-loop-overrun.md +214 -0
- package/docs/recipes/oscar64/frame-sync-loop.md +254 -0
- package/docs/recipes/oscar64/game-tree-search.md +743 -0
- package/docs/recipes/oscar64/ghost-targeting.md +867 -0
- package/docs/recipes/oscar64/headless-verify.md +345 -0
- package/docs/recipes/oscar64/hello-world.md +83 -0
- package/docs/recipes/oscar64/high-score-persist.md +772 -0
- package/docs/recipes/oscar64/iffl-kernal-skip.md +421 -0
- package/docs/recipes/oscar64/joystick-input.md +358 -0
- package/docs/recipes/oscar64/lane-pursuit.md +1028 -0
- package/docs/recipes/oscar64/level-rle-decoder.md +620 -0
- package/docs/recipes/oscar64/lfsr-random-seed2.md +338 -0
- package/docs/recipes/oscar64/lfsr-random.md +403 -0
- package/docs/recipes/oscar64/load-asset-runtime.md +492 -0
- package/docs/recipes/oscar64/memory-layout.md +232 -0
- package/docs/recipes/oscar64/mixed-fighters.md +781 -0
- package/docs/recipes/oscar64/multi-sprite-object.md +533 -0
- package/docs/recipes/oscar64/nav-area-pathfinding.md +881 -0
- package/docs/recipes/oscar64/object-pool.md +572 -0
- package/docs/recipes/oscar64/pal-ntsc-detect.md +257 -0
- package/docs/recipes/oscar64/password-state.md +532 -0
- package/docs/recipes/oscar64/per-frame-hitbox.md +651 -0
- package/docs/recipes/oscar64/petscii-screen-codes.md +428 -0
- package/docs/recipes/oscar64/platformer-scaffold.md +1467 -0
- package/docs/recipes/oscar64/print-number.md +367 -0
- package/docs/recipes/oscar64/raster-bars.md +239 -0
- package/docs/recipes/oscar64/raster-profile-bars.md +404 -0
- package/docs/recipes/oscar64/rel-side-sectors.md +391 -0
- package/docs/recipes/oscar64/relative-file-records.md +378 -0
- package/docs/recipes/oscar64/save-load-seq-file.md +365 -0
- package/docs/recipes/oscar64/screenshots/README.md +99 -0
- package/docs/recipes/oscar64/screenshots/actor-activation-window-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/actor-activation-window.png +0 -0
- package/docs/recipes/oscar64/screenshots/adventure-engine-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/adventure-engine.png +0 -0
- package/docs/recipes/oscar64/screenshots/attract-replay-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/attract-replay.png +0 -0
- package/docs/recipes/oscar64/screenshots/beat-em-up-lanes-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/beat-em-up-lanes.png +0 -0
- package/docs/recipes/oscar64/screenshots/bfs-distance-map-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/bfs-distance-map.png +0 -0
- package/docs/recipes/oscar64/screenshots/bitmap-koala-viewer.png +0 -0
- package/docs/recipes/oscar64/screenshots/car-contact-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/car-contact.png +0 -0
- package/docs/recipes/oscar64/screenshots/cave-scan-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/cave-scan.png +0 -0
- package/docs/recipes/oscar64/screenshots/char-bullets-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/char-bullets.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-animation-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-animation.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-parallax-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/charset-parallax.png +0 -0
- package/docs/recipes/oscar64/screenshots/destructible-terrain-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/destructible-terrain.png +0 -0
- package/docs/recipes/oscar64/screenshots/difficulty-tables-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/difficulty-tables.png +0 -0
- package/docs/recipes/oscar64/screenshots/dig-and-guards-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/dig-and-guards.png +0 -0
- package/docs/recipes/oscar64/screenshots/directory-reader-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/directory-reader.png +0 -0
- package/docs/recipes/oscar64/screenshots/divide-check-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/divide-check.png +0 -0
- package/docs/recipes/oscar64/screenshots/double-buffer-nomirror.png +0 -0
- package/docs/recipes/oscar64/screenshots/double-buffer-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/double-buffer.png +0 -0
- package/docs/recipes/oscar64/screenshots/falling-blocks-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/falling-blocks.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump-velocity.png +0 -0
- package/docs/recipes/oscar64/screenshots/fixed-point-jump.png +0 -0
- package/docs/recipes/oscar64/screenshots/flip-screen-rooms-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/flip-screen-rooms.png +0 -0
- package/docs/recipes/oscar64/screenshots/frame-sync-loop-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/frame-sync-loop-overrun.png +0 -0
- package/docs/recipes/oscar64/screenshots/frame-sync-loop.png +0 -0
- package/docs/recipes/oscar64/screenshots/game-tree-search-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/game-tree-search.png +0 -0
- package/docs/recipes/oscar64/screenshots/ghost-targeting-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/ghost-targeting.png +0 -0
- package/docs/recipes/oscar64/screenshots/headless-verify-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/headless-verify.png +0 -0
- package/docs/recipes/oscar64/screenshots/hello-world.png +0 -0
- package/docs/recipes/oscar64/screenshots/high-score-persist-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/high-score-persist.png +0 -0
- package/docs/recipes/oscar64/screenshots/iffl-kernal-skip-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/iffl-kernal-skip.png +0 -0
- package/docs/recipes/oscar64/screenshots/joystick-input-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/joystick-input.png +0 -0
- package/docs/recipes/oscar64/screenshots/lane-pursuit-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/lane-pursuit.png +0 -0
- package/docs/recipes/oscar64/screenshots/level-rle-decoder-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/level-rle-decoder.png +0 -0
- package/docs/recipes/oscar64/screenshots/lfsr-random-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/lfsr-random-seed2.png +0 -0
- package/docs/recipes/oscar64/screenshots/lfsr-random.png +0 -0
- package/docs/recipes/oscar64/screenshots/load-asset-runtime-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/load-asset-runtime.png +0 -0
- package/docs/recipes/oscar64/screenshots/memory-layout-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/memory-layout.png +0 -0
- package/docs/recipes/oscar64/screenshots/mixed-fighters-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/mixed-fighters.png +0 -0
- package/docs/recipes/oscar64/screenshots/multi-sprite-object-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/multi-sprite-object.png +0 -0
- package/docs/recipes/oscar64/screenshots/nav-area-pathfinding-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/nav-area-pathfinding.png +0 -0
- package/docs/recipes/oscar64/screenshots/object-pool-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/object-pool.png +0 -0
- package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-oldntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/pal-ntsc-detect-pal.png +0 -0
- package/docs/recipes/oscar64/screenshots/password-state-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/password-state.png +0 -0
- package/docs/recipes/oscar64/screenshots/per-frame-hitbox-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/per-frame-hitbox.png +0 -0
- package/docs/recipes/oscar64/screenshots/petscii-screen-codes-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/petscii-screen-codes.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold-d64.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/platformer-scaffold.png +0 -0
- package/docs/recipes/oscar64/screenshots/print-number-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/print-number.png +0 -0
- package/docs/recipes/oscar64/screenshots/raster-bars.png +0 -0
- package/docs/recipes/oscar64/screenshots/raster-profile-bars-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/raster-profile-bars.png +0 -0
- package/docs/recipes/oscar64/screenshots/rel-side-sectors-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/rel-side-sectors.png +0 -0
- package/docs/recipes/oscar64/screenshots/relative-file-records-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/relative-file-records.png +0 -0
- package/docs/recipes/oscar64/screenshots/save-load-seq-file-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/save-load-seq-file.png +0 -0
- package/docs/recipes/oscar64/screenshots/seeded-level-fill-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/seeded-level-fill.png +0 -0
- package/docs/recipes/oscar64/screenshots/sfx-engine-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/sfx-engine.png +0 -0
- package/docs/recipes/oscar64/screenshots/sid-music-player.png +0 -0
- package/docs/recipes/oscar64/screenshots/simple-shmup.png +0 -0
- package/docs/recipes/oscar64/screenshots/slope-collision-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/slope-collision.png +0 -0
- package/docs/recipes/oscar64/screenshots/soft-scroll-h.png +0 -0
- package/docs/recipes/oscar64/screenshots/sprite-animation-table-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/sprite-animation-table.png +0 -0
- package/docs/recipes/oscar64/screenshots/sprite-multiplex-8.png +0 -0
- package/docs/recipes/oscar64/screenshots/stable-raster-irq.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-input-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-input.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-gameover.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-notrail-control.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield-ungated-control.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-overlay-playfield.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-window-menu-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/text-window-menu.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-grid-collision-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-grid-collision.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-map-render-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/tile-map-render.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-player-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-player.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-word-parser-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/two-word-parser.png +0 -0
- package/docs/recipes/oscar64/screenshots/vehicle-control-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/vehicle-control.png +0 -0
- package/docs/recipes/oscar64/screenshots/wave-director-ntsc.png +0 -0
- package/docs/recipes/oscar64/screenshots/wave-director.png +0 -0
- package/docs/recipes/oscar64/seeded-level-fill.md +364 -0
- package/docs/recipes/oscar64/sfx-engine.md +514 -0
- package/docs/recipes/oscar64/sid-music-player.md +441 -0
- package/docs/recipes/oscar64/simple-shmup.md +1000 -0
- package/docs/recipes/oscar64/slope-collision.md +610 -0
- package/docs/recipes/oscar64/soft-scroll-h.md +261 -0
- package/docs/recipes/oscar64/sprite-animation-table.md +671 -0
- package/docs/recipes/oscar64/sprite-multiplex-8.md +314 -0
- package/docs/recipes/oscar64/stable-raster-irq.md +236 -0
- package/docs/recipes/oscar64/text-input.md +274 -0
- package/docs/recipes/oscar64/text-overlay-playfield.md +617 -0
- package/docs/recipes/oscar64/text-window-menu.md +551 -0
- package/docs/recipes/oscar64/tile-grid-collision.md +563 -0
- package/docs/recipes/oscar64/tile-map-render.md +395 -0
- package/docs/recipes/oscar64/two-player.md +528 -0
- package/docs/recipes/oscar64/two-word-parser.md +510 -0
- package/docs/recipes/oscar64/vehicle-control.md +771 -0
- package/docs/recipes/oscar64/wave-director.md +787 -0
- package/docs/recipes/runs.json +1606 -0
- package/docs/runtime/sim6502-reference.md +466 -0
- package/docs/runtime/vice-mcp-reference.md +351 -0
- package/docs/runtime/vice-reference.md +1393 -0
- package/docs/techniques/bitmap-modes.md +685 -0
- package/docs/techniques/cpu-cycle-tricks.md +1570 -0
- package/docs/techniques/effects-vector-3d.md +1431 -0
- package/docs/techniques/file-io.md +1427 -0
- package/docs/techniques/input.md +1072 -0
- package/docs/techniques/loaders-packers.md +768 -0
- package/docs/techniques/logic.md +3091 -0
- package/docs/techniques/maths.md +1524 -0
- package/docs/techniques/memory-banking.md +1686 -0
- package/docs/techniques/music-sid.md +1144 -0
- package/docs/techniques/raster.md +1543 -0
- package/docs/techniques/scroll.md +1292 -0
- package/docs/techniques/sprite.md +2566 -0
- package/docs/techniques/text-mode-render.md +717 -0
- package/docs/techniques/text.md +1095 -0
- package/docs/techniques/transitions.md +405 -0
- package/docs/toolchains/cartconv-reference.md +262 -0
- package/docs/toolchains/cc1541-reference.md +316 -0
- package/docs/toolchains/cc65-reference.md +667 -0
- package/docs/toolchains/error-sources/cc65/README.md +1 -0
- package/docs/toolchains/error-sources/cc65/missing-setcpu.s +4 -0
- package/docs/toolchains/error-sources/cc65/range-error.s +4 -0
- package/docs/toolchains/error-sources/cc65/segment-overflow.c +6 -0
- package/docs/toolchains/error-sources/cc65/unresolved-external.c +6 -0
- package/docs/toolchains/error-sources/kickassembler/README.md +1 -0
- package/docs/toolchains/error-sources/kickassembler/branch-out-of-range.asm +4 -0
- package/docs/toolchains/error-sources/kickassembler/failed-assert.asm +3 -0
- package/docs/toolchains/error-sources/kickassembler/flat-lib.asm +4 -0
- package/docs/toolchains/error-sources/kickassembler/import-source-no-namespace.asm +5 -0
- package/docs/toolchains/error-sources/kickassembler/macro-without-parentheses.asm +6 -0
- package/docs/toolchains/error-sources/kickassembler/memory-block-overlap.asm +4 -0
- package/docs/toolchains/error-sources/kickassembler/symbol-clash-lib.asm +5 -0
- package/docs/toolchains/error-sources/kickassembler/symbol-clash-main.asm +6 -0
- package/docs/toolchains/error-sources/kickassembler/unknown-symbol.asm +4 -0
- package/docs/toolchains/error-sources/oscar64/README.md +1 -0
- package/docs/toolchains/error-sources/oscar64/asm-addressing-mode.c +7 -0
- package/docs/toolchains/error-sources/oscar64/region-overflow.c +6 -0
- package/docs/toolchains/error-sources/oscar64/undefined-extern-var.c +5 -0
- package/docs/toolchains/error-sources/oscar64/undefined-extern.c +6 -0
- package/docs/toolchains/error-sources/oscar64/unknown-vic-field.c +6 -0
- package/docs/toolchains/error-sources/oscar64/void-main.c +3 -0
- package/docs/toolchains/kickassembler-reference.md +1020 -0
- package/docs/toolchains/memory-layout-planning.md +362 -0
- package/docs/toolchains/oscar64-headers-reference.md +583 -0
- package/docs/toolchains/oscar64-reference.md +892 -0
- package/docs/toolchains/petcat-reference.md +290 -0
- package/docs/toolchains/png2prg.md +188 -0
- package/docs/toolchains/release-disk.md +314 -0
- package/docs/toolchains/sidreloc.md +236 -0
- package/docs/toolchains/spindle-reference.md +487 -0
- package/docs/toolchains/tape-mastering.md +592 -0
- package/docs/toolchains/unit-testing-6502.md +281 -0
- package/docs/workflow/agent-harness.md +478 -0
- package/package.json +105 -0
- package/templates/_harness/CLAUDE.md.template +91 -0
- package/templates/_harness/PLAN.md.template +72 -0
- package/templates/_harness/check.py +442 -0
- package/templates/_harness/claude/settings.json +17 -0
- package/templates/_harness/gen-asm-header.py +96 -0
- package/templates/_harness/harness.mk +273 -0
- package/templates/_harness/hooks/plan-gate.py +185 -0
- package/templates/_harness/meter/frame_meter.asm +311 -0
- package/templates/_harness/meter/frame_meter.c +155 -0
- package/templates/_harness/meter/frame_meter.h +80 -0
- package/templates/_harness/zp-used.py +104 -0
- package/templates/action-puzzle/.claude/settings.json +17 -0
- package/templates/action-puzzle/.mcp.json +10 -0
- package/templates/action-puzzle/CLAUDE.md +120 -0
- package/templates/action-puzzle/Makefile +125 -0
- package/templates/action-puzzle/PLAN.md +388 -0
- package/templates/action-puzzle/README.md +240 -0
- package/templates/action-puzzle/expect.json +25 -0
- package/templates/action-puzzle/src/cave.c +280 -0
- package/templates/action-puzzle/src/cave.h +80 -0
- package/templates/action-puzzle/src/gen_autopilot.h +20 -0
- package/templates/action-puzzle/src/gen_caves.h +59 -0
- package/templates/action-puzzle/src/gen_notes.h +16 -0
- package/templates/action-puzzle/src/hiscore.c +152 -0
- package/templates/action-puzzle/src/hiscore.h +41 -0
- package/templates/action-puzzle/src/level.c +64 -0
- package/templates/action-puzzle/src/level.h +24 -0
- package/templates/action-puzzle/src/main.c +599 -0
- package/templates/action-puzzle/src/render.c +239 -0
- package/templates/action-puzzle/src/render.h +31 -0
- package/templates/action-puzzle/src/sound.c +158 -0
- package/templates/action-puzzle/src/sound.h +22 -0
- package/templates/action-puzzle/tools/disk_check.py +77 -0
- package/templates/action-puzzle/tools/drive.py +106 -0
- package/templates/action-puzzle/tools/gen.py +454 -0
- package/templates/action-puzzle/tools/model_check.py +49 -0
- package/templates/action-puzzle/tools/verdict_codes.py +24 -0
- package/templates/adventure/.claude/settings.json +17 -0
- package/templates/adventure/.mcp.json +10 -0
- package/templates/adventure/CLAUDE.md +118 -0
- package/templates/adventure/Makefile +113 -0
- package/templates/adventure/PLAN.md +396 -0
- package/templates/adventure/README.md +277 -0
- package/templates/adventure/expect.json +25 -0
- package/templates/adventure/src/engine.c +543 -0
- package/templates/adventure/src/engine.h +48 -0
- package/templates/adventure/src/gen_script.h +141 -0
- package/templates/adventure/src/gen_world.h +511 -0
- package/templates/adventure/src/main.c +439 -0
- package/templates/adventure/src/picture.c +83 -0
- package/templates/adventure/src/picture.h +16 -0
- package/templates/adventure/src/save.c +159 -0
- package/templates/adventure/src/save.h +25 -0
- package/templates/adventure/src/sound.c +71 -0
- package/templates/adventure/src/sound.h +16 -0
- package/templates/adventure/src/text.c +349 -0
- package/templates/adventure/src/text.h +40 -0
- package/templates/adventure/tools/disk_check.py +128 -0
- package/templates/adventure/tools/drive.py +119 -0
- package/templates/adventure/tools/gen.py +1033 -0
- package/templates/adventure/tools/world.py +356 -0
- package/templates/beat-em-up/.claude/settings.json +17 -0
- package/templates/beat-em-up/.mcp.json +10 -0
- package/templates/beat-em-up/CLAUDE.md +136 -0
- package/templates/beat-em-up/Makefile +96 -0
- package/templates/beat-em-up/PLAN.md +502 -0
- package/templates/beat-em-up/README.md +315 -0
- package/templates/beat-em-up/expect-gameover.json +8 -0
- package/templates/beat-em-up/expect.json +29 -0
- package/templates/beat-em-up/src/anim.c +70 -0
- package/templates/beat-em-up/src/art.c +344 -0
- package/templates/beat-em-up/src/autopilot.h +154 -0
- package/templates/beat-em-up/src/brute.c +273 -0
- package/templates/beat-em-up/src/enemy.c +281 -0
- package/templates/beat-em-up/src/engine.asm +512 -0
- package/templates/beat-em-up/src/fighter.c +384 -0
- package/templates/beat-em-up/src/game.h +269 -0
- package/templates/beat-em-up/src/hud.c +135 -0
- package/templates/beat-em-up/src/main.c +341 -0
- package/templates/beat-em-up/src/sound.c +44 -0
- package/templates/beat-em-up/src/street.c +93 -0
- package/templates/beat-em-up/src/verdict.h +523 -0
- package/templates/beat-em-up/src/view.c +362 -0
- package/templates/beat-em-up/tools/drive.py +105 -0
- package/templates/beat-em-up/tools/flickercheck.py +273 -0
- package/templates/demo/.claude/settings.json +17 -0
- package/templates/demo/.mcp.json +10 -0
- package/templates/demo/CLAUDE.md +129 -0
- package/templates/demo/Makefile +66 -0
- package/templates/demo/PLAN.md +401 -0
- package/templates/demo/README.md +322 -0
- package/templates/demo/expect.json +945 -0
- package/templates/demo/src/config.asm +80 -0
- package/templates/demo/src/framework.asm +390 -0
- package/templates/demo/src/main.asm +139 -0
- package/templates/demo/src/music.asm +197 -0
- package/templates/demo/src/part_main.asm +279 -0
- package/templates/demo/src/part_title.asm +79 -0
- package/templates/demo/src/parts.asm +43 -0
- package/templates/demo/src/tables.asm +73 -0
- package/templates/demo/src/verdict.asm +179 -0
- package/templates/demo/tools/audio.py +80 -0
- package/templates/demo/tools/gen_expect.py +167 -0
- package/templates/demo/tools/probe.py +95 -0
- package/templates/hello/.claude/settings.json +17 -0
- package/templates/hello/.mcp.json +10 -0
- package/templates/hello/CLAUDE.md +100 -0
- package/templates/hello/Makefile +38 -0
- package/templates/hello/PLAN.md +200 -0
- package/templates/hello/expect.json +20 -0
- package/templates/hello/src/main.c +161 -0
- package/templates/hello/src/sprite.asm +27 -0
- package/templates/hello-kick/.claude/settings.json +17 -0
- package/templates/hello-kick/.mcp.json +10 -0
- package/templates/hello-kick/CLAUDE.md +100 -0
- package/templates/hello-kick/Makefile +17 -0
- package/templates/hello-kick/PLAN.md +199 -0
- package/templates/hello-kick/expect.json +20 -0
- package/templates/hello-kick/src/main.asm +233 -0
- package/templates/platformer/.claude/settings.json +17 -0
- package/templates/platformer/.mcp.json +10 -0
- package/templates/platformer/CLAUDE.md +125 -0
- package/templates/platformer/Makefile +86 -0
- package/templates/platformer/PLAN.md +360 -0
- package/templates/platformer/README.md +277 -0
- package/templates/platformer/expect.json +32 -0
- package/templates/platformer/src/actors.c +289 -0
- package/templates/platformer/src/anim.c +51 -0
- package/templates/platformer/src/art.c +212 -0
- package/templates/platformer/src/autopilot.h +30 -0
- package/templates/platformer/src/engine.asm +253 -0
- package/templates/platformer/src/game.h +248 -0
- package/templates/platformer/src/hud.c +90 -0
- package/templates/platformer/src/level.c +184 -0
- package/templates/platformer/src/main.c +306 -0
- package/templates/platformer/src/player.c +268 -0
- package/templates/platformer/src/sound.c +42 -0
- package/templates/platformer/src/verdict.h +206 -0
- package/templates/platformer/src/view.c +331 -0
- package/templates/platformer/stage-expect.json +6 -0
- package/templates/platformer/tools/drive.py +112 -0
- package/templates/platformer/tools/tearcheck.py +229 -0
- package/templates/shmup-vertical/.claude/settings.json +17 -0
- package/templates/shmup-vertical/.mcp.json +10 -0
- package/templates/shmup-vertical/CLAUDE.md +137 -0
- package/templates/shmup-vertical/Makefile +131 -0
- package/templates/shmup-vertical/PLAN.md +569 -0
- package/templates/shmup-vertical/README.md +189 -0
- package/templates/shmup-vertical/expect.json +38 -0
- package/templates/shmup-vertical/src/bullets.c +158 -0
- package/templates/shmup-vertical/src/bullets.h +35 -0
- package/templates/shmup-vertical/src/display.c +239 -0
- package/templates/shmup-vertical/src/display.h +40 -0
- package/templates/shmup-vertical/src/game.h +85 -0
- package/templates/shmup-vertical/src/glyph.asm +358 -0
- package/templates/shmup-vertical/src/hiscore.c +141 -0
- package/templates/shmup-vertical/src/hiscore.h +16 -0
- package/templates/shmup-vertical/src/hit.asm +180 -0
- package/templates/shmup-vertical/src/hitbox.c +59 -0
- package/templates/shmup-vertical/src/hitbox.h +25 -0
- package/templates/shmup-vertical/src/kernel.asm +330 -0
- package/templates/shmup-vertical/src/level.c +174 -0
- package/templates/shmup-vertical/src/level.h +27 -0
- package/templates/shmup-vertical/src/main.c +824 -0
- package/templates/shmup-vertical/src/mux.asm +321 -0
- package/templates/shmup-vertical/src/sound.asm +255 -0
- package/templates/shmup-vertical/src/step.asm +169 -0
- package/templates/shmup-vertical/src/waves.c +195 -0
- package/templates/shmup-vertical/src/waves.h +33 -0
- package/templates/shmup-vertical/stage-expect.json +6 -0
- package/templates/shmup-vertical/tools/drive.py +152 -0
- package/templates/shmup-vertical/tools/joytest.py +159 -0
- package/templates/shmup-vertical/tools/meter.py +15 -0
- package/templates/shmup-vertical/tools/phases.py +73 -0
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: raster
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<!-- doc-type: pitfall-reference -->
|
|
6
|
+
|
|
7
|
+
# Raster and Badline Pitfalls
|
|
8
|
+
|
|
9
|
+
The pitfalls in this document share a common thread: they all stem from
|
|
10
|
+
the VIC-II's asynchronous relationship with the CPU. The chip runs on the same
|
|
11
|
+
clock but does not wait for the CPU to finish what it is doing. Badlines steal
|
|
12
|
+
cycles without warning. The raster compare register wraps silently at line 255.
|
|
13
|
+
Sprite DMA freezes the CPU mid-instruction. The stable-raster polling technique
|
|
14
|
+
(and its two-handler `double_irq` refinement) exists precisely because the
|
|
15
|
+
first IRQ you enable has unpredictable entry timing. Each pitfall below has
|
|
16
|
+
caused demo coders and game developers to lose hours to glitches that look random but are in fact completely deterministic once
|
|
17
|
+
you know the mechanism.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## badline_cycle_loss — Badline DMA steals 40-43 cycles from the CPU
|
|
22
|
+
|
|
23
|
+
**Severity:** critical
|
|
24
|
+
**Region:** both
|
|
25
|
+
**Triggered by registers:** D011, D012
|
|
26
|
+
**Triggered by techniques:** stable_raster_irq, sprite_multiplex_8, raster_bars, frame_sync_loop, double_irq, badline_synchronization, sideborder_open, fli_image, afli_image, ifli_image, soft_scroll_v, tile_map_render, dma_steal_avoidance, speedcode_generation, big_font_2x2, dycp_scroller, sine_table_generation, scroll_panel_split, sprite_multiplex_game, software_sprite_preshifted, fld_flexible_line_distance, raster_profile_bars, reu_dma, pwm_digi, eight_way_scroll_double_buffer, sprite_color_swap_mid_line, solid_vector_3d, mode7_lookalike, vsp_glitch, pseudo_3d_road_raster, sprite_stretcher_d017, tech_tech_wobbler, dysp_side_border_sprites
|
|
27
|
+
|
|
28
|
+
### Symptom
|
|
29
|
+
|
|
30
|
+
The raster IRQ handler runs correctly during development, then silently breaks
|
|
31
|
+
every 8 lines. Color bars bleed across line boundaries. Sprite Y-position writes
|
|
32
|
+
arrive one scanline late. A tight per-line loop that works in isolation suddenly
|
|
33
|
+
takes 40 extra cycles at unpredictable intervals. The glitch looks like random
|
|
34
|
+
jitter but repeats at exactly 8-line intervals because the underlying cause is
|
|
35
|
+
perfectly periodic.
|
|
36
|
+
|
|
37
|
+
### Mechanism
|
|
38
|
+
|
|
39
|
+
A badline occurs on every raster line where `(raster_line & 7) == YSCROLL`,
|
|
40
|
+
where YSCROLL is the low 3 bits of $D011 (default value 3). With the default
|
|
41
|
+
YSCROLL, badlines fall at raster lines 51, 59, 67 ... 243 — 25 lines per frame
|
|
42
|
+
in both regions (the window $30-$F7 and the 25 character rows do not depend on
|
|
43
|
+
frame length; an earlier version of this entry said 24 on NTSC). On each
|
|
44
|
+
badline, the VIC-II must fetch the 40 screen code bytes for the character row
|
|
45
|
+
that begins on that line. The chip asserts the BA
|
|
46
|
+
(Bus Available) signal low 3 cycles before it needs the bus. The CPU, seeing BA
|
|
47
|
+
low, can still complete any instruction that has no remaining bus cycles, but
|
|
48
|
+
cannot issue new memory accesses. Three cycles later, the VIC takes the phi2
|
|
49
|
+
bus for 40 cycles of screen RAM fetch, then releases it.
|
|
50
|
+
|
|
51
|
+
The VIC takes the bus for 40 cycles (15-54) and pulls BA low three cycles
|
|
52
|
+
earlier, on cycle 12; the CPU can spend those three cycles only on write
|
|
53
|
+
cycles. So a PAL badline leaves 20 CPU cycles guaranteed (1-11 and 55-63) and
|
|
54
|
+
23 at best, not 23 flat. Any raster handler that assumes a fixed 63-cycle
|
|
55
|
+
budget per line will slip by 40 or 43 cycles on every badline it hits. Sprite
|
|
56
|
+
DMA is on top of that: each active sprite takes two bus cycles at the end of
|
|
57
|
+
the line (cycles 58-63 for sprites 0-2, 1-10 of the next line for 3-7), with BA
|
|
58
|
+
dropping at cycle 55, three cycles before the first (an earlier version of this
|
|
59
|
+
entry put sprites 0-2 at 55-62 and then counted the BA lead-in a second time),
|
|
60
|
+
so a badline with all eight sprites active leaves the CPU almost nothing — one
|
|
61
|
+
guaranteed cycle; see `vic_bus_takeover_on_dma` below for the measurement.
|
|
62
|
+
|
|
63
|
+
### Fix
|
|
64
|
+
|
|
65
|
+
Two approaches, often combined:
|
|
66
|
+
|
|
67
|
+
1. **Badline avoidance:** Schedule IRQ handlers to fire on non-bad lines. Given
|
|
68
|
+
a fixed YSCROLL of 3, any line where `(target_line & 7) != 3` is safe. A
|
|
69
|
+
status bar split at line 200 (200 & 7 = 0) is safe; at line 203 (203 & 7 = 3)
|
|
70
|
+
it is not. Move the split by 1 line.
|
|
71
|
+
|
|
72
|
+
2. **DEN off for the whole frame:** the VIC latches DEN once, during raster
|
|
73
|
+
line $30 (48); if it is clear then, no line of that frame is a badline and
|
|
74
|
+
the display is blank. Clearing DEN later in the frame does *not* stop the
|
|
75
|
+
remaining badlines — an earlier version of this entry said it did. Sprite
|
|
76
|
+
DMA still occurs either way.
|
|
77
|
+
|
|
78
|
+
3. **YSCROLL steering for a region:** on each line of the region write $D011
|
|
79
|
+
with YSCROLL set to a value the line number cannot match (for instance
|
|
80
|
+
`(line + 4) & 7`, written early in the line). The badline condition is
|
|
81
|
+
evaluated every cycle, so no line in the region becomes bad; the character
|
|
82
|
+
display goes idle there (it shows the background colour). This is what
|
|
83
|
+
`recipes/kickassembler/sideborder-open.md` does and measures. Elsewhere,
|
|
84
|
+
rewrite YSCROLL only after the current line's window has passed (from
|
|
85
|
+
cycle 55) so the write cannot create a badline on the line it lands in.
|
|
86
|
+
|
|
87
|
+
### Worked example
|
|
88
|
+
|
|
89
|
+
```kick
|
|
90
|
+
// BAD: handler fires on a line that may be a badline.
|
|
91
|
+
// On badline rows, the STA $D020 arrives ~40 cycles late,
|
|
92
|
+
// producing a color bleed into the next line.
|
|
93
|
+
irq_handler:
|
|
94
|
+
lda #WHITE
|
|
95
|
+
sta $d020 // May arrive 40 cycles late on badlines
|
|
96
|
+
lda #(irq_handler >> 8)
|
|
97
|
+
sta $0315
|
|
98
|
+
lda #<irq_handler
|
|
99
|
+
sta $0314
|
|
100
|
+
asl $d019 // Ack VIC interrupt
|
|
101
|
+
rti
|
|
102
|
+
|
|
103
|
+
// GOOD: keep the split off badline rows. With YSCROLL=3 a line is bad when
|
|
104
|
+
// (line & 7) == 3; arm the IRQ a line early and spin to the target so the
|
|
105
|
+
// colour write lands in the blank, and pick a target with (line & 7) != 3.
|
|
106
|
+
.const SPLIT = 200 // 200 & 7 = 0: not a badline
|
|
107
|
+
effect_irq:
|
|
108
|
+
ldx #WHITE
|
|
109
|
+
lda #SPLIT
|
|
110
|
+
!: cmp $d012
|
|
111
|
+
bne !-
|
|
112
|
+
stx $d020 // cycle <= 15 of line SPLIT
|
|
113
|
+
// ... other work ...
|
|
114
|
+
asl $d019
|
|
115
|
+
jmp $ea81
|
|
116
|
+
|
|
117
|
+
// For a whole region with no badlines at all (blank display, all 63 cycles):
|
|
118
|
+
// write YSCROLL = (line + 4) & 7 on every line of the region, as
|
|
119
|
+
// recipes/kickassembler/sideborder-open.md does. Clearing DEN mid-frame
|
|
120
|
+
// does NOT do this; DEN is sampled once, on line $30.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
For code that must run on a potentially bad line (e.g., per-line raster bars),
|
|
124
|
+
subtract 43 from the available cycle count and ensure the handler body fits
|
|
125
|
+
within 20 cycles on PAL or 22 cycles on NTSC (23 and 25 only if the three
|
|
126
|
+
cycles after BA drops on cycle 12 happen to be write cycles).
|
|
127
|
+
|
|
128
|
+
### Cross-references
|
|
129
|
+
|
|
130
|
+
- Technique: `stable_raster_irq` — the polling stable-raster technique that
|
|
131
|
+
this pitfall most visibly affects; the technique doc discusses badline avoidance in its
|
|
132
|
+
cycle budget section.
|
|
133
|
+
- Technique: `sprite_multiplex_8` — active sprites add 2 cycles/sprite of DMA
|
|
134
|
+
on top of the 40-43-cycle badline stall; together they take 62 of the 63
|
|
135
|
+
cycles on such a line (see `vic_bus_takeover_on_dma` below).
|
|
136
|
+
- Technique: `badline_synchronization` — the raster.md technique covering the
|
|
137
|
+
full badline accounting framework.
|
|
138
|
+
- Registers: `D011` (SCROLY — carries DEN bit and YSCROLL), `D012` (RASTER).
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## d012_wrap_around — $D012 wraps at line 255; bit 7 of $D011 holds the 9th bit
|
|
143
|
+
|
|
144
|
+
**Severity:** high
|
|
145
|
+
**Region:** both
|
|
146
|
+
**Triggered by registers:** D011, D012
|
|
147
|
+
**Triggered by techniques:** stable_raster_irq, raster_bars, irq_chain_table, raster_split_modes, pal_ntsc_detection, frame_sync_loop, big_font_2x2, dycp_scroller, logic_rate_decoupling, sprite_multiplex_game, sprite_border_scroller, sprites_only_screen_mode
|
|
148
|
+
|
|
149
|
+
### Symptom
|
|
150
|
+
|
|
151
|
+
A raster IRQ set for line 260 (a valid PAL line in the lower border area) fires
|
|
152
|
+
at line 4 instead, because only the low byte was written and RST8 was clear. On
|
|
153
|
+
a freshly booted machine the sticky bit points the other way: the KERNAL's VIC
|
|
154
|
+
init writes $9B to $D011, so RST8 starts SET and a bare `sta $d012` with a low
|
|
155
|
+
target resolves to target+256 — that exists on PAL only for targets 0-55 (NTSC
|
|
156
|
+
0-6), so the IRQ usually never fires at all. In a handler chain that rewrites
|
|
157
|
+
only $D012, each handler inherits whatever RST8 the previous one left, so
|
|
158
|
+
alternate splits land 256 lines away, or the chain stalls on a target above the
|
|
159
|
+
last line and the frame rate appears to halve. (An earlier version of this
|
|
160
|
+
entry said a single stale write could fire twice per frame; it cannot — see
|
|
161
|
+
Mechanism.)
|
|
162
|
+
|
|
163
|
+
On NTSC the effect is more immediately visible: the frame is only 263 lines
|
|
164
|
+
(6567R8; 262 on the 6567R56A), so lines 256-262 are ordinary visible
|
|
165
|
+
bottom-border lines (the NTSC vertical blank is lines 13-40, per
|
|
166
|
+
`docs/hardware/pal-ntsc-reference.md`; an earlier version of this entry called
|
|
167
|
+
256-262 "vertical blank"), and any bottom-border effect crosses line 255 without
|
|
168
|
+
deliberately targeting high line numbers — a handler that chains forward by
|
|
169
|
+
setting `$D012 = next_line` forgets the 9th bit and wraps to `next_line - 256`.
|
|
170
|
+
|
|
171
|
+
### Mechanism
|
|
172
|
+
|
|
173
|
+
The VIC-II's internal raster counter is 9 bits wide. $D012 holds the low 8 bits
|
|
174
|
+
of the raster compare target. The 9th bit (the high bit) is bit 7 of $D011 —
|
|
175
|
+
the RST8 bit. When the compare target is 256 or higher, RST8 must be set. When
|
|
176
|
+
the compare target is 255 or lower, RST8 must be clear.
|
|
177
|
+
|
|
178
|
+
The failure mode is: code writes only `STA $D012` with the low byte of the
|
|
179
|
+
desired line, and never touches $D011 bit 7. On the first frame this works if
|
|
180
|
+
the target line is below 256. On a line at or above 256, the actual compare
|
|
181
|
+
target the VIC sees is `desired_line & 0xFF` with the 9th bit from whatever
|
|
182
|
+
$D011 bit 7 happens to be. If it is clear, the compare fires at line
|
|
183
|
+
`target - 256` instead of `target`. One IRQ fires per frame, at the wrong line
|
|
184
|
+
— the compare is a single 9-bit value, so it can never match two lines in one
|
|
185
|
+
frame. (An earlier version of this page said two IRQs fire per frame; measured
|
|
186
|
+
in VICE x64sc: RST8=0/$D012=4 gives exactly one IRQ per frame at line 4,
|
|
187
|
+
RST8=1/$D012=80 gives none, on both PAL and NTSC.) Two firings only occur when
|
|
188
|
+
a chain of handlers changes RST8 or $D012 between them.
|
|
189
|
+
|
|
190
|
+
The bit is also sticky: it remains set until explicitly cleared. Code that
|
|
191
|
+
handles both low and high lines must clear RST8 when switching to a target below
|
|
192
|
+
256, not just omit setting it.
|
|
193
|
+
|
|
194
|
+
### Fix
|
|
195
|
+
|
|
196
|
+
Always perform a read-modify-write on $D011 when setting or clearing RST8:
|
|
197
|
+
|
|
198
|
+
```kick
|
|
199
|
+
// Set the raster compare target to TARGET_LINE (may be >= 256).
|
|
200
|
+
.const TARGET_LINE = 260
|
|
201
|
+
|
|
202
|
+
set_irq_line:
|
|
203
|
+
lda $d011
|
|
204
|
+
.if (TARGET_LINE >= 256) {
|
|
205
|
+
ora #%10000000 // Set RST8 (bit 7)
|
|
206
|
+
} else {
|
|
207
|
+
and #%01111111 // Clear RST8
|
|
208
|
+
}
|
|
209
|
+
sta $d011
|
|
210
|
+
lda #<TARGET_LINE // Low 8 bits
|
|
211
|
+
sta $d012
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
In a dynamic context where the target line is a variable at runtime:
|
|
215
|
+
|
|
216
|
+
```kick
|
|
217
|
+
// runtime: .X = target line low byte, carry = 1 if line >= 256
|
|
218
|
+
set_irq_dynamic:
|
|
219
|
+
lda $d011
|
|
220
|
+
and #%01111111 // Clear RST8
|
|
221
|
+
bcc !+ // If target < 256, leave RST8 clear
|
|
222
|
+
ora #%10000000 // Otherwise set RST8
|
|
223
|
+
!: sta $d011
|
|
224
|
+
stx $d012 // Write low 8 bits
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Worked example
|
|
228
|
+
|
|
229
|
+
```kick
|
|
230
|
+
// BAD: only writes $D012, assumes target < 256.
|
|
231
|
+
// On PAL line 260, $D012 = 4, RST8 = 0,
|
|
232
|
+
// so the IRQ fires at line 4 instead of 260.
|
|
233
|
+
lda #<260 // $04
|
|
234
|
+
sta $d012 // Compare target = line 4 (WRONG)
|
|
235
|
+
|
|
236
|
+
// GOOD: writes both RST8 and $D012.
|
|
237
|
+
lda $d011
|
|
238
|
+
ora #%10000000 // Set RST8 for line >= 256
|
|
239
|
+
sta $d011
|
|
240
|
+
lda #<260 // $04
|
|
241
|
+
sta $d012 // Compare target = line 260 (correct)
|
|
242
|
+
|
|
243
|
+
// ALSO BAD: forgets to CLEAR RST8 when switching back to line 80.
|
|
244
|
+
// $D011 bit 7 is still set from the previous write above,
|
|
245
|
+
// so the compare target becomes 80 + 256 = 336 — which never fires on PAL.
|
|
246
|
+
lda #80
|
|
247
|
+
sta $d012 // Bug: RST8 still set, target = 336
|
|
248
|
+
|
|
249
|
+
// CORRECT:
|
|
250
|
+
lda $d011
|
|
251
|
+
and #%01111111 // Clear RST8 for line < 256
|
|
252
|
+
sta $d011
|
|
253
|
+
lda #80
|
|
254
|
+
sta $d012
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Cross-references
|
|
258
|
+
|
|
259
|
+
- Technique: `stable_raster_irq` — the technique this pitfall most directly
|
|
260
|
+
affects; the KickAssembler recipe keeps every target below 256 and writes
|
|
261
|
+
RST8=0 once via `lda #$1b`; it does not exercise the >= 256 path.
|
|
262
|
+
- Registers: `D012` (RASTER — low 8 bits of raster counter and compare),
|
|
263
|
+
`D011` (SCROLY — bit 7 is RST8, the 9th raster bit).
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## raster_irq_first_line_jitter — First raster IRQ after enable has unpredictable entry timing
|
|
268
|
+
|
|
269
|
+
**Severity:** high
|
|
270
|
+
**Region:** both
|
|
271
|
+
**Triggered by registers:** D011, D012
|
|
272
|
+
**Triggered by techniques:** stable_raster_irq, irq_chain_table, phase_inverted_irq, frame_sync_loop, raster_split_modes, mode7_lookalike, vsp_glitch, pseudo_3d_road_raster, sprite_stretcher_d017, tech_tech_wobbler, dysp_side_border_sprites
|
|
273
|
+
**Mitigated by techniques:** stable_raster_irq, double_irq
|
|
274
|
+
|
|
275
|
+
### Symptom
|
|
276
|
+
|
|
277
|
+
A raster effect that works perfectly after the first few frames is unstable on
|
|
278
|
+
the very first frame after IRQ enable. Color splits land 1-7 pixels to the right
|
|
279
|
+
on the first frame. A sprite multiplex update on the first frame puts sprites
|
|
280
|
+
one line too low. The symptom disappears by frame 2. Alternatively, a raster
|
|
281
|
+
effect coded without the stable-raster polling technique shows a permanent 0-7
|
|
282
|
+
cycle wobble that makes split lines look "fuzzy" — a 1-7 pixel horizontal smear
|
|
283
|
+
on every frame where the interrupted instruction happened to be long.
|
|
284
|
+
|
|
285
|
+
### Mechanism
|
|
286
|
+
|
|
287
|
+
The 6510 does not sample the /IRQ line between clock cycles — it samples it at
|
|
288
|
+
the end of each instruction. When the VIC-II asserts the IRQ line, the CPU
|
|
289
|
+
finishes whatever instruction it is currently executing, then begins the 7-cycle
|
|
290
|
+
interrupt entry sequence (two dummy cycles, push PCH, push PCL, push P, fetch
|
|
291
|
+
vector low, fetch vector high; the handler's first opcode fetch is its own first
|
|
292
|
+
cycle — an earlier version of this entry counted it inside the 7). The number
|
|
293
|
+
of cycles between the VIC asserting the line and the handler's first instruction executing depends on how many cycles
|
|
294
|
+
were left in the interrupted instruction. A 2-cycle `NOP` interrupted on its
|
|
295
|
+
last cycle adds 1 cycle of delay; a 6-cycle `STA ($zp,X)` interrupted on its
|
|
296
|
+
first cycle adds 5 cycles of delay. The total jitter window is 0-6 cycles for
|
|
297
|
+
common instructions (the 7-cycle `BRK` is a pathological case that adds up to
|
|
298
|
+
6 cycles, but is not found in normal runtime code).
|
|
299
|
+
|
|
300
|
+
On the very first frame after enabling IRQs (writing $D01A bit 0 = 1), the CPU
|
|
301
|
+
has no idea what instruction it will be executing when the first IRQ fires. The
|
|
302
|
+
jitter is random within the 0-6 cycle window. On subsequent frames, if the
|
|
303
|
+
main loop is a tight `JMP *` or a counted NOP sled, the interrupted instruction
|
|
304
|
+
is always the same (a 3-cycle `JMP`, leaving 0-2 cycles of jitter, or a 2-cycle
|
|
305
|
+
`NOP`, leaving 0-1 — an earlier version of this entry called `JMP *` a 2-cycle
|
|
306
|
+
branch; a taken same-page branch is itself 3 cycles), so the jitter narrows
|
|
307
|
+
— but it does not disappear. The polling loop bounds the jitter to one loop
|
|
308
|
+
iteration (0-8 cycles for the 9-cycle `LDA/CMP/BNE` form); the `double_irq`
|
|
309
|
+
variant then removes that residual before the cycle-tight register writes begin.
|
|
310
|
+
That is why `stable_raster_irq` is on both metadata lines above: the pitfall
|
|
311
|
+
is what a raster interrupt does before the technique is applied to it (the
|
|
312
|
+
naive form), and the technique's polling loop — with `double_irq` for the
|
|
313
|
+
last cycle — is the cure.
|
|
314
|
+
|
|
315
|
+
### Fix
|
|
316
|
+
|
|
317
|
+
Use the stable-raster technique (`stable_raster_irq`): the polling form below
|
|
318
|
+
bounds jitter to one loop iteration (0-8 cycles with the 9-cycle `LDA/CMP/BNE`
|
|
319
|
+
loop shown); for zero jitter use the two-handler `double_irq` form described in
|
|
320
|
+
the technique doc and in `recipes/kickassembler/stable-raster-irq.md`. The
|
|
321
|
+
polling pattern:
|
|
322
|
+
|
|
323
|
+
1. Enable raster IRQs with the IRQ line set to one line before the target line
|
|
324
|
+
(line N-1).
|
|
325
|
+
2. In the IRQ handler for line N-1: acknowledge $D019, leave $D012 at N-1, and
|
|
326
|
+
poll $D012 in a tight loop until the counter increments to N. (An earlier
|
|
327
|
+
version of this entry said to set $D012 to N here; that re-arms the compare
|
|
328
|
+
for a line the handler is still polling through, latches a second IRQ that
|
|
329
|
+
is never acknowledged, and re-enters the handler straight after RTI — see the
|
|
330
|
+
worked example.)
|
|
331
|
+
3. Once $D012 reads N, execute a counted NOP pad to place the writes at the
|
|
332
|
+
desired cycle to within the loop's residual (the pad sets the mean position
|
|
333
|
+
only).
|
|
334
|
+
4. Perform the cycle-tight register writes.
|
|
335
|
+
|
|
336
|
+
The polling loop at step 2 bounds whatever jitter existed on entry to the
|
|
337
|
+
handler. By the time the loop exits ($D012 has just incremented to N), every
|
|
338
|
+
subsequent instruction runs within one poll iteration of the start of line N.
|
|
339
|
+
The initial first-frame jitter is bounded the same way — the first handler
|
|
340
|
+
entry may be anywhere within line N-1, but the polling loop absorbs that and
|
|
341
|
+
exits within one poll iteration of the start of line N regardless — but not at
|
|
342
|
+
one fixed cycle: the exit cycle still depends on where in the iteration the
|
|
343
|
+
entry fell.
|
|
344
|
+
|
|
345
|
+
### Worked example
|
|
346
|
+
|
|
347
|
+
```kick
|
|
348
|
+
// Single-IRQ approach — JITTERY. The STA $D020 can land 0-6 cycles
|
|
349
|
+
// late depending on what instruction was running when the IRQ fired.
|
|
350
|
+
irq_jittery:
|
|
351
|
+
lda #BLUE
|
|
352
|
+
sta $d020 // Horizontal seam varies by 0-6 pixels
|
|
353
|
+
asl $d019 // Ack
|
|
354
|
+
rti
|
|
355
|
+
|
|
356
|
+
// Stable-raster polling approach — jitter bounded to one 9-cycle poll
|
|
357
|
+
// iteration, not zero. Measured in VICE x64sc 3.10: with a frame-locked main
|
|
358
|
+
// loop the exit phase kept the entry spread unchanged (two phases 4 cycles
|
|
359
|
+
// apart over 60 frames); with a 19-cycle main loop it took three phases
|
|
360
|
+
// spanning 5 cycles. Zero jitter needs double_irq.
|
|
361
|
+
// IRQ fires at line TARGET_LINE-1. It acks, leaves the compare where it is,
|
|
362
|
+
// then spins until $D012 increments to TARGET_LINE.
|
|
363
|
+
// An earlier version of this fragment wrote TARGET_LINE to $D012 before the
|
|
364
|
+
// poll; that fired a second compare during the poll, left $D019 latched, and
|
|
365
|
+
// re-entered the handler right after RTI (measured: ~2 main-loop iterations
|
|
366
|
+
// per frame). Leaving $D012 at TARGET_LINE-1 needs no second ack and no re-arm.
|
|
367
|
+
irq_stable_setup:
|
|
368
|
+
asl $d019 // Ack IRQ for line TARGET_LINE-1
|
|
369
|
+
// Poll until raster reaches TARGET_LINE.
|
|
370
|
+
// Each loop iteration: LDA abs (4) + CMP imm (2) + BNE (3) = 9 cycles.
|
|
371
|
+
// The loop exits within 0-8 cycles of the line start, bounding jitter.
|
|
372
|
+
!: lda $d012
|
|
373
|
+
cmp #TARGET_LINE
|
|
374
|
+
bne !-
|
|
375
|
+
// Now on line TARGET_LINE. Add NOP padding to reach the desired cycle
|
|
376
|
+
// (to within the loop's residual).
|
|
377
|
+
nop // 2 cycles — tune count for the mean cycle target
|
|
378
|
+
nop
|
|
379
|
+
// Effect code lands here within one poll iteration of the line start.
|
|
380
|
+
lda #RED
|
|
381
|
+
sta $d020 // Lands within one poll iteration of the line
|
|
382
|
+
// start; use double_irq for a fixed cycle
|
|
383
|
+
rti
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
The key insight: the `LDA $D012 / CMP / BNE` loop quantises the jitter window
|
|
387
|
+
to its own 9-cycle period; it does not remove it (an earlier version of this
|
|
388
|
+
entry said the loop "consumes" the jitter and the writes land at a fixed cycle;
|
|
389
|
+
measured in VICE x64sc, the exit phase spread equalled the entry spread). The
|
|
390
|
+
exit of the loop always happens within one loop iteration (9 cycles) of the
|
|
391
|
+
raster line's start. NOP pads after the loop bring the writes to the desired
|
|
392
|
+
cycle to within that residual. The first-frame case is no different: the
|
|
393
|
+
polling loop bounds any entry-time jitter, including the variable amount from
|
|
394
|
+
the random interrupted instruction on frame 1.
|
|
395
|
+
|
|
396
|
+
For single-cycle precision, the `double_irq` technique fires two consecutive
|
|
397
|
+
IRQs on lines N-1 and N, where the second IRQ's entry timing is constrained by
|
|
398
|
+
the known instruction in the main loop between the two handlers (typically a
|
|
399
|
+
2-cycle NOP), eliminating even the 0-8 cycle polling-loop residual. "Lines N-1
|
|
400
|
+
and N" holds with the KERNAL out; through $0314 the first handler arms the
|
|
401
|
+
second IRQ two lines down (see the technique doc and the recipe's "The double
|
|
402
|
+
IRQ").
|
|
403
|
+
|
|
404
|
+
### Cross-references
|
|
405
|
+
|
|
406
|
+
- Technique: `stable_raster_irq` — the complete description of the polling
|
|
407
|
+
stable-raster pattern, including the NOP-pad sizing and the `double_irq`
|
|
408
|
+
variant for single-cycle work.
|
|
409
|
+
- Technique: `double_irq` — scene-tier zero-jitter extension of stable_raster_irq.
|
|
410
|
+
- Registers: `D019` (VICIRQ — interrupt flag register; must be acked before
|
|
411
|
+
RTI), `D012` (RASTER — the register being polled), `D011` (SCROLY — RST8 bit
|
|
412
|
+
for targets >= 256).
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## vic_bus_takeover_on_dma — VIC sprite DMA freezes the CPU for 5-19 cycles per scanline
|
|
417
|
+
|
|
418
|
+
**Severity:** medium
|
|
419
|
+
**Region:** both
|
|
420
|
+
**Triggered by registers:** D015
|
|
421
|
+
**Triggered by techniques:** sprite_multiplex_8, dma_steal_avoidance, sideborder_open, sprite_multiplex_24, sprite_sine_chain, badline_synchronization, sprite_multiplex_game, reu_dma, raster_profile_bars, sprites_only_screen_mode, dysp_side_border_sprites
|
|
422
|
+
|
|
423
|
+
### Symptom
|
|
424
|
+
|
|
425
|
+
A raster IRQ that runs cleanly with no sprites enabled suddenly slips its timing
|
|
426
|
+
when sprites are turned on. The slip is not random — it is proportional to the
|
|
427
|
+
number of sprites active on the scanline where the IRQ handler runs. With 8
|
|
428
|
+
sprites active on the handler's line, the CPU appears to freeze for approximately
|
|
429
|
+
19 cycles mid-instruction, then resume. Register writes that were cycle-tight
|
|
430
|
+
arrive late. In extreme cases, the handler misses its intended scanline
|
|
431
|
+
entirely and writes land on the line below.
|
|
432
|
+
|
|
433
|
+
### Mechanism
|
|
434
|
+
|
|
435
|
+
For each sprite enabled in $D015, the VIC-II must fetch 3 bytes of sprite pixel
|
|
436
|
+
data (s-accesses) on every raster line covered by that sprite's 21 pixel rows.
|
|
437
|
+
The chip claims the bus for these fetches during specific cycles of the scanline.
|
|
438
|
+
Before the s-accesses begin, the VIC also issues 2 p-access cycles (pointer
|
|
439
|
+
fetches) for each active sprite. Not all of these accesses cost the CPU: the
|
|
440
|
+
p-access and one of the three s-accesses are phi1 accesses, the VIC's own bus
|
|
441
|
+
phase; only the two phi2 s-accesses take CPU bus cycles, which is why the cost
|
|
442
|
+
is two cycles per sprite and not three or five. (An earlier version of this
|
|
443
|
+
entry said all of them happen during phi2.)
|
|
444
|
+
|
|
445
|
+
The exact stall per sprite, per DMA scanline (an earlier version of this entry
|
|
446
|
+
charged 2 cycles of p-access on the first line plus 3 of s-access per line, and
|
|
447
|
+
its sums did not add up — 3 + 2 + 16 is 21, not 19):
|
|
448
|
+
- **0 cycles** for the p-access: it happens on every raster line for every
|
|
449
|
+
sprite regardless of enable state, in phi1, and costs the CPU nothing.
|
|
450
|
+
- **2 bus cycles** of s-access per sprite on every line of its 21 DMA lines.
|
|
451
|
+
- **3 cycles of BA lead-in** per contiguous group of sprite slots, during which
|
|
452
|
+
the CPU can only complete write cycles.
|
|
453
|
+
|
|
454
|
+
Measured in VICE x64sc 3.10 with an all-read loop timed by CIA1 between raster
|
|
455
|
+
lines 100 and 200, DEN off, sprites at Y=150 (21 DMA lines): 105/147/231/399
|
|
456
|
+
cycles stolen over the 21 lines of 1/2/4/8 sprites (= 21 × 5, 7, 11, 19), and
|
|
457
|
+
210 for sprites 0 and 7 as two BA groups (21 × 10). The 3 lead-in cycles per
|
|
458
|
+
group being write-usable is from the VIC-II reference and Bauer's model, not
|
|
459
|
+
measured here. Sprite DMA and badline costs simply add: 8 sprites plus 5
|
|
460
|
+
badlines over lines 140-180 measured 614 = 399 + 5 × 43.
|
|
461
|
+
|
|
462
|
+
With all 8 sprites enabled and active on a single line, the VIC steals 3 cycles
|
|
463
|
+
of BA + 8 × 2 s-access = 19 cycles from the CPU on that line. On PAL, this
|
|
464
|
+
reduces the effective CPU budget from 63 cycles to 44 cycles. On NTSC, from 65
|
|
465
|
+
cycles to 46 cycles.
|
|
466
|
+
|
|
467
|
+
The CPU cannot choose when the stall happens — it is determined by the VIC's
|
|
468
|
+
internal DMA schedule, which runs on fixed cycle slots within each line. If an
|
|
469
|
+
instruction spans a DMA window, the CPU stalls mid-instruction and resumes when
|
|
470
|
+
the VIC releases the bus. The instruction completes correctly but takes more wall
|
|
471
|
+
clock cycles than its documented cycle count.
|
|
472
|
+
|
|
473
|
+
### Fix
|
|
474
|
+
|
|
475
|
+
Account for sprite DMA in the cycle budget wherever sprites are active on the
|
|
476
|
+
IRQ handler's scanline:
|
|
477
|
+
|
|
478
|
+
| Active sprites on handler line (one contiguous group) | Cycles stolen | Usable cycles PAL | Usable cycles NTSC |
|
|
479
|
+
|---:|---:|---:|---:|
|
|
480
|
+
| 0 | 0 | 63 | 65 |
|
|
481
|
+
| 1 | 5 | 58 | 60 |
|
|
482
|
+
| 2 | 7 | 56 | 58 |
|
|
483
|
+
| 4 | 11 | 52 | 54 |
|
|
484
|
+
| 8 | 19 | 44 | 46 |
|
|
485
|
+
|
|
486
|
+
(Measured in VICE x64sc: 2 per sprite plus 3 lead-in per group. An earlier
|
|
487
|
+
version of this table gave 2/5/9 for 1/2/4 sprites, under-budgeting by 3 cycles
|
|
488
|
+
each; sprites in separate groups pay the lead-in once per group.)
|
|
489
|
+
|
|
490
|
+
Strategies:
|
|
491
|
+
|
|
492
|
+
1. **Fire the handler on a line where no sprites are active.** If sprites are
|
|
493
|
+
enabled for display rows 50-100 and the raster handler must run on line 95,
|
|
494
|
+
check whether all 8 sprites are active there. If they are, move the handler
|
|
495
|
+
to line 101 (below the sprite zone) if the effect permits.
|
|
496
|
+
|
|
497
|
+
2. **Account for DMA in cycle-counted code.** Add the DMA stall cycles to the
|
|
498
|
+
cycle count for any instruction that may execute during the DMA window. Use
|
|
499
|
+
VICE's cycle counter to measure actual cycle consumption rather than the
|
|
500
|
+
documented cycle count.
|
|
501
|
+
|
|
502
|
+
3. **Disable sprites in the effect zone.** Write $D015 = $00 above the effect
|
|
503
|
+
line to disable all sprites; restore after the effect section. This is
|
|
504
|
+
compatible with sprite multiplexing: the multiplexer can disable sprites it
|
|
505
|
+
is not currently showing.
|
|
506
|
+
|
|
507
|
+
4. **Use the sprite DMA window deliberately.** Some advanced techniques
|
|
508
|
+
(sprite-crunch, sprite stretching) exploit the DMA cycle slots. Out of scope
|
|
509
|
+
here, but the point is the DMA slots are fixed and therefore predictable.
|
|
510
|
+
|
|
511
|
+
### Worked example
|
|
512
|
+
|
|
513
|
+
```kick
|
|
514
|
+
// WRONG: assumes 63 available cycles on a line where 8 sprites are active.
|
|
515
|
+
// The handler body takes 54 cycles as written (8 colour writes), but sprite
|
|
516
|
+
// DMA steals 19, so total wall-clock consumption is 73 cycles — bleeds into
|
|
517
|
+
// the next line. (An earlier version of this example counted a LDA #imm /
|
|
518
|
+
// STA abs pair as 3 or 4 cycles; it is 2 + 4 = 6.)
|
|
519
|
+
sprite_irq_buggy:
|
|
520
|
+
asl $d019 // 6 cycles (read-modify-write)
|
|
521
|
+
lda #BLUE // 2 cycles
|
|
522
|
+
sta $d020 // 4 cycles — color write 1 (pair = 6)
|
|
523
|
+
lda #RED
|
|
524
|
+
sta $d021 // pair = 6 — color write 2
|
|
525
|
+
lda #GREEN
|
|
526
|
+
sta $d022 // pair = 6 — color write 3
|
|
527
|
+
// ... 5 more store pairs = 30 more cycles ...
|
|
528
|
+
// Total: 54 coded cycles + 19 DMA = 73 actual cycles (OVERFLOW)
|
|
529
|
+
rti
|
|
530
|
+
|
|
531
|
+
// CORRECT: handler is scheduled on a line where 0 sprites are active,
|
|
532
|
+
// OR the handler body is trimmed to fit within 44 usable cycles.
|
|
533
|
+
// With 8 sprites: coded body must fit in 44 cycles, not 63.
|
|
534
|
+
sprite_irq_correct:
|
|
535
|
+
asl $d019 // 6 cycles
|
|
536
|
+
lda #BLUE // 2 cycles
|
|
537
|
+
sta $d020 // 4 cycles
|
|
538
|
+
lda #RED // 2 cycles
|
|
539
|
+
sta $d021 // 4 cycles
|
|
540
|
+
// Only 2 color writes: 18 coded cycles + 19 DMA = 37 actual cycles (OK)
|
|
541
|
+
// The RTI (6) and the IRQ entry (7, plus up to 29 via the KERNAL
|
|
542
|
+
// dispatcher) are on top of the body.
|
|
543
|
+
rti
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Cross-references
|
|
547
|
+
|
|
548
|
+
- Technique: `sprite_multiplex_8` — the primary technique that enables 8+
|
|
549
|
+
sprites per frame; its cycle budget section discusses DMA accounting.
|
|
550
|
+
- Register: `D015` (SPENA — sprite enable bits; each set bit triggers DMA
|
|
551
|
+
on active lines for that sprite).
|
|
552
|
+
- Pitfall: `badline_cycle_loss` — the two cycle thieves stack, not overlap: a
|
|
553
|
+
badline on a line with 8 active sprites leaves the CPU one cycle on PAL
|
|
554
|
+
(cycle 11), plus at most the three write-only cycles 12-14 if the instruction
|
|
555
|
+
in flight is writing then — 4 at best, never the 20-23 an earlier version of
|
|
556
|
+
this entry gave. Measured in VICE x64sc: 43 (badline) + 19 (eight sprites) =
|
|
557
|
+
62 of 63 cycles stolen on every line where both occur (915 - 516 - 399 = 0
|
|
558
|
+
over two overlapping lines; 1314 - 516 - 798 = 0 over five). The sprite
|
|
559
|
+
lead-in cycles 55-57 are not usable on such a line: BA is already low from
|
|
560
|
+
cycle 12 and does not rise again until cycle 11 of the next line, so a CPU
|
|
561
|
+
halted on a read at cycle 15 cannot reach them.
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## scroll_phase_breaks_panel_split — A panel split with a fixed delay breaks at one YSCROLL phase
|
|
566
|
+
|
|
567
|
+
**Severity:** high
|
|
568
|
+
**Region:** both
|
|
569
|
+
**Triggered by registers:** D011, D012
|
|
570
|
+
**Triggered by techniques:** scroll_panel_split, soft_scroll_v, char_scroll_buffer_v
|
|
571
|
+
**Mitigated by techniques:** scroll_panel_split
|
|
572
|
+
|
|
573
|
+
### Symptom
|
|
574
|
+
|
|
575
|
+
A vertically scrolling playfield sits above a fixed score panel. Seven frames
|
|
576
|
+
in eight the panel is clean. On the eighth, the panel's first line keeps the
|
|
577
|
+
playfield's blue and its 38-column left edge, and the next six lines have the
|
|
578
|
+
panel's grey and width but stray light-blue character pixels where the rule
|
|
579
|
+
row should be. The rest of the panel is correct. The flicker repeats every
|
|
580
|
+
eight pixels of scroll. Measured with PIL on the recipe's `USE_TABLE = 0`
|
|
581
|
+
build at YSCROLL 6, PAL and NTSC: line 215 x 39-351 on blue, lines 216-221
|
|
582
|
+
x 32-351 on grey (98, 98, 98), line 222 on identical to the reference.
|
|
583
|
+
|
|
584
|
+
### Mechanism
|
|
585
|
+
|
|
586
|
+
The split IRQ polls for the playfield's last line and then waits a fixed
|
|
587
|
+
delay so its stores land in that line's right border. A line is a badline when
|
|
588
|
+
its low three bits equal YSCROLL. The playfield's YSCROLL takes all eight
|
|
589
|
+
values, so the split line is a badline at exactly one of them. At that phase
|
|
590
|
+
the VIC holds the CPU from cycle 12 to cycle 54 during the delay, and the
|
|
591
|
+
stores land about 40 cycles late, inside the panel's first line. The
|
|
592
|
+
panel's `$D011` then makes that line a badline too late for a normal fetch,
|
|
593
|
+
and the `$D016` and `$D018` changes arrive mid-line.
|
|
594
|
+
|
|
595
|
+
Measured in VICE x64sc 3.10, PAL and NTSC, with
|
|
596
|
+
`recipes/kickassembler/scroll-panel-split.md` and `USE_TABLE = 0` (split
|
|
597
|
+
line 214, the same 5-pass delay at every phase): at YSCROLL 0-5 and 7 the
|
|
598
|
+
panel region, lines 215-250, is pixel-identical to the reference. At YSCROLL
|
|
599
|
+
6, where line 214 is a badline, lines 215-221 differ (1,108 pixels on PAL,
|
|
600
|
+
1,107 on NTSC). Two forum threads name YSCROLL 7 as the bad
|
|
601
|
+
phase (https://www.lemon64.com/forum/viewtopic.php?t=52763 and
|
|
602
|
+
https://www.lemon64.com/forum/viewtopic.php?t=64112, read as search
|
|
603
|
+
snippets, and the site returned 403 for the second; forum reports, not
|
|
604
|
+
measured here); that is the phase for their split line, not a constant.
|
|
605
|
+
|
|
606
|
+
`scroll_panel_split` is on both lines above: the naive form of the split
|
|
607
|
+
raises the pitfall and the table-driven form cures it.
|
|
608
|
+
|
|
609
|
+
### Fix
|
|
610
|
+
|
|
611
|
+
Index the delay by the playfield's YSCROLL and give the phase at which the
|
|
612
|
+
split line is a badline a short or zero delay: the badline stall is the wait.
|
|
613
|
+
Load every register value before the poll, so that after the stall only the
|
|
614
|
+
stores remain. In the recipe the table is 5, 5, 5, 5, 5, 5, 0, 5 passes of 9
|
|
615
|
+
cycles, and all eight phases leave the panel pixel-identical on PAL and NTSC.
|
|
616
|
+
|
|
617
|
+
A second, separate phase effect: put the panel's first line on a line that is
|
|
618
|
+
7 mod 8. Elsewhere the panel's first row reads a different screen row at
|
|
619
|
+
different phases (measured: panel on line 216 with YSCROLL 0 read screen row
|
|
620
|
+
21 at playfield YSCROLL 0 and row 20 at YSCROLL 3).
|
|
621
|
+
|
|
622
|
+
### Worked example
|
|
623
|
+
|
|
624
|
+
```text
|
|
625
|
+
// Naive: one delay for every phase. Breaks when (split line & 7) = YSCROLL.
|
|
626
|
+
lda #LAST_PF-1
|
|
627
|
+
wait: cmp $d012
|
|
628
|
+
bcs wait
|
|
629
|
+
lda #5
|
|
630
|
+
sta count
|
|
631
|
+
delay: dec count
|
|
632
|
+
bpl delay
|
|
633
|
+
sty $d016 ...
|
|
634
|
+
|
|
635
|
+
// Fixed: the delay comes from a table indexed by YSCROLL.
|
|
636
|
+
ldx yscroll
|
|
637
|
+
lda delay_tbl,x // 5, 5, 5, 5, 5, 5, 0, 5 for split line 214
|
|
638
|
+
sta count
|
|
639
|
+
... // load the panel values, poll, dec count / bpl
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Cross-references
|
|
643
|
+
|
|
644
|
+
- Technique: `scroll_panel_split` in `techniques/scroll.md`.
|
|
645
|
+
- Pitfall: `badline_cycle_loss`: the 40-43 cycle stall that moves the stores.
|
|
646
|
+
- Recipe: `recipes/kickassembler/scroll-panel-split.md`, with the per-phase table.
|
|
647
|
+
- Source of the table idea: c64gameframework `raster.s`, `irq4DelayTbl`
|
|
648
|
+
(https://github.com/cadaver/c64gameframework, read, not run).
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
## idle_fetch_byte_shows_in_gaps — The byte at $3FFF is drawn wherever the VIC has no row to show
|
|
653
|
+
|
|
654
|
+
**Severity:** medium
|
|
655
|
+
**Region:** both
|
|
656
|
+
**Triggered by registers:** D011
|
|
657
|
+
**Triggered by techniques:** fld_flexible_line_distance, sideborder_open, topbottom_border_open, sprites_only_screen_mode, dysp_side_border_sprites
|
|
658
|
+
|
|
659
|
+
### Symptom
|
|
660
|
+
|
|
661
|
+
A band of thin vertical stripes, or a repeated pattern, appears across the
|
|
662
|
+
display window where there should be plain background: in the gap an FLD
|
|
663
|
+
opens above the screen, in the lines a side-border loop keeps badline-free,
|
|
664
|
+
or in the opened top and bottom borders. On the developer's machine or in a
|
|
665
|
+
fresh emulator the same lines are clean. Garbage that "only shows on real
|
|
666
|
+
hardware", or only after another program has run, is the usual report.
|
|
667
|
+
|
|
668
|
+
### Mechanism
|
|
669
|
+
|
|
670
|
+
When no badline has loaded the video matrix latch the VIC is in idle state,
|
|
671
|
+
and its g-accesses read one fixed address instead of the character
|
|
672
|
+
generator: `$3FFF` in VIC bank 0, `$7FFF`, `$BFFF` or `$FFFF` in banks 1-3,
|
|
673
|
+
and `$39FF` (or the bank equivalent) with ECM set. The byte fetched is
|
|
674
|
+
drawn as pixels across the whole window on every idle line, bit 1 in colour
|
|
675
|
+
0, bit 0 in the background colour. VICE's RAM starts cleared, so the byte
|
|
676
|
+
is zero and the idle lines look like background. On hardware the byte holds
|
|
677
|
+
whatever was there: the power-on RAM pattern, or the tail of a previous
|
|
678
|
+
program's data, tables or code. Every technique that opens lines the VIC
|
|
679
|
+
does not fetch a row for exposes it: the FLD gap (`fld_flexible_line_distance`),
|
|
680
|
+
a side-border region whose YSCROLL is rewritten each line
|
|
681
|
+
(`sideborder_open`), and the top and bottom borders once opened
|
|
682
|
+
(`topbottom_border_open`). Measured in VICE x64sc 3.10: with `$3FFF` set to
|
|
683
|
+
`%10101010`, every line of an 18-line FLD gap on PAL and a 22-line gap on
|
|
684
|
+
NTSC is 160 black and 160 background pixels across x 32-351, alternating
|
|
685
|
+
from x = 32.
|
|
686
|
+
|
|
687
|
+
### Fix
|
|
688
|
+
|
|
689
|
+
Own the byte. Store `$00` at the idle address of the bank in use before the
|
|
690
|
+
effect starts, or store a chosen pattern when the stripes are wanted; in
|
|
691
|
+
bank 3 the address is `$FFFF`, which is RAM to the VIC and to a CPU store
|
|
692
|
+
even with the KERNAL ROM banked in. Do it once at start-up and again
|
|
693
|
+
whenever the VIC bank changes. The address is not free memory: a table
|
|
694
|
+
that ends at `$3FFF` puts its last byte on the screen.
|
|
695
|
+
|
|
696
|
+
### Worked example
|
|
697
|
+
|
|
698
|
+
From `recipes/kickassembler/fld.md`: the recipe wants the gap to be
|
|
699
|
+
visible, so it plants the pattern deliberately.
|
|
700
|
+
|
|
701
|
+
```text
|
|
702
|
+
// Bank 0: the idle fetch reads $3FFF. Plant the stripe once at start-up.
|
|
703
|
+
lda #%10101010
|
|
704
|
+
sta $3fff
|
|
705
|
+
|
|
706
|
+
// The same program wanting a clean gap stores zero instead:
|
|
707
|
+
lda #0
|
|
708
|
+
sta $3fff
|
|
709
|
+
|
|
710
|
+
// Bank 3 ($C000-$FFFF): the equivalent address is $FFFF, RAM under the
|
|
711
|
+
// KERNAL for both the VIC's fetch and the CPU's store.
|
|
712
|
+
lda #0
|
|
713
|
+
sta $ffff
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Cross-references
|
|
717
|
+
|
|
718
|
+
- Technique: `fld_flexible_line_distance` in `techniques/raster.md`: the gap is idle lines by design.
|
|
719
|
+
- Technique: `sideborder_open` and `topbottom_border_open` in `techniques/raster.md`: idle lines as a side effect.
|
|
720
|
+
- Hardware: `hardware/vic-ii-reference.md`, "Idle vs display state" and the `$3FFF` phantom-pixel note.
|
|
721
|
+
- Recipe: `recipes/kickassembler/fld.md`, where the byte is `%10101010` and the stripes are measured.
|