R3000 instruction set
Contents
Intro
Registers
Registers are 32-bit boxes that hold values during computation.
Registers that can be used as arguments to instructions.
- r0: Always 0. Writing to this register does nothing.
- r1: Reserved for the assembler. For ASM hacking, you're basically the assembler, so it might be safe to use, until someone figures out it isn't.
- r2-r3: Used as scrap paper for work.
- r4-r7: Used as arguments.
- r8-r15: Temporaries.
- r16-r23: Non-temporaries.
- r24-r25: Temporaries.
- r26-r27: Reserved. Do not modify.
- r28: Global pointer. Do not modify.
- r29: Stack pointer. Points to the first free address on the stack. Change this to make more room on the stack. As more things are put on the stack, this pointer decreases.
- r30: Frame pointer. Do not modify.
- r31: Typically the return address. The
jal
instruction implicitly writes to this register. Do not modify except to restore an earlier value.
The following registers are expected to be preserved across calls. If used, their original values must be restored before returning.
- r16 - r23
- r26 - r27 (maybe)
- r28 - r31 (probably)
The following registers are expected NOT to be preserved across calls. A subroutine is free to change the value of these registers. After a call, these registers should be assumed to have garbage values (except r2).
- r2-r3: If the function has a return value, that value is stored here.
- r4-r7: The first four arguments of a call. (Additional arguments are passed on the stack.)
- r8-r15, r24-r25: Nothing special.
For calculations, use r2 and r3, then r4-r15 and r24-r25. Use r16-r23 for values that need to be preserved while calling a function, but make sure to store their original values on the stack, and to restore them before the return.
There are other registers, but they are special and require special instructions to use.
Instructions
Note: This section is meant to be linked to, and used to generate tooltips (title text) for code pages.
The first paragraph of an instruction's description should be a short one-liner. It will be used as the tooltip. Think "reminder", rather than "explanation".
These are stolen from Wikipedia. Whoops.
nop
No operation
Used to cause delays between instructions, because some instructions step on each other's toes.
Example:
nop
Arithmetic
These instructions act on registers as 32-bit two's-complement integers.
add
Add
Example:
add $d,$s,$t
addu
Add unsigned
Example:
addu $d,$s,$t
This operation is used to add both signed and unsigned integers (and is in fact the default used by C compilers). The "unsigned" part is misleading: it means that, if the sign changes, don't set the "overflow" error flag, which can cause an exception handler to trigger.
sub
Subtract
Example:
sub $d,$s,$t
subu
Subtract unsigned
Example:
subu $d,$s,$t
addi
Add immediate
Example:
addi $t,$s,C
addiu
Add immediate unsigned
Example:
addiu $t,$s,C
mult
mult $s,$t
Multiply $s and $t.
Unlike most instructions, this instruction doesn't say where to store the result. The product of two 32-bit integers is at most 64 bits long, so the top and bottom parts of the result are stored separately. To access them, use the #mflo (move from low) and #mfhi (move from high) instructions.
This instruction is slow, so the compiler might instead use a combination of shifts and additions for multiplications by constants.
This instruction is sometimes used to multiply by positive fractions less than 1. For example, to multiply by 0.14, the compiler can multiply by an integer close to 0.14 * 2^32, and then only take the high part of the result.
Example:
mult r2,r3 Multiply mflo r4 r4 = the lower part of the product mfhi r5 r5 = the upper part of the product (r5 * 2^32) + r4 == r2 * r3 (mathematically)
multu
Multiply unsigned. Multiply as if the arguments are 32-bit unsigned integers.
Example:
multu $s,$t
div
Divide (signed).
The quotient $s / $t is stored in the LO register, while the remainder $s % $t is stored in the HI register. See #mult.
Example:
div $s, $t
divu
Divide unsigned
Example:
divu $s, $t
mflo
mfhi
Move from [low/high]
Copy from the [LO/HI] special register to the given destination register.
Used to retrieve results from multiplication and division instructions.
Syntax:
mfhi $d mflo $d
Memory
Getting data from/to the RAM.
Warning: Memory instructions require aligned addresses.
- word (= 32 bits = 4 bytes): Requires address divisible by 4. The hex address must end with 0, 4, 8, or C.
- halfword (= 16 bits, = 2 bytes: Requires address divisible by 2. The hex address must end with one of: 0 2 4 6 8 A C E.
- byte (= 8 bits): No requirements.
lw
Load word
Example:
lw $t,C($s)
lh
Load halfword
Example:
lh $t,C($s)
lhu
Load halfword unsigned
Example:
lhu $t,C($s)
lb
Load byte
Example:
lb $t,C($s)
lbu
Load byte unsigned
Example:
lbu $t,C($s)
lwl
lwr
Load word left/right.
Used for unaligned loads (loads where you want a 4-byte word, but the address is not divisible by 4). For example, 0x80 is aligned, but 0x81, 0x82, and 0x83 are not aligned to 4.
lwr takes the first byte to load, while lwl takes the last byte.
Example: Assume r7 is aligned. To read the four bytes starting from r7+0x4e:
lwl r2,0x0051(r7) lwr r2,0x004e(r7)
sw
Store word
Example:
sw $t,C($s)
sh
Store half
Example:
sh $t,C($s)
sb
Store byte
Example:
sb $t,C($s)
lui
Load upper immediate
Loads the given 16-bit constant into the top 16 bits of the given register.
Not a memory access, but often used with memory access instructions.
Example:
lui $t,C
Comparison
Comparing numbers.
Set $d to 1 if true, 0 if false.
slt
Set on less than
Example:
slt $d,$s,$t
slti
Set on less than immediate
Example:
slti $t,$s,C
Binary
These instructions act on registers as sequences of 0's and 1's.
and
And
Example:
and $d,$s,$t
andi
And immediate
Example:
andi $t,$s,C
or
Or
Example:
or $d,$s,$t
ori
Or immediate
Example:
ori $t,$s,C
xor
Exclusive or
Example:
xor $d,$s,$t
nor
Nor
Example:
nor $d,$s,$t
sll
Shift left logical immediate
Example:
sll $d,$t,shamt
srl
Shift right logical immediate
Example:
srl $d,$t,shamt
sra
Shift right arithmetic immediate
Example:
sra $d,$t,shamt
sllv
Shift left logical
Example:
sllv $d,$t,$s
srlv
Shift right logical
Example:
srlv $d,$t,$s
srav
Shift right arithmetic
Example:
srav $d,$t,$s
Control
These instructions may or will cause a jump to a different part of the program.
The instruction right after one of these will always be executed, even if there's a jump.
beq
Branch on equal
Format:
beq $s,$t,C
bne
Branch on not equal
Format:
bne $s,$t,C
j
Jump. Jump to the given constant address.
Format:
j C
jr
Jump register. Like #j, but jumps to the address stored in the given register.
Format:
jr $s
jal
Jump and link. Used for calling subroutines.
Stores PC+8 (current instruction address plus 8) into r31, and then jump to the given constant. The idea is, when the subroutine is done, it will jump back to the instruction two steps after this one (thus, linking to PC+8).
Format:
jal C
jalr
Jump and link register. Like jal, but jumps to the address in the source register instead of to a constant.
The two-argument form also states which register to store the link (PC+8) into. The one-argument form assumes r31 is the destination register.
Warning: psxfin's disassembly has the arguments for the 2-arg form in the wrong order. This wiki and FFH's tools use the wrong order, for consistency with psxfin.
Format (psxfin):
jalr $s jalr $s,$d
Format (MIPS specification, page 117):
jalr $s jalr $d,$s