'Subtraction Carry (was Complements (no not thanks)'
|Thanks, Andy, for the DETAILED explanation of adders, subtraction, and
complements. I have a somewhat related question.
What does the carry flag represent after a PIC subtraction? I've
heard from one place that it should be thought of as a "non-negative
result" flag, but that doesn't always work. The PSIM simulator gave
the following reslts for these values:
-4 - -2 = -2 No Carry
-4 - 2 = -6 Carry
-2 - 4 = -6 Carry
-2 - -4 = 2 Carry
4 - -2 = 6 No Carry
2 - -4 = 6 No Carry
My 16C84 code looked like this:
movwf temp ; temp = -4
movlw -2 ; w = -2
subwf temp, 0 ; w = temp - w (-4 - -2)
; result is -2 (FE) and NO CARRY (positive?)
I was bit by this mis-understanding this weekend and my resolution
was to AND the result with 0x80 and test for zero to determine a
Byon Garrabrant N6BG netcom.combyon
| To ensure that you got this entire message, scroll down to the
end and make sure that you see the line "If you can read this,
you got the whole thing".
Byon Garrabrant <MITVMA.MIT.EDU> wrote: PICLIST
and Bob Fehrenback replied:
> I'm sure Andy Warren will want to take a shot at this, but just in
> case he is busy --
> PICs don't do signed arithmetic. The basic instructions treat
> each opperand as an 8 bit absolute value.
Bob's correct on all three counts: I DO want to take a shot at it, I
AM busy, and PICs don't do signed arithmetic.
Here's the long-form version of Bob's concise answer:
MPASM AND NEGATIVE NUMBERS
When you write something like:
the assembler automatically converts that "-4" into its
two's-complement form by taking the binary representation for decimal
4, inverting all the bits, and adding 1:
Decimal 4 = Binary 00000100.
Inverting the bits gives 11111011.
Adding 1 gives 11111100.
If you convert that final binary number back to decimal, you'll see
Binary 11111100 = Decimal 252.
Therefore, writing "MOVLW -4" is EXACTLY THE SAME as writing
Since "MOVLW -4" and "MOVLW 252" assemble to exactly the same
opcodes, there's no way for the PIC to tell the difference between
the two instructions. In fact, the PIC ALWAYS treats 8-bit numbers
as though they were positive integers in the range [0-255].
When two positive numbers are added, the carry flag indicates whether
the result will fit in 8 bits: The carry flag is cleared to 0 if the
result fits in 8 bits, and it's set to 1 if the result is larger than
8 bits. For example:
1 + 1 = 2. Decimal 2 = Binary 10, which fits in 8 bits, so the
carry flag is cleared to 0.
252 + 254 = 506. Decimal 506 = Binary 111111010, which requires
9 bits, so the carry flag is set to 1.
You already knew this, right?
Ok. Take a look at that second addition example, "252 + 254", and
imagine that you want to write a PIC program to perform it. Using the
16Cxx instruction set for simplicity's sake, the code would look like
The result of the addition is 506, or binary 111111010. Since this
is larger than 8 bits, the carry flag is set to 1 and W ends up
holding the low 8 bits of the result (11111010, or decimal 250).
Clear so far? Good, because it gets a little tricky now.
Remember that "MOVLW -4" is the same as "MOVLW 252"? Similarly,
"ADDLW -2" is the same as "ADDLW 254". This means that the two-line
program above is EXACTLY THE SAME as:
Do not read any further until you understand why this is true.
Ok... We said that the carry flag indicates that the result of an
addition is too large to fit in 8 bits, so you would EXPECT the carry
to be set after adding 252 to 254. After adding -4 to -2, though,
you WOULDN'T expect the carry to be set, because the result (-6) fits
in 8 bits (we know this because 8-bit two's-complement numbers can
hold any value in the range [-127 - +128]).
Nevertheless, the carry IS set after exacuting the "-4 + -2" code,
because the PIC sees the addition as exactly equivalent to "254 +
So what do you do?
There's a simple rule:
If you're treating the 8-bit addends as non-negative numbers in
the range [0-255] (that is, if binary 11111100 means "252" to
you, rather than "-4"), you can safely treat the carry as a
"result is larger than 8 bits" indicator.
If, on the other hand, you're treating the 8-bit addends as
two's-complement numbers in the range [-128 - +127] (that is,
binary 11111100 means "-4" to you), you must IGNORE the carry;
it provides no useful information on the size of the result.
See? I told you it was simple.
Now let's see how this applies to YOUR question.
A quick review: The PIC treats all 8-bit numbers as though they were
positive numbers in the range [0-255]. After adding two of these
numbers, it sets the carry flag if the result is larger than 255 (the
largest number that can be represented in 8 bits).
Ok... As I explained in that two-part series on two's-complement
math, the PIC performs subtractions by negating the subtrahend and
ADDING it to the minuend. That is, when you ask the PIC to calculate
"A - B", it ACTUALLY calculates "A + (-B)".
Since it's internally ADDING two numbers in order to perform the
"subtraction" (and since, as I discussed in that two's-complement
tutorial, it even uses the same circuitry for both addition and
subtraction), the PIC handles the carry flag EXACTLY THE SAME WAY for
both addition and subtraction.
Let's say that you ask the PIC to calculate "-4 - 2" using the
SUBLW -4 ;Note that "SUBLW -4" means "Subtract W from -4".
The assembler translates this to:
When the PIC performs the "252 - 2" operation, it treats it
as "252 + (-2)".
"-2", as we know, is internally represented as binary 11111110
(decimal 254), so the PIC performs the "-4 - 2" operation by ACTUALLY
calculating "252 + 254".
Again, read no further until you understand why this is true.
Ok... Let's continue.
252 + 254 equals 506, or binary 111111010. Since this is larger than
8 bits, the carry flag is set to 1 and W ends up holding the low 8
bits of the result (11111010, or decimal 250).
Since you're treating your numbers as two's-complement values in the
range [-128 - +127], you know that "250" must actually be some
negative number "-x" (because, in the 8-bit two's-complement world,
positive numbers larger than 127 don't exist).
We know that 250 equals "-x" in our numbering scheme, but what's
"x"? Let's see...
Decimal 250 = Binary 11111010.
Inverting the bits gives 00000101.
Adding one gives 00000110.
Binary 00000110 = Decimal 6.
In our two's-complement number system, therefore, "250" equals "-6",
so even though we subtracted 2 from -4 by adding 252 to 254, we got
the correct result.
This is cool, but unimportant at this point. Two's-complement math
was yesterday's topic; what we want to know TODAY is what the carry
flag has to do with all of it.
So "-4 - 2" sets the carry flag. What does this mean? Maybe
nothing... Let's see.
SUBTRACTION AND THE CARRY FLAG
You said "I've heard from one place that [the carry flag] should be
thought of as a 'non-negative result' flag". As you noticed (and as
I've just shown with the "-4 - 2" example), this is demonstrably
So what the hell was the guy THINKING when he gave you that
Well... Since the guy was me, I'll tell you.
Remember what I said about the PIC treating all numbers that you
give it as positive integers in the range [0-255]? Imagine that
you're as dumb as a PIC, and look at the "-4 - 2" example from IT'S
point of view.
"-4 - 2", from the PIC's perspective, is equal to "252 - 2". The
result of THAT operation is 250, a NON-NEGATIVE NUMBER.
Therefore, it sets the carry flag to 1... The carry flag indicates
that the result is non-negative.
See the problem? YOU'RE treating "252" as though it's a negative
number, and treating the result (250) as a negative number as well,
but the PIC treats them both as POSITIVE numbers.
Ok... Let's try another example: Instead of subtracting 2 from -4,
subtract -2 from -4:
The PIC treats "-4 - (-2)" as "-4 + (-(-2))", or "-4 + 2".
The PIC represents "-4" internally as 252.
Therefore, the calculaton boils down to "252 + 2".
252 + 2 equals 254.
254 fits in 8 bits, so the carry is cleared to 0.
Since we're treating this as a two's-complement operation (we have
to, in order for an operation like "-4 - (-2)" to have any meaning),
we treat the result (254) as a two's-complement number equivalent to
Again, the math worked, but THIS time (even though the result is
just as negative as the "-6" result we got earlier), the carry flag
is cleared to 0.
The upshot of all this?
After a subtraction, the carry flag is only meningful if you're NOT
treating your numbers as two's-complement values.
Just as with addition, then, the rule is:
IGNORE the carry flag if you're treating the 8-bit subtrahend and
minuend as two's-complement numbers in the range [-128 - +127].
If you're treating the numbers as non-negative values in the
range [0 - 255], on the other hand, you can safely use the carry
flag to indicate whether the result is non-negative (i.e., in
the range [0 - 255]), or negative (i.e., in the range
[-1 - (-255)]; the carry will be SET TO 1 in the former case and
CLEARED TO 0 in the latter.
So there you go... I just spent over an hour explaining what Bob
Fehrenbach managed to say in one sentence. Sigh...
If you can read this, you got the whole thing.
=== Andrew Warren - ix.netcom.com === fastfwd
=== Fast Forward Engineering - Vista, California ===
=== Did the information in this post help you? Consider ===
=== contributing to the PICLIST Fund. Details are at: ===
=== http://www.geocities.com/SiliconValley/2499/fund.html ===
More... (looser matching)
- Last day of these posts
- In 1997
, 1998 only
- New search...