home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff214.lzh / MandelVroom / src / mandint32.c < prev    next >
C/C++ Source or Header  |  1989-05-30  |  16KB  |  681 lines

  1. /*
  2.  * MandelVroom 2.0
  3.  *
  4.  * (c) Copyright 1987,1989  Kevin L. Clague, San Jose, CA
  5.  *
  6.  * All rights reserved.
  7.  *
  8.  * Permission is hereby granted to distribute this program's source
  9.  * executable, and documentation for non-comercial purposes, so long as the
  10.  * copyright notices are not removed from the sources, executable or
  11.  * documentation.  This program may not be distributed for a profit without
  12.  * the express written consent of the author Kevin L. Clague.
  13.  *
  14.  * This program is not in the public domain.
  15.  *
  16.  * Fred Fish is expressly granted permission to distribute this program's
  17.  * source and executable as part of the "Fred Fish freely redistributable
  18.  * Amiga software library."
  19.  *
  20.  * Permission is expressly granted for this program and it's source to be
  21.  * distributed as part of the Amicus Amiga software disks, and the
  22.  * First Amiga User Group's Hot Mix disks.
  23.  *
  24.  * contents: this file contains the functions to calculate Mandelbrot and
  25.  * Julia pictures using a special and fast fixed point (scaled ints) format.
  26.  * It has generators for 68000 and 68020 in assembly.
  27.  */
  28.  
  29. #include "mandp.h"
  30.  
  31. #include "parms.h"
  32.  
  33. #define BITS2SHIFT 27
  34.  
  35. /*
  36.  * 32 bit fixed point generator
  37.  */
  38. MandelbrotInt32( Pict )
  39.   register struct Picture *Pict;
  40. {
  41.   register LONG   i, j, k;
  42.   register SHORT *CountPtr;
  43.  
  44.   double gap;
  45.  
  46.   UBYTE ConvFlag;
  47.   LONG  gapx, gapy, startx;
  48.  
  49.   struct IntPotParms Parms;
  50.   struct RastPort   *Rp;
  51.  
  52.   if (Pict->Flags & NO_RAM_GENERATE)
  53.     CountPtr = Pict->Counts;
  54.   else
  55.     CountPtr = Pict->Counts + Pict->CurLine*Pict->CountX;
  56.  
  57.   /* figure out horizontal and verticle distances between points in plane.
  58.    * convert them to fixed point format                                    */
  59.  
  60.   gapy = (int) (Pict->ImagGap*((double)(1<<BITS2SHIFT)));
  61.   gapx = (int) (Pict->RealGap*((double)(1<<BITS2SHIFT)));
  62.  
  63.   startx = (int)(Pict->RealLow*((double)(1<<BITS2SHIFT)));
  64.  
  65.   /*
  66.    * for each point in the image, calculate Mandelbrot
  67.    */
  68.   Parms.C_Imag = (int)(Pict->ImagLow*((double)(1<<BITS2SHIFT)));
  69.  
  70.   Parms.C_Imag += Pict->CurLine*gapy;
  71.  
  72.   Parms.ScreenReal = 0;
  73.   Parms.ScreenImag = 0;
  74.  
  75.   Parms.MaxIteration = Pict->MaxIteration;
  76.  
  77.   for (i = Pict->CurLine; i < Pict->CountY; i++) {
  78.  
  79.     Parms.C_Real = startx;
  80.  
  81.     ConvFlag = 0;
  82.  
  83.     if ( Pict->Flags & NO_RAM_GENERATE )
  84.       CountPtr = Pict->Counts;
  85.  
  86.     for (j = 0; j < Pict->CountX; j++) {
  87.  
  88.       if (*CountPtr == 0) {
  89.  
  90.         /*
  91.          * if the last pixel was mandelbrot, then use trace table
  92.          */
  93.         if (ConvFlag) {
  94.  
  95.           k = Int32_Trace_Height( &Parms );
  96.         } else {
  97.  
  98.           k = Int32_Height( &Parms );
  99.         }
  100.  
  101.         ConvFlag = k == Pict->MaxIteration;
  102.         *CountPtr = k;
  103.       }
  104.       CountPtr++;
  105.  
  106.       Parms.C_Real += gapx;
  107.  
  108.       ChildPause( Pict );
  109.     }
  110.     Parms.C_Imag += gapy;
  111.  
  112.     CheckEOL( Pict );
  113.   }
  114. } /* Mandelbrot32Int */
  115.  
  116. #ifdef CHECK_TASK_STACK
  117.  
  118. int stackerr;
  119. LONG stacklow;
  120. LONG stackhi;
  121. LONG stackovfl;
  122. LONG stackmax;
  123.  
  124. CheckStack() {
  125.   register struct Task *Task;
  126.   register LONG hi,reg,low;
  127.   register LONG size;
  128.  
  129.   Task = FindTask(0L);
  130.  
  131.   hi = Task->tc_SPUpper;
  132.   reg = Task->tc_SPReg;
  133.   low = Task->tc_SPLower;
  134.  
  135.   size = hi - reg;
  136.  
  137.   if (reg < low) {
  138.  
  139.     if (size > stackmax) {
  140.       stackerr  = 1;
  141.  
  142.       stacklow   = low;
  143.       stackhi    = hi;
  144.       stackovfl  = reg;
  145.       stackmax   = size;
  146.     }
  147.   } else {
  148.  
  149.     if (stackerr == 0 && size > stackmax) {
  150.       stacklow   = low;
  151.       stackhi    = hi;
  152.       stackovfl  = reg;
  153.       stackmax   = size;
  154.     }
  155.   }
  156. }
  157.  
  158. PrintStack()
  159. {
  160.   if (stackerr != 0)
  161.     printf("********* STACK ERR ***********\n");
  162.  
  163.   printf("Low   %08x\nHigh  %08x\nSP     %08x\n",
  164.           stacklow, stackhi, stackovfl );
  165.  
  166.   printf("MinStack %d\n",stackmax);
  167. }
  168.  
  169. #endif
  170.  
  171. /*
  172.  * 32 bit fixed point generator
  173.  */
  174. JuliaInt32( Pict )
  175.   register struct Picture *Pict;
  176. {
  177.   register LONG   i, j, k;
  178.   register SHORT *CountPtr;
  179.  
  180.   LONG  gapx, gapy, startx;
  181.   UBYTE ConvFlag;
  182.  
  183.   struct IntPotParms Parms;
  184.  
  185.   if (Pict->Flags & NO_RAM_GENERATE)
  186.     CountPtr = Pict->Counts;
  187.   else
  188.     CountPtr = Pict->Counts + (Pict->CurLine*Pict->CountX);
  189.  
  190.   /* figure out horizontal and verticle distances between points in plane.
  191.    * convert them to fixed point format                                    */
  192.  
  193.   gapx = (int) ( Pict->RealGap * (double) (1 << BITS2SHIFT) );
  194.   gapy = (int) ( Pict->ImagGap * (double) (1 << BITS2SHIFT) );
  195.  
  196.   /*
  197.    * for each point in the image, calculate Julia
  198.    */
  199.   Parms.ScreenImag  = (int) ( Pict->ImagLow * (double) (1 << BITS2SHIFT) );
  200.   Parms.ScreenImag += Pict->CurLine*gapy;
  201.  
  202.   startx = (int) ( Pict->RealLow * (double) (1 << BITS2SHIFT) );
  203.  
  204.   Parms.C_Real = (int) ( Pict->Real * (double) (1 << BITS2SHIFT) );
  205.   Parms.C_Imag = (int) ( Pict->Imag * (double) (1 << BITS2SHIFT) );
  206.  
  207.   Parms.MaxIteration = Pict->MaxIteration;
  208.  
  209.   for (i = Pict->CurLine; i < Pict->CountY; i++) {
  210.  
  211.     Parms.ScreenReal = startx;
  212.     ConvFlag = 0;
  213.  
  214.     if ( Pict->Flags & NO_RAM_GENERATE )
  215.       CountPtr = Pict->Counts;
  216.  
  217.     for (j = 0; j < Pict->CountX; j++) {
  218.  
  219.       if (*CountPtr == 0) {
  220.  
  221.         /*
  222.          * if the last pixel was mandelbrot, then use trace table
  223.          */
  224.  
  225.         if ( ConvFlag ) {
  226.           k = Int32_Trace_Height( &Parms );
  227.         } else {
  228.           k = Int32_Height( &Parms );
  229.         }
  230.  
  231.         ConvFlag = k == Pict->MaxIteration;
  232.         *CountPtr = k;
  233.       }
  234.       CountPtr++;
  235.  
  236.       Parms.ScreenReal += gapx;
  237.  
  238.       ChildPause( Pict );
  239.     }
  240.     Parms.ScreenImag += gapy;
  241.  
  242.     CheckEOL( Pict );
  243.   }
  244. } /* Julia32Int */
  245.  
  246. /*
  247.  * 32 bit fixed point generator
  248.  */
  249. MandelbrotInt32II( Pict )
  250.   register struct Picture *Pict;
  251. {
  252.   register LONG   i, j, k;
  253.   register struct RastPort *Rp;
  254.  
  255.   double gap;
  256.  
  257.   SHORT *CountPtr;
  258.   LONG  gapx, gapy, startx;
  259.  
  260.   struct IntPotParms Parms;
  261.  
  262.   if (Pict->Flags & NO_RAM_GENERATE)
  263.     CountPtr = Pict->Counts;
  264.   else
  265.     CountPtr = Pict->Counts + Pict->CurLine*Pict->CountX;
  266.  
  267.   /* figure out horizontal and verticle distances between points in plane.
  268.    * convert them to fixed point format                                    */
  269.  
  270.   gapy = (int) (Pict->ImagGap*((double)(1<<BITS2SHIFT)));
  271.   gapx = (int) (Pict->RealGap*((double)(1<<BITS2SHIFT)));
  272.  
  273.   startx = (int)(Pict->RealLow*((double)(1<<BITS2SHIFT)));
  274.  
  275.   /*
  276.    * for each point in the image, calculate Mandelbrot
  277.    */
  278.   Parms.C_Imag = (int)(Pict->ImagLow*((double)(1<<BITS2SHIFT)));
  279.   Parms.C_Imag += Pict->CurLine*gapy;
  280.  
  281.   Parms.ScreenReal = 0;
  282.   Parms.ScreenImag = 0;
  283.  
  284.   Parms.MaxIteration = Pict->MaxIteration;
  285.  
  286.   for (i = Pict->CurLine; i < Pict->CountY; i++) {
  287.  
  288.     Parms.C_Real = startx;
  289.  
  290.     if ( Pict->Flags & NO_RAM_GENERATE )
  291.       CountPtr = Pict->Counts;
  292.  
  293.     for (j = 0; j < Pict->CountX; j++) {
  294.  
  295.       /*
  296.        * if the last pixel was mandelbrot, then use trace table
  297.        */
  298.  
  299.       k = Int32_Height_Fast( &Parms );
  300.  
  301.       *CountPtr++ = k;
  302.  
  303.       Parms.C_Real += gapx;
  304.  
  305.       ChildPause( Pict );
  306.     }
  307.     Parms.C_Imag += gapy;
  308.  
  309.     CheckEOL( Pict );
  310.   }
  311. } /* MandelbrotInt32II */
  312.  
  313. /*
  314.  *  This code does mandelbrot without any trace lookup.
  315.  *  It is the fastest 68000 generator in the house.
  316.  */
  317. Int32_Height( Parms )
  318.  
  319.   struct IntPotParms *Parms;
  320. {
  321.   LONG Height;
  322.  
  323.   register struct IntPotParms *P = Parms;
  324.  
  325.   register LONG cura, curb, cura2, curb2;
  326.  
  327. #asm
  328. height  equ -4
  329. Bits2Shift equ  5
  330. ;
  331. ;
  332. ;  d1 - BITS2SHIFT
  333. ;  d2 - k
  334. ;  d4 - a
  335. ;  d5 - b
  336. ;  d6 - a2
  337. ;  d7 - b2
  338. ;
  339. screenr  equ 0
  340. screeni  equ 4
  341. curx     equ 8
  342. cury     equ 12
  343. maxi     equ 16
  344. ;
  345.    move.l   #Bits2Shift,d1
  346.    move.l   screenr(a2),d4
  347.    move.l   screeni(a2),d5
  348.    move.w   maxi(a2),d2
  349.    bra      Fposa2
  350. ;
  351. FKLoop
  352. ;
  353. ;  cura = cura2 - curb2 + curx;
  354.    exg      d6,d4       ; exchange cura and cura2
  355.    sub.l    d7,d4       ; subtract curb
  356.    add.l    curx(a2),d4 ; add curx
  357. ;
  358. ;  curb = cura * curb >> 12;
  359.    move.l   d6,d7      ; get copy of op1 sign bit
  360.    bpl      Fpos1       ; get absolute value of op1
  361.    neg.l    d6
  362. Fpos1
  363.    eor.l    d5,d7      ; calculate result sign
  364.    tst.l    d5         ; get absolute value of op2
  365.    bpl      Fpos2
  366.    neg.l    d5
  367. Fpos2
  368.    move.l   d6,d0      ; get a copy of op1
  369.    swap     d0         ; get high half of op1
  370.    move.w   d0,d7      ; save a copy of high half
  371.    mulu     d5,d0      ; multiply op2 low by op1 high
  372.    clr.w    d0         ;  clear least significant part
  373.    swap     d0         ;  put it in it's place
  374.    swap     d5         ; get high half of op2
  375.    mulu     d5,d6      ; multiply op2 high with op1 low
  376.    clr.w    d6         ;  clear least significant part
  377.    swap     d6         ;  put it in its place
  378.    mulu     d7,d5      ; multiply op2 high by op1 high
  379.    add.l    d0,d5      ; add partial results
  380.    add.l    d6,d5      ; add partial results
  381.    tst.l    d7         ; is the result negative?
  382.    bpl      Fpos3
  383.    neg.l    d5         ; yes, better negate it.
  384. Fpos3
  385.    asl.l    d1,d5      ; now, rescale it.
  386. ;
  387. ;  curb += curb + cury;
  388.    add.l    d5,d5      ; double it and add cury
  389.    add.l    cury(a2),d5
  390. Fposa2
  391. ;
  392. ;  cura2 = cura * cura;
  393.    move.l   d4,d0      ; get absolute value of a in d0
  394.    bpl      Fposa
  395.    neg.l    d0
  396. Fposa
  397.    move.l   d0,d6      ; copy absolute value into d6
  398.    swap     d6         ; get high part in d6
  399.    mulu     d6,d0      ; multiply high and low destroying low
  400.    clr.w    d0         ; clear the least significant part
  401.    swap     d0         ; put most sig. part in low half
  402.    mulu     d6,d6      ; multiply high and high destroing high
  403.    add.l    d0,d6      ; add in lower half twice
  404.    add.l    d0,d6
  405.    asl.l    d1,d6      ; get radix point back in correct place
  406.    bvs      Fbailout
  407. ;
  408. ;  curb2 = curb * curb;
  409.    move.l   d5,d0      ; get absolute value of a in d0
  410.    bpl      Fposb
  411.    neg.l    d0
  412. Fposb
  413.    move.l   d0,d7      ; copy absolute value into d7
  414.    swap     d7         ; get high part in d7
  415.    mulu     d7,d0      ; multiply high and low destroying low
  416.    clr.w    d0         ; clear the least significant part
  417.    swap     d0         ; put most sig. part in low half
  418.    mulu     d7,d7      ; multiply high and high destroing high
  419.    add.l    d0,d7      ; add in lower half twice
  420.    add.l    d0,d7
  421.    asl.l    d1,d7      ; get radix point back in correct place
  422.    bvs      Fbailout
  423. ;
  424.    move.l   d6,d0      ; if (cura2 + curb2 >= 4) goto bailout;
  425.    add.l    d7,d0
  426.    bvs      Fbailout
  427. ;
  428.    dbra     d2,FKLoop
  429. ;  addq     #1,d2
  430. Fbailout
  431.    move.w   maxi(a2),d0
  432.    sub.w    d2,d0
  433.    sub.w    #1,d0
  434.    ext.l    d0
  435. #endasm
  436.    ;;
  437. }
  438.  
  439. Int32_Trace_Height( Parms )
  440.  
  441.   register struct IntPotParms *Parms;
  442. {
  443.   SHORT  k,TLen;
  444.   LONG  OldA[17];
  445.  
  446.   register LONG cura, curb, cura2, curb2;
  447.  
  448. #asm
  449. ;
  450. ;
  451. ;  d1 - BITS2SHIFT
  452. ;  d2 - k
  453. ;  d4 - a
  454. ;  d5 - b
  455. ;  d6 - a2
  456. ;  d7 - b2
  457. ;  a0 - Trace Table pointer
  458. ;
  459. Trace equ 16
  460. OldA  equ -132
  461. k     equ -2
  462. TLen  equ -4
  463.  
  464.    move.l   #Bits2Shift,d1
  465.    move.l   screenr(a2),d4
  466.    move.l   screeni(a2),d5
  467. ;
  468.    lea      OldA(a5),a0          ; Set up Trace table pointer
  469.    move.w   #Trace,d2            ; Set up Trace table len
  470. ;
  471.    move.w   #-1,k(a5)
  472.    bra      TPosa2               ; branch in to middle to get a2 = a * a
  473. ;
  474. TLoop
  475. ;
  476. ;  cura = cura2 - curb2 + curx;
  477.    exg      d6,d4       ; exchange cura and cura2
  478.    sub.l    d7,d4       ; subtract curb
  479.    add.l    curx(a2),d4 ; add curx
  480. ;
  481. ;  curb = cura * curb >> 12;
  482.    move.l   d6,d7      ; get copy of op1 sign bit
  483.    bpl      TPos1       ; get absolute value of op1
  484.    neg.l    d6
  485. TPos1
  486.    eor.l    d5,d7      ; calculate result sign
  487.    tst.l    d5         ; get absolute value of op2
  488.    bpl      TPos2
  489.    neg.l    d5
  490. TPos2
  491.    move.l   d6,d0      ; get a copy of op1
  492.    swap     d0         ; get high half of op1
  493.    move.w   d0,d7      ; save a copy of high half
  494.    mulu     d5,d0      ; multiply op2 low by op1 high
  495.    clr.w    d0         ;  clear least significant part
  496.    swap     d0         ;  put it in it's place
  497.    swap     d5         ; get high half of op2
  498.    mulu     d5,d6      ; multiply op2 high with op1 low
  499.    clr.w    d6         ;  clear least significant part
  500.    swap     d6         ;  put it in its place
  501.    mulu     d7,d5      ; multiply op2 high by op1 high
  502.    add.l    d0,d5      ; add partial results
  503.    add.l    d6,d5      ; add partial results
  504.    tst.l    d7         ; is the result negative?
  505.    bpl      TPos3
  506.    neg.l    d5         ; yes, better negate it.
  507. TPos3
  508.    asl.l    d1,d5      ; now, rescale it.
  509. ;
  510. ;  curb += curb + cury;
  511.    add.l    d5,d5      ; double it and add cury
  512.    add.l    cury(a2),d5
  513. TPosa2
  514. ;
  515. ;  cura2 = cura * cura;
  516.    move.l   d4,d0      ; get absolute value of a in d0
  517.    bpl      TPosa
  518.    neg.l    d0
  519. TPosa
  520.    move.l   d0,d6      ; copy absolute value into d6
  521.    swap     d6         ; get high part in d6
  522.    mulu     d6,d0      ; multiply high and low destroying low
  523.    clr.w    d0         ; clear the least significant part
  524.    swap     d0         ; put most sig. part in low half
  525.    mulu     d6,d6      ; multiply high and high destroing high
  526.    add.l    d0,d6      ; add in lower half twice
  527.    add.l    d0,d6
  528.    asl.l    d1,d6      ; get radix point back in correct place
  529.    bvs      bailout
  530. ;
  531. ;  curb2 = curb * curb;
  532.    move.l   d5,d0      ; get absolute value of a in d0
  533.    bpl      TPosb
  534.    neg.l    d0
  535. TPosb
  536.    move.l   d0,d7      ; copy absolute value into d7
  537.    swap     d7         ; get high part in d7
  538.    mulu     d7,d0      ; multiply high and low destroying low
  539.    clr.w    d0         ; clear the least significant part
  540.    swap     d0         ; put most sig. part in low half
  541.    mulu     d7,d7      ; multiply high and high destroing high
  542.    add.l    d0,d7      ; add in lower half twice
  543.    add.l    d0,d7
  544.    asl.l    d1,d7      ; get radix point back in correct place
  545.    bvs      bailout
  546.  
  547.    move.l   d6,d0      ; if (cura2 + curb2 >= 4) goto bailout;
  548.    add.l    d7,d0
  549.    bvs      bailout
  550.  
  551.    move     d0,(a0)+   ; save magnitude in trace table
  552.  
  553.    addq.w   #1,k(a5)   ; are we out of iterations?
  554.    move.w   maxi(a2),d0
  555.    cmp.w    k(a5),d0
  556.    ble      GotIt
  557.    dbra     d2,TLoop   ; nope, so try again till trace table full
  558.  
  559.    move.w   -(a0),d0   ; get last entry in the trace
  560.  
  561.    move.w   #Trace-1,d2  ; set up length and address for comparison loop
  562.    lea      OldA(a5),a0
  563.  
  564. TCLoop
  565.    cmp      (a0)+,d0
  566.    beq      GotIt       ; did we find it?
  567.    dbra     d2,TCLoop
  568.  
  569.    lea      OldA(a5),a0 ; no match, so prepare for the next round
  570.    move     d0,(a0)+    ; move last entry of the table
  571.  
  572.    move.w   #Trace,d2
  573.    bra      TLoop
  574.  
  575. GotIt
  576.    move.w   maxi(a2),k(a5)
  577. bailout
  578.    move.w   k(a5),d0
  579.    ext.l    d0
  580. #endasm
  581.    ;;
  582. }
  583.  
  584. /*
  585.  * 32 bit fixed point generator
  586.  */
  587. Int32_Height_Fast( Parms )
  588.   struct IntPotParms *Parms;
  589. {
  590.   register struct IntPotParms *P = Parms;
  591.   register LONG cura,curb,cura2,curb2;
  592.   /*
  593.    *  This is the fastest generator in the house.
  594.    */
  595. #asm
  596.    machine mc68020
  597. fscreenr  equ 0
  598. fscreeni  equ 4
  599. fcurx     equ 8
  600. fcury     equ 12
  601. fmaxi     equ 16
  602.  
  603. Zcurx      equ   8
  604. Zcury      equ  12
  605. ;
  606. ;  d1 - BITS2SHIFT
  607. ;  d2 - k
  608. ;  d4 - a
  609. ;  d5 - b
  610. ;  d6 - a2
  611. ;  d7 - b2
  612. ;
  613. ;  cura = curb = curc = curd = 0;
  614.    move.w   maxi(a2),d1
  615.    move.l   #27,d2
  616.    move.l   fscreenr(a2),d4
  617.    move.l   fscreeni(a2),d5
  618.    move.l   fcurx(a2),a0
  619.    move.l   fcury(a2),a1
  620.    bra      Zpos2
  621.  
  622. ZLoop
  623. ;
  624. ;  cura = cura2 - curb2 + curx;
  625. ;
  626.    exg      d6,d4
  627.    sub.l    d7,d4
  628. ;   move.l   a0,d0
  629.    add.l    a0,d4
  630. ;
  631. ;  curb = cura * curb
  632. ;
  633.    muls.l   d6,d0:d5
  634.    asl.l    #5,d0
  635.    lsr.l    d2,d5
  636.    or.l     d0,d5
  637. ;
  638. ;  curb += curb + cury;
  639. ;
  640.    add.l    d5,d5
  641. ;   move.l   a1,d0
  642.    add.l    a1,d5
  643. Zpos2
  644. ;
  645. ;  cura2 = cura * cura;
  646. ;
  647.    move.l   d4,d6
  648.    muls.l   d6,d0:d6
  649.    asl.l    #5,d0
  650.    bvs      Zbailout
  651.    lsr.l    d2,d6
  652.    or.l     d0,d6
  653. ;
  654. ;  curb2 = curb * curb;
  655. ;
  656.    move.l   d5,d7
  657.    muls.l   d7,d0:d7
  658.    asl.l    #5,d0
  659.    bvs      Zbailout
  660.    lsr.l    d2,d7
  661.    or.l     d0,d7
  662. ;
  663.    move.l   d6,d0
  664.    add.l    d7,d0
  665.    bvs      Zbailout
  666. ;
  667. ;  cmp.l    #536870912,d0
  668. ;   bge      Zbailout
  669. ;
  670.    dbra     d1,ZLoop
  671. ;
  672. ;  addq     #1,d1
  673. Zbailout
  674.    move.w   fmaxi(a2),d0
  675.    sub.w    d1,d0
  676.    sub.w    #1,d0
  677.    ext.l    d0
  678. #endasm
  679.    ;
  680. }
  681.