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,772 @@
|
|
|
1
|
+
---
|
|
2
|
+
recipe: high-score-persist
|
|
3
|
+
toolchain: oscar64
|
|
4
|
+
output_format: PRG
|
|
5
|
+
region: both
|
|
6
|
+
techniques: [kernal_file_write_seq, kernal_file_read_seq, error_channel_check]
|
|
7
|
+
file_formats: [PRG]
|
|
8
|
+
uses_registers: []
|
|
9
|
+
uses_kernal: [SETLFS, SETNAM, OPEN, CLOSE, CHKIN, CHKOUT, CLRCHN, CHRIN, CHROUT, READST]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- doc-type: recipe -->
|
|
13
|
+
|
|
14
|
+
# Oscar64 High-Score File: First Run, Replace, Version Check
|
|
15
|
+
|
|
16
|
+
## Synopsis
|
|
17
|
+
|
|
18
|
+
The save-file policy a game needs around the file calls, run end to
|
|
19
|
+
end against drive 8 through Oscar64's `kernalio.h`. On start the
|
|
20
|
+
program tries to read the sequential file `HISCORE`. That OPEN sends a
|
|
21
|
+
name down the bus, so it is also the device test: when no drive answers
|
|
22
|
+
it returns false with ST bit 7 set and the bus is left alone for the
|
|
23
|
+
rest of the run. A drive reply of
|
|
24
|
+
`62` is the first run: it shows the default table and writes it. A
|
|
25
|
+
reply of `00` with a record of the right size, magic and version is a
|
|
26
|
+
load. A record of the wrong size or version is rejected, scratched and
|
|
27
|
+
replaced. Any other reply, `74` with no disk in the drive for one,
|
|
28
|
+
turns saving off for the session and the defaults are used. It then
|
|
29
|
+
enters a new score, replaces the file by scratch-then-write, reads it
|
|
30
|
+
back and prints it, with the drive's reply and `krnio_status()` after
|
|
31
|
+
every step and a 16-bit checksum of the record that came back matched
|
|
32
|
+
against the value Python computed. The verifier gives every run a
|
|
33
|
+
freshly formatted disk, so one pinned run exercises the first-run path,
|
|
34
|
+
the first write, the scratch, the rewrite and the read-back in
|
|
35
|
+
sequence. The other paths were run once each and are described below.
|
|
36
|
+
Use it as the skeleton for a high-score file or a save slot.
|
|
37
|
+
|
|
38
|
+
## Source
|
|
39
|
+
|
|
40
|
+
```c
|
|
41
|
+
// high-score-persist.c
|
|
42
|
+
// The save-game policy in one run against drive 8, through Oscar64's
|
|
43
|
+
// kernalio.h. On start, try to read the SEQ file HISCORE. That OPEN
|
|
44
|
+
// sends a name down the bus, so it is also the device test: if no drive
|
|
45
|
+
// answers it returns false with ST bit 7 (KRNIO_NODEVICE) and the bus
|
|
46
|
+
// is not touched again. A drive reply of 62 means first run: show the
|
|
47
|
+
// default table and write it. A reply of 00 with a record of the right
|
|
48
|
+
// size and version means loaded. Any other reply means saving is off
|
|
49
|
+
// for this session and the defaults are used. Then a new high score is
|
|
50
|
+
// entered, the file is scratched and rewritten, and read back. The
|
|
51
|
+
// drive reply and krnio_status() are printed at every step, and a
|
|
52
|
+
// 16-bit checksum of the record that came back is shown with PASS or
|
|
53
|
+
// FAIL against the value Python computed.
|
|
54
|
+
#include <stdio.h>
|
|
55
|
+
#include <string.h>
|
|
56
|
+
#include <c64/kernalio.h>
|
|
57
|
+
|
|
58
|
+
#define DRIVE 8
|
|
59
|
+
#define VERSION 1
|
|
60
|
+
#define ENTRIES 3
|
|
61
|
+
#define EXPECT_CHK 0xF1F6 // python: same fold over the 21 bytes
|
|
62
|
+
|
|
63
|
+
typedef struct {
|
|
64
|
+
char name[4]; // three letters and a terminating zero
|
|
65
|
+
unsigned score; // 16 bits, stored low byte first
|
|
66
|
+
} Score;
|
|
67
|
+
|
|
68
|
+
typedef struct {
|
|
69
|
+
char magic[2]; // 'H','S'
|
|
70
|
+
char version; // bump when the layout changes
|
|
71
|
+
Score entry[ENTRIES];
|
|
72
|
+
} Table; // 21 bytes: no padding in Oscar64
|
|
73
|
+
|
|
74
|
+
static const Table defaults = {
|
|
75
|
+
{ 'H', 'S' }, VERSION,
|
|
76
|
+
{{ "ABC", 5000 }, { "DEF", 2500 }, { "GHI", 1000 }}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
static Table table; // the live table
|
|
80
|
+
static char back[64]; // read buffer, bigger than the file
|
|
81
|
+
static char reply[40]; // one drive status line
|
|
82
|
+
static char code; // first two digits of the last reply
|
|
83
|
+
static bool saving; // false: drive 8 is not usable
|
|
84
|
+
|
|
85
|
+
static void put_hex2(char v)
|
|
86
|
+
{
|
|
87
|
+
char d = v >> 4;
|
|
88
|
+
putchar(d < 10 ? '0' + d : 'A' + d - 10);
|
|
89
|
+
d = v & 15;
|
|
90
|
+
putchar(d < 10 ? '0' + d : 'A' + d - 10);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Open the command channel with cmd as the name ("" to read the status,
|
|
94
|
+
// or a DOS command such as "S0:HISCORE"), read one status line from the
|
|
95
|
+
// same open channel, close it. The reply to a command is only there
|
|
96
|
+
// until the channel that sent it is closed. Sets code to the two-digit
|
|
97
|
+
// number at the head of the line. Never called once the device is known
|
|
98
|
+
// to be absent: an empty name sends nothing on the bus, so this OPEN
|
|
99
|
+
// succeeds whether or not a drive exists, and the CHKIN inside
|
|
100
|
+
// krnio_gets would then hang with no timeout.
|
|
101
|
+
static void drive_reply(const char *cmd)
|
|
102
|
+
{
|
|
103
|
+
reply[0] = 0;
|
|
104
|
+
code = 99;
|
|
105
|
+
krnio_setnam(cmd);
|
|
106
|
+
if (krnio_open(15, DRIVE, 15)) {
|
|
107
|
+
int n = krnio_gets(15, reply, sizeof(reply));
|
|
108
|
+
if (n > 0 && reply[n - 1] == 13)
|
|
109
|
+
reply[n - 1] = 0;
|
|
110
|
+
if (n >= 2)
|
|
111
|
+
code = (reply[0] - '0') * 10 + (reply[1] - '0');
|
|
112
|
+
krnio_close(15);
|
|
113
|
+
}
|
|
114
|
+
printf("DRIVE: %s\n", reply);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// chk = ((chk ^ b) * 5 + 1) & 0xffff over n bytes
|
|
118
|
+
static unsigned fold(const char *p, int n)
|
|
119
|
+
{
|
|
120
|
+
unsigned c = 0;
|
|
121
|
+
for (int i = 0; i < n; i++)
|
|
122
|
+
c = (c ^ p[i]) * 5 + 1;
|
|
123
|
+
return c;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Write the live table as HISCORE,S,W. Returns true when the drive
|
|
127
|
+
// answered 00 after the close.
|
|
128
|
+
static bool save_table(void)
|
|
129
|
+
{
|
|
130
|
+
printf("WRITE HISCORE,S,W %d BYTES\n", (int)sizeof(Table));
|
|
131
|
+
krnio_setnam("HISCORE,S,W");
|
|
132
|
+
bool ok = krnio_open(2, DRIVE, 2);
|
|
133
|
+
printf("OPEN %d ST=", ok); put_hex2(krnio_status());
|
|
134
|
+
int n = krnio_write(2, (const char *)&table, sizeof(Table));
|
|
135
|
+
printf(" WRITE %d ST=", n); put_hex2(krnio_status());
|
|
136
|
+
krnio_close(2);
|
|
137
|
+
printf(" CLOSE ST="); put_hex2(krnio_status());
|
|
138
|
+
putchar('\n');
|
|
139
|
+
drive_reply("");
|
|
140
|
+
return code == 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Try to read HISCORE,S,R into back[]. Returns the byte count (0 when
|
|
144
|
+
// the file is missing or the device did not answer). This OPEN sends
|
|
145
|
+
// the name down the bus, so it is the one call that can see an absent
|
|
146
|
+
// drive: it then returns false with KRNIO_NODEVICE in the status.
|
|
147
|
+
static int load_table(void)
|
|
148
|
+
{
|
|
149
|
+
printf("READ HISCORE,S,R\n");
|
|
150
|
+
krnio_setnam("HISCORE,S,R");
|
|
151
|
+
bool ok = krnio_open(2, DRIVE, 2);
|
|
152
|
+
printf("OPEN %d ST=", ok); put_hex2(krnio_status());
|
|
153
|
+
if (!ok && (krnio_status() & KRNIO_NODEVICE)) {
|
|
154
|
+
// nothing answered: do not CHKIN, it hangs with no timeout on a
|
|
155
|
+
// device that does not answer, and do not ask for a reply
|
|
156
|
+
krnio_close(2);
|
|
157
|
+
printf("\nDRIVE: NO DEVICE\n");
|
|
158
|
+
code = 99;
|
|
159
|
+
saving = false;
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
int n = 0;
|
|
163
|
+
if (ok) {
|
|
164
|
+
n = krnio_read(2, back, sizeof(back));
|
|
165
|
+
printf(" READ %d ST=", n); put_hex2(krnio_pstatus[2]);
|
|
166
|
+
}
|
|
167
|
+
putchar('\n');
|
|
168
|
+
krnio_close(2);
|
|
169
|
+
drive_reply("");
|
|
170
|
+
return n;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Replace the file on disk: scratch it, then write. Writing HISCORE,S,W
|
|
174
|
+
// over an existing name is refused with 63, FILE EXISTS, and every byte
|
|
175
|
+
// written afterwards comes back with ST=$80, KRNIO_NODEVICE: the drive
|
|
176
|
+
// does not acknowledge bytes on a channel it never opened.
|
|
177
|
+
static bool rewrite_table(void)
|
|
178
|
+
{
|
|
179
|
+
printf("SCRATCH S0:HISCORE\n");
|
|
180
|
+
drive_reply("S0:HISCORE");
|
|
181
|
+
return save_table();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static void show_table(const char *label)
|
|
185
|
+
{
|
|
186
|
+
printf("%s", label);
|
|
187
|
+
for (char i = 0; i < ENTRIES; i++)
|
|
188
|
+
printf(" %s %u", table.entry[i].name, table.entry[i].score);
|
|
189
|
+
putchar('\n');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Insert a score in rank order, dropping the last entry.
|
|
193
|
+
static void enter_score(const char *name, unsigned score)
|
|
194
|
+
{
|
|
195
|
+
char i = ENTRIES;
|
|
196
|
+
while (i > 0 && table.entry[i - 1].score < score) {
|
|
197
|
+
if (i < ENTRIES)
|
|
198
|
+
table.entry[i] = table.entry[i - 1];
|
|
199
|
+
i--;
|
|
200
|
+
}
|
|
201
|
+
if (i < ENTRIES) {
|
|
202
|
+
strcpy(table.entry[i].name, name);
|
|
203
|
+
table.entry[i].score = score;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
int main(void)
|
|
208
|
+
{
|
|
209
|
+
printf("%cHIGH SCORE PERSIST (KERNALIO.H)\n", 147);
|
|
210
|
+
|
|
211
|
+
// 1. try to load; the named OPEN inside is also the device test
|
|
212
|
+
table = defaults;
|
|
213
|
+
saving = true;
|
|
214
|
+
int n = load_table();
|
|
215
|
+
const Table *got = (const Table *)back;
|
|
216
|
+
|
|
217
|
+
// 2. decide what state the save is in
|
|
218
|
+
if (code == 0 && n == sizeof(Table) &&
|
|
219
|
+
got->magic[0] == 'H' && got->magic[1] == 'S' &&
|
|
220
|
+
got->version == VERSION) {
|
|
221
|
+
table = *got;
|
|
222
|
+
show_table("LOADED:");
|
|
223
|
+
} else if (code == 0 && n > 0) {
|
|
224
|
+
// right name, wrong layout: reject it and start again
|
|
225
|
+
printf("OLD FORMAT %d BYTES V%d: RESET\n", n, got->version);
|
|
226
|
+
saving = rewrite_table();
|
|
227
|
+
show_table("DEFAULTS:");
|
|
228
|
+
} else if (code == 62) {
|
|
229
|
+
printf("FIRST RUN\n");
|
|
230
|
+
saving = save_table();
|
|
231
|
+
show_table("DEFAULTS:");
|
|
232
|
+
} else {
|
|
233
|
+
// 74 with no disk, 99 with no device, anything else unexpected
|
|
234
|
+
printf("SAVING OFF (%d)\n", code);
|
|
235
|
+
saving = false;
|
|
236
|
+
show_table("DEFAULTS:");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// 3. a new high score, then rewrite: scratch first, then write
|
|
240
|
+
enter_score("YOU", 4000);
|
|
241
|
+
show_table("NEW:");
|
|
242
|
+
if (saving)
|
|
243
|
+
saving = rewrite_table();
|
|
244
|
+
|
|
245
|
+
// 4. read back what is on the disk now and check it
|
|
246
|
+
if (saving) {
|
|
247
|
+
n = load_table();
|
|
248
|
+
got = (const Table *)back;
|
|
249
|
+
printf("BACK V%d:", got->version);
|
|
250
|
+
for (char i = 0; i < ENTRIES; i++)
|
|
251
|
+
printf(" %s %u", got->entry[i].name, got->entry[i].score);
|
|
252
|
+
putchar('\n');
|
|
253
|
+
} else {
|
|
254
|
+
printf("NOT SAVED\n");
|
|
255
|
+
memcpy(back, &table, sizeof(Table));
|
|
256
|
+
n = sizeof(Table);
|
|
257
|
+
}
|
|
258
|
+
unsigned chk = fold(back, n);
|
|
259
|
+
printf("CHK ");
|
|
260
|
+
put_hex2(chk >> 8);
|
|
261
|
+
put_hex2(chk & 0xff);
|
|
262
|
+
printf(chk == EXPECT_CHK ? " PASS\n" : " FAIL\n");
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Build
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
oscar64 -tm=c64 -O2 -o=high-score-persist.prg high-score-persist.c
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Produces `high-score-persist.prg`. `kernalio.h` carries
|
|
274
|
+
`#pragma compile("kernalio.c")`, so the wrapper source is compiled in
|
|
275
|
+
without a second file on the command line. The run needs a disk in
|
|
276
|
+
drive 8:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
c1541 -format "test,01" d64 test.d64
|
|
280
|
+
x64sc -default -warp +sound +autostart-delay-random -autostartprgmode 1 \
|
|
281
|
+
-limitcycles 24000000 -8 test.d64 \
|
|
282
|
+
-drive8wobbleamplitude 0 -drive8wobblefrequency 0 \
|
|
283
|
+
-exitscreenshot high-score-persist.png -autostart high-score-persist.prg
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Putting a finished game on a D64 that boots from `LOAD"*",8,1`, and what
|
|
287
|
+
its own score file does to that image, is
|
|
288
|
+
[release-disk](../../toolchains/release-disk.md).
|
|
289
|
+
|
|
290
|
+
## Expected output
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
HIGH SCORE PERSIST (KERNALIO.H)
|
|
294
|
+
READ HISCORE,S,R
|
|
295
|
+
OPEN 1 ST=00 READ 0 ST=42
|
|
296
|
+
DRIVE: 62, FILE NOT FOUND,00,00
|
|
297
|
+
FIRST RUN
|
|
298
|
+
WRITE HISCORE,S,W 21 BYTES
|
|
299
|
+
OPEN 1 ST=00 WRITE 21 ST=00 CLOSE ST=00
|
|
300
|
+
DRIVE: 00, OK,00,00
|
|
301
|
+
DEFAULTS: ABC 5000 DEF 2500 GHI 1000
|
|
302
|
+
NEW: ABC 5000 YOU 4000 DEF 2500
|
|
303
|
+
SCRATCH S0:HISCORE
|
|
304
|
+
DRIVE: 01, FILES SCRATCHED,01,00
|
|
305
|
+
WRITE HISCORE,S,W 21 BYTES
|
|
306
|
+
OPEN 1 ST=00 WRITE 21 ST=00 CLOSE ST=00
|
|
307
|
+
DRIVE: 00, OK,00,00
|
|
308
|
+
READ HISCORE,S,R
|
|
309
|
+
OPEN 1 ST=00 READ 21 ST=40
|
|
310
|
+
DRIVE: 00, OK,00,00
|
|
311
|
+
BACK V1: ABC 5000 YOU 4000 DEF 2500
|
|
312
|
+
CHK F1F6 PASS
|
|
313
|
+
|
|
314
|
+
READY.
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Light blue text on blue, the ordinary power-on screen. The text is the
|
|
318
|
+
same on PAL and NTSC. Screenshots from the VICE runs this page
|
|
319
|
+
describes: `screenshots/high-score-persist.png` (PAL) and
|
|
320
|
+
`screenshots/high-score-persist-ntsc.png` (NTSC), both from the pinned
|
|
321
|
+
command above with a disk formatted as `TEST,01` immediately before the
|
|
322
|
+
run. A second PAL run on another fresh disk gave a pixel-identical PNG.
|
|
323
|
+
`c1541 -list` of the disk afterwards shows one file, `"hiscore" seq`,
|
|
324
|
+
and 663 blocks free.
|
|
325
|
+
|
|
326
|
+
Read the lines in pairs. `ST=` is `krnio_status()`, the KERNAL's status
|
|
327
|
+
byte (READST, `$FFB7`); after the read it is `krnio_pstatus[2]`, the
|
|
328
|
+
value the wrapper kept for that logical file. `DRIVE:` is the text the
|
|
329
|
+
1541 put on its command channel.
|
|
330
|
+
|
|
331
|
+
- The first call is the OPEN for read, and it is the device test as
|
|
332
|
+
well: it sends the name `HISCORE,S,R` down the bus, so a bus with no
|
|
333
|
+
drive on it returns `OPEN 0 ST=80` (measured below). The 1541's
|
|
334
|
+
power-on banner, `73,CBM DOS V2.6 1541,00,00`, does not appear in
|
|
335
|
+
this run: the error the OPEN raises replaces it before the channel is
|
|
336
|
+
first read. A probe that reads the channel before any other command
|
|
337
|
+
gets the `73` line first (measured in the same VICE build).
|
|
338
|
+
- First run: the OPEN for read succeeds (`OPEN 1 ST=00`), the read
|
|
339
|
+
returns 0 bytes with ST `$42` (EOF and timeout bits) and the drive
|
|
340
|
+
says `62, FILE NOT FOUND`. The program takes that as "no save yet",
|
|
341
|
+
writes the defaults (21 bytes, ST `00` through open, write and close,
|
|
342
|
+
drive `00, OK`) and shows them.
|
|
343
|
+
- New score: `YOU 4000` is inserted in rank order and `GHI 1000` drops
|
|
344
|
+
off the end.
|
|
345
|
+
- Replace: `S0:HISCORE` on the command channel answers `01, FILES
|
|
346
|
+
SCRATCHED,01,00`, read from the same open channel. The rewrite then
|
|
347
|
+
opens cleanly. An earlier build of this listing wrote over the
|
|
348
|
+
existing name without the scratch: the drive answered `63, FILE
|
|
349
|
+
EXISTS,00,00`, `krnio_write` still returned 21 but ST was `$80` after
|
|
350
|
+
the write and the close, and nothing reached the disk. That `$80` is
|
|
351
|
+
the device-not-present bit (`KRNIO_NODEVICE`), not a timeout: the
|
|
352
|
+
drive did not acknowledge bytes on a channel it never opened.
|
|
353
|
+
Reading the
|
|
354
|
+
scratch reply after closing and reopening channel 15 gave `00, OK`
|
|
355
|
+
instead of the `01` line; the reply to a command lasts only while the
|
|
356
|
+
channel that sent it is open.
|
|
357
|
+
- Read-back: 21 bytes with ST `$40` (EOF), drive `00, OK`, and the
|
|
358
|
+
record decodes to the table that was written. `CHK F1F6` is the fold
|
|
359
|
+
`chk = ((chk ^ byte) * 5 + 1) & 0xFFFF` over those 21 bytes; Python
|
|
360
|
+
gives `0xF1F6` for the same bytes, so the line reads `PASS`.
|
|
361
|
+
|
|
362
|
+
### The other paths, run once each (not pinned)
|
|
363
|
+
|
|
364
|
+
**Second run, same disk, file present.** The same command run again on
|
|
365
|
+
the disk the pinned run left behind. The read returns 21 bytes with ST
|
|
366
|
+
`$40` and the drive says `00, OK`; the program prints `LOADED: ABC 5000
|
|
367
|
+
YOU 4000 DEF 2500`. The new score is entered again, so the table becomes
|
|
368
|
+
`ABC 5000 YOU 4000 YOU 4000` (a tie is placed below the entry already
|
|
369
|
+
there), the scratch answers `01, FILES SCRATCHED,01,00`, the rewrite and
|
|
370
|
+
read-back succeed, and the last line reads `CHK B91C FAIL`. That FAIL
|
|
371
|
+
is expected: `EXPECT_CHK` is the first-run table's value, and Python's
|
|
372
|
+
fold of the second-run table is `0xB91C`, so the disk holds exactly
|
|
373
|
+
what was written. The screen ends at row 15 with `READY.` on row 17.
|
|
374
|
+
|
|
375
|
+
**No disk attached.** The same command with no `-8` argument. VICE
|
|
376
|
+
`-default` still emulates a 1541 on device 8, so the drive answers: the
|
|
377
|
+
OPEN for read succeeds with ST `00`, the read returns 0 bytes with ST
|
|
378
|
+
`$42`, and the error channel says `74,DRIVE NOT READY,00,00`. The
|
|
379
|
+
program prints `SAVING OFF (74)`, shows the defaults, enters the new
|
|
380
|
+
score, prints `NOT SAVED`, and the checksum line reads `CHK F1F6 PASS`
|
|
381
|
+
because it is then folded over the in-memory table, which is the same
|
|
382
|
+
21 bytes. Nine lines of text on rows 0 to 8, `READY.` on row 10. This
|
|
383
|
+
measures a drive with no disk, not an absent drive.
|
|
384
|
+
|
|
385
|
+
**No device on the bus.** The same command with no `-8` and
|
|
386
|
+
`-drive8type 0` added, so that nothing is emulated on device 8. The
|
|
387
|
+
OPEN for read comes back as `OPEN 0 ST=80`: OPEN returned C=1,
|
|
388
|
+
and ST holds bit 7, `KRNIO_NODEVICE`, which the KERNAL sets when no
|
|
389
|
+
device pulls DATA low in answer to the LISTEN
|
|
390
|
+
(`../../hardware/kernal-routines-reference.md`, CHKOUT entry). The
|
|
391
|
+
program prints `DRIVE: NO DEVICE`, then `SAVING OFF (99)`, the defaults,
|
|
392
|
+
the new score, `NOT SAVED` and `CHK F1F6 PASS`: the same nine lines as
|
|
393
|
+
the no-disk case with the two drive lines changed, `READY.` on row 10.
|
|
394
|
+
The same screen comes from `+drive8truedrive` with no `-8` and the
|
|
395
|
+
drive type left at its default.
|
|
396
|
+
|
|
397
|
+
Two things about that path are worth knowing, both measured in this
|
|
398
|
+
VICE build with `-drive8type 0`. First, an OPEN of channel 15 with an
|
|
399
|
+
empty name cannot detect an absent drive: the KERNAL sends nothing on
|
|
400
|
+
the bus when the filename length is zero, so that OPEN returned 1 with
|
|
401
|
+
ST `00` with no drive present, while OPEN of `I0` on channel 15 and of
|
|
402
|
+
`HISCORE,S,R` on channel 2 both returned 0 with ST `$80`. Second, the
|
|
403
|
+
first CHKIN on a channel whose device does not answer hangs with no
|
|
404
|
+
timeout (`../../hardware/kernal-routines-reference.md`, CHKIN entry), and
|
|
405
|
+
`krnio_gets` starts with CHKIN. An earlier build of this listing read
|
|
406
|
+
the banner with an empty-name OPEN before anything else and then hung
|
|
407
|
+
inside `krnio_gets` with the title line alone on screen after 24,000,000
|
|
408
|
+
cycles. That is why `drive_reply` is only ever called after a named OPEN
|
|
409
|
+
has succeeded, and why the named OPEN of the save file comes first.
|
|
410
|
+
|
|
411
|
+
**Old format on the disk.** A 15-byte `HISCORE` with version byte 0 was
|
|
412
|
+
written to a fresh disk with `c1541 -write old.bin hiscore,s`. The read
|
|
413
|
+
returned 15 bytes with ST `$40` and drive `00, OK`; the program printed
|
|
414
|
+
`OLD FORMAT 15 BYTES V0: RESET`, scratched (`01, FILES SCRATCHED,01,00`),
|
|
415
|
+
wrote the defaults, then entered the new score, scratched and wrote
|
|
416
|
+
again, and read back `BACK V1: ABC 5000 YOU 4000 DEF 2500` with
|
|
417
|
+
`CHK F1F6 PASS`.
|
|
418
|
+
|
|
419
|
+
## Why this works
|
|
420
|
+
|
|
421
|
+
The policy turns on the first two digits of the drive's reply, not on
|
|
422
|
+
the KERNAL's status byte alone. After a failed OPEN for read the
|
|
423
|
+
KERNAL only knows that the read timed out (ST `$42`); it is the error
|
|
424
|
+
channel that separates `62` (no file: write the defaults) from `74` (no
|
|
425
|
+
disk: leave the disk alone) from `00` (a file came back: check it).
|
|
426
|
+
The one case the status byte does settle on its own is an absent drive:
|
|
427
|
+
OPEN of a named file returns false with `KRNIO_NODEVICE` set, and the
|
|
428
|
+
program never touches the bus again. `drive_reply` opens logical file
|
|
429
|
+
15 on secondary 15 with the string it is given, an empty name to read
|
|
430
|
+
the status or a DOS command such as `S0:HISCORE`, reads one line with
|
|
431
|
+
`krnio_gets`, strips the CR and closes; `code` keeps the two digits so
|
|
432
|
+
the caller can branch on them. The reply is read on the same open
|
|
433
|
+
channel in both uses because the reply to a command is gone once
|
|
434
|
+
channel 15 is closed.
|
|
435
|
+
|
|
436
|
+
A 21-byte record with a magic pair, a version byte and three fixed
|
|
437
|
+
six-byte entries lets `load_table` accept or reject a file with three
|
|
438
|
+
comparisons: the byte count, the magic and the version. A record that
|
|
439
|
+
grows in a later release changes the version byte, and the old file is
|
|
440
|
+
then rejected and rewritten rather than read as garbage. Oscar64 packs
|
|
441
|
+
the struct with no padding, so `sizeof(Table)` is the file size on disk
|
|
442
|
+
and the record can be written and read as raw bytes.
|
|
443
|
+
|
|
444
|
+
Replacing the file is scratch, then write. OPEN of `HISCORE,S,W` over an
|
|
445
|
+
existing name is refused by the DOS with `63, FILE EXISTS` and every
|
|
446
|
+
byte written afterwards comes back with ST `$80`, the device-not-present
|
|
447
|
+
bit (`KRNIO_NODEVICE`): the drive does not acknowledge bytes on a
|
|
448
|
+
channel it never opened. The earlier build of this listing measured
|
|
449
|
+
that, and the disk was unchanged afterwards. `@0:HISCORE,S,W` would ask
|
|
450
|
+
the DOS to replace in place; `../../techniques/file-io.md` says why this
|
|
451
|
+
KB does not lean on that command. A scratch of a name that is not there
|
|
452
|
+
costs one command-channel round trip and does no harm: `S0:NOSUCH` on a
|
|
453
|
+
disk without that file answers `01, FILES SCRATCHED,00,00`, count `00`,
|
|
454
|
+
and the directory is unchanged (measured in VICE). Every call here is a
|
|
455
|
+
KERNAL call, so the ROM must be banked in from the first OPEN to the
|
|
456
|
+
last CLOSE; the write of a 21-byte file and its close must also be
|
|
457
|
+
allowed to finish before the machine is reset or the emulator exits, or
|
|
458
|
+
the directory holds a splat file (`../../pitfalls/kernal-and-io.md`,
|
|
459
|
+
`krnio_save_leaves_splat_file`). The bare write-and-read sequence
|
|
460
|
+
without the policy is `save-load-seq-file.md` in this directory and
|
|
461
|
+
`../kickassembler/file-io-roundtrip.md` in assembly.
|
|
462
|
+
|
|
463
|
+
## A raster IRQ during file I/O
|
|
464
|
+
|
|
465
|
+
The listing above runs with the KERNAL's own IRQ only. A game that
|
|
466
|
+
saves from a screen with a `rasterirq.h` split on it needs to know what
|
|
467
|
+
the file calls do to that split. Measured on 2026-09-22 in VICE x64sc
|
|
468
|
+
3.10, true-drive 1541, fresh `TEST,01` disk, PAL and `-model ntsc`, with
|
|
469
|
+
the program quoted at the end of this section: a border split at rows
|
|
470
|
+
100 (white) and 200 (light blue), a `rirq_call` handler on the row-100
|
|
471
|
+
slot that counts its entries and keeps the lowest and highest `$D012` it
|
|
472
|
+
saw on entry, and a 2,048-byte sequential file written and read back
|
|
473
|
+
with a 16-bit fold checked against the buffer that went out. Time is
|
|
474
|
+
CIA2 timers A and B cascaded into one 32-bit cycle counter, which the
|
|
475
|
+
KERNAL never touches; frames are those cycles over 19,656 or 17,095,
|
|
476
|
+
arithmetic.
|
|
477
|
+
|
|
478
|
+
| Build | Model | Write | Handler entries during it | `$D012` at entry | Read | Handler entries during it | `$D012` at entry |
|
|
479
|
+
|---|---|---|---|---|---|---|---|
|
|
480
|
+
| armed throughout | PAL | 9,359,321 cycles, 476 frames | 145 | 101 to 240 | 5,656,966 cycles, 288 frames | 226 | 101 to 234 |
|
|
481
|
+
| armed throughout | NTSC | 9,702,621 cycles, 568 frames | 169 | 101 to 241 | 5,991,068 cycles, 350 frames | 268 | 101 to 242 |
|
|
482
|
+
| `rirq_stop()` / `rirq_start()` around each call | PAL | 9,359,424 cycles, 476 frames | 144 | 101 to 238 | 5,659,833 cycles, 288 frames | 226 | 101 to 233 |
|
|
483
|
+
| `rirq_stop()` / `rirq_start()` around each call | NTSC | 9,702,713 cycles, 568 frames | 168 | 101 to 240 | 5,983,652 cycles, 350 frames | 270 | 101 to 247 |
|
|
484
|
+
| `$D01A = 0` around each call | PAL | 9,158,718 cycles, 466 frames | 0 | none | 5,553,710 cycles, 283 frames | 0 | none |
|
|
485
|
+
| `$D01A = 0` around each call | NTSC | 9,498,969 cycles, 556 frames | 0 | none | 5,765,998 cycles, 337 frames | 0 | none |
|
|
486
|
+
|
|
487
|
+
Every row: `OPEN=1`, 2,048 bytes written with ST `00` after the close,
|
|
488
|
+
2,048 bytes read with ST `40`, `CHK F000/F000 PASS`, `DRIVE: 00, OK,00,00`.
|
|
489
|
+
Idle before and after, the handler entered on line 101 in every frame
|
|
490
|
+
(50 of 50 before; 48 or 49 of the 50 `rirq_wait()` calls after, the
|
|
491
|
+
first call returning early on the count already in flight). The file is
|
|
492
|
+
never at risk; the picture and the frame count are.
|
|
493
|
+
|
|
494
|
+
Read the armed rows against the idle line. In 476 PAL frames of writing
|
|
495
|
+
the row-100 handler ran 145 times, and when it ran it entered anywhere
|
|
496
|
+
from line 101 to line 240. The KERNAL's serial primitives run every
|
|
497
|
+
byte with the I flag set and hold it while they wait for the drive, with
|
|
498
|
+
no timeout on those waits (`$ED50` to `$ED5D`, `$EDD6`, `$EE1B`; ROM
|
|
499
|
+
bytes, rung 1). Under the monitor one such wait, the TALK that follows a
|
|
500
|
+
directory lookup, held the flag for 1,512,351 cycles. A raster match
|
|
501
|
+
inside the window is delivered at the `CLI`, late; a second match in the
|
|
502
|
+
same window is lost. `rirq_stop()` is `sei` alone (`rasterirq.c`), and
|
|
503
|
+
the first primitive's `CLI` cancels it, which is why its rows repeat the
|
|
504
|
+
armed rows to within a frame. Clearing `$D01A` is the stop that holds:
|
|
505
|
+
no entries, and the transfer two per cent shorter.
|
|
506
|
+
|
|
507
|
+
The exit screenshot at 8,000,000 cycles lands inside the write. Armed
|
|
508
|
+
on PAL, the left border is white on lines 240 to 242 only: the row-100
|
|
509
|
+
slot was delivered around line 240 and the row-200 slot ran straight
|
|
510
|
+
after it. Armed on NTSC, white on lines 104 to 201 against 101 to 200
|
|
511
|
+
idle. With `$D01A` cleared, one colour for the whole frame, white on PAL
|
|
512
|
+
and light blue on NTSC, whichever the border held when the register
|
|
513
|
+
was cleared. In every split the right border changes one row above the
|
|
514
|
+
left, the store landing mid-line. These pictures are not pinned; the
|
|
515
|
+
recipe's own run is.
|
|
516
|
+
|
|
517
|
+
Recommendation: save and load on a static screen. Set the border and
|
|
518
|
+
the screen to what you want held, clear `$D01A`, make the calls, then
|
|
519
|
+
write 1 to `$D019` and set `$D01A` again; `rasterirq.h` resumes on its
|
|
520
|
+
next row. Do not use `rirq_stop()` for this. If the IRQ must stay armed,
|
|
521
|
+
do not count frames or drive music from it across the calls; the
|
|
522
|
+
pitfall is `../../pitfalls/kernal-and-io.md`,
|
|
523
|
+
`raster_irq_during_serial_io`. The transfer rate, about 216 bytes per
|
|
524
|
+
second writing and 355 reading on either model, is the KERNAL's.
|
|
525
|
+
|
|
526
|
+
The test program, built three ways with `-dMODE=0`, `1` and `2`. It is
|
|
527
|
+
not a recipe listing; the numbers above are its output, read from the
|
|
528
|
+
exit screenshots of runs at 40,000,000 cycles:
|
|
529
|
+
|
|
530
|
+
```text
|
|
531
|
+
// iotest.c -- a rirq border split kept armed while 2 KB goes to a
|
|
532
|
+
// SEQ file on drive 8 and comes back. Build with -dMODE=0 (armed
|
|
533
|
+
// throughout), -dMODE=1 (rirq_stop()/rirq_start() around each file
|
|
534
|
+
// call) or -dMODE=2 ($D01A cleared around each file call).
|
|
535
|
+
// Prints, per phase: KERNAL status, CIA2 cycles, frames from that,
|
|
536
|
+
// raster IRQs counted by the handler, and the min/max $D012 seen at
|
|
537
|
+
// handler entry for the split slot (row SPLIT_ROW).
|
|
538
|
+
#include <stdio.h>
|
|
539
|
+
#include <string.h>
|
|
540
|
+
#include <c64/vic.h>
|
|
541
|
+
#include <c64/cia.h>
|
|
542
|
+
#include <c64/rasterirq.h>
|
|
543
|
+
#include <c64/kernalio.h>
|
|
544
|
+
|
|
545
|
+
#ifndef MODE
|
|
546
|
+
#define MODE 0
|
|
547
|
+
#endif
|
|
548
|
+
#define DRIVE 8
|
|
549
|
+
#define SIZE 2048
|
|
550
|
+
#define SPLIT_ROW 100
|
|
551
|
+
#define RESTORE_ROW 200
|
|
552
|
+
|
|
553
|
+
static RIRQCode split, restore;
|
|
554
|
+
static char buf[SIZE];
|
|
555
|
+
static char back[SIZE];
|
|
556
|
+
static char reply[40];
|
|
557
|
+
|
|
558
|
+
static volatile unsigned irqs; // split-slot handler entries
|
|
559
|
+
static volatile char rmin, rmax; // $D012 at handler entry
|
|
560
|
+
|
|
561
|
+
__interrupt void on_split(void)
|
|
562
|
+
{
|
|
563
|
+
char r = vic.raster;
|
|
564
|
+
if (r < rmin) rmin = r;
|
|
565
|
+
if (r > rmax) rmax = r;
|
|
566
|
+
irqs++;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
static void stats_reset(void)
|
|
570
|
+
{
|
|
571
|
+
irqs = 0; rmin = 255; rmax = 0;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// CIA2 timer A counts cycles, timer B counts A underflows: a 32-bit
|
|
575
|
+
// down counter the KERNAL never touches (its serial timeout is CIA1 B).
|
|
576
|
+
static void clock_init(void)
|
|
577
|
+
{
|
|
578
|
+
cia2.cra = 0x00; cia2.crb = 0x00;
|
|
579
|
+
cia2.ta = 0xffff; cia2.tb = 0xffff;
|
|
580
|
+
cia2.crb = 0x51; // count TA underflows, force load, start
|
|
581
|
+
cia2.cra = 0x11; // cycles, force load, start
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
static unsigned long clock_now(void)
|
|
585
|
+
{
|
|
586
|
+
unsigned hi, lo, hi2;
|
|
587
|
+
do {
|
|
588
|
+
hi = cia2.tb; lo = cia2.ta; hi2 = cia2.tb;
|
|
589
|
+
} while (hi != hi2);
|
|
590
|
+
return 0xffffffffUL - (((unsigned long)hi << 16) | lo);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
static unsigned fold(const char *p, int n)
|
|
594
|
+
{
|
|
595
|
+
unsigned c = 0;
|
|
596
|
+
for (int i = 0; i < n; i++)
|
|
597
|
+
c = (c ^ p[i]) * 5 + 1;
|
|
598
|
+
return c;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
static unsigned long period; // cycles per frame for this model
|
|
602
|
+
|
|
603
|
+
static void report(const char *tag, char st, unsigned long cyc)
|
|
604
|
+
{
|
|
605
|
+
printf("%s ST=%02X CYC=%lu F=%lu IRQ=%u R=%u..%u\n",
|
|
606
|
+
tag, st, cyc, cyc / period, irqs, rmin, rmax);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
static void io_begin(void)
|
|
610
|
+
{
|
|
611
|
+
#if MODE == 1
|
|
612
|
+
rirq_stop();
|
|
613
|
+
#elif MODE == 2
|
|
614
|
+
vic.intr_enable = 0;
|
|
615
|
+
#endif
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
static void io_end(void)
|
|
619
|
+
{
|
|
620
|
+
#if MODE == 1
|
|
621
|
+
rirq_start();
|
|
622
|
+
#elif MODE == 2
|
|
623
|
+
vic.intr_ctrl = 1;
|
|
624
|
+
vic.intr_enable = 1;
|
|
625
|
+
#endif
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
static void drive_reply(void)
|
|
629
|
+
{
|
|
630
|
+
reply[0] = 0;
|
|
631
|
+
krnio_setnam("");
|
|
632
|
+
io_begin();
|
|
633
|
+
if (krnio_open(15, DRIVE, 15)) {
|
|
634
|
+
int n = krnio_gets(15, reply, sizeof(reply));
|
|
635
|
+
if (n > 0 && reply[n - 1] == 13) reply[n - 1] = 0;
|
|
636
|
+
krnio_close(15);
|
|
637
|
+
}
|
|
638
|
+
io_end();
|
|
639
|
+
printf("DRIVE: %s\n", reply);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
int main(void)
|
|
643
|
+
{
|
|
644
|
+
printf("%cIOTEST MODE %d\n", 147, MODE);
|
|
645
|
+
|
|
646
|
+
// model: the highest raster line seen in one frame
|
|
647
|
+
char top = 0;
|
|
648
|
+
for (unsigned i = 0; i < 20000; i++) {
|
|
649
|
+
char r = vic.raster;
|
|
650
|
+
if ((vic.ctrl1 & 0x80) && r > top) top = r;
|
|
651
|
+
}
|
|
652
|
+
bool pal = top >= 0x37; // 0x137 = 311 on PAL; NTSC tops at 0x106
|
|
653
|
+
period = pal ? 19656UL : 17095UL;
|
|
654
|
+
printf("%s\n", pal ? "PAL" : "NTSC");
|
|
655
|
+
|
|
656
|
+
for (int i = 0; i < SIZE; i++) buf[i] = (char)(i * 7 + 3);
|
|
657
|
+
unsigned want = fold(buf, SIZE);
|
|
658
|
+
|
|
659
|
+
rirq_init(true);
|
|
660
|
+
rirq_build(&split, 2);
|
|
661
|
+
rirq_write(&split, 0, &vic.color_border, VCOL_WHITE);
|
|
662
|
+
rirq_call(&split, 1, on_split);
|
|
663
|
+
rirq_set(0, SPLIT_ROW, &split);
|
|
664
|
+
rirq_build(&restore, 1);
|
|
665
|
+
rirq_write(&restore, 0, &vic.color_border, VCOL_LT_BLUE);
|
|
666
|
+
rirq_set(1, RESTORE_ROW, &restore);
|
|
667
|
+
rirq_sort();
|
|
668
|
+
rirq_start();
|
|
669
|
+
clock_init();
|
|
670
|
+
|
|
671
|
+
// idle baseline: 50 frames of the split with the bus quiet
|
|
672
|
+
stats_reset();
|
|
673
|
+
unsigned long t0 = clock_now();
|
|
674
|
+
for (char i = 0; i < 50; i++) rirq_wait();
|
|
675
|
+
report("IDLE", 0, clock_now() - t0);
|
|
676
|
+
|
|
677
|
+
// write
|
|
678
|
+
stats_reset();
|
|
679
|
+
krnio_setnam("IOTEST,S,W");
|
|
680
|
+
t0 = clock_now();
|
|
681
|
+
io_begin();
|
|
682
|
+
bool ok = krnio_open(2, DRIVE, 2);
|
|
683
|
+
int n = ok ? krnio_write(2, buf, SIZE) : 0;
|
|
684
|
+
krnio_close(2);
|
|
685
|
+
char st = krnio_status();
|
|
686
|
+
io_end();
|
|
687
|
+
report("WRITE", st, clock_now() - t0);
|
|
688
|
+
printf(" OPEN=%d N=%d\n", ok, n);
|
|
689
|
+
|
|
690
|
+
// read back
|
|
691
|
+
stats_reset();
|
|
692
|
+
krnio_setnam("IOTEST,S,R");
|
|
693
|
+
t0 = clock_now();
|
|
694
|
+
io_begin();
|
|
695
|
+
ok = krnio_open(2, DRIVE, 2);
|
|
696
|
+
n = ok ? krnio_read(2, back, SIZE) : 0;
|
|
697
|
+
st = krnio_pstatus[2];
|
|
698
|
+
krnio_close(2);
|
|
699
|
+
io_end();
|
|
700
|
+
report("READ", st, clock_now() - t0);
|
|
701
|
+
unsigned got = fold(back, n);
|
|
702
|
+
printf(" OPEN=%d N=%d CHK=%04X/%04X %s\n", ok, n, got, want,
|
|
703
|
+
(n == SIZE && got == want) ? "PASS" : "FAIL");
|
|
704
|
+
|
|
705
|
+
drive_reply();
|
|
706
|
+
|
|
707
|
+
// idle again: does the split come back the same
|
|
708
|
+
stats_reset();
|
|
709
|
+
t0 = clock_now();
|
|
710
|
+
for (char i = 0; i < 50; i++) rirq_wait();
|
|
711
|
+
report("AFTER", 0, clock_now() - t0);
|
|
712
|
+
printf("DONE\n");
|
|
713
|
+
for (;;) ;
|
|
714
|
+
return 0;
|
|
715
|
+
}
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
One defect in it, left as run: the model check at the top read `PAL` on
|
|
719
|
+
NTSC in the `MODE=1` and `MODE=2` builds, so their printed `F=` values
|
|
720
|
+
divided by 19,656. The frames in the table were recomputed from the
|
|
721
|
+
printed cycle counts, which do not depend on it. The `MODE=0` NTSC build
|
|
722
|
+
detected NTSC and its printed frames agree with the table.
|
|
723
|
+
|
|
724
|
+
## A start-up hang seen in VICE, located but not explained
|
|
725
|
+
|
|
726
|
+
A game built from this recipe, whose first act after its own set-up was
|
|
727
|
+
`krnio_open` of `HISCORE,S,R` on a fresh disk, hung in that OPEN's
|
|
728
|
+
read-back on PAL every time and not on NTSC (VICE x64sc 3.10,
|
|
729
|
+
`-autostart` with `-8`, true drive, `+autostart-delay-random`; three
|
|
730
|
+
plain PAL runs hung, one plain NTSC run and one under the monitor did
|
|
731
|
+
not, and the game's own author had seen the same split before the
|
|
732
|
+
delay went in). Fifty `vic_waitFrame()` calls
|
|
733
|
+
before the OPEN, or an unrelated change of code size, removed it. What
|
|
734
|
+
follows is what the remote monitor showed on 2026-09-22, rung 1. The
|
|
735
|
+
figures come from three monitor sessions with different breakpoint
|
|
736
|
+
sets; they agree to the cycle at OPEN and drift apart by about 70,000
|
|
737
|
+
cycles after the first drive-side stop, so read each bullet as its own
|
|
738
|
+
run:
|
|
739
|
+
|
|
740
|
+
- The drive was not resetting. Its idle loop at `$EBE7` was first
|
|
741
|
+
reached 1,002,456 drive cycles after reset; the program's OPEN
|
|
742
|
+
entered `$F34A` at C64 cycle 3,173,695, about two seconds later.
|
|
743
|
+
- OPEN itself completed. LISTEN, the eleven name bytes and UNLISTEN
|
|
744
|
+
each went out in about 1,150 cycles. The TALK byte for the read
|
|
745
|
+
entered `$ED40` at 3,196,393 and left through `$EDAB` at 4,708,744:
|
|
746
|
+
the drive served ATN (`$E85B`) only when its directory search had
|
|
747
|
+
finished, and the C64 stayed inside `$ED40`'s `SEI` bracket for those
|
|
748
|
+
1,512,351 cycles. By the ROM flow the wait is the DATA loop at
|
|
749
|
+
`$ED5A`, not stopped on here. TKSA (`$62`) followed at 4,709,842 to
|
|
750
|
+
4,710,959.
|
|
751
|
+
- The spin is `$EDD6`, the loop after TKSA that waits for the drive to
|
|
752
|
+
pull CLK low and become the talker. It has no timeout. `$DD00` read
|
|
753
|
+
`$67` on every pass: DATA held low by the C64, CLK released by both
|
|
754
|
+
sides. The drive's port `$1800` read `$01` (DATA OUT set, CLK OUT
|
|
755
|
+
clear), its secondary-address cell `$84` held `$62`, its ATN-pending
|
|
756
|
+
flag `$7C` was 0. The drive had taken TALK and TKSA and stayed a
|
|
757
|
+
listener.
|
|
758
|
+
- Reading the drive CPU's registers from the monitor at each C64 stop
|
|
759
|
+
made the same run pass: the drive went through `$E8E5`, `$E8F4` and
|
|
760
|
+
`$E909`, the C64 reached ACPTR at `$EE13`, and the program went on
|
|
761
|
+
to its next OPEN. Memory dumps alone did not change the outcome. Two
|
|
762
|
+
runs each way.
|
|
763
|
+
|
|
764
|
+
What was measured is consistent with a race at the TALK turnaround
|
|
765
|
+
between the C64 releasing ATN and CLK and the drive sampling them. Why
|
|
766
|
+
the drive misses the release, and whether a real drive can, is not
|
|
767
|
+
measured here: the drive's state in the hanging case could only be read
|
|
768
|
+
by an act that changed it. What a program can do is what the
|
|
769
|
+
game did: give the bus a moment before the first OPEN, and check the
|
|
770
|
+
status and the error channel after it rather than assuming the read
|
|
771
|
+
returns. A wait of fifty frames was enough in every run tried; the
|
|
772
|
+
smallest wait that suffices was not measured.
|