MIPS Instruction Set
The MIPS instruction set is relatively easy to read since all instructions are 32 bits.
There are 4 types of instructions (though R and FR are basically the same):
- R instructions - where all the data values used by the instruction are located in registers.
- FR instructions - Like the R instructions but used for floating point numbers.
- I instructions - where the instruction must operate on an immediate value and a register value. Immediate values may be a maximum of 16 bits long.
- J instructions - where jumps are needed. The immediate jump offset can be up to 26 bits
See: https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats
MIPS overview
Instruction | Name | Action | Fields | |||||
---|---|---|---|---|---|---|---|---|
R instruction | Used when all the data values used by the instruction are located in registers. | Opcode
6 bits |
Reg Source
(rs, 5 bits) |
Reg Source
(rt, 5 bits) |
Reg Dest
(rd, 5 bits) |
Shift
(shamt) 5 bits |
Function
6 bits | |
I instruction | Used when the instruction must operate on an immediate value and a register value.
Immediate values may be a maximum of 16 bits long. |
Opcode
6 bits |
Reg Source
(rs, 5 bits) |
Reg Source
(rt, 5 bits) |
Immediate value
16 bits | |||
J instruction | Used when jumps are needed.
The immediate jump offset can be up to 26 bits |
Opcode
6 bits |
Address (26 bits) | |||||
Arithmetic Logic Unit | ||||||||
ADD rd, rs, rt
|
Add | rd = rs + rt
|
000000 | rs | rt | rd | 00000 | 100000 |
ADDI rt, rs, imm
|
Add Immediate | rt = rs + imm
|
001000 | rs | rt | imm | ||
ADDIU rt, rs, imm
|
Add Immediate Unsigned (no 2's complement) | rt = rs + imm
|
001001 | rs | rt | imm | ||
ADDU rd, rs, rt
|
Add Unsigned | rd = rs + rt
|
000000 | rs | rt | rd | 00000 | 100001 |
SUB rd, rs, rt
|
Subtract | rd = rs - rt
|
000000 | rs | rt | rd | 00000 | 100010 |
SUBU rd, rs, rt
|
Subtract Unsigned | rd = rs - rt
|
000000 | rs | rt | rd | 00000 | 100011 |
AND rd, rs, rt
|
And | rd = rs & rt
|
000000 | rs | rt | rd | 00000 | 100100 |
ANDI rt, rs, imm
|
And Immediate | rt = rs & imm
|
001100 | rs | rt | imm | ||
NOR rd, rs, rt
|
NOR | rd = ~(rs|rt)
|
000000 | rs | rt | rd | 00000 | 100111 |
OR rd, rs, rt
|
OR | rd = rs|rt
|
000000 | rs | rt | rd | 00000 | 100101 |
ORI rt, rs, imm
|
OR Immediate | rt = rs|imm
|
001101 | rs | rt | imm | ||
SLT rd, rs, rt
|
Set On Less Than | rd = (rs < rt) ? 1 : 0
|
000000 | rs | rt | rd | 00000 | 101010 |
SLTI rt, rs, imm
|
Set On Less Than Immediate | rt = (rs < imm) ? 1 : 0
|
001010 | rs | rt | imm | ||
SLTIU rt, rs, imm
|
Set On < Immediate Unsigned | rt = (rs < imm) ? 1 : 0
|
001011 | rs | rt | imm | ||
SLTU rd, rs, rt
|
Set On Less Than Unsigned | rd = (rs < rt) ? 1 : 0
|
000000 | rs | rt | rd | 00000 | 101011 |
XOR rd, rs, rt
|
Exclusive OR | rd = rs ^ rt
|
000000 | rs | rt | rd | 00000 | 100110 |
XORI rt, rs, imm
|
Exclusive OR Immediate | rt = rs ^ imm
|
001110 | rs | rt | imm | ||
Logical Shifts | ||||||||
SLL rd, rt, sa
|
Shift Left Logical | rd = rt << sa
|
000000 | rs | rt | rd | sa | 000000 |
SLLV rd, rt, rs
|
Shift Left Logical Variable | rd = rt << rs
|
000000 | rs | rt | rd | 00000 | 000100 |
SRA rd, rt, sa
|
Shift Right Arithmetic | rd = rt >> sa
|
000000 | rs=00000 | rt | rd | sa | 000011 |
SRAV rd, rt, rs
|
Shift Right Arithmetic Variable | rd = rt >> rs
|
000000 | rs | rt | rd | 00000 | 000111 |
SRL rd, rt, sa
|
Shift Right Logical | rd = rt >> sa
|
000000 | rs | rt | rd | sa | 000010 |
SRLV rd, rt, rs
|
Shift Right Logical Variable | rd = rt >> rs
|
000000 | rs | rt | rd | 00000 | 000110 |
Multiply | ||||||||
DIV rs, rt
|
Divide | HI= rs % rt; LO = rs/rt
|
000000 | rs | rt | 0000000000 | 011010 | |
DIVU rs, rt
|
Divide Unsigned | HI= rs % rt; LO = rs/rt
|
000000 | rs | rt | 0000000000 | 011011 | |
MFHI rd
|
Move From HI | rd = HI
|
000000 | 0000000000 | rd | 00000 | 010000 | |
MFLO rd
|
Move From LO | rd = LO
|
000000 | 0000000000 | rd | 00000 | 010010 | |
MTHI rs
|
Move To HI register | HI= rs
|
000000 | rs | 000000000000000 | 010001 | ||
MTLO rs
|
Move To LO register | LO = rs
|
000000 | rs | 000000000000000 | 010011 | ||
MULT rs, rt
|
Multiply | HI, LO = rs*rt
|
000000 | rs | rt | 0000000000 | 011000 | |
MULTU rs, rt
|
Multiply Unsigned | HI, LO = rs*rt
|
000000 | rs | rt | 0000000000 | 011001 | |
Branch | ||||||||
BEQ rs, rt, offset
|
Branch On Equal | if (rs == rt) pc = pc + 4 + offset
|
000100 | rs | rt | offset | ||
BGEZ rs, offset
|
Branch On >= 0 | if (rs >= 0) pc = pc + 4 + offset
|
000001 | rs | rt=00001 | offset | ||
BGEZAL rs, offset
|
Branch On >= 0 and link. Saves return address in $ra | $ra = pc; if (rs>= 0) pc = pc + 4 + offset
|
000001 | rs | rt=10001 | offset | ||
BGTZ rs, offset
|
Branch On > 0 | if (rs>0) pc = pc + 4 + offset
|
000111 | rs | rt=00000 | offset | ||
BLEZ rs, offset
|
Branch On | if (rs<= 0) pc = pc + 4 + offset
|
000110 | rs | rt=00000 | offset | ||
BLTZ rs, offset
|
Branch On < 0 | if (rs<0) pc = pc + 4 + offset
|
000001 | rs | rt=00000 | offset | ||
BLTZAL rs, offset
|
Branch On < 0 and link. Saves return address in $ra | $ra = pc; if (rs<0) pc = pc + 4 + offset
|
000001 | rs | rt=10000 | offset | ||
BNE rs, rt, offset
|
Branch On Not Equal | if (rs != rt) pc = pc + 4 + offset
|
000101 | rs | rt | offset | ||
bgt $1,$2,100
|
branch on greater than | if ($1 > $2) pc = pc + 4 + 100
|
Pseudo instruction | |||||
bge $1,$2,100
|
branch on greater than or equal | if ($1 >= $2) pc = pc + 4 + 100
|
Pseudo instruction | |||||
blt $1,$2,100
|
branch on less than | if ($1 < $2) pc = pc + 4 + 100
|
Pseudo instruction | |||||
ble $1,$2,100
|
branch on less than or equal | if ($1 <= $2) pc = pc + 4 + 100
|
Pseudo instruction | |||||
BREAK
|
Breakpoint | epc = pc; pc = 0x3c
|
000000 | code | 001101 | |||
J target
|
Jump | pc = pc_upper|(target<<2)
|
000010 | target | ||||
JAL target
|
Jump and link.
Saves return address in $ra |
$ra = pc + 4; pc = target<<2
|
000011 | target | ||||
JR rs
|
Jump register | pc = rs
|
000000 | rs | rt=00000 | rd=00000 | 00000 | 001000 |
JALR rs
|
Jump and link register.
Like JR, but return address saved in specified register. |
$ra = pc + 4; pc = rs
|
000000 | rs | rt=00000 | rd | 00000 | 001001 |
MFC0 rt, rd
|
Move From Coprocessor | rt = CPR[0, rd]
|
010000 | 00000 | rt | rd | 00000000000 | |
MTC0 rt, rd
|
Move To Coprocessor | CPR[0, rd]= rt
|
010000 | 00100 | rt | rd | 00000000000 | |
SYSCALL
|
System Call | epc = pc; pc = 0x3c
|
000000 | 00000000000000000000 | 001100 | |||
Memory Access | ||||||||
LB rt, imm(rs)
|
Load Byte | rt = (char) Mem[rs + imm]
|
100000 | rs | rt | imm | ||
LBU rt, imm(rs)
|
Load Byte Unsigned | rt = (uchar) Mem[rs + imm]
|
100100 | rs | rt | imm | ||
LH rt, imm(rs)
|
Load Halfword, 2 bytes | rt = (short) Mem[rs + imm]
|
100001 | rs | rt | imm | ||
LHU rt, imm(rs)
|
Load Halfword Unsigned | rt = (ushort) Mem[rs + imm]
|
100101 | rs | rt | imm | ||
LW rt, imm(rs)
|
Load Word, 4 bytes. | rt = Mem[rs + imm]
|
100011 | rs | rt | imm | ||
LUI rt, imm
|
Load Upper Immediate | rt = imm << 16
|
001111 | rs=00000 | rt | imm | ||
SB rt, imm(rs)
|
Store (least significant) byte | Mem[rs + imm] = (byte) rt
|
101000 | rs | rt | imm | ||
SH rt, imm(rs)
|
Store (least significant) halfword content of rt | Mem[rs + imm] = (short) rt
|
101001 | rs | rt | imm | ||
SW rt, imm(rs)
|
Store content of rt in memory | Mem[rs + imm] = rt
|
101011 | rs | rt | imm |
Pseudo instructions
There are pseudo instructions that are provided by your assembler and are converted to multiple instructions. Think of these as assembler macros.
See: https://en.wikibooks.org/wiki/MIPS_Assembly/Pseudoinstructions
move $1, $2
|
Move data from one register to another | $1 = $2
|
li $1,100
|
Loads immediate value into register | $1 = 100
|
la $1,label
|
Loads computed address of label (not its contents) into register | $1 = Address of label
|
bgt $1,$2,100
|
branch on greater than | if ($1 > $2) pc = pc + 4 + 100
|
bge $1,$2,100
|
branch on greater than or equal | if ($1 >= $2) pc = pc + 4 + 100
|
blt $1,$2,100
|
branch on less than | if ($1 < $2) pc = pc + 4 + 100
|
ble $1,$2,100
|
branch on less than or equal | if ($1 <= $2) pc = pc + 4 + 100
|
abs $1, $2
|
Puts the absolute value from one register ao another | $1 = abs($2) |
neg
|
||
negu
|
||
not
|
||
sge
|
||
sgt
|
||
NOP
|
No operation. This can be done by running SLL $0 $0 $0 or 32bits of 0's.
|
Registers
All the register fields are 5 bits in size giving us 32 registers in total to work with.
All 32 registers are listed in the following table.
Register | Decimal | Binary | Comments |
---|---|---|---|
$zero
|
$0
|
00000
|
Always zero |
$at
|
$1
|
00001
|
used for temporary values within pseudo commands |
$v0
|
$2
|
00010
|
used for returning values from functions
first and second, respectively. |
$v1
|
$3
|
00011
| |
$a0
|
$4
|
00100
|
used for the first 4 function arguments. |
$a1
|
$5
|
00101
| |
$a2
|
$6
|
00110
| |
$a3
|
$7
|
00111
| |
$t0
|
$8
|
01000
|
temporary registers. 8 in total |
$t1
|
$9
|
01001
| |
$t2
|
$10
|
01010
| |
$t3
|
$11
|
01011
| |
$t4
|
$12
|
01100
| |
$t5
|
$13
|
01101
| |
$t6
|
$14
|
01110
| |
$t7
|
$15
|
01111
| |
$s0
|
$16
|
10000
|
Saved values representing final computed results |
$s1
|
$17
|
10001
| |
$s2
|
$18
|
10010
| |
$s3
|
$19
|
10011
| |
$s4
|
$20
|
10100
| |
$s5
|
$21
|
10101
| |
$s6
|
$22
|
10110
| |
$s7
|
$23
|
10111
| |
$t8
|
$24
|
11000
|
Two additional temporary registers |
$t9
|
$25
|
11001
| |
$k0
|
$26
|
11010
|
Registers reserved for the kernel / operating system |
$k1
|
$27
|
11011
| |
$gp
|
$28
|
11100
|
Global pointer |
$sp
|
$29
|
11101
|
Stack pointer |
$fp
|
$30
|
11110
|
Frame pointer |
$ra
|
$31
|
11111
|
Return address |