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