C64 Font

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.

Default font

The tool ships the C64 default in Sprites.Platform.C64.Font.DefaultFont, a font object of 256 glyphs, codes 0 to 255, one byte per pixel row, the top bit the leftmost pixel. The platform carries the range as Sprites.Platform.C64.Font.CharStart, 0, and Sprites.Platform.C64.Font.CharCount, 256. The two charsets are extracted from the real C64 character ROM, 256 glyphs each, in screen-code order.

The C64 uppercase and graphics character set, 256 glyphs
Uppercase and graphics (charset 0), the real C64 character ROM, screen-code order.
The C64 upper and lowercase character set, 256 glyphs
Upper and lowercase (charset 1). See the full definition and code in the library: Sprites.Platform.C64.Font.DefaultFont.