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,528 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: two-player
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [two_player_state_swap, joystick_edge_detect, keyboard_matrix_scan]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: [DC00, DC01, DD04, DD05, DD0E, D000, D001, D012, D015, D020, D027, D028]
|
|
9
|
+
uses_kernal: [CHROUT]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 two-player: alternating play by state-block swap, and simultaneous play from both control ports
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
Two player sprites and one listing that plays two ways. In alternating
|
|
19
|
+
play one game runs at a time: each player owns an eight-byte state block
|
|
20
|
+
(score, lives, level, cell, random seed) in a two-entry array, and a
|
|
21
|
+
death stores the block in play and loads the other player's, so each
|
|
22
|
+
player resumes their own game with their own score and their own random
|
|
23
|
+
sequence. In simultaneous play both blocks are live and both control
|
|
24
|
+
ports are read every frame with the KERNAL IRQ still running. Port 1
|
|
25
|
+
shares `$DC01` with the keyboard rows, and the KERNAL leaves `$DC00` at
|
|
26
|
+
`$7F` between scans, so a key held in column 7 (1, left-arrow, CTRL, 2,
|
|
27
|
+
SPACE) would read as a direction on port 1. The listing writes `$FF` to
|
|
28
|
+
`$DC00` right before each `$DC01` read, with the IRQ held off across the
|
|
29
|
+
pair so the scan cannot run between them, and counts how many reads it
|
|
30
|
+
took with a column selected; the same build with `MITIGATE=0` counts one
|
|
31
|
+
per frame and goes red. The mode is a byte written at start from the
|
|
32
|
+
`MODE` define; both paths are compiled in. The verdict is the pattern of
|
|
33
|
+
`headless-verify.md`: a code at `$02FF`, the border colour, and a line of
|
|
34
|
+
text. The technique is `two_player_state_swap` in `techniques/logic.md`.
|
|
35
|
+
|
|
36
|
+
## Source
|
|
37
|
+
|
|
38
|
+
```c
|
|
39
|
+
// two-player.c
|
|
40
|
+
// Two players, two sprites, two ways to share one machine.
|
|
41
|
+
// ALTERNATING: one game runs at a time. Each player owns a state block
|
|
42
|
+
// (score, lives, level, cell, random seed); on death the block in play is
|
|
43
|
+
// stored and the other player's block is loaded, so each resumes their
|
|
44
|
+
// own game. SIMULTANEOUS: both control ports are read every frame with
|
|
45
|
+
// the KERNAL IRQ live. Port 1 shares $DC01 with the keyboard rows, and
|
|
46
|
+
// the KERNAL leaves $DC00 at $7F between scans, so a key in column 7
|
|
47
|
+
// would read as a direction; $DC00 is set to $FF right before the $DC01
|
|
48
|
+
// read, with the IRQ held off across the pair so the scan cannot run in
|
|
49
|
+
// between. The autopilot scripts both ports; the
|
|
50
|
+
// program checks the outcome and reports at $02FF, in the border colour
|
|
51
|
+
// and on screen.
|
|
52
|
+
#include <stdio.h>
|
|
53
|
+
#include <c64/vic.h>
|
|
54
|
+
#include <c64/cia.h>
|
|
55
|
+
|
|
56
|
+
#ifndef AUTOPILOT
|
|
57
|
+
#define AUTOPILOT 1 // 1: scripted port bytes instead of the ports
|
|
58
|
+
#endif
|
|
59
|
+
#ifndef MODE
|
|
60
|
+
#define MODE 1 // byte written at start: 0 alternating, 1 simultaneous
|
|
61
|
+
#endif
|
|
62
|
+
#ifndef MITIGATE
|
|
63
|
+
#define MITIGATE 1 // 1: set $DC00 to $FF before every $DC01 read
|
|
64
|
+
#endif
|
|
65
|
+
|
|
66
|
+
#define CODE_PASS 0x01
|
|
67
|
+
#define CODE_FAIL 0x02
|
|
68
|
+
#define RESULT (*(volatile char *)0x02ff)
|
|
69
|
+
#define JOY_MASK 0x1f // bits 0-4: up, down, left, right, fire
|
|
70
|
+
#define FRAMES 40
|
|
71
|
+
#define SCREEN ((char *)0x0400)
|
|
72
|
+
#define SPR_DATA ((char *)0x0340) // cassette buffer, pointer 13
|
|
73
|
+
#define SPR_PTR ((char *)0x07f8)
|
|
74
|
+
#define START_X 2
|
|
75
|
+
#define PIT_COL 14 // stepping onto this column is a death
|
|
76
|
+
#define MAX_X 28 // keeps sprite x below 256
|
|
77
|
+
|
|
78
|
+
struct PlayerState {
|
|
79
|
+
unsigned score; // 10 per cell moved
|
|
80
|
+
char lives, level;
|
|
81
|
+
char cx, cy; // cell, 8 px each
|
|
82
|
+
unsigned rng; // 16-bit xorshift, stepped once per own frame
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
static struct PlayerState players[2]; // one block per player
|
|
86
|
+
static struct PlayerState g; // the block in play (alternating)
|
|
87
|
+
static char cur; // whose turn (alternating)
|
|
88
|
+
static char mode; // 0 alternating, 1 simultaneous
|
|
89
|
+
static char raw2, raw1; // last port reads, active low
|
|
90
|
+
static char colsel, phantom; // port-1 hazard counters
|
|
91
|
+
|
|
92
|
+
// ---- per-player step ------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
static void step(struct PlayerState *p, char port)
|
|
95
|
+
{
|
|
96
|
+
char pressed = ~port & JOY_MASK;
|
|
97
|
+
p->rng ^= p->rng << 7;
|
|
98
|
+
p->rng ^= p->rng >> 9;
|
|
99
|
+
p->rng ^= p->rng << 8;
|
|
100
|
+
if ((pressed & 0x01) && p->cy > 0) { p->cy--; p->score += 10; }
|
|
101
|
+
if ((pressed & 0x02) && p->cy < 24) { p->cy++; p->score += 10; }
|
|
102
|
+
if ((pressed & 0x04) && p->cx > 0) { p->cx--; p->score += 10; }
|
|
103
|
+
if ((pressed & 0x08) && p->cx < MAX_X) { p->cx++; p->score += 10; }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Death in alternating play: the block in play goes back to its slot,
|
|
107
|
+
// the other player's block comes out, if that player still has lives.
|
|
108
|
+
static void swap_on_death(void)
|
|
109
|
+
{
|
|
110
|
+
g.lives--;
|
|
111
|
+
g.cx = START_X;
|
|
112
|
+
players[cur] = g;
|
|
113
|
+
if (players[cur ^ 1].lives)
|
|
114
|
+
cur ^= 1;
|
|
115
|
+
g = players[cur];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---- ports ----------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
// Reads both ports from the real registers every frame. With MITIGATE the
|
|
121
|
+
// $FF store to $DC00 and the two reads run with the IRQ held off, so the
|
|
122
|
+
// KERNAL scan cannot land between them and leave $7F behind; the flags
|
|
123
|
+
// are restored, so a caller that already has the IRQ off keeps it off.
|
|
124
|
+
// colsel counts reads that found a column line among bits 5-7 of $DC00
|
|
125
|
+
// low, the state the scan leaves; phantom counts $DC01 reads with any
|
|
126
|
+
// direction bit low.
|
|
127
|
+
static char port_a, port_b; // raw $DC00 and $DC01
|
|
128
|
+
static void read_ports(void)
|
|
129
|
+
{
|
|
130
|
+
#if MITIGATE
|
|
131
|
+
__asm {
|
|
132
|
+
php
|
|
133
|
+
sei
|
|
134
|
+
lda #$ff // no keyboard column selected
|
|
135
|
+
sta $dc00
|
|
136
|
+
lda $dc00
|
|
137
|
+
sta port_a
|
|
138
|
+
lda $dc01
|
|
139
|
+
sta port_b
|
|
140
|
+
plp
|
|
141
|
+
}
|
|
142
|
+
#else
|
|
143
|
+
port_a = cia1.pra;
|
|
144
|
+
port_b = cia1.prb;
|
|
145
|
+
#endif
|
|
146
|
+
raw2 = port_a | ~JOY_MASK; // port 2 sits on bits 0-4
|
|
147
|
+
if ((port_a | JOY_MASK) != 0xff) colsel++;
|
|
148
|
+
raw1 = port_b | ~JOY_MASK; // port 1 on the row lines
|
|
149
|
+
if ((raw1 & JOY_MASK) != JOY_MASK) phantom++;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#if AUTOPILOT
|
|
153
|
+
// { frames, port byte } for port 2 (alternating: the active player).
|
|
154
|
+
static const char script2[7][2] = {
|
|
155
|
+
{ 12, 0xf7 }, { 3, 0xfd }, { 12, 0xf7 }, { 2, 0xfe }, { 3, 0xf7 },
|
|
156
|
+
{ 8, 0xff }, { 0, 0xff }
|
|
157
|
+
};
|
|
158
|
+
// Port 2 and port 1 in simultaneous play.
|
|
159
|
+
static const char sim2[3][2] = { { 8, 0xf7 }, { 4, 0xfd }, { 0, 0xff } };
|
|
160
|
+
static const char sim1[3][2] = { { 6, 0xf7 }, { 3, 0xfd }, { 0, 0xff } };
|
|
161
|
+
|
|
162
|
+
struct Cursor { char idx, used; };
|
|
163
|
+
static struct Cursor c2, c1;
|
|
164
|
+
|
|
165
|
+
static char script_byte(const char (*s)[2], struct Cursor *c)
|
|
166
|
+
{
|
|
167
|
+
char out = 0xff;
|
|
168
|
+
if (s[c->idx][0]) {
|
|
169
|
+
out = s[c->idx][1];
|
|
170
|
+
if (++c->used == s[c->idx][0]) { c->used = 0; c->idx++; }
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
#endif
|
|
175
|
+
|
|
176
|
+
// ---- timing: CIA2 timer A, KERNAL IRQ held off for the measured span ---
|
|
177
|
+
|
|
178
|
+
static unsigned cost, base, swap_cost, read_cost;
|
|
179
|
+
|
|
180
|
+
static void time_begin(void)
|
|
181
|
+
{
|
|
182
|
+
__asm { sei }
|
|
183
|
+
cia2.cra = 0x00;
|
|
184
|
+
cia2.ta = 0xffff;
|
|
185
|
+
cia2.cra = 0x11;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static void time_end(void)
|
|
189
|
+
{
|
|
190
|
+
cia2.cra = 0x00;
|
|
191
|
+
cost = 0xffff - cia2.ta;
|
|
192
|
+
__asm { cli }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ---- screen ---------------------------------------------------------------
|
|
196
|
+
|
|
197
|
+
static void put_str(char pos, const char *s)
|
|
198
|
+
{
|
|
199
|
+
char *p = SCREEN + pos;
|
|
200
|
+
while (*s) { char c = *s++; *p++ = (c >= 'A' && c <= 'Z') ? c - 64 : c; }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static void put_num(char pos, unsigned v, char digits)
|
|
204
|
+
{
|
|
205
|
+
char *p = SCREEN + pos + digits;
|
|
206
|
+
while (digits--) { *--p = '0' + v % 10; v /= 10; }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static void hud(void)
|
|
210
|
+
{
|
|
211
|
+
put_str(0, "P1 SC"); put_num(6, players[0].score, 5);
|
|
212
|
+
put_str(12, "L"); put_num(13, players[0].lives, 1);
|
|
213
|
+
put_str(20, "P2 SC"); put_num(26, players[1].score, 5);
|
|
214
|
+
put_str(32, "L"); put_num(33, players[1].lives, 1);
|
|
215
|
+
put_str(40, "TURN P"); put_num(46, cur + 1, 1);
|
|
216
|
+
if (mode) put_str(40, "BOTH ");
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static void place(char i, const struct PlayerState *p)
|
|
220
|
+
{
|
|
221
|
+
vic.spr_pos[i].x = 24 + p->cx * 8;
|
|
222
|
+
vic.spr_pos[i].y = 50 + p->cy * 8;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
static void wait_frame(void)
|
|
226
|
+
{
|
|
227
|
+
while (vic.raster == 250) ;
|
|
228
|
+
while (vic.raster != 250) ;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ---- expected blocks after the alternating script (host model) ----------
|
|
232
|
+
|
|
233
|
+
static const struct PlayerState exp_alt[2] = {
|
|
234
|
+
{ 170, 2, 1, 5, 3, 0xb717 }, { 150, 2, 1, 2, 18, 0x5b98 }
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
static char same(const struct PlayerState *a, const struct PlayerState *b)
|
|
238
|
+
{
|
|
239
|
+
return a->score == b->score && a->lives == b->lives && a->level == b->level
|
|
240
|
+
&& a->cx == b->cx && a->cy == b->cy && a->rng == b->rng;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
int main(void)
|
|
244
|
+
{
|
|
245
|
+
mode = MODE; // the byte the autopilot writes
|
|
246
|
+
|
|
247
|
+
for (char i = 0; i < 63; i++)
|
|
248
|
+
SPR_DATA[i] = (i < 3 || i >= 60) ? 0xff : (i % 3 == 0 ? 0x80 : (i % 3 == 2 ? 0x01 : 0x00));
|
|
249
|
+
SPR_PTR[0] = SPR_PTR[1] = 13;
|
|
250
|
+
vic.spr_color[0] = 7; vic.spr_color[1] = 3;
|
|
251
|
+
vic.spr_enable = 0x03;
|
|
252
|
+
|
|
253
|
+
for (char i = 0; i < 2; i++) {
|
|
254
|
+
players[i].score = 0; players[i].lives = 3; players[i].level = 1;
|
|
255
|
+
players[i].cx = START_X; players[i].cy = i ? 15 : 5;
|
|
256
|
+
players[i].rng = i ? 0xbeef : 0xace1;
|
|
257
|
+
}
|
|
258
|
+
cur = 0;
|
|
259
|
+
g = players[0];
|
|
260
|
+
|
|
261
|
+
for (char f = 0; f < FRAMES; f++) {
|
|
262
|
+
wait_frame();
|
|
263
|
+
read_ports();
|
|
264
|
+
#if AUTOPILOT
|
|
265
|
+
char b2 = script_byte(mode ? sim2 : script2, &c2);
|
|
266
|
+
char b1 = script_byte(sim1, &c1);
|
|
267
|
+
#else
|
|
268
|
+
char b2 = raw2, b1 = raw1;
|
|
269
|
+
#endif
|
|
270
|
+
if (mode) {
|
|
271
|
+
step(&players[0], b2);
|
|
272
|
+
step(&players[1], b1);
|
|
273
|
+
} else {
|
|
274
|
+
step(&g, b2);
|
|
275
|
+
if (g.cx == PIT_COL) swap_on_death();
|
|
276
|
+
players[cur] = g;
|
|
277
|
+
}
|
|
278
|
+
place(0, &players[0]);
|
|
279
|
+
place(1, &players[1]);
|
|
280
|
+
hud();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
char code = CODE_FAIL;
|
|
284
|
+
if (mode) {
|
|
285
|
+
if (players[0].cx == 10 && players[0].cy == 9 && players[1].cx == 8
|
|
286
|
+
&& players[1].cy == 18 && phantom == 0 && colsel == 0)
|
|
287
|
+
code = CODE_PASS;
|
|
288
|
+
} else if (same(&players[0], &exp_alt[0]) && same(&players[1], &exp_alt[1])) {
|
|
289
|
+
code = CODE_PASS;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Timing, after the verdict, on a copy of everything it touches, in
|
|
293
|
+
// the lower border where no badline or sprite fetch stalls the CPU.
|
|
294
|
+
struct PlayerState keep_g = g;
|
|
295
|
+
char keep_cur = cur, keep_colsel = colsel, keep_phantom = phantom;
|
|
296
|
+
wait_frame(); time_begin(); time_end(); base = cost;
|
|
297
|
+
wait_frame(); time_begin(); swap_on_death(); time_end(); swap_cost = cost - base;
|
|
298
|
+
wait_frame(); time_begin(); read_ports(); time_end(); read_cost = cost - base;
|
|
299
|
+
g = keep_g; cur = keep_cur; colsel = keep_colsel; phantom = keep_phantom;
|
|
300
|
+
players[cur] = g;
|
|
301
|
+
|
|
302
|
+
RESULT = code;
|
|
303
|
+
vic.color_border = (code == CODE_PASS) ? 5 : 2;
|
|
304
|
+
|
|
305
|
+
if (mode)
|
|
306
|
+
printf("SIM COLSEL %d PHANTOM %d\n", colsel, phantom);
|
|
307
|
+
else
|
|
308
|
+
printf("ALT P1 %d/%d/%d/%d/%04X P2 %d/%d/%d/%d/%04X\n",
|
|
309
|
+
players[0].score, players[0].lives, players[0].cx, players[0].cy, players[0].rng,
|
|
310
|
+
players[1].score, players[1].lives, players[1].cx, players[1].cy, players[1].rng);
|
|
311
|
+
printf("SWAP %d READ %d RESULT %02X %s\n", swap_cost, read_cost, code,
|
|
312
|
+
code == CODE_PASS ? "PASS" : "FAIL");
|
|
313
|
+
return 0;
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Build
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
oscar64 -tm=c64 -O2 -n -o=two-player.prg two-player.c
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Produces `two-player.prg`, 5,952 bytes (Oscar64 build 2026-05-19), the
|
|
324
|
+
pinned simultaneous build: `AUTOPILOT=1`, `MODE=1`, `MITIGATE=1` are the
|
|
325
|
+
defaults behind `#ifndef`. `-n` asks for native code for every
|
|
326
|
+
function, which this Oscar64 does by default; it stays on the line
|
|
327
|
+
because the screenshots were made with it. Every build writes a map
|
|
328
|
+
file. In `two-player.map` the size of `players` is `0010` and the size
|
|
329
|
+
of `g` is `0008`: eight bytes per block, sixteen for the pair, one more
|
|
330
|
+
block for the copy in play. The addresses move with any edit and are
|
|
331
|
+
not quoted. The two other builds this page measures:
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
oscar64 -tm=c64 -O2 -dMODE=0 -o=two-player-alt.prg two-player.c # 6,211 bytes, alternating
|
|
335
|
+
oscar64 -tm=c64 -O2 -dMITIGATE=0 -o=two-player-nomit.prg two-player.c # 5,932 bytes, the red case
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`exp_alt` comes from a host model of `step()` and `swap_on_death()` run
|
|
339
|
+
over the alternating script:
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
JOY, PIT, MAXX, STARTX = 0x1f, 14, 28, 2
|
|
343
|
+
def step(p, port):
|
|
344
|
+
pressed = ~port & JOY
|
|
345
|
+
r = p['rng']
|
|
346
|
+
r ^= (r << 7) & 0xffff; r ^= r >> 9; r ^= (r << 8) & 0xffff
|
|
347
|
+
p['rng'] = r
|
|
348
|
+
if pressed & 1 and p['cy'] > 0: p['cy'] -= 1; p['score'] += 10
|
|
349
|
+
if pressed & 2 and p['cy'] < 24: p['cy'] += 1; p['score'] += 10
|
|
350
|
+
if pressed & 4 and p['cx'] > 0: p['cx'] -= 1; p['score'] += 10
|
|
351
|
+
if pressed & 8 and p['cx'] < MAXX: p['cx'] += 1; p['score'] += 10
|
|
352
|
+
players = [dict(score=0, lives=3, level=1, cx=STARTX, cy=5, rng=0xace1),
|
|
353
|
+
dict(score=0, lives=3, level=1, cx=STARTX, cy=15, rng=0xbeef)]
|
|
354
|
+
script2 = [(12, 0xf7), (3, 0xfd), (12, 0xf7), (2, 0xfe), (3, 0xf7), (8, 0xff)]
|
|
355
|
+
stream = [b for n, b in script2 for _ in range(n)]
|
|
356
|
+
cur, g = 0, dict(players[0])
|
|
357
|
+
for f in range(40):
|
|
358
|
+
step(g, stream[f] if f < len(stream) else 0xff)
|
|
359
|
+
if g['cx'] == PIT:
|
|
360
|
+
g['lives'] -= 1; g['cx'] = STARTX
|
|
361
|
+
players[cur] = dict(g)
|
|
362
|
+
if players[cur ^ 1]['lives']: cur ^= 1
|
|
363
|
+
g = dict(players[cur])
|
|
364
|
+
players[cur] = dict(g)
|
|
365
|
+
for p in players:
|
|
366
|
+
print("{ %d, %d, %d, %d, %d, 0x%04x }" % (p['score'], p['lives'], p['level'], p['cx'], p['cy'], p['rng']))
|
|
367
|
+
# { 170, 2, 1, 5, 3, 0xb717 }
|
|
368
|
+
# { 150, 2, 1, 2, 18, 0x5b98 }
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Expected output
|
|
372
|
+
|
|
373
|
+
Border green. Row 0 is the HUD, `P1 SC 00120 L3 P2 SC 00090 L3`,
|
|
374
|
+
with `BOTH` at the start of row 1 over the BASIC banner. Two hollow
|
|
375
|
+
sprites, yellow at cell (10, 9) and cyan at cell (8, 18). Rows 7 and 8:
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
SIM COLSEL 0 PHANTOM 0
|
|
379
|
+
SWAP 206 READ 65 RESULT 01 PASS
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Screenshots from the pinned run, 8,000,000 cycles:
|
|
383
|
+
`screenshots/two-player.png` (PAL) and `screenshots/two-player-ntsc.png`
|
|
384
|
+
(NTSC). Measured on both with the char ROM decoder and PIL: the two rows
|
|
385
|
+
above on screen rows 7 and 8; border pixel (2, 100) = (98, 213, 50) on
|
|
386
|
+
PAL and (114, 189, 103) on NTSC, index 5 in both palettes of
|
|
387
|
+
`runtime/vice-reference.md`; the top row of sprite 0 at pixel
|
|
388
|
+
(114, 107) on PAL reads (255, 255, 70), index 7, and the top row of
|
|
389
|
+
sprite 1 at (98, 179) reads (126, 243, 214), index 3, which are the
|
|
390
|
+
pixels of cells (10, 9) and (8, 18) with the text area's origin at
|
|
391
|
+
(32, 35); on NTSC the same cells with the origin at (32, 23). Each
|
|
392
|
+
picture was produced twice by the pinned command and the two files were
|
|
393
|
+
identical bytes.
|
|
394
|
+
|
|
395
|
+
The alternating build, `-dMODE=0`, was run on PAL and NTSC and not
|
|
396
|
+
pinned. The HUD reads `P1 SC 00170 L2 P2 SC 00150 L2`, `TURN P1`
|
|
397
|
+
at the start of row 1, the sprites at cells (5, 3) and (2, 18), and rows
|
|
398
|
+
7 to 9:
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
ALT P1 170/2/5/3/B717 P2 150/2/2/18/5B98
|
|
402
|
+
|
|
403
|
+
SWAP 206 READ 65 RESULT 01 PASS
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
The fields are score, lives, cx, cy and rng for each block, and they
|
|
407
|
+
match `exp_alt` on both models. Player 1 walked twelve cells right into
|
|
408
|
+
the pit at column 14, lost a life and went back to column 2; player 2
|
|
409
|
+
then played fifteen frames (three down, twelve right) into the same pit;
|
|
410
|
+
player 1 resumed at their own cell (2, 5) with their own seed and moved
|
|
411
|
+
two up and three right. The script is forty frames and the loop runs
|
|
412
|
+
forty. Player 1's seed advanced 25 times (12 + 2 + 3 + 8 frames),
|
|
413
|
+
player 2's 15 times (3 + 12), and the blocks hold different seeds
|
|
414
|
+
because neither stepped while the other played.
|
|
415
|
+
|
|
416
|
+
The red case, `-dMITIGATE=0`, was run on PAL and NTSC and not pinned:
|
|
417
|
+
the same simultaneous screen with `SIM COLSEL 40 PHANTOM 0` on row 7,
|
|
418
|
+
`SWAP 206 READ 39 RESULT 02 FAIL` on row 8 and the border at
|
|
419
|
+
(175, 60, 88) on PAL, (169, 71, 100) on NTSC, index 2. Forty frames,
|
|
420
|
+
forty reads taken with column 7 selected. The mitigation costs 26
|
|
421
|
+
cycles a frame against this build, 39 to 65: the `php`, `sei` and
|
|
422
|
+
`plp`, the store, and the two reads going through memory. `PHANTOM` is 0 in both builds
|
|
423
|
+
because a headless run holds no key; see "What the counters can and
|
|
424
|
+
cannot show".
|
|
425
|
+
|
|
426
|
+
## Why this works
|
|
427
|
+
|
|
428
|
+
**The block.** `struct PlayerState` is eight bytes: `score` and `rng`
|
|
429
|
+
are `unsigned` (16 bits in Oscar64), the other four are `char`. The map
|
|
430
|
+
file confirms it: `players` has size `0010`, sixteen bytes for two, and
|
|
431
|
+
`g` has size `0008`. Everything that makes a player's
|
|
432
|
+
game theirs is in the block, including the random seed, so a swap
|
|
433
|
+
cannot leak one player's random sequence into the other's game. Nothing
|
|
434
|
+
outside the block is per player; the sprite positions are recomputed
|
|
435
|
+
from the blocks every frame by `place()`, and the HUD is redrawn from
|
|
436
|
+
both blocks.
|
|
437
|
+
|
|
438
|
+
**The swap.** `swap_on_death()` is three assignments and a compare: take
|
|
439
|
+
the life, reset the cell, store `g` into `players[cur]`, flip `cur` if
|
|
440
|
+
the other player still has lives, load `g` from `players[cur]`. Oscar64
|
|
441
|
+
compiles the two struct assignments as eight-byte copies. Measured with
|
|
442
|
+
CIA2 timer A, KERNAL IRQ held off with `sei` and the span started in the
|
|
443
|
+
lower border after a `wait_frame()`, net of an empty start-stop span:
|
|
444
|
+
206 cycles on PAL and on NTSC. The first measurement, taken wherever the
|
|
445
|
+
raster happened to be, gave 206 on one run and 249 on another; the
|
|
446
|
+
difference was a badline or the sprite fetch stalling the CPU inside the
|
|
447
|
+
span, which is why the timed spans wait for line 250 first. The game
|
|
448
|
+
loop keeps the block in play in `g` and writes it back to `players[cur]`
|
|
449
|
+
each frame, so the array is always current and the end-of-run check
|
|
450
|
+
reads the array alone.
|
|
451
|
+
|
|
452
|
+
**Port 1 with the KERNAL live.** The KERNAL's jiffy IRQ calls SCNKEY,
|
|
453
|
+
which drives `$DC00` and reads `$DC01`, and leaves `$DC00` at `$7F` on
|
|
454
|
+
its way out, column 7 selected. A main-loop read cannot land inside the
|
|
455
|
+
scan (`pitfalls/input.md`, joystick2_scan_phantom_press, measured
|
|
456
|
+
there), so a read between scans sees what the scan left: with column 7
|
|
457
|
+
selected, a held 1, left-arrow, CTRL, 2 or SPACE grounds a row line and
|
|
458
|
+
reads as up, down, left, right or fire on `$DC01`. `read_ports()`
|
|
459
|
+
therefore writes `$FF` to `$DC00` first, selecting no column, and reads
|
|
460
|
+
`$DC01` after.
|
|
461
|
+
|
|
462
|
+
The store alone is not enough, and an earlier draft of this page said
|
|
463
|
+
it was. The jiffy IRQ comes from CIA1 timer A every 16,422 cycles on
|
|
464
|
+
PAL and 17,046 on NTSC (`hardware/cia-reference.md`), the game loop is
|
|
465
|
+
locked to the raster, so the interrupt drifts through the loop and can
|
|
466
|
+
be taken between the store and the read. When it is, SCNKEY runs, puts
|
|
467
|
+
`$7F` back, and the read that follows is taken with column 7 selected
|
|
468
|
+
after all. Measured, PAL, windowless VICE: the bare store-then-read
|
|
469
|
+
shape called 50,000 times in a tight loop with the IRQ live found `$7F`
|
|
470
|
+
on the read right after the store 9 times, and finished the `$DC01`
|
|
471
|
+
read with `$DC00` back at `$7F` 63 times; the reviewer's run of the
|
|
472
|
+
same shape gave 14 and 92. Per frame the odds are the window over the
|
|
473
|
+
timer period. The compiled window from the store to the `$DC01` read
|
|
474
|
+
was 19 cycles, so about one frame in 860 on PAL and one in 900 on NTSC,
|
|
475
|
+
a few times a minute in a real game; the 0 of 40 frames this page
|
|
476
|
+
first reported was a small sample of that, not proof. The listing now
|
|
477
|
+
holds the interrupt off across the pair: `php`, `sei`, the store, the
|
|
478
|
+
two reads, `plp`. The interrupt waits 22 cycles and is taken right
|
|
479
|
+
after, so no scan is lost, and the flags are restored rather than
|
|
480
|
+
cleared, so the timed spans, which already run under `sei`, keep it
|
|
481
|
+
off. The same 50,000-iteration loop with the held-off shape found `$7F`
|
|
482
|
+
after the store 0 times. The direction registers are left as IOINIT set
|
|
483
|
+
them; a program that clears `$DC02` kills the keyboard
|
|
484
|
+
(`pitfalls/input.md`, cia1_ddr_cleared_kills_keyboard). `$DC00` is read
|
|
485
|
+
for port 2 inside the same held-off span, before `$DC01`; with `$FF` in
|
|
486
|
+
the latch the low five bits are the stick and nothing else.
|
|
487
|
+
|
|
488
|
+
**What the counters can and cannot show.** `colsel` counts reads taken
|
|
489
|
+
while any of bits 5 to 7 of `$DC00` was low, which is what the KERNAL's
|
|
490
|
+
`$7F` looks like from the main loop. With the held-off store it is 0 in
|
|
491
|
+
40 frames; without it, 40 in 40, on both models: every unmitigated read
|
|
492
|
+
happens in the state where a held column-7 key would be a phantom
|
|
493
|
+
direction. `phantom` counts `$DC01` reads with any direction bit low.
|
|
494
|
+
It is 0 in both builds here because the harness cannot hold a key:
|
|
495
|
+
VICE's keyboard feed and `-keybuf` write the KERNAL buffer at `$0277`,
|
|
496
|
+
not the matrix, so nothing grounds a row line in a headless run. The
|
|
497
|
+
phantom itself, a held SPACE reading as fire on port 1 with `$DC00` at
|
|
498
|
+
`$7F`, follows from the matrix wiring in `hardware/cia-reference.md`
|
|
499
|
+
and is stated by both input pages; it was not measured here. What was
|
|
500
|
+
measured is the precondition, and that the mitigation removes it on
|
|
501
|
+
every frame.
|
|
502
|
+
|
|
503
|
+
**The mode byte.** `mode` is one variable set at the top of `main()`
|
|
504
|
+
from the `MODE` define; both paths are always compiled, and the loop
|
|
505
|
+
branches on the byte each frame. A real front end would set it from a
|
|
506
|
+
menu; the autopilot sets it so one listing pins both.
|
|
507
|
+
|
|
508
|
+
**The autopilot.** `script_byte()` walks a `{ frames, port byte }`
|
|
509
|
+
table per port, active low as the ports read it, and `read_ports()` is
|
|
510
|
+
still called every frame so the counters measure the real registers.
|
|
511
|
+
Without `AUTOPILOT` the two `raw` bytes drive the game and the
|
|
512
|
+
mode-specific checks fail on an idle machine, which is the expected red
|
|
513
|
+
in that build.
|
|
514
|
+
|
|
515
|
+
Verified: compiled with Oscar64 (build 2026-05-19), run headless in VICE
|
|
516
|
+
x64sc 3.10 with the pinned command on PAL and NTSC; the screenshots were
|
|
517
|
+
decoded with the char ROM and the sprite cells read with PIL, not by
|
|
518
|
+
eye.
|
|
519
|
+
|
|
520
|
+
## Sources
|
|
521
|
+
|
|
522
|
+
- `pitfalls/input.md`, joystick2_scan_phantom_press and
|
|
523
|
+
cia1_ddr_cleared_kills_keyboard: the main-loop measurement, the `$7F`
|
|
524
|
+
the KERNAL leaves, and the column-7 keys.
|
|
525
|
+
- `techniques/input.md`, keyboard_matrix_scan: the port-1 paragraph and
|
|
526
|
+
the ordering rule, read port 1 only with `$DC00` at `$FF`.
|
|
527
|
+
- `hardware/cia-reference.md`: the shared-pin table for `$DC00` and
|
|
528
|
+
`$DC01`, the `$DC02` entry, and the jiffy timer periods.
|