← Back to The Vault

PRINT vs POKE

Why games don't use PRINT statements

Performance comparison of PRINT and POKE for screen output—and why understanding the difference makes you a better C64 programmer.

C64 PerformanceBASICScreen outputOptimisation 1982–1994

Overview

Every C64 programmer learns PRINT first—it’s simple, friendly, and handles all the details for you. But games never use it. They POKE directly to screen memory instead. Why? Speed. PRINT is convenient. POKE is fast. The difference isn’t subtle—it’s the gap between a slideshow and a game.

The Simple Version

PRINT:

  • Easy to use
  • Handles scrolling, cursor, colours
  • Converts characters automatically
  • Slow (dozens of operations per character)

POKE:

  • Direct memory write
  • No automatic features
  • You handle everything
  • Fast (one operation per character)

When to use PRINT: User input, text adventures, file listings, debugging.

When to use POKE: Games, graphics, fast updates, static screens.

What PRINT Actually Does

When you type PRINT "A", BASIC:

  1. Parses the string
  2. Converts PETSCII ‘A’ (65) to screen code 1
  3. Checks cursor position
  4. Checks if screen will scroll
  5. Calls KERNAL routine CHROUT ($FFD2)
  6. CHROUT checks for control characters
  7. CHROUT checks for quote mode
  8. CHROUT updates cursor position
  9. CHROUT writes to screen memory
  10. CHROUT updates colour memory
  11. CHROUT updates cursor RAM location

All of that for one character.

What POKE Actually Does

When you type POKE 1024,1:

  1. Writes value 1 to address 1024

Done.

Performance Benchmark

Let’s fill the screen with the letter ‘A’ using both methods:

Using PRINT

10 PRINT CHR$(147);
20 FOR I=1 TO 1000
30 PRINT "A";
40 NEXT I

Time: Approximately 18 seconds (PAL C64)

Using POKE

10 FOR I=1024 TO 2023
20 POKE I,1
30 NEXT I

Time: Approximately 2 seconds (PAL C64)

Result: POKE is 9 times faster for this simple task.

Real-World Example: Score Display

Method 1: Using PRINT

10 SCORE=9999
20 PRINT CHR$(19);
30 PRINT "SCORE:";SCORE

Clears screen, homes cursor, prints text. Takes ~50 milliseconds (nearly one frame at 50Hz).

Method 2: Using POKE

10 SCORE=9999
20 S$=STR$(SCORE)
30 FOR I=1 TO LEN(S$)
40 C=ASC(MID$(S$,I,1))
50 POKE 1024+I-1,C
60 NEXT I

Writes directly to screen RAM. Takes ~10 milliseconds (much less than one frame).

Method 3: Using POKE (Optimised)

10 SCORE=9999
20 POKE 1024,48+(SCORE/1000)
30 POKE 1025,48+((SCORE/100) AND 15)
40 POKE 1026,48+((SCORE/10) AND 15)
50 POKE 1027,48+(SCORE AND 15)

No string conversion, direct digit extraction. Takes ~2 milliseconds (instant).

Frame Time Budget

The C64 updates the screen 50 times per second (PAL). That gives you 20 milliseconds per frame to:

  • Read joystick input
  • Update player position
  • Check collisions
  • Move enemies
  • Update score
  • Redraw sprites
  • Play sound effects

If updating your score takes 50ms with PRINT, you’ve blown 2.5 frames just displaying a number. The game slows down, sprites judder, controls feel sluggish. Use POKE and it’s instant.

When PRINT Is Actually Better

Text adventures and interactive fiction:

PRINT "YOU ARE IN A DARK ROOM."
PRINT "EXITS: NORTH, SOUTH, EAST"
INPUT "WHAT NOW";A$

PRINT handles word wrap, scrolling, and cursor positioning. You focus on the story, not screen coordinates.

Debugging:

PRINT "X=";X;" Y=";Y;" SCORE=";S

Fast to write, easy to read. Perfect for development.

File listings and utilities:

PRINT "LOADING...PLEASE WAIT"

User doesn’t care about speed. They’re waiting anyway.

