home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / sys / sun / misc / 3255 < prev    next >
Encoding:
Internet Message Format  |  1992-07-27  |  24.8 KB

  1. Xref: sparky comp.sys.sun.misc:3255 comp.sys.sun.apps:1434
  2. Path: sparky!uunet!munnari.oz.au!yoyo.aarnet.edu.au!sirius.ucs.adelaide.edu.au!winnie.cs.adelaide.edu.au
  3. From: gordoni@winnie.cs.adelaide.edu.au (Gordon Irlam)
  4. Newsgroups: comp.sys.sun.misc,comp.sys.sun.apps
  5. Subject: Re: Zeroing memory, quickly.
  6. Message-ID: <7871@sirius.ucs.adelaide.edu.au>
  7. Date: 21 Jul 92 08:28:10 GMT
  8. Sender: news@ucs.adelaide.edu.au
  9. Reply-To: gordoni@cs.adelaide.edu.au
  10. Followup-To: comp.sys.sun.misc
  11. Lines: 950
  12. Nntp-Posting-Host: winnie.cs.adelaide.edu.au
  13.  
  14. > Hi,
  15. >     I'm looking for a really fast way for zeroing (clearing) a
  16. > section of memory. Same functionality as bzero(), basically; but as
  17. > fast as possible. I have an application that needs to clear lots of 
  18. > memory; and the bzero() is the biggest time hog in it. 
  19.  
  20. I wrote VERY heavily optimized versions of bcopy() and bzero() a few
  21. years back for an experimental SPARC system we were developing.
  22.  
  23. The routines also seem to work fairly well on various Sun systems.
  24. Although they have not been optimized for Suns.
  25.  
  26. The minimal write buffer on the SPARCstation 1 means that for this
  27. machine the code can probably be improved considerably by splitting up
  28. adjacent stores.  For machines with write-through caches (all
  29. currently available SPARCstations) the code probably carries loop
  30. unrolling to excess - write buffer stalls limit the potential gains of
  31. unrolling.
  32.  
  33. I don't have any times for bzero(), and they probably aren't quite as
  34. impressive, but on a SPARCstation 2 my bcopy() typically consumes 50%
  35. to 60% of the time of Sun's libc version - depending upon whether the
  36. data is cached or not.
  37.  
  38. Warning: Readability was totally sacrificed in the pursuit of speed.
  39. This was on account of simulated bcopy()'s/bzero()'s constituting the
  40. prime bottleneck during the simulated bootstraping of the kernel we
  41. were porting.
  42.  
  43. Code suplied, just add water.
  44.  
  45.                                          Gordon Irlam
  46.                                          (gordoni@cs.adelaide.edu.au)
  47.  
  48.  
  49. *** IMPORTANT NOTE ***
  50. It is University policy to protect its intellectual property.
  51. Consequently use of the following code in commercial products requires
  52. permission.  Use of this code for non-commercial purposes is
  53. permitted.
  54. *** END IMPORTANT NOTE ***
  55.  
  56. [Yes this is silly for something as trivial as this, but their is
  57. little I can do about it, sorry.]
  58.  
  59. ----------------------------- cut here ----------------------------
  60.  
  61. /**************************************************************************
  62. ** Actor =
  63. **
  64. ** Component = Libraries
  65. ** Module = SPARC/memset.x
  66. ** 
  67. ** Synopsis = System V memset.
  68. **
  69. ** Originally written by = Gordon Irlam
  70. ** Responsible = Gordon Irlam
  71. **
  72. ** Copyright (c) 1990 Department of Computer Science, Adelaide University
  73. **
  74. ***************************************************************************
  75. ** $Header: /usr/home/projects/mars/people/gordoni/rcs.files/chorus/chorus_3.2/lib/SPARC/RCS/utMemSet.x,v 1.2 90/09/10 14:11:30 gordoni Exp $
  76. ***************************************************************************
  77. * The interface between assembly code and C code follows the Sparc register
  78. * conventions.  This requires the caller to place parameters in %o0 through
  79. * %o5.  The return value, if any is returned in %o0.  Register %o6 is the stack
  80. * pointer, and %o7 stores the return address.
  81. *
  82. * The callee can use %o0 through %o5, and %g1 through %g3 for scrach values.
  83. * Registers %g4 through %g7 must never be used.  Register %o6 must always
  84. * contain a pointer to the current top of the stack.  All other registers can
  85. * be used only if they are restored prior to return.
  86. *
  87. * The stack grows downwards and the stack pointer must be double word aligned.
  88. * On the top of the stack is space for the operating system to store the 16 in
  89. * and local registers currently used.  This is performed on window overflow,
  90. * and context switch.  Below this is a word used to hold the address at which
  91. * structure return values should be stored.  This is followed by six words that
  92. * can be used by the called routine to store the first six arguments it was
  93. * passed in registers.  This is followed by any additional arguments that are
  94. * passed.
  95. */
  96.  
  97. ! Exported symbols.
  98. .global    _memset            ! ANSI C memory fill.
  99.  
  100. /***************************************************************************
  101. * void *memset(void *s, int c, int n): Fill the first n bytes starting at s
  102. * with the value c.  Return s.
  103. ***************************************************************************
  104. */
  105.  
  106. _memset:
  107.     tst    %o2        ! Finished if n < 0.
  108.     bneg    fill_done
  109.     mov    %o0, %o3    ! Current s in %o3 (delay slot).
  110.     cmp    %o2, 7
  111.     ble    last_fill    ! Make sure can fill to a double word boundary.
  112.  
  113.     ! Fill byte by byte until reach double word boundary.
  114.     btst    7, %o3        ! Delay slot.
  115.     be,a    big_fill
  116.     nop
  117.  
  118. first_chunk:
  119.     stb    %o1, [%o3]    ! Fill byte.
  120.     inc    %o3
  121.     btst    7, %o3
  122.     bne    first_chunk
  123.     dec    %o2        ! Delay slot.
  124.  
  125. big_fill:
  126.     ! Fill %o4 and %o5 with the fill value.
  127.     and    %o1, 0xff, %o1    ! Make sure fill value is a single byte.
  128.     sll    %o1, 8, %o4
  129.     or    %o4, %o1, %o4    ! Fill value in low halfword of %04
  130.     sll    %o4, 16, %o5
  131.     or    %o4, %o5, %o4    ! Fill value in entire word of %o4.
  132.     mov    %o4, %o5
  133.  
  134.     deccc    64, %o2        ! See if can fill a 64 byte chunk.
  135.     bneg,a    small_fill
  136.     inc    64, %o2        ! Delay slot.
  137.  
  138. big_chunk:
  139.     std    %o4, [%o3 +  0]    ! Fill a 64 byte chunk.
  140.     std    %o4, [%o3 +  8]
  141.     std    %o4, [%o3 + 16]
  142.     std    %o4, [%o3 + 24]
  143.     std    %o4, [%o3 + 32]
  144.     std    %o4, [%o3 + 40]
  145.     std    %o4, [%o3 + 48]
  146.     deccc    64, %o2
  147.     std    %o4, [%o3 + 56]
  148.     bpos    big_chunk
  149.     inc    64, %o3        ! Delay slot.
  150.     inc    64, %o2
  151.  
  152. small_fill:
  153.     deccc    8, %o2        ! See if can fill an 8 byte chunk.
  154.     bneg,a    last_fill
  155.     inc    8, %o2        ! Delay slot.
  156.  
  157. small_chunk:
  158.     deccc    8, %o2
  159.     std    %o4, [%o3 +  0]    ! Fill an 8 byte chunk.
  160.     bpos    small_chunk
  161.     inc    8, %o3        ! Delay slot.
  162.     inc    8, %o2
  163.  
  164. last_fill:
  165.     deccc    %o2        ! See if can fill next byte.
  166.     bneg,a    fill_done
  167.     nop
  168.  
  169. last_chunk:
  170.     deccc    %o2
  171.     stb    %o1, [%o3]    ! Fill byte.
  172.     bpos,a    last_chunk
  173.     inc    %o3        ! Delay slot.
  174.  
  175. fill_done:
  176.     retl            ! Return value will still be in %o0.
  177.     nop
  178.  
  179. ----------------------------- cut here ----------------------------
  180.  
  181. /**************************************************************************
  182. ** Actor =
  183. **
  184. ** Component = Libraries
  185. ** Module = SPARC/memmove.x
  186. ** 
  187. ** Synopsis = System V memmove.
  188. **
  189. ** Originally written by = Gordon Irlam
  190. ** Responsible = Gordon Irlam
  191. **
  192. ** Copyright (c) 1990 Department of Computer Science, Adelaide University
  193. **
  194. ***************************************************************************
  195. ** $Header: /a/berlioz/ed/projects/mars/people/gordoni/rcs.files/chorus/chorus_3.2/lib/SPARC/RCS/utMemMove.x,v 1.3 90/09/27 18:18:40 gordoni Exp $
  196. ***************************************************************************
  197. * The interface between assembly code and C code follows the Sparc register
  198. * conventions.  This requires the caller to place parameters in %o0 through
  199. * %o5.  The return value, if any is returned in %o0.  Register %o6 is the stack
  200. * pointer, and %o7 stores the return address.
  201. *
  202. * The callee can use %o0 through %o5, and %g1 through %g3 for scrach values.
  203. * Registers %g4 through %g7 must never be used.  Register %o6 must always
  204. * contain a pointer to the current top of the stack.  All other registers can
  205. * be used only if they are restored prior to return.
  206. *
  207. * The stack grows downwards and the stack pointer must be double word aligned.
  208. * On the top of the stack is space for the operating system to store the 16 in
  209. * and local registers currently used.  This is performed on window overflow,
  210. * and context switch.  Below this is a word used to hold the address at which
  211. * structure return values should be stored.  This is followed by six words that
  212. * can be used by the called routine to store the first six arguments it was
  213. * passed in registers.  This is followed by any additional arguments that are
  214. * passed.
  215. */
  216.  
  217. ! Exported symbols.
  218. .global    _memmove        ! ANSI C Overlapping memory copy.
  219.  
  220. /***************************************************************************
  221. * void *memmove(void *dest, void *src, int n): Copy n bytes from src to dest.
  222. * Safe to use even if memory areas overlap.  Return dest.
  223. ***************************************************************************
  224. */
  225.  
  226. _memmove:
  227.     tst    %o2        ! Finished if n <= 0.
  228.     ble    copy_done
  229.     cmp    %o0, %o1    ! Copy backwards if dest >= src.
  230.     bgeu    bwd_copy
  231.     cmp    %o2, 7        ! Delay slot.
  232.     ble    fwd_last_copy    ! Make sure can copy first few bytes.
  233.     mov    %o0, %o3    ! Current destination in %o3 (delay slot).
  234.  
  235.     ! Copy slowly until reach word boundary for source.
  236.     btst    3, %o1        ! Delay slot.
  237.     be    fwd_third_copy
  238.     btst    1, %o1        ! Delay slot.
  239.     be,a    fwd_second_copy
  240.     lduh    [%o1], %o4    ! Delay slot.
  241.  
  242.     ldub    [%o1], %o4    ! Copy byte.
  243.     inc    %o1
  244.     stb    %o4, [%o3]
  245.     inc    %o3
  246.     btst    3, %o1
  247.     be    fwd_third_copy
  248.     dec    %o2        ! Delay slot.
  249.  
  250.     lduh    [%o1], %o4    ! Copy half word.
  251. fwd_second_copy:
  252.     inc    2, %o1
  253.     srl    %o4, 8, %o5
  254.     stb    %o5, [%o3 + 0]
  255.     stb    %o4, [%o3 + 1]
  256.     inc    2, %o3
  257.     dec    2, %o2
  258.  
  259. fwd_third_copy:
  260.     btst    3, %o3
  261.     beq    fwd_word_copy    ! Destination mod 4 = 0.
  262.     btst    4, %o3        ! Delay slot.
  263.  
  264.     ! Copy next word if destination is in low half of a double word.
  265.     bne,a    fwd_test_alignment
  266.     deccc    32 + 4, %o2    ! Delay slot.
  267.  
  268.     ld    [%o1], %o4    ! Copy word.
  269.     inc    4, %o1
  270.     srl    %o4, 24, %g3
  271.     srl    %o4, 16, %g2
  272.     srl    %o4, 8, %o5
  273.     stb    %g3, [%o3 + 0]
  274.     stb    %g2, [%o3 + 1]
  275.     stb    %o5, [%o3 + 2]
  276.     stb    %o4, [%o3 + 3]
  277.     inc    4, %o3
  278.  
  279.     deccc    32 + 4 + 4, %o2    ! See if can copy a 32 + 4 byte chunk.
  280. fwd_test_alignment:
  281.     bneg,a    fwd_small_byte_copy
  282.     inc    32 + 4, %o2    ! Delay slot.
  283.     ! Call appropriate routine according to alignment of destination.
  284.     btst    1, %o3
  285.     beq    fwd_byte_2_copy    ! Destination mod 4 = 2.
  286.     btst    2, %o3
  287.     beq,a    fwd_byte_1_copy    ! Destination mod 4 = 1.
  288.     nop
  289.     ba,a    fwd_byte_3_copy    ! Destination mod 4 = 3.
  290.  
  291. fwd_word_copy:
  292.     ! Copy slowly until destination is double word aligned.
  293.     beq,a    fwd_word_test_alignment
  294.     deccc    64, %o2        ! See if can copy a 64 byte chunk (delay slot).
  295.  
  296.     ld    [%o1], %o4    ! Copy word.
  297.     inc    4, %o1
  298.     st    %o4, [%o3]
  299.     inc    4, %o3
  300.     deccc    64 + 4, %o2    ! See if can copy a 64 byte chunk.
  301.  
  302. fwd_word_test_alignment:
  303.     bneg,a    fwd_small_word_copy
  304.     inccc    64 - 8, %o2    ! See if can fill an 8 byte chunk (delay slot).
  305.     btst    7, %o1
  306.     beq,a    fwd_doubleword_chunk
  307.     nop
  308.  
  309. fwd_word_chunk:
  310.     ld    [%o1 +  0], %o4    ! Copy a 64 byte chunk.
  311.     ld    [%o1 +  4], %o5
  312.     ld    [%o1 +  8], %g2
  313.     ld    [%o1 + 12], %g3
  314.     std    %o4, [%o3 +  0]
  315.     std    %g2, [%o3 +  8]
  316.     ld    [%o1 + 16], %o4
  317.     ld    [%o1 + 20], %o5
  318.     ld    [%o1 + 24], %g2
  319.     ld    [%o1 + 28], %g3
  320.     std    %o4, [%o3 + 16]
  321.     std    %g2, [%o3 + 24]
  322.     ld    [%o1 + 32], %o4
  323.     ld    [%o1 + 36], %o5
  324.     ld    [%o1 + 40], %g2
  325.     ld    [%o1 + 44], %g3
  326.     std    %o4, [%o3 + 32]
  327.     std    %g2, [%o3 + 40]
  328.     ld    [%o1 + 48], %o4
  329.     ld    [%o1 + 52], %o5
  330.     ld    [%o1 + 56], %g2
  331.     ld    [%o1 + 60], %g3
  332.     std    %o4, [%o3 + 48]
  333.     std    %g2, [%o3 + 56]
  334.     deccc    64, %o2
  335.     inc    64, %o1
  336.     bpos    fwd_word_chunk
  337.     inc    64, %o3        ! Delay slot.
  338.     ba    fwd_small_word_copy
  339.     inccc    64 - 8, %o2    ! See if can fill an 8 byte chunk (delay slot).
  340.  
  341. fwd_doubleword_chunk:
  342.     ldd    [%o1 +  0], %o4    ! Copy a 64 byte chunk.
  343.     ldd    [%o1 +  8], %g2
  344.     std    %o4, [%o3 +  0]
  345.     std    %g2, [%o3 +  8]
  346.     ldd    [%o1 + 16], %o4
  347.     ldd    [%o1 + 24], %g2
  348.     std    %o4, [%o3 + 16]
  349.     std    %g2, [%o3 + 24]
  350.     ldd    [%o1 + 32], %o4
  351.     ldd    [%o1 + 40], %g2
  352.     std    %o4, [%o3 + 32]
  353.     std    %g2, [%o3 + 40]
  354.     ldd    [%o1 + 48], %o4
  355.     ldd    [%o1 + 56], %g2
  356.     std    %o4, [%o3 + 48]
  357.     std    %g2, [%o3 + 56]
  358.     deccc    64, %o2
  359.     inc    64, %o1
  360.     bpos    fwd_doubleword_chunk
  361.     inc    64, %o3        ! Delay slot.
  362.     inccc    64 - 8, %o2    ! See if can fill an 8 byte chunk.
  363.  
  364. fwd_small_word_copy:
  365.     bneg,a    fwd_last_copy_tested
  366.     inccc    8, %o2        ! See if can copy next byte (delay slot).
  367.  
  368. fwd_small_word_chunk:
  369.     ld    [%o1 + 0], %o4    ! Copy an 8 byte chunk.
  370.     ld    [%o1 + 4], %o5
  371.     deccc    8, %o2
  372.     std    %o4, [%o3]
  373.     inc    8, %o1
  374.     bpos    fwd_small_word_chunk
  375.     inc    8, %o3        ! Delay slot.
  376.     inc    8, %o2
  377.  
  378. fwd_last_copy:
  379.     tst    %o2        ! See if can copy next byte.
  380.  
  381. fwd_last_copy_tested:
  382.     ble    copy_done
  383.  
  384. fwd_last_chunk:
  385.     deccc    2, %o2        ! Delay slot.
  386.     ldub    [%o1 + 0], %o4    ! Copy byte.
  387.     bneg    copy_done
  388.     stb    %o4, [%o3 + 0]    ! Delay slot.
  389.     ldub    [%o1 + 1], %o4    ! Copy byte.
  390.     inc    2, %o1
  391.     stb    %o4, [%o3 + 1]
  392.     bne,a    fwd_last_chunk
  393.     inc    2, %o3        ! Delay slot.
  394.     retl            ! Return value will still be in %o0.
  395.     nop
  396.  
  397. fwd_small_byte_copy:
  398.     deccc    8, %o2        ! See if can fill an 8 byte chunk.
  399.     bneg,a    fwd_last_copy_tested
  400.     inccc    8, %o2        ! See if can copy next byte (delay slot).
  401.  
  402. fwd_small_byte_chunk:
  403.     ld    [%o1 + 0], %o4    ! Copy an 8 byte chunk.
  404.     ld    [%o1 + 4], %o5
  405.     srl    %o4, 24, %g2
  406.     srl    %o4, 16, %g3
  407.     stb    %g2, [%o3 + 0]
  408.     srl    %o4, 8, %g2
  409.     stb    %g3, [%o3 + 1]
  410.     stb    %g2, [%o3 + 2]
  411.     stb    %o4, [%o3 + 3]
  412.     srl    %o5, 24, %g2
  413.     srl    %o5, 16, %g3
  414.     stb    %g2, [%o3 + 4]
  415.     srl    %o5, 8, %g2
  416.     stb    %g3, [%o3 + 5]
  417.     stb    %g2, [%o3 + 6]
  418.     stb    %o5, [%o3 + 7]
  419.     inc    8, %o1
  420.     ba    fwd_small_byte_copy
  421.     inc    8, %o3        ! Delay slot.
  422.  
  423. fwd_byte_1_copy:
  424.     ld    [%o1], %o4    ! Load first 4 bytes.
  425.     srl    %o4, 24, %g2
  426.     srl    %o4, 8, %g3
  427.     sll    %o4, 24, %g1    ! Last byte in top part of %g1.
  428.     stb    %g2, [%o3 + 0]    ! Store first 3 bytes.
  429.     sth    %g3, [%o3 + 1]
  430.     inc    4, %o1
  431.     inc    4, %o3
  432.  
  433. fwd_byte_1_chunk:
  434.     ld    [%o1 +  0], %o4    ! Copy a 32 byte chunk.
  435.     ld    [%o1 +  4], %o5
  436.     deccc    32, %o2
  437.     srl    %o4, 8, %g2    ! First 3 bytes in %g2.
  438.     or    %g2, %g1, %g2    ! Add top byte in %g1 from previous cycle.
  439.     sll    %o4, 24, %o4    ! Fourth byte in high part of %o4.
  440.     srl    %o5, 8, %g3    ! Next 3 bytes in low part of %g3.
  441.     or    %o4, %g3, %g3    ! Add fourth byte from %o4.
  442.     sll    %o5, 24, %g1    ! Save last byte in %g1 for next cycle.
  443.     ld    [%o1 +  8], %o4
  444.     ld    [%o1 + 12], %o5
  445.     std    %g2, [%o3 +  0 - 1]
  446.     srl    %o4, 8, %g2
  447.     or    %g2, %g1, %g2
  448.     sll    %o4, 24, %o4
  449.     srl    %o5, 8, %g3
  450.     or    %o4, %g3, %g3
  451.     sll    %o5, 24, %g1
  452.     ld    [%o1 + 16], %o4
  453.     ld    [%o1 + 20], %o5
  454.     std    %g2, [%o3 +  8 - 1]
  455.     srl    %o4, 8, %g2
  456.     or    %g2, %g1, %g2
  457.     sll    %o4, 24, %o4
  458.     srl    %o5, 8, %g3
  459.     or    %o4, %g3, %g3
  460.     sll    %o5, 24, %g1
  461.     ld    [%o1 + 24], %o4
  462.     ld    [%o1 + 28], %o5
  463.     std    %g2, [%o3 + 16 - 1]
  464.     srl    %o4, 8, %g2
  465.     or    %g2, %g1, %g2
  466.     sll    %o4, 24, %o4
  467.     srl    %o5, 8, %g3
  468.     or    %o4, %g3, %g3
  469.     sll    %o5, 24, %g1
  470.     std    %g2, [%o3 + 24 - 1]
  471.     inc    32, %o1
  472.     bpos    fwd_byte_1_chunk
  473.     inc    32, %o3        ! Delay slot.
  474.     inc    32, %o2
  475.     srl    %g1, 24, %g1
  476.     ba    fwd_small_byte_copy
  477.     stb    %g1, [%o3 - 1]    ! Store last byte (delay slot).
  478.  
  479. fwd_byte_2_copy:
  480.     ld    [%o1], %o4    ! Load first 4 bytes.
  481.     srl    %o4, 16, %g3
  482.     sll    %o4, 16, %g1    ! Second 2 bytes in top half of %g1.
  483.     sth    %g3, [%o3]    ! Store first 2 bytes.
  484.     inc    4, %o1
  485.     inc    4, %o3
  486.  
  487. fwd_byte_2_chunk:
  488.     ld    [%o1 +  0], %o4    ! Copy a 32 byte chunk.
  489.     ld    [%o1 +  4], %o5
  490.     deccc    32, %o2
  491.     srl    %o4, 16, %g2    ! First 2 bytes in %g2.
  492.     or    %g2, %g1, %g2    ! Add top 2 bytes in %g1 from previous cycle.
  493.     sll    %o4, 16, %o4    ! Second 2 bytes in high part of %o4.
  494.     srl    %o5, 16, %g3    ! Third 2 bytes in low part of %g3.
  495.     or    %o4, %g3, %g3    ! Add second 2 bytes from %o4.
  496.     sll    %o5, 16, %g1    ! Save last 2 bytes in %g1 for next cycle.
  497.     ld    [%o1 +  8], %o4
  498.     ld    [%o1 + 12], %o5
  499.     std    %g2, [%o3 +  0 - 2]
  500.     srl    %o4, 16, %g2
  501.     or    %g2, %g1, %g2
  502.     sll    %o4, 16, %o4
  503.     srl    %o5, 16, %g3
  504.     or    %o4, %g3, %g3
  505.     sll    %o5, 16, %g1
  506.     ld    [%o1 + 16], %o4
  507.     ld    [%o1 + 20], %o5
  508.     std    %g2, [%o3 +  8 - 2]
  509.     srl    %o4, 16, %g2
  510.     or    %g2, %g1, %g2
  511.     sll    %o4, 16, %o4
  512.     srl    %o5, 16, %g3
  513.     or    %o4, %g3, %g3
  514.     sll    %o5, 16, %g1
  515.     ld    [%o1 + 24], %o4
  516.     ld    [%o1 + 28], %o5
  517.     std    %g2, [%o3 + 16 - 2]
  518.     srl    %o4, 16, %g2
  519.     or    %g2, %g1, %g2
  520.     sll    %o4, 16, %o4
  521.     srl    %o5, 16, %g3
  522.     or    %o4, %g3, %g3
  523.     sll    %o5, 16, %g1
  524.     std    %g2, [%o3 + 24 - 2]
  525.     inc    32, %o1
  526.     bpos    fwd_byte_2_chunk
  527.     inc    32, %o3        ! Delay slot.
  528.     inc    32, %o2
  529.     srl    %g1, 16, %g1
  530.     ba    fwd_small_byte_copy
  531.     sth    %g1, [%o3 - 2]    ! Store last 2 bytes (delay slot).
  532.  
  533. fwd_byte_3_copy:
  534.     ld    [%o1], %o4    ! Load first 4 bytes.
  535.     srl    %o4, 24, %g2
  536.     sll    %o4, 8, %g1    ! Last 3 bytes in top part of %g1.
  537.     stb    %g2, [%o3 + 0]    ! Store first byte.
  538.     inc    4, %o1
  539.     inc    4, %o3
  540.  
  541. fwd_byte_3_chunk:
  542.     ld    [%o1 +  0], %o4    ! Copy a 32 byte chunk.
  543.     ld    [%o1 +  4], %o5
  544.     deccc    32, %o2
  545.     srl    %o4, 24, %g2    ! First byte in %g2.
  546.     or    %g2, %g1, %g2    ! Add top 3 bytes in %g1 from previous cycle.
  547.     sll    %o4, 8, %o4    ! Next 3 bytes in high part of %o4.
  548.     srl    %o5, 24, %g3    ! Next byte in low part of %g3.
  549.     or    %o4, %g3, %g3    ! Add 3 bytes from %o4.
  550.     sll    %o5, 8, %g1    ! Save last 3 bytes in %g1 for next cycle.
  551.     ld    [%o1 +  8], %o4
  552.     ld    [%o1 + 12], %o5
  553.     std    %g2, [%o3 +  0 - 3]
  554.     srl    %o4, 24, %g2
  555.     or    %g2, %g1, %g2
  556.     sll    %o4, 8, %o4
  557.     srl    %o5, 24, %g3
  558.     or    %o4, %g3, %g3
  559.     sll    %o5, 8, %g1
  560.     ld    [%o1 + 16], %o4
  561.     ld    [%o1 + 20], %o5
  562.     std    %g2, [%o3 +  8 - 3]
  563.     srl    %o4, 24, %g2
  564.     or    %g2, %g1, %g2
  565.     sll    %o4, 8, %o4
  566.     srl    %o5, 24, %g3
  567.     or    %o4, %g3, %g3
  568.     sll    %o5, 8, %g1
  569.     ld    [%o1 + 24], %o4
  570.     ld    [%o1 + 28], %o5
  571.     std    %g2, [%o3 + 16 - 3]
  572.     srl    %o4, 24, %g2
  573.     or    %g2, %g1, %g2
  574.     sll    %o4, 8, %o4
  575.     srl    %o5, 24, %g3
  576.     or    %o4, %g3, %g3
  577.     sll    %o5, 8, %g1
  578.     std    %g2, [%o3 + 24 - 3]
  579.     inc    32, %o1
  580.     bpos    fwd_byte_3_chunk
  581.     inc    32, %o3        ! Delay slot.
  582.     inc    32, %o2
  583.     srl    %g1, 16, %g2
  584.     srl    %g1, 8, %g1
  585.     sth    %g2, [%o3 - 3]    ! Store last 3 bytes.
  586.     ba    fwd_small_byte_copy
  587.     stb    %g1, [%o3 - 1]    ! Delay slot.
  588.  
  589. bwd_copy:
  590.     add    %o1, %o2, %o1    ! Start from other end.
  591.     ble    bwd_last_copy    ! Make sure can copy first few bytes.
  592.     add    %o0, %o2, %o3    ! Current destination in %o3 (delay slot).
  593.  
  594.     ! Copy slowly until reach word boundary for source.
  595.     btst    3, %o1        ! Delay slot.
  596.     be    bwd_third_copy
  597.     btst    1, %o1        ! Delay slot.
  598.     be,a    bwd_second_copy
  599.     lduh    [%o1 - 2], %o4    ! Delay slot.
  600.  
  601.     ldub    [%o1 - 1], %o4    ! Copy byte.
  602.     dec    %o1
  603.     stb    %o4, [%o3 - 1]
  604.     dec    %o3
  605.     btst    3, %o1
  606.     be    bwd_third_copy
  607.     dec    %o2        ! Delay slot.
  608.  
  609.     lduh    [%o1 - 2], %o4    ! Copy half word.
  610. bwd_second_copy:
  611.     dec    2, %o1
  612.     srl    %o4, 8, %o5
  613.     stb    %o4, [%o3 - 1]
  614.     stb    %o5, [%o3 - 2]
  615.     dec    2, %o3
  616.     dec    2, %o2
  617.  
  618. bwd_third_copy:
  619.     btst    3, %o3
  620.     beq    bwd_word_copy    ! Destination mod 4 = 0.
  621.     btst    4, %o3        ! Delay slot.
  622.  
  623.     ! Copy next word if destination is in high half of a double word.
  624.     beq,a    bwd_test_alignment
  625.     deccc    32 + 4, %o2    ! Delay slot.
  626.  
  627.     ld    [%o1 - 4], %o4    ! Copy word.
  628.     dec    4, %o1
  629.     srl    %o4, 8, %o5
  630.     srl    %o4, 16, %g2
  631.     srl    %o4, 24, %g3
  632.     stb    %o4, [%o3 - 1]
  633.     stb    %o5, [%o3 - 2]
  634.     stb    %g2, [%o3 - 3]
  635.     stb    %g3, [%o3 - 4]
  636.     dec    4, %o3
  637.  
  638.     deccc    32 + 4 + 4, %o2    ! See if can copy a 32 + 4 byte chunk.
  639. bwd_test_alignment:
  640.     bneg,a    bwd_small_byte_copy
  641.     inc    32 + 4, %o2    ! Delay slot.
  642.     ! Call appropriate routine according to alignment of dest.
  643.     btst    1, %o3
  644.     beq    bwd_byte_2_copy    ! Destination mod 4 = 2.
  645.     btst    2, %o3
  646.     beq,a    bwd_byte_1_copy    ! Destination mod 4 = 1.
  647.     nop
  648.     ba,a    bwd_byte_3_copy    ! Destination mod 4 = 3.
  649.  
  650. bwd_word_copy:
  651.     ! Copy slowly until destination is double word aligned.
  652.     beq,a    bwd_word_test_alignment
  653.     deccc    64, %o2        ! See if can copy a 64 byte chunk (delay slot).
  654.  
  655.     ld    [%o1 - 4], %o4    ! Copy word.
  656.     dec    4, %o1
  657.     st    %o4, [%o3 - 4]
  658.     dec    4, %o3
  659.     deccc    64 + 4, %o2    ! See if can copy a 64 byte chunk.
  660.  
  661. bwd_word_test_alignment:
  662.     bneg,a    bwd_small_word_copy
  663.     inccc    64 - 8, %o2    ! See if can fill an 8 byte chunk (delay slot).
  664.     btst    7, %o1
  665.     beq,a    bwd_doubleword_chunk
  666.     nop
  667.  
  668. bwd_word_chunk:
  669.     ld    [%o1 -  4], %o5    ! Copy a 64 byte chunk.
  670.     ld    [%o1 -  8], %o4
  671.     ld    [%o1 - 12], %g3
  672.     ld    [%o1 - 16], %g2
  673.     std    %o4, [%o3 -  8]
  674.     std    %g2, [%o3 - 16]
  675.     ld    [%o1 - 20], %o5
  676.     ld    [%o1 - 24], %o4
  677.     ld    [%o1 - 28], %g3
  678.     ld    [%o1 - 32], %g2
  679.     std    %o4, [%o3 - 24]
  680.     std    %g2, [%o3 - 32]
  681.     ld    [%o1 - 36], %o5
  682.     ld    [%o1 - 40], %o4
  683.     ld    [%o1 - 44], %g3
  684.     ld    [%o1 - 48], %g2
  685.     std    %o4, [%o3 - 40]
  686.     std    %g2, [%o3 - 48]
  687.     ld    [%o1 - 52], %o5
  688.     ld    [%o1 - 56], %o4
  689.     ld    [%o1 - 60], %g3
  690.     ld    [%o1 - 64], %g2
  691.     std    %o4, [%o3 - 56]
  692.     std    %g2, [%o3 - 64]
  693.     deccc    64, %o2
  694.     dec    64, %o1
  695.     bpos    bwd_word_chunk
  696.     dec    64, %o3        ! Delay slot.
  697.     ba    bwd_small_word_copy
  698.     inccc    64 - 8, %o2    ! See if can fill an 8 byte chunk (delay slot).
  699.  
  700. bwd_doubleword_chunk:
  701.     ldd    [%o1 -  8], %o4    ! Copy a 64 byte chunk.
  702.     ldd    [%o1 - 16], %g2
  703.     std    %o4, [%o3 -  8]
  704.     std    %g2, [%o3 - 16]
  705.     ldd    [%o1 - 24], %o4
  706.     ldd    [%o1 - 32], %g2
  707.     std    %o4, [%o3 - 24]
  708.     std    %g2, [%o3 - 32]
  709.     ldd    [%o1 - 40], %o4
  710.     ldd    [%o1 - 48], %g2
  711.     std    %o4, [%o3 - 40]
  712.     std    %g2, [%o3 - 48]
  713.     ldd    [%o1 - 56], %o4
  714.     ldd    [%o1 - 64], %g2
  715.     std    %o4, [%o3 - 56]
  716.     std    %g2, [%o3 - 64]
  717.     deccc    64, %o2
  718.     dec    64, %o1
  719.     bpos    bwd_doubleword_chunk
  720.     dec    64, %o3        ! Delay slot.
  721.     inccc    64 - 8, %o2    ! See if can fill an 8 byte chunk.
  722.  
  723. bwd_small_word_copy:
  724.     bneg,a    bwd_last_copy_tested
  725.     inccc    8, %o2        ! See if can copy next byte (delay slot).
  726.  
  727. bwd_small_word_chunk:
  728.     ld    [%o1 - 4], %o5    ! Copy an 8 byte chunk.
  729.     ld    [%o1 - 8], %o4
  730.     deccc    8, %o2
  731.     std    %o4, [%o3 - 8]
  732.     dec    8, %o1
  733.     bpos    bwd_small_word_chunk
  734.     dec    8, %o3        ! Delay slot.
  735.     inc    8, %o2
  736.  
  737. bwd_last_copy:
  738.     tst    %o2        ! See if can copy next byte.
  739.  
  740. bwd_last_copy_tested:
  741.     ble    copy_done
  742.  
  743. bwd_last_chunk:
  744.     deccc    2, %o2        ! Delay slot.
  745.     ldub    [%o1 - 1], %o4    ! Copy byte.
  746.     bneg    copy_done
  747.     stb    %o4, [%o3 - 1]    ! Delay slot.
  748.     ldub    [%o1 - 2], %o4    ! Copy byte.
  749.     dec    2, %o1
  750.     stb    %o4, [%o3 - 2]
  751.     bne,a    bwd_last_chunk
  752.     dec    2, %o3        ! Delay slot.
  753.     retl            ! Return value will still be in %o0.
  754.     nop
  755.  
  756. bwd_small_byte_copy:
  757.     deccc    8, %o2        ! See if can fill an 8 byte chunk.
  758.     bneg,a    bwd_last_copy_tested
  759.     inccc    8, %o2        ! See if can copy next byte (delay slot).
  760.  
  761. bwd_small_byte_chunk:
  762.     ld    [%o1 - 4], %o4    ! Copy an 8 byte chunk.
  763.     ld    [%o1 - 8], %o5
  764.     srl    %o4, 8, %g2
  765.     stb    %o4, [%o3 - 1]
  766.     stb    %g2, [%o3 - 2]
  767.     srl    %o4, 16, %g2
  768.     srl    %o4, 24, %g3
  769.     stb    %g2, [%o3 - 3]
  770.     stb    %g3, [%o3 - 4]
  771.     srl    %o5, 8, %g2
  772.     stb    %o5, [%o3 - 5]
  773.     stb    %g2, [%o3 - 6]
  774.     srl    %o5, 16, %g2
  775.     srl    %o5, 24, %g3
  776.     stb    %g2, [%o3 - 7]
  777.     stb    %g3, [%o3 - 8]
  778.     dec    8, %o1
  779.     ba    bwd_small_byte_copy
  780.     dec    8, %o3        ! Delay slot.
  781.  
  782. bwd_byte_1_copy:
  783.     ld    [%o1 - 4], %o5    ! Load first 4 bytes.
  784.     srl    %o5, 8, %g1    ! Last 3 bytes in low part of %g1.
  785.     stb    %o5, [%o3 - 1]    ! Store first byte.
  786.     dec    4, %o1
  787.     dec    4, %o3
  788.  
  789. bwd_byte_1_chunk:
  790.     ld    [%o1 -  4], %o5    ! Copy a 32 byte chunk.
  791.     ld    [%o1 -  8], %o4
  792.     deccc    32, %o2
  793.     sll    %o5, 24, %g3    ! First byte in %g3.
  794.     or    %g3, %g1, %g3    ! Add 3 low bytes in %g1 from previous cycle.
  795.     srl    %o5, 8, %o5    ! Next 3 bytes in low part of %o5.
  796.     sll    %o4, 24, %g2    ! Next byte in high part of %g2.
  797.     or    %o5, %g2, %g2    ! Add low 3 bytes from %o5.
  798.     srl    %o4, 8, %g1    ! Save last 3 bytes in %g1 for next cycle.
  799.     ld    [%o1 - 12], %o5
  800.     ld    [%o1 - 16], %o4
  801.     std    %g2, [%o3 -  8 + 3]
  802.     sll    %o5, 24, %g3
  803.     or    %g3, %g1, %g3
  804.     srl    %o5, 8, %o5
  805.     sll    %o4, 24, %g2
  806.     or    %o5, %g2, %g2
  807.     srl    %o4, 8, %g1
  808.     ld    [%o1 - 20], %o5
  809.     ld    [%o1 - 24], %o4
  810.     std    %g2, [%o3 - 16 + 3]
  811.     sll    %o5, 24, %g3
  812.     or    %g3, %g1, %g3
  813.     srl    %o5, 8, %o5
  814.     sll    %o4, 24, %g2
  815.     or    %o5, %g2, %g2
  816.     srl    %o4, 8, %g1
  817.     ld    [%o1 - 28], %o5
  818.     ld    [%o1 - 32], %o4
  819.     std    %g2, [%o3 - 24 + 3]
  820.     sll    %o5, 24, %g3
  821.     or    %g3, %g1, %g3
  822.     srl    %o5, 8, %o5
  823.     sll    %o4, 24, %g2
  824.     or    %o5, %g2, %g2
  825.     srl    %o4, 8, %g1
  826.     std    %g2, [%o3 - 32 + 3]
  827.     dec    32, %o1
  828.     bpos    bwd_byte_1_chunk
  829.     dec    32, %o3        ! Delay slot.
  830.     inc    32, %o2
  831.     srl    %g1, 16, %g2
  832.     sth    %g1, [%o3 + 1]    ! Store last 3 bytes.
  833.     ba    bwd_small_byte_copy
  834.     stb    %g2, [%o3 + 0]    ! Delay slot.
  835.  
  836. bwd_byte_2_copy:
  837.     ld    [%o1 - 4], %o4    ! Load first 4 bytes.
  838.     srl    %o4, 16, %g1    ! Second 2 bytes in low half of %g1.
  839.     sth    %o4, [%o3 - 2]    ! Store first 2 bytes.
  840.     dec    4, %o1
  841.     dec    4, %o3
  842.  
  843. bwd_byte_2_chunk:
  844.     ld    [%o1 -  4], %o5    ! Copy a 32 byte chunk.
  845.     ld    [%o1 -  8], %o4
  846.     deccc    32, %o2
  847.     sll    %o5, 16, %g3    ! First 2 bytes in %g3.
  848.     or    %g3, %g1, %g3    ! Add low 2 bytes in %g1 from previous cycle.
  849.     srl    %o5, 16, %o5    ! Second 2 bytes in low part of %o5.
  850.     sll    %o4, 16, %g2    ! Third 2 bytes in high part of %g2.
  851.     or    %o5, %g2, %g2    ! Add second 2 bytes from %o5.
  852.     srl    %o4, 16, %g1    ! Save last 2 bytes in %g1 for next cycle.
  853.     ld    [%o1 - 12], %o5
  854.     ld    [%o1 - 16], %o4
  855.     std    %g2, [%o3 -  8 + 2]
  856.     sll    %o5, 16, %g3
  857.     or    %g3, %g1, %g3
  858.     srl    %o5, 16, %o5
  859.     sll    %o4, 16, %g2
  860.     or    %o5, %g2, %g2
  861.     srl    %o4, 16, %g1
  862.     ld    [%o1 - 20], %o5
  863.     ld    [%o1 - 24], %o4
  864.     std    %g2, [%o3 - 16 + 2]
  865.     sll    %o5, 16, %g3
  866.     or    %g3, %g1, %g3
  867.     srl    %o5, 16, %o5
  868.     sll    %o4, 16, %g2
  869.     or    %o5, %g2, %g2
  870.     srl    %o4, 16, %g1
  871.     ld    [%o1 - 28], %o5
  872.     ld    [%o1 - 32], %o4
  873.     std    %g2, [%o3 - 24 + 2]
  874.     sll    %o5, 16, %g3
  875.     or    %g3, %g1, %g3
  876.     srl    %o5, 16, %o5
  877.     sll    %o4, 16, %g2
  878.     or    %o5, %g2, %g2
  879.     srl    %o4, 16, %g1
  880.     std    %g2, [%o3 - 32 + 2]
  881.     dec    32, %o1
  882.     bpos    bwd_byte_2_chunk
  883.     dec    32, %o3        ! Delay slot.
  884.     inc    32, %o2
  885.     ba    bwd_small_byte_copy
  886.     sth    %g1, [%o3 + 0]    ! Store last 2 bytes (delay slot).
  887.  
  888. bwd_byte_3_copy:
  889.     ld    [%o1 - 4], %o4    ! Load first 4 bytes.
  890.     srl    %o4, 8, %g3
  891.     srl    %o4, 24, %g1    ! Last byte in low part of %g1.
  892.     stb    %o4, [%o3 - 1]    ! Store first 3 bytes.
  893.     sth    %g3, [%o3 - 3]
  894.     dec    4, %o1
  895.     dec    4, %o3
  896.  
  897. bwd_byte_3_chunk:
  898.     ld    [%o1 -  4], %o5    ! Copy a 32 byte chunk.
  899.     ld    [%o1 -  8], %o4
  900.     deccc    32, %o2
  901.     sll    %o5, 8, %g3    ! First 3 bytes in %g3.
  902.     or    %g3, %g1, %g3    ! Add low byte in %g1 from previous cycle.
  903.     srl    %o5, 24, %o5    ! Fourth byte in low part of %o5.
  904.     sll    %o4, 8, %g2    ! Next 3 bytes in high part of %g2.
  905.     or    %o5, %g2, %g2    ! Add low byte from %o5.
  906.     srl    %o4, 24, %g1    ! Save last byte in %g1 for next cycle.
  907.     ld    [%o1 - 12], %o5
  908.     ld    [%o1 - 16], %o4
  909.     std    %g2, [%o3 -  8 + 1]
  910.     sll    %o5, 8, %g3
  911.     or    %g3, %g1, %g3
  912.     srl    %o5, 24, %o5
  913.     sll    %o4, 8, %g2
  914.     or    %o5, %g2, %g2
  915.     srl    %o4, 24, %g1
  916.     ld    [%o1 - 20], %o5
  917.     ld    [%o1 - 24], %o4
  918.     std    %g2, [%o3 - 16 + 1]
  919.     sll    %o5, 8, %g3
  920.     or    %g3, %g1, %g3
  921.     srl    %o5, 24, %o5
  922.     sll    %o4, 8, %g2
  923.     or    %o5, %g2, %g2
  924.     srl    %o4, 24, %g1
  925.     ld    [%o1 - 28], %o5
  926.     ld    [%o1 - 32], %o4
  927.     std    %g2, [%o3 - 24 + 1]
  928.     sll    %o5, 8, %g3
  929.     or    %g3, %g1, %g3
  930.     srl    %o5, 24, %o5
  931.     sll    %o4, 8, %g2
  932.     or    %o5, %g2, %g2
  933.     srl    %o4, 24, %g1
  934.     std    %g2, [%o3 - 32 + 1]
  935.     dec    32, %o1
  936.     bpos    bwd_byte_3_chunk
  937.     dec    32, %o3        ! Delay slot.
  938.     inc    32, %o2
  939.     ba    bwd_small_byte_copy
  940.     stb    %g1, [%o3 + 0]    ! Store last byte (delay slot).
  941.  
  942. copy_done:
  943.     retl            ! Return value will still be in %o0.
  944.     nop
  945.  
  946. ----------------------------- cut here ----------------------------
  947.  
  948. void bzero(dst, length)
  949. char *dst;
  950. int length;
  951. {
  952.   (void) memset((void *) dst, 0, (int) length);
  953. }
  954.  
  955. ----------------------------- cut here ----------------------------
  956.  
  957. void bcopy(src, dst, length)
  958. char *src;
  959. char *dst;
  960. int length;
  961. {
  962.   (void) memcpy((void *) dst, (void *) src, (int) length);
  963. }
  964.