Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
A 6502 emulator in Lisp.
Common Lisp Shell

This branch is 196 commits behind master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.

cl-6502, or The 6502...IBM 704 edition ;)

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...

A few notes on why I'm doing this are here. Some notes on the design of cl-6502 are here.


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 and 6502-cpu packages. There is also a 6502 package but it exists primarily to house the implementation of all the opcodes.
  • Play around at the REPL!
  • Use it to create your own wacky code artifacts. (NOTE: As the 6502 package shadows BIT and AND, you're hereby advised not to :use it in any other packages.)

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

A simple example:

(An example program, *benchmark*, currently exists.)

  1. Load cl-6502.
  2. Write some 6502 code and run it through asm (e.g. (asm "brk")) to get a bytevector to execute. Optionally, check the disassembly with (disasm *my-bytevector*).
  3. Load it into memory and run it with (execute *cpu* *my-bytevector*) OR load it with (setf (get-range 0) *my-bytevector*), set the program counter to 0 with (setf (cpu-pc *cpu*) 0) and manually step through it with (6502-step *cpu* (get-byte (immediate *cpu*))).

A note on supported Assembler syntax

The assembler supports comments, constants, and labels in addition to 6502 assembler code. There should only be one statement per line. A label currently stores the absolute address of the next instruction. Thus, loop: {newline} lda should store the absolute address of lda. Forward references, i.e. use of labels before their definition, are allowed. Instructions and register names are case insensitive; labels and constants names are case sensitive.

Syntax Table:

  • Label definition: name:
  • Label usage: jmp !label where ! is the syntax of the desired addressing mode.
  • Constant definition: name=val
  • Constant usage: lda !name where ! is the syntax of the desired addressing mode.
    • Currently, labels and constants support: indirect, absolute, absolute-x, absolute-y, and relative addressed instructions.
  • Comments: foo ; a note about foo
  • Implied mode: BRK
  • Accumulator mode: ldx a
  • Immediate mode: lda #$00
  • Zero-page mode: lda $03
  • Zero-page-x mode: lda $03, x
  • Zero-page-y mode: ldx $03, y
  • Absolute mode: sbc $0001
  • Absolute-x mode: lda $1234, x
  • Absolute-y mode: lda $1234, y
  • Indirect mode: jmp ($1234)
  • Indirect-x mode: lda ($12), x
  • Indirect-y mode: lda ($34), y
  • Relative mode: 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. There is a dearth of tests at the moment but there will be more soon as the design has recently solidified.

Something went wrong with that request. Please try again.