; DIV16.ASM - 16 x 16 Unsigned Division on PIC ; Written: Summer 2002 ; Copyright (C) 2002, 2003 by Charles McManis, All rights Reserved ; $Id: div16.asm,v 1.0 2003-01-02 16:45:10-08 chuck_mcmanis Exp chuck_mcmanis $ ; ; 16-bit x 16-bit unsigned divide. ; ; Divide two 16 bit numbers returning a 16 bit result ; and a 16 bit remainder. ; ; Requires 16bits.inc (16 bit number manipulation macros) ; ; DIVIDEND (top part) - 16 bit variable ; DIVISOR (bottom part) - 16 bit variable ; ; The 16 bit numbers are stored in 'low-high' format (little endian) so that ; referring to a variable by name gives you the low byte, the high byte is ; stored at offset +1 from NAME. This is consistent with the 16 bit number ; macros. ; ; Division takes a variable number of cycles, depending on the values passed ; in DIVIDEND and DIVISOR. Worst case occurs when DIVISOR is '1' (divide by 1) ; Which requires 16 iterations of the loop. ; ; After this function is called, RESULT has the division result and DIVIDEND ; will have the remainder. DIVISOR is not changed. ; ; Don't divide by zero, its bad. The routine checks for it and returns 0xff ; in W if you try it. You can't eliminate this check because if you do then ; the loop that finds the first '1' bit in the divisor will loop forever. ; ; Total RAM requirement 7 bytes. ; CBLOCK ; ; Variables used by this routine. ; RESULT:2 ; 16 bit result of the division DIVISOR:2 ; Divisor (bottom part) DIVIDEND:2 ; Dividend (top part) DIV_COUNT ; Temporary to count needed loops ENDC ; ; This is the entry point for the divide, at this point ; the Dividend and Divisor must be already initialized. If you ; are going to call it from anywhere then you need to be sure that ; the data bytes land in the common File Register area ($70 - $7F) ; DIV16X16: CLR16 RESULT ; Clear the result MOVF DIVISOR,W ; Check for zero IORWF DIVISOR+1,W ; BTFSC STATUS,Z ; Check for zero RETLW H'FF' ; return 0xFF if illegal MOVLW 1 ; Start count at 1 MOVWF DIV_COUNT ; Clear Count D1: BTFSC DIVISOR+1,7 ; High bit set ? GOTO D2 ; Yes then continue INCF DIV_COUNT,F ; Increment count LSL16 DIVISOR ; Shift it left GOTO D1 D2: LSL16 RESULT ; Shift result left SUB16 DIVIDEND, DIVISOR ; Reduce Divisor BTFSC STATUS, C ; Did it reduce? GOTO D3 ; No, so it was less than ADD16 DIVIDEND, DIVISOR ; Reverse subtraction GOTO D4 ; Continue the process D3: BSF RESULT,0 ; Yes it did, this gets a 1 bit D4: DECF DIV_COUNT,F ; Decrement N_COUNT BTFSC STATUS,Z ; If its not zero then continue RETLW 0 ; Else return, as we are done. LSR16 DIVISOR ; Adjust divisor GOTO D2 ; Next bit.