This lecture, number six in the Computer Organization discipline, will focus on the MIPS instruction set, explaining how the concepts of instruction set architecture are applied in a specific processor. MIPS is a didactic example widely used in textbooks, especially given one of its authors is also a MIPS designer. It's also a commercial processor found in embedded systems like routers, network equipment, storage devices, and printers. MIPS is chosen due to its RISC architecture characteristics, simplifying instruction formats for easier learning and demonstrating features typical of modern instruction sets.
The first MIPS design principle states that simplicity favors regularity. Simple and regular instructions lead to easier decoding, simpler hardware, and better processor performance. For instance, all arithmetic operations in MIPS have the same format: three operands (one destination, two sources), e.g., 'Add a b c' where 'a' receives 'b + c'. This standardized format simplifies instruction decoding and enhances performance.
The second principle, 'smaller is faster,' emphasizes the use of registers as operands because they offer faster access times compared to main memory. MIPS processors typically feature 32 32-bit registers, numbered 0 to 31. These registers are given special names in MIPS assembly language for ease of use, such as $t0 to $t9 for temporary values and $s0 to $s7 for saved values. The distinction between temporary (T) and saved (S) registers is crucial for procedure calls and interrupt handling, requiring specific saving and restoring protocols.
Among the 32 MIPS registers, register zero ($zero) has a special purpose: it always holds the constant value zero and cannot be overwritten. This design choice is significant because zero is a frequently used value in programming (e.g., for loop initializations, comparisons). By having a dedicated register for zero, the processor avoids the need to access memory for this value, leading to performance gains. It also facilitates operations like moving data between registers by adding the content of a register to $zero.
MIPS memory is byte-addressable, despite having a 32-bit word size (4 bytes). This flexibility allows accessing individual bytes, half-words (16 bits), or full words (32 bits). However, words must be aligned in memory, meaning they always start at addresses that are multiples of four. This alignment rule is critical for fetching instructions efficiently, as each instruction occupies a full word. MIPS also uses a 'big-endian' byte order, where the most significant byte of a word is stored at the lowest memory address.
An example demonstrates how to access memory in MIPS. For a C code snippet like 'g = h + A[8]', where A is an array, the MIPS assembly would first load the value of A[8] into a temporary register. This involves calculating the memory address by adding an offset (8 positions * 4 bytes/position = 32 bytes) to the base address of A, which is stored in another register. Once A[8] is loaded, it is then added to 'h' (also in a register), and the result is stored in 'g' (another register).
The third design principle, 'make the common case fast,' aligns with Amdahl's Law by optimizing frequently occurring operations. Besides the use of the zero register, MIPS optimizes for small constants (e.g., increments of 1 in loops) or small additions/subtractions. This leads to specialized instruction types that embed small constants directly within the instruction itself, avoiding the need to load them from memory. These 'immediate' values are typically 16 bits, allowing a range of values (e.g., -2^15 to +2^15 - 1).
MIPS defines different instruction formats to achieve regularity and efficiency. Type R instructions, used for operations involving only registers, comprise a 6-bit opcode, two 5-bit source register fields (rs, rt), a 5-bit destination register field (rd), a 5-bit shift amount field (shamt), and a 6-bit function code (funct). The function code extends the number of available operations by specifying the exact arithmetic or logical operation when the opcode identifies a general arithmetic type. For example, an 'add' instruction would use a specific opcode and a function code (e.g., 32 decimal) to identify the addition.
Type I instructions feature a 6-bit opcode, two 5-bit register fields (rs, rt), and a 16-bit immediate field. This immediate field can represent a small constant for arithmetic operations (e.g., 'addi' for add immediate) or an offset for memory access instructions (e.g., 'lw' for load word). For memory access, the 16-bit offset is sign-extended to 32 bits and added to the base address in register 'rs' to form the effective memory address. The result of a load operation is stored in register 'rt'.
The fourth design principle, 'good design demands compromises,' highlights the balance between desired functionalities and practical constraints. While a larger address range and constant values would be beneficial, maintaining a fixed 32-bit instruction format and regularity across instruction types necessitates trade-offs. Thus, the immediate field is limited to 16 bits, accepting a smaller range for constants and memory offsets to preserve the overall instruction structure.
Type I instructions are also used for conditional branches. These instructions compare the values of two registers (rs and rt) and, if the condition is met, branch to a new address. The 16-bit immediate field specifies the branch target, which is an offset added to the program counter. MIPS simplifies branching by offering only two types: 'branch if equal' (beq) and 'branch if not equal' (bne), requiring separate comparison operations for more complex conditions.
The final instruction format is Type J, used for unconditional jumps. These instructions have a 6-bit opcode and a 26-bit target address field. Since the full 32-bit address cannot fit, a new addressing mode is employed: the upper bits of the current Program Counter (PC) are combined with the 26-bit target address (left-shifted by two bits to account for byte addressing and word alignment) to form the final 32-bit jump address. This allows jumping to any address within the current 256MB segment, offering a broad range for unconditional transfers of control.