• AVR Freaks

Helpful ReplyHot!Unsigned 32 by 32 divide routine in assembler

Page: < 12345.. > >> Showing page 2 of 7
Author
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/02 19:27:36 (permalink)
0
Spinlectrix
Ok, I haven't fully tested this routine yet, and it does somehow seem a bit too simple (am I missing something?), but it does appear to function properly at first inspection.
It uses one fewer register, and is approximately ten times faster than using looped trial subtraction:

; Unsigned Integer Division of 32-bit by 32-bit
;
; Calling Parameters
;   w1:w0 = Dividend
;   w3:w2 = Divisor
;
; Return Values
;   w1:w0 = Quotient
;
; Used Registers
;  w5,w4
;
; Tcy (max) = 4 + 19 + 2 + 19 + 1 = 45
;
udiv3232:
   mov.d w0,w4
   ff1l w3,w1
   bra C,0f
 
; Here the hi word of the divisor is non-zero, so the result of this long division would
 
; fit into a ushort (hi word of quotient must be zero) -- calculate shifts required:
 
   subr w1,#17,w1
 
   subr w1,#16,w0
 
;Shift divisor to move the most-significant-set bit of its value as a long to the MSb of its lo word
 
   lsr w2,w1,w2
   sl w3,w0,w3
   ior w2,w3,w2
;Apply corresponding shifts to dividend (as a result preserving the ratio of numerator to denominator)
   lsr w4,w1,w4
   sl w5,w0,w3
   lsr w5,w1,w5
   ior w4,w3,w4
;Perform division
   repeat #17
   div.ud w4,w2
   clr w1
   bra 1f
; Handle case where result _may_ not fit into a word -- Here the hi word of the divisor is zero:
; First divide hi word of the dividend by the divisor
0: repeat #17
   div.uw w5,w2
   mov w0,w3 ; Save result (hi word of quotient)
   mov w1,w5 ; Replace the hi word of the dividend with the remainder.
;Then follow up with a long divide:
   repeat #17
   div.ud w4,w2 ; Calculate lo word of quotient
   mov w3,w1    ; Restore hi word of quotient
1:  return




Very impressive!!!  It takes only 36 (min) or 49 (max) cycles. I'd replace the BRA 1f with a RETURN. ;)  When I have some free time, I'm going to run an exhaustive test on it.
; Tcy (max) = 5 + 19 + 2 + 19 + 4 = 49

#21
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/02 19:44:20 (permalink)
4 (1)
peterg1000
... problem now is to get an ageing brain to understand the subtleties!!

 
That division algorithm is the same one we learned in elementary school. Instead of calculating one decimal digit at a time, it computes one binary bit at a time. By the way, at the end of that routine W5:W4 contains the remainder.
;
; Return Values
;   w1:w0 = Quotient
;   w5:w4 = Remainder
;

post edited by 1and0 - 2020/09/02 19:45:34
#22
Spinlectrix
Junior Member
  • Total Posts : 72
  • Reward points : 0
  • Joined: 2016/03/20 14:48:37
  • Location: 0
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/02 20:20:12 (permalink)
0
1and0Very impressive!!!  It takes only 36 (min) or 49 (max) cycles. I'd replace the BRA 1f with a RETURN. ;)  When I have some free time, I'm going to run an exhaustive test on it.
; Tcy (max) = 5 + 19 + 2 + 19 + 4 = 49




