0
\$\begingroup\$

Currently I am learning simple binary math for a microprocessors course and have a trivial question on signed addition in 2's complement notation.
My professor mentioned that when we substract two numbers (to be precise, addition with a negative number) a carry is generated which is not an error and which can be discarded. Some examples with 8-bit signed numbers could be as:

   1111 1111 (-1)       0010 1000 (+40) 
+  1111 1110 (-2)     + 1110 1100 (-20)
------------------    ------------------
 1 1111 1101 (-3)     1 0001 0100 (+20)        
 ^carry discarded     ^carry discarded

Now, a carry is generated, but it does not indicate an error as without it the result is correct and we discard it. My question is, how the arithmetic logic unit handles this, knowing that binary adders don't know about signed/unsigned numbers. And if we take a look at a simple Full Adder circuit, the carry generated from the most significant bit is directly transferred, so the carry flag should be set if there is a carry.
But then how does it work when we need to discard the carry? Wouldn't it cause problems in consecutive arithmetic operations where an operation's carry-out becomes the other's carry-in?4-bit full adder

\$\endgroup\$
3
  • 2
    \$\begingroup\$ The carry-out is usually preserved in processors in order to permit multi-word operations. You find it in what is usually called a "status byte/word." \$\endgroup\$ – jonk Mar 25 at 20:39
  • \$\begingroup\$ What @jonk said is correct, for example an 8-bit processor doing the operations above as part of a 16-bit operation wouldn't discard the carry, but would use it in adding the more-significant bytes. To understand when the carry would be an error and couldn't be discarded, think about what input conditions would lead to it. \$\endgroup\$ – Theodore Mar 25 at 20:59
  • \$\begingroup\$ Depends on context.... If this ALU is part of a CPU, the next instruction may be ADC (Add with Carry) or ADD (which ignores carry). So there's one way. \$\endgroup\$ – user_1818839 Mar 25 at 21:06
1
\$\begingroup\$

Here's an example of a simplified 4-bit adder/subtractor that supports ADD, ADC, SUB, and SBB instructions:

enter image description here

(It doesn't include instructions to clear or set the CARRY flag. You'll just have to imagine that those also exist.)

The supported instructions are:

       ADD/SUB      ADC/SBB       CARRY-IN
ADD       0            0             0
ADC       0            1             C
SUB       1            0             1
SBB       1            1             C

I've added the last column above to tell you what the carry-in to the adder will be for each instruction. Where C is shown, the value comes from the result's carry-out of the prior operation. Otherwise, it's hard-coded to the value shown.

I want you to pay particular attention to this detail of how the carry-in is handled, because it's different from what you show. In the above diagram, you will see a mux used there, which either selects an opcode bit to pass along to the carry-in or else it grabs the carry flag that was stored in the prior operation.

Let's look at the six permutations adding two signed 4-bit values. (The carry-in is forced to 0 in this ADD case.) These are:

enter image description here

Take note of the carry and overflow status values, above.

We don't care, right now, about the ADC instruction. That will have to wait until later when we address multi-word operations.

There will be a similar set of six permutations for subtraction, as well.

enter image description here

Again, take note of the carry and overflow status values, above.

Now, of all the above there are four (two from the ADD group and two from the SUB group) where there was an overflow (V) set. Both pairs show a case where the CARRY is zero and a case where the CARRY is one. So this gives us a chance to see how multi-word operations take place where the CARRY value will be '0' in one case and '1' in the other. That should be good enough, I think.

So we have the following four cases where an overflow occurs (V=1):

  0000 0100 (4)      1111 1100 (-4)      0000 0100  (4)      1111 1100 (-4)
+ 0000 0101 (5)    + 1111 1011 (-5)    - 1111 1011 (-5)    - 0000 0101  (5)
-----------        -----------         -----------         -----------

I've keep these to just two 4-bit words above. But in the operations below, it's helpful to see it extended further. So I'll do that, below.

Let's start with the first case, 4+5. We already have the bits for the low order word from above. I'll then perform the high order word using ADC:

     STEP 1         STEP 2         STEP 3         STEP 4

          0 ADD          0 C            0 C            0 C
       0100           0000           0000           0000
 ADD   0101     ADC   0000     ADC   0000     ADC   0000
-----------     ----------     ----------     ----------
 0 1 0 1001     1 0 0 0000     1 0 0 0000     1 0 0 0000   ---> 0000 0000 0000 1001
 Z V C          Z V C          Z V C          Z V C 

