If you’re confused, don’t start writing code to “have something to turn in.”

100% of the time, this will only make you more confused and frustrated, and the resulting code will probably be impossible to fix and difficult to grade. If you’re totally lost, get help before you start writing!

Never skip a confusing step to “come back to it later.”

You probably learned to do this on exams, but this strategy does not work when building something. For example, when you’re building a house, you don’t “come back” to the walls after building the roof. YOU HAVE TO BUILD THE WALLS FIRST. Programming is no different. Things build on top of each other.

In this lab, you’ll be making a very simple interactive program: a four-function calculator.

Since you’re very new to control flow in MIPS, I’m giving you a Java implementation of the lab so you can see how your program will work, and see the code that you will be translating to MIPS.

Right click and save the Java solution from this link. Read the code, compile it, and run it. Basically, you’ll be translating the main function into MIPS. (If you’re already familiar with MIPS, just go for it, but maybe read the instructions below anyway. You might learn something new!)

How it works

Just like a real calculator, it remembers one value at a time, and everything you do operates on that value. In the Java program, it’s the static variable display.

The program accepts a command, and then optionally an operand. The commands are:

Here’s an example interaction with the Java program (and your program will work almost the same way):

Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): =
Value: 55
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): *
Value: 123
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): /
Value: 4
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): /
Value: 0
Attempting to divide by 0!
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): c
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): x
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): q

Like the message above says, when entering the operation in the Java version, you have to hit enter. There is no way to just “get a character” in Java, so that’s why. In MARS, there is a way to “get a character”.

0. Getting started

I’ve written a macro to make it easier to print messages to the output. Copy and paste this code into a new asm file, and save it as yourusername_lab2.asm like you did with lab 1. Then, assemble and run.


# preserves a0, v0
.macro print_str %str
	print_str_message: .asciiz %str
	push a0
	push v0
	la a0, print_str_message
	li v0, 4
	pop v0
	pop a0

.globl main
	print_str "hello! remove this print_str line after you confirm it works.\n"

1. Variables

Never write a program all at once and then assemble it. Write a little at a time and let the assembler help you along the way. Then test it! Do this in other languages like C and Java, too!

In the Java file, you’ll see this:

// These variables will go in the .data segment.
static int display = 0;
static char operation = 0;
  1. After the .end_macro line, you’re going to declare two variables. You have to switch to the .data segment, then declare the variables, and then switch back to .text.
    • Look at the lecture 3 slides (Memory and Addresses) for the syntax for declaring global variables.
    • Although the Java uses char for operation, you can declare both display and operation as .word variables in your MIPS code.
  2. Now assemble your code. This program doesn’t do anything yet, but it’s good to check your syntax and see if you’re on the right track.

    In the Labels window, you should see:

    • main at 0x00400000
    • display at 0x10010000
    • operation at 0x10010004
      • display and operation could be swapped if you declare operation before display. That’s okay.

2. main and the main loop

  1. Inside main (anything after main: is “inside” it), print out a welcome message using print_str. You use it like this:

     print_str "Hello! Welcome!\n"

    Don’t forget the \n at the end of the string if you want a newline.

  2. Now make an infinite loop after that. Name it _loop, like so:

         # while(true) {
         # }
         j _loop

    The code inside the loop will go between that label and the j instruction.

  3. Assemble and run. It should print your welcome message once, and then…

    Well, it’s in an infinite loop. It will run forever. Hit the stop button to make it stop. Otherwise your computer fans will start whirring. ;)

From here on, I’m leaving it up to you to assemble and test your program after each step. Get in the habit now while the programs are still simple. Use single-stepping and print_str to test that your control flow works before you try to fill it in. Take it slow!

3. Input and output

Inside the loop, remove any test prints, and now you’re going to do the equivalent of this:

System.out.print("\nOperation (=,+,-,*,/,c,q): ");
operation = read_char();
System.out.print("\n"); // <<<<<< this is not in Lab2.java but you should do this!
  1. Use syscall number 1 to print out display’s contents.
    • Since display is a variable, you must use lw to get its value into a0.
  2. Print the prompt string by using print_str: "\nOperation (=,+,-,*,/,c,q): "
  3. Use syscall number 12 to read a single character, then store it into operation.
    • after the syscall instruction, the character typed will be in v0 (it replaces whatever you put into it before syscall).
    • so now, you can store v0 into the operation variable, with sw.
      • Remember that sw is the only instruction that is “backwards,” i.e. the variable that you are storing into is the second argument to the instruction!
  4. Finally, just print the string "\n". This will make the output a little more readable.

If you assemble and run now, it should print 0 and the prompt, then if you hit a character, it loops around, printing 0 and the prompt again.

Try this: To check that you really are printing out the value of display, change your declaration of display so it’s like, 17. When you run the program, now it should print 17 instead of 0. Be sure to change it back to 0 once you’ve confirmed it’s working!

Formatting check!

Don’t forget to keep your code looking nice! Make sure your instructions are properly indented.

