Casso is a retro / classic-machine platform emulator and from-scratch AS65-compatible 6502 assembler, written in C++. Today the platform emulator targets the Apple II family (][, ][+, //e); the abstractions are generic enough to host other 6502-based machines later.
Two of the three built-in themes booting the casso-rocks demo disk — same Apple //e core, different chrome:
| Skeuomorphic | Dark Modern |
|---|---|
![]() |
![]() |
The project includes:
- Apple II platform emulator — GUI-based Apple II, II+, and //e emulator with D3D11 rendering, WASAPI audio, Disk II controller with realistic mechanical sounds, data-driven machine configs, 80-column text + Double Hi-Res, auxiliary RAM, audit-correct Language Card state machine, and cycle-accurate IRQ/NMI infrastructure.
- 6502 CPU emulator — passes Klaus Dormann's functional test suite and all 151 legal-opcode sets from Tom Harte's SingleStepTests (10,000 vectors each).
- AS65-compatible assembler — a from-scratch reimplementation of Frank A. Kingswood's AS65, intended as a drop-in replacement. Supports the complete AS65 syntax: macros, conditional assembly (
if/ifdef/ifndef/else/endif), the full expression evaluator (arithmetic, bitwise, logical, shift,</>byte selectors, current-PC*),equ/=constants,include, three-segment model (code/data/bss), AS65-style listing output, and AS65 command-line flags (-l,-t,-s,-s2,-z,-c,-w,-d,-g, ...) including flag concatenation (-tlfile). - CLI tool — runs as an AS65-style assembler by default, or with the
runsubcommand to load and execute a binary or assembly source. - First-run asset bootstrap — Casso fetches the ROMs, sample disks, and Disk II audio samples it needs on first launch (with user consent), so a fresh
Casso.exeboots to a usable //e BASIC prompt with no manual setup. - Headless test harness —
HeadlessHostdrives the emulator with no Win32 window, enabling deterministic integration tests for cold boot, disk boot, video framebuffer hashing, and reset semantics. - 1500+ unit tests — comprehensive coverage of CPU instruction encoding, addressing modes, arithmetic, branching, assembler features, audio pipeline (speaker + drive), //e MMU + Language Card, video timing, Disk II nibble engine, WOZ + nibblized image formats, 80-col + DHGR video, reset semantics, perf budget, and backwards-compat for ][/][+ machines.
See CHANGELOG.md for the granular history.
Casso's entire chrome moved from the legacy Win32 menu bar / Win32 dialogs to a borderless, themed shell rendered straight onto the same D3D11 framebuffer that draws the emulator video — using a native Direct2D / DirectWrite pipeline (DxUiPainter + DwriteTextRenderer), no third-party UI engine.
Three built-in themes — Skeuomorphic, Dark Modern, Retro Terminal — hot-swappable from Settings → Theme with no restart and no machine reset. Each theme ships under Resources/Themes/<Name>/ (extracted to Themes/<Name>/ at first run) with a theme.json describing colors, CRT defaults, drive visual profile, and other UI tokens consumed by the native widget renderer. The token-based custom-theme authoring surface is still being wired through the native widgets — see docs/themes/AUTHORING.md for the current state.
Skeuomorphic drive widgets with realistic Apple Disk II faceplates: perspective-projected case top with two indented lid panels that taper toward the back, nine vent slits down each side, beige case wrapping a black inset faceplate on all four sides, cantilever door hinged at the slot top that tilts up and back (tucking inside the case with a small flap visible when fully open) revealing a recessed finger-pull behind it, status LED, and the Cassowary rainbow logo. Click a drive to pick a disk image, or drag-and-drop a .dsk / .do / .po / .nib file onto it. Eject animates the door open even on an empty drive.
Consolidated Settings panel replaces the old OptionsDialog and MachinePickerDialog. Machine selection, machine info, emulation speed, video color mode, disk write mode, floppy sound + mechanism, write-protect, theme picker, and the new CRT controls live in one non-modal in-window panel with full keyboard navigation.
CRT effects — scanlines, phosphor bloom, and color bleed (each independently toggleable, with its own parameter sliders), plus persistence trails, contrast, and gamma sliders. Per-monitor presets (Color / Green / Amber / White) seed sensible defaults; themes can override; user tweaks persist as overrides on top of either. The Settings popup gets out of your way as you scrub a control — the panel fades, the emulator behind it stays sharp inside a per-pixel clip, and only the focused control remains opaque — so you can evaluate the effect of every parameter change live.
Unified user preferences persist in %LOCALAPPDATA%\Casso\UserPrefs.json: global UI state under global, and per-machine deltas under machines keyed by display name. Most settings live there today; a small set of legacy values (last-loaded machine, per-machine last-inserted disk paths, audio download consent, window placement) still live in the registry for backwards compatibility and will migrate to JSON in a follow-up.
Realistic mechanical sounds during disk activity, mixed into the WASAPI pipeline alongside the //e speaker:
- Stereo motor hum, head-step clicks, track-0 / max-track bumps, and disk insert / eject sounds.
- Per-drive equal-power stereo panning: single-drive profiles play centered; in two-drive profiles Drive 1 leans left, Drive 2 leans right.
- Step-vs-seek discrimination: contiguous step bursts during DOS RWTS recalibration fuse into a continuous seek buzz instead of N overlapping clicks.
- View → Options... dialog with a Drive Audio toggle (default on) and a Disk II mechanism dropdown (Shugart SA400 by default, or Alps 2124A). Both persist per-machine via the registry.
- First-run consent dialog downloads the actual recordings from the OpenEmulator project; OGGs are decoded in memory via vendored
stb_vorbisand written as WAV (no.oggretained on disk). Asked once per machine, persisted thereafter. - Generic
IDriveAudioSink/IDriveAudioSource/DriveAudioMixerabstraction so future drive types (//c internal 5.25, DuoDisk, Apple 5.25 Drive, ProFile, ...) plug in without touching the mixer.
Casso.sln
├── CassoCore/ Static library — CPU emulator, assembler, parser, opcode table
├── CassoEmuCore/ Static library — Apple II devices, video modes, audio generator + drive-audio mixer
├── Casso/ Win32 application — Apple II platform emulator (D3D11, WASAPI, Disk II audio)
├── CassoCli/ Console application — AS65-compatible assembler CLI with `run` subcommand
└── UnitTest/ Test DLL — Microsoft Native CppUnitTest (1500+ tests)
- Windows 10/11
- PowerShell 7 (
pwsh) for build/test scripts - Visual Studio 2026 (v18.x)
- Workload: Desktop development with C++
- Components: MSVC build tools, Windows SDK, C++ unit test framework
- Optional: MSVC ARM64 build tools (for ARM64 builds)
- Optional: VS Code (repo includes
.vscode/tasks)
# Build Debug for current architecture (Ctrl+Shift+B in VS Code)
.\scripts\Build.ps1
# Build Release
.\scripts\Build.ps1 -Configuration Release
# Build all platforms
.\scripts\Build.ps1 -Target BuildAllRelease
# Rebuild with code analysis (warnings as errors)
.\scripts\Build.ps1 -Configuration Release -RunCodeAnalysis# Build and run tests
.\scripts\RunTests.ps1
# Or use VS Code: Run Tests (current arch)# Assemble a source file to a flat binary (AS65 mode — no subcommand)
CassoCli input.a65 -o output.bin
# Assemble with a listing file and a symbol table
CassoCli input.a65 -o output.bin -l listing.txt -t
# Output Motorola S-record (.s19) or Intel HEX (.hex)
CassoCli input.a65 -s -o output.s19
CassoCli input.a65 -s2 -o output.hex
# Pre-define a symbol on the command line
CassoCli input.a65 -d DEBUG=1 -o output.bin
# Generate a listing with cycle counts
CassoCli input.a65 -c -l listing.txt
# Assemble and run an assembly source directly
CassoCli run input.a65
# Load and run a pre-assembled binary at a specific address
CassoCli run output.bin --load $8000The emulator requires Apple II ROM images, which are copyrighted by Apple and not distributed with this project. A script is included to download them from the AppleWin project:
# Download ROM images into the per-machine Machines/<Name>/ folders
.\scripts\FetchRoms.ps1
# Run the emulator (defaults to Apple II+)
Casso
# Run with a specific machine config
Casso --machine Apple2eROM images live under Machines/<MachineName>/ (e.g.,
Machines/Apple2e/Apple2e.rom) and shared device boot ROMs live
under Devices/<Family>/ (e.g., Devices/DiskII/Disk2.rom). Both
Machines/ and Devices/ are fully runtime-managed: every file
inside is either extracted from binary-embedded resources or
downloaded on first launch (with user consent). Delete either
directory and the next launch rebuilds it from scratch.
Available machine configs are in Machines/<MachineName>/<MachineName>.json.
| Feature | Syntax / Flag |
|---|---|
| All 56 mnemonics | LDA, STA, ADC, BNE, etc. |
| All addressing modes | #$42, $30, $1234,X, ($20),Y, A |
| Labels | loop: DEX / BNE loop |
| Directives | .org $8000, .byte $FF, .word $1234, .text "hello", code/data/bss |
| Constants | value = $42, carry equ %00000001 (chains and forward refs supported) |
| Conditionals | if/ifdef/ifndef/else/endif |
| Macros | name macro … endm, with arguments and \ line continuation |
| Includes | include "file.a65" |
| Comments | ; full line / LDA #$42 ; inline |
| Number formats | $FF (hex), %10101010 (binary), 255 (decimal) |
| Expressions | full operator set: + - * / % & | ^ ~ << >>, <label, >label, current-PC * |
| Listing output | -l [file] (stdout or file), -c for cycle counts, -m for macro expansion |
| Symbol table | -t |
| Output formats | flat binary (default), -s (S-record), -s2 (Intel HEX) |
| Fill control | -z for $00 fill (default $FF) |
| Pre-defined symbols | -d NAME or -d NAME=VALUE |
| Debug info | -g [file] |
| Warning control | --warn, --no-warn, --fatal-warnings |
| Verbose / quiet | -v / -q |
| Flag concatenation | -tlfile ≡ -t -l file (AS65 style) |
All 56 standard 6502 mnemonics are implemented. Validated against Klaus Dormann's functional test suite (full pass) and Tom Harte's SingleStepTests (all 151 legal-opcode test sets, 10,000 vectors each).
- Pass Klaus Dormann's 6502 functional test suite (#7)
- Per-opcode validation against Tom Harte's SingleStepTests (#29, #38)
- Apple //e fidelity — cold boot to BASIC, audit-correct Language Card, 64 KB aux RAM, 80-column text + Double Hi-Res, soft reset vs. power cycle, IRQ/NMI dispatch, RDVBLBAR
- Disk II controller — DOS 3.3 / ProDOS
.dsk/.do/.ponibblization + WOZ v1 / v2 with auto-flush on eject - Disk II mechanical audio — stereo motor hum, head-step clicks, track-0 bump, disk insert / eject sounds, with a runtime Settings → Machine → Drive audio toggle. Built on a generic
IDriveAudioSink/IDriveAudioSource/DriveAudioMixerabstraction so future drive types (//c internal 5.25, DuoDisk, ProFile, …) plug in without touching the mixer - Headless test harness for deterministic integration tests (
HeadlessHost, framebuffer scraper, keyboard injector) - Performance gate — emulator throughput budget enforced in CI (Release-only)
- Cycle-accurate execution and profiling (#57)
- 65C02 extended instruction support, with assembler
--cpuflag (#9) - Undocumented / illegal opcode support (#52)
- Rockwell / WDC 65C02 variants (#49, #50)
- Disk II copy-protection fidelity — spin-up delay, cycle-accurate rotational position, bit-level write path (#67)
- Boot Karateka from its WOZ image (RWTS18 copy protection) (#68)
- Choplifter gameplay starts after the title screen (WOZ copy protection) (#69)
- Boot Lode Runner from its WOZ image (copy protection) (#70)
- NES 6502 / Ricoh 2A03 variant (#47)
- Example programs — ready-to-assemble demos and tutorials (#55)
- VS Code extension — syntax highlighting, assemble-on-save, inline diagnostics (#54)
- Interactive debugger / monitor — step, breakpoints, register watch, memory dump (#51)
- Relocatable object output — o65 format for cc65 toolchain integration (#58)
While emu is the more obvious name and mascot for an emulator, I wanted Casso to stand out; to be just a little weird; to think different. I picked its larger, flightless, considerably more dangerous cousin: the cassowary—Casso to his friends.
I thus present to you our regal namesake—revel in his splendor!
Cassowary photo by Mr. Smiley / BunyipCo, licensed under CC BY-NC-SA 3.0.
Casso's correctness is validated against two exceptional open-source test suites:
- Klaus Dormann's 6502 Functional Test Suite — @Klaus2m5's exhaustive functional test exercises every documented 6502 behavior: all instructions, addressing modes, flag interactions, BCD arithmetic, and edge cases. Casso passes the full suite.
- Tom Harte's SingleStepTests — @TomHarte's per-opcode test vectors validate every legal 6502 opcode against cycle-accurate reference traces. Casso passes all 151 legal-opcode test sets (10,000 vectors each).
Thank you to both authors for making these invaluable resources freely available. They are the gold standard for 6502 emulator validation.
See CONTRIBUTING.md for commit conventions, build instructions, code style guidelines, and other contributor guidelines.







