0da1c5dcca
First commit of the 4.5 version (latest version available)
291 lines
13 KiB
HTML
291 lines
13 KiB
HTML
<html>
|
|
<title>Macros in MARS</title>
|
|
<body>
|
|
<center>
|
|
<h3>Writing and Using Macros</h3>
|
|
<h4><tt>.macro</tt>, <tt>.end_macro</tt>,<tt>.eqv</tt> and <tt>.include</tt> directives are new in MARS 4.3</h4>
|
|
</center>
|
|
<h3> Introduction to macros</h3>
|
|
<p>Patterson and Hennessy define a <b>macro</b> as <i>a pattern-matching and replacement facility
|
|
that provides a simple mechanism to name a frequently used sequence of instructions</i> [1].
|
|
This permits the programmer to specify the instruction sequence by invoking the macro. This requires
|
|
only one line of code for each use instead of repeatedly typing
|
|
in the instruction sequence each time. It follows the axiom "define once, use many times," which
|
|
not only reduces the chance for error but also facilitates program maintenance.</p>
|
|
|
|
<p>Macros are like procedures (subroutines) in this sense but operate differently than procedures.
|
|
Procedures in MIPS assembly language follow particular protocols for procedure definition, call and return.
|
|
Macros operate by substituting the macro body for each use at the time of assembly. This substitution
|
|
is called <i>macro expansion.</i>. They do not require the protocols and execution overhead of procedures.</p>
|
|
|
|
<p>As a simple example, you may want to terminate your program from a number of locations. If you are running
|
|
from the MARS IDE, you will use system call 10, <tt>exit</tt>. The instruction sequence is pretty easy</p>
|
|
<pre>
|
|
li $v0,10
|
|
syscall </pre>
|
|
but still tedious. You can define a macro, let's call it <tt>done</tt>, to represent this sequence
|
|
<pre>
|
|
.macro done
|
|
li $v0,10
|
|
syscall
|
|
.end_macro </pre>
|
|
then invoke it whenever you wish with the statement
|
|
<pre>
|
|
done</pre>
|
|
At assembly time, the assembler will replace each occurrence of the statement <tt>done</tt> with the two-statement
|
|
sequence
|
|
<pre>
|
|
li $v0,10
|
|
syscall </pre>
|
|
This is the macro expansion. The runtime simulator is unaware of macros or macro expansion.</p>
|
|
|
|
<p>If running MARS from the command line, perhaps you want to return a termination value. This can be done
|
|
with syscall 17, <tt>exit2</tt>, which takes the termination value as an argument. An equivalent macro,
|
|
let's call it <tt>terminate</tt> would be
|
|
<pre>
|
|
.macro terminate (%termination_value)
|
|
li $a0, %termination_value
|
|
li $v0, 17
|
|
syscall
|
|
.end_macro </pre>
|
|
This macro defines a <i>formal parameter</i> to represent the termination value. You would invoke it
|
|
with the statement
|
|
<pre>
|
|
terminate (1)</pre>
|
|
to terminate with value 1. Upon assembly,
|
|
the statement <tt>terminate (1)</tt> would be replaced by the three-statement sequence
|
|
<pre>
|
|
li $a0, 1
|
|
li $v0, 17
|
|
syscall </pre>
|
|
The <i>argument value</i>, 1, is substituted wherever the formal parameter <tt>%termination_value</tt> appears
|
|
in the macro body.
|
|
This is a textual substitution. Note that in this example the argument value must be an integer, not a
|
|
register name or a label, because the parameter is used as the second operand in the Load Immediate operation.</p>
|
|
|
|
<p>In MARS, a macro is similar to an extended (pseudo) instruction. They are distinguished in that the expansion of
|
|
extended instructions is supported by an internally-defined specification language and mechanism which can manipulate argument values.
|
|
The macro facility can only substitute argument values as given, and it uses a separate mechanism from extended instructions. </p>
|
|
|
|
<p>Additional examples and details follow.</p>
|
|
|
|
<h3> How to define macros </h3>
|
|
The first line begins with a <tt>.macro</tt> directive followed by an optional list of formal parameters.
|
|
Placing commas between parameters and parentheses around the list is optional.
|
|
<p>
|
|
Each formal parameter is an identifier that begins with a <tt>%</tt> character. For compatibility with
|
|
the SPIM preprocessor APP, it may alternatively begin with <tt>$</tt>.
|
|
</p>
|
|
<p>
|
|
The lines that follow define the body of the macro. Use the formal parameters as appropriate. The body
|
|
may contain data segments as well as text segments.
|
|
</p>
|
|
<p>The macro definition finishes with a <tt>.end_macro</tt> directive.
|
|
</p>
|
|
<p>See the Notes below for additional information.</p>
|
|
|
|
<h3> How to use macros</h3>
|
|
|
|
To invoke a macro, form a statement consisting of the macro name and then one token for each argument
|
|
to be substituted for its corresponding formal parameter by the assembler.
|
|
The argument list may optionally be surrounded by parentheses.
|
|
Arguments may be separated either by spaces or commas.
|
|
<p>
|
|
Macro expansion is a pre-processing task for assemblers.
|
|
</p>
|
|
<h3> Notes</h3>
|
|
<ul>
|
|
<li>
|
|
A macro definition must appear before its use. No forward references.
|
|
</li>
|
|
<li>
|
|
All macro definitions are local in each file and they cannot be global.
|
|
</li>
|
|
<li>
|
|
Nested macro definitions are not supported. No <tt>.macro</tt> directive should appear inside body of a macro definition.
|
|
</li>
|
|
<li>
|
|
A macro definition can contain a call to a previously-defined macro. Only backward references are allowed.
|
|
</li>
|
|
<li>
|
|
Labels placed in the body of a macro definition will not have same name after macro expansion.
|
|
During expansion, their name will be followed by "_M#" where # will be a unique number for each macro expansion.
|
|
</li>
|
|
<li>
|
|
Two macros with the same name but different number of parameters are considered different and both can be used.
|
|
</li>
|
|
<li>
|
|
A macro defined with the same name and same number of parameters as another macro defined before it will be ignored.
|
|
</li>
|
|
<li>
|
|
Each argument in a macro call can only be a single language element (token). For instance "4($t0)" cannot be an argument.
|
|
</li>
|
|
<li>
|
|
Macros are a part of the assembler, not the ISA. So the syntax might be different with other assemblers.
|
|
For compatibility with the SPIM simulator, <i>SPIM-style macros are also supported in MARS</i>. SPIM-style macros are same as MARS but formal parameters begin with "$" instead of "%".
|
|
</li>
|
|
</ul>
|
|
<h3> Examples</h3>
|
|
<ul>
|
|
<li>
|
|
Printing an integer (argument may be either an immediate value or register name):
|
|
<pre><tt> .macro print_int (%x)
|
|
li $v0, 1
|
|
add $a0, $zero, %x
|
|
syscall
|
|
.end_macro
|
|
|
|
print_int ($s0)
|
|
print_int (10)
|
|
</tt></pre>
|
|
</li>
|
|
<li>
|
|
Printing a string (macro will first assign a label to its parameter in data segment then print it):
|
|
<pre><tt> .macro print_str (%str)
|
|
.data
|
|
myLabel: .asciiz %str
|
|
.text
|
|
li $v0, 4
|
|
la $a0, myLabel
|
|
syscall
|
|
.end_macro
|
|
|
|
print_str ("test1") #"test1" will be labeled with name "myLabel_M0"
|
|
print_str ("test2") #"test2" will be labeled with name "myLabel_M1"
|
|
</tt></pre>
|
|
</li>
|
|
<li>
|
|
Implementing a simple for-loop:
|
|
<pre><tt> # generic looping mechanism
|
|
.macro for (%regIterator, %from, %to, %bodyMacroName)
|
|
add %regIterator, $zero, %from
|
|
Loop:
|
|
%bodyMacroName ()
|
|
add %regIterator, %regIterator, 1
|
|
ble %regIterator, %to, Loop
|
|
.end_macro
|
|
|
|
#print an integer
|
|
.macro body()
|
|
print_int $t0
|
|
print_str "\n"
|
|
.end_macro
|
|
|
|
#printing 1 to 10:
|
|
for ($t0, 1, 10, body)
|
|
</tt></pre>
|
|
The <tt>for</tt> macro has 4 parameters. <tt>%regIterator</tt> should be the name of a register which iterates from <tt>%from</tt> to <tt>%to</tt> and in each iteration <tt>%bodyMacroName</tt> will be expanded and run.
|
|
Arguments for
|
|
<tt>%from</tt> and <tt>%to</tt> can be either a register name or an immediate value, and <tt>%bodyMacroName</tt> should be name of a macro that has no parameters.
|
|
</li>
|
|
</ul>
|
|
<h3>Macro source line numbers</h3>
|
|
<p>For purpose of error messaging and Text Segment display, MARS attempts to display line numbers for both the definition and use of the pertinent
|
|
macro statement. If an error message shows the line number in the form "<tt>X->Y</tt>" (e.g. "<tt>20->4</tt>"), then <tt>X</tt> is the line number in the expansion
|
|
(use) where the error was detected and <tt>Y</tt> is the line number in the macro definition. In the Text Segment display
|
|
of source code, the macro definition
|
|
line number will be displayed within brackets, e.g. "<tt><4></tt>", at the point of expansion. Line numbers should correspond to the
|
|
numbers you would see in the text editor. </p>
|
|
|
|
<h3>The .eqv directive</h3>
|
|
<p>The <tt>.eqv</tt> directive (short for "equivalence") is also new in MARS 4.3. It is similar to <tt>#define</tt> in C or C++. It
|
|
is used to substitute an arbitrary string for an identifier. It is useful but much less powerful than macros.
|
|
It was developed independently of the macro facility.
|
|
</p>
|
|
<p>Using <tt>.eqv</tt>, you can specify simple substitutions that provide "define once, use many times" capability at assembly
|
|
pre-processing time. For example, once you define
|
|
<pre>
|
|
.eqv LIMIT 20
|
|
.eqv CTR $t2
|
|
.eqv CLEAR_CTR add CTR, $zero, 0</pre>
|
|
then you can refer to them in subsequent code:
|
|
<pre>
|
|
li $v0,1
|
|
CLEAR_CTR
|
|
loop: move $a0, CTR
|
|
syscall
|
|
add CTR, CTR, 1
|
|
blt CTR, LIMIT, loop
|
|
CLEAR_CTR</pre>
|
|
During assembly pre-processing, the <tt>.eqv</tt> substitutions will be applied. The resulting code is
|
|
<pre>
|
|
li $v0,1
|
|
add $t2, $zero, 0
|
|
loop: move $a0, $t2
|
|
syscall
|
|
add $t2, $t2, 1
|
|
blt $t2, 20, loop
|
|
add $t2, $zero, 0</pre>
|
|
which when run will display the values 0 through 19 on one line with no intervening spaces.
|
|
</p>
|
|
<p>Note that the substitution string is not limited to a single token. Like <tt>.macro</tt>, <tt>.eqv</tt> is local to the file
|
|
in which it is defined, and must be defined prior to use. Macro bodies can contain references to <tt>.eqv</tt> directives.
|
|
</p>
|
|
|
|
<h3>The .include directive</h3>
|
|
<p>The <tt>.include</tt> directive is also new in MARS 4.3. It has one operand, a quoted filename. When the
|
|
directive is carried out, the contents of the specified file are substituted for the directive. This occurs
|
|
during assembly preprocessing. It is like <tt>#include</tt> in C or C++.</p>
|
|
|
|
<p><tt>.include</tt> is designed to make macro and equivalence (.eqv directive) use
|
|
more convenient. Both macro definitions and equivalence definitions are <i>local</i>, which means they can be used only
|
|
in the same file where defined. Without <tt>.include</tt>, you would have to repeat their definitions in every
|
|
file where you want to use them. Besides being tedious, this is poor programming practice; remember
|
|
"define once, use many times." Now you can define macros and equivalences in a separate file, then include it
|
|
in any file where you want to use them.</p>
|
|
|
|
<p>The <tt>.include</tt> preprocessor will detect and flag any circular includes (file that includes itself, directly or
|
|
indirectly).</pp>
|
|
|
|
<p>The use of <tt>.include</tt> presents some challenges for error messaging and for source code numbering in the Text
|
|
Segment display. If a file being included has any assembly errors, the filename and line number in the error
|
|
message should refer to the file being included, not the file it was substituted into. Similarly, the line number
|
|
given in the Text Segment source code display refers to the line in the file being included. Thus the displayed line numbers do not
|
|
monotonically increase - this is also the case when using the "assemble all" setting. Line numbers should correspond to the numbers
|
|
you would see in the text editor.</p>
|
|
|
|
<p>As a simple example, you could define the <tt>done</tt> macro (and others) in a separate file
|
|
then include it wherever you need it. Suppose "macros.asm" contains the following:
|
|
<pre>
|
|
.macro done
|
|
li $v0,10
|
|
syscall
|
|
.end_macro </pre>
|
|
|
|
You could then include it in a different source file something like this:
|
|
<pre>
|
|
.include "macros.asm"
|
|
.data
|
|
value: .word 13
|
|
.text
|
|
li $v0, 1
|
|
lw $a0, value
|
|
syscall
|
|
done </pre>
|
|
<p>During assembly preprocessing, this would be expanded to
|
|
<pre>
|
|
.macro done
|
|
li $v0,10
|
|
syscall
|
|
.end_macro
|
|
.data
|
|
value: .word 13
|
|
.text
|
|
li $v0, 1
|
|
lw $a0, value
|
|
syscall
|
|
done </pre>
|
|
<p>The assembler will then perform the appropriate macro expansion.
|
|
|
|
|
|
|
|
<h3>Acknowledgements</h3>
|
|
<p>The MARS macro facility was developed in 2012 by Mohammad Hossein Sekhavat, sekhavat17@gmail.com, while an engineering student at
|
|
Sharif University in Tehran. MARS creators Pete and Ken are incredibly grateful for his contribution! Pete developed <tt>.eqv</tt>
|
|
and <tt>.include</tt> at about the same time.</p>
|
|
|
|
<h3>References</h3>
|
|
<p>[1] <i>Computer Organization and Design: The Hardware/Software Interface, Fourth Edition,</i> Patterson and Hennessy,
|
|
Morgan Kauffman Publishers, 2009.</p>
|
|
</body>
|
|
</html> |