#define bf_carry 3, 0 #define bf_zero 3, 2 #define same 1 #define wreg 0 #define stc bsf bf_carry #define clc bcf bf_carry ;[ Div ] ; Call w/: Number in f_divhi:f_divlo, divisor in W. ; Returns: Quotient in f_divlo, remainder in f_divhi. W preserved. ; Carry set if error. Z if divide by zero, NZ if divide overflow. ; Notes: Works by left shifted subtraction. ; Size = 29, Speed(w/ call&ret) = 7 cycles if div by zero ; Speed = 94 minimum, 129 maximum cycles Div; addlw 0 ; w+=0 (to test for div by zero) stc ; set carry in case of error btfsc bf_zero ; if zero return ; return (error C,Z) call DivSkipHiShift iDivRepeat = 8 while iDivRepeat call DivCode iDivRepeat endw rlf f_divlo, same ; C << lo << C ; If the first subtract didn't underflow, and the carry was shifted ; into the quotient, then it will be shifted back off the end by this ; last RLF. This will automatically raise carry to indicate an error. ; The divide will be accurate to quotients of 9bits, but past that ; the quotient and remainder will be bogus and carry will be set. bcf bf_zero ; NZ (in case of overflow error) return ; we are done! DivCode rlf f_divlo, same ; C << lo << C rlf f_divhi, same ; C << hi << C btfss bf_carry ; if Carry goto DivSkipHiShift ; subwf f_divhi, same ; hi=w stc ; ignore carry return ; done ; endif DivSkipHiShift subwf f_divhi, same ; hi=w btfsc bf_carry ; if carry set return ; done addwf f_divhi, same ; hi+=w clc ; clear carry return ; done
Questions:
hi,James Newton of Massmind replies: At that point in the code, we know we are not dividing by zero; we already tested for that withbtfsc bf_zero ; if zero. Clearing bf_zero after we detect an overflow, just makes sure the routine does not send an ambiguous error message. At this point, we might have an overflow (see the previous lines) but we certainly do not have a divide by zero error.+
only one comment i suppose i donÂ´t understand
this instruction:
bcf bf_zero ; NZ (in case of overflow error)
Always clear FLAG Z > so always indicates an overflow error ?
Very Good logic..I had been searching for a this type of division algorithm for a long time Thanks a Ton :), Sid +
Comments:
Code:
+The next function divides a 16bit number in MODREG1:MODREG0 by any N<=16 bit number in TEMP1:TEMP0. The quotient will be stored in DIVREG1:DIVREG:0 and the modulo in MODREG1:MODREG0. (in this notation, MODREG1 is th HI byte, etc.) It is optimized for dividing numbers by a constant. Restraints:  The divisor in TEMP1:TEMP0 should be leftaligned (eg, padded with zeroes on the LSB side). This is easy if you divide by 8bits.  The high bit of the divisor (TEMP1.7) should be 1. If the high bit of the divisor is not 1 then the result may overflow. This will cause the (17N)bit quotient in DIVREG1:DIVREG0 to contain all ones and can be further detected by comparing MODREG1:MODREG0 by the used divisor (which was btw destroyed by this function). Bottomline, it is better to avoid this.  No detection for a divisor of zero (which would mean a divisor of 0 bits long which is nonsense) Worst case timing: 6+(17N)*23 (where N is the number of bits in the divisor) N=4: T=305 N=8: T=213 N=12: T=121 Here's the universal version: ;;DIVIDE A 16BIT NUMBER BY AN NBIT NUMBER ;;IN: ;; MODREG1:MODREG0 = 16BIT DIVIDEND ;; TEMP1:TEMP0 = NBIT DIVISOR, LEFT ALIGNED, WITH TEMP1.7 = 1 ;;OUT: ;; DIVREG1:DIVREG0 = (17N)BIT WIDE QUOTIENT ;; MODREG1:MODREG0 = NBIT REMAINDER ;;DESTROYED: ;; COUNT = 0 ;; TEMO1:TEMP0 = ORIGINAL TEMO1:TEMP0 << (17N) ;; THAT MEANS TEMO1:TEMP0 = 0 IF INPUT IS CORRECT DIV16 MOVLW 17N MOVWF COUNT CLRF DIVREG0 CLRF DIVREG1 DIV16_LOOP MOVF TEMP0,W ;W=MODDIVISOR SUBWF MODREG0,W MOVF TEMP1,W BTFSS STATUS,C ;PROCESS BORROW ADDLW 1 SUBWF MODREG1,W BTFSS STATUS,C ;IF W<0 GOTO DIV16_NOSUB MOVF TEMP0,W ;MOD=MODDIVISOR SUBWF MODREG0,F BTFSS STATUS,C DECF MODREG1,F MOVF TEMP1,W SUBWF MODREG1,F BSF STATUS,C DIV16_NOSUB RLF DIVREG0,F ;DIV << 1 + CARRY RLF DIVREG1,F BCF STATUS,C ;DIVISOR>>=1 RRF TEMP1,F RRF TEMP0,F DECFSZ COUNT,F GOTO DIV16_LOOP RETURN In the next example, it has been configured to divide a 16bit number by a 6bit number in WREG. It will put it in TEMP1 (and clear TEMP0) and shift it to the left by 2 bits to align it left. The result is 11bits wide in DIVREG1:DIVREG0 and the remainder is of course 6bits wide (same width as the divisor) and still occupies MODREG1:MODREG0. ;;DIVIDE A 16BIT NUMBER BY A 6BIT WREG. RESULT IS 11BIT WIDE DIV16_6 ;SHIFT LEFT BY 10 BITS MOVWF TEMP1 CLRF TEMP0 BCF STATUS,C RLF TEMP1,F RLF TEMP1,F MOVLW 11 MOVWF COUNT CLRF DIVREG0 CLRF DIVREG1 DIV16_6_LOOP MOVF TEMP0,W ;W=MODDIVISOR SUBWF MODREG0,W MOVF TEMP1,W BTFSS STATUS,C ;PROCESS BORROW ADDLW 1 SUBWF MODREG1,W BTFSS STATUS,C ;IF W<0 GOTO DIV16_6_NOSUB MOVF TEMP0,W ;MOD=MODDIVISOR SUBWF MODREG0,F BTFSS STATUS,C DECF MODREG1,F MOVF TEMP1,W SUBWF MODREG1,F BSF STATUS,C DIV16_6_NOSUB RLF DIVREG0,F ;DIV << 1 + CARRY RLF DIVREG1,F BCF STATUS,C ;DIVISOR>>=1 RRF TEMP1,F RRF TEMP0,F DECFSZ COUNT,F GOTO DIV16_6_LOOP RETURN
See also:
file: /Techref/microchip/math/div/16by8lz.htm, 8KB, , updated: 2010/2/24 13:30, local time: 2020/2/20 22:56,

©2020 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/microchip/math/div/16by8lz.htm"> PIC Microcontoller Math Method</A> 
Did you find what you needed? 
Welcome to massmind.org! 
Welcome to massmind.org! 
.