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:movfw X subwf 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 movf RAMx,w addlw 255 - Y ; eg if RAMx > 5 ... addlw d'250' btfsc status,carry goto True ;if RAMx < Y movf RAMx,w addlw 255 - Y + 1 ; eg if RAMx < 5 ... addlw d'251' btfss status,carry goto True ;if RAMx >= Y movf RAMx,w addlw 255 - Y + 1 ; eg if RAMx >= 5 ... addlw d'251' btfsc status,carry goto True ;if RAMx <= Y movf RAMx,w addlw 255 - Y ; eg if RAMx <= 5 ... addlw d'250' btfss status,carry goto 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 movf RAMy,w sublw 0xFF addwf RAMx,w btfsc status,carry goto trueScott Dattalo says:
on the 18cxxx chips this can be shortened to:movf RAMx,w ;wreg = RAMx subwf 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:
movf RAMx,w subwf RAMy,w skpc goto 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 movf RAMx,w sublw 0xFF addwf RAMy,w btfsc status,carry goto true ;if RAMx >= RAMy movf RAMx,w sublw 0xFF addwf RAMy,w btfss status,carry goto trueScott Dattalo says:
on the 18cxxx chips this can be shortened to:movf RAMy,w ;wreg = RAMy subwf 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 movf RAMy,w sublw 0xFF addwf RAMx,w btfss status,carry goto true ;********** 16 BIT ;RAM > X movf RAMH,w sublw XH btfss status,c goto true btfss status,z goto false movf RAML,w sublw XL btfss status,c goto true ;RAM < X movlw XH subwf RAMH,w btfss status,c goto true btfss status,z goto false movlw XL subwf RAML,w btfss status,c goto true ;RAM >= X movf RAMH,w sublw XH btfss status,c goto true btfss status,z goto false movlw XL subwf RAML,w btfsc status,c goto true ;RAM <= X movlw XH subwf RAMH,w btfss status,c goto true btfss status,z goto false movf RAML,w sublw XL btfsc status,c goto trueScott Dattalo says:
for the 16-bit sequences it'd be much quicker to:;XH:XL YH:YL movf yl,w subwf xl,w movf yh,w skpz incf yh,w ;propagate the carry from the low byte subtraction. subwf xh,w skpnc goto 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 } } movf y_hi,w cpfslt x_hi bra x_is_ge_y movf y_lo,w 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:
movf y_lo,w subwf x_lo,w movf y_hi,w subwfc x_hi,w bnc x_is_lt_y ;or bc x_is_ge_y ;or bn x_is_gt_y
Also: