xref: /openbmc/u-boot/arch/arm/lib/memcpy.S (revision c0dcece7)
1/*
2 *  linux/arch/arm/lib/memcpy.S
3 *
4 *  Author:	Nicolas Pitre
5 *  Created:	Sep 28, 2005
6 *  Copyright:	MontaVista Software, Inc.
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License version 2 as
10 *  published by the Free Software Foundation.
11 */
12
13#include <asm/assembler.h>
14
15#define W(instr)	instr
16
17#define LDR1W_SHIFT	0
18#define STR1W_SHIFT	0
19
20	.macro ldr1w ptr reg abort
21	W(ldr) \reg, [\ptr], #4
22	.endm
23
24	.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
25	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
26	.endm
27
28	.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
29	ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
30	.endm
31
32	.macro ldr1b ptr reg cond=al abort
33	ldr\cond\()b \reg, [\ptr], #1
34	.endm
35
36	.macro str1w ptr reg abort
37	W(str) \reg, [\ptr], #4
38	.endm
39
40	.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
41	stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
42	.endm
43
44	.macro str1b ptr reg cond=al abort
45	str\cond\()b \reg, [\ptr], #1
46	.endm
47
48	.macro enter reg1 reg2
49	stmdb sp!, {r0, \reg1, \reg2}
50	.endm
51
52	.macro exit reg1 reg2
53	ldmfd sp!, {r0, \reg1, \reg2}
54	.endm
55
56	.text
57
58/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
59
60.globl memcpy
61memcpy:
62
63		cmp	r0, r1
64		moveq	pc, lr
65
66		enter	r4, lr
67
68		subs	r2, r2, #4
69		blt	8f
70		ands	ip, r0, #3
71	PLD(	pld	[r1, #0]		)
72		bne	9f
73		ands	ip, r1, #3
74		bne	10f
75
761:		subs	r2, r2, #(28)
77		stmfd	sp!, {r5 - r8}
78		blt	5f
79
80	CALGN(	ands	ip, r0, #31		)
81	CALGN(	rsb	r3, ip, #32		)
82	CALGN(	sbcnes	r4, r3, r2		)  @ C is always set here
83	CALGN(	bcs	2f			)
84	CALGN(	adr	r4, 6f			)
85	CALGN(	subs	r2, r2, r3		)  @ C gets set
86	CALGN(	add	pc, r4, ip		)
87
88	PLD(	pld	[r1, #0]		)
892:	PLD(	subs	r2, r2, #96		)
90	PLD(	pld	[r1, #28]		)
91	PLD(	blt	4f			)
92	PLD(	pld	[r1, #60]		)
93	PLD(	pld	[r1, #92]		)
94
953:	PLD(	pld	[r1, #124]		)
964:		ldr8w	r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
97		subs	r2, r2, #32
98		str8w	r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
99		bge	3b
100	PLD(	cmn	r2, #96			)
101	PLD(	bge	4b			)
102
1035:		ands	ip, r2, #28
104		rsb	ip, ip, #32
105#if LDR1W_SHIFT > 0
106		lsl	ip, ip, #LDR1W_SHIFT
107#endif
108		addne	pc, pc, ip		@ C is always clear here
109		b	7f
1106:
111		.rept	(1 << LDR1W_SHIFT)
112		W(nop)
113		.endr
114		ldr1w	r1, r3, abort=20f
115		ldr1w	r1, r4, abort=20f
116		ldr1w	r1, r5, abort=20f
117		ldr1w	r1, r6, abort=20f
118		ldr1w	r1, r7, abort=20f
119		ldr1w	r1, r8, abort=20f
120		ldr1w	r1, lr, abort=20f
121
122#if LDR1W_SHIFT < STR1W_SHIFT
123		lsl	ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
124#elif LDR1W_SHIFT > STR1W_SHIFT
125		lsr	ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
126#endif
127		add	pc, pc, ip
128		nop
129		.rept	(1 << STR1W_SHIFT)
130		W(nop)
131		.endr
132		str1w	r0, r3, abort=20f
133		str1w	r0, r4, abort=20f
134		str1w	r0, r5, abort=20f
135		str1w	r0, r6, abort=20f
136		str1w	r0, r7, abort=20f
137		str1w	r0, r8, abort=20f
138		str1w	r0, lr, abort=20f
139
140	CALGN(	bcs	2b			)
141
1427:		ldmfd	sp!, {r5 - r8}
143
1448:		movs	r2, r2, lsl #31
145		ldr1b	r1, r3, ne, abort=21f
146		ldr1b	r1, r4, cs, abort=21f
147		ldr1b	r1, ip, cs, abort=21f
148		str1b	r0, r3, ne, abort=21f
149		str1b	r0, r4, cs, abort=21f
150		str1b	r0, ip, cs, abort=21f
151
152		exit	r4, pc
153
1549:		rsb	ip, ip, #4
155		cmp	ip, #2
156		ldr1b	r1, r3, gt, abort=21f
157		ldr1b	r1, r4, ge, abort=21f
158		ldr1b	r1, lr, abort=21f
159		str1b	r0, r3, gt, abort=21f
160		str1b	r0, r4, ge, abort=21f
161		subs	r2, r2, ip
162		str1b	r0, lr, abort=21f
163		blt	8b
164		ands	ip, r1, #3
165		beq	1b
166
16710:		bic	r1, r1, #3
168		cmp	ip, #2
169		ldr1w	r1, lr, abort=21f
170		beq	17f
171		bgt	18f
172
173
174		.macro	forward_copy_shift pull push
175
176		subs	r2, r2, #28
177		blt	14f
178
179	CALGN(	ands	ip, r0, #31		)
180	CALGN(	rsb	ip, ip, #32		)
181	CALGN(	sbcnes	r4, ip, r2		)  @ C is always set here
182	CALGN(	subcc	r2, r2, ip		)
183	CALGN(	bcc	15f			)
184
18511:		stmfd	sp!, {r5 - r9}
186
187	PLD(	pld	[r1, #0]		)
188	PLD(	subs	r2, r2, #96		)
189	PLD(	pld	[r1, #28]		)
190	PLD(	blt	13f			)
191	PLD(	pld	[r1, #60]		)
192	PLD(	pld	[r1, #92]		)
193
19412:	PLD(	pld	[r1, #124]		)
19513:		ldr4w	r1, r4, r5, r6, r7, abort=19f
196		mov	r3, lr, pull #\pull
197		subs	r2, r2, #32
198		ldr4w	r1, r8, r9, ip, lr, abort=19f
199		orr	r3, r3, r4, push #\push
200		mov	r4, r4, pull #\pull
201		orr	r4, r4, r5, push #\push
202		mov	r5, r5, pull #\pull
203		orr	r5, r5, r6, push #\push
204		mov	r6, r6, pull #\pull
205		orr	r6, r6, r7, push #\push
206		mov	r7, r7, pull #\pull
207		orr	r7, r7, r8, push #\push
208		mov	r8, r8, pull #\pull
209		orr	r8, r8, r9, push #\push
210		mov	r9, r9, pull #\pull
211		orr	r9, r9, ip, push #\push
212		mov	ip, ip, pull #\pull
213		orr	ip, ip, lr, push #\push
214		str8w	r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
215		bge	12b
216	PLD(	cmn	r2, #96			)
217	PLD(	bge	13b			)
218
219		ldmfd	sp!, {r5 - r9}
220
22114:		ands	ip, r2, #28
222		beq	16f
223
22415:		mov	r3, lr, pull #\pull
225		ldr1w	r1, lr, abort=21f
226		subs	ip, ip, #4
227		orr	r3, r3, lr, push #\push
228		str1w	r0, r3, abort=21f
229		bgt	15b
230	CALGN(	cmp	r2, #0			)
231	CALGN(	bge	11b			)
232
23316:		sub	r1, r1, #(\push / 8)
234		b	8b
235
236		.endm
237
238
239		forward_copy_shift	pull=8	push=24
240
24117:		forward_copy_shift	pull=16	push=16
242
24318:		forward_copy_shift	pull=24	push=8
244