xref: /linux/arch/powerpc/math-emu/math_efp.c (revision 6a800f36acd5bf06b5fe2cb27c4d0524d60c3df5)
1*6a800f36SLiu Yu /*
2*6a800f36SLiu Yu  * arch/powerpc/math-emu/math_efp.c
3*6a800f36SLiu Yu  *
4*6a800f36SLiu Yu  * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved.
5*6a800f36SLiu Yu  *
6*6a800f36SLiu Yu  * Author: Ebony Zhu,	<ebony.zhu@freescale.com>
7*6a800f36SLiu Yu  *         Yu Liu,	<yu.liu@freescale.com>
8*6a800f36SLiu Yu  *
9*6a800f36SLiu Yu  * Derived from arch/alpha/math-emu/math.c
10*6a800f36SLiu Yu  *              arch/powerpc/math-emu/math.c
11*6a800f36SLiu Yu  *
12*6a800f36SLiu Yu  * Description:
13*6a800f36SLiu Yu  * This file is the exception handler to make E500 SPE instructions
14*6a800f36SLiu Yu  * fully comply with IEEE-754 floating point standard.
15*6a800f36SLiu Yu  *
16*6a800f36SLiu Yu  * This program is free software; you can redistribute it and/or
17*6a800f36SLiu Yu  * modify it under the terms of the GNU General Public License
18*6a800f36SLiu Yu  * as published by the Free Software Foundation; either version
19*6a800f36SLiu Yu  * 2 of the License, or (at your option) any later version.
20*6a800f36SLiu Yu  */
21*6a800f36SLiu Yu 
22*6a800f36SLiu Yu #include <linux/types.h>
23*6a800f36SLiu Yu 
24*6a800f36SLiu Yu #include <asm/uaccess.h>
25*6a800f36SLiu Yu #include <asm/reg.h>
26*6a800f36SLiu Yu 
27*6a800f36SLiu Yu #define FP_EX_BOOKE_E500_SPE
28*6a800f36SLiu Yu #include <asm/sfp-machine.h>
29*6a800f36SLiu Yu 
30*6a800f36SLiu Yu #include <math-emu/soft-fp.h>
31*6a800f36SLiu Yu #include <math-emu/single.h>
32*6a800f36SLiu Yu #include <math-emu/double.h>
33*6a800f36SLiu Yu 
34*6a800f36SLiu Yu #define EFAPU		0x4
35*6a800f36SLiu Yu 
36*6a800f36SLiu Yu #define VCT		0x4
37*6a800f36SLiu Yu #define SPFP		0x6
38*6a800f36SLiu Yu #define DPFP		0x7
39*6a800f36SLiu Yu 
40*6a800f36SLiu Yu #define EFSADD		0x2c0
41*6a800f36SLiu Yu #define EFSSUB		0x2c1
42*6a800f36SLiu Yu #define EFSABS		0x2c4
43*6a800f36SLiu Yu #define EFSNABS		0x2c5
44*6a800f36SLiu Yu #define EFSNEG		0x2c6
45*6a800f36SLiu Yu #define EFSMUL		0x2c8
46*6a800f36SLiu Yu #define EFSDIV		0x2c9
47*6a800f36SLiu Yu #define EFSCMPGT	0x2cc
48*6a800f36SLiu Yu #define EFSCMPLT	0x2cd
49*6a800f36SLiu Yu #define EFSCMPEQ	0x2ce
50*6a800f36SLiu Yu #define EFSCFD		0x2cf
51*6a800f36SLiu Yu #define EFSCFSI		0x2d1
52*6a800f36SLiu Yu #define EFSCTUI		0x2d4
53*6a800f36SLiu Yu #define EFSCTSI		0x2d5
54*6a800f36SLiu Yu #define EFSCTUF		0x2d6
55*6a800f36SLiu Yu #define EFSCTSF		0x2d7
56*6a800f36SLiu Yu #define EFSCTUIZ	0x2d8
57*6a800f36SLiu Yu #define EFSCTSIZ	0x2da
58*6a800f36SLiu Yu 
59*6a800f36SLiu Yu #define EVFSADD		0x280
60*6a800f36SLiu Yu #define EVFSSUB		0x281
61*6a800f36SLiu Yu #define EVFSABS		0x284
62*6a800f36SLiu Yu #define EVFSNABS	0x285
63*6a800f36SLiu Yu #define EVFSNEG		0x286
64*6a800f36SLiu Yu #define EVFSMUL		0x288
65*6a800f36SLiu Yu #define EVFSDIV		0x289
66*6a800f36SLiu Yu #define EVFSCMPGT	0x28c
67*6a800f36SLiu Yu #define EVFSCMPLT	0x28d
68*6a800f36SLiu Yu #define EVFSCMPEQ	0x28e
69*6a800f36SLiu Yu #define EVFSCTUI	0x294
70*6a800f36SLiu Yu #define EVFSCTSI	0x295
71*6a800f36SLiu Yu #define EVFSCTUF	0x296
72*6a800f36SLiu Yu #define EVFSCTSF	0x297
73*6a800f36SLiu Yu #define EVFSCTUIZ	0x298
74*6a800f36SLiu Yu #define EVFSCTSIZ	0x29a
75*6a800f36SLiu Yu 
76*6a800f36SLiu Yu #define EFDADD		0x2e0
77*6a800f36SLiu Yu #define EFDSUB		0x2e1
78*6a800f36SLiu Yu #define EFDABS		0x2e4
79*6a800f36SLiu Yu #define EFDNABS		0x2e5
80*6a800f36SLiu Yu #define EFDNEG		0x2e6
81*6a800f36SLiu Yu #define EFDMUL		0x2e8
82*6a800f36SLiu Yu #define EFDDIV		0x2e9
83*6a800f36SLiu Yu #define EFDCTUIDZ	0x2ea
84*6a800f36SLiu Yu #define EFDCTSIDZ	0x2eb
85*6a800f36SLiu Yu #define EFDCMPGT	0x2ec
86*6a800f36SLiu Yu #define EFDCMPLT	0x2ed
87*6a800f36SLiu Yu #define EFDCMPEQ	0x2ee
88*6a800f36SLiu Yu #define EFDCFS		0x2ef
89*6a800f36SLiu Yu #define EFDCTUI		0x2f4
90*6a800f36SLiu Yu #define EFDCTSI		0x2f5
91*6a800f36SLiu Yu #define EFDCTUF		0x2f6
92*6a800f36SLiu Yu #define EFDCTSF		0x2f7
93*6a800f36SLiu Yu #define EFDCTUIZ	0x2f8
94*6a800f36SLiu Yu #define EFDCTSIZ	0x2fa
95*6a800f36SLiu Yu 
96*6a800f36SLiu Yu #define AB	2
97*6a800f36SLiu Yu #define XA	3
98*6a800f36SLiu Yu #define XB	4
99*6a800f36SLiu Yu #define XCR	5
100*6a800f36SLiu Yu #define NOTYPE	0
101*6a800f36SLiu Yu 
102*6a800f36SLiu Yu #define SIGN_BIT_S	(1UL << 31)
103*6a800f36SLiu Yu #define SIGN_BIT_D	(1ULL << 63)
104*6a800f36SLiu Yu #define FP_EX_MASK	(FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \
105*6a800f36SLiu Yu 			FP_EX_UNDERFLOW | FP_EX_OVERFLOW)
106*6a800f36SLiu Yu 
107*6a800f36SLiu Yu union dw_union {
108*6a800f36SLiu Yu 	u64 dp[1];
109*6a800f36SLiu Yu 	u32 wp[2];
110*6a800f36SLiu Yu };
111*6a800f36SLiu Yu 
112*6a800f36SLiu Yu static unsigned long insn_type(unsigned long speinsn)
113*6a800f36SLiu Yu {
114*6a800f36SLiu Yu 	unsigned long ret = NOTYPE;
115*6a800f36SLiu Yu 
116*6a800f36SLiu Yu 	switch (speinsn & 0x7ff) {
117*6a800f36SLiu Yu 	case EFSABS:	ret = XA;	break;
118*6a800f36SLiu Yu 	case EFSADD:	ret = AB;	break;
119*6a800f36SLiu Yu 	case EFSCFD:	ret = XB;	break;
120*6a800f36SLiu Yu 	case EFSCMPEQ:	ret = XCR;	break;
121*6a800f36SLiu Yu 	case EFSCMPGT:	ret = XCR;	break;
122*6a800f36SLiu Yu 	case EFSCMPLT:	ret = XCR;	break;
123*6a800f36SLiu Yu 	case EFSCTSF:	ret = XB;	break;
124*6a800f36SLiu Yu 	case EFSCTSI:	ret = XB;	break;
125*6a800f36SLiu Yu 	case EFSCTSIZ:	ret = XB;	break;
126*6a800f36SLiu Yu 	case EFSCTUF:	ret = XB;	break;
127*6a800f36SLiu Yu 	case EFSCTUI:	ret = XB;	break;
128*6a800f36SLiu Yu 	case EFSCTUIZ:	ret = XB;	break;
129*6a800f36SLiu Yu 	case EFSDIV:	ret = AB;	break;
130*6a800f36SLiu Yu 	case EFSMUL:	ret = AB;	break;
131*6a800f36SLiu Yu 	case EFSNABS:	ret = XA;	break;
132*6a800f36SLiu Yu 	case EFSNEG:	ret = XA;	break;
133*6a800f36SLiu Yu 	case EFSSUB:	ret = AB;	break;
134*6a800f36SLiu Yu 	case EFSCFSI:	ret = XB;	break;
135*6a800f36SLiu Yu 
136*6a800f36SLiu Yu 	case EVFSABS:	ret = XA;	break;
137*6a800f36SLiu Yu 	case EVFSADD:	ret = AB;	break;
138*6a800f36SLiu Yu 	case EVFSCMPEQ:	ret = XCR;	break;
139*6a800f36SLiu Yu 	case EVFSCMPGT:	ret = XCR;	break;
140*6a800f36SLiu Yu 	case EVFSCMPLT:	ret = XCR;	break;
141*6a800f36SLiu Yu 	case EVFSCTSF:	ret = XB;	break;
142*6a800f36SLiu Yu 	case EVFSCTSI:	ret = XB;	break;
143*6a800f36SLiu Yu 	case EVFSCTSIZ:	ret = XB;	break;
144*6a800f36SLiu Yu 	case EVFSCTUF:	ret = XB;	break;
145*6a800f36SLiu Yu 	case EVFSCTUI:	ret = XB;	break;
146*6a800f36SLiu Yu 	case EVFSCTUIZ:	ret = XB;	break;
147*6a800f36SLiu Yu 	case EVFSDIV:	ret = AB;	break;
148*6a800f36SLiu Yu 	case EVFSMUL:	ret = AB;	break;
149*6a800f36SLiu Yu 	case EVFSNABS:	ret = XA;	break;
150*6a800f36SLiu Yu 	case EVFSNEG:	ret = XA;	break;
151*6a800f36SLiu Yu 	case EVFSSUB:	ret = AB;	break;
152*6a800f36SLiu Yu 
153*6a800f36SLiu Yu 	case EFDABS:	ret = XA;	break;
154*6a800f36SLiu Yu 	case EFDADD:	ret = AB;	break;
155*6a800f36SLiu Yu 	case EFDCFS:	ret = XB;	break;
156*6a800f36SLiu Yu 	case EFDCMPEQ:	ret = XCR;	break;
157*6a800f36SLiu Yu 	case EFDCMPGT:	ret = XCR;	break;
158*6a800f36SLiu Yu 	case EFDCMPLT:	ret = XCR;	break;
159*6a800f36SLiu Yu 	case EFDCTSF:	ret = XB;	break;
160*6a800f36SLiu Yu 	case EFDCTSI:	ret = XB;	break;
161*6a800f36SLiu Yu 	case EFDCTSIDZ:	ret = XB;	break;
162*6a800f36SLiu Yu 	case EFDCTSIZ:	ret = XB;	break;
163*6a800f36SLiu Yu 	case EFDCTUF:	ret = XB;	break;
164*6a800f36SLiu Yu 	case EFDCTUI:	ret = XB;	break;
165*6a800f36SLiu Yu 	case EFDCTUIDZ:	ret = XB;	break;
166*6a800f36SLiu Yu 	case EFDCTUIZ:	ret = XB;	break;
167*6a800f36SLiu Yu 	case EFDDIV:	ret = AB;	break;
168*6a800f36SLiu Yu 	case EFDMUL:	ret = AB;	break;
169*6a800f36SLiu Yu 	case EFDNABS:	ret = XA;	break;
170*6a800f36SLiu Yu 	case EFDNEG:	ret = XA;	break;
171*6a800f36SLiu Yu 	case EFDSUB:	ret = AB;	break;
172*6a800f36SLiu Yu 
173*6a800f36SLiu Yu 	default:
174*6a800f36SLiu Yu 		printk(KERN_ERR "\nOoops! SPE instruction no type found.");
175*6a800f36SLiu Yu 		printk(KERN_ERR "\ninst code: %08lx\n", speinsn);
176*6a800f36SLiu Yu 	}
177*6a800f36SLiu Yu 
178*6a800f36SLiu Yu 	return ret;
179*6a800f36SLiu Yu }
180*6a800f36SLiu Yu 
181*6a800f36SLiu Yu int do_spe_mathemu(struct pt_regs *regs)
182*6a800f36SLiu Yu {
183*6a800f36SLiu Yu 	FP_DECL_EX;
184*6a800f36SLiu Yu 	int IR, cmp;
185*6a800f36SLiu Yu 
186*6a800f36SLiu Yu 	unsigned long type, func, fc, fa, fb, src, speinsn;
187*6a800f36SLiu Yu 	union dw_union vc, va, vb;
188*6a800f36SLiu Yu 
189*6a800f36SLiu Yu 	if (get_user(speinsn, (unsigned int __user *) regs->nip))
190*6a800f36SLiu Yu 		return -EFAULT;
191*6a800f36SLiu Yu 	if ((speinsn >> 26) != EFAPU)
192*6a800f36SLiu Yu 		return -EINVAL;         /* not an spe instruction */
193*6a800f36SLiu Yu 
194*6a800f36SLiu Yu 	type = insn_type(speinsn);
195*6a800f36SLiu Yu 	if (type == NOTYPE)
196*6a800f36SLiu Yu 		return -ENOSYS;
197*6a800f36SLiu Yu 
198*6a800f36SLiu Yu 	func = speinsn & 0x7ff;
199*6a800f36SLiu Yu 	fc = (speinsn >> 21) & 0x1f;
200*6a800f36SLiu Yu 	fa = (speinsn >> 16) & 0x1f;
201*6a800f36SLiu Yu 	fb = (speinsn >> 11) & 0x1f;
202*6a800f36SLiu Yu 	src = (speinsn >> 5) & 0x7;
203*6a800f36SLiu Yu 
204*6a800f36SLiu Yu 	vc.wp[0] = current->thread.evr[fc];
205*6a800f36SLiu Yu 	vc.wp[1] = regs->gpr[fc];
206*6a800f36SLiu Yu 	va.wp[0] = current->thread.evr[fa];
207*6a800f36SLiu Yu 	va.wp[1] = regs->gpr[fa];
208*6a800f36SLiu Yu 	vb.wp[0] = current->thread.evr[fb];
209*6a800f36SLiu Yu 	vb.wp[1] = regs->gpr[fb];
210*6a800f36SLiu Yu 
211*6a800f36SLiu Yu 	__FPU_FPSCR = mfspr(SPRN_SPEFSCR);
212*6a800f36SLiu Yu 
213*6a800f36SLiu Yu #ifdef DEBUG
214*6a800f36SLiu Yu 	printk("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
215*6a800f36SLiu Yu 	printk("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
216*6a800f36SLiu Yu 	printk("va: %08x  %08x\n", va.wp[0], va.wp[1]);
217*6a800f36SLiu Yu 	printk("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
218*6a800f36SLiu Yu #endif
219*6a800f36SLiu Yu 
220*6a800f36SLiu Yu 	switch (src) {
221*6a800f36SLiu Yu 	case SPFP: {
222*6a800f36SLiu Yu 		FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
223*6a800f36SLiu Yu 
224*6a800f36SLiu Yu 		switch (type) {
225*6a800f36SLiu Yu 		case AB:
226*6a800f36SLiu Yu 		case XCR:
227*6a800f36SLiu Yu 			FP_UNPACK_SP(SA, va.wp + 1);
228*6a800f36SLiu Yu 		case XB:
229*6a800f36SLiu Yu 			FP_UNPACK_SP(SB, vb.wp + 1);
230*6a800f36SLiu Yu 			break;
231*6a800f36SLiu Yu 		case XA:
232*6a800f36SLiu Yu 			FP_UNPACK_SP(SA, va.wp + 1);
233*6a800f36SLiu Yu 			break;
234*6a800f36SLiu Yu 		}
235*6a800f36SLiu Yu 
236*6a800f36SLiu Yu #ifdef DEBUG
237*6a800f36SLiu Yu 		printk("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c);
238*6a800f36SLiu Yu 		printk("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c);
239*6a800f36SLiu Yu #endif
240*6a800f36SLiu Yu 
241*6a800f36SLiu Yu 		switch (func) {
242*6a800f36SLiu Yu 		case EFSABS:
243*6a800f36SLiu Yu 			vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
244*6a800f36SLiu Yu 			goto update_regs;
245*6a800f36SLiu Yu 
246*6a800f36SLiu Yu 		case EFSNABS:
247*6a800f36SLiu Yu 			vc.wp[1] = va.wp[1] | SIGN_BIT_S;
248*6a800f36SLiu Yu 			goto update_regs;
249*6a800f36SLiu Yu 
250*6a800f36SLiu Yu 		case EFSNEG:
251*6a800f36SLiu Yu 			vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
252*6a800f36SLiu Yu 			goto update_regs;
253*6a800f36SLiu Yu 
254*6a800f36SLiu Yu 		case EFSADD:
255*6a800f36SLiu Yu 			FP_ADD_S(SR, SA, SB);
256*6a800f36SLiu Yu 			goto pack_s;
257*6a800f36SLiu Yu 
258*6a800f36SLiu Yu 		case EFSSUB:
259*6a800f36SLiu Yu 			FP_SUB_S(SR, SA, SB);
260*6a800f36SLiu Yu 			goto pack_s;
261*6a800f36SLiu Yu 
262*6a800f36SLiu Yu 		case EFSMUL:
263*6a800f36SLiu Yu 			FP_MUL_S(SR, SA, SB);
264*6a800f36SLiu Yu 			goto pack_s;
265*6a800f36SLiu Yu 
266*6a800f36SLiu Yu 		case EFSDIV:
267*6a800f36SLiu Yu 			FP_DIV_S(SR, SA, SB);
268*6a800f36SLiu Yu 			goto pack_s;
269*6a800f36SLiu Yu 
270*6a800f36SLiu Yu 		case EFSCMPEQ:
271*6a800f36SLiu Yu 			cmp = 0;
272*6a800f36SLiu Yu 			goto cmp_s;
273*6a800f36SLiu Yu 
274*6a800f36SLiu Yu 		case EFSCMPGT:
275*6a800f36SLiu Yu 			cmp = 1;
276*6a800f36SLiu Yu 			goto cmp_s;
277*6a800f36SLiu Yu 
278*6a800f36SLiu Yu 		case EFSCMPLT:
279*6a800f36SLiu Yu 			cmp = -1;
280*6a800f36SLiu Yu 			goto cmp_s;
281*6a800f36SLiu Yu 
282*6a800f36SLiu Yu 		case EFSCTSF:
283*6a800f36SLiu Yu 		case EFSCTUF:
284*6a800f36SLiu Yu 			if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) {
285*6a800f36SLiu Yu 				/* NaN */
286*6a800f36SLiu Yu 				if (((vb.wp[1] >> 23) & 0xff) == 0) {
287*6a800f36SLiu Yu 					/* denorm */
288*6a800f36SLiu Yu 					vc.wp[1] = 0x0;
289*6a800f36SLiu Yu 				} else if ((vb.wp[1] >> 31) == 0) {
290*6a800f36SLiu Yu 					/* positive normal */
291*6a800f36SLiu Yu 					vc.wp[1] = (func == EFSCTSF) ?
292*6a800f36SLiu Yu 						0x7fffffff : 0xffffffff;
293*6a800f36SLiu Yu 				} else { /* negative normal */
294*6a800f36SLiu Yu 					vc.wp[1] = (func == EFSCTSF) ?
295*6a800f36SLiu Yu 						0x80000000 : 0x0;
296*6a800f36SLiu Yu 				}
297*6a800f36SLiu Yu 			} else { /* rB is NaN */
298*6a800f36SLiu Yu 				vc.wp[1] = 0x0;
299*6a800f36SLiu Yu 			}
300*6a800f36SLiu Yu 			goto update_regs;
301*6a800f36SLiu Yu 
302*6a800f36SLiu Yu 		case EFSCFD: {
303*6a800f36SLiu Yu 			FP_DECL_D(DB);
304*6a800f36SLiu Yu 			FP_CLEAR_EXCEPTIONS;
305*6a800f36SLiu Yu 			FP_UNPACK_DP(DB, vb.dp);
306*6a800f36SLiu Yu #ifdef DEBUG
307*6a800f36SLiu Yu 			printk("DB: %ld %08lx %08lx %ld (%ld)\n",
308*6a800f36SLiu Yu 					DB_s, DB_f1, DB_f0, DB_e, DB_c);
309*6a800f36SLiu Yu #endif
310*6a800f36SLiu Yu 			FP_CONV(S, D, 1, 2, SR, DB);
311*6a800f36SLiu Yu 			goto pack_s;
312*6a800f36SLiu Yu 		}
313*6a800f36SLiu Yu 
314*6a800f36SLiu Yu 		case EFSCTSI:
315*6a800f36SLiu Yu 		case EFSCTSIZ:
316*6a800f36SLiu Yu 		case EFSCTUI:
317*6a800f36SLiu Yu 		case EFSCTUIZ:
318*6a800f36SLiu Yu 			if (func & 0x4) {
319*6a800f36SLiu Yu 				_FP_ROUND(1, SB);
320*6a800f36SLiu Yu 			} else {
321*6a800f36SLiu Yu 				_FP_ROUND_ZERO(1, SB);
322*6a800f36SLiu Yu 			}
323*6a800f36SLiu Yu 			FP_TO_INT_S(vc.wp[1], SB, 32, ((func & 0x3) != 0));
324*6a800f36SLiu Yu 			goto update_regs;
325*6a800f36SLiu Yu 
326*6a800f36SLiu Yu 		default:
327*6a800f36SLiu Yu 			goto illegal;
328*6a800f36SLiu Yu 		}
329*6a800f36SLiu Yu 		break;
330*6a800f36SLiu Yu 
331*6a800f36SLiu Yu pack_s:
332*6a800f36SLiu Yu #ifdef DEBUG
333*6a800f36SLiu Yu 		printk("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c);
334*6a800f36SLiu Yu #endif
335*6a800f36SLiu Yu 		FP_PACK_SP(vc.wp + 1, SR);
336*6a800f36SLiu Yu 		goto update_regs;
337*6a800f36SLiu Yu 
338*6a800f36SLiu Yu cmp_s:
339*6a800f36SLiu Yu 		FP_CMP_S(IR, SA, SB, 3);
340*6a800f36SLiu Yu 		if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB)))
341*6a800f36SLiu Yu 			FP_SET_EXCEPTION(FP_EX_INVALID);
342*6a800f36SLiu Yu 		if (IR == cmp) {
343*6a800f36SLiu Yu 			IR = 0x4;
344*6a800f36SLiu Yu 		} else {
345*6a800f36SLiu Yu 			IR = 0;
346*6a800f36SLiu Yu 		}
347*6a800f36SLiu Yu 		goto update_ccr;
348*6a800f36SLiu Yu 	}
349*6a800f36SLiu Yu 
350*6a800f36SLiu Yu 	case DPFP: {
351*6a800f36SLiu Yu 		FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
352*6a800f36SLiu Yu 
353*6a800f36SLiu Yu 		switch (type) {
354*6a800f36SLiu Yu 		case AB:
355*6a800f36SLiu Yu 		case XCR:
356*6a800f36SLiu Yu 			FP_UNPACK_DP(DA, va.dp);
357*6a800f36SLiu Yu 		case XB:
358*6a800f36SLiu Yu 			FP_UNPACK_DP(DB, vb.dp);
359*6a800f36SLiu Yu 			break;
360*6a800f36SLiu Yu 		case XA:
361*6a800f36SLiu Yu 			FP_UNPACK_DP(DA, va.dp);
362*6a800f36SLiu Yu 			break;
363*6a800f36SLiu Yu 		}
364*6a800f36SLiu Yu 
365*6a800f36SLiu Yu #ifdef DEBUG
366*6a800f36SLiu Yu 		printk("DA: %ld %08lx %08lx %ld (%ld)\n",
367*6a800f36SLiu Yu 				DA_s, DA_f1, DA_f0, DA_e, DA_c);
368*6a800f36SLiu Yu 		printk("DB: %ld %08lx %08lx %ld (%ld)\n",
369*6a800f36SLiu Yu 				DB_s, DB_f1, DB_f0, DB_e, DB_c);
370*6a800f36SLiu Yu #endif
371*6a800f36SLiu Yu 
372*6a800f36SLiu Yu 		switch (func) {
373*6a800f36SLiu Yu 		case EFDABS:
374*6a800f36SLiu Yu 			vc.dp[0] = va.dp[0] & ~SIGN_BIT_D;
375*6a800f36SLiu Yu 			goto update_regs;
376*6a800f36SLiu Yu 
377*6a800f36SLiu Yu 		case EFDNABS:
378*6a800f36SLiu Yu 			vc.dp[0] = va.dp[0] | SIGN_BIT_D;
379*6a800f36SLiu Yu 			goto update_regs;
380*6a800f36SLiu Yu 
381*6a800f36SLiu Yu 		case EFDNEG:
382*6a800f36SLiu Yu 			vc.dp[0] = va.dp[0] ^ SIGN_BIT_D;
383*6a800f36SLiu Yu 			goto update_regs;
384*6a800f36SLiu Yu 
385*6a800f36SLiu Yu 		case EFDADD:
386*6a800f36SLiu Yu 			FP_ADD_D(DR, DA, DB);
387*6a800f36SLiu Yu 			goto pack_d;
388*6a800f36SLiu Yu 
389*6a800f36SLiu Yu 		case EFDSUB:
390*6a800f36SLiu Yu 			FP_SUB_D(DR, DA, DB);
391*6a800f36SLiu Yu 			goto pack_d;
392*6a800f36SLiu Yu 
393*6a800f36SLiu Yu 		case EFDMUL:
394*6a800f36SLiu Yu 			FP_MUL_D(DR, DA, DB);
395*6a800f36SLiu Yu 			goto pack_d;
396*6a800f36SLiu Yu 
397*6a800f36SLiu Yu 		case EFDDIV:
398*6a800f36SLiu Yu 			FP_DIV_D(DR, DA, DB);
399*6a800f36SLiu Yu 			goto pack_d;
400*6a800f36SLiu Yu 
401*6a800f36SLiu Yu 		case EFDCMPEQ:
402*6a800f36SLiu Yu 			cmp = 0;
403*6a800f36SLiu Yu 			goto cmp_d;
404*6a800f36SLiu Yu 
405*6a800f36SLiu Yu 		case EFDCMPGT:
406*6a800f36SLiu Yu 			cmp = 1;
407*6a800f36SLiu Yu 			goto cmp_d;
408*6a800f36SLiu Yu 
409*6a800f36SLiu Yu 		case EFDCMPLT:
410*6a800f36SLiu Yu 			cmp = -1;
411*6a800f36SLiu Yu 			goto cmp_d;
412*6a800f36SLiu Yu 
413*6a800f36SLiu Yu 		case EFDCTSF:
414*6a800f36SLiu Yu 		case EFDCTUF:
415*6a800f36SLiu Yu 			if (!((vb.wp[0] >> 20) == 0x7ff &&
416*6a800f36SLiu Yu 			   ((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) {
417*6a800f36SLiu Yu 				/* not a NaN */
418*6a800f36SLiu Yu 				if (((vb.wp[0] >> 20) & 0x7ff) == 0) {
419*6a800f36SLiu Yu 					/* denorm */
420*6a800f36SLiu Yu 					vc.wp[1] = 0x0;
421*6a800f36SLiu Yu 				} else if ((vb.wp[0] >> 31) == 0) {
422*6a800f36SLiu Yu 					/* positive normal */
423*6a800f36SLiu Yu 					vc.wp[1] = (func == EFDCTSF) ?
424*6a800f36SLiu Yu 						0x7fffffff : 0xffffffff;
425*6a800f36SLiu Yu 				} else { /* negative normal */
426*6a800f36SLiu Yu 					vc.wp[1] = (func == EFDCTSF) ?
427*6a800f36SLiu Yu 						0x80000000 : 0x0;
428*6a800f36SLiu Yu 				}
429*6a800f36SLiu Yu 			} else { /* NaN */
430*6a800f36SLiu Yu 				vc.wp[1] = 0x0;
431*6a800f36SLiu Yu 			}
432*6a800f36SLiu Yu 			goto update_regs;
433*6a800f36SLiu Yu 
434*6a800f36SLiu Yu 		case EFDCFS: {
435*6a800f36SLiu Yu 			FP_DECL_S(SB);
436*6a800f36SLiu Yu 			FP_CLEAR_EXCEPTIONS;
437*6a800f36SLiu Yu 			FP_UNPACK_SP(SB, vb.wp + 1);
438*6a800f36SLiu Yu #ifdef DEBUG
439*6a800f36SLiu Yu 			printk("SB: %ld %08lx %ld (%ld)\n",
440*6a800f36SLiu Yu 					SB_s, SB_f, SB_e, SB_c);
441*6a800f36SLiu Yu #endif
442*6a800f36SLiu Yu 			FP_CONV(D, S, 2, 1, DR, SB);
443*6a800f36SLiu Yu 			goto pack_d;
444*6a800f36SLiu Yu 		}
445*6a800f36SLiu Yu 
446*6a800f36SLiu Yu 		case EFDCTUIDZ:
447*6a800f36SLiu Yu 		case EFDCTSIDZ:
448*6a800f36SLiu Yu 			_FP_ROUND_ZERO(2, DB);
449*6a800f36SLiu Yu 			FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0));
450*6a800f36SLiu Yu 			goto update_regs;
451*6a800f36SLiu Yu 
452*6a800f36SLiu Yu 		case EFDCTUI:
453*6a800f36SLiu Yu 		case EFDCTSI:
454*6a800f36SLiu Yu 		case EFDCTUIZ:
455*6a800f36SLiu Yu 		case EFDCTSIZ:
456*6a800f36SLiu Yu 			if (func & 0x4) {
457*6a800f36SLiu Yu 				_FP_ROUND(2, DB);
458*6a800f36SLiu Yu 			} else {
459*6a800f36SLiu Yu 				_FP_ROUND_ZERO(2, DB);
460*6a800f36SLiu Yu 			}
461*6a800f36SLiu Yu 			FP_TO_INT_D(vc.wp[1], DB, 32, ((func & 0x3) != 0));
462*6a800f36SLiu Yu 			goto update_regs;
463*6a800f36SLiu Yu 
464*6a800f36SLiu Yu 		default:
465*6a800f36SLiu Yu 			goto illegal;
466*6a800f36SLiu Yu 		}
467*6a800f36SLiu Yu 		break;
468*6a800f36SLiu Yu 
469*6a800f36SLiu Yu pack_d:
470*6a800f36SLiu Yu #ifdef DEBUG
471*6a800f36SLiu Yu 		printk("DR: %ld %08lx %08lx %ld (%ld)\n",
472*6a800f36SLiu Yu 				DR_s, DR_f1, DR_f0, DR_e, DR_c);
473*6a800f36SLiu Yu #endif
474*6a800f36SLiu Yu 		FP_PACK_DP(vc.dp, DR);
475*6a800f36SLiu Yu 		goto update_regs;
476*6a800f36SLiu Yu 
477*6a800f36SLiu Yu cmp_d:
478*6a800f36SLiu Yu 		FP_CMP_D(IR, DA, DB, 3);
479*6a800f36SLiu Yu 		if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
480*6a800f36SLiu Yu 			FP_SET_EXCEPTION(FP_EX_INVALID);
481*6a800f36SLiu Yu 		if (IR == cmp) {
482*6a800f36SLiu Yu 			IR = 0x4;
483*6a800f36SLiu Yu 		} else {
484*6a800f36SLiu Yu 			IR = 0;
485*6a800f36SLiu Yu 		}
486*6a800f36SLiu Yu 		goto update_ccr;
487*6a800f36SLiu Yu 
488*6a800f36SLiu Yu 	}
489*6a800f36SLiu Yu 
490*6a800f36SLiu Yu 	case VCT: {
491*6a800f36SLiu Yu 		FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0);
492*6a800f36SLiu Yu 		FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1);
493*6a800f36SLiu Yu 		int IR0, IR1;
494*6a800f36SLiu Yu 
495*6a800f36SLiu Yu 		switch (type) {
496*6a800f36SLiu Yu 		case AB:
497*6a800f36SLiu Yu 		case XCR:
498*6a800f36SLiu Yu 			FP_UNPACK_SP(SA0, va.wp);
499*6a800f36SLiu Yu 			FP_UNPACK_SP(SA1, va.wp + 1);
500*6a800f36SLiu Yu 		case XB:
501*6a800f36SLiu Yu 			FP_UNPACK_SP(SB0, vb.wp);
502*6a800f36SLiu Yu 			FP_UNPACK_SP(SB1, vb.wp + 1);
503*6a800f36SLiu Yu 			break;
504*6a800f36SLiu Yu 		case XA:
505*6a800f36SLiu Yu 			FP_UNPACK_SP(SA0, va.wp);
506*6a800f36SLiu Yu 			FP_UNPACK_SP(SA1, va.wp + 1);
507*6a800f36SLiu Yu 			break;
508*6a800f36SLiu Yu 		}
509*6a800f36SLiu Yu 
510*6a800f36SLiu Yu #ifdef DEBUG
511*6a800f36SLiu Yu 		printk("SA0: %ld %08lx %ld (%ld)\n", SA0_s, SA0_f, SA0_e, SA0_c);
512*6a800f36SLiu Yu 		printk("SA1: %ld %08lx %ld (%ld)\n", SA1_s, SA1_f, SA1_e, SA1_c);
513*6a800f36SLiu Yu 		printk("SB0: %ld %08lx %ld (%ld)\n", SB0_s, SB0_f, SB0_e, SB0_c);
514*6a800f36SLiu Yu 		printk("SB1: %ld %08lx %ld (%ld)\n", SB1_s, SB1_f, SB1_e, SB1_c);
515*6a800f36SLiu Yu #endif
516*6a800f36SLiu Yu 
517*6a800f36SLiu Yu 		switch (func) {
518*6a800f36SLiu Yu 		case EVFSABS:
519*6a800f36SLiu Yu 			vc.wp[0] = va.wp[0] & ~SIGN_BIT_S;
520*6a800f36SLiu Yu 			vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
521*6a800f36SLiu Yu 			goto update_regs;
522*6a800f36SLiu Yu 
523*6a800f36SLiu Yu 		case EVFSNABS:
524*6a800f36SLiu Yu 			vc.wp[0] = va.wp[0] | SIGN_BIT_S;
525*6a800f36SLiu Yu 			vc.wp[1] = va.wp[1] | SIGN_BIT_S;
526*6a800f36SLiu Yu 			goto update_regs;
527*6a800f36SLiu Yu 
528*6a800f36SLiu Yu 		case EVFSNEG:
529*6a800f36SLiu Yu 			vc.wp[0] = va.wp[0] ^ SIGN_BIT_S;
530*6a800f36SLiu Yu 			vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
531*6a800f36SLiu Yu 			goto update_regs;
532*6a800f36SLiu Yu 
533*6a800f36SLiu Yu 		case EVFSADD:
534*6a800f36SLiu Yu 			FP_ADD_S(SR0, SA0, SB0);
535*6a800f36SLiu Yu 			FP_ADD_S(SR1, SA1, SB1);
536*6a800f36SLiu Yu 			goto pack_vs;
537*6a800f36SLiu Yu 
538*6a800f36SLiu Yu 		case EVFSSUB:
539*6a800f36SLiu Yu 			FP_SUB_S(SR0, SA0, SB0);
540*6a800f36SLiu Yu 			FP_SUB_S(SR1, SA1, SB1);
541*6a800f36SLiu Yu 			goto pack_vs;
542*6a800f36SLiu Yu 
543*6a800f36SLiu Yu 		case EVFSMUL:
544*6a800f36SLiu Yu 			FP_MUL_S(SR0, SA0, SB0);
545*6a800f36SLiu Yu 			FP_MUL_S(SR1, SA1, SB1);
546*6a800f36SLiu Yu 			goto pack_vs;
547*6a800f36SLiu Yu 
548*6a800f36SLiu Yu 		case EVFSDIV:
549*6a800f36SLiu Yu 			FP_DIV_S(SR0, SA0, SB0);
550*6a800f36SLiu Yu 			FP_DIV_S(SR1, SA1, SB1);
551*6a800f36SLiu Yu 			goto pack_vs;
552*6a800f36SLiu Yu 
553*6a800f36SLiu Yu 		case EVFSCMPEQ:
554*6a800f36SLiu Yu 			cmp = 0;
555*6a800f36SLiu Yu 			goto cmp_vs;
556*6a800f36SLiu Yu 
557*6a800f36SLiu Yu 		case EVFSCMPGT:
558*6a800f36SLiu Yu 			cmp = 1;
559*6a800f36SLiu Yu 			goto cmp_vs;
560*6a800f36SLiu Yu 
561*6a800f36SLiu Yu 		case EVFSCMPLT:
562*6a800f36SLiu Yu 			cmp = -1;
563*6a800f36SLiu Yu 			goto cmp_vs;
564*6a800f36SLiu Yu 
565*6a800f36SLiu Yu 		case EVFSCTSF:
566*6a800f36SLiu Yu 			__asm__ __volatile__ ("mtspr 512, %4\n"
567*6a800f36SLiu Yu 				"efsctsf %0, %2\n"
568*6a800f36SLiu Yu 				"efsctsf %1, %3\n"
569*6a800f36SLiu Yu 				: "=r" (vc.wp[0]), "=r" (vc.wp[1])
570*6a800f36SLiu Yu 				: "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
571*6a800f36SLiu Yu 			goto update_regs;
572*6a800f36SLiu Yu 
573*6a800f36SLiu Yu 		case EVFSCTUF:
574*6a800f36SLiu Yu 			__asm__ __volatile__ ("mtspr 512, %4\n"
575*6a800f36SLiu Yu 				"efsctuf %0, %2\n"
576*6a800f36SLiu Yu 				"efsctuf %1, %3\n"
577*6a800f36SLiu Yu 				: "=r" (vc.wp[0]), "=r" (vc.wp[1])
578*6a800f36SLiu Yu 				: "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
579*6a800f36SLiu Yu 			goto update_regs;
580*6a800f36SLiu Yu 
581*6a800f36SLiu Yu 		case EVFSCTUI:
582*6a800f36SLiu Yu 		case EVFSCTSI:
583*6a800f36SLiu Yu 		case EVFSCTUIZ:
584*6a800f36SLiu Yu 		case EVFSCTSIZ:
585*6a800f36SLiu Yu 			if (func & 0x4) {
586*6a800f36SLiu Yu 				_FP_ROUND(1, SB0);
587*6a800f36SLiu Yu 				_FP_ROUND(1, SB1);
588*6a800f36SLiu Yu 			} else {
589*6a800f36SLiu Yu 				_FP_ROUND_ZERO(1, SB0);
590*6a800f36SLiu Yu 				_FP_ROUND_ZERO(1, SB1);
591*6a800f36SLiu Yu 			}
592*6a800f36SLiu Yu 			FP_TO_INT_S(vc.wp[0], SB0, 32, ((func & 0x3) != 0));
593*6a800f36SLiu Yu 			FP_TO_INT_S(vc.wp[1], SB1, 32, ((func & 0x3) != 0));
594*6a800f36SLiu Yu 			goto update_regs;
595*6a800f36SLiu Yu 
596*6a800f36SLiu Yu 		default:
597*6a800f36SLiu Yu 			goto illegal;
598*6a800f36SLiu Yu 		}
599*6a800f36SLiu Yu 		break;
600*6a800f36SLiu Yu 
601*6a800f36SLiu Yu pack_vs:
602*6a800f36SLiu Yu #ifdef DEBUG
603*6a800f36SLiu Yu 		printk("SR0: %ld %08lx %ld (%ld)\n", SR0_s, SR0_f, SR0_e, SR0_c);
604*6a800f36SLiu Yu 		printk("SR1: %ld %08lx %ld (%ld)\n", SR1_s, SR1_f, SR1_e, SR1_c);
605*6a800f36SLiu Yu #endif
606*6a800f36SLiu Yu 		FP_PACK_SP(vc.wp, SR0);
607*6a800f36SLiu Yu 		FP_PACK_SP(vc.wp + 1, SR1);
608*6a800f36SLiu Yu 		goto update_regs;
609*6a800f36SLiu Yu 
610*6a800f36SLiu Yu cmp_vs:
611*6a800f36SLiu Yu 		{
612*6a800f36SLiu Yu 			int ch, cl;
613*6a800f36SLiu Yu 
614*6a800f36SLiu Yu 			FP_CMP_S(IR0, SA0, SB0, 3);
615*6a800f36SLiu Yu 			FP_CMP_S(IR1, SA1, SB1, 3);
616*6a800f36SLiu Yu 			if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0)))
617*6a800f36SLiu Yu 				FP_SET_EXCEPTION(FP_EX_INVALID);
618*6a800f36SLiu Yu 			if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1)))
619*6a800f36SLiu Yu 				FP_SET_EXCEPTION(FP_EX_INVALID);
620*6a800f36SLiu Yu 			ch = (IR0 == cmp) ? 1 : 0;
621*6a800f36SLiu Yu 			cl = (IR1 == cmp) ? 1 : 0;
622*6a800f36SLiu Yu 			IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) |
623*6a800f36SLiu Yu 				((ch & cl) << 0);
624*6a800f36SLiu Yu 			goto update_ccr;
625*6a800f36SLiu Yu 		}
626*6a800f36SLiu Yu 	}
627*6a800f36SLiu Yu 	default:
628*6a800f36SLiu Yu 		return -EINVAL;
629*6a800f36SLiu Yu 	}
630*6a800f36SLiu Yu 
631*6a800f36SLiu Yu update_ccr:
632*6a800f36SLiu Yu 	regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2));
633*6a800f36SLiu Yu 	regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2));
634*6a800f36SLiu Yu 
635*6a800f36SLiu Yu update_regs:
636*6a800f36SLiu Yu 	__FPU_FPSCR &= ~FP_EX_MASK;
637*6a800f36SLiu Yu 	__FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);
638*6a800f36SLiu Yu 	mtspr(SPRN_SPEFSCR, __FPU_FPSCR);
639*6a800f36SLiu Yu 
640*6a800f36SLiu Yu 	current->thread.evr[fc] = vc.wp[0];
641*6a800f36SLiu Yu 	regs->gpr[fc] = vc.wp[1];
642*6a800f36SLiu Yu 
643*6a800f36SLiu Yu #ifdef DEBUG
644*6a800f36SLiu Yu 	printk("ccr = %08lx\n", regs->ccr);
645*6a800f36SLiu Yu 	printk("cur exceptions = %08x spefscr = %08lx\n",
646*6a800f36SLiu Yu 			FP_CUR_EXCEPTIONS, __FPU_FPSCR);
647*6a800f36SLiu Yu 	printk("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
648*6a800f36SLiu Yu 	printk("va: %08x  %08x\n", va.wp[0], va.wp[1]);
649*6a800f36SLiu Yu 	printk("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
650*6a800f36SLiu Yu #endif
651*6a800f36SLiu Yu 
652*6a800f36SLiu Yu 	return 0;
653*6a800f36SLiu Yu 
654*6a800f36SLiu Yu illegal:
655*6a800f36SLiu Yu 	printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);
656*6a800f36SLiu Yu 	return -ENOSYS;
657*6a800f36SLiu Yu }
658*6a800f36SLiu Yu 
659*6a800f36SLiu Yu int speround_handler(struct pt_regs *regs)
660*6a800f36SLiu Yu {
661*6a800f36SLiu Yu 	union dw_union fgpr;
662*6a800f36SLiu Yu 	int s_lo, s_hi;
663*6a800f36SLiu Yu 	unsigned long speinsn, type, fc;
664*6a800f36SLiu Yu 
665*6a800f36SLiu Yu 	if (get_user(speinsn, (unsigned int __user *) regs->nip))
666*6a800f36SLiu Yu 		return -EFAULT;
667*6a800f36SLiu Yu 	if ((speinsn >> 26) != 4)
668*6a800f36SLiu Yu 		return -EINVAL;         /* not an spe instruction */
669*6a800f36SLiu Yu 
670*6a800f36SLiu Yu 	type = insn_type(speinsn & 0x7ff);
671*6a800f36SLiu Yu 	if (type == XCR) return -ENOSYS;
672*6a800f36SLiu Yu 
673*6a800f36SLiu Yu 	fc = (speinsn >> 21) & 0x1f;
674*6a800f36SLiu Yu 	s_lo = regs->gpr[fc] & SIGN_BIT_S;
675*6a800f36SLiu Yu 	s_hi = current->thread.evr[fc] & SIGN_BIT_S;
676*6a800f36SLiu Yu 	fgpr.wp[0] = current->thread.evr[fc];
677*6a800f36SLiu Yu 	fgpr.wp[1] = regs->gpr[fc];
678*6a800f36SLiu Yu 
679*6a800f36SLiu Yu 	__FPU_FPSCR = mfspr(SPRN_SPEFSCR);
680*6a800f36SLiu Yu 
681*6a800f36SLiu Yu 	switch ((speinsn >> 5) & 0x7) {
682*6a800f36SLiu Yu 	/* Since SPE instructions on E500 core can handle round to nearest
683*6a800f36SLiu Yu 	 * and round toward zero with IEEE-754 complied, we just need
684*6a800f36SLiu Yu 	 * to handle round toward +Inf and round toward -Inf by software.
685*6a800f36SLiu Yu 	 */
686*6a800f36SLiu Yu 	case SPFP:
687*6a800f36SLiu Yu 		if ((FP_ROUNDMODE) == FP_RND_PINF) {
688*6a800f36SLiu Yu 			if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */
689*6a800f36SLiu Yu 		} else { /* round to -Inf */
690*6a800f36SLiu Yu 			if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */
691*6a800f36SLiu Yu 		}
692*6a800f36SLiu Yu 		break;
693*6a800f36SLiu Yu 
694*6a800f36SLiu Yu 	case DPFP:
695*6a800f36SLiu Yu 		if (FP_ROUNDMODE == FP_RND_PINF) {
696*6a800f36SLiu Yu 			if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */
697*6a800f36SLiu Yu 		} else { /* round to -Inf */
698*6a800f36SLiu Yu 			if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */
699*6a800f36SLiu Yu 		}
700*6a800f36SLiu Yu 		break;
701*6a800f36SLiu Yu 
702*6a800f36SLiu Yu 	case VCT:
703*6a800f36SLiu Yu 		if (FP_ROUNDMODE == FP_RND_PINF) {
704*6a800f36SLiu Yu 			if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */
705*6a800f36SLiu Yu 			if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
706*6a800f36SLiu Yu 		} else { /* round to -Inf */
707*6a800f36SLiu Yu 			if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */
708*6a800f36SLiu Yu 			if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */
709*6a800f36SLiu Yu 		}
710*6a800f36SLiu Yu 		break;
711*6a800f36SLiu Yu 
712*6a800f36SLiu Yu 	default:
713*6a800f36SLiu Yu 		return -EINVAL;
714*6a800f36SLiu Yu 	}
715*6a800f36SLiu Yu 
716*6a800f36SLiu Yu 	current->thread.evr[fc] = fgpr.wp[0];
717*6a800f36SLiu Yu 	regs->gpr[fc] = fgpr.wp[1];
718*6a800f36SLiu Yu 
719*6a800f36SLiu Yu 	return 0;
720*6a800f36SLiu Yu }
721