MORE PIC TRICKS (Peter Hemsley - July '01) - updated 12July01 The original version of this very useful library routine has been used on many occasions for scaling data. Many amateur programmers who do not fully understand binary numbers often find binary arithmetic a daunting prospect and may resort to cheating, i.e. using multiple additions and subtractions to perform multiplication and division. The routine divides two 16-bit numbers, the dividend by the divisor, which have been pre-loaded into dividl,h and divisl,h respectively, and returns the result (quotient) in dividl,h with the remainder in remdrl,h. The original dividend is lost, being overwritten by the quotient. Readers who are familiar with arithmetic routines will not find anything unusual in the listing, in fact it is based on a standard algorithm, optimised for the PIC instruction set. Note the lines that show how to compare two 16-bit numbers using the limited instructions of the PIC. However, it is worth noting that a bug exists in Microchip's standard division routine. It's the carry (or borrow) out from double precision addition or subtraction that I found is not guaranteed to be correct for all possible input values. The double precision addition and subtraction codes are standard ones published in various Microchip documents and must have been used unimaginable number of times by pic programmers around the world. The good news is that my division routine is ok because a borrow out from the double precision subtraction is guaranteed not to occur. Here is the Microchip double precision addition code. ACCb + ACCa -> ACCb movf ACCaLO,w addwf ACCbLO btfsc STATUS,CARRY incf ACCbHI movf ACCaHI addwf ACCbHI Assume for the moment that the addition of the low bytes produces a carry, this means that the instruction incf ACCbHI will be executed. Now if the input value of ACCbHI is $FF, it will be incremented to $00. The subsequent addition of the high bytes will not produce a carry out, which is not correct since the incf instruction produced an overflow condition and the carry should be set. I have checked Microchip's published multiply routine and it also suffers the same problem. ***************** ;Divide 16bit dividend (dividL,H) by 16bit divisor (divisL,H) ;Result (quotient) in dividL,H and remdrL,H processor 16f84 include p16f84.inc radix dec ;Ram equates dividL equ 0xC ;Dividend and quotient quotL equ dividL dividH equ 0xD quotH equ dividH remdrL equ 0xE ;Remainder remdrH equ 0xF divisL equ 0x10 ;Divisor divisH equ 0x11 bitcnt equ 0x12 ;Bit count divd equ 5432 ;Test code for MPLAB simulator divs equ 22 org 0 test movlw low divd movwf dividL movlw high divd movwf dividH movlw low divs movwf divisL movlw high divs movwf divisH call divide return divide movfw divisL iorwf divisH,w skpnz goto div0 ;Division by zero ! movlw 16 ;16 bit division movwf bitcnt clrf remdrH ;Clear remainder clrf remdrL dvloop clrc ;Set quotient bit to 0 rlf dividL ;Shift left dividend and quotient rlf dividH ;Msb into carry rlf remdrL ;and then into partial remainder rlf remdrH movfw divisH ;Compare partial remainder and divisor subwf remdrH,w skpz goto testgt ;Not equal so test if remdrH is greater movfw divisL ;High bytes are equal,compare low bytes subwf remdrL,w testgt skpc ;Carry set if remdr >= divis goto remrlt movfw divisL ;Subtract divisor from partial remainder subwf remdrL skpc ;Test for borrow decf remdrH ;Subtract borrow movfw divisH subwf remdrH bsf dividL,0 ;Set quotient bit to 1 ;Quotient replaces dividend which is lost remrlt decfsz bitcnt goto dvloop clrz ;Clear error flag (z) div0 return ;Return with z set if error end