MIPS Assembly (and MARS)

Our result is $t4, and the value is 0x262, which is \(2\times 16^2 + 6\times 16^1 + 2\times 16^0=610_\). Notice that we executed the mul (multiply) instruction first. In assembly, the order of operations is whenever that instruction gets executed, so we must be the arbiter.

Registers

Registers are very small pieces of memory inside of the CPU. For our MIPS architecture, these are 32 bits a piece. Therefore, our MIPS is a 32-bit machine. On the Hydra and Tesla machines, each register is at least 64 bits, so our Hydra and Tesla labs machines are 64 bits.

MIPS has several registers which can be address by number, such as $0, $1, $2, or by its name, such as $a0, $t0, $s0. Here are the registers and their purpose in MIPS.

NZCV can come with different names, such as SF (sign flag), ZF (zero flag), CF (carry flag), and OF (overflow flag) in the Intel/AMD architecture. The point of this is to see that you can use a mathematical operation to compare two numbers. Since our architecture deals with numbers, hopefully it is becoming clear(er) how conditions can be implemented.

To see these conditions in action, we can see different ways to represent these flags to give a certain conditional outcome.

Notice that I used .asciiz in the .data section to create the string. In C++, string literals go in the .rodata section, but MARS doesn't have one. Also, .asciiz means "use the ASCII table for characters and put a Z (zero) at the end of it". C-style strings don't have a length. We know the length of a string by counting until we hit a 0--this 0 is called the null byte. This is why we have .asciiz. If we don't want a zero to automatically be put into our string, we can use just .ascii. The null byte (0) is why we call strings null-terminated. Since we keep writing the string until we hit that null byte, which is 0.

Unfortunately, we don't have the power of printf. So, if we want to print strings and integers, we need two different system calls. The following example shows how to print an integer.

.text main: li $v0, 1 li $a0, 100 syscall

As you can see, we put the value 1 into $v0 for the "print integer" system call, and then we put whatever value we want to print in $a0. This produces the following.

Input

Just like printf and cout, we have scanf and cin. Unfortunately, we don't have that power with MARS. So, we need to use the input system calls as summarized below.

You might see the move instruction. This is yet another pseudo-instruction that resolves to using the add instruction. So, move $t0, $s0 is the same as add $t0, $s0, $zero. This is why the syscall help in MARS uses add $a0, $t0, $zero instead of move $a0, $t0. They do the same thing, but the add instruction is real.

Yes, there is a register called $zero. This can be used to load a value of 0 always. If we write to this register, the value is discarded. The zero register is hardwired to 0 and cannot be changed.

"Dropped off Bottom"

The MARS simulator will end your program whenever there are no more instructions to execute. This is NOT how an actual system works. Instead, when we return from int main(), C++ will make a request to the operating system to close your program. However, for purposes of this course, whenever you want to quit your program, just jump to the very end. I always make a label called "end" that is at the bottom of each program.

In normal situations, we would use the exit (or exit2) system calls to tell the operating system to terminate our process.