root/common/lib/libc/arch/powerpc/string/memcpy.S
/* $NetBSD: memcpy.S,v 1.6 2014/03/04 17:05:14 macallan Exp $ */

/* stropt/memcpy_440.S, pl_string_common, pl_linux 10/11/04 11:45:36
 * ==========================================================================
 * Optimized memcpy implementation for IBM PowerPC 440.
 *
 *  Copyright (c) 2003, IBM Corporation
 *  All rights reserved.               
 *                                   
 *  Redistribution and use in source and binary forms, with or      
 *  without modification, are permitted provided that the following 
 *  conditions are met:                                      
 *                                                                
 *    * Redistributions of source code must retain the above    
 *      copyright notice, this list of conditions and the following 
 *      disclaimer.                                              
 *    * Redistributions in binary form must reproduce the above     
 *      copyright notice, this list of conditions and the following 
 *      disclaimer in the documentation and/or other materials      
 *      provided with the distribution.                      
 *    * Neither the name of IBM nor the names of its contributors   
 *      may be used to endorse or promote products derived from this
 *      software without specific prior written permission.      
 *                                                                
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND        
 *  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,     
 *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF    
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE    
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS   
 *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
 *  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,        
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR  
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
 *  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT        
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE   
 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *                                                                        
 * ==========================================================================
 *
 * Function: Copy n bytes of the source to the destination. Behavior is
 *         undefined for objects that overlap.
 *
 *
 *         void *memcpy(void * dest, const void * src, int n)
 *
 * Input:  r3 - destination address
 *       r4 - source address
 *       r5 - byte count
 * Output: r3 - destination address
 *
 * ==========================================================================
 */

#include <machine/asm.h>
#ifdef _KERNEL_OPT
#include "opt_ppcarch.h"
#endif

        .text
        .align 4
/* LINTSTUB: Func: void *memcpy(void *, const void *, size_t) */
ENTRY(memcpy)
        /*
         * Check count passed in R5. If zero, return; otherwise continue.
         */
        cmpwi   %r5,0
        beqlr-

#if defined(_KERNEL) && defined(PPC_OEA601)
        /*
        * 601 will generate alignment exceptions if operand crosses
         * 4k page boundary, so do byte copy when exception handler
         * not available.  Maybe want to have a different memcpy for 601
         * that checks for page boundaries/word alignment...
         */
        mfspr   %r6, 287                /* mfpvbr %r6 PVR = 287        */
        srwi    %r6, %r6, 0x10          /* get version field from PVR  */
        cmpwi   %r6, 0x1                /* 601 CPU = 0x0001            */
        bne     bnorm                   /* skip byte-only unless 601   */

        or      %r6, %r3, %r4           /* see if both source and dest */
        andi.   %r6, %r6, 3             /* are 32bit aligned           */
        beq     bnorm                   /* skip byte-only if they are  */
bcpy:
        mtctr   %r5                     /* byte copy everything */
        li      %r6, 0
bloop:          
        lbzx    %r7, %r4, %r6
        stbx    %r7, %r3, %r6
        addi    %r6, %r6, 1
        bdnz    bloop
        blr

bnorm:

#endif  

        mr      %r8, %r3                /* Copy dst (return value)      */

        addi    %r4, %r4, -4            /* Prepare for main loop's auto */
        addi    %r8, %r8, -4            /* update                      */

        srwi.   %r9,%r5,2               /* Word count -> r9             */
        beq-    last1                   /* Partial copy if <4 bytes     */

        mtctr   %r9                     /* Word cnt in CTR for loop     */
        lwzu    %r7, 4(%r4)             /* Preload for main loop        */

        b       g1

g0:                                     /* Main loop                    */

        lwzu    %r7, 4(%r4)             /* Load a new word              */
        stwu    %r6, 4(%r8)             /* Store previous word          */

g1:

        bdz-    last                    /* Dec ctr and exit loop if no  */
                                        /* more words              */
        lwzu    %r6, 4(%r4)             /* Load another word            */
        stwu    %r7, 4(%r8)             /* Store previous word          */
        bdnz+   g0                      /* Dec ctr and continue loop if */
                                        /* more words              */

        mr      %r7, %r6

last:

        stwu    %r7, 4(%r8)             /* Store last word              */

last1:                                  /* Byte-by-byte copy            */

        clrlwi. %r5,%r5,30
        beqlr

        mtctr   %r5

        lbzu    %r6, 4(%r4)             /* 1st byte: update by word     */
        stbu    %r6, 4(%r8)
        bdzlr-

last2:

        lbzu    %r6, 1(%r4)             /* Handle the rest              */
        stbu    %r6, 1(%r8)
        bdnz+   last2

        blr
END(memcpy)