Yeah, the reason for the BRA is that I was looking ahead to structuring the code as an inline routine (see post #20 in this thread), not only saving the call/return overhead (which, when you think about it is over 10% of the total cycles for so short a routine!), but would also allow the compiler to select any set of input registers that proved optimal, while still providing the answer in w1:w0.  This can also save the 2 cycles from the initial register copy:  mov.d  w0,w4.  The entire inline routine is only 20 instructions long, so invoking another copy at each longword divide does just not eat up that much program space.
post edited by Spinlectrix - 2020/09/02 21:58:25
#23
GlennP
Super Member
  • Total Posts : 833
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 00:31:46 (permalink)
0
I really hope I've got some transcription error, but when I divide 0x1FFFE by 0x1FFFF, I get 1.  I believe I should get 0.  I suspected a loss of precision in the shifting, so that's why I tried those values.

I scraped the code but could have made an error when I added my own styling (mostly tabs and comments).

Before the divide sequence, W45 = 0x0000FFFF and W2 = 0xFFFF.  W2 just can't hold all the bits.

Entry, Before Divide, and Exit Registers can be seen in the images.  I zipped up the source in case I did something horrible.  I'd suggest interested parties just try the test case shown above - don't bother with my transcription.

Hope it's me.

GP

Attached Image(s)

#24
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 05:21:37 (permalink)
3.67 (3)
glennp17321
I really hope I've got some transcription error, but when I divide 0x1FFFE by 0x1FFFF, I get 1.  I believe I should get 0.  I suspected a loss of precision in the shifting, so that's why I tried those values.

 
You're correct. One fix is to check if the dividend is less than the divisor and return zero -- replace the start with this:
udiv3232u:
        mov.d   w0,w4    ; copy dividend
        ff1l    w3,w1    ; w1 = first one left of divisor
        bra     c,0f     ; if (divisor hi == 0) branch

        sub     w4,w2,w0 ; if (dividend < divisor)
        subb    w5,w3,w0
        clr     w0       ; quotient = 0
        bra     nc,2f

where label 2 is
2:      clr     w1
        return

post edited by 1and0 - 2020/09/03 05:31:59
#25
GlennP
Super Member
  • Total Posts : 833
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 08:32:36 (permalink)
0
1and0 ...
One fix is to check if the dividend is less than the divisor and return zero -- replace the start with this: ...



Well, then try 3FFFD / 1FFFF.  The correct answer is 1 but the code (even modified as you suggest) gives 2.  You just can't fit 32 bits in a 16 bit word.
 
GP
#26
Spinlectrix
Junior Member
  • Total Posts : 72
  • Reward points : 0
  • Joined: 2016/03/20 14:48:37
  • Location: 0
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 08:38:00 (permalink)
4 (1)
Glenn & Harry are absolutely correct; this inaccuracy is not due to a transcription error, but inherent in the algorithm itself:  When any bits are set in the hi word of the divisor, the maximum accuracy of the result is 1 part in 2^16, leading to rounding errors as in the specific case Glenn pointed out.
 
Harry's fix is not enough, however, to resurrect bit-accuracy; The quotient can be 1 too high from the precise result for 65535 values, and not just 1 instead of 0, but 2 instead of 1, 3 instead of 2, etc.  I currently see two approaches to this issue:
 
1.   Screw it:  This routine is designed to be used in a micro controller for providing very fast, real-time feedback, and we are using this algorithm because it is an order of magnitude faster than bit-accurate alternatives.  One part in 65k better be close-enough to close your control loop.  Therefore you'd recommend use of this routine only when the designer has an appreciation of its limitations, which should be (but are not yet) well documented in its header.
 
2.  If bit-accuracy is critical for an application, we can append a short and quick fix to find and correct the off-by-one errors to that specific branch of the code.  (Fortunately, the error exists in the faster leg of the algorithm; we may not even have to increase the Tcy(max)).  On that branch, follow up with a multiply w0 to check the result, followed by a dec w0,w0 if the result is too large. It will require using more registers or memory.
 
Since all my work firmly resides in the Option-1 domain, I'll leave it to others to pursue Option-2.
 
post edited by Spinlectrix - 2020/09/03 08:53:57
#27
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 08:40:03 (permalink)
0
glennp17321
1and0 ...
One fix is to check if the dividend is less than the divisor and return zero -- replace the start with this: ...



Well, then try 3FFFD / 1FFFF.  The correct answer is 1 but the code (even modified as you suggest) gives 2.  You just can't fit 32 bits in a 16 bit word.

You're correct again. That's why I want to run an exhaustive test on this routine. I don't have the time now. Maybe its author has a fix. ;)
 
#28
GlennP
Super Member
  • Total Posts : 833
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 08:54:08 (permalink)
0
1and0  ...
You're correct again. That's why I want to run an exhaustive test on this routine. I don't have the time now. Maybe its author has a fix. ;)



You many never have time.  A truly exhaustive check would involve 2^64 tests.  That somewhat more than 18*10^18 tests.
 
The author says it's an error of 1 and good enough for the OP's purpose.  I'm inclined to agree that as long as the user knows it's not divide but "approximate divide".
 
But, as currently coded, it's not integer divide.
 
On the bright side, I think there is a relatively simple fix.
 
GP
#29
GlennP
Super Member
  • Total Posts : 833
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 09:52:05 (permalink)
0
peterg1000 ...
All this is ito calculate a stepper motor speed profile using the "standard" equation :-
  Cn = Cn-1 - (2Cn-1)/(4n -1). 
This quickly runs out of resolution for large values of n, so the extra quotient bits will give me a "partial step accumulator" to stretch the acceleration profile.

Peter:
 
Assuming Cn-1 means the (n-1)th C, then is this true:
 
Cn = Cn-1  * (1 - 2/(4n-1)) ??
 
If so, would this approach be accurate enough:
 
for n = 0 .. 511, use a scaling table starting with 0.333333, 0.714286, 0.818182, ... and ending with 0.999021.
At n = 512 and beyond, use 0.99904 (or so).
 
Then multiply Cn-1 by the entry in the scaling table (or constant beyond 511).  That's a 32 x 32 multiply and just use the HO 32 bits.  Four multiplies and a few adds would likely be faster than one divide.
 
Since 1/(4n-1) gets pretty linear when n > 512, you could (at the cost of another multiply and subtract) use a linear approximation for entries beyond 512 if the constant (say 0.99904) wasn't accurate enough.
 
GP
 
#30
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 09:57:44 (permalink)
0
glennp17321
You many never have time.  A truly exhaustive check would involve 2^64 tests.  That somewhat more than 18*10^18 tests.

;)
 

