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,314 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: sprite-multiplex-8
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [sprite_multiplex_8]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: [D015, D000, D001, D010, D027, D012, D019, D01A, D020, D021]
|
|
9
|
+
uses_kernal: []
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 8-Sprite Multiplexer (12 Logical Sprites)
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
Displays 12 independently moving logical sprites using only the VIC-II's 8
|
|
19
|
+
hardware sprite slots, via `sprites.h` virtual sprite (`vspr_*`) functions.
|
|
20
|
+
The `vspr_*` layer sorts logical sprites by Y position each frame and uses
|
|
21
|
+
`rasterirq.h` slots to reposition hardware sprites mid-screen. Each logical
|
|
22
|
+
sprite beyond the eighth gets its own raster IRQ slot that re-arms one
|
|
23
|
+
hardware sprite as soon as that sprite's first draw has finished, so with 12
|
|
24
|
+
logical sprites four of the eight hardware sprites are reused once and the
|
|
25
|
+
other four are not (an earlier version of this page described "two vertical
|
|
26
|
+
passes" with every hardware sprite reused; the library does not work that
|
|
27
|
+
way). This is the `sprite_multiplex_8` technique from
|
|
28
|
+
`docs/techniques/sprite.md`.
|
|
29
|
+
|
|
30
|
+
## Source
|
|
31
|
+
|
|
32
|
+
```c
|
|
33
|
+
// sprite-multiplex-8.c
|
|
34
|
+
//
|
|
35
|
+
// 12 logical sprites on 8 hardware sprites using vspr_* multiplexer.
|
|
36
|
+
// Sprites move in circular paths computed from a precomputed sine table.
|
|
37
|
+
//
|
|
38
|
+
// Memory layout: sprite data is placed at a fixed page-aligned address
|
|
39
|
+
// ($2000) so that block numbers are predictable (block = addr / 64).
|
|
40
|
+
//
|
|
41
|
+
#include <c64/vic.h>
|
|
42
|
+
#include <c64/sprites.h>
|
|
43
|
+
#include <c64/rasterirq.h>
|
|
44
|
+
#include <math.h>
|
|
45
|
+
|
|
46
|
+
// Screen RAM at the default C64 address.
|
|
47
|
+
#define Screen ((char *)0x0400)
|
|
48
|
+
|
|
49
|
+
// Keep code and writable data below $2000 so sprite data fits at $2000.
|
|
50
|
+
#pragma region( lower, 0x0a00, 0x2000, , , {code, data} )
|
|
51
|
+
|
|
52
|
+
// Reserve $2000-$2800 for the sprite set (32 sprites × 64 bytes each = 2048).
|
|
53
|
+
#pragma section( spriteset, 0 )
|
|
54
|
+
#pragma region( spriteset, 0x2000, 0x2800, , , {spriteset} )
|
|
55
|
+
|
|
56
|
+
// Remaining code, data, bss, heap, and stack go above $2800.
|
|
57
|
+
#pragma region( main, 0x2800, 0xa000, , , {code, data, bss, heap, stack} )
|
|
58
|
+
|
|
59
|
+
// --- Sprite bitmap data ---
|
|
60
|
+
// Twelve distinct 24x21 bitmaps, each 63 bytes (padded to 64-byte alignment).
|
|
61
|
+
// For this demo each sprite is a simple filled diamond shape generated by the
|
|
62
|
+
// initializer. In a real program, use: #embed spd_sprites "sprites.spd"
|
|
63
|
+
// or #embed "../resources/sprites.bin" to load SpritePad data.
|
|
64
|
+
#pragma data(spriteset)
|
|
65
|
+
|
|
66
|
+
static char spriteset[2048]; // 32 × 64-byte blocks; first 12 used
|
|
67
|
+
|
|
68
|
+
#pragma data(data)
|
|
69
|
+
|
|
70
|
+
// --- Sine tables for circular motion ---
|
|
71
|
+
// 128 entries covering one full cycle, pre-scaled to the orbit radius so the
|
|
72
|
+
// frame loop is a table lookup. An earlier version kept one -90..+90 table
|
|
73
|
+
// and scaled it in the loop with a 16-bit multiply and divide per axis; that
|
|
74
|
+
// loop measured 23,213-26,694 cycles per frame in VICE, more than a 19,656-
|
|
75
|
+
// cycle PAL frame, so rirq_wait() returned at arbitrary raster lines and
|
|
76
|
+
// vspr_update() rewrote the hardware sprites mid-frame, losing up to half the
|
|
77
|
+
// sprites. The table-only loop below measured 6,292-9,162 cycles.
|
|
78
|
+
static int sinx[128]; // -RADIUS_X..+RADIUS_X
|
|
79
|
+
static int siny[128]; // -RADIUS_Y..+RADIUS_Y
|
|
80
|
+
|
|
81
|
+
// Number of logical sprites to display.
|
|
82
|
+
#define NUM_SPRITES 12
|
|
83
|
+
|
|
84
|
+
// Radius of each sprite's circular orbit in screen pixels.
|
|
85
|
+
#define RADIUS_X 80
|
|
86
|
+
#define RADIUS_Y 60
|
|
87
|
+
|
|
88
|
+
// Center of the display area (sprite Y origin on PAL is approximately 50
|
|
89
|
+
// for the top of the visible area; sprites are Y=50..250).
|
|
90
|
+
#define CENTER_X 160
|
|
91
|
+
#define CENTER_Y 150
|
|
92
|
+
|
|
93
|
+
int main(void)
|
|
94
|
+
{
|
|
95
|
+
// --- Initialize sine tables (floating point once, at start-up) ---
|
|
96
|
+
for (int i = 0; i < 128; i++) {
|
|
97
|
+
sinx[i] = (int)(RADIUS_X * sin(i * 3.14159265 / 64.0));
|
|
98
|
+
siny[i] = (int)(RADIUS_Y * sin(i * 3.14159265 / 64.0));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// --- Initialize sprite bitmaps in place ---
|
|
102
|
+
// Paint each block with a distinct simple pattern so sprites are
|
|
103
|
+
// visually distinguishable. A filled diamond is 9 bytes per sprite row.
|
|
104
|
+
for (char s = 0; s < NUM_SPRITES; s++) {
|
|
105
|
+
char *blk = spriteset + (int)s * 64;
|
|
106
|
+
// Row 10 (middle row) of the diamond: all three bytes filled.
|
|
107
|
+
for (char row = 0; row < 21; row++) {
|
|
108
|
+
// Diamond shape: row 0 and 20 have 1 pixel, row 10 is full.
|
|
109
|
+
char w = (row <= 10) ? row : (20 - row);
|
|
110
|
+
// Shift a centered mask to the right by (10 - w) bits.
|
|
111
|
+
// Each row is 3 bytes = 24 bits of sprite data.
|
|
112
|
+
unsigned long mask = ((1UL << (2 * w + 1)) - 1) << (10 - w);
|
|
113
|
+
blk[row * 3 + 0] = (byte)(mask >> 16);
|
|
114
|
+
blk[row * 3 + 1] = (byte)(mask >> 8);
|
|
115
|
+
blk[row * 3 + 2] = (byte)(mask );
|
|
116
|
+
}
|
|
117
|
+
blk[63] = 0; // padding byte
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// --- Initialize raster IRQ system ---
|
|
121
|
+
// rirq_init must be called by the program: vspr_init does NOT call it.
|
|
122
|
+
// Without it the raster IRQ lands in the KERNAL handler, is never
|
|
123
|
+
// acknowledged, and the main loop hangs in rirq_wait() with only the
|
|
124
|
+
// first eight sprites on screen (measured in VICE; an earlier version of
|
|
125
|
+
// this listing omitted the call). true = hook the KERNAL $0314 vector.
|
|
126
|
+
rirq_init(true);
|
|
127
|
+
// vspr_init occupies rirq slots 0 through VSPRITES_MAX-8 : one reuse
|
|
128
|
+
// slot per virtual sprite beyond the eighth, plus a sync slot at line 250.
|
|
129
|
+
vspr_init(Screen);
|
|
130
|
+
|
|
131
|
+
// --- Configure 12 logical sprites ---
|
|
132
|
+
// vspr_set(index, x, y, image_block, color)
|
|
133
|
+
// image_block = address / 64. With spriteset at $2000, block 0 = sprite 0.
|
|
134
|
+
char base_block = (unsigned)spriteset / 64;
|
|
135
|
+
|
|
136
|
+
for (char i = 0; i < NUM_SPRITES; i++) {
|
|
137
|
+
// Stagger starting phase so sprites spread around the circle.
|
|
138
|
+
char phase = (i * 128) / NUM_SPRITES;
|
|
139
|
+
int sx = CENTER_X + sinx[phase & 127];
|
|
140
|
+
int sy = CENTER_Y + siny[(phase + 32) & 127];
|
|
141
|
+
|
|
142
|
+
// Color cycles through the 8 non-black palette entries.
|
|
143
|
+
byte col = (byte)(8 + (i & 7));
|
|
144
|
+
|
|
145
|
+
vspr_set(i, sx, sy, base_block + i, col);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- Initial sort and update ---
|
|
149
|
+
// vspr_sort orders the logical sprites by ascending Y before the
|
|
150
|
+
// first frame. vspr_update programs the 8 hardware sprites with the
|
|
151
|
+
// top 8 by Y, and arms one reuse IRQ slot per remaining sprite.
|
|
152
|
+
vspr_sort();
|
|
153
|
+
vspr_update();
|
|
154
|
+
rirq_sort();
|
|
155
|
+
|
|
156
|
+
// --- Start the raster IRQ engine ---
|
|
157
|
+
rirq_start();
|
|
158
|
+
|
|
159
|
+
// Set a dark background so sprites are visible.
|
|
160
|
+
vic.color_back = VCOL_BLACK;
|
|
161
|
+
vic.color_border = VCOL_BLACK;
|
|
162
|
+
|
|
163
|
+
// --- Animation loop ---
|
|
164
|
+
unsigned frame = 0;
|
|
165
|
+
|
|
166
|
+
for (;;) {
|
|
167
|
+
// Advance animation counter.
|
|
168
|
+
frame++;
|
|
169
|
+
|
|
170
|
+
// Compute new positions for each logical sprite. Keep this cheap:
|
|
171
|
+
// everything between one rirq_wait() and the next must fit in a
|
|
172
|
+
// frame, or the hardware sprites get rewritten mid-screen.
|
|
173
|
+
for (char i = 0; i < NUM_SPRITES; i++) {
|
|
174
|
+
// Each sprite orbits the center with a unique phase offset.
|
|
175
|
+
// The tables have 128 entries; the frame counter drives the angle.
|
|
176
|
+
char phase = (char)frame + (char)((i * 128) / NUM_SPRITES);
|
|
177
|
+
int nx = CENTER_X + sinx[phase & 127];
|
|
178
|
+
int ny = CENTER_Y + siny[(phase + 32) & 127];
|
|
179
|
+
vspr_move(i, nx, ny);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Sort by Y: the multiplexer requires ascending Y order to assign
|
|
183
|
+
// hardware sprites to the correct vertical bands.
|
|
184
|
+
vspr_sort();
|
|
185
|
+
|
|
186
|
+
// Wait for the last raster IRQ of the current frame to complete.
|
|
187
|
+
// This ensures vspr_update is never called while the IRQ engine is
|
|
188
|
+
// still consuming the sprite slot table from the previous frame.
|
|
189
|
+
rirq_wait();
|
|
190
|
+
|
|
191
|
+
// Reprogram hardware sprite registers and raster IRQ reuse slots
|
|
192
|
+
// based on the freshly sorted logical sprite list.
|
|
193
|
+
vspr_update();
|
|
194
|
+
|
|
195
|
+
// Re-sort IRQ slots because vspr_update may have moved reuse slots.
|
|
196
|
+
rirq_sort();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Build
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
oscar64 -O2 -o=sprite-multiplex-8.prg -tf=prg sprite-multiplex-8.c
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`-O2` enables auto-inlining of small functions and 8-bit narrowing of the loop
|
|
210
|
+
index arithmetic, both of which matter for the per-frame sprite update loop.
|
|
211
|
+
|
|
212
|
+
Outputs: `sprite-multiplex-8.prg`, `.map`, `.asm`, `.lbl`.
|
|
213
|
+
|
|
214
|
+
## Expected output
|
|
215
|
+
|
|
216
|
+
Twelve filled 21×21 diamonds orbit a common center on an 80×60-pixel ellipse
|
|
217
|
+
over the untouched power-on text screen (the listing never clears it, so the
|
|
218
|
+
BASIC banner and `READY.`/`RUN` stay on the top rows). Colours are 8–15 with
|
|
219
|
+
8–11 used twice, so the twelve are not all distinct. All 12 are visible
|
|
220
|
+
simultaneously: the eight topmost by Y sit on the hardware sprites, and each
|
|
221
|
+
of the other four is put on screen by its own reuse IRQ, which fires 23 lines
|
|
222
|
+
below the Y of one of the four topmost sprites and re-arms that hardware
|
|
223
|
+
sprite. The main loop is paced by `rirq_wait()`, one iteration per frame.
|
|
224
|
+
|
|
225
|
+
Measured in VICE 3.10 (PAL) with the positions held at frame 200: twelve
|
|
226
|
+
221-pixel diamonds at raster lines 92–230, at exactly the Y values the
|
|
227
|
+
arithmetic gives (the first drawn row is at raster line Y+1). On the orbit
|
|
228
|
+
used here the ninth-lowest sprite is always at least ~60 lines below the
|
|
229
|
+
lowest, well past the 23-line reuse point, so no reused slot is asked to
|
|
230
|
+
draw before its first sprite has finished (arithmetic, not a flicker sweep).
|
|
231
|
+
|
|
232
|
+
An earlier version of this page said eight sprites sat "in the top half" and
|
|
233
|
+
one IRQ "at the midpoint" moved them to the bottom half; there is no single
|
|
234
|
+
midpoint IRQ, and the listing as then published never called `rirq_init()`,
|
|
235
|
+
which left it frozen with eight sprites at their starting positions.
|
|
236
|
+
|
|
237
|
+
## Why this works
|
|
238
|
+
|
|
239
|
+
### The core multiplexer contract
|
|
240
|
+
|
|
241
|
+
The VIC-II compares each hardware sprite's Y register against the raster counter
|
|
242
|
+
at the start of every scanline. Once a sprite is latched as active (its top line
|
|
243
|
+
passed), it renders for 21 lines even if the Y register changes. This gives the
|
|
244
|
+
CPU a 21-line safe window per sprite to reprogram Y and the image pointer before
|
|
245
|
+
the chip needs those values for the next activation.
|
|
246
|
+
|
|
247
|
+
The multiplexer exploits this window. After sorting the logical sprites by Y,
|
|
248
|
+
the top 8 are written to hardware at frame start. For each sorted sprite `8+n`
|
|
249
|
+
a raster IRQ slot `n` is moved to `Y(sorted sprite n) + 23`, the line after
|
|
250
|
+
hardware sprite `n & 7` has finished its first 21-row draw; that handler writes
|
|
251
|
+
the new Y, X, colour, image pointer and MSB-X mask for that one hardware sprite
|
|
252
|
+
(read from `sprites.c`: `rirq_move(ti, spriteYPos[ti + 1] + 23)`). An earlier
|
|
253
|
+
version of this page said one IRQ fired "just before logical sprites 9-12";
|
|
254
|
+
there is one per reused sprite, keyed to the finished sprite, not the next one.
|
|
255
|
+
|
|
256
|
+
### `vspr_init` and the rirq slot reservation
|
|
257
|
+
|
|
258
|
+
`vspr_init(Screen)` does **not** call `rirq_init()`; the program must, before
|
|
259
|
+
`vspr_init`, as Oscar64's own `samples/sprites/multiplexer.c` does. It sets
|
|
260
|
+
`$D015 = $FF`, clears both expand registers, and reserves `VSPRITES_MAX - 8`
|
|
261
|
+
rirq slots for reuse IRQs plus one empty sync slot at line 250 — slots 0–8
|
|
262
|
+
with the default `VSPRITES_MAX = 16` (read from `sprites.c`; the header
|
|
263
|
+
comment says the same). With 12 logical sprites, `vspr_update` arms slots 0–3
|
|
264
|
+
and clears 4–7 every frame. An earlier version of this page said `vspr_init`
|
|
265
|
+
called `rirq_init(true)` and reserved `VSPRITES_MAX / 8 - 1` slots ("one
|
|
266
|
+
slot"); both were wrong, and the missing `rirq_init` call left the listing
|
|
267
|
+
frozen. To display more than 16 logical sprites, rebuild with
|
|
268
|
+
`-dVSPRITES_MAX=24` (or higher) **and** raise `-dNUM_IRQS=` so that
|
|
269
|
+
`VSPRITES_MAX - 7` slots fit (the default `NUM_IRQS` is 16; Oscar64's
|
|
270
|
+
`sprmux32` sample builds with `-dVSPRITES_MAX=32 -dNUM_IRQS=28`). Each
|
|
271
|
+
additional logical sprite, not each group of eight, costs one rirq slot, and
|
|
272
|
+
its Y must be at least 23 lines plus a few lines of IRQ latency below the
|
|
273
|
+
sprite whose hardware slot it reuses.
|
|
274
|
+
|
|
275
|
+
### `vspr_sort`, `vspr_update`, `rirq_sort` — the per-frame triple
|
|
276
|
+
|
|
277
|
+
These three calls form the per-frame multiplexer ritual:
|
|
278
|
+
|
|
279
|
+
1. **`vspr_sort()`** — insertion sort on the logical sprite array by ascending Y.
|
|
280
|
+
It always walks all `VSPRITES_MAX` entries (the four unused ones sit at
|
|
281
|
+
Y = $FF). Measured with a CIA 2 timer around the call in this program on
|
|
282
|
+
VICE 3.10, over 200 frames: 457 cycles minimum, 2,018 maximum (the maximum
|
|
283
|
+
includes interrupts landing inside the call). An earlier version of this
|
|
284
|
+
page said "approximately 20-40 cycles", which is too small by an order of
|
|
285
|
+
magnitude.
|
|
286
|
+
|
|
287
|
+
2. **`rirq_wait()`** — returns once `rirq_count` has changed since the last
|
|
288
|
+
`rirq_wait()`/`rirq_sort()`; the ISR increments it after the last slot of
|
|
289
|
+
the frame (the sync slot at line 250). Must precede `vspr_update()` to
|
|
290
|
+
prevent writing into the slot table while the IRQ engine is reading it.
|
|
291
|
+
**It only paces the loop if the loop is faster than a frame.** If the work
|
|
292
|
+
since the last `rirq_sort()` already took longer than a frame, the count
|
|
293
|
+
has already changed and `rirq_wait()` returns at once, wherever the beam
|
|
294
|
+
is. Measured here with the earlier multiply-and-divide position loop: the
|
|
295
|
+
raster line on return ranged over 1–311, and the screenshot showed six of
|
|
296
|
+
the twelve sprites. That is why the listing uses pre-scaled tables.
|
|
297
|
+
|
|
298
|
+
3. **`vspr_update()`** — writes the sorted list to hardware: Y positions, image
|
|
299
|
+
pointers in the sprite pointer block (`Screen + $3F8`), colors (`$D027-$D02E`),
|
|
300
|
+
and the combined MSB-X byte (`$D010`). Also moves each active reuse slot
|
|
301
|
+
`n` to `Y(sorted sprite n) + 23` and stores the reused sprite's registers
|
|
302
|
+
in that slot's code with `rirq_data`. Measured as above: 554–1,853 cycles.
|
|
303
|
+
|
|
304
|
+
4. **`rirq_sort()`** — re-sorts the rirq slot table after `vspr_update` has
|
|
305
|
+
moved any reuse slots to new Y positions. Measured as above: 441–1,430
|
|
306
|
+
cycles.
|
|
307
|
+
|
|
308
|
+
The sprite pointer block at `Screen + $3F8` (address `$07F8` for the default
|
|
309
|
+
$0400 screen) holds one byte per hardware sprite indicating which 64-byte block
|
|
310
|
+
of sprite data it reads. `vspr_update` writes this block to change which logical
|
|
311
|
+
sprite image each hardware slot displays on the next activation. `$D010` (MSIGX)
|
|
312
|
+
packs the MSB of the X coordinate for all eight sprites into a single byte;
|
|
313
|
+
`vspr_update` recomputes the full combined mask each frame so sprites whose X
|
|
314
|
+
position exceeds 255 display at the correct horizontal position.
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: stable-raster-irq
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [stable_raster_irq]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: [D011, D012, D019, D01A, D020]
|
|
9
|
+
uses_kernal: []
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 Stable Raster IRQ
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
Demonstrates the canonical Oscar64 idiom for raster-synchronized interrupts using
|
|
19
|
+
`rasterirq.h`. The program fires a single raster IRQ at line 100, changes the border
|
|
20
|
+
color to white on entry, and holds it white for the rest of the frame. This is the
|
|
21
|
+
foundational pattern that all other raster effects in this KB build on.
|
|
22
|
+
|
|
23
|
+
## Source
|
|
24
|
+
|
|
25
|
+
```c
|
|
26
|
+
// stable-raster-irq.c
|
|
27
|
+
#include <c64/vic.h>
|
|
28
|
+
#include <c64/rasterirq.h>
|
|
29
|
+
|
|
30
|
+
// RIRQCode is a 32-byte struct (a size byte plus 31 bytes of generated
|
|
31
|
+
// code) that encodes up to five writes. Declare it at file scope so it
|
|
32
|
+
// lives in static storage.
|
|
33
|
+
RIRQCode rirq;
|
|
34
|
+
RIRQCode restore;
|
|
35
|
+
|
|
36
|
+
int main(void)
|
|
37
|
+
{
|
|
38
|
+
// rirq_init(true) installs the raster IRQ system and routes it through
|
|
39
|
+
// the KERNAL IRQ vector at $0314/$0315; it also sets $D01A bit 0 and
|
|
40
|
+
// clears $D011 bit 7. It does NOT disable the CIA1 timer: the KERNAL's
|
|
41
|
+
// jiffy IRQ keeps running and is handed on to $EA31. Pass false to
|
|
42
|
+
// install directly at the hardware vector $FFFE/$FFFF (faster, but
|
|
43
|
+
// requires KERNAL off). true is safe for cartridge-free PRG programs
|
|
44
|
+
// that load over BASIC.
|
|
45
|
+
rirq_init(true);
|
|
46
|
+
|
|
47
|
+
// rirq_build initializes the RIRQCode struct for one write slot.
|
|
48
|
+
// The second argument is the number of writes (1-5). Each write slot
|
|
49
|
+
// is one store to <address> in the IRQ handler at the programmed
|
|
50
|
+
// raster line. No heap allocation; you supply the struct.
|
|
51
|
+
rirq_build(&rirq, 1);
|
|
52
|
+
|
|
53
|
+
// rirq_write sets write slot 0 to store VCOL_WHITE into vic.color_border
|
|
54
|
+
// ($D020). When the raster IRQ fires, the generated code executes:
|
|
55
|
+
// LDY #VCOL_WHITE ; loaded before the wait loop
|
|
56
|
+
// CMP $D012 / BCS -5 ; spin until the target line
|
|
57
|
+
// STY $D020
|
|
58
|
+
// (slot 0 uses Y, slot 1 uses X, slots 2-4 use LDA/STA after the loop).
|
|
59
|
+
// Hand-optimized bytes generated by rirq_build; no C function overhead.
|
|
60
|
+
rirq_write(&rirq, 0, &vic.color_border, VCOL_WHITE);
|
|
61
|
+
|
|
62
|
+
// rirq_set installs the RIRQCode into slot 0, scheduled to fire one
|
|
63
|
+
// raster line below line 100 (i.e., at the start of raster line 101).
|
|
64
|
+
// Slots are numbered 0-15 (up to NUM_IRQS, default 16).
|
|
65
|
+
rirq_set(0, 100, &rirq);
|
|
66
|
+
|
|
67
|
+
// A second slot puts the border back to light blue at line 201. Without
|
|
68
|
+
// it the first interrupt leaves the whole border white for good and
|
|
69
|
+
// there is nothing to see: a register write persists until something
|
|
70
|
+
// writes the register again.
|
|
71
|
+
rirq_build(&restore, 1);
|
|
72
|
+
rirq_write(&restore, 0, &vic.color_border, VCOL_LT_BLUE);
|
|
73
|
+
rirq_set(1, 200, &restore);
|
|
74
|
+
|
|
75
|
+
// rirq_sort orders all installed slots by ascending raster line.
|
|
76
|
+
// Always call this after any rirq_set or rirq_move before rirq_start,
|
|
77
|
+
// and once per frame after moving slots mid-loop.
|
|
78
|
+
rirq_sort();
|
|
79
|
+
|
|
80
|
+
// rirq_start clears D011 bit 7, writes the constant 100 to D012 (not
|
|
81
|
+
// the first slot's line: it happens to coincide here), acknowledges
|
|
82
|
+
// D019 and unmasks the CPU IRQ. D01A was already set by rirq_init.
|
|
83
|
+
// From the first interrupt on, the dispatcher re-arms D012 itself
|
|
84
|
+
// and the handler fires automatically each frame.
|
|
85
|
+
rirq_start();
|
|
86
|
+
|
|
87
|
+
// Spin forever. The raster IRQ changes the border color on every frame
|
|
88
|
+
// without any CPU involvement in the main loop.
|
|
89
|
+
for (;;) { }
|
|
90
|
+
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Build
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
oscar64 -o=stable-raster-irq.prg -tf=prg stable-raster-irq.c
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Expected outputs: `stable-raster-irq.prg`, `stable-raster-irq.map`,
|
|
102
|
+
`stable-raster-irq.asm`, `stable-raster-irq.lbl`.
|
|
103
|
+
|
|
104
|
+
Load with `LOAD"STABLE-RASTER-IRQ",8,1` followed by `RUN`, or pass
|
|
105
|
+
`-autostart stable-raster-irq.prg` to VICE.
|
|
106
|
+
|
|
107
|
+
## Expected output
|
|
108
|
+
|
|
109
|
+
A white band in the border from raster line 101 to line 200; light blue above
|
|
110
|
+
and below. Both edges are straight across the frame: the dispatcher's polling
|
|
111
|
+
loop (below) puts the write in the horizontal blank.
|
|
112
|
+
|
|
113
|
+
On both PAL (50 Hz, 312 lines) and NTSC (60 Hz, 263 lines) the effect is
|
|
114
|
+
identical in appearance.
|
|
115
|
+
|
|
116
|
+
Verified with Oscar64 (build 2026-05-19) and VICE 3.10 x64sc, measured
|
|
117
|
+
2026-09-22 on both models: the left and right border columns are white on
|
|
118
|
+
raster lines 101-200 inclusive and light blue on 100 and 201, and the
|
|
119
|
+
transition rows are one colour from the first border pixel to the last (PAL
|
|
120
|
+
C64C, VIC-II 8565, and NTSC 6567R8 both; an earlier version said PAL 6569,
|
|
121
|
+
but `x64sc -default` is the C64C). No baseline PNG was committed for this recipe
|
|
122
|
+
before this audit. The earlier version
|
|
123
|
+
of this recipe had only the first slot and described a split at line 101;
|
|
124
|
+
what it produced was an all-white border, because nothing ever wrote light
|
|
125
|
+
blue back.
|
|
126
|
+
|
|
127
|
+
## Why this works
|
|
128
|
+
|
|
129
|
+
### What `rirq_init` actually does
|
|
130
|
+
|
|
131
|
+
`rirq_init(true)` (which is `rirq_init_kernal()` in `rasterirq.c`) does three
|
|
132
|
+
things. First, it installs the `rasterirq` dispatcher at `$0314`/`$0315` (the
|
|
133
|
+
KERNAL software IRQ vector), so the KERNAL's IRQ entry at `$FF48` jumps into
|
|
134
|
+
the dispatcher after doing its standard register save. Second, it sets `$D01A`
|
|
135
|
+
bit 0 to enable VIC-II raster interrupts. Third, it clears `$D011` bit 7 and
|
|
136
|
+
writes 255 to `$D012`, a line that never matches until `rirq_start` re-arms
|
|
137
|
+
it.
|
|
138
|
+
|
|
139
|
+
It does **not** disable the CIA1 timer A interrupt. The earlier text of this
|
|
140
|
+
recipe said it wrote `$DC0D` to switch the jiffy timer off; the source does no
|
|
141
|
+
such write, and a run of this listing on 2026-09-22 with the main loop
|
|
142
|
+
watching `$A1`/`$A2` showed the KERNAL jiffy clock still counting after
|
|
143
|
+
`rirq_start`. What the dispatcher does instead is test `$D019` bit 7 on entry:
|
|
144
|
+
a VIC interrupt is serviced and exits through the KERNAL's bare `$EA81`; any
|
|
145
|
+
other IRQ reads `$DC0D` to acknowledge the CIA and jumps to `$EA31`, the full
|
|
146
|
+
KERNAL service, so the clock, keyboard scan and STOP key all keep working
|
|
147
|
+
(about 190 cycles per jiffy tick idle). Both sources therefore share the IRQ
|
|
148
|
+
line by design; the dispatcher tells them apart rather than silencing one.
|
|
149
|
+
If you need the CIA quiet, write `$DC0D = 0x7F` yourself before `rirq_start`.
|
|
150
|
+
|
|
151
|
+
### What "stable" means here, and what it does not
|
|
152
|
+
|
|
153
|
+
Raw VIC-II raster IRQs carry 0-6 cycles of jitter because the CPU finishes
|
|
154
|
+
its current instruction before entering the handler, and on top of that the
|
|
155
|
+
KERNAL dispatcher adds 29 fixed cycles, so the handler starts on cycle 37-43
|
|
156
|
+
of the line. A colour write from there lands two-thirds of the way across the
|
|
157
|
+
visible line.
|
|
158
|
+
|
|
159
|
+
What `rasterirq.c` does about it can be read in `rirq_build`: every
|
|
160
|
+
`RIRQCode` begins with `LDY #d0 / LDX #d1 / CMP $D012 / BCS -5`: the first
|
|
161
|
+
two data bytes are preloaded, then a 7-cycle loop spins until the raster
|
|
162
|
+
counter passes the programmed row (A holds the row; the branch falls through
|
|
163
|
+
once `$D012` exceeds it). In the KERNAL-vector mode used here the dispatcher
|
|
164
|
+
arms `$D012` *two* lines before the target (the hardware-vector mode arms it
|
|
165
|
+
one line before; the earlier text said "the row before" for both), so the
|
|
166
|
+
KERNAL's 37-43-cycle entry and the dispatcher's own table walk are paid on
|
|
167
|
+
the lines above and the loop is already spinning when the target line
|
|
168
|
+
begins. Its `CMP` reads `$D012` on cycles 1-7 of that line, the branch falls
|
|
169
|
+
through in 2 and the `STY` (slot 0 is a `STY`, not a `STA`; slot 1 is `STX`)
|
|
170
|
+
writes 4 later, so the first write lands by about cycle 13 — arithmetic from
|
|
171
|
+
the loop's 7-cycle period, not a cycle-level measurement — inside the
|
|
172
|
+
horizontal blank. That is why the band edges are straight: the write is
|
|
173
|
+
early, not exact. The residual jitter is the loop's granularity, up to six
|
|
174
|
+
cycles, which is invisible for a border colour and would not be for a
|
|
175
|
+
$D016 side-border write or an FLI $D018 write. The genuinely cycle-exact
|
|
176
|
+
entry — the double-IRQ method — is in
|
|
177
|
+
`docs/recipes/kickassembler/stable-raster-irq.md`; `rasterirq.h` does not
|
|
178
|
+
implement it, and the earlier text of this recipe, which said the offset
|
|
179
|
+
was "fixed" and "jitter-free", overstated the library.
|
|
180
|
+
|
|
181
|
+
### `rirq_build`, `rirq_write`, `rirq_set`
|
|
182
|
+
|
|
183
|
+
`rirq_build(&rirq, n)` initializes an `RIRQCode` struct for `n` writes (1-5).
|
|
184
|
+
The struct is 32 bytes — a size byte and `RIRQ_SIZE` = 31 bytes of code (the
|
|
185
|
+
earlier text said 31; `sizeof(RIRQCode)` is 32, checked with a compile-time
|
|
186
|
+
assertion against the 2026-05-19 headers); larger variants `RIRQCode10` and
|
|
187
|
+
`RIRQCode20` (62 and 107 bytes) hold 10
|
|
188
|
+
and 20 writes respectively. The writes are stored as immediate operands and
|
|
189
|
+
absolute addresses of real 6502 instructions inside the struct — no heap, no
|
|
190
|
+
indirection at fire time; the dispatcher `JSR`s into the struct.
|
|
191
|
+
|
|
192
|
+
`rirq_write(&rirq, slot, addr, data)` patches slot `slot` of the struct with the
|
|
193
|
+
target address and data byte. At IRQ fire time the code runs `LDY #d0 / LDX
|
|
194
|
+
#d1`, the wait loop, then `STY a0 / STX a1`, then `LDA #d / STA a` for slots
|
|
195
|
+
2-4 in sequence (the earlier text said `LDA #data / STA addr` for every slot;
|
|
196
|
+
the first two are preloaded so they can land 4 cycles apart right after the
|
|
197
|
+
loop). Up to five writes fire within the cycle
|
|
198
|
+
budget of a single raster line on both PAL (63 cycles/line) and NTSC
|
|
199
|
+
(65 cycles/line). For more writes per line, use `RIRQCode10` or `RIRQCode20`.
|
|
200
|
+
|
|
201
|
+
`rirq_set(n, row, &rirq)` installs the code into IRQ slot `n` and programs it to
|
|
202
|
+
fire one line below `row`. The "one below" offset is a documented convention in
|
|
203
|
+
`rasterirq.h`: `rirq_set(0, 100, ...)` fires at the start of line 101, not
|
|
204
|
+
line 100. This gives the CPU the entirety of line 101 to execute the writes
|
|
205
|
+
before the raster beam reaches the point where writes need to be visible.
|
|
206
|
+
|
|
207
|
+
### `rirq_sort` and `rirq_start`
|
|
208
|
+
|
|
209
|
+
`rirq_sort()` orders the slot table by ascending raster line. The dispatcher
|
|
210
|
+
walks this sorted table on every frame, firing each slot as the beam reaches its
|
|
211
|
+
line. If slots are installed out of order or moved mid-frame (via `rirq_move`),
|
|
212
|
+
`rirq_sort()` must be called again before the next frame begins. The idiomatic
|
|
213
|
+
call site is at the bottom of the main loop, after `rirq_wait()`.
|
|
214
|
+
|
|
215
|
+
`rirq_start()` clears `$D011` bit 7, writes the constant 100 to `$D012`,
|
|
216
|
+
acknowledges `$D019` and executes `CLI`. It does not read the slot table: the
|
|
217
|
+
earlier text said it programmed `$D012` to the first slot's line, and in this
|
|
218
|
+
recipe the two coincide only because the first slot *is* line 100. The first
|
|
219
|
+
interrupt therefore fires at line 100 whatever the first slot says; the
|
|
220
|
+
dispatcher then runs slot 0's code (which spins until the raster passes its
|
|
221
|
+
own row) and from then on re-arms `$D012` for each following slot itself. A
|
|
222
|
+
first slot far above line 100 pays that difference once, on the first frame.
|
|
223
|
+
After this call the handler runs autonomously — the main loop never needs to
|
|
224
|
+
touch IRQ machinery again unless slots are being moved.
|
|
225
|
+
|
|
226
|
+
### Oscar64 vs cc65 IRQ style
|
|
227
|
+
|
|
228
|
+
The cc65 equivalent of this recipe requires writing `$DC0D = 0x7F` to disable
|
|
229
|
+
CIA interrupts, storing a function pointer at `$0314`/`$0315`, writing `$D01A =
|
|
230
|
+
0x01`, and writing `$D012 = 100` manually. The handler stub must acknowledge
|
|
231
|
+
`$D019`, re-arm `$D012` for the next frame, and return via RTI with A/X/Y/SR
|
|
232
|
+
restored. None of that appears in this recipe because `rasterirq.h` encapsulates
|
|
233
|
+
it — with one difference worth knowing: the library never disables the CIA, it
|
|
234
|
+
forwards CIA interrupts to `$EA31` and keeps the KERNAL clock alive (see "What
|
|
235
|
+
`rirq_init` actually does"). The Oscar64 idiom is three function calls to set up and one `for (;;)`
|
|
236
|
+
to hold: the handler is data, not code, and the dispatcher is a reusable library.
|