C64 Fonts

The Commodore 64 draws text from a character generator holding 8×8 glyphs. Two charsets live in the character ROM, and a program can point the VIC-II at RAM instead to use its own redefined font. Each glyph is 8 bytes, one row per byte, with the top bit on the left.

C64 Fonts

Overview

In text mode the screen is 40×25 character cells. Each cell holds one screen code, and the VIC-II looks up that code's 8×8 shape in the character generator and draws it in the cell's colour. The generator is a table of 256 glyphs, 8 bytes each, so a full charset is 2K.

PropertyValue
Cells40 × 25
Glyph size8 × 8 pixels
Bytes per glyph8 (one row each)
Glyphs per charset256
Charset size2048 bytes

The character ROM

The character ROM is 4K and is visible to the VIC-II at $D000–$DFFF in its address space. It holds two 256-glyph charsets of 2K each. The first is the uppercase and graphics set; the second is the upper and lowercase set. A program picks between them at runtime, and each is a full 8×8 font.

Offset in ROMCharset
$0000–$07FFUppercase and graphics (256 glyphs)
$0800–$0FFFUpper and lowercase (256 glyphs)

Glyph byte format

A glyph is 8 consecutive bytes. Byte 0 is the top pixel row and byte 7 the bottom. In each byte the most significant bit is the leftmost pixel: a 1 draws the character colour, a 0 leaves the background. So the glyph for code c starts at charset base + c × 8.

ByteBit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
0 (top)Leftmost pixel … rightmost pixel of the top row
1–6Middle rows, top to bottom
7 (bottom)Bottom row, left to right

In multicolour character mode a cell can show up to four colours. When the cell's Colour RAM nibble has bit 3 set, the glyph bytes are read two bits per pixel, giving 4×8 double-width pixels whose pairs select the background and two shared colours from $D022 and $D023, plus the low three bits of the cell's colour.

Screen codes and PETSCII

Two numbering schemes exist. PETSCII is Commodore's character encoding used for keyboard input, strings and printing; it resembles ASCII but with its own order and the graphics characters. Screen codes are what actually goes into a screen cell, and they run 0 to 255 as the direct index into the charset.

The two differ: for example the letter A is PETSCII 65 but screen code 1. The KERNAL converts PETSCII to screen codes when it prints, so code you place directly into screen RAM must already be a screen code.

SchemeRangeRole
PETSCII0–255Keyboard, strings, printing.
Screen code0–255Direct glyph index written to screen RAM.

Redefining the font

The VIC-II does not have to use the ROM font. The upper bits of the memory-control register $D018 set the character base, in 2K steps, within the current 16K VIC bank. Pointing that base at RAM and filling it with new glyphs replaces the whole charset, so a game can draw with custom tiles and symbols.

The usual method is to copy the ROM font into RAM, edit the glyphs that need to change, then set $D018 to the new base. Two ROM areas, $1000–$1FFF and $9000–$9FFF, are where the character ROM appears to the VIC-II by default, so a redefined font is normally placed elsewhere in the bank.

RegisterBitsMeaning
$D0181–3Character base within bank, in 2K steps.
$DD000–1VIC bank select, so the font must be in that bank.