ObjAsm has good support for conditional assembly. It’s not quite as powerful as BASIC, but it’s a lot better than is available with a ‘plain’ assembler like GNU gas which typically relies on the C preprocessor for implementing conditional assembly and macro functionality.
Let’s consider the following simple example, which assembles a simple function which copies a block of memory using either byte, halfword, or word transfers. First, the BASIC version:
[ OPT pass ; In: ; R0 -> dest ; R1 -> src ; R2 = length (bytes) .memcpy CMP R2,#0 MOVEQ PC,LR .memcpy_loop ] IF size=1 THEN [ OPT pass LDRB R3,[R1],#1 STRB R3,[R0],#1 SUBS R2,R2,#1 ] ELSE IF size=2 then [ OPT pass LDRH R3,[R1],#2 STRH R3,[R0],#2 SUBS R2,R2,#2 ] ELSE [ OPT pass LDR R3,[R1],#4 STR R3,[R0],#4 SUBS R2,R2,#4 ] ENDIF ENDIF [ OPT pass BNE memcpy_loop MOV PC,LR ]
For ObjAsm, the code would instead look like this:
; In: ; R0 -> dest ; R1 -> src ; R2 = length (bytes) memcpy CMP R2,#0 MOVEQ PC,LR memcpy_loop [ size = 1 LDRB R3,[R1],#1 STRB R3,[R0],#1 SUBS R2,R2,#1 | [ size = 2 LDRH R3,[R1],#2 STRH R3,[R0],#2 SUBS R2,R2,#2 | LDR R3,[R1],#4 STR R3,[R0],#4 SUBS R2,R2,#4 ] ] BNE memcpy_loop MOV PC,LR
This highlights the three main conditional assembly directives:
[
marks the start of a conditional block, and must be followed by an expression. It is functionally equivalent to the IF ... THEN
statement in BASIC; if the expression evaluates to true then the block will be assembled. If it is false, it will be skipped.|
is equivalent to ELSE, allowing you to define a block that will be assembled if the expression evaluated to false. As with BASIC, an ‘else’ clause is optional.]
marks the end of the conditional block.There’s also a fourth directive available, ELIF
, which is equivalent to a single-line ELSE IF
in BASIC: It removes the need for an extra ]
/ ENDIF
in the block. E.g.:
[ size = 1 LDRB R3,[R1],#1 STRB R3,[R0],#1 SUBS R2,R2,#1 ELIF size = 2 LDRH R3,[R1],#2 STRH R3,[R0],#2 SUBS R2,R2,#2 | LDR R3,[R1],#4 STR R3,[R0],#4 SUBS R2,R2,#4 ]
Note that ObjAsm also accepts IF, ELSE and ENDIF in place of [
, |
and ]
. However in practice the single-character versions are the most widely used. Likewise, it’s conventional (at least in the RISC OS sources) to indent any nested conditional assembly directives in proportion to their nesting level.