-
address is a value used to specify the location of a specific data element within a memory array
-
mips is a reduced instruction set computer (RISC) instruction set architecture (ISA) developed by MIPS Computer Systems, now MIPS Technologies, based in the United States
-
MIPS has a load-store architecture, meaning it only performs arithmetic and logic operations between registers, and memory access is done through load/store instructions
-
the endianness of MIPS is big-endian
-
A word is 32 bits (4 bytes) long
-
To access an element at a given index, the index is multiplied by the size of each element (often 4 bytes for integers) to calculate the offset.
- This offset is added to the base address of the array to locate the specific element.
- The base address is the memory location of the first element of the array, typically stored in a register. All elements are accessed relative to this address by calculating their offsets.
-
MIPS assembly language
-
alignment restriction is a requirement that data be aligned in memory on natural boundaries
Registers
- MIPS has 32 general-purpose registers, each 32 bits wide
Register (32) | Assembly Name | Use | Preserved on call? |
---|---|---|---|
0 | $zero | constant value 0 | N.A. |
1 | $at | Assembler Temporary | No |
2-3 | $v0–$v1 | Values (2) | No |
4-7 | $a0–$a3 | Arguments (4) | No |
8-15 | $t0–$t7 | Temporaries | No |
16-23 | $s0–$s7 | Saved Temporaries | Yes |
24-25 | $t8–$t9 | Temporaries | No |
26-27 | $k0–$k1 | Reserved for OS Kernel | No |
28 | $gp | Global Pointer | Yes |
29 | $sp | Stack Pointer | Yes |
30 | $fp | Frame Pointer | Yes |
31 | $ra | Return Address | Yes |
Memory
- The memory is byte-addressable (each byte has a unique address from
0x00000000
to0xFFFFFFFF
) - The memory is organized as a sequence of 32-bit words
- The memory is big-endian
- The memory is accessed only by data transfer instructions
- The size of the memory is bytes (4GB)
- Memory holds data structures, arrays, and spilled registers
- Memory Segments: (from low to high addresses,
0x00000000
to0xFFFFFFFF
)`- The reserved segment contains the operating system and other reserved areas
- The text segment contains the MIPS machine code
- The static data segment contains constants and global variables
- Used for:
- constants (using
const
in C) - static variables (using
static
in C) - global variables (declared outside of any procedure in C)
- constants (using
- fixed size data structures like arrays
- Allocated at compile time and deallocated when the program exits
- The global pointer
$gp
points to the midpoint of the static data segment, the access is using a 16-bit signed offset, in the following range:- (negative offset)
$gp - 32768 = 0x10000000
- (zero offset)
$gp = 0x10008000
- (positive offset)
$gp + 32767 = 0x1000FFFF
- The total length of the static data segment is
0x1000FFFF - 0x10000000 = 65535 = 2^16
bytes (64KB, where KB = 1024 bytes)
- (negative offset)
- Used for:
- The heap (dynamic data in the diagram)
- Grows upward (toward the stack, from lower to higher addresses)
- Used for:
- dynamic memory allocation
- for data structures like linked lists that grow and shrink during execution, or for arrays whose size is not known until runtime
- In C, memory allocation controlled by the programmer (allocated using
malloc
and deallocated usingfree
)- see also: memory leaks, dangling pointers
- Java uses automatic memory allocation and garbage collection
- The stack
- contains the procedure frames
- Grows downward (toward the heap, from higher to lower addresses)
- The segment of the stack containing a procedure’s saved registers and local variables is called called a procedure frame (or activation record)
- The stack pointer
$sp
always points to the top of the stack (lowest address in the stack) - Stack memory is allocated at runtime and is automatically deallocated when the function exits
- Used for:
- local variables (automatic) declared inside a procedure, and discarded when the procedure exits
- procedure call information (e.g., return address, saved registers)
- The remaining memory (doesn’t appear in the diagram) is reserved for input/output devices
Text Representation
- ascii
- strings:
- the first byte is reserved for the length of the string (Java uses this convention)
- an accommpanying variable holds the length of the string
- the string is null-terminated, i.e. ends with a
NUL
byte,0x00
in ASCII, (C uses this convention)
- load and store byte instructions
- halfword
Instructions
- instruction is a command given to a computer to perform a specific operation
- instructions are 32 bits long (4 bytes, 8 hex digits)
- data transfer instruction is an instruction that transfer data between memory and registers
- immediate is a constant value that is part of the instruction itself
- immediate instruction is an instruction that has an immediate operand
Format
Types
- R-type (register type)
- used for arithmetic and logical operations
- format:
op rs rt rd shamt funct
- it has a fixed opcode of
000000
. The actual operation is specified by thefunct
Fields
Field | Description | Size (bits) |
---|---|---|
opcode | basic operation of the instruction | 6 |
rs | 1st register source operand | 5 |
rt | 2nd register source operand | 5 |
rd | register destination operand | 5 |
shamt | shift amount | 5 |
funct | function code, selects the specific variant of the operation in the op field | 6 |
immediate | immediate operand | 16 |
address | jump address | 26 |
R Type Instructions
Name | Instruction | Meaning | Funct (hex) |
---|---|---|---|
Jump Register | jr rs | PC = R[rs] | 08 |
Add | add rd, rs, rt | R[rd] = R[rs] + R[rt] | 20 |
Add Unsigned | addu rd, rs, rt | R[rd] = R[rs] + R[rt] | 21 |
Subtract | sub rd, rs, rt | R[rd] = R[rs] - R[rt] | 22 |
Subtract Unsigned | subu rd, rs, rt | R[rd] = R[rs] - R[rt] | 23 |
And | and rd, rs, rt | R[rd] = R[rs] & R[rt] | 24 |
Or | or rd, rs, rt | R[rd] = R[rs] OR R[rt] | 25 |
Nor | nor rd, rs, rt | R[rd] = ~(R[rs] OR R[rt]) | 27 |
Shift Left Logical | sll rd, rt, shamt | R[rd] = R[rt] << shamt | 00 |
Shift Right Logical | srl rd, rt, shamt | R[rd] = R[rt] >>> shamt | 02 |
Set Less Than | slt rd, rs, rt | R[rd] = (R[rs] < R[rt]) ? 1 : 0 | 2A |
Set Less Than Unsigned | sltu rd, rs, rt | R[rd] = (R[rs] < R[rt]) ? 1 : 0 | 2B |
I Type Instructions
Name | Instruction | Meaning | Opcode (hex) |
---|---|---|---|
Add Imm. | addi rt, rs, SignExtImm | R[rt] = R[rs] + SignExtImm | 8 |
Add Imm. Unsigned | addiu rt, rs, SignExtImm | R[rt] = R[rs] + SignExtImm | 9 |
And Imm. | andi rt, rs, ZeroExtImm | R[rt] = R[rs] & ZeroExtImm | C |
Branch on Equal | beq rs, rt, offset | if (R[rs] == R[rt]) PC = PC + 4 + (4 * offset) | 4 |
Branch on Not Equal | bne rs, rt, offset | if (R[rs] != R[rt]) PC = PC + 4 + (4 * offset) | 5 |
Load Byte Unsigned | lbu rt, imm(rs) | R[rt] = Mem[R[rs] + imm] | 24 |
Load Halfword Unsigned | lhu rt, imm(rs) | R[rt] = Mem[R[rs] + imm] | 25 |
Load Linked | ll TODO | ||
Load Upper Imm. | lui TODO | ||
Load Word | lw rt, imm(rs) | R[rt] = Memory[R[rs] + imm] | 23 |
Store Word | sw rt, imm(rs) | Memory[R[rs] + imm] = R[rt] | 2B |
Or Imm. | ori rt, rs, imm | R[rt] = R[rs] OR imm | D |
Set Less Than Imm. | slti rt, rs, imm | R[rt] = (R[rs] < imm) ? 1 : 0 | A |
Set Less Than Imm. Unsigned | sltiu rt, rs, imm | R[rt] = (R[rs] < imm) ? 1 : 0 | B |
Store Byte | sb rt, imm(rs) | Memory[R[rs] + imm] = R[rt] | 28 |
Store Halfword | sh rt, imm(rs) | Memory[R[rs] + imm] = R[rt] | 29 |
Store Word | sw rt, imm(rs) | Memory[R[rs] + imm] = R[rt] | 2B |
J Type Instructions
Name | Instruction | Meaning | Opcode (hex) |
---|---|---|---|
Jump | j address | PC = address | 2 |
Jump and Link | jal address | R[31] = PC + 8; PC = address | 3 |
notes
- May cause overflow exception
SignExtImm = { 16{immediate[15]}, immediate }
ZeroExtImm = { 16{lb'0}, immediate }
BranchAddr = { 14{immediate[15]}, immediate, 2'b0 }
JumpAddr = { PC+4[31:28], address, 2'b0 }
- Operands considered unsigned numbers (vs. 2’s comp.)
- Atomic test&set pair;
R[rt] = 1
if pair atomic,0
if not atomic
Load and Store
- The data transfer instructions that copy data from memory to a register, or copy data from a register to memory, are called load and store (resp.). The actual MIPS names for this instructions are
lw
andsw
, standing for load word and store word.- the base address is the address of the first element of the array
- syntax:
lw register, offset(base)
(orsw register, offset(base)
)offset
is the displacement from the base address in bytes- if
offset
is0
, it can be omitted:lw register, (base)
orsw register, (base)
- the offset can be negative (because the offset is a 16-bit signed integer (using 2’s complement)), e.g
sw $7, -8($6)
stores the word from register$7
to memory at address$6 - 8
- the offset must be a multiple of 4 (see alignment restriction)
- if
base
is the base register that holds the base address of the arrayregister
is the destination register that holds the value loaded from memory (or the source register that holds the value to be stored in memory)
Example (section 2.3)
Suppose we have the following C code:
Where
A
is an array (of words) whose base address is in register$s3
, andh
is in register$s2
. The MIPS assembly code for this C code is:explanation:
32
is because8 * 4 = 32
(each array element is a word), and48
is because12 * 4 = 48
, in general,offset = index * 4
Cannot Add Two Registers for Address Calculation Directly
To add two registers for address calculation, we need to use an intermediate register to store the sum of the two registers, then use the intermediate register as the offset:
Logical Operations
-
sll
(shift left logical,<<
) andsrl
(shift right logical,>>>
) are used for shifting bits in a register left or right by a fixed number of bits specified by theshamt
field (shift amount) -
Shift left by bits is equivalent to multiplying by
-
sra
(shift right arithmetic,>>
) is used for shifting bits in a register right by a fixed number of bits specified by theshamt
field, but it fills the leftmost bits with the sign bit (the most significant bit) to preserve the sign of the number, hence arithmetic shift right by bits is equivalent to dividing by -
MIPS excludes the
not
instruction, because it can be implemented usingnor
the value with0
, orxor
with1
-
Immediate logical operations:
andi
(and immediate)ori
(or immediate)xori
(exclusive or immediate)- the 16-bit immediate value is zero-extended to 32 bits before the operation is performed because the other operand (source register) is 32 bits
Conditional Branches
-
beq
(branch if equal): jumps to a label if two registers are equal -
bne
(branch if not equal): jumps to a label if two registers are not equal -
These are used to compare two registers and set a destination register to
1
if the first register is less than the second, and0
otherwise -
slt
(set less than) -
sltu
(set less than, unsigned) -
slti
(set less than, immediate) -
sltiu
(set less than, immediate, unsigned) -
A branch is an instruction that can change the flow of control in a program (e.g.
beq $s1, $s2, label
) -
A branch target is the destination of a branch instruction (e.g.
label
inbeq $s1, $s2, label
) -
A branch label is a label that marks the target of a branch instruction (e.g.
label:
inlabel: add $s1, $s2, $s3
) -
A basic block is a sequence of instructions without branches (except possibly at the end) and without branch targets or branch labels (except possibly at the beginning)
if-then-else
in MIPSThe following C code:
Where
f,g,h,i,j
are variables corresponding to registers$s0,$s1,$s2,$s3,$s4
(resp.), can be translated to MIPS as:or:
Loop in MIPS
The following C code:
Where
save
is an array of words whose base address is in register$s3
,k
is in register$s2
, andi
is in register$s4
, can be translated to MIPS as:
Jump Instructions
-
caller is the program that instigates a procedure and provides the necessary parameter values
-
callee is a procedure that executes a series of stored instructions based on the parameters provided by the caller and then returns control to the caller
-
program counter (PC) is the register containing the address of the next instruction to be executed
- The term program counter is used for historical reasons; a more sensible name would have been instruction address register
jal
(jump and link) does:- stores the return address (the address of the next instruction after the
jal
instruction;$ra = PC + 4
) in register$ra
(return address). - jumps to the address specified in the instruction (the target address)
- stores the return address (the address of the next instruction after the
jr
(jump register) jumps to the address stored in a register (e.g.jr $ra
unconditionally jumps to the return address stored in$ra
)
-
An argument is a value passed to a procedure by the caller
- Arguments are passed either in registers (four arguments in
$a0-$a3
) or on the stack (if more than four arguments)
- Arguments are passed either in registers (four arguments in
-
The return values are two values that can be returned by a procedure in registers
$v0-$v1
-
stack is a data structure
- The stack pointer is adjusted by one word for each register that is saved or restored
- By historical precedent, the stack grows from higher addresses to lower addresses
Procedure in MIPS
- The caller places input parameters in
$a0-$a3
- The caller uses
jal
to (i) save the return address in$ra
and (ii) jump to the callee- Acquire the storage resources needed for the procedure
- The callee completes its task
- The callee places the result in
$v0-$v1
- The callee uses
jr $ra
to return to the caller
Compiling a C procedure that doesn't call another procedure
The MIPS assembly code for this C code is:
- leaf procedure is a procedure that does not call any other procedures
- non-leaf procedure is a procedure that calls other procedures (or even themselves, as in recursion)
- Just as we need to be careful when using registers in procedures, more care must also be taken when invoking nonleaf procedures.
NOTE
Example Scenario:
- The main program calls procedure
A
with an argument in$a0
(e.g. value3
)- Procedure
A
calls procedureB
with a new argument also placed in$a0
(e.g. value7
)The Conflict:
$a0
now holds7
, overridding the previous value3
needed byA
- Similarly, the return address register
$ra
now hasB
’s return address, overwritingA
’s return addressSolution: Using the Stack
- Caller saves any needed argument or temporary registers (like
$a0
and$t0-$t9
) on the stack before calling a procedure- Callee saves the return address register
$ra
and any saved registers ($s0-$s7
) it uses
Compiling a recursive C procedure, showing nested procedure linking
The following C code is a recursive function that calculates the factorial of a number:
The MIPS assembly code for this C code is: