Programming the Commodore 64 in BASIC and C
(Note, this document was generated by the “deep research” facility of ChatGPT. It's intended to provide a broad overview while also giving links to other resources for more detailed information.)
Historical Context
The Commodore 64 (C64) is a legendary 8-bit home computer released in 1982. It became the best-selling single computer model in history (with around 12.5–17 million units sold) (Commodore 64 - Wikipedia). The C64’s success came from its advanced multimedia hardware and affordability. It was one of the first personal computers with dedicated custom chips for graphics and sound – including support for multicolor sprites (independently moving graphic objects) and a SID sound chip for real synthesizer-style audio (Commodore 64 - Wikipedia) (Commodore 64 – The Best Selling Computer In History – Commodore Computers: C64 VIC20 PET C128 Plus4 – 8 Bit PC's). This meant the C64 could produce visuals and music far beyond many competitors of its time. Its 64 KB of RAM was huge for an early-1980s home computer, and its price was low for what it offered, embodying Commodore’s mantra of “computers for the masses, not the classes.” The C64’s capabilities and price helped cultivate a massive community of gamers, hobbyist programmers, and eventually a vibrant demoscene (creative programmers pushing the machine to its limits). Even decades later, the C64’s distinctive sound and graphics remain an inspiration, and it’s still celebrated by retro computing enthusiasts.
Unique Hardware Highlights: The C64’s custom chips set it apart. The VIC-II graphics chip allowed up to 16 colors on screen and introduced hardware sprites – small 24×21 pixel images that the system can move autonomously over the background (Commodore 64 Sprite Registers - Commodore 64 Brain). Rather than redrawing graphics in software, you could simply update sprite coordinates in memory, and the VIC-II would render them at the new position, even supporting collision detection in hardware (Commodore C64: The Most Popular Home Computer Ever Turns 40 | Hackaday). This made programming smooth animations and games easier. The sound was handled by the SID (Sound Interface Device) chip, a 3-voice analog-digital hybrid synthesizer. The SID chip had features like multiple waveforms (sawtooth, triangle, pulse, noise), envelope generators, and an audio filter – essentially offering the building blocks of a mini synthesizer (Commodore C64: The Most Popular Home Computer Ever Turns 40 | Hackaday). It was the first home computer sound chip capable of complex music, and it remained the gold standard for years (Commodore 64 – The Best Selling Computer In History – Commodore Computers: C64 VIC20 PET C128 Plus4 – 8 Bit PC's). These features enabled the C64 to deliver arcade-like games and music at home, driving its popularity and enduring appeal.
Setting Up the Development Environment
Before coding, you’ll need a C64 emulator to run your programs. The most popular choice is VICE (Versatile Commodore Emulator), which is free and runs on Windows, macOS, and Linux (VICE - the Versatile Commodore Emulator). VICE emulates the Commodore 64 hardware (and other Commodore 8-bit machines) with high accuracy, essentially giving you a virtual C64 on your modern computer. Here’s how to get started:
-
Install VICE: Download the latest VICE package from the official website (the download page on vice-emu.sourceforge.io). Choose the version for your OS – for Windows it’s often a ZIP or installer (e.g. WinVICE), and for macOS there’s a bundled app or a Homebrew package (
brew install vice). No complicated setup is required – on Windows you usually just unzip and run thex64.exe(the C64 emulator executable) (WinVICE - C64-Wiki), and on Mac launch the VICE app. VICE’s UI will open with a typical C64 blue screen ready for BASIC input. -
Basic Usage of VICE: When VICE is running, you see the C64 startup screen with the
READY.prompt – this is exactly how a real C64 boots into BASIC. You can type commands or BASIC code just as on original hardware. VICE provides a toolbar and menus for common tasks. For example, to load a program from a “virtual disk,” you can go to File → Attach Disk Image and select a.d64file (a disk image). After attaching, typeLOAD"*",8,1inside the C64 emulator to load the program as you would on a real C64. However, for development convenience, VICE also lets you autostart programs: you can drag-and-drop a C64 program file (e.g. a.prgfile) into the emulator window or use File → Autostart to instantly load and run it. This is very handy for quickly testing code that you’ve assembled or compiled on your host machine. -
Web-Based Alternatives: If you don’t want to install anything initially, there are browser-based C64 emulators that can run code. For example, the “Online C64 BASIC” tool by Stig Nygaard lets you type BASIC code into a webpage, then it converts the code to a C64 PRG and runs it in a web-based C64 emulator (Online C64 BASIC). This is great for sharing small snippets or trying code on the fly. Another example is the JavaScript-based C64 emulators (like those by Krisztián Tóth and others) that run entirely in your browser. These web solutions are fun for quick experiments, but for serious development (especially in C or projects involving multiple files), using VICE on your own machine is more robust. The emulator gives you more control, the ability to use the built-in machine code monitor for debugging, and better integration with build tools.
Ensuring Cross-Platform Compatibility: All the tools mentioned (VICE, cross-compilers, editors) have versions for both Windows and macOS. VICE, in particular, is actively maintained and works well on modern OS versions (VICE emulator on Mac : r/c64 - Reddit). When setting up, follow platform-specific instructions (e.g., on Mac, use the GTK-based build of VICE as recommended (VICE emulator on Mac : r/c64 - Reddit)). Once installed, the workflow (editing code, running in emulator) is identical on both platforms.
Programming in C64 BASIC
When you boot up the C64 (or VICE), you land in Commodore BASIC V2.0 – a built-in Microsoft BASIC interpreter. Programming here is an exercise in retro computing: it’s interactive and simple to start, but comes with quirks that modern programmers might find unusual.
Basics of BASIC on the C64
Commodore 64’s BASIC is immediate mode and line-numbered. This means you can type a command at the READY. prompt and it executes immediately (for instance, try typing PRINT 2+2 and press Enter – it will print 4). More typically, you’ll write a program as a series of numbered lines, then run it. For example:
10 PRINT "HELLO, C64 WORLD!"
20 FOR I = 1 TO 5
30 PRINT "I=", I, " I^2=", I*I
40 NEXT I
If you type these lines into the emulator, you can list them back with the LIST command, and run the program by typing RUN. The output will print a greeting and a small table of squares. BASIC is case-insensitive (the C64 will auto-capitalize keywords as you type them), and it only has a limited set of keywords. Line numbers can be 0–63999, and they determine the execution order (there are no structured code blocks – you use line numbers with GOTO or GOSUB for control flow, and FOR/NEXT loops as shown).
Quirks and Limitations: It’s important to understand that C64 BASIC V2.0 is quite primitive by today’s standards. It was designed in an era when RAM was precious, so it lacks dedicated commands for the C64’s graphics and sound hardware. There’s “no provision for using graphics or sound from within a BASIC program except by means of POKE commands.” (Commodore 64 - Wikipedia) In other words, to change colors, draw pixels, move sprites, or play a note in BASIC, you have to manipulate memory-mapped hardware registers with POKE (and read them with PEEK). This can be fun (it’s a very hands-on way to control the machine) but also cumbersome for complex tasks. BASIC also has very limited error handling (you’ll see simple errors like ?SYNTAX ERROR or ?OUT OF MEMORY ERROR with little explanation), and it executes quite slowly, especially for graphics-heavy operations, since it’s an interpreter.
Another oddity is the text encoding: the C64 uses PETSCII rather than ASCII. Printable characters will mostly behave as expected, but there are some differences (for instance, the characters for lowercase vs uppercase switch in certain modes). Generally, if you stick to the normal letters, numbers, and symbols, you won’t notice this. Just be aware when writing code on a modern PC to run on the C64, the case of letters can matter in an odd way – more on that in a moment.
Despite these quirks, BASIC on the C64 is quite capable for simpler programs. You can read keyboard input (GET or INPUT statements), print formatted text, perform math (it even has floating-point), and use the full 38 KB of free RAM for your program and data. Many classic type-in games and tools from 1980s magazines were written in pure BASIC (with occasional POKEs for special effects). It’s a great way to get a feel for the machine.
Editing and Running BASIC Programs
When working within the C64 emulator, you’ll likely type in programs by hand. You create/edit lines directly at the prompt (there’s no full-screen text editor – you edit a line by retyping it with the same number, or use the cursor keys to make minor changes). This can be tedious for anything beyond small snippets. Fortunately, as modern developers, we have a better workflow: edit BASIC code on your PC, then import it into the emulator.
One recommended approach is to use a text editor on your PC to write the BASIC program, then use VICE’s utility petcat to convert that text into a tokenized .prg file that the C64 can run. petcat comes with VICE and is a command-line tool. The key trick: write your BASIC code in all-lowercase in the text file. Commodore BASIC stores keywords as single-byte tokens internally, and petcat expects unambiguous lowercase keywords to translate them correctly (Tokenize/De-tokenize Commodore Basic Programs Using petcat). For example, if your text file has a line 10 print "hello" (lowercase print), petcat will recognize “print” as the PRINT token. If you had 10 PRINT "hello" in all-caps, it might still work when pasted into the emulator, but when using conversion tools, sticking to lowercase avoids any confusion in translation (Tokenize/De-tokenize Commodore Basic Programs Using petcat).
A typical workflow for BASIC cross-development is:
- Write your program in a plain text file (e.g.,
myprog.bas), using lowercase for all BASIC keywords and adding line numbers as needed. Keep lines under 80 characters and avoid tab characters (spaces are fine). - Run
petcatto tokenize this file into a C64 PRG. For a BASIC V2 program, you’d use the-w2switch (write C64/VIC20 BASIC) along with-oto specify the output file. For example:
bash petcat -w2 -o myprog.prg -- myprog.bas
This producesmyprog.prg, which is a C64 executable BASIC program file (Tokenize/De-tokenize Commodore Basic Programs Using petcat) (Tokenize/De-tokenize Commodore Basic Programs Using petcat). (The--tells petcat that the following is a file name, not an option.) If there are any syntax errors,petcatwill report them – this helps catch mistakes before you even run the code. - Load
myprog.prgin the emulator. As mentioned, the easiest way is often to drag and drop it into the VICE window, which will auto-run it. Or you can attach it to a disk image andLOADit as if from disk. Once loaded, you canRUNit in the C64 environment.
Using this method, you get the comfort of a modern editor (you can even use version control on your BASIC source file!) while still ending up with a real C64 program. There are also dedicated cross-development IDEs like CBM prg Studio (Windows) that provide a GUI for writing BASIC or assembly with syntax highlighting, and can launch VICE to run the result. But the text editor + petcat route is simple and works on any platform.
To test out petcat, here's a short BASIC program you can try:
10 rem *** cool c64 demo ***
20 rem clear screen and set colors
30 print chr$(147) : rem clear screen
40 poke 53280,0 : rem border color (black)
50 poke 53281,1 : rem background color (white)
60 rem *** scrolling text ***
70 t$=" welcome to my c64 demo! " : rem scrolling message
80 for i=1 to len(t$)
90 print mid$(t$,i,len(t$)) + left$(t$,i-1);
100 for d=1 to 100 : next d : rem delay
110 next i
120 rem *** color flashing ***
130 for c=0 to 15
140 poke 53280,c : rem change border color
150 poke 53281,c : rem change background color
160 for d=1 to 200 : next d : rem delay
170 next c
180 rem *** sid sound effect ***
190 poke 54296,15 : rem volume (max)
200 poke 54277,9 : rem attack/decay
210 poke 54278,240 : rem sustain/release
220 poke 54273,17 : rem frequency (low byte)
230 poke 54272,37 : rem frequency (high byte)
240 poke 54276,17 : rem waveform (triangle)
250 for d=1 to 1000 : next d : rem play for a while
260 poke 54276,16 : rem turn off waveform
270 poke 54296,0 : rem turn off volume
280 rem *** loop back to start ***
290 goto 60
BASIC Best Practices: When writing BASIC for the C64, a few tips can improve your experience:
- Lowercase keywords in external editors: As explained, use lowercase for keywords in your source file to ensure correct tokenization (Tokenize/De-tokenize Commodore Basic Programs Using petcat). It doesn’t matter in the C64 itself (it will show them in uppercase by default), but it matters for conversion tools.
- Line numbering strategy: Use increments (10,20,… or 100,200,…) so you can insert lines in between if needed. You can start at 1 or 10 – it’s up to you. Smaller increments give you more room to add lines later without renumbering the whole program.
- Comments: You can use the
REMkeyword to add comments, e.g.,0 REM *** My Program ***. This helps document your code. (Using line 0 or other non-executed lines for a big comment header is a common trick.) - Avoid long tight loops in BASIC: BASIC is slow for heavy computation. If you need to, for example, fill the screen with graphics using POKEs, doing it in pure BASIC will flicker or take time. For better performance, consider offloading to a small machine code routine (beyond the scope of this guide, but something to explore later).
- Saving your work: When working in the emulator, remember that the C64 has no autosave. On a real C64, you’d save to disk or tape. In VICE, you can attach a blank disk image and use the BASIC command
SAVE "MYPROG",8to save it. However, since you likely have the source on your PC, you can always re-petcat it. Still, to avoid losing work typed in the emulator, useSAVEor the VICE snapshot feature.
With BASIC, you can immediately start tinkering. Try printing text, doing math, or even simple graphics (for example, POKE 53280,0 will turn the screen border black by writing to the border color register). It’s an excellent way to get a feel for the C64’s personality and constraints.
Going Beyond BASIC – Writing C Code for the C64
BASIC is fun and easy, but it has serious limitations in speed and access to advanced features. For more ambitious projects, you might want to write compiled code that runs much faster and gives you more direct control. One accessible way to do this is by using the C programming language. Surprisingly, it is possible to write C for the Commodore 64 – you’ll cross-compile it on your PC and generate a native C64 program. This allows you to leverage some of your modern programming knowledge while targeting the old hardware.
C Cross-Compilers for the Commodore 64
Several C cross-compilers exist for 6502-based machines like the C64. The most well-known is cc65, a free C compiler and toolkit that’s been around for years (Putting The C In C64 | Hackaday). It supports C89-ish syntax (with some limitations) and comes with an assembler and linker, plus C64-specific libraries (for I/O, graphics, etc.). Another option is SDCC (Small Device C Compiler), which in recent years added a 6502 back-end (C Compiler Assembler and Runtime for C64 | Hacker News). SDCC is open-source and known for targeting microcontrollers; its 6502 support is newer, but it’s being actively developed. There are also others like VBCC (a 6502 C compiler with very optimized output, though not open source) and KickC, which is a C-like language tailored for C64 development (C Compiler Assembler and Runtime for C64 | Hacker News). For getting started, cc65 is a solid choice due to its community and documentation. The concepts here will apply similarly if you use SDCC or another tool.
Setting up cc65: It's already installed on retro.cs.hmc.edu, but you can download cc65 from its official site or install it via package managers (e.g., Homebrew on Mac: brew install cc65). It’s a command-line tool. Once installed, you’ll have commands like cc65 (the compiler), ca65 (the assembler, for assembling the compiler’s output or your assembly files), ld65 (linker), and a convenient driver cl65 that can compile and link in one step.
Compiling a C program for C64: Let’s say you write a simple C program hello.c. To compile and link it for the C64 target using cc65, you could use:
cl65 -t c64 -O -o hello.prg hello.c
This tells cc65 to use the C64 code generator and linker config (-t c64), apply some optimizations (-O), and output a runnable C64 program hello.prg. The result hello.prg can be loaded in VICE just like a BASIC program – drag and drop it or attach and LOAD it (most cc65 programs include a small BASIC stub so that the C program auto-runs when loaded with LOAD"*",8,1).
Keep in mind that working in C on a 64KB, 1 MHz machine is very different from on a modern PC. There is no operating system – just the KERNAL and BASIC ROM routines. The C runtime provided by cc65 will initialize the machine for you (set up the stack, etc.), but you’re still constrained by the C64’s memory and CPU. For example, the standard C library is limited (e.g., printf exists, but floating point support might not). In practice, you’ll often directly manipulate memory or use C64-specific library calls for things like text output or reading the keyboard, because calling heavy-duty library routines could be slow or big in size. That said, a huge benefit of C is you can mix it with assembly as needed, and you can access memory-mapped hardware just by dereferencing pointers.
Example: A Simple C Program for C64
Below is an example C program that runs on the Commodore 64. It changes the screen border color, clears the screen, prints a message, and waits for a key press:
#include <conio.h> // Console I/O for cc65 (provides kbhit(), cgetc(), etc.)
#include <stdio.h> // Standard I/O (for printf)
#define VIC_BORDER ((unsigned char*)0xD020) // address of border color register
int main(void) {
*VIC_BORDER = 2; // Set border color to red (color code 2)
printf("Hello, Commodore 64 from C!\n");
printf("Press any key to continue...");
// Wait for a keypress
while(!kbhit()) { /* wait */ }
cgetc(); // read the key (and discard it)
return 0;
}
A few things to note in this C code:
- We directly define a pointer to the VIC-II chip’s color register for the border (
0xD020in memory) and write to it. This is equivalent to doingPOKE 53280,2in BASIC (since 53280 decimal = 0xD020, the border color register). By writing that memory location, we instantly change the screen border color. This shows how easy hardware access is in C – the C64’s hardware is just memory-mapped bytes. We useunsigned char*and dereference it to set a value. (We could also use thec64.hheader from cc65 which defines names for these addresses, but here we did it manually for clarity.) - We included
<conio.h>which is a CC65-specific header providing console I/O functions. We usekbhit()to check if a key has been hit, andcgetc()to get a character from the keyboard (this is easier than dealing with KERNAL calls yourself). - We used
printfto print text. In CC65,printfwill ultimately call the C64’s CHROUT routine to output characters to the screen (by default). We could have also used CC65’scprintforcputsfor slightly smaller code if we wanted. - The program uses only a few hundred bytes of the C64’s memory for code and ends with
return 0(which in a hosted environment would exit to OS, but on the C64 it will drop back to the BASIC READY prompt after main, since there’s no OS to return to). We included the key wait so the text stays on screen until a key is pressed – otherwise the program would end immediately and you’d be back at the BASIC prompt, which would overwrite the screen. Little things like this matter when you’re running on the bare metal machine.
To build this, you’d compile with cc65 as described. The resulting hello.prg can be run in VICE. You should see the border flash to red, background to light blue, and the message appear. Press a key and it will exit (border and background will likely revert as the BASIC system regains control).
Using C to Access C64 Hardware
The example above demonstrates the general approach: use pointers or provided routines to interact with hardware. You can do almost anything in C that you could do in BASIC or assembly, as long as you know the right memory addresses or KERNAL routines:
- Want to move a sprite? You can
*(unsigned char*)0xD000 = x;and*(unsigned char*)0xD001 = y;to set a sprite’s X/Y position, just like POKEing 53248 and 53249. - Want to play a sound? Set the SID registers via pointers (e.g., an array at 0xD400) or use a small sound library.
- Need to read joystick input? The joystick ports are mapped to certain bits of CIA chip registers at
$DC00/$DC01; you could read those bytes in C to get input.
However, remember that C introduces some overhead – it’s compiled to 6510 assembly, but not all C constructs are efficient on an 8-bit CPU. Simple loops and arithmetic are fine, but heavy use of 16-bit/32-bit math, dynamic allocation, or recursion is not really practical on the C64. You typically use C for the game or application logic, and for speed-critical inner loops (or very hardware-tied code) you might still drop into assembly. In fact, many developers find that to fully optimize C64 programs, they replace bits of C with hand-tuned assembly. One hobbyist C64 developer noted that they had to do “a lot of direct memory access, unrolling loops, and avoiding stack usage” to get a C game running smoothly, and that it’s clear why serious C64 projects often utilize assembly for performance-critical parts (C Compiler Assembler and Runtime for C64 | Hacker News). Nonetheless, writing in C can greatly accelerate development and make the code more readable compared to raw assembly, especially for moderately complex game logic or tools.
Other C Tools: If you explore SDCC for C64, the principles are similar, though setup may differ (you might need to link with a C64 runtime library from an open-source project, since SDCC’s 6502 support is newer). VBCC and KickC have their own quirks: KickC, for instance, isn’t strictly standard C, but a C-like language aimed at optimizing well for C64. As an undergrad starting out, CC65 is the most straightforward path. Its documentation covers C64-specific details (like how to set the memory model, use C64 BIOS calls, etc.), and it even includes headers for things like <c64.h> which provides convenient definitions for hardware registers and useful functions (e.g., verseq() to load a file, etc.).
Exploring the C64’s Unique Capabilities (Graphics, Sound, and More)
One of the joys of programming the C64 is tapping into its unique capabilities – the very features that made it a standout in the 1980s. Let’s delve a bit into how you can work with sprites, sound, and video modes. Understanding these will spark ideas for projects and help you appreciate the C64’s design. (We will keep examples brief; entire books are written on each of these topics, but this will give you a jumping-off point.)
Sprites: Hardware-Assisted Graphics
What are sprites? Sprites are independent graphic objects that the hardware can move over the background without altering the background data. The Commodore 64 has 8 sprite units, each by default 24×21 pixels in size (if using standard high-resolution; they can be doubled in width/height or put in multicolor mode, but 24×21 is the base) (Commodore 64 Sprite Registers - Commodore 64 Brain). The VIC-II chip treats sprites almost like “stickers” you can position on the screen at arbitrary coordinates.
Each sprite has a set of registers:
- X and Y position (
$D000–$D00Fcover X/Y for sprites 0–7) (Commodore 64 Sprite Registers - Commodore 64 Brain). - A sprite enable register (
$D015) – you set a bit to show or hide each sprite (Commodore 64 Sprite Registers - Commodore 64 Brain). - Registers for sprite appearance (e.g.,
$D027–$D02Eto set each sprite’s color, since each sprite can have its own single color) and for special features like multi-color mode and expansion (Commodore 64 Sprite Registers - Commodore 64 Brain) (Commodore 64 Sprite Registers - Commodore 64 Brain). - Pointers to the sprite image data in memory. The C64’s video memory at $07F8–$07FF (addresses 2040–2047 decimal) holds one byte per sprite to point to its image data block (Commodore 64 Sprite Registers - Commodore 64 Brain). Each sprite image is 64 bytes (technically 63 bytes used for 24×21 bitmap) in memory, typically stored somewhere in video RAM. By changing the pointer, you can have the sprite use a different image (for animation) or point offscreen if not used.
To use a sprite, you’d do the following in a program:
- Design the sprite image (a 24×21 pixel art, usually drawn on graph paper or with a tool, then translated into binary data). For example, a simple shape like a ball or character. You store this data in memory (in your BASIC program via
DATAstatements or in your C program as an array of bytes). - Set the sprite pointer to the memory block containing your sprite image. In BASIC, if your sprite data starts at address 832 (a common place, as 832 is the top of default screen memory), you might do
POKE 2040, 832/64(since pointer = start address/64). In C, you’d just calculate the value and poke it into address $07F8. - Enable the sprite by setting the corresponding bit in
$D015. Sprite 0 is bit 0, sprite 1 is bit 1, etc. SoPOKE 53269,1in BASIC turns on sprite 0 (r/c64 - Im trying to load a sprite on screen, but its not working. Does ...). In C,*(unsigned char*)0xD015 = 0x01;does the same. - Set the sprite’s position via
$D000(X) and$D001(Y) for sprite 0, etc. Note that X coordinates range 0–255 in$D000, but the screen is 320 pixels wide, so there’s another register$D010for the 9th bit of X for all sprites (Commodore 64 Sprite Registers - Commodore 64 Brain). If you keep X under 255 it’s simple. - Set the sprite’s color in
$D027(sprite 0’s color, etc.). This is a value 0–15 for the palette color. If you’re in multicolor sprite mode, the sprite can use more colors (two shared, one unique). - Now the sprite will appear at that position. You can move it by updating X/Y registers each frame (perhaps inside a loop or timed by the screen refresh). Because the VIC-II handles the drawing, movement is very smooth even if your code just changes coordinates. Sprites can overlap each other and the background. The VIC-II can even detect collisions: if two sprites overlap, it sets a bit in a collision register ($D01E) (Commodore 64 Sprite Registers - Commodore 64 Brain) that you can check, and similarly for sprite-to-background collisions ($D01F for sprite vs screen characters) (Commodore 64 Sprite Registers - Commodore 64 Brain) (Commodore 64 Sprite Registers - Commodore 64 Brain).
Why are sprites exciting? In the era of the C64, not all computers had this feature. With sprites, you could make flicker-free motion and complex scenes without redrawing everything in software. For example, a classic use is a character (sprite) moving over a static background (drawn with characters or bitmap) – you only update the sprite’s coordinates, rather than reprinting the character at a new position and erasing the old one. This offloads a ton of work to the VIC-II chip. Sprites also have built-in collision detection as mentioned, which is useful for games (e.g., know when your player sprite touches an enemy sprite) (Commodore C64: The Most Popular Home Computer Ever Turns 40 | Hackaday). Each sprite can also be set to appear in front of or behind background characters, and you can even multiplex sprites (reuse the same sprite hardware for multiple objects in different screen regions via quick reprogramming during the screen draw – an advanced trick seen in many games and demos).
In summary, sprites are your ticket to making moving graphics on the C64. Whether you use BASIC (with many POKEs) or C (with pointers or library calls), controlling them is a matter of writing to those memory-mapped registers. The Programmer’s Reference Guide and numerous online tutorials have tables of these registers. Once you get one sprite on screen, you’ve basically cracked the door open to making games.
Sound: The SID Chip and Making Noise
The C64’s SID sound chip is famous for a reason. It wasn’t just a simple tone generator; it was a synthesizer-on-a-chip. It provides 3 independent audio channels (voices), each of which can produce several waveforms (square/pulse, triangle, sawtooth, noise) over a wide frequency range (SID - C64-Wiki). Each voice has its own ADSR envelope (Attack/Decay/Sustain/Release controls to shape the volume over time), and all three voices can be mixed and filtered using a global analog filter (low-pass, high-pass, band-pass) (SID - C64-Wiki). There’s also a fourth “voice” that is essentially a direct audio input and a volume control register. All of these are accessible via memory-mapped registers in the range $D400–$D418.
Basic SID usage: To make a sound, at minimum you choose a voice, set its frequency, waveform, and envelope, and turn the voice on. For example, voice 1’s registers start at $D400:
$D400and$D401– 16-bit frequency value. (The number corresponds to a tone; e.g., roughly 0x1000 might be a middle A, etc. Exact values can be looked up in tables – the SID uses a 16-bit phase accumulator for generating tones.)$D402and$D403– pulse width (for the pulse waveform). Not needed if you’re using non-pulse waveforms.$D404– control register for voice 1. This is where you select the waveform (bits for saw/triangle/pulse/noise) and also the special bits like the gate (bit that starts the note) (Commodore 64 Users Guide) (Commodore 64 Users Guide). For instance, a common value is 17 decimal (0x11) to select a triangle wave and set the Gate=1 (note on) (Commodore 64 Users Guide). Turning the gate bit off ends the note (the release phase of the envelope then takes effect).$D405– Attack/Decay and$D406– Sustain/Release for voice 1’s envelope. Each is a nybble (4 bits) packed into a byte. For example, $D405 = $8F might mean Attack=8 (medium-slow attack), Decay=F (very slow decay). You typically set these once, or per note if you need varying dynamics.- There are analogous registers for voice 2 ($D407–D40C) and voice 3 ($D40E–D413).
$D417– Filter control and resonance (if using the filter to affect voices).$D418– Volume and filter enable. The lower 4 bits of $D418 set the master volume (0–15) (Commodore 64 Users Guide). You must turn the volume up or you won’t hear anything! (By default on reset, volume = 0, mute). So one of the first things a sound program does is POKE 54296,15 (0xD418 = 15) to max the volume (Commodore 64 Users Guide).
In BASIC, sound is achieved by a series of POKEs to these registers. For example, a simple tone on voice 1 could be:
POKE 54296,15 : rem set volume max (register $D418)
POKE 54272, $50 : rem low byte of frequency ($D400)
POKE 54273, $1C : rem high byte of frequency ($D401) – together this sets some freq.
POKE 54276, 17 : rem voice1 control ($D404): triangle waveform + gate on ([Commodore 64 Users Guide](https://www.commodore.ca/manuals/c64_users_guide/c64-users_guide-07-creating_sound.pdf))
POKE 54277, 10 : rem voice1 Attack/Decay ($D405)
POKE 54278, 168 : rem voice1 Sustain/Release ($D406)
This would start a sound (say a note) on voice 1. To stop it, you’d POKE 54276,16 (same waveform but gate off – notice in the Programmer’s Reference Guide table, each waveform has a value with gate on vs off, e.g., 17/16 for triangle on/off) (Commodore 64 Users Guide). In C, you’d do the equivalent by writing to those addresses with pointers or perhaps using a small SID library.
Sound programming on the C64 can get deep. You can play musical scales by changing the frequency registers in real-time (there are known frequency tables for equal-tempered scale). You can create drum sounds or effects by using the noise waveform and altering the volume or frequency quickly. Many games had music playing in the background – typically they were using an interrupt to update the SID registers each frame (50 or 60 times a second) to play notes according to a score. There is also the entire world of Tracker music and the SID music format (SID files) which are essentially 6510 machine code music routines that directly drive the chip.
As a beginner, try simple experiments: generate a tone, modulate it, or make a siren by sweeping the frequency in a loop. The SID is immediate – POKE a value and you’ll hear the change. This tight feedback loop is quite fun. Just be sure to set the volume register, as mentioned, or you might be puzzled by silence! And remember, SID audio output goes to the emulator’s sound output – so unmute or use headphones as needed.
Graphics Modes and Visual Tricks
The C64 has two primary graphics modes: Text (Character) Mode and Bitmap Mode, plus some variations of each.
-
Text Mode (Character Graphics): This is the default mode you see on boot: a 40×25 grid of characters (cells), each cell showing a character from the built-in font (or a custom font you define). The screen memory at $0400–$07E7 holds the character codes for each cell, and a separate 1KB color memory at $D800–$DBFF holds the color for each cell. By redefining characters (i.e., changing the font data in memory), you can create simple graphics or tiles – this was a common technique for games because it uses less memory than a full bitmap. In standard text mode, each character cell can have its own foreground color (from 16 colors) but shares a common background color (the one you set with POKE 53281, or $D021). There’s also an extended background mode that sacrifices some characters to allow four different background colors across the screen. The resolution of text mode is effectively 320×200, but composed of 8×8 blocks (characters). It’s very efficient to use (printing a character is far easier than painting pixels).
-
Bitmap Mode: In bitmap mode, the screen is a pixel-addressable canvas of 320×200. You have two flavors:
- High-Resolution Bitmap: 320×200 pixels, with 2 colors per 8×8 block (one background, one foreground). Essentially, the screen is divided into 1000 char-blocks (40×25), and within each 8×8 block, all the pixels that are “1” in the bitmap use that block’s foreground color, and “0” use the background color. You get finer detail (320px across) but limited colors locally.
- Multicolor Bitmap: 160×200 pixels (half horizontal resolution) (Multicolor Bitmap Mode - C64-Wiki), but you can have up to 4 colors per 4×8 block. Pixels are twice as wide (so it’s like 160 columns). In each 4×8 cell, you can use the background color plus three other colors (two are global across the screen, and one is specific to that cell via color RAM). This mode was used for more colorful graphics like game backgrounds or pictures, at the cost of some sharpness.
To enable bitmap mode, you have to set a bit in register $D011 (the VIC-II control register) and $D016, and also arrange memory accordingly (point the VIC-II to a bitmap memory region and character set, etc.). The details are intricate, but in essence, you allocate 8K for the bitmap data and 1K for color data, and tell the VIC where it is. Many C64 art and loading screens you might have seen are in bitmap mode.
Resolution and Color Summary: The C64’s VIC-II can display 40×25 text or a 320×200 (hi-res) or 160×200 (multicolor) bitmap ( Commodore Hardware Information | C64 OS ). In all modes, there are 16 colors available in the palette (black, white, red, cyan, purple, green, blue, yellow, orange, brown, light red, dark grey, medium grey, light green, light blue, light grey). The palette is fixed, but clever tricks like raster effects can simulate more shades or blends.
Graphics Programming: In BASIC, there are no drawing commands (unlike, say, BBC BASIC or Turbo BASIC on other systems). So you manipulate graphics by POKEing values into screen memory or color memory, or switching modes via POKEs. For example, you can create simple PETSCII art by storing character codes into screen memory – try POKE 1024,81 in BASIC (1024 ($0400) is top-left cell, and 81 is the code for the 'A' character graphic) then POKE 55296,2 (55296 ($D800) is top-left cell’s color, 2 = red) and you’ll see a red ‘A’ at top-left. In a loop, you could fill the screen with characters. This is essentially how you’d make a game background out of tiles: define custom character graphics and fill screen memory with those character codes.
In bitmap mode, BASIC alone is extremely slow to plot points (it would mean computing the byte and bit for each pixel and POKEing). That’s why many BASIC drawing programs rely on machine code routines. In C, you could theoretically manipulate a bitmap array and copy it to video RAM, but again C might be too slow in pure form; usually assembly is used for blitting graphics.
Smooth Scrolling and Raster Tricks: The VIC-II has some special registers for scrolling the screen smoothly ($D011 and $D016 fine scroll bits) and for splitting the screen (using raster interrupts). An example of a popular trick is the split screen: use a raster interrupt (trigger an interrupt when the electron beam reaches a certain scanline) to change a register mid-frame. This is how games put a status bar at the bottom with a different background color or how demos show multiple horizontal bars of color – they wait for the raster, then change $D021 (background color) on the fly. Raster interrupts also enable sprite multiplexing (reusing sprites by reloading their Y positions after they’ve been drawn in an earlier part of the frame). These are advanced techniques that typically require 6502 assembly to do reliably (because timing is critical). But even as a C or BASIC programmer, it’s good to know these possibilities exist – they’re what gives the C64 its visual flair in demos and high-end games.
To sum up: the C64’s video system is extremely flexible for its time, but not very hand-holdy. You can get a lot done with POKEs (and in C, pointer assignments) to the right registers:
- Turn on multicolor text mode by setting bit 4 of $D016 and using color nybbles in screen RAM.
- Change border/background color with $D020/$D021.
- Toggle bitmap mode via $D011 bits.
- Repoint the character set to RAM to make custom fonts/tiles (by default the character glyphs come from ROM at $D000, but you can copy that to RAM, modify it, and point the VIC-II to your RAM version).
Each of these topics could be an exercise or mini-project in itself. The important thing is that with a relatively small number of control registers, you control what the VIC-II displays. And because these are memory-mapped, any language that can write to memory (which BASIC and C both can, via POKE or pointer) can utilize them. The Programmer’s Reference Guide includes a whole chapter on graphics with examples (in BASIC) of using these features ([PDF] Programming Graphics On The Commodore 64) ( Commodore Hardware Information | C64 OS ).
Mini-Projects & Exercises
Now that you have an idea of the C64’s capabilities and programming tools, here are some project ideas to put your knowledge into practice. Each of these is scoped such that it could be done in a afternoon or a weekend (around 6–8 hours), and they’re chosen to be fun and educational. They range from simple BASIC programs to hybrid or C programs. Feel free to get creative and most importantly, enjoy the process – programming the C64 is as much about discovery as it is about results!
-
1. PETSCII Art or Animation (BASIC): Use BASIC to draw something on the screen with PETSCII characters. You could make a colorful design or logo using the block graphics characters (there are triangles, circles, card suits, etc. in the default font). For animation, try making a “bouncing ball” by printing an
Oand then erasing and re-printing it at a new position inside a loop. This will teach you about screen memory coordinates and timing loops (and the limits of BASIC speed). Bonus: change the ball’s color as it moves (POKE values into color memory at 55296+offset). Skills: Loops, printing/positioning, simple physics (if bouncing), color memory. -
2. Reaction Timer (BASIC): A simple interactive program: the computer waits a random interval, then prints “PRESS A KEY NOW!” and you have to respond. It measures the time (the C64 has a TI$ clock you can use, or you can count loops roughly) and gives you a score. This is mostly BASIC logic and I/O (using
GETto detect a key without waiting for Enter). It’s a good exercise in using the keyboard and timers. Skills: Keyboard input, random numbers (RND), timing with the TI system variable. -
3. Play a Melody (BASIC or C): Make the C64 produce a simple melody (like a few notes of a song). You can do this in BASIC by POKEing the SID registers. For example, program a scale by setting frequency registers to the corresponding values for C, D, E, etc., and use
FOR...NEXTloops as delays between notes. Or, in C, set up an array of frequency values and loop through them withcgetc()to go to the next note on key press. There are references (e.g., the Programmer’s Reference Guide sound section) with frequency values for musical notes (SID - C64-Wiki). Skills: Sound register manipulation, timing loops or delays, possibly arrays of data (notes). -
4. Sprite Demo (C or BASIC): Get a sprite on the screen and move it around. In BASIC, you’ll have to POKE a lot of values (to set sprite data, pointers, etc.), but it’s doable – the PRG has an example in Chapter 4. In C, you can embed the sprite binary data in an array. For simplicity, you could use one of the C64’s built-in shape data (the default ROM has some, like the balloon from the Simon’s BASIC I think) – but better is to create your own simple shape. Move the sprite in response to input: e.g., use cursor keys (you can read the keyboard or joystick) to move a sprite around like a little character. Skills: Sprite register use, memory pointers, input handling, double-buffering concept if erasing is needed (though with sprites you don’t erase – that’s the beauty!).
-
5. Tiny Text Adventure or Quiz (BASIC): If graphics aren’t your thing, write a text-based game. For example, a simple quiz that asks a few questions and checks answers, or a mini text-adventure with a couple of rooms where you can pick up an item and win by doing something. The C64’s BASIC is well-suited for text and logic. You’ll practice string handling (using
INPUTand string comparisons) and game logic. Skills: Prompting and reading input, using IF/GOTO for game flow, maybe simple random events. -
6. “Raster Bars” Demo (assembly or advanced C, optional): This is a bit more advanced, but a classic C64 demo effect is the raster color bars – horizontal bands of color that ripple down the screen. You achieve this by changing the background color every few scanlines in an interrupt. Attempting this will push you to learn about the 6510 assembly (because doing it in BASIC is impossible and in C is extremely difficult due to timing). Perhaps as a guided exercise, modify an example from a book or online. Skills: Interrupts, cycle timing, low-level hardware access. (This is an assembly intro disguised as a project.)
For any graphics/sound project, it’s helpful to consult references for the exact register values and memory addresses. As you implement these, you’ll inevitably refer to documentation – which is a good thing! It means you’re learning to navigate the C64’s internals. Also, don’t be afraid to look at existing code for inspiration. There are many one-liner and short BASIC programs out there (Easy type-in software for a BASIC demonstration : r/c64 - Reddit) that can spark ideas or show techniques (for example, how to scroll text, or how to use string CHR$ functions to create special characters).
Further Resources & Next Steps
Congratulations on taking your first steps in Commodore 64 programming! Whether you wrote BASIC one-liners or a C program that pokes hardware, you’ve gotten a taste of retrocoding. There’s a rich ecosystem of resources and community knowledge to support you as you dig deeper. Here are some highly recommended resources and suggestions for next steps:
-
Commodore 64 Programmer’s Reference Guide – The bible for C64 developers back in the day. This book (available as a free PDF online) covers BASIC, the KERNAL (OS routines), detailed hardware information, memory maps, and even a tutorial on 6510 assembly. It includes example programs and was written by Commodore’s team. If you’re serious about C64 coding, you’ll find yourself looking things up in here often (Manuals | Commodore 64 Programmers Reference).
-
Mapping the Commodore 64 – A book (also available online) that literally maps out every memory address and what it does. It’s an amazing reference when you need to know “what does memory location X do?” or “where is the routine for Y.” It complements the Programmer’s Reference Guide by focusing on memory and ROM routines in detail. Many consider it “the best reference ever written for the C64” for low-level programming (Mapping The Commodore 64 - RELOADED!).
-
C64 User’s Guide – The original beginner’s manual that came with the Commodore 64. It’s great for learning BASIC and contains beginner-friendly introductions to graphics and sound (using BASIC). It won’t cover advanced topics, but it’s a gentle introduction and has some fun example programs.
-
cc65 Documentation and Wiki – If you are using cc65 for C, read through its docs on the C64 target. It lists what C library functions are available, how the memory is laid out, and any gotchas (for example, the default runtime doesn’t support
mallocwithout extra config, etc.). Their function reference is handy (cc65/include/conio.h at master - GitHub). The cc65 community wiki (though a bit hidden) and forums have threads on things like optimizing C code for speed, using assembly with C, etc. -
C64-Wiki.com – An online wiki dedicated to Commodore 64 topics. Great for quick look-ups (e.g., “what is the address for sprite 3 X coordinate?” or “details of SID chip”). It often has more explanation than just a raw memory map. For example, the SID page on C64-wiki provides tables of waveform values and some example BASIC code (SID - C64-Wiki).
-
Codebase 64 – This is a community-driven wiki with tons of articles, tutorials, and code snippets on C64 programming (mostly assembly, but also graphics tricks, etc.) (start [Codebase64 wiki]). It’s gold when you want to learn something advanced – e.g., sprite multiplexing, fast bitmap drawing, or even how to do 3D on a C64. The articles assume some knowledge, but they are very practical.
-
Communities and Forums: The C64 scene is alive and well. You can join the conversation on the Lemon64 forums (one of the oldest C64 forum communities), the Commodore 64 subreddit (r/c64), or various Discord servers and Facebook groups dedicated to retro computing. If you get stuck or want feedback, these communities are welcoming to newcomers – after all, everyone is excited to see fresh enthusiasm for the 64! Just remember to search the archives or wiki first if you have a common question. There’s decades worth of Q&A out there.
-
Sample Code and Type-Ins: Looking at existing code is incredibly educational. Check out the VICE included demos or CSDb (Commodore Scene Database) for productions. Even better, find some classic magazine type-in listings (Compute!’s Gazette, for instance) – typing in those BASIC programs (or at least reading through them) can teach you clever tricks. Many are available online in text form. There’s a collection of “one-liner programs” (Easy type-in software for a BASIC demonstration : r/c64 - Reddit) that show surprising effects in just 1 line of BASIC – great for learning concise coding.
Next Steps – Learn 6502 Assembly
After you’ve done some BASIC and maybe dipped into C, you’ll probably start bumping into the performance limits of high-level coding on this machine. The natural next step for a C64 programmer is to learn 6510 assembly language (the 6510 is the C64’s CPU, a variant of the MOS 6502). Assembly will let you unlock the full power of the C64 – precise timing, maximum graphics performance, and techniques that simply aren’t possible in BASIC or C (like cycle-timed raster effects, custom interrupts, fast multiplication, etc.).
Learning assembly on the C64 might sound daunting, but the 6502 is actually one of the simplest CPUs to learn assembly on (only 3 registers to worry about, and a fairly small instruction set). There are many tutorials geared towards beginners. A good path is:
- Start with a generic 6502 assembly intro (such as the famous “Easy 6502” tutorial available on the web, which uses a simulator in the browser). This teaches you the basics of the CPU instructions and concepts like addressing modes.
- Then move specifically to C64 assembly: There are video series on YouTube (for example, “C64 Assembly for Beginners” by RetroCrunch) and text guides (c64/asm/C64 Assembly Coding Guide.md at main - GitHub) (the C64 Wiki’s assembly guide, and Codebase64 has beginner sections). These will show you how to assemble code (using tools like ACME or Kick Assembler), how to integrate with BASIC (using a BASIC stub to call your code with SYS), and how to do things like play a sound or move a sprite with assembly. You will find that many of the POKEs you did in BASIC translate to just a couple of assembly instructions – and they execute hundreds of times faster.
- The ultimate goal could be to write a small game or demo entirely in assembly. When you get there, you’ll appreciate how much you can squeeze out of the C64. People have made astonishing programs in 6510 assembly – from smooth scrolling platformers to demos with 3D graphics – by exploiting every cycle.
Even if you don’t plan to write large programs in assembly, understanding it will deepen your overall skill. It also helps when debugging C code (since you can read the assembly output to see why something might be slow). And it’s just a great way to learn low-level computer architecture, which is valuable for any computer science student.
In summary, programming the Commodore 64 is a journey into the fundamentals of computing. You interact directly with memory and hardware, you optimize for bytes and cycles, and you get instant feedback from a machine that, despite its age, feels very alive when your code makes it sing or dance on the screen. By starting with BASIC, you learned the essentials of the C64 environment. By moving to C, you leveraged your existing knowledge to go a bit lower-level and faster. The next step, assembly, will remove almost all abstractions and put you in total control – which can be incredibly rewarding. Along the way, don’t hesitate to tap into the community and the treasure trove of documentation available. Many of us find C64 programming addictively fun – it’s both nostalgic and a great exercise in problem-solving and optimization.
Good luck, and happy coding on your Commodore 64! Enjoy the process of making those blue pixels and 8-bit sounds come alive with your own programs. The skills and mindset you’ll develop – understanding hardware, careful debugging, creative optimization – will serve you well beyond the 64, even as you return to modern systems. Plus, you’ll have some cool retro projects to show off to your friends. Now, grab that emulator (or a real C64 if you’re lucky) and start creating! READY. 😊
(When logged in, completion status appears here.)