Conditional execution

From ARMwiki
(Difference between revisions)
Jump to: navigation, search
(Created.)
 

Latest revision as of 18:23, 17 June 2011

A very special feature of the ARM processor is its conditional execution. We are not talking your basic Branch if Carry Set, the ARM takes this a stage further to mean XXX if carry set - where XXX is just about anything.

Contents

[edit] CISC style branches (x86)

By way of example of the flexibility and power of the condition codes, here is a list of branch instructions understood by the Intel 8086 processor:

  • JA Jump if Above
  • JAE Jump if Above or Equal
  • JB Jump if Below
  • JBE Jump if Below or Equal
  • JC Jump if Carry
  • JCXZ Jump if CX Zero (CX is a register that can be used for loop counts)
  • JE Jump if Equal
  • JG Jump if Greater than
  • JGE Jump if Greater than or Equal
  • JL Jump if Less than
  • JLE Jump if Less Than or Equal
  • JMP JuMP (unconditional)
  • JNA Jump if Not Above
  • JNAE Jump if Not Above or Equal
  • JNB Jump if Not Below
  • JNBE Jump if Not Below or Equal
  • JNC Jump if No Carry
  • JNE Jump if Not Equal
  • JNG Jump if Not Greater than
  • JNGE Jump if Not Greater than or Equal
  • JNL Jump if Not Less than
  • JNLE Jump if Not Less than or Equal
  • JNO Jump if Not Overflow
  • JNP Jump if Not Parity
  • JNS Jump if Not Sign
  • JNZ Jump if Not Zero
  • JO Jump if Overflow
  • JP Jump if Parity
  • JPE Jump if Parity Even
  • JPO Jump if Parity Odd
  • JS Jump if Sign
  • JZ Jump if Zero

And the 80386 added:

  • JCXZ Jump if CX Zero
  • JECXZ Jump if ECX Zero

Not forgetting the closely related:

  • LOOP Decrement CX and loop if not zero
  • LOOPE/LOOPZ Decrement (E)CX and loop if not zero and ZF = 1
  • LOOPNE/LOOPNZ Decrement (E)CX and loop if not zero and ZF = 0

Added caveat:

  JZ    far_address

is illegal, you must use:

  JNZ   skip_jump
  JMP   far_address
  skip_jump:

which messes up the pipeline as only JMP can jump to a 'far' address.

Please take a moment to contemplate that long list of instructions.


[edit] ARM style branches

Contrast, the ARM processor offers a whopping...uh...

  • B Branch
  • BL Branch with Link

there is also BX/BLX for Thumb, but since this also switches mode, we can consider this the same as B/BL only with additional side-effects.


The ARM is not limited by this seemingly inflexible approach due to conditional execution which offers you:

  • BEQ Branch if EQual
  • BNE Branch if Not Equal
  • BVS Branch if oVerflow Set
  • BVC Branch if oVerflow Clear
  • BHI Branch if HIgher
  • BLS Branch if Lower or the Same
  • BPL Branch if PLus
  • BMI Branch if MInus
  • BCS Branch if Carry Set
  • BCC Branch if Carry Clear
  • BGE Branch if Greater than or Equal
  • BGT Branch if Greater Than
  • BLE Branch if Less than or Equal
  • BLT Branch if Less Than


  • BLEQ Branch with Link if EQual
  • ...
  • BLLT Branch with Link if Less Than

The crunch comes, however, when you realise that all of the Bxx instructions are actually the same instruction. Then you will think: if you can do all that to a branch instruction, can it be done to, say, a register load instruction?

The answer is yes.

Most ARM instructions can be conditionally executed.


[edit] Condition codes

The available condition codes are:

EQ : EQual
If the Z flag is set after a comparison.

NE : Not Equal
If the Z flag is clear after a comparison.

VS : oVerflow Set
If the V flag is set after an arithmetical operation, the result of which will not fit into a 32 bit destination register.

VC : oVerflow Clear
If the V flag is clear, the reverse of VS.

HI : HIgher than (unsigned)
If after a comparison the C flag is set and the Z flag is clear.

LS : Lower than or Same (unsigned)
If after a comparison the C flag is clear or the Z flag is set.

PL : PLus
If the N flag is clear after an arithmetical operation. For the purposes of defining 'plus', zero is positive because it isn't negative...

MI : Minus
If the N flag is set after an arithmetical operation.

CS : Carry Set
Set if the C flag is set after an arithmetical operation the result of which cannot be represented in 32 bits. You can think of the C flag as the 33rd bit of the result.
Alternatively, if shift operations have been used, the C flag is set to the value of the last bit shifted out of the shifter.

CC : Carry Clear
The reverse of CS.

GE : Greater than or Equal (signed)
If after a comparison:
the N flag is set and the V flag is set
or:
the N flag is clear and the V flag is clear.

GT : Greater Than (signed)
If after a comparison...
the N flag is set and the V flag is set
or...
the N flag is clear and the V flag is clear
and... the Z flag is clear.

LE : Less than or Equal to (signed)
If after a comparison...
the N flag is set and the V flag is clear
or...
the N flag is clear and the V flag is set
and...
the Z flag is set.

LT : Less Than (signed)
If after a comparison...
the N flag is set and the V flag is clear
or...
the N flag is clear and the V flag is set.

AL : Always
The default condition, so does not need to be explicity stated. Any instruction without a condition code is AL.

NV : Never
This specifies that the instruction should never be executed. It is a poor man's NOP. It was originally included for completeness, the opposite of AL.
The NV condition has been deprecated and should not be used. If you wish to execute a NOP, use MOV R0, R0.


There is a final aspect to the condition code system. The S flag, which when applied to an arithmetic instruction will cause the status flags to be updated. Thus you can choose whether or not such an instruction affects the status flags.

For example, a 64 bit addition can be implemented by using the Carry flag from one addition to control the behaviour of the second part of the addition:

  ADDS    R4, R0, R2
  ADC     R5, R1, R3

You can combine condition codes and the S flag, here is an example addition that updates the status flags but is only executed if the result of the previous operation was EQual (Z set):

  ADDEQS  R0, R0, R1


[edit] Examples

Here is an example of conditional execution at work. You want to compare register zero with the contents of something stored in register ten. If not equal to R10, then call a software interrupt, increment and branch back to do it again. Otherwise clear R10 and return to a calling piece of code (whose address is stored in R14).

  \ An example of conditional execution
  STMFD   R13!, {R0-R12,R14}      ; Save registers and return address
  .loop                           ; Mark the loop start position
  CMP     R0, R10                 ; Compare R0 with R10
  SWINE   &12345                  ; Not equal: Call SWI &12345
  ADDNE   R0, R0, #1              ;            Add 1 to R0
  BNE     loop                    ;            Branch to 'loop'
  MOV     R10, #0                 ; Equal    : Set R10 to zero
  LDMFD   R13!, {R0-R12,PC}       ;            Return to caller

This is just an example of condition codes, there is a lot wrong with the code otherwise (do we need to save all of the registers? would the SWI corrupt R0? does the SWI take other parameters?)


Another example, after a block of code, we return with Z set or clear. The message we print on the screen depends upon the result, thus:

  \ If Z set, print Z set else print Z unset
  ADR     R0, z_clear_message
  ADREQ   R0, z_set_message
  SWI     "OS_Write0"
  SWI     "OS_NewLine"
Personal tools
Namespaces

Variants
Actions
Navigation
Contents
Toolbox