From: Tom Barrett <[email protected]>
Date: Tue, 26 Jul 1994 10:06:11 -0400

This is an update to info-mac/sci/fft-in-asm-src.txt

This file contains three routines:
* void tb_68k_four1_extended(long double *data, long nn, long isign);
* void tb_68k_four1_single(float *data, long nn, long isign);
* void tb_68k_fourn_single(float *data, long *nn, long ndim, long isign)

------------------------------ CUT HERE ------------------------------

/* This code is a hand-assembled version of the fft routine from Numerical
Recipes.  See the book for information about how it works.  All variable
names in comments refer to those in the book.

To use this routine:
* You must have a math coprocessor.
* Use Think C (users of other compilers may be able to adapt it).

This file contains three routines:
* void tb_68k_four1_extended(long double *data, long nn, long isign);
* void tb_68k_four1_single(float *data, long nn, long isign);
* void tb_68k_fourn_single(float *data, long *nn, long ndim, long isign)

The data to be processed is stored in an array of nn complex numbers, so
that data[] is an array of 2*nn extendeds or floats.

Notes:

* Set "Native floating-point format" under "Compiler Settings" in the
       Options... dialog box for the extended routine.  This uses the
       12-byte format which the math coprocessor uses internally.

* This routine is DESTRUCTIVE.  The output data is placed in the space
       where the input data was.  If you still want the input, make a copy
       and pass the copy to the routine.

* In the book Numerical recipes in C, from which this routine is taken,
       the first element of the array is accessed as data[1].  This is due
       the the book's Fortran heritage.  In the the first element is data[0].
       One way to compensate is to subtract one from the pointer before calling
       the FFT routine.  Another way would be to use data[i-1] and data[i]
       instead of data[i] and data[i+1] (they always occur in pairs).  This
       routine expects 'data' to be a pointer to the first element of the array.
       If you are replacing the C version, and compensated for this in the
       routine that called four1 (like the book suggests), then this is an issue.

* 'nn' must be a power of 2 (like 8, 16, 32...).  Useable range is between
       8 and 128M (2^27 complex numbers) for four1.  Fourn has been tested up
       to 1024^2.

* 'isign' must be 1 or -1, where -1 corresponds to an inverse fft.


Test results (Quadra 950) for 1024-point IFFT:

four1           extended                single

C                       56 msec                 27
asm                     29                              20
DSP                     ---                             1.9 *

* this number from August 92 Byte magazine

fourn           32^2            128^2           512^2           1024^2

C                       25 msec         557                     12.8 sec        59.4
asm                     19                      425                     10.14           47.1

---> about 30% faster !

Thomas Barrett
Physics Dept, Ohio State University
[email protected]
1994

Thanks to:  Dan Flatin & Pascal Laubin.
*/

#define PI      3.1415926535897932384626433

/* ----------------------- tb_four1.c -----------------------------

optimized version of Numerical Recipes' fft routine

Thomas Barrett, 1993

written for Think C
this routine assumes that data contains 12-byte 6888x-native long doubles
also, you must have a math coprocessor to run this routine

-------------------------------------------------------------------
register usage:

d0      I                               a0      data[I]                 fp0     WPR
d1      J                               a1      data[J]                 fp1     WPI
d2      M                               a2      data[0]                 fp2     WR
d3      loop, MMAX                                                      fp3     WI
d4      ISTEP                                                           fp4     TEMPR   \
d5      NN,N                                                            fp5     TEMPI    \      internal
d6      internal                                                        fp6                      /      calculations
                                                                               fp7                     /
---------------------------------------------------------------- */

void tb_68k_four1_extended(long double *data, long nn, long isign)
{
       long double twopi = 2.0 * PI * isign;

       asm 68020, 68881 {
               movem.l a2/d3-d6,-(sp)
               fmovem.x        fp4-fp7,-(sp)

               move.l  nn,d5
               clr.l   d3
               move.l  d5,d3           ; d3 = loop counter
               move.l  #-1,d0          ; i(d0) = -1
               movea.l data,a0
               suba.l  #12,a0          ; pointer to array indexed by 0
               movea.l a0,a2           ; a2 = *(data[0])
               suba.l  #12,a0

       ; ------------ re-order values ---------------------------------

               move.l  #1,d1           ; j(d1) = 1
@bits   adda.l  #24,a0          ; a0 = *(data[i])
               addq.l  #2,d0           ; i += 2
               cmp.l   d1,d0           ; cmp j,i
               bge             @nosw           ; branch if i(d0) >= j(d1)
@swap   movea.l a2,a1
               move.l  d1,d6
       ;       mulu.l  #12,d6
               lsl.l   #2,d6           ; these four instructions are equivalent to
               adda.l  d6,a1           ; the mulu.l #12 and save a dozen cycles
               lsl.l   #1,d6
               adda.l  d6,a1           ; a1 = *(data[j])

               fmove.x (a0),fp0        ; swap
               fmove.x (a1),fp1
               fmove.x fp1,(a0)
               fmove.x fp0,(a1)
               fmove.x 12(a0),fp0
               fmove.x 12(a1),fp1
               fmove.x fp1,12(a0)
               fmove.x fp0,12(a1)

@nosw   move.l  d5,d2           ; m(d2) = nn(d5) = #points
@jloop  cmp.l   #2,d2
               blt             @jrdy           ; branch if m(d2) < 2
               cmp.l   d2,d1
               ble             @jrdy           ; branch if j(d1) <= m(d2)
@fixj   sub.l   d2,d1           ; j -= m
               lsr.l   #1,d2           ; m /= 2
               bra             @jloop
@jrdy   add.l   d2,d1           ; j += m
               subq.l  #1,d3
               bne             @bits

       ; --------------- order is now ready -------------------------

               lsl.l   #1,d5           ; n(d5) = 2*nn(was d5) = #long doubles
               move.l  #2,d3           ; mmax(d3) = 2

       ; -------------------- outer loop -----------------------------

@loop   cmp.l   d3,d5
               ble             @done           ; branch if n(d5) <= mmax(d3)
               move.l  d3,d4
               lsl.l   #1,d4           ; istep(d4) = 2*mmax(d3)
               fmove.x twopi,fp1
               fmove.l d3,fp0
               fdiv.x  fp0,fp1         ; theta(fp1) = 2 pi / mmax(d3)
               fmove.x fp1,fp0
               fmove.w #2,fp2
               fdiv.x  fp2,fp0         ; fp0 = 1/2 theta
               fsin.x  fp0
               fmul.x  fp0,fp0
               fmul.x  fp2,fp0
               fneg.x  fp0                     ; wpr(fp0) = -2 sin^2(1/2 theta)
               fsin.x  fp1                     ; wpi(fp1) = sin(theta)
               fmove.w #1,fp2          ; wr(fp2) = 1
               fmove.w #0,fp3          ; wi(fp3) = 0

       ; ------------------ inner loops -------------------------

               move.l  #1,d2           ; m(d2) = 1
@mloop  move.l  d2,d0           ; i(d0) = m(d2)

               move.l  d0,d6           ; i(d0)
               movea.l a2,a0
               lsl.l   #2,d6
               adda.l  d6,a0
               lsl.l   #1,d6
               adda.l  d6,a0           ; a0 = pointer to 1st i
               movea.l a0,a1
               move.l  d3,d6           ; mmax(d3)
               lsl.l   #2,d6
               adda.l  d6,a1
               lsl.l   #1,d6
               adda.l  d6,a1           ; a1 = pointer to 1st j
               move.l  d4,d6           ; istep(d4)
               mulu.l  #12,d6          ; 12 * istep. pointer increment

@iloop  move.l  d0,d1
               add.l   d3,d1           ; j(d1) = i(d0) + mmax(d3)

               fmove.x (a1),fp4        ; fp4 = data[j]
               fmove.x fp4,fp7
               fmul.x  fp2,fp4
               fmove.x 12(a1),fp6      ; fp6 = data[j+1]
               fmove.x fp6,fp5
               fmul.x  fp3,fp6
               fsub.x  fp6,fp4         ; tempr(fp4) = wr(fp2)*data[j] - wi(fp3)*data[j+1]
               fmul.x  fp2,fp5
               fmul.x  fp3,fp7
               fadd.x  fp7,fp5         ; tempi(fp5) = wr*data[j+1] + wi*data[j]

               fmove.x (a0),fp6        ; fp6 = data[i]
               fmove.x fp6,fp7
               fadd.x  fp4,fp6
               fmove.x fp6,(a0)        ; data[i] = data[i] + tempr(fp4)
               fsub.x  fp4,fp7
               fmove.x fp7,(a1)        ; data[j] = data[i] - tempr(fp4)

               fmove.x 12(a0),fp6      ; fp6 = data[i+1]
               fmove.x fp6,fp7
               fadd.x  fp5,fp6
               fmove.x fp6,12(a0)      ; data[i+1] = data[i+1] + tempi(fp5)
               fsub.x  fp5,fp7
               fmove.x fp7,12(a1)      ; data[j+1] = data[i+1] - tempi(fp5)

               adda.l  d6,a0
               adda.l  d6,a1

               add.l   d4,d0           ; i(d0) += istep(d4)
               cmp.l   d5,d0
               ble             @iloop          ; branch if i(d0) <= n(d5)

       ; ---------------update wr & wi ------------------------

               fmove.x fp2,fp5         ; wtemp(fp5) = wr(fp2)
               fmove.x fp2,fp6
               fmul.x  fp0,fp6
               fadd.x  fp6,fp2         ; wr(fp2) += wr(fp2) * wpr(fp0)
               fmove.x fp3,fp6
               fmul.x  fp1,fp6
               fsub.x  fp6,fp2         ; wr(fp2) -= wi(fp3) * wpi(fp1)
               fmove.x fp3,fp6
               fmul.x  fp0,fp6
               fadd.x  fp6,fp3         ; wi(fp3) += wi(fp3) * wpr(fp0)
               fmul.x  fp1,fp5
               fadd.x  fp5,fp3         ; wi(fp3) += wtemp(fp5) * wpi(fp1)

               addq.l  #2,d2           ; m(d2) += 2
               cmp.l   d3,d2
               blt             @mloop          ; branch if m(d2) < mmax(d3)
               move.l  d4,d3           ; mmax(d3) = istep(d4)
               bra             @loop

       ; -------------------- done ----------------------------

@done   fmovem.x        (sp)+,fp4-fp7
               movem.l (sp)+,a2/d3-d6
       }
}


