ON 20081006@3:26:21 PM at page: http://www.piclist.com/techref/microchip/math/div/index.htm# [mark_jeronimus-gmail-] I have agreed to maintain this page. ON 20081006@3:33:45 PM at page: http://www.piclist.com/techref/microchip/math/div/index.htm# [mark_jeronimus-gmail-] change |Replace: '' with: '' ON 20081007@7:56:18 AM at page: http://www.piclist.com/techref/microchip/math/div/16by8lz.htm#39728.3307523148 [mark_jeronimus-gmail-] Code:
The next function divides a 16-bit 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 left-aligned (eg, padded with zeroes on
the LSB side). This is easy if you divide by 8-bits.
- 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 (17-N)-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+(17-N)*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 16-BIT NUMBER BY AN N-BIT NUMBER
;;IN:
;; MODREG1:MODREG0 = 16-BIT DIVIDEND
;; TEMP1:TEMP0 = N-BIT DIVISOR, LEFT ALIGNED, WITH TEMP1.7 = 1
;;OUT:
;; DIVREG1:DIVREG0 = (17-N)-BIT WIDE QUOTIENT
;; MODREG1:MODREG0 = N-BIT REMAINDER
;;DESTROYED:
;; COUNT = 0
;; TEMO1:TEMP0 = ORIGINAL TEMO1:TEMP0 << (17-N)
;; THAT MEANS TEMO1:TEMP0 = 0 IF INPUT IS CORRECT
DIV16
MOVLW 17-N
MOVWF COUNT
CLRF DIVREG0
CLRF DIVREG1
DIV16_LOOP
MOVF TEMP0,W ;W=MOD-DIVISOR
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=MOD-DIVISOR
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 16-bit number by a
6-bit 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 11-bits wide in
DIVREG1:DIVREG0 and the remainder is of course 6-bits wide (same width as the
divisor) and still occupies MODREG1:MODREG0.
;;DIVIDE A 16-BIT NUMBER BY A 6-BIT WREG. RESULT IS 11-BIT 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=MOD-DIVISOR
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=MOD-DIVISOR
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
ON 20081009@9:27:07 AM at page:
http://www.piclist.com/microchip/math/div/div16or32by16to16.htm#39730.3405208333
James Newton[JMN-EFP-786] published post 39730.3405208333
Nikolai, you're a genius! Thanks for the division routine, it'll be used in an ignition mapping system for a motorcycle.
|Delete 'P-' before: '' but after: '