Lab 3: MIPS Control Instructions and Basic Memory Usage


Due Monday, October 19 at 11:59:59 PM

Goals for This Week

By the time you have completed this work, you should be able to:

Provided files: Documentation:

Step by Step Instructions

There are three tasks that you need to complete for this week, some with multiple steps. Strictly speaking, you may complete them in any order, though for this lab it is recommended to go in order. The tasks are listed below:

The initial step below describes how to get the files you will need into the appropriate place. These files are used for all the different tasks.

Initial Step: Create a Directory for This Lab and Copy Over the Files

After you log in, go into your cs64 directory that you created last time:

cd cs64

Then create a new directory for this lab: lab3:

mkdir lab3

Then go into that directory.

Now copy over all of the files necessary for this week's tasks:

cp ~kyledewey/public_html/cs64/labs/3/MedianNumbers.asm ~kyledewey/public_html/cs64/labs/3/factorial.asm ~kyledewey/public_html/cs64/labs/3/lab3funcs.asm ~kyledewey/public_html/cs64/labs/3/partner.txt .

Note the use of the trailing . in the above command, which stipulates that the specified files should be copied into the current directory.

Task 1: Control Operations

This task requires you to use branches in MIPS assembly. To this end, you will write a MIPS program which will ask the user for three numbers and then print out the median. A sample run of this program will look like this, with user input in bold:

Enter the next number:
3
Enter the next number:
5
Enter the next number:
-13
Median: 3

Your code should be written in the provided MedianNumbers.asm template file. Be sure that your output matches exactly with the output above.

Note that you do not need to use a complex sorting algorithm because you are only comparing exactly 3 numbers, not some arbitrary number of numbers. A good development strategy here is to write a small program in C that will behave the same way as the program above, and to test it out. From there, it can be ported to assembly, which should be simpler than directly writing in assembly (considering that you are just starting to write in assembly). Try to write as simple of C code as possible, as ultimately any complexity in C will almost certainly translate to complexity in assembly.

Task 2: Basic Loops

This task requires you to write a basic loop in MIPS assembly. To this end, you will implement the factorial function iteratively (i.e., without using recursion), which will take as an input some number gathered from the user. The factorial function will print out all the partial products as they are encountered, along with the final result. Each of the printed out numbers should be followed by a newline. Pseudocode showing how to do this is shown below:

n = <<user input>>
accum = 1
while (n != 0) {
  accum = accum * n
  print accum
  print “\n”
  n = n - 1
}
print accum
print “\n”

A sample run of the program on input 1 is shown below, with user input in bold:

Enter the number:
1
1
1

A second run of this program on input 0 is shown below, with user input in bold:

Enter the number:
0
1

A third run of this program on input 5 is shown below, with user input in bold:

Enter the number:
5
5
20
60
120
120
120

You should write your program in the provided factorial.asm template file.

For full credit, your solution's output must match the above output exactly. Additionally, while you may write your own algorithm to do this, it must be iterative; that is, you may not use recursion. You may assume that the user will only input non-negative numbers, and that no multiplication will lead to overflow. You will be working only with unsigned integers for this task.

Task 3: Basic Memory Operations

This tutorial is a sequence of memory operations, each slightly harder than the last one. In order to allow us to produce different test cases, the main code is separate from your code. We will supply a different main file depending on what we want the initial values to be.

Step 1: Familiarize Yourself With the Code

Because it is assembly, it is a little hard to get a high-level sense of what you are being asked to do. Open the file lab3funcs.asm. The first thing to look at is the global variables, declared in the .data section. There are four global integers: globalA, globalB, globalC, and globalD. Then there is an array: myArray. These are the variables you will be working with this week.

