diff options
Diffstat (limited to 'src/engine/libc.c')
-rw-r--r-- | src/engine/libc.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/engine/libc.c b/src/engine/libc.c new file mode 100644 index 000000000..920673e3e --- /dev/null +++ b/src/engine/libc.c @@ -0,0 +1,143 @@ +#include "global.h" +#include <stddef.h> + +#define LBLOCKSIZE (sizeof(long)) + +// Nonzero if (long)X contains a NULL byte. +#define CONTAINSNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) + +// Nonzero if X is not aligned on a "long" boundary. +#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) + +void *memcpy(void *dst0, const void *src0, size_t len0) +{ + char *dst = dst0; + const char *src = src0; + long *aligned_dst; + const long *aligned_src; + unsigned int len = len0; + + // If the size is small, or either src or dst is unaligned, + // then go to the byte copy loop. This should be rare. + if (len >= 16 && !(UNALIGNED(src) | UNALIGNED(dst))) + { + aligned_dst = (long *)dst; + aligned_src = (long *)src; + + // Copy 4X long words at a time if possible. + while (len >= 16) + { + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + len -= 16; + } + + // Copy one long word at a time if possible + while (len >= 4) + { + *aligned_dst++ = *aligned_src++; + len -= 4; + } + + dst = (char *)aligned_dst; + src = (char *)aligned_src; + } + + // Pick up any remaining bytes with a byte copier. + while (len--) + *dst++ = *src++; + + return dst0; +} + +void *memset(void *m, int c, size_t n) +{ + char *s = (char *)m; + int count, i; + unsigned long buffer; + unsigned long *aligned_addr; + unsigned char *unaligned_addr; + + // If the size is small or m is unaligned, + // then go to the byte copy loop. This should be rare. + if (n >= LBLOCKSIZE && !UNALIGNED(m)) + { + // We know that n is large and m is word-aligned. + aligned_addr = (unsigned long *)m; + + // Store C into each char sized location in buffer so that + // we can set large blocks quickly. + c &= 0xFF; + if (LBLOCKSIZE == 4) + { + buffer = (c << 8) | c; + buffer |= (buffer << 16); + } + else + { + buffer = 0; + for (i = 0; i < LBLOCKSIZE; i++) + buffer = (buffer << 8) | c; + } + + while (n >= LBLOCKSIZE * 4) + { + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + n -= LBLOCKSIZE * 4; + } + while (n >= LBLOCKSIZE) + { + *aligned_addr++ = buffer; + n -= LBLOCKSIZE; + } + + s = (char *)aligned_addr; + } + + // Pick up the remainder with a bytewise loop. + while (n--) + *s++ = (char)c; + + return m; +} + +int strcmp(const char *s1, const char *s2) +{ + unsigned long *a1; + unsigned long *a2; + + // If s1 or s2 are unaligned, then skip this and compare bytes. + if (!(UNALIGNED(s1) | UNALIGNED(s2))) + { + // Compare them a word at a time. + a1 = (unsigned long *)s1; + a2 = (unsigned long *)s2; + while (*a1 == *a2) + { + // If *a1 == *a2, and we find a null in *a1, + // then the strings must be equal, so return zero. + if (CONTAINSNULL(*a1)) + return 0; + + a1++; + a2++; + } + + s1 = (char *)a1; + s2 = (char *)a2; + } + + // Check the remaining few bytes. + while (*s1 != '\0' && *s1 == *s2) + { + s1++; + s2++; + } + + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +} |