Registers
MIPS ASM Tutorial Part 2
By Arthurtilly
The Registers
MIPS ASM uses 32 different registers to help with storing values. Each register can store exactly 4 bytes, or 8 hexadecimal numbers. This is called a word, or long. Similarly, a halfword (or short) is 2 bytes. Most ASM commands work with halfwords, which can be annoying when trying to give a register a certain value.
Let’s look at the names and usage of each of these 32 registers.
R0
R0 is the first register, and it simply means, “Register 0”. R0 is equal to 0. Always 0. You can’t assign values to it, it is always 0. R0 is useful when trying to assign a value to another register, because of the way commands work. For example, if you wanted to set T0 to 0x1234, you would do it like this:
It’s important to use R0 because of how many commands need a register that can usually just be 0. We’ll look at what T0 is later.
ADDIU T0, R0, 0x1234
V0 - V1
V0 and V1 are the return values of functions. Once a function is called, it can set V0 and V1 to values that can be used by the current function. For example, the function at 0x802A1424 checks for collision between two objects. If there is collision, then V0 is set to 1, otherwise it is set to 0.
A0 - A3
The registers A0, A1, A2 and A3 are arguments for functions. Before calling a function that takes arguments, you would set these registers to certain values to pass those arguments to the function. For the previous collision function we looked at, A0 and A1 need to be set to pointers to the two objects you want to check for collision.
(Important: A pointer is a RAM address that contains another RAM address. For example, the address 0x80361158 always contains the RAM address of Mario’s object. If you simply pass the RAM address of an object to this function, it won’t work correctly.)
T0 - T9 and S0 - S7
The ten registers from T0 to T9 are temporary registers. These are the registers that we will be using the most. They are general-purpose “variables”.
The eight registers from S0 to S7 are saved registers. They act similarly to temporary registers, but have one major difference that makes them hard to use.
Do note however that the processor doesn’t treat S, T, A or V registers any differently. The way they’re used is merely convention, but unless you know what you’re doing, it’s best to stick to that convention.
The difference between T and S
The difference between the two types of registers is best shown with an example:
Note that this is NOT automatic. If you want to use saved registers in your function, you should make sure that you set the saved registers to their original value before the function finishes, otherwise unexpected behaviour may occur.
ADDIU T0, R0, 0x1
ADDIU S0, R0, 0x1 // T0 = 1, S0 = 1
JAL 0x<function> // call a function
// S0 is guaranteed to still be 1, but T0 is not
Other registers
There are a few other important registers we should look at. These shouldn’t be used in our code, but it’s important that we know what they mean:
AT - Assembler Temporary (used for assembling macros)�K0 / K1 - Reserved for the kernel�GP - Global Pointer�SP - Stack Pointer�FP - Frame Pointer�RA - Return Address (automatically set by the JAL command)
Floating-point registers
In addition to the 32 registers we’ve covered, there are 32 floating-point registers as well, F0 to F31, all 4 bytes long. Like the 32 we’ve seen, they have certain roles, but unlike the ones we’ve covered, we can use all of them in our programs.
We’ll cover floating-point registers and commands in later tutorials, but for now we’ll stick with the regular registers.
In the next tutorial, we’ll look at some common commands used in ASM and how to use them. Goodbye for now!