Showing changes from revision #2 to #3:
Added | Removed | Changed
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.
Macros in ObjAsm are a very powerful and capable feature. They allow for extra layers of abstraction to be built ontop of the base instruction set, making complex or frequently-used constructs easier to deal with.
In BASIC, you can fake support for macros by using functions or procedures which contain assembler blocks. But ObjAsm’s native support for macros makes things much more elegant and convenient.
Macros are defined using the MACRO
and MEND
directives, e.g.:
MACRO $label UpperCase $reg, $wrk $label CMP $reg, #"a" RSBGES $wrk, $reg, #"z" CMPLT $reg, #&e0 RSBGES $wrk, $reg, #&f6 CMPLT $reg, #&f8 RSBGES $wrk, $reg, #&fe SUBGE $reg, $reg, #"a"-"A" MEND
Once defined, they can then be invoked directly as if they were an instruction:
strtoupper LDRB R1,[R0] CMP R1,#0 MOVEQ PC,LR UpperCase R1,R2 STRB R1,[R0],#1 B strtoupper
There are a few key things to take away from the above example:
MACRO
directive contains the macro nameThe macro body can contain conditional constructs, invocations of other macros, local labels (as discussed in part 1 of the guide), and pretty much anything else that can appear elsewhere in an ObjAsm source file.
Macros can also contain optional arguments. For example, the RISC OS sources contain a 6502-inspired DEC
macro which has an optional argument:
MACRO $label DEC $reg,$by [ "$by" = "" $label SUB $reg,$reg,#1 | $label SUB $reg,$reg,#$by ] MEND
In this case, the macro body contains a manual check for whether the argument is provided. But modern versions of ObjAsm also allow default values to be specified for arguments, so the above could be simplified to the following:
MACRO $label DEC $reg,$by=1 $label SUB $reg,$reg,#$by MEND
Optional / default arguments can appear anywhere in the argument list. For example, all of the macros provided so far have used $label
to allow them to be placed on the same line as a label definition, but specifying a label is not required.
Another useful feature of arguments is that you can have an argument which is a suffix on the macro name. Typically this is used to add condition code support to macros, e.g.:
MACRO $label DEC$cc $reg,$by=1 $label SUB$cc $reg,$reg,#$by MEND