18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * copy_page, __copy_user_page, __copy_user implementation of SuperH
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2001  Niibe Yutaka & Kaz Kojima
68c2ecf20Sopenharmony_ci * Copyright (C) 2002  Toshinobu Sugioka
78c2ecf20Sopenharmony_ci * Copyright (C) 2006  Paul Mundt
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/linkage.h>
108c2ecf20Sopenharmony_ci#include <asm/page.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/*
138c2ecf20Sopenharmony_ci * copy_page
148c2ecf20Sopenharmony_ci * @to: P1 address
158c2ecf20Sopenharmony_ci * @from: P1 address
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * void copy_page(void *to, void *from)
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch
228c2ecf20Sopenharmony_ci * r8 --- from + PAGE_SIZE
238c2ecf20Sopenharmony_ci * r9 --- not used
248c2ecf20Sopenharmony_ci * r10 --- to
258c2ecf20Sopenharmony_ci * r11 --- from
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ciENTRY(copy_page)
288c2ecf20Sopenharmony_ci	mov.l	r8,@-r15
298c2ecf20Sopenharmony_ci	mov.l	r10,@-r15
308c2ecf20Sopenharmony_ci	mov.l	r11,@-r15
318c2ecf20Sopenharmony_ci	mov	r4,r10
328c2ecf20Sopenharmony_ci	mov	r5,r11
338c2ecf20Sopenharmony_ci	mov	r5,r8
348c2ecf20Sopenharmony_ci	mov	#(PAGE_SIZE >> 10), r0
358c2ecf20Sopenharmony_ci	shll8	r0
368c2ecf20Sopenharmony_ci	shll2	r0
378c2ecf20Sopenharmony_ci	add	r0,r8
388c2ecf20Sopenharmony_ci	!
398c2ecf20Sopenharmony_ci1:	mov.l	@r11+,r0
408c2ecf20Sopenharmony_ci	mov.l	@r11+,r1
418c2ecf20Sopenharmony_ci	mov.l	@r11+,r2
428c2ecf20Sopenharmony_ci	mov.l	@r11+,r3
438c2ecf20Sopenharmony_ci	mov.l	@r11+,r4
448c2ecf20Sopenharmony_ci	mov.l	@r11+,r5
458c2ecf20Sopenharmony_ci	mov.l	@r11+,r6
468c2ecf20Sopenharmony_ci	mov.l	@r11+,r7
478c2ecf20Sopenharmony_ci#if defined(CONFIG_CPU_SH4)
488c2ecf20Sopenharmony_ci	movca.l	r0,@r10
498c2ecf20Sopenharmony_ci#else
508c2ecf20Sopenharmony_ci	mov.l	r0,@r10
518c2ecf20Sopenharmony_ci#endif
528c2ecf20Sopenharmony_ci	add	#32,r10
538c2ecf20Sopenharmony_ci	mov.l	r7,@-r10
548c2ecf20Sopenharmony_ci	mov.l	r6,@-r10
558c2ecf20Sopenharmony_ci	mov.l	r5,@-r10
568c2ecf20Sopenharmony_ci	mov.l	r4,@-r10
578c2ecf20Sopenharmony_ci	mov.l	r3,@-r10
588c2ecf20Sopenharmony_ci	mov.l	r2,@-r10
598c2ecf20Sopenharmony_ci	mov.l	r1,@-r10
608c2ecf20Sopenharmony_ci	cmp/eq	r11,r8
618c2ecf20Sopenharmony_ci	bf/s	1b
628c2ecf20Sopenharmony_ci	 add	#28,r10
638c2ecf20Sopenharmony_ci	!
648c2ecf20Sopenharmony_ci	mov.l	@r15+,r11
658c2ecf20Sopenharmony_ci	mov.l	@r15+,r10
668c2ecf20Sopenharmony_ci	mov.l	@r15+,r8
678c2ecf20Sopenharmony_ci	rts
688c2ecf20Sopenharmony_ci	 nop
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/*
718c2ecf20Sopenharmony_ci * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
728c2ecf20Sopenharmony_ci * Return the number of bytes NOT copied
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_ci#define EX(...)			\
758c2ecf20Sopenharmony_ci	9999: __VA_ARGS__ ;		\
768c2ecf20Sopenharmony_ci	.section __ex_table, "a";	\
778c2ecf20Sopenharmony_ci	.long 9999b, 6000f	;	\
788c2ecf20Sopenharmony_ci	.previous
798c2ecf20Sopenharmony_ci#define EX_NO_POP(...)			\
808c2ecf20Sopenharmony_ci	9999: __VA_ARGS__ ;		\
818c2ecf20Sopenharmony_ci	.section __ex_table, "a";	\
828c2ecf20Sopenharmony_ci	.long 9999b, 6005f	;	\
838c2ecf20Sopenharmony_ci	.previous
848c2ecf20Sopenharmony_ciENTRY(__copy_user)
858c2ecf20Sopenharmony_ci	! Check if small number of bytes
868c2ecf20Sopenharmony_ci	mov	#11,r0
878c2ecf20Sopenharmony_ci	mov	r4,r3
888c2ecf20Sopenharmony_ci	cmp/gt	r0,r6		! r6 (len) > r0 (11)
898c2ecf20Sopenharmony_ci	bf/s	.L_cleanup_loop_no_pop
908c2ecf20Sopenharmony_ci	 add	r6,r3		! last destination address
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	! Calculate bytes needed to align to src
938c2ecf20Sopenharmony_ci	mov.l	r11,@-r15
948c2ecf20Sopenharmony_ci	neg	r5,r0
958c2ecf20Sopenharmony_ci	mov.l	r10,@-r15
968c2ecf20Sopenharmony_ci	add	#4,r0
978c2ecf20Sopenharmony_ci	mov.l	r9,@-r15
988c2ecf20Sopenharmony_ci	and	#3,r0
998c2ecf20Sopenharmony_ci	mov.l	r8,@-r15
1008c2ecf20Sopenharmony_ci	tst	r0,r0
1018c2ecf20Sopenharmony_ci	bt	2f
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci1:
1048c2ecf20Sopenharmony_ci	! Copy bytes to long word align src
1058c2ecf20Sopenharmony_ciEX(	mov.b	@r5+,r1		)
1068c2ecf20Sopenharmony_ci	dt	r0
1078c2ecf20Sopenharmony_ci	add	#-1,r6
1088c2ecf20Sopenharmony_ciEX(	mov.b	r1,@r4		)
1098c2ecf20Sopenharmony_ci	bf/s	1b
1108c2ecf20Sopenharmony_ci	 add	#1,r4
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	! Jump to appropriate routine depending on dest
1138c2ecf20Sopenharmony_ci2:	mov	#3,r1
1148c2ecf20Sopenharmony_ci	mov	r6, r2
1158c2ecf20Sopenharmony_ci	and	r4,r1
1168c2ecf20Sopenharmony_ci	shlr2	r2
1178c2ecf20Sopenharmony_ci	shll2	r1
1188c2ecf20Sopenharmony_ci	mova	.L_jump_tbl,r0
1198c2ecf20Sopenharmony_ci	mov.l	@(r0,r1),r1
1208c2ecf20Sopenharmony_ci	jmp	@r1
1218c2ecf20Sopenharmony_ci	 nop
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	.align 2
1248c2ecf20Sopenharmony_ci.L_jump_tbl:
1258c2ecf20Sopenharmony_ci	.long	.L_dest00
1268c2ecf20Sopenharmony_ci	.long	.L_dest01
1278c2ecf20Sopenharmony_ci	.long	.L_dest10
1288c2ecf20Sopenharmony_ci	.long	.L_dest11
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/*
1318c2ecf20Sopenharmony_ci * Come here if there are less than 12 bytes to copy
1328c2ecf20Sopenharmony_ci *
1338c2ecf20Sopenharmony_ci * Keep the branch target close, so the bf/s callee doesn't overflow
1348c2ecf20Sopenharmony_ci * and result in a more expensive branch being inserted. This is the
1358c2ecf20Sopenharmony_ci * fast-path for small copies, the jump via the jump table will hit the
1368c2ecf20Sopenharmony_ci * default slow-path cleanup. -PFM.
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_ci.L_cleanup_loop_no_pop:
1398c2ecf20Sopenharmony_ci	tst	r6,r6		! Check explicitly for zero
1408c2ecf20Sopenharmony_ci	bt	1f
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci2:
1438c2ecf20Sopenharmony_ciEX_NO_POP(	mov.b	@r5+,r0		)
1448c2ecf20Sopenharmony_ci	dt	r6
1458c2ecf20Sopenharmony_ciEX_NO_POP(	mov.b	r0,@r4		)
1468c2ecf20Sopenharmony_ci	bf/s	2b
1478c2ecf20Sopenharmony_ci	 add	#1,r4
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci1:	mov	#0,r0		! normal return
1508c2ecf20Sopenharmony_ci5000:
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci# Exception handler:
1538c2ecf20Sopenharmony_ci.section .fixup, "ax"
1548c2ecf20Sopenharmony_ci6005:
1558c2ecf20Sopenharmony_ci	mov.l	8000f,r1
1568c2ecf20Sopenharmony_ci	mov	r3,r0
1578c2ecf20Sopenharmony_ci	jmp	@r1
1588c2ecf20Sopenharmony_ci	 sub	r4,r0
1598c2ecf20Sopenharmony_ci	.align	2
1608c2ecf20Sopenharmony_ci8000:	.long	5000b
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci.previous
1638c2ecf20Sopenharmony_ci	rts
1648c2ecf20Sopenharmony_ci	 nop
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci! Destination = 00
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci.L_dest00:
1698c2ecf20Sopenharmony_ci	! Skip the large copy for small transfers
1708c2ecf20Sopenharmony_ci	mov	#(32+32-4), r0
1718c2ecf20Sopenharmony_ci	cmp/gt	r6, r0		! r0 (60) > r6 (len)
1728c2ecf20Sopenharmony_ci	bt	1f
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	! Align dest to a 32 byte boundary
1758c2ecf20Sopenharmony_ci	neg	r4,r0
1768c2ecf20Sopenharmony_ci	add	#0x20, r0
1778c2ecf20Sopenharmony_ci	and	#0x1f, r0
1788c2ecf20Sopenharmony_ci	tst	r0, r0
1798c2ecf20Sopenharmony_ci	bt	2f
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	sub	r0, r6
1828c2ecf20Sopenharmony_ci	shlr2	r0
1838c2ecf20Sopenharmony_ci3:
1848c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r1		)
1858c2ecf20Sopenharmony_ci	dt	r0
1868c2ecf20Sopenharmony_ciEX(	mov.l	r1,@r4		)
1878c2ecf20Sopenharmony_ci	bf/s	3b
1888c2ecf20Sopenharmony_ci	 add	#4,r4
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci2:
1918c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r0		)
1928c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r1		)
1938c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r2		)
1948c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r7		)
1958c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r8		)
1968c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r9		)
1978c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r10	)
1988c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r11	)
1998c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SH4
2008c2ecf20Sopenharmony_ciEX(	movca.l	r0,@r4		)
2018c2ecf20Sopenharmony_ci#else
2028c2ecf20Sopenharmony_ciEX(	mov.l	r0,@r4		)
2038c2ecf20Sopenharmony_ci#endif
2048c2ecf20Sopenharmony_ci	add	#-32, r6
2058c2ecf20Sopenharmony_ciEX(	mov.l	r1,@(4,r4)	)
2068c2ecf20Sopenharmony_ci	mov	#32, r0
2078c2ecf20Sopenharmony_ciEX(	mov.l	r2,@(8,r4)	)
2088c2ecf20Sopenharmony_ci	cmp/gt	r6, r0		! r0 (32) > r6 (len)
2098c2ecf20Sopenharmony_ciEX(	mov.l	r7,@(12,r4)	)
2108c2ecf20Sopenharmony_ciEX(	mov.l	r8,@(16,r4)	)
2118c2ecf20Sopenharmony_ciEX(	mov.l	r9,@(20,r4)	)
2128c2ecf20Sopenharmony_ciEX(	mov.l	r10,@(24,r4)	)
2138c2ecf20Sopenharmony_ciEX(	mov.l	r11,@(28,r4)	)
2148c2ecf20Sopenharmony_ci	bf/s	2b
2158c2ecf20Sopenharmony_ci	 add	#32,r4
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci1:	mov	r6, r0
2188c2ecf20Sopenharmony_ci	shlr2	r0
2198c2ecf20Sopenharmony_ci	tst	r0, r0
2208c2ecf20Sopenharmony_ci	bt	.L_cleanup
2218c2ecf20Sopenharmony_ci1:
2228c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r1		)
2238c2ecf20Sopenharmony_ci	dt	r0
2248c2ecf20Sopenharmony_ciEX(	mov.l	r1,@r4		)
2258c2ecf20Sopenharmony_ci	bf/s	1b
2268c2ecf20Sopenharmony_ci	 add	#4,r4
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	bra	.L_cleanup
2298c2ecf20Sopenharmony_ci	 nop
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci! Destination = 10
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci.L_dest10:
2348c2ecf20Sopenharmony_ci	mov	r2,r7
2358c2ecf20Sopenharmony_ci	shlr2	r7
2368c2ecf20Sopenharmony_ci	shlr	r7
2378c2ecf20Sopenharmony_ci	tst	r7,r7
2388c2ecf20Sopenharmony_ci	mov	#7,r0
2398c2ecf20Sopenharmony_ci	bt/s	1f
2408c2ecf20Sopenharmony_ci	 and	r0,r2
2418c2ecf20Sopenharmony_ci2:
2428c2ecf20Sopenharmony_ci	dt	r7
2438c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_LITTLE_ENDIAN
2448c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r0		)
2458c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r1		)
2468c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r8		)
2478c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r9		)
2488c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r10	)
2498c2ecf20Sopenharmony_ciEX(	mov.w	r0,@r4		)
2508c2ecf20Sopenharmony_ci	add	#2,r4
2518c2ecf20Sopenharmony_ci	xtrct	r1,r0
2528c2ecf20Sopenharmony_ci	xtrct	r8,r1
2538c2ecf20Sopenharmony_ci	xtrct	r9,r8
2548c2ecf20Sopenharmony_ci	xtrct	r10,r9
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciEX(	mov.l	r0,@r4		)
2578c2ecf20Sopenharmony_ciEX(	mov.l	r1,@(4,r4)	)
2588c2ecf20Sopenharmony_ciEX(	mov.l	r8,@(8,r4)	)
2598c2ecf20Sopenharmony_ciEX(	mov.l	r9,@(12,r4)	)
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r1		)
2628c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r8		)
2638c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r0		)
2648c2ecf20Sopenharmony_ci	xtrct	r1,r10
2658c2ecf20Sopenharmony_ci	xtrct	r8,r1
2668c2ecf20Sopenharmony_ci	xtrct	r0,r8
2678c2ecf20Sopenharmony_ci	shlr16	r0
2688c2ecf20Sopenharmony_ciEX(	mov.l	r10,@(16,r4)	)
2698c2ecf20Sopenharmony_ciEX(	mov.l	r1,@(20,r4)	)
2708c2ecf20Sopenharmony_ciEX(	mov.l	r8,@(24,r4)	)
2718c2ecf20Sopenharmony_ciEX(	mov.w	r0,@(28,r4)	)
2728c2ecf20Sopenharmony_ci	bf/s	2b
2738c2ecf20Sopenharmony_ci	 add	#30,r4
2748c2ecf20Sopenharmony_ci#else
2758c2ecf20Sopenharmony_ciEX(	mov.l	@(28,r5),r0	)
2768c2ecf20Sopenharmony_ciEX(	mov.l	@(24,r5),r8	)
2778c2ecf20Sopenharmony_ciEX(	mov.l	@(20,r5),r9	)
2788c2ecf20Sopenharmony_ciEX(	mov.l	@(16,r5),r10	)
2798c2ecf20Sopenharmony_ciEX(	mov.w	r0,@(30,r4)	)
2808c2ecf20Sopenharmony_ci	add	#-2,r4
2818c2ecf20Sopenharmony_ci	xtrct	r8,r0
2828c2ecf20Sopenharmony_ci	xtrct	r9,r8
2838c2ecf20Sopenharmony_ci	xtrct	r10,r9
2848c2ecf20Sopenharmony_ciEX(	mov.l	r0,@(28,r4)	)
2858c2ecf20Sopenharmony_ciEX(	mov.l	r8,@(24,r4)	)
2868c2ecf20Sopenharmony_ciEX(	mov.l	r9,@(20,r4)	)
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ciEX(	mov.l	@(12,r5),r0	)
2898c2ecf20Sopenharmony_ciEX(	mov.l	@(8,r5),r8	)
2908c2ecf20Sopenharmony_ci	xtrct	r0,r10
2918c2ecf20Sopenharmony_ciEX(	mov.l	@(4,r5),r9	)
2928c2ecf20Sopenharmony_ci	mov.l	r10,@(16,r4)
2938c2ecf20Sopenharmony_ciEX(	mov.l	@r5,r10		)
2948c2ecf20Sopenharmony_ci	xtrct	r8,r0
2958c2ecf20Sopenharmony_ci	xtrct	r9,r8
2968c2ecf20Sopenharmony_ci	xtrct	r10,r9
2978c2ecf20Sopenharmony_ciEX(	mov.l	r0,@(12,r4)	)
2988c2ecf20Sopenharmony_ciEX(	mov.l	r8,@(8,r4)	)
2998c2ecf20Sopenharmony_ci	swap.w	r10,r0
3008c2ecf20Sopenharmony_ciEX(	mov.l	r9,@(4,r4)	)
3018c2ecf20Sopenharmony_ciEX(	mov.w	r0,@(2,r4)	)
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	add	#32,r5
3048c2ecf20Sopenharmony_ci	bf/s	2b
3058c2ecf20Sopenharmony_ci	 add	#34,r4
3068c2ecf20Sopenharmony_ci#endif
3078c2ecf20Sopenharmony_ci	tst	r2,r2
3088c2ecf20Sopenharmony_ci	bt	.L_cleanup
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci1:	! Read longword, write two words per iteration
3118c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r0		)
3128c2ecf20Sopenharmony_ci	dt	r2
3138c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_LITTLE_ENDIAN
3148c2ecf20Sopenharmony_ciEX(	mov.w	r0,@r4		)
3158c2ecf20Sopenharmony_ci	shlr16	r0
3168c2ecf20Sopenharmony_ciEX(	mov.w 	r0,@(2,r4)	)
3178c2ecf20Sopenharmony_ci#else
3188c2ecf20Sopenharmony_ciEX(	mov.w	r0,@(2,r4)	)
3198c2ecf20Sopenharmony_ci	shlr16	r0
3208c2ecf20Sopenharmony_ciEX(	mov.w	r0,@r4		)
3218c2ecf20Sopenharmony_ci#endif
3228c2ecf20Sopenharmony_ci	bf/s	1b
3238c2ecf20Sopenharmony_ci	 add	#4,r4
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	bra	.L_cleanup
3268c2ecf20Sopenharmony_ci	 nop
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci! Destination = 01 or 11
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci.L_dest01:
3318c2ecf20Sopenharmony_ci.L_dest11:
3328c2ecf20Sopenharmony_ci	! Read longword, write byte, word, byte per iteration
3338c2ecf20Sopenharmony_ciEX(	mov.l	@r5+,r0		)
3348c2ecf20Sopenharmony_ci	dt	r2
3358c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_LITTLE_ENDIAN
3368c2ecf20Sopenharmony_ciEX(	mov.b	r0,@r4		)
3378c2ecf20Sopenharmony_ci	shlr8	r0
3388c2ecf20Sopenharmony_ci	add	#1,r4
3398c2ecf20Sopenharmony_ciEX(	mov.w	r0,@r4		)
3408c2ecf20Sopenharmony_ci	shlr16	r0
3418c2ecf20Sopenharmony_ciEX(	mov.b	r0,@(2,r4)	)
3428c2ecf20Sopenharmony_ci	bf/s	.L_dest01
3438c2ecf20Sopenharmony_ci	 add	#3,r4
3448c2ecf20Sopenharmony_ci#else
3458c2ecf20Sopenharmony_ciEX(	mov.b	r0,@(3,r4)	)
3468c2ecf20Sopenharmony_ci	shlr8	r0
3478c2ecf20Sopenharmony_ci	swap.w	r0,r7
3488c2ecf20Sopenharmony_ciEX(	mov.b	r7,@r4		)
3498c2ecf20Sopenharmony_ci	add	#1,r4
3508c2ecf20Sopenharmony_ciEX(	mov.w	r0,@r4		)
3518c2ecf20Sopenharmony_ci	bf/s	.L_dest01
3528c2ecf20Sopenharmony_ci	 add	#3,r4
3538c2ecf20Sopenharmony_ci#endif
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci! Cleanup last few bytes
3568c2ecf20Sopenharmony_ci.L_cleanup:
3578c2ecf20Sopenharmony_ci	mov	r6,r0
3588c2ecf20Sopenharmony_ci	and	#3,r0
3598c2ecf20Sopenharmony_ci	tst	r0,r0
3608c2ecf20Sopenharmony_ci	bt	.L_exit
3618c2ecf20Sopenharmony_ci	mov	r0,r6
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci.L_cleanup_loop:
3648c2ecf20Sopenharmony_ciEX(	mov.b	@r5+,r0		)
3658c2ecf20Sopenharmony_ci	dt	r6
3668c2ecf20Sopenharmony_ciEX(	mov.b	r0,@r4		)
3678c2ecf20Sopenharmony_ci	bf/s	.L_cleanup_loop
3688c2ecf20Sopenharmony_ci	 add	#1,r4
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci.L_exit:
3718c2ecf20Sopenharmony_ci	mov	#0,r0		! normal return
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci5000:
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci# Exception handler:
3768c2ecf20Sopenharmony_ci.section .fixup, "ax"
3778c2ecf20Sopenharmony_ci6000:
3788c2ecf20Sopenharmony_ci	mov.l	8000f,r1
3798c2ecf20Sopenharmony_ci	mov	r3,r0
3808c2ecf20Sopenharmony_ci	jmp	@r1
3818c2ecf20Sopenharmony_ci	 sub	r4,r0
3828c2ecf20Sopenharmony_ci	.align	2
3838c2ecf20Sopenharmony_ci8000:	.long	5000b
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci.previous
3868c2ecf20Sopenharmony_ci	mov.l	@r15+,r8
3878c2ecf20Sopenharmony_ci	mov.l	@r15+,r9
3888c2ecf20Sopenharmony_ci	mov.l	@r15+,r10
3898c2ecf20Sopenharmony_ci	rts
3908c2ecf20Sopenharmony_ci	 mov.l	@r15+,r11
391