--- name: memory-map description: > Use this skill for questions about C64 memory organization, zero page locations, memory banking, PEEK/POKE addresses, sprite memory, screen RAM, color RAM, protecting ML programs, and placing data/code in RAM. Sources: COMPUTE!'s Mapping the Commodore 64, The Anatomy of the C64, The Complete C64 ROM Disassembly. --- # Commodore 64 Memory Map ## Complete Address Space ``` Address Decimal Contents (default banking) ----------- ------------- ---------------------------------------- $0000 0 6510 I/O direction register $0001 1 6510 I/O port (bank control/tape/motor) $0002 2 Unused (3 free bytes: $02) $0003-$0004 3-4 Float→integer vector (ADRAY1) $0005-$0006 5-6 Integer→float vector (ADRAY2) $0007 7 Search character (BASIC) $0008 8 Quote mode flag $0009 9 TAB column counter $000A 10 Load/Verify flag (0=LOAD, 1=VERIFY) $000B 11 Input buffer pointer / subscript counter $000C 12 Default DIM flag $000E 14 Type flag (80=integer, 00=float) $000F 15 DATA scan / LIST quote / memory flag $0010 16 Subscript / FNx flag $0011 17 0=INPUT, $40=GET, $98=READ $0012 18 ATN sign / comparison flag $0013 19 Current I/O prompt flag $0014-$0015 20-21 Integer value temporary $0016 22 Pointer to temp string stack $0017-$0018 23-24 Last temp string vector $0019-$0021 25-33 Stack for temporary strings $0022-$0025 34-37 Miscellaneous work area $0026-$002A 38-42 Product area (math) $002B-$002C 43-44 TXTTAB — pointer to start of BASIC text $002D-$002E 45-46 VARTAB — start of variable storage $002F-$0030 47-48 ARYTAB — start of array storage $0031-$0032 49-50 STREND — end of array storage (+1) $0033-$0034 51-52 FRETOP — top of free string space $0035-$0036 53-54 FRESPC — string utility pointer $0037-$0038 55-56 MEMSIZ — pointer to end of memory / bottom of strings $0039-$003A 57-58 CURLIN — current BASIC line number $003B-$003C 59-60 OLDLIN — previous BASIC line number $003D-$003E 61-62 OLDTXT — pointer to previous BASIC statement $003F-$0040 63-64 DATLIN — line number of current DATA statement $0041-$0042 65-66 DATPTR — pointer to current DATA item $0043-$0044 67-68 INPPTR — INPUT source pointer $0045-$0046 69-70 VARNAM — name of current variable $0047-$0048 71-72 VARPNT — pointer to current variable $0049-$004A 73-74 FORPNT — pointer to FOR/NEXT variable $004B 75 OPPTR — operator precedence $004C 76 OPMASK — mask for operator $004D-$0050 77-80 TEMPPT — temp string and area $0051 81 LASTPT — pointer to last temp string $0052-$0053 82-83 TEMPST — pointer to string $0054 84 INDEX (low), INDEX+1 (high) $005E 94 FAC#2 (floating point accumulator #2) $0060-$0066 96-102 FAC#1 (floating point accumulator #1, 5 bytes + sign/exp) $006F 111 Pointer to start of string being processed $0071-$0072 113-114 RESULT — pointer to end of string $0073 115 Jump instruction for USR $0074-$0075 116-117 USR function address (JSR target) $0076 118 CHARAC — search character $007A-$007B 122-123 FNPNT — pointer for FN functions $00AC-$00AD 172-173 STRNG1 — string 1 pointer $00AE-$00AF 174-175 STRNG2 — string 2 pointer $00B7 183 FNLEN — length of filename $00B8 184 LOGICAL — logical file number $00B9 185 DFLTO — output device number $00BA 186 DFLTI — input device number $00BB 187 SA — secondary address $00BC 188 EAL — tape end address (low) $00BD 189 EAH — tape end address (high) $00BE 190 TAPE1 — tape buffer pointer $00BF 191 COUNT — tape character counter $00C0 192 INIT — tape signal level $00C1 193 SKPO — skip byte count $00C2 194 BPTR — tape data pointer $00C3-$00C4 195-196 TAPE2 — tape end buffer pointer $00C5 197 LSTX — last key pressed (keyboard matrix row) $00C6 198 NDX — number of characters in keyboard buffer $00C7 199 RVS — reverse mode flag (1=reverse on) $00C8 200 INDX — end-of-line pointer for current screen line $00C9-$00CA 201-202 LNMX — pointer to cursor on screen $00CB 203 SCHAR — character under cursor $00CC 204 BLNSW — cursor blink switch (0=blink) $00CD 205 BLNCT — countdown to cursor blink $00CE 206 GDBLN — char under cursor (save) $00CF 207 BLNON — cursor blink status (0=off) $00D0 208 CRSW — flag: 0=cursor in key queue, 1=not $00D1-$00D2 209-210 PNT — pointer to cursor line in screen RAM $00D3 211 PNTR — column of cursor on screen $00D4 212 QTSW — quote mode flag $00D5 213 LNMX — screen line length (39 or 79) $00D6 214 TBLX — current cursor row (0-24) $00D7 215 Spare byte $00D8 216 INSRT — insert mode count $00D9-$00F2 217-242 LDTB1 — line link table (25 lines) $00F3-$00F4 243-244 USER — pointer to color RAM for cursor line $00F5-$00F6 245-246 KEYTAB — pointer to keyboard decode table $00F7-$00F8 247-248 RIBUF — RS-232 input buffer pointer $00F9-$00FA 249-250 ROBUF — RS-232 output buffer pointer $00FB-$00FE 251-254 FREKZP — FREE ZERO PAGE (user programs) $00FF 255 (used by BASIC math) $0100-$01FF 256-511 6510 Stack (grows down from $01FF) $0200-$0258 512-600 Basic input buffer (80 chars) $0259-$0262 601-610 LDTB2 — open file logical-number table $0263-$026C 611-620 LATBL — open file device-number table $026D-$0276 621-630 SATBL — open file secondary-address table $0277-$0280 631-640 Keyboard buffer (10 chars, FIFO) $0281-$0282 641-642 MEMBOT — bottom of memory pointer $0283-$0284 643-644 MEMTOP — top of memory pointer $0285 645 TIMOUT — serial bus timeout flag $0286 646 COLOR — current text foreground color $0287 647 BDRCLR — border color at cursor $0288 648 HIBASE — high byte of screen RAM base ($04 = $0400) $0289 649 XMAX — max chars in keyboard buffer (default: 10) $028A 650 RPTFLG — key repeat flag (0=cursor keys+INS/DEL only) $028B 651 KOUNT — repeat delay counter $028C 652 DELAY — repeat speed counter $028D 653 SHFLAG — shift/ctrl/C= key flags $028E 654 LSTSHF — previous shift key state $028F-$0290 655-656 KEYLOG — pointer to keyboard decode logic $0291 657 DFLTN — default input device (0=keyboard) $0292 658 DFLTO — default output device (3=screen) $0293 659 PRTY — serial bus parity $0294 660 DPSW — serial bus deferred character flag $0295 661 MSGFLG — OS message flag $0296 662 ARGT — type of FAC#1 argument $0297 663 ERRNUM — BASIC error number $0298 664 ERRSAV — BASIC error line save $0299-$029A 665-666 IOLINK — I/O start address $029B-$029E 667-670 TRPTAB — trap vectors $02A1-$02FF 673-767 Free RAM (87 bytes) $0300-$0301 768-769 IERROR — indirect BASIC error vector $0302-$0303 770-771 IMAIN — indirect BASIC main loop vector $0304-$0305 772-773 ICRNCH — indirect BASIC crunch vector $0306-$0307 774-775 IQPLOP — indirect BASIC LIST vector $0308-$0309 776-777 IGONE — indirect BASIC execute vector $030A-$030B 778-779 IEVAL — indirect BASIC expression evaluate vector $030C 780 SAREG — A register save on SYS $030D 781 SXREG — X register save on SYS $030E 782 SYREG — Y register save on SYS $030F 783 SPREG — Status register save on SYS $0310-$0311 784-785 USRPOK — USR function vector (JMP opcode + address) $0312-$0313 786-787 (USR vector high byte + unused) $0314-$0315 788-789 CINV — IRQ vector (default: $EA31) $0316-$0317 790-791 CBINV — BRK vector (default: $FE66) $0318-$0319 792-793 NMINV — NMI vector (default: $FE47) $031A-$031B 794-795 IOPEN — indirect OPEN vector $031C-$031D 796-797 ICLOSE — indirect CLOSE vector $031E-$031F 798-799 ICHKIN — indirect CHKIN vector $0320-$0321 800-801 ICHKOUT — indirect CHKOUT vector $0322-$0323 802-803 ICLRCH — indirect CLRCH vector $0324-$0325 804-805 IBASIN — indirect BASIN (CHRIN) vector $0326-$0327 806-807 IBSOUT — indirect BSOUT (CHROUT) vector $0328-$0329 808-809 ISTOP — indirect STOP vector $032A-$032B 810-811 IGETIN — indirect GETIN vector $032C-$032D 812-813 ICLALL — indirect CLALL vector $032E-$032F 814-815 USRCMD — user-defined command vector $0330-$0331 816-817 ILOAD — indirect LOAD vector $0332-$0333 818-819 ISAVE — indirect SAVE vector $0334-$033B 820-827 (spare) $033C-$03FB 828-1019 Cassette buffer (192 bytes) $03FC-$03FF 1020-1023 (free) $0400-$07E7 1024-2023 Screen RAM (default: 40×25 = 1000 bytes) $07E8-$07FF 2024-2047 Sprite pointers (8 bytes, one per sprite) $0800-$9FFF 2048-40959 BASIC program area (38912 bytes) $A000-$BFFF 40960-49151 BASIC ROM (or RAM when banked out) $C000-$CFFF 49152-53247 Upper RAM (always RAM, 4KB) $D000-$D3FF 53248-54271 VIC-II chip registers (I/O mode) $D000-$DFFF 53248-57343 Character ROM (when CHAREN=0) $D400-$D7FF 54272-55295 SID chip registers $D800-$DBFF 55296-56319 Color RAM (nybbles, 1000 bytes) $DC00-$DCFF 56320-56575 CIA #1 (keyboard, joystick, IRQ timer) $DD00-$DDFF 56576-56831 CIA #2 (serial bus, NMI, VIC bank) $DE00-$DEFF 56832-57087 I/O area 1 (expansion port) $DF00-$DFFF 57088-57343 I/O area 2 (expansion port) $E000-$FFFF 57344-65535 Kernal ROM (or RAM when banked out) ``` --- ## Memory Banking The C64 uses **soft banking** via location $0001 (6510 I/O port). | $0001 Bits 2-0 | LORAM | HIRAM | CHAREN | Memory Configuration | |-----------------|-------|-------|--------|---------------------| | %111 (7) | BASIC ROM | Kernal ROM | I/O | **Normal (default)** | | %110 (6) | RAM | Kernal ROM | I/O | ML programs using Kernal | | %101 (5) | BASIC ROM | Kernal ROM | Char ROM | Character ROM visible | | %100 (4) | RAM | RAM | I/O | All RAM + I/O | | %011 (3) | RAM | RAM | Char ROM | All RAM + Char ROM | | %010 (2) | RAM | RAM | Char ROM | All RAM + Char ROM | | %001 (1) | RAM | RAM | RAM | All 64KB RAM | | %000 (0) | RAM | RAM | RAM | All 64KB RAM | Direction register at $0000 should have bits 0, 1, 2, 3, 5 as outputs: `POKE 0, 47` (default). ```asm ; Bank out BASIC, keep Kernal + I/O (common for ML programs) LDA $0001 AND #$FE ; clear bit 0 (LORAM) STA $0001 ; Restore normal LDA $0001 ORA #$07 ; set bits 0-2 STA $0001 ``` --- ## VIC-II Memory Banking The VIC-II chip sees a **16KB bank** of memory selected by CIA #2 Port A bits 0-1: | $DD00 bits 1-0 | VIC-II Bank | Address Range | |-----------------|-------------|---------------| | %11 (3) | Bank 0 | $0000–$3FFF (default) | | %10 (2) | Bank 1 | $4000–$7FFF | | %01 (1) | Bank 2 | $8000–$BFFF | | %00 (0) | Bank 3 | $C000–$FFFF | **Note**: Banks 0 and 2 have Character ROM "mirrored" at offsets $1000–$1FFF and $9000–$9FFF. This means the VIC-II sees character data even though the CPU cannot (in normal banking). ```basic ' Switch VIC to Bank 1 ($4000-$7FFF) POKE 56576, (PEEK(56576) AND 252) OR 2 ``` --- ## Sprite Memory Each sprite needs **64 bytes** of data. Sprite data must be within the VIC-II's currently active 16KB bank. - **Sprite pointer table**: Located at top of current screen RAM + offsets $F8–$FF - Default: $07F8–$07FF (when screen is at $0400) - **Pointer value** = sprite data address / 64 (within the VIC-II bank) - **Default safe areas for sprite data**: Blocks 11–14 at $02C0–$03BF (within default Bank 0) ```basic ' Place sprite 0 data at block 13 ($0340) POKE 2040, 13 ' sprite 0 pointer ($07F8) = block 13 ' Now fill $0340-$037F with sprite pixel data ``` --- ## Protecting ML Code from BASIC **Method 1** — Lower BASIC top: ```basic POKE 56, 192 : CLR ' MEMSIZ high byte = $C0, BASIC top = $C000 ' Now place ML at $C000 safely ``` **Method 2** — Raise BASIC bottom: ```basic POKE 44, 18 : POKE 4608, 0 : CLR ' Start BASIC at $1200 ' Place ML at $0800–$11FF ``` **Method 3** — Use cassette buffer at $033C–$03FB (192 bytes): ```basic ' Safe for short routines; no special protection needed FOR I = 828 TO 828+N : READ D : POKE I,D : NEXT SYS 828 ``` --- ## Key POKE/PEEK Locations for BASIC Programmers | POKE/PEEK | Address | Effect | |-----------|---------|--------| | `POKE 53280, N` | $D020 | Border color (0-15) | | `POKE 53281, N` | $D021 | Background color 0 (0-15) | | `POKE 646, N` | $0286 | Text foreground color (0-15) | | `POKE 53265, PEEK(53265) OR 32` | $D011 bit 5 | Switch to bitmap mode | | `POKE 53272, N` | $D018 | VIC-II memory control | | `POKE 648, N` | $0288 | Screen RAM high byte (4=$0400, 8=$0800 etc) | | `PEEK(197)` | $00C5 | Last key scan code (no key = 64) | | `PEEK(198)` | $00C6 | Number of chars in keyboard buffer | | `PEEK(653)` | $028D | Shift/Ctrl/C= key status | | `POKE 650, 128` | $028A | Enable key repeat for all keys | | `POKE 56334, PEEK(56334) AND 254` | $DC0E | Disable timer (stop CIA #1 timer A) | | `POKE 788, 52 : POKE 789, 193` | $0314/15 | IRQ vector → $C134 (example) |