C64 READY.

Docs / Component status

Component status

Where the emulator stands against real Commodore 64 and 1541 hardware, subsystem by subsystem. This is the deliberately conservative view: a component is rated Implemented only when it behaves correctly for normal software, and known gaps are called out rather than glossed over.

For how the pieces fit together, see the master overview (and the per-subsystem deep-dives it links). For what the emulator can do from a user's seat, see Features.

Status

Spec alignment (High / Medium-high / Medium / Low) rates how close the implementation is to documented hardware behavior for that component.

Area Component Status Spec alignment Notes
Main unit C64 system integration Implemented High machine.js clocks CPU, VIC-II, CIA1, CIA2, SID, datasette, shadow SID voices, and optional 1541 on a PAL master timeline (50.125 Hz, 19656 cycles/frame). Power-cycle semantics: POWER OFF destroys the machine instance, POWER ON constructs a fresh one. The RESET button is also a hard reset — it destroys and rebuilds the machine (identical to POWER OFF + POWER ON), so demos reliably re-LOAD afterwards; a soft /RESET-line reset (RAM preserved) also exists for programmatic use.
CPU MOS 6510 core Implemented High cpu.js includes official opcodes, common illegal opcodes, decimal mode, IRQ/NMI handling, page-cross penalties, and micro-op paths for timing-sensitive cases. Passes Klaus Dormann's 6502 functional test.
CPU 6510 I/O port at $0000/$0001 Implemented High DDR/data-port behavior is modeled and drives memory banking plus datasette SENSE/MOTOR lines.
Memory RAM / ROM / PLA-style banking Implemented High memory.js handles BASIC, KERNAL, CHAR ROM visibility, I/O mapping, and Ultimax cartridge mode through the processor port bits.
Video VIC-II raster timing Implemented Medium-high PAL raster count, bad-line steals, BA/AEC modeling, internal counters (VC, RC, VMLI), raster IRQs (including mid-line $D011/$D012 LOW→HIGH per Bauer §3.12), borders, scroll, and mid-line register changes are correctly sequenced cycle-by-cycle.
Video Character and bitmap display modes Implemented High All eight (ECM, BMM, MCM) combinations: standard / multicolor / extended-background text, hi-res and multicolor bitmap, plus the three invalid modes (101, 110, 111) — which correctly force black output (modes 110/111 also apply the Bauer §3.7.3.7/8 invalid-VC address mask) while still setting foreground bits so collisions register. Mode bits are sampled live per pixel (Bauer §3.7.3). The XSCROLL edge filler follows the §3.7.3 shifter model: the line-start preload (empty shifter before the first delayed reload) takes the mode's idle background — $D021 in text, matrix low nibble in hi-res bitmap, black in the invalid modes — and each group's leading XSCROLL pixels drain the previous g-access byte, in display and idle state alike (see VIC2-ARCHITECTURE §8).
Video Sprites Implemented Medium-high Eight sprites, expansion, multicolor, priority, sprite DMA steals, and multiplex-friendly line rendering are implemented. Sprite-crunch latched at PHI2 of cycle 15 with bit-interleave formula; display disable deferred to cycle 58 phi1 (per VICE addendum, not cycle 16). Sprite idle-fetch (VIC-bus spectator on inactive sprite cycles) is modelled via the shared external-bus + vicInternalBus latches — see "Shared external-data-bus model" below; the leaked-byte garbage region reproduces VICE's sprite-fetch reference pixel-for-pixel.
Video Collision latches and IRQs Implemented High Sprite-sprite and sprite-background collision flags/IRQs are implemented cycle-by-cycle via the incremental rendering pipeline, providing accurate mid-line register reads.
Video Light pen Implemented High $D013/$D014 latch on the negative edge of the LP input. One-shot per frame, re-armed at raster=0. Line 311 negative edges silently ignored; LP held LOW across the frame boundary retriggers at L0 cycle 1 (per VICE addendum).
Video VIC-II model selection Implemented High Runtime toggle between 6569 (NMOS) and 8565 (HMOS / C64C); the 8565 grey-dot artifact and its 1-cycle register-pipeline delay switch with it. UI selector persists in localStorage.
Video NTSC (6567) timing Missing Low NTSC has not been a focus for this emulator — everything targets the PAL machine (6569/8565: 312 lines × 63 cycles, 50.125 Hz). The NTSC 6567 raster geometry (263 lines × 65 cycles, ~59.83 Hz), its different bad-line/sprite cycle layout, and per-variant quirks are not modeled. NTSC-only software is out of scope.
Audio SID register write path Implemented High SID register writes are cycle-stamped in the main thread and consumed in an AudioWorklet via SharedArrayBuffer ring buffer (128k entries). Cycle-sync hook on every init/reset snaps the worklet clock to the first event so digi timing survives power-cycles. The worklet drains the ring into a preallocated typed circular buffer (no per-event allocation or splice in the real-time audio callback) and posts lateMax/late/overrun/maxDepth diagnostics (gated behind c64Trace.sidDiag).
Audio SID synthesis (oscillator + envelope) Implemented High sid-voice.js provides the SIDVoice class shared by the worklet and the main-thread shadow. Phase accumulator, sync, ring mod, test bit, ADSR with 15-bit rate counter + exponential decay divider + ADSR-bug-accurate exact-match timing, NOISE LFSR (23-bit, taps 22/17), NOISE+combined LFSR clobbering.
Audio SID combined waveforms Implemented Medium-high TRI+SAW / PULSE+TRI / PULSE+SAW / PULSE+TRI+SAW use 4096-entry synthetic lookup tables fitted from black-box OSC3 captures (Hermit / jsSID-style bit coupling plus per-bit 6581 thresholds where needed; reSID's measured tables not redistributed). The phase lookup index is full 12-bit for both chips — pitch is model-independent, so only the value scaling differs (an earlier 11-bit mask on the 6581 folded the phase, dropping the fundamental and pitching combined waveforms up an octave; fixed).
Audio SID filter Implemented Medium-high State-variable filter (Chamberlin SVF). 6581 cutoff via 2048-entry log-interpolated lookup calibrated against headless VICE reSID 6581 noise sweeps (about 220 Hz floor → 12.5 kHz top). 8580 uses a linear ramp. Resonance follows reSID's measured laws: 8580 1/Q = 2^((4−res)/8) (Q 0.707 → 2.59), 6581 the die-derived 1/Q = (15−res)/8 (floored for SVF stability, so high-res patches keep their resonant peak). 6581 filter saturation on lp/bp accumulators. $D417 bit 3 (EXT IN routing) intentionally stubbed — no expansion-port audio modeled.
Audio $D418 4-bit digi Implemented Medium-high DC bias on master volume (matches real 6581 analog mixer) lets 1-bit Galway-style PWM digi (WOTEF, Summer Holiday) and 4-bit Mahoney-style sample playback work. The 8580 has only a faint volume-step response (calibrated to −8.9 dB digi/tone vs reSID) — switch to 6581 for digi playback.
Audio SID register reads ($D41B / $D41C) Implemented High Cycle-exact OSC3 / ENV3 readback via a main-thread "shadow SID" — three SIDVoice instances clocked in lockstep with sidCycleCounter. Demos that poll voice 3 in tight loops (NOISE RNG, sample-trigger timing, raster sync) see the same byte the worklet would emit at that simulated cycle, not an audio-block-stale snapshot. Only voice 3 is read, so voices 1 & 2 run a cheaper phase-only clock (clockPhaseOnly) that advances just the oscillator they feed into the sync/ring-mod chain — byte-identical readback, ~⅔ less per-cycle shadow work.
Audio SID paddle reads ($D419 / $D41A) Implemented High POTX/POTY sample-and-hold every 512 master cycles, modeling the real chip's RC-discharge ADC. Mouse position (canvas mousemove) drives the live paddle value.
Audio Analog output stage Implemented Medium-high 1-pole HP at 15.9 Hz (DC blocker per reSID extfilt R=1kΩ, C=10µF). 1-pole LP at 15.9 kHz (motherboard analog LP per reSID extfilt R=10kΩ, C=1nF). A 3-pole reconstruction low-pass at 0.42·Fs (≈18.5 kHz) runs per SID cycle before the boxcar decimation, anti-aliasing the >Nyquist content of sharp $D418 digi edges that the extfilt + boxcar alone leave only ~4 dB down at the output Nyquist (~15 dB on the worst alias line, +3 dB digi SNR). tanh soft saturator instead of hard clipping (no clip-harmonic aliasing). Brief 6 ms fade-in on init/reset to mask DC-blocker settling transient.
Audio SID model selection Implemented High UI toggle for 6581 vs 8580. Combined-waveform shapes, filter cutoff curves, resonance ramps, and DC bias all differ between models.
Audio 1541 drive sounds Implemented Medium Synthesized motor hum (sawtooth + filtered noise + 5 Hz rotation tremolo) and stepper clicks (bandpass-filtered noise burst) via WebAudio. Trap-mode loads produce a canned fake-load click train. Off by default; enabled at runtime via the DRIVE SOUND toggle in ⚙ OPTIONS ▸ Sound (the choice persists in localStorage).
I/O CIA1 Partial Medium-high Timers (incl. CNT-count modes), TOD clock, keyboard matrix, joystick merge, and datasette FLAG IRQ support are present. The serial register's output path is modeled — an SDR write shifts out over 16 Timer A underflows and raises the SP IRQ (ICR bit 3), with pending-byte chaining and output→input cancel. Only the physical SP/CNT pins and input-mode shifting (both of which need external user-port hardware) are unmodeled.
I/O CIA2 Partial Medium-high Timers, TOD, NMI signaling, and VIC bank switching are present. Serial-register coverage matches CIA1 (output-mode SP IRQ modeled; physical SP/CNT pins + input-mode shifting absent). This does not affect the IEC bus — the KERNAL bit-bangs IEC on CIA2 Port A (ATN/CLK/DATA), not the shift register.
I/O CIA chip model Implemented High A single generic MOS 6526 is emulated for both CIA1 and CIA2 — there is no old-vs-new variant (6526 vs 6526A / 8521) selector, unlike the VIC-II (6569/8565) and SID (6581/8580) which are switchable. The known old/new CIA differences — TOD tick edge, one-shot Timer-B underflow IRQ timing, and the ICR read-acknowledge race — are not separately modeled; behavior follows the common 6526 subset. This does not affect keyboard-matrix reads (identical across CIA revisions). A timer started with a plain START ($DC0E/$DC0F bit 0, no force-load) holds its count for one clock before the first decrement — measured against VICE with a probe run in both emulators; force-load+START keeps its separate 2-clock load phase. Cycle-exact timer-based stable rasters depend on this.
Input Keyboard matrix Implemented High Standard C64 key mappings plus host-friendly remaps: TAB = INST/DEL, F9 = RUN/STOP, F10 = Commodore key, F11 = CLR/HOME, F12 = RESTORE (NMI). On-screen clickable key map available from the Controls panel.
Input Control-port routing Implemented High A Control Ports UI panel assigns each of the two ports independently (Joystick, Touch Joystick on touch devices, Mouse 1351, Mouse NEOS, Paddle, Key Joystick 1/2, or None), with a SWAP PORTS button. The DOM-free byte builders and NEOS strobe state machine live in control-port.js so they are unit-tested without a browser.
Input Digital joystick Implemented Medium-high Joystick ports are merged into CIA1 reads and support gamepads (per-port selection), key-joystick mode, and a touch-only eight-way/two-button overlay. Both two-button inputs wire their second button to the UP line. Covers digital directions/fire, not analog.
Input 1351 proportional mouse Implemented Medium GEOS-convention 1351: canvas mousemove drives POTX/POTY through the SID's 512-cycle sample-and-hold; LMB→FIRE (joy bit 4), RMB→UP (joy bit 0), matching the real 1351 and what GEOS reads.
Input NEOS mouse Implemented Medium Nibble-multiplexed strobe protocol (per the c64os reference): DDR-mode-gated button/strobe readout cycling Xhi→Xlo→Yhi→Ylo with snapshot at phase 0; right button on $D419 bit 7.
Input Paddle Implemented Medium Paddle pair driven by the mouse through POTX/POTY's sample-and-hold; paddle-A fire on the joystick LEFT line, paddle-B fire on the FIRE line. Behaves enough for paddle-control games (Arkanoid clones, etc.); not a real pot's analog response.
Input Light pen Implemented Medium-high VIC-II light-pen latch implemented and wired: the LP input is driven by CIA1 Port B bit 4 (output-low) OR joystick-1 FIRE, so the "stable raster via light pen" trick works. No dedicated light-pen pointer device through the UI yet.
Tape 1530 Datasette playback Implemented Medium-high .tap v0/v1 (full-wave) / v2 (half-wave) playback modeled cycle-by-cycle through CIA1 FLAG pulses and motor/SENSE handling. Play / Stop / Rewind transport buttons in the UI.
Tape Tape recording / fast-forward Missing Low No recording, fast-forward, or tape write path.
Serial bus IEC bus (C64 ↔ 1541) Implemented High Real-time wired-AND signal reflection with correct open-collector inverter polarity, properly driving hardware interrupts on the 1541 CPU for reliable handshakes. Drive output pins reach the C64's CIA one master cycle later than the run order inherently gives — a $DD00 read at cycle S sees drive writes from ≤ S−2 — modeling the input-latch margin the two asynchronous clocks provide on real hardware; the C64→drive direction is instant (iecEdgeLatency switch, default on). This margin is what keeps NOSDOS-class 2-bit loaders' drive-release-vs-last-sample race positive across the swept drive phase.
Disk KERNAL LOAD trap Implemented Medium When true-drive is off, machine.js intercepts LOAD at $FFD5 for fast convenience loading from mounted .d64 images. Not real hardware behavior.
Disk 1541 drive CPU + DOS ROM Implemented High A separate 6502-based drive computer runs alongside the C64 whenever a 1541 ROM is loaded; true-drive emulation controls whether $FFD5 LOAD is trap-served or handled by the real IEC protocol (1541-II.251968-03.bin verified). When idle, recognized DOS/fastloader wait loops are skipped and VIA time is settled on wake, so device 8 does not full-clock forever while unused. The drive clocks at the true PAL ratio — its 1 MHz against the C64's 985 248 Hz via a 16.16 fixed-point accumulator (66517/65536 per master cycle, VICE drivesync.c parity) — so the drive↔C64 phase sweeps continuously like real hardware instead of freezing at the load-start alignment (driveTrueClockRatio switch, default on; DRIVE_TRUE_CLOCK_RATIO=0 pins the legacy 1:1 lockstep bit-exactly). Spindle and VIA time scale with it, making disk rotation real-time-correct.
Disk 1541 VIA pair (6522) Partial Medium The two 6522 VIAs cover the timer and port behavior the DOS ROM depends on. Tailored implementation rather than a generic 6522.
Disk GCR read/write channel / spindle / sync Partial Medium The emulator synthesizes GCR track streams from .d64 data, models speed zones, sync marks, and byte-ready signaling. A matching write channel shifts the drive's outgoing bytes back onto the track buffer. Mechanics simplified.
Disk .d64 filesystem support Implemented Medium Directory parsing, wildcard loads, directory listing generation, and file extraction for 35- and 40-track images.
Disk Disk writing / save-back Implemented Medium The 1541 write head is modeled: the DOS selects write mode (VIA2 CB2 low + Port-A output), the spindle shifts the outgoing GCR bytes onto the track buffer, and a GCR decoder (gcr.js decodeTrackStream / commitDirtyTracks) folds them back into the .d64 image. SAVE, scratch, rename, and N: format run through the real DOS over the emulated IEC bus. Write-protect is honored (VIA2 PB4, active-low — an inverted-polarity bug there was what previously blocked all writes). Modified disks auto-save to the browser Library and export to a .d64; BLANK inserts a raw unformatted image, FORMAT lays down an empty format.
Storage .prg injection Implemented N/A Direct RAM loading plus SYS/RUN injection. Convenience feature, not original hardware.
Storage Auto-RUN after PRG load Implemented N/A Toggleable from UI; persists in localStorage.
Storage Save / load machine state Implemented N/A Full-machine snapshot — RAM + every chip (CPU, VIC-II, CIA1/2, SID shadow voices, datasette, and the 1541 when true-drive is on) plus the inserted disk/tape/cartridge bytes and chip variants — frozen into a named IndexedDB slot with a PNG thumbnail, restored through the same fresh-machine reattach path POWER ON uses. Slots are self-contained (survive deleting the source library entry) and can be exported to / imported from a file. SAVE STATE / LOAD STATE buttons in the UI (save is disabled while powered off). Convenience feature, not original hardware.
Expansion Cartridges Implemented Medium-high .crt files supported through hardware-type devices: type 0 (generic 8K/16K/Ultimax), type 1 (Action Replay v4.x/v5/v6 — ROM/RAM banking, IO1/IO2, RESET/FREEZE), type 3 (Final Cartridge III — four 16K banks, IO1/IO2 ROM mirror, $DFFF control, RESET/FREEZE), type 19 (Magic Desk / Domark / HES Australia), and type 32 (EasyFlash). Loadable while powered off.
Expansion REU / other cartridge types / user port / printer / modem Missing Low Not implemented.