Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

104 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C64

A cycle-accurate Commodore 64 and 1541 disk drive, written from scratch in C11.

This is two complete machines, not one. The C64 (a 6510 CPU, the VIC-II video chip, the SID 6581, two CIA 6526s) and the 1541 drive (a second 6502 with its own ROM, RAM, two VIAs, and a rotating GCR surface) each run in their own clock domain, modelled cycle by cycle. They talk over the real IEC serial bus: three open-collector lines, with the KERNAL and the drive's DOS running the LISTEN/TALK handshake themselves, one bit at a time. That is what makes fastloaders work. No emulator source was used as a reference; see Provenance.

Design notes on how the emulator works and why it makes its choices are in docs/.

Quick start

make MODE=release          # optimised build -> build/c64
./build/c64 --disk games/yourgame.d64 --autorun

--autorun waits for the cold boot to reach READY., then types LOAD"*",8,1 and RUN for you, so a mounted disk loads and starts hands-free. Drop it to stop at the prompt and type them yourself:

LOAD"*",8,1
RUN

The load runs at authentic 1541 speed (slow, by design). Press F10 for warp if you would rather not wait.

You must supply your own ROM images first, see ROM images.

Status

Runs commercial software. The following are verified against real games, not only against unit tests:

Subsystem State
6510 CPU Full documented instruction set plus undocumented opcodes, cycle-accurate, IRQ/NMI/reset.
VIC-II All five graphics modes (standard/multicolour text, standard/multicolour bitmap, ECM), invalid-mode black, sprites with priority and both collision types, badlines, raster interrupts, the six border flip-flop rules (so open-border and FLD tricks behave), XSCROLL/YSCROLL, RSEL/CSEL, idle state, and the CIA2-selected video bank.
SID 6581 Oscillators, all four waveforms with combined-waveform wired-AND, hard sync, ring modulation, the noise LFSR, ADSR with the free-running rate counter (so the ADSR delay bug is reproduced), a multimode filter, and $D418 volume-register sample playback. Anti-aliased and resampled to 44.1 kHz.
CIA 6526 (x2) Cycle-exact timers and interrupts, the 8x8 keyboard matrix, both joystick ports, the RESTORE NMI, TOD clock, serial shift register, and the CIA2 IEC lines.
1541 drive A full second machine: 2 KB RAM, 16 KB DOS ROM, two 6522 VIAs, its own 1.0 MHz clock domain, and a modelled rotating GCR surface with per-zone bit rates. Read and write: LOAD, SAVE and NEW (format) all work, with changes written back to the .d64 on clean exit.
IEC serial bus The three-wire link (ATN, CLK, DATA) between the C64 (CIA2) and the drive (VIA1), modelled as the real open-collector wired-AND lines. The two machines run the byte-level handshake themselves, each on its own clock, so bus timing and fastloaders behave.

Input

Key Function
F8 Joystick port: swap between port 2 (default) and port 1. Title shows [JOY2] or [JOY1]. Most games use port 2; some read port 1.
F9 Joystick mode: the cursor keys become the joystick; Right Alt or Left Ctrl fire. Title adds CRSR.
F10 Warp (turbo). Runs unthrottled and mutes audio; a stock 1541 load finishes in seconds instead of ~80.
F11 Keyboard layout: symbolic (default, maps by character) or positional (authentic C64 key positions).
F12 Quit.

C64 keys that are not obvious:

C64 Host
RUN/STOP Escape
CTRL Tab
Commodore Left Alt or Left Meta
RESTORE Page Up
INS/DEL Backspace
F1 / F3 / F5 / F7 F1 / F3 / F5 / F7 (add Shift for F2 / F4 / F6 / F8)

Joystick: a connected game controller, or the numpad (8/2/4/6 for directions, 0 for fire), or F9 plus the cursor keys. Right Ctrl always fires. F9 exists because most laptops have no numpad. The joystick drives port 2 by default, which nearly every game uses; some titles read port 1, so press F8 to switch ports. The active port shows in the title bar.