Also, when you did operation = read_char();, that turned into multiple lines of assembly. To make it easier for you to read, put the Java code as a comment before the assembly that implements it.

    # operation = read_char();
    ...the instructions that do syscall 12 and then store into operation...

    # and keep commenting as you write

Typically, each line of high-level language code will turn into multiple lines of assembly. Make sure to use high-level language comments like this so you don’t have to “decode” the assembly in your head to know what it does.

4. Checking what command it is

Okay. Now that we’ve stored the user’s input into operation, we have to look at it and decide what to do.

After the previous step (and still inside the loop!), do this:

	# switch(operation) {
	lw  t0, operation
	beq t0, 'q', _quit
	beq t0, 'c', _clear
	j   _default

	# indentation is not *required* in asm, but it can be helpful.

	# case 'q':
		print_str "quit\n"
		j _break

	# case 'c'
		print_str "clear\n"
		j _break

	# default:
		print_str "Huh?\n"
		# no j _break needed cause it's the next line.
	# }

	# this "j _loop" is already here! you just add the code above before it.
	j _loop

This is the equivalent of this Java code. See the similarities?

switch(operation) {
    case 'q':

    case 'c':


Try it out. What happens when you hit c? q? Anything else? Does it make sense?

Try this: Comment out the j _break lines. What happens now? Does that make sense? Be sure to uncomment them after you test it.

5. Implementing the quit and clear commands

Right now, q and c just print a message. You’re gonna replace that code.

  1. For _quit, make it use syscall 10 to exit the program (like you learned in lab 1).
    • Make sure it works! When you use the q command, it should say “program is finished running.”
  2. _clear will set the display variable to 0, like the clear key on a calculator. You can do this with one instruction:
    • What instruction stores into a word variable?
    • What register holds 0, always? (It’s named after it.)
    • You can test this command by temporarily changing the display variable declaration so it holds some nonzero value, then running the program, using c, and it should change to 0. But change the declaration back to 0 when you’re done testing it.

Do not “move on” if you can’t get these working. Get help.

6. The commands with an operand

Now you’ll implement =, +, -, *, and /. Notice in the Java code, this line:

case '+': case '-': case '*': case '/': case '=':

This means “for all of these characters, run the following code.”

  1. Add beqs for those commands in the switch you just made, and have them all go to a new case label, like _get_operand.
    • Don’t just put that label anywhere. Think like you’re writing HLL code. Put it before the default case.
  2. After that label, translate the Java code for prompting the user and reading an int.
    • Don’t forget to do the equivalent of the System.out.print("Value: "); line. Everyone forgets that!
    • Syscall 5 is like scanner.nextInt() in Java.
    • After doing syscall 5, the return value (what the user typed) will come out in v0, like usual.

    When you run syscall 5, if you type something that isn’t an integer, or you hit enter without typing anything, it will crash with an error like: Runtime exception at 0x00400080: invalid integer input (syscall 5). It’s okay! There’s nothing you can do about that.

  3. Now, just like the Java code, you will do another switch-case on operation inside this case.
    • Look in Lab2.java! See, there are two switches, one inside the other.
    • Make cases for each of the five operations but don’t fill them in yet.
    • You can jump to the same _break label to break at the end of each case.
    • Since you already know that the character is one of + - * / =, you don’t have to check for an invalid character here.
  4. For the = command, store what the user typed in (v0) into display.

Now test it. You should be able to enter the = command, then type a value, and the display should change to that value. Then you should be able to clear it back to 0 with c. For example:

Operation (=,+,-,*,/,c,q): =
Value: 50
Operation (=,+,-,*,/,c,q): c
Operation (=,+,-,*,/,c,q):

If it doesn’t work, DO NOT MOVE ONTO THE NEXT SECTION. Don’t “come back and fix it.” This is the easiest way to get completely overwhelmed and discouraged. Try single-stepping through your program, seeing where it goes, and comparing that to where you expect it to go. And if you can’t figure it out, ask for help.

7. Finishing it off

All that’s left are the arithmetic commands, + - * /.

  1. Fill out the code for each of those operations after the labels you made.
    • You will load display, modify that value, and store it back into display.
  2. Try it out.
    • If you divide by 0, what happens?
  3. To avoid that, let’s add an if-else inside the division case:
    • Look at Lab2.java in the case '/'. You want to do that!
    • See this part of the correspondences page or review the lecture 4 slides for the “shape” of an if-else.
    • Do not exit the program if they try to divide by 0. Just print an error message like the Java program does.

And that’s it! It should work just like the Java program now.


First, be sure to test your program thoroughly.

Then, you can submit:

  1. On Canvas, go to “Assignments” and click on this lab.
  2. Click “Start Assignment.”
  3. Under “File Upload,” click the “Browse” button and choose your .asm file.
  4. Click “Submit Assignment.”

If you need to resubmit, that’s fine, just click “New Attempt” on the assignment page and upload it again.

Try this: If you want to go further, here are some things to try: