Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?


Failed to load latest commit information.
Latest commit message
Commit time
July 5, 2013 12:28
September 2, 2015 15:38
June 9, 2013 11:41
March 3, 2014 23:47
September 2, 2015 15:38
September 2, 2015 15:41
September 2, 2015 15:38
February 22, 2013 17:14

cl-6502 - A Readable CPU Emulator

Build Status Quicklisp

cl-6502 is a Common Lisp emulator, assembler and disassembler for the MOS 6502 processor. In case that sounds weird to you, the MOS 6502 is famous for its use in...

I gave a talk on cl-6502 called 'On Programmer Archaeology'. You can watch it on Vimeo or grab the slides. A few notes on why I'm writing it are here and minor notes on the design are here.


Inspired by Luke Gorrie's call for Readable Programs, there is a readable PDF book of the source. You can also produce it from the git repo with: cd repo/src && make book. You'll need make, pandoc, and some latex packages (texlive-luatex, texlive-xetex, and texlive-latex-extra on debian) installed to build it yourself.


You are strongly encouraged to use this library via Quicklisp. Simply start your lisp and run: (ql:quickload 'cl-6502).

Getting Started

  • Check out the docs for the cl-6502 package or have a look on quickdocs.
  • Play around at the REPL!
  • Use it to create your own wacky code artifacts.
  • There is also a lower-level 6502 package if you really want to get your hands dirty. NOTE: The 6502 package shadows BIT and AND so you likely don't want to :use it in your own packages.

In particular, asm, disasm, execute, step-cpu, and reset are likely of interest.

A simple example:

  1. Load cl-6502 and switch to the cl-6502 package.
  2. Write some 6502 code and run it through asm (e.g. (asm "brk")) to get a bytevector to execute.
  3. Load it into memory with (setf (get-range 0) *my-bytevector*).
  4. Set the program counter to 0 with (setf (6502:cpu-pc *cpu*) 0).
  5. Run it with (run *cpu*) or manually step through it with (step-cpu *cpu* (get-byte (cpu-pc *cpu*))).
  6. (reset) the CPU as necessary and keep hacking! :)

Supported Assembler Syntax

There are sexp-based and string-based assemblers, both invoked via asm. The string-based assembler expects statements to be separated by newlines. The sexp-based assembler expects each statement to be in its own list. Disassembling to both formats is supported via disasm and disasm-to-list. Semicolons are treated as "comment to end-of-line" in the string assembler.

| Addressing Mode | SEXP-based format | String format  |
|   Implied       |  (:brk)           | "brk"          |
|   Immediate     |  (:lda :#$00)     | "lda #$00"     |
|   Accumulator   |  (:rol :a)        | "rol a"        |
|   Zero-page     |  (:lda :$03)      | "lda $03"      |
|   Zero-page, X  |  (:lda :$03.x)    | "lda $03, x"   |
|   Zero-page, Y  |  (:ldx :$03.y)    | "ldx $03, y"   |
|   Absolute      |  (:sbc :$0001)    | "sbc $0001"    |
|   Absolute, X   |  (:lda :$1234.x)  | "lda $1234, x" |
|   Absolute, Y   |  (:lda :$1234.y)  | "lda $1234, y" |
|   Indirect      |  (:jmp :@1234)    | "jmp ($1234)   |
|   Indirect, X   |  (:lda :@12.x)    | "lda ($12), x" |
|   Indirect, Y   |  (:lda :@34.y)    | "lda ($34), y" |
|   Relative      |  (:bne :&fd)      | "bne &fd"      |


  • Using Quicklisp: For local development, git clone this repository into the local-projects subdirectory of quicklisp.

To run the tests, after you've loaded cl-6502 just run (asdf:oos 'asdf:test-op 'cl-6502). You may need to (ql:quickload 'cl-6502-tests) to ensure that the fiveam dependency is satisfied first.


The code is under a BSD license except for docs/6502.txt and tests/6502_functional_test.a65 which are only present by 'mere aggregation' and not strictly part of my sources.


A 6502 emulator in Lisp.







No releases published


No packages published