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