Due: 10:30 pm Wednesday 8 April 2026
Summary: You will develop a suite of MIPS procedures including recursion with the stack, tail recursion, arrays, and strings.
Collaboration: Complete this assignment individually. You may ask the instructor for assistance if anything is unclear, but may not collaborate with others for this assignment.
Submitting: Submit your completed
mips-procedures.asm and references.txt to
Gradescope. Be sure to follow the submission guidelines and use
precisely these file names.
You will continue practicing encapsulating sequences of instructions into callable, reusable sequences (procedures) that use the stack and respect conventions. You will also begin to use MIPS to operate on arrays and strings.
To easily simulate MIPS code in software, we will once again use the MIPS Assembly and Runtime Simulator MARS.
To launch MARS on the MathLAN, you can type
java -jar /home/weinman/shared/Mars4_5.jar
In addition, you may also copy the JAR (Java ARchive) file from that location to your own computer and run it there, using a similar invocation of Java.
Download the starter file mips-procedures.asm
Open the file in MARS.
To assemble your code, click “Assemble” under the Run menu (or the Screwdriver and Wrench icon in the toolbar).
You can step through your code line by line with the F7 key (or
the green and white arrow button with a “1”), but this is tedious. A
better way is to switch to the “Execute” pane, which shows your
assembled code (along with the actual instructions, the machine version,
and its address in the virtual machine). The left-most column allows you
to set any breakpoints at which you may want to investigate behavior. If
you just want to run the whole test program, the nop at the
end of main is good point at which to stop. Other points may arise as
you wish to diagnose certain behaviors.
Before we proceed, we will unpack a few additional bits of syntax and semantics it is helpful to understand.
The previous assignment introduced the notion directives as special
indications to the MIPS assembler. This assignment re-introduces a few
additional directives to support arrays, which must appear in the data
section (as indicated by the .data directive) of the
program.
.wordWithin the data section, followed by a label, reserves and initializes word-aligned, comma-separated blocks of data. For example, if you declared the following global variable in C,
int [] sloane211 = {4, 3, 5, 6, 9, 13, 20, 31, 49};then you might end up with the following MIPS assembly line
sloane211: .word 4, 3, 5, 6, 9, 13, 20, 31, 49.bytelb (load
byte) or lbu (load byte unsigned), depending on the
contextual need.
.asciizWithin a data section, followed by a label, reserves space for and initializes a null-terminated ASCII string of bytes. For example,
message: .asciiz "Hello, world!"| Byte | 3 | 2 | 1 | 0 | 3 | 2 | 1 | 0 | 3 | 2 | 1 | 0 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Value | l |
l |
e |
H |
w |
|
, |
o |
d |
l |
r |
o |
□ |
□ |
␀ |
! |
To place the address of a label into a register (i.e., for issuing a
load or store command), you must use the la (load address)
instruction. For example,
la $t0, sloane211 # Set $t0 to &sloane211[0] (address of the array's start)
lw $t1,0($t0) # Dereference the pointer, i.e., put sloane211[0] into $t1Certain privileged or specialized operations on microprocessors are often accomplished by system calls. Toward the end of the term, we’ll revisit how those are implemented in hardware, but all you need to understand for now is that when a system call is invoked, control of the processor is transferred to a special program that enjoys certain elevated hardware permissions. When that special code concludes, control typically returns to your program just after the system call.
System calls in MIPS work by placing a specific integer (indicating
the particular function) into the register $v0 and then
invoking the syscall instruction.
For example, to terminate your program’s execution, you would invoke
system call 10 as follows:
li $v0, 10 # Place the "exit" system call code in the appropriate register
syscall # Invoke the system call
# No further instructions are reached or executedSome system calls take arguments (in addition to specifying which
specific system call is desired). To print a null-terminated string to
the output terminal, one gives the address of the first byte of the
string in argument register $a0. For example, if the string
message were declared as above, you could print it in MIPS
as follows anywhere in a text (program) region.
la $a0, message # Load the address of message into the argument register
li $v0, 4 # "Print string" system call
syscall
# Instructions here would continue executing after the printing has completedFor the curious, the MARS documentation gives the complete list of MIPS and MARS-specific system calls available in the MARS simulator.
Note that the MARS simulator does not enable simulation of the branch/jump delay by default. Do not enable it; branch delays will not be activated during grading for correctness, so your program would likely fail many tests, leading to a poor grade.
The only pseudoinstructions you may use for completing the problems in this assignment are:
movenoplibeqz and bnezIn particular, you may NOT use ble,
blt, etc.
Your procedures must follow all MIPS calling conventions (see Figures 2.11, 2.12, and 2.14).
Your grade on each procedure will depend on its correctness. A test suite will be used to validate your problem’s correctness; the grade for each problem will be determined by how many tests each problem passes.
In addition to being graded on correctness, your code will be evaluated on its clarity, organization, and overall efficiency with respect to the number of instructions required to complete any given task. In part that means
Do not modify the existing .globl directives; the
labels for your procedures are required to be global for them to be
discoverable by the autograder. Moreover, do not add your
main to the list of global labels; it will conflict with
the autograder’s main.
Translate the following C procedure into MIPS to calculate the remainder of two 32-bit integers. We can consider them signed, but they should be positive.
// Repeatedly subtract (that's division after all) until we find the remainder
int
remainder (int a, int b) {
while (a>=b)
a = a-b;
return a;
} // remainderYou may discover that MIPS has a rem pseudoinstruction
to do just this, but for now we’re practicing the translation process.
(You can certainly use rem in your testing, but your
procedure should not use it or the div instruction upon
which it is built.)
Euclid’s algorithm for finding the greatest common divisor between two numbers can be elegantly expressed recursively as follows:
int
gcd (int m, int n) {
if (n==0)
return m;
else
return gcd(n, remainder(m,n));
} // gcdTranslate this recursive function into MIPS “as is”, being sure
to follow all the MIPS calling conventions. That is, you should use the
stack and jal instructions to accomplish the recursion.
Your MIPS gcd must call your remainder
procedure, rather than use the rem
pseudoinstruction.
Create another version of the function in MIPS that uses tail
recursion to accomplish the iteration (i.e., the repeated call to the
same function). Call this version gcdtail. Although it is
still considered tail recursion when you (necessarily) use the stack for
a call to a helper procedure like remainder, we instead
will simplify your task here by allowing you to use the rem
pseudoinstruction, which has the following syntax
rem rd, rs, rtand is roughly equivalent to the C expression
rd = rs % rt. Thus your code should be a tail recursive
adaptation where the call remainder(m,n) is replaced by the
simpler expression C expression m % n.
Write a procedure in MIPS called count that has the
following signature and returns the frequency of the value
k in the array of n items starting at
p.
int count (int * p, int n, int k)In addition to being correct, your procedure should use pointer arithmetic to be as efficient as possible (running in as few instructions as possible).
Write a procedure reverse in MIPS that takes a pointer
to a null-terminated string and reverses that string “in place.” (That
is, no other memory addresses should be used). The C signature would
be
void reverse (char* s)Note: Within your procedure you will need to determine the length of the given string; there is no need to write a separate helper procedure formally.
Copyright © 2019–2025 Jerod Weinman
This work is
licensed under a Creative Commons Attribution NonCommercial ShareAlike
4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San
Francisco, California, 94105, USA.