NOTE: As of Version 5, all code blocks are wrapped in { and } braces. To revert to previous behavior, you must pass the --legacy-blocks option in the command line.
Certain directives permit the programmer to assemble code conditionally. The most basic conditional assembly statement, where an expression is tested to be true or false, is:
.if * % 256 != 0 // if program counter not page aligned
{
nop // output 2 nops
nop
}
Alternate conditions are possible where previous conditions are not met.
.if * % 256 == 0
{
jmp tightloop
}
.else
{
nop
nop
}
.if BACKGROUND == 1
{
lda #1
}
.elseif BACKGROUND == 2
{
lda #2
}
.else
{
lda #0
}
Other conditions can check if a symbol is defined.
.ifdef DEBUGMODE
{
brk
}
.ifndef RELEASE // RELEASE not defined
{
rts
}
.else versions exist for each of these conditional directives.
.ifdef CBM
{
chrout = $ffd2
}
.elseifdef APPLEII
{
chrout = $fded
}
The programmer can direct the assembler to jump to other parts of source. The .goto directive will commence assembly at the specified label.
.ifdef CBM
{
.goto commodore
}
commodore
jsr $ffd2
Switch statements allow more compact forms of conditional assembly. For each .switch directive one more more .case labels follows where the case condition is tested for equality with the .switch argument.
.switch CPU_NAME
{
.case "65816"
jsr long_address
.break
.case "45GS02"
.case "65CE02"
.case "m65"
jmp long_address
.break
.default
jmp long_address
}
afterswitch nop
In the above example the .break directives cause assembly to resume to the afterswitch label. If ommitted assembly would fall through to the next case.
Assembly repetitions are possible using the .repeat directive, where a block of code will be assembled a specified number of times.
ldx #$00
.repeat 3
{
inx
}
rts
/* will assemble as:
ldx #$00
inx
inx
inx
rts
*/
The .do and .while directives allow repeat assembly conditionally.
num := 0
.while num < 256
{
ld b,num
ld (hl),b
inc hl
num += 1
}
.do and .while are nearly identical, except that for .do the condition occurs after the first iteration of the block assembly, so the code block process at least once.
* = 0
.do
{
nop
} .while * < 0 // emits a nop
.while * < 1
{
nop
} // no code generated
If using --legacy-blocks option, the .do expects a .whiletrue condition expression.
For loops are a common feature in higher level languages. 6502.Net provides two variants. The .for directive is C-like, where a variable is initialized or defined, a condition is tested, and then one or more one or more iterations are evaluated.
.for i = 0, i < 5, i += 1
{
nop
} // five nops
The initial variable assignment and condition are optional. An alternative way to perform the above is:
.let i = 0
.for ,,i += 1
{
.if i == 5
{
.break
}
nop
}
The .foreach takes a more modern approach to the .for loop, where loop assembly occurs during the iteration of a string or collection.
high_scores = [10000,5000,3000,2000,1000]
.foreach score, high_scores
{
.long score
}
// The iteration in the dictionary is a key/value pair
prizes = {.cherry: 100, .strawberry: 200, .peach: 300}
.foreach prize, prizes
{
.string prize.key
.long prize.value
}
Any variables declared in the .for and .foreach directives are local in scope to the directive block unless previously declared.
The .break and .continue directive can appear within the code block of any loop directive. As expected, .continue will return processing to the beginning of the block while .break takes the assembler out of the loop altogether.
.for addr=0x100,,addr += 1
{
.if addr >= 0x200
{
.break // no more output at page change
}
.byte $11
}
.for i = 0, i < 5, i += 1
{
.if i % 2 == 0
{
.continue // do not process on even counts
}
.byte i
}
Because labels might change address values between passes, and 6502.Net is a multi-pass assembler, this can cause an issue if a label is declared inside a loop assembly block.
.while * < 5
{
start nop
}
The above code is technically "legal", but what happens is start defined at each loop, which is not valid.
The solution is to declare all labels before the block.
start
.while * < 5
{
nop
}
Alternatively, you can use an anonymous label if there is a a need to branch to a specific instruction inside the loop.
.repeat 5
{
ldx #0
- stx *+$100
bne -
}