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):

Welcome to CALCY THE CALCULATOR!
0
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): =
Value: 55
55
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): *
Value: 123
6765
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): /
Value: 4
1691
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): /
Value: 0
Attempting to divide by 0!
1691
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): c
0
Operation (=,+,-,*,/,c,q) (YOU HAVE TO PRESS ENTER HERE BUT YOU WON'T IN MARS): x
Huh?
0
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:

# YOUR NAME
# YOUR USERNAME

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

.globl main
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; // a char is 1 byte.
  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.
  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.

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) {
     _loop:
         print_str "loooop\n"
         # }
         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 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(display);
System.out.print("\nOperation (=,+,-,*,/,c,q): ");
operation = read_char();
  1. Use syscall number 1 to print out display’s contents.
    • (you’ll use lw to put 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).
    • store v0 into the operation variable, but…
      • it is a byte variable, so you have to use sb, not sw.

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


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) {
	lb  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':
	_quit:
		print_str "quit\n"
		j _break

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

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

	# this "j _loop" is already here!
	j _loop

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

switch(operation) {
	case 'q':
		System.out.println("quit");
		break;

	case 'c':
		System.out.println("clear");
		break;

	default:
		System.out.println("Huh?");
		break;
}

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?

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!
  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?
    • 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.

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.
    • 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.
  3. Do another switch-case on operation. Make cases for each of the five operations but don’t fill them in yet.
    • Look in Lab2.java! See, there are two switches, one inside the other.
    • 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:

Welcome to CALCY THE CALCULATOR!
0
Operation (=,+,-,*,/,c,q): =
Value: 50
50
Operation (=,+,-,*,/,c,q): c
0
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 '/'. Do that!

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


Submitting

First, be sure to test your program thoroughly.

Then, make sure your file is named username_lab2.asm, like jfb42_lab2.asm.

Submit here.

Drag your asm file into your browser to upload. If you can see your file in the folder, you uploaded it correctly!

You can also re-upload if you made a mistake and need to fix it.

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