Due: 10:30 pm Sunday 13 March 2022
Summary: You will develop a suite of MIPS procedures including conditionals and loops.
Collaboration: Complete this assignment individually. You may ask the mentors or instructor for assistance if anything is unclear, but may not collaborate with others for this assignment.
Submitting: Submit your completed mips-basics.asm
and references.txt
to Gradescope. Be sure to follow the submission guidelines and use precisely these file names.
To easily simulate MIPS code in software, separately from the PIC32 hardware, we will use the MIPS Assembly and Runtime Simulator MARS. We won’t make it beep and blink, but it will be good enough for us to verify that you can think structurally about MIPS operations.
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 or directly download it to your own computer and run it there, using a similar invocation of Java.
Download the first starter file mips-basics.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 syscall
at the end of main will terminate the program and allow you to inspect the final state of the registers. Other desirable breakpoints may arise as you wish to diagnose certain (mis)behaviors.
Before we proceed, we will unpack a few new bits of syntax and semantics it is helpful to understand.
In addition to the sequence of instructions you have seen (e.g., addi
, lw
), assembly files usually contain other important information. Like many assembly languages, directives to the MIPS assembler begin with a period and typically mark up regions and provide data. You will see the following directives:
.globl
.data
.text
.ent
.word
Within 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 meaning = 42;
then you might end up with the following MIPS assembly line
meaning: .word 42
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, meaning # Set $t0 to &meaning (address of the value)
lw $t1, 0($t0) # Dereference the pointer, i.e., put meaning into $t1
There are other important directives, but these constitute most of the important ones we will use this term.
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:
move
nop
li
beqz
and bnez
In particular, you may NOT use ble
, blt
, etc.
Your grade on each problem 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.
Complete a procedure called swap
that transposes the values at the memory addresses stored in its two argument registers $a0
and $a1
. The following C program illustrates how it might be used.
int a = 5;
int b = 7;
int * p = &a;
int * q = &b;
("%d %d\n",a,b); // prints "5 7"
printf(p,q);
swap("%d %d\n",a,b); // prints "7 5" printf
Occasions sometime arise when one needs to reverse the order of bytes presented to you by the host platform. This often happens when reading data produced by a platform with a different “endian-ness”.
Complete a procedure byteflip
that transposes the single 32-bit integer in register $a0
and returns the value in register $v0
with the bytes reversed. For example, if given the value 0xBA5EBA77
, a byte flip would yield 0x77BA5EBA
.
(Sadly, given 0xB7EF65C6
your procedure would not produce “Lilliput”.)
Complete a procedure extremes
that takes four 32-bit signed integers in registers $a0
, $a1
, $a2
, and $a3
and returns the smallest of the four values in register $v0
and the largest of the four values in $v1
.
Branching gets more interesting when loops are involved.
Suppose your microchip’s ISA did not have an MDU (multiply and division unit) that supported multiplication with a mult
instruction. This can happen with extremely low cost devices that not only “make the common case fast” but pay very close attention to their minimal energy “budget”.
Complete a procedure product
that multiplies the multiplicand value in register $a0
by the multiplier value in register $a1
, using the elementary strategy of repeated addition. The result should be returned in register $v0
.
You should assume $a1
is non-negative.
Copyright © 2019, 2020, 2022 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.