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:
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):
- Show Labels Window (symbol table)
- Clear Run I/O upon assembling
- Initialize Program Counter to global ‘main’ if defined
Leave the other settings unchanged.
Make a new file, and save it with the name
usernameis your username. (I would put
In MIPS, comments start with a
#sign. At the top of the file, put your name and username in a comment.
Just like in Java or C, our assembly programs start at a
mainfunction. Type these lines into your file.
.globldirective 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.
Instead of “compiling,” we “assemble” an asm program. When you assemble the program with , it’ll switch to the Execute tab.
Now run with . 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.”
Type these instructions in after your
listands for “load immediate”, and it puts a constant value into a register.
li t0, 1 li t1, 2 li t2, 3
Assemble and run. Those
t0, t1, t2registers on the right side changed to 1, 2, and 3!
But it was too fast to see what happened. Assemble again, but this time, step through instruction-by-instruction with this 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.
But wait! You can go backwards too. Use this 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!
Last, we can copy values between registers with the
moveinstruction. 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.
After all the code from above, type this:
li a0, 97 li v0, 1 syscall
Assemble and run, and you’ll see the number
97printed in the “Run I/O”.
Now do the same thing again (copy and paste those 3 lines), but put 11 into
v0instead of 1. When you assemble and run, you’ll see
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
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.
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
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.
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
.textdirectives 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.
Try assembling, and look at the labels and memory views. The labels view shows your new
hello_messagelabel at address
In the memory view, make sure the “ASCII” option is checked, and you can see your string in memory starting at address
Now to print the string. Look up syscall 4 in the MARS help. It says
a0is the “address of null-terminated string to print.” Your string has an address; you saw it in the labels window. But writing
li a0, 0x10010000would be silly. Instead, we can use the
laor “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
lainstruction 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
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.
Make sure your file is named
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.