You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
348 lines
14 KiB
348 lines
14 KiB
/**************************************************************************** |
|
* File: lib/string/lib_vikmemcpy.c |
|
* |
|
* This is version of the optimized memcpy by Daniel Vik, adapted to the |
|
* NuttX environment. |
|
* |
|
* Copyright (C) 1999-2010 Daniel Vik |
|
* |
|
* Adaptations include: |
|
* - File name change |
|
* - Use of types defined in stdint.h |
|
* - Integration with the NuttX configuration system |
|
* - Other cosmetic changes for consistency with NuttX coding standards |
|
* |
|
* 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 |
|
* 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: |
|
* |
|
* CONFIG_ENDIAN_BIG |
|
* Uses processor with big endian addressing. Default is little endian. |
|
* |
|
* CONFIG_MEMCPY_PRE_INC_PTRS |
|
* Use pre increment of pointers. Default is post increment of pointers. |
|
* |
|
* CONFIG_MEMCPY_INDEXED_COPY |
|
* Copying data using array indexing. Using this option, disables the |
|
* CONFIG_MEMCPY_PRE_INC_PTRS option. |
|
* |
|
* CONFIG_MEMCPY_64BIT - Compiles memcpy for 64 bit architectures |
|
* |
|
****************************************************************************/ |
|
|
|
/**************************************************************************** |
|
* Configuration definitions. |
|
****************************************************************************/ |
|
|
|
#define CONFIG_MEMCPY_INDEXED_COPY |
|
|
|
/******************************************************************** |
|
* Included Files |
|
*******************************************************************/ |
|
|
|
#include <nuttx/config.h> |
|
#include <nuttx/compiler.h> |
|
|
|
#include <stddef.h> |
|
#include <stdint.h> |
|
#include <string.h> |
|
|
|
/******************************************************************** |
|
* Pre-processor Definitions |
|
*******************************************************************/ |
|
|
|
/* Can't support CONFIG_MEMCPY_64BIT if the platform does not have 64-bit |
|
* integer types. |
|
*/ |
|
|
|
#ifndef CONFIG_HAVE_LONG_LONG |
|
# undef CONFIG_MEMCPY_64BIT |
|
#endif |
|
|
|
/* Remove definitions when CONFIG_MEMCPY_INDEXED_COPY is defined */ |
|
|
|
#if defined (CONFIG_MEMCPY_INDEXED_COPY) |
|
# if defined (CONFIG_MEMCPY_PRE_INC_PTRS) |
|
# undef CONFIG_MEMCPY_PRE_INC_PTRS |
|
# endif /* CONFIG_MEMCPY_PRE_INC_PTRS */ |
|
#endif /* CONFIG_MEMCPY_INDEXED_COPY */ |
|
|
|
/* Definitions for pre and post increment of pointers */ |
|
|
|
#if defined (CONFIG_MEMCPY_PRE_INC_PTRS) |
|
|
|
# define START_VAL(x) (x)-- |
|
# define INC_VAL(x) *++(x) |
|
# define CAST_TO_U8(p, o) ((uint8_t*)p + o + TYPE_WIDTH) |
|
# define WHILE_DEST_BREAK (TYPE_WIDTH - 1) |
|
# define PRE_LOOP_ADJUST - (TYPE_WIDTH - 1) |
|
# define PRE_SWITCH_ADJUST + 1 |
|
|
|
#else /* CONFIG_MEMCPY_PRE_INC_PTRS */ |
|
|
|
# define START_VAL(x) |
|
# define INC_VAL(x) *(x)++ |
|
# define CAST_TO_U8(p, o) ((uint8_t*)p + o) |
|
# define WHILE_DEST_BREAK 0 |
|
# define PRE_LOOP_ADJUST |
|
# define PRE_SWITCH_ADJUST |
|
|
|
#endif /* CONFIG_MEMCPY_PRE_INC_PTRS */ |
|
|
|
/* Definitions for endian-ness */ |
|
|
|
#ifdef CONFIG_ENDIAN_BIG |
|
|
|
# define SHL << |
|
# define SHR >> |
|
|
|
#else /* CONFIG_ENDIAN_BIG */ |
|
|
|
# define SHL >> |
|
# define SHR << |
|
|
|
#endif /* CONFIG_ENDIAN_BIG */ |
|
|
|
/******************************************************************** |
|
* 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 (CONFIG_MEMCPY_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 /* CONFIG_MEMCPY_INDEXED_COPY */ |
|
|
|
# define CP(idx) CP_INCR() |
|
# define CP_SH(idx, shl, shr) CP_INCR_SH(shl, shr) |
|
|
|
# define INC_INDEX(p, o) |
|
|
|
#endif /* CONFIG_MEMCPY_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*)((((UIntN)dst8) PRE_LOOP_ADJUST) & \ |
|
~(TYPE_WIDTH - 1)); \ |
|
UIntN* srcN = (UIntN*)((((UIntN)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; \ |
|
} |
|
|
|
/******************************************************************** |
|
* Type Definitions |
|
*******************************************************************/ |
|
|
|
#ifdef CONFIG_MEMCPY_64BIT |
|
typedef uint64_t UIntN; |
|
# define TYPE_WIDTH 8L |
|
#else |
|
typedef uint32_t UIntN; |
|
# define TYPE_WIDTH 4L |
|
#endif |
|
|
|
/******************************************************************** |
|
* Public Functions |
|
*******************************************************************/ |
|
/******************************************************************** |
|
* Name: memcpy |
|
* |
|
* Description: |
|
* Copies count bytes from src to dest. No overlap check is performed. |
|
* |
|
* Input Parameters: |
|
* dest - pointer to destination buffer |
|
* src - pointer to source buffer |
|
* count - number of bytes to copy |
|
* |
|
* Returned Value: |
|
* A pointer to destination buffer |
|
* |
|
*******************************************************************/ |
|
|
|
void *memcpy(void *dest, const void *src, size_t count) |
|
{ |
|
uint8_t *dst8 = (uint8_t*)dest; |
|
uint8_t *src8 = (uint8_t*)src; |
|
|
|
if (count < 8) |
|
{ |
|
COPY_REMAINING(count); |
|
return dest; |
|
} |
|
|
|
START_VAL(dst8); |
|
START_VAL(src8); |
|
|
|
while (((UIntN)dst8 & (TYPE_WIDTH - 1)) != WHILE_DEST_BREAK) |
|
{ |
|
INC_VAL(dst8) = INC_VAL(src8); |
|
count--; |
|
} |
|
|
|
switch ((((UIntN)src8) PRE_SWITCH_ADJUST) & (TYPE_WIDTH - 1)) |
|
{ |
|
case 0: COPY_NO_SHIFT(); break; |
|
case 1: COPY_SHIFT(1); break; |
|
case 2: COPY_SHIFT(2); break; |
|
case 3: COPY_SHIFT(3); break; |
|
#if TYPE_WIDTH > 4 |
|
case 4: COPY_SHIFT(4); break; |
|
case 5: COPY_SHIFT(5); break; |
|
case 6: COPY_SHIFT(6); break; |
|
case 7: COPY_SHIFT(7); break; |
|
#endif |
|
} |
|
|
|
return dest; |
|
}
|
|
|