xref: /linux/arch/powerpc/lib/ldstfp.S (revision 8d0f1e05ab16c4bd628ddaefd20b94ffb36d799c)
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 <asm/asm-compat.h>
19#include <linux/errno.h>
20
21#define STKFRM	(PPC_MIN_STKFRM + 16)
22
23/* Get the contents of frN into *p; N is in r3 and p is in r4. */
24_GLOBAL(get_fpr)
25	mflr	r0
26	mfmsr	r6
27	ori	r7, r6, MSR_FP
28	MTMSRD(r7)
29	isync
30	rlwinm	r3,r3,3,0xf8
31	bcl	20,31,1f
32reg = 0
33	.rept	32
34	stfd	reg, 0(r4)
35	b	2f
36reg = reg + 1
37	.endr
381:	mflr	r5
39	add	r5,r3,r5
40	mtctr	r5
41	mtlr	r0
42	bctr
432:	MTMSRD(r6)
44	isync
45	blr
46
47/* Put the contents of *p into frN; N is in r3 and p is in r4. */
48_GLOBAL(put_fpr)
49	mflr	r0
50	mfmsr	r6
51	ori	r7, r6, MSR_FP
52	MTMSRD(r7)
53	isync
54	rlwinm	r3,r3,3,0xf8
55	bcl	20,31,1f
56reg = 0
57	.rept	32
58	lfd	reg, 0(r4)
59	b	2f
60reg = reg + 1
61	.endr
621:	mflr	r5
63	add	r5,r3,r5
64	mtctr	r5
65	mtlr	r0
66	bctr
672:	MTMSRD(r6)
68	isync
69	blr
70
71#ifdef CONFIG_ALTIVEC
72/* Get the contents of vrN into *p; N is in r3 and p is in r4. */
73_GLOBAL(get_vr)
74	mflr	r0
75	mfmsr	r6
76	oris	r7, r6, MSR_VEC@h
77	MTMSRD(r7)
78	isync
79	rlwinm	r3,r3,3,0xf8
80	bcl	20,31,1f
81reg = 0
82	.rept	32
83	stvx	reg, 0, r4
84	b	2f
85reg = reg + 1
86	.endr
871:	mflr	r5
88	add	r5,r3,r5
89	mtctr	r5
90	mtlr	r0
91	bctr
922:	MTMSRD(r6)
93	isync
94	blr
95
96/* Put the contents of *p into vrN; N is in r3 and p is in r4. */
97_GLOBAL(put_vr)
98	mflr	r0
99	mfmsr	r6
100	oris	r7, r6, MSR_VEC@h
101	MTMSRD(r7)
102	isync
103	rlwinm	r3,r3,3,0xf8
104	bcl	20,31,1f
105reg = 0
106	.rept	32
107	lvx	reg, 0, r4
108	b	2f
109reg = reg + 1
110	.endr
1111:	mflr	r5
112	add	r5,r3,r5
113	mtctr	r5
114	mtlr	r0
115	bctr
1162:	MTMSRD(r6)
117	isync
118	blr
119#endif /* CONFIG_ALTIVEC */
120
121#ifdef CONFIG_VSX
122/* Get the contents of vsN into vs0; N is in r3. */
123_GLOBAL(get_vsr)
124	mflr	r0
125	rlwinm	r3,r3,3,0x1f8
126	bcl	20,31,1f
127	blr			/* vs0 is already in vs0 */
128	nop
129reg = 1
130	.rept	63
131	XXLOR(0,reg,reg)
132	blr
133reg = reg + 1
134	.endr
1351:	mflr	r5
136	add	r5,r3,r5
137	mtctr	r5
138	mtlr	r0
139	bctr
140
141/* Put the contents of vs0 into vsN; N is in r3. */
142_GLOBAL(put_vsr)
143	mflr	r0
144	rlwinm	r3,r3,3,0x1f8
145	bcl	20,31,1f
146	blr			/* v0 is already in v0 */
147	nop
148reg = 1
149	.rept	63
150	XXLOR(reg,0,0)
151	blr
152reg = reg + 1
153	.endr
1541:	mflr	r5
155	add	r5,r3,r5
156	mtctr	r5
157	mtlr	r0
158	bctr
159
160/* Load VSX reg N from vector doubleword *p.  N is in r3, p in r4. */
161_GLOBAL(load_vsrn)
162	PPC_STLU r1,-STKFRM(r1)
163	mflr	r0
164	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
165	mfmsr	r6
166	oris	r7,r6,MSR_VSX@h
167	cmpwi	cr7,r3,0
168	li	r8,STKFRM-16
169	MTMSRD(r7)
170	isync
171	beq	cr7,1f
172	STXVD2X(0,R1,R8)
1731:	LXVD2X(0,R0,R4)
174#ifdef __LITTLE_ENDIAN__
175	XXSWAPD(0,0)
176#endif
177	beq	cr7,4f
178	bl	put_vsr
179	LXVD2X(0,R1,R8)
1804:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
181	mtlr	r0
182	MTMSRD(r6)
183	isync
184	addi	r1,r1,STKFRM
185	blr
186
187/* Store VSX reg N to vector doubleword *p.  N is in r3, p in r4. */
188_GLOBAL(store_vsrn)
189	PPC_STLU r1,-STKFRM(r1)
190	mflr	r0
191	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
192	mfmsr	r6
193	oris	r7,r6,MSR_VSX@h
194	li	r8,STKFRM-16
195	MTMSRD(r7)
196	isync
197	STXVD2X(0,R1,R8)
198	bl	get_vsr
199#ifdef __LITTLE_ENDIAN__
200	XXSWAPD(0,0)
201#endif
202	STXVD2X(0,R0,R4)
203	LXVD2X(0,R1,R8)
204	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
205	mtlr	r0
206	MTMSRD(r6)
207	isync
208	mr	r3,r9
209	addi	r1,r1,STKFRM
210	blr
211#endif /* CONFIG_VSX */
212
213/* Convert single-precision to double, without disturbing FPRs. */
214/* conv_sp_to_dp(float *sp, double *dp) */
215_GLOBAL(conv_sp_to_dp)
216	mfmsr	r6
217	ori	r7, r6, MSR_FP
218	MTMSRD(r7)
219	isync
220	stfd	fr0, -16(r1)
221	lfs	fr0, 0(r3)
222	stfd	fr0, 0(r4)
223	lfd	fr0, -16(r1)
224	MTMSRD(r6)
225	isync
226	blr
227
228/* Convert single-precision to double, without disturbing FPRs. */
229/* conv_sp_to_dp(double *dp, float *sp) */
230_GLOBAL(conv_dp_to_sp)
231	mfmsr	r6
232	ori	r7, r6, MSR_FP
233	MTMSRD(r7)
234	isync
235	stfd	fr0, -16(r1)
236	lfd	fr0, 0(r3)
237	stfs	fr0, 0(r4)
238	lfd	fr0, -16(r1)
239	MTMSRD(r6)
240	isync
241	blr
242