In this article, we will understand MIPS control instructions by examples. MIPS control instructions are a fundamental aspect of programming in MIPS assembly language. They allow you to control the flow of your program, make decisions, and loop through code based on conditions.
MIPS Control Instructions
Here are some common MIPS control instructions:
Conditional Branching Instructions
- beq (Branch on Equal): Branches if two registers are equal.
- bne (Branch on Not Equal): Branches if two registers are not equal.
- bgtz (Branch on Greater Than Zero): Branches if a register is greater than zero.
- blez (Branch on Less Than or Equal to Zero): Branches if a register is less than or equal to zero.
- bgez (Branch on Greater Than or Equal to Zero): Branches if a register is greater than or equal to zero.
- bltz (Branch on Less Than Zero): Branches if a register is less than zero.
Unconditional Jump Instructions
j (Jump): Jumps to a specified address.
jal (Jump and Link): Jumps to a specified address and saves the return address in $ra (return address register).
Comparison Instructions
- slt (Set Less Than): Sets a register to 1 if one register is less than another; otherwise, sets it to 0.
Function Calls
- jr (Jump Register): Jumps to an address stored in a register (typically used for returning from functions).
- jal (Jump and Link): Jumps to a function and stores the return address in $ra.
Working with arrays in MIPS involves using these control instructions along with load and store instructions to access and manipulate array elements. Here’s a high-level overview of working with arrays in MIPS:
MIPS Control Instructions Examples
In this example, we will use both branch and jump instructions to sum the first ten positive integers (10+9+8+7+…). Follow along with the code provided below and fill in the missing parts:
.text
.globl main
main:
addi $s0, $zero, 10 # counter initialized to 10
addi $t0, $zero, 0 # sum/accumulator initialized to 0
loop1:
add $t0, $t0, $s0 # Performing accumulation in $t0
addi $s0, $s0, -1 # counter−−
bne $s0, $zero, loop1 # Exit the loop after 10th iteration
nop # Few no operations to indicate end of interest
nop
After running the program, the value of $t0
will be 0x00000037
in hexadecimal or 55
in decimal when we reach the end of the program (after the first nop
).
Exercise 2
Now let’s modify the program from Exercise 1 to calculate the sum of powers of 2 (1+2+4+8+16+32+…) for the first 20 numbers. Use the registers mentioned in Exercise 1, i.e., $s0
, $t0
, and $zero
. You can also use $t1
. Two possible implementations are shown below:
Implementation 1:
.text
.globl main
main:
addi $s0, $zero, 20 # counter initialized to 20
addi $t0, $zero, 0 # sum/accumulator initialized to 0
addi $t1, $zero, 1 # $t1 initialized with “1”
loop1:
add $t0, $t0, $t1 # Performing accumulation in $t0
add $t1, $t1, $t1 # Calculating new number to be added
addi $s0, $s0, -1 # counter−−
bne $s0, $zero, loop1 # Exit the loop after 20th iteration
nop
After running this program, the final sum will be 0x000fffff
in hexadecimal or 1048575
in decimal.
Implementation 2:
.text
.globl main
main:
addi $s0, $zero, 20 # counter initialized to 20
addi $t0, $zero, 0 # sum/accumulator initialized to 0
addi $t1, $zero, 1 # $t1 initialized with “1”
loop1:
add $t0, $t0, $t1 # Performing accumulation in $t0
sll $t1, $t1, 1 # Calculating new number to be added
addi $s0, $s0, -1 # counter−−
bne $s0, $zero, loop1 # Exit the loop after 20th iteration
nop
nop
After running this modified program, the final sum will still be 0x000fffff
in hexadecimal or 1048575
in decimal.
Solution for Implementation 1:
Let’s modify the program from Implementation 1 to calculate the sum of more numbers. We will increase the number of loops to 50 and observe the intermediate sum contained in $t0
when an overflow occurs in any of the registers involved:
After running the modified program for 50 numbers, when an overflow occurs, the intermediate sum contained in $t0
will be 0x7fffffff
in hexadecimal. We can identify the overflow by the exception caused due to an arithmetic overflow. However, note that the overflow was not caused by the intermediate sum but by the new number obtained using the instruction (add $t1, $t1, $t1)
. This instruction performs a signed addition. When the value in $t1
reaches 0x40000000
, an overflow occurs and the program jumps to the kernel part of the code due to the exception caused by an arithmetic overflow into the signed bit.
Now, let’s repeat the above program for 50 numbers but this time use the addu
instruction instead of add
while calculating the sum. We will observe the first value of the intermediate sum for which an overflow occurs:
After running the modified program with the addu
instruction, the first value of the intermediate sum for which an overflow occurs is 0xffffffff
in hexadecimal. This overflow is caused by the new number obtained by the instruction (addu $t1, $t1, $t1)
. The overflow is caused because the value of $t1
becomes 0x100000000
, which cannot be accommodated in the 32-bit space. At this point, the value in $t1
becomes zero, and the register $t0
contains 0xffffffff
for the rest of the program. It is important to note that this overflow occurs at a different point compared to the signed addition case, because the unsigned addition does not cause an exception but overflows in $t1
due to running out of space.
Solution for Implementation 2:
Similarly, let’s modify Implementation 2 to calculate the sum of more numbers (50 numbers) and observe the intermediate sum contained in $t0
when an overflow occurs:
After running the modified program for 50 numbers, when an overflow occurs, the intermediate sum contained in $t0
will be 0xffffffff
in hexadecimal. We can identify the overflow by observing that the instruction add $t0, $t0, $t1
performs the signed accumulation, while the instruction sll $t1, $t1, 1
creates the new number to be added on each iteration. When the value in $t1
reaches 0x40000000
, an overflow occurs and the value of $t0
becomes 0xffffffff
.
On the next left shift operation, the number 0x80000000
becomes 0x100000000
, which cannot be accommodated in a 32-bit space. As a result, $t1
becomes 0x00000000
. This can be classified as a logical overflow beyond the available 32-bit space. The contents of $t0
at this point are 0xffffffff
, and this value remains in $t0
until the end of the program.
To observe the same behavior with the addu
instruction, repeat the above program (of the same 50 numbers) using the addu
instruction instead of add
. The value and overflow occur at the same point in this case.
Using Array in MIPS Assembly Language
Let’s see example to use arrays in MIPS assembly language with or without control and branch instructions.
Summing the Integers in an Array
Now, let’s write a program without using branches to sum the integers in an array with 5 elements. We will save the result in the variable “sum”. The starting code is provided below:
.data
myData: .word 2, 12, -5, 7, 4 # array initialization
sum: .word 0 # this will contain the sum
.text
.globl main
main:
la $s0, myData # load the address of myData into $s0
li $t2, 0 # initialize $t2 to save the sum
lw $t0, 0($s0)
add $t2, $t2, $t0
lw $t0, 4($s0)
add $t2, $t2, $t0
lw $t0, 8($s0)
add $t2, $t2, $t0
lw $t0, 12($s0)
add $t2, $t2, $t0
lw $t0, 16($s0)
add $t2, $t2, $t0
la $s0, sum # Load the address of "sum" into $s0
sw $t2, 0($s0) # Store the value of the final sum from $t2 to the memory location at "sum"
After running this program, the value of sum
will be 0x00000014
in hexadecimal or 20
in decimal.
Below are the missing values filled in the table:
Address (Hex) | Value (Hex) | Value (Decimal) |
---|---|---|
0x10010000 | 0x00000002 | 2 |
0x10010004 | 0x0000000c | 12 |
0x10010008 | 0xfffffffb | -5 |
0x1001000c | 0x00000007 | 7 |
0x10010010 | 0x00000004 | 4 |
Summing the Integers in an Array using Branch Instructions
Let’s repeat Exercise 3 but this time use branch instructions and the following 15-element array:
.data
myData: .word 200, -1299, -5000, 7123, 4, -2, 3, -7, 89, 4, -1000, 11, 0, 14, -1
sum: .word 0 # this location will contain the sum
.text
.globl main
main:
la $s0, myData # load the address of myData into $s0
li $t1, 15 # initialize the index
add $t2, $zero, $zero # initialize to save the sum in $t2
loop:
addi $t1, $t1, -1
sll $t3, $t1, 2 # Multiply the index by 4 to get the offset
add $t3, $s0, $t3 # Calculate the memory address of the current element
lw $t0, 0($t3) # Load the value from memory
add $t2, $t2, $t0 # Add the value to the sum in $t2
bne $t1, $zero, loop # Continue until the index becomes zero
exit:
la $s0, sum # Load the address of "sum" into $s0
sw $t2, 0($s0) # Store the value of the final sum from $t2 to memory
After running this program, the value of sum
will be 0x0000008b
in hexadecimal or 139
in decimal. The branch instruction produced by the assembler is bne $9, $0, −20
.
How Does this Code Work?
This MIPS assembly code calculates the sum of the elements stored in an array named myData
and stores the result in a memory location named sum
. Here’s a step-by-step explanation of what the code does:
- In the
.data
section, an arraymyData
is defined with 15 integer values. Another memory locationsum
is also reserved to store the sum of the array elements. - In the
.text
section, the program starts with themain
function:- The base address of the
myData
array is loaded into register$s0
using thela
(load address) instruction. - Register
$t1
is initialized to 15, representing the index of the last element in the array. - Register
$t2
is initialized to zero to store the sum of the elements.
- The base address of the
- The program enters a loop labeled as
loop
:- It decrements the index in
$t1
by 1. - It calculates the memory address of the current element using the index by multiplying it by 4 (since each element is 4 bytes) and adding it to the base address in
$s0
. The result is stored in$t3
. - It loads the value from memory at the calculated address into
$t0
. - It adds the loaded value (
$t0
) to the running sum ($t2
).
- It decrements the index in
- The loop continues to the next element until the index (
$t1
) becomes zero. At this point, the sum of all elements in the array is stored in$t2
. - The program exits the loop and proceeds to the
exit
section:- The address of the
sum
memory location is loaded into$s0
. - The final sum stored in
$t2
is stored in the memory location pointed to by$s0
, which issum
.
- The address of the
In summary, this code calculates the sum of the elements in the myData
array and stores the result in the sum
memory location. It demonstrates the use of load and store instructions, indexing, and looping in MIPS assembly to perform a common array operation.
Video Demonstration
Conclusion
In conclusion, this article provided an in-depth understanding of MIPS control instructions through examples. We explored conditional branching instructions, unconditional jump instructions, and comparison instructions. We also learned about function calls and how to work with arrays in MIPS assembly language. By going through the provided exercises and modified implementations, we were able to gain hands-on experience with these control instructions and observe their effects on program execution. Overall, this article serves as a comprehensive guide for anyone looking to enhance their proficiency in programming with MIPS control instructions.
Related content: