PIC Microcontoller Comparison Math Methods
Robin Abbott - robin.abbott@dial.pipex.com says
I find it easier to show the state of the flags in a table, consider:mov W, X mov W, Y-w ;This subtracts X from Y and leaves the result in W. ;Now look at flags for the compare operations: X<Y C=1, Z=0 X<=Y C=1, Z=Don't Care X==Y C=1, Z=1 X>=Y C=0, Z=Don't Care X>Y C=0, Z=0 X!=Y C=?, Z=0Hope this helps! (Mind you it would have been easier if Microchip had simply put the logic in Hardware to "correct" the carry flag after a subtraction !
Tony Nixon says
Just a few code snippets I discovered in the last two weeks while writing some new software.;if RAMx > Y mov W, RAMx ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ;addlw 255 - Y ; eg if RAMx > 5 ... addlw d'250' mov Hack, W mov W, #255 - Y ; eg if RAMx > 5 ... addlw d'250' add W, Hack snb status.carry jmp True ;if RAMx < Y mov W, RAMx ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ;addlw 255 - Y + 1 ; eg if RAMx < 5 ... addlw d'251' mov Hack, W mov W, #255 - Y + 1 ; eg if RAMx < 5 ... addlw d'251' add W, Hack sb status.carry jmp True ;if RAMx >= Y mov W, RAMx ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ;addlw 255 - Y + 1 ; eg if RAMx >= 5 ... addlw d'251' mov Hack, W mov W, #255 - Y + 1 ; eg if RAMx >= 5 ... addlw d'251' add W, Hack snb status.carry jmp True ;if RAMx <= Y mov W, RAMx ;*** WARNING: ADDLW was expanded in three instructions! Check if previous instruction is a skip instruction. ;addlw 255 - Y ; eg if RAMx <= 5 ... addlw d'250' mov Hack, W mov W, #255 - Y ; eg if RAMx <= 5 ... addlw d'250' add W, Hack sb status.carry jmp TrueJust following on from the previous snippets, in an effort to make comparisons easier to understand, here are some more. The best part is, the Z flag is ignored.
;if RAMx > RAMy mov W, RAMy ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw 0xFF add W, RAMx snb status.carry jmp trueScott Dattalo says:
on the 18cxxx chips this can be shortened to:mov W, RAMx ;wreg = RAMx mov W, RAMy-w ;wreg = RAMy - RAMx bn true ;Branch if negative ;The N bit will be cleared if RAMx == RAMy or ;RAMy > RAMx, and will be set if RAMy < RAMx ;18cxxx 3*16 = 48 bits of program memory ;16cxxx 5*14 = 70 bits of program memory(or you could use the bnc [branch if no carry] to achieve the same effect. The negative bit has a clearer meaning in this context).
btw, Tony's example can be shortened to:
mov W, RAMx mov W, RAMy-w sb C jmp true but there are still 4*14 = 52 bits. however this works on the 12bit core, so only 4*12 = 48 bits of program memory are required there.;if RAMx < RAMy mov W, RAMx ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw 0xFF add W, RAMy snb status.carry jmp true ;if RAMx >= RAMy mov W, RAMx ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw 0xFF add W, RAMy sb status.carry jmp trueScott Dattalo says:
on the 18cxxx chips this can be shortened to:mov W, RAMy ;wreg = RAMy mov W, RAMx-w ;wreg = RAMx - RAMy bnn true ;branch if not negative ;The N bit will be cleared if RAMx == RAMy or ;RAMx > RAMy, and will be set if RAMy < RAMxAgain, you could use the bc (branch on carry) instruction too. Also, Tony's sequence can be reduced by an instruction.
;if RAMx <= RAMy mov W, RAMy ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw 0xFF add W, RAMx sb status.carry jmp true ;********** 16 BIT ;RAM > X mov W, RAMH ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw XH sb C jmp true sb Z jmp false mov W, RAML ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw XL sb C jmp true ;RAM < X mov W, #XH mov W, RAMH-w sb C jmp true sb Z jmp false mov W, #XL mov W, RAML-w sb C jmp true ;RAM >= X mov W, RAMH ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw XH sb C jmp true sb Z jmp false mov W, #XL mov W, RAML-w snb C jmp true ;RAM <= X mov W, #XH mov W, RAMH-w sb C jmp true sb Z jmp false mov W, RAML ;*** WARNING: Manual replacement required for "SUBLW k" instruction (w = k - w). Check if previous instruction is a skip instruction. sublw XL snb C jmp trueScott Dattalo says:
for the 16-bit sequences it'd be much quicker to:;XH:XL YH:YL mov W, yl mov W, xl-w mov W, yh sb Z mov W, ++yh ;propagate the carry from the low byte subtraction. mov W, xh-w snb C jmp x_is_greater_than_or_equal_to_ySimilar sequences exist for the other cases. for the 18cxxx
char compare(unsigned int x, unsigned int y) { if(x<y) { x is less than y } else { x is greater than or equal to y } } mov W, y_hi cpfslt x_hi bra x_is_ge_y mov W, y_lo cpfslt x_lo bra x_is_ge_y x_is_lt_y ... x_is_ge_y ...But this can be made faster by using subtracts:
mov W, y_lo mov W, x_lo-w mov W, y_hi subwfc x_hi,w ;*** WARNING: MPASM macro BNC is not supported yet. Replace manually. bnc x_is_lt_y ;or ;*** WARNING: MPASM macro BC is not supported yet. Replace manually. bc x_is_ge_y ;or bn x_is_gt_y
Also: