MIPS Assembly

Writing MIPS assembly is not necessary to make a Nintendo 64 game. You can make a game entirely using C, C++, or any other programming language you can get working on the Nintendo 64. However, you may want to be able to read MIPS assembly from time to time, and you may want to write small snippets of MIPS assembly.

This page will not teach you MIPS assembly, but just give you the highlights.

= Learning MIPS Assembly =

MIPS is, still, commonly chosen as an architecture for teaching assembly language to computer science students. It has been used in countless college courses on assembly language. There several reasons why MIPS is a good language for teaching computer science classes, but that’s not really important for game developers—what is important is that you can easily find high-quality guides for programming in MIPS that teach the associated concepts and theory, and that don’t assume that you have any prior experience with MIPS.

= MIPS Versions =

The VR4300 in the Nintendo 64 console uses the MIPS III architecture. This is somewhat older than architectures like MIPS32 and MIPS64. Even though MIPS III is 64-bit, it is a different (older) architecture from MIPS64.

= MIPS Quirks =

The one big quirk of MIPS is that it contains (depending on the specific version) various non-interlocked hazards. This is what the MIPS acronym originally stood for, supposedly: “Microprocessor without Interlocked Pipeline Stages”.

A hazard happens when the results of one instruction are not complete by the time the next instruction executes.

An interlock prevents an instruction from executing until the inputs are ready, creating a pipeline stall—the pipeline stall delays the instruction so it can execute correctly.

In most other processors, you don’t have to know about these things, because the hazards are protected by interlocks. MIPS has some common hazards which are not protected by interlocks, so you must structure your assembly code to avoid the hazards. In some cases, the assembler can help you by automatically reordering the instructions to avoid hazards.

Warning: The MIPS assembler will reorder your instructions by default. This means that the assembly you write will not exactly match what you get when you disassemble the code afterwards. You can disable this with, or you can simply let the MIPS assembler make your job easier.

Three hazards you might commonly encounter on the VR4300 are the branch delay slot, the integer multiply and division instructions, and the floating-point multiply instruction (VR4300 multiply bug). There are other hazards that you would only typically see in kernel code, like changes to the TLB—refer to the CPU manual if you are doing anything special.

Branch Delay Slot
The instruction after a branch instruction is executed, regardless of whether the branch is taken. For example, consider the C function:

int add(int x, int y) { return x + y; }

The actual MIPS generated by the compiler may be:

.set   noreorder add: jr     $31 addu   $2,$4,$5

Note that the  instruction appears after the function returns—it is in the branch delay slot, and will be executed anyway. However, if you are writing assembly, you can write the function like this instead:

add: addu   $2,$4,$5 jr     $31

When you assemble it, you will get the same result as above… because by default, the assembler will reorder instructions so you don’t have to think about the delay slot. Disassembling the code from the second snippet will show you the first snippet.

Integer Multiplication and Division
After a, the next two instructions may not modify the   register. After, the next two instructions may not modify the   register. Operations which modify those registers are:



Like the branch delay slot, the assembler will fix this for you. For example, if you try to assemble the following code:

my_function: mfhi $2 mthi $2

The assembler will insert two  instructions between   and   to avoid the hazard. This can be disabled with, just like the branch delay slot.

VR4300 Multiplication Bug
TODO: What is the exact nature of this bug?

The assembler will not fix this one for you. After  or , insert two   instructions to avoid triggering the bug.