The author says it's an error of 1 and good enough for the OP's purpose.  I'm inclined to agree that as long as the user knows it's not divide but "approximate divide".
 
But, as currently coded, it's not integer divide.

Agree.
 

On the bright side, I think there is a relatively simple fix.

 
I've also thought of the Option-2 solution in Post #27, quoted below, and wondering if there's a simpler fix. ;)
 
Spinlectrix
2.  If bit-accuracy is critical for an application, we can append a short and quick fix to find and correct the off-by-one errors to that specific branch of the code.  (Fortunately, the error exists in the faster leg of the algorithm; we may not even have to increase the Tcy(max)).  On that branch, follow up with a multiply w0 to check the result, followed by a dec w0,w0 if the result is too large. It will require using more registers or memory.

post edited by 1and0 - 2020/09/03 10:11:18
#31
Spinlectrix
Junior Member
  • Total Posts : 72
  • Reward points : 0
  • Joined: 2016/03/20 14:48:37
  • Location: 0
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 10:17:49 (permalink)
4 (1)
glennp17321
Well, then try 3FFFD / 1FFFF.  The correct answer is 1 but the code (even modified as you suggest) gives 2.

 
Well, more precisely the correct answer is 1.99999237...   or 0x1.ffff in binary fixed-point...
Again, this is about a rounding error.
 
