There was a brief mention about the status codes stored in the CPSR. This is when you get to start using them. Because assembly doesn’t have the concept of data types, the processor needs to figure out another way to define conditions such as equal, not equal, greater than, less than or equal, etc. It does this by looking at the flags of the CPSR.
Comparison methods #
The first thing you need to do is to tell the processor that you want it to update
the CPSR. The first opcode you will use is
cmp takes the two operands and
subtracts the second from the first. From this result, it will then update the CPSR.
mov r0, #5 @ Move 5 into r0 mov r1, #2 @ Move 2 into r1 cmp r0, r1 @ Compare r0, r1 and set CPSR
From this, we now know that the processor will subtract 2 from 5, and use the result (3) to set the correct flags.
- The N flag will not be set because the number (3) is not a signed negative.
- The Z flag will not be set because the number (3) is not zero
- The C flag will be set because we didn’t not need to do an imaginary borrow to solve
- The V flag will not be set because there was no overflow (greater than or equal to 231, or less than –231)
The -S suffix #
The other common way to set the CPSR flags is by appending an -s suffix to an opcode. Not all opcodes can take the -s suffix, but most can. It’s always worth checking the processor guides when in doubt. The CPSR will be set based on the result of the operation. 1
mov r0, #2 @ move 2 into r0 mov r1, #1 @ move 3 into r1 adds r0, r1 @ adds 2 and 3 stores into r0 @ ALSO sets the following flags based on the number 5 @ N = 0 because 5 is not signed negative @ Z = 0 because 5 is not zero @ C = 0 because there was no carry @ V = 0 because there was no overflow
Conditional table #
From there you can see how the processor interprets the results with this table. Using the table, you can see that because of the flags set above, the following conditions are true for 5 - 2:
- The two numbers are not equal (Z == 0)
- The first number is signed greater than (Z==0) && (N==V)
- The first number is signed greater than or equal (N==V)
- The first number is unsigned higher or same (C==1)
- The result is positive (N==0)
- There was no signed overflow (V==0)
- The first number is unsigned higher (C==1) && (Z==0)
|Condition Code||Meaning with
||Status of Flags|
|GT||Signed Greater Than||(Z==0) && (N==V)|
|LT||Signed Less Than||N!=V|
|GE||Signed Greater Than or Equal||N==V|
|LE||Signed Less Than or Equal||(Z==1)|
|CS or HS||Unsigned Higher or Same (or Carry Set)||C==1|
|CC or LO||Unsigned Lower (or Carry Clear)||C==0|
|MI||Negative (or Minus)||N==1|
|PL||Positive (or Plus)||N==0|
|VC||No signed Overflow||V==0|
|HI||Unsigned Higher||(C==1) && (Z==0)|
|LS||Unsigned Lower or same||(C==0)|
Conditions in practice #
From here, you can use these condition codes and affix them to most opcodes!
mov r0, #5 @ Move 5 into r0 mov r1, #7 @ Move 7 into r1 cmp r0, r1 @ Internally performs 5-7 and updates CPSR @ based on result (-2), @ specifically Z = 0 in this case addeq r0, #10 @ Will NOT add 10 (eq requires Z == 1) addne r0, #5 @ Will add 5 (ne requires Z == 0)
Since CMP uses subtraction it is essentially using the SUBS opcode. The difference is that SUBS will save the result, CMP discards it. ↩︎