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