void tb_68k_four1_single(float *data, long nn, long isign)
{
       float twopi = 2.0 * PI * isign;

       asm 68020, 68881 {
               movem.l a2/d3-d6,-(sp)
               fmovem.x        fp4-fp7,-(sp)

               move.l  nn,d5
               clr.l   d3
               move.l  d5,d3           ; d3 = loop counter
               move.l  #-1,d0          ; i(d0) = -1
               movea.l data,a0
               suba.l  #4,a0           ; pointer to array indexed by 0
               movea.l a0,a2           ; a2 = *(data[0])
               suba.l  #4,a0

       ; ------------ re-order values ---------------------------------

               move.l  #1,d1           ; j(d1) = 1
@bits   adda.l  #8,a0           ; a0 = *(data[i])
               addq.l  #2,d0           ; i += 2
               cmp.l   d1,d0           ; cmp j,i
               bge             @nosw           ; branch if i(d0) >= j(d1)
@swap   movea.l a2,a1
               move.l  d1,d6
       ;       mulu.l  #4,d6
               lsl.l   #2,d6
               adda.l  d6,a1           ; a1 = *(data[j])

               move.l  (a0),d2
               move.l  (a1),d4
               move.l  d4,(a0)
               move.l  d2,(a1)
               move.l  4(a0),d2
               move.l  4(a1),d4
               move.l  d4,4(a0)
               move.l  d2,4(a1)

@nosw   move.l  d5,d2           ; m(d2) = nn(d5) = #points
@jloop  cmp.l   #2,d2
               blt             @jrdy           ; branch if m(d2) < 2
               cmp.l   d2,d1
               ble             @jrdy           ; branch if j(d1) <= m(d2)
@fixj   sub.l   d2,d1           ; j -= m
               lsr.l   #1,d2           ; m /= 2
               bra             @jloop
@jrdy   add.l   d2,d1           ; j += m
               subq.l  #1,d3
               bne             @bits

       ; --------------- order is now ready -------------------------

               lsl.l   #1,d5           ; n(d5) = 2*nn(was d5) = #long doubles
               move.l  #2,d3           ; mmax(d3) = 2

       ; -------------------- outer loop -----------------------------

@loop   cmp.l   d3,d5
               ble             @done           ; branch if n(d5) <= mmax(d3)
               move.l  d3,d4
               lsl.l   #1,d4           ; istep(d4) = 2*mmax(d3)
               fmove.s twopi,fp1
               fmove.l d3,fp0
               fdiv.x  fp0,fp1         ; theta(fp1) = 2 pi / mmax(d3)
               fmove.x fp1,fp0
               fmove.w #2,fp2
               fdiv.x  fp2,fp0         ; fp0 = 1/2 theta
               fsin.x  fp0
               fmul.x  fp0,fp0
               fmul.x  fp2,fp0
               fneg.x  fp0                     ; wpr(fp0) = -2 sin^2(1/2 theta)
               fsin.x  fp1                     ; wpi(fp1) = sin(theta)
               fmove.w #1,fp2          ; wr(fp2) = 1
               fmove.w #0,fp3          ; wi(fp3) = 0

       ; ------------------ inner loops -------------------------

               move.l  #1,d2           ; m(d2) = 1
@mloop  move.l  d2,d0           ; i(d0) = m(d2)

               move.l  d0,d6           ; i(d0)
               movea.l a2,a0
               lsl.l   #2,d6
               adda.l  d6,a0           ; a0 = pointer to 1st i
               movea.l a0,a1
               move.l  d3,d6           ; mmax(d3)
               lsl.l   #2,d6
               adda.l  d6,a1           ; a1 = pointer to 1st j
               move.l  d4,d6           ; istep(d4)
               mulu.l  #4,d6           ; 4 * istep. pointer increment

@iloop  move.l  d0,d1
               add.l   d3,d1           ; j(d1) = i(d0) + mmax(d3)

               fmove.s (a1),fp4        ; fp4 = data[j]
               fmove.x fp4,fp7
               fmul.x  fp2,fp4
               fmove.s 4(a1),fp6       ; fp6 = data[j+1]
               fmove.x fp6,fp5
               fmul.x  fp3,fp6
               fsub.x  fp6,fp4         ; tempr(fp4) = wr(fp2)*data[j] - wi(fp3)*data[j+1]
               fmul.x  fp2,fp5
               fmul.x  fp3,fp7
               fadd.x  fp7,fp5         ; tempi(fp5) = wr*data[j+1] + wi*data[j]

               fmove.s (a0),fp6        ; fp6 = data[i]
               fmove.x fp6,fp7
               fadd.x  fp4,fp6
               fmove.s fp6,(a0)        ; data[i] = data[i] + tempr(fp4)
               fsub.x  fp4,fp7
               fmove.s fp7,(a1)        ; data[j] = data[i] - tempr(fp4)

               fmove.s 4(a0),fp6       ; fp6 = data[i+1]
               fmove.x fp6,fp7
               fadd.x  fp5,fp6
               fmove.s fp6,4(a0)       ; data[i+1] = data[i+1] + tempi(fp5)
               fsub.x  fp5,fp7
               fmove.s fp7,4(a1)       ; data[j+1] = data[i+1] - tempi(fp5)

               adda.l  d6,a0
               adda.l  d6,a1

               add.l   d4,d0           ; i(d0) += istep(d4)
               cmp.l   d5,d0
               ble             @iloop          ; branch if i(d0) <= n(d5)

       ; ---------------update wr & wi ------------------------

               fmove.x fp2,fp5         ; wtemp(fp5) = wr(fp2)
               fmove.x fp2,fp6
               fmul.x  fp0,fp6
               fadd.x  fp6,fp2         ; wr(fp2) += wr(fp2) * wpr(fp0)
               fmove.x fp3,fp6
               fmul.x  fp1,fp6
               fsub.x  fp6,fp2         ; wr(fp2) -= wi(fp3) * wpi(fp1)
               fmove.x fp3,fp6
               fmul.x  fp0,fp6
               fadd.x  fp6,fp3         ; wi(fp3) += wi(fp3) * wpr(fp0)
               fmul.x  fp1,fp5
               fadd.x  fp5,fp3         ; wi(fp3) += wtemp(fp5) * wpi(fp1)

               addq.l  #2,d2           ; m(d2) += 2
               cmp.l   d3,d2
               blt             @mloop          ; branch if m(d2) < mmax(d3)
               move.l  d4,d3           ; mmax(d3) = istep(d4)
               bra             @loop

       ; -------------------- done ----------------------------

@done   fmovem.x        (sp)+,fp4-fp7
               movem.l (sp)+,a2/d3-d6
       }
}


