Tools / Command-Line Tool
6502 Disassembler
A 6502 disassembler with both linear and recursive-descent modes. Decodes the 256 documented + undocumented opcodes, supports labels, and includes Apple II soft-switch comment annotations. Reusable on any 6502 binary, not just Apple II.
Tested on: Windows 11 · Python 3.13
A standalone 6502 disassembler usable on any 6502 binary — written for reverse-engineering Apple ][ software but with no Apple-specific dependencies in the core. Currently lives inside the Orchard repository as nibbler/disasm.py; invoked via the nibbler CLI as the disasm subcommand.
Two modes
Linear disassembly treats every byte in the input as code and decodes sequentially. Fast, complete, but cannot distinguish code from interleaved data — strings, jump tables, and constants will appear as bogus instructions in the output. Useful for quick orientation in unknown binaries.
Recursive-descent disassembly starts from a known entry point and follows control flow — branches, jumps, subroutine calls — only marking bytes that are actually reachable as code. Everything else is left as data. Produces much cleaner output for programs that interleave code and data tables (which is most non-trivial Apple ][ software). Generates SUB_xxxx and L_xxxx style labels automatically based on call/branch targets, so the disassembly reads with named subroutines instead of bare addresses.
Apple II hardware comments
When recursive-descent mode is enabled, accesses to Apple ][ I/O space ($C000-$C0FF) are annotated inline with what each soft switch does — STA $C030 becomes STA $C030 ; toggle speaker, LDA $C081 becomes LDA $C081 ; LC RAM read enable, and so on. Same for Disk II controller writes ($C08x,X), keyboard reads, video page selection, etc. Roughly 40 distinct annotations covering the standard Apple ][+/IIe I/O map.
Usage
git clone https://github.com/BrentRector/orchard
cd orchard
# Linear mode (everything decoded as code):
python -m nibbler disasm myprogram.bin --base 0x4000
# Recursive descent (only reachable code; cleaner output):
python -m nibbler disasm myprogram.bin --base 0x4000 --entry 0x4000 -r
# Disassemble a specific range within the binary:
python -m nibbler disasm myprogram.bin --base 0x800 --start 0x1000 --end 0x1100
Coverage
All 151 documented 6502 opcodes plus the common undocumented ones (LAX, SAX, DCP, ISC, SLO, RLA, SRE, RRA, KIL, NOP-with-operand, etc.). 13 addressing modes. Both NMOS 6502 and 65C02 variants are partially supported — the 65C02-specific opcodes (PHX, PHY, PLX, PLY, STZ, BRA, etc.) decode correctly but are commented as 65C02-only.
Where it’s been used
- Apple Panic copy-protection investigation — disassembling 8,800 lines of game runtime extracted from a non-standard-format WOZ image. See the apple-panic series.
- Microsoft SoftCard CP/M boot loader — annotating ~3 KB of 6502 code from disk through the SoftCard CPU handoff. See the cpm-videx series.
Related tools
- Z-80 Disassembler — companion tool for the Z-80 side of SoftCard CP/M analysis
- nibbler — the WOZ-format disk analysis toolkit (the disassemblers happen to share its repository home)