CapyASM is a 6502-family assembler written in Python built as a learning exercise. Its syntax, particularly in regards to addressing modes, differs from the typical 65xx syntax, with the goal of trying to make the instructions more explicit and easy to understand.
The following cpus are currently supported:
- MOS 6502
- RC 2A03 (nes)
- WDC 65c02
- HuC6280 (pc-engine)
Note: This assembler is very much a WIP, I do not recommend using it in serious projects.
The examples
folder contains source code for several NES roms, these are being used to test the assembler.
python3 capyasm.py -i input.asm -o output.asm
In CapyASM the type of addressing to be used is always written explicitly, avoiding ambiguity. Immediate values are written without decoration, memory/absolute values are written between []
brackets, zero page is written between <>
brackets and relative addressing is written between ()
brackets. Commands that take multiple arguments are separated by :
symbols, long versions of data (16-bit immediate and 24-bit absolute) are prefixed with a #
symbol.
- Implied -
RTS
- Registers -
PSH A | PSH X | PSH Y | PSH P
- Immediate -
LDA 20
- Relative -
BRA (label)
- Absolute -
LDA [$2000]
- Zero Page -
LDA <$20>
- Indirect -
JMP [[$1000]]
- Absolute Indexed -
LDA [$1000+x]
- Zero Page Indexed -
LDA <$10+x>
- Indexed Indirect -
LDA [<$10+x>]
- Indirect Indexed -
LDA [<$10>+y]
- Zero Page Relative (65c02) -
BBR4 <$20>:(label)
- Block Move (HuC6280)-
TIA [$2000]:[$3000]:@$1000
29
- Decimal$29
- Hexadecimal%11110000
- Binary'Hello World'
- ASCII"Hello World"
- ASCII (zero-terminated)
.byte $xx,$xx,(...)
- Inserts 8-bit data.word $xxxx,$xxxx,(...)
- Inserts 16-bit data (little-endian).bin "file.bin"
- Inserts a binary file.asm "file.asm"
- Inserts an assembly file.org [$xx]
- Sets the Program Counter.pad $xx|pad $[xx]
- Adds zeros to the file, either a set amount or until a certain PC is reached.padpage <value>
- Pads to align with the start of a 256 byte page.val NAME $xx
- Define a constant value.var NAME SIZE
- Define a memory variable of set byte length.zp NAME SIZE
- Define a zero page variable..macro name $xx,$xx
- Define Macro.cpu 6502
- Set the CPU to use# Comment
clc ; adc 2
- Multiple commands can be written on the same line using semicolons
In addition to the traditional opcode mnemonics, CapyASM also provides some alternative mnemonics for certain instructions:
bzc
- Branch on zero clearbzs
- Branch on zero setbnc
- Branch on negative clearbns
- Branch on negative setxor
- Exclusive-Orinc A/X/Y
- Increment registerdec A/X/Y
- Decrement registerbbc0
- Branch on Bit Cleartcb
- Test and Clear Bit
Labels are defined using a _
prefix. Labels have namespaces that are determined by the amount of _
symbols in their name, for example:
_reset
(...) ;do things
__loop
jmp [loop]
_nmi
(...) ;do things
__loop
bne [loop]
; Both `_reset` and `_nmi` have a `__loop` label inside them
Macros are defined with the symbol macro
and terminated with endmacro
. The contents of a macro are code with opcional content to be replaced by arguments written between curly braces. Here is an example macro for writing a byte to memory:
macro wrb
lda {0}
sta {1}
endmacro
wrb $20,[$2000]
CapyASM supports some simple compile-time math operations, these are:
a+b
a-b
a*b
a/b
-a
a.lo
a.hi