/*-------------------------------------------------------------------
register usage:

d0      nprev   ip3             ip3                             fp0     WPR
d1                      i1              i1                              fp1     WPI
d2                      i2              i2                              fp2     WR
d3                      i3              i3                              fp3     WI
d4                      i2rev   ifp1                    fp4     TEMPR   \
d5      idim,n  ip2             ip2                             fp5     TEMPI    \      internal
d6      *               *,ibit  ifp2                    fp6                      /      calculations
d7      *               *               *                               fp7                     /

               * = temp
---------------------------------------------------------------- */

void tb_68k_fourn_single(float *data, long *nn, long ndim, long isign)
{
       float twopi = 2.0 * PI * isign;
       long ip1,idim,n,nprev,ntot;

       asm 68020, 68881 {
               movem.l a2/d3-d7,-(sp)
               fmovem.x        fp4-fp7,-(sp)

               move.l  #1,d6           ; d6 = ntot
               movea.l data,a2
               suba.l  #4,a2           ; a2 = pointer to array indexed by zero
               movea.l nn,a1
               move.l  ndim,d7
               subq.l  #1,d7
@1              mulu.l  (a1),d6
               adda.l  #4,a1
               dbra    d7,@1
               move.l  d6,ntot

       ; -------------------- begin outer loop  ---------------

               move.l  #1,d0           ; nprev(d0) = 1
               move.l  ndim,d5         ; idim(d5) = ndim
@loop0  move.l  d5,idim         ; save idim
               move.l  d0,nprev        ; save nprev

               subq.l  #1,d5
               lsl.l   #2,d5
               movea.l nn,a1
               adda.l  d5,a1
               move.l  (a1),d5         ; n(d5)=nn[idim]
               move.l  d5,n

               move.l  d0,d7
               move.l  d0,d4
               mulu.l  d5,d4
               move.l  ntot,d0
               divu.l  d4,d0           ; nrem(d0) = ntot/(n*nprev)

               lsl.l   #1,d7           ; ip1 = nprev << 1
               move.l  d7,ip1
               mulu.l  d7,d5           ; ip2(d5) = ip1 * n
               mulu.l  d5,d0           ; ip3(d0) = ip2 * nrem
               move.l  #1,d4           ; i2rev(d4) = 1

       ; -------------------- loop 1 --------------------------

               move.l  #1,d2           ; i2(d2) = 1
@loop1  cmp.l   d4,d2
               bge             @l1a            ; skip if i2(d2) >= i2rev(d4)

               move.l  d2,d1
@l1b    move.l  d1,d3

@l1c    move.l  d4,d7
               add.l   d3,d7
               sub.l   d2,d7           ; i3rev(d7) = i2rev(d4) + i3(d3) - i2(d2)

@swap   move.l  d3,d6
               lsl.l   #2,d6
               movea.l a2,a0
               adda.l  d6,a0           ; a0 -> data[i3]
               move.l  d7,d6
               lsl.l   #2,d6
               movea.l a2,a1
               adda.l  d6,a1           ; a1 -> data[i3rev]

               move.l  (a0),d6
               move.l  (a1),d7
               move.l  d6,(a1)
               move.l  d7,(a0)
               move.l  4(a0),d6
               move.l  4(a1),d7
               move.l  d6,4(a1)
               move.l  d7,4(a0)

               add.l   d5,d3
               cmp.l   d0,d3
               ble             @l1c

               add.l   #2,d1
               move.l  d2,d7
               add.l   ip1,d7
               subq.l  #2,d7
               cmp.l   d7,d1
               ble             @l1b

@l1a    move.l  d5,d6
               lsr.l   #1,d6           ; ibit(d6) = ip2 >> 1

@l1y    cmp.l   ip1,d6
               blt             @l1x
               cmp.l   d4,d6
               bge             @l1x

               sub.l   d6,d4           ; i2rev(d4) -= ibit(d6)
               lsr.l   #1,d6           ; ibit >>= 1
               bra             @l1y

@l1x    add.l   d6,d4           ; i2rev += ibit

               add.l   ip1,d2
               cmp.l   d5,d2
               ble             @loop1          ; loop if i2(d2) <= ip2(d5)

       ; -------------------- loop 2 --------------------------

               move.l  ip1,d4          ; ifp1(d4) = ip1
@loop2  cmp.l   d5,d4
               bge             @l2x            ; branch if ifp1(d4) >= ip2(d5)

               move.l  d4,d6
               lsl.l   #1,d6           ; ifp2(d6) = ifp1 << 1
               move.l  d6,d7

               fmove.s twopi,fp1
               divu.l  ip1,d7
               fmove.l d7,fp0
               fdiv.x  fp0,fp1         ; theta(fp1) = 2 pi / (ifp2/ip1)
               fmove.x fp1,fp0
               fmove.w #2,fp2
               fdiv.x  fp2,fp0         ; fp0 = 1/2 theta
               fsin.x  fp0
               fmul.x  fp0,fp0
               fmul.x  fp2,fp0
               fneg.x  fp0                     ; wpr(fp0) = -2 sin^2(1/2 theta)
               fsin.x  fp1                     ; wpi(fp1) = sin(theta)
               fmove.w #1,fp2          ; wr(fp2) = 1
               fmove.w #0,fp3          ; wi(fp3) = 0

               move.l  #1,d3
@l2a    move.l  d3,d1
@l2b    move.l  d1,d2
@l2c    move.l  d2,d7           ; k1(d7) = i2(d2)
               lsl.l   #2,d7
               movea.l a2,a0
               adda.l  d7,a0           ; a0 -> data[k1]
               move.l  d4,d7
               add.l   d2,d7           ; k2(d7) = k1(=i2(d2))+ifp1(d4)
               lsl.l   #2,d7
               movea.l a2,a1
               adda.l  d7,a1           ; a1 -> data[k2]

               fmove.s (a1),fp4        ; fp4 = data[k2]
               fmove.x fp4,fp7
               fmul.x  fp2,fp4
               fmove.s 4(a1),fp6       ; fp6 = data[k2+1]
               fmove.x fp6,fp5
               fmul.x  fp3,fp6
               fsub.x  fp6,fp4         ; tempr(fp4) = wr(fp2)*data[k2] - wi(fp3)*data[k2+1]
               fmul.x  fp2,fp5
               fmul.x  fp3,fp7
               fadd.x  fp7,fp5         ; tempi(fp5) = wr*data[k2+1] + wi*data[k2]

               fmove.s (a0),fp6        ; fp6 = data[k1]
               fmove.x fp6,fp7
               fadd.x  fp4,fp6
               fmove.s fp6,(a0)        ; data[k1] = data[k1] + tempr(fp4)
               fsub.x  fp4,fp7
               fmove.s fp7,(a1)        ; data[k2] = data[k1] - tempr(fp4)

               fmove.s 4(a0),fp6       ; fp6 = data[k1+1]
               fmove.x fp6,fp7
               fadd.x  fp5,fp6
               fmove.s fp6,4(a0)       ; data[k1+1] = data[k1+1] + tempi(fp5)
               fsub.x  fp5,fp7
               fmove.s fp7,4(a1)       ; data[k2+1] = data[k1+1] - tempi(fp5)

               add.l   d6,d2           ; i2(d2) += ifp2(d6)
               cmp.l   d0,d2
               ble             @l2c            ; branch if i2(d2) <= ip3(d0)

               add.l   #2,d1
               move.l  d3,d7
               add.l   ip1,d7
               subq.l  #2,d7
               cmp.l   d7,d1
               ble             @l2b            ; branch if i1(d1) <= (i3(d3) + ip1 - 2)(d7)

       ; ---------------update wr & wi ------------------------

               fmove.x fp2,fp5         ; wtemp(fp5) = wr(fp2)
               fmove.x fp2,fp6
               fmul.x  fp0,fp6
               fadd.x  fp6,fp2         ; wr(fp2) += wr(fp2) * wpr(fp0)
               fmove.x fp3,fp6
               fmul.x  fp1,fp6
               fsub.x  fp6,fp2         ; wr(fp2) -= wi(fp3) * wpi(fp1)
               fmove.x fp3,fp6
               fmul.x  fp0,fp6
               fadd.x  fp6,fp3         ; wi(fp3) += wi(fp3) * wpr(fp0)
               fmul.x  fp1,fp5
               fadd.x  fp5,fp3         ; wi(fp3) += wtemp(fp5) * wpi(fp1)

               add.l   ip1,d3          ; i3(d3) += ip1
               cmp.l   d4,d3
               ble             @l2a            ; branch if i3(d3) <= ifp1(d4)

               move.l  d6,d4           ; ifp1(d4) = ifp2(d6)
               bra             @loop2

       ; -------------------- end outer loop  -----------------

@l2x    move.l  nprev,d0
               mulu.l  n,d0            ; nprev(d0) *= n
               move.l  idim,d5
               subq.l  #1,d5
               bne             @loop0

       ; -------------------- done ----------------------------

@done   fmovem.x        (sp)+,fp4-fp7
               movem.l (sp)+,a2/d3-d7
       }
}