Hybrid Approach

Many programs use both:

10 REM Setup screen with POKE (once)
20 FOR I=1024 TO 2023:POKE I,32:NEXT
30 REM Draw UI borders with POKE
40 POKE 1024,85:POKE 1063,73
50 REM Use PRINT for user messages (occasionally)
60 PRINT CHR$(19);"READY"
70 REM Update game state with POKE (constantly)
80 FOR I=1 TO 100
90 POKE ENEMYX+I,160
100 NEXT I

POKE for frequent updates, PRINT for convenience.

Technical Details

Why PRINT Is Slow

PRINT goes through the BASIC interpreter, then the KERNAL. Each layer adds overhead:

BASIC layer:

  • String evaluation
  • Expression parsing
  • Type checking
  • PETSCII handling

KERNAL layer:

  • CHROUT routine ($FFD2)
  • Control character checking
  • Scroll handling
  • Cursor management
  • IRQ synchronisation

Why POKE Is Fast

POKE is a single BASIC command that compiles to approximately:

LDA #value      ; Load value
STA address     ; Store to address

Two machine language instructions. Done.

Advanced: Inline Assembly

For ultimate speed, embed machine code:

10 FOR I=0 TO 50
20 READ B:POKE 49152+I,B
30 NEXT I
40 SYS 49152
50 DATA 162,0,169,1,157,0,4,232,224,232,208,248,96

This fills the screen in under 0.5 seconds—40× faster than PRINT.

Memory Considerations

PRINT:

  • Uses BASIC string buffers
  • Uses KERNAL workspace
  • Affects zero page temporaries
  • Can trigger garbage collection

POKE:

  • Direct memory write
  • No intermediate storage
  • No side effects
  • Predictable behaviour

For tight game loops, predictability matters. POKE never surprises you.

The Learning Curve

PRINT: Instant gratification. Works immediately.

POKE: Requires understanding:

  • Screen memory layout (1024-2023)
  • Colour memory layout (55296-56295)
  • Screen codes vs PETSCII
  • Position calculation formulas

Worth learning? Absolutely. It’s the difference between “I made a program” and “I made a game.”

Historical Context

Early C64 software (1982-1983) used PRINT extensively. Zork, Adventureland, and business software didn’t need speed. But arcade conversions like Pac-Man and Donkey Kong failed because programmers tried using PRINT for animation. It couldn’t keep up.

By 1984, magazines like ZZAP!64 and Compute’s Gazette were teaching POKE techniques. Games like Impossible Mission, Raid on Bungeling Bay, and The Last Ninja demonstrated what direct screen access could achieve. By 1985, using PRINT in a game marked you as a beginner.

Demo coders pushed further, bypassing BASIC entirely. Pure machine code demos like Dutch Breeze and Koala updated screens in under one frame—physically impossible with PRINT.

Practical Rules

  1. Starting out: Use PRINT. Learn BASIC first.
  2. Building a game: Switch to POKE for anything that moves or updates frequently.
  3. Text-heavy program: PRINT is fine.
  4. Real-time display: Always POKE.
  5. Not sure: Time it. If it’s slow, switch to POKE.

Code Comparison: Status Bar

10 PRINT CHR$(19);
20 PRINT "LIVES: ";L;" SCORE: ";S;" TIME: ";T

Executes in ~30 milliseconds. Causes visible flicker if updated every frame.

POKE Version (Fast)

10 REM Lives (position 7)
20 POKE 1031,48+L
30 REM Score (position 20-24)
40 FOR I=0 TO 4:POKE 1044+I,48+((S/10^(4-I)) AND 15):NEXT
50 REM Time (position 36-38)
60 FOR I=0 TO 2:POKE 1060+I,48+((T/10^(2-I)) AND 15):NEXT

Executes in ~5 milliseconds. No visible delay.

The Bottom Line

PRINT taught millions to program. It’s friendly, forgiving, and perfect for learning.

POKE made the games you loved. It’s fast, precise, and essential for real-time software.

Learn PRINT first. Master POKE next. Use both wisely.

See Also