linux/arch/microblaze/lib/memcpy.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
   3 * Copyright (C) 2008-2009 PetaLogix
   4 * Copyright (C) 2007 John Williams
   5 *
   6 * Reasonably optimised generic C-code for memcpy on Microblaze
   7 * This is generic C code to do efficient, alignment-aware memcpy.
   8 *
   9 * It is based on demo code originally Copyright 2001 by Intel Corp, taken from
  10 * http://www.embedded.com/showArticle.jhtml?articleID=19205567
  11 *
  12 * Attempts were made, unsuccessfully, to contact the original
  13 * author of this code (Michael Morrow, Intel).  Below is the original
  14 * copyright notice.
  15 *
  16 * This software has been developed by Intel Corporation.
  17 * Intel specifically disclaims all warranties, express or
  18 * implied, and all liability, including consequential and
  19 * other indirect damages, for the use of this program, including
  20 * liability for infringement of any proprietary rights,
  21 * and including the warranties of merchantability and fitness
  22 * for a particular purpose. Intel does not assume any
  23 * responsibility for and errors which may appear in this program
  24 * not any responsibility to update it.
  25 */
  26
  27#include <linux/types.h>
  28#include <linux/stddef.h>
  29#include <linux/compiler.h>
  30#include <linux/module.h>
  31
  32#include <linux/string.h>
  33#include <asm/system.h>
  34
  35#ifdef __HAVE_ARCH_MEMCPY
  36#ifndef CONFIG_OPT_LIB_FUNCTION
  37void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
  38{
  39        const char *src = v_src;
  40        char *dst = v_dst;
  41
  42        /* Simple, byte oriented memcpy. */
  43        while (c--)
  44                *dst++ = *src++;
  45
  46        return v_dst;
  47}
  48#else /* CONFIG_OPT_LIB_FUNCTION */
  49void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
  50{
  51        const char *src = v_src;
  52        char *dst = v_dst;
  53
  54        /* The following code tries to optimize the copy by using unsigned
  55         * alignment. This will work fine if both source and destination are
  56         * aligned on the same boundary. However, if they are aligned on
  57         * different boundaries shifts will be necessary. This might result in
  58         * bad performance on MicroBlaze systems without a barrel shifter.
  59         */
  60        const uint32_t *i_src;
  61        uint32_t *i_dst;
  62
  63        if (likely(c >= 4)) {
  64                unsigned  value, buf_hold;
  65
  66                /* Align the dstination to a word boundry. */
  67                /* This is done in an endian independant manner. */
  68                switch ((unsigned long)dst & 3) {
  69                case 1:
  70                        *dst++ = *src++;
  71                        --c;
  72                case 2:
  73                        *dst++ = *src++;
  74                        --c;
  75                case 3:
  76                        *dst++ = *src++;
  77                        --c;
  78                }
  79
  80                i_dst = (void *)dst;
  81
  82                /* Choose a copy scheme based on the source */
  83                /* alignment relative to dstination. */
  84                switch ((unsigned long)src & 3) {
  85                case 0x0:       /* Both byte offsets are aligned */
  86                        i_src  = (const void *)src;
  87
  88                        for (; c >= 4; c -= 4)
  89                                *i_dst++ = *i_src++;
  90
  91                        src  = (const void *)i_src;
  92                        break;
  93                case 0x1:       /* Unaligned - Off by 1 */
  94                        /* Word align the source */
  95                        i_src = (const void *) ((unsigned)src & ~3);
  96#ifndef __MICROBLAZEEL__
  97                        /* Load the holding buffer */
  98                        buf_hold = *i_src++ << 8;
  99
 100                        for (; c >= 4; c -= 4) {
 101                                value = *i_src++;
 102                                *i_dst++ = buf_hold | value >> 24;
 103                                buf_hold = value << 8;
 104                        }
 105#else
 106                        /* Load the holding buffer */
 107                        buf_hold = (*i_src++ & 0xFFFFFF00) >>8;
 108
 109                        for (; c >= 4; c -= 4) {
 110                                value = *i_src++;
 111                                *i_dst++ = buf_hold | ((value & 0xFF) << 24);
 112                                buf_hold = (value & 0xFFFFFF00) >>8;
 113                        }
 114#endif
 115                        /* Realign the source */
 116                        src = (const void *)i_src;
 117                        src -= 3;
 118                        break;
 119                case 0x2:       /* Unaligned - Off by 2 */
 120                        /* Word align the source */
 121                        i_src = (const void *) ((unsigned)src & ~3);
 122#ifndef __MICROBLAZEEL__
 123                        /* Load the holding buffer */
 124                        buf_hold = *i_src++ << 16;
 125
 126                        for (; c >= 4; c -= 4) {
 127                                value = *i_src++;
 128                                *i_dst++ = buf_hold | value >> 16;
 129                                buf_hold = value << 16;
 130                        }
 131#else
 132                        /* Load the holding buffer */
 133                        buf_hold = (*i_src++ & 0xFFFF0000 )>>16;
 134
 135                        for (; c >= 4; c -= 4) {
 136                                value = *i_src++;
 137                                *i_dst++ = buf_hold | ((value & 0xFFFF)<<16);
 138                                buf_hold = (value & 0xFFFF0000) >>16;
 139                        }
 140#endif
 141                        /* Realign the source */
 142                        src = (const void *)i_src;
 143                        src -= 2;
 144                        break;
 145                case 0x3:       /* Unaligned - Off by 3 */
 146                        /* Word align the source */
 147                        i_src = (const void *) ((unsigned)src & ~3);
 148#ifndef __MICROBLAZEEL__
 149                        /* Load the holding buffer */
 150                        buf_hold = *i_src++ << 24;
 151
 152                        for (; c >= 4; c -= 4) {
 153                                value = *i_src++;
 154                                *i_dst++ = buf_hold | value >> 8;
 155                                buf_hold = value << 24;
 156                        }
 157#else
 158                        /* Load the holding buffer */
 159                        buf_hold = (*i_src++ & 0xFF000000) >> 24;
 160
 161                        for (; c >= 4; c -= 4) {
 162                                value = *i_src++;
 163                                *i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
 164                                buf_hold = (value & 0xFF000000) >> 24;
 165                        }
 166#endif
 167                        /* Realign the source */
 168                        src = (const void *)i_src;
 169                        src -= 1;
 170                        break;
 171                }
 172                dst = (void *)i_dst;
 173        }
 174
 175        /* Finish off any remaining bytes */
 176        /* simple fast copy, ... unless a cache boundry is crossed */
 177        switch (c) {
 178        case 3:
 179                *dst++ = *src++;
 180        case 2:
 181                *dst++ = *src++;
 182        case 1:
 183                *dst++ = *src++;
 184        }
 185
 186        return v_dst;
 187}
 188#endif /* CONFIG_OPT_LIB_FUNCTION */
 189EXPORT_SYMBOL(memcpy);
 190#endif /* __HAVE_ARCH_MEMCPY */
 191