takanuva15
takanuva15

Reputation: 1668

Confusion about ARM documentation on carry flag

In the ARM documentation here, it says that:

A carry occurs:

... if the result of a subtraction is positive or zero ...

I know from this answer on SO that the carry flag is set in subtraction when there is unsigned underflow (ie the number being subtracted (subtrahend) is greater than the number that is being subtracted from (minuend)).

So consider the example:

r1 = 5
r2 = 10
CMP r1, r2

Compare (CMP) does a subtraction as mentioned here and then sets the appropriate flags. In this case, r1-r2 = 5-10 = -5. Since we have unsigned underflow here (5 < 10), we expect the carry flag to be set. But according to the ARM documentation, the result (-5) is not positive or zero, so the carry flag should not be set. (Assuming we look at the result signed; otherwise a carry would never occur according to the documentation).

Is the ARM documentation wrong? What's my misunderstanding?

Upvotes: 9

Views: 10583

Answers (3)

old_timer
old_timer

Reputation: 71506

We don't need all 32 bits to show what is going on with a subtraction:

5 - 3

From grade school we know that 5 - 3 = 5 +(-3) which is how it is done in logic, a feature of twos complement is to get to -3 you invert and add one so:

5 - 3

      1
   0101
 + 1100
=========

Finish it:

  11011
   0101
 + 1100
=========
   0010

So generically (not processor specific) 5 - 3 = 2. the carry in and carry out of the msbit are both one so the signed overflow would be not set the carry out is a 1. But some architectures as well as inverting the second operand and the carry in (to the lsbit) also invert the carry out calling it a borrow. Some don't.

Some document this when you look at things like greater than and less than as to what the definition of the carry bit is:

5 - 4

  11111
   0101
 + 1011
=========
   0001

5 - 5

  11111
   0101
 + 1010
=========
   0000

5 - 6

  00011
   0101
 + 1001
=========
   1111

5 - 7

  00011
   0101
 + 1000
=========
   1110

What this is showing is that if you look at the raw carry out it switches when operand b equals operand a, when b is less than a it is set when b is equal to or greater than a it is clear. So then if the architecture leaves it unmodified you can use the carry bit for unsigned greater than or less than (but not equal) in one of the cases greater than or equal is defined by that flag and which direction depends on the architecture (if it inverts carry out into a borrow). the other direction you either flip the operands and use the one bit or you use N and C to determine something than or equal.

The arm docs unlike some others show you for each of the conditionals what the flags are and knowing the above or being able to repeat it in a simple test you can figure out if they invert or don't. the instruction sbb is subtract with borrow rather than sbc subtract with carry which sort of, but not by itself, implies how that instruction set interprets the bit.

Upvotes: 2

crifan
crifan

Reputation: 14318

I have same confusion about:

  • The ALU status flags
    • A carry occurs 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

thought: 5 - 3 = 2 -> positive result -> should C=1 ?

finally found ARM official useful doc: Carry flag

In A32/T32 code, C is set in one of the following ways:

  • For an addition, including the comparison instruction CMN, C is set to 1 if the addition produced a carry (that is, an unsigned overflow), and to 0 otherwise.
  • For a subtraction, including the comparison instruction CMP, C is set to 0 if the subtraction produced a borrow (that is, an unsigned underflow), and to 1 otherwise.

to know:

  • for subtraction: 5 - 10 = -5 -> produced a borrow = unsigned underflow = negative result -> should C=0
    • Note: NOT C=1

so, conform to:

  • for subtraction: 5 - 3 = 2 -> positive result -> should C=1

Upvotes: 1

fuz
fuz

Reputation: 92966

ARM uses an inverted carry flag for borrow (i.e. subtraction). That's why the carry is set whenever there is no borrow and clear whenever there is. This design decision makes building an ALU slightly simpler which is why some CPUs do it.

Upvotes: 10

Related Questions