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