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