glennp17321
You just can't fit 32 bits in a 16 bit word.

 
Yet, for this branch of the code we know the divisor is greater than 65k (it has at least one bit set in its high word).  Therefore we also know the result will have to fit in 16 bits; we don't need 32 -- the high word of the quotient is guaranteed to be 0.
 
 
{Dammit!  The perfect is the enemy of the good!  Now I just can't seem to let go of this!}
 
 
post edited by Spinlectrix - 2020/09/03 12:58:07
#32
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/03 21:13:50 (permalink)
5 (1)
Put the slower leg of the algorithm in the front shaves one cycle off the maximum. The following routine corrects the off-by-one error (at the expense of 4 more registers and 11 more cycles) and takes 48 cycles isochronous.
;
; Unsigned Integer Division of 32-bit by 32-bit
;
; Calling Parameters
;   w1:w0 = Dividend
;   w3:w2 = Divisor
;
; Return Values
;   w1:w0 = Quotient
;
; Used Registers
;   w9,w8, w7,w6, w5,w4
;
; Tcy = 48 isochronous
;
; Source: https://www.microchip.com/forums/FindPost/1151719
;
_udiv3232:
        mov.d   w0,w4       ; copy dividend
        ff1l    w3,w1       ; w1 = first one left of divisor hi
        bra     nc,0f       ; if (divisor > 0xFFFF) branch
;-------
; Case of Divisor <= 0xFFFF
;
; Here the high word of the divisor is zero, so the quotient may overflow a
; 16-bit word.
;
; w1:w0 = w5:w4 / w2
;       = [(w5 / w2) << 16] + [(w5 % w2):w4 / w2]

; Divide high word of dividend by the divisor

        repeat  #17         ; divide hi word of dividend by the divisor
        div.uw  w5,w2       ; w0 = w5 / w2, w1 = w5 % w2

        mov     w0,w3       ; save hi word of quotient
        mov     w1,w5       ; replace hi word of dividend with the remainder

; Follow with a long division

        repeat  #17         ; calculate lo word of quotient
        div.ud  w4,w2       ; w0 = w5:w4 / w2

        mov     w3,w1       ; restore hi word of quotient
        return              ; return to caller
;-------
; Case of Divisor > 0xFFFF
;
; Here the high word of the divisor is non-zero, so the quotient will fit in
; a 16-bit word; i.e. the high word of the quotient is guaranteed to be zero.
;
; w1 = 0
; w0 = w5:w4 / w3:w2
;    = [(w5:w4) >> n] / [(w3:w2) >> n]

; Copy dividend and divisor for correction of the quotient later

0:      mov.d   w4,w6       ; copy dividend
        mov.d   w2,w8       ; copy divisor

; Calculate shifts required

        subr    w1,#17,w1   ; shift for lo word >> (w1 = 17 - w1)
        subr    w1,#16,w0   ; shift for hi word << (w0 = 16 - w1)

; Normalize the divisor so the MSb of its lo word is 1

        lsr     w2,w1,w2    ;
        sl      w3,w0,w3    ;
        ior     w2,w3,w2    ; w2 = (w3:w2) >> w1

; Apply same shift to dividend to preserve the ratio of dividend to divisor

        lsr     w4,w1,w4    ;
        sl      w5,w0,w3    ;
        lsr     w5,w1,w5    ;
        ior     w4,w3,w4    ; w5:w4 >>= w1

; Perform division

        repeat  #17         ; calculate the quotient
        div.ud  w4,w2       ; w0 = w5:w4 / w2

; Correct the quotient

        mul.uu  w8,w0,w2    ;    w3:w2 = w8 * w0
        mul.uu  w9,w0,w4    ; w5:w4    = w9 * w0
        add     w3,w4,w3    ;    w3:w2 = divisor * quotient

        sub     w6,w2,w4    ; if (dividend < (divisor * quotient))
        subb    w7,w3,w4    ;
        bra     c,1f        ;
        dec     w0,w0       ; correct lo word of quotient

1:      clr     w1          ; zero hi word of quotient
        return              ; return to caller

 
#33
GlennP
Super Member
  • Total Posts : 833
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/04 01:00:02 (permalink)
0
I have one minor suggestion.
 
Replace:
         sub w6,w2,w4 ; if (dividend < (divisor * quotient))
         subb w7,w3,w4 ;
         bra c,1f ;
         dec w0,w0 ; correct lo word of quotient
 
1:       clr w1 ; zero hi word of quotient

 
with:
 
         sub w6,w2,w4 ; if (dividend < (divisor * quotient))
         subb w7,w3,w4 ;
         subb w0,#0,w0 ; correct lo word of quotient if borrow == 1.
 
         clr w1 ; zero hi word of quotient

 
This saves an instruction, some cycles (especially for the 'E' series) and eliminates a label (I hate labels).
 
GP
#34
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/04 04:06:18 (permalink)
0
glennp17321
I have one minor suggestion.

 +1
 
There is no need to save the dividend a second time (use different registers for calculation), and this will shave two registers, one instruction and two more cycles. :)  Works in progress...
 
