Chapter 7 Integer Logic and Arithmetic
7.2 Flags and Their Use
Recall from Chapter 2 that the Program Status Register holds the current state of the machine: the flags, the mode, the interrupt bits, and the Thumb bit for the ARM7TDMI, and the flags, the exception number, the Interrupt-Continuable Instruction (ICI) bits, and the Thumb bit for the Cortex-M4, shown in Figure 7.1.
There are four bits, N, Z, C, and V, in the uppermost nibble that help determine whether or not an instruction will be conditionally executed. The flags are set and cleared based on one of four things:
• Instructions that are specifically used for setting and clearing flags, such TST or CMP
• Instructions that are told to set the flags by appending an “S” to the mne- monic. For example, EORS would perform an exclusive OR operation and set the flags afterward, since the S bit is set in the instruction. We can do this with all of the ALU instructions, so we control whether or not to update the flags
• A direct write to the Program Status Register, where you explicitly set or clear flags
• A 16-bit Thumb ALU instruction, which will be covered both here and in Chapter 17
7
The Q flag on the Cortex-M4 indicates a value has saturated and different rules gov- ern its behavior, so it is discussed separately in Section 7.4.4. In the next sections, we’ll examine each flag individually—some are quite easy and some require a little thought.
7.2.1 The n fLAg
This flag is useful when checking for a negative result. What does this mean, nega- tive? This definition sits in the context of a two’s complement number system, and as we saw in the last few chapters, a two’s complement number is considered to be negative if the most significant bit is set. Be careful, though, as you could easily have two perfectly good positive numbers add together to produce a value with the uppermost bit set.
EXAMPLE 7.1
Adding −1 to −2 is easy enough, and the result has the most-significant bit set, as expected. In two’s complement notation, this would be represented as
FFFFFFFF FFFFFFFE FFFFFFFD +
If we were to code this on the ARM7TDMI as MOV r3, #-1
MOV r4, #-2 ADDS r3, r4, r3
we would expect to see the N bit set in the CPSR, as shown in Figure 7.2, which it is, as the most significant bit of register r3 was set as a result of the addition.
EXAMPLE 7.2
If we add the values below, the addends are positive in two’s complement nota- tion, but the sum is negative, i.e.,
N
ARM7TDMI Status Register
Cortex-M4 Status Register
Z C V Do not modify/Read as zero I F T M
4 M
3 M
2 M
1 M
0 0 1 2 3 4 5 6 7 8 27
28 29 30 31
31
N Z C V QICI/IT T GE ICI/IT
30 29 28 27 26 25 24 19 18 17 1615 14 1312 11 10 7 6 5 ISRNUM
4 3 2 1 0
FIGURE 7.1 Status registers.
7B 3
AB 000000 0000000 000000 +
which means that something might be wrong. First, notice that since the most- significant bit is now set, this forces the N bit to be set if our ADD instruction actually sets the flags (remember, it doesn’t have to). Second, if you aren’t work- ing with two’s complement numbers, then perhaps we don’t really care what the value of the N bit is. Finally, in a two’s complement representation, notice that we originally meant to add two positive numbers together to get a bigger positive sum, but the result indicates that this positive sum cannot be represented in 32 bits, so the result effectively overflowed the precision we had available. So perhaps we need one more flag to work with signed values.
7.2.2 The V fLAg
When performing an operation like addition or subtraction, if we calculate the V flag as an exclusive OR of the carry bit going into the most significant bit of the result with the carry bit coming out of the most significant bit, then the V flag accurately indicates a signed overflow. Overflow occurs if the result of an add, subtract, or com- pare is greater than or equal to 231, or less than –231.
EXAMPLE 7.3
Two signed values, assumed to be in two’s complement representations, are added to produce the sum
A1234567 B
151234567 + 0000000
which does not fit into 32 bits. More importantly, since the numbers are consid- ered to be in a two’s complement format, then we overflowed, since we added two fairly large, negative numbers together, and the most significant bit of the 32-bit result is clear (notice the 5 in the most significant byte of the result).
FIGURE 7.2 Status flags in the CPSR.
Let’s examine Example 7.2 again. When we added 0x7B000000 to 0x30000000, the result did, in fact, fit into 32 bits. However, the result would be interpreted as a negative number when we started off adding two positive numbers, so is this an over- flow case? The answer is yes. Both the N and the V bits would be set in the xPSR, as shown in Figure 7.3, if you were to run the following code on the Cortex-M4:
LDR r3, =0x7B000000 LDR r4, =0x30000000 ADDS r5, r4, r3
Notice that the ‘S’ extension is added to the ADD mnemonic, indicating that we want the flags updated as a result of the addition.
7.2.3 The Z fLAg
This is one of the easiest to understand, as the only thing the Z flag tells us is that the result of an operation produces zero, meaning all 32 bits must be zero. This might be the result of a counter expiring, or a routine might need to examine an operand before performing some other kind of arithmetic routine, such as division.
EXAMPLE 7.4
In Chapter 16, we’ll create a short program to change the color of the LED on the Tiva Launchpad, part of which is shown below.
MOVT r7, #0xF4 ; set counter to 0xF40000 spin
SUBS r7, r7, #1 ; just twiddling our thumbs....
BNE spin
In order to hold the LED at a particular color for a second or two, a short loop sets a register to a fixed value then subtracts one, setting the flags in the process, until the register equals zero. The Z flag is used to determine when the counter hits zero, where the BNE (branch if not equal to zero) instruction uses the value of the Z flag. If it is clear, then the program jumps back to the SUBS instruction FIGURE 7.3 Status flags indicating an overflow.
and repeats. Otherwise, the loop is exhausted and the program continues doing something else.
7.2.4 The C fLAg
The Carry flag is set if the result of an addition is greater than or equal to 232, if the result of a subtraction is positive, or as the result of an inline barrel shifter operation in a move or logical instruction. Carry is a useful flag, allowing us to build opera- tions with greater precision should we need it, e.g., creating routines to add 64-bit numbers, which we will see in a moment. If we were to add the two values shown in the code below, the C bit will be set in the status register, since the sum is greater than 232.
LDR r3, =0x7B000000 LDR r7, =0xF0000000
ADDS r4, r7, r3 ; value exceeds 32 bits, generates C out Like older processors, such as the MC68000 and its predecessors, the carry flag is inverted after a subtraction operation, making the carry bit more like a borrow bit, primarily due to the way subtraction is implemented in hardware. For example, these instructions will set the carry bit to a one, since the operation produces no carry out and the bit is inverted:
LDR r0, =0xC0000000 LDR r2, =0x80000000
SUBS r4, r0, r2 ; r4 = r0 - r2 (watch the order!) Let’s further suppose that we really want to subtract two 64-bit numbers:
0x7000BEEFC0000000
− 0x3000BABE80000000
We know the answer should be 0x4000043140000000, and to get this, we use the following code:
LDR r0, =0xC0000000 ; lower 32-bits LDR r1, =0x7000BEEF ; upper 32-bits LDR r2, =0x80000000 ; lower 32-bits LDR r3, =0x3000BABE ; upper 32-bits
SUBS r4, r0, r2 ; set C bit for next subtraction SBC r5, r1, r3 ; upper 32 bits use the carry flag
The first subtraction operation will set the status flags for us. We saw earlier that the C flag is set, since there is no carry out for the first operation, e.g., 0xC minus 0x8 produces no carry. The second subtraction is a subtract with carry (SBC) oper- ation, using the carry bit to perform a normal subtraction. If the carry bit had been clear, the SBC instruction would have subtracted one more from its result.