Viitor_cc65/usr/share/doc/cc65/webdoc/ca65-11.html
kueller 223cc6685e Neue Version V963
git-svn-id: svn://svn.compuextreme.de/Viitor/V963/Viitor_cc65@5933 504e572c-2e33-0410-9681-be2bf7408885
2011-01-03 10:48:06 +00:00

490 lines
15 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.20">
<TITLE>ca65 Users Guide: Macros</TITLE>
<LINK HREF="ca65-12.html" REL=next>
<LINK HREF="ca65-10.html" REL=previous>
<LINK HREF="ca65.html#toc11" REL=contents>
</HEAD>
<BODY>
<A HREF="ca65-12.html">Next</A>
<A HREF="ca65-10.html">Previous</A>
<A HREF="ca65.html#toc11">Contents</A>
<HR>
<H2><A NAME="macros"></A> <A NAME="s11">11.</A> <A HREF="ca65.html#toc11">Macros</A></H2>
<H2><A NAME="ss11.1">11.1</A> <A HREF="ca65.html#toc11.1">Introduction</A>
</H2>
<P>Macros may be thought of as "parametrized super instructions". Macros are
sequences of tokens that have a name. If that name is used in the source
file, the macro is "expanded", that is, it is replaced by the tokens that
were specified when the macro was defined.</P>
<H2><A NAME="ss11.2">11.2</A> <A HREF="ca65.html#toc11.2">Macros without parameters</A>
</H2>
<P>In it's simplest form, a macro does not have parameters. Here's an
example:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro asr ; Arithmetic shift right
cmp #$80 ; Put bit 7 into carry
ror ; Rotate right with carry
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>The macro above consists of two real instructions, that are inserted into
the code, whenever the macro is expanded. Macro expansion is simply done
by using the name, like this:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
lda $2010
asr
sta $2010
</PRE>
</CODE></BLOCKQUOTE>
</P>
<H2><A NAME="ss11.3">11.3</A> <A HREF="ca65.html#toc11.3">Parametrized macros</A>
</H2>
<P>When using macro parameters, macros can be even more useful:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro inc16 addr
clc
lda addr
adc #$01
sta addr
lda addr+1
adc #$00
sta addr+1
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>When calling the macro, you may give a parameter, and each occurrence of
the name "addr" in the macro definition will be replaced by the given
parameter. So</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
inc16 $1000
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>will be expanded to</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
clc
lda $1000
adc #$01
sta $1000
lda $1000+1
adc #$00
sta $1000+1
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>A macro may have more than one parameter, in this case, the parameters
are separated by commas. You are free to give less parameters than the
macro actually takes in the definition. You may also leave intermediate
parameters empty. Empty parameters are replaced by empty space (that is,
they are removed when the macro is expanded). If you have a look at our
macro definition above, you will see, that replacing the "addr" parameter
by nothing will lead to wrong code in most lines. To help you, writing
macros with a variable parameter list, there are some control commands:</P>
<P><CODE>
<A HREF="ca65-10.html#.IFBLANK">.IFBLANK</A></CODE> tests the rest of the line and
returns true, if there are any tokens on the remainder of the line. Since
empty parameters are replaced by nothing, this may be used to test if a given
parameter is empty. <CODE>
<A HREF="ca65-10.html#.IFNBLANK">.IFNBLANK</A></CODE> tests the
opposite.</P>
<P>Look at this example:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro ldaxy a, x, y
.ifnblank a
lda #a
.endif
.ifnblank x
ldx #x
.endif
.ifnblank y
ldy #y
.endif
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>This macro may be called as follows:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
ldaxy 1, 2, 3 ; Load all three registers
ldaxy 1, , 3 ; Load only a and y
ldaxy , , 3 ; Load y only
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>There's another helper command for determining, which macro parameters are
valid: <CODE>
<A HREF="ca65-8.html#.PARAMCOUNT">.PARAMCOUNT</A></CODE> This command is
replaced by the parameter count given, <EM>including</EM> intermediate empty macro
parameters:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
ldaxy 1 ; .PARAMCOUNT = 1
ldaxy 1,,3 ; .PARAMCOUNT = 3
ldaxy 1,2 ; .PARAMCOUNT = 2
ldaxy 1, ; .PARAMCOUNT = 2
ldaxy 1,2,3 ; .PARAMCOUNT = 3
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Macro parameters may optionally be enclosed into curly braces. This allows the
inclusion of tokens that would otherwise terminate the parameter (the comma in
case of a macro parameter).</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro foo arg1, arg2
...
.endmacro
foo ($00,x) ; Two parameters passed
foo {($00,x)} ; One parameter passed
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>In the first case, the macro is called with two parameters: '<CODE>($00</CODE>'
and 'x)'. The comma is not passed to the macro, since it is part of the
calling sequence, not the parameters.</P>
<P>In the second case, '($00,x)' is passed to the macro, this time
including the comma.</P>
<H2><A NAME="ss11.4">11.4</A> <A HREF="ca65.html#toc11.4">Detecting parameter types</A>
</H2>
<P>Sometimes it is nice to write a macro that acts differently depending on the
type of the argument supplied. An example would be a macro that loads a 16 bit
value from either an immediate operand, or from memory. The <CODE>
<A HREF="ca65-9.html#.MATCH">.MATCH</A></CODE> and <CODE>
<A HREF="ca65-9.html#.XMATCH">.XMATCH</A></CODE>
functions will allow you to do exactly this:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro ldax arg
.if (.match (.left (1, {arg}), #))
; immediate mode
lda #&lt;(.right (.tcount ({arg})-1, {arg}))
ldx #>(.right (.tcount ({arg})-1, {arg}))
.else
; assume absolute or zero page
lda arg
ldx 1+(arg)
.endif
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Using the <CODE>
<A HREF="ca65-9.html#.MATCH">.MATCH</A></CODE> function, the macro is able to
check if its argument begins with a hash mark. If so, two immediate loads are
emitted, Otherwise a load from an absolute zero page memory location is
assumed. Please note how the curly braces are used to enclose parameters to
pseudo functions handling token lists. This is necessary, because the token
lists may include commas or parens, which would be treated by the assembler
as end-of-list.</P>
<P>The macro can be used as</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
foo: .word $5678
...
ldax #$1234 ; X=$12, A=$34
...
ldax foo ; X=$56, A=$78
</PRE>
</CODE></BLOCKQUOTE>
</P>
<H2><A NAME="ss11.5">11.5</A> <A HREF="ca65.html#toc11.5">Recursive macros</A>
</H2>
<P>Macros may be used recursively:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro push r1, r2, r3
lda r1
pha
.if .paramcount > 1
push r2, r3
.endif
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>There's also a special macro to help writing recursive macros: <CODE>
<A HREF="ca65-10.html#.EXITMACRO">.EXITMACRO</A></CODE> This command will stop macro expansion
immediately:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro push r1, r2, r3, r4, r5, r6, r7
.ifblank r1
; First parameter is empty
.exitmacro
.else
lda r1
pha
.endif
push r2, r3, r4, r5, r6, r7
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>When expanding this macro, the expansion will push all given parameters
until an empty one is encountered. The macro may be called like this:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
push $20, $21, $32 ; Push 3 ZP locations
push $21 ; Push one ZP location
</PRE>
</CODE></BLOCKQUOTE>
</P>
<H2><A NAME="ss11.6">11.6</A> <A HREF="ca65.html#toc11.6">Local symbols inside macros</A>
</H2>
<P>Now, with recursive macros, <CODE>
<A HREF="ca65-10.html#.IFBLANK">.IFBLANK</A></CODE> and
<CODE>
<A HREF="ca65-8.html#.PARAMCOUNT">.PARAMCOUNT</A></CODE>, what else do you need?
Have a look at the inc16 macro above. Here is it again:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro inc16 addr
clc
lda addr
adc #$01
sta addr
lda addr+1
adc #$00
sta addr+1
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>If you have a closer look at the code, you will notice, that it could be
written more efficiently, like this:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro inc16 addr
inc addr
bne Skip
inc addr+1
Skip:
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>But imagine what happens, if you use this macro twice? Since the label
"Skip" has the same name both times, you get a "duplicate symbol" error.
Without a way to circumvent this problem, macros are not as useful, as
they could be. One solution is, to start a new lexical block inside the
macro:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro inc16 addr
.proc
inc addr
bne Skip
inc addr+1
Skip:
.endproc
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Now the label is local to the block and not visible outside. However,
sometimes you want a label inside the macro to be visible outside. To make
that possible, there's a new command that's only usable inside a macro
definition: <CODE>
<A HREF="ca65-10.html#.LOCAL">.LOCAL</A></CODE>. <CODE>.LOCAL</CODE> declares one
or more symbols as local to the macro expansion. The names of local variables
are replaced by a unique name in each separate macro expansion. So we could
also solve the problem above by using <CODE>.LOCAL</CODE>:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro inc16 addr
.local Skip ; Make Skip a local symbol
clc
lda addr
adc #$01
sta addr
bcc Skip
inc addr+1
Skip: ; Not visible outside
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<H2><A NAME="ss11.7">11.7</A> <A HREF="ca65.html#toc11.7">C style macros</A>
</H2>
<P>Starting with version 2.5 of the assembler, there is a second macro type
available: C style macros using the <CODE>.DEFINE</CODE> directive. These macros are
similar to the classic macro type described above, but behaviour is sometimes
different:</P>
<P>
<UL>
<LI> Macros defined with <CODE>
<A HREF="ca65-10.html#.DEFINE">.DEFINE</A></CODE> may not
span more than a line. You may use line continuation (see <CODE>
<A HREF="ca65-10.html#.LINECONT">.LINECONT</A></CODE>) to spread the definition over
more than one line for increased readability, but the macro itself
may not contain an end-of-line token.
</LI>
<LI> Macros defined with <CODE>
<A HREF="ca65-10.html#.DEFINE">.DEFINE</A></CODE> share
the name space with classic macros, but they are detected and replaced
at the scanner level. While classic macros may be used in every place,
where a mnemonic or other directive is allowed, <CODE>
<A HREF="ca65-10.html#.DEFINE">.DEFINE</A></CODE> style macros are allowed anywhere in a line. So
they are more versatile in some situations.
</LI>
<LI> <CODE>
<A HREF="ca65-10.html#.DEFINE">.DEFINE</A></CODE> style macros may take
parameters. While classic macros may have empty parameters, this is
not true for <CODE>
<A HREF="ca65-10.html#.DEFINE">.DEFINE</A></CODE> style macros.
For this macro type, the number of actual parameters must match
exactly the number of formal parameters.
To make this possible, formal parameters are enclosed in braces when
defining the macro. If there are no parameters, the empty braces may
be omitted.
</LI>
<LI> Since <CODE>
<A HREF="ca65-10.html#.DEFINE">.DEFINE</A></CODE> style macros may not
contain end-of-line tokens, there are things that cannot be done. They
may not contain several processor instructions for example. So, while
some things may be done with both macro types, each type has special
usages. The types complement each other.
</LI>
</UL>
</P>
<P>Let's look at a few examples to make the advantages and disadvantages
clear.</P>
<P>To emulate assemblers that use "<CODE>EQU</CODE>" instead of "<CODE>=</CODE>" you may use the
following <CODE>.DEFINE</CODE>:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.define EQU =
foo EQU $1234 ; This is accepted now
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>You may use the directive to define string constants used elsewhere:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
; Define the version number
.define VERSION "12.3a"
; ... and use it
.asciiz VERSION
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Macros with parameters may also be useful:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.define DEBUG(message) .out message
DEBUG "Assembling include file #3"
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Note that, while formal parameters have to be placed in braces, this is
not true for the actual parameters. Beware: Since the assembler cannot
detect the end of one parameter, only the first token is used. If you
don't like that, use classic macros instead:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
.macro message
.out message
.endmacro
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>(This is an example where a problem can be solved with both macro types).</P>
<H2><A NAME="ss11.8">11.8</A> <A HREF="ca65.html#toc11.8">Characters in macros</A>
</H2>
<P>When using the
<A HREF="ca65-2.html#option-t">-t</A> option, characters are translated
into the target character set of the specific machine. However, this happens
as late as possible. This means that strings are translated if they are part
of a <CODE>
<A HREF="ca65-10.html#.BYTE">.BYTE</A></CODE> or <CODE>
<A HREF="ca65-10.html#.ASCIIZ">.ASCIIZ</A></CODE> command. Characters are translated as soon as they are
used as part of an expression.</P>
<P>This behaviour is very intuitive outside of macros but may be confusing when
doing more complex macros. If you compare characters against numeric values,
be sure to take the translation into account.</P>
<HR>
<A HREF="ca65-12.html">Next</A>
<A HREF="ca65-10.html">Previous</A>
<A HREF="ca65.html#toc11">Contents</A>
</BODY>
</HTML>