from by Nikolai
Golovchenko
FXD2416U: CLRF REMB0 CLRF REMB1 MOVLW 24 MOVWF LOOPCOUNT LOOPU2416 RLF ACCB0, W ;left shift of accb0's msb to reminder RLF REMB1, F RLF REMB0, F MOVF BARGB1, W ;REMB -= BARGB SUBWF REMB1, F MOVF BARGB0, W BTFSS _C INCFSZ BARGB0,W SUBWF REMB0, F BTFSC _C GOTO UOK46LL ;if no borrow MOVF BARGB1, W ;REMB += BARGB ADDWF REMB1, F MOVF BARGB0, W BTFSC _C INCFSZ BARGB0,W ADDWF REMB0, F BCF _C UOK46LL RLF AARGB2, F RLF AARGB1, F RLF AARGB0, F DECFSZ LOOPCOUNT, F GOTO LOOPU2416 RETURN
The routine above is actually 24 by 15 bits division. Below is a 24 by 16 bits division routine:;Inputs: ; Dividend - AARGB0:AARGB1:AARGB2 (0 - most significant!) ; Divisor - BARGB0:BARGB1 ;Temporary: ; Counter - LOOPCOUNT ; Remainder- REMB0:REMB1 ;Output: ; Quotient - AARGB0:AARGB1:AARGB2 ; ; Size: 28 ; Max timing: 4+24*(6+6+4+3+6)-1+3+2=608 cycles (with return) ; Min timing: 4+24*(6+6+5+6)-1+3+2=560 cycles (with return) ; FXD2416U: CLRF REMB0 CLRF REMB1 MOVLW 24 MOVWF LOOPCOUNT LOOPU2416 RLF AARGB2, F ;shift left divider to pass next bit to remainder RLF AARGB1, F ;and shift in next bit of result RLF AARGB0, F RLF REMB1, F ;shift carry into remainder RLF REMB0, F RLF LOOPCOUNT, F ;save carry in counter MOVF BARGB1, W ;substract divisor from remainder SUBWF REMB1, F MOVF BARGB0, W BTFSS _C INCFSZ BARGB0, W SUBWF REMB0, W ;keep that byte in W untill we make sure about borrow SKPNC ;if no borrow BSF LOOPCOUNT, 0 ;set bit 0 of counter (saved carry) BTFSC LOOPCOUNT, 0 ;if no borrow GOTO UOK46LL ;jump MOVF BARGB1, W ;restore remainder if borrow ADDWF REMB1, F MOVF REMB0, W ;read high byte of remainder to W ;to not change it by next instruction UOK46LL MOVWF REMB0 ;store high byte of remainder CLRC ;copy bit 0 to carry RRF LOOPCOUNT, F ;and restore counter DECFSZ LOOPCOUNT, f ;decrement counter GOTO LOOPU2416 ;and repeat loop if not zero RLF AARGB2, F ;shift in last bit of result RLF AARGB1, F RLF AARGB0, F RETURN
Nikolai Golovchenko shares this code:
Here is a slightly optimized version - 1 instruction shorter, 24 cycles faster! ;Inputs: ; Dividend - AARGB0:AARGB1:AARGB2 (0 - most significant!) ; Divisor - BARGB0:BARGB1 ;Temporary: ; Counter - LOOPCOUNT ; Remainder- REMB0:REMB1 ;Output: ; Quotient - AARGB0:AARGB1:AARGB2 ; ; Size: 27 ; Max timing: 4+24*(6+6+4+3+5)-1+3+2=584 cycles (with return) ; Min timing: 4+24*(6+6+5+5)-1+3+2=536 cycles (with return) ; ;25-Sep-2000 Original version ;20-Oct-2001 Made the loop one instruction shorter, comments ; review. FXD2416U: CLRF REMB0 CLRF REMB1 MOVLW 24 MOVWF LOOPCOUNT LOOPU2416 RLF AARGB2, F ;shift dividend left to move next bit to remainder RLF AARGB1, F ;and shift in next bit of result RLF AARGB0, F ; RLF REMB1, F ;shift carry (next dividend bit) into remainder RLF REMB0, F RLF LOOPCOUNT, F ;save carry in counter, since remainder ;can be 17 bit long in some cases (e.g. ;0x800000/0xFFFF) MOVF BARGB1, W ;substract divisor from 16-bit remainder SUBWF REMB1, F ; MOVF BARGB0, W ; BTFSS STATUS, C ; INCFSZ BARGB0, W ; SUBWF REMB0, F ; ;here we also need to take into account the 17th bit of remainder, which ;is in LOOPCOUNT.0. If we don't have a borrow after subtracting from lower ;16 bits of remainder, then there is no borrow regardless of 17th bit ;value. But, if we have the borrow, then that will depend on 17th bit ;value. If it is 1, then no final borrow will occur. If it is 0, borrow ;will occur. SKPNC ;if no borrow after 16 bit subtraction BSF LOOPCOUNT, 0 ;then no no borrow in result. Overwrite ;LOOPCOUNT.0 with 1 to indicate no ;borrow. ;if borrow did occur, LOOPCOUNT.0 will ;hold the eventual borrow value (0-borrow, ;1-no borrow) BTFSC LOOPCOUNT, 0 ;if no borrow after 17-bit subtraction GOTO UOK46LL ;skip remainder restoration. ADDWF REMB0, F ;restore higher byte of remainder. (w ;contains the value subtracted from it ;previously) MOVF BARGB1, W ;restore lower byte of remainder ADDWF REMB1, F ; UOK46LL CLRC ;copy bit LOOPCOUNT.0 to carry RRF LOOPCOUNT, F ;and restore counter DECFSZ LOOPCOUNT, f ;decrement counter GOTO LOOPU2416 ;and repeat loop if not zero. carry ;contains next quotient bit (if borrow, ;it is 0, if not, it is 1). RLF AARGB2, F ;shift in last bit of quotient RLF AARGB1, F RLF AARGB0, F RETURN
Nikolai Golovchenko shares this code:
Well, the routine can be made even simpler! This version is 5 instructions shorter and 48 cycles faster. Thanks to Zlatko Petkov for an idea of removing the extra shifts after the loop. Nikolai Golovchenko. 5-Dec-2004.FXD2416U: CLRF REMB0 CLRF REMB1 MOVLW .24 MOVWF LOOPCOUNT LOOPU2416 RLF AARGB2, W ;shift dividend left to move next bit to remainder RLF AARGB1, F ; RLF AARGB0, F ; RLF REMB1, F ;shift carry (next dividend bit) into remainder RLF REMB0, F RLF AARGB2, F ;finish shifting the dividend and save carry in AARGB2.0, ;since remainder can be 17 bit long in some cases ;(e.g. 0x800000/0xFFFF). This bit will also serve ;as the next result bit. MOVF BARGB1, W ;substract divisor from 16-bit remainder SUBWF REMB1, F ; MOVF BARGB0, W ; BTFSS STATUS, C ; INCFSZ BARGB0, W ; SUBWF REMB0, F ; ;here we also need to take into account the 17th bit of remainder, which ;is in AARGB2.0. If we don't have a borrow after subtracting from lower ;16 bits of remainder, then there is no borrow regardless of 17th bit ;value. But, if we have the borrow, then that will depend on 17th bit ;value. If it is 1, then no final borrow will occur. If it is 0, borrow ;will occur. These values match the borrow flag polarity. SKPNC ;if no borrow after 16 bit subtraction BSF AARGB2, 0 ;then there is no borrow in result. Overwrite ;AARGB2.0 with 1 to indicate no ;borrow. ;if borrow did occur, AARGB2.0 already ;holds the final borrow value (0-borrow, ;1-no borrow) BTFSC AARGB2, 0 ;if no borrow after 17-bit subtraction GOTO UOK46LL ;skip remainder restoration. ADDWF REMB0, F ;restore higher byte of remainder. (w ;contains the value subtracted from it ;previously) MOVF BARGB1, W ;restore lower byte of remainder ADDWF REMB1, F ; UOK46LL DECFSZ LOOPCOUNT, f ;decrement counter GOTO LOOPU2416 ;and repeat the loop if not zero. RETURN
Fathy Lotfy Samaha of Freelancer Says:
Thanks so much, this is a much simple routine,
but it did not work with me until I changed
the first line to :movlw .24 ,I am using MPASM and MPLAB, it recogonize
the decimal numbers precedded with a dot .
Questions:
Dear Piclist People:
Thanks to all for sharing your knowledge. I was wondering if some of you have had a problem like the one I describe below. Any help will be welcomed!
Iâ¬m dealing with integer unsigned binary division using a PIC. I implemented 24/24 bit division and everything went ok. But when performing 24/16 bit division, something goes wrong.
The dividend (numerator) is a 24 bit constant, but the divisor (denominator) is a variable number. When this denominator takes a low value (but still 16 bit value), say 10700 i.e., the error in the result is quite a lot, and it becomes bigger as the difference between both operands does too. Is there a solution to this?
Thanks again for your help. Greetings!
Comments:
reference the LAST code segment.
Using a PIC18F4520, please note the code changes.
THANKS YOU all for saving me a lot of work.LOOPU2416 bcf CARRY ; addition of code line rlcf BSR1_Larger24Lo,W ; shift dividend left to move next bit to remainder rlcf BSR1_Larger24Mi,F rlcf BSR1_Larger24Hi,F rlcf BSR1_Remain16Lo,F ; shift carry (next dividend bit) into remainder rlcf BSR1_Remain16Hi,F rlcf BSR1_Larger24Lo,F ; finish shifting the dividend and save carry in ; BSR1_Larger24Lo.0, ; since remainder can be 17 bit long in some cases ; (e.g. 0x800000/0xFFFF). This bit will also serve ; as the next result bit.I apologise for spiling the convention in MY labels, but you can work backwards from the origonal code.
Rick
Sorry, I forgot...
Also, for PIC184520...
replace SKPNC with btfsc CARRY; SKPNC ;if no borrow after 16 bit subtraction btfsc CARRY ; if no borrow after 16 bit subtraction