Just recently I had a very long conversation with a patreon of mine who was struggling to get his character set and screen set up for the game they where creating.

So I thought I would create an article about how the VIC II Addressing system works so this sould not happen again 😉

So the VIC II Chip has only 14 addressing lines and so can only address 16KB block at a time, so buy default, the VIC II only addresses Memory locations from $0000 -> $3FFF

The memory block the VIC II can see, can be changed via one of the CIA chips, which alter the address of the VIC II to see the other 3 Blocks of 16KB

So how do we tell the VIC II (or CIA really) which block the VIC II can read?

This is simple, we alter the lower most two bits of $DD00/56576/CI2PRA

$DD00 = %xxxxxx11 -> Bank0: $0000-$3FFF
$DD00 = %xxxxxx10 -> Bank1: $4000-$7FFF
$DD00 = %xxxxxx01 -> Bank2: $8000-$BFFF
$DD00 = %xxxxxx00 -> Bank3: $C000-$FFFF

$DD00 should be handled with care when also loading while changing VIC bank, because the other bits in it are controlling the serial transfer.

If speed is not critical its generally a good idea to change VIC bank like this:

lda $DD00
and #%11111100
ora #%000000xx      ;<- your desired VIC bank value, see above
sta $DD00

this code will change the VIC Bank without affecting the CIA chip that controls other equally important systems on the C64 system.

Now, if you do this, thinking this should be ok :

lda #%000000xx ;<- your desired VIC bank value, see above
sta $dd00

Then dont, because this will clear out the rest of the byte the CIA uses and will cause the C64 to black screen or even worse, Black Screen with White Border lol

Now, the rest of the addressing lines are located in byte $D018, this byte serves three functions :

  1. To tell the VIC II Chip where the screen ram is located
  2. Tells the VIC II chip where the Bitmapping memory is located
  3. Tells the VIC II where the character set rram is located

so we have to be careful about “Poking” this particular Byte lol

The $D018/53272/VIC+24: Memory Control Register (VMCSB)
+----------+---------------------------------------------------+
| Bits 7-4 | Video Matrix Base Address (inside VIC)            |
| Bit 3    | Bitmap-Mode: Select Base Address (inside VIC)     |
| Bits 3-1 | Character Dot-Data Base Address (inside VIC)      |
| Bit 0    | Unused                                            |
+----------+---------------------------------------------------+

So this byte looks like this format in Binary : VVVVCCCx (default Value : $15 / #21 / %0001 0101)

Where :
V = Video Memeory Location,
C = Character Set location, but the top most bit of the Character set also denotes the Memeory block for the BitMap Mode (which we will go through in a later post)

Now to work out the bit settings for the VIC II chip needs some basic maths.
First we know the Block we are using, so we will call that the BASE Address ( so either, $0000, $4000, $8000 and $A000).
Now for the Character Set, we have Eight different possibilities (xxx in binary has a range of 000 -> 111 so 0 -> 7 )

These possibilities are :
$D018 = %xxxx000x -> CharMem is at $0000 (#0)
$D018 = %xxxx001x -> CharMem is at $0800 (#2048)
$D018 = %xxxx010x -> CharMem is at $1000 (#4096)
$D018 = %xxxx011x -> CharMem is at $1800 (#6144)
$D018 = %xxxx100x -> CharMem is at $2000 (#8192)
$D018 = %xxxx101x -> CharMem is at $2800 (#10240)
$D018 = %xxxx110x -> CharMem is at $3000 (#12288)
$D018 = %xxxx111x -> CharMem is at $3800 (#14336)

Now this is in essence an offset to the Base Address, so like in Neptune Lander, we used the Character Memory Bank 14 (%1110), now remember the lower most bit is unused, so we are addressing the character memory bank $111x.


This means my character set should be located in $0000 (Bank 0) + $3800 (CharMem bank 7) = $3800 (#14336)
Now, if our base address was Bank 1 ($4000), then the character set would need to be located at $4000 + $3800 = $7800 (#30720)

So the way to change this value is buy using this code:

lda $D018
and #%11110001
ora #%0000xxx0      ;<- your desired CharMem bank value, see above
sta $D018

This code protects the data elsewhere in the byte, but allows you to change the CharMem address.

For the Video memory address we have Sixteen different possibilities (xxxx is binary has a range of 0000 -> 1111 so 0> 15 )
These possibilities are :

$D018 = %0000xxxx -> ScreenMem is at $0000 (#0)
$D018 = %0001xxxx -> ScreenMem is at $0400 (#1024)
$D018 = %0010xxxx -> ScreenMem is at $0800 (#2048)
$D018 = %0011xxxx -> ScreenMem is at $0c00 (#3072)
$D018 = %0100xxxx -> ScreenMem is at $1000 (#4096)
$D018 = %0101xxxx -> ScreenMem is at $1400 (#5120)
$D018 = %0110xxxx -> ScreenMem is at $1800 (#6144)
$D018 = %0111xxxx -> ScreenMem is at $1c00 (#7168)
$D018 = %1000xxxx -> ScreenMem is at $2000 (#8192)
$D018 = %1001xxxx -> ScreenMem is at $2400 (#9216)
$D018 = %1010xxxx -> ScreenMem is at $2800 (#10240)
$D018 = %1011xxxx -> ScreenMem is at $2c00 (#11264)
$D018 = %1100xxxx -> ScreenMem is at $3000 (#12288)
$D018 = %1101xxxx -> ScreenMem is at $3400 (#13312)
$D018 = %1110xxxx -> ScreenMem is at $3800 (#14336)
$D018 = %1111xxxx -> ScreenMem is at $3c00 (#15360)

Now this is in essence an offset to the Base Address, so like in Neptune Lander, we used the Screen Memory Bank 1 (%0001), so we are addressing the screen memory bank $0001.

This means my screen set should be located in $0000 (Bank 0) + $0400 (Screen bank 1) = $0400 (#1024)
Now, if our base address was Bank 1 ($4000), then the character set would need to be located at $4000 + $0400 = $4400 (#17408)

So the way to change this value is buy using this code:

lda $D018
and #%00001111
ora #%xxxx0000      ;<- your desired Screen bank value, see above
sta $D018

This code protects the data elsewhere in the byte, but allows you to change the ScreenMem address.

I Hope this better explains the mine feild of VIC II chip addressing better (hopefully) 😉

Leave a Comment