# MIPS Instruction Set

Last edited on 24 September 2022, at 22:16.

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):

1. R instructions - where all the data values used by the instruction are located in registers.
2. FR instructions - Like the R instructions but used for floating point numbers.
3. 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.
4. J instructions - where jumps are needed. The immediate jump offset can be up to 26 bits

### 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

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.

`\$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.

 `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.

`\$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