Conditional Instructions

Program Status Register

The ARM Cortex-M architecture contains a status register (Program Status Register) that stores information about a previously executed instruction.  The PSR is a combination of status registers: Application Program Status Register (APSR), Interrupt Program Status Register (IPSR), and the Exception Program Status Register (EPSR).  For now, we will concern ourselves only with the upper 4 bits of the APSR.  These 4 status bits provide a mechanism to conditionally execute instruction(s) based on the results of a previous instruction.  The figure below shows the contents of the APSR.

Cortex-M4 Device Generic User Guide, Pg 2-4

The APSR contains the following condition flags:

N Set to 1 when the result of the operation was negative, cleared to 0 otherwise.

Z Set to 1 when the result of the operation was zero, cleared to 0 otherwise.

C Set to 1 when the operation resulted in a carry, cleared to 0 otherwise.

V Set to 1 when the operation caused overflow, cleared to 0 otherwise.

When a Carry Occurs

  • if the result of an addition is greater than or equal to 2^32
  • if the result of a subtraction is positive or zero
  • as the result of an inline barrel shifter operation in a move or logical instruction.

When Overflow Occurs

Overflow occurs when the sign of the result, in bit[31], does not match the sign of the result had the operation been performed at infinite precision, for example:

  •  if adding two negative values results in a positive value
  •  if adding two positive values results in a negative value
  • if subtracting a positive value from a negative value generates a positive value
  • if subtracting a negative value from a positive value generates a negative value.

Cortex-M4 Device Generic User Guide, Pg 3-19

It is important to note that the APSR is NOT updated after every instruction.  There are two ways to set the status bits in the APSR: use a special suffix at the end of an instruction  or use one of several instructions that always update the APSR.

Dedicated Comparison Instructions

Lets take a look at a few different ways to set the APSR.  The first method to set the APSR is to use instructions that always update the APSR.  There are four commonly used instructions that always set the flags bits: CMP, CMN, TST, and TEQ.  Each of these instructions will update only the APSR.  They do not modify the contents of either register used in the comparison.

;CMP (Compare)                   Subtracts the value of Operand2
;CMN (Compare Negative)          Adds the value of Operand2
;TST (Test Bits)                 Bitwise AND operation with Operand2
;TEQ (Test Equivalent)           Bitwise XOR operation with Operand2

; Initialize R0, R1, and R2
MOV  R0, #10
MOV  R1, #10
MOV  R2, #20

; Non-destructive subtract (R0, R1, R2 are not modified), update flags registers
CMP  R0, #10         ; N=0, Z=1, C=1, V=0
CMP  R0, R1          ; N=0, Z=1, C=1, V=0
CMP  R0, R2          ; N=1, Z=0, C=0, V=0

Appending S to an Instruction

In addition to dedicated comparison operations, you can also use the results of any of our arithmetic/logical instructions to set the APSR.  All you have to do is append an ‘S’ to the end of the instruction.  The major difference between this method is that the result of the the ALU instruction is stored into one of the General Purpose Registers.  Lets take a look at a few examples.

MOV32   R0, #0x7FFFFFFE   ; Initialize R0 to a very large value
ADD     R0, R0, #1        ; Flags are not updated since there is no 'S'
ADDS    R0, R0, #1        ; Flags ARE updated. N=1, Z=0, C=0, V=1

MOV32   R0, #0x7FFFFFFF   ; Initialize R0 to a very large value
AND     R0, R0, #0xFF     ; Flags are not updated
ANDS    R1, R0, #0x03     ; N=0, Z=0, C=0, V=1

It is important to note is that even with the ‘S’ suffix, an instructions may not update all of the flag bits.  The last instruction in the example above states that V is equal to 1.  This is because most logical instructions do not update the overflow bit.  Make sure to examine the ARM Instruction Referenceto see which flags a given instruction will modify.

Conditional Instructions

Using the status flags in the APSR, you can write assembly instructions that will conditionally execute.  Conditional instructions allow us to implement high level language constructs like if/else and for loops.  So what instructions are conditional in the Cortex-M architecture?  The answer is that all instructions can be conditional.   The Cortex-M architecture supports a variety of condition codes that can be appended to any ARM assembly instruction.  If the flags in the APSR match the given condition code, the instruction is executed as normal.  If the condition code is not met, the instruction becomes a NO OP and has no effect.

Let’s examine the EQ suffix.  The EQ suffix is used to determine if the result of a prior instruction resulted in a value that was equal to zero.  If the result was equal to zero, the instruction would execute as normal.  If the result was non-zero, the instruction would become a NO OP.

The GE suffix is used to determine if a prior instruction resulted in a value that is greater than or equal to 0.  

TI Cortex-M Instruction Set. pg33

Examples

Appending S to MOV

    MOVS   R1, #-1 
    MOV    R0, #1
    MOVEQ  R0, #0      
    MOVMI  R0, #-1
    MOVGT  R0, #1

(1) R1 is set to 0xFFFFFFFF and flags are updated (N=1, Z=0, C=0, V=0).  This is the only instruction that updates the flags register in this sequence since it is the only instruction with S appended to it.
(2) R0 is set to 0x1. Flags are not updated
(3) Acts as a NO OP since Z = 0
(4) R0 is set to 0xFFFFFFFF since N = 1
(5) Acts as a NO OP.  The value in instruction 1 was a negative value, so it cannot be greater than 0.

if Statement

The ARM assembly below shows how to implement an IF/ELSE statement without using branch statements.  You could have used a branch statement to implement this code fragment, but it would have been a less efficient implementation.  When a branch statement is issued, the 3-stage pipeline has to flush the two instructions following the branch instruction since they should not execute.  This results in a two clock cycles where the processor effectively does nothing.  By using the conditional instructions below, only a single operation is turned into a NO OP, so only a single clock cycle is lost.

 i = 10;

 if(i>5)                                                           
   i = 7;
 else
   i = 0;
  ; Initialize R0                        
  MOV R0, #10

  ; If Else
  CMP R0, #5
  MOVGT R0, #7
  MOVLE R0, #0

 

Lets take a look at an if statement with multiple conditions

    MOV32   R0, 0xDEADBEEF

    ; If bit0 AND bit 31 are both 1, set R1 to 1, else set R1 to 0
    MOV     R1, #1
    TST     R0, #0x80000000
    MOVEQ   R1, #0
    TST     R0, #0x00000001
    MOVEQ   R1, #0