162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* $Id: memcpy.S,v 1.3 2001/07/27 11:50:52 gniibe Exp $ 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * "memcpy" implementation of SuperH 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1999 Niibe Yutaka 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * void *memcpy(void *dst, const void *src, size_t n); 1262306a36Sopenharmony_ci * No overlap between the memory of DST and of SRC are assumed. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/linkage.h> 1662306a36Sopenharmony_ciENTRY(memcpy) 1762306a36Sopenharmony_ci tst r6,r6 1862306a36Sopenharmony_ci bt/s 9f ! if n=0, do nothing 1962306a36Sopenharmony_ci mov r4,r0 2062306a36Sopenharmony_ci sub r4,r5 ! From here, r5 has the distance to r0 2162306a36Sopenharmony_ci add r6,r0 ! From here, r0 points the end of copying point 2262306a36Sopenharmony_ci mov #12,r1 2362306a36Sopenharmony_ci cmp/gt r6,r1 2462306a36Sopenharmony_ci bt/s 7f ! if it's too small, copy a byte at once 2562306a36Sopenharmony_ci add #-1,r5 2662306a36Sopenharmony_ci add #1,r5 2762306a36Sopenharmony_ci ! From here, r6 is free 2862306a36Sopenharmony_ci ! 2962306a36Sopenharmony_ci ! r4 --> [ ... ] DST [ ... ] SRC 3062306a36Sopenharmony_ci ! [ ... ] [ ... ] 3162306a36Sopenharmony_ci ! : : 3262306a36Sopenharmony_ci ! r0 --> [ ... ] r0+r5 --> [ ... ] 3362306a36Sopenharmony_ci ! 3462306a36Sopenharmony_ci ! 3562306a36Sopenharmony_ci mov r5,r1 3662306a36Sopenharmony_ci mov #3,r2 3762306a36Sopenharmony_ci and r2,r1 3862306a36Sopenharmony_ci shll2 r1 3962306a36Sopenharmony_ci mov r0,r3 ! Save the value on R0 to R3 4062306a36Sopenharmony_ci mova jmptable,r0 4162306a36Sopenharmony_ci add r1,r0 4262306a36Sopenharmony_ci mov.l @r0,r1 4362306a36Sopenharmony_ci jmp @r1 4462306a36Sopenharmony_ci mov r3,r0 ! and back to R0 4562306a36Sopenharmony_ci .balign 4 4662306a36Sopenharmony_cijmptable: 4762306a36Sopenharmony_ci .long case0 4862306a36Sopenharmony_ci .long case1 4962306a36Sopenharmony_ci .long case2 5062306a36Sopenharmony_ci .long case3 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ! copy a byte at once 5362306a36Sopenharmony_ci7: mov r4,r2 5462306a36Sopenharmony_ci add #1,r2 5562306a36Sopenharmony_ci8: 5662306a36Sopenharmony_ci cmp/hi r2,r0 5762306a36Sopenharmony_ci mov.b @(r0,r5),r1 5862306a36Sopenharmony_ci bt/s 8b ! while (r0>r2) 5962306a36Sopenharmony_ci mov.b r1,@-r0 6062306a36Sopenharmony_ci9: 6162306a36Sopenharmony_ci rts 6262306a36Sopenharmony_ci nop 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cicase0: 6562306a36Sopenharmony_ci ! 6662306a36Sopenharmony_ci ! GHIJ KLMN OPQR --> GHIJ KLMN OPQR 6762306a36Sopenharmony_ci ! 6862306a36Sopenharmony_ci ! First, align to long word boundary 6962306a36Sopenharmony_ci mov r0,r3 7062306a36Sopenharmony_ci and r2,r3 7162306a36Sopenharmony_ci tst r3,r3 7262306a36Sopenharmony_ci bt/s 2f 7362306a36Sopenharmony_ci add #-4,r5 7462306a36Sopenharmony_ci add #3,r5 7562306a36Sopenharmony_ci1: dt r3 7662306a36Sopenharmony_ci mov.b @(r0,r5),r1 7762306a36Sopenharmony_ci bf/s 1b 7862306a36Sopenharmony_ci mov.b r1,@-r0 7962306a36Sopenharmony_ci ! 8062306a36Sopenharmony_ci add #-3,r5 8162306a36Sopenharmony_ci2: ! Second, copy a long word at once 8262306a36Sopenharmony_ci mov r4,r2 8362306a36Sopenharmony_ci add #7,r2 8462306a36Sopenharmony_ci3: mov.l @(r0,r5),r1 8562306a36Sopenharmony_ci cmp/hi r2,r0 8662306a36Sopenharmony_ci bt/s 3b 8762306a36Sopenharmony_ci mov.l r1,@-r0 8862306a36Sopenharmony_ci ! 8962306a36Sopenharmony_ci ! Third, copy a byte at once, if necessary 9062306a36Sopenharmony_ci cmp/eq r4,r0 9162306a36Sopenharmony_ci bt/s 9b 9262306a36Sopenharmony_ci add #3,r5 9362306a36Sopenharmony_ci bra 8b 9462306a36Sopenharmony_ci add #-6,r2 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cicase1: 9762306a36Sopenharmony_ci ! 9862306a36Sopenharmony_ci ! GHIJ KLMN OPQR --> ...G HIJK LMNO PQR. 9962306a36Sopenharmony_ci ! 10062306a36Sopenharmony_ci ! First, align to long word boundary 10162306a36Sopenharmony_ci mov r0,r3 10262306a36Sopenharmony_ci and r2,r3 10362306a36Sopenharmony_ci tst r3,r3 10462306a36Sopenharmony_ci bt/s 2f 10562306a36Sopenharmony_ci add #-1,r5 10662306a36Sopenharmony_ci1: dt r3 10762306a36Sopenharmony_ci mov.b @(r0,r5),r1 10862306a36Sopenharmony_ci bf/s 1b 10962306a36Sopenharmony_ci mov.b r1,@-r0 11062306a36Sopenharmony_ci ! 11162306a36Sopenharmony_ci2: ! Second, read a long word and write a long word at once 11262306a36Sopenharmony_ci mov.l @(r0,r5),r1 11362306a36Sopenharmony_ci add #-4,r5 11462306a36Sopenharmony_ci mov r4,r2 11562306a36Sopenharmony_ci add #7,r2 11662306a36Sopenharmony_ci ! 11762306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 11862306a36Sopenharmony_ci3: mov r1,r3 ! RQPO 11962306a36Sopenharmony_ci shll16 r3 12062306a36Sopenharmony_ci shll8 r3 ! Oxxx 12162306a36Sopenharmony_ci mov.l @(r0,r5),r1 ! NMLK 12262306a36Sopenharmony_ci mov r1,r6 12362306a36Sopenharmony_ci shlr8 r6 ! xNML 12462306a36Sopenharmony_ci or r6,r3 ! ONML 12562306a36Sopenharmony_ci cmp/hi r2,r0 12662306a36Sopenharmony_ci bt/s 3b 12762306a36Sopenharmony_ci mov.l r3,@-r0 12862306a36Sopenharmony_ci#else 12962306a36Sopenharmony_ci3: mov r1,r3 ! OPQR 13062306a36Sopenharmony_ci shlr16 r3 13162306a36Sopenharmony_ci shlr8 r3 ! xxxO 13262306a36Sopenharmony_ci mov.l @(r0,r5),r1 ! KLMN 13362306a36Sopenharmony_ci mov r1,r6 13462306a36Sopenharmony_ci shll8 r6 ! LMNx 13562306a36Sopenharmony_ci or r6,r3 ! LMNO 13662306a36Sopenharmony_ci cmp/hi r2,r0 13762306a36Sopenharmony_ci bt/s 3b 13862306a36Sopenharmony_ci mov.l r3,@-r0 13962306a36Sopenharmony_ci#endif 14062306a36Sopenharmony_ci ! 14162306a36Sopenharmony_ci ! Third, copy a byte at once, if necessary 14262306a36Sopenharmony_ci cmp/eq r4,r0 14362306a36Sopenharmony_ci bt/s 9b 14462306a36Sopenharmony_ci add #4,r5 14562306a36Sopenharmony_ci bra 8b 14662306a36Sopenharmony_ci add #-6,r2 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cicase2: 14962306a36Sopenharmony_ci ! 15062306a36Sopenharmony_ci ! GHIJ KLMN OPQR --> ..GH IJKL MNOP QR.. 15162306a36Sopenharmony_ci ! 15262306a36Sopenharmony_ci ! First, align to word boundary 15362306a36Sopenharmony_ci tst #1,r0 15462306a36Sopenharmony_ci bt/s 2f 15562306a36Sopenharmony_ci add #-1,r5 15662306a36Sopenharmony_ci mov.b @(r0,r5),r1 15762306a36Sopenharmony_ci mov.b r1,@-r0 15862306a36Sopenharmony_ci ! 15962306a36Sopenharmony_ci2: ! Second, read a word and write a word at once 16062306a36Sopenharmony_ci add #-1,r5 16162306a36Sopenharmony_ci mov r4,r2 16262306a36Sopenharmony_ci add #3,r2 16362306a36Sopenharmony_ci ! 16462306a36Sopenharmony_ci3: mov.w @(r0,r5),r1 16562306a36Sopenharmony_ci cmp/hi r2,r0 16662306a36Sopenharmony_ci bt/s 3b 16762306a36Sopenharmony_ci mov.w r1,@-r0 16862306a36Sopenharmony_ci ! 16962306a36Sopenharmony_ci ! Third, copy a byte at once, if necessary 17062306a36Sopenharmony_ci cmp/eq r4,r0 17162306a36Sopenharmony_ci bt/s 9b 17262306a36Sopenharmony_ci add #1,r5 17362306a36Sopenharmony_ci mov.b @(r0,r5),r1 17462306a36Sopenharmony_ci rts 17562306a36Sopenharmony_ci mov.b r1,@-r0 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cicase3: 17862306a36Sopenharmony_ci ! 17962306a36Sopenharmony_ci ! GHIJ KLMN OPQR --> .GHI JKLM NOPQ R... 18062306a36Sopenharmony_ci ! 18162306a36Sopenharmony_ci ! First, align to long word boundary 18262306a36Sopenharmony_ci mov r0,r3 18362306a36Sopenharmony_ci and r2,r3 18462306a36Sopenharmony_ci tst r3,r3 18562306a36Sopenharmony_ci bt/s 2f 18662306a36Sopenharmony_ci add #-1,r5 18762306a36Sopenharmony_ci1: dt r3 18862306a36Sopenharmony_ci mov.b @(r0,r5),r1 18962306a36Sopenharmony_ci bf/s 1b 19062306a36Sopenharmony_ci mov.b r1,@-r0 19162306a36Sopenharmony_ci ! 19262306a36Sopenharmony_ci2: ! Second, read a long word and write a long word at once 19362306a36Sopenharmony_ci add #-2,r5 19462306a36Sopenharmony_ci mov.l @(r0,r5),r1 19562306a36Sopenharmony_ci add #-4,r5 19662306a36Sopenharmony_ci mov r4,r2 19762306a36Sopenharmony_ci add #7,r2 19862306a36Sopenharmony_ci ! 19962306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__ 20062306a36Sopenharmony_ci3: mov r1,r3 ! RQPO 20162306a36Sopenharmony_ci shll8 r3 ! QPOx 20262306a36Sopenharmony_ci mov.l @(r0,r5),r1 ! NMLK 20362306a36Sopenharmony_ci mov r1,r6 20462306a36Sopenharmony_ci shlr16 r6 20562306a36Sopenharmony_ci shlr8 r6 ! xxxN 20662306a36Sopenharmony_ci or r6,r3 ! QPON 20762306a36Sopenharmony_ci cmp/hi r2,r0 20862306a36Sopenharmony_ci bt/s 3b 20962306a36Sopenharmony_ci mov.l r3,@-r0 21062306a36Sopenharmony_ci#else 21162306a36Sopenharmony_ci3: mov r1,r3 ! OPQR 21262306a36Sopenharmony_ci shlr8 r3 ! xOPQ 21362306a36Sopenharmony_ci mov.l @(r0,r5),r1 ! KLMN 21462306a36Sopenharmony_ci mov r1,r6 21562306a36Sopenharmony_ci shll16 r6 21662306a36Sopenharmony_ci shll8 r6 ! Nxxx 21762306a36Sopenharmony_ci or r6,r3 ! NOPQ 21862306a36Sopenharmony_ci cmp/hi r2,r0 21962306a36Sopenharmony_ci bt/s 3b 22062306a36Sopenharmony_ci mov.l r3,@-r0 22162306a36Sopenharmony_ci#endif 22262306a36Sopenharmony_ci ! 22362306a36Sopenharmony_ci ! Third, copy a byte at once, if necessary 22462306a36Sopenharmony_ci cmp/eq r4,r0 22562306a36Sopenharmony_ci bt/s 9b 22662306a36Sopenharmony_ci add #6,r5 22762306a36Sopenharmony_ci bra 8b 22862306a36Sopenharmony_ci add #-6,r2 229