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,3184 @@
|
|
|
1
|
+
# C64 Memory Map
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Commodore 64 has a flat 16-bit address space — exactly 65,536 bytes from
|
|
6
|
+
$0000 to $FFFF — but it ships with far more than 64 KB of physical storage.
|
|
7
|
+
Inside the machine there are 64 KB of dynamic RAM, 8 KB of BASIC ROM, 8 KB
|
|
8
|
+
of KERNAL ROM, 4 KB of character generator ROM, the 47-register VIC-II,
|
|
9
|
+
the 29-register SID, two CIA chips, and 1 KB of nibble-wide Color RAM. All
|
|
10
|
+
of those pieces have to share the single address bus the 6510 sees. They do
|
|
11
|
+
not coexist in parallel — they are *banked* in and out of view by a tiny
|
|
12
|
+
configuration latch built into the CPU itself.
|
|
13
|
+
|
|
14
|
+
The 6510 has six on-chip I/O pins that exit the chip alongside the address
|
|
15
|
+
and data buses. The lowest three of those pins (P0, P1, P2) drive the
|
|
16
|
+
PLA chip's bank-select inputs. Software controls them by writing the
|
|
17
|
+
data-direction register at $0000 (DDR) and the data register at $0001.
|
|
18
|
+
With three bits there are eight possible patterns; the PLA collapses them
|
|
19
|
+
into seven distinct memory layouts that swap chunks of RAM, ROM, and I/O
|
|
20
|
+
into the address space. Every C64 program — every game, every demo, every
|
|
21
|
+
copy-protection scheme — ultimately reduces to choosing one of those
|
|
22
|
+
seven configurations and writing to whatever happens to be visible.
|
|
23
|
+
|
|
24
|
+
This document maps the entire $0000-$FFFF address space, explains how
|
|
25
|
+
banking works, lists every fixed-purpose region of zero page, the stack
|
|
26
|
+
page, KERNAL workspace, ROM ranges, and the I/O area. It is the primary
|
|
27
|
+
reference for any code that needs to know "is this address RAM or ROM
|
|
28
|
+
right now?" or "what does the KERNAL clobber if I let it run?"
|
|
29
|
+
|
|
30
|
+
Memory addresses in this doc use the standard Commodore convention:
|
|
31
|
+
hexadecimal with a `$` prefix, four digits, uppercase. The dollar sign is
|
|
32
|
+
syntactically meaningful in 6502 assemblers and is the recognized
|
|
33
|
+
canonical form across the entire C64 documentation corpus. Decimal
|
|
34
|
+
equivalents are given where useful.
|
|
35
|
+
|
|
36
|
+
### The 64KB address space at a glance
|
|
37
|
+
|
|
38
|
+
| Range | Contents (default after reset) |
|
|
39
|
+
|---------------|----------------------------------------------|
|
|
40
|
+
| $0000-$0001 | 6510 processor port (DDR + data) |
|
|
41
|
+
| $0002-$00FF | Zero page (BASIC + KERNAL workspace + free) |
|
|
42
|
+
| $0100-$01FF | CPU stack |
|
|
43
|
+
| $0200-$02FF | KERNAL input buffer + workspace |
|
|
44
|
+
| $0300-$03FF | KERNAL vectors + workspace |
|
|
45
|
+
| $0400-$07E7 | Default screen RAM (40 × 25 = 1000 bytes) |
|
|
46
|
+
| $07E8-$07F7 | Unused (tail of the screen page) |
|
|
47
|
+
| $07F8-$07FF | Default sprite pointers (8 bytes) |
|
|
48
|
+
| $0800-$9FFF | BASIC program + variables / general user RAM |
|
|
49
|
+
| $A000-$BFFF | BASIC ROM (or RAM under it) |
|
|
50
|
+
| $C000-$CFFF | Free RAM (never banked, always present) |
|
|
51
|
+
| $D000-$D3FF | VIC-II registers (or character ROM, or RAM) |
|
|
52
|
+
| $D400-$D7FF | SID registers (or character ROM, or RAM) |
|
|
53
|
+
| $D800-$DBFF | Color RAM (4 bits wide; or character ROM) |
|
|
54
|
+
| $DC00-$DCFF | CIA #1 (or character ROM, or RAM) |
|
|
55
|
+
| $DD00-$DDFF | CIA #2 (or character ROM, or RAM) |
|
|
56
|
+
| $DE00-$DEFF | I/O expansion area 1 (cartridge) |
|
|
57
|
+
| $DF00-$DFFF | I/O expansion area 2 (cartridge) |
|
|
58
|
+
| $E000-$FFFF | KERNAL ROM (or RAM under it) |
|
|
59
|
+
|
|
60
|
+
### Hardware backing for each region
|
|
61
|
+
|
|
62
|
+
Address space is the CPU's view; *physical storage* is what the bytes
|
|
63
|
+
actually live in. The C64 has the following physical sources of bytes
|
|
64
|
+
visible to the CPU:
|
|
65
|
+
|
|
66
|
+
- 64 KB DRAM (eight 4164 chips), addressing the full $0000-$FFFF
|
|
67
|
+
- 8 KB KERNAL ROM, mapped at $E000-$FFFF when banked in
|
|
68
|
+
- 8 KB BASIC ROM, mapped at $A000-$BFFF when banked in
|
|
69
|
+
- 4 KB character ROM, mapped at $D000-$DFFF when banked in (charrom mode)
|
|
70
|
+
- 1 KB Color RAM (a separate 4-bit static RAM at $D800-$DBFF)
|
|
71
|
+
- VIC-II registers, mapped at $D000-$D02F (64-byte window, shadow-repeats
|
|
72
|
+
through $D03F and the whole way to $D3FF as 64-byte mirrors)
|
|
73
|
+
- SID registers, mapped at $D400-$D41C (29 bytes; shadow-repeats every
|
|
74
|
+
32 bytes through $D7FF)
|
|
75
|
+
- CIA #1 at $DC00-$DC0F (16 bytes; shadow-repeats every 16 bytes through $DCFF)
|
|
76
|
+
- CIA #2 at $DD00-$DD0F (16 bytes; shadow-repeats every 16 bytes through $DDFF)
|
|
77
|
+
- Cartridge ROMs and expansion-port I/O at $DE00-$DFFF and $8000-$9FFF
|
|
78
|
+
and $A000-$BFFF (depending on cartridge type — GAME and EXROM lines)
|
|
79
|
+
|
|
80
|
+
The 64 KB of DRAM is always physically present at every address. When a
|
|
81
|
+
ROM is "banked in," the PLA disables the RAM's CAS line for reads only in
|
|
82
|
+
that range — writes still go to RAM. This is why you can poke a value into
|
|
83
|
+
$E000 even though KERNAL ROM is mapped there: the byte lands in the RAM
|
|
84
|
+
underneath and reveals itself if you bank the ROM out. This dual-write
|
|
85
|
+
behavior is critical for relocating screens, swapping in custom fonts,
|
|
86
|
+
and using $E000-$FFFF as 8 KB of additional RAM by banking KERNAL out.
|
|
87
|
+
|
|
88
|
+
### Reset state
|
|
89
|
+
|
|
90
|
+
When the CPU comes out of reset, the KERNAL's IOINIT ($FDA3; called from
|
|
91
|
+
RESET at $FCF2, and reachable through the jump table at $FF84) puts the
|
|
92
|
+
6510 processor port into a known state: it writes $E7 to the data
|
|
93
|
+
register at $0001 first, then $2F (00101111, bits 0-3 + 5 outputs; bits 4
|
|
94
|
+
and 6 inputs; bit 7 unused on a stock C64) to the DDR at $0000
|
|
95
|
+
(`LDA #$E7 / STA $01 / LDA #$2F / STA $00` at $FDD5). With that DDR and no
|
|
96
|
+
tape button pressed, $01 reads back as $37 (00110111) once the
|
|
97
|
+
unconnected bits 6/7 have decayed to 0, and the KERNAL's default IRQ
|
|
98
|
+
service then writes the read-back value ORed with $20 (motor off) back
|
|
99
|
+
into $01 on every tick ($EA6B-$EA79, the datasette motor interlock), so a
|
|
100
|
+
running C64 holds $37 in the latch as well. An earlier version of this
|
|
101
|
+
section said the data register was "set to $37"; that is the settled
|
|
102
|
+
read-back value, not what IOINIT writes (measured in VICE x64sc: latch
|
|
103
|
+
$E7 immediately after `JSR $FF84`, $F7 a few frames after IRQs start, $37
|
|
104
|
+
by the time BASIC is running). Bits 2-0 = 111 mean: BASIC
|
|
105
|
+
ROM in, KERNAL ROM in, I/O in (the default user layout).
|
|
106
|
+
|
|
107
|
+
The KERNAL cold start ($FCE2, via the $FFFC vector) runs IOINIT, RAMTAS,
|
|
108
|
+
RESTOR and CINT in that order. RAMTAS ($FF87 → $FD50) clears $0002-$0101
|
|
109
|
+
and $0200-$03FF — the rest of the stack page, $0102-$01FF, is not touched
|
|
110
|
+
— sets the tape-buffer pointer $B2/$B3 to $033C, finds the top of memory
|
|
111
|
+
by walking pages from $0400 (MEMTOP = $A000 with BASIC ROM in), and sets
|
|
112
|
+
MEMBOT to $0800 ($0282) and the screen page $0288 to $04. It does not
|
|
113
|
+
clear the screen and it does not install any vector: its page-3 clear
|
|
114
|
+
leaves $0314/$0315 at $0000. RESTOR ($FF8A → $FD15) then copies the
|
|
115
|
+
16-vector table at $FD30 into $0314-$0333, which is what puts $EA31 in
|
|
116
|
+
$0314/$0315, and CINT ($FF81 → $FF5B → $E518) clears the screen at
|
|
117
|
+
$0400-$07E7 and initialises the VIC-II. An earlier version of this page
|
|
118
|
+
credited all of this to RAMTAS; the split is from the ROM bytes and a
|
|
119
|
+
VICE x64sc run calling $FF87 alone. By the time BASIC's
|
|
120
|
+
"READY." prompt prints, the system is in mode 31 (the default seven-bank
|
|
121
|
+
configuration) with all ROMs visible.
|
|
122
|
+
|
|
123
|
+
### Banks vs banking — terminology
|
|
124
|
+
|
|
125
|
+
"Bank" is overloaded in C64 literature. Three distinct uses:
|
|
126
|
+
|
|
127
|
+
- **CPU bank** / **memory mode** / **mode N** (0-31): one of the 32
|
|
128
|
+
configurations controlled by $01 bits 0-2 plus the GAME and EXROM lines
|
|
129
|
+
from the cartridge port. Only 7 of the 32 are functionally distinct in
|
|
130
|
+
the absence of a cartridge.
|
|
131
|
+
- **VIC-II bank** (0-3): a 16 KB window the VIC-II chip uses to fetch
|
|
132
|
+
screen, character, sprite, and bitmap data. Selected by CIA #2 port A
|
|
133
|
+
bits 0-1 (inverted). Bank 0 = $0000-$3FFF; bank 1 = $4000-$7FFF;
|
|
134
|
+
bank 2 = $8000-$BFFF; bank 3 = $C000-$FFFF. See
|
|
135
|
+
[vic-ii-reference.md](vic-ii-reference.md) for VIC-II bank details.
|
|
136
|
+
- **Bank** in the C128/REU sense: 64 KB chunks. Not applicable to a
|
|
137
|
+
stock C64.
|
|
138
|
+
|
|
139
|
+
This doc covers CPU banks. VIC-II banking is independent and orthogonal —
|
|
140
|
+
the VIC sees its own memory map and never sees ROMs (with one wrinkle:
|
|
141
|
+
the character ROM is shadowed into VIC banks 0 and 2 at $1000-$1FFF and
|
|
142
|
+
$9000-$9FFF respectively).
|
|
143
|
+
|
|
144
|
+
### Sources
|
|
145
|
+
|
|
146
|
+
- *Mapping the Commodore 64* (Sheldon Leemon, Compute! Publications 1984;
|
|
147
|
+
Project 64 transcription at zimmers.net) — the canonical zeropage and
|
|
148
|
+
KERNAL workspace map.
|
|
149
|
+
- C64-Wiki Memory Map article — modern collation.
|
|
150
|
+
- sta.c64.org cbm64mem.html (Joe Forster/STA's "Commodore 64 Memory Map")
|
|
151
|
+
— exhaustive per-byte zero-page reference.
|
|
152
|
+
- *Commodore 64 Programmer's Reference Guide* (Commodore, 1982) chapters 2 + 7.
|
|
153
|
+
- *The C64 PLA Dissected* (Thomas Giesel, 2010) for bank-select truth table.
|
|
154
|
+
|
|
155
|
+
## Quick reference
|
|
156
|
+
|
|
157
|
+
The address space resolves at each fetch through three layers:
|
|
158
|
+
|
|
159
|
+
1. **CPU pins** A0-A15 emit the address.
|
|
160
|
+
2. **PLA (906114)** sees A12-A15 (the high nibble, which picks the 4 KB
|
|
161
|
+
chunk — the same inputs listed under [Bank switching](#bank-switching)),
|
|
162
|
+
the GAME/EXROM lines from the cartridge, and the LORAM/HIRAM/CHAREN
|
|
163
|
+
lines from the 6510's processor port. It produces enable signals:
|
|
164
|
+
CASRAM (RAM read enable), ROML/ROMH (cartridge ROM enables), KERNAL,
|
|
165
|
+
BASIC, CHAROM, and I/O. Splitting the I/O block below 4 KB into VIC,
|
|
166
|
+
SID, colour RAM, CIA1, CIA2, IO1 and IO2 is done from A8-A11 by a
|
|
167
|
+
separate decoder downstream of the PLA's I/O enable (a 74LS139 on the
|
|
168
|
+
boards that carry the 906114; from the schematics, not measured here).
|
|
169
|
+
An earlier revision of this line said A8-A15; the 906114 has no
|
|
170
|
+
A8-A11 inputs.
|
|
171
|
+
3. **Selected device** drives the data bus.
|
|
172
|
+
|
|
173
|
+
For most software the only thing that matters is the value at $01. Bits
|
|
174
|
+
2-0 of $01 control:
|
|
175
|
+
|
|
176
|
+
| $01 bit | Name | 0 means | 1 means |
|
|
177
|
+
|---------|---------|-----------------------------------------|-------------------------------|
|
|
178
|
+
| 0 | LORAM | $A000-$BFFF is RAM | $A000-$BFFF can be BASIC ROM |
|
|
179
|
+
| 1 | HIRAM | $E000-$FFFF is RAM | $E000-$FFFF can be KERNAL ROM |
|
|
180
|
+
| 2 | CHAREN | $D000-$DFFF is character ROM | $D000-$DFFF is I/O |
|
|
181
|
+
|
|
182
|
+
Higher bits of $01 are used for cassette control (bits 3-5) and the cassette
|
|
183
|
+
sense line (bit 4 input).
|
|
184
|
+
|
|
185
|
+
The seven distinct CPU bank configurations (with no cartridge attached —
|
|
186
|
+
GAME=1, EXROM=1) are summarized in the [Bank switching](#bank-switching)
|
|
187
|
+
section.
|
|
188
|
+
|
|
189
|
+
### Memory ranges that are always RAM
|
|
190
|
+
|
|
191
|
+
These ranges are always RAM regardless of $01 setting, on a stock C64 with
|
|
192
|
+
no cartridge:
|
|
193
|
+
|
|
194
|
+
- $0000-$0001 — processor port (special — see below)
|
|
195
|
+
- $0002-$9FFF — 40 KB of contiguous RAM
|
|
196
|
+
- $C000-$CFFF — 4 KB of free RAM
|
|
197
|
+
|
|
198
|
+
The remaining 20 KB ($A000-$BFFF, $D000-$DFFF, $E000-$FFFF) is the
|
|
199
|
+
multiplexed region.
|
|
200
|
+
|
|
201
|
+
### Memory ranges that change meaning
|
|
202
|
+
|
|
203
|
+
These ranges depend on $01 and cartridge lines:
|
|
204
|
+
|
|
205
|
+
- $A000-$BFFF — 8 KB: BASIC ROM, RAM, or cartridge ROM (ROMH)
|
|
206
|
+
- $D000-$DFFF — 4 KB: I/O, character ROM, or RAM
|
|
207
|
+
- $E000-$FFFF — 8 KB: KERNAL ROM, RAM, or cartridge ROM (ROMH in Ultimax)
|
|
208
|
+
- $8000-$9FFF — 8 KB: RAM, or cartridge ROM (ROML in 8K/16K/Ultimax)
|
|
209
|
+
|
|
210
|
+
## Memory regions
|
|
211
|
+
|
|
212
|
+
The following H3 entries cover the entire $0000-$FFFF address space. Each
|
|
213
|
+
region includes its default function on a freshly-booted C64, whether the
|
|
214
|
+
region is bank-switchable, and key sub-addresses or registers within it.
|
|
215
|
+
|
|
216
|
+
### $0000-$0001 — Processor I/O port
|
|
217
|
+
|
|
218
|
+
**Default use:** 6510 on-chip I/O port; controls memory banking and cassette
|
|
219
|
+
**Bank-switchable:** No (the port itself is on-die in the CPU and is always reachable)
|
|
220
|
+
|
|
221
|
+
The 6510 CPU has six general-purpose I/O pins that exit the chip on the
|
|
222
|
+
package pins normally unused by a stock 6502. These pins are made
|
|
223
|
+
accessible to software as memory locations $0000 (the data direction
|
|
224
|
+
register) and $0001 (the data register). The PLA reads three of those
|
|
225
|
+
pins to decide which ROMs are banked into the address space.
|
|
226
|
+
|
|
227
|
+
$0000 = DDR. Each bit decides whether the corresponding pin in $0001 is
|
|
228
|
+
an output (bit = 1) or an input (bit = 0).
|
|
229
|
+
|
|
230
|
+
$0001 = data. For output pins, the written value drives the pin. For
|
|
231
|
+
input pins, the value read reflects the pin's external state.
|
|
232
|
+
|
|
233
|
+
**Reset value:** DDR = $2F; data written by IOINIT = $E7, reads back as $37 (see Reset state above).
|
|
234
|
+
|
|
235
|
+
After reset, bits 0-2 of $01 are outputs driving LORAM, HIRAM, CHAREN
|
|
236
|
+
high — selecting BASIC ROM + KERNAL ROM + I/O visible.
|
|
237
|
+
|
|
238
|
+
| Bit | Name | I/O | Function |
|
|
239
|
+
|-----|-----------|-------|-----------------------------------------------------------------------|
|
|
240
|
+
| 0 | LORAM | Out | 0 = $A000-$BFFF is RAM; 1 = BASIC ROM enabled (subject to HIRAM) |
|
|
241
|
+
| 1 | HIRAM | Out | 0 = $E000-$FFFF is RAM; 1 = KERNAL ROM enabled |
|
|
242
|
+
| 2 | CHAREN | Out | 0 = $D000-$DFFF is char ROM (if HIRAM or LORAM); 1 = $D000-$DFFF I/O |
|
|
243
|
+
| 3 | CASSDOUT | Out | Datasette write line |
|
|
244
|
+
| 4 | CASSSENS | In | Datasette sense (0 = button pressed) |
|
|
245
|
+
| 5 | CASSMOT | Out | Datasette motor control (0 = motor on) |
|
|
246
|
+
| 6 | - | - | No pin on the 6510. As an input it reads the last level driven when it was an output, decaying to 0 after a few hundred ms (VICE models 350,000-420,000 cycles, ~0.35-0.43 s; measured 360k-417k in x64sc 3.10). Reads 0 after boot ($01 = $37). Do not rely on it. |
|
|
247
|
+
| 7 | - | - | No pin on the 6510. As an input it reads the last level driven when it was an output, decaying to 0 after a few hundred ms (VICE models 350,000-420,000 cycles, ~0.35-0.43 s; measured 360k-417k in x64sc 3.10). Reads 0 after boot ($01 = $37). Do not rely on it. |
|
|
248
|
+
|
|
249
|
+
**Notes:**
|
|
250
|
+
- **DDR must be set first.** When you write a new value to $01, the
|
|
251
|
+
underlying CPU latches the value through the DDR mask. Bits configured
|
|
252
|
+
as input ignore writes. If you intend to drive a pin, set the DDR
|
|
253
|
+
bit to 1 first, then write the data register.
|
|
254
|
+
- **Reading $01 can be glitchy.** When CASSMOT is driving low (motor on)
|
|
255
|
+
and you read $01, the input bit CASSSENS may read back as the most
|
|
256
|
+
recent value the line was driven to during the cassette sense window.
|
|
257
|
+
This is reported in *Mapping the Commodore 64* (p. 32) and is not
|
|
258
|
+
checked here — no tape device is attached in the headless runs.
|
|
259
|
+
- **Bit 6/7 unconnected.** On a stock C64 these pins are not bonded out
|
|
260
|
+
and read as their previous output state with very slow capacitive
|
|
261
|
+
decay. *Do not rely on bit 6/7 values for anything.* An earlier version
|
|
262
|
+
of the table said these bits were "pulled high"; the reset state
|
|
263
|
+
DDR=$2F / $01=$37 contradicts that — they are inputs reading 0, and a
|
|
264
|
+
driven 0 switched to input stays 0. See
|
|
265
|
+
[6510-cpu-reference.md](6510-cpu-reference.md#reading-the-port) for the
|
|
266
|
+
decay figure.
|
|
267
|
+
|
|
268
|
+
### $0002-$0002 — Unused (free zero-page byte)
|
|
269
|
+
|
|
270
|
+
**Default use:** None — not referenced by BASIC or the KERNAL; free for user code alongside $FB-$FE
|
|
271
|
+
**Bank-switchable:** No (always RAM)
|
|
272
|
+
|
|
273
|
+
Cleared to $00 by RAMTAS (`STA $0002,Y` at $FD53) and never touched
|
|
274
|
+
again: no instruction in the BASIC (901226-01) or KERNAL (901227-03) ROM
|
|
275
|
+
names $02 apart from that clearing loop — the only `$02` operands are
|
|
276
|
+
`$02,X` offsets into FAC1/FAC2 in the math package, with X = $61 or $69
|
|
277
|
+
(the sites at $B4DF and $B98D-$B9B0 run with X ≥ $19) — and a sentinel
|
|
278
|
+
POKEd into $02 survives a forced garbage collection (FRE(0)) and the
|
|
279
|
+
BASIC I/O error path (verified against the ROM images and in VICE x64sc
|
|
280
|
+
3.9). An earlier version of this entry said BASIC used $02 as a working
|
|
281
|
+
register during garbage collection and I/O error handling; neither
|
|
282
|
+
routine ($B526-$B605, $E0F9-$E109) references it. Programs that call ROM
|
|
283
|
+
routines can use it too; the one caveat is KERNAL SAVE, which reads its
|
|
284
|
+
start address through whichever zero-page pointer the caller names in A.
|
|
285
|
+
|
|
286
|
+
### $0003-$0004 — Float-to-fix vector
|
|
287
|
+
|
|
288
|
+
**Default use:** Vector to BASIC's float-to-fix conversion ($B1AA)
|
|
289
|
+
**Bank-switchable:** No (always RAM)
|
|
290
|
+
|
|
291
|
+
Patchable: if you want to override how BASIC converts floats to integers,
|
|
292
|
+
point this here. Installed by BASIC's cold-start initialisation at $E3BF
|
|
293
|
+
(the KERNAL reset reaches it only via JMP ($A000) -> $E394 -> JSR $E3BF),
|
|
294
|
+
not by the KERNAL. RESTOR ($FF8A -> $FD15) rewrites only $0314-$0333 from
|
|
295
|
+
the table at $FD30 and leaves $03-$06 alone; an earlier version of this
|
|
296
|
+
page said RESTOR pre-loads them (ROM bytes; confirmed in VICE x64sc 3.10).
|
|
297
|
+
|
|
298
|
+
### $0005-$0006 — Fix-to-float vector
|
|
299
|
+
|
|
300
|
+
**Default use:** Vector to BASIC's fix-to-float conversion ($B391)
|
|
301
|
+
**Bank-switchable:** No (always RAM)
|
|
302
|
+
|
|
303
|
+
Installed by the same BASIC init at $E3BF, default $B391; see $0003-$0004.
|
|
304
|
+
|
|
305
|
+
### $0007-$0008 — Search character / quote flag
|
|
306
|
+
|
|
307
|
+
**Default use:** BASIC tokenization workspace (current search char + quote-state flag)
|
|
308
|
+
**Bank-switchable:** No
|
|
309
|
+
|
|
310
|
+
### $0009-$0009 — TRMPOS (TAB/SPC cursor column)
|
|
311
|
+
|
|
312
|
+
**Default use:** Cursor column (read via PLOT $FFF0) at the moment PRINT evaluates a TAB( or SPC( — the column before the move. Earlier text called this an input-buffer pointer; the only ROM references are $AAFD/$AB0A in PRINT's TAB/SPC code (measured in VICE x64sc: 3 after PRINT "ABC";TAB(20)).
|
|
313
|
+
**Bank-switchable:** No
|
|
314
|
+
|
|
315
|
+
### $000A-$000A — VERCK (LOAD/VERIFY flag)
|
|
316
|
+
|
|
317
|
+
**Default use:** BASIC LOAD = $00, VERIFY = $01; passed in A to KERNAL LOAD ($FFD5). Earlier text called this an array-dimension flag; the only references are $E16A/$E16F/$E17A in the BASIC LOAD/VERIFY entry.
|
|
318
|
+
**Bank-switchable:** No
|
|
319
|
+
|
|
320
|
+
### $000B-$000B — COUNT (input-buffer index / subscript count)
|
|
321
|
+
|
|
322
|
+
**Default use:** Tokeniser keyword counter and crunched-line length; number of array subscripts while an array reference is processed (compared with the array header at $B256, counted down to 0 by the dimension loops). Earlier text called this a type flag; the numeric/string flag is VALTYP at $000D.
|
|
323
|
+
**Bank-switchable:** No
|
|
324
|
+
|
|
325
|
+
### $000C-$000C — DIMFLG (DIM in progress)
|
|
326
|
+
|
|
327
|
+
**Default use:** Non-zero while DIM is creating an array (DIM enters the variable-lookup routine with this set; it holds the first character of the array name), $00 for an ordinary variable reference. Earlier text called this a DEF FN flag; the FN flag is SUBFLG at $0010.
|
|
328
|
+
**Bank-switchable:** No
|
|
329
|
+
|
|
330
|
+
### $000D-$000D — Data type flag
|
|
331
|
+
|
|
332
|
+
**Default use:** $00 = numeric expression result, $FF = string
|
|
333
|
+
**Bank-switchable:** No
|
|
334
|
+
|
|
335
|
+
### $000E-$000E — Integer/float flag
|
|
336
|
+
|
|
337
|
+
**Default use:** $80 = integer, $00 = floating-point result
|
|
338
|
+
**Bank-switchable:** No
|
|
339
|
+
|
|
340
|
+
### $000F-$000F — GARBFL (DATA-scan / LIST-quote / garbage-collection flag)
|
|
341
|
+
|
|
342
|
+
**Default use:** Tokeniser: set when a DATA statement is found so the rest of the line is not tokenised, cleared at ':'; LIST: quote-mode toggle; string allocation: bit 7 set once garbage collection has run so it is not run twice. A flag, not workspace, and not a DATA pointer — DATPTR is $0041-$0042 below.
|
|
343
|
+
**Bank-switchable:** No
|
|
344
|
+
|
|
345
|
+
### $0010-$0010 — SUBFLG (subscript / FN reference allowed)
|
|
346
|
+
|
|
347
|
+
**Default use:** $00 = subscripts and integer variables allowed; $80 = set by FOR and DEF FN/FN so the variable-lookup routine refuses an integer name or a subscript (?SYNTAX ERROR). Cleared by CLR and after each plain variable lookup.
|
|
348
|
+
**Bank-switchable:** No
|
|
349
|
+
|
|
350
|
+
### $0011-$0013 — Input source + LIST mode + scan offset
|
|
351
|
+
|
|
352
|
+
**Default use:** Subscript pointer and IO type code; LIST current line pointer
|
|
353
|
+
**Bank-switchable:** No
|
|
354
|
+
|
|
355
|
+
### $0014-$0015 — Line number temp
|
|
356
|
+
|
|
357
|
+
**Default use:** Temporary line number from BASIC text — used by GOTO, GOSUB, RUN, LIST
|
|
358
|
+
**Bank-switchable:** No
|
|
359
|
+
|
|
360
|
+
### $0016-$001A — String descriptor stack
|
|
361
|
+
|
|
362
|
+
**Default use:** Top of BASIC string descriptor stack (LASTPT, TEMPPT)
|
|
363
|
+
**Bank-switchable:** No
|
|
364
|
+
|
|
365
|
+
### $001B-$0021 — Misc BASIC workspace
|
|
366
|
+
|
|
367
|
+
**Default use:** String descriptor temp + index/temp pointers used by BASIC
|
|
368
|
+
**Bank-switchable:** No
|
|
369
|
+
|
|
370
|
+
### $0022-$0025 — INDEX1, INDEX2
|
|
371
|
+
|
|
372
|
+
**Default use:** General-purpose 16-bit pointers used by BASIC functions
|
|
373
|
+
**Bank-switchable:** No
|
|
374
|
+
|
|
375
|
+
Usable by assembly when BASIC is dormant.
|
|
376
|
+
|
|
377
|
+
### $0026-$002A — Floating-point accumulator C
|
|
378
|
+
|
|
379
|
+
**Default use:** Working register for BASIC's floating-point routines
|
|
380
|
+
**Bank-switchable:** No
|
|
381
|
+
|
|
382
|
+
### $002B-$002C — TXTTAB (start of BASIC program)
|
|
383
|
+
|
|
384
|
+
**Default use:** Pointer to first byte of stored BASIC program (default $0801)
|
|
385
|
+
**Bank-switchable:** No
|
|
386
|
+
|
|
387
|
+
Reset value: $0801. Set lower to relocate the BASIC program below the
|
|
388
|
+
screen; set higher to reserve memory below the program. After modifying
|
|
389
|
+
TXTTAB, POKE the byte at TXTTAB-1 with $00 (e.g. POKE 16384,0 for TXTTAB
|
|
390
|
+
= $4001) and run NEW so BASIC initializes the link bytes. RUN and NEW
|
|
391
|
+
both set TXTPTR to TXTTAB-1 ($A68E) and the statement loop ($A7C0) reads
|
|
392
|
+
that byte expecting an end-of-line zero, so anything else there gives
|
|
393
|
+
?SYNTAX ERROR before the first line runs; the cold start zeroes $0800
|
|
394
|
+
($E419) only because the default TXTTAB is $0801. An earlier version of
|
|
395
|
+
this page said to zero $0800, which is right only for the default.
|
|
396
|
+
(Measured in VICE x64sc 3.10: POKE44,64:POKE2048,0:NEW gave ?SYNTAX ERROR,
|
|
397
|
+
POKE44,64:POKE16384,0:NEW ran.)
|
|
398
|
+
|
|
399
|
+
### $002D-$002E — VARTAB (start of BASIC variables)
|
|
400
|
+
|
|
401
|
+
**Default use:** Pointer to first byte past the tokenized BASIC program; start of simple variables
|
|
402
|
+
**Bank-switchable:** No
|
|
403
|
+
|
|
404
|
+
Set by BASIC at the end of every program edit. Reading VARTAB gives the
|
|
405
|
+
true end of the BASIC program in memory.
|
|
406
|
+
|
|
407
|
+
### $002F-$0030 — ARYTAB (start of arrays)
|
|
408
|
+
|
|
409
|
+
**Default use:** Pointer to first byte past simple variables; start of array storage
|
|
410
|
+
**Bank-switchable:** No
|
|
411
|
+
|
|
412
|
+
### $0031-$0032 — STREND (end of arrays)
|
|
413
|
+
|
|
414
|
+
**Default use:** Pointer to first byte past arrays; bottom of free memory
|
|
415
|
+
**Bank-switchable:** No
|
|
416
|
+
|
|
417
|
+
The 256-byte BASIC variable namespace lives between $002B and $0033 as a
|
|
418
|
+
chain of four pointers. The order is invariant: TXTTAB < VARTAB < ARYTAB
|
|
419
|
+
< STREND. STREND <= MEMSIZ (top-of-BASIC) always.
|
|
420
|
+
|
|
421
|
+
### $0033-$0034 — STRBOT (bottom of string descriptor heap)
|
|
422
|
+
|
|
423
|
+
**Default use:** Pointer to bottom of string heap (grows down from MEMSIZ)
|
|
424
|
+
**Bank-switchable:** No
|
|
425
|
+
|
|
426
|
+
Strings live at the top of BASIC's workspace and grow downward. The
|
|
427
|
+
distance between STREND and STRBOT is the available free memory before
|
|
428
|
+
garbage collection runs.
|
|
429
|
+
|
|
430
|
+
### $0035-$0036 — Unused / FRESPC
|
|
431
|
+
|
|
432
|
+
**Default use:** Pointer used during string concatenation; safe to clobber
|
|
433
|
+
**Bank-switchable:** No
|
|
434
|
+
|
|
435
|
+
### $0037-$0038 — MEMSIZ (top of BASIC)
|
|
436
|
+
|
|
437
|
+
**Default use:** Highest address BASIC can use (default $A000 on cold boot)
|
|
438
|
+
**Bank-switchable:** No
|
|
439
|
+
|
|
440
|
+
Lower MEMSIZ to reserve a chunk of high RAM for assembly code, custom
|
|
441
|
+
char sets, or sprite data. MEMSIZ is BASIC's hard cap — string heap
|
|
442
|
+
grows down from MEMSIZ.
|
|
443
|
+
|
|
444
|
+
### $0039-$003A — CURLIN (current BASIC line number)
|
|
445
|
+
|
|
446
|
+
**Default use:** Line number of the currently-executing BASIC statement; in direct mode only the high byte is set ($3A = $FF) — the low byte keeps whatever line ran last
|
|
447
|
+
**Bank-switchable:** No
|
|
448
|
+
|
|
449
|
+
A useful test: PEEK(58) = 255 means direct mode. Do not compare the
|
|
450
|
+
16-bit value with 65535 — the main loop ($A490: LDX #$FF / STX $3A) sets
|
|
451
|
+
only the high byte, so after a program has run the pair reads $FFnn with
|
|
452
|
+
nn the low byte of the last executed line, and even on a fresh boot it
|
|
453
|
+
reads 65280 ($39 is 0 from the KERNAL's RAM clear; nothing in either ROM
|
|
454
|
+
ever writes $FF to $39). BASIC's own direct-mode checks ($A46C, $A838,
|
|
455
|
+
$B3A6) test only $3A. An earlier version of this page said 65535;
|
|
456
|
+
measured in VICE x64sc 3.10: 65280 at boot, 65300 after a program ending
|
|
457
|
+
at line 20.
|
|
458
|
+
|
|
459
|
+
### $003B-$003C — OLDLIN (previous BASIC line)
|
|
460
|
+
|
|
461
|
+
**Default use:** Line of last STOP, END, or CONT-able statement
|
|
462
|
+
**Bank-switchable:** No
|
|
463
|
+
|
|
464
|
+
### $003D-$003E — OLDTXT (previous BASIC text pointer)
|
|
465
|
+
|
|
466
|
+
**Default use:** Text pointer for CONT (continue) command
|
|
467
|
+
**Bank-switchable:** No
|
|
468
|
+
|
|
469
|
+
### $003F-$0040 — DATLIN (last DATA line number)
|
|
470
|
+
|
|
471
|
+
**Default use:** Line number containing the next DATA item for READ
|
|
472
|
+
**Bank-switchable:** No
|
|
473
|
+
|
|
474
|
+
### $0041-$0042 — DATPTR (next DATA pointer)
|
|
475
|
+
|
|
476
|
+
**Default use:** Pointer to next DATA byte to be read by READ
|
|
477
|
+
**Bank-switchable:** No
|
|
478
|
+
|
|
479
|
+
RESTORE sets DATPTR back to start of program.
|
|
480
|
+
|
|
481
|
+
### $0043-$0044 — INPTR (input vector)
|
|
482
|
+
|
|
483
|
+
**Default use:** Pointer to current INPUT character source
|
|
484
|
+
**Bank-switchable:** No
|
|
485
|
+
|
|
486
|
+
### $0045-$0046 — VARNAM (current variable name)
|
|
487
|
+
|
|
488
|
+
**Default use:** Two-character variable name being looked up
|
|
489
|
+
**Bank-switchable:** No
|
|
490
|
+
|
|
491
|
+
### $0047-$0048 — VARPNT (current variable pointer)
|
|
492
|
+
|
|
493
|
+
**Default use:** Pointer to variable value in BASIC variable space
|
|
494
|
+
**Bank-switchable:** No
|
|
495
|
+
|
|
496
|
+
### $0049-$004A — FORPNT (FOR loop pointer)
|
|
497
|
+
|
|
498
|
+
**Default use:** Pointer to FOR-loop control variable
|
|
499
|
+
**Bank-switchable:** No
|
|
500
|
+
|
|
501
|
+
### $004B-$0052 — Misc BASIC arithmetic / expression evaluation
|
|
502
|
+
|
|
503
|
+
**Default use:** Op stack temps for BASIC's expression evaluator
|
|
504
|
+
**Bank-switchable:** No
|
|
505
|
+
|
|
506
|
+
### $0053-$0053 — Garbage-collection step size
|
|
507
|
+
|
|
508
|
+
**Default use:** Step the BASIC garbage collector adds to its walk pointer ($22-$23): 3 while scanning the temporary string-descriptor stack and array elements, 7 while scanning simple variables (set at $B54D and $B56A, applied at $B5F6); BASIC cold start initialises it to 3 ($E3EA). Not a string length, and not VALTYP — the numeric/string type flag is $000D.
|
|
509
|
+
**Bank-switchable:** No
|
|
510
|
+
|
|
511
|
+
Conventionally labelled FOUR6 (the Microsoft/Commodore source name — not
|
|
512
|
+
verified from an instrument on this machine). An earlier version of this
|
|
513
|
+
entry was headed VALTYP; that name belongs to $000D, and the ROM shows
|
|
514
|
+
$53 is the collector's step size (3 or 7), not a length.
|
|
515
|
+
|
|
516
|
+
### $0054-$0056 — Jump-to-function temp
|
|
517
|
+
|
|
518
|
+
**Default use:** JMP instruction template used by BASIC to call function code
|
|
519
|
+
**Bank-switchable:** No
|
|
520
|
+
|
|
521
|
+
### $0057-$0060 — Misc numeric work area (two 5-byte FP temporaries)
|
|
522
|
+
|
|
523
|
+
**Default use:** BASIC math temporaries at $57-$5B and $5C-$60; MOV2F stores FAC to either ($BBCA -> $57, $BBC7 -> $5C), the series evaluator POLY1 ($E043) multiplies by them, and FIN clears $5D-$67 at entry and uses $5D-$60 as its digit/exponent counters
|
|
524
|
+
**Bank-switchable:** No
|
|
525
|
+
|
|
526
|
+
Earlier revisions called this ARG; ARG is at $69-$6E (see below), as the
|
|
527
|
+
BASIC ROM's CONUPK $BA8C shows. The conventional labels TEMPF1/TEMPF2
|
|
528
|
+
are names from the published maps, not read from an instrument.
|
|
529
|
+
|
|
530
|
+
### $0061-$0066 — Floating-point accumulator #1 (FAC)
|
|
531
|
+
|
|
532
|
+
**Default use:** Primary floating-point register; result of every BASIC math op
|
|
533
|
+
**Bank-switchable:** No
|
|
534
|
+
|
|
535
|
+
| Address | Meaning |
|
|
536
|
+
|---------|----------------------------------------|
|
|
537
|
+
| $0061 | Exponent |
|
|
538
|
+
| $0062-$0065 | Mantissa (4 bytes, MSB first) |
|
|
539
|
+
| $0066 | Sign |
|
|
540
|
+
|
|
541
|
+
### $0067-$0067 — SGNFLG
|
|
542
|
+
|
|
543
|
+
**Default use:** Sign flag during number input (FIN, $BD02); term counter during series evaluation, loaded from the coefficient table's first byte at $E062 and decremented at $E088 — it is a counter, not a pointer
|
|
544
|
+
**Bank-switchable:** No
|
|
545
|
+
|
|
546
|
+
### $0068-$0068 — BITS
|
|
547
|
+
|
|
548
|
+
**Default use:** FAC overflow byte, set by INT ($BCA9) and normalisation, cleared by BASIC init ($E3F0)
|
|
549
|
+
**Bank-switchable:** No
|
|
550
|
+
|
|
551
|
+
### $0069-$006E — Floating-point accumulator #2 (ARG)
|
|
552
|
+
|
|
553
|
+
**Default use:** Second floating-point register used by BASIC math; CONUPK ($BA8C) loads it from memory
|
|
554
|
+
**Bank-switchable:** No
|
|
555
|
+
|
|
556
|
+
| Address | Meaning |
|
|
557
|
+
|---------|------------------------------------------------------------|
|
|
558
|
+
| $0069 | Exponent |
|
|
559
|
+
| $006A-$006D | Mantissa (4 bytes, MSB first, bit 7 of $6A forced set) |
|
|
560
|
+
| $006E | Sign |
|
|
561
|
+
|
|
562
|
+
### $006F-$006F — ARISGN
|
|
563
|
+
|
|
564
|
+
**Default use:** Sign-comparison byte = ARG sign EOR FAC sign, written by CONUPK ($BAA5-$BAA7) and tested by FADD ($B8A3)
|
|
565
|
+
**Bank-switchable:** No
|
|
566
|
+
|
|
567
|
+
Earlier revisions labelled $67-$6F polynomial workspace; the series
|
|
568
|
+
evaluator's temporaries are actually $57-$60, $67 and $71-$72.
|
|
569
|
+
|
|
570
|
+
### $0070-$0072 — FACOV + FBUFPT (floating-point scratch)
|
|
571
|
+
|
|
572
|
+
**Default use:** $70 is the FAC rounding/overflow byte (FADD reads it at $B86F, ROUND shifts it at $BC1B, MOVAF zeroes it, FMULT uses it as the first multiplier byte); $71-$72 is the pointer the series/polynomial evaluator POLY1 stores at $E043 for the coefficient table (also borrowed by the tokenizer and string routines as scratch)
|
|
573
|
+
**Bank-switchable:** No
|
|
574
|
+
|
|
575
|
+
Not part of CHRGET: the reset-time copy loop (LDX #$1C / LDA $E3A2,X /
|
|
576
|
+
STA $73,X) starts at $73, so an earlier version of this page that titled
|
|
577
|
+
$70-$72 "CHRGET / CHRGOT" was wrong. Label names FACOV/FBUFPT follow the
|
|
578
|
+
conventional Commodore source labels; the usages above are read from the
|
|
579
|
+
ROM images.
|
|
580
|
+
|
|
581
|
+
### $0073-$008A — CHRGET routine (executable code)
|
|
582
|
+
|
|
583
|
+
**Default use:** Inline machine code for BASIC's next-token reader
|
|
584
|
+
**Bank-switchable:** No
|
|
585
|
+
|
|
586
|
+
Machine code copied from the ROM image at $E3A2 by BASIC's cold-start
|
|
587
|
+
init ($E3BF, in the KERNAL ROM image) at reset — the CHRGET/CHRGOT
|
|
588
|
+
subroutine BASIC uses to read its own tokenized program. CHRGET is $0073
|
|
589
|
+
(advance TXTPTR then fetch); CHRGOT is $0079 (re-fetch the current byte
|
|
590
|
+
without advancing); the LDA operand at $007A-$007B is TXTPTR. The bytes
|
|
591
|
+
at $0073-$008F are a 29-byte image copied down from $E3A2 (LDX #$1C /
|
|
592
|
+
LDA $E3A2,X / STA $73,X): the CHRGET/CHRGOT subroutine at $73-$8A plus
|
|
593
|
+
the initial RND seed at $8B-$8F ($80 $4F $C7 $52 $58). $E3A2 is BASIC
|
|
594
|
+
interpreter code that physically lives in the KERNAL ROM chip's
|
|
595
|
+
$E000-$E4D2 span (kernal-901227-03.bin offset $03A2), not in
|
|
596
|
+
basic-901226-01.bin. Nothing else reinstalls it — not the KERNAL's
|
|
597
|
+
RESTOR/CINT/IOINIT and not the RUN/STOP-RESTORE warm start at $E37B — so
|
|
598
|
+
once overwritten only a cold start ($E394, SYS 58260) or a reset brings
|
|
599
|
+
it back. An earlier version of this page said the KERNAL copies it in at
|
|
600
|
+
reset.
|
|
601
|
+
|
|
602
|
+
**Notes:**
|
|
603
|
+
- This block is *executable code in zeropage*. Overwriting it crashes BASIC.
|
|
604
|
+
- If you don't use BASIC (i.e. you're a pure assembly program that
|
|
605
|
+
doesn't return to the READY prompt), this 24-byte range is free.
|
|
606
|
+
|
|
607
|
+
### $007A-$007B — TXTPTR (BASIC program pointer)
|
|
608
|
+
|
|
609
|
+
**Default use:** Pointer to next byte the BASIC interpreter will read
|
|
610
|
+
**Bank-switchable:** No
|
|
611
|
+
|
|
612
|
+
Embedded inside the CHRGET routine. Modifying TXTPTR changes where
|
|
613
|
+
BASIC reads its next statement — used by RUN, GOTO, GOSUB.
|
|
614
|
+
|
|
615
|
+
### $008B-$008F — RNDX (random number seed)
|
|
616
|
+
|
|
617
|
+
**Default use:** 5-byte floating-point seed for BASIC's RND function
|
|
618
|
+
**Bank-switchable:** No
|
|
619
|
+
|
|
620
|
+
Seeded to $80 $4F $C7 $52 $58 by the same 29-byte copy from $E3A2 that
|
|
621
|
+
installs CHRGET (BASIC cold-start init at $E3BF, not the KERNAL); nothing
|
|
622
|
+
else rewrites it except RND itself.
|
|
623
|
+
|
|
624
|
+
### $0090-$0090 — STATUS (KERNAL I/O status)
|
|
625
|
+
|
|
626
|
+
**Default use:** I/O operation status flags; read by READST/CALLST
|
|
627
|
+
**Bank-switchable:** No
|
|
628
|
+
|
|
629
|
+
| Bit | Meaning (after IEC/cassette op) |
|
|
630
|
+
|-----|--------------------------------------------------|
|
|
631
|
+
| 0 | Time out write (IEC) |
|
|
632
|
+
| 1 | Time out read (IEC) |
|
|
633
|
+
| 2 | Short block (cassette) |
|
|
634
|
+
| 3 | Long block (cassette) |
|
|
635
|
+
| 4 | Unrecoverable read error (cassette) |
|
|
636
|
+
| 5 | Checksum error (cassette) |
|
|
637
|
+
| 6 | EOI (end-of-info) line set on IEC |
|
|
638
|
+
| 7 | Device not present (IEC) |
|
|
639
|
+
|
|
640
|
+
ST in BASIC reads this byte.
|
|
641
|
+
|
|
642
|
+
### $0091-$0091 — Stop key flag
|
|
643
|
+
|
|
644
|
+
**Default use:** Set to $7F if RUN/STOP key was depressed at last keyboard scan
|
|
645
|
+
**Bank-switchable:** No
|
|
646
|
+
|
|
647
|
+
Polled by the KERNAL STOP routine ($FFE1). $7F means STOP pressed
|
|
648
|
+
*alone*. Any other value means STOP not pressed.
|
|
649
|
+
|
|
650
|
+
### $0092-$0092 — Cassette timing constant
|
|
651
|
+
|
|
652
|
+
**Default use:** Timing adjustment for cassette read; KERNAL internal
|
|
653
|
+
**Bank-switchable:** No
|
|
654
|
+
|
|
655
|
+
### $0093-$0093 — LOAD/VERIFY flag
|
|
656
|
+
|
|
657
|
+
**Default use:** $00 = LOAD, $01 = VERIFY for the next ROM LOAD call
|
|
658
|
+
**Bank-switchable:** No
|
|
659
|
+
|
|
660
|
+
### $0094-$0094 — Serial output deferred char
|
|
661
|
+
|
|
662
|
+
**Default use:** Holds the next IEC byte to send (output buffer flag)
|
|
663
|
+
**Bank-switchable:** No
|
|
664
|
+
|
|
665
|
+
### $0095-$0095 — Serial deferred char
|
|
666
|
+
|
|
667
|
+
**Default use:** Buffered byte for IEC output
|
|
668
|
+
**Bank-switchable:** No
|
|
669
|
+
|
|
670
|
+
### $0096-$0096 — Cassette short-count
|
|
671
|
+
|
|
672
|
+
**Default use:** Cassette read short-count tracker
|
|
673
|
+
**Bank-switchable:** No
|
|
674
|
+
|
|
675
|
+
### $0097-$0097 — Temp for register save during IRQ
|
|
676
|
+
|
|
677
|
+
**Default use:** Y-register temp during IRQ entry to GETIN
|
|
678
|
+
**Bank-switchable:** No
|
|
679
|
+
|
|
680
|
+
### $0098-$0098 — Logical files open (LDTND)
|
|
681
|
+
|
|
682
|
+
**Default use:** Number of currently-open logical files; max 10
|
|
683
|
+
**Bank-switchable:** No
|
|
684
|
+
|
|
685
|
+
### $0099-$0099 — Default input device (DFLTN)
|
|
686
|
+
|
|
687
|
+
**Default use:** Current input device (0 = keyboard)
|
|
688
|
+
**Bank-switchable:** No
|
|
689
|
+
|
|
690
|
+
Used by CHKIN/CHRIN. Changed by CHKIN to redirect input from a file.
|
|
691
|
+
|
|
692
|
+
### $009A-$009A — Default output device (DFLTO)
|
|
693
|
+
|
|
694
|
+
**Default use:** Current output device (3 = screen)
|
|
695
|
+
**Bank-switchable:** No
|
|
696
|
+
|
|
697
|
+
Used by CHKOUT/CHROUT. Changed by CHKOUT to redirect output to a file.
|
|
698
|
+
|
|
699
|
+
### $009B-$009B — Parity byte (cassette / IEC)
|
|
700
|
+
|
|
701
|
+
**Default use:** Running parity during cassette/IEC byte transfer
|
|
702
|
+
**Bank-switchable:** No
|
|
703
|
+
|
|
704
|
+
### $009C-$009C — Byte-received flag
|
|
705
|
+
|
|
706
|
+
**Default use:** Flag for byte ready (IEC RS-232-ish protocols)
|
|
707
|
+
**Bank-switchable:** No
|
|
708
|
+
|
|
709
|
+
### $009D-$009D — Direct/program mode message flag
|
|
710
|
+
|
|
711
|
+
**Default use:** $80 = direct mode (control messages on, error text off), $00 = program mode (both off)
|
|
712
|
+
**Bank-switchable:** No
|
|
713
|
+
|
|
714
|
+
Bit 7 = print KERNAL control messages (SEARCHING FOR, LOADING, VERIFYING,
|
|
715
|
+
SAVING, FOUND); bit 6 = print KERNAL error messages ('I/O ERROR #n'). An
|
|
716
|
+
earlier version of this page had the two bits swapped. BASIC writes $80
|
|
717
|
+
here in direct mode (READY, $A47B) and $00 when a program is RUN ($A872),
|
|
718
|
+
so a running program prints neither unless it calls SETMSG ($FF90, which
|
|
719
|
+
just stores A at $9D). $C0 prints both; $00 is silent. Two things this
|
|
720
|
+
flag does NOT control: the tape prompts 'PRESS PLAY ON TAPE' / 'PRESS
|
|
721
|
+
RECORD & PLAY ON TAPE' and the 'OK' after them are printed
|
|
722
|
+
unconditionally ($F81E/$F82B enter the printer at $F12F, past the $9D
|
|
723
|
+
test), and 'FILE NOT FOUND' is BASIC's message from its own error table,
|
|
724
|
+
not the KERNAL's — the KERNAL prints 'I/O ERROR #4' for that case.
|
|
725
|
+
Verified against the ROM bytes and in VICE x64sc.
|
|
726
|
+
|
|
727
|
+
### $009E-$009F — Cassette block-read pointer + byte temp
|
|
728
|
+
|
|
729
|
+
**Default use:** KERNAL cassette internal
|
|
730
|
+
**Bank-switchable:** No
|
|
731
|
+
|
|
732
|
+
### $00A0-$00A2 — Jiffy clock (TI variable)
|
|
733
|
+
|
|
734
|
+
**Default use:** 24-bit jiffy counter incremented by KERNAL IRQ; TI in BASIC
|
|
735
|
+
**Bank-switchable:** No
|
|
736
|
+
|
|
737
|
+
| Address | Meaning |
|
|
738
|
+
|---------|--------------------------|
|
|
739
|
+
| $00A0 | Jiffy MSB |
|
|
740
|
+
| $00A1 | Jiffy middle byte |
|
|
741
|
+
| $00A2 | Jiffy LSB |
|
|
742
|
+
|
|
743
|
+
Incremented once per KERNAL IRQ by UDTIM ($FFEA → $F69B). That IRQ is
|
|
744
|
+
CIA #1 Timer A, which the KERNAL sets at $FDDD from the $02A6 region flag
|
|
745
|
+
to ≈60 Hz on BOTH regions — latch $4025 on PAL (16,422 cycles, 59.996 Hz)
|
|
746
|
+
and $4295 on NTSC (17,046 cycles, 59.998 Hz), read from the 901227-03
|
|
747
|
+
ROM and confirmed in VICE x64sc (359 jiffies in 300 PAL frames, 301 in
|
|
748
|
+
300 NTSC frames; a second run counted 298-299 ticks in 250 PAL frames).
|
|
749
|
+
So TI counts ~60ths of a second everywhere and runs very slightly *slow*
|
|
750
|
+
on both (0.007 % on PAL, 0.003 % on NTSC); UDTIM's 24-hour rollover at
|
|
751
|
+
$4F1A01 = 86,400 × 60 assumes the same 60/s. An earlier version of this
|
|
752
|
+
page said the PAL IRQ was 50 Hz and TI ran fast; neither was true. See
|
|
753
|
+
pal-ntsc-reference.md.
|
|
754
|
+
|
|
755
|
+
TI$ in BASIC formats the jiffy clock as "HHMMSS".
|
|
756
|
+
|
|
757
|
+
### $00A3-$00A4 — Serial bit count + cassette bit timer
|
|
758
|
+
|
|
759
|
+
**Default use:** Workspace for serial/cassette bit-banging
|
|
760
|
+
**Bank-switchable:** No
|
|
761
|
+
|
|
762
|
+
### $00A5-$00A6 — Cassette synchronization
|
|
763
|
+
|
|
764
|
+
**Default use:** Cassette sync mark counter
|
|
765
|
+
**Bank-switchable:** No
|
|
766
|
+
|
|
767
|
+
### $00A7-$00A8 — Serial-byte buffer + cycle counter
|
|
768
|
+
|
|
769
|
+
**Default use:** Cassette and serial-bus workspace
|
|
770
|
+
**Bank-switchable:** No
|
|
771
|
+
|
|
772
|
+
### $00A9-$00AD — Tape header / file workspace
|
|
773
|
+
|
|
774
|
+
**Default use:** Workspace for OPEN, LOAD, SAVE tape protocols
|
|
775
|
+
**Bank-switchable:** No
|
|
776
|
+
|
|
777
|
+
### $00AE-$00AF — EAL: end address of the last LOAD/SAVE
|
|
778
|
+
|
|
779
|
+
**Default use:** One past the last byte loaded or saved
|
|
780
|
+
**Bank-switchable:** No
|
|
781
|
+
|
|
782
|
+
SAVE ($FFD8) takes the end address in X/Y and stores it here on entry
|
|
783
|
+
($F5DD). LOAD uses it as the running store pointer (STA ($AE),Y / INC at
|
|
784
|
+
$F51C-$F522) and returns it in X/Y at exit ($F5AA-$F5AE), so after a
|
|
785
|
+
successful LOAD, $AE/$AF (or the returned X/Y) is the end of the program.
|
|
786
|
+
Also used as a temporary pointer by the screen-editor scroll
|
|
787
|
+
($E8F0-$E9ED). Verified against kernal-901227-03 and a SAVE/LOAD round
|
|
788
|
+
trip in VICE x64sc.
|
|
789
|
+
|
|
790
|
+
### $00B0-$00B1 — Tape header / file workspace
|
|
791
|
+
|
|
792
|
+
**Default use:** Workspace for OPEN, LOAD, SAVE tape protocols
|
|
793
|
+
**Bank-switchable:** No
|
|
794
|
+
|
|
795
|
+
### $00B2-$00B3 — Tape buffer pointer
|
|
796
|
+
|
|
797
|
+
**Default use:** Pointer to next byte in tape I/O buffer at $033C
|
|
798
|
+
**Bank-switchable:** No
|
|
799
|
+
|
|
800
|
+
### $00B4-$00BD — Cassette read/write internal state
|
|
801
|
+
|
|
802
|
+
**Default use:** Bit/byte/dword counters for tape protocol
|
|
803
|
+
**Bank-switchable:** No
|
|
804
|
+
|
|
805
|
+
### $00BE-$00BE — Tape block count
|
|
806
|
+
|
|
807
|
+
**Default use:** Number of tape blocks remaining
|
|
808
|
+
**Bank-switchable:** No
|
|
809
|
+
|
|
810
|
+
### $00BF-$00C0 — Serial output workspace
|
|
811
|
+
|
|
812
|
+
**Default use:** IEC clock-low timing constants
|
|
813
|
+
**Bank-switchable:** No
|
|
814
|
+
|
|
815
|
+
### $00C1-$00C2 — Memory pointer #1 / Filename source
|
|
816
|
+
|
|
817
|
+
**Default use:** Start-address pointer for SAVE and for tape LOAD
|
|
818
|
+
**Bank-switchable:** No
|
|
819
|
+
|
|
820
|
+
Start address for SAVE (copied from the zero-page pointer named in A,
|
|
821
|
+
$F5E4/$F5E8) and for tape LOAD ($F59C/$F5A0); a serial LOAD does not use
|
|
822
|
+
it — it stores straight through $AE/$AF.
|
|
823
|
+
|
|
824
|
+
### $00C3-$00C4 — MEMUSS: load address passed to LOAD
|
|
825
|
+
|
|
826
|
+
**Default use:** The X/Y the caller hands to LOAD ($FFD5); honoured only when the secondary address is 0 (relocating load)
|
|
827
|
+
**Bank-switchable:** No
|
|
828
|
+
|
|
829
|
+
LOAD's entry ($F49E) stores X/Y here before anything else. With SA=0 the
|
|
830
|
+
KERNAL copies it into $AE/$AF and loads there; with SA≠0 it is ignored
|
|
831
|
+
and the file's own address is used. A tape LOAD overwrites it with the
|
|
832
|
+
header's start address for non-relocatable (type 3) files or when SA≠0
|
|
833
|
+
($F56C-$F575). The VECTOR routine ($FD1A) borrows it as the pointer to
|
|
834
|
+
the caller's vector table. SAVE never touches it. Earlier revisions of
|
|
835
|
+
this page called it the end-address pointer; that is $AE/$AF — verified
|
|
836
|
+
against the ROM bytes and a SAVE/LOAD round trip in VICE x64sc.
|
|
837
|
+
|
|
838
|
+
### $00C5-$00C5 — Last key pressed (matrix code)
|
|
839
|
+
|
|
840
|
+
**Default use:** Raw matrix index of last key scanned by IRQ; $40 = no key
|
|
841
|
+
**Bank-switchable:** No
|
|
842
|
+
|
|
843
|
+
Updated 60 times per second by the KERNAL IRQ. *Not* the PETSCII code —
|
|
844
|
+
this is the row/column matrix index 0-63. The actual key code goes
|
|
845
|
+
through KEYTAB ($EB81-$ECB9) to produce a PETSCII byte that gets
|
|
846
|
+
written to the keyboard buffer at $0277.
|
|
847
|
+
|
|
848
|
+
### $00C6-$00C6 — Number of chars in keyboard buffer (NDX)
|
|
849
|
+
|
|
850
|
+
**Default use:** Count of characters waiting in keyboard buffer; 0-10
|
|
851
|
+
**Bank-switchable:** No
|
|
852
|
+
|
|
853
|
+
Polled by GETIN. Stuff $C6 to a count and write characters to $0277-$0280
|
|
854
|
+
to simulate keyboard input.
|
|
855
|
+
|
|
856
|
+
### $00C7-$00C7 — Reverse-video flag
|
|
857
|
+
|
|
858
|
+
**Default use:** $00 = normal, $12 = reverse video; controls upcoming PRINT chars
|
|
859
|
+
**Bank-switchable:** No
|
|
860
|
+
|
|
861
|
+
### $00C8-$00C8 — End-of-line pointer
|
|
862
|
+
|
|
863
|
+
**Default use:** PRINT routine end-of-line column
|
|
864
|
+
**Bank-switchable:** No
|
|
865
|
+
|
|
866
|
+
### $00C9-$00CA — Cursor X/Y on input
|
|
867
|
+
|
|
868
|
+
**Default use:** Cursor position saved at INPUT command entry
|
|
869
|
+
**Bank-switchable:** No
|
|
870
|
+
|
|
871
|
+
### $00CB-$00CB — Key being processed
|
|
872
|
+
|
|
873
|
+
**Default use:** Current key matrix code being processed by IRQ
|
|
874
|
+
**Bank-switchable:** No
|
|
875
|
+
|
|
876
|
+
### $00CC-$00CC — Cursor enable flag
|
|
877
|
+
|
|
878
|
+
**Default use:** $00 = blink enabled, $01 = disabled (set to $01 to suppress cursor)
|
|
879
|
+
**Bank-switchable:** No
|
|
880
|
+
|
|
881
|
+
### $00CD-$00CD — Blink timer
|
|
882
|
+
|
|
883
|
+
**Default use:** Frames until next cursor blink
|
|
884
|
+
**Bank-switchable:** No
|
|
885
|
+
|
|
886
|
+
### $00CE-$00CE — Character under cursor
|
|
887
|
+
|
|
888
|
+
**Default use:** Screen code of the character the cursor is sitting on
|
|
889
|
+
**Bank-switchable:** No
|
|
890
|
+
|
|
891
|
+
### $00CF-$00CF — Cursor blink phase
|
|
892
|
+
|
|
893
|
+
**Default use:** $00 or $01 — which half of the blink cycle
|
|
894
|
+
**Bank-switchable:** No
|
|
895
|
+
|
|
896
|
+
### $00D0-$00D0 — Input from screen flag
|
|
897
|
+
|
|
898
|
+
**Default use:** $00 = keyboard input, $03 = screen scroll buffer input
|
|
899
|
+
**Bank-switchable:** No
|
|
900
|
+
|
|
901
|
+
### $00D1-$00D2 — Pointer to current screen line (PNT)
|
|
902
|
+
|
|
903
|
+
**Default use:** Address of first character of the line containing the cursor
|
|
904
|
+
**Bank-switchable:** No
|
|
905
|
+
|
|
906
|
+
The cursor line pointer. PNT + cursor X = the screen RAM byte for the
|
|
907
|
+
character about to be printed.
|
|
908
|
+
|
|
909
|
+
### $00D3-$00D3 — Cursor column (X)
|
|
910
|
+
|
|
911
|
+
**Default use:** Cursor column 0-39
|
|
912
|
+
**Bank-switchable:** No
|
|
913
|
+
|
|
914
|
+
### $00D4-$00D4 — Quote-mode flag
|
|
915
|
+
|
|
916
|
+
**Default use:** $01 = inside a quoted string in PRINT; controls control-char printing
|
|
917
|
+
**Bank-switchable:** No
|
|
918
|
+
|
|
919
|
+
### $00D5-$00D5 — Screen line length
|
|
920
|
+
|
|
921
|
+
**Default use:** 39 for unwrapped lines, 79 for logical wrapped lines
|
|
922
|
+
**Bank-switchable:** No
|
|
923
|
+
|
|
924
|
+
### $00D6-$00D6 — Cursor row (Y)
|
|
925
|
+
|
|
926
|
+
**Default use:** Cursor row 0-24
|
|
927
|
+
**Bank-switchable:** No
|
|
928
|
+
|
|
929
|
+
### $00D7-$00D7 — Last key shift state / temp char
|
|
930
|
+
|
|
931
|
+
**Default use:** Last PETSCII char output; shift state during keyscan
|
|
932
|
+
**Bank-switchable:** No
|
|
933
|
+
|
|
934
|
+
### $00D8-$00D8 — Insert count
|
|
935
|
+
|
|
936
|
+
**Default use:** Number of pending insert operations
|
|
937
|
+
**Bank-switchable:** No
|
|
938
|
+
|
|
939
|
+
### $00D9-$00F2 — Screen line link table
|
|
940
|
+
|
|
941
|
+
**Default use:** 26-byte table — one entry per row plus a sentinel at $F2; bits 0-1 give the row's address high-byte offset, bit 7 set marks the start of a logical line
|
|
942
|
+
**Bank-switchable:** No
|
|
943
|
+
|
|
944
|
+
Bit 7 set means the row starts a logical line; clear means it is the
|
|
945
|
+
continuation of the row above (a fresh screen has bit 7 set on every
|
|
946
|
+
entry). The KERNAL walks this table to find a logical line's start and
|
|
947
|
+
length. (This page previously ended the table at $F1 and had a separate
|
|
948
|
+
"$00F2 — Insert mode count" entry; the KERNAL's fill loop at $E544
|
|
949
|
+
writes 26 entries and never addresses $F2 on its own — there is one
|
|
950
|
+
insert counter and it is $D8.)
|
|
951
|
+
|
|
952
|
+
### $00F3-$00F4 — Color RAM pointer
|
|
953
|
+
|
|
954
|
+
**Default use:** Pointer to current line's color RAM (PNT + $D800)
|
|
955
|
+
**Bank-switchable:** No
|
|
956
|
+
|
|
957
|
+
### $00F5-$00F6 — Keytable pointer
|
|
958
|
+
|
|
959
|
+
**Default use:** Pointer to one of four keyboard decode tables (selected by shift state)
|
|
960
|
+
**Bank-switchable:** No
|
|
961
|
+
|
|
962
|
+
### $00F7-$00F8 — RS-232 input buffer pointer
|
|
963
|
+
|
|
964
|
+
**Default use:** Pointer to user-allocated RS-232 input ring buffer
|
|
965
|
+
**Bank-switchable:** No
|
|
966
|
+
|
|
967
|
+
### $00F9-$00FA — RS-232 output buffer pointer
|
|
968
|
+
|
|
969
|
+
**Default use:** Pointer to user-allocated RS-232 output ring buffer
|
|
970
|
+
**Bank-switchable:** No
|
|
971
|
+
|
|
972
|
+
### $00FB-$00FE — Free zero-page
|
|
973
|
+
|
|
974
|
+
**Default use:** Unused by KERNAL or BASIC; 4 bytes of free zero-page for user code
|
|
975
|
+
**Bank-switchable:** No
|
|
976
|
+
|
|
977
|
+
**Notes:** Together with $02 these are the five zero-page bytes neither
|
|
978
|
+
ROM touches after reset (this page used to say $FB-$FE were the only
|
|
979
|
+
four). Assembly that coexists with BASIC should use $FB-$FE and $02 for
|
|
980
|
+
its hottest pointers.
|
|
981
|
+
|
|
982
|
+
### $00FF-$00FF — BASIC float-to-ASCII workspace
|
|
983
|
+
|
|
984
|
+
**Default use:** Temp byte used by BASIC's FOUT (float-to-string) routine
|
|
985
|
+
**Bank-switchable:** No
|
|
986
|
+
|
|
987
|
+
If BASIC's PRINT is not in use, $FF is free.
|
|
988
|
+
|
|
989
|
+
### $0100-$01FF — Stack page
|
|
990
|
+
|
|
991
|
+
**Default use:** 6510 hardware stack (S pointer descends from $01FF)
|
|
992
|
+
**Bank-switchable:** No
|
|
993
|
+
|
|
994
|
+
The 6510 has a single 8-bit stack pointer S that fixes the stack on
|
|
995
|
+
memory page 1 ($0100-$01FF). Pushes write to $0100+S then decrement S;
|
|
996
|
+
pulls increment S then read $0100+S. The stack grows downward from
|
|
997
|
+
$01FF toward $0100.
|
|
998
|
+
|
|
999
|
+
The KERNAL reset ($FCE2) sets S = $FF and hands over with JMP ($A000),
|
|
1000
|
+
leaving nothing of its own on the stack. It is BASIC that lowers it: the
|
|
1001
|
+
cold start sets S = $FB ($E39D), and CLR -- run by NEW, CLR, RUN and the
|
|
1002
|
+
RUN/STOP-RESTORE warm start via $A67A -- sets S = $FA ($A681). A routine
|
|
1003
|
+
entered by SYS sees four bytes less again (NEWSTT's return address and
|
|
1004
|
+
SYS's own pushed $E146): S = $F7 from immediate mode straight after a
|
|
1005
|
+
cold start, S = $F6 from a RUN BASIC stub. Measured in VICE x64sc 3.10
|
|
1006
|
+
against the ROM images; an earlier revision attributed the $FB to the
|
|
1007
|
+
KERNAL.
|
|
1008
|
+
|
|
1009
|
+
**Subdivisions:**
|
|
1010
|
+
|
|
1011
|
+
- $0100-$010F shared with tape buffer index in some workflows
|
|
1012
|
+
- $01FA-$01FF reserved for KERNAL's deepest pushes during reset
|
|
1013
|
+
- Floating-point ASCII conversion (BASIC's FOUT, $BDDD) uses $00FF-$010F
|
|
1014
|
+
as a temporary buffer — $0100-$010F from PRINT, $00FF-$010E from STR$
|
|
1015
|
+
(measured in VICE; *Mapping the C64* p. 39 gives $0100-$010A, which is
|
|
1016
|
+
five bytes short)
|
|
1017
|
+
|
|
1018
|
+
**Notes:**
|
|
1019
|
+
- **Stack overflow wraps.** If S decrements past $00, it wraps to $FF
|
|
1020
|
+
and overwrites the top of the stack page. There is no overflow trap.
|
|
1021
|
+
- **JSR pushes return-address-minus-one.** RTS pulls then increments.
|
|
1022
|
+
This affects manual stack manipulation.
|
|
1023
|
+
- BASIC uses *much* more of the stack than a typical assembly program,
|
|
1024
|
+
especially with deep GOSUBs and nested FOR loops. Each GOSUB pushes
|
|
1025
|
+
5 bytes; each FOR pushes 18 bytes.
|
|
1026
|
+
|
|
1027
|
+
### $0200-$0258 — BASIC input buffer (BUF)
|
|
1028
|
+
|
|
1029
|
+
**Default use:** Direct-mode keyboard input buffer; lines from screen end up here
|
|
1030
|
+
**Bank-switchable:** No
|
|
1031
|
+
|
|
1032
|
+
89-byte buffer. When you hit RETURN at the BASIC prompt, the screen line
|
|
1033
|
+
under the cursor is copied to $0200-$0258 (or until 89 chars or RETURN
|
|
1034
|
+
hits) and then tokenized.
|
|
1035
|
+
|
|
1036
|
+
### $0259-$0262 — Logical file table (LAT)
|
|
1037
|
+
|
|
1038
|
+
**Default use:** 10-entry table of logical file numbers passed to OPEN
|
|
1039
|
+
**Bank-switchable:** No
|
|
1040
|
+
|
|
1041
|
+
### $0263-$026C — Device number table (FAT)
|
|
1042
|
+
|
|
1043
|
+
**Default use:** Device numbers for each open logical file
|
|
1044
|
+
**Bank-switchable:** No
|
|
1045
|
+
|
|
1046
|
+
### $026D-$0276 — Secondary address table (SAT)
|
|
1047
|
+
|
|
1048
|
+
**Default use:** Secondary addresses for each open logical file
|
|
1049
|
+
**Bank-switchable:** No
|
|
1050
|
+
|
|
1051
|
+
### $0277-$0280 — Keyboard buffer (KEYD)
|
|
1052
|
+
|
|
1053
|
+
**Default use:** PETSCII keystrokes waiting to be consumed by GETIN; max 10 chars
|
|
1054
|
+
**Bank-switchable:** No
|
|
1055
|
+
|
|
1056
|
+
Stuff characters here and update NDX ($C6) to inject keystrokes — this
|
|
1057
|
+
is how autostart utilities feed BASIC a "LOAD..." command after reset.
|
|
1058
|
+
|
|
1059
|
+
### $0281-$0282 — MEMSTR (start of basic memory)
|
|
1060
|
+
|
|
1061
|
+
**Default use:** Lowest address BASIC can use (default $0800)
|
|
1062
|
+
**Bank-switchable:** No
|
|
1063
|
+
|
|
1064
|
+
### $0283-$0284 — MEMSIZ (top of memory)
|
|
1065
|
+
|
|
1066
|
+
**Default use:** Copy of top-of-RAM pointer set by MEMTOP at boot ($A000)
|
|
1067
|
+
**Bank-switchable:** No
|
|
1068
|
+
|
|
1069
|
+
### $0285-$0285 — IEC timeout
|
|
1070
|
+
|
|
1071
|
+
**Default use:** Serial bus timeout flag
|
|
1072
|
+
**Bank-switchable:** No
|
|
1073
|
+
|
|
1074
|
+
### $0286-$0286 — Current screen color (COLOR)
|
|
1075
|
+
|
|
1076
|
+
**Default use:** Current PRINT color — value 0-15 (next char printed uses this)
|
|
1077
|
+
**Bank-switchable:** No
|
|
1078
|
+
|
|
1079
|
+
Loaded by KERNAL CHROUT with the upper-nibble color of any color control
|
|
1080
|
+
char processed. Read by all subsequent PRINTs.
|
|
1081
|
+
|
|
1082
|
+
### $0287-$0287 — Color under cursor
|
|
1083
|
+
|
|
1084
|
+
**Default use:** Color RAM value the cursor is currently sitting over
|
|
1085
|
+
**Bank-switchable:** No
|
|
1086
|
+
|
|
1087
|
+
### $0288-$0288 — Screen memory page
|
|
1088
|
+
|
|
1089
|
+
**Default use:** High byte of current screen RAM start ($04 = $0400)
|
|
1090
|
+
**Bank-switchable:** No
|
|
1091
|
+
|
|
1092
|
+
Used by PLOT and CHROUT to compute screen addresses. Change this byte to
|
|
1093
|
+
move the screen to a different page; also update VIC-II $D018 and the
|
|
1094
|
+
line-link table to keep things consistent.
|
|
1095
|
+
|
|
1096
|
+
### $0289-$0289 — Keyboard buffer max size
|
|
1097
|
+
|
|
1098
|
+
**Default use:** Maximum chars allowed in keyboard buffer (default 10)
|
|
1099
|
+
**Bank-switchable:** No
|
|
1100
|
+
|
|
1101
|
+
Lower this to zero to disable keyboard input; raise it to extend buffer
|
|
1102
|
+
(buffer area is only 10 bytes; raising doesn't extend storage).
|
|
1103
|
+
|
|
1104
|
+
### $028A-$028A — Key repeat enable
|
|
1105
|
+
|
|
1106
|
+
**Default use:** Key-repeat mode (RPTFLG). Bit 7 set ($80) = all keys repeat; bit 6 set with bit 7 clear ($40) = no key repeats; $00 (the power-up value — RAMTAS clears it and nothing in the ROMs ever writes it) = only INST/DEL, SPACE and the four cursor keys repeat. Bit 7 wins when both are set (KERNAL $EAF2: BIT $028A / BMI / BVS, then CMP #$14/#$20/#$1D/#$11 — read from the 901227-03 ROM image; boot value measured in VICE x64sc). An earlier revision of this line had bit 6 and $00 the wrong way round.
|
|
1107
|
+
**Bank-switchable:** No
|
|
1108
|
+
|
|
1109
|
+
### $028B-$028C — Repeat speed counter / countdown
|
|
1110
|
+
|
|
1111
|
+
**Default use:** Frames between key repeats
|
|
1112
|
+
**Bank-switchable:** No
|
|
1113
|
+
|
|
1114
|
+
### $028D-$028D — Shift / Ctrl / C= state
|
|
1115
|
+
|
|
1116
|
+
**Default use:** Bitmask of shift modifier keys held down this frame
|
|
1117
|
+
**Bank-switchable:** No
|
|
1118
|
+
|
|
1119
|
+
| Value | Bit | Meaning |
|
|
1120
|
+
|-------|-----|------------------------------------------------------------------------------------------------------|
|
|
1121
|
+
| 1 | 0 | SHIFT — left shift, right shift or shift-lock, which the KERNAL does not distinguish (both matrix positions carry the value 1 in the $EB81 table) |
|
|
1122
|
+
| 2 | 1 | Commodore key |
|
|
1123
|
+
| 4 | 2 | CTRL |
|
|
1124
|
+
|
|
1125
|
+
There is no bit 3. The scanner ($EAB7) ORs the raw table values 1, 2 and
|
|
1126
|
+
4 into $028D and never stores those keys as the keypress; the value 3 at
|
|
1127
|
+
index 63 is RUN/STOP and is treated as an ordinary key. Table selection
|
|
1128
|
+
($EB48-$EB76): 0 -> unshifted $EB81, 1 -> shifted $EBC2, 2 -> C= $EC03,
|
|
1129
|
+
any value with CTRL set (4-7) -> CTRL $EC78. Value 3 (SHIFT+C=) does NOT
|
|
1130
|
+
go through that selector: on the frame it first appears, and unless
|
|
1131
|
+
$0291 bit 7 is set, the KERNAL flips $D018 bit 1 (upper/lower case) and
|
|
1132
|
+
decodes the key through the unshifted table, which $EA9B resets to $EB81
|
|
1133
|
+
at the start of every scan; while SHIFT+C= is held steady ($028D ==
|
|
1134
|
+
$028E) the scan exits at $EB42 without decoding any key. An earlier
|
|
1135
|
+
revision listed four bits (left shift, right shift, C=, CTRL as bits
|
|
1136
|
+
0-3); the values were read from kernal-901227-03.bin.
|
|
1137
|
+
|
|
1138
|
+
### $028E-$028E — Last shift state
|
|
1139
|
+
|
|
1140
|
+
**Default use:** Previous frame's $028D value (debouncing)
|
|
1141
|
+
**Bank-switchable:** No
|
|
1142
|
+
|
|
1143
|
+
### $028F-$0290 — Keyboard table-setup vector (KEYLOG)
|
|
1144
|
+
|
|
1145
|
+
**Default use:** Vector to the routine that selects the keyboard decode table from the shift state; default $EB48 (set by CINT at $E522)
|
|
1146
|
+
**Bank-switchable:** No
|
|
1147
|
+
|
|
1148
|
+
The keyscan calls it with JMP ($028F) at $EADD; the routine reads the
|
|
1149
|
+
shift/Ctrl/C= flags in $028D, picks one of the four tables listed at
|
|
1150
|
+
$EB79 ($EB81 unshifted, $EBC2 shifted, $EC03 C=, $EC78 Ctrl) and stores
|
|
1151
|
+
that address in $F5/$F6, then exits with JMP $EAE0, where the keyscan
|
|
1152
|
+
fetches the PETSCII code with LDY $CB / LDA ($F5),Y. To install custom
|
|
1153
|
+
key tables, point $028F/$0290 at a routine that does the same — leave
|
|
1154
|
+
the table address in $F5/$F6 and exit via JMP $EAE0 — rather than at a
|
|
1155
|
+
table: this vector holds a code address, not a table address. (An
|
|
1156
|
+
earlier version of this entry called it a pointer to the decode table
|
|
1157
|
+
itself; it never was — the table pointer is $F5/$F6, see $00F5-$00F6.
|
|
1158
|
+
Read from the 901227-03 ROM and confirmed in VICE: $028F/$0290 = $48 $EB
|
|
1159
|
+
at boot.)
|
|
1160
|
+
|
|
1161
|
+
### $0291-$0291 — Shift-lock / Commodore-shift switch
|
|
1162
|
+
|
|
1163
|
+
**Default use:** $00 = SHIFT+C= switches between upper/lower; $80 = locked
|
|
1164
|
+
**Bank-switchable:** No
|
|
1165
|
+
|
|
1166
|
+
### $0292-$0292 — Scroll-down flag
|
|
1167
|
+
|
|
1168
|
+
**Default use:** $00 enables auto-scroll on cursor down past line 24
|
|
1169
|
+
**Bank-switchable:** No
|
|
1170
|
+
|
|
1171
|
+
### $0293-$0297 — RS-232 workspace
|
|
1172
|
+
|
|
1173
|
+
**Default use:** Baud rate, parity, etc., for RS-232 implementation
|
|
1174
|
+
**Bank-switchable:** No
|
|
1175
|
+
|
|
1176
|
+
### $0298-$029B — RS-232 status + buffer pointers
|
|
1177
|
+
|
|
1178
|
+
**Default use:** Software UART internal state
|
|
1179
|
+
**Bank-switchable:** No
|
|
1180
|
+
|
|
1181
|
+
### $029C-$029F — RS-232 bit counters
|
|
1182
|
+
|
|
1183
|
+
**Default use:** Sample timing for software UART
|
|
1184
|
+
**Bank-switchable:** No
|
|
1185
|
+
|
|
1186
|
+
### $02A0-$02A1 — RS-232 timer constants
|
|
1187
|
+
|
|
1188
|
+
**Default use:** CIA-derived bit timing constants for RS-232
|
|
1189
|
+
**Bank-switchable:** No
|
|
1190
|
+
|
|
1191
|
+
### $02A2-$02A4 — Tape I/O temporaries
|
|
1192
|
+
|
|
1193
|
+
**Default use:** CIA #1 control/ICR images saved by the cassette code ($02A2 written at $F887 in the tape setup and read at $F911; $02A3 at $F94B/$F9B0 and $02A4 at $F917/$F9C0 in the tape read IRQ). Not RS-232: free only if you never touch tape.
|
|
1194
|
+
**Bank-switchable:** No
|
|
1195
|
+
|
|
1196
|
+
### $02A5-$02A5 — Screen scroll temporary
|
|
1197
|
+
|
|
1198
|
+
**Default use:** Line index used by the screen editor's scroll and insert-line code ($E8EA-$E9C2: $E8FC, $E935, $E96C, $E978, $E993, $E9AB, $E9BF). Clobbered by any PRINT that scrolls the screen, whatever RS-232 is doing.
|
|
1199
|
+
**Bank-switchable:** No
|
|
1200
|
+
|
|
1201
|
+
### $02A6-$02A6 — PAL/NTSC flag
|
|
1202
|
+
|
|
1203
|
+
**Default use:** 1 = PAL, 0 = NTSC. Written once by CINT ($FF5B: waits for $D012 = 0 after the VIC table set raster compare 311, then stores $D019 bit 0), read by IOINIT at $FDDD to pick the CIA #1 Timer A jiffy latch ($4025 PAL / $4295 NTSC) and by RS-232 OPEN at $F42C to pick the baud table. Leave it alone: RUN/STOP-RESTORE ($FE66) re-runs IOINIT but not CINT, so an overwritten flag is not re-derived and the jiffy clock and RS-232 timing switch to the other region (measured in VICE x64sc: storing 0 here and calling $FF84 on a PAL machine moves the Timer A latch from $4025 to $4295). Bit-exact in 901227-02 and -03; -01 has no detector and leaves this byte alone.
|
|
1204
|
+
**Bank-switchable:** No
|
|
1205
|
+
|
|
1206
|
+
### $02A7-$02FF — Unused
|
|
1207
|
+
|
|
1208
|
+
**Default use:** Free for user code. No KERNAL or BASIC ROM write touches this range (census of absolute operands in 901227-03 / 901226-01); the only reads are two `BIT $02A9` skip idioms at $EFCF and $F6FD that discard the value. RAMTAS clears it at reset. An earlier version of this page lumped $02A2-$02A6 into this range as "extra RS-232 workspace, safe if RS-232 is not in use"; five of those bytes belong to the tape driver, the screen editor and the PAL/NTSC flag.
|
|
1209
|
+
**Bank-switchable:** No
|
|
1210
|
+
|
|
1211
|
+
### $0300-$0301 — IERROR (BASIC error vector)
|
|
1212
|
+
|
|
1213
|
+
**Default use:** Pointer to BASIC's error-message routine; default $E38B
|
|
1214
|
+
**Bank-switchable:** No
|
|
1215
|
+
|
|
1216
|
+
Patch this to intercept all BASIC errors. The KERNAL hand-off into
|
|
1217
|
+
"ERROR" passes the error number in X.
|
|
1218
|
+
|
|
1219
|
+
### $0302-$0303 — IMAIN (BASIC warm-start vector)
|
|
1220
|
+
|
|
1221
|
+
**Default use:** Pointer to BASIC's input-loop routine; default $A483
|
|
1222
|
+
**Bank-switchable:** No
|
|
1223
|
+
|
|
1224
|
+
Default is the BASIC interpreter ready-prompt loop. Patch this to take
|
|
1225
|
+
control after every command.
|
|
1226
|
+
|
|
1227
|
+
### $0304-$0305 — ICRNCH (BASIC crunch / tokenize vector)
|
|
1228
|
+
|
|
1229
|
+
**Default use:** Pointer to BASIC's tokenize routine; default $A57C
|
|
1230
|
+
**Bank-switchable:** No
|
|
1231
|
+
|
|
1232
|
+
### $0306-$0307 — IQPLOP (BASIC LIST vector)
|
|
1233
|
+
|
|
1234
|
+
**Default use:** Pointer to BASIC's de-tokenize routine; default $A71A
|
|
1235
|
+
**Bank-switchable:** No
|
|
1236
|
+
|
|
1237
|
+
### $0308-$0309 — IGONE (BASIC execute-statement vector)
|
|
1238
|
+
|
|
1239
|
+
**Default use:** Pointer to BASIC's statement-dispatch routine; default $A7E4
|
|
1240
|
+
**Bank-switchable:** No
|
|
1241
|
+
|
|
1242
|
+
### $030A-$030B — IEVAL (BASIC expression evaluator)
|
|
1243
|
+
|
|
1244
|
+
**Default use:** Pointer to BASIC's expression evaluator; default $AE86
|
|
1245
|
+
**Bank-switchable:** No
|
|
1246
|
+
|
|
1247
|
+
### $030C-$030C — Saved A
|
|
1248
|
+
|
|
1249
|
+
**Default use:** Saved A register for SYS call argument-pass
|
|
1250
|
+
**Bank-switchable:** No
|
|
1251
|
+
|
|
1252
|
+
### $030D-$030D — Saved X
|
|
1253
|
+
|
|
1254
|
+
**Default use:** Saved X for SYS
|
|
1255
|
+
**Bank-switchable:** No
|
|
1256
|
+
|
|
1257
|
+
### $030E-$030E — Saved Y
|
|
1258
|
+
|
|
1259
|
+
**Default use:** Saved Y for SYS
|
|
1260
|
+
**Bank-switchable:** No
|
|
1261
|
+
|
|
1262
|
+
### $030F-$030F — Saved P (flags)
|
|
1263
|
+
|
|
1264
|
+
**Default use:** Saved status flags for SYS
|
|
1265
|
+
**Bank-switchable:** No
|
|
1266
|
+
|
|
1267
|
+
### $0310-$0312 — USR vector
|
|
1268
|
+
|
|
1269
|
+
**Default use:** USR()'s 3-byte jump instruction (JMP to user routine)
|
|
1270
|
+
**Bank-switchable:** No
|
|
1271
|
+
|
|
1272
|
+
The $4C opcode and the default target are installed by BASIC init
|
|
1273
|
+
($E3BF), not by USR(): USR() jumps *through* $0310 (its entry in the
|
|
1274
|
+
function-dispatch table at $A058 is $0310 itself, dispatched via the JMP
|
|
1275
|
+
that the same init writes at $54). The default target is $B248 = LDX
|
|
1276
|
+
#$0E / JMP $A437, i.e. ?ILLEGAL QUANTITY ERROR, so POKE 785/786 (lo/hi)
|
|
1277
|
+
with the routine address before calling USR(). An earlier version said
|
|
1278
|
+
USR() sets this vector.
|
|
1279
|
+
|
|
1280
|
+
### $0313-$0313 — Unused
|
|
1281
|
+
|
|
1282
|
+
**Default use:** Unused
|
|
1283
|
+
**Bank-switchable:** No
|
|
1284
|
+
|
|
1285
|
+
### $0314-$0315 — CINV (IRQ vector)
|
|
1286
|
+
|
|
1287
|
+
**Default use:** Pointer to IRQ handler; default $EA31
|
|
1288
|
+
**Bank-switchable:** No
|
|
1289
|
+
|
|
1290
|
+
**This is THE vector** for replacing the IRQ. Every C64 demo that does
|
|
1291
|
+
raster effects writes to $0314/$0315 to point at its own raster handler.
|
|
1292
|
+
|
|
1293
|
+
### $0316-$0317 — CBINV (BRK vector)
|
|
1294
|
+
|
|
1295
|
+
**Default use:** Pointer to BRK handler; default $FE66
|
|
1296
|
+
**Bank-switchable:** No
|
|
1297
|
+
|
|
1298
|
+
BRK instructions vector through here (which on a 6510 is the same line
|
|
1299
|
+
as IRQ; the handler reads the B flag to distinguish).
|
|
1300
|
+
|
|
1301
|
+
### $0318-$0319 — NMINV (NMI vector)
|
|
1302
|
+
|
|
1303
|
+
**Default use:** Pointer to NMI handler; default $FE47
|
|
1304
|
+
**Bank-switchable:** No
|
|
1305
|
+
|
|
1306
|
+
NMI fires on RESTORE key and on CIA #2 events. The default NMI handler
|
|
1307
|
+
checks for RUN/STOP+RESTORE (warm boot) and returns.
|
|
1308
|
+
|
|
1309
|
+
### $031A-$031B — IOPEN
|
|
1310
|
+
|
|
1311
|
+
**Default use:** Pointer to OPEN logic; default $F34A
|
|
1312
|
+
**Bank-switchable:** No
|
|
1313
|
+
|
|
1314
|
+
### $031C-$031D — ICLOSE
|
|
1315
|
+
|
|
1316
|
+
**Default use:** Pointer to CLOSE logic; default $F291
|
|
1317
|
+
**Bank-switchable:** No
|
|
1318
|
+
|
|
1319
|
+
### $031E-$031F — ICHKIN
|
|
1320
|
+
|
|
1321
|
+
**Default use:** Pointer to CHKIN logic; default $F20E
|
|
1322
|
+
**Bank-switchable:** No
|
|
1323
|
+
|
|
1324
|
+
### $0320-$0321 — ICKOUT
|
|
1325
|
+
|
|
1326
|
+
**Default use:** Pointer to CHKOUT logic; default $F250
|
|
1327
|
+
**Bank-switchable:** No
|
|
1328
|
+
|
|
1329
|
+
### $0322-$0323 — ICLRCH
|
|
1330
|
+
|
|
1331
|
+
**Default use:** Pointer to CLRCHN logic; default $F333
|
|
1332
|
+
**Bank-switchable:** No
|
|
1333
|
+
|
|
1334
|
+
### $0324-$0325 — IBASIN
|
|
1335
|
+
|
|
1336
|
+
**Default use:** Pointer to CHRIN; default $F157
|
|
1337
|
+
**Bank-switchable:** No
|
|
1338
|
+
|
|
1339
|
+
Patching IBASIN intercepts all input from any device.
|
|
1340
|
+
|
|
1341
|
+
### $0326-$0327 — IBSOUT
|
|
1342
|
+
|
|
1343
|
+
**Default use:** Pointer to CHROUT; default $F1CA
|
|
1344
|
+
**Bank-switchable:** No
|
|
1345
|
+
|
|
1346
|
+
Patching IBSOUT intercepts all output; the default lets KERNAL handle
|
|
1347
|
+
character output, but games and demos hook here to add character filters,
|
|
1348
|
+
implement custom screen managers, or capture printf-style debug streams.
|
|
1349
|
+
|
|
1350
|
+
### $0328-$0329 — ISTOP
|
|
1351
|
+
|
|
1352
|
+
**Default use:** Pointer to STOP-key check; default $F6ED
|
|
1353
|
+
**Bank-switchable:** No
|
|
1354
|
+
|
|
1355
|
+
### $032A-$032B — IGETIN
|
|
1356
|
+
|
|
1357
|
+
**Default use:** Pointer to GETIN; default $F13E
|
|
1358
|
+
**Bank-switchable:** No
|
|
1359
|
+
|
|
1360
|
+
### $032C-$032D — ICLALL
|
|
1361
|
+
|
|
1362
|
+
**Default use:** Pointer to CLALL; default $F32F
|
|
1363
|
+
**Bank-switchable:** No
|
|
1364
|
+
|
|
1365
|
+
### $032E-$032F — User vector (USRCMD)
|
|
1366
|
+
|
|
1367
|
+
**Default use:** Generic user-command vector; default $FE66
|
|
1368
|
+
**Bank-switchable:** No
|
|
1369
|
+
|
|
1370
|
+
### $0330-$0331 — ILOAD
|
|
1371
|
+
|
|
1372
|
+
**Default use:** Pointer to LOAD; default $F4A5
|
|
1373
|
+
**Bank-switchable:** No
|
|
1374
|
+
|
|
1375
|
+
Patching ILOAD is the classic way to install a fastloader: when BASIC's
|
|
1376
|
+
LOAD command runs, control goes through this vector instead of the
|
|
1377
|
+
ROM's IEC-bus byte-banging routine.
|
|
1378
|
+
|
|
1379
|
+
### $0332-$0333 — ISAVE
|
|
1380
|
+
|
|
1381
|
+
**Default use:** Pointer to SAVE; default $F5ED
|
|
1382
|
+
**Bank-switchable:** No
|
|
1383
|
+
|
|
1384
|
+
### $0334-$033B — Unused KERNAL workspace
|
|
1385
|
+
|
|
1386
|
+
**Default use:** Reserved; usually safe for user code
|
|
1387
|
+
**Bank-switchable:** No
|
|
1388
|
+
|
|
1389
|
+
### $033C-$03FB — Cassette tape buffer
|
|
1390
|
+
|
|
1391
|
+
**Default use:** 192-byte tape I/O buffer
|
|
1392
|
+
**Bank-switchable:** No
|
|
1393
|
+
|
|
1394
|
+
When the cassette is not in use, this 192-byte buffer is free RAM. It
|
|
1395
|
+
is a popular place to hide small machine-language routines (raster
|
|
1396
|
+
interrupt handlers, sprite editors). Programs that load themselves into
|
|
1397
|
+
this buffer and then exit can survive a tape LOAD.
|
|
1398
|
+
|
|
1399
|
+
### $03FC-$03FF — Unused / sound workspace
|
|
1400
|
+
|
|
1401
|
+
**Default use:** Free RAM in default configuration
|
|
1402
|
+
**Bank-switchable:** No
|
|
1403
|
+
|
|
1404
|
+
### $0400-$07E7 — Default screen RAM
|
|
1405
|
+
|
|
1406
|
+
**Default use:** 40 × 25 = 1000 screen-code character bytes
|
|
1407
|
+
**Bank-switchable:** No (always RAM; the *VIC* sees this address through its VIC bank)
|
|
1408
|
+
|
|
1409
|
+
The screen at $0400 is the default location after a cold boot. The
|
|
1410
|
+
VIC-II reads screen codes from here when fetching characters for the
|
|
1411
|
+
text display. Writing a character code (0-255) to $0400+row*40+col
|
|
1412
|
+
places that character on screen.
|
|
1413
|
+
|
|
1414
|
+
The screen code is *not* PETSCII — it is an 8-bit index into the
|
|
1415
|
+
character generator. In the default uppercase/graphics set, codes 0–31
|
|
1416
|
+
are @ A–Z [ £ ] ↑ ←, 32–63 are space, punctuation and the digits (48–57
|
|
1417
|
+
= 0–9), 64–127 are the graphics glyphs, and 128–255 are the same 128
|
|
1418
|
+
glyphs in reverse video. The lowercase set puts a–z at 1–26 and A–Z at
|
|
1419
|
+
65–90. See [Character ROM layout](#character-rom-layout) below (ranges
|
|
1420
|
+
read from chargen-901225-01.bin; an earlier revision linked a
|
|
1421
|
+
vic-ii-reference section that does not exist).
|
|
1422
|
+
|
|
1423
|
+
To move the screen: set the upper nibble of $D018 to the 1 KB slot
|
|
1424
|
+
inside the current VIC bank (upper nibble × 1 KB = screen offset from
|
|
1425
|
+
the base of the VIC bank; e.g. $D018 = $3x puts the screen at bank+$0C00,
|
|
1426
|
+
and the default $14 gives $0400). An earlier revision said 4 × upper
|
|
1427
|
+
nibble, which would have put the default screen at $1000; measured in
|
|
1428
|
+
VICE x64sc: $D018 = $34 displays $0C00 and $C4 displays $3000. Then
|
|
1429
|
+
update $0288 (the KERNAL's idea of screen page) and the line-link table
|
|
1430
|
+
at $D9-$F2.
|
|
1431
|
+
|
|
1432
|
+
### $07E8-$07F7 — Unused tail of the screen page
|
|
1433
|
+
|
|
1434
|
+
**Default use:** 16 bytes between the 1000-byte screen and the sprite pointers; the KERNAL neither clears nor uses them (measured in VICE x64sc: they still hold the RAM-init pattern after boot)
|
|
1435
|
+
**Bank-switchable:** No
|
|
1436
|
+
|
|
1437
|
+
### $07F8-$07FF — Default sprite pointers
|
|
1438
|
+
|
|
1439
|
+
**Default use:** 8 bytes — one sprite pointer per hardware sprite (0-7)
|
|
1440
|
+
**Bank-switchable:** No (RAM region; visible to VIC inside VIC bank)
|
|
1441
|
+
|
|
1442
|
+
The eight bytes at the *very end* of screen memory hold the sprite
|
|
1443
|
+
pointers. Each byte's value × 64 is the address (within the current
|
|
1444
|
+
VIC bank) of that sprite's 63-byte data block.
|
|
1445
|
+
|
|
1446
|
+
By default sprite 0's data pointer is at $07F8, sprite 1's at $07F9, etc.
|
|
1447
|
+
If you relocate the screen, the sprite pointers move too (always 1016
|
|
1448
|
+
bytes past the start of screen RAM). (An earlier version of this page
|
|
1449
|
+
headed this entry $07E8-$07FF, a 24-byte range; the pointers are the
|
|
1450
|
+
last 8 bytes of the 1 KB screen page, screen base + $3F8.)
|
|
1451
|
+
|
|
1452
|
+
### $0800-$9FFF — BASIC program area / general user RAM
|
|
1453
|
+
|
|
1454
|
+
**Default use:** Tokenized BASIC program + variables + free user RAM (38 KB = 38,912 bytes; 38,911 from $0801, the figure the boot screen prints — an earlier revision said 38.4 KB, which matches no byte count)
|
|
1455
|
+
**Bank-switchable:** No (always RAM; only $A000-$BFFF can swap to ROM)
|
|
1456
|
+
|
|
1457
|
+
**Subdivisions on cold boot:**
|
|
1458
|
+
|
|
1459
|
+
- $0800 = zero byte (BASIC program-start sentinel; mandatory)
|
|
1460
|
+
- $0801-VARTAB = tokenized BASIC program
|
|
1461
|
+
- VARTAB-ARYTAB = simple variables
|
|
1462
|
+
- ARYTAB-STREND = arrays
|
|
1463
|
+
- STREND-STRBOT = free RAM
|
|
1464
|
+
- STRBOT-MEMSIZ = string descriptor heap (grows down)
|
|
1465
|
+
|
|
1466
|
+
**Notes:**
|
|
1467
|
+
- A pure-assembly program with no BASIC stub can use $0801-$9FFF as 38 KB
|
|
1468
|
+
of contiguous free RAM.
|
|
1469
|
+
- Loading at $0801 with a BASIC stub like `1 SYS 2061` is the canonical
|
|
1470
|
+
way to autostart a machine-language program (2061 = $080D, the address
|
|
1471
|
+
just past the stub).
|
|
1472
|
+
- The screen at $0400-$07FF is a separate region — *not* part of the BASIC
|
|
1473
|
+
area despite being lower in memory.
|
|
1474
|
+
|
|
1475
|
+
### $0800-$0800 — BASIC start sentinel
|
|
1476
|
+
|
|
1477
|
+
**Default use:** Always $00; BASIC program-start marker
|
|
1478
|
+
**Bank-switchable:** No
|
|
1479
|
+
|
|
1480
|
+
### $0801-$9EFF — BASIC program + variables + free RAM
|
|
1481
|
+
|
|
1482
|
+
**Default use:** Tokenized BASIC + variables + heap
|
|
1483
|
+
**Bank-switchable:** No
|
|
1484
|
+
|
|
1485
|
+
### $9F00-$9FFF — Top of BASIC RAM (just below ROM boundary)
|
|
1486
|
+
|
|
1487
|
+
**Default use:** Last 256 bytes of contiguous free RAM before $A000 ROM/RAM switch
|
|
1488
|
+
**Bank-switchable:** No
|
|
1489
|
+
|
|
1490
|
+
### $A000-$BFFF — BASIC ROM region
|
|
1491
|
+
|
|
1492
|
+
**Default use:** 8 KB of BASIC interpreter ROM (when LORAM = 1 and HIRAM = 1)
|
|
1493
|
+
**Bank-switchable:** Yes — see [Bank switching](#bank-switching)
|
|
1494
|
+
|
|
1495
|
+
The BASIC interpreter lives here on a fresh boot. Bank out by clearing
|
|
1496
|
+
LORAM ($01 bit 0) to reveal the 8 KB of RAM underneath. The RAM is
|
|
1497
|
+
*always there* — writes to $A000-$BFFF always go to RAM. Reads return
|
|
1498
|
+
ROM bytes only when the BASIC ROM is banked in.
|
|
1499
|
+
|
|
1500
|
+
**Notes:**
|
|
1501
|
+
- This is the standard place to put a 256-cell character set (only need
|
|
1502
|
+
2 KB at $1000 or $3000 inside the VIC bank — but the underlying RAM
|
|
1503
|
+
here is sometimes used for sprite data or extra screen pages).
|
|
1504
|
+
- A 16 KB cartridge (EXROM = 0, GAME = 0) maps its ROMH here whenever
|
|
1505
|
+
HIRAM = 1, whatever LORAM is (modes 2, 3, 6 and 7); with HIRAM = 0 the
|
|
1506
|
+
range is RAM even with the cart present. See
|
|
1507
|
+
[Cartridge modes](#cartridge-modes-exrom--game). (This note used to
|
|
1508
|
+
point at 'modes 8 and 16': mode 8 is an 8 KB cart with all three port
|
|
1509
|
+
bits low and is all RAM, and mode 16 is Ultimax with ROMH at $E000 -
|
|
1510
|
+
measured in VICE x64sc, default C64C model, not on a bench.)
|
|
1511
|
+
|
|
1512
|
+
### $A000-$A00B — BASIC cold-start vectors
|
|
1513
|
+
|
|
1514
|
+
**Default use:** Cold-start jump table — first 12 bytes of BASIC ROM
|
|
1515
|
+
**Bank-switchable:** Yes
|
|
1516
|
+
|
|
1517
|
+
| Address | Content | Meaning |
|
|
1518
|
+
|----------|--------------|---------------------------------|
|
|
1519
|
+
| $A000 | $94 $E3 | Cold-start vector (jumps $E394) |
|
|
1520
|
+
| $A002 | $7B $E3 | Warm-start vector ($E37B) |
|
|
1521
|
+
| $A004 | $43 $42 $4D… | "CBMBASIC" ID string |
|
|
1522
|
+
|
|
1523
|
+
The cold-start vector at $A000-$A001 is where the KERNAL's reset routine
|
|
1524
|
+
ends up (`JMP ($A000)` at $FCFE, after IOINIT, RAMTAS, RESTOR and CINT).
|
|
1525
|
+
Cartridge auto-start does not involve $A000 at all. The reset routine
|
|
1526
|
+
($FCE2) first calls the signature check at $FD02, which compares
|
|
1527
|
+
$8004-$8008 with `$C3 $C2 $CD $38 $30` ("CBM80", held at $FD10) and, on
|
|
1528
|
+
a match, does `JMP ($8000)` — the cartridge *cold*-start vector — before
|
|
1529
|
+
any RAM or I/O initialisation. A cart ROM's first nine bytes are
|
|
1530
|
+
therefore: cold vector (2), warm vector (2), `CBM80` (5), at
|
|
1531
|
+
$8000-$8008. The warm vector at $8002 is taken by the RESTORE/NMI
|
|
1532
|
+
handler ($FE56: `JSR $FD02; BNE; JMP ($8002)`), and only when CIA #2 did
|
|
1533
|
+
not raise the NMI. See the $8000 pitfall below. (An earlier version of
|
|
1534
|
+
this page put the signature at $A000 and had reset jump through the warm
|
|
1535
|
+
vector; both were wrong — at reset $A000 is BASIC ROM, whose first bytes
|
|
1536
|
+
are the `$94 $E3 $7B $E3 'CBMBASIC'` shown above. Verified against
|
|
1537
|
+
kernal-901227-03 bytes and in VICE x64sc 3.10.)
|
|
1538
|
+
|
|
1539
|
+
### $A00C-$A389 — BASIC dispatch tables, keywords, messages
|
|
1540
|
+
|
|
1541
|
+
**Default use:** Statement dispatch ($A00C, entry-1), function dispatch ($A052), operator table, keyword text ($A09E), error messages, "OK"/"ERROR"/"IN"/"READY."/"BREAK" strings ($A364-$A389)
|
|
1542
|
+
**Bank-switchable:** Yes
|
|
1543
|
+
|
|
1544
|
+
### $A38A-$A47F — Stack search, memory checks, ERROR, READY
|
|
1545
|
+
|
|
1546
|
+
**Default use:** FOR-stack search ($A38A), stack/memory checks ($A3FB, $A408), ERROR ($A437 = JMP ($0300)), READY ($A474)
|
|
1547
|
+
**Bank-switchable:** Yes
|
|
1548
|
+
|
|
1549
|
+
### $A480-$A641 — BASIC main loop, line entry, CRUNCH
|
|
1550
|
+
|
|
1551
|
+
**Default use:** Main loop ($A480 = JMP ($0302), $A483), insert line, INLIN ($A560), CRUNCH ($A57C), FNDLIN ($A613)
|
|
1552
|
+
**Bank-switchable:** Yes
|
|
1553
|
+
|
|
1554
|
+
### $A642-$A741 — NEW, CLR, LIST
|
|
1555
|
+
|
|
1556
|
+
**Default use:** NEW ($A642), CLR ($A65E), LIST ($A69C, detokenize $A71A)
|
|
1557
|
+
**Bank-switchable:** Yes
|
|
1558
|
+
|
|
1559
|
+
### $A742-$A9A4 — FOR, statement loop, control-flow statements
|
|
1560
|
+
|
|
1561
|
+
**Default use:** FOR ($A742), NEWSTT/GONE ($A7AE/$A7E4), RESTORE ($A81D), STOP/END ($A82F/$A831), CONT ($A857), RUN ($A871), GOSUB ($A883), GOTO ($A8A0), RETURN ($A8D2), DATA ($A8F8), IF ($A928), REM ($A93B), ON ($A94B), LINGET
|
|
1562
|
+
**Bank-switchable:** Yes
|
|
1563
|
+
|
|
1564
|
+
### $A9A5-$AC05 — LET, PRINT, GET, INPUT
|
|
1565
|
+
|
|
1566
|
+
**Default use:** LET ($A9A5), PRINT# ($AA80), CMD ($AA86), PRINT ($AAA0), STROUT ($AB1E), GET ($AB7B), INPUT# ($ABA5), INPUT ($ABBF)
|
|
1567
|
+
**Bank-switchable:** Yes
|
|
1568
|
+
|
|
1569
|
+
### $AC06-$AD1D — READ
|
|
1570
|
+
|
|
1571
|
+
**Default use:** READ ($AC06) and its "?EXTRA IGNORED"/"?REDO FROM START" messages
|
|
1572
|
+
**Bank-switchable:** Yes
|
|
1573
|
+
|
|
1574
|
+
### $AD1E-$AD89 — NEXT
|
|
1575
|
+
|
|
1576
|
+
**Default use:** NEXT ($AD1E)
|
|
1577
|
+
**Bank-switchable:** Yes
|
|
1578
|
+
|
|
1579
|
+
### $AD8A-$B07D — Expression evaluator
|
|
1580
|
+
|
|
1581
|
+
**Default use:** FRMNUM ($AD8A), CHKNUM ($AD8D), FRMEVL ($AD9E), EVAL ($AE86), string concatenation entry via $ADE5
|
|
1582
|
+
**Bank-switchable:** Yes
|
|
1583
|
+
|
|
1584
|
+
### $B07E-$B08A — DIM
|
|
1585
|
+
|
|
1586
|
+
**Default use:** DIM (dispatch entry $B081)
|
|
1587
|
+
**Bank-switchable:** Yes
|
|
1588
|
+
|
|
1589
|
+
### $B08B-$B3B2 — Variable lookup, FRE, POS
|
|
1590
|
+
|
|
1591
|
+
**Default use:** PTRGET ($B08B) variable/array lookup, FRE ($B37D), POS ($B39E)
|
|
1592
|
+
**Bank-switchable:** Yes
|
|
1593
|
+
|
|
1594
|
+
### $B3B3-$B6DA — DEF/FN, string allocation, garbage collection
|
|
1595
|
+
|
|
1596
|
+
**Default use:** DEF/FN ($B3B3), STR$ ($B465), string allocation ($B475), garbage collection ($B526), concatenation ($B63D), string move ($B67A)
|
|
1597
|
+
**Bank-switchable:** Yes
|
|
1598
|
+
|
|
1599
|
+
### $B6DB-$B80C — String functions
|
|
1600
|
+
|
|
1601
|
+
**Default use:** CHR$ ($B6EC), LEFT$ ($B700), RIGHT$ ($B72C), MID$ ($B737), LEN ($B77C), ASC ($B78B), VAL ($B7AD), GETNUM/GETADR ($B7EB/$B7F7); the block opens with FRETMS ($B6DB), the string-descriptor-stack pop
|
|
1602
|
+
**Bank-switchable:** Yes
|
|
1603
|
+
|
|
1604
|
+
### $B80D-$BAE1 — PEEK/POKE/WAIT and the floating-point add/multiply package
|
|
1605
|
+
|
|
1606
|
+
**Default use:** PEEK ($B80D), POKE ($B824), WAIT ($B82D), FADDH/FSUB/FADD ($B849/$B850/$B867), LOG ($B9EA), FMULT ($BA28), CONUPK ($BA8C)
|
|
1607
|
+
**Bank-switchable:** Yes
|
|
1608
|
+
|
|
1609
|
+
This is the famous "Microsoft BASIC math". FADD is at $B867 (FADDT
|
|
1610
|
+
$B86A; FSUB $B850, FMULT $BA28, FDIV $BB0F, FIN $BCF3, FOUT $BDDD, SQR
|
|
1611
|
+
$BF71) — an earlier revision said $B6DB, which is FRETMS, the
|
|
1612
|
+
string-descriptor-stack pop. The package runs on past $BAE1 to EXP at
|
|
1613
|
+
$BFED, which ends with JMP $E000: SIN, COS, TAN, ATN and RND live in the
|
|
1614
|
+
KERNAL ROM ($E26B, $E264, $E2B4, $E30E, $E097). Demo coders sometimes
|
|
1615
|
+
bank in BASIC just to call these.
|
|
1616
|
+
|
|
1617
|
+
### $BAE2-$BFFF — Rest of the floating-point package (FIN, FOUT, SQR, EXP)
|
|
1618
|
+
|
|
1619
|
+
**Default use:** MUL10 ($BAE2), DIV10 ($BAFE), FDIV ($BB0F), MOVFM ($BBA2), MOVMF ($BBD4), MOVFA ($BBFC), MOVAF ($BC0C), SGN ($BC39), ABS ($BC58), FCOMP ($BC5B), INT ($BCCC), FIN ($BCF3), FOUT ($BDDD), SQR ($BF71), power, EXP ($BFED; ends with JMP $E000 and continues in the KERNAL ROM)
|
|
1620
|
+
**Bank-switchable:** Yes
|
|
1621
|
+
|
|
1622
|
+
An earlier version of this sub-map placed the string functions at $A9A5
|
|
1623
|
+
(that is LET), FIN/FOUT in $AF7E-$B6DA (they are at $BCF3/$BDDD) and
|
|
1624
|
+
"initialization, sign-on message" in $BAE2-$BFFF; BASIC's cold start
|
|
1625
|
+
($E394), warm start ($E37B), init ($E3BF), default vector table ($E447)
|
|
1626
|
+
and sign-on text ($E460ff), plus the LOAD/SAVE/VERIFY/SYS/OPEN/CLOSE
|
|
1627
|
+
statement handlers ($E12A-$E1C7) and RND/COS/SIN/TAN/ATN, live in the
|
|
1628
|
+
KERNAL ROM, where EXP also finishes. Ranges read from basic-901226-01.bin
|
|
1629
|
+
and kernal-901227-03.bin.
|
|
1630
|
+
|
|
1631
|
+
### $C000-$CFFF — Free RAM (never banked)
|
|
1632
|
+
|
|
1633
|
+
**Default use:** 4 KB of always-RAM, never overlaid by any ROM or I/O
|
|
1634
|
+
**Bank-switchable:** No
|
|
1635
|
+
|
|
1636
|
+
This 4 KB region is special: it is the **largest contiguous chunk of RAM
|
|
1637
|
+
guaranteed to be RAM in every bank configuration**. Cartridges can't map
|
|
1638
|
+
here; KERNAL doesn't touch it; BASIC doesn't use it.
|
|
1639
|
+
|
|
1640
|
+
Everyone uses $C000 for machine-language routines that need to coexist
|
|
1641
|
+
with BASIC. The canonical pattern is to write a BASIC loader that POKEs
|
|
1642
|
+
a small ML routine into $C000 and then SYS 49152 to call it.
|
|
1643
|
+
|
|
1644
|
+
**Notes:**
|
|
1645
|
+
- Some software uses $C800-$CFFF as a 2 KB custom character set since
|
|
1646
|
+
it falls within VIC bank 3 at $C000-$FFFF — but only after relocating
|
|
1647
|
+
the VIC bank. By default the VIC sees bank 0 ($0000-$3FFF) and would
|
|
1648
|
+
not fetch from $C000.
|
|
1649
|
+
- Cassette I/O does NOT use $C000-$CFFF (it uses $033C-$03FB only).
|
|
1650
|
+
|
|
1651
|
+
### $D000-$D02E — VIC-II registers
|
|
1652
|
+
|
|
1653
|
+
**Default use:** 47 VIC-II registers (when CHAREN = 1 and I/O is banked in)
|
|
1654
|
+
**Bank-switchable:** Yes — character ROM or RAM replaces this when CHAREN = 0
|
|
1655
|
+
|
|
1656
|
+
Full per-register details are in [vic-ii-reference.md](vic-ii-reference.md).
|
|
1657
|
+
|
|
1658
|
+
| Range | Function |
|
|
1659
|
+
|-------------|------------------------------------------------|
|
|
1660
|
+
| $D000-$D00F | Sprite X/Y positions (8 sprites × 2 bytes) |
|
|
1661
|
+
| $D010 | Sprite X MSBs |
|
|
1662
|
+
| $D011 | Screen control 1 / Y-scroll / display enable |
|
|
1663
|
+
| $D012 | Raster compare / current raster line |
|
|
1664
|
+
| $D013-$D014 | Light pen X, Y (latched) |
|
|
1665
|
+
| $D015 | Sprite enable |
|
|
1666
|
+
| $D016 | Screen control 2 / X-scroll / 38-col |
|
|
1667
|
+
| $D017 | Sprite Y expand |
|
|
1668
|
+
| $D018 | Memory pointers (video matrix / charset) |
|
|
1669
|
+
| $D019 | IRQ status (write 1 to clear) |
|
|
1670
|
+
| $D01A | IRQ mask |
|
|
1671
|
+
| $D01B | Sprite-to-background priority |
|
|
1672
|
+
| $D01C | Sprite multicolor enable |
|
|
1673
|
+
| $D01D | Sprite X expand |
|
|
1674
|
+
| $D01E-$D01F | Collision registers (sprite-sprite / sprite-BG)|
|
|
1675
|
+
| $D020-$D024 | Border + background colors |
|
|
1676
|
+
| $D025-$D026 | Sprite multicolor (shared) |
|
|
1677
|
+
| $D027-$D02E | Sprite 0-7 individual colors |
|
|
1678
|
+
|
|
1679
|
+
### $D02F-$D03F — VIC-II unused / shadow padding
|
|
1680
|
+
|
|
1681
|
+
**Default use:** Unused; reads as $FF
|
|
1682
|
+
**Bank-switchable:** Yes
|
|
1683
|
+
|
|
1684
|
+
### $D040-$D3FF — VIC-II shadow mirrors
|
|
1685
|
+
|
|
1686
|
+
**Default use:** $D000-$D03F repeats every 64 bytes through $D3FF
|
|
1687
|
+
**Bank-switchable:** Yes
|
|
1688
|
+
|
|
1689
|
+
Reading $D040 returns the same value as $D000, and so on. Avoid relying
|
|
1690
|
+
on this — direct-address all VIC writes in the $D000-$D03F window.
|
|
1691
|
+
|
|
1692
|
+
### $D400-$D418 — SID registers
|
|
1693
|
+
|
|
1694
|
+
**Default use:** 25 SID write registers (voice control, filter, master volume)
|
|
1695
|
+
**Bank-switchable:** Yes — character ROM or RAM replaces this when CHAREN = 0
|
|
1696
|
+
|
|
1697
|
+
Full per-register details are in [sid-reference.md](sid-reference.md).
|
|
1698
|
+
|
|
1699
|
+
| Range | Function |
|
|
1700
|
+
|-------------|------------------------------------------------|
|
|
1701
|
+
| $D400-$D406 | Voice 1 (freq lo/hi, pulse lo/hi, ctrl, AD, SR)|
|
|
1702
|
+
| $D407-$D40D | Voice 2 (same layout) |
|
|
1703
|
+
| $D40E-$D414 | Voice 3 (same layout) |
|
|
1704
|
+
| $D415-$D416 | Filter cutoff lo/hi |
|
|
1705
|
+
| $D417 | Filter resonance / voice routing |
|
|
1706
|
+
| $D418 | Master volume + filter type select |
|
|
1707
|
+
|
|
1708
|
+
### $D419-$D41C — SID read registers
|
|
1709
|
+
|
|
1710
|
+
**Default use:** Paddle X/Y, oscillator 3 / envelope 3 readback
|
|
1711
|
+
**Bank-switchable:** Yes
|
|
1712
|
+
|
|
1713
|
+
| Addr | Function |
|
|
1714
|
+
|--------|-------------------------------------------|
|
|
1715
|
+
| $D419 | Paddle X (POTX) |
|
|
1716
|
+
| $D41A | Paddle Y (POTY) |
|
|
1717
|
+
| $D41B | Voice 3 oscillator readback (OSC3) |
|
|
1718
|
+
| $D41C | Voice 3 envelope readback (ENV3) |
|
|
1719
|
+
|
|
1720
|
+
### $D41D-$D41F — SID unused
|
|
1721
|
+
|
|
1722
|
+
**Default use:** Reads return last data-bus value (open bus)
|
|
1723
|
+
**Bank-switchable:** Yes
|
|
1724
|
+
|
|
1725
|
+
### $D420-$D7FF — SID shadow mirrors
|
|
1726
|
+
|
|
1727
|
+
**Default use:** $D400-$D41F repeats every 32 bytes through $D7FF
|
|
1728
|
+
**Bank-switchable:** Yes
|
|
1729
|
+
|
|
1730
|
+
Like the VIC mirrors, every 32-byte block from $D420 onward is an alias
|
|
1731
|
+
of $D400-$D41F. The SID's last register $D41C cuts off at 29; writes to
|
|
1732
|
+
$D41D-$D41F have no effect.
|
|
1733
|
+
|
|
1734
|
+
### $D800-$DBE7 — Color RAM (visible 1000 bytes)
|
|
1735
|
+
|
|
1736
|
+
**Default use:** 4-bit color attribute per character cell on screen
|
|
1737
|
+
**Bank-switchable:** Yes — character ROM replaces this when CHAREN = 0
|
|
1738
|
+
|
|
1739
|
+
The Color RAM is a separate 1024 × 4-bit static RAM chip. Each byte
|
|
1740
|
+
corresponds positionally with screen RAM at $0400-$07E7: writing $1
|
|
1741
|
+
to $D800 makes the character at top-left ($0400) display as color 1
|
|
1742
|
+
(white).
|
|
1743
|
+
|
|
1744
|
+
Only the lower 4 bits matter; the upper 4 bits are open bus and read
|
|
1745
|
+
random values. *Always mask with #$0F when reading Color RAM*.
|
|
1746
|
+
|
|
1747
|
+
### $DBE8-$DBFF — Color RAM (unused 24 bytes)
|
|
1748
|
+
|
|
1749
|
+
**Default use:** 24 bytes of Color RAM not aligned with any visible cell
|
|
1750
|
+
**Bank-switchable:** Yes
|
|
1751
|
+
|
|
1752
|
+
The Color RAM is 1024 bytes but only 1000 cells are on screen. The
|
|
1753
|
+
trailing 24 bytes ($DBE8-$DBFF, immediately past the last screen cell at
|
|
1754
|
+
$DBE7) are still RAM and can hold 24 nibbles of program state. An
|
|
1755
|
+
earlier revision of this page headed this block $D8E8-$DBFF, which is a
|
|
1756
|
+
792-byte range starting at row 5, column 32 of the visible screen;
|
|
1757
|
+
$D800 + 1000 = $DBE8 is the first unused byte (measured in VICE x64sc: a
|
|
1758
|
+
write to $DBE7 colours cell 24/39, a write to $DBE8 colours nothing).
|
|
1759
|
+
|
|
1760
|
+
### $DC00-$DC0F — CIA #1 registers
|
|
1761
|
+
|
|
1762
|
+
**Default use:** Keyboard scan, joystick port 2, IRQ timer
|
|
1763
|
+
**Bank-switchable:** Yes — character ROM or RAM replaces this when CHAREN = 0
|
|
1764
|
+
|
|
1765
|
+
Full details in [cia-reference.md](cia-reference.md).
|
|
1766
|
+
|
|
1767
|
+
| Addr | Function |
|
|
1768
|
+
|--------|-------------------------------------------------|
|
|
1769
|
+
| $DC00 | Data port A (keyboard col output, joy 2) |
|
|
1770
|
+
| $DC01 | Data port B (keyboard row input, joy 1) |
|
|
1771
|
+
| $DC02 | Data direction A |
|
|
1772
|
+
| $DC03 | Data direction B |
|
|
1773
|
+
| $DC04 | Timer A low |
|
|
1774
|
+
| $DC05 | Timer A high |
|
|
1775
|
+
| $DC06 | Timer B low |
|
|
1776
|
+
| $DC07 | Timer B high |
|
|
1777
|
+
| $DC08 | TOD tenths |
|
|
1778
|
+
| $DC09 | TOD seconds |
|
|
1779
|
+
| $DC0A | TOD minutes |
|
|
1780
|
+
| $DC0B | TOD hours |
|
|
1781
|
+
| $DC0C | Serial shift register |
|
|
1782
|
+
| $DC0D | Interrupt control |
|
|
1783
|
+
| $DC0E | Control A |
|
|
1784
|
+
| $DC0F | Control B |
|
|
1785
|
+
|
|
1786
|
+
CIA #1's IRQ line drives the 6510's IRQ pin. The KERNAL's 60 Hz IRQ
|
|
1787
|
+
ticks via CIA #1 Timer A.
|
|
1788
|
+
|
|
1789
|
+
### $DC10-$DCFF — CIA #1 shadow mirrors
|
|
1790
|
+
|
|
1791
|
+
**Default use:** $DC00-$DC0F repeats every 16 bytes through $DCFF
|
|
1792
|
+
**Bank-switchable:** Yes
|
|
1793
|
+
|
|
1794
|
+
### $DD00-$DD0F — CIA #2 registers
|
|
1795
|
+
|
|
1796
|
+
**Default use:** Serial IEC bus, VIC-II bank select, RS-232 port, user port
|
|
1797
|
+
**Bank-switchable:** Yes
|
|
1798
|
+
|
|
1799
|
+
| Addr | Function |
|
|
1800
|
+
|--------|-------------------------------------------------|
|
|
1801
|
+
| $DD00 | Data port A (IEC bus + VIC-II bank select bits) |
|
|
1802
|
+
| $DD01 | Data port B (user port / RS-232) |
|
|
1803
|
+
| $DD02 | Data direction A |
|
|
1804
|
+
| $DD03 | Data direction B |
|
|
1805
|
+
| $DD04 | Timer A low |
|
|
1806
|
+
| $DD05 | Timer A high |
|
|
1807
|
+
| $DD06 | Timer B low |
|
|
1808
|
+
| $DD07 | Timer B high |
|
|
1809
|
+
| $DD08 | TOD tenths |
|
|
1810
|
+
| $DD09 | TOD seconds |
|
|
1811
|
+
| $DD0A | TOD minutes |
|
|
1812
|
+
| $DD0B | TOD hours |
|
|
1813
|
+
| $DD0C | Serial shift register |
|
|
1814
|
+
| $DD0D | Interrupt control |
|
|
1815
|
+
| $DD0E | Control A |
|
|
1816
|
+
| $DD0F | Control B |
|
|
1817
|
+
|
|
1818
|
+
CIA #2's IRQ line drives the 6510's NMI pin (not IRQ). The RESTORE key
|
|
1819
|
+
also pulls /NMI low — in parallel with CIA2's /IRQ, not through the CIA,
|
|
1820
|
+
so no $DD0D write touches it (this line used to say "through CIA #2";
|
|
1821
|
+
see `pitfalls/kernal-and-io.md` → `restore_nmi_not_maskable`).
|
|
1822
|
+
|
|
1823
|
+
**$DD00 bits 0-1** select the VIC-II bank, *inverted*:
|
|
1824
|
+
|
|
1825
|
+
| Bits | VIC bank | Address range |
|
|
1826
|
+
|------|----------|----------------|
|
|
1827
|
+
| 11 | 0 | $0000-$3FFF |
|
|
1828
|
+
| 10 | 1 | $4000-$7FFF |
|
|
1829
|
+
| 01 | 2 | $8000-$BFFF |
|
|
1830
|
+
| 00 | 3 | $C000-$FFFF |
|
|
1831
|
+
|
|
1832
|
+
### $DD10-$DDFF — CIA #2 shadow mirrors
|
|
1833
|
+
|
|
1834
|
+
**Default use:** $DD00-$DD0F repeats every 16 bytes through $DDFF
|
|
1835
|
+
**Bank-switchable:** Yes
|
|
1836
|
+
|
|
1837
|
+
### $DE00-$DEFF — I/O expansion area 1
|
|
1838
|
+
|
|
1839
|
+
**Default use:** Cartridge I/O area 1 (mapped only when a cartridge presents I/O)
|
|
1840
|
+
**Bank-switchable:** Yes — open bus when no cartridge present
|
|
1841
|
+
|
|
1842
|
+
On a bare machine, reads from $DE00-$DEFF return open-bus values
|
|
1843
|
+
(usually echoes of the most recent VIC fetch). Cartridges with an
|
|
1844
|
+
I/O space (REU, geoRAM, IDE64, etc.) decode their registers here.
|
|
1845
|
+
|
|
1846
|
+
### $DF00-$DFFF — I/O expansion area 2
|
|
1847
|
+
|
|
1848
|
+
**Default use:** Cartridge I/O area 2 (mapped only when a cartridge presents I/O)
|
|
1849
|
+
**Bank-switchable:** Yes — open bus when no cartridge present
|
|
1850
|
+
|
|
1851
|
+
Same logic as area 1. The REU at $DF00-$DF0A is the most prominent user.
|
|
1852
|
+
|
|
1853
|
+
### $E000-$FFFF — KERNAL ROM region
|
|
1854
|
+
|
|
1855
|
+
**Default use:** 8 KB of KERNAL ROM (when HIRAM = 1)
|
|
1856
|
+
**Bank-switchable:** Yes — bank out by clearing HIRAM ($01 bit 1)
|
|
1857
|
+
|
|
1858
|
+
Holds the I/O routines, IRQ handler, BRK handler, NMI handler,
|
|
1859
|
+
character output, screen editor, IEC bus driver, cassette driver, RS-232
|
|
1860
|
+
driver, and the public jump table at $FF81-$FFF5.
|
|
1861
|
+
|
|
1862
|
+
Writes to $E000-$FFFF go to RAM regardless of HIRAM. To use this 8 KB
|
|
1863
|
+
as RAM, bank out KERNAL and read it back: `LDA #$35 / STA $01` puts
|
|
1864
|
+
KERNAL out and I/O still in.
|
|
1865
|
+
|
|
1866
|
+
The sub-map below was rebuilt from the 901227-03 jump table and the
|
|
1867
|
+
$FD30 vector table because ten of its earlier headings named routines
|
|
1868
|
+
that live elsewhere — RESET at $FCE2 not $FCFC, RAMTAS at $FD50 not
|
|
1869
|
+
$FD90+, SCNKEY at $EA87 not $E4AC, the keyboard decode tables at
|
|
1870
|
+
$EB81-$ECB8 not $ECE7, SETMSG/MEMTOP/MEMBOT at $FE18/$FE25/$FE34 not
|
|
1871
|
+
$F130, the IRQ handler at $EA31-$EA86 not $E97D, and the cassette read
|
|
1872
|
+
IRQ at $F92C where "Disk LOAD/SAVE" stood. Every address below was read
|
|
1873
|
+
from the ROM image; the routine names are the conventional Commodore
|
|
1874
|
+
labels.
|
|
1875
|
+
|
|
1876
|
+
### $E000-$E393 — BASIC ROM continuation (EXP tail, RND, trig, BASIC I/O statements, warm start)
|
|
1877
|
+
|
|
1878
|
+
**Default use:** Not KERNAL code: EXP finishes here ($E000, entered by JMP from $BFED), the polynomial evaluator ($E043/$E059), RND ($E097), the SYS/SAVE/VERIFY/LOAD/OPEN/CLOSE statement handlers ($E12A-$E1C7), COS/SIN/TAN/ATN ($E264/$E26B/$E2B4/$E30E) and the RUN/STOP-RESTORE warm start ($E37B, reached through the $A002 vector)
|
|
1879
|
+
**Bank-switchable:** Yes
|
|
1880
|
+
|
|
1881
|
+
### $E394-$E4AB — BASIC cold start, init, default vectors, sign-on text
|
|
1882
|
+
|
|
1883
|
+
**Default use:** Cold start $E394 (the $A000 vector), CHRGET/RND-seed image $E3A2, init $E3BF (copies CHRGET to $73, installs $03-$06, $54 and $0310, snapshots MEMTOP), default BASIC vector table $E447 (copied to $0300-$030B), sign-on text $E460-$E4AB printed from $E473 (" BASIC BYTES FREE" precedes "**** COMMODORE 64 BASIC V2 ****", which starts at $E47E)
|
|
1884
|
+
**Bank-switchable:** Yes
|
|
1885
|
+
|
|
1886
|
+
### $E4AC-$E4FF — Revision patch area
|
|
1887
|
+
|
|
1888
|
+
**Default use:** Code added in 901227-02/-03: CHKOUT wrapper patch $E4AD (called from BASIC's $E118), RS-232 receive patch $E4D3, screen-clear colour $E4DA, FOUND-message pause $E4E0, PAL RS-232 baud table $E4EC; $E4B7-$E4D2 are unused ($AA fill)
|
|
1889
|
+
**Bank-switchable:** Yes
|
|
1890
|
+
|
|
1891
|
+
### $E500-$E5C9 — IOBASE, SCREEN, PLOT, CINT body, screen clear, VIC init
|
|
1892
|
+
|
|
1893
|
+
**Default use:** IOBASE $E500 (returns $DC00), SCREEN $E505 (40 × 25), PLOT $E50A, CINT body $E518 (sets $028F/$0290 = $EB48 and the editor defaults, then VIC init $E5A0 from the $ECB9 table), clear screen $E544 (also fills the $D9-$F2 link table), home $E566, cursor set-up $E56C, keyboard-buffer fetch $E5B4
|
|
1894
|
+
**Bank-switchable:** Yes
|
|
1895
|
+
|
|
1896
|
+
### $E5CA-$EA30 — Screen editor (keyboard/screen input, CHROUT screen body, scroll)
|
|
1897
|
+
|
|
1898
|
+
**Default use:** Keyboard input $E5CA, input from screen $E632, CHROUT's screen-device body $E716 (control codes, colour codes, cursor movement), scroll $E8EA, insert line $E965, screen-line set-up $E9F0, print-to-screen $EA13 and colour-pointer sync $EA24
|
|
1899
|
+
**Bank-switchable:** Yes
|
|
1900
|
+
|
|
1901
|
+
### $EA31-$EA86 — Default IRQ handler
|
|
1902
|
+
|
|
1903
|
+
**Default use:** The service routine $0314/$0315 points to: jiffy clock, cursor blink, tape-motor sense, keyboard scan, CIA #1 acknowledge, register restore and RTI
|
|
1904
|
+
**Bank-switchable:** Yes
|
|
1905
|
+
|
|
1906
|
+
The default IRQ handler at $EA31 is what $0314/$0315 points to. Read
|
|
1907
|
+
from the kernal-901227-03 ROM bytes, it:
|
|
1908
|
+
|
|
1909
|
+
1. Calls UDTIM ($FFEA -> $F69B) to bump the jiffy clock and sample the
|
|
1910
|
+
STOP key.
|
|
1911
|
+
2. Runs the cursor blink ($EA34-$EA60), skipped when $CC is non-zero.
|
|
1912
|
+
3. Handles the cassette-switch / tape-motor sense via $01 ($EA61-$EA79).
|
|
1913
|
+
4. Calls SCNKEY ($EA7B: JSR $EA87).
|
|
1914
|
+
5. Reads $DC0D to acknowledge CIA #1 — last, at $EA7E.
|
|
1915
|
+
6. Restores Y, X and A and RTIs ($EA81-$EA86).
|
|
1916
|
+
|
|
1917
|
+
Replacing $0314/$0315 with your own handler lets you intercept this
|
|
1918
|
+
sequence — typically you JMP $EA31 to run the whole service after your
|
|
1919
|
+
raster routine completes, or JMP $EA81 for the bare register-restore
|
|
1920
|
+
exit. $EA7E is not a cursor-skipping shortcut: it is the
|
|
1921
|
+
acknowledge-and-exit tail (LDA $DC0D, then $EA81's PLA/TAY/PLA/TAX/PLA/
|
|
1922
|
+
RTI), so entering there skips the jiffy clock, the STOP-key sense and
|
|
1923
|
+
the keyboard scan as well as the cursor. Measured in VICE x64sc: with
|
|
1924
|
+
$0314 pointed at $EA7E, TI did not advance in one second (0 jiffies,
|
|
1925
|
+
against 64 through $EA31). An earlier version of this page listed the
|
|
1926
|
+
$DC0D read first and described $EA7E as a shorter path that skipped only
|
|
1927
|
+
the cursor; the ROM bytes say otherwise.
|
|
1928
|
+
|
|
1929
|
+
### $EA87-$ECE6 — SCNKEY keyboard scanner, key decode and key tables
|
|
1930
|
+
|
|
1931
|
+
**Default use:** SCNKEY body $EA87 (jump table $FF9F; $EA9B resets the table pointer to $EB81), KEYLOG table-select routine $EB48 (reached via $028F/$0290; toggles $D018 bit 1 on SHIFT+C= at $EB5E), table pointers $EB79, decode tables $EB81 (unshifted), $EBC2 (shifted), $EC03 (C=), the CHR$(14)/CHR$(142) case switch $EC44-$EC5B, CTRL table $EC78-$ECB8, 47-byte VIC-II power-on register table $ECB9-$ECE6
|
|
1932
|
+
**Bank-switchable:** Yes
|
|
1933
|
+
|
|
1934
|
+
### $ECE7-$ED08 — "LOAD/RUN" string and screen-line low-byte table
|
|
1935
|
+
|
|
1936
|
+
**Default use:** $ECE7-$ECEF is the PETSCII string `LOAD<CR>RUN<CR>` that SHIFT+RUN/STOP stuffs into the keyboard buffer; $ECF0-$ED08 is the 25-entry table of screen-line start low bytes ($00 $28 $50 …). Not the keyboard decode tables, which are at $EB81-$ECB8 — an earlier version of this page labelled this range KEYTAB
|
|
1937
|
+
**Bank-switchable:** Yes
|
|
1938
|
+
|
|
1939
|
+
### $ED09-$EEBA — IEC bus driver
|
|
1940
|
+
|
|
1941
|
+
**Default use:** TALK $ED09, LISTEN $ED0C, SECOND $EDB9, TKSA $EDC7, IECOUT $EDDD, UNTLK $EDEF, UNLSN $EDFE, IECIN $EE13, clock/data line helpers to $EEB2, 1 ms delay $EEB3 — the only span of the ROM that touches $DD00
|
|
1942
|
+
**Bank-switchable:** Yes
|
|
1943
|
+
|
|
1944
|
+
### $EEBB-$F0BC — RS-232 driver
|
|
1945
|
+
|
|
1946
|
+
**Default use:** Software UART: send $EEBB, receive, buffer handling; driven from CIA #2 timers through the NMI and touching only $DD01/$DD0D. (An earlier version of this page began the RS-232 driver at $EF94 and ran the IEC driver to $EF93; the IEC code ends at $EEBA.)
|
|
1947
|
+
**Bank-switchable:** Yes
|
|
1948
|
+
|
|
1949
|
+
### $F0BD-$F12A — KERNAL message text
|
|
1950
|
+
|
|
1951
|
+
**Default use:** The control/error message table: I/O ERROR #, SEARCHING FOR, PRESS PLAY ON TAPE, PRESS RECORD & PLAY ON TAPE, LOADING, SAVING, VERIFYING, FOUND, OK (bit 7 set on the last character of each)
|
|
1952
|
+
**Bank-switchable:** Yes
|
|
1953
|
+
|
|
1954
|
+
### $F12B-$F349 — Message printer, GETIN, CHRIN, CHROUT, CHKIN, CHKOUT, CLOSE, CLALL, CLRCHN
|
|
1955
|
+
|
|
1956
|
+
**Default use:** Message printer $F12B (tests $9D bit 7; $F12F prints unconditionally), GETIN $F13E, CHRIN $F157, CHROUT $F1CA, CHKIN $F20E, CHKOUT $F250, CLOSE $F291, CLALL $F32F, CLRCHN $F333 (RTS at $F349). STATUS/SETMSG/MEMTOP/MEMBOT are not here — READST is $FE07, SETMSG $FE18, MEMTOP $FE25, MEMBOT $FE34; an earlier version of this page headed $F130-$F156 with those names
|
|
1957
|
+
**Bank-switchable:** Yes
|
|
1958
|
+
|
|
1959
|
+
### $F34A-$F49D — OPEN
|
|
1960
|
+
|
|
1961
|
+
**Default use:** OPEN body $F34A (the $031A default), including the RS-232 OPEN path $F409
|
|
1962
|
+
**Bank-switchable:** Yes
|
|
1963
|
+
|
|
1964
|
+
### $F49E-$F5DC — LOAD
|
|
1965
|
+
|
|
1966
|
+
**Default use:** LOAD entry $F49E (stores X/Y to $C3/$C4, then JMP ($0330) → body $F4A5, the $0330 default); serial LOAD falls through at $F4B8, tape LOAD branches at $F4B6 to $F533. VERIFY is LOAD with A = 1
|
|
1967
|
+
**Bank-switchable:** Yes
|
|
1968
|
+
|
|
1969
|
+
### $F5DD-$F69A — SAVE
|
|
1970
|
+
|
|
1971
|
+
**Default use:** SAVE entry $F5DD (stores the end address to $AE/$AF, then JMP ($0332) → body $F5ED, the $0332 default)
|
|
1972
|
+
**Bank-switchable:** Yes
|
|
1973
|
+
|
|
1974
|
+
### $F69B-$F6FA — UDTIM, RDTIM, SETTIM, STOP
|
|
1975
|
+
|
|
1976
|
+
**Default use:** UDTIM $F69B (jiffy increment, then the STOP-key sample at $F6BC that debounces $DC01 row 7 into $91), RDTIM $F6DD, SETTIM $F6E4, STOP $F6ED (the $0328 default). An earlier version headed $F69C-$F7AF "VERIFY, MEMTOP/MEMBOT defaults"; VERIFY is a LOAD mode and MEMTOP/MEMBOT are at $FE25/$FE34
|
|
1977
|
+
**Bank-switchable:** Yes
|
|
1978
|
+
|
|
1979
|
+
### $F6FB-$F92B — I/O error entries, tape header handling, tape prompts
|
|
1980
|
+
|
|
1981
|
+
**Default use:** I/O error entry points $F6FB-$F713 (errors 1-9 → "I/O ERROR #n" through the $9D bit-6 test), tape header find $F72C and write $F76A, buffer address helpers $F7D0, PRESS PLAY $F817 / PRESS RECORD $F838 prompts (printed unconditionally through $F12F), tape read/write set-up $F841/$F864
|
|
1982
|
+
**Bank-switchable:** Yes
|
|
1983
|
+
|
|
1984
|
+
### $F92C-$FBCC — Cassette read IRQ
|
|
1985
|
+
|
|
1986
|
+
**Default use:** The tape READ interrupt service $F92C (installed from the $FD9B vector table; measures pulse widths on CIA #1 Timer B) and the byte-store routine $FA60. Not disk I/O: this span references CIA #1 sixteen times and CIA #2 never; an earlier version of this page headed $F901-$FB54 "Disk LOAD/SAVE (IEC-bus protocol)" — the serial path is inside LOAD/SAVE above
|
|
1987
|
+
**Bank-switchable:** Yes
|
|
1988
|
+
|
|
1989
|
+
### $FBCD-$FCE1 — Cassette write IRQs and tape housekeeping
|
|
1990
|
+
|
|
1991
|
+
**Default use:** Tape WRITE interrupt services ($FBCD data, $FC6A leader), leader/bit timing, restore normal IRQ and screen $FC93, tape motor off $FCCA, read/write pointer compare and bump $FCD1/$FCDB
|
|
1992
|
+
**Bank-switchable:** Yes
|
|
1993
|
+
|
|
1994
|
+
### $FCE2-$FD4F — RESET, cartridge check, RESTOR, VECTOR, default vector table
|
|
1995
|
+
|
|
1996
|
+
**Default use:** RESET $FCE2 (the $FFFC vector: LDX #$FF / SEI / TXS / CLD, cartridge check, then IOINIT, RAMTAS, RESTOR, CINT, CLI, JMP ($A000)), cartridge signature check $FD02 comparing $8004-$8008 with "CBM80" at $FD10, RESTOR $FD15, VECTOR $FD1A, 16-word default vector table $FD30-$FD4F copied to $0314-$0333. An earlier version headed $FCFC-$FD2F "RESET handler" and $FD30-$FD8F "vectors initialization"; RESET is $FCE2 and $FD30 is the table, not code
|
|
1997
|
+
**Bank-switchable:** Yes
|
|
1998
|
+
|
|
1999
|
+
The first code that runs after the CPU comes out of reset is $FCE2,
|
|
2000
|
+
entered via the reset vector at $FFFC.
|
|
2001
|
+
|
|
2002
|
+
### $FD50-$FDF8 — RAMTAS, tape IRQ vector table, IOINIT
|
|
2003
|
+
|
|
2004
|
+
**Default use:** RAMTAS $FD50 (clears $0002-$0101 and $0200-$03FF, finds top of memory, sets $B2/$B3, $0282, $0288), tape-IRQ vector table $FD9B ($FC6A, $FBCD, $EA31, $F92C), IOINIT $FDA3 (CIA set-up, $01/$00 = $E7/$2F at $FDD5, jiffy timer latch from $02A6 at $FDDD, continued at $FF6E)
|
|
2005
|
+
**Bank-switchable:** Yes
|
|
2006
|
+
|
|
2007
|
+
### $FDF9-$FE42 — SETNAM, SETLFS, READST, SETMSG, SETTMO, MEMTOP, MEMBOT
|
|
2008
|
+
|
|
2009
|
+
**Default use:** SETNAM $FDF9, SETLFS $FE00, READST $FE07 (RS-232 status from $0297 when the device is 2), SETMSG $FE18 (STA $9D), SETTMO $FE21, MEMTOP $FE25, MEMBOT $FE34
|
|
2010
|
+
**Bank-switchable:** Yes
|
|
2011
|
+
|
|
2012
|
+
### $FE43-$FF42 — NMI handler, RUN/STOP-RESTORE warm start, RS-232 NMI paths
|
|
2013
|
+
|
|
2014
|
+
**Default use:** NMI entry $FE43 (SEI, JMP ($0318)); default handler $FE47 (acknowledges CIA #2, cartridge check, STOP-key test); warm start $FE66 (RESTOR, IOINIT, CINT, JMP ($A002)); NMI exit $FEBC; RS-232 baud-rate table $FEC2; RS-232 NMI receive $FED6 and send $FF07
|
|
2015
|
+
**Bank-switchable:** Yes
|
|
2016
|
+
|
|
2017
|
+
### $FF43-$FF7F — IRQ/BRK dispatcher, CINT wrapper, IOINIT tail
|
|
2018
|
+
|
|
2019
|
+
**Default use:** Fake-IRQ entry $FF43 (PHP / PLA / AND #$EF / PHA, falling into) the dispatcher $FF48 (the $FFFE vector: saves A, X, Y, tests the pushed B flag, JMP ($0316) or JMP ($0314)); CINT wrapper $FF5B (the $FF81 target: JSR $E518, PAL/NTSC detect into $02A6, JMP $FDDD); IOINIT timer-start tail $FF6E (reached by JMP from $FDF6)
|
|
2020
|
+
**Bank-switchable:** Yes
|
|
2021
|
+
|
|
2022
|
+
### $FF80-$FF80 — KERNAL revision byte
|
|
2023
|
+
|
|
2024
|
+
**Default use:** $AA in 901227-01, $00 in -02, $03 in -03 (PEEK(65408))
|
|
2025
|
+
**Bank-switchable:** Yes
|
|
2026
|
+
|
|
2027
|
+
### $FF81-$FFA5 — KERNAL routine jump table (Editor + new)
|
|
2028
|
+
|
|
2029
|
+
**Default use:** Public jump table entries for CINT, IOINIT, RAMTAS, RESTOR, VECTOR
|
|
2030
|
+
**Bank-switchable:** Yes
|
|
2031
|
+
|
|
2032
|
+
| $FF81 | CINT | Initialize screen editor |
|
|
2033
|
+
| $FF84 | IOINIT | Initialize I/O |
|
|
2034
|
+
| $FF87 | RAMTAS | Initialize RAM, allocate workspace |
|
|
2035
|
+
| $FF8A | RESTOR | Restore default I/O vectors |
|
|
2036
|
+
| $FF8D | VECTOR | Read/set indirect vectors |
|
|
2037
|
+
| $FF90 | SETMSG | Control KERNAL messages |
|
|
2038
|
+
| $FF93 | SECOND | Send secondary address after LISTEN |
|
|
2039
|
+
| $FF96 | TKSA | Send secondary address after TALK |
|
|
2040
|
+
| $FF99 | MEMTOP | Set/read top of memory |
|
|
2041
|
+
| $FF9C | MEMBOT | Set/read bottom of memory |
|
|
2042
|
+
| $FF9F | SCNKEY | Scan keyboard |
|
|
2043
|
+
| $FFA2 | SETTMO | Set IEC bus timeout |
|
|
2044
|
+
|
|
2045
|
+
### $FFA5-$FFC0 — KERNAL jump table (IEC bus)
|
|
2046
|
+
|
|
2047
|
+
**Default use:** IEC bus jump entries
|
|
2048
|
+
**Bank-switchable:** Yes
|
|
2049
|
+
|
|
2050
|
+
| $FFA5 | IECIN | Read byte from IEC bus |
|
|
2051
|
+
| $FFA8 | IECOUT | Write byte to IEC bus |
|
|
2052
|
+
| $FFAB | UNTLK | Send UNTALK on IEC bus |
|
|
2053
|
+
| $FFAE | UNLSN | Send UNLISTEN on IEC bus |
|
|
2054
|
+
| $FFB1 | LISTEN | Command device on IEC to LISTEN |
|
|
2055
|
+
| $FFB4 | TALK | Command device on IEC to TALK |
|
|
2056
|
+
| $FFB7 | READST | Read I/O STATUS |
|
|
2057
|
+
| $FFBA | SETLFS | Set logical file params |
|
|
2058
|
+
| $FFBD | SETNAM | Set filename |
|
|
2059
|
+
|
|
2060
|
+
### $FFC0-$FFE5 — KERNAL jump table (File I/O + Char I/O)
|
|
2061
|
+
|
|
2062
|
+
**Default use:** Public entry points for KERNAL routines
|
|
2063
|
+
**Bank-switchable:** Yes
|
|
2064
|
+
|
|
2065
|
+
| $FFC0 | OPEN | Open a logical file |
|
|
2066
|
+
| $FFC3 | CLOSE | Close a logical file |
|
|
2067
|
+
| $FFC6 | CHKIN | Set input channel |
|
|
2068
|
+
| $FFC9 | CHKOUT | Set output channel |
|
|
2069
|
+
| $FFCC | CLRCHN | Restore default I/O |
|
|
2070
|
+
| $FFCF | CHRIN | Get char from current input |
|
|
2071
|
+
| $FFD2 | CHROUT | Output char to current output |
|
|
2072
|
+
| $FFD5 | LOAD | Load file from device |
|
|
2073
|
+
| $FFD8 | SAVE | Save file to device |
|
|
2074
|
+
| $FFDB | SETTIM | Set jiffy clock |
|
|
2075
|
+
| $FFDE | RDTIM | Read jiffy clock |
|
|
2076
|
+
| $FFE1 | STOP | Check if STOP key pressed |
|
|
2077
|
+
| $FFE4 | GETIN | Get char from queue (non-blocking) |
|
|
2078
|
+
|
|
2079
|
+
### $FFE6-$FFF5 — KERNAL jump table (close-all, etc.)
|
|
2080
|
+
|
|
2081
|
+
**Default use:** Final entries of the public jump table
|
|
2082
|
+
**Bank-switchable:** Yes
|
|
2083
|
+
|
|
2084
|
+
| $FFE7 | CLALL | Close all files |
|
|
2085
|
+
| $FFEA | UDTIM | Update jiffy clock + STOP flag |
|
|
2086
|
+
| $FFED | SCREEN | Return screen dimensions |
|
|
2087
|
+
| $FFF0 | PLOT | Read/set cursor row/col |
|
|
2088
|
+
| $FFF3 | IOBASE | Return base address of CIA #1 |
|
|
2089
|
+
|
|
2090
|
+
### $FFF6-$FFF9 — Unused
|
|
2091
|
+
|
|
2092
|
+
**Default use:** Four bytes not reached by any code: $52 $52 $42 $59 in 901227-03
|
|
2093
|
+
**Bank-switchable:** Yes
|
|
2094
|
+
|
|
2095
|
+
### $FFFA-$FFFB — NMI vector
|
|
2096
|
+
|
|
2097
|
+
**Default use:** Pointer to NMI handler ($FE43 in KERNAL ROM)
|
|
2098
|
+
**Bank-switchable:** Yes — if KERNAL banked out, this is RAM and you must write your own vector
|
|
2099
|
+
|
|
2100
|
+
The CPU reads $FFFA/$FFFB on every NMI to find the handler address. In
|
|
2101
|
+
the default config this is in KERNAL ROM and points to the chained NMI
|
|
2102
|
+
handler that dispatches through $0318.
|
|
2103
|
+
|
|
2104
|
+
### $FFFC-$FFFD — Reset vector
|
|
2105
|
+
|
|
2106
|
+
**Default use:** Pointer to RESET handler ($FCE2 in KERNAL ROM)
|
|
2107
|
+
**Bank-switchable:** Yes
|
|
2108
|
+
|
|
2109
|
+
Read by the CPU on power-on and on the hardware RESET line.
|
|
2110
|
+
|
|
2111
|
+
### $FFFE-$FFFF — IRQ / BRK vector
|
|
2112
|
+
|
|
2113
|
+
**Default use:** Pointer to IRQ/BRK handler ($FF48 in KERNAL ROM)
|
|
2114
|
+
**Bank-switchable:** Yes — if KERNAL banked out, must point at user-supplied handler
|
|
2115
|
+
|
|
2116
|
+
The CPU reads $FFFE/$FFFF on every IRQ and BRK. With KERNAL banked in,
|
|
2117
|
+
this points at $FF48 which saves registers and then JMPs through
|
|
2118
|
+
$0314 (IRQ) or $0316 (BRK).
|
|
2119
|
+
|
|
2120
|
+
**Crucial:** If you bank out KERNAL ROM ($01 = $35 or lower) and IRQ
|
|
2121
|
+
fires, the CPU reads $FFFE/$FFFF *from RAM*. You must have pre-loaded
|
|
2122
|
+
RAM bytes at $FFFE/$FFFF with the address of your own IRQ handler before
|
|
2123
|
+
banking out, or the machine will crash. Same for NMI ($FFFA/$FFFB) and
|
|
2124
|
+
RESET ($FFFC/$FFFD).
|
|
2125
|
+
|
|
2126
|
+
## Bank switching
|
|
2127
|
+
|
|
2128
|
+
The 6510 sees a 64 KB address space but the C64 holds more memory than
|
|
2129
|
+
that. The PLA (programmable logic array, MOS 906114) decides, at every
|
|
2130
|
+
memory access, which physical resource the CPU is talking to. Its
|
|
2131
|
+
inputs are:
|
|
2132
|
+
|
|
2133
|
+
- **A15-A12** — the high nibble of the address bus, which selects the
|
|
2134
|
+
4 KB chunk.
|
|
2135
|
+
- **R/W** — distinguishes reads from writes.
|
|
2136
|
+
- **LORAM, HIRAM, CHAREN** — the three configurable processor-port pins
|
|
2137
|
+
from $01 bits 0, 1, 2.
|
|
2138
|
+
- **GAME, EXROM** — the two cartridge-port lines, pulled high (1) when
|
|
2139
|
+
no cart is present.
|
|
2140
|
+
|
|
2141
|
+
The PLA hardwires 32 possible input combinations into seven distinct
|
|
2142
|
+
output configurations (plus a few cartridge-only modes). These are the
|
|
2143
|
+
**memory modes** — sometimes called **banks** in PLA literature.
|
|
2144
|
+
|
|
2145
|
+
Software running on a bare C64 (no cart) sees five practically-useful
|
|
2146
|
+
configurations and two rarely-used edge cases.
|
|
2147
|
+
|
|
2148
|
+
### Mode 31 — default (BASIC + KERNAL + I/O)
|
|
2149
|
+
|
|
2150
|
+
**$01 value:** $37 (or any value with bits 0-2 = 111)
|
|
2151
|
+
**LORAM:** 1, **HIRAM:** 1, **CHAREN:** 1
|
|
2152
|
+
|
|
2153
|
+
| Range | Contents |
|
|
2154
|
+
|--------------|--------------|
|
|
2155
|
+
| $0000-$0FFF | RAM |
|
|
2156
|
+
| $1000-$7FFF | RAM |
|
|
2157
|
+
| $8000-$9FFF | RAM |
|
|
2158
|
+
| $A000-$BFFF | BASIC ROM |
|
|
2159
|
+
| $C000-$CFFF | RAM |
|
|
2160
|
+
| $D000-$DFFF | I/O |
|
|
2161
|
+
| $E000-$FFFF | KERNAL ROM |
|
|
2162
|
+
|
|
2163
|
+
The mode the machine boots into. BASIC visible, KERNAL visible, I/O
|
|
2164
|
+
visible at $D000-$DFFF.
|
|
2165
|
+
|
|
2166
|
+
### Mode 30 — KERNAL + I/O (BASIC banked out)
|
|
2167
|
+
|
|
2168
|
+
**$01 value:** $36
|
|
2169
|
+
**LORAM:** 0, **HIRAM:** 1, **CHAREN:** 1
|
|
2170
|
+
|
|
2171
|
+
| Range | Contents |
|
|
2172
|
+
|--------------|--------------|
|
|
2173
|
+
| $A000-$BFFF | RAM (BASIC banked out) |
|
|
2174
|
+
| $D000-$DFFF | I/O |
|
|
2175
|
+
| $E000-$FFFF | KERNAL ROM |
|
|
2176
|
+
|
|
2177
|
+
Used by machine-language programs that want the 8 KB at $A000-$BFFF as
|
|
2178
|
+
RAM but still want KERNAL routines accessible.
|
|
2179
|
+
|
|
2180
|
+
### Mode 27 — character ROM + KERNAL + BASIC (no I/O)
|
|
2181
|
+
|
|
2182
|
+
**$01 value:** $33
|
|
2183
|
+
**LORAM:** 1, **HIRAM:** 1, **CHAREN:** 0
|
|
2184
|
+
|
|
2185
|
+
| Range | Contents |
|
|
2186
|
+
|--------------|--------------|
|
|
2187
|
+
| $A000-$BFFF | BASIC ROM |
|
|
2188
|
+
| $D000-$DFFF | Character ROM|
|
|
2189
|
+
| $E000-$FFFF | KERNAL ROM |
|
|
2190
|
+
|
|
2191
|
+
The I/O chips at $D000-$DFFF are replaced by the character generator
|
|
2192
|
+
ROM. Useful for copying the character set into RAM (`LDA $D000,X / STA
|
|
2193
|
+
target,X`) — you read the font directly, then bank I/O back in.
|
|
2194
|
+
|
|
2195
|
+
**Caution:** With I/O banked out, you cannot read CIA, VIC, or SID
|
|
2196
|
+
registers. *And* the IRQ vector goes through $FFFE/$FFFF which still
|
|
2197
|
+
points at the KERNAL ROM, so the KERNAL IRQ handler will run — and the
|
|
2198
|
+
KERNAL handler tries to LDA $DC0D *which now reads the character ROM*.
|
|
2199
|
+
It does not work; an earlier version of this page said it generally did.
|
|
2200
|
+
The handler does discard the value, but the read itself is the
|
|
2201
|
+
acknowledge: `LDA $DC0D` at $EA7E is the only place the service routine
|
|
2202
|
+
touches the CIA's interrupt register, and the ICR is cleared only when
|
|
2203
|
+
the CIA sees the read. With CHAREN = 0 the PLA selects the character ROM
|
|
2204
|
+
instead of the CIA, so the flag stays set, /IRQ stays low, and because
|
|
2205
|
+
RTI has no interrupt-delay the CPU re-enters the handler immediately
|
|
2206
|
+
after every RTI. The main program never executes another instruction —
|
|
2207
|
+
measured in VICE x64sc: with a `$0314` handler counting passes, a
|
|
2208
|
+
main-program instruction counter stayed at 0 across 4,909 handler passes
|
|
2209
|
+
in 20M cycles and 7,822 in 30M, while the identical code with $01 = $37
|
|
2210
|
+
finished inside one jiffy. (The handler also reads $DC01 as char-ROM
|
|
2211
|
+
byte $99, so SCNKEY runs a full phantom matrix scan on every pass.)
|
|
2212
|
+
*Always SEI before banking the character ROM in, and restore $01 before
|
|
2213
|
+
CLI — not only "if timing matters".*
|
|
2214
|
+
|
|
2215
|
+
### Mode 26 — KERNAL + character ROM (no BASIC, no I/O)
|
|
2216
|
+
|
|
2217
|
+
**$01 value:** $32
|
|
2218
|
+
**LORAM:** 0, **HIRAM:** 1, **CHAREN:** 0
|
|
2219
|
+
|
|
2220
|
+
| Range | Contents |
|
|
2221
|
+
|--------------|--------------|
|
|
2222
|
+
| $A000-$BFFF | RAM |
|
|
2223
|
+
| $D000-$DFFF | Character ROM|
|
|
2224
|
+
| $E000-$FFFF | KERNAL ROM |
|
|
2225
|
+
|
|
2226
|
+
### Mode 25 — Character ROM only (no BASIC, no KERNAL, no I/O)
|
|
2227
|
+
|
|
2228
|
+
**$01 value:** $31
|
|
2229
|
+
**LORAM:** 1, **HIRAM:** 0, **CHAREN:** 0
|
|
2230
|
+
|
|
2231
|
+
| Range | Contents |
|
|
2232
|
+
|--------------|--------------|
|
|
2233
|
+
| $A000-$BFFF | RAM |
|
|
2234
|
+
| $D000-$DFFF | Character ROM|
|
|
2235
|
+
| $E000-$FFFF | RAM |
|
|
2236
|
+
|
|
2237
|
+
Almost never used — see Mode 24 instead.
|
|
2238
|
+
|
|
2239
|
+
### Mode 29 — I/O only (no BASIC, no KERNAL)
|
|
2240
|
+
|
|
2241
|
+
**$01 value:** $35
|
|
2242
|
+
**LORAM:** 1, **HIRAM:** 0, **CHAREN:** 1
|
|
2243
|
+
|
|
2244
|
+
| Range | Contents |
|
|
2245
|
+
|--------------|--------------|
|
|
2246
|
+
| $A000-$BFFF | RAM |
|
|
2247
|
+
| $D000-$DFFF | I/O |
|
|
2248
|
+
| $E000-$FFFF | RAM |
|
|
2249
|
+
|
|
2250
|
+
The most common alternative to mode 31. Demos and games use this when
|
|
2251
|
+
they want all RAM but still need to talk to VIC/SID/CIA. The big catch:
|
|
2252
|
+
the IRQ vectors at $FFFE/$FFFF are now in RAM. You must:
|
|
2253
|
+
|
|
2254
|
+
1. Disable IRQs with SEI.
|
|
2255
|
+
2. Write your IRQ handler's address into $FFFE/$FFFF (and NMI into
|
|
2256
|
+
$FFFA/$FFFB).
|
|
2257
|
+
3. Bank out KERNAL with `LDA #$35 / STA $01`.
|
|
2258
|
+
4. Re-enable IRQs with CLI when ready.
|
|
2259
|
+
|
|
2260
|
+
(An earlier version of this page gave LORAM = 0 for modes 29 and 25 and
|
|
2261
|
+
CHAREN = 1 for mode 24; the $01 values and the truth table below were
|
|
2262
|
+
right, the bit prose was not — measured in VICE x64sc: $35 maps
|
|
2263
|
+
RAM/I-O/RAM at $A000/$D000/$E000, $31 maps RAM/char ROM/RAM, and $30
|
|
2264
|
+
and $34 are both all RAM.)
|
|
2265
|
+
|
|
2266
|
+
### Mode 24 — all RAM (no ROM, no I/O)
|
|
2267
|
+
|
|
2268
|
+
**$01 value:** $30
|
|
2269
|
+
**LORAM:** 0, **HIRAM:** 0, **CHAREN:** 0 ($34, CHAREN = 1, is mode 28 and maps identically — with LORAM and HIRAM both 0 the PLA ignores CHAREN)
|
|
2270
|
+
|
|
2271
|
+
| Range | Contents |
|
|
2272
|
+
|--------------|--------------|
|
|
2273
|
+
| $A000-$BFFF | RAM |
|
|
2274
|
+
| $D000-$DFFF | RAM |
|
|
2275
|
+
| $E000-$FFFF | RAM |
|
|
2276
|
+
|
|
2277
|
+
A pure 64 KB of RAM. Used for software that brings its own everything
|
|
2278
|
+
— typically the cracked-game intro / demoscene "filler" code that
|
|
2279
|
+
needs maximum RAM for music + graphics + code.
|
|
2280
|
+
|
|
2281
|
+
**Same IRQ catch as mode 29.** Plus you lose all I/O — your code must
|
|
2282
|
+
either disable interrupts and never need to talk to VIC/SID/CIA, or
|
|
2283
|
+
temporarily bank I/O back in (`LDA #$35 / STA $01`) when needed.
|
|
2284
|
+
|
|
2285
|
+
### The truth table - no-cartridge rows
|
|
2286
|
+
|
|
2287
|
+
Below are the eight no-cartridge rows (GAME = EXROM = 1, modes 24-31) of
|
|
2288
|
+
the 32-row PLA table. Modes are numbered 0-31 as LORAM + HIRAM x 2 +
|
|
2289
|
+
CHAREN x 4 + GAME x 8 + EXROM x 16, so the eight rows here are $01 bits
|
|
2290
|
+
0-2 plus 24. The remaining 24 rows are the cartridge configurations
|
|
2291
|
+
(16 KB cart: modes 0-7; 8 KB cart: 8-15; Ultimax: 16-23) - see
|
|
2292
|
+
[Cartridge modes](#cartridge-modes-exrom--game). An earlier version of
|
|
2293
|
+
this page called this table the full 32-mode table; it never was.
|
|
2294
|
+
|
|
2295
|
+
Cart-active modes (EXROM = 0 or GAME = 0) include "Ultimax" cartridges
|
|
2296
|
+
where ROMH+ROML+CHAREN+I/O selectively replace huge swaths of the map.
|
|
2297
|
+
|
|
2298
|
+
| Mode | $01 | LORAM | HIRAM | CHAREN | $8000-$9FFF | $A000-$BFFF | $D000-$DFFF | $E000-$FFFF |
|
|
2299
|
+
|------|-----|-------|-------|--------|-------------|-------------|-------------|-------------|
|
|
2300
|
+
| 31 | 7 | 1 | 1 | 1 | RAM | BASIC ROM | I/O | KERNAL ROM |
|
|
2301
|
+
| 30 | 6 | 0 | 1 | 1 | RAM | RAM | I/O | KERNAL ROM |
|
|
2302
|
+
| 29 | 5 | 1 | 0 | 1 | RAM | RAM | I/O | RAM |
|
|
2303
|
+
| 28 | 4 | 0 | 0 | 1 | RAM | RAM | RAM | RAM |
|
|
2304
|
+
| 27 | 3 | 1 | 1 | 0 | RAM | BASIC ROM | CHARROM | KERNAL ROM |
|
|
2305
|
+
| 26 | 2 | 0 | 1 | 0 | RAM | RAM | CHARROM | KERNAL ROM |
|
|
2306
|
+
| 25 | 1 | 1 | 0 | 0 | RAM | RAM | CHARROM | RAM |
|
|
2307
|
+
| 24 | 0 | 0 | 0 | 0 | RAM | RAM | RAM | RAM |
|
|
2308
|
+
|
|
2309
|
+
The seven distinct configurations boil down to **which of {RAM, BASIC,
|
|
2310
|
+
CHARROM} sits at $A000-$BFFF**, **which of {RAM, KERNAL} sits at
|
|
2311
|
+
$E000-$FFFF**, and **which of {RAM, CHARROM, I/O} sits at $D000-$DFFF**.
|
|
2312
|
+
|
|
2313
|
+
### Writes always go to RAM
|
|
2314
|
+
|
|
2315
|
+
This is the most important invariant in C64 banking: **writes to
|
|
2316
|
+
$A000-$BFFF, $D000-$DFFF (when I/O isn't there), and $E000-$FFFF always
|
|
2317
|
+
hit RAM**. Reads return ROM bytes when ROM is banked in; writes never
|
|
2318
|
+
do — they always update the underlying DRAM cell.
|
|
2319
|
+
|
|
2320
|
+
Exceptions to this rule:
|
|
2321
|
+
- $D000-$DFFF when I/O is banked in: writes go to the chip (VIC, SID,
|
|
2322
|
+
CIA, Color RAM, etc.) — not to RAM.
|
|
2323
|
+
- $D000-$DFFF when CHARROM is banked in: writes go to RAM (character ROM
|
|
2324
|
+
is read-only). This is unintuitive — you can write to $D000 while
|
|
2325
|
+
CHARROM is selected and the byte will be silently buried in RAM, only
|
|
2326
|
+
visible if you then bank I/O *out* and CHARROM out and read again.
|
|
2327
|
+
|
|
2328
|
+
### DDR must be set before $01 writes
|
|
2329
|
+
|
|
2330
|
+
The DDR at $0000 controls which bits of $01 are outputs. Bits configured
|
|
2331
|
+
as inputs ignore writes to $01.
|
|
2332
|
+
|
|
2333
|
+
The KERNAL sets DDR to $2F at reset (bits 0-3 and 5 are outputs; bits 4
|
|
2334
|
+
and 6 are inputs). Bits 0-2 are *always* outputs in the default config,
|
|
2335
|
+
so writing $35, $36, $37 to $01 takes effect.
|
|
2336
|
+
|
|
2337
|
+
**The pitfall:** code that does `LDA #$30 / STA $01` to bank to mode 24
|
|
2338
|
+
needs to *first* write $2F to $00 — otherwise some prior program may
|
|
2339
|
+
have left bit 7 of DDR as an input, in which case the high bit of $01
|
|
2340
|
+
won't change. In practice this is rarely a problem on a reset-fresh C64
|
|
2341
|
+
but is a known reliability issue when chaining loader stages.
|
|
2342
|
+
|
|
2343
|
+
The safest banking sequence:
|
|
2344
|
+
|
|
2345
|
+
```
|
|
2346
|
+
SEI ; disable IRQs
|
|
2347
|
+
LDA #$2F ; DDR mask: bits 0-3,5 output
|
|
2348
|
+
STA $00
|
|
2349
|
+
LDA #$35 ; new bank value
|
|
2350
|
+
STA $01
|
|
2351
|
+
```
|
|
2352
|
+
|
|
2353
|
+
### Cartridge modes (EXROM / GAME)
|
|
2354
|
+
|
|
2355
|
+
When a cartridge is inserted, EXROM and/or GAME pull low and the PLA
|
|
2356
|
+
maps cartridge ROM into the address space. The two relevant cart
|
|
2357
|
+
configurations are:
|
|
2358
|
+
|
|
2359
|
+
- **8 KB cart** (EXROM = 0, GAME = 1): ROML at $8000-$9FFF.
|
|
2360
|
+
- **16 KB cart** (EXROM = 0, GAME = 0): ROML at $8000-$9FFF + ROMH at
|
|
2361
|
+
$A000-$BFFF, with BASIC ROM disabled. ROMH at $A000 requires HIRAM = 1;
|
|
2362
|
+
LORAM only gates ROML (measured in VICE x64sc).
|
|
2363
|
+
- **Ultimax cart** (EXROM = 1, GAME = 0): a weird hybrid where ROML is
|
|
2364
|
+
at $8000-$9FFF + ROMH is at $E000-$FFFF replacing KERNAL, *and* most
|
|
2365
|
+
of the RAM is disabled. Used by the Commodore Ultimax — the only place
|
|
2366
|
+
in the C64 ecosystem this matters.
|
|
2367
|
+
|
|
2368
|
+
The PLA truth table for cart modes is documented in *The C64 PLA
|
|
2369
|
+
Dissected*. Most software developers don't need to think about cart
|
|
2370
|
+
modes unless they're writing cartridges or copy-protection.
|
|
2371
|
+
|
|
2372
|
+
## Zero page details
|
|
2373
|
+
|
|
2374
|
+
The 6510's zero-page addressing modes — LDA $XX, LDA $XX,X, LDA
|
|
2375
|
+
($XX,X), LDA ($XX),Y — are one or two cycles faster than absolute
|
|
2376
|
+
modes and use one fewer byte. Zero page (the first 256 bytes of RAM,
|
|
2377
|
+
$0000-$00FF) is therefore precious real estate. The KERNAL and BASIC
|
|
2378
|
+
have already claimed most of it.
|
|
2379
|
+
|
|
2380
|
+
### What KERNAL uses
|
|
2381
|
+
|
|
2382
|
+
The KERNAL workspace in zero page is roughly $90-$FE. Subsections:
|
|
2383
|
+
|
|
2384
|
+
- **$90-$93** — I/O state: STATUS, STOP-key flag, cassette flag, etc.
|
|
2385
|
+
- **$94-$9F** — IEC and cassette bit-level workspace.
|
|
2386
|
+
- **$A0-$A2** — Jiffy clock (TI).
|
|
2387
|
+
- **$A3-$BD** — More cassette + IEC workspace.
|
|
2388
|
+
- **$BE-$BF** — Tape block + serial workspace.
|
|
2389
|
+
- **$C1-$C4** — Memory pointer pairs (LOAD/SAVE/VERIFY).
|
|
2390
|
+
- **$C5-$D7** — Screen editor: last key, keyboard buffer count, cursor
|
|
2391
|
+
X/Y, cursor blink state, line pointer.
|
|
2392
|
+
- **$D8** — Insert count (INSRT): number of pending INST presses; CHROUT
|
|
2393
|
+
decrements it as characters are typed.
|
|
2394
|
+
- **$D9-$F2** — Screen line link table (LDTB1), 26 entries: one per
|
|
2395
|
+
screen row plus a sentinel entry at $F2 so row 24 is never read as
|
|
2396
|
+
continued. Bits 0-1 of an entry are the row's screen-address high-byte
|
|
2397
|
+
offset (OR'd with $0288 when used); bit 7 set means the row starts a
|
|
2398
|
+
logical line, clear means it continues the row above. (This page
|
|
2399
|
+
previously ended the table at $F1 and put the insert count at $F2; the
|
|
2400
|
+
KERNAL's fill loop at $E544 writes 26 entries and never addresses $F2
|
|
2401
|
+
on its own — measured from the ROM and in VICE x64sc.)
|
|
2402
|
+
- **$F3-$F4** — Colour RAM pointer for the current line (low byte = $D1;
|
|
2403
|
+
high byte = ($D2 & 3) | $D8).
|
|
2404
|
+
- **$F5-$F6** — Key decode table pointer.
|
|
2405
|
+
- **$F7-$FA** — RS-232 buffer pointers.
|
|
2406
|
+
|
|
2407
|
+
If your program calls *any* KERNAL routine — even CHROUT — the KERNAL
|
|
2408
|
+
will read and write zero page. The full list of zeropage bytes the
|
|
2409
|
+
KERNAL uses is in *Mapping the Commodore 64* chapter 1.
|
|
2410
|
+
|
|
2411
|
+
Five zero-page bytes are never touched by either ROM after RAMTAS's
|
|
2412
|
+
reset clear: $02 and $FB-$FE (this page used to say $FB-$FE were the
|
|
2413
|
+
only four).
|
|
2414
|
+
|
|
2415
|
+
### What BASIC uses
|
|
2416
|
+
|
|
2417
|
+
BASIC's workspace is $03-$8F, with the executable CHRGET routine at
|
|
2418
|
+
$73-$8A ($02 is not BASIC's — see $0002 above).
|
|
2419
|
+
|
|
2420
|
+
- **$03-$8A** — Working registers and pointers for parsing, tokenization,
|
|
2421
|
+
expression evaluation, floating-point math.
|
|
2422
|
+
- **$8B-$8F** — RND seed.
|
|
2423
|
+
|
|
2424
|
+
If your program doesn't return to the BASIC READY prompt and doesn't
|
|
2425
|
+
call BASIC ROM routines, all of $03-$8F is free except where it overlaps
|
|
2426
|
+
the CHRGET code at $73-$8A. To free up $73-$8A, you'd need to make sure
|
|
2427
|
+
no future BASIC interpretation happens.
|
|
2428
|
+
|
|
2429
|
+
### Best practices for zero page
|
|
2430
|
+
|
|
2431
|
+
When writing assembly that coexists with KERNAL:
|
|
2432
|
+
|
|
2433
|
+
1. **Use $FB-$FE and $02 first.** These five bytes are safe.
|
|
2434
|
+
2. **Disable IRQs (SEI) before using any other zeropage location.** That
|
|
2435
|
+
prevents the KERNAL IRQ (jiffy clock + keyscan) from clobbering your
|
|
2436
|
+
bytes mid-operation.
|
|
2437
|
+
3. **Read $0314-$0333 to find what hooks you've installed.** A
|
|
2438
|
+
non-default vector indicates someone else has installed a handler
|
|
2439
|
+
and may use additional zero page.
|
|
2440
|
+
|
|
2441
|
+
When writing assembly that takes over the machine completely (bank
|
|
2442
|
+
KERNAL out + own IRQ handler):
|
|
2443
|
+
|
|
2444
|
+
1. The entire zero page $00-$FF is yours, except $00 and $01 which still
|
|
2445
|
+
talk to the 6510 processor port.
|
|
2446
|
+
|
|
2447
|
+
## Stack page
|
|
2448
|
+
|
|
2449
|
+
$0100-$01FF is the 6502/6510 hardware stack. The stack pointer S
|
|
2450
|
+
descends from $01FF and the page address is hard-coded — the stack
|
|
2451
|
+
*always* lives on page 1.
|
|
2452
|
+
|
|
2453
|
+
### Stack operations
|
|
2454
|
+
|
|
2455
|
+
- **PHA / PHP** — push 1 byte, decrement S.
|
|
2456
|
+
- **PLA / PLP** — increment S, pull 1 byte.
|
|
2457
|
+
- **JSR addr** — push the address of the JSR's last byte (the return
|
|
2458
|
+
address minus one), high byte first then low byte, so inside the
|
|
2459
|
+
callee the low byte is at $0101+S and the high byte at $0102+S
|
|
2460
|
+
(measured in VICE x64sc; an earlier version of this bullet said the
|
|
2461
|
+
low byte sat at the higher address, which is backwards). Then
|
|
2462
|
+
PC := addr.
|
|
2463
|
+
- **RTS** — pull return-address-minus-one + 1.
|
|
2464
|
+
- **BRK / IRQ / NMI** — push PCH, PCL, status; PC := vector.
|
|
2465
|
+
|
|
2466
|
+
### BASIC use of the stack
|
|
2467
|
+
|
|
2468
|
+
BASIC pushes substantial state on the stack for GOSUB and FOR-NEXT:
|
|
2469
|
+
|
|
2470
|
+
- **GOSUB** pushes 5 bytes: `$8D` (GOSUB token), current line number
|
|
2471
|
+
(2 bytes), text pointer (2 bytes).
|
|
2472
|
+
- **FOR** pushes 18 bytes (push order; read back last-pushed first):
|
|
2473
|
+
text pointer (2), line number (2), TO limit (5 bytes FP, sign folded
|
|
2474
|
+
into the first mantissa byte), STEP sign (1), STEP value (5 bytes FP),
|
|
2475
|
+
pointer to the index variable's descriptor (2), `$81` (FOR token). The
|
|
2476
|
+
stack search at $A38A walks frames in steps of 18 (`ADC #$12`). An
|
|
2477
|
+
earlier revision of this page also listed an "index variable name (2)"
|
|
2478
|
+
entry and put STEP before the limit; the frame holds a pointer, not
|
|
2479
|
+
the name, and that entry made the itemization sum to 20 (verified
|
|
2480
|
+
against the ROM at $A75D-$A7AD and a stack dump in VICE x64sc).
|
|
2481
|
+
|
|
2482
|
+
So a deeply-nested BASIC program can exhaust the stack faster than you'd
|
|
2483
|
+
expect — 8 nested FORs = 144 bytes, more than half the stack.
|
|
2484
|
+
|
|
2485
|
+
### Assembly hygiene
|
|
2486
|
+
|
|
2487
|
+
The KERNAL reset ($FCE2) sets S to $FF (LDX #$FF / SEI / TXS) and hands
|
|
2488
|
+
over to BASIC with S still $FF; it is BASIC's cold start that then does
|
|
2489
|
+
LDX #$FB / TXS ($E39D), and CLR/RUN lower the base to $FA ($A681).
|
|
2490
|
+
Earlier text credited the $FB to the KERNAL. By the time a SYS reaches
|
|
2491
|
+
your code S is lower again: $F7 for a SYS typed at the READY prompt on a
|
|
2492
|
+
freshly booted machine, $F6 for a SYS inside a RUN program or typed
|
|
2493
|
+
after one (RUN's CLR resets the base to $FA, then the statement
|
|
2494
|
+
dispatcher's JSR and SYS's pushed return address each take two bytes) —
|
|
2495
|
+
both measured in VICE x64sc 3.10. Pure-assembly programs that take over
|
|
2496
|
+
should do `LDX #$FF / TXS` to reset the stack pointer to the top.
|
|
2497
|
+
|
|
2498
|
+
When you push values for "local variables" via PHA, pull them back in
|
|
2499
|
+
*reverse order*. The 6502 has no offset-based stack-relative addressing
|
|
2500
|
+
(unlike the 65C816), so manually accessing pushed values from inside a
|
|
2501
|
+
routine requires `TSX` to load S into X and then absolute-indexed reads
|
|
2502
|
+
from $0100,X.
|
|
2503
|
+
|
|
2504
|
+
## KERNAL ROM map
|
|
2505
|
+
|
|
2506
|
+
The KERNAL ROM at $E000-$FFFF (8 KB) contains the firmware that handles
|
|
2507
|
+
all I/O, character output, screen scrolling, cursor management,
|
|
2508
|
+
keyboard scanning, the IRQ/NMI handlers, the BRK handler, the IEC bus
|
|
2509
|
+
driver, the RS-232 driver, and the cassette driver. It also contains
|
|
2510
|
+
the standard reset routine.
|
|
2511
|
+
|
|
2512
|
+
The public interface is the jump table at $FF81-$FFF5 — 39 entries of 3
|
|
2513
|
+
bytes each. Twenty-nine are `JMP addr`; the ten I/O entries (OPEN,
|
|
2514
|
+
CLOSE, CHKIN, CHKOUT, CLRCHN, CHRIN, CHROUT, STOP, GETIN, CLALL) are
|
|
2515
|
+
`JMP (vector)` through the RAM vectors at $031A-$032D, which is why
|
|
2516
|
+
patching $0326/$0327 redirects `JSR $FFD2` while a direct `JSR $F1CA`
|
|
2517
|
+
bypasses the hook. (An earlier version said every entry was a direct
|
|
2518
|
+
`JMP addr`; the ROM bytes show opcode $6C at ten of them.) Calling
|
|
2519
|
+
KERNAL routines through the jump table is *strongly* preferred over
|
|
2520
|
+
calling them directly: the jump table is stable across KERNAL ROM
|
|
2521
|
+
revisions; the implementation addresses are not.
|
|
2522
|
+
|
|
2523
|
+
### KERNAL revisions
|
|
2524
|
+
|
|
2525
|
+
Three production KERNAL ROMs shipped: 901227-01, -02 and -03 (the C64C's
|
|
2526
|
+
combined 16 KB BASIC+KERNAL mask, usually given as 251913-01, is
|
|
2527
|
+
documented as carrying the -03 KERNAL — no image on this machine, not
|
|
2528
|
+
measured here). `PEEK(65408)` ($FF80) returns 170, 0 or 3. The jump
|
|
2529
|
+
table $FF81-$FFF5 is at the same addresses in all three and 38 of 39
|
|
2530
|
+
targets are unchanged; the one that moved is CINT ($FF81 = `JMP $E518`
|
|
2531
|
+
in -01, `JMP $FF5B` in -02/-03). The differences are 277 bytes of
|
|
2532
|
+
in-place patches (-01/-02 227, -02/-03 57; `cmp` of the VICE 3.9
|
|
2533
|
+
images):
|
|
2534
|
+
|
|
2535
|
+
- **-02 added PAL/NTSC detection.** A CINT wrapper at $FF5B runs $E518,
|
|
2536
|
+
waits for $D012 to wrap, stores $D019 bit 0 (the raster compare for
|
|
2537
|
+
line 311 set by the new VIC init table $D011/$D012 = $9B/$37) in
|
|
2538
|
+
$02A6, and IOINIT ($FDDD) then loads the jiffy timer with $4025 (PAL)
|
|
2539
|
+
or $4295 (NTSC) where -01 hard-coded $411B. RS-232 OPEN ($F428) and
|
|
2540
|
+
the NMI baud code ($FF08-$FF42) pick a PAL baud table at $E4EC by
|
|
2541
|
+
$02A6; BASIC's CHKOUT wrapper ($E118) calls a patch at $E4AD that
|
|
2542
|
+
preserves A.
|
|
2543
|
+
- **-02 and -03 each changed the screen-clear colour** ($EA0B → $E4DA:
|
|
2544
|
+
-01 white `LDA #$01`, -02 background `LDA $D021`, -03 current text
|
|
2545
|
+
colour `LDA $0286`). -03 also patched the screen editor's cursor-line
|
|
2546
|
+
set-up ($E57C-$E599, $E621: the colour pointer $F3/$F4 is resynced via
|
|
2547
|
+
$EA24, and the line-start search is skipped when the cursor row
|
|
2548
|
+
already equals the input row $C9) and one RS-232 receive path ($EF94
|
|
2549
|
+
→ $E4D3).
|
|
2550
|
+
- **The only cassette change is the pause after the FOUND message**
|
|
2551
|
+
($F761): -01 waits for a key to register in $91; -02/-03 wait until
|
|
2552
|
+
the jiffy clock's middle byte $A1 has advanced by three (`ADC #$02`
|
|
2553
|
+
with the carry left set by the preceding `CPY #$15`, roughly 9-13 s)
|
|
2554
|
+
or a key registers in $91 — routine $E4E0. The tape read/write code
|
|
2555
|
+
$F767-$FCFB, every pulse-timing constant included, is byte-identical
|
|
2556
|
+
in all three, and so are the keyboard scan, decode and key tables
|
|
2557
|
+
($EA13-$ECC9). An earlier version of this section said the revisions
|
|
2558
|
+
differed in "cassette timing constants and one keyboard-handling fix";
|
|
2559
|
+
neither is in the ROM bytes.
|
|
2560
|
+
|
|
2561
|
+
*Always JSR through the jump table.* See kernal-routines-reference.md
|
|
2562
|
+
§ KERNAL ROM revisions, which gives the same account.
|
|
2563
|
+
|
|
2564
|
+
### KERNAL layout summary
|
|
2565
|
+
|
|
2566
|
+
| Range | Function |
|
|
2567
|
+
|---------------|----------------------------------------------------|
|
|
2568
|
+
| $E000-$E393 | BASIC ROM overflow (EXP/RND/trig, BASIC I/O command handlers, warm start $E37B) |
|
|
2569
|
+
| $E394-$E4AB | BASIC cold start $E394, init $E3BF, default vector table $E447, sign-on text ($E460-$E4AB, printed from $E473) |
|
|
2570
|
+
| $E4AC-$E4FF | Revision patches (CHKOUT wrapper $E4AD, RS-232 $E4D3, screen-clear colour $E4DA, FOUND pause $E4E0, PAL baud table $E4EC); $E4B7-$E4D2 unused |
|
|
2571
|
+
| $E500-$E5C9 | IOBASE $E500, SCREEN $E505, PLOT $E50A, CINT body $E518, clear screen $E544, VIC init $E5A0 |
|
|
2572
|
+
| $E5CA-$EA30 | Screen editor: keyboard/screen input, CHROUT screen body $E716, scroll $E8EA |
|
|
2573
|
+
| $EA31-$EA86 | Default IRQ handler (CIA acknowledge $EA7E, register restore/RTI $EA81) |
|
|
2574
|
+
| $EA87-$ECE6 | SCNKEY $EA87, KEYLOG $EB48, key decode tables $EB81-$ECB8, VIC power-on table $ECB9 |
|
|
2575
|
+
| $ECE7-$ED08 | "LOAD/RUN" string, screen-line low-byte table |
|
|
2576
|
+
| $ED09-$EEBA | IEC bus (TALK $ED09, LISTEN $ED0C, SECOND $EDB9, TKSA $EDC7, IECOUT $EDDD, UNTLK $EDEF, UNLSN $EDFE, IECIN $EE13, 1 ms delay $EEB3) |
|
|
2577
|
+
| $EEBB-$F0BC | RS-232 driver |
|
|
2578
|
+
| $F0BD-$F12A | KERNAL message text |
|
|
2579
|
+
| $F12B-$F349 | Message printer $F12B, GETIN $F13E, CHRIN $F157, CHROUT $F1CA, CHKIN $F20E, CHKOUT $F250, CLOSE $F291, CLALL $F32F, CLRCHN $F333 |
|
|
2580
|
+
| $F34A-$F49D | OPEN |
|
|
2581
|
+
| $F49E-$F5DC | LOAD (entry $F49E, body $F4A5; serial $F4B8, tape $F533) |
|
|
2582
|
+
| $F5DD-$F69A | SAVE (entry $F5DD, body $F5ED) |
|
|
2583
|
+
| $F69B-$F6FA | UDTIM $F69B (STOP-key sample $F6BC), RDTIM $F6DD, SETTIM $F6E4, STOP $F6ED |
|
|
2584
|
+
| $F6FB-$F92B | I/O error entries, tape header find/write, PRESS PLAY/RECORD prompts |
|
|
2585
|
+
| $F92C-$FBCC | Cassette READ IRQ ($F92C), tape byte store $FA60 |
|
|
2586
|
+
| $FBCD-$FCE1 | Cassette WRITE IRQs ($FBCD, $FC6A), restore IRQ $FC93, motor off $FCCA |
|
|
2587
|
+
| $FCE2-$FD4F | RESET $FCE2, cartridge check $FD02, RESTOR $FD15, VECTOR $FD1A, vector table $FD30 |
|
|
2588
|
+
| $FD50-$FDF8 | RAMTAS $FD50, tape IRQ vectors $FD9B, IOINIT $FDA3 (timer latch $FDDD) |
|
|
2589
|
+
| $FDF9-$FE42 | SETNAM $FDF9, SETLFS $FE00, READST $FE07, SETMSG $FE18, SETTMO $FE21, MEMTOP $FE25, MEMBOT $FE34 |
|
|
2590
|
+
| $FE43-$FF42 | NMI $FE43 → $FE47, RUN/STOP-RESTORE warm start $FE66, RS-232 NMI paths $FED6/$FF07 |
|
|
2591
|
+
| $FF43-$FF7F | IRQ/BRK dispatcher $FF48 (fake-IRQ entry $FF43), CINT wrapper $FF5B, IOINIT timer tail $FF6E |
|
|
2592
|
+
| $FF80-$FF80 | Revision byte ($03) |
|
|
2593
|
+
| $FF81-$FFF5 | Public jump table (39 entries; 10 indirect via $031A-$032D) |
|
|
2594
|
+
| $FFF6-$FFF9 | Unused |
|
|
2595
|
+
| $FFFA-$FFFF | CPU vectors (NMI $FE43, RESET $FCE2, IRQ/BRK $FF48) |
|
|
2596
|
+
|
|
2597
|
+
The previous version of this table misattributed several ranges — the
|
|
2598
|
+
keyboard scan sat inside a row labelled "IEC bus driver", the cassette
|
|
2599
|
+
read IRQ was labelled "Disk LOAD/SAVE via IEC", RAMTAS was placed in the
|
|
2600
|
+
BASIC-entry row, "$FF48-$FF80" was called IRQ/BRK preamble although
|
|
2601
|
+
$FF5B-$FF7F is CINT's PAL/NTSC wrapper and IOINIT's timer tail, and the
|
|
2602
|
+
first row overlapped the second by one byte. The boundaries above were
|
|
2603
|
+
read from the 901227-03 jump table, the $FD30 vector table and the
|
|
2604
|
+
$FD9B tape-IRQ vector table.
|
|
2605
|
+
|
|
2606
|
+
### Public jump table at $FF81-$FFF5
|
|
2607
|
+
|
|
2608
|
+
The full jump table is documented in
|
|
2609
|
+
[kernal-routines-reference.md](kernal-routines-reference.md). Summary:
|
|
2610
|
+
|
|
2611
|
+
| Addr | Routine | Function |
|
|
2612
|
+
|-------|---------|---------------------------------------|
|
|
2613
|
+
| $FF81 | CINT | Initialize screen editor |
|
|
2614
|
+
| $FF84 | IOINIT | Initialize I/O chips |
|
|
2615
|
+
| $FF87 | RAMTAS | RAM test, allocate workspace |
|
|
2616
|
+
| $FF8A | RESTOR | Restore default vectors |
|
|
2617
|
+
| $FF8D | VECTOR | Read or set indirect vectors |
|
|
2618
|
+
| $FF90 | SETMSG | Control KERNAL messages |
|
|
2619
|
+
| $FF93 | SECOND | Send secondary address (after LISTEN) |
|
|
2620
|
+
| $FF96 | TKSA | Send secondary address (after TALK) |
|
|
2621
|
+
| $FF99 | MEMTOP | Set / read top-of-memory |
|
|
2622
|
+
| $FF9C | MEMBOT | Set / read bottom-of-memory |
|
|
2623
|
+
| $FF9F | SCNKEY | Scan the keyboard |
|
|
2624
|
+
| $FFA2 | SETTMO | Set IEC timeout |
|
|
2625
|
+
| $FFA5 | IECIN | Receive byte from IEC bus |
|
|
2626
|
+
| $FFA8 | IECOUT | Send byte to IEC bus |
|
|
2627
|
+
| $FFAB | UNTLK | Send UNTALK on IEC bus |
|
|
2628
|
+
| $FFAE | UNLSN | Send UNLISTEN on IEC bus |
|
|
2629
|
+
| $FFB1 | LISTEN | Command device on IEC to LISTEN |
|
|
2630
|
+
| $FFB4 | TALK | Command device on IEC to TALK |
|
|
2631
|
+
| $FFB7 | READST | Read I/O STATUS |
|
|
2632
|
+
| $FFBA | SETLFS | Set logical file parameters |
|
|
2633
|
+
| $FFBD | SETNAM | Set filename |
|
|
2634
|
+
| $FFC0 | OPEN | Open a file |
|
|
2635
|
+
| $FFC3 | CLOSE | Close a file |
|
|
2636
|
+
| $FFC6 | CHKIN | Set input channel |
|
|
2637
|
+
| $FFC9 | CHKOUT | Set output channel |
|
|
2638
|
+
| $FFCC | CLRCHN | Restore default I/O |
|
|
2639
|
+
| $FFCF | CHRIN | Get char from input |
|
|
2640
|
+
| $FFD2 | CHROUT | Output char |
|
|
2641
|
+
| $FFD5 | LOAD | Load file |
|
|
2642
|
+
| $FFD8 | SAVE | Save file |
|
|
2643
|
+
| $FFDB | SETTIM | Set jiffy clock |
|
|
2644
|
+
| $FFDE | RDTIM | Read jiffy clock |
|
|
2645
|
+
| $FFE1 | STOP | Test STOP key |
|
|
2646
|
+
| $FFE4 | GETIN | Get char from queue |
|
|
2647
|
+
| $FFE7 | CLALL | Close all files |
|
|
2648
|
+
| $FFEA | UDTIM | Update jiffy clock |
|
|
2649
|
+
| $FFED | SCREEN | Return screen dimensions |
|
|
2650
|
+
| $FFF0 | PLOT | Read / set cursor |
|
|
2651
|
+
| $FFF3 | IOBASE | Return base of CIA #1 |
|
|
2652
|
+
|
|
2653
|
+
### Critical KERNAL internal addresses
|
|
2654
|
+
|
|
2655
|
+
A few internal KERNAL addresses are worth knowing because they're
|
|
2656
|
+
referenced by replacement IRQ handlers:
|
|
2657
|
+
|
|
2658
|
+
- **$EA31** — default IRQ handler entry (the one $0314 points to).
|
|
2659
|
+
After your custom raster IRQ, you typically `JMP $EA31` to chain
|
|
2660
|
+
back to the default handler.
|
|
2661
|
+
- **$EA7E** — acknowledge-and-exit tail of the default handler:
|
|
2662
|
+
`LDA $DC0D`, then the `$EA81` register restore and RTI. It does not
|
|
2663
|
+
run UDTIM or SCNKEY; chain here only when your own handler has done,
|
|
2664
|
+
or does not need, the jiffy clock, the STOP key and the keyboard.
|
|
2665
|
+
(This bullet used to say $EA7E kept UDTIM and the keyscan and skipped
|
|
2666
|
+
only the cursor blink; it skips all three — an agent following the
|
|
2667
|
+
old text ships a dead keyboard, a frozen TI$ and a dead RUN/STOP.)
|
|
2668
|
+
- **$EA81** — bare exit: PLA/TAY/PLA/TAX/PLA/RTI. Chain here from a
|
|
2669
|
+
handler that has acknowledged its own interrupt source.
|
|
2670
|
+
- **$FF48** — IRQ preamble (saves A, X, Y to stack). The default IRQ
|
|
2671
|
+
vector at $FFFE points here.
|
|
2672
|
+
- **$F6BC** — the STOP-key sample at the tail of UDTIM ($F69B falls
|
|
2673
|
+
into it): reads keyboard row 7 from $DC01 (SCNKEY leaves $DC00 = $7F,
|
|
2674
|
+
the row that holds RUN/STOP), debounces it and stores it in $91 for
|
|
2675
|
+
STOP ($FFE1 → $F6ED) to test, then RTS. Calling it yourself only
|
|
2676
|
+
refreshes $91. An earlier revision called this the "RUN/STOP loop
|
|
2677
|
+
entry" that RUN/STOP+RESTORE bounces to; it is not. RUN/STOP+RESTORE
|
|
2678
|
+
is the NMI handler ($FFFA → $FE43 → ($0318) = **$FE47**): it
|
|
2679
|
+
acknowledges CIA #2 ($DD0D — a CIA #2 NMI takes the RS-232 path
|
|
2680
|
+
instead), checks for a CBM80 cartridge ($FD02; a cartridge's $8002
|
|
2681
|
+
vector wins), then `JSR $F6BC`, `JSR $FFE1`, and if STOP is down falls
|
|
2682
|
+
into **$FE66**: RESTOR ($FD15), IOINIT ($FDA3), CINT ($E518),
|
|
2683
|
+
`JMP ($A002)` → $E37B warm start. RESTORE alone (STOP up) returns
|
|
2684
|
+
through $FEBC and does nothing. To do what RUN/STOP+RESTORE does from
|
|
2685
|
+
software use `SEI : JMP $FE66` (SYS 65126 from BASIC): the real path
|
|
2686
|
+
arrives with I set, RESTOR rewrites $0314–$0333 with no SEI of its
|
|
2687
|
+
own, and $E37B ends in CLI. Measured in VICE x64sc 3.10 against the
|
|
2688
|
+
901227-03 ROM: `JSR $F6BC` returns with $91 = $FF; `SEI : JMP $FE66`
|
|
2689
|
+
clears the screen, restores $D020/$D021 to $0E/$06 and prints READY.
|
|
2690
|
+
with no banner; `JMP $FCE2` (SYS 64738, cold reset) prints the banner.
|
|
2691
|
+
|
|
2692
|
+
## BASIC ROM map
|
|
2693
|
+
|
|
2694
|
+
The BASIC ROM at $A000-$BFFF (8 KB) contains Microsoft BASIC v2.0,
|
|
2695
|
+
licensed from Microsoft in 1977. The implementation is virtually
|
|
2696
|
+
identical to PET BASIC 4.0 minus the disk commands, plus a few C64
|
|
2697
|
+
quirks.
|
|
2698
|
+
|
|
2699
|
+
### BASIC ROM layout
|
|
2700
|
+
|
|
2701
|
+
| Range | Function |
|
|
2702
|
+
|---|---|
|
|
2703
|
+
| $A000-$A00B | Cold/warm-start vectors ($E394/$E37B), "CBMBASIC" |
|
|
2704
|
+
| $A00C-$A389 | Statement dispatch ($A00C, entry-1), function dispatch ($A052), operator table, keyword text ($A09E), error messages, "OK"/"ERROR"/"IN"/"READY."/"BREAK" strings ($A364-$A389) |
|
|
2705
|
+
| $A38A-$A47F | FOR-stack search ($A38A), stack/memory checks ($A3FB, $A408), ERROR ($A437 = JMP ($0300)), READY ($A474) |
|
|
2706
|
+
| $A480-$A641 | Main loop ($A480 = JMP ($0302), $A483), insert line, INLIN ($A560), CRUNCH ($A57C), FNDLIN ($A613) |
|
|
2707
|
+
| $A642-$A741 | NEW ($A642), CLR ($A65E), LIST ($A69C, detokenize $A71A) |
|
|
2708
|
+
| $A742-$A9A4 | FOR ($A742), NEWSTT/GONE ($A7AE/$A7E4), RESTORE ($A81D), STOP/END ($A82F/$A831), CONT ($A857), RUN ($A871), GOSUB ($A883), GOTO ($A8A0), RETURN ($A8D2), DATA ($A8F8), IF ($A928), REM ($A93B), ON ($A94B), LINGET |
|
|
2709
|
+
| $A9A5-$AC05 | LET ($A9A5), PRINT# ($AA80), CMD ($AA86), PRINT ($AAA0), STROUT ($AB1E), GET ($AB7B), INPUT# ($ABA5), INPUT ($ABBF) |
|
|
2710
|
+
| $AC06-$AD1D | READ ($AC06) and its "?EXTRA IGNORED"/"?REDO FROM START" messages |
|
|
2711
|
+
| $AD1E-$AD89 | NEXT ($AD1E) |
|
|
2712
|
+
| $AD8A-$B07D | Expression evaluator: FRMNUM ($AD8A), CHKNUM ($AD8D), FRMEVL ($AD9E), EVAL ($AE86), string concatenation entry via $ADE5 |
|
|
2713
|
+
| $B07E-$B08A | DIM (dispatch entry $B081) |
|
|
2714
|
+
| $B08B-$B3B2 | PTRGET ($B08B) variable/array lookup, FRE ($B37D), POS ($B39E) |
|
|
2715
|
+
| $B3B3-$B6DA | DEF/FN ($B3B3), STR$ ($B465), string allocation ($B475), garbage collection ($B526), concatenation ($B63D), string move ($B67A) |
|
|
2716
|
+
| $B6DB-$B80C | String functions: CHR$ ($B6EC), LEFT$ ($B700), RIGHT$ ($B72C), MID$ ($B737), LEN ($B77C), ASC ($B78B), VAL ($B7AD), GETNUM/GETADR ($B7EB/$B7F7) |
|
|
2717
|
+
| $B80D-$BAE1 | PEEK ($B80D), POKE ($B824), WAIT ($B82D), FADDH/FSUB/FADD ($B849/$B850/$B867), LOG ($B9EA), FMULT ($BA28), CONUPK ($BA8C) |
|
|
2718
|
+
| $BAE2-$BFFF | MUL10 ($BAE2), DIV10 ($BAFE), FDIV ($BB0F), MOVFM ($BBA2), MOVMF ($BBD4), MOVFA ($BBFC), MOVAF ($BC0C), SGN ($BC39), ABS ($BC58), FCOMP ($BC5B), INT ($BCCC), FIN ($BCF3), FOUT ($BDDD), SQR ($BF71), power, EXP ($BFED; ends with JMP $E000 and continues in the KERNAL ROM) |
|
|
2719
|
+
|
|
2720
|
+
An earlier version of this table placed the string functions at $A9A5
|
|
2721
|
+
(that is LET), FIN/FOUT at $AF7E-$B6DA (they are at $BCF3/$BDDD) and
|
|
2722
|
+
the cold start in $BAE2-$BFFF; BASIC's cold start ($E394), warm start
|
|
2723
|
+
($E37B), init ($E3BF), default vector table ($E447) and sign-on text
|
|
2724
|
+
($E460ff), plus the LOAD/SAVE/VERIFY/SYS/OPEN/CLOSE statement handlers
|
|
2725
|
+
($E12A-$E1C7) and RND/COS/SIN/TAN/ATN, live in the KERNAL ROM, where EXP
|
|
2726
|
+
also finishes. All addresses read from basic-901226-01.bin /
|
|
2727
|
+
kernal-901227-03.bin.
|
|
2728
|
+
|
|
2729
|
+
### Useful BASIC entry points
|
|
2730
|
+
|
|
2731
|
+
Even if you're writing pure assembly, a few BASIC ROM routines are
|
|
2732
|
+
worth calling. The addresses and behaviour below are read from the
|
|
2733
|
+
basic-901226-01 ROM image; the names are the conventional Microsoft
|
|
2734
|
+
BASIC labels, corroborated by the call sites (PRINT's number path is
|
|
2735
|
+
FOUT's only caller, FPWRT's tail is EXP's only caller, FOR loads its
|
|
2736
|
+
default STEP through $BBA2). An earlier version of this list had five of
|
|
2737
|
+
the six entries mislabelled; each line says what it used to claim.
|
|
2738
|
+
|
|
2739
|
+
- **$A560** — INLIN (read a line of input into the buffer at $0200);
|
|
2740
|
+
an earlier version listed it as CRUNCH.
|
|
2741
|
+
- **$A57C** — CRUNCH body (tokenize the line at $0200); $A579 is the
|
|
2742
|
+
`JMP ($0304)` that reaches it.
|
|
2743
|
+
- **$AB1E** — STROUT (print a string terminated by $00 or a quote,
|
|
2744
|
+
pointer in A=lo, **Y=hi**; A, X and Y are all clobbered). An earlier
|
|
2745
|
+
version of this line said X=hi; STRLIT at $B487 stores `STA $6F /
|
|
2746
|
+
STY $70` and overwrites X with #$22 before ever reading it, so a call
|
|
2747
|
+
with the high byte in X prints from a garbage pointer.
|
|
2748
|
+
- **$BA8C** — CONUPK (unpack the 5-byte float at (A/Y) into ARG,
|
|
2749
|
+
$69-$6E); an earlier version called this MOVFA. MOVFA (ARG → FAC) is
|
|
2750
|
+
$BBFC.
|
|
2751
|
+
- **$BBA2** — MOVFM (load FAC from the 5-byte float at (A/Y)); an
|
|
2752
|
+
earlier version called this FIN.
|
|
2753
|
+
- **$BC0C** — MOVAF (copy FAC to ARG); an earlier version called this
|
|
2754
|
+
FOUT.
|
|
2755
|
+
- **$BCF3** — FIN (ASCII at TXTPTR to FAC). Call it the way the ROM
|
|
2756
|
+
does: JSR $0079 (CHRGOT) or $0073 (CHRGET) first, so A holds the first
|
|
2757
|
+
character and the carry is clear for a digit; both ROM callers ($AE8A,
|
|
2758
|
+
$B7D7) do exactly that.
|
|
2759
|
+
- **$BDDD** — FOUT (FAC to a $00-terminated ASCII string starting at
|
|
2760
|
+
$0100; A/Y return the pointer).
|
|
2761
|
+
- **$BFED** — EXP (e^FAC; continues at $E000). Earlier revisions called
|
|
2762
|
+
this MULT2.
|
|
2763
|
+
|
|
2764
|
+
### BASIC vectors (RAM)
|
|
2765
|
+
|
|
2766
|
+
BASIC's behavior is partly steered by 6 vector pairs at $0300-$030B (an
|
|
2767
|
+
earlier revision of this page said 7; the range is 12 bytes, and the
|
|
2768
|
+
defaults are the six words the BASIC cold start copies from the ROM
|
|
2769
|
+
table at $E447 via the loop at $E453). $030C-$030F hold the SYS register
|
|
2770
|
+
images and $0310-$0312 the USR JMP, not further vectors.
|
|
2771
|
+
|
|
2772
|
+
| Vector | Default | Function |
|
|
2773
|
+
|---------|---------|------------------------------------|
|
|
2774
|
+
| IERROR | $E38B | Print BASIC error message |
|
|
2775
|
+
| IMAIN | $A483 | Main BASIC interpreter loop |
|
|
2776
|
+
| ICRNCH | $A57C | Tokenize a line |
|
|
2777
|
+
| IQPLOP | $A71A | De-tokenize for LIST |
|
|
2778
|
+
| IGONE | $A7E4 | Execute a tokenized statement |
|
|
2779
|
+
| IEVAL | $AE86 | Evaluate an expression |
|
|
2780
|
+
|
|
2781
|
+
These get re-initialized to the defaults above on every reset. Custom
|
|
2782
|
+
BASIC extensions (Simon's BASIC, Power BASIC, etc.) wedge in by patching
|
|
2783
|
+
these vectors.
|
|
2784
|
+
|
|
2785
|
+
## Character ROM map
|
|
2786
|
+
|
|
2787
|
+
The character generator ROM is a 4 KB ROM that the VIC-II reads to
|
|
2788
|
+
fetch the pixel patterns for text characters. The CPU can also read
|
|
2789
|
+
it via $D000-$DFFF, but only when CHAREN is 0 (and either LORAM or
|
|
2790
|
+
HIRAM is 1 so the I/O area isn't kept visible).
|
|
2791
|
+
|
|
2792
|
+
### Two character sets
|
|
2793
|
+
|
|
2794
|
+
The character ROM holds two complete 256-character sets:
|
|
2795
|
+
|
|
2796
|
+
- **Set 1 (uppercase + graphics):** $D000-$D7FF (2 KB) — the default
|
|
2797
|
+
after reset.
|
|
2798
|
+
- **Set 2 (uppercase + lowercase):** $D800-$DFFF (2 KB) — switched in
|
|
2799
|
+
by pressing SHIFT+C= or by VIC's character pointer.
|
|
2800
|
+
|
|
2801
|
+
Each character is 8 bytes (8 × 8 = 64 pixels). 256 chars × 8 bytes =
|
|
2802
|
+
2 KB per set.
|
|
2803
|
+
|
|
2804
|
+
### Character ROM layout
|
|
2805
|
+
|
|
2806
|
+
| Range | Set | Codes | Contents |
|
|
2807
|
+
|--------------|-----|---------|-----------------------------------------------------------------|
|
|
2808
|
+
| $D000-$D0FF | 1 | 0-31 | @, A-Z, [ £ ] ↑ ← |
|
|
2809
|
+
| $D100-$D1FF | 1 | 32-63 | space ! " # $ % & ' ( ) * + , - . / 0-9 : ; < = > ? |
|
|
2810
|
+
| $D200-$D3FF | 1 | 64-127 | graphics: horizontal bar (64), card suits, box-drawing, blocks |
|
|
2811
|
+
| $D400-$D7FF | 1 | 128-255 | reverse video of 0-127 |
|
|
2812
|
+
| $D800-$D8FF | 2 | 0-31 | @, a-z, [ £ ] ↑ ← |
|
|
2813
|
+
| $D900-$D9FF | 2 | 32-63 | space, punctuation, 0-9 (byte-identical to set 1) |
|
|
2814
|
+
| $DA00-$DBFF | 2 | 64-127 | horizontal bar (64), A-Z (65-90), remaining graphics |
|
|
2815
|
+
| $DC00-$DFFF | 2 | 128-255 | reverse video of set 2's 0-127 |
|
|
2816
|
+
|
|
2817
|
+
An earlier version of this table put space, punctuation and the digits
|
|
2818
|
+
at codes 64-127 and listed a backslash at code 28; measured against
|
|
2819
|
+
`chargen-901225-01.bin`, the digits and punctuation are codes 32-63
|
|
2820
|
+
(`0` is code 48 at $D180), codes 64-127 are the graphics set (code 64 at
|
|
2821
|
+
$D200 is the horizontal bar), and code 28 is £ — the C64 character ROM
|
|
2822
|
+
has no backslash. The reverse-video halves are the bitwise inverse of
|
|
2823
|
+
codes 0-127 for every glyph except `@`: reversed `@` (code 128, $D400
|
|
2824
|
+
and $DC00) differs from the true inverse by one pixel in row 6 ($99
|
|
2825
|
+
where NOT $62 = $9D).
|
|
2826
|
+
|
|
2827
|
+
### How VIC-II finds the character set
|
|
2828
|
+
|
|
2829
|
+
The VIC-II's $D018 register controls character pointer + screen pointer
|
|
2830
|
+
within the current 16 KB VIC bank. The default value $14 means:
|
|
2831
|
+
|
|
2832
|
+
- Screen RAM at offset $400 inside VIC bank 0 → $0400-$07E7.
|
|
2833
|
+
- Character ROM at offset $1000 inside VIC bank 0 → $1000-$1FFF (a
|
|
2834
|
+
shadow of $D000-$D7FF inside the VIC bank).
|
|
2835
|
+
|
|
2836
|
+
The character ROM is *shadowed* into VIC banks 0 and 2:
|
|
2837
|
+
- Bank 0 ($0000-$3FFF): char ROM at $1000-$1FFF.
|
|
2838
|
+
- Bank 2 ($8000-$BFFF): char ROM at $9000-$9FFF.
|
|
2839
|
+
- Banks 1 and 3 see RAM there.
|
|
2840
|
+
|
|
2841
|
+
This is why custom character sets typically live in VIC bank 1 or 3:
|
|
2842
|
+
those banks don't have the character ROM shadowed, so the VIC sees
|
|
2843
|
+
whatever RAM is there.
|
|
2844
|
+
|
|
2845
|
+
### Copying the char ROM to RAM
|
|
2846
|
+
|
|
2847
|
+
The canonical pattern for a custom font is to copy the char ROM out
|
|
2848
|
+
of $D000-$D7FF into RAM somewhere (often $3000-$37FF), then update
|
|
2849
|
+
$D018 to point at the RAM copy. The copy code:
|
|
2850
|
+
|
|
2851
|
+
```
|
|
2852
|
+
SEI ; disable IRQs (KERNAL will choke)
|
|
2853
|
+
LDA $01
|
|
2854
|
+
PHA
|
|
2855
|
+
AND #$FB ; clear CHAREN bit (CHAREN = 0 → char ROM visible)
|
|
2856
|
+
STA $01
|
|
2857
|
+
|
|
2858
|
+
LDX #$00
|
|
2859
|
+
loop:
|
|
2860
|
+
LDA $D000,X
|
|
2861
|
+
STA $3000,X
|
|
2862
|
+
LDA $D100,X
|
|
2863
|
+
STA $3100,X
|
|
2864
|
+
... ; repeat for $D200-$D7FF
|
|
2865
|
+
INX
|
|
2866
|
+
BNE loop
|
|
2867
|
+
|
|
2868
|
+
PLA
|
|
2869
|
+
STA $01 ; restore $01 (CHAREN back to default)
|
|
2870
|
+
CLI
|
|
2871
|
+
```
|
|
2872
|
+
|
|
2873
|
+
After copying, set $D018 bits 1-3 to point at $3000 (= $0C):
|
|
2874
|
+
`LDA #$1C / STA $D018`.
|
|
2875
|
+
|
|
2876
|
+
## I/O area
|
|
2877
|
+
|
|
2878
|
+
The I/O area at $D000-$DFFF is only present when CHAREN = 1 *and*
|
|
2879
|
+
LORAM = 1 *or* HIRAM = 1. In the default config it's a 4 KB window
|
|
2880
|
+
containing four chips' worth of registers (VIC-II, SID, CIA #1, CIA #2)
|
|
2881
|
+
plus 1 KB of Color RAM plus 2 × 256 bytes of cartridge I/O. (An earlier
|
|
2882
|
+
version of this sentence said five; the Color RAM is a nibble-wide
|
|
2883
|
+
static RAM with no registers and is already counted separately here.)
|
|
2884
|
+
|
|
2885
|
+
### Sub-regions
|
|
2886
|
+
|
|
2887
|
+
| Range | Contents |
|
|
2888
|
+
|--------------|----------------------------------------------|
|
|
2889
|
+
| $D000-$D3FF | VIC-II registers + 16-fold shadow |
|
|
2890
|
+
| $D400-$D7FF | SID registers + 32-fold shadow |
|
|
2891
|
+
| $D800-$DBFF | Color RAM (1024 × 4 bits) |
|
|
2892
|
+
| $DC00-$DCFF | CIA #1 + 16-fold shadow |
|
|
2893
|
+
| $DD00-$DDFF | CIA #2 + 16-fold shadow |
|
|
2894
|
+
| $DE00-$DEFF | I/O expansion area 1 (cartridge) |
|
|
2895
|
+
| $DF00-$DFFF | I/O expansion area 2 (cartridge) |
|
|
2896
|
+
|
|
2897
|
+
### Shadow / mirror behavior
|
|
2898
|
+
|
|
2899
|
+
Each chip occupies a small number of register bytes but is decoded
|
|
2900
|
+
across a much larger address window:
|
|
2901
|
+
|
|
2902
|
+
- **VIC-II**: 47 registers ($D000-$D02E) + 1 unused. The chip decodes
|
|
2903
|
+
on the lower 6 bits of the address, so the next 64-byte block
|
|
2904
|
+
($D040-$D07F) is a mirror, and the pattern repeats every 64 bytes
|
|
2905
|
+
through $D3FF.
|
|
2906
|
+
- **SID**: 29 registers ($D400-$D41C). Decoded on the lower 5 bits, so
|
|
2907
|
+
$D420-$D43F mirrors $D400-$D41F, repeating every 32 bytes through
|
|
2908
|
+
$D7FF.
|
|
2909
|
+
- **Color RAM**: 1024 bytes; no shadow within $D800-$DBFF.
|
|
2910
|
+
- **CIA #1**: 16 registers ($DC00-$DC0F). Mirrors every 16 bytes through
|
|
2911
|
+
$DCFF.
|
|
2912
|
+
- **CIA #2**: 16 registers ($DD00-$DD0F). Mirrors every 16 bytes through
|
|
2913
|
+
$DDFF.
|
|
2914
|
+
|
|
2915
|
+
Software should always address the canonical low addresses ($D000,
|
|
2916
|
+
$D400, $DC00, $DD00) — the shadows are an artifact of partial address
|
|
2917
|
+
decoding, not a feature, and some clones don't replicate them.
|
|
2918
|
+
|
|
2919
|
+
### When you read from a non-existent I/O location
|
|
2920
|
+
|
|
2921
|
+
If you read from an address in the I/O block that no chip drives, you
|
|
2922
|
+
get an "open bus" read: whatever the data bus last carried, which on a
|
|
2923
|
+
C64 is usually the byte the VIC-II fetched in the preceding half-cycle.
|
|
2924
|
+
On a stock machine that means $DE00-$DFFF with no cartridge fitted (and
|
|
2925
|
+
the upper nibble of Color RAM, see $D800 above). The VIC-II's unused
|
|
2926
|
+
addresses $D02F-$D03F are *not* open bus: the chip answers $FF and
|
|
2927
|
+
ignores writes (measured in VICE x64sc; see
|
|
2928
|
+
[vic-ii-reference.md](vic-ii-reference.md)). An earlier version of this
|
|
2929
|
+
section used $D02F as the open-bus example, which it is not. Open-bus
|
|
2930
|
+
values are unpredictable; don't rely on them.
|
|
2931
|
+
|
|
2932
|
+
### I/O timing
|
|
2933
|
+
|
|
2934
|
+
Reading or writing any I/O register takes the normal 4 CPU cycles for
|
|
2935
|
+
the access. The CIAs and SID have no wait states. The VIC-II can,
|
|
2936
|
+
however, *steal* the bus from the CPU on badlines and during sprite
|
|
2937
|
+
DMA, which appears to the CPU as the instruction simply taking longer
|
|
2938
|
+
to execute. See [vic-ii-reference.md](vic-ii-reference.md#raster-system).
|
|
2939
|
+
|
|
2940
|
+
## Pitfalls
|
|
2941
|
+
|
|
2942
|
+
- **$0001 — clobbering KERNAL zeropage.** Writing to addresses in
|
|
2943
|
+
$90-$FE while interrupts are enabled risks the KERNAL IRQ handler
|
|
2944
|
+
reading or writing the same byte. The IRQ ticks about 60 times a
|
|
2945
|
+
second on both PAL and NTSC (CIA #1 Timer A, latch $4025 on PAL and
|
|
2946
|
+
$4295 on NTSC — the period is latch+1 cycles; see $00A0-$00A2; an
|
|
2947
|
+
earlier version said "or 50 Hz on PAL") and runs UDTIM ($FFEA) + the
|
|
2948
|
+
keyscan, both of which touch zeropage. Disable IRQs (SEI) before
|
|
2949
|
+
manipulating KERNAL-owned zero-page bytes.
|
|
2950
|
+
|
|
2951
|
+
- **$0000 / $0001 — DDR must be set first.** Writing to the
|
|
2952
|
+
processor-port data register $01 only affects pins configured as
|
|
2953
|
+
outputs by the DDR at $00. If a prior program (or a bug) has left
|
|
2954
|
+
bits of $00 as inputs, your bank-switch write won't take. Always
|
|
2955
|
+
write the expected DDR ($2F for a stock C64) before writing $01:
|
|
2956
|
+
`LDA #$2F / STA $00 / LDA #$35 / STA $01`.
|
|
2957
|
+
|
|
2958
|
+
- **$01 bit 6/7 — unconnected pins on stock C64.** Bits 6 and 7 of $01
|
|
2959
|
+
are not bonded out on a stock C64 (the C128's 8502 gives bit 6 to the
|
|
2960
|
+
CAPS LOCK key; whether SX-64 boards differ is sometimes claimed and
|
|
2961
|
+
not verified here).
|
|
2962
|
+
Reading them yields the last-driven value with very slow capacitive
|
|
2963
|
+
decay. Treat as undefined and mask off when reading $01 for the
|
|
2964
|
+
bank-config bits.
|
|
2965
|
+
|
|
2966
|
+
- **$E000-$FFFF — IRQ vectors live in RAM when KERNAL banked out.**
|
|
2967
|
+
When you bank KERNAL ROM out (any mode with HIRAM = 0), $FFFA/$FFFB
|
|
2968
|
+
(NMI), $FFFC/$FFFD (RESET), and $FFFE/$FFFF (IRQ/BRK) are *RAM*. The
|
|
2969
|
+
CPU still reads them on interrupts. You *must* populate those RAM
|
|
2970
|
+
bytes with valid handler addresses before banking out. Forgetting
|
|
2971
|
+
causes the machine to jump to wherever-uninitialized-RAM-happens-to-
|
|
2972
|
+
point and crash. The fix: SEI; write your handler addresses into
|
|
2973
|
+
$FFFA-$FFFF; then write $01.
|
|
2974
|
+
|
|
2975
|
+
- **$D018 — CHROUT changes it for exactly two codes, and the keyboard
|
|
2976
|
+
can too.** CHROUT does not touch $D018 on ordinary output (an earlier
|
|
2977
|
+
version of this page said it wrote $D018 on every call "in screen
|
|
2978
|
+
mode 1"; the KERNAL has no such path — the 901227-03 ROM holds only
|
|
2979
|
+
the two conditional stores named here). PETSCII $0E / CHR$(14) *sets*
|
|
2980
|
+
bit 1 (charset 2, lower case) and $8E / CHR$(142) *clears* it
|
|
2981
|
+
($EC44-$EC5B); the IRQ keyscan *toggles* bit 1 with EOR when SHIFT+C=
|
|
2982
|
+
is pressed ($EB48-$EB61), once per press and only while $0291 bit 7
|
|
2983
|
+
is clear. Measured in VICE x64sc: with $D018 preset to $1C, 60
|
|
2984
|
+
CHROUTs of "A" and 30 scrolling CRs left it unchanged, and a sweep of
|
|
2985
|
+
all 256 codes changed it exactly twice, at $0E and $8E. A custom font
|
|
2986
|
+
is the usual victim, because bit 1 selects the odd 2 KB half: a font
|
|
2987
|
+
at $2000 ($D018 = $18) becomes $2800 ($1A) on SHIFT+C=. Remedies: do
|
|
2988
|
+
not send $0E/$8E; lock the keyboard path with CHR$(8) (or POKE $0291
|
|
2989
|
+
= $80) — which does *not* suppress the CHROUT codes (measured: after
|
|
2990
|
+
CHR$(8), CHR$(14) still set bit 1); or re-write $D018 in your own
|
|
2991
|
+
IRQ. Wrapping every CHROUT in a save/restore of $D018 is unnecessary.
|
|
2992
|
+
|
|
2993
|
+
- **$DD00 — VIC-II bank changes via CIA #2 are inverted.** Setting
|
|
2994
|
+
$DD00 bits 0-1 to 11 (binary) selects VIC bank 0, not 3. The bits
|
|
2995
|
+
are inverted because the lines drive the VIC's address pins active-
|
|
2996
|
+
low. Off-by-one bank selection is a classic crash mode. (An earlier
|
|
2997
|
+
version of this entry was headed $DC00-$DCFF; that range is CIA #1,
|
|
2998
|
+
the keyboard/joystick chip, and writing bank bits there leaves the
|
|
2999
|
+
VIC where it was — measured in VICE x64sc.)
|
|
3000
|
+
|
|
3001
|
+
- **$D7FF — SID write side-effects via shadow.** A write to $D7FF lands
|
|
3002
|
+
in SID register $1F (which is undefined). Some emulators handle this
|
|
3003
|
+
differently from real hardware. Avoid writing to SID shadow addresses;
|
|
3004
|
+
always use the canonical $D400-$D41C window.
|
|
3005
|
+
|
|
3006
|
+
- **$02, $00FB-$00FE — five bytes of safe zeropage.** When coexisting
|
|
3007
|
+
with BASIC and KERNAL, $02 and $FB-$FE are the only zero-page bytes
|
|
3008
|
+
neither ROM touches after reset. Using $03-$8F clobbers BASIC; using
|
|
3009
|
+
$90-$FA clobbers KERNAL; $FF is BASIC's FOUT workspace. (Earlier text
|
|
3010
|
+
counted four bytes and put $02 in BASIC's range; the ROM bytes show no
|
|
3011
|
+
reference to $02 beyond RAMTAS's reset clear.) The fix: take over the
|
|
3012
|
+
machine, or stay inside those five.
|
|
3013
|
+
|
|
3014
|
+
- **$0100-$01FF — stack page wraparound.** The stack pointer S is 8
|
|
3015
|
+
bits and wraps from $00 to $FF without warning — but only your own
|
|
3016
|
+
machine code can get there. BASIC guards its stack: every GOSUB, FOR
|
|
3017
|
+
and expression-nesting level first calls the check at $A3FB, which
|
|
3018
|
+
raises ?OUT OF MEMORY (error 16) unless the stack pointer seen inside
|
|
3019
|
+
that routine is at least 2×n+$3E ($44 for GOSUB, n=3; $50 for FOR,
|
|
3020
|
+
n=9; $40 per expression level, n=1). So `10 GOSUB 10` stops with
|
|
3021
|
+
"?OUT OF MEMORY ERROR IN 10" and S never falls below about $40 —
|
|
3022
|
+
measured in VICE x64sc: the GOSUB loop trips with S=$40, 64 bytes of
|
|
3023
|
+
the page still unused. An earlier version of this page said a deep
|
|
3024
|
+
BASIC nest wraps S past zero with no trap; it does not. PHA/JSR chains
|
|
3025
|
+
in your own code under an existing stack have no such guard: that is
|
|
3026
|
+
where the wrap bites.
|
|
3027
|
+
|
|
3028
|
+
- **$0314-$0333 — vector resetting on KERNAL RESTOR.** The KERNAL's
|
|
3029
|
+
RESTOR routine ($FF8A, body at $FD15) copies the ROM default table at
|
|
3030
|
+
$FD30-$FD4F over $0314-$0333. Calling RESTOR, VECTOR ($FF8D) with
|
|
3031
|
+
C=0, or anything that runs the reset ($FCE2) or RUN/STOP+RESTORE
|
|
3032
|
+
($FE47) sequence — both of which call RESTOR themselves — wipes your
|
|
3033
|
+
custom IRQ handler. IOINIT ($FF84) and CINT ($FF81) do *not*: the only
|
|
3034
|
+
callers of $FD15 in the ROM are $FCF8 and $FE66, and in VICE x64sc a
|
|
3035
|
+
custom $0314/$0315 survives both IOINIT and CINT and is replaced by
|
|
3036
|
+
RESTOR (an earlier version of this page said IOINIT calls RESTOR
|
|
3037
|
+
internally; it does not). Hook by writing $0314/$0315 *after* the
|
|
3038
|
+
last such call.
|
|
3039
|
+
|
|
3040
|
+
- **$0800 — BASIC program-start sentinel.** BASIC requires the byte
|
|
3041
|
+
just below TXTTAB — $0800, not $0801 as an earlier revision of this
|
|
3042
|
+
entry said — to be $00 (see $0800 above). It stands in for the
|
|
3043
|
+
end-of-line marker of the line before the first one: RUN and NEW both
|
|
3044
|
+
reset TXTPTR to TXTTAB−1 (RUNC, $A68E) and the next-statement fetch
|
|
3045
|
+
($A7BE) reads that byte, so anything but $00 there answers
|
|
3046
|
+
`?SYNTAX ERROR` (measured in VICE x64sc: `POKE 2048,1` then RUN →
|
|
3047
|
+
`?SYNTAX ERROR`; NEW → `?SYNTAX ERROR` too, although the program is
|
|
3048
|
+
still erased). LIST is unaffected — it walks the link chain from
|
|
3049
|
+
TXTTAB. $0801–$0802 are the first line's link pointer and are
|
|
3050
|
+
non-zero in any program with a line (`0B 08` for the stub below). A
|
|
3051
|
+
machine-language file with load address $0801 cannot disturb the
|
|
3052
|
+
sentinel; what breaks it is a file that loads at $0800 with a non-zero
|
|
3053
|
+
first byte, or code that uses $0800 as scratch. Use a BASIC SYS stub
|
|
3054
|
+
at $0801; a raw load at $0801 without one is started with `SYS 2049`,
|
|
3055
|
+
not RUN.
|
|
3056
|
+
|
|
3057
|
+
- **$8000 — "CBM80" cart auto-start magic.** At reset (and on NMI) the
|
|
3058
|
+
KERNAL routine at $FD02 (called from $FCE2) compares $8004-$8008 with
|
|
3059
|
+
`C3 C2 CD 38 30` ("CBM80" in PETSCII, the letters shifted); on a
|
|
3060
|
+
match reset does `JMP ($8000)` before any initialisation, and RESTORE
|
|
3061
|
+
jumps through $8002/$8003. A cartridge at $8000-$9FFF (or a 16 KB one
|
|
3062
|
+
at $8000-$BFFF) autostarts this way; ROM at $A000-$BFFF alone cannot,
|
|
3063
|
+
because the check runs while BASIC ROM is still mapped there.
|
|
3064
|
+
$8000-$9FFF is ordinary RAM when no cartridge is inserted, so if a
|
|
3065
|
+
program leaves those nine bytes looking like a cartridge header, the
|
|
3066
|
+
next reset jumps through whatever is at $8000 instead of booting
|
|
3067
|
+
BASIC — a trick reset-protected software has used deliberately, and a
|
|
3068
|
+
crash mode if it is left there by accident (which programs do it is
|
|
3069
|
+
not verified here). (An earlier version placed the check at
|
|
3070
|
+
$A000-$A008; $A000 is BASIC ROM at reset and is never checked — the
|
|
3071
|
+
ROM compares $8003,X, verified against kernal-901227-03 and in VICE.)
|
|
3072
|
+
|
|
3073
|
+
- **$D018 — pointing at non-existent character data.** The character-set
|
|
3074
|
+
bits in $D018 (bits 1-3) point to 2 KB chunks inside the current VIC
|
|
3075
|
+
bank. If you select a chunk that has no font data — say a screen
|
|
3076
|
+
RAM range — the display will show garbage. Always set $D018 to a
|
|
3077
|
+
known-good font pointer before enabling display.
|
|
3078
|
+
|
|
3079
|
+
- **$DD00 — touching CIA #2 disables RS-232.** Writes to $DD00 control
|
|
3080
|
+
both VIC-II bank selection *and* the RS-232 transmit line. If you're
|
|
3081
|
+
using RS-232 + want to change VIC bank, you must mask carefully:
|
|
3082
|
+
preserve bits 2-7 of $DD00 while updating bits 0-1.
|
|
3083
|
+
|
|
3084
|
+
- **$FFFE-$FFFF — IRQ fired during bank switch.** If an IRQ fires between
|
|
3085
|
+
your write to $01 (banking KERNAL out) and your install of the new
|
|
3086
|
+
IRQ handler, the CPU will read $FFFE/$FFFF from RAM and crash. *Always*
|
|
3087
|
+
SEI before banking; install $FFFA-$FFFF; only then CLI.
|
|
3088
|
+
|
|
3089
|
+
- **$D012 raster wrap vs $D011 bit 7.** $D012 reports the low 8 bits
|
|
3090
|
+
of the current raster line, but PAL has 312 raster lines (NTSC has
|
|
3091
|
+
263). Lines ≥ 256 read $D012 with bit 8 in $D011. Comparing $D012
|
|
3092
|
+
to 256+ requires combining $D011 bit 7 — see
|
|
3093
|
+
[vic-ii-reference.md](vic-ii-reference.md#raster-system).
|
|
3094
|
+
|
|
3095
|
+
- **Mixing CHAREN + raster IRQs.** If you bank in the character ROM
|
|
3096
|
+
($01 with CHAREN = 0) and a raster IRQ fires, the IRQ handler will
|
|
3097
|
+
read $DC0D as part of acknowledging — but $DC0D is now reading
|
|
3098
|
+
character-ROM data, not the CIA. The KERNAL's IRQ acknowledge will
|
|
3099
|
+
not clear the CIA, and the IRQ will fire again immediately, locking
|
|
3100
|
+
the machine. Always bank I/O in before allowing IRQs.
|
|
3101
|
+
|
|
3102
|
+
- **Color RAM upper nibble is random.** Reads from $D800-$DBFF return
|
|
3103
|
+
4 bits of color in the lower nibble and garbage in the upper. Always
|
|
3104
|
+
AND with #$0F when reading Color RAM.
|
|
3105
|
+
|
|
3106
|
+
- **Stack page double-duty.** BASIC's float-to-ASCII routine FOUT
|
|
3107
|
+
($BDDD, in the BASIC ROM; reached by PRINT and STR$, and by the
|
|
3108
|
+
line-number print that LIST and the `IN` message use) builds its
|
|
3109
|
+
string at the bottom of the stack page. The PRINT entry writes
|
|
3110
|
+
$0100-$010F in the worst case (`-1.23456789E+28` is 15 characters
|
|
3111
|
+
plus the terminator; the routine caps output at nine digits); the
|
|
3112
|
+
STR$ and LIST entries start one byte lower, at $00FF. Measured in
|
|
3113
|
+
VICE x64sc by seeding $00F8-$011F and calling the routine. An earlier
|
|
3114
|
+
version of this note called the routine the KERNAL's, said it was
|
|
3115
|
+
reached through CHROUT, and stopped the buffer at $010A — CHROUT
|
|
3116
|
+
prints one character and never converts a number. Anything parked at
|
|
3117
|
+
$00FF-$010F (a depacker, a saved register block, the tape error log)
|
|
3118
|
+
is overwritten the next time BASIC prints a number. Pushed data is
|
|
3119
|
+
only reached once S has descended below $10 — about 240 bytes deep —
|
|
3120
|
+
so "PHA'd 11 bytes" was never the hazard.
|
|
3121
|
+
|
|
3122
|
+
- **$DE00/$DF00 open bus.** With no cartridge, reads from $DE00-$DFFF
|
|
3123
|
+
return open-bus garbage (typically the last VIC fetch). Don't probe
|
|
3124
|
+
for cartridge presence by reading these — write a known pattern
|
|
3125
|
+
and read it back, or use a dedicated detection sequence.
|
|
3126
|
+
|
|
3127
|
+
- **$0000/$0001 cassette-motor write side-effect.** Writing to $01
|
|
3128
|
+
with bit 5 cleared turns on the cassette motor. If your bank-switch
|
|
3129
|
+
code uses `LDA #$05 / STA $01`, you're also turning the cassette
|
|
3130
|
+
motor *on*. Mask carefully: typical bank values keep bit 5 = 1.
|
|
3131
|
+
|
|
3132
|
+
- **MEMSIZ is snapshotted by BASIC.** $0283/$0284 is the KERNAL's
|
|
3133
|
+
top-of-memory, set by RAMTAS (via $FE2D) at reset. BASIC copies it
|
|
3134
|
+
into its own MEMSIZ ($37/$38) and STRBOT/FRETOP ($33/$34) once, at
|
|
3135
|
+
cold start ($E40A-$E414: SEC / JSR $FF99 / STX $37 / STY $38 /
|
|
3136
|
+
STX $33 / STY $34), and never reads $0283/$0284 again — the BASIC ROM
|
|
3137
|
+
contains no reference to it. Poking $0283/$0284, or calling MEMTOP
|
|
3138
|
+
($FF99) with C=0 — which does nothing but STX $0283 / STY $0284 —
|
|
3139
|
+
therefore has no effect on BASIC's string space (an earlier revision
|
|
3140
|
+
of this page said to call MEMTOP instead of poking; measured in VICE,
|
|
3141
|
+
both leave BASIC's top at $A000 and the next string is placed just
|
|
3142
|
+
under it). To reserve memory above BASIC, lower $37/$38 and then CLR,
|
|
3143
|
+
which recopies MEMSIZ into FRETOP: `POKE 55,lo: POKE 56,hi: CLR`
|
|
3144
|
+
(e.g. `POKE 56,128: CLR` for $8000). The one runtime path that does
|
|
3145
|
+
resync BASIC from the KERNAL's top is RS-232: OPEN/CLOSE of device 2
|
|
3146
|
+
returns pseudo-error $F0 with the new top in X/Y ($F47D), and BASIC's
|
|
3147
|
+
error handler ($E0F9) stores it to $37/$38 and jumps into CLR at
|
|
3148
|
+
$A663 — which is why OPEN 2,2 performs an automatic CLR and lowers
|
|
3149
|
+
BASIC's top by 512 bytes.
|
|
3150
|
+
|
|
3151
|
+
- **TXTPTR mid-statement.** Modifying $7A/$7B (TXTPTR) while a BASIC
|
|
3152
|
+
statement is executing makes BASIC read its next token from your
|
|
3153
|
+
chosen address. Useful for "GOSUB to dynamic line number" but easy
|
|
3154
|
+
to crash if you point at non-BASIC data.
|
|
3155
|
+
|
|
3156
|
+
- **$0801 BASIC stub for ML programs.** The canonical ML autostart
|
|
3157
|
+
uses a BASIC stub like `10 SYS 2064` at $0801: `0B 08` (link to the
|
|
3158
|
+
next line at $080B) `0A 00` (line 10) `9E` (SYS token) `32 30 36 34`
|
|
3159
|
+
("2064" as PETSCII digits) `00` (end of line) `00 00` (end of
|
|
3160
|
+
program) — 12 bytes, $0801-$080C — with the ML at $0810 (= 2064).
|
|
3161
|
+
This is byte-for-byte what KickAssembler 5.25's `BasicUpstart2` emits
|
|
3162
|
+
for code at `*=$0810`; the assembler zero-fills $080D-$080F. If you
|
|
3163
|
+
type the line at the keyboard instead, the tokenizer keeps the space
|
|
3164
|
+
after SYS: `0C 08 0A 00 9E 20 32 30 36 34 00 00 00`, 13 bytes to
|
|
3165
|
+
$080D with the link at $080C (measured in VICE x64sc 3.10). An earlier
|
|
3166
|
+
version of this bullet mixed the two forms — the $20 space with the
|
|
3167
|
+
12-byte link $080B — and put the ML at $080D, which SYS 2064 does not
|
|
3168
|
+
reach ($080D is 2061). Skipping the stub and loading raw code at
|
|
3169
|
+
$0801 means the user must type `SYS 2049` (2049 = $0801).
|
|
3170
|
+
|
|
3171
|
+
- **CIA timers count φ2 cycles.** In the default input mode (CRA bit 5
|
|
3172
|
+
= 0, CRB bits 5-6 = 00) a timer *decrements* once per CPU cycle —
|
|
3173
|
+
985,248/s PAL, 1,022,727/s NTSC — and underflows every latch+1 cycles
|
|
3174
|
+
(measured in VICE x64sc: latch 9 gives 400 underflows in 4006
|
|
3175
|
+
cycles). There is no prescaler; the rate is set by the latch, and
|
|
3176
|
+
Timer B can instead be clocked by Timer A underflows (CRB INMODE 10,
|
|
3177
|
+
also measured), or either timer by CNT-pin edges (datasheet; not
|
|
3178
|
+
measurable in VICE). Code copied from a platform whose timers tick at
|
|
3179
|
+
a divided clock will time wrong. (An earlier version of this bullet
|
|
3180
|
+
said the timer "underflows once per CPU cycle" under a "DC clock" and
|
|
3181
|
+
that the divisor was fixed; it decrements once per cycle, and Timer
|
|
3182
|
+
B's input is selectable.)
|
|
3183
|
+
|
|
3184
|
+
<!-- doc-type: hardware-reference -->
|