That result is correct. It's 9 and there's no carry-out nor overflow. (The Z indicates a zero, which is not right for the double-word result. But it is right for the upper word.)

Next case:

     STEP 1         STEP 2         STEP 3         STEP 4

          0 ADD          1 C            1 C            1 C
       1100           1111           1111           1111
 ADD   1011     ADC   1111     ADC   1111     ADC   1111
-----------     ----------     ----------     ----------
 0 1 1 0111     0 0 1 1111     0 0 1 1111     0 0 1 1111   ---> 1111 1111 1111 0111
 Z V C          Z V C          Z V C          Z V C

That result is correct. It's -9. The carry of '1' in this case could be extended to still more words, if there were any.

Next case. Here, when reading the following keep in mind that the subtrahend is inverted before the addition takes place. A SUB operation sets the carry-in to '1', not '0'. A SBB operation leaves the carry-in alone -- to whatever was stored by the prior operation.

     STEP 1         STEP 2         STEP 3         STEP 4

          1 SUB          0 C            0 C            0 C
       0100           0000           0000           0000
 SUB   1011     SBB   1111     SBB   1111     SBB   1111
-----------     ----------     ----------     ----------
 0 1 0 1001     1 0 0 0000     1 0 0 0000     1 0 0 0000   ---> 0000 0000 0000 1001
 Z V C          Z V C          Z V C          Z V C

That result is correct. It's 9. The final carry is '0' which means there's a borrow if we were to continue extending the operation to additional words.

Finally, this:

     STEP 1         STEP 2         STEP 3         STEP 4

          1 SUB          1 C            1 C            1 C
       1100           1111           1111           1111
 SUB   0101     SBB   0000     SBB   0000     SBB   0000
-----------     ----------     ----------     ----------
 0 1 1 0111     0 0 1 1111     0 0 1 1111     0 0 1 1111   ---> 1111 1111 1111 0111
 Z V C          Z V C          Z V C          Z V C

That result is correct. It's -9. The final carry is '1' which means there's no further borrow if we were to continue extending the operation to additional words.

As another thing for you to consider when reading through the above extended word operations, please note that when an operation results in an overflow (V is set), then this means an extended word operation is required to take care of the issue. (If supported.) Once the V bit is cleared by an operation, there's no need to keep extending the size with added words. You can see that V=1 in STEP 1 of each case, indicating that another word operation is needed. But STEP 2 and beyond all have V=0. So that means no further extension is required and we didn't have to go all the way through STEP 4.

\$\endgroup\$
2
\$\begingroup\$

This depends entirely on what the processor architects decided to do with the carry. Remember that the processor won't know whether a carry will or will not occur, and won't know whether the operands are signed or unsigned, so it just does the same thing whenever it does an addition.

Perhaps a better way to think about this is that there will always be a carry out of the MSB during addition. Sometimes the value of the carry will be 0 and sometimes it will be 1.

\$\endgroup\$
1
\$\begingroup\$

Status bits are set/cleared by the processor depending on the result of an instruction execution. These status bits may or may not affect the execution of a subsequent instruction, it depends on the particular instruction. For example, processors have separate instructions for "add" and "add with carry"; the former is affected by the carry bit, the latter ignores it. The compiler will choose the appropriate instruction. For subtraction operations, the carry bit is regarded as a negated borrow

\$\endgroup\$
4
  • \$\begingroup\$ The difference you are talking about is whether the addition will use a carry in, not whether the processor will save a carry out. \$\endgroup\$ – Elliot Alderson Mar 25 at 21:07
  • \$\begingroup\$ @ElliotAlderson the point is : where does that Carry In come from? Yes ... the previous Carry Out. The question asks how to choose to use or discard it; and this answers that. (There are of course other instructions which can access the Carry flag but one example will do) \$\endgroup\$ – user_1818839 Mar 25 at 21:17
  • \$\begingroup\$ @BrianDrummond I don't follow your reasoning. When the processor is performing an ADD it can't know whether the next instruction will be another ADD or an ADC. My point is that the carry is never discarded. The carry flag always gets the value of carry out...sometimes that is 1, sometimes it is 0. \$\endgroup\$ – Elliot Alderson Mar 25 at 21:20
  • \$\begingroup\$ Edited, thanks for the comments \$\endgroup\$ – user28910 Mar 25 at 21:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.