memcpy.S 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (c) 2008 Travis Geiselbrecht
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files
  6. * (the "Software"), to deal in the Software without restriction,
  7. * including without limitation the rights to use, copy, modify, merge,
  8. * publish, distribute, sublicense, and/or sell copies of the Software,
  9. * and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  20. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  21. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. #include <asm.h>
  24. #include <arch/arm/cores.h>
  25. .text
  26. .align 2
  27. /* void bcopy(const void *src, void *dest, size_t n); */
  28. FUNCTION(bcopy)
  29. // swap args for bcopy
  30. mov r12, r0
  31. mov r0, r1
  32. mov r1, r12
  33. /* void *memcpy(void *dest, const void *src, size_t n); */
  34. FUNCTION(memmove)
  35. FUNCTION(memcpy)
  36. // check for zero length copy or the same pointer
  37. cmp r2, #0
  38. cmpne r1, r0
  39. bxeq lr
  40. // save a few registers for use and the return code (input dst)
  41. stmfd sp!, {r0, r4, r5, lr}
  42. // check for forwards overlap (src > dst, distance < len)
  43. subs r3, r0, r1
  44. cmpgt r2, r3
  45. bgt .L_forwardoverlap
  46. // check for a short copy len.
  47. // 20 bytes is enough so that if a 16 byte alignment needs to happen there is at least a
  48. // wordwise copy worth of work to be done.
  49. cmp r2, #(16+4)
  50. blt .L_bytewise
  51. // see if they are similarly aligned on 4 byte boundaries
  52. eor r3, r0, r1
  53. tst r3, #3
  54. bne .L_bytewise // dissimilarly aligned, nothing we can do (for now)
  55. // check for 16 byte alignment on dst.
  56. // this will also catch src being not 4 byte aligned, since it is similarly 4 byte
  57. // aligned with dst at this point.
  58. tst r0, #15
  59. bne .L_not16bytealigned
  60. // check to see if we have at least 32 bytes of data to copy.
  61. // if not, just revert to wordwise copy
  62. cmp r2, #32
  63. blt .L_wordwise
  64. .L_bigcopy:
  65. // copy 32 bytes at a time. src & dst need to be at least 4 byte aligned,
  66. // and we need at least 32 bytes remaining to copy
  67. // save r6-r7 for use in the big copy
  68. stmfd sp!, {r6-r7}
  69. sub r2, r2, #32 // subtract an extra 32 to the len so we can avoid an extra compare
  70. .L_bigcopy_loop:
  71. ldmia r1!, {r4, r5, r6, r7}
  72. stmia r0!, {r4, r5, r6, r7}
  73. ldmia r1!, {r4, r5, r6, r7}
  74. subs r2, r2, #32
  75. stmia r0!, {r4, r5, r6, r7}
  76. bge .L_bigcopy_loop
  77. // restore r6-r7
  78. ldmfd sp!, {r6-r7}
  79. // see if we are done
  80. adds r2, r2, #32
  81. beq .L_done
  82. // less then 4 bytes left?
  83. cmp r2, #4
  84. blt .L_bytewise
  85. .L_wordwise:
  86. // copy 4 bytes at a time.
  87. // src & dst are guaranteed to be word aligned, and at least 4 bytes are left to copy.
  88. subs r2, r2, #4
  89. .L_wordwise_loop:
  90. ldr r3, [r1], #4
  91. subs r2, r2, #4
  92. str r3, [r0], #4
  93. bge .L_wordwise_loop
  94. // correct the remaining len and test for completion
  95. adds r2, r2, #4
  96. beq .L_done
  97. .L_bytewise:
  98. // simple bytewise copy
  99. ldrb r3, [r1], #1
  100. subs r2, r2, #1
  101. strb r3, [r0], #1
  102. bgt .L_bytewise
  103. .L_done:
  104. // load dst for return and restore r4,r5
  105. #if ARM_ARCH_LEVEL >= 5
  106. ldmfd sp!, {r0, r4, r5, pc}
  107. #else
  108. ldmfd sp!, {r0, r4, r5, lr}
  109. bx lr
  110. #endif
  111. .L_not16bytealigned:
  112. // dst is not 16 byte aligned, so we will copy up to 15 bytes to get it aligned.
  113. // src is guaranteed to be similarly word aligned with dst.
  114. // set the condition flags based on the alignment.
  115. lsl r12, r0, #28
  116. rsb r12, r12, #0
  117. msr CPSR_f, r12 // move into NZCV fields in CPSR
  118. // move as many bytes as necessary to get the dst aligned
  119. ldrvsb r3, [r1], #1 // V set
  120. ldrcsh r4, [r1], #2 // C set
  121. ldreq r5, [r1], #4 // Z set
  122. strvsb r3, [r0], #1
  123. strcsh r4, [r0], #2
  124. streq r5, [r0], #4
  125. ldmmiia r1!, {r3-r4} // N set
  126. stmmiia r0!, {r3-r4}
  127. // fix the remaining len
  128. sub r2, r2, r12, lsr #28
  129. // test to see what we should do now
  130. cmp r2, #32
  131. bge .L_bigcopy
  132. b .L_wordwise
  133. // src and dest overlap 'forwards' or dst > src
  134. .L_forwardoverlap:
  135. // do a bytewise reverse copy for now
  136. add r1, r1, r2
  137. add r0, r0, r2
  138. sub r1, r1, #1
  139. sub r0, r0, #1
  140. .L_bytewisereverse:
  141. // simple bytewise reverse copy
  142. ldrb r3, [r1], #-1
  143. subs r2, r2, #1
  144. strb r3, [r0], #-1
  145. bgt .L_bytewisereverse
  146. b .L_done