| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* $Id: memmove.S,v 1.2 2001/07/27 11:51:09 gniibe Exp $ | |
| * | |
| * "memmove" implementation of SuperH | |
| * | |
| * Copyright (C) 1999 Niibe Yutaka | |
| * | |
| */ | |
| /* | |
| * void *memmove(void *dst, const void *src, size_t n); | |
| * The memory areas may overlap. | |
| */ | |
| #include <linux/linkage.h> | |
| ENTRY(memmove) | |
| ! if dest > src, call memcpy (it copies in decreasing order) | |
| cmp/hi r5,r4 | |
| bf 1f | |
| mov.l 2f,r0 | |
| jmp @r0 | |
| nop | |
| .balign 4 | |
| 2: .long memcpy | |
| 1: | |
| sub r5,r4 ! From here, r4 has the distance to r0 | |
| tst r6,r6 | |
| bt/s 9f ! if n=0, do nothing | |
| mov r5,r0 | |
| add r6,r5 | |
| mov #12,r1 | |
| cmp/gt r6,r1 | |
| bt/s 8f ! if it's too small, copy a byte at once | |
| add #-1,r4 | |
| add #1,r4 | |
| ! | |
| ! [ ... ] DST [ ... ] SRC | |
| ! [ ... ] [ ... ] | |
| ! : : | |
| ! r0+r4--> [ ... ] r0 --> [ ... ] | |
| ! : : | |
| ! [ ... ] [ ... ] | |
| ! r5 --> | |
| ! | |
| mov r4,r1 | |
| mov #3,r2 | |
| and r2,r1 | |
| shll2 r1 | |
| mov r0,r3 ! Save the value on R0 to R3 | |
| mova jmptable,r0 | |
| add r1,r0 | |
| mov.l @r0,r1 | |
| jmp @r1 | |
| mov r3,r0 ! and back to R0 | |
| .balign 4 | |
| jmptable: | |
| .long case0 | |
| .long case1 | |
| .long case2 | |
| .long case3 | |
| ! copy a byte at once | |
| 8: mov.b @r0+,r1 | |
| cmp/hs r5,r0 | |
| bf/s 8b ! while (r0<r5) | |
| mov.b r1,@(r0,r4) | |
| add #1,r4 | |
| 9: | |
| add r4,r0 | |
| rts | |
| sub r6,r0 | |
| case_none: | |
| bra 8b | |
| add #-1,r4 | |
| case0: | |
| ! | |
| ! GHIJ KLMN OPQR --> GHIJ KLMN OPQR | |
| ! | |
| ! First, align to long word boundary | |
| mov r0,r3 | |
| and r2,r3 | |
| tst r3,r3 | |
| bt/s 2f | |
| add #-1,r4 | |
| mov #4,r2 | |
| sub r3,r2 | |
| 1: dt r2 | |
| mov.b @r0+,r1 | |
| bf/s 1b | |
| mov.b r1,@(r0,r4) | |
| ! | |
| 2: ! Second, copy a long word at once | |
| add #-3,r4 | |
| add #-3,r5 | |
| 3: mov.l @r0+,r1 | |
| cmp/hs r5,r0 | |
| bf/s 3b | |
| mov.l r1,@(r0,r4) | |
| add #3,r5 | |
| ! | |
| ! Third, copy a byte at once, if necessary | |
| cmp/eq r5,r0 | |
| bt/s 9b | |
| add #4,r4 | |
| bra 8b | |
| add #-1,r4 | |
| case3: | |
| ! | |
| ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR. | |
| ! | |
| ! First, align to long word boundary | |
| mov r0,r3 | |
| and r2,r3 | |
| tst r3,r3 | |
| bt/s 2f | |
| add #-1,r4 | |
| mov #4,r2 | |
| sub r3,r2 | |
| 1: dt r2 | |
| mov.b @r0+,r1 | |
| bf/s 1b | |
| mov.b r1,@(r0,r4) | |
| ! | |
| 2: ! Second, read a long word and write a long word at once | |
| add #-2,r4 | |
| mov.l @(r0,r4),r1 | |
| add #-7,r5 | |
| add #-4,r4 | |
| ! | |
| #ifdef __LITTLE_ENDIAN__ | |
| shll8 r1 | |
| 3: mov r1,r3 ! JIHG | |
| shlr8 r3 ! xJIH | |
| mov.l @r0+,r1 ! NMLK | |
| mov r1,r2 | |
| shll16 r2 | |
| shll8 r2 ! Kxxx | |
| or r2,r3 ! KJIH | |
| cmp/hs r5,r0 | |
| bf/s 3b | |
| mov.l r3,@(r0,r4) | |
| #else | |
| shlr8 r1 | |
| 3: mov r1,r3 ! GHIJ | |
| shll8 r3 ! HIJx | |
| mov.l @r0+,r1 ! KLMN | |
| mov r1,r2 | |
| shlr16 r2 | |
| shlr8 r2 ! xxxK | |
| or r2,r3 ! HIJK | |
| cmp/hs r5,r0 | |
| bf/s 3b | |
| mov.l r3,@(r0,r4) | |
| #endif | |
| add #7,r5 | |
| ! | |
| ! Third, copy a byte at once, if necessary | |
| cmp/eq r5,r0 | |
| bt/s 9b | |
| add #7,r4 | |
| add #-3,r0 | |
| bra 8b | |
| add #-1,r4 | |
| case2: | |
| ! | |
| ! GHIJ KLMN OPQR --> ..GH IJKL MNOP QR.. | |
| ! | |
| ! First, align to word boundary | |
| tst #1,r0 | |
| bt/s 2f | |
| add #-1,r4 | |
| mov.b @r0+,r1 | |
| mov.b r1,@(r0,r4) | |
| ! | |
| 2: ! Second, read a word and write a word at once | |
| add #-1,r4 | |
| add #-1,r5 | |
| ! | |
| 3: mov.w @r0+,r1 | |
| cmp/hs r5,r0 | |
| bf/s 3b | |
| mov.w r1,@(r0,r4) | |
| add #1,r5 | |
| ! | |
| ! Third, copy a byte at once, if necessary | |
| cmp/eq r5,r0 | |
| bt/s 9b | |
| add #2,r4 | |
| mov.b @r0,r1 | |
| mov.b r1,@(r0,r4) | |
| bra 9b | |
| add #1,r0 | |
| case1: | |
| ! | |
| ! GHIJ KLMN OPQR --> .GHI JKLM NOPQ R... | |
| ! | |
| ! First, align to long word boundary | |
| mov r0,r3 | |
| and r2,r3 | |
| tst r3,r3 | |
| bt/s 2f | |
| add #-1,r4 | |
| mov #4,r2 | |
| sub r3,r2 | |
| 1: dt r2 | |
| mov.b @r0+,r1 | |
| bf/s 1b | |
| mov.b r1,@(r0,r4) | |
| ! | |
| 2: ! Second, read a long word and write a long word at once | |
| mov.l @(r0,r4),r1 | |
| add #-7,r5 | |
| add #-4,r4 | |
| ! | |
| #ifdef __LITTLE_ENDIAN__ | |
| shll16 r1 | |
| shll8 r1 | |
| 3: mov r1,r3 ! JIHG | |
| shlr16 r3 | |
| shlr8 r3 ! xxxJ | |
| mov.l @r0+,r1 ! NMLK | |
| mov r1,r2 | |
| shll8 r2 ! MLKx | |
| or r2,r3 ! MLKJ | |
| cmp/hs r5,r0 | |
| bf/s 3b | |
| mov.l r3,@(r0,r4) | |
| #else | |
| shlr16 r1 | |
| shlr8 r1 | |
| 3: mov r1,r3 ! GHIJ | |
| shll16 r3 | |
| shll8 r3 ! Jxxx | |
| mov.l @r0+,r1 ! KLMN | |
| mov r1,r2 | |
| shlr8 r2 ! xKLM | |
| or r2,r3 ! JKLM | |
| cmp/hs r5,r0 | |
| bf/s 3b ! while(r0<r5) | |
| mov.l r3,@(r0,r4) | |
| #endif | |
| add #7,r5 | |
| ! | |
| ! Third, copy a byte at once, if necessary | |
| cmp/eq r5,r0 | |
| bt/s 9b | |
| add #5,r4 | |
| add #-3,r0 | |
| bra 8b | |
| add #-1,r4 |