1/* $NetBSD: memcpy_arm.S,v 1.1 2003/10/14 07:51:45 scw Exp $ */ 2 3/*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Neil A. Carson and Mark Brinicombe 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <machine/asm.h> 33.syntax unified 34 35/* 36 * This is one fun bit of code ... 37 * Some easy listening music is suggested while trying to understand this 38 * code e.g. Iron Maiden 39 * 40 * For anyone attempting to understand it : 41 * 42 * The core code is implemented here with simple stubs for memcpy(). 43 * 44 * All local labels are prefixed with Lmemcpy_ 45 * Following the prefix a label starting f is used in the forward copy code 46 * while a label using b is used in the backwards copy code 47 * The source and destination addresses determine whether a forward or 48 * backward copy is performed. 49 * Separate bits of code are used to deal with the following situations 50 * for both the forward and backwards copy. 51 * unaligned source address 52 * unaligned destination address 53 * Separate copy routines are used to produce an optimised result for each 54 * of these cases. 55 * The copy code will use LDM/STM instructions to copy up to 32 bytes at 56 * a time where possible. 57 * 58 * Note: r12 (aka ip) can be trashed during the function along with 59 * r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out. 60 * Additional registers are preserved prior to use i.e. r4, r5 & lr 61 * 62 * Apologies for the state of the comments ;-) 63 */ 64/* LINTSTUB: Func: void *memcpy(void *dst, const void *src, size_t len) */ 65ENTRY(memcpy) 66 /* save leaf functions having to store this away */ 67 stmdb sp!, {r0, lr} /* memcpy() returns dest addr */ 68 69 subs r2, r2, #4 70 blt .Lmemcpy_l4 /* less than 4 bytes */ 71 ands r12, r0, #3 72 bne .Lmemcpy_destul /* oh unaligned destination addr */ 73 ands r12, r1, #3 74 bne .Lmemcpy_srcul /* oh unaligned source addr */ 75 76.Lmemcpy_t8: 77 /* We have aligned source and destination */ 78 subs r2, r2, #8 79 blt .Lmemcpy_l12 /* less than 12 bytes (4 from above) */ 80 subs r2, r2, #0x14 81 blt .Lmemcpy_l32 /* less than 32 bytes (12 from above) */ 82 stmdb sp!, {r4} /* borrow r4 */ 83 84 /* blat 32 bytes at a time */ 85 /* XXX for really big copies perhaps we should use more registers */ 86.Lmemcpy_loop32: 87 ldmia r1!, {r3, r4, r12, lr} 88 stmia r0!, {r3, r4, r12, lr} 89 ldmia r1!, {r3, r4, r12, lr} 90 stmia r0!, {r3, r4, r12, lr} 91 subs r2, r2, #0x20 92 bge .Lmemcpy_loop32 93 94 cmn r2, #0x10 95 ldmiage r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */ 96 stmiage r0!, {r3, r4, r12, lr} 97 subge r2, r2, #0x10 98 ldmia sp!, {r4} /* return r4 */ 99 100.Lmemcpy_l32: 101 adds r2, r2, #0x14 102 103 /* blat 12 bytes at a time */ 104.Lmemcpy_loop12: 105 ldmiage r1!, {r3, r12, lr} 106 stmiage r0!, {r3, r12, lr} 107 subsge r2, r2, #0x0c 108 bge .Lmemcpy_loop12 109 110.Lmemcpy_l12: 111 adds r2, r2, #8 112 blt .Lmemcpy_l4 113 114 subs r2, r2, #4 115 ldrlt r3, [r1], #4 116 strlt r3, [r0], #4 117 ldmiage r1!, {r3, r12} 118 stmiage r0!, {r3, r12} 119 subge r2, r2, #4 120 121.Lmemcpy_l4: 122 /* less than 4 bytes to go */ 123 adds r2, r2, #4 124#ifdef __APCS_26_ 125 ldmiaeq sp!, {r0, pc}^ /* done */ 126#else 127 ldmiaeq sp!, {r0, pc} /* done */ 128#endif 129 /* copy the crud byte at a time */ 130 cmp r2, #2 131 ldrb r3, [r1], #1 132 strb r3, [r0], #1 133 ldrbge r3, [r1], #1 134 strbge r3, [r0], #1 135 ldrbgt r3, [r1], #1 136 strbgt r3, [r0], #1 137 ldmia sp!, {r0, pc} 138 139 /* erg - unaligned destination */ 140.Lmemcpy_destul: 141 rsb r12, r12, #4 142 cmp r12, #2 143 144 /* align destination with byte copies */ 145 ldrb r3, [r1], #1 146 strb r3, [r0], #1 147 ldrbge r3, [r1], #1 148 strbge r3, [r0], #1 149 ldrbgt r3, [r1], #1 150 strbgt r3, [r0], #1 151 subs r2, r2, r12 152 blt .Lmemcpy_l4 /* less the 4 bytes */ 153 154 ands r12, r1, #3 155 beq .Lmemcpy_t8 /* we have an aligned source */ 156 157 /* erg - unaligned source */ 158 /* This is where it gets nasty ... */ 159.Lmemcpy_srcul: 160 bic r1, r1, #3 161 ldr lr, [r1], #4 162 cmp r12, #2 163 bgt .Lmemcpy_srcul3 164 beq .Lmemcpy_srcul2 165 cmp r2, #0x0c 166 blt .Lmemcpy_srcul1loop4 167 sub r2, r2, #0x0c 168 stmdb sp!, {r4, r5} 169 170.Lmemcpy_srcul1loop16: 171#ifdef __ARMEB__ 172 mov r3, lr, lsl #8 173#else 174 mov r3, lr, lsr #8 175#endif 176 ldmia r1!, {r4, r5, r12, lr} 177#ifdef __ARMEB__ 178 orr r3, r3, r4, lsr #24 179 mov r4, r4, lsl #8 180 orr r4, r4, r5, lsr #24 181 mov r5, r5, lsl #8 182 orr r5, r5, r12, lsr #24 183 mov r12, r12, lsl #8 184 orr r12, r12, lr, lsr #24 185#else 186 orr r3, r3, r4, lsl #24 187 mov r4, r4, lsr #8 188 orr r4, r4, r5, lsl #24 189 mov r5, r5, lsr #8 190 orr r5, r5, r12, lsl #24 191 mov r12, r12, lsr #8 192 orr r12, r12, lr, lsl #24 193#endif 194 stmia r0!, {r3-r5, r12} 195 subs r2, r2, #0x10 196 bge .Lmemcpy_srcul1loop16 197 ldmia sp!, {r4, r5} 198 adds r2, r2, #0x0c 199 blt .Lmemcpy_srcul1l4 200 201.Lmemcpy_srcul1loop4: 202#ifdef __ARMEB__ 203 mov r12, lr, lsl #8 204#else 205 mov r12, lr, lsr #8 206#endif 207 ldr lr, [r1], #4 208#ifdef __ARMEB__ 209 orr r12, r12, lr, lsr #24 210#else 211 orr r12, r12, lr, lsl #24 212#endif 213 str r12, [r0], #4 214 subs r2, r2, #4 215 bge .Lmemcpy_srcul1loop4 216 217.Lmemcpy_srcul1l4: 218 sub r1, r1, #3 219 b .Lmemcpy_l4 220 221.Lmemcpy_srcul2: 222 cmp r2, #0x0c 223 blt .Lmemcpy_srcul2loop4 224 sub r2, r2, #0x0c 225 stmdb sp!, {r4, r5} 226 227.Lmemcpy_srcul2loop16: 228#ifdef __ARMEB__ 229 mov r3, lr, lsl #16 230#else 231 mov r3, lr, lsr #16 232#endif 233 ldmia r1!, {r4, r5, r12, lr} 234#ifdef __ARMEB__ 235 orr r3, r3, r4, lsr #16 236 mov r4, r4, lsl #16 237 orr r4, r4, r5, lsr #16 238 mov r5, r5, lsl #16 239 orr r5, r5, r12, lsr #16 240 mov r12, r12, lsl #16 241 orr r12, r12, lr, lsr #16 242#else 243 orr r3, r3, r4, lsl #16 244 mov r4, r4, lsr #16 245 orr r4, r4, r5, lsl #16 246 mov r5, r5, lsr #16 247 orr r5, r5, r12, lsl #16 248 mov r12, r12, lsr #16 249 orr r12, r12, lr, lsl #16 250#endif 251 stmia r0!, {r3-r5, r12} 252 subs r2, r2, #0x10 253 bge .Lmemcpy_srcul2loop16 254 ldmia sp!, {r4, r5} 255 adds r2, r2, #0x0c 256 blt .Lmemcpy_srcul2l4 257 258.Lmemcpy_srcul2loop4: 259#ifdef __ARMEB__ 260 mov r12, lr, lsl #16 261#else 262 mov r12, lr, lsr #16 263#endif 264 ldr lr, [r1], #4 265#ifdef __ARMEB__ 266 orr r12, r12, lr, lsr #16 267#else 268 orr r12, r12, lr, lsl #16 269#endif 270 str r12, [r0], #4 271 subs r2, r2, #4 272 bge .Lmemcpy_srcul2loop4 273 274.Lmemcpy_srcul2l4: 275 sub r1, r1, #2 276 b .Lmemcpy_l4 277 278.Lmemcpy_srcul3: 279 cmp r2, #0x0c 280 blt .Lmemcpy_srcul3loop4 281 sub r2, r2, #0x0c 282 stmdb sp!, {r4, r5} 283 284.Lmemcpy_srcul3loop16: 285#ifdef __ARMEB__ 286 mov r3, lr, lsl #24 287#else 288 mov r3, lr, lsr #24 289#endif 290 ldmia r1!, {r4, r5, r12, lr} 291#ifdef __ARMEB__ 292 orr r3, r3, r4, lsr #8 293 mov r4, r4, lsl #24 294 orr r4, r4, r5, lsr #8 295 mov r5, r5, lsl #24 296 orr r5, r5, r12, lsr #8 297 mov r12, r12, lsl #24 298 orr r12, r12, lr, lsr #8 299#else 300 orr r3, r3, r4, lsl #8 301 mov r4, r4, lsr #24 302 orr r4, r4, r5, lsl #8 303 mov r5, r5, lsr #24 304 orr r5, r5, r12, lsl #8 305 mov r12, r12, lsr #24 306 orr r12, r12, lr, lsl #8 307#endif 308 stmia r0!, {r3-r5, r12} 309 subs r2, r2, #0x10 310 bge .Lmemcpy_srcul3loop16 311 ldmia sp!, {r4, r5} 312 adds r2, r2, #0x0c 313 blt .Lmemcpy_srcul3l4 314 315.Lmemcpy_srcul3loop4: 316#ifdef __ARMEB__ 317 mov r12, lr, lsl #24 318#else 319 mov r12, lr, lsr #24 320#endif 321 ldr lr, [r1], #4 322#ifdef __ARMEB__ 323 orr r12, r12, lr, lsr #8 324#else 325 orr r12, r12, lr, lsl #8 326#endif 327 str r12, [r0], #4 328 subs r2, r2, #4 329 bge .Lmemcpy_srcul3loop4 330 331.Lmemcpy_srcul3l4: 332 sub r1, r1, #1 333 b .Lmemcpy_l4 334END(memcpy) 335 336 .section .note.GNU-stack,"",%progbits 337