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,660 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: region
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<!-- doc-type: pitfall-reference -->
|
|
6
|
+
|
|
7
|
+
# Region Timing Pitfalls
|
|
8
|
+
|
|
9
|
+
All three pitfalls in this file stem from the same root: the C64 shipped in two
|
|
10
|
+
incompatible clock domains. PAL runs at 985,248 Hz with 312 raster lines per
|
|
11
|
+
frame; NTSC runs at 1,022,727 Hz with 263 lines per frame. Any hard-coded
|
|
12
|
+
assumption about frame rate, clock speed, or line count breaks when code crosses
|
|
13
|
+
regions. The fix in every case is to detect the region at boot — 36 bytes of
|
|
14
|
+
6502 and just over one frame of waiting at worst, usually much less — and
|
|
15
|
+
branch on it.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## pal_ntsc_tempo_mismatch — Music written for 50 Hz PAL plays 20% fast on 60 Hz NTSC
|
|
20
|
+
|
|
21
|
+
**Severity:** high
|
|
22
|
+
**Region:** both
|
|
23
|
+
**Triggered by techniques:** sid_play_routine_pattern, sid_voice_setup, frame_sync_loop, sfx_engine_beside_music, colour_fade, colour_cycling, screen_wipe, logic_rate_decoupling, difficulty_ramp_tables, falling_block_rules, ghost_target_tile_ai, cave_scan_engine, jump_arc_table, vehicle_control, lane_pursuit_ai
|
|
24
|
+
**Mitigated by techniques:** pal_ntsc_detection
|
|
25
|
+
|
|
26
|
+
### Symptom
|
|
27
|
+
|
|
28
|
+
Music that sounds correct on a PAL machine plays noticeably faster on NTSC —
|
|
29
|
+
the tempo is roughly 20% too high, giving ballads a frantic quality and
|
|
30
|
+
fast-paced tracks an unintended frenzy. The pitch of each note is correct (the
|
|
31
|
+
SID frequency registers produce slightly different Hz but the difference is a
|
|
32
|
+
fraction of a semitone); only the rhythm is wrong. On an NTSC machine running a
|
|
33
|
+
PAL-authored music driver, a track meant to run at 120 BPM plays at roughly 144
|
|
34
|
+
BPM.
|
|
35
|
+
|
|
36
|
+
The inverse problem — NTSC-authored music played on PAL — produces a tempo about
|
|
37
|
+
16% too slow (50.125 / 59.826 = 0.838, the inverse of the 19.4% below; an
|
|
38
|
+
earlier version said 17%). Energetic chiptunes become sluggish. This is rarer in practice because
|
|
39
|
+
most C64 music was authored in Europe on PAL machines.
|
|
40
|
+
|
|
41
|
+
### Mechanism
|
|
42
|
+
|
|
43
|
+
Tracker-based music drivers call a `play` subroutine once per video frame from a
|
|
44
|
+
raster or CIA IRQ handler. The play routine advances the tracker pattern by one
|
|
45
|
+
tick. The composer sets note durations in ticks, so the audible tempo is directly
|
|
46
|
+
proportional to the tick rate, which equals the frame rate.
|
|
47
|
+
|
|
48
|
+
PAL frame rate is 50.125 Hz (one frame every 19.95 ms). NTSC frame rate is
|
|
49
|
+
59.826 Hz (one frame every 16.71 ms). If the play routine fires once per frame
|
|
50
|
+
unconditionally, the NTSC tick rate is 59.826 / 50.125 = 1.194× the PAL rate —
|
|
51
|
+
a 19.4% tempo increase. Rounded to the nearest whole number, this is the "20%
|
|
52
|
+
too fast" figure that has followed European C64 ports to U.S. machines for
|
|
53
|
+
decades.
|
|
54
|
+
|
|
55
|
+
The problem is compounded by tempo subdivision: a speed value of N ticks per
|
|
56
|
+
note step scales the tempo by the same 20% ratio on NTSC.
|
|
57
|
+
|
|
58
|
+
### Fix
|
|
59
|
+
|
|
60
|
+
Two approaches cover all cases:
|
|
61
|
+
|
|
62
|
+
**Approach 1 — 5-of-6 frame skip on NTSC.** Call the play routine every frame
|
|
63
|
+
on PAL. On NTSC, call it every frame *except* every 6th frame (5 calls out of 6).
|
|
64
|
+
The effective NTSC tick rate becomes 59.826 × (5/6) = 49.855 Hz — within 0.54%
|
|
65
|
+
of the 50.125 Hz PAL rate. Tempo error drops from 19.4% to under 1%, which is
|
|
66
|
+
inaudible. Implement this with a single frame counter and a conditional skip:
|
|
67
|
+
|
|
68
|
+
```kick
|
|
69
|
+
// Region-detect at boot (Method 2 from pal-ntsc-reference.md; technique
|
|
70
|
+
// pal_ntsc_detection). On exit: region_flag = 0 for PAL, 1 for NTSC.
|
|
71
|
+
detect_region:
|
|
72
|
+
sei
|
|
73
|
+
wait_lo:
|
|
74
|
+
bit $d011
|
|
75
|
+
bmi wait_lo // If already inside the RST8 band, let it finish
|
|
76
|
+
wait_hi:
|
|
77
|
+
bit $d011
|
|
78
|
+
bpl wait_hi // RST8 rises: raster line 256 on every chip
|
|
79
|
+
track:
|
|
80
|
+
lda $d012 // Sample the low byte...
|
|
81
|
+
bit $d011
|
|
82
|
+
bpl band_over // ...kept only if RST8 was still set
|
|
83
|
+
tax
|
|
84
|
+
jmp track
|
|
85
|
+
band_over:
|
|
86
|
+
lda #0 // Last line seen: PAL $37, NTSC $06 or $05
|
|
87
|
+
cpx #$10
|
|
88
|
+
bcs set_flag // $10 or more exists only on PAL: flag 0
|
|
89
|
+
lda #1 // Below $10: NTSC, flag 1
|
|
90
|
+
set_flag:
|
|
91
|
+
sta region_flag
|
|
92
|
+
cli
|
|
93
|
+
rts
|
|
94
|
+
|
|
95
|
+
// Per-frame IRQ handler calling music play. Installed at $0314, so the
|
|
96
|
+
// KERNAL dispatcher at $FF48 has already pushed A, X, Y; the handler exits
|
|
97
|
+
// through $EA81 (PLA/TAY/PLA/TAX/PLA/RTI), which pops them. Use $EA31
|
|
98
|
+
// instead if the KERNAL's jiffy clock and keyboard scan are wanted.
|
|
99
|
+
frame_irq:
|
|
100
|
+
asl $d019 // Ack VIC raster IRQ
|
|
101
|
+
lda region_flag
|
|
102
|
+
beq call_play // PAL: always call play
|
|
103
|
+
// NTSC: skip every 6th frame.
|
|
104
|
+
inc ntsc_frame_counter
|
|
105
|
+
lda ntsc_frame_counter
|
|
106
|
+
cmp #6
|
|
107
|
+
bne call_play
|
|
108
|
+
lda #0
|
|
109
|
+
sta ntsc_frame_counter
|
|
110
|
+
jmp skip_play // Skip this frame's tick
|
|
111
|
+
call_play:
|
|
112
|
+
jsr music_play
|
|
113
|
+
skip_play:
|
|
114
|
+
jmp $ea81 // Not rti: the dispatcher's A, X, Y are still on the stack
|
|
115
|
+
|
|
116
|
+
region_flag: .byte 0
|
|
117
|
+
ntsc_frame_counter: .byte 0
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Correction (2026-09-22).** `frame_irq` used to end in a bare `rti`. From a
|
|
121
|
+
`$0314` handler that pops the dispatcher's saved Y, X and A as P, PCL and
|
|
122
|
+
PCH, so the first interrupt returns to whatever address the interrupted
|
|
123
|
+
code's A:X happened to form (measured in VICE x64sc 3.10: the verbatim
|
|
124
|
+
listing warm-starts on the first frame; with A:X pointed at a label,
|
|
125
|
+
execution lands on that label). It is not a 3-byte-per-frame stack leak.
|
|
126
|
+
The same change applies to the three `irq_reset_*` handlers in the third
|
|
127
|
+
pitfall below, which also write `$0314`.
|
|
128
|
+
|
|
129
|
+
**Correction (2026-09-21).** The `detect_region` above replaces one that had
|
|
130
|
+
two faults. It read `$D012` once, immediately after RST8 rose — that read is
|
|
131
|
+
line 256, the first line of the band, and returns `$00` on every chip, so
|
|
132
|
+
its `cmp #$10` always failed. And its PAL path ran `lda #0` / `sta
|
|
133
|
+
region_flag` / `bne done_detect`: `lda #0` sets Z, so the `bne` never
|
|
134
|
+
branched and execution fell through into `is_ntsc`, leaving `region_flag`
|
|
135
|
+
at 1 whichever way the compare had gone. Measured in VICE x64sc 3.10: the old
|
|
136
|
+
fragment, unchanged, in a wrapper that paints `region_flag` to the border,
|
|
137
|
+
reported NTSC on the default PAL model both when entered from raster line 100
|
|
138
|
+
and when entered from line 288 — inside the band, where the single read was
|
|
139
|
+
`$20` and the compare passed, which isolates the second fault. The fragment
|
|
140
|
+
above reported PAL when entered from lines 100, 300 and 311 on the PAL model,
|
|
141
|
+
and NTSC when entered from lines 100 and 262 with `-model ntsc` and from 100
|
|
142
|
+
with `-model oldntsc`.
|
|
143
|
+
|
|
144
|
+
**Approach 2 — Ship two tempo tables.** Some music drivers (GoatTracker,
|
|
145
|
+
SID-Wizard) support a per-region speed table embedded in the music data. The
|
|
146
|
+
driver reads the active table based on a region flag set at boot. This is the
|
|
147
|
+
cleanest solution when the music driver already has the infrastructure — no
|
|
148
|
+
frame-skipping artefacts, no timing drift. Approach 1 is preferable when
|
|
149
|
+
modifying the driver is not an option (e.g., a pre-built binary player).
|
|
150
|
+
|
|
151
|
+
**A 50 Hz CIA tick is a valid third approach for the music alone.** Set CIA1
|
|
152
|
+
Timer A to one tick per 20 ms of the *local* φ2 clock — latch $4FE5 (20,454
|
|
153
|
+
cycles) on NTSC R8, $4CE5 (19,686) on PAL — and call the play routine from its
|
|
154
|
+
IRQ; CIA-timed and multi-speed tunes already run this way (see music-sid.md,
|
|
155
|
+
`sid_play_routine_pattern` Variations). Measured in VICE x64sc 3.10: on the
|
|
156
|
+
NTSC model that latch fired 251 times in 300 frames (300 × 17,095 / 20,454 =
|
|
157
|
+
250.7), a 50.0 Hz tick, so the tempo is correct without frame-skipping. Two
|
|
158
|
+
costs come with it. The latch must be region-corrected — the same NTSC latch
|
|
159
|
+
on PAL fired 289 times in 300 frames, 3.8% slow (see
|
|
160
|
+
`cia_timer_phi2_difference` below) — and the IRQ is not locked to the frame:
|
|
161
|
+
across those 300 frames it entered on every raster line ($D012 min 0, max
|
|
162
|
+
255), so any screen update placed in the same handler lands mid-frame and
|
|
163
|
+
drifts against the display, and a long play routine in it can delay a raster
|
|
164
|
+
IRQ it collides with. Keep the music IRQ to the play call, or re-enable IRQs
|
|
165
|
+
around it, and do screen work from the raster IRQ. **What not to do** is run
|
|
166
|
+
one per-frame latch or one per-frame raster tick unchanged on both regions.
|
|
167
|
+
An earlier version of this paragraph forbade a 50 Hz CIA tick on NTSC and
|
|
168
|
+
claimed it caused tearing and audio artefacts; a music tick does not draw,
|
|
169
|
+
and no instrument or independent page supported the claim.
|
|
170
|
+
|
|
171
|
+
### Worked example
|
|
172
|
+
|
|
173
|
+
The full dispatcher in **Fix** above covers both detection and skipping. When
|
|
174
|
+
the region flag is set elsewhere at boot, reduce it to the skip logic alone:
|
|
175
|
+
check `region_flag`, increment a 0-5 counter, call `music_play` unless counter
|
|
176
|
+
just reached 6 (then reset it and return without calling play).
|
|
177
|
+
|
|
178
|
+
### Cross-references
|
|
179
|
+
|
|
180
|
+
- Technique: `sid_play_routine_pattern` — the canonical per-frame SID player
|
|
181
|
+
structure that this pitfall affects.
|
|
182
|
+
- Technique: `sid_voice_setup` — voice envelope setup is unaffected by tempo
|
|
183
|
+
mismatch, but pitch tables must also be region-adjusted (a separate concern;
|
|
184
|
+
see pal-ntsc-reference.md SID frequency section).
|
|
185
|
+
- Technique: `pal_ntsc_detection` — the region-detect sub-technique used in
|
|
186
|
+
the fix.
|
|
187
|
+
- Reference: `pal-ntsc-reference.md` — canonical clock rates, frame rates, and
|
|
188
|
+
the music-tempo section.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## cia_timer_phi2_difference — CIA timers count φ2 cycles; 3.8% clock drift between PAL and NTSC
|
|
193
|
+
|
|
194
|
+
**Severity:** high
|
|
195
|
+
**Region:** both
|
|
196
|
+
**Triggered by registers:** DC04, DC05, DC06, DC07
|
|
197
|
+
**Triggered by techniques:** frame_sync_loop, pwm_digi, difficulty_ramp_tables, digi_4bit
|
|
198
|
+
**Mitigated by techniques:** pal_ntsc_detection
|
|
199
|
+
|
|
200
|
+
### Symptom
|
|
201
|
+
|
|
202
|
+
A CIA timer calibrated for one second on PAL fires after 0.963 s on NTSC
|
|
203
|
+
(985,248 counts at 1,022,727 Hz — about 37 ms early per intended second; a
|
|
204
|
+
PAL-calibrated software clock reads 1.038 s after one real NTSC second, and
|
|
205
|
+
the error accumulates without bound; an earlier version had the direction
|
|
206
|
+
backwards, "fires after 1.038 seconds"). A digi sample played via a
|
|
207
|
+
CIA-timed loop pitches 3.8% sharp on NTSC — well above the ~20-cent audibility
|
|
208
|
+
threshold. RS-232 via CIA2 is the most immediately obvious failure: wrong baud-
|
|
209
|
+
rate timer values cause framing errors on every byte, making the user port
|
|
210
|
+
non-functional.
|
|
211
|
+
|
|
212
|
+
### Mechanism
|
|
213
|
+
|
|
214
|
+
CIA timers (Timer A: $DC04/$DC05, Timer B: $DC06/$DC07 for CIA1; same offsets
|
|
215
|
+
at $DD04-$DD07 for CIA2) are 16-bit down-counters driven by the CPU's φ2 clock.
|
|
216
|
+
They count one tick per φ2 rising edge. φ2 is the CPU clock — the same signal
|
|
217
|
+
that clocks the 6510 through each instruction.
|
|
218
|
+
|
|
219
|
+
The φ2 clock frequency differs by region:
|
|
220
|
+
|
|
221
|
+
- **PAL:** 985,248.444 Hz (derived from 17.734472 MHz crystal ÷ 18; an earlier
|
|
222
|
+
version paired this quotient with a 17.734475 MHz crystal, which gives
|
|
223
|
+
985,248.61 Hz)
|
|
224
|
+
- **NTSC R8:** 1,022,727.143 Hz (derived from 14.31818 MHz crystal ÷ 14)
|
|
225
|
+
|
|
226
|
+
The ratio is 1,022,727 / 985,248 = 1.03804. Any timer reload value calibrated on
|
|
227
|
+
PAL fires 3.8% too soon on NTSC, and vice versa.
|
|
228
|
+
|
|
229
|
+
For a 1-second interval on PAL, the reload value is 985,248 ($F08A0, not the
|
|
230
|
+
$F0960 an earlier version gave — but CIA
|
|
231
|
+
timers are 16-bit, so the maximum interval is 65,536 cycles, i.e., 66.5 ms on
|
|
232
|
+
PAL or 64.1 ms on NTSC). Long intervals require a software counter to chain
|
|
233
|
+
multiple timer underflows. Each hardware underflow fires 64.1 ms apart on NTSC
|
|
234
|
+
vs 66.5 ms on PAL — a 2.4 ms difference per underflow that accumulates linearly.
|
|
235
|
+
|
|
236
|
+
Common affected uses: 1-second countdown timers (about 37 ms short per second,
|
|
237
|
+
visible in under 10 seconds), CIA-driven music ticks (3.8% fast, not 20%: a
|
|
238
|
+
CIA tick is insulated from the frame-rate difference but not from the φ2
|
|
239
|
+
clock difference; measured in VICE x64sc 3.10 as 217 CIA underflows of the
|
|
240
|
+
PAL latch $4CC6 per 250 NTSC frames versus 250 per 250 PAL frames — an
|
|
241
|
+
earlier version claimed the "same 20% tempo jump" as the frame-rate pitfall,
|
|
242
|
+
which only a per-frame latch set for the wrong region gives), $D418 digi via
|
|
243
|
+
CIA (3.8% pitch shift — ≈ 65 cents, clearly audible; 1200 × log2(1.03804) =
|
|
244
|
+
64.6, not the 63 given earlier), and RS-232 baud-rate timers (wrong baud
|
|
245
|
+
fails immediately with framing errors on every byte).
|
|
246
|
+
|
|
247
|
+
The pal-ntsc-reference.md CIA timer section gives the once-per-frame timer
|
|
248
|
+
latches: PAL $4CC7 (19,655) for a 19,656-cycle frame, NTSC R8 $42C6 (17,094)
|
|
249
|
+
for 17,095. Latch = cycles − 1, because a continuous timer with latch N
|
|
250
|
+
repeats every N + 1 cycles. An earlier version of this page gave $4CC6 /
|
|
251
|
+
$42C5 and attributed them to the reference; those are one cycle short of a
|
|
252
|
+
frame (63 × 312 = 19,656; 65 × 263 = 17,095) and the reference measured them
|
|
253
|
+
drifting one cycle per frame — in VICE x64sc a continuous $4CC7 timer holds
|
|
254
|
+
the same PAL raster line indefinitely while $4CC6 walks one raster line every
|
|
255
|
+
63 frames; $42C6 / $42C5 behave the same way on the 6567R8 (one line every 65
|
|
256
|
+
frames).
|
|
257
|
+
|
|
258
|
+
### Fix
|
|
259
|
+
|
|
260
|
+
Detect the region at boot and apply the appropriate reload constant. Provide
|
|
261
|
+
both constants as named symbols and branch on the region flag:
|
|
262
|
+
|
|
263
|
+
```kick
|
|
264
|
+
// CIA1 Timer A configured for once-per-frame, region-adaptive.
|
|
265
|
+
// Must be called after detect_region (sets region_flag).
|
|
266
|
+
|
|
267
|
+
.const CIA1_TA_LO = $DC04
|
|
268
|
+
.const CIA1_TA_HI = $DC05
|
|
269
|
+
.const CIA1_CRA = $DC0E
|
|
270
|
+
|
|
271
|
+
// Timer A latch values for once-per-frame IRQ (latch = cycles - 1).
|
|
272
|
+
// PAL: latch $4CC7 = 19,655. Timer fires after $4CC7+1 = 19,656 cycles = 63 x 312.
|
|
273
|
+
// NTSC: latch $42C6 = 17,094. Timer fires after $42C6+1 = 17,095 cycles = 65 x 263.
|
|
274
|
+
// (An earlier version used $4CC6 / $42C5, one cycle short of a frame.)
|
|
275
|
+
.const PAL_FRAME_LATCH_LO = $C7
|
|
276
|
+
.const PAL_FRAME_LATCH_HI = $4C
|
|
277
|
+
.const NTSC_FRAME_LATCH_LO = $C6
|
|
278
|
+
.const NTSC_FRAME_LATCH_HI = $42
|
|
279
|
+
|
|
280
|
+
setup_frame_timer:
|
|
281
|
+
lda region_flag
|
|
282
|
+
bne setup_ntsc
|
|
283
|
+
|
|
284
|
+
setup_pal:
|
|
285
|
+
lda #PAL_FRAME_LATCH_LO
|
|
286
|
+
sta CIA1_TA_LO
|
|
287
|
+
lda #PAL_FRAME_LATCH_HI
|
|
288
|
+
sta CIA1_TA_HI
|
|
289
|
+
bne timer_go // Always taken
|
|
290
|
+
|
|
291
|
+
setup_ntsc:
|
|
292
|
+
lda #NTSC_FRAME_LATCH_LO
|
|
293
|
+
sta CIA1_TA_LO
|
|
294
|
+
lda #NTSC_FRAME_LATCH_HI
|
|
295
|
+
sta CIA1_TA_HI
|
|
296
|
+
|
|
297
|
+
timer_go:
|
|
298
|
+
// Enable Timer A IRQ (bit 0), start timer in continuous mode (bit 0 of CRA).
|
|
299
|
+
lda #$81
|
|
300
|
+
sta $DC0D // Enable Timer A IRQ source
|
|
301
|
+
lda #$11 // Start, phi2 input, continuous
|
|
302
|
+
sta CIA1_CRA
|
|
303
|
+
cli
|
|
304
|
+
rts
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
For arbitrary intervals, compute: `reload = round(interval_sec * cpu_hz) - 1`.
|
|
308
|
+
For digi or RS-232 timers: `timer_ntsc = round(timer_pal * 1.03804)`.
|
|
309
|
+
Custom RS-232 code that bypasses the KERNAL must apply the same ratio — the
|
|
310
|
+
KERNAL handles its own baud-rate constants, but custom code does not inherit
|
|
311
|
+
those corrections.
|
|
312
|
+
|
|
313
|
+
### Worked example
|
|
314
|
+
|
|
315
|
+
```kick
|
|
316
|
+
// BAD: hard-coded PAL latch value used on both regions.
|
|
317
|
+
// On NTSC, timer fires after 19,656 phi2 cycles ($4CC7+1).
|
|
318
|
+
// NTSC phi2 = 1,022,727 Hz, so interval = 19656 / 1022727 = 19.22 ms.
|
|
319
|
+
// PAL frame = 19.95 ms. Delta = 0.73 ms per frame — visible in seconds.
|
|
320
|
+
lda #$C7
|
|
321
|
+
sta $DC04 // $4CC7 = PAL frame latch (WRONG on NTSC)
|
|
322
|
+
lda #$4C
|
|
323
|
+
sta $DC05
|
|
324
|
+
|
|
325
|
+
// GOOD: region-conditional latch selection.
|
|
326
|
+
lda region_flag
|
|
327
|
+
bne !+
|
|
328
|
+
lda #$C7 // PAL lo
|
|
329
|
+
sta $DC04
|
|
330
|
+
lda #$4C // PAL hi
|
|
331
|
+
sta $DC05
|
|
332
|
+
bne !++ // Always taken: A = $4C, Z clear (same idiom as
|
|
333
|
+
// setup_frame_timer's bne timer_go); jmp also works
|
|
334
|
+
!: lda #$C6 // NTSC lo
|
|
335
|
+
sta $DC04
|
|
336
|
+
lda #$42 // NTSC hi
|
|
337
|
+
sta $DC05
|
|
338
|
+
!: // timer latch is now correct for both regions
|
|
339
|
+
|
|
340
|
+
// For CIA2 (DD04/DD05/DD06/DD07): identical arithmetic, different addresses.
|
|
341
|
+
// The 3.8% drift applies equally to CIA2 because both chips are clocked
|
|
342
|
+
// from the same phi2 source.
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Correction (2026-09-22).** The GOOD block above used to leave the PAL path
|
|
346
|
+
with `beq !++`. `lda #$4C` clears Z, so that branch was never taken and the
|
|
347
|
+
PAL path fell straight through into the NTSC stores. Measured in VICE x64sc
|
|
348
|
+
3.10 on the PAL model: with the block assembled verbatim and `region_flag` =
|
|
349
|
+
0, stopping Timer A and force-loading the latch (`$DC0E` = $10) read
|
|
350
|
+
`$DC04`/`$DC05` = $C5/$42 — the NTSC value — and the same with
|
|
351
|
+
`region_flag` = 1. The same run confirmed that `setup_frame_timer`'s `bne
|
|
352
|
+
timer_go` is always taken (PAL gave $C6/$4C, NTSC $C5/$42, before the latch
|
|
353
|
+
constants themselves were corrected to $4CC7 / $42C6 as noted above).
|
|
354
|
+
|
|
355
|
+
### Cross-references
|
|
356
|
+
|
|
357
|
+
- Registers: `DC04`, `DC05` (CIA1 Timer A latch/counter), `DC06`, `DC07`
|
|
358
|
+
(CIA1 Timer B latch/counter). CIA2 equivalents at `DD04`, `DD05`, `DD06`,
|
|
359
|
+
`DD07` — same arithmetic, different base address.
|
|
360
|
+
- Reference: `pal-ntsc-reference.md` CIA timer values table — canonical
|
|
361
|
+
once-per-frame latch constants for PAL ($4CC7) and NTSC R8 ($42C6), with
|
|
362
|
+
the latch = cycles − 1 rule and the drift measurement for $4CC6.
|
|
363
|
+
- Pitfall: `pal_ntsc_tempo_mismatch` — the music-tempo problem; closely
|
|
364
|
+
related when a CIA timer drives the music tick instead of the VIC raster IRQ.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## raster_line_count_difference — PAL has 312 lines per frame; NTSC has 263; loops that hard-code 312 break
|
|
369
|
+
|
|
370
|
+
**Severity:** medium
|
|
371
|
+
**Region:** both
|
|
372
|
+
**Triggered by registers:** D012, D011
|
|
373
|
+
**Triggered by techniques:** stable_raster_irq, frame_sync_loop, irq_chain_table, raster_split_modes, sideborder_open
|
|
374
|
+
**Mitigated by techniques:** pal_ntsc_detection
|
|
375
|
+
|
|
376
|
+
### Symptom
|
|
377
|
+
|
|
378
|
+
A raster table loop that walks through IRQ entries for lines 0-311 appears to
|
|
379
|
+
work on PAL. On NTSC the same loop reaches line 263 and then either:
|
|
380
|
+
|
|
381
|
+
- **Fires at the wrong line** — the raster compare is a 9-bit equality against
|
|
382
|
+
the counter; nothing is reduced modulo the line count. A hard-coded target
|
|
383
|
+
of 280 with RST8 clear is the low byte alone: 280 → $18 → line 24, inside
|
|
384
|
+
the NTSC vertical blank / PAL top border (measured in VICE x64sc 3.10, both
|
|
385
|
+
models: RST8 clear + $D012 = $18 fires at $D012 = $18 = 24) instead of the
|
|
386
|
+
expected bottom area. An earlier version said the target "wraps" to 280 −
|
|
387
|
+
263 = 17; the VIC does no such reduction.
|
|
388
|
+
- **Never fires** — if the code sets RST8 and $D012 = $18 (the 9-bit value
|
|
389
|
+
280), the NTSC counter never reaches 280. The IRQ chain halts and the screen
|
|
390
|
+
freezes. (280 cannot be written to $D012 at all; it is RST8 = 1 with low
|
|
391
|
+
byte $18. An earlier version described this as "280 + 256 = 536".)
|
|
392
|
+
- **Stalls, or wraps on both chips** — a target at line 250 is inside the
|
|
393
|
+
valid range on both PAL (250 < 312) and NTSC (250 < 263), but a chain that
|
|
394
|
+
then steps to 264 behaves in one of two ways, neither of them "wrap to line
|
|
395
|
+
1 on NTSC" as an earlier version said. A chain that sets RST8 for 264 stalls
|
|
396
|
+
on NTSC (0 fires) and fires at 264 on PAL — a region difference. A chain
|
|
397
|
+
that steps only $D012 and never sets RST8 arms $08 and fires at line 8 on
|
|
398
|
+
BOTH chips (measured: RST8 clear + $08 → line 8 on PAL and NTSC); that is
|
|
399
|
+
the 8-bit wrap covered by `d012_wrap_around`, not a region difference.
|
|
400
|
+
|
|
401
|
+
More subtly: PAL has 64 lines past the badline window (248-311, where no
|
|
402
|
+
badline can steal cycles: the window is $30-$F7); NTSC has only 15 (248-262).
|
|
403
|
+
A sprite multiplexer that updates Y positions in that range has enough cycles
|
|
404
|
+
on PAL; on NTSC it runs into the next frame's visible area. These lines are
|
|
405
|
+
not blanking, as an earlier version called them: on PAL, 248-250 are the last
|
|
406
|
+
three lines of the 25-row display window, 251-299 are visible lower border
|
|
407
|
+
and only 300-311 (12 lines) are in vertical blank; on NTSC all of 248-262 is
|
|
408
|
+
display or border and visible (NTSC vertical blank is 13-40). A $D020/$D021 or
|
|
409
|
+
sprite write in that range is visible in the border on both regions.
|
|
410
|
+
|
|
411
|
+
### Mechanism
|
|
412
|
+
|
|
413
|
+
The VIC-II's internal raster counter is 9 bits wide (0-511, though not all
|
|
414
|
+
values are used). $D012 holds the low 8 bits of the current counter value; bit 7
|
|
415
|
+
of $D011 (RST8) holds the 9th bit. The counter increments once per scanline and
|
|
416
|
+
wraps at the frame boundary.
|
|
417
|
+
|
|
418
|
+
The wrap point is chip-specific:
|
|
419
|
+
|
|
420
|
+
| Chip | Lines/frame | $D012 at wrap |
|
|
421
|
+
|---|---|---|
|
|
422
|
+
| 6569 (PAL) | 312 | $37 (55) |
|
|
423
|
+
| 6567R8 (NTSC) | 263 | $06 (6) |
|
|
424
|
+
| 6567R56A (rare) | 262 | $05 (5) |
|
|
425
|
+
|
|
426
|
+
Code that hard-codes the line count fails in two ways:
|
|
427
|
+
|
|
428
|
+
1. **Table sized for 312 entries.** A raster effect that allocates one byte per
|
|
429
|
+
raster line and walks the whole table runs off the end of the usable NTSC
|
|
430
|
+
range. Entries for lines 263-311 are NTSC dead zones — those raster lines do
|
|
431
|
+
not exist. The table-walker runs past valid data.
|
|
432
|
+
|
|
433
|
+
2. **IRQ target lines above 262.** Any line number above 262 is outside the
|
|
434
|
+
NTSC frame. Writing such a value to $D012 with the appropriate RST8 state
|
|
435
|
+
creates a compare that the NTSC VIC never reaches. The IRQ chain stalls. The
|
|
436
|
+
program hangs or loses its raster chain permanently.
|
|
437
|
+
|
|
438
|
+
PAL has 64 lines past the badline window (248-311). NTSC has 15 (248-262).
|
|
439
|
+
The practical consequence: NTSC end-of-frame work must complete in 15 × 65 =
|
|
440
|
+
975 cycles vs PAL's 64 × 63 = 4,032 cycles — a 4× cycle-budget reduction that
|
|
441
|
+
makes some PAL effects impossible on NTSC without redesign. (Anchored on the
|
|
442
|
+
last badline, line 243, pal-ntsc-reference.md counts 68 and 19 lines after
|
|
443
|
+
it: 4,284 vs 1,235 cycles; the ratio is the same. Most of those lines are
|
|
444
|
+
visible border, not blanking — see the Symptom above.)
|
|
445
|
+
|
|
446
|
+
### Fix
|
|
447
|
+
|
|
448
|
+
Two strategies:
|
|
449
|
+
|
|
450
|
+
**Strategy 1 — Clamp line targets to the safe range.** The "safe" raster
|
|
451
|
+
lines that exist on both PAL and NTSC are 0-262. Schedule all raster IRQs and
|
|
452
|
+
table-driven effects within this range. Accept that the bottom-of-frame window
|
|
453
|
+
past the badlines for NTSC-targeted code is only 15 lines (248-262) rather
|
|
454
|
+
than 64 lines.
|
|
455
|
+
|
|
456
|
+
**Strategy 2 — Region-conditional line tables.** Maintain two versions of any
|
|
457
|
+
raster-table structure — one parameterized for PAL (lines 0-311) and one for
|
|
458
|
+
NTSC (lines 0-262). Select the active table at boot based on the detected region.
|
|
459
|
+
This is the pattern used by production demos that target both regions.
|
|
460
|
+
|
|
461
|
+
The region-detect waits for $D011 bit 7 (RST8) to clear and then set, keeps
|
|
462
|
+
the last $D012 seen while it stays set, and compares that value against $10
|
|
463
|
+
once it clears: PAL ends its frame at $37, NTSC at $06 or $05. The
|
|
464
|
+
three-way form is `detect_region` in `pal-ntsc-reference.md` (Method 1);
|
|
465
|
+
the flag-store form is `detect_region` in the first pitfall above (36 bytes).
|
|
466
|
+
|
|
467
|
+
```kick
|
|
468
|
+
// BROKEN: raster table loop hard-coded for 312 lines.
|
|
469
|
+
// On NTSC, entries for lines 263-311 don't exist — IRQs misfire or stall.
|
|
470
|
+
// Illustrative only: KickAssembler 5.25 assembles `cpx #312` as `cpx #$38`
|
|
471
|
+
// (the immediate is truncated to 8 bits, no error), and an 8-bit X cannot
|
|
472
|
+
// count to 312 anyway. The fault shown is the hard-coded constant.
|
|
473
|
+
.const NUM_LINES_PAL = 312
|
|
474
|
+
setup_irq_table:
|
|
475
|
+
ldx #0
|
|
476
|
+
loop_irq:
|
|
477
|
+
lda raster_lo,x
|
|
478
|
+
sta $d012
|
|
479
|
+
lda raster_hi,x // 0 or 1: the 9th bit of the target
|
|
480
|
+
lsr // ... into carry
|
|
481
|
+
lda $d011
|
|
482
|
+
and #%01111111
|
|
483
|
+
bcc !+
|
|
484
|
+
ora #%10000000 // Set RST8 for targets >= 256
|
|
485
|
+
!: sta $d011
|
|
486
|
+
// ... install handler ...
|
|
487
|
+
inx
|
|
488
|
+
cpx #NUM_LINES_PAL // Hard-coded 312 — WRONG on NTSC (and truncated to $38)
|
|
489
|
+
bne loop_irq
|
|
490
|
+
rts
|
|
491
|
+
|
|
492
|
+
// FIXED: walk a table of NUM_ENTRIES 9-bit targets (two bytes each) and skip
|
|
493
|
+
// any entry at or above num_lines_active, a 16-bit line count set at boot.
|
|
494
|
+
.const NUM_ENTRIES = 8 // Table length (< 256) — not the frame's line count
|
|
495
|
+
setup_irq_table_fixed:
|
|
496
|
+
ldx #0
|
|
497
|
+
loop_irq_fixed:
|
|
498
|
+
cpx #NUM_ENTRIES
|
|
499
|
+
beq done_loop
|
|
500
|
+
// 16-bit compare: target (hi:lo) against num_lines_active; skip if >=.
|
|
501
|
+
lda raster_hi,x
|
|
502
|
+
cmp num_lines_active+1
|
|
503
|
+
bcc install_entry // hi below: target is in range
|
|
504
|
+
bne skip_entry // hi above: target is past the frame
|
|
505
|
+
lda raster_lo,x
|
|
506
|
+
cmp num_lines_active
|
|
507
|
+
bcs skip_entry // hi equal, lo at or above: past the frame
|
|
508
|
+
install_entry:
|
|
509
|
+
lda raster_lo,x
|
|
510
|
+
sta $d012
|
|
511
|
+
lda raster_hi,x
|
|
512
|
+
lsr // 9th bit into carry
|
|
513
|
+
lda $d011
|
|
514
|
+
and #%01111111
|
|
515
|
+
bcc !+
|
|
516
|
+
ora #%10000000 // Set RST8 for targets >= 256
|
|
517
|
+
!: sta $d011
|
|
518
|
+
// ... install handler ...
|
|
519
|
+
skip_entry:
|
|
520
|
+
inx
|
|
521
|
+
bne loop_irq_fixed
|
|
522
|
+
done_loop:
|
|
523
|
+
rts
|
|
524
|
+
|
|
525
|
+
num_lines_active: .word 0 // set to 312 (PAL) or 263 (NTSC) at boot
|
|
526
|
+
raster_lo: .fill NUM_ENTRIES, <(50 + i * 30) // example targets 50, 80, ... 260
|
|
527
|
+
raster_hi: .fill NUM_ENTRIES, >(50 + i * 30)
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
**Correction (2026-09-22).** An earlier FIXED listing kept `num_lines_active`
|
|
531
|
+
as one byte "set to 56 (low byte of 312) PAL, 7 (263) NTSC" and compared
|
|
532
|
+
8-bit targets against it. 312 & 255 = 56 and 263 & 255 = 7, so `cpx
|
|
533
|
+
num_lines_active` stopped the walk after 56 entries on PAL and 7 on NTSC, and
|
|
534
|
+
`cmp num_lines_active / bcs skip_entry` skipped every target at or above 56
|
|
535
|
+
(PAL) or 7 (NTSC) — nearly the whole frame. Neither listing installed RST8,
|
|
536
|
+
so a 9-bit target could not be armed. Both now carry two-byte targets, and
|
|
537
|
+
the FIXED one loops on the table length and compares 16 bits (arithmetic;
|
|
538
|
+
the truncation of `cpx #312` was confirmed by assembling it: `E0 38`).
|
|
539
|
+
|
|
540
|
+
For most effects the simplest fix is to cap all IRQ line targets at 262 and
|
|
541
|
+
avoid scheduling work in the PAL-only lines (263-311; visible lower border up
|
|
542
|
+
to 299, vertical blank from 300). This sacrifices 49 lines of end-of-frame CPU
|
|
543
|
+
time on PAL but produces code that works unmodified on both regions.
|
|
544
|
+
|
|
545
|
+
### Worked example
|
|
546
|
+
|
|
547
|
+
```kick
|
|
548
|
+
// Scenario: raster bar effect that colors every other scanline
|
|
549
|
+
// from line 50 to line 250, then resets at the start of each frame.
|
|
550
|
+
// The reset IRQ is placed at line 280 — PAL lower border, outside NTSC frame.
|
|
551
|
+
// All three handlers are installed at $0314 and exit via $EA81, which pops
|
|
552
|
+
// the A, X, Y that the KERNAL dispatcher at $FF48 pushed.
|
|
553
|
+
|
|
554
|
+
// BAD: reset IRQ targets line 280.
|
|
555
|
+
// On PAL: fires in the lower border — the line exists, so the chain runs;
|
|
556
|
+
// any colour/sprite change there is visible.
|
|
557
|
+
// On NTSC: line 280 doesn't exist. With RST8 cleared as below the compare
|
|
558
|
+
// is the low byte alone, $18 = line 24 (inside the NTSC vertical
|
|
559
|
+
// blank) — the reset runs during the next frame's top and corrupts
|
|
560
|
+
// the display. (The VIC does not reduce 280 modulo 263 to 17, as an
|
|
561
|
+
// earlier comment said; measured in VICE x64sc 3.10, both models.)
|
|
562
|
+
irq_reset_bad:
|
|
563
|
+
asl $d019
|
|
564
|
+
lda $d011
|
|
565
|
+
and #%01111111 // Clear RST8
|
|
566
|
+
sta $d011
|
|
567
|
+
lda #<280 // $18 — RST8 must be set for 280, but it's cleared above
|
|
568
|
+
sta $d012 // Target = line 24 on NTSC (RST8 clear), not 280
|
|
569
|
+
lda #<irq_color
|
|
570
|
+
sta $0314
|
|
571
|
+
lda #>irq_color
|
|
572
|
+
sta $0315
|
|
573
|
+
jmp $ea81
|
|
574
|
+
|
|
575
|
+
// GOOD: reset IRQ targets line 255 (safe on both PAL and NTSC).
|
|
576
|
+
// Both regions have raster lines 0-254 inside the active / border area.
|
|
577
|
+
irq_reset_good:
|
|
578
|
+
asl $d019
|
|
579
|
+
lda $d011
|
|
580
|
+
and #%01111111 // Clear RST8 (line 255 < 256, RST8 not needed)
|
|
581
|
+
sta $d011
|
|
582
|
+
lda #255
|
|
583
|
+
sta $d012 // Line 255 exists on both PAL (< 312) and NTSC (< 263)
|
|
584
|
+
lda #<irq_color
|
|
585
|
+
sta $0314
|
|
586
|
+
lda #>irq_color
|
|
587
|
+
sta $0315
|
|
588
|
+
jmp $ea81
|
|
589
|
+
|
|
590
|
+
// When you need region-specific end-of-frame lines, select at runtime:
|
|
591
|
+
irq_reset_region_aware:
|
|
592
|
+
asl $d019
|
|
593
|
+
lda region_flag
|
|
594
|
+
bne !+
|
|
595
|
+
// PAL: line 280 (lower border; 64 lines past the badline window)
|
|
596
|
+
lda $d011
|
|
597
|
+
ora #%10000000 // Set RST8 — line 280 >= 256
|
|
598
|
+
sta $d011
|
|
599
|
+
lda #<280
|
|
600
|
+
sta $d012
|
|
601
|
+
jmp done_reset_irq // Not a conditional branch: <280 = $18 leaves Z clear
|
|
602
|
+
!: // NTSC: line 253 (lower border; 15 lines past the badline window)
|
|
603
|
+
lda $d011
|
|
604
|
+
and #%01111111 // Clear RST8
|
|
605
|
+
sta $d011
|
|
606
|
+
lda #253
|
|
607
|
+
sta $d012
|
|
608
|
+
done_reset_irq:
|
|
609
|
+
lda #<irq_color
|
|
610
|
+
sta $0314
|
|
611
|
+
lda #>irq_color
|
|
612
|
+
sta $0315
|
|
613
|
+
jmp $ea81
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**Correction (2026-09-22).** The PAL path of `irq_reset_region_aware` ended
|
|
617
|
+
`lda #<280` / `sta $d012` / `beq done_reset_irq`; `<280` is $18, so Z was
|
|
618
|
+
clear, the branch never taken, and the code fell through into the NTSC
|
|
619
|
+
branch — clearing RST8 and arming line 253. Measured in VICE x64sc 3.10 on
|
|
620
|
+
the PAL model with `region_flag` = 0: the next raster IRQ read $D012 = $FD,
|
|
621
|
+
$D011 = $1B; with the branch replaced by `jmp done_reset_irq` it read $D012 =
|
|
622
|
+
$18, $D011 = $9B (9-bit line 280). `jmp` rather than `bne` because `bne`
|
|
623
|
+
would only work while the low byte happens to be non-zero — a target of 256
|
|
624
|
+
or 512 would silently break it again, the same failure the `detect_region`
|
|
625
|
+
correction in the first pitfall records. All three handlers also ended in a
|
|
626
|
+
bare `rti`, which from a `$0314` handler pops the dispatcher's saved
|
|
627
|
+
registers as the return frame (see the `frame_irq` correction above); they
|
|
628
|
+
exit through `$EA81` now.
|
|
629
|
+
|
|
630
|
+
### Cross-references
|
|
631
|
+
|
|
632
|
+
- Technique: `stable_raster_irq` — the double-IRQ pattern this pitfall
|
|
633
|
+
affects (its NTSC notes cover the per-line budget only; the narrower
|
|
634
|
+
post-display window is in pal-ntsc-reference.md, Badline range).
|
|
635
|
+
- Registers: `D012` (RASTER — low 8 bits of raster counter and compare
|
|
636
|
+
target), `D011` (SCROLY — bit 7 is RST8, the 9th raster bit).
|
|
637
|
+
- Reference: `pal-ntsc-reference.md` — quick-reference table for lines per
|
|
638
|
+
frame and $D012 wrap values; its "Badline range" section gives the lines
|
|
639
|
+
after the last badline (68 PAL, 19 NTSC R8) and its "Visible region"
|
|
640
|
+
section the vertical blank (300-15 PAL, 13-40 NTSC). It does not give the
|
|
641
|
+
"post-display blanking" counts an earlier version of this entry cited.
|
|
642
|
+
- Pitfall: `d012_wrap_around` — the complementary pitfall about RST8 and the
|
|
643
|
+
9-bit raster counter; the two pitfalls often co-occur.
|
|
644
|
+
|
|
645
|
+
## Sources
|
|
646
|
+
|
|
647
|
+
- VICE 3.10, `x64sc`, models `default`, `ntsc`, `oldntsc` — the instrument
|
|
648
|
+
behind every "measured" figure on this page (the `detect_region`
|
|
649
|
+
correction and the entry-line runs; the 2026-09-22 corrections' latch
|
|
650
|
+
reads, raster-compare targets, CIA tick counts and handler-exit runs).
|
|
651
|
+
https://vice-emu.sourceforge.io/
|
|
652
|
+
- KickAssembler 5.25 — assembled every `kick` fragment here; the 36-byte
|
|
653
|
+
count is its.
|
|
654
|
+
- Christian Bauer, "The MOS 6567/6569 video controller (VIC-II) and its
|
|
655
|
+
application in the Commodore 64", https://www.cebix.net/VIC-Article.txt —
|
|
656
|
+
§3.2 (RST8 as bit 8 of the raster register), §3.4 (lines per frame for
|
|
657
|
+
the 6569, 6567R8 and 6567R56A).
|
|
658
|
+
- This repository: `hardware/pal-ntsc-reference.md` (clock rates, frame
|
|
659
|
+
rates, CIA latch table, Method 2), `techniques/raster.md`
|
|
660
|
+
(`pal_ntsc_detection`, with the duration and race measurements).
|