6

Consider:

LDR r0,=(1:SHL:31) ; this means r0 contains = 2^31 = 0x80000000

ADDS r0,r0,r0 ; which means r0 = 0x80000000+ 0x80000000.

Firstly, I know it is an overflow from the looks of it, but how do I exactly calculate it? Do I use the brute-force method, convert it to binary and sum them together using 1's and 0's? Or is there an alternative way?

Also, I noticed that the flags are updated with N=0 Z=1 C=1 V=1.

While I can understand why C=1, why are Z and V=1? Why is 0x80000000+ 0x80000000 a zero and has unsigned overflow too?

Peter Mortensen
  • 1,676
  • 3
  • 17
  • 23
Meep
  • 375
  • 1
  • 6

2 Answers2

15

Add the two numbers together and truncate to the lower (right) 32 bits or 8 nibbles.

So 0x80000000 + 0x80000000 = 0x100000000, we then truncate and we have 0x00000000 left in the 32-bit register (so the Zero flag is set- it only cares about what is in the register- or more specifically what was in the register from the last flag-setting operation) with a one in the extra bit- which shows up as a Carry flag set in the ARM. When you're adding unsigned numbers that means you have an overflow.

The N flag indicates that the result from the last flag-setting operation was negative if interpreted as a 2's complement number. A 2's complement number is negative if the MSB is 1.

The V flag indicates an overflow in adding when the numbers are interpreted as 2's complement (signed) numbers.

One way to look at the signed overflow is that if the two numbers being added have opposite signs then overflow is impossible. If the two number have the same signs but the result has the opposite sign from the operands then overflow has occurred. No need to look at the carry.

Neither, both or either flag may be set, depending on the numbers.

For example 0x7FFFFFFF + 0x7FFFFFFF = 0xFFFFFFFE C = 0, V = 1, Z = 0 indicates an overflow if the addition was signed but not if unsigned.

Or 0xFFFFFFFF + 1 = 0x00000000 C = 1, V = 0, Z = 1 indicates an overflow if the addition was unsigned but not if signed.

The ARM core does not know what interpretation you are using, but provides both flags so you can use the one that is appropriate.

Spehro Pefhany
  • 376,485
  • 21
  • 320
  • 842
14

In most modern circumstances (it wasn't always so easy to say this), the part of the ALU that performs addition and subtraction is fundamentally agnostic about signed and unsigned operations. It doesn't know about signed values and it doesn't care about signed values. The ALU simply performs an unsigned operation and that's all it does.

For subtraction, the subtrahend is simply inverted and the operation's carry-in, which in addition is set to 0, will be set to 1, instead. That's it. It's all just an ADD operation with some modifications done to one of the inputs and the carry-in, if you choose SUB instead of ADD. The exact same ADD operation takes place, either way.

It's brain-dead easy.

Because some operations need to be extended to multi-word, the ALU includes a copy of a bit you otherwise would not get -- the carry-out of the word operation. It saves this bit into the C status bit. This is a simple capture. All it does is snap a copy of the carry-out of the ALU ADD logic block. If you are doing unsigned operations, the C status bit tells you if you had an unsigned arithmetic overflow. (And need multi-word storage, likely.) But what it actually means is entirely up to you. The ALU simply doesn't care. It's just "being helpful" in case you care.

The Z status bit is 1 if the ALU operation result is zero and 0 otherwise. Usually, this is the case not only for ADD and SUB but also for many other logical operations -- check the manual to be sure as there is usually a giant mux and a designer may or may not use this detection for other operations.

The Z status bit is very important because of the very common need of decrementing some counter and detecting when it goes to zero, quickly branching out of a loop. There are other important uses (signed operations, included), but this is the primary reason. You very often want to know when an operation produces an exact zero result. So designers add the extra (cheap) logic to save you an instruction or two and hand the answer to you on a silver platter, instead.

The V status bit is there because it is also cheap to generate and you can use it, if you are working with signed interpretations. It signifies an arithmetic overflow and is calculated as the XOR of the carry out of the next-to-most significant bit and the carry bit itself. Again, the ALU doesn't really care about signed values and doesn't have any logic to observe them. It's just calculating a flag that is helpful for detecting signed arithmetic overflow. If it is set, and if you think you are working with signed values, then you had such an overflow. You don't care about the V status bit if you imagine you are doing unsigned operations.

So,

  1. If you believe you are using unsigned values then watch the C status flag to detect something requiring extra attention. You don't care about the V status flag.
  2. If you believe you are using signed values then watch the V status flag to detect something requiring extra attention. You don't care about the C status flag.

Since it's not important to think about this with wide words, we can drop back to 3-bit words to keep it simple. Here, there are only 8 symbols:

         Unsigned    Signed     Subtrahend
000          0          0          111
001          1          1          110
010          2          2          101
011          3          3          100
100          4         -4          011
101          5         -3          010
110          6         -2          001
111          7         -1          000

                                     Result          Unsigned            Signed
  Operation     Actual Operation    V C ALU       Interpretation     Interpretation
ADD 011 + 001 = ADD 011 + 001 + 0 = 1 0 100         3 + 1 =  4          3 +  1 = 4 E
ADD 011 + 110 = ADD 011 + 110 + 0 = 0 1 001         3 + 6 =  9 E        3 + -2 = 1
SUB 011 - 001 = ADD 011 + 110 + 1 = 0 1 010         3 - 1 =  2          3 -  1 = 2
SUB 011 - 110 = ADD 011 + 001 + 1 = 1 0 101         3 - 6 = -3 E        3 - -2 = 5 E

From the above (E is an error) you can see how to interpret the bits. In unsigned addition, C=1 is an error (carry required.) In unsigned subtraction, C=0 is an error (failure to borrow.) In signed addition, V=1 is an error (signed carry required.) In signed subtraction, V=0 is an error (failure to signed-borrow.)

See also this discussion for a specific case of signed conditional branching.

jonk
  • 77,059
  • 6
  • 73
  • 185
  • Really nice explanation, you could be writing textbooks. – JosephDoggie Aug 10 '21 at 20:56
  • 2
    @JosephDoggie Thanks! I appreciate the kind thought. [But here today](https://electronics.stackexchange.com/a/581013/38098) you can see where Elliot would probably disagree with you. ;) – jonk Aug 10 '21 at 20:58