Now look at the code in lab3funcs.asm, particularly the functions (i.e., storevalues, storeregvalues, copyvalues, operations, arrays, and arraycalcs). There are a number of functions you need to fill in. We have not gone over how to properly call functions yet, so you might not know how to do all the steps necessary to write a function. As such, for this portion, you are restricted to use only certain registers (more on why this makes sense later in the class). Each function uses a different restricted set; for example, with storevalues, only registers $v0 - $v1, $t0 - $t7, and $a0 - $a3 may be used. Some of the functions receive input; any input received will be in registers $a0 - $a3.

Now look at the lines of code in comments. For each function, there are some lines of code written in high-level language. Translating those to assembly is your task. A description of function inputs, along with C-like code describing what the function does, is supplied in the table below. Like C, semicolon (;) should be viewed as a sequencing operator, meaning the statements should be performed in order, and previous statements can influence the results of later statements. For example, with operations, the second use of globalA refers to the value of globalA set in the previous line.

Your code should not trigger a processor-level exception if overflow occurs. With MIPS, this means that you should use the addu instruction instead of the add instruction for adding numbers together.

Function Name Function Number Input Description
storevalues 0 None
globalA = 6;
globalB = 6;
globalC = 30;
globalD = 30;
storeregvalues 1
  • $a0: New value for globalA
  • $a1: New value for globalB
  • $a2: New value for globalC
  • $a3: New value for globalD
globalA = $a0;
globalB = $a1;
globalC = $a2;
globalD = $a3;
copyvalues 2 None
globalA = globalC;
globalD = globalB;
operations 3 None
globalA = globalB + globalC;
globalD = globalA + globalB;
arrays 4
  • $a0: The new value of myArray[0]
  • $a1: The new value of myArray[1]
myArray[2] = globalA;
globalA = myArray[3];
myArray[0] = $a0;
myArray[1] = $a1;
arraycalcs 5 None
globalA = myArray[0] + myArray[1];

The code is also equipped with a main function, which calls the functions you will be writing. Each run of the program calls a single function. The name of the function to execute is specified with a number, supplied by the user. The table above specifies which number executes which function (e.g., a user-supplied 1 will call storeregvalues). The main function prints out the global variables and the first four array values before and after every function call, and, depending on the function selected, may also print out registers $a0 - $a3.

For example, below is a sample run testing storevalues, which is function number 0 from the preceding table. User input is shown in bold.

This program loads, stores, and operates on variables
Looking at the comments in the code, perform the operations specified.  Make sure you make changes to this code in order to test it.
You can change the initial values of variables as well as the inputs you test.
Global variable values are: 35, 39, 54, 90
Array values are: 537067794, 537002737, 269156513, 7032874
Enter a value: 0
0
Global variable values are: 6, 6, 30, 30
Array values are: 537067794, 537002737, 269156513, 7032874

As an aside, you may have noticed something a bit odd about the memory layout here: we have declared globalA and other global mutable variables in the .data section, whereas in class we discussed that global mutable variables should be in the .bss section. The reason why is specific to limitations of SPIM; on a real processor, these should be separated out.

Step 2: Implement the Functions

Look for the words “TODO” in the file. (If you are using vi, you can search for those words by using “/TODO”.) Make sure you test often. After implementing each function, make sure you run it using the supplied main function.

Make sure your code does not depend on initial values. Remember that the program we run it on will have different global declarations.

Turn in Everything Using turnin

If you partnered with someone, record the email address they are using for the class in partner.txt. For example, if your partner had the email address foo@bar.com, then the contents of partner.txt should be the following (and only the following):

Partner: foo@bar.com

If you did not partner with anyone, you do not need to (and should not) edit partner.txt.

Assuming you are in the cs64/lab3 directory you created at the beginning, you can send in your answers via the following command:

turnin lab3@cs64 MedianNumbers.asm factorial.asm lab3funcs.asm partner.txt

You may turn in the same assignment up to 100 times, which is useful if you are working on it incrementally. Note that only the last version you submitted will be graded.

Even if you did not partner with anyone, you should still turn in partner.txt, which should not have been modified.


Prepared for Computer Science 64 by Diana Franklin, with slight adaptation by Kyle Dewey.