Game controller setup: a controller is used only if SDL recognises it as a game controller (it is in SDL's controller database). Then the D-pad and left stick move, the A button fires, and it drives the active port (F8 swaps port 2 / port 1).

  1. Plug the controller in before or during a run. Prefer a pad that presents as a standard USB HID gamepad; that is the mode SDL maps without extra drivers.
  2. Confirm it is seen. At startup the emulator logs one line per input device with its name, GUID, and whether SDL treats it as a game controller:
    host: joy 0 name="..." guid=03000000....  gamecontroller=yes
    
    gamecontroller=yes means it will be used. no means SDL has no mapping for that GUID, so it is ignored even though it enumerated fine.
  3. If it says no, supply a mapping. Take the GUID from the log, build an SDL mapping string, and export it before launching, no rebuild needed:
    export SDL_GAMECONTROLLERCONFIG="03000000....,My Pad,a:b1,b:b0,dpup:h0.1,..."
    SDL reads that variable at init and the device then reports gamecontroller=yes.

On Linux the controller must first appear under /dev/input as an event device. Under WSL2 a USB pad reaches Linux only after it is passed through from Windows (for example with usbipd); until then no input device exists to detect.

Command line:

--disk <path.d64>   mount a disk on device 8
--autorun           after boot, type LOAD"*",8,1 and RUN by itself (needs --disk)
--headless          run with no window

Environment (audio tuning, optional):

C64_AUDIO_BUF <n>     SDL audio device buffer in samples (default 2048)
C64_AUDIO_TARGET <n>  pacing cushion in samples (default 3528, about 80 ms); raise
                      on a jittery host to trade latency for fewer audio dropouts

Build

make                 # development build (-O0 -g)
make MODE=release    # optimised build (-O2)   <- use this to play
make clean

MODE=dev is the default and is roughly half the speed of the release build. It is for debugging, not for playing.

Requires a C11 compiler and SDL2. Builds clean under -Wall -Wextra -Werror.

ROM images

The KERNAL, BASIC and character ROMs are copyrighted, are not included, and are never committed. Supply your own under rom/:

File Size Maps to
rom/kernal.rom 8192 $E000-$FFFF
rom/basic.rom 8192 $A000-$BFFF
rom/chargen.rom 4096 $D000-$DFFF when banked
rom/1541.rom 16384 the drive's DOS (optional; without it the C64 runs alone)

Any legally obtained copies work. If you own a C64 you can dump your own; the open-source VICE distribution also ships the standard set (kernal-901227-03.bin, basic-901226-01.bin, chargen-901225-01.bin), and its Open ROMs are a copyright-clean alternative that boots but will not run all software. Without the ROMs the build still succeeds; the binary reports which files are missing and exits.

If you downloaded a binary release rather than the source, ROMS.md has this same list and the steps to obtain the files. It is the first thing to do before the emulator will run.

Accuracy and testing

make test        # ~965 checks, fast unit suites (~2 s)
make test-slow   # 69 checks, DOS/serial integration (~80 s)
make test-cpu    # Wolfgang Lorenz 6502/6510 conformance (~10 min)
  • Lorenz suite: 236 tests pass. The run stops at TRAP16; the remaining tests are 6510 interrupt-sequencing cases that assume a booted KERNAL with a $0314 handler installed, which the bare test runner does not provide. That is an environment limit, not a CPU defect.
  • Boot-render hash: a full KERNAL boot is hashed and pinned, so any change to VIC/CPU/CIA timing that alters a single pixel is caught.
  • Per-subsystem unit tests cite their expected values to Christian Bauer's VIC-II documentation, the Lorenz CIA model, or the MOS datasheets.
  • Real software: commercial titles load, run, and are bit-identical across repeated runs.

Provenance

Written from scratch. No code, structure or tables were taken from reSID, VICE or any other emulator. Where a hardware fact was needed it came from the MOS datasheets, Christian Bauer's VIC-II reference, Wolfgang Lorenz's published CIA timing model, or independent reverse-engineering work by others, each cited in the source at the point it is used.

The unstable illegal opcodes (ANE, LXA and the SH group) are analog-unstable on real silicon; this core uses the standard deterministic model, and src/cpu6502.c records exactly what the Lorenz suite does and does not pin about the magic constants.

License

MIT, see LICENSE. Copyright (c) 2026 Altug Tatlisu.

The licence covers this source code only. It does not cover the C64 ROM images, disk images, or any other software you use with the emulator.

Releases

Packages

Contributors

Languages