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