# Assembler syntax
The assembler allows you to write regular 6502 assembly instructions. However, some more powerful features are of course also available.
# Labels
Labels can be defined to make it easier to refer to memory locations. Labels should consist of a valid identifier followed by a colon. A valid identifier starts with a character or underscore and may contain only characters, underscores or numbers.
For example, a label can be used to loop:
ldx #$20
label:
dex
bne label
2
3
4
You can also add braces after the label to aid formatting:
ldx #$20
label: {
dex
bne label
}
2
3
4
5
# Variables and constants
You can define variables and constants using the .var
and .const
directives respectively. They can then be used in expressions.
For example:
.const BORDER_COLOUR = $d020
lda #7
sta BORDER_COLOUR
2
3
4
Variables may be redefined, constants may not.
# Symbol scopes
Labels, variables and constants are symbols. Symbols are defined in scopes. A scope is defined by a block (starting with {
and ending with }
). As long as symbols reside in different scopes they can have duplicate names. You can use the super
keyword to access symbols in outer scopes.
Sounds complicated perhaps, so here's an example:
label: {
label: {
jmp label
jmp super.label
}
}
2
3
4
5
6
The first jmp
will jump to the innermost label. The second jmp
will jump to the outermost label.
# Automatic symbols
Some symbols are generated for you automatically.
# -
and +
You can use -
or +
to refer to the start or the end of a block.
For instance, the following code loops 64 times:
ldx #$40
{
dex
bne -
}
2
3
4
5
# Loops
Loops may be generated using the .loop
directive:
.loop 5 {
lda #$00
sta $0400 + index
}
2
3
4
The index
symbol contains the current loop index (zero-based).
# Expressions
Simple calculations may be performed.
This program:
lda #5 + 10
Is equal to:
lda #15
# Operators
Supported operators are:
*
Multiplication/
Division%
Modulo<<
Shift left>>
Shift right^
Exclusive or (XOR)+
Addition-
Subtraction
You can also use parentheses, for example:
lda #(3 + 4) * 5
# Equality tests
Equality tests may also be performed. They will evaluate to 0
when false and 1
when true:
==
Equality!=
Inequality>
Greater than>=
Greater than or equal<
Less than<=
Less than or equal&&
And||
Or
# Word operators
Additionally, the high or low byte of 16-bit variables may be accessed using the <
and >
modifiers, e.g.:
.const ADDRESS = $1234
lda #<ADDRESS // a will now contain '$34'
ldx #>ADDRESS // x will now contain '$12'
2
3
# Modifiers
There are two ways to modify a factor in an expression.
- Prefix with
!
to convert0
into1
and any positive number into0
- Prefix with
-
to negate the value
# Built-in functions
Currently the only built-in function is defined
which evaluates to 1
if a variable or constant is defined and to 0
otherwise.
.const ADDRESS = $1234
lda defined(ADDRESS) // a will now contain '1'
lda !defined(ADDRESS) // a will now contain '0'
2
3
# String handling
It is possible to use strings in expressions and in variable definitions, e.g.:
.const MY_HELLO = "hello"
.const MY_WORLD = " world"
.const GREETING = MY_HELLO + MY_WORLD
2
3
It is also possible to do string interpolation using curly braces, e.g.:
.const MY_HELLO = "hello"
.const GREETING = "{MY_HELLO} world" // <-- results in "hello world"
2
# Data definition
You may include data inline like so:
.byte 1, 2, 3
Supported data types are .byte
, .word
and .dword
.
# Text definition
You may include text inline like so:
.text "hello"
The default encoding is ascii
. You may also use the encodings petscii
or petscreen
. The latter emits Commodore-compatible screen codes. For example:
.text petscreen "abc" // This emits $01, $02, $03
# Including from files
It is also possible to include data from files, like so:
.file "foo.bin"
The file is located relative to the source file that contains the .file
directive.
# Comments
Lines may end with a C++-style //
comment, like so:
nop // hello, I am a comment
C-style comment blocks are also supported:
/*
hello there!
*/
nop
2
3
4
C-style comments may also be nested.
# Conditional assembly
It is possible to conditionally assemble chunks of code by wrapping them in an .if
block:
.const FOO = 1
.if defined(FOO) {
nop
} else {
brk
}
2
3
4
5
6
7
The else
clause is optional.
# Program counter
During assembly it is possible to change the current program counter (i.e. the location where instructions are assembled to).
# Setting
You can set the program counter with the *
directive, like so:
* = $0800
# Aligning
You can move the program counter forward to make it align on a certain number of bytes, using the .align
directive:
.align 256
nop // This will always be assembled to $xx00
2