You are here
Basic Control Flow
The MicroBlaze processor, along with most RISC microprocessors, contains only a single instruction to perform control flow within a program, the branch instruction. This instruction, which has many variants, is used to change the program counter location. It is useful, however, to abstract this low-level support in to more useful control flow idioms such as loops and if-then-else statements.
If-the-else Statements
if( guard )
{
then-clause
}
else
{
else-clause
}
Consider the example if-then-else pseudo code show in figure 1. This is a standard control flow idiom found in nearly all programming languages. How can we implement this in assembly language. If we read the if-then-else statement carefully then the mechanisms become clear. First, the program must calculate the value of the guard. If the guard is true then we begin executing the then clause and if it is false then we begin executing the false clause. The following is a generic template for an if-then-else statement in MicroBlaze assembly
calculate_guard:
...
...
...
beqi R20, else_clause
nop
then_clause:
...
...
...
bri end
nop
else_clause:
...
...
...
end:
This example starts off with the calculate_guard label. At this point the assembly program will calculate the guard condition as a boolean value, the standard representation of which is zero means false and non-zero means true, and stores that value in R20. The program then uses the beqi opcode. This opcode, which stands for branch immediate if equal to zero, checks if R20 is false and if it is then it branches to else_clause. If the value is true then the branch is not taken and control falls through to the then clause. The then clause ends with an unconditional branch to the end of the if statement to avoid executing else_clause.
While Loops
while( guard )
{
loop-statements
}
While loops, like the if-then-else statement, uses a boolean guard to control the execution of a block of code. Figure 2 shows basic pseudo code for a while loop. In this case, as long as guard is true then the loop statements will execute. Because while loops and if-then-else statements both use a guard, their basic construction is similar. The following MicroBlaze assembly gives a generic framework for a while statement:
calculate_guard:
...
...
...
beqi R20, end
nop
loop_statements:
...
...
...
back_to_guard:
bri calculate_guard
nop
end:
In this example the guard is calculate by the program in calculate_guard just like in the if-then-else statement. Also just like the if-then-else statement, the while loop idiom uses the beqi instruction to determine if the value stored in R20 is true or false. If the value is true then the branch is not taken and control falls through the beqi opcode and the loop_statements section will execute. After the loop_statements, the back_to_guard code will unconditionally branch back to the calculate_guard statements where the entire process will repeat. If the value in R20 during the beqi statement is false then the execution of the while loop is terminated by branching to end. At that point any code after the while loop will execute.
For Loops
for( initialize; guard; next )
{
loop-statements
}
Figure 3 shows the basic format of a C-style for loop. This loop has a four main parts: initialize, guard, next, and loop-statements. The guard and loop-statements parts of the loop are implemented in assembly much in the same way as while loops and the initialize and next parts are implemented using standard assembly mechanisms. The following gives a generic template for implementing a for loop in assembly:
perform_initialize:
...
...
...
calculate_guard:
...
...
...
beqi R20, end
nop
loop_statements:
...
...
...
perform_next:
...
...
...
back_to_guard:
bri calculate_guard
nop
end:
In this example, the loop begins with the perform_initialize section of code. This section of code will perform the initialization using whatever assembly is needed. After the initialization section has been completed, the calculate_guard and loop_statements sections execute just as they do in the while loop example. Like the while loop, if the guard is false then the loop is terminated by branching to end. Otherwise the guard condition is true and control falls through to loop_statements. In the while loop idiom, after the execution of the loop body, we would simply branch back to the loop guard. In the for loop idiom, however, we must first perform the next statements. Thus, after loop_statements finishes, control falls through to the perform_next statements which is implemented using the required assembly. After the perform_next statements have finished executing, the for loop will branch back to the calculate_guard label and execute the next iteration of the loop.
