MIPS Assembly Language


MIPS Structure has 32 registers, which are shown in the following table:

Number Name Description
$0 $zero $zero register holds the value of 0 as a constant.
$1 $at Reserved for pseudo instructions such as Move
$2 - $3 $v0, $v1 Save the return value of an expression or function.($v0 for 32-bit value)
$4 - $7 $a0 - $a3 Save the arguments of function, more arguments are saved in stack.
$8 - $15 $t0 - $t7 Temporary data created by subprogram, not preserved.
$16 - $23 $s0 - $s7 Saved registers, it means callee should restore it.
$24 - $25 $t8 - $t9 Extra temporary registers, and $9 is often associated with function calling.
$26 - $27 $k0 - $k1 Reserved for kernel, not ought to be used.(see more in interrupt handler)
$28 $gp Points to the global environment area, do not use.
$31 $pc(ra) Program Counter, points to the position of handler.
$29 - $30 $hi, $lo Save the answer of multiply and divide. $hi for remainder and $lo for divider.

These are registers for 32-bit MIPS, and 64-bit has more.

Registers can be divided into 3 categories, caller saved, callee saved and system saved. Caller saved means caller should save the value in these registers before calling a function. Callee saved means before returning to caller function, callee should restore these registers, or ought to do so. System saved like $zero and $gp is preserved for kernel usage.

A function related to $pc is advance_pc(int), it decides the steps of $pc, i.e.:

function advance_pc(offset):
	PC = nPC;
	nPC += offset;


In MIPS, there are two different data types, sign-extended and unsigned. The main difference between them is overflow exceptions. While sign-extended type overflowed when adding or multiplying, unsigned does not. Unsigned is often marked with an 'U' in commands.

Sometimes we load a value into register or memory for future usage, or use it immediately. Immediate use is often marked with an 'I' in commands.

