diff --git a/src/libc/memmove.src b/src/libc/memmove.src new file mode 100644 index 000000000..e684f11c7 --- /dev/null +++ b/src/libc/memmove.src @@ -0,0 +1,100 @@ + assume adl=1 + + section .text + + public _memmove + +if PREFER_OS_LIBC + +_memmove := 0000A8h + +else + +if 1 + +; Optimized for when src != dst +_memmove: + ; src > dst | LDIR | 32F + 15R + 1 + ; src < dst | LDDR | 35F + 12R + 2 + ; src = dst | LDDR | 35F + 12R + 2 + ; zero size | | 24F + 12R + 2 + + ld iy, -1 + add iy, sp + ld bc, (iy + 10) + sbc hl, hl + add hl, bc + jr nc, .zero + ld hl, (iy + 7) + ld de, (iy + 4) + sbc hl, de + ; src <= dst + jr c, .copy_backwards + ; src > dst +; .copy_forwards: + add hl, de + inc hl + ldir +.zero: + ld hl, (iy + 4) + ret + +.copy_backwards: + ; move HL and DE to the end + ex de, hl + add hl, bc + ex de, hl ; HL = src - dst - 1, DE = dst + size + add hl, de ; HL = src + size - 1 + dec de ; DE = dst + size - 1 + lddr + ex de, hl + inc hl + ret + +else + +; Optimized for when src == dst +_memmove: + ; src > dst | LDIR | 33F + 15R + 2 + ; src < dst | LDDR | 36F + 12R + 2 + ; src = dst | | 29F + 12R + 2 + ; zero size | | 24F + 12R + 2 + + ld iy, -1 + add iy, sp + ld bc, (iy + 10) + sbc hl, hl + add hl, bc + jr nc, .zero + ld de, (iy + 4) + ld hl, (iy + 7) + or a, a + sbc hl, de + ; src < dst + jr c, .copy_backwards + ; src >= dst +; .copy_forwards: + add hl, de + ; src == dst + ret z ; skips LDIR when src == dst + ; src > dst + ldir +.zero: + ld hl, (iy + 4) + ret + +.copy_backwards: + ; move HL and DE to the end + dec de ; DE = dst - 1 + ex de, hl + add hl, bc ; HL = dst + size - 1, DE = src - dst + ex de, hl + add hl, de ; HL = src + size - 1, DE = dst + size - 1 + lddr + ex de, hl + inc hl + ret + +end if + +end if diff --git a/src/libc/os.src b/src/libc/os.src index e78ada685..0eea559ee 100644 --- a/src/libc/os.src +++ b/src/libc/os.src @@ -8,8 +8,6 @@ _longjmp := 000098h _memchr := 00009Ch public _memcmp _memcmp := 0000A0h - public _memmove -_memmove := 0000A8h public _setjmp _setjmp := 0000B8h public _strcat diff --git a/test/standalone/asprintf_fprintf/src/main.c b/test/standalone/asprintf_fprintf/src/main.c index 7fcde2e94..3bf27ccef 100644 --- a/test/standalone/asprintf_fprintf/src/main.c +++ b/test/standalone/asprintf_fprintf/src/main.c @@ -33,6 +33,9 @@ extern void* NULL_ptr; void *T_memcpy(void *__restrict dest, const void *__restrict src, size_t n) __attribute__((nonnull(1, 2))); +void *T_memmove(void *dest, const void *src, size_t n) + __attribute__((nonnull(1, 2))); + void *T_memset(void *s, int c, size_t n) __attribute__((nonnull(1))); @@ -65,6 +68,7 @@ void T_bzero(void* s, size_t n); #else #define T_memcpy memcpy +#define T_memmove memmove #define T_memset memset #define T_memcmp memcmp #define T_memccpy memccpy @@ -575,6 +579,24 @@ int memrchr_test(void) { return 0; } +int memmove_test(void) { + char move_str[] = "0123456789"; + const char truth_str[] = "9344545689"; + C(move_str + 5 == (char*)T_memmove(move_str + 5, move_str + 4, 3)); + C(move_str + 3 == (char*)T_memmove(move_str + 3, move_str + 3, 0)); + C(move_str + 1 == (char*)T_memmove(move_str + 1, move_str + 3, 4)); + C(move_str + 2 == (char*)T_memmove(move_str + 2, move_str + 2, 6)); + C(move_str + 9 == (char*)T_memmove(move_str + 9, move_str + 0, 0)); + C(move_str + 0 == (char*)T_memmove(move_str + 0, move_str + 9, 1)); + C(strcmp(move_str, truth_str) == 0); + + C(NULL_ptr - 0 == (char*)T_memmove(NULL_ptr - 0, NULL_ptr - 0, 0)); + C(NULL_ptr - 0 == (char*)T_memmove(NULL_ptr - 0, NULL_ptr - 1, 0)); + C(NULL_ptr - 1 == (char*)T_memmove(NULL_ptr - 1, NULL_ptr - 0, 0)); + + return 0; +} + int run_tests(void) { int ret = 0; /* boot_asprintf */ @@ -608,10 +630,14 @@ int run_tests(void) { ret = strncmp_test(); if (ret != 0) { return ret; } - /* strncmp */ + /* memrchr */ ret = memrchr_test(); if (ret != 0) { return ret; } + /* memrchr */ + ret = memmove_test(); + if (ret != 0) { return ret; } + return 0; } diff --git a/test/standalone/asprintf_fprintf/src/rename.asm b/test/standalone/asprintf_fprintf/src/rename.asm index af6b27aba..a14203fe8 100644 --- a/test/standalone/asprintf_fprintf/src/rename.asm +++ b/test/standalone/asprintf_fprintf/src/rename.asm @@ -2,12 +2,13 @@ section .text - public _T_memset, _T_memcpy, _T_memcmp, _T_memccpy, _T_mempcpy, _T_memrchr + public _T_memset, _T_memcpy, _T_memmove, _T_memcmp, _T_memccpy, _T_mempcpy, _T_memrchr public _T_strlen, _T_strcmp, _T_strncmp, _T_stpcpy public _T_bzero _T_memset := _memset _T_memcpy := _memcpy +_T_memmove := _memmove _T_memcmp := _memcmp _T_memccpy := _memccpy _T_mempcpy := _mempcpy @@ -26,6 +27,6 @@ _T_bzero := _bzero _NULL_ptr: db $00, $00, $00 - extern _memset, _memcpy, _memcmp, _memccpy, _mempcpy, _memrchr + extern _memset, _memcpy, _memmove, _memcmp, _memccpy, _mempcpy, _memrchr extern _strlen, _strcmp, _strncmp, _stpcpy extern _bzero