/* ******************************************************************************** ** ** \file ./boot/startup/src/memcpy.c ** ** \version $Id: memcpy.c 7112 2011-08-15 15:24:45Z dkless $ ** ** \brief ARM1176 function retargeting. ** ** This files implements an optimized memcpy(). ** ** \attention THIS SAMPLE CODE IS PROVIDED AS IS. FUJITSU SEMICONDUCTOR ** ACCEPTS NO RESPONSIBILITY OR LIABILITY FOR ANY ERRORS OR ** OMMISSIONS. ** ** (C) Copyright 2006-2010 by Fujitsu Microelectronics Europe GmbH ** ***************************************************************************** */ /******************************************************************** ** File: memcpy.c ** ** Copyright (C) 1999-2010 Daniel Vik ** ** This software is provided 'as-is', without any express or implied ** warranty. In no event will the authors be held liable for any ** damages arising from the use of this software. ** Permission is granted to anyone to use this software for any ** purpose, including commercial applications, and to alter it and ** redistribute it freely, subject to the following restrictions: ** ** 1. The origin of this software must not be misrepresented; you ** must not claim that you wrote the original software. If you ** use this software in a product, an acknowledgment in the ** product documentation would be appreciated but is not ** required. ** ** 2. Altered source versions must be plainly marked as such, and ** must not be misrepresented as being the original software. ** ** 3. This notice may not be removed or altered from any source ** distribution. ** ** ** Description: Implementation of the standard library function memcpy. ** This implementation of memcpy() is ANSI-C89 compatible. ** ** The following configuration options can be set: ** ** LITTLE_ENDIAN - Uses processor with little endian ** addressing. Default is big endian. ** ** PRE_INC_PTRS - Use pre increment of pointers. ** Default is post increment of ** pointers. ** ** INDEXED_COPY - Copying data using array indexing. ** Using this option, disables the ** PRE_INC_PTRS option. ** ** MEMCPY_64BIT - Compiles memcpy for 64 bit ** architectures ** ** ** Best Settings: ** ** Intel x86: LITTLE_ENDIAN and INDEXED_COPY ** *******************************************************************/ /*lint -save -e* */ /******************************************************************** ** Configuration definitions. *******************************************************************/ #define LITTLE_ENDIAN #define INDEXED_COPY #define MEMCPY_64BIT /******************************************************************** ** Includes for size_t definition *******************************************************************/ #include #include /******************************************************************** ** Typedefs *******************************************************************/ /*lint -save -e751 */ typedef unsigned char UInt8; typedef unsigned short UInt16; typedef unsigned int UInt32; #ifdef _WIN32 typedef unsigned __int64 UInt64; #else typedef unsigned long long UInt64; #endif #ifdef MEMCPY_64BIT typedef UInt64 UIntN; #define TYPE_WIDTH 8L #else typedef UInt32 UIntN; #define TYPE_WIDTH 4L #endif /******************************************************************** ** Remove definitions when INDEXED_COPY is defined. *******************************************************************/ #if defined (INDEXED_COPY) #if defined (PRE_INC_PTRS) #undef PRE_INC_PTRS #endif /*PRE_INC_PTRS*/ #endif /*INDEXED_COPY*/ /******************************************************************** ** Definitions for pre and post increment of pointers. *******************************************************************/ #if defined (PRE_INC_PTRS) #define START_VAL(x) (x)-- #define INC_VAL(x) *++(x) #define CAST_TO_U8(p, o) ((UInt8*)p + o + TYPE_WIDTH) #define WHILE_DEST_BREAK (TYPE_WIDTH - 1) #define PRE_LOOP_ADJUST - (TYPE_WIDTH - 1) #define PRE_SWITCH_ADJUST + 1 #else /*PRE_INC_PTRS*/ #define START_VAL(x) #define INC_VAL(x) *(x)++ #define CAST_TO_U8(p, o) ((UInt8*)p + o) #define WHILE_DEST_BREAK 0 #define PRE_LOOP_ADJUST #define PRE_SWITCH_ADJUST #endif /*PRE_INC_PTRS*/ /******************************************************************** ** Definitions for endians *******************************************************************/ #if defined (LITTLE_ENDIAN) #define SHL >> #define SHR << #else /* LITTLE_ENDIAN */ #define SHL << #define SHR >> #endif /* LITTLE_ENDIAN */ /******************************************************************** ** Macros for copying words of different alignment. ** Uses incremening pointers. *******************************************************************/ #define CP_INCR() { \ INC_VAL(dstN) = INC_VAL(srcN); \ } #define CP_INCR_SH(shl, shr) { \ dstWord = srcWord SHL shl; \ srcWord = INC_VAL(srcN); \ dstWord |= srcWord SHR shr; \ INC_VAL(dstN) = dstWord; \ } /******************************************************************** ** Macros for copying words of different alignment. ** Uses array indexes. *******************************************************************/ #define CP_INDEX(idx) { \ dstN[idx] = srcN[idx]; \ } #define CP_INDEX_SH(x, shl, shr) { \ dstWord = srcWord SHL shl; \ srcWord = srcN[x]; \ dstWord |= srcWord SHR shr; \ dstN[x] = dstWord; \ } /******************************************************************** ** Macros for copying words of different alignment. ** Uses incremening pointers or array indexes depending on ** configuration. *******************************************************************/ #if defined (INDEXED_COPY) #define CP(idx) CP_INDEX(idx) #define CP_SH(idx, shl, shr) CP_INDEX_SH(idx, shl, shr) #define INC_INDEX(p, o) ((p) += (o)) #else /* INDEXED_COPY */ #define CP(idx) CP_INCR() #define CP_SH(idx, shl, shr) CP_INCR_SH(shl, shr) #define INC_INDEX(p, o) #endif /* INDEXED_COPY */ #define COPY_REMAINING(count) { \ START_VAL(dst8); \ START_VAL(src8); \ \ switch (count) { \ case 7: INC_VAL(dst8) = INC_VAL(src8); \ case 6: INC_VAL(dst8) = INC_VAL(src8); \ case 5: INC_VAL(dst8) = INC_VAL(src8); \ case 4: INC_VAL(dst8) = INC_VAL(src8); \ case 3: INC_VAL(dst8) = INC_VAL(src8); \ case 2: INC_VAL(dst8) = INC_VAL(src8); \ case 1: INC_VAL(dst8) = INC_VAL(src8); \ case 0: \ default: break; \ } \ } #define COPY_NO_SHIFT() { \ UIntN* dstN = (UIntN*)(dst8 PRE_LOOP_ADJUST); \ UIntN* srcN = (UIntN*)(src8 PRE_LOOP_ADJUST); \ size_t length = count / TYPE_WIDTH; \ \ while (length & 7) { \ CP_INCR(); \ length--; \ } \ \ length /= 8; \ \ while (length--) { \ CP(0); \ CP(1); \ CP(2); \ CP(3); \ CP(4); \ CP(5); \ CP(6); \ CP(7); \ \ INC_INDEX(dstN, 8); \ INC_INDEX(srcN, 8); \ } \ \ src8 = CAST_TO_U8(srcN, 0); \ dst8 = CAST_TO_U8(dstN, 0); \ \ COPY_REMAINING(count & (TYPE_WIDTH - 1)); \ \ return dest; \ } #define COPY_SHIFT(shift) { \ UIntN* dstN = (UIntN*)(intptr_t)((((UIntN)(intptr_t)dst8) PRE_LOOP_ADJUST) & \ ~(TYPE_WIDTH - 1)); \ UIntN* srcN = (UIntN*)(intptr_t)((((UIntN)(intptr_t)src8) PRE_LOOP_ADJUST) & \ ~(TYPE_WIDTH - 1)); \ size_t length = count / TYPE_WIDTH; \ UIntN srcWord = INC_VAL(srcN); \ UIntN dstWord; \ \ while (length & 7) { \ CP_INCR_SH(8 * shift, 8 * (TYPE_WIDTH - shift)); \ length--; \ } \ \ length /= 8; \ \ while (length--) { \ CP_SH(0, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ CP_SH(1, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ CP_SH(2, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ CP_SH(3, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ CP_SH(4, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ CP_SH(5, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ CP_SH(6, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ CP_SH(7, 8 * shift, 8 * (TYPE_WIDTH - shift)); \ \ INC_INDEX(dstN, 8); \ INC_INDEX(srcN, 8); \ } \ \ src8 = CAST_TO_U8(srcN, (shift - TYPE_WIDTH)); \ dst8 = CAST_TO_U8(dstN, 0); \ \ COPY_REMAINING(count & (TYPE_WIDTH - 1)); \ \ return dest; \ } /******************************************************************** ** ** void *memcpy(void *dest, const void *src, size_t count) ** ** Args: dest - pointer to destination buffer ** src - pointer to source buffer ** count - number of bytes to copy ** ** Return: A pointer to destination buffer ** ** Purpose: Copies count bytes from src to dest. ** No overlap check is performed. ** *******************************************************************/ #if 0//use libc 's api to improve performance. void *memcpy(void *dest, const void *src, size_t count) { UInt8* dst8 = (UInt8*)dest; UInt8* src8 = (UInt8*)src; if (count < 8) { COPY_REMAINING(count); return dest; } START_VAL(dst8); START_VAL(src8); while (((UIntN)(intptr_t)dst8 & (TYPE_WIDTH - 1)) != WHILE_DEST_BREAK) { INC_VAL(dst8) = INC_VAL(src8); count--; } switch ((((UIntN)(intptr_t)src8) PRE_SWITCH_ADJUST) & (TYPE_WIDTH - 1)) { case 0: COPY_NO_SHIFT(); case 1: COPY_SHIFT(1); case 2: COPY_SHIFT(2); case 3: COPY_SHIFT(3); #if TYPE_WIDTH >= 4 case 4: COPY_SHIFT(4); case 5: COPY_SHIFT(5); case 6: COPY_SHIFT(6); case 7: COPY_SHIFT(7); #endif } return 0; } /** * memset - Fill a region of memory with the given value * @s: Pointer to the start of the area. * @c: The byte to fill the area with * @count: The size of the area. * * Do not use memset() to access IO space, use memset_io() instead. */ void * memset(void * s,int c,size_t count) { unsigned long *sl = (unsigned long *) s; unsigned long cl = 0; char *s8; int i; /* do it one word at a time (32 bits or 64 bits) while possible */ if ( ((unsigned long)s & (sizeof(*sl) - 1)) == 0) { for (i = 0; i < sizeof(*sl); i++) { cl <<= 8; cl |= c & 0xff; } while (count >= sizeof(*sl)) { *sl++ = cl; count -= sizeof(*sl); } } /* fill 8 bits at a time */ s8 = (char *)sl; while (count--) *s8++ = c; return s; } /** * memmove - Copy one area of memory to another * @dest: Where to copy to * @src: Where to copy from * @count: The size of the area. * * Unlike memcpy(), memmove() copes with overlapping areas. */ void * memmove(void * dest,const void *src,size_t count) { char *tmp, *s; if (src == dest) return dest; if (dest <= src) { tmp = (char *) dest; s = (char *) src; while (count--) *tmp++ = *s++; } else { tmp = (char *) dest + count; s = (char *) src + count; while (count--) *--tmp = *--s; } return dest; } /** * memcmp - Compare two areas of memory * @cs: One area of memory * @ct: Another area of memory * @count: The size of the area. */ int memcmp(const void * cs,const void * ct,size_t count) { const unsigned char *su1, *su2; int res = 0; for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) if ((res = *su1 - *su2) != 0) break; return res; } #endif /*lint -restore */