This video will talk about ARM Cortex-M conditionally executed instructions.
In the previous video on conditional branch instructions, we have mentioned that:
if we add a B before these conditional codes, we can obtain conditional branch instructions.
For example, BGT is branch if signed greater than. BHI is branch if unsigned greater than.
In Thumb-2, these conditional codes can be appended to other instructions. This table
shows all different types of ADD instructions that are conditionally executed. For example,
ADDEQ is executed only if the equivalent condition is satisfied.
ADDNE is executed only if not equal, ADDHS is executed only if unsigned higher than or the same.
There are a total of 14 conditional codes, as listed in this table.
Conditionally executed instructions can reduce the number of branch instructions in an assembly
program. Let s look at this example. The if-else statement in the C program sets the value of
y based on the value of a. If a is less than or equal to 0, the program
sets y to -1. Otherwise, it sets y to 1. Without using any branch instructions,
the assembly program can implement the C program in this way. Assume the value of a is stored in
register r0, the value of y in register r1. In the assembly program, we first compare r0 with 0.
The MOVLE instruction is executed only if r0 is less than or equal to 0. The MOVGT
is executed only if r0 is greater than 0. We cannot use MOVSLE in the assembly program.
The last instruction, MOVGT, has to be executed based on the result of the first instruction CMP.
Therefore, the second instruction MOVLE should not modify the NZCV flags.
Let s look at a more complex example. If a is equal to 1, 7, or 11, then y is set to -1.
Otherwise, y is set to 1. In the assembly program, we use three comparison instructions. The second
and third comparison instructions are conditionally executed,
and they have a condition code NE, not equal. They are executed only if the not equal condition
is satisfied. Pay attention here, the second CMP will change the NZCV flags if it is executed.
If a is 1, those three instructions won t be executed. Since the second
and third CMP instructions are not executed,
the NZCV flags remain unchanged after the first instruction is executed. Therefore,
the MOV instructions use the comparison results of the first CMP to test whether
they should be executed. More specifically, the MOV instructions are conditionally executed based
on the NZCV flags modified by the first CMP. If a is 7, the comparison result of the first CMP
is not equal. Thus, the second CMP will be executed. The third CMP
is not executed because the comparison result of the second CMP is equal. The MOV instructions are
conditionally executed based on the comparison result of the second CMP. In other words, the
MOV instructions are conditionally executed based on the NZCV flags modified by the second CMP.
If a is 11, the result of the first CMP is not equal. Thus, the second CMP will be executed.
Again, the result of the second CMP is not equal. Thus, the third CMP will be executed. The MOV
instructions are conditionally executed based on the result of the third CMP, more specifically,
the NZCV flags of the third CMP. If a is 100, both the second and
third CMP instructions will be executed. The MOV instructions are conditionally
executed after three comparisons. How does the processor use the NZCV
bit flags in the program status register (PSR) to test whether a condition is satisfied?
This table summarizes the answers. For example, the processor checks whether the zero flag is
set or cleared to test the condition of equal and not equal. If Z is 1, the result of comparison,
or we say the result of subtraction, is zero. Thus, the operands are equal.
If Z is 0, the result of subtraction is non-zero. Thus, the operands are not equal. To test the
condition GE, signed greater than or equal to, the processor checks whether the negative flag
N and the overflow flag V are equal. If they are equal, the GE condition is satisfied.
Now, let me give you a short explanation why the GE condition checks whether
the N flag and the V flag are equal. In this short example, ADDGE is executed only if
the signed integer held in register r0 is greater than or equal to the one held in register r1.
The CMP instruction performs the subtraction and updates the NZCV flags based on the subtraction
result. Since we are comparing two signed integers, we should pay attention to the
overflow flag V, instead of the carry flag C. Now, let me explain why the result is
signed greater than or equal to if the overflow flag V equals the negative flag N. When V is 0,
it represents that no overflow has taken place in the signed subtraction. If there is no overflow,
the result of signed subtract will be correct. Since N is zero, we know that
the result of the subtraction is non-negative. Based on these two observations, we know the
result of r0 minus r1 is larger than or equal to 0. Thus, r0 is signed greater than or equal to r1.
Similarly, if N is 1, we know the subtract result is truly negative. Thus, r0 is signed less than
r1. On the other hand, if V is 1, an overflow has taken place, indicating the subtract result
was incorrect. If N is 0, the N flag mistakenly reports that the result is non-negative. In
reality, the result should be negative. Therefore, r0 is signed less than r1. Similarly, if N is 1,
the subtract result is mistakenly reported as negative while it should be non-negative. Thus,
r0 is signed greater than or equal to r1. This truth table summarizes the conclusion we
have obtained. It shows that r0 is signed greater than or equal to r1 if and only if
the overflow flag V and the negative flag N are equal to each other.