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