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.
204 lines
6.2 KiB
204 lines
6.2 KiB
/* |
|
* Copyright (c) 2017 Imagination Technologies. |
|
* |
|
* 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 Imagination Technologies 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. |
|
*/ |
|
|
|
#include <string.h> |
|
|
|
#define op_t unsigned long int |
|
|
|
#if !defined(UNALIGNED_INSTR_SUPPORT) |
|
/* does target have unaligned lw/ld/ualw/uald instructions? */ |
|
#define UNALIGNED_INSTR_SUPPORT 0 |
|
#if __mips_isa_rev < 6 && !__mips1 |
|
#undef UNALIGNED_INSTR_SUPPORT |
|
#define UNALIGNED_INSTR_SUPPORT 1 |
|
#endif |
|
#endif |
|
|
|
#if !defined(HW_UNALIGNED_SUPPORT) |
|
/* Does target have hardware support for unaligned accesses? */ |
|
#define HW_UNALIGNED_SUPPORT 0 |
|
#if __mips_isa_rev >= 6 |
|
#undef HW_UNALIGNED_SUPPORT |
|
#define HW_UNALIGNED_SUPPORT 1 |
|
#endif |
|
#endif |
|
|
|
#if __mips64 |
|
typedef struct |
|
{ |
|
op_t B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8; |
|
} bits_t; |
|
#else |
|
typedef struct |
|
{ |
|
op_t B0:8, B1:8, B2:8, B3:8; |
|
} bits_t; |
|
#endif |
|
|
|
typedef union |
|
{ |
|
op_t v; |
|
bits_t b; |
|
} bitfields_t; |
|
|
|
#if !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT |
|
/* for MIPS GCC, there are no unaligned builtins - so this struct forces |
|
the compiler to treat the pointer access as unaligned. */ |
|
struct ulw |
|
{ |
|
op_t uli; |
|
} __attribute__ ((packed)); |
|
#endif /* !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT */ |
|
|
|
#define DO_BYTE(i, ptdst) { \ |
|
*(ptdst+i) = a.b.B##i; \ |
|
if(a.b.B##i == '\0') \ |
|
return ret; \ |
|
} |
|
|
|
#if __mips64 |
|
#define DO_BYTES(val, dst) { \ |
|
bitfields_t a; \ |
|
char *tdst = (char *)(dst); \ |
|
a.v = val; \ |
|
DO_BYTE(0, tdst) \ |
|
DO_BYTE(1, tdst) \ |
|
DO_BYTE(2, tdst) \ |
|
DO_BYTE(3, tdst) \ |
|
DO_BYTE(4, tdst) \ |
|
DO_BYTE(5, tdst) \ |
|
DO_BYTE(6, tdst) \ |
|
DO_BYTE(7, tdst) \ |
|
} |
|
#else |
|
#define DO_BYTES(val, dst) { \ |
|
bitfields_t a; \ |
|
char *tdst = (char *)(dst); \ |
|
a.v = val; \ |
|
DO_BYTE(0, tdst) \ |
|
DO_BYTE(1, tdst) \ |
|
DO_BYTE(2, tdst) \ |
|
DO_BYTE(3, tdst) \ |
|
} |
|
#endif |
|
|
|
#define DO_WORD_ALIGNED(dst, src) { \ |
|
op_t val = *(src); \ |
|
if ((((val - mask_1) & ~val) & mask_128) != 0) { \ |
|
DO_BYTES(val, dst); \ |
|
} else *(dst) = val; \ |
|
} |
|
|
|
#if !HW_UNALIGNED_SUPPORT |
|
#if UNALIGNED_INSTR_SUPPORT |
|
#define DO_WORD_UNALIGNED(dst, src) { \ |
|
op_t val = *(src); \ |
|
if ((((val - mask_1) & ~val) & mask_128) != 0) { \ |
|
DO_BYTES(val, dst); \ |
|
} else { \ |
|
struct ulw *a = (struct ulw *)(dst); \ |
|
a->uli = val; \ |
|
} \ |
|
} |
|
#else |
|
#define DO_WORD_UNALIGNED(dst, src) { \ |
|
op_t val = *(src); \ |
|
if ((((val - mask_1) & ~val) & mask_128) != 0) { \ |
|
DO_BYTES(val, dst); \ |
|
} else { \ |
|
char *pdst = (char *) dst; \ |
|
const char *psrc = (const char *) src; \ |
|
for (; (*pdst = *psrc) != '\0'; ++psrc, ++pdst); \ |
|
return ret; \ |
|
} \ |
|
} |
|
#endif /* UNALIGNED_INSTR_SUPPORT */ |
|
|
|
#define PROCESS_UNALIGNED_WORDS(a, b) { \ |
|
while (1) { \ |
|
DO_WORD_UNALIGNED(a, b); \ |
|
DO_WORD_UNALIGNED(a + 1, b + 1); \ |
|
DO_WORD_UNALIGNED(a + 2, b + 2); \ |
|
DO_WORD_UNALIGNED(a + 3, b + 3); \ |
|
a += 4; \ |
|
b += 4; \ |
|
} \ |
|
} |
|
#endif /* HW_UNALIGNED_SUPPORT */ |
|
|
|
#define PROCESS_ALIGNED_WORDS(a, b) { \ |
|
while (1) { \ |
|
DO_WORD_ALIGNED(a, b); \ |
|
DO_WORD_ALIGNED(a + 1, b + 1); \ |
|
DO_WORD_ALIGNED(a + 2, b + 2); \ |
|
DO_WORD_ALIGNED(a + 3, b + 3); \ |
|
a += 4; \ |
|
b += 4; \ |
|
} \ |
|
} |
|
|
|
char * |
|
strcpy (char *to, const char *from) __overloadable |
|
{ |
|
char *ret = to; |
|
op_t mask_1, mask_128; |
|
const op_t *src; |
|
op_t *dst; |
|
|
|
for (; (*to = *from) != '\0' && ((size_t) from % sizeof (op_t)) != 0; ++from, ++to); |
|
|
|
if(*to != '\0') { |
|
__asm__ volatile ( |
|
"li %0, 0x01010101 \n\t" |
|
: "=r" (mask_1) |
|
); |
|
#if __mips64 |
|
mask_1 |= mask_1 << 32; |
|
#endif |
|
mask_128 = mask_1 << 7; |
|
|
|
src = (const op_t *) from; |
|
dst = (op_t *) to; |
|
|
|
#if HW_UNALIGNED_SUPPORT |
|
PROCESS_ALIGNED_WORDS(dst, src); |
|
#else |
|
if (((unsigned long) dst) % sizeof (op_t) == 0) { |
|
PROCESS_ALIGNED_WORDS(dst, src); |
|
} else { |
|
PROCESS_UNALIGNED_WORDS(dst, src); |
|
} |
|
#endif |
|
} |
|
|
|
return ret; |
|
}
|
|
|