post edited by 1and0 - 2020/09/04 09:11:20
#35
Spinlectrix
Junior Member
  • Total Posts : 72
  • Reward points : 0
  • Joined: 2016/03/20 14:48:37
  • Location: 0
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/04 08:23:01 (permalink)
0
If we are allowed to kibitz with minor suggestions, firstly _very_ much concur with Harry's avoiding touching 2 additional registers;  Standard function calling conventions would dictate that any register beyond w7 that is modified would have to be preserved by the routine, meaning a double stack store and restore — they are just not necessary to touch, so trim down how many registers are used!
 
One tweak that will help with that is using a mulw.uu instruction, instead of a mul.uu instruction when calculating the hi word of the divisor*quotient product -- you only need one word of result, so don't unnecessarily pollute two words (remember, though, that the destination reg of a mulw.uu must still be an even register!).  You can also use w1 as a scratch register at any point in this section — you're just going to zero it out before you return!
 
post edited by Spinlectrix - 2020/09/04 09:33:55
#36
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/04 09:14:53 (permalink)
0
Spinlectrix
If we are allowed to kibitz with minor suggestions, firstly _very_ much concur with Harry's avoiding touching 2 additional registers;  Standard function calling conventions would dictate that any register beyond w7 that is modified would have to be preserved by the routine, meaning a double stack store and restore — they are just not necessary to touch, so trim down how many registers are used!

 
I'm able to remove the usage of W9 and W8. :)
 

One tweak that will help with that is using a mulw.uu instruction, instead of a mul.uu instruction when calculating the divisor*quotient product -- you only need one word of result, so don't unnecessarily pollute two words (remember, though, that the destination reg of a mulw.uu must still be an even register!).  You can also use w1 as a scratch register at any point in this section — you're just going to zero it out before you return!

 
Good idea, but OP uses a PIC24F which does not support the MULW.UU instruction.  I also changed to use W1 but it really does not matter at this latter stage, as there are plenty of Wx registers to go around. ;)
 
#37
Spinlectrix
Junior Member
  • Total Posts : 72
  • Reward points : 0
  • Joined: 2016/03/20 14:48:37
  • Location: 0
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/04 09:29:36 (permalink)
0
1and0
I'm able to remove the usage of W9 and W8. :)

 I knew you could!
 

 a PIC24F which does not support the MULW.UU instruction.

Wow!  I didn't realize, but of course you are correct.  I thought these got added a long time ago (I've been using dsPIC33E's for too long, I guess!)
 
Now, onto testing?
post edited by Spinlectrix - 2020/09/04 09:49:21
#38
1and0
Access is Denied
  • Total Posts : 11506
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/04 09:52:56 (permalink)
5 (1)
Here's what I have so far -- trimmed two registers, one instruction, and three cycles:
;
; Unsigned Integer Division of 32-bit by 32-bit
;
; Calling Parameters
;   w1:w0 = Dividend
;   w3:w2 = Divisor
;
; Return Values
;   w1:w0 = Quotient
;
; Used Registers
;   w7,w6, w5,w4
;
; Tcy = 48 or 45 , for PIC24F
;
; Ref: https://www.microchip.com/forums/FindPost/1151719
;
_udiv3232:
        mov.d   w0,w4    ; copy dividend
        ff1l    w3,w1    ; w1 = first one left of divisor hi word
        bra     nc,0f    ; if (divisor > 0xFFFF) branch
