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 wrote: > 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 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. Byon: 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: MOVLW -4 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 that: Binary 11111100 = Decimal 252. Therefore, writing "MOVLW -4" is EXACTLY THE SAME as writing "MOVLW 252". 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]. 8-BIT ADDITION -------------- 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 this: MOVLW 252 ADDLW 254 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: MOVLW -4 ADDLW -2 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 + 252". 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. SUBTRACTION ----------- 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 following code: MOVLW 2 SUBLW -4 ;Note that "SUBLW -4" means "Subtract W from -4". The assembler translates this to: MOVLW 2 SUBLW 252 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 untrue. So what the hell was the guy THINKING when he gave you that misinformation? 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 "-2". 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... -Andy If you can read this, you got the whole thing. === Andrew Warren - fastfwd@ix.netcom.com === === 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 ===