xref: /linux/arch/powerpc/lib/ldstfp.S (revision 9095bf25ea08135a5b74875dd0e3eeaddc4218a0)
1/*
2 * Floating-point, VMX/Altivec and VSX loads and stores
3 * for use in instruction emulation.
4 *
5 * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
6 *
7 *  This program is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU General Public License
9 *  as published by the Free Software Foundation; either version
10 *  2 of the License, or (at your option) any later version.
11 */
12
13#include <asm/processor.h>
14#include <asm/ppc_asm.h>
15#include <asm/ppc-opcode.h>
16#include <asm/reg.h>
17#include <asm/asm-offsets.h>
18#include <linux/errno.h>
19
20#ifdef CONFIG_PPC_FPU
21
22#define STKFRM	(PPC_MIN_STKFRM + 16)
23
24	.macro	inst32	op
25reg = 0
26	.rept	32
2720:	\op	reg,0,r4
28	b	3f
29	EX_TABLE(20b,99f)
30reg = reg + 1
31	.endr
32	.endm
33
34/* Get the contents of frN into fr0; N is in r3. */
35_GLOBAL(get_fpr)
36	mflr	r0
37	rlwinm	r3,r3,3,0xf8
38	bcl	20,31,1f
39	blr			/* fr0 is already in fr0 */
40	nop
41reg = 1
42	.rept	31
43	fmr	fr0,reg
44	blr
45reg = reg + 1
46	.endr
471:	mflr	r5
48	add	r5,r3,r5
49	mtctr	r5
50	mtlr	r0
51	bctr
52
53/* Put the contents of fr0 into frN; N is in r3. */
54_GLOBAL(put_fpr)
55	mflr	r0
56	rlwinm	r3,r3,3,0xf8
57	bcl	20,31,1f
58	blr			/* fr0 is already in fr0 */
59	nop
60reg = 1
61	.rept	31
62	fmr	reg,fr0
63	blr
64reg = reg + 1
65	.endr
661:	mflr	r5
67	add	r5,r3,r5
68	mtctr	r5
69	mtlr	r0
70	bctr
71
72/* Load FP reg N from float at *p.  N is in r3, p in r4. */
73_GLOBAL(do_lfs)
74	PPC_STLU r1,-STKFRM(r1)
75	mflr	r0
76	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
77	mfmsr	r6
78	ori	r7,r6,MSR_FP
79	cmpwi	cr7,r3,0
80	MTMSRD(r7)
81	isync
82	beq	cr7,1f
83	stfd	fr0,STKFRM-16(r1)
841:	li	r9,-EFAULT
852:	lfs	fr0,0(r4)
86	li	r9,0
873:	bl	put_fpr
88	beq	cr7,4f
89	lfd	fr0,STKFRM-16(r1)
904:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
91	mtlr	r0
92	MTMSRD(r6)
93	isync
94	mr	r3,r9
95	addi	r1,r1,STKFRM
96	blr
97	EX_TABLE(2b,3b)
98
99/* Load FP reg N from double at *p.  N is in r3, p in r4. */
100_GLOBAL(do_lfd)
101	PPC_STLU r1,-STKFRM(r1)
102	mflr	r0
103	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
104	mfmsr	r6
105	ori	r7,r6,MSR_FP
106	cmpwi	cr7,r3,0
107	MTMSRD(r7)
108	isync
109	beq	cr7,1f
110	stfd	fr0,STKFRM-16(r1)
1111:	li	r9,-EFAULT
1122:	lfd	fr0,0(r4)
113	li	r9,0
1143:	beq	cr7,4f
115	bl	put_fpr
116	lfd	fr0,STKFRM-16(r1)
1174:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
118	mtlr	r0
119	MTMSRD(r6)
120	isync
121	mr	r3,r9
122	addi	r1,r1,STKFRM
123	blr
124	EX_TABLE(2b,3b)
125
126/* Store FP reg N to float at *p.  N is in r3, p in r4. */
127_GLOBAL(do_stfs)
128	PPC_STLU r1,-STKFRM(r1)
129	mflr	r0
130	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
131	mfmsr	r6
132	ori	r7,r6,MSR_FP
133	cmpwi	cr7,r3,0
134	MTMSRD(r7)
135	isync
136	beq	cr7,1f
137	stfd	fr0,STKFRM-16(r1)
138	bl	get_fpr
1391:	li	r9,-EFAULT
1402:	stfs	fr0,0(r4)
141	li	r9,0
1423:	beq	cr7,4f
143	lfd	fr0,STKFRM-16(r1)
1444:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
145	mtlr	r0
146	MTMSRD(r6)
147	isync
148	mr	r3,r9
149	addi	r1,r1,STKFRM
150	blr
151	EX_TABLE(2b,3b)
152
153/* Store FP reg N to double at *p.  N is in r3, p in r4. */
154_GLOBAL(do_stfd)
155	PPC_STLU r1,-STKFRM(r1)
156	mflr	r0
157	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
158	mfmsr	r6
159	ori	r7,r6,MSR_FP
160	cmpwi	cr7,r3,0
161	MTMSRD(r7)
162	isync
163	beq	cr7,1f
164	stfd	fr0,STKFRM-16(r1)
165	bl	get_fpr
1661:	li	r9,-EFAULT
1672:	stfd	fr0,0(r4)
168	li	r9,0
1693:	beq	cr7,4f
170	lfd	fr0,STKFRM-16(r1)
1714:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
172	mtlr	r0
173	MTMSRD(r6)
174	isync
175	mr	r3,r9
176	addi	r1,r1,STKFRM
177	blr
178	EX_TABLE(2b,3b)
179
180#ifdef CONFIG_ALTIVEC
181/* Get the contents of vrN into v0; N is in r3. */
182_GLOBAL(get_vr)
183	mflr	r0
184	rlwinm	r3,r3,3,0xf8
185	bcl	20,31,1f
186	blr			/* v0 is already in v0 */
187	nop
188reg = 1
189	.rept	31
190	vor	v0,reg,reg	/* assembler doesn't know vmr? */
191	blr
192reg = reg + 1
193	.endr
1941:	mflr	r5
195	add	r5,r3,r5
196	mtctr	r5
197	mtlr	r0
198	bctr
199
200/* Put the contents of v0 into vrN; N is in r3. */
201_GLOBAL(put_vr)
202	mflr	r0
203	rlwinm	r3,r3,3,0xf8
204	bcl	20,31,1f
205	blr			/* v0 is already in v0 */
206	nop
207reg = 1
208	.rept	31
209	vor	reg,v0,v0
210	blr
211reg = reg + 1
212	.endr
2131:	mflr	r5
214	add	r5,r3,r5
215	mtctr	r5
216	mtlr	r0
217	bctr
218
219/* Load vector reg N from *p.  N is in r3, p in r4. */
220_GLOBAL(do_lvx)
221	PPC_STLU r1,-STKFRM(r1)
222	mflr	r0
223	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
224	mfmsr	r6
225	oris	r7,r6,MSR_VEC@h
226	cmpwi	cr7,r3,0
227	li	r8,STKFRM-16
228	MTMSRD(r7)
229	isync
230	beq	cr7,1f
231	stvx	v0,r1,r8
2321:	li	r9,-EFAULT
2332:	lvx	v0,0,r4
234	li	r9,0
2353:	beq	cr7,4f
236	bl	put_vr
237	lvx	v0,r1,r8
2384:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
239	mtlr	r0
240	MTMSRD(r6)
241	isync
242	mr	r3,r9
243	addi	r1,r1,STKFRM
244	blr
245	EX_TABLE(2b,3b)
246
247/* Store vector reg N to *p.  N is in r3, p in r4. */
248_GLOBAL(do_stvx)
249	PPC_STLU r1,-STKFRM(r1)
250	mflr	r0
251	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
252	mfmsr	r6
253	oris	r7,r6,MSR_VEC@h
254	cmpwi	cr7,r3,0
255	li	r8,STKFRM-16
256	MTMSRD(r7)
257	isync
258	beq	cr7,1f
259	stvx	v0,r1,r8
260	bl	get_vr
2611:	li	r9,-EFAULT
2622:	stvx	v0,0,r4
263	li	r9,0
2643:	beq	cr7,4f
265	lvx	v0,r1,r8
2664:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
267	mtlr	r0
268	MTMSRD(r6)
269	isync
270	mr	r3,r9
271	addi	r1,r1,STKFRM
272	blr
273	EX_TABLE(2b,3b)
274#endif /* CONFIG_ALTIVEC */
275
276#ifdef CONFIG_VSX
277/* Get the contents of vsN into vs0; N is in r3. */
278_GLOBAL(get_vsr)
279	mflr	r0
280	rlwinm	r3,r3,3,0x1f8
281	bcl	20,31,1f
282	blr			/* vs0 is already in vs0 */
283	nop
284reg = 1
285	.rept	63
286	XXLOR(0,reg,reg)
287	blr
288reg = reg + 1
289	.endr
2901:	mflr	r5
291	add	r5,r3,r5
292	mtctr	r5
293	mtlr	r0
294	bctr
295
296/* Put the contents of vs0 into vsN; N is in r3. */
297_GLOBAL(put_vsr)
298	mflr	r0
299	rlwinm	r3,r3,3,0x1f8
300	bcl	20,31,1f
301	blr			/* v0 is already in v0 */
302	nop
303reg = 1
304	.rept	63
305	XXLOR(reg,0,0)
306	blr
307reg = reg + 1
308	.endr
3091:	mflr	r5
310	add	r5,r3,r5
311	mtctr	r5
312	mtlr	r0
313	bctr
314
315/* Load VSX reg N from vector doubleword *p.  N is in r3, p in r4. */
316_GLOBAL(do_lxvd2x)
317	PPC_STLU r1,-STKFRM(r1)
318	mflr	r0
319	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
320	mfmsr	r6
321	oris	r7,r6,MSR_VSX@h
322	cmpwi	cr7,r3,0
323	li	r8,STKFRM-16
324	MTMSRD(r7)
325	isync
326	beq	cr7,1f
327	STXVD2X(0,R1,R8)
3281:	li	r9,-EFAULT
3292:	LXVD2X(0,R0,R4)
330	li	r9,0
3313:	beq	cr7,4f
332	bl	put_vsr
333	LXVD2X(0,R1,R8)
3344:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
335	mtlr	r0
336	MTMSRD(r6)
337	isync
338	mr	r3,r9
339	addi	r1,r1,STKFRM
340	blr
341	EX_TABLE(2b,3b)
342
343/* Store VSX reg N to vector doubleword *p.  N is in r3, p in r4. */
344_GLOBAL(do_stxvd2x)
345	PPC_STLU r1,-STKFRM(r1)
346	mflr	r0
347	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
348	mfmsr	r6
349	oris	r7,r6,MSR_VSX@h
350	cmpwi	cr7,r3,0
351	li	r8,STKFRM-16
352	MTMSRD(r7)
353	isync
354	beq	cr7,1f
355	STXVD2X(0,R1,R8)
356	bl	get_vsr
3571:	li	r9,-EFAULT
3582:	STXVD2X(0,R0,R4)
359	li	r9,0
3603:	beq	cr7,4f
361	LXVD2X(0,R1,R8)
3624:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
363	mtlr	r0
364	MTMSRD(r6)
365	isync
366	mr	r3,r9
367	addi	r1,r1,STKFRM
368	blr
369	EX_TABLE(2b,3b)
370
371#endif /* CONFIG_VSX */
372
373#endif	/* CONFIG_PPC_FPU */
374