home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / sys / mac / programm / 18561 < prev    next >
Encoding:
Internet Message Format  |  1992-11-17  |  20.8 KB

  1. Path: sparky!uunet!pageworks.com!world!eff!sol.ctr.columbia.edu!spool.mu.edu!uwm.edu!ogicse!cs.uoregon.edu!mystix.cs.uoregon.edu!mkelly
  2. From: mkelly@mystix.cs.uoregon.edu (Michael A. Kelly)
  3. Newsgroups: comp.sys.mac.programmer
  4. Subject: Re: Help! making an assembly routine faster
  5. Message-ID: <1992Nov18.010815.6649@cs.uoregon.edu>
  6. Date: 18 Nov 92 01:08:15 GMT
  7. Article-I.D.: cs.1992Nov18.010815.6649
  8. References: <1992Nov14.200831.20477@nntp.hut.fi> <1992Nov16.014850.28678@cs.uoregon.edu> <1992Nov16.190947.9920@nntp.hut.fi>
  9. Sender: news@cs.uoregon.edu (Netnews Owner)
  10. Organization: High Risk Ventures
  11. Lines: 597
  12.  
  13. In article <1992Nov16.190947.9920@nntp.hut.fi> jmunkki@vipunen.hut.fi (Juri Munkki) writes:
  14. >In article <1992Nov16.014850.28678@cs.uoregon.edu> mkelly@mystix.cs.uoregon.edu (Michael A. Kelly) writes:
  15. >>        CMPI.B    #0xFF, D2
  16. >>        BNE       @hardway            ; don't copy everything
  17. >
  18. >An addq.w #1, and then a beq might prove to be faster than the cmp with
  19. >an immediate value. You have to adjust the mask back to its old value,
  20. >if the test fails, but this can be done either with the jump tables
  21. >(not with the ones you are using now, but the longer ones I will suggest
  22. >later in this article) or by a subq.w #1
  23.  
  24. According to the Motorola manual, you're right.  But in practice this slowed
  25. things down quite a bit.  I can't figure out why.  I replaced the CMPI with
  26. an ADDQ #1, then at @hardway I did a SUBQ #1.  My test case is a 32x32 rect
  27. with a 32x32 filled circle as the mask.  I think it would slow things down
  28. a lot more with more complicated masks.  But still, I don't know why it's
  29. slower, since the CMPI takes 8 clock cycles and the ADDQ and SUBQ each
  30. take 4, so it really should be faster....  Then again, those timings are
  31. for the 68000 (and 68020 too I think), and I'm using a 68040.
  32.  
  33. >>    @hardway:
  34. >>        ANDI.L    #0xF0, D2           ; mask off the low four bits
  35. >>        LSR.W     #4, D2              ; shift bits 4-7 into bits 0-3
  36. >
  37. >The AND is totally wasted. The LSR will do the masking for you.
  38.  
  39. :)  I don't know *what* I was thinking....
  40.  
  41. At this point, I ran my test again with the above modifications.  They
  42. improved the speed by about 10%.  (Changing the CMPI above decreased
  43. performance by about 30% with these other changes also in place.)
  44.  
  45. >You can also eliminate the and and lsr, if you use two 256-entry jump
  46. >tables that simply ignore the high or low 4 bits. The tables will take
  47. >some memory (2 x 4 x 256 bytes), but they are easy to construct with
  48. >copy and paste.
  49.  
  50. You mean two 16-entry jump tables, right?  I didn't implement this, but
  51. instead made a separate CopyMask function that used a single 256-entry
  52. jump table, with 256 subroutines for each of the 256 possible mask-bytes.
  53. See the code fragment below.
  54.  
  55. Hey, maybe I could just save 256 (times two) masks, AND each mask with the
  56. source and destination bytes, then OR those two results together to get
  57. the resulting pixel.  Hmmm, I wonder if it would be even faster....
  58.  
  59. >>        ADD.W     D2, D2              ; double the index
  60. >>        ADD.W     @table(D2.W), D2    ; calculate the address
  61. >>        JSR       @table(D2.W)        ; plot four pixels
  62. >
  63. >The 68020 has addressing modes that do the multiplication of the index.
  64. >I haven't needed them myself, but I'm fairly certain that you can improve
  65. >this part with the right addressing mode.
  66.  
  67. Nope, I don't think so.  You're talking about Address Register Indirect with
  68. Offset and Index, like so: @table( <no address in this case>, D2.W*2 ).
  69. The problem is that the value of D2 is preserved in that operation, so instead
  70. of D2 = (D2 * 2) + @table + (D2 * 2), you get D2 = D2 + @table + (D2 * 2).
  71.  
  72. >Replace the jsr with a LEA An to the return address and a JMP to the
  73. >subroutine. Then jump back with a JMP (An). This is quite a bit faster
  74. >than a JSR/RTS combination, although it's not "good style".
  75.  
  76. Wow, that made a big difference!  About a 17% improvement, making the total
  77. speedup about 25%.
  78.  
  79. >>        CLR.L     D2                  ; clear the mask register
  80. >>        MOVE.B    (A2)+, D2           ; copy the next mask byte
  81. >>        ANDI.B    #0xF, D2            ; mask off the high four bits
  82. >
  83. >Use BFEXTU, if you must read the mask again. Remember that you can use
  84. >-1(A2), if you already incremented A2 or you might be able to account
  85. >for this with the bitfield offset. You can also use constant bitfield
  86. >offsets, if I remember correctly. I think you have some registers that
  87. >you could use, so you could store fairly constant bitfield indices
  88. >there.
  89.  
  90. I'm not sure what you mean by constant offsets.  I did this:
  91.     BFEXTU    -1(A2){4:4}
  92. and it slowed it down by about 4%.
  93.  
  94. >>    @sub8:                            ; mask = 1000
  95. >>        MOVE.B    (A0)+, (A1)+
  96. >>        ADDQ.L    #3, A0
  97. >>        ADDQ.L    #3, A1
  98. >>        RTS
  99. >
  100. >A move.b (a0),(a1) along with addq #4 is faster on a 68000, but I
  101. >don't think it matters on new processors. I may be wrong, but you'll
  102. >probably never see the difference.
  103.  
  104. You're right, it didn't make any difference at all on my '040.
  105.  
  106. >In the deep mask version, you could unroll the loop. It's kind of
  107. >surprising the the 1 bit mask is actually faster, but it's mostly
  108. >because of the superior algorithm that allows you to directly copy
  109. >8 bytes at a time in the most common case.
  110.  
  111. I tossed that code.  I don't really think unrolling the loop will get it
  112. down to my current speed, which is more than twice as fast.
  113.  
  114. >it might be as much as 10%. The only way to go beyond this is to make
  115. >the move.l commands aligned on long word destinations, as I mentioned
  116. >in my previous article.
  117.  
  118. But as long as I align the source and destination Pixmaps, that isn't an
  119. issue, right?
  120.  
  121. >I hope my articles offer proof for the other half of my .signature... :-)
  122.  
  123. Definitely :)
  124.  
  125.  
  126. OK, here's the new code.  The first one is the newer, better version of
  127. Quick8CopyMask, with most of the optimizations suggested by Juri.  It's
  128. about 5.5 times as fast as QuickDraw's CopyMask, at least with my simple
  129. circle mask test case.  The second one is a small part of a very large
  130. Quick8CopyMask that has 256 separate subroutines to handle each mask
  131. byte, rather than only 16 subroutines to handle a mask nibble (a nibble is
  132. half a byte, right?).  It's far too long to post here, but if you want a
  133. copy I'll be happy to email it to you.  It's about 6.5 times as fast as
  134. CopyMask; about 15% faster than the short version.
  135.  
  136. I tested the routines with the mask used in the CalcCMask DTS snippet;
  137. the short version was 5.7 times as fast as CopyMask and the long version
  138. was 7 times as fast.
  139.  
  140. And once again, if anyone can improve on these routines, please tell me how!
  141.  
  142.  
  143. void Quick8CopyMask(
  144.     PixMapHandle    srcMap,
  145.     PixMapHandle    dstMap,
  146.     Ptr             mask,
  147.     Point           srcPt,
  148.     Point           dstPt,
  149.     short           width,
  150.     short           height )
  151. {
  152.  
  153.     register char   *src;
  154.     register char   *dst;
  155.     register long   srcNewline;
  156.     register long   dstNewline;
  157.     char            mode32 = QD32COMPATIBLE;
  158.     short           w = (width >> 3) - 1;
  159.     short           e = (width & 0x07) - 1;
  160.     short           h = height - 1;
  161.     
  162.     // Set up pointers to the beginning of the memory to copy
  163.     // and calculate the newline value for the source and destination
  164.     
  165.     src = GetPixBaseAddr( srcMap ) + (long) ((*srcMap)->rowBytes & 0x3fff) * srcPt.v + srcPt.h;
  166.     srcNewline = ((*srcMap)->rowBytes & 0x3fff) - width;
  167.     
  168.     dst = GetPixBaseAddr( dstMap ) + (long) ((*dstMap)->rowBytes & 0x3fff) * dstPt.v + dstPt.h;
  169.     dstNewline = ((*dstMap)->rowBytes & 0x3fff) - width;
  170.  
  171.     // Switch into 32 bit addressing mode
  172.     
  173.     SwapMMUMode( &mode32 );
  174.     
  175.     // Copy the rect from the source to the destination
  176.     
  177.     asm {
  178.     
  179.         MOVE.W     h, D0               ; put height loop variable in D0
  180.         MOVEA.L    src, A0             ; put the source pixmap address in A0
  181.         MOVEA.L    dst, A1             ; put the destination address in A1
  182.         MOVEA.L    mask, A2            ; put the mask address in A2
  183.         CLR.L      D2                  ; clear the mask register
  184.         
  185.     @1:                                ; copy the next row
  186.         MOVE.W     w, D1
  187.         
  188.     @2:                                ; copy the next eight bytes in the row
  189.     
  190.         MOVE.B     (A2)+, D2           ; copy the next mask byte
  191.         BEQ        @nocopy             ; if zero, don't copy anything
  192.         
  193.         CMPI.B     #0xFF, D2
  194.         BNE        @hardway            ; don't copy everything
  195.         
  196.         MOVE.L     (A0)+, (A1)+        ; copy all bytes
  197.         MOVE.L     (A0)+, (A1)+
  198.         
  199.         DBF        D1, @2
  200.         JMP        @endloop
  201.     
  202.     @nocopy:                           ; copy no bytes
  203.         ADDQ.L     #8, A0
  204.         ADDQ.L     #8, A1
  205.         
  206.         DBF        D1, @2
  207.         JMP        @endloop
  208.     
  209.     @hardway:
  210.         LSR.W      #4, D2              ; shift bits 4-7 into bits 0-3
  211.         ADD.W      D2, D2              ; double the index
  212.         ADD.W      @table(D2.W), D2    ; calculate the address
  213.         LEA        @rts1, A3           ; save the return address
  214.         JMP        @table(D2.W)        ; plot four pixels
  215.     @rts1:
  216.         
  217.         MOVE.B     -1(A2), D2          ; copy the next mask byte
  218.         ANDI.B     #0xF, D2            ; mask off the high four bits
  219.         ADD.W      D2, D2              ; double the index
  220.         ADD.W      @table(D2.W), D2    ; calculate the address
  221.         LEA        @rts2, A3           ; save the return address
  222.         JMP        @table(D2.W)        ; plot four pixels
  223.     @rts2:
  224.     
  225.         DBF        D1, @2
  226.         
  227.     @endloop:
  228.     
  229.         TST.W      e
  230.         BLT        @4                  ; continue if e is less than 0
  231.     
  232.         MOVE.B     (A2)+, D2           ; copy the next mask byte
  233.         MOVE.W     e, D1               ; initialize the loop counter
  234.         MOVEQ.L    #7, D3              ; initialize the bit counter
  235.     
  236.     @3:                                ; copy the next byte
  237.         BTST       D3, D2              ; test the next bit in the mask
  238.         BEQ        @skip               ; if zero, continue
  239.         MOVE.B     (A0)+, (A1)+        ; else copy the pixel
  240.         SUBQ.L     #1, D3              ; decrement the bit counter
  241.         DBF        D1, @3
  242.         JMP        @4
  243.     @skip:
  244.         ADDQ.L     #1, A0
  245.         ADDQ.L     #1, A1
  246.         SUBQ.L     #1, D3              ; decrement the bit counter
  247.         DBF        D1, @3
  248.     
  249.     @4:
  250.         ADDA.L     srcNewline, A0      ; bring the src pointer to the start of the next row
  251.         ADDA.L     dstNewline, A1      ; bring the dst pointer to the start of the next row
  252.         
  253.         DBF        D0, @1
  254.         
  255.         JMP        @end                ; skip to the end
  256.         
  257.     @table:
  258.         DC.W       @sub0
  259.         DC.W       @sub1
  260.         DC.W       @sub2
  261.         DC.W       @sub3
  262.         DC.W       @sub4
  263.         DC.W       @sub5
  264.         DC.W       @sub6
  265.         DC.W       @sub7
  266.         DC.W       @sub8
  267.         DC.W       @sub9
  268.         DC.W       @sub10
  269.         DC.W       @sub11
  270.         DC.W       @sub12
  271.         DC.W       @sub13
  272.         DC.W       @sub14
  273.         DC.W       @sub15
  274.     
  275.     @sub0:                            ; mask = 0000, draw nothing
  276.         ADDQ.L     #4, A0
  277.         ADDQ.L     #4, A1
  278.         JMP        (A3)               ; RTS
  279.     
  280.     @sub1:                            ; mask = 0001
  281.         ADDQ.L     #3, A0
  282.         ADDQ.L     #3, A1
  283.         MOVE.B     (A0)+, (A1)+
  284.         JMP        (A3)               ; RTS
  285.     
  286.     @sub2:                            ; mask = 0010
  287.         ADDQ.L     #2, A0
  288.         ADDQ.L     #2, A1
  289.         MOVE.B     (A0), (A1)
  290.         ADDQ.L     #2, A0
  291.         ADDQ.L     #2, A1
  292.         JMP        (A3)               ; RTS
  293.     
  294.     @sub3:                            ; mask = 0011
  295.         ADDQ.L     #2, A0
  296.         ADDQ.L     #2, A1
  297.         MOVE.W     (A0)+, (A1)+
  298.         JMP        (A3)               ; RTS
  299.     
  300.     @sub4:                            ; mask = 0100
  301.         ADDQ.L     #1, A0
  302.         ADDQ.L     #1, A1
  303.         MOVE.B     (A0), (A1)
  304.         ADDQ.L     #3, A0
  305.         ADDQ.L     #3, A1
  306.         JMP        (A3)               ; RTS
  307.     
  308.     @sub5:                            ; mask = 0101
  309.         ADDQ.L     #1, A0
  310.         ADDQ.L     #1, A1
  311.         MOVE.B     (A0), (A1)
  312.         ADDQ.L     #2, A0
  313.         ADDQ.L     #2, A1
  314.         MOVE.B     (A0)+, (A1)+
  315.         JMP        (A3)               ; RTS
  316.     
  317.     @sub6:                            ; mask = 0110
  318.         ADDQ.L     #1, A0
  319.         ADDQ.L     #1, A1
  320.         MOVE.W     (A0), (A1)
  321.         ADDQ.L     #3, A0
  322.         ADDQ.L     #3, A1
  323.         JMP        (A3)               ; RTS
  324.     
  325.     @sub7:                            ; mask = 0111
  326.         ADDQ.L     #1, A0
  327.         ADDQ.L     #1, A1
  328.         MOVE.B     (A0)+, (A1)+
  329.         MOVE.W     (A0)+, (A1)+
  330.         JMP        (A3)               ; RTS
  331.     
  332.     @sub8:                            ; mask = 1000
  333.         MOVE.B     (A0), (A1)
  334.         ADDQ.L     #4, A0
  335.         ADDQ.L     #4, A1
  336.         JMP        (A3)               ; RTS
  337.     
  338.     @sub9:                            ; mask = 1001
  339.         MOVE.B     (A0), (A1)
  340.         ADDQ.L     #3, A0
  341.         ADDQ.L     #3, A1
  342.         MOVE.B     (A0)+, (A1)+
  343.         JMP        (A3)               ; RTS
  344.     
  345.     @sub10:                           ; mask = 1010
  346.         MOVE.B     (A0), (A1)
  347.         ADDQ.L     #2, A0
  348.         ADDQ.L     #2, A1
  349.         MOVE.B     (A0), (A1)
  350.         ADDQ.L     #2, A0
  351.         ADDQ.L     #2, A1
  352.         JMP        (A3)               ; RTS
  353.     
  354.     @sub11:                           ; mask = 1011
  355.         MOVE.B     (A0), (A1)
  356.         ADDQ.L     #2, A0
  357.         ADDQ.L     #2, A1
  358.         MOVE.W     (A0)+, (A1)+
  359.         JMP        (A3)               ; RTS
  360.     
  361.     @sub12:                           ; mask = 1100
  362.         MOVE.W     (A0), (A1)
  363.         ADDQ.L     #4, A0
  364.         ADDQ.L     #4, A1
  365.         JMP        (A3)               ; RTS
  366.     
  367.     @sub13:                           ; mask = 1101
  368.         MOVE.W     (A0), (A1)
  369.         ADDQ.L     #3, A0
  370.         ADDQ.L     #3, A1
  371.         MOVE.B     (A0)+, (A1)+
  372.         JMP        (A3)               ; RTS
  373.     
  374.     @sub14:                           ; mask = 1110
  375.         MOVE.W     (A0)+, (A1)+
  376.         MOVE.B     (A0), (A1)
  377.         ADDQ.L     #2, A0
  378.         ADDQ.L     #2, A1
  379.         JMP        (A3)               ; RTS
  380.     
  381.     @sub15:                           ; mask = 1111
  382.         MOVE.L     (A0)+, (A1)+
  383.         JMP        (A3)               ; RTS
  384.     
  385.     @end:
  386.     
  387.     }
  388.     
  389.     // Switch back to the previous addressing mode
  390.     
  391.     SwapMMUMode( &mode32 );
  392.  
  393. }
  394.  
  395.  
  396.  
  397.  
  398. And this is the extremely long version, truncated for this posting:
  399.  
  400.  
  401. void Quick8CopyMask(
  402.     PixMapHandle    srcMap,
  403.     PixMapHandle    dstMap,
  404.     Ptr             mask,
  405.     Point           srcPt,
  406.     Point           dstPt,
  407.     short           width,
  408.     short           height )
  409. {
  410.  
  411.     register char   *src;
  412.     register char   *dst;
  413.     register long   srcNewline;
  414.     register long   dstNewline;
  415.     char            mode32 = QD32COMPATIBLE;
  416.     short           w = (width >> 3) - 1;
  417.     short           e = (width & 0x07) - 1;
  418.     short           h = height - 1;
  419.     
  420.     // Set up pointers to the beginning of the memory to copy
  421.     // and calculate the newline value for the source and destination
  422.     
  423.     src = GetPixBaseAddr( srcMap ) + (long) ((*srcMap)->rowBytes & 0x3fff) * srcPt.v + srcPt.h;
  424.     srcNewline = ((*srcMap)->rowBytes & 0x3fff) - width;
  425.     
  426.     dst = GetPixBaseAddr( dstMap ) + (long) ((*dstMap)->rowBytes & 0x3fff) * dstPt.v + dstPt.h;
  427.     dstNewline = ((*dstMap)->rowBytes & 0x3fff) - width;
  428.  
  429.     // Switch into 32 bit addressing mode
  430.     
  431.     SwapMMUMode( &mode32 );
  432.     
  433.     // Copy the rect from the source to the destination
  434.     
  435.     asm {
  436.     
  437.         MOVE.W     h, D0               ; put height loop variable in D0
  438.         MOVEA.L    src, A0             ; put the source pixmap address in A0
  439.         MOVEA.L    dst, A1             ; put the destination address in A1
  440.         MOVEA.L    mask, A2            ; put the mask address in A2
  441.         CLR.L      D2                  ; clear the mask register
  442.         
  443.     @1:                                ; copy the next row
  444.         MOVE.W     w, D1
  445.         
  446.     @2:                                ; copy the next eight bytes in the row
  447.     
  448.         CLR.W      D2                  ; clear the mask register
  449.         MOVE.B     (A2)+, D2           ; copy the next mask byte
  450.         BEQ        @nocopy             ; if zero, don't copy anything
  451.         
  452.         CMPI.B     #0xFF, D2
  453.         BNE        @hardway            ; don't copy everything
  454.         
  455.         MOVE.L     (A0)+, (A1)+        ; copy all bytes
  456.         MOVE.L     (A0)+, (A1)+
  457.         
  458.         DBF        D1, @2
  459.         JMP        @endloop
  460.     
  461.     @nocopy:                           ; copy no bytes
  462.         ADDQ.L     #8, A0
  463.         ADDQ.L     #8, A1
  464.         
  465.         DBF        D1, @2
  466.         JMP        @endloop
  467.     
  468.     @hardway:
  469.         ADD.W      D2, D2              ; double the index
  470.         ADD.W      @table(D2.W), D2    ; calculate the address
  471.         JMP        @table(D2.W)        ; plot eight pixels
  472.         
  473.     @endloop:
  474.     
  475.         TST.W      e
  476.         BLT        @4                  ; continue if e is less than 0
  477.     
  478.         MOVE.B     (A2)+, D2           ; copy the next mask byte
  479.         MOVE.W     e, D1               ; initialize the loop counter
  480.         MOVEQ.L    #7, D3              ; initialize the bit counter
  481.     
  482.     @3:                                ; copy the next byte
  483.         BTST       D3, D2              ; test the next bit in the mask
  484.         BEQ        @skip               ; if zero, continue
  485.         MOVE.B     (A0)+, (A1)+        ; else copy the pixel
  486.         SUBQ.L     #1, D3              ; decrement the bit counter
  487.         DBF        D1, @3
  488.         JMP        @4
  489.     @skip:
  490.         ADDQ.L     #1, A0
  491.         ADDQ.L     #1, A1
  492.         SUBQ.L     #1, D3              ; decrement the bit counter
  493.         DBF        D1, @3
  494.     
  495.     @4:
  496.         ADDA.L     srcNewline, A0      ; bring the src pointer to the start of the next row
  497.         ADDA.L     dstNewline, A1      ; bring the dst pointer to the start of the next row
  498.         
  499.         DBF        D0, @1
  500.         
  501.         JMP        @end                ; skip to the end
  502.         
  503.     @table:
  504.         DC.W       @sub0
  505.         DC.W       @sub1
  506.         DC.W       @sub2
  507.         DC.W       @sub3
  508.         .           .
  509.         .           .
  510.         .           .
  511.         DC.W       @sub253
  512.         DC.W       @sub254
  513.         DC.W       @sub255
  514.     
  515.     @sub0:                            ; mask = 00000000
  516.         ADDQ.L     #8, A0
  517.         ADDQ.L     #8, A1
  518.         DBF        D1, @2
  519.         JMP        @endloop
  520.     
  521.     @sub1:                            ; mask = 00000001
  522.         ADDQ.L     #7, A0
  523.         ADDQ.L     #7, A1
  524.         MOVE.B     (A0)+, (A1)+
  525.         DBF        D1, @2
  526.         JMP        @endloop
  527.     
  528.     @sub2:                            ; mask = 00000010
  529.         ADDQ.L     #6, A0
  530.         ADDQ.L     #6, A1
  531.         MOVE.B     (A0), (A1)
  532.         ADDQ.L     #2, A0
  533.         ADDQ.L     #2, A1
  534.         DBF        D1, @2
  535.         JMP        @endloop
  536.     
  537.        .              .
  538.        .              .
  539.        .              .
  540.     
  541.     @sub182:                        ; mask = 10110110
  542.         MOVE.B     (A0), (A1)
  543.         ADDQ.L     #2, A0
  544.         ADDQ.L     #2, A1
  545.         MOVE.W     (A0), (A1)
  546.         ADDQ.L     #3, A0
  547.         ADDQ.L     #3, A1
  548.         MOVE.W     (A0), (A1)
  549.         ADDQ.L     #3, A0
  550.         ADDQ.L     #3, A1
  551.         DBF        D1, @2
  552.         JMP        @endloop
  553.     
  554.     @sub183:                        ; mask = 10110111
  555.         MOVE.B     (A0), (A1)
  556.         ADDQ.L     #2, A0
  557.         ADDQ.L     #2, A1
  558.         MOVE.W     (A0), (A1)
  559.         ADDQ.L     #3, A0
  560.         ADDQ.L     #3, A1
  561.         MOVE.B     (A0)+, (A1)+
  562.         MOVE.W     (A0)+, (A1)+
  563.         DBF        D1, @2
  564.         JMP        @endloop
  565.     
  566.        .             .
  567.        .             .
  568.        .             .
  569.     
  570.     @sub253:                        ; mask = 11111101
  571.         MOVE.L     (A0)+, (A1)+
  572.         MOVE.W     (A0), (A1)
  573.         ADDQ.L     #3, A0
  574.         ADDQ.L     #3, A1
  575.         MOVE.B     (A0)+, (A1)+
  576.         DBF        D1, @2
  577.         JMP        @endloop
  578.     
  579.     @sub254:                        ; mask = 11111110
  580.         MOVE.L     (A0)+, (A1)+
  581.         MOVE.W     (A0)+, (A1)+
  582.         MOVE.B     (A0), (A1)
  583.         ADDQ.L     #2, A0
  584.         ADDQ.L     #2, A1
  585.         DBF        D1, @2
  586.         JMP        @endloop
  587.     
  588.     @sub255:                        ; mask = 11111111
  589.         MOVE.L     (A0)+, (A1)+
  590.         MOVE.L     (A0)+, (A1)+
  591.         DBF        D1, @2
  592.         JMP        @endloop
  593.     
  594.     @end:
  595.     
  596.     }
  597.     
  598.     // Switch back to the previous addressing mode
  599.     
  600.     SwapMMUMode( &mode32 );
  601.  
  602. }
  603.  
  604.  
  605. -- 
  606. _____________________________________________________________________________
  607. Michael A. Kelly                                               Senior Partner
  608. mkelly@cs.uoregon.edu                                      High Risk Ventures
  609. _____________________________________________________________________________
  610.