The MOS 6567 (NTSC) / MOS 6569 (PAL) Video Interface Chip II is the C64's graphics processor. It resides at addresses $D000–$D3FF (53248–54271) when I/O is banked in.
Key capabilities:
| Address | Decimal | Register | Description |
|---|---|---|---|
| $D000 | 53248 | SP0X | Sprite 0 X position |
| $D001 | 53249 | SP0Y | Sprite 0 Y position |
| $D002 | 53250 | SP1X | Sprite 1 X position |
| $D003 | 53251 | SP1Y | Sprite 1 Y position |
| $D004 | 53252 | SP2X | Sprite 2 X position |
| $D005 | 53253 | SP2Y | Sprite 2 Y position |
| $D006 | 53254 | SP3X | Sprite 3 X position |
| $D007 | 53255 | SP3Y | Sprite 3 Y position |
| $D008 | 53256 | SP4X | Sprite 4 X position |
| $D009 | 53257 | SP4Y | Sprite 4 Y position |
| $D00A | 53258 | SP5X | Sprite 5 X position |
| $D00B | 53259 | SP5Y | Sprite 5 Y position |
| $D00C | 53260 | SP6X | Sprite 6 X position |
| $D00D | 53261 | SP6Y | Sprite 6 Y position |
| $D00E | 53262 | SP7X | Sprite 7 X position |
| $D00F | 53263 | SP7Y | Sprite 7 Y position |
| $D010 | 53264 | MSIGX | Most significant bits of sprites’ X positions (bit N = sprite N) |
| Address | Decimal | Register | Description |
|---|---|---|---|
| $D011 | 53265 | SCROLY | Vertical control register |
| $D012 | 53266 | RASTER | Raster counter / raster IRQ compare |
| $D013 | 53267 | LPENX | Light pen X (read-only) |
| $D014 | 53268 | LPENY | Light pen Y (read-only) |
| $D015 | 53269 | SPENA | Sprite enable (bit N = sprite N) |
| $D016 | 53270 | SCROLX | Horizontal control register |
| $D017 | 53271 | YXPAND | Sprite Y-expansion (bit N = sprite N) |
| $D018 | 53272 | VMCSB | VIC-II memory control |
| $D019 | 53273 | VICIRQ | Interrupt register (read/clear) |
| $D01A | 53274 | IRQMSK | Interrupt enable mask |
| $D01B | 53275 | SPBGPR | Sprite-background priority |
| $D01C | 53276 | SPMC | Sprite multicolor enable |
| $D01D | 53277 | XXPAND | Sprite X-expansion |
| $D01E | 53278 | SPSPCL | Sprite-sprite collision (clears on read) |
| $D01F | 53279 | SPBGCL | Sprite-background collision (clears on read) |
| $D020 | 53280 | EXTCOL | Border color |
| $D021 | 53281 | BGCOL0 | Background color 0 |
| $D022 | 53282 | BGCOL1 | Background color 1 (extended/multicolor) |
| $D023 | 53283 | BGCOL2 | Background color 2 (extended/multicolor) |
| $D024 | 53284 | BGCOL3 | Background color 3 (extended color text only) |
| $D025 | 53285 | SPMC0 | Sprite multicolor register 0 |
| $D026 | 53286 | SPMC1 | Sprite multicolor register 1 |
| $D027 | 53287 | SP0COL | Sprite 0 color |
| $D028 | 53288 | SP1COL | Sprite 1 color |
| $D029 | 53289 | SP2COL | Sprite 2 color |
| $D02A | 53290 | SP3COL | Sprite 3 color |
| $D02B | 53291 | SP4COL | Sprite 4 color |
| $D02C | 53292 | SP5COL | Sprite 5 color |
| $D02D | 53293 | SP6COL | Sprite 6 color |
| $D02E | 53294 | SP7COL | Sprite 7 color |
Bit 7 RST8 — Bit 8 of raster compare (use with $D012 for lines > 255)
Bit 6 ECM — Extended Color Mode (1=on)
Bit 5 BMM — Bitmap Mode (1=on, 0=text mode)
Bit 4 DEN — Display Enable (1=display on)
Bit 3 RSEL — Row Select: 1=25 rows, 0=24 rows (borders shown)
Bit 2-0 YSCL — Fine vertical scroll (0-7)
Default value: $1B = %00011011 (display on, 25 rows, scroll=3)
Bit 7 (unused)
Bit 6 (unused)
Bit 5 RES — Always set to 1 for normal operation
Bit 4 MCM — Multicolor Mode (1=on)
Bit 3 CSEL — Column Select: 1=40 columns, 0=38 columns
Bit 2-0 XSCL — Fine horizontal scroll (0-7)
Default value: $C8 = %11001000 (40 cols, scroll=0)
Bits 7-4 VM — Video matrix base address (within current VIC-II bank)
Bits 3-1 CB — Character base address (within current VIC-II bank)
Bit 0 (unused)
Video matrix address = bits[7:4] × $0400 within the VIC-II bank Character base = bits[3:1] × $0800 within the VIC-II bank
| $D018 Value | Screen RAM | Character Set |
|---|---|---|
| $10 (default) | $0400 | $1000 (ROM chars via mirror) |
| $14 | $0400 | $1800 (ROM chars, inverted) |
| $18 | $0400 | $2000 (user char at $2000) |
| $15 | $0400 | $1400 (user chars at $1400 in Bank 0) |
Step 1 — Define sprite shape data (63 bytes in a 64-byte block):
' Write sprite data to block 13 ($0340-$037F)
FOR B = 0 TO 62 : POKE 832+B, 0 : NEXT ' clear first
' Each row is 3 bytes (24 bits = 24 horizontal pixels)
POKE 832, 255 : POKE 833, 255 : POKE 834, 255 ' row 0: solid line
Step 2 — Point sprite pointer to the block:
POKE 2040, 13 ' sprite 0 → block 13 ($0340)
' Sprite pointer addresses: 2040-2047 = sprites 0-7
' (at default screen RAM $0400 + $03F8-$03FF = $07F8-$07FF)
Step 3 — Set sprite position:
POKE 53248, 160 ' sprite 0 X position
POKE 53249, 100 ' sprite 0 Y position
Step 4 — Set color and enable:
POKE 53287, 1 ' sprite 0 color = white (1)
POKE 53269, PEEK(53269) OR 1 ' enable sprite 0 (bit 0)
' Set sprite 0 X to 300 (= 256 + 44)
POKE 53248, 44 ' low 8 bits
POKE 53264, PEEK(53264) OR 1 ' set MSB for sprite 0
POKE 53275, 1 ' sprite 0 behind background characters
POKE 53275, 0 ' sprite 0 in front of background (default)
' Read and clear sprite-sprite collisions
C = PEEK(53278) ' bit N set if sprite N collided with another sprite
' Read and clear sprite-background collisions
C = PEEK(53279) ' bit N set if sprite N hit a background pixel
| Code | Color | Code | Color |
|---|---|---|---|
| 0 | Black | 8 | Orange |
| 1 | White | 9 | Brown |
| 2 | Red | 10 | Light Red |
| 3 | Cyan | 11 | Dark Grey |
| 4 | Purple | 12 | Grey |
| 5 | Green | 13 | Light Green |
| 6 | Blue | 14 | Light Blue |
| 7 | Yellow | 15 | Light Grey |
The VIC-II generates an interrupt when the raster beam reaches the line stored in $D012 (plus bit 8 in $D011 bit 7).
NTSC: 262 lines (0-261), PAL: 312 lines (0-311). Visible screen starts around line 50.
SEI
LDA #<RasterIRQ
STA $0314 ; IRQ vector low
LDA #>RasterIRQ
STA $0315 ; IRQ vector high
LDA #50 ; trigger at line 50
STA $D012
LDA $D011
AND #$7F ; clear bit 8 of raster
STA $D011
LDA #$01 ; enable raster IRQ
STA $D01A
CLI
RasterIRQ:
LDA $D019 ; read IRQ status
STA $D019 ; acknowledge (write-back clears)
; ... your raster effect code ...
JMP $EA31 ; chain to normal IRQ handler
; After acknowledging the interrupt, wait for the specific raster line
WAIT LDA $D012
CMP #100 ; target line
BNE WAIT
; Now change colors etc.
$D011 bits 0-2 (YSCL) from 7 down to 0 each frame$D016 bits 0-2 (XSCL) from 7 down to 0 each frame' Smooth vertical scroll - change scroll register each frame
FOR S = 7 TO 0 STEP -1
POKE 53265, (PEEK(53265) AND 248) OR S
FOR W = 1 TO 100 : NEXT ' wait
NEXT S
' Then scroll screen RAM and reset to 7
Powered by TurnKey Linux.