;-------
; Case of Divisor <= 0xFFFF
;
; Here the high word of the divisor is zero, so the quotient may overflow a
; 16-bit word.
;
; w1:w0 = w5:w4 / w2
;       = [(w5 / w2) << 16] + [(w5 % w2):w4 / w2]

; Divide high word of dividend by the divisor

        repeat  #17      ; divide hi word of dividend by the divisor
        div.uw  w5,w2    ; w0 = w5 / w2, w1 = w5 % w2

        mov     w0,w3    ; save hi word of quotient
        mov     w1,w5    ; replace hi word of dividend with the remainder

; Follow with a long division

        repeat  #17      ; calculate lo word of quotient
        div.ud  w4,w2    ; w0 = w5:w4 / w2

        mov     w3,w1    ; restore hi word of quotient
        return           ; return to caller
;-------
; Case of Divisor > 0xFFFF
;
; Here the high word of the divisor is non-zero, so the quotient will fit in
; a 16-bit word; i.e. the high word of the quotient is guaranteed to be zero.
;
; w1 = 0
; w0 = w5:w4 / w3:w2
;    = [(w5:w4 >> n] / [(w3:w2) >> n]

; Copy divisor for correction of the quotient later

0:      mov.d   w2,w6     ; copy divisor

; Calculate shifts required

        subr    w1,#17,w1 ; right shift >> (w1 = 17 - w1)
        subr    w1,#16,w0 ; left  shift << (w0 = 16 - w1)

; Normalize the divisor so the MSb of its lo word is 1

        sl      w3,w0,w3  ; divisor >>= w1
        lsr     w2,w1,w2  ;
        ior     w3,w2,w2  ; w2 = (w3:w2) >> w1

; Apply same shift to dividend to preserve the ratio of dividend to divisor

        sl      w5,w0,w3  ; dividend >>= w1
        lsr     w4,w1,w0  ;
        lsr     w5,w1,w1  ;
        ior     w3,w0,w0  ; w1:w0 = (w5:w4) >> w1

; Perform division

        repeat  #17       ; calculate the quotient
        div.ud  w0,w2     ; w0 = w1:w0 / w2

; Correct quotient for rounding error due to lower bits discarded by the shifts

        mul.uu  w6,w0,w2  ; w3:w2 = w6 * w0
        mul.uu  w7,w0,w6  ; w7:w6 = w7 * w0
        add     w3,w6,w3  ; w3:w2 = divisor * quotient

        sub     w4,w2,w1  ; if (dividend < (divisor * quotient))
        subb    w5,w3,w1  ;
        subb    w0,#0,w0  ; correct quotient if borrow = 1

        clr     w1        ; zero hi word of quotient
        return            ; return to caller

 
Now, I am wondering if the remainder can be used somehow to correct the quotient.?
 
WTF Microchip. Every time I pasted code onto the editor, this stupid forum software messes up all the format by stripping all the leading spaces and replacing strings of space characters with a single space character. I am tired of manually re-typing all the spaces to make my code looks properly formatted. :(  It used to work with Edge, and not with Chrome; now it does not work with Edge anymore. :(  Someone here knows of a workaround?
#39
GlennP
Super Member
  • Total Posts : 833
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Unsigned 32 by 32 divide routine in assembler 2020/09/04 10:11:06 (permalink)
0
1and0 ...
Now, I am wondering if the remainder can be used somehow to correct the quotient.?
...



I don't think so because it was computed from a (possibly) too small divisor.  If you don't get to this by later today, I'll try it be certain by late this PM (MDT).
 
GP
#40
Page: < 12345.. > >> Showing page 2 of 7
Jump to:
© 2020 APG vNext Commercial Version 4.5