From CloudModding OoT Wiki

MIPS is a reduced instruction set computer (RISC) instruction set architecture developed by MIPS Technologies. The N64's CPU is a NEC VR4300.

Helpful Links

MIPS Tutorial

Introduction

What is MIPS?

MIPS instructions are used by the N64's processor to store and load data, thereby (...)

Why learn?

In Ocarina of Time and Majora's Mask, object files contain models and their textures and animations, while actor files contain information about how, when, where, and under what conditions these resources should be loaded. Object files can be thought of as puppets, while actor files can be thought of as the puppet masters that control them. The actor files give the puppets orders in the form of MIPS instructions.

Learning to read MIPS will enable you to decode these orders, as well as write your own. You will thus be able to understand exactly what each actor file is doing, as well as be able write your own custom actor files.

Also, because MIPS is an assembly language, understand MIPS will give you an understanding of how processors and computers function at a very basic level. These low-level instructions form the underpinnings of every program and programming language.

Terminology

Memory Values

Name Hex Representation Bits
bit - 1
nibble 0x0 4
byte 0x00 8
halfword 0x0000 16
word 0x00000000 32
doubleword 0x0000000000000000 64

Registers

Register Meaning Notes
$at address temporary The value stored in the $at register is overwritten when a new function is accessed.
$ra return address The value stored in the $ra register is overwritten when a new function is accessed.
$sp stack pointer Unlike values stored in other registers, values stored in the $sp register are not overwritten when a new function is accessed. Therefore, values that need to be preserved across functions can be saved by storing them in the stack.
a1~a3 argument
t1~t9 temporary Values stored in t registers are overwritten when a new function is accessed.
v0~v1 value Values stored in v registers are overwritten when a new function is accessed.

Deciphering MIPS Instructions

Examples of the MIPS instructions found at the beginning of actor En_Hy are listed below.

When you come across an unfamiliar instruction, look it up in the MIPS R4000 Microprocessor User's Manual.

Name Instruction Format Method
addiu add immediate unsigned rt,rs,immediate Add the value at rs to the value at immediate. Store the result in rt.
addu add unsigned rd,rs,rt Add the value at rs to the value at rt. Store the result in rd.
andi and immediate rt,rs,immediate And the value at rs and the value at immediate. Store the result in rt.
b branch target Branch to the location at target after executing the next instruction.
bgez branch if greater than or equal to 0 rs, offset If the value at rs is greater than or equal to 0, execute the instruction below, then branch to the location at offset.
jal jump and link target
jr jump register rs
lb load byte rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt.
lbu load byte unsigned rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt.
lh load halfword rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the halfword found at the address into rt.
li load immediate
lui load upper immediate rt,immediate Shift the value at immediate left by 16. Load the result into rt.
lw load word rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the word found at the RAM address into rt.
nop no operation
or or rd,rs,rt Or the value at rs and the value at rt. Store the result at rd.
ori or immediate rt,rs,immediate Or the value at rs and the value at immediate. Store the result at rt.
sb store byte rt,offset(base) Add the value at offset to the value at base to get an address. Store the byte found at rt at the address.
sll shift left logical rd,rt,sa Shift the value at rt left by the value at sa. Store the result at rd.
subu substract unsigned rd,rs,rt Subtract the value at rs from the value at rt. Store the result at rd.
sw store word rt,offset(base) Add the value at offset to the value at base to get an address. Store the word found at rt at the address.

Decoding En_Hy

En_Hy is the actor that determines when, where, how, and under what conditions to spawn various Hylian NPCs. In addition, En_Hy also determines the following (by no means a complete list):

  • Which text IDs they use
  • How to colour certain sections of their outfits
  • When, where, and under what conditions they display their animations
  • When, where, and under what conditions they blink or change expression
  • How they react depending on which quest items Link has acquired
  • How their actions and dialogue change depending on conditions such as the time of day, Link's age, and what's happened in the story so far
  • How they react when Link shows them certain items
  • The amount of Rupees they give when the player sells them an item
  • The reward they give when the player completes their subquest

By learning MIPS, you will be able to modify these aspects, as well as write your own instructions for how the NPCs behave.

func_80A6F5B0

func_80A6F5B0 is the first function in En_Hy.

