Assembler/Disassembler for the Dreamcast VMU
This project is maintained by wtetzner
Macros are a way to introduce custom abstractions into an assembly program. They are invoked using syntax that looks just like an instruction, but the assembler automatically expands them into actual instructions before assembling the final binary.
The %macro
keyword is used to define a new macro. It’s followed by
the name of the macro, as well as a comma-separated list of argument
names, all of which start with %
.
%macro my_macro %arg1, %arg2, %arg3
The following lines make up the body of the macro, which can refer to the arguments.
ld %arg1
add %arg2
The body can also use hygienic labels, which end with a %
.
my_label%:
Each time the macro is invoked, a hygienic label gets a completely unique name, so it won’t conflict with other similarly named labels in the rest of the program.
Finally, the macro ends with %end
.
Here’s an example of a macro (courtesy of Kresna Susila).
It adds an 8-bit number to
acc
, but if the addition overflows, acc
is set to the maximum
value ($ff
).
%macro Safe_8bit_Add %op
; Adds an 8bit number to acc and prevents overflow by maxing acc
; if detected
add %op
bn psw, 7, .no_carry%
mov #$ff, acc
.no_carry%
%end
The usage of a macro looks identical to an instruction. The name of the macro is followed by a comma separated list of arguments.
Safe_8bit_Add my_var
When assembling this code, the call to Safe_8bit_Add
will be
expanded into the body of the macro, with the argument replaced.
To see what a macro invocation looks like, the expand
subcommand can
be used. It will expand all macros and print the resulting assembly.
% waterbear expand example.s
my_var = $48
add my_var
bn psw, 7, .no_carry_541957e1bc47460b88675e597f900408
mov #$FF, acc
.no_carry_541957e1bc47460b88675e597f900408:
You can see that %op
was replaced with my_var
, and .no_carry%
was expanded into .no_carry_541957e1bc47460b88675e597f900408
, which
is a unique label name.
To further illustrate the unique label names, lets look at an example
with two invocations of Safe_8bit_Add
.
Safe_8bit_Add my_var
Safe_8bit_Add my_var2
This expands to:
% waterbear expand example.s
my_var = $48
my_var2 = $49
add my_var
bn psw, 7, .no_carry_f909e567e61249f6853f0c939d50982f
mov #$FF, acc
.no_carry_f909e567e61249f6853f0c939d50982f:
add my_var2
bn psw, 7, .no_carry_10a78ffefae24a828adf29904d7bae8e
mov #$FF, acc
.no_carry_10a78ffefae24a828adf29904d7bae8e:
You can see that the .no_carry
in the first invocation expands to
.no_carry_f909e567e61249f6853f0c939d50982f
, and the .no_carry
in
the second invocation expands to
.no_carry_10a78ffefae24a828adf29904d7bae8e
. This way, you don’t need
to worry about macro invocations conflicting with each other.