Next I will introduce all MIPS instructions(except pseudo instructions), I will classify them in different categories.

  1. add, addi, addu and addiu.

    Syntax: <command> <saved_register>, <addend>, <augend>

    the differences have been shown above.

    The four commands are all used for add two values together and save it into a register.

    Example: add $t0, $t0, $t1

  2. and and andi.

    Syntax: <command> <saved_register>, <andv1>, <andv2>

    the differences have been shown above.

    Perform bitwise and, save the value into a register.

    Example: and $s1, $s1, 42

  3. beq, bgez, bgezal, bgtz, blez, bltz, bltzal and bne.

    Syntax: the beq and bne is <command> <comp1>, <comp2>, <offset>, and others are <command> <comp>, <offset>

    beq means branch when equal and bne comes opposite. "al" means "and link", so these command saves the return value in $ra as an extra action. "ge" means "greater or equal" while "le" means "less or equal". Except beq and bne, the object to compare is always zero. These commands show us the ability of MIPS to express conditional branch.

    Example: bgezal $t0, 2

  4. div and divu.

    Syntax: <command> <dividend>, <divisor>

    As mentioned above, register $hi saves the remainder and $lo saves the divider. The differences have been mentioned above.

    Perform divide and save the value into $hi and $lo.

    Example: div $s0 $t0

  5. j, jal and jr.

    Syntax: <command> <target_or_register>

    The three instructions make jump over memory address or registers. "al" means "and link" also. So the return value will be saved in $31. and "r" means "register" simply. Jump is an absolute function. How the $pc makes move is shown below:

    j: PC =nPC; nPC = (PC & 0xf0000000) | (target<<2); jr: PC=nPC; nPC = $s;

    Example: jr $s0

  6. lb, lui and lw.

    Syntax: <command> <register>, <offset_or_value>(<address_if_offset>)

    They load some data into a given register. The differences among them are: lb means load bytes into the 32-bit register, and extend the most significant bit into upper 24 bit, for example: lb $s0, 0(0x10000000), and data in 0x10000000 is 0x88 0x45 0x57 0x61, then lb instruction will load 0x88 into the $s0, since 0x88's msb is 1, the answer should be 0xffffff88. lui loads a immediate value into register and shift left 16 bits, so the lower 16 bits are all zero. lw means load a word into register, therefore, it requests the address be word-aligned(multiple of 4).

    Example: lw $t0 8($v0)

  7. mfhi and mflo.

    Syntax: <command> <register>

    Move the value in $hi or $lo into a register.

    Example: mfhi $a0

  8. mult and multu.

    Syntax: <command> <multiplier>, <multiplyee>

    Multiply the value in two registers and store it in $lo(more than 32 bits will be saved in $hi).

    The differences have been mentioned above.

    Example: multu $s0 $s1

  9. noop.

    Syntax: <command>

    Simply do nothing. In fact, noop is a pseudo instruction of SLL $0 $0 0, and all instructions which have a destination of $zero will have no side effect to program.

  10. or and ori.

    Syntax: <command> <saved_register>, <or1>, <or2>

    Bitwise or and save the value into a register.

    The differences have been mentioned above.

    Example: or $s0 $t0 $t1

  11. sb and sw.

    Syntax: <command> <source_reg>, <offset>(<destination>)

    Just like lb and lw, sb saves the least significant byte from register into given address. and sw means store the whole content of register into given address.

    Example: sw $t0 0($s0)

  12. sub and subu.

    Syntax: <command> <saved_register>, <subtracted>, <subtraction>

    Subtract two registers and store the value into a register. The differences have been mentioned above.

    Example: sub $s0, $t0, $t1

  13. sll, sllv, sra, srl and srlv.

    Syntax: <command> <save_register>, <source_register>, <value_or_register>

    Shift means bitwise move. and the first "l" means left while "r" represents right. The second "l" has the meaning of "logical", so the shifted bit will be filled by zero. "a" means "arithmetic", so the shifted bit will be covered by sign bit. At last, 'v' represents variable, the shift bit number comes from a register.

    Example: srlv $r0, $a0, $t0

  14. slt, slti, sltu and sltiu.

    Syntax <command> <saved_register>, <compare_reg>, <value_or_register>

    slt represents "set on less than", so if the compared register is less than the compare value, no matter a register or an immediate value, the saved register will be set to 1, else 0. The differences have been mentioned above.

    Example: sltiu $s0, $t0, 10

  15. xor and xori.

    Syntax: <command> <saved_register>, <xor1>, <xor2>

    Bitwise exclusive or on two registers and store the value into a register. The differences have been mentioned above.

    Example: xor $a0, $t0, $t1

  16. syscall.

    Syntax: <command>

    Generate a system interrupt.

All MIPS instructions will be encoded into a 32 bits command in machines. Remember that instructions are no more than data. PC will show CPU how to find, decode and exectute the instructions. ISA defines the format of a command. While OPCODE analyze semantics, OPERAND deals with input and output of a instruction.

The MIPS instructions can be divided into three different types: I-type(immediate), R-type(register) and J-type(Jump).

I-type: OPCODE rs rt imme We allow 6 bits for OPCODE and 5 bits for registers, so there leaves 16 bits for immediate values.

R-type: 0 rd rs rt The opcode for all R-types are zero, and the 16 bits for immediate value in I-type are split into three parts: 5 bits for rd the destination, 5 bits for shift amount and 6 bits for function code.

J-type: OPCODE address, we only have 26 bits for address, but an address in MIPS is 32 bits long. To solve this problem, we can shift left two bits for address and gets another 4 bits by combining with high-order bit of PC.

The branch type likes J-type, but we divide the offset by 4 to leave some space for encode (>, <, >=, <=).


I mainly learned MIPS Assembly Language from UIDAHO's website.

The encoding for MIPS instructions come from UW's course CSE378.

I have looked up so many Stack Overflow questions that I cannot list them all.