Off. Func. Contents Format Instructions Result
0000 addiu $sp,$sp,-32 rt,rs,immediate Add the value at rs ($sp) to the value at immediate (-32). Store the result ($sp-32) in rt. $sp = $sp-32
0004 sw $ra,20($sp) rt,offset(base) Add the value at offset (20) to the value at base ($sp) to get an address ($sp20). Store the word found at rt (?) at the address. $sp20 = 0x????????
0008 lh t6,28(a0) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the halfword found at the address into rt. t6 = 0x????
000C lui t9,%hi(data_80A722D8) rt,immediate Shift the value at immediate (the upper 4 digits of 0x80A722D8) left by 16. Load the result (0x80A70000) into rt. t9 = 0x80A70000
0010 addiu t9,t9,%lo(data_80A722D8) rt,rs,immediate Add the value at rs (0x80A70000) to the value at immediate (the lower 4 digits of 0x80A722D8). Store the result (0x80A722D8) in rt. t9 = 0x80A722D8
0014 andi t7,t6,0x7f rt,rs,immediate And the value at rs and the value at immediate. Store the result in rt. t7 = 0x0
0018 sll t8,t7,2 rd,rt,sa Shift the value at rt left by the value at sa. Store the result at rd. t8 = 0x0
001C subu t8,t8,t7 rd,rs,rt Subtract the value at rs from the value at rt. Store the result at rd. t8 = 0x0
0020 sll t8,t8,2 rd,rt,sa Shift the value at rt left by the value at sa. Store the result at rd. t8 = 0x0
0024 addu v0,t8,t9 rd,rs,rt Add the value at rs to the value at rt. Store the result in rd. v0 = 0x80A722D8
0028 lbu v1,6(v0) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt. v1 = 0x0
002C lui $at,0x1 rt,immediate Shift the value at immediate left by 16. Load the result into rt. $at = 0x10000
0030 or a2,a0,$zero rd,rs,rt Or the value at rs and the value at rt. Store the result at rd.
0034 ori $at,$at,0x17a4 rt,rs,immediate Or the value at rs and the value at immediate. Store the result at rt. $at = 0x117A4
0038 addu a0,a1,$at rd,rs,rt Add the value at rs to the value at rt. Store the result in rd. a0 = 0x802237C4
003C lbu t0,0(v0) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt. t0 = 0x00
0040 lbu t1,1(v0) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt. t0 = 0x00
0044 lui a1,%hi(data_80A72010) rt,immediate Shift the value at immediate left by 16. Load the result into rt. a1 = 0x80A70000
0048 sll t2,v1,3 rd,rt,sa Shift the value at rt left by the value at sa. Store the result at rd.
004C addu a1,a1,t2 rd,rs,rt Add the value at rs to the value at rt. Store the result in rd. a1 = 0x80A70000
0050 lh a1,%lo(data_80A72010)(a1) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the halfword found at the address into rt. a1 = 0x80A72010
0054 sw a0,24($sp) rt,offset(base) Add the value at offset to the value at base to get an address. Store the word found at rt at the address. $sp24 = 0x802237C4
0058 sw a2,32($sp) rt,offset(base) Add the value at offset to the value at base to get an address. Store the word found at rt at the address. $sp32 = 0x????????
005C sb t0,31($sp) rt,offset(base) Add the value at offset to the value at base to get an address. Store the byte found at rt at the address. $sp31 = 0x00
0060 jal external_func_8009812C
0064 sb t1,30($sp) rt,offset(base) Add the value at offset to the value at base to get an address. Store the byte found at rt at the address. $sp30 = 0x00
0068 lw a2,32($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the word found at the RAM address into rt. a2 = 0x????????
006C lui a1,%hi(data_80A72010) rt,immediate Shift the value at immediate left by 16. Load the result into rt. a1 = 0x80A70000
0070 sb v0,408(a2) rt,offset(base) Add the value at offset to the value at base to get an address. Store the byte found at rt at the address. v0 = 0x00
0074 lb t3,408(a2) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt. t3 = 0x00
0078 lbu t4,30($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt. t4 = 0x00
007C lw a0,24($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the word found at the RAM address into rt. a0 = 0x802237C4
0080 bgez t3,$L000000 rs,offset If the value at rs is greater than or equal to 0, execute the instruction below, then branch to the location at offset.
0084 sll t5,t4,3 rd,rt,sa Shift the value at rt left by the value at sa. Store the result at rd. t5 = 0x0
0088 b $L000001 target Branch to the location at target after executing the next instruction.
008C or v0,$zero,$zero rd,rs,rt Or the value at rs and the value at rt. Store the result at rd. v0 = 0x0

$L000000

$L000000 is the first chronological label in func_80A6F5B0.

Off. Func. Contents Format Instructions Result
0090 addu a1,a1,t5 rd,rs,rt Add the value at rs to the value at rt. Store the result in rd. a1 = 0x80A70000
0094 lh a1,%lo(data_80A72010)(a1) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the halfword found at the address into rt. a1 = 0x80A72010
0098 jal external_func_8009812C
009C sw a2,32($sp) rt,offset(base) Add the value at offset to the value at base to get an address. Store the word found at rt at the address. $sp32 = 0x????????
00A0 lw a2,32($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the word found at the RAM address into rt. a2 = 0x????????
00A4 lui a1,%hi(data_80A71F50) rt,immediate Shift the value at immediate left by 16. Load the result into rt. a1 = 0x80A70000
00A8 sb v0,407(a2) Add the value at offset to the value at base to get an address. Store the byte found at rt at the address. v0 = 0x00
00AC lb t6,407(a2) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt. t6 = 0x00
00B0 lbu t7,31($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt. t7 = 0x00
00B4 lw a0,24($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the word found at the RAM address into rt. a0 = 0x802237C4
00B8 bgez t6,$L000002 rs,offset If the value at rs is greater than or equal to 0, execute the instruction below, then branch to the location at offset.
00BC sll t8,t7,2 rd,rt,sa Shift the value at rt left by the value at sa. Store the result at rd. t8 = 0x00
00C0 b $L000001 target Branch to the location at target after executing the next instruction.
00C4 or v0,$zero,$zero rd,rs,rt Or the value at rs and the value at rt. Store the result at rd. v0 = 0x0

$L000002

$L000002 is the second chronological label in func_80A6F5B0.

Off. Func. Contents Format Instructions Result
00C8 subu t8,t8,t7 rd,rs,rt Subtract the value at rs from the value at rt. Store the result at rd.
00CC sll t8,t8,2 rd,rt,sa Shift the value at rt left by the value at sa. Store the result at rd.
00D0 addu a1,a1,t8 rd,rs,rt Add the value at rs to the value at rt. Store the result in rd.
00D4 lh a1,%lo(data_80A71F50)(a1) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the halfword found at the address into rt.
00D8 jal external_func_8009812C
00DC sw a2,32($sp) rt,offset(base) Add the value at offset to the value at base to get an address. Store the word found at rt at the address.
00E0 lw a2,32($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the word found at the RAM address into rt.
00E4 sb v0,406(a2) rt,offset(base) Add the value at offset to the value at base to get an address. Store the byte found at rt at the address.
00E8 lb t9,406(a2) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the byte found at the address into rt.
00EC li v0,1 v0 = 0x1
00F0 bgez t9,$L000001 rs,offset If the value at rs is greater than or equal to 0, execute the instruction below, then branch to the location at offset.
00F4 nop - Do nothing.
00F8 b $L000001 target Branch to the location at target after executing the next instruction.
00FC or v0,$zero,$zero rd,rs,rt Or the value at rs and the value at rt. Store the result at rd.

$L000001

$L000001 is the third chronological label in func_80A6F5B0.

Off. Func. Contents Format Instructions Result
0100 lw $ra,20($sp) rt,offset(base) Add the value at offset to the value at base to get a RAM address. Load the word found at the RAM address into rt. $ra = $sp20
0104 addiu $sp,$sp,32 rt,rs,immediate Add the value at rs to the value at immediate. Store the result in rt. $sp = $sp32
0108 jr $ra target
010C nop - Do nothing.

Advanced Notes

Stack Frame

Current Stack Frame
0x00 - 0x10 Called function arguments 0 to 4
(args-4) * 4 Called function arguments 4 to args
 ? Unknown
(saved) * 4 Saved registers
ra Return Address
(local) * 4 Local variables
Callee Stack Frame
0x00 - 0x10 Current function arguments 0 to 4
(args-4) * 4 Current function arguments 4 to args