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...
- the Apple II,
- the original NES,
- the Commodore 64,
- the BBC Micro,
- and Michael Steil's phenomenal talk at 27C3.
I gave a talk on cl-6502 and related ideas which is online here. The slides are available separately here. A few notes on why I'm writing it are here and minor notes on the design are here.
You are strongly encouraged to use this library via Quicklisp. Simply start your lisp and run: (ql:quickload 'cl-6502)
.
- Check out the docs for the cl-6502 package.
- 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
andAND
so you likely don't want to:use
it in your own packages.
In particular, asm, disasm, execute, 6502-step, and reset are likely of interest.
- Load cl-6502 and switch to the
cl-6502
package. - Write some 6502 code and run it through
asm
(e.g.(asm "brk")
) to get a bytevector to execute. - 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 (6502::cpu-pc *cpu*) 0)
- Manually step through it with
(6502-step *cpu* (get-byte (6502::immediate *cpu*)))
(reset)
the CPU as necessary and keep hacking! :)
The assembler supports comments, constants, and labels in addition to 6502 assembler code. There should only be one statement per line. A label stores the Program Counter, that is, the absolute address of the next instruction. Thus, loop: {newline} lda
should store the absolute address of lda. If a label is used with a relative addressed instruction, it will be truncated as needed. 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.- Labels and constants support: indirect, absolute, absolute-x, absolute-y, implied, 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.
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.