Here are tables of common MIPS instructions and what they do. If you want some in-context examples of when you’d use them, see the cookbook.
Arithmetic and Bitwise Instructions
All arithmetic and bitwise instructions can be written in two ways:
add t0, t1, t2
- adds two registers and puts the result in a third register.
- this does
t0 = t1 + t2
add t0, t1, 4
- adds a register and a constant and puts the result in a second register.
- this does
t0 = t1 + 4
The i
means “immediate,” since numbers inside instructions are called immediates.
Sometimes for this second form, you will see it written like addi
or subi
. These are completely equivalent, just a different name for the same instruction.
Mnemonic | Operation | Description |
---|---|---|
neg a, b |
a = -b |
gives the negative of b. |
add a, b, c |
a = b + c |
adds signed numbers. |
sub a, b, c |
a = b - c |
subtracts signed numbers. |
mul a, b, c |
a = b * c |
gives low 32 bits of signed multiplication. |
div a, b, c |
a = b / c |
gives quotient of signed division. |
rem a, b, c |
a = b % c |
gives remainder of signed division. |
addu a, b, c |
a = b + c |
adds unsigned numbers. |
subu a, b, c |
a = b - c |
subtracts unsigned numbers. |
mulu a, b, c |
a = b * c |
gives low 32 bits of unsigned multiplication. |
divu a, b, c |
a = b / c |
gives quotient of unsigned division. |
remu a, b, c |
a = b % c |
gives remainder of unsigned division. |
mfhi a |
a = HI |
after mul , gives high 32 bits. after div , gives remainder. |
mflo a |
a = LO |
after mul , gives low 32 bits. after div , gives quotient. |
not a, b |
a = ~b |
gives the bitwise complement of b (all bits flipped). |
and a, b, c |
a = b & c |
bitwise ANDs numbers. |
or a, b, c |
a = b | c |
bitwise ORs numbers. |
xor a, b, c |
a = b ^ c |
bitwise XORs numbers. |
Shift Instructions
MIPS decided to implement shifts a little differently than the rest of the arithmetic and bitwise instructions.
Mnemonic | Operation | Description |
---|---|---|
sll a, b, imm |
a = b << imm |
shift left by a constant amount. |
srl a, b, imm |
a = b >>> imm |
shift right unsigned (logical) by a constant amount. |
sra a, b, imm |
a = b >> imm |
shift right arithmetic by a constant amount. |
sllv a, b, reg |
a = b << reg |
shift left by the amount in a register. |
srlv a, b, reg |
a = b >>> reg |
shift right unsigned (logical) by the amount in a register. |
srav a, b, reg |
a = b >> reg |
shift right arithmetic by the amount in a register. |
Data Transfer Instructions
There are two “load” instructions which do not access memory. Also, move
does not move, it copies. THAT’S LIFE.
Mnemonic | Operation | Description |
---|---|---|
li a, imm |
a = imm |
put a constant value into a register. |
la a, label |
a = &label |
put the address that a label points to into a register. |
move a, b |
` a = b ` | copy value from one register to another. |
The rest of the load/store instructions always access memory. All of these instructions can be written in three different ways:
lw t0, var
- copies a word (32-bit value) from the memory variable
var
into registert0
var
must have been declared as something like:.data var: .word 0
- copies a word (32-bit value) from the memory variable
lw t0, (t1)
- copies a word from the memory address given by
t1
into registert0
- copies a word from the memory address given by
lw t0, 4(t1)
- copies a word from the memory address given by
t1 + 4
into registert0
- copies a word from the memory address given by
REMEMBER: stores copy values FROM registers TO memory. So FROM the left side TO the address on the right side.
Mnemonic | Operation | Description |
---|---|---|
lw reg, addr |
reg = MEM[addr] |
loads the 4 bytes at addr as a 32-bit value into reg . |
lh reg, addr |
reg = sxt(MEM[addr]) |
loads the 2 bytes at addr as a signed 16-bit value into reg . |
lb reg, addr |
reg = sxt(MEM[addr]) |
loads the 1 byte at addr as a signed 8-bit value into reg . |
lhu reg, addr |
reg = zxt(MEM[addr]) |
loads the 2 bytes at addr as an unsigned 16-bit value into reg . |
lbu reg, addr |
reg = zxt(MEM[addr]) |
loads the 1 byte at addr as an unsigned 8-bit value into reg . |
sw reg, addr |
MEM[addr] = reg |
stores the value of reg into memory as 4 bytes starting at addr . |
sh reg, addr |
MEM[addr] = lo16(reg) |
stores the low 16 bits of reg into memory as 2 bytes starting at addr . |
sb reg, addr |
MEM[addr] = lo8(reg) |
stores the low 8 bits of reg into memory as 1 byte at addr . |
Last, there are two stack (pseudo-)instructions which are used to save and restore values in functions:
Mnemonic | Operation | Description |
---|---|---|
push reg |
sp -= 4; MEM[sp] = reg |
pushes the value of reg onto the call stack |
pop reg |
reg = MEM[sp]; sp += 4 |
pops the top call stack value and puts it into reg |
Unconditional Control Flow Instructions
These always change the PC to a new location.
Mnemonic | Operation | Description |
---|---|---|
j label |
PC = label |
goes to the instruction at label . |
jal label |
ra = PC + 4; PC = label |
function call to label . stores return address in ra . |
jr reg |
PC = reg |
goes to the instruction whose address is in reg , often ra . |
syscall |
---> |
runs the system call function whose number is in v0 . |
Conditional Control Flow Instructions
All these instructions check the given condition, and if it’s:
- true, goes to the given label
- false, goes to the next instruction (i.e. it does nothing)
Also, all of these instructions can be written two ways:
blt t0, t1, label
- compares two registers (sees if
t0 < t1
)
- compares two registers (sees if
blt t0, 10, label
- compares a register to a constant (sees if
t0 < 10
)
- compares a register to a constant (sees if
Mnemonic | Operation | Description |
---|---|---|
beq a, b, label |
if(a == b) { PC = label } |
if a is equal to b , goes to label . |
bne a, b, label |
if(a != b) { PC = label } |
if a is NOT equal to b , goes to label . |
blt a, b, label |
if(a < b) { PC = label } |
if a is less than b , goes to label . |
ble a, b, label |
if(a <= b) { PC = label } |
if a is less than or equal to b , goes to label . |
bgt a, b, label |
if(a > b) { PC = label } |
if a is greater than b , goes to label . |
bge a, b, label |
if(a >= b) { PC = label } |
if a is greater than or equal to b , goes to label . |
bltu a, b, label |
if(a < b) { PC = label } |
same as blt but does an unsigned comparison. |
bleu a, b, label |
if(a <= b) { PC = label } |
same as ble but does an unsigned comparison. |
bgtu a, b, label |
if(a > b) { PC = label } |
same as bgt but does an unsigned comparison. |
bgeu a, b, label |
if(a >= b) { PC = label } |
same as bge but does an unsigned comparison. |