1*0a6a1f1dSLionel Sambuc/* $NetBSD: memmove.S,v 1.1 2014/09/03 19:34:25 matt Exp $ */ 2*0a6a1f1dSLionel Sambuc 3*0a6a1f1dSLionel Sambuc/* stropt/memmove.S, pl_string_common, pl_linux 10/11/04 11:45:37 4*0a6a1f1dSLionel Sambuc * ========================================================================== 5*0a6a1f1dSLionel Sambuc * Optimized memmove implementation for IBM PowerPC 405/440. 6*0a6a1f1dSLionel Sambuc * 7*0a6a1f1dSLionel Sambuc * Copyright (c) 2003, IBM Corporation 8*0a6a1f1dSLionel Sambuc * All rights reserved. 9*0a6a1f1dSLionel Sambuc * 10*0a6a1f1dSLionel Sambuc * Redistribution and use in source and binary forms, with or 11*0a6a1f1dSLionel Sambuc * without modification, are permitted provided that the following 12*0a6a1f1dSLionel Sambuc * conditions are met: 13*0a6a1f1dSLionel Sambuc * 14*0a6a1f1dSLionel Sambuc * * Redistributions of source code must retain the above 15*0a6a1f1dSLionel Sambuc * copyright notice, this list of conditions and the following 16*0a6a1f1dSLionel Sambuc * disclaimer. 17*0a6a1f1dSLionel Sambuc * * Redistributions in binary form must reproduce the above 18*0a6a1f1dSLionel Sambuc * copyright notice, this list of conditions and the following 19*0a6a1f1dSLionel Sambuc * disclaimer in the documentation and/or other materials 20*0a6a1f1dSLionel Sambuc * provided with the distribution. 21*0a6a1f1dSLionel Sambuc * * Neither the name of IBM nor the names of its contributors 22*0a6a1f1dSLionel Sambuc * may be used to endorse or promote products derived from this 23*0a6a1f1dSLionel Sambuc * software without specific prior written permission. 24*0a6a1f1dSLionel Sambuc * 25*0a6a1f1dSLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 26*0a6a1f1dSLionel Sambuc * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 27*0a6a1f1dSLionel Sambuc * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28*0a6a1f1dSLionel Sambuc * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29*0a6a1f1dSLionel Sambuc * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 30*0a6a1f1dSLionel Sambuc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31*0a6a1f1dSLionel Sambuc * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 32*0a6a1f1dSLionel Sambuc * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 33*0a6a1f1dSLionel Sambuc * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 34*0a6a1f1dSLionel Sambuc * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35*0a6a1f1dSLionel Sambuc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 36*0a6a1f1dSLionel Sambuc * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37*0a6a1f1dSLionel Sambuc * 38*0a6a1f1dSLionel Sambuc * ========================================================================== 39*0a6a1f1dSLionel Sambuc * 40*0a6a1f1dSLionel Sambuc * Function: Move memory area (handles overlapping regions) 41*0a6a1f1dSLionel Sambuc * 42*0a6a1f1dSLionel Sambuc * void *memmove(void * dest, const void * src, int n) 43*0a6a1f1dSLionel Sambuc * 44*0a6a1f1dSLionel Sambuc * Input: r3 - destination address 45*0a6a1f1dSLionel Sambuc * r4 - source address 46*0a6a1f1dSLionel Sambuc * r5 - byte count 47*0a6a1f1dSLionel Sambuc * Output: r11 - destination address 48*0a6a1f1dSLionel Sambuc * 49*0a6a1f1dSLionel Sambuc * ========================================================================== 50*0a6a1f1dSLionel Sambuc */ 51*0a6a1f1dSLionel Sambuc 52*0a6a1f1dSLionel Sambuc#include <machine/asm.h> 53*0a6a1f1dSLionel Sambuc 54*0a6a1f1dSLionel Sambuc#ifdef _BCOPY 55*0a6a1f1dSLionel Sambuc/* bcopy = memcpy/memmove with arguments reversed. */ 56*0a6a1f1dSLionel Sambuc/* LINTSTUB: Func: void bcopy(void *, void *, size_t) */ 57*0a6a1f1dSLionel SambucENTRY(bcopy) 58*0a6a1f1dSLionel Sambuc l.or r6, r3, r0 /* swap src/dst */ 59*0a6a1f1dSLionel Sambuc l.or r3, r4, r0 60*0a6a1f1dSLionel Sambuc l.or r4, r6, r0 61*0a6a1f1dSLionel Sambuc#else 62*0a6a1f1dSLionel Sambuc/* LINTSTUB: Func: void *memmove(void *, const void *, size_t) */ 63*0a6a1f1dSLionel SambucENTRY(memmove) 64*0a6a1f1dSLionel Sambuc#endif 65*0a6a1f1dSLionel Sambuc 66*0a6a1f1dSLionel Sambuc l.or r11, r3, r0 /* Save dst (return value) */ 67*0a6a1f1dSLionel Sambuc 68*0a6a1f1dSLionel Sambuc l.sfges r4, r3 /* Branch to reverse if */ 69*0a6a1f1dSLionel Sambuc l.bnf .Lreverse /* src < dest. Don't want to */ 70*0a6a1f1dSLionel Sambuc /* overwrite end of src with */ 71*0a6a1f1dSLionel Sambuc /* start of dest */ 72*0a6a1f1dSLionel Sambuc 73*0a6a1f1dSLionel Sambuc l.addi r4, r4, -4 /* Back up src and dst pointers */ 74*0a6a1f1dSLionel Sambuc l.addi r3, r3, -4 /* due to auto-update of 'load' */ 75*0a6a1f1dSLionel Sambuc 76*0a6a1f1dSLionel Sambuc l.srli r13, r5, 2 /* How many words in total cnt */ 77*0a6a1f1dSLionel Sambuc l.sfeqi r13, 0 78*0a6a1f1dSLionel Sambuc l.bf .Llast1 /* Handle byte by byte if < 4 */ 79*0a6a1f1dSLionel Sambuc /* bytes total */ 80*0a6a1f1dSLionel Sambuc l.lwz r7, 4(r4) /* Preload first word */ 81*0a6a1f1dSLionel Sambuc l.addi r4, r4, 4 82*0a6a1f1dSLionel Sambuc 83*0a6a1f1dSLionel Sambuc l.j .Lg1 84*0a6a1f1dSLionel Sambuc l.nop 85*0a6a1f1dSLionel Sambuc 86*0a6a1f1dSLionel Sambuc.Lg0: /* Main loop */ 87*0a6a1f1dSLionel Sambuc 88*0a6a1f1dSLionel Sambuc l.lwz r7, 4(r4) /* Load a new word */ 89*0a6a1f1dSLionel Sambuc l.sw 4(r3), r6 /* Store previous word */ 90*0a6a1f1dSLionel Sambuc l.addi r4, r4, 4 /* advance */ 91*0a6a1f1dSLionel Sambuc l.addi r3, r3, 4 /* advance */ 92*0a6a1f1dSLionel Sambuc 93*0a6a1f1dSLionel Sambuc.Lg1: 94*0a6a1f1dSLionel Sambuc 95*0a6a1f1dSLionel Sambuc l.addi r13, r13, -1 96*0a6a1f1dSLionel Sambuc l.sfeqi r13, 0 97*0a6a1f1dSLionel Sambuc l.bf .Llast /* Dec cnt, and branch if just */ 98*0a6a1f1dSLionel Sambuc l.nop 99*0a6a1f1dSLionel Sambuc /* one word to store */ 100*0a6a1f1dSLionel Sambuc l.lwz r6, 4(r4) /* Load another word */ 101*0a6a1f1dSLionel Sambuc l.sw 4(r3), r7 /* Store previous word */ 102*0a6a1f1dSLionel Sambuc l.addi r4, r4, 4 /* advance to next word */ 103*0a6a1f1dSLionel Sambuc l.addi r3, r3, 4 /* advance to next word */ 104*0a6a1f1dSLionel Sambuc l.addi r13, r13, -1 /* Decrement count */ 105*0a6a1f1dSLionel Sambuc l.sfeqi r13, 0 /* last word? */ 106*0a6a1f1dSLionel Sambuc l.bnf .Lg0 /* no, loop, more words */ 107*0a6a1f1dSLionel Sambuc l.nop 108*0a6a1f1dSLionel Sambuc 109*0a6a1f1dSLionel Sambuc l.or r7, r6, r0 /* If word count -> 0, then... */ 110*0a6a1f1dSLionel Sambuc 111*0a6a1f1dSLionel Sambuc.Llast: 112*0a6a1f1dSLionel Sambuc 113*0a6a1f1dSLionel Sambuc l.sw 4(r3), r7 /* ... store last word */ 114*0a6a1f1dSLionel Sambuc l.addi r3, r3, 4 115*0a6a1f1dSLionel Sambuc 116*0a6a1f1dSLionel Sambuc.Llast1: /* Byte-by-byte copy */ 117*0a6a1f1dSLionel Sambuc 118*0a6a1f1dSLionel Sambuc l.andi r5, r5, 3 /* get remaining byte count */ 119*0a6a1f1dSLionel Sambuc l.sfeqi r5, 0 /* is it 0? */ 120*0a6a1f1dSLionel Sambuc l.bf .Ldone /* yes, we're done */ 121*0a6a1f1dSLionel Sambuc l.nop /* -- delay slot -- */ 122*0a6a1f1dSLionel Sambuc 123*0a6a1f1dSLionel Sambuc l.lbz r6, 4(r4) /* 1st byte: update addr by 4 */ 124*0a6a1f1dSLionel Sambuc l.sb 4(r3), r6 /* since we pre-adjusted by 4 */ 125*0a6a1f1dSLionel Sambuc l.addi r4, r4, 4 /* advance to next word */ 126*0a6a1f1dSLionel Sambuc l.addi r3, r3, 4 /* advance to next word */ 127*0a6a1f1dSLionel Sambuc l.addi r5, r5, -1 /* decrement count */ 128*0a6a1f1dSLionel Sambuc l.sfeqi r5, 0 /* is it 0? */ 129*0a6a1f1dSLionel Sambuc l.bf .Ldone /* yes, we're done */ 130*0a6a1f1dSLionel Sambuc l.nop /* -- delay slot -- */ 131*0a6a1f1dSLionel Sambuc 132*0a6a1f1dSLionel Sambuc.Llast2: 133*0a6a1f1dSLionel Sambuc 134*0a6a1f1dSLionel Sambuc l.lbz r6, 1(r4) /* But handle the rest by */ 135*0a6a1f1dSLionel Sambuc l.sb 1(r3), r6 /* updating addr by 1 */ 136*0a6a1f1dSLionel Sambuc l.addi r4, r4, 1 /* advance to next word */ 137*0a6a1f1dSLionel Sambuc l.addi r3, r3, 1 /* advance to next word */ 138*0a6a1f1dSLionel Sambuc l.addi r5, r5, -1 /* decrement count */ 139*0a6a1f1dSLionel Sambuc l.sfeqi r5, 0 /* is it 0? */ 140*0a6a1f1dSLionel Sambuc l.bnf .Llast2 /* yes, we're done */ 141*0a6a1f1dSLionel Sambuc l.nop /* -- delay slot -- */ 142*0a6a1f1dSLionel Sambuc.Ldone: 143*0a6a1f1dSLionel Sambuc l.jr lr /* return */ 144*0a6a1f1dSLionel Sambuc l.nop /* -- delay slot -- */ 145*0a6a1f1dSLionel Sambuc 146*0a6a1f1dSLionel Sambuc /* We're here since src < dest. Don't want to overwrite end of */ 147*0a6a1f1dSLionel Sambuc /* src with start of dest */ 148*0a6a1f1dSLionel Sambuc 149*0a6a1f1dSLionel Sambuc.Lreverse: 150*0a6a1f1dSLionel Sambuc 151*0a6a1f1dSLionel Sambuc l.add r4, r4, r5 /* Work from end to beginning */ 152*0a6a1f1dSLionel Sambuc l.add r3, r3, r5 /* so add count to string ptrs */ 153*0a6a1f1dSLionel Sambuc l.srli r13, r5, 2 /* Words in total count */ 154*0a6a1f1dSLionel Sambuc l.sfeqi r13, 0 155*0a6a1f1dSLionel Sambuc l.bf .Lrlast1 /* Handle byte by byte if < 4 */ 156*0a6a1f1dSLionel Sambuc /* bytes total */ 157*0a6a1f1dSLionel Sambuc l.nop 158*0a6a1f1dSLionel Sambuc 159*0a6a1f1dSLionel Sambuc l.lwz r7, -4(r4) /* Preload first word */ 160*0a6a1f1dSLionel Sambuc l.addi r4, r4, -4 /* update pointer */ 161*0a6a1f1dSLionel Sambuc 162*0a6a1f1dSLionel Sambuc l.j .Lrg1 163*0a6a1f1dSLionel Sambuc 164*0a6a1f1dSLionel Sambuc.Lrg0: /* Main loop */ 165*0a6a1f1dSLionel Sambuc 166*0a6a1f1dSLionel Sambuc l.lwz r7, -4(r4) /* Load a new word */ 167*0a6a1f1dSLionel Sambuc l.sw -4(r3), r6 /* Store previous word */ 168*0a6a1f1dSLionel Sambuc l.addi r4, r4, -4 169*0a6a1f1dSLionel Sambuc l.addi r3, r3, -4 170*0a6a1f1dSLionel Sambuc 171*0a6a1f1dSLionel Sambuc.Lrg1: 172*0a6a1f1dSLionel Sambuc 173*0a6a1f1dSLionel Sambuc l.addi r13, r13, -1 /* decrement count */ 174*0a6a1f1dSLionel Sambuc l.sfeqi r13, 0 /* just one pending word left? */ 175*0a6a1f1dSLionel Sambuc l.bf .Lrlast /* yes, deal with it */ 176*0a6a1f1dSLionel Sambuc 177*0a6a1f1dSLionel Sambuc l.lwz r6, -4(r4) /* Load another word */ 178*0a6a1f1dSLionel Sambuc l.sw -4(r3), r7 /* Store previous word */ 179*0a6a1f1dSLionel Sambuc l.addi r4, r4, -4 180*0a6a1f1dSLionel Sambuc l.addi r3, r3, -4 181*0a6a1f1dSLionel Sambuc 182*0a6a1f1dSLionel Sambuc l.addi r13, r13, -1 /* decrement count */ 183*0a6a1f1dSLionel Sambuc l.sfeqi r13, 0 /* just one pending word left? */ 184*0a6a1f1dSLionel Sambuc l.bnf .Lrg0 /* no, loop again more words */ 185*0a6a1f1dSLionel Sambuc l.nop 186*0a6a1f1dSLionel Sambuc 187*0a6a1f1dSLionel Sambuc l.or r7, r6, r0 /* If word count -> 0, then... */ 188*0a6a1f1dSLionel Sambuc 189*0a6a1f1dSLionel Sambuc.Lrlast: 190*0a6a1f1dSLionel Sambuc 191*0a6a1f1dSLionel Sambuc l.sw -4(r3), r7 /* ... store last word */ 192*0a6a1f1dSLionel Sambuc l.addi r3, r3, -4 /* update pointer */ 193*0a6a1f1dSLionel Sambuc 194*0a6a1f1dSLionel Sambuc.Lrlast1: /* Byte-by-byte copy */ 195*0a6a1f1dSLionel Sambuc 196*0a6a1f1dSLionel Sambuc l.andi r5, r5, 3 197*0a6a1f1dSLionel Sambuc l.sfeqi r5, 0 198*0a6a1f1dSLionel Sambuc l.bf .Lrdone 199*0a6a1f1dSLionel Sambuc 200*0a6a1f1dSLionel Sambuc.Lrlast2: 201*0a6a1f1dSLionel Sambuc 202*0a6a1f1dSLionel Sambuc l.lbz r6, -1(r4) /* Handle the rest, byte by */ 203*0a6a1f1dSLionel Sambuc l.sb -1(r3), r6 /* byte */ 204*0a6a1f1dSLionel Sambuc l.addi r4, r4, -1 205*0a6a1f1dSLionel Sambuc l.addi r3, r3, -1 206*0a6a1f1dSLionel Sambuc l.addi r5, r5, -1 /* decrement count */ 207*0a6a1f1dSLionel Sambuc l.sfeqi r5, 0 /* is it 0? */ 208*0a6a1f1dSLionel Sambuc l.bnf .Lrlast2 /* no, loop again */ 209*0a6a1f1dSLionel Sambuc l.nop 210*0a6a1f1dSLionel Sambuc.Lrdone: 211*0a6a1f1dSLionel Sambuc l.jr lr 212*0a6a1f1dSLionel Sambuc l.nop 213*0a6a1f1dSLionel Sambuc 214*0a6a1f1dSLionel Sambuc#ifdef _BCOPY 215*0a6a1f1dSLionel SambucEND(bcopy) 216*0a6a1f1dSLionel Sambuc#else 217*0a6a1f1dSLionel SambucEND(memmove) 218*0a6a1f1dSLionel Sambuc#endif 219