MIPS Instruction Set Architecture
The MIPS (Microprocessor without Interlocked Pipeline Stages) Instruction Set Architecture (ISA) is one of the most widely studied and implemented ISAs in the field of computer science and engineering. Developed in the early 1980s at Stanford University by a team led by John L. Hennessy, the MIPS architecture is renowned for its simplicity, efficiency, and scalability.
What is an ISA?
An Instruction Set Architecture (ISA) is a crucial interface between hardware and software in a computer system. It defines the set of instructions that a processor can execute, including arithmetic operations, data manipulation, control flow instructions, and memory access commands. The ISA serves as a blueprint for designing both hardware (CPU) and software (compilers, operating systems).
Why MIPS?
The MIPS architecture is particularly favored in educational settings for several reasons:
Simplicity: MIPS has a small, regular instruction set, making it easier to learn and understand.
RISC Principles: MIPS is a classic example of a Reduced Instruction Set Computer (RISC) architecture, which uses a small number of simple instructions for efficient performance.
Scalability: MIPS architecture is scalable, allowing it to be used in a wide range of applications, from embedded systems to high-performance computing.
Educational Tools: A variety of simulation tools and resources are available for learning and experimenting with MIPS, including the SPIM simulator and MARS (MIPS Assembler and Runtime Simulator).
Key Features of MIPS ISA
Load/Store Architecture: MIPS uses a load/store architecture where operations are performed on registers, and only load and store instructions access memory.
Fixed Instruction Length: All MIPS instructions are 32 bits long, simplifying instruction decoding.
Three-Operand Format: Most arithmetic instructions use a three-operand format (e.g.,
ADD R1, R2, R3
), enhancing readability and reducing the need for complex instruction decoding.Pipeline-Friendly: The design of the MIPS instruction set facilitates pipelining, a technique used to increase the throughput of a processor.
MIPS Instruction Categories
MIPS instructions are categorized into three main types:
R-type (Register): Instructions that perform operations on registers. Example:
ADD R1, R2, R3
.I-type (Immediate): Instructions that use an immediate value. Example:
ADDI R1, R2, 10
.J-type (Jump): Instructions for control flow changes. Example:
J label
.
Understanding MIPS Registers
In the MIPS Instruction Set Architecture (ISA), registers play a crucial role in the execution of instructions. Registers are small, fast storage locations within the CPU that hold data to be processed. MIPS has 32 general-purpose registers, each 32 bits wide, as well as a few special-purpose registers.
General-Purpose Registers
MIPS registers are conventionally named and numbered for ease of use. Here's a detailed breakdown of these registers:
Register Name | Register Number | Alias | Description |
$zero | 0 | - | Constant value 0 |
$at | 1 | - | Assembler temporary |
$v0-$v1 | 2-3 | - | Function return values |
$a0-$a3 | 4-7 | - | Function arguments |
$t0-$t7 | 8-15 | - | Temporary registers, not preserved across calls |
$s0-$s7 | 16-23 | - | Saved registers, preserved across calls |
$t8-$t9 | 24-25 | - | Additional temporary registers |
$k0-$k1 | 26-27 | - | Reserved for kernel use |
$gp | 28 | - | Global pointer |
$sp | 29 | - | Stack pointer |
$fp | 30 | - | Frame pointer |
$ra | 31 | - | Return address |
Special-Purpose Registers
In addition to the general-purpose registers, MIPS includes several special-purpose registers:
Register Name | Description |
HI | High result of multiplication and division operations |
LO | Low result of multiplication and division operations |
PC | Program Counter, holds the address of the next instruction to be executed |
Detailed Descriptions
General-Purpose Registers
$zero (Register 0): Always contains the constant value 0. Any attempt to write to this register is ignored.
$at (Register 1): Reserved for use by the assembler.
$v0-$v1 (Registers 2-3): Used to hold the return values of functions.
$a0-$a3 (Registers 4-7): Used to pass the first four arguments to functions.
$t0-$t7 (Registers 8-15): Temporary registers that are not preserved across function calls. Can be used freely within a function.
$s0-$s7 (Registers 16-23): Saved registers that must be preserved across function calls. If a function uses these registers, it must save their values and restore them before returning.
$t8-$t9 (Registers 24-25): Additional temporary registers, similar to
$t0-$t7
.$k0-$k1 (Registers 26-27): Reserved for operating system kernel use.
$gp (Register 28): Global pointer, used to access static data.
$sp (Register 29): Stack pointer, points to the top of the stack.
$fp (Register 30): Frame pointer, used to reference the base of the current stack frame.
$ra (Register 31): Return address, holds the return address for function calls.
Special-Purpose Registers
HI and LO Registers: These are used to store the results of multiplication and division operations. For example, after a multiplication operation, the higher-order 32 bits of the result are stored in
HI
and the lower-order 32 bits are stored inLO
.Program Counter (PC): This register holds the address of the next instruction to be executed. It is automatically updated by the CPU as instructions are executed.
MIPS Instruction Categories
MIPS instructions are grouped into several categories based on their functionality. Here's a summary of the main instruction categories in the MIPS ISA:
Instruction Category | Description |
Arithmetic Instructions | Perform arithmetic operations like addition, subtraction, multiplication, and division. |
Logical Instructions | Perform bitwise logical operations like AND, OR, XOR, and NOT. |
Data Transfer Instructions | Move data between registers and memory (load and store operations). |
Control Flow Instructions | Change the sequence of instruction execution (branching, jumping). |
Comparison Instructions | Compare values and set flags or produce results based on the comparison. |
Shift Instructions | Perform bit shifting operations (left shift, right shift). |
Immediate Instructions | Use immediate (constant) values as operands. |
Special Instructions | Include miscellaneous operations like NOP (no operation) and system calls. |
Arithmetic Instructions
Name | Assembler Format | Operation | Type | Opcode | Function Code |
ADD | ADD rd, rs, rt | rd = rs + rt | R | 000000 | 100000 |
ADDI | ADDI rt, rs, imm | rt = rs + imm | I | 001000 | - |
ADDU | ADDU rd, rs, rt | rd = rs + rt | R | 000000 | 100001 |
ADDIU | ADDIU rt, rs, imm | rt = rs + imm | I | 001001 | - |
SUB | SUB rd, rs, rt | rd = rs - rt | R | 000000 | 100010 |
SUBU | SUBU rd, rs, rt | rd = rs - rt | R | 000000 | 100011 |
MULT | MULT rs, rt | HI:LO = rs * rt | R | 000000 | 011000 |
MULTU | MULTU rs, rt | HI:LO = rs * rt (unsigned) | R | 000000 | 011001 |
DIV | DIV rs, rt | LO = rs / rt, HI = rs % rt | R | 000000 | 011010 |
DIVU | DIVU rs, rt | LO = rs / rt, HI = rs % rt (unsigned) | R | 000000 | 011011 |
Logical Instructions
Name | Assembler Format | Operation | Type | Opcode | Function Code |
AND | AND rd, rs, rt | rd = rs AND rt | R | 000000 | 100100 |
ANDI | ANDI rt, rs, imm | rt = rs AND imm | I | 001100 | - |
OR | OR rd, rs, rt | rd = rs OR rt | R | 000000 | 100101 |
ORI | ORI rt, rs, imm | rt = rs OR imm | I | 001101 | - |
XOR | XOR rd, rs, rt | rd = rs XOR rt | R | 000000 | 100110 |
XORI | XORI rt, rs, imm | rt = rs XOR imm | I | 001110 | - |
NOR | NOR rd, rs, rt | rd = ~(rs OR rt) | R | R | R |
Data Transfer Instructions
Name | Assembler Format | Operation | Type | Opcode | Function Code |
LW | LW rt, offset(rs) | rt = Memory[rs + offset] | I | 100011 | - |
SW | SW rt, offset(rs) | Memory[rs + offset] = rt | I | 101011 | - |
LB | LB rt, offset(rs) | rt = Memory[rs + offset] (byte) | I | 100000 | - |
SB | SB rt, offset(rs) | Memory[rs + offset] = rt (byte) | I | 101000 | - |
LUI | LUI rt, imm | rt = imm << 16 | I | 001111 | - |
Control Flow Instructions
Name | Assembler Format | Operation | Type | Opcode | Function Code | ||
J | J target | PC = PC[31:28] then append (target « 2) | J | 000010 | |||
JAL | JAL target | ra = PC + 4, PC = PC[31:28] then append (target « 2) | J | 000011 | |||
JR | JR rs | PC = rs | R | 000000 | 001000 | ||
BEQ | BEQ rs, rt, offset | if (rs == rt) PC = PC + 4 + (offset << 2) | I | 000100 | - | ||
BNE | BNE rs, rt, offset | if (rs != rt) PC = PC + 4 + (offset << 2) | I | 000101 | - | ||
BGEZ | BGEZ rs, offset | if (rs >= 0) PC = PC + 4 + (offset << 2) | I | 000001 | - |
Comparison Instructions
Name | Assembler Format | Operation | Type | Opcode | Function Code |
SLT | SLT rd, rs, rt | rd = (rs < rt) | R | 000000 | 101010 |
SLTI | SLTI rt, rs, imm | rt = (rs < imm) | I | 001010 | - |
SLTU | SLTU rd, rs, rt | rd = (rs < rt) (unsigned) | R | 000000 | 101011 |
SLTIU | SLTIU rt, rs, imm | rt = (rs < imm) (unsigned) | I | 001011 | - |
Shift Instructions
Name | Assembler Format | Operation | Type | Opcode | Function Code |
SLL | SLL rd, rt, sa | rd = rt << sa | R | 000000 | 000000 |
SRL | SRL rd, rt, sa | rd = rt >> sa | R | 000000 | 000010 |
SRA | SRA rd, rt, sa | rd = rt >>> sa | R | 000000 | 000011 |
SLLV | SLLV rd, rt, rs | rd = rt << rs | R | 000000 | 000100 |
SRLV | SRLV rd, rt, rs | rd = rt >> rs | R | 000000 | 000110 |
SRAV | SRAV rd, rt, rs | rd = rt >>> rs | R | 000000 | 000111 |
Special Instructions
Name | Assembler Format | Operation | Type | Opcode | Function Code |
NOP | SLL $0, $0, 0 | No operation | R | 000000 | 000000 |
SYSCALL | SYSCALL | System call | Special | 000000 | 001100 |
BREAK | BREAK | Breakpoint | Special | 000000 | 001101 |
Legend
rs
,rt
,rd
: Source and destination registers.immediate
: Immediate value (a constant).sa
: Shift amount.HI
,LO
: Special registers used for multiplication and division results.PC
: Program Counter, the address of the next instruction.[address]
: Memory address.[rs]
: Address contained in registerrs
.[x:y]
: Slice of bits from x to y (inclusive).<<
: Left shift operator.>>
: Logical right shift operator.>>>
: Arithmetic right shift operator (preserves the sign bit).^
: Bitwise XOR operator.&
: Bitwise AND operator.\|
: Bitwise OR operator.~
: Bitwise NOT operator.R-type: Register type instructions.
I-type: Immediate type instructions.
J-type: Jump type instructions.
Special: Instructions that do not fit into the R, I, or J types.
MIPS Instruction Encodings
In the MIPS Instruction Set Architecture, different types of instructions have specific binary encodings. Each instruction type is encoded using a fixed format that specifies the opcode, registers, immediate values, and other relevant information.
R-Type Instructions
R-type instructions are used for arithmetic and logical operations, and they have the following encoding format:
31-26 | 25-21 | 20-16 | 15-11 | 10-6 | 5-0 |
opcode | rs | rt | rd | shamt | funct |
opcode: 6 bits (always 000000 for R-type instructions)
rs: Source register (5 bits)
rt: Second source register (5 bits)
rd: Destination register (5 bits)
shamt: Shift amount (5 bits, used only for shift instructions)
funct: Function code (6 bits, specifies the exact operation)
I-Type Instructions
I-type instructions are used for immediate arithmetic, logical operations, and data transfer. They have the following encoding format:
31-26 | 25-21 | 20-16 | 15-0 |
opcode | rs | rt | immediate |
opcode: 6 bits (specifies the operation)
rs: Source register (5 bits)
rt: Destination register or source/destination register (5 bits)
immediate: Immediate value or address offset (16 bits)
J-Type Instructions
J-type instructions are used for jump operations. They have the following encoding format:
31-26 | 25-0 |
opcode | address |
opcode: 6 bits (specifies the operation)
address: Target address (26 bits)
Special Instructions
Special instructions have unique formats and are used for operations like system calls and breakpoints. Here are the typical formats:
SYSCALL Instruction
The SYSCALL instruction has the following format:
31-26 | 25-6 | 5-0 |
000000 | sys_code | 001100 |
opcode: 6 bits (always 000000 for SYSCALL)
sys_code: System call code (20 bits, usually zero for standard syscall)
funct: Function code (6 bits, always 001100 for SYSCALL)
BREAK Instruction
The BREAK instruction has the following format:
31-26 | 25-6 | 5-0 |
000000 | break_code | 001101 |
opcode: 6 bits (always 000000 for BREAK)
break_code: Breakpoint code (20 bits)
funct: Function code (6 bits, always 001101 for BREAK)
Encoding Summary
R-Type: Encodes the operation with a function code and uses three registers (rs, rt, rd) and an optional shift amount.
I-Type: Encodes the operation with an opcode and uses two registers (rs, rt) and an immediate value or address offset.
J-Type: Encodes the operation with an opcode and a large address field for jumps.
Special: Unique formats for system calls and breakpoints with specific function codes.
Subscribe to my newsletter
Read articles from Jyotiprakash Mishra directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Jyotiprakash Mishra
Jyotiprakash Mishra
I am Jyotiprakash, a deeply driven computer systems engineer, software developer, teacher, and philosopher. With a decade of professional experience, I have contributed to various cutting-edge software products in network security, mobile apps, and healthcare software at renowned companies like Oracle, Yahoo, and Epic. My academic journey has taken me to prestigious institutions such as the University of Wisconsin-Madison and BITS Pilani in India, where I consistently ranked among the top of my class. At my core, I am a computer enthusiast with a profound interest in understanding the intricacies of computer programming. My skills are not limited to application programming in Java; I have also delved deeply into computer hardware, learning about various architectures, low-level assembly programming, Linux kernel implementation, and writing device drivers. The contributions of Linus Torvalds, Ken Thompson, and Dennis Ritchie—who revolutionized the computer industry—inspire me. I believe that real contributions to computer science are made by mastering all levels of abstraction and understanding systems inside out. In addition to my professional pursuits, I am passionate about teaching and sharing knowledge. I have spent two years as a teaching assistant at UW Madison, where I taught complex concepts in operating systems, computer graphics, and data structures to both graduate and undergraduate students. Currently, I am an assistant professor at KIIT, Bhubaneswar, where I continue to teach computer science to undergraduate and graduate students. I am also working on writing a few free books on systems programming, as I believe in freely sharing knowledge to empower others.