File: /usr/src/linux/arch/ppc/math-emu/math.c

1     /*
2      * BK Id: SCCS/s.math.c 1.6 05/17/01 18:14:23 cort
3      */
4     /*
5      * arch/ppc/math-emu/math.c
6      *
7      * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
8      */
9     
10     #include <linux/config.h>
11     #include <linux/types.h>
12     #include <linux/sched.h>
13     
14     #include <asm/uaccess.h>
15     #include <asm/processor.h>
16     
17     #include "sfp-machine.h"
18     #include "double.h"
19     
20     #define FLOATFUNC(x)	extern int x(void *, void *, void *, void *)
21     
22     FLOATFUNC(fadd);
23     FLOATFUNC(fadds);
24     FLOATFUNC(fdiv);
25     FLOATFUNC(fdivs);
26     FLOATFUNC(fmul);
27     FLOATFUNC(fmuls);
28     FLOATFUNC(fsub);
29     FLOATFUNC(fsubs);
30     
31     FLOATFUNC(fmadd);
32     FLOATFUNC(fmadds);
33     FLOATFUNC(fmsub);
34     FLOATFUNC(fmsubs);
35     FLOATFUNC(fnmadd);
36     FLOATFUNC(fnmadds);
37     FLOATFUNC(fnmsub);
38     FLOATFUNC(fnmsubs);
39     
40     FLOATFUNC(fctiw);
41     FLOATFUNC(fctiwz);
42     FLOATFUNC(frsp);
43     
44     FLOATFUNC(fcmpo);
45     FLOATFUNC(fcmpu);
46     
47     FLOATFUNC(mcrfs);
48     FLOATFUNC(mffs);
49     FLOATFUNC(mtfsb0);
50     FLOATFUNC(mtfsb1);
51     FLOATFUNC(mtfsf);
52     FLOATFUNC(mtfsfi);
53     
54     FLOATFUNC(lfd);
55     FLOATFUNC(lfs);
56     
57     FLOATFUNC(stfd);
58     FLOATFUNC(stfs);
59     FLOATFUNC(stfiwx);
60     
61     FLOATFUNC(fabs);
62     FLOATFUNC(fmr);
63     FLOATFUNC(fnabs);
64     FLOATFUNC(fneg);
65     
66     /* Optional */
67     FLOATFUNC(fres);
68     FLOATFUNC(frsqrte);
69     FLOATFUNC(fsel);
70     FLOATFUNC(fsqrt);
71     FLOATFUNC(fsqrts);
72     
73     
74     #define OP31		0x1f		/*   31 */
75     #define LFS		0x30		/*   48 */
76     #define LFSU		0x31		/*   49 */
77     #define LFD		0x32		/*   50 */
78     #define LFDU		0x33		/*   51 */
79     #define STFS		0x34		/*   52 */
80     #define STFSU		0x35		/*   53 */
81     #define STFD		0x36		/*   54 */
82     #define STFDU		0x37		/*   55 */
83     #define OP59		0x3b		/*   59 */
84     #define OP63		0x3f		/*   63 */
85     
86     /* Opcode 31: */
87     /* X-Form: */
88     #define LFSX		0x217		/*  535 */
89     #define LFSUX		0x237		/*  567 */
90     #define LFDX		0x257		/*  599 */
91     #define LFDUX		0x277		/*  631 */
92     #define STFSX		0x297		/*  663 */
93     #define STFSUX		0x2b7		/*  695 */
94     #define STFDX		0x2d7		/*  727 */
95     #define STFDUX		0x2f7		/*  759 */
96     #define STFIWX		0x3d7		/*  983 */
97     
98     /* Opcode 59: */
99     /* A-Form: */
100     #define FDIVS		0x012		/*   18 */
101     #define FSUBS		0x014		/*   20 */
102     #define FADDS		0x015		/*   21 */
103     #define FSQRTS		0x016		/*   22 */
104     #define FRES		0x018		/*   24 */
105     #define FMULS		0x019		/*   25 */
106     #define FMSUBS		0x01c		/*   28 */
107     #define FMADDS		0x01d		/*   29 */
108     #define FNMSUBS		0x01e		/*   30 */
109     #define FNMADDS		0x01f		/*   31 */
110     
111     /* Opcode 63: */
112     /* A-Form: */
113     #define FDIV		0x012		/*   18 */
114     #define FSUB		0x014		/*   20 */
115     #define FADD		0x015		/*   21 */
116     #define FSQRT		0x016		/*   22 */
117     #define FSEL		0x017		/*   23 */
118     #define FMUL		0x019		/*   25 */
119     #define FRSQRTE		0x01a		/*   26 */
120     #define FMSUB		0x01c		/*   28 */
121     #define FMADD		0x01d		/*   29 */
122     #define FNMSUB		0x01e		/*   30 */
123     #define FNMADD		0x01f		/*   31 */
124     
125     /* X-Form: */
126     #define FCMPU		0x000		/*    0	*/
127     #define FRSP		0x00c		/*   12 */
128     #define FCTIW		0x00e		/*   14 */
129     #define FCTIWZ		0x00f		/*   15 */
130     #define FCMPO		0x020		/*   32 */
131     #define MTFSB1		0x026		/*   38 */
132     #define FNEG		0x028		/*   40 */
133     #define MCRFS		0x040		/*   64 */
134     #define MTFSB0		0x046		/*   70 */
135     #define FMR		0x048		/*   72 */
136     #define MTFSFI		0x086		/*  134 */
137     #define FNABS		0x088		/*  136 */
138     #define FABS		0x108		/*  264 */
139     #define MFFS		0x247		/*  583 */
140     #define MTFSF		0x2c7		/*  711 */
141     
142     
143     #define AB	2
144     #define AC	3
145     #define ABC	4
146     #define D	5
147     #define DU	6
148     #define X	7
149     #define XA	8
150     #define XB	9
151     #define XCR	11
152     #define XCRB	12
153     #define XCRI	13
154     #define XCRL	16
155     #define XE	14
156     #define XEU	15
157     #define XFLB	10
158     
159     #ifdef CONFIG_MATH_EMULATION
160     static int
161     record_exception(struct pt_regs *regs, int eflag)
162     {
163     	u32 fpscr;
164     
165     	fpscr = __FPU_FPSCR;
166     
167     	if (eflag) {
168     		fpscr |= FPSCR_FX;
169     		if (eflag & EFLAG_OVERFLOW)
170     			fpscr |= FPSCR_OX;
171     		if (eflag & EFLAG_UNDERFLOW)
172     			fpscr |= FPSCR_UX;
173     		if (eflag & EFLAG_DIVZERO)
174     			fpscr |= FPSCR_ZX;
175     		if (eflag & EFLAG_INEXACT)
176     			fpscr |= FPSCR_XX;
177     		if (eflag & EFLAG_VXSNAN)
178     			fpscr |= FPSCR_VXSNAN;
179     		if (eflag & EFLAG_VXISI)
180     			fpscr |= FPSCR_VXISI;
181     		if (eflag & EFLAG_VXIDI)
182     			fpscr |= FPSCR_VXIDI;
183     		if (eflag & EFLAG_VXZDZ)
184     			fpscr |= FPSCR_VXZDZ;
185     		if (eflag & EFLAG_VXIMZ)
186     			fpscr |= FPSCR_VXIMZ;
187     		if (eflag & EFLAG_VXVC)
188     			fpscr |= FPSCR_VXVC;
189     		if (eflag & EFLAG_VXSOFT)
190     			fpscr |= FPSCR_VXSOFT;
191     		if (eflag & EFLAG_VXSQRT)
192     			fpscr |= FPSCR_VXSQRT;
193     		if (eflag & EFLAG_VXCVI)
194     			fpscr |= FPSCR_VXCVI;
195     	}
196     
197     	fpscr &= ~(FPSCR_VX);
198     	if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
199     		     FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
200     		     FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
201     		fpscr |= FPSCR_VX;
202     
203     	fpscr &= ~(FPSCR_FEX);
204     	if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
205     	    ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
206     	    ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
207     	    ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
208     	    ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
209     		fpscr |= FPSCR_FEX;
210     
211     	__FPU_FPSCR = fpscr;
212     
213     	return (fpscr & FPSCR_FEX) ? 1 : 0;
214     }
215     #endif /* CONFIG_MATH_EMULATION */
216     
217     int
218     do_mathemu(struct pt_regs *regs)
219     {
220     	void *op0 = 0, *op1 = 0, *op2 = 0, *op3 = 0;
221     	unsigned long pc = regs->nip;
222     	signed short sdisp;
223     	u32 insn = 0;
224     	int idx = 0;
225     #ifdef CONFIG_MATH_EMULATION
226     	int (*func)(void *, void *, void *, void *);
227     	int type = 0;
228     	int eflag, trap;
229     #endif
230     
231     	if (get_user(insn, (u32 *)pc))
232     		return -EFAULT;
233     
234     #ifndef CONFIG_MATH_EMULATION
235     	switch (insn >> 26) {
236     	case LFD:
237     		idx = (insn >> 16) & 0x1f;
238     		sdisp = (insn & 0xffff);
239     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
240     		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
241     		lfd(op0, op1, op2, op3);
242     		break;
243     	case LFDU:
244     		idx = (insn >> 16) & 0x1f;
245     		sdisp = (insn & 0xffff);
246     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
247     		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
248     		lfd(op0, op1, op2, op3);
249     		regs->gpr[idx] = (unsigned long)op1;
250     		break;
251     	case STFD:
252     		idx = (insn >> 16) & 0x1f;
253     		sdisp = (insn & 0xffff);
254     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
255     		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
256     		stfd(op0, op1, op2, op3);
257     		break;
258     	case STFDU:
259     		idx = (insn >> 16) & 0x1f;
260     		sdisp = (insn & 0xffff);
261     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
262     		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
263     		stfd(op0, op1, op2, op3);
264     		regs->gpr[idx] = (unsigned long)op1;
265     		break;
266     	case OP63:
267     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
268     		op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
269     		fmr(op0, op1, op2, op3);
270     		break;
271     	default:
272     		goto illegal;
273     	}
274     #else /* CONFIG_MATH_EMULATION */
275     	switch (insn >> 26) {
276     	case LFS:	func = lfs;	type = D;	break;
277     	case LFSU:	func = lfs;	type = DU;	break;
278     	case LFD:	func = lfd;	type = D;	break;
279     	case LFDU:	func = lfd;	type = DU;	break;
280     	case STFS:	func = stfs;	type = D;	break;
281     	case STFSU:	func = stfs;	type = DU;	break;
282     	case STFD:	func = stfd;	type = D;	break;
283     	case STFDU:	func = stfd;	type = DU;	break;
284     
285     	case OP31:
286     		switch ((insn >> 1) & 0x3ff) {
287     		case LFSX:	func = lfs;	type = XE;	break;
288     		case LFSUX:	func = lfs;	type = XEU;	break;
289     		case LFDX:	func = lfd;	type = XE;	break;
290     		case LFDUX:	func = lfd;	type = XEU;	break;
291     		case STFSX:	func = stfs;	type = XE;	break;
292     		case STFSUX:	func = stfs;	type = XEU;	break;
293     		case STFDX:	func = stfd;	type = XE;	break;
294     		case STFDUX:	func = stfd;	type = XEU;	break;
295     		case STFIWX:	func = stfiwx;	type = XE;	break;
296     		default:
297     			goto illegal;
298     		}
299     		break;
300     
301     	case OP59:
302     		switch ((insn >> 1) & 0x1f) {
303     		case FDIVS:	func = fdivs;	type = AB;	break;
304     		case FSUBS:	func = fsubs;	type = AB;	break;
305     		case FADDS:	func = fadds;	type = AB;	break;
306     		case FSQRTS:	func = fsqrts;	type = AB;	break;
307     		case FRES:	func = fres;	type = AB;	break;
308     		case FMULS:	func = fmuls;	type = AC;	break;
309     		case FMSUBS:	func = fmsubs;	type = ABC;	break;
310     		case FMADDS:	func = fmadds;	type = ABC;	break;
311     		case FNMSUBS:	func = fnmsubs;	type = ABC;	break;
312     		case FNMADDS:	func = fnmadds;	type = ABC;	break;
313     		default:
314     			goto illegal;
315     		}
316     		break;
317     
318     	case OP63:
319     		if (insn & 0x20) {
320     			switch ((insn >> 1) & 0x1f) {
321     			case FDIV:	func = fdiv;	type = AB;	break;
322     			case FSUB:	func = fsub;	type = AB;	break;
323     			case FADD:	func = fadd;	type = AB;	break;
324     			case FSQRT:	func = fsqrt;	type = AB;	break;
325     			case FSEL:	func = fsel;	type = ABC;	break;
326     			case FMUL:	func = fmul;	type = AC;	break;
327     			case FRSQRTE:	func = frsqrte;	type = AB;	break;
328     			case FMSUB:	func = fmsub;	type = ABC;	break;
329     			case FMADD:	func = fmadd;	type = ABC;	break;
330     			case FNMSUB:	func = fnmsub;	type = ABC;	break;
331     			case FNMADD:	func = fnmadd;	type = ABC;	break;
332     			default:
333     				goto illegal;
334     			}
335     			break;
336     		}
337     
338     		switch ((insn >> 1) & 0x3ff) {
339     		case FCMPU:	func = fcmpu;	type = XCR;	break;
340     		case FRSP:	func = frsp;	type = XB;	break;
341     		case FCTIW:	func = fctiw;	type = XB;	break;
342     		case FCTIWZ:	func = fctiwz;	type = XB;	break;
343     		case FCMPO:	func = fcmpo;	type = XCR;	break;
344     		case MTFSB1:	func = mtfsb1;	type = XCRB;	break;
345     		case FNEG:	func = fneg;	type = XB;	break;
346     		case MCRFS:	func = mcrfs;	type = XCRL;	break;
347     		case MTFSB0:	func = mtfsb0;	type = XCRB;	break;
348     		case FMR:	func = fmr;	type = XB;	break;
349     		case MTFSFI:	func = mtfsfi;	type = XCRI;	break;
350     		case FNABS:	func = fnabs;	type = XB;	break;
351     		case FABS:	func = fabs;	type = XB;	break;
352     		case MFFS:	func = mffs;	type = X;	break;
353     		case MTFSF:	func = mtfsf;	type = XFLB;	break;
354     		default:
355     			goto illegal;
356     		}
357     		break;
358     
359     	default:
360     		goto illegal;
361     	}
362     
363     	switch (type) {
364     	case AB:
365     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
366     		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
367     		op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
368     		break;
369     
370     	case AC:
371     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
372     		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
373     		op2 = (void *)&current->thread.fpr[(insn >>  6) & 0x1f];
374     		break;
375     
376     	case ABC:
377     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
378     		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
379     		op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
380     		op3 = (void *)&current->thread.fpr[(insn >>  6) & 0x1f];
381     		break;
382     
383     	case D:
384     		idx = (insn >> 16) & 0x1f;
385     		sdisp = (insn & 0xffff);
386     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
387     		op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
388     		break;
389     
390     	case DU:
391     		idx = (insn >> 16) & 0x1f;
392     		if (!idx)
393     			goto illegal;
394     
395     		sdisp = (insn & 0xffff);
396     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
397     		op1 = (void *)(regs->gpr[idx] + sdisp);
398     		break;
399     
400     	case X:
401     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
402     		break;
403     
404     	case XA:
405     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
406     		op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
407     		break;
408     
409     	case XB:
410     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
411     		op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
412     		break;
413     
414     	case XE:
415     		idx = (insn >> 16) & 0x1f;
416     		if (!idx)
417     			goto illegal;
418     
419     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
420     		op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]);
421     		break;
422     
423     	case XEU:
424     		idx = (insn >> 16) & 0x1f;
425     		op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
426     		op1 = (void *)((idx ? regs->gpr[idx] : 0)
427     				+ regs->gpr[(insn >> 11) & 0x1f]);
428     		break;
429     
430     	case XCR:
431     		op0 = (void *)&regs->ccr;
432     		op1 = (void *)((insn >> 23) & 0x7);
433     		op2 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
434     		op3 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
435     		break;
436     
437     	case XCRL:
438     		op0 = (void *)&regs->ccr;
439     		op1 = (void *)((insn >> 23) & 0x7);
440     		op2 = (void *)((insn >> 18) & 0x7);
441     		break;
442     
443     	case XCRB:
444     		op0 = (void *)((insn >> 21) & 0x1f);
445     		break;
446     
447     	case XCRI:
448     		op0 = (void *)((insn >> 23) & 0x7);
449     		op1 = (void *)((insn >> 12) & 0xf);
450     		break;
451     
452     	case XFLB:
453     		op0 = (void *)((insn >> 17) & 0xff);
454     		op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
455     		break;
456     
457     	default:
458     		goto illegal;
459     	}
460     
461     	eflag = func(op0, op1, op2, op3);
462     
463     	if (insn & 1) {
464     		regs->ccr &= ~(0x0f000000);
465     		regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000;
466     	}
467     
468     	trap = record_exception(regs, eflag);
469     	if (trap)
470     		return 1;
471     
472     	switch (type) {
473     	case DU:
474     	case XEU:
475     		regs->gpr[idx] = (unsigned long)op1;
476     		break;
477     
478     	default:
479     		break;
480     	}
481     #endif /* CONFIG_MATH_EMULATION */
482     
483     	regs->nip += 4;
484     	return 0;
485     
486     illegal:
487     	return -ENOSYS;
488     }
489