Preface

I write my labs and projects like tutorials. There’s a lot of writing, but that’s because you’re new to all these things and I have to explain everything. Just follow the directions in order and you’ll be done in no time.

Try this: these boxes are things to play around with and learn a little more. You don’t have to do them, but doing them will improve your understanding.

PAY ATTENTION to these colored boxes.


1. Getting started

This lab is about familiarizing you with the MARS MIPS simulator software, and getting you started on your FUN ASSEMBLY LANGUAGE JOURNEY. Well I think it’s fun.

You must use the modified version of MARS available on the software page.

When you run it, you will see this:

a diagram of the mars interface.


2. Hello, nothing

Now you’ll learn how to make an empty program, assemble it, and run it.

Setting things up (important!)

In the Settings menu, make sure the following things are checked (enabled):

Leave the other settings unchanged.

  1. Make a new file, and save it with the name username_lab1.asm, where username is your username. (I would put jfb42_lab1.asm.)

  2. In MIPS, comments start with a # sign. At the top of the file, put your name and username in a comment.

  3. Just like in Java or C, our assembly programs start at a main function. Type these lines into your file.

    The .globl directive is only needed for main. Most of your functions won’t need it.

     .globl main
     main:
    

    main: is a label. Labels name parts of your code; not just functions, but also loops, if-elses, etc.

  4. Instead of “compiling,” we “assemble” an asm program. When you assemble the program with the assemble button, it’ll switch to the Execute tab.

    a diagram of MARS's execution view.

  5. Now run with the run button. In the “Run I/O” at the bottom of the screen, it’ll say

     -- program is finished running (dropped off bottom) --
    

    It’s a completely empty program that does nothing. Yay!

Try this: what error do you get if you remove the .globl main line?


3. Playing with registers

Now you’ll learn how to put integers into registers and copy them around, and also to step through your program one instruction at a time.

Look at the register pane on the right side of the window. There are 35 registers listed, and all but sp contain 0. These are the values they are set to when your program starts.

“Immediate” means “a constant that is written inside the instruction.”

  1. Type these instructions in after your main: line. li stands for “load immediate”, and it puts a constant value into a register.

         li   t0, 1
         li   t1, 2
         li   t2, 3
    
  2. Assemble and run. Those t0, t1, t2 registers on the right side changed to 1, 2, and 3!

  3. But it was too fast to see what happened. Assemble again, but this time, step through instruction-by-instruction with this button: the step button. Watch the values of the registers and the highlighted instruction in the text window.

    • You’ll see the registers highlighted green when they change.
    • You’ll notice that the highlighted instruction is the one that is just about to run.
  4. But wait! You can go backwards too. Use this button: the step back button.

    • You’ll see the instructions happen in reverse, and the registers will get set back to 0.

    Stepping forward and backward one instruction at a time is extremely helpful when you first learn to program assembly. (It’s extremely helpful even when you’ve been using it for years, too.)

    Half a century ago, someone decided to use the word “move” instead of “copy” and now we’re stuck with it. Sorry!

  5. Last, we can copy values between registers with the move instruction. After your lis, write these lines:

         move a0, t0
         move v0, t1
         move t2, zero
    
    • Assemble and step through. The values are copied from the register on the right into the register on the left. This is important: data is never “moved” on a computer, always copied. (What would moving it even do? What would be left in the original register? I dunno.)

Try this: Load a hexadecimal immediate into a register, like li t0, 0xF00D. Assemble, and look at the “Basic” column in the text segment. Do you see it?

Now try putting a value into the zero register. That’s its name. li zero, 10. What happens when that runs?

When you step through your program, one other register changes on every instruction… step back, too.


4. Printing things

Now you’ll learn to call special functions called system calls. As you’ll find out in 449, programs have to ask the operating system to get input or produce output, and we do that with system calls. MARS pretends like it’s a tiny operating system.

  1. After all the code from above, type this:

         li   a0, 97
         li   v0, 1
         syscall
    
  2. Assemble and run, and you’ll see the number 97 printed in the “Run I/O”.

  3. Now do the same thing again (copy and paste those 3 lines), but put 11 into v0 instead of 1. When you assemble and run, you’ll see 97a printed. Huh??

Here’s what’s happening

MARS has many built-in “system calls” to print numbers, print strings, ask the user to type something etc. We pick which system call to run by putting a number into the v0 register.

Hit the F1 key in MARS. Then click “Syscalls”. This tells you about what syscalls are, which ones are available, what their numbers are, and their arguments and return values.

The first time, we put 1 into v0, and the second time, 11. Which syscalls are 1 and 11?

This is basically what’s happening. Important: what is one line of code in Java, C etc. is usually multiple lines of code in assembly.

it's like doing "System.out.print(97)". "li a0, 97" puts the argument in the right place. "li v0, 1" chooses which function to call. And "syscall" actually executes the function.

Try this: Look at this ASCII table. What (decimal) number is used to represent lowercase a? Change that number in your code and see what character comes out.

Now change your li a0, ... instructions to instead do li a1, ... It won’t work right. Step through the program and see what values are in the a0 and v0 registers right before the syscall instructions run. (Then undo that change.)


5. Printing strings

Now you’ll learn about the data segment, which is where we store strings, variables, arrays, and so on.

In the previous section, you saw that you can print a single character with syscall 11. A character is represented as an integer, and fits into a register.

A string is an array of characters. ASCII uses 1 byte for each character. But an array won’t fit into a register, so we have to put it somewhere else.

  1. To put a string into memory, we have to switch to the data segment. At the top of your program (before .globl main), do this:

     .data
     hello_message: .asciiz "Hello, world!"
    
     .text
    

    The .data and .text directives tell the assembler to switch to the data and text (code) segments. Any time you switch to the data segment, you must switch back to the text segment to write more code.

  2. Try assembling, and look at the labels and memory views. The labels view shows your new hello_message label at address 0x10010000.

    In the memory view, make sure the “ASCII” option is checked, and you can see your string in memory starting at address 0x10010000.

  3. Now to print the string. Look up syscall 4 in the MARS help. It says a0 is the “address of null-terminated string to print.” Your string has an address; you saw it in the labels window. But writing li a0, 0x10010000 would be silly. Instead, we can use the la or “load address” instruction. Do this at the end of your program:

         la   a0, hello_message
         li   v0, 4
         syscall
    

    Now it should print 97aHello world!. That’s kind of silly, so you can comment out the two previous syscalls if you like.

    Step through the program. Watch what the la instruction actually does.

Try this: uncheck that “ASCII” box in the memory view. The string looks like a bunch of numbers now. Go back and look at the ASCII table and look in the “Hx” (hexadecimal) column for H, e, l, etc. But something is weird about how the numbers are written in the memory view. What’s up with the order?


6. Exiting gracefully

Finally, you’ll learn how to exit your program more “properly”.

At the end of your main function (so, the end of your program), use the exit syscall (number 10).

When you run now, you’ll see the message changed to:

-- program is finished running --

It might not seem that important now, but it’ll save you a lot of trouble later if you end every main with the exit syscall.


Submitting

Make sure your file is named username_lab1.asm, like jfb42_lab1.asm.

Submit here.

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

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