xref: /openbmc/u-boot/arch/arm/lib/memcpy.S (revision cd8c8775)
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		enter	r4, lr
64
65		subs	r2, r2, #4
66		blt	8f
67		ands	ip, r0, #3
68	PLD(	pld	[r1, #0]		)
69		bne	9f
70		ands	ip, r1, #3
71		bne	10f
72
731:		subs	r2, r2, #(28)
74		stmfd	sp!, {r5 - r8}
75		blt	5f
76
77	CALGN(	ands	ip, r0, #31		)
78	CALGN(	rsb	r3, ip, #32		)
79	CALGN(	sbcnes	r4, r3, r2		)  @ C is always set here
80	CALGN(	bcs	2f			)
81	CALGN(	adr	r4, 6f			)
82	CALGN(	subs	r2, r2, r3		)  @ C gets set
83	CALGN(	add	pc, r4, ip		)
84
85	PLD(	pld	[r1, #0]		)
862:	PLD(	subs	r2, r2, #96		)
87	PLD(	pld	[r1, #28]		)
88	PLD(	blt	4f			)
89	PLD(	pld	[r1, #60]		)
90	PLD(	pld	[r1, #92]		)
91
923:	PLD(	pld	[r1, #124]		)
934:		ldr8w	r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
94		subs	r2, r2, #32
95		str8w	r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
96		bge	3b
97	PLD(	cmn	r2, #96			)
98	PLD(	bge	4b			)
99
1005:		ands	ip, r2, #28
101		rsb	ip, ip, #32
102#if LDR1W_SHIFT > 0
103		lsl	ip, ip, #LDR1W_SHIFT
104#endif
105		addne	pc, pc, ip		@ C is always clear here
106		b	7f
1076:
108		.rept	(1 << LDR1W_SHIFT)
109		W(nop)
110		.endr
111		ldr1w	r1, r3, abort=20f
112		ldr1w	r1, r4, abort=20f
113		ldr1w	r1, r5, abort=20f
114		ldr1w	r1, r6, abort=20f
115		ldr1w	r1, r7, abort=20f
116		ldr1w	r1, r8, abort=20f
117		ldr1w	r1, lr, abort=20f
118
119#if LDR1W_SHIFT < STR1W_SHIFT
120		lsl	ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
121#elif LDR1W_SHIFT > STR1W_SHIFT
122		lsr	ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
123#endif
124		add	pc, pc, ip
125		nop
126		.rept	(1 << STR1W_SHIFT)
127		W(nop)
128		.endr
129		str1w	r0, r3, abort=20f
130		str1w	r0, r4, abort=20f
131		str1w	r0, r5, abort=20f
132		str1w	r0, r6, abort=20f
133		str1w	r0, r7, abort=20f
134		str1w	r0, r8, abort=20f
135		str1w	r0, lr, abort=20f
136
137	CALGN(	bcs	2b			)
138
1397:		ldmfd	sp!, {r5 - r8}
140
1418:		movs	r2, r2, lsl #31
142		ldr1b	r1, r3, ne, abort=21f
143		ldr1b	r1, r4, cs, abort=21f
144		ldr1b	r1, ip, cs, abort=21f
145		str1b	r0, r3, ne, abort=21f
146		str1b	r0, r4, cs, abort=21f
147		str1b	r0, ip, cs, abort=21f
148
149		exit	r4, pc
150
1519:		rsb	ip, ip, #4
152		cmp	ip, #2
153		ldr1b	r1, r3, gt, abort=21f
154		ldr1b	r1, r4, ge, abort=21f
155		ldr1b	r1, lr, abort=21f
156		str1b	r0, r3, gt, abort=21f
157		str1b	r0, r4, ge, abort=21f
158		subs	r2, r2, ip
159		str1b	r0, lr, abort=21f
160		blt	8b
161		ands	ip, r1, #3
162		beq	1b
163
16410:		bic	r1, r1, #3
165		cmp	ip, #2
166		ldr1w	r1, lr, abort=21f
167		beq	17f
168		bgt	18f
169
170
171		.macro	forward_copy_shift pull push
172
173		subs	r2, r2, #28
174		blt	14f
175
176	CALGN(	ands	ip, r0, #31		)
177	CALGN(	rsb	ip, ip, #32		)
178	CALGN(	sbcnes	r4, ip, r2		)  @ C is always set here
179	CALGN(	subcc	r2, r2, ip		)
180	CALGN(	bcc	15f			)
181
18211:		stmfd	sp!, {r5 - r9}
183
184	PLD(	pld	[r1, #0]		)
185	PLD(	subs	r2, r2, #96		)
186	PLD(	pld	[r1, #28]		)
187	PLD(	blt	13f			)
188	PLD(	pld	[r1, #60]		)
189	PLD(	pld	[r1, #92]		)
190
19112:	PLD(	pld	[r1, #124]		)
19213:		ldr4w	r1, r4, r5, r6, r7, abort=19f
193		mov	r3, lr, pull #\pull
194		subs	r2, r2, #32
195		ldr4w	r1, r8, r9, ip, lr, abort=19f
196		orr	r3, r3, r4, push #\push
197		mov	r4, r4, pull #\pull
198		orr	r4, r4, r5, push #\push
199		mov	r5, r5, pull #\pull
200		orr	r5, r5, r6, push #\push
201		mov	r6, r6, pull #\pull
202		orr	r6, r6, r7, push #\push
203		mov	r7, r7, pull #\pull
204		orr	r7, r7, r8, push #\push
205		mov	r8, r8, pull #\pull
206		orr	r8, r8, r9, push #\push
207		mov	r9, r9, pull #\pull
208		orr	r9, r9, ip, push #\push
209		mov	ip, ip, pull #\pull
210		orr	ip, ip, lr, push #\push
211		str8w	r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
212		bge	12b
213	PLD(	cmn	r2, #96			)
214	PLD(	bge	13b			)
215
216		ldmfd	sp!, {r5 - r9}
217
21814:		ands	ip, r2, #28
219		beq	16f
220
22115:		mov	r3, lr, pull #\pull
222		ldr1w	r1, lr, abort=21f
223		subs	ip, ip, #4
224		orr	r3, r3, lr, push #\push
225		str1w	r0, r3, abort=21f
226		bgt	15b
227	CALGN(	cmp	r2, #0			)
228	CALGN(	bge	11b			)
229
23016:		sub	r1, r1, #(\push / 8)
231		b	8b
232
233		.endm
234
235
236		forward_copy_shift	pull=8	push=24
237
23817:		forward_copy_shift	pull=16	push=16
239
24018:		forward_copy_shift	pull=24	push=8
241
242