Annotation of sys/arch/sparc64/fpu/fpu.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: fpu.c,v 1.12 2006/06/21 19:24:38 jason Exp $ */
2: /* $NetBSD: fpu.c,v 1.11 2000/12/06 01:47:50 mrg Exp $ */
3:
4: /*
5: * Copyright (c) 2001 Jason L. Wright (jason@thought.net)
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27: * POSSIBILITY OF SUCH DAMAGE.
28: */
29:
30: /*
31: * Copyright (c) 1992, 1993
32: * The Regents of the University of California. All rights reserved.
33: *
34: * This software was developed by the Computer Systems Engineering group
35: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
36: * contributed to Berkeley.
37: *
38: * All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Lawrence Berkeley Laboratory.
42: *
43: * Redistribution and use in source and binary forms, with or without
44: * modification, are permitted provided that the following conditions
45: * are met:
46: * 1. Redistributions of source code must retain the above copyright
47: * notice, this list of conditions and the following disclaimer.
48: * 2. Redistributions in binary form must reproduce the above copyright
49: * notice, this list of conditions and the following disclaimer in the
50: * documentation and/or other materials provided with the distribution.
51: * 3. Neither the name of the University nor the names of its contributors
52: * may be used to endorse or promote products derived from this software
53: * without specific prior written permission.
54: *
55: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65: * SUCH DAMAGE.
66: *
67: * @(#)fpu.c 8.1 (Berkeley) 6/11/93
68: */
69:
70: #include <sys/param.h>
71: #include <sys/proc.h>
72: #include <sys/signal.h>
73: #include <sys/systm.h>
74: #include <sys/syslog.h>
75: #include <sys/signalvar.h>
76:
77: #include <machine/instr.h>
78: #include <machine/reg.h>
79:
80: #include <sparc64/fpu/fpu_emu.h>
81: #include <sparc64/fpu/fpu_extern.h>
82:
83: int fpu_regoffset(int, int);
84: int fpu_insn_fmov(struct fpstate64 *, struct fpemu *, union instr);
85: int fpu_insn_fabs(struct fpstate64 *, struct fpemu *, union instr);
86: int fpu_insn_fneg(struct fpstate64 *, struct fpemu *, union instr);
87: int fpu_insn_itof(struct fpemu *, union instr, int, int *,
88: int *, u_int *);
89: int fpu_insn_ftoi(struct fpemu *, union instr, int *, int, u_int *);
90: int fpu_insn_ftof(struct fpemu *, union instr, int *, int *, u_int *);
91: int fpu_insn_fsqrt(struct fpemu *, union instr, int *, int *, u_int *);
92: int fpu_insn_fcmp(struct fpstate64 *, struct fpemu *, union instr, int);
93: int fpu_insn_fmul(struct fpemu *, union instr, int *, int *, u_int *);
94: int fpu_insn_fmulx(struct fpemu *, union instr, int *, int *, u_int *);
95: int fpu_insn_fdiv(struct fpemu *, union instr, int *, int *, u_int *);
96: int fpu_insn_fadd(struct fpemu *, union instr, int *, int *, u_int *);
97: int fpu_insn_fsub(struct fpemu *, union instr, int *, int *, u_int *);
98: int fpu_insn_fmovcc(struct proc *, struct fpstate64 *, union instr);
99: int fpu_insn_fmovr(struct proc *, struct fpstate64 *, union instr);
100: void fpu_fcopy(u_int *, u_int *, int);
101:
102: #ifdef DEBUG
103: int fpe_debug = 0;
104:
105: /*
106: * Dump a `fpn' structure.
107: */
108: void
109: fpu_dumpfpn(struct fpn *fp)
110: {
111: static char *class[] = { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
112:
113: printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2],
114: fp->fp_sign ? '-' : ' ', fp->fp_mant[0], fp->fp_mant[1],
115: fp->fp_mant[2], fp->fp_mant[3], fp->fp_exp);
116: }
117: void
118: fpu_dumpstate(struct fpstate64 *fs)
119: {
120: int i;
121:
122: for (i = 0; i < 64; i++)
123: printf("%%f%02d: %08x%s",
124: i, fs->fs_regs[i], ((i & 3) == 3) ? "\n" : " ");
125: }
126: #endif
127:
128: /*
129: * fpu_execute returns the following error numbers (0 = no error):
130: */
131: #define FPE 1 /* take a floating point exception */
132: #define NOTFPU 2 /* not an FPU instruction */
133:
134: /*
135: * Translate current exceptions into `first' exception. The
136: * bits go the wrong way for ffs() (0x10 is most important, etc).
137: * There are only 5, so do it the obvious way.
138: */
139: #define X1(x) x
140: #define X2(x) x,x
141: #define X4(x) x,x,x,x
142: #define X8(x) X4(x),X4(x)
143: #define X16(x) X8(x),X8(x)
144:
145: static char cx_to_trapx[] = {
146: X1(FSR_NX),
147: X2(FSR_DZ),
148: X4(FSR_UF),
149: X8(FSR_OF),
150: X16(FSR_NV)
151: };
152: static u_char fpu_codes[] = {
153: X1(FPE_FLTINEX_TRAP),
154: X2(FPE_FLTDIV_TRAP),
155: X4(FPE_FLTUND_TRAP),
156: X8(FPE_FLTOVF_TRAP),
157: X16(FPE_FLTOPERR_TRAP)
158: };
159:
160: static int fpu_types[] = {
161: X1(FPE_FLTRES),
162: X2(FPE_FLTDIV),
163: X4(FPE_FLTUND),
164: X8(FPE_FLTOVF),
165: X16(FPE_FLTINV)
166: };
167:
168: void
169: fpu_fcopy(src, dst, type)
170: u_int *src, *dst;
171: int type;
172: {
173: *dst++ = *src++;
174: if (type == FTYPE_SNG || type == FTYPE_INT)
175: return;
176: *dst++ = *src++;
177: if (type != FTYPE_EXT)
178: return;
179: *dst++ = *src++;
180: *dst = *src;
181: }
182:
183: /*
184: * The FPU gave us an exception. Clean up the mess. Note that the
185: * fp queue can only have FPops in it, never load/store FP registers
186: * nor FBfcc instructions. Experiments with `crashme' prove that
187: * unknown FPops do enter the queue, however.
188: */
189: void
190: fpu_cleanup(p, fs)
191: register struct proc *p;
192: register struct fpstate64 *fs;
193: {
194: register int i, fsr = fs->fs_fsr, error;
195: union instr instr;
196: union sigval sv;
197: struct fpemu fe;
198:
199: sv.sival_int = p->p_md.md_tf->tf_pc; /* XXX only approximate */
200:
201: switch ((fsr >> FSR_FTT_SHIFT) & FSR_FTT_MASK) {
202:
203: case FSR_TT_NONE:
204: #if 0
205: /* XXX I'm not sure how we get here, but ignoring the trap */
206: /* XXX seems to work in my limited tests */
207: /* XXX More research to be done =) */
208: panic("fpu_cleanup 1"); /* ??? */
209: #else
210: printf("fpu_cleanup 1\n");
211: #endif
212: break;
213:
214: case FSR_TT_IEEE:
215: if ((i = fsr & FSR_CX) == 0)
216: panic("fpu ieee trap, but no exception");
217: trapsignal(p, SIGFPE, fpu_codes[i - 1], fpu_types[i - 1], sv);
218: break; /* XXX should return, but queue remains */
219:
220: case FSR_TT_UNFIN:
221: if (fs->fs_qsize == 0) {
222: printf("fpu_cleanup: unfinished fpop");
223: /* The book says reexecute or emulate. */
224: return;
225: }
226: break;
227: case FSR_TT_UNIMP:
228: if (fs->fs_qsize == 0)
229: panic("fpu_cleanup: unimplemented fpop");
230: break;
231:
232: case FSR_TT_SEQ:
233: panic("fpu sequence error");
234: /* NOTREACHED */
235:
236: case FSR_TT_HWERR:
237: log(LOG_ERR, "fpu hardware error (%s[%d])\n",
238: p->p_comm, p->p_pid);
239: uprintf("%s[%d]: fpu hardware error\n", p->p_comm, p->p_pid);
240: trapsignal(p, SIGFPE, -1, FPE_FLTINV, sv); /* ??? */
241: goto out;
242:
243: default:
244: printf("fsr=0x%x\n", fsr);
245: panic("fpu error");
246: }
247:
248: /* emulate the instructions left in the queue */
249: fe.fe_fpstate = fs;
250: for (i = 0; i < fs->fs_qsize; i++) {
251: instr.i_int = fs->fs_queue[i].fq_instr;
252: if (instr.i_any.i_op != IOP_reg ||
253: (instr.i_op3.i_op3 != IOP3_FPop1 &&
254: instr.i_op3.i_op3 != IOP3_FPop2))
255: panic("bogus fpu queue");
256: error = fpu_execute(p, &fe, instr);
257: switch (error) {
258:
259: case 0:
260: continue;
261:
262: case FPE:
263: trapsignal(p, SIGFPE,
264: fpu_codes[(fs->fs_fsr & FSR_CX) - 1],
265: fpu_types[(fs->fs_fsr & FSR_CX) - 1], sv);
266: break;
267:
268: case NOTFPU:
269: trapsignal(p, SIGILL, 0, ILL_COPROC, sv);
270: break;
271:
272: default:
273: panic("fpu_cleanup 3");
274: /* NOTREACHED */
275: }
276: /* XXX should stop here, but queue remains */
277: }
278: out:
279: fs->fs_qsize = 0;
280: }
281:
282: /*
283: * Compute offset given a register and type. For 32 bit sparc, bits 1 and 0
284: * must be zero for ext types, and bit 0 must be 0 for double and long types.
285: * For 64bit sparc, bit 1 must be zero for quad types, and bit 0 becomes bit
286: * 5 in the register offset for long, double, and quad types.
287: */
288: int
289: fpu_regoffset(rx, type)
290: int rx, type;
291: {
292: if (type == FTYPE_LNG || type == FTYPE_DBL || type == FTYPE_EXT) {
293: rx |= (rx & 1) << 5;
294: rx &= 0x3e;
295: if ((type == FTYPE_EXT) && (rx & 2))
296: return (-1);
297: }
298: return (rx);
299: }
300:
301: /*
302: * Execute an FPU instruction (one that runs entirely in the FPU; not
303: * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be
304: * modified to reflect the setting the hardware would have left.
305: */
306: int
307: fpu_execute(fpproc, fe, instr)
308: struct proc *fpproc;
309: struct fpemu *fe;
310: union instr instr;
311: {
312: struct fpstate *fs;
313: int opf, rdtype, rd, err, mask, cx, fsr;
314: u_int space[4];
315:
316: DPRINTF(FPE_INSN, ("op3: %x, opf %x\n", instr.i_opf.i_op3,
317: instr.i_opf.i_opf));
318: DPRINTF(FPE_STATE, ("BEFORE:\n"));
319: DUMPSTATE(FPE_STATE, fe->fe_fpstate);
320: opf = instr.i_opf.i_opf;
321: fs = fe->fe_fpstate;
322: fe->fe_fsr = fs->fs_fsr & ~FSR_CX;
323: fe->fe_cx = 0;
324:
325: if ((instr.i_int & 0xc0000000) != 0x80000000)
326: return (NOTFPU);
327:
328: if (instr.i_opf.i_op3 == IOP3_FPop2) {
329: switch (opf) {
330: case FCMPS: case FCMPD: case FCMPQ:
331: return (fpu_insn_fcmp(fs, fe, instr, 0));
332:
333: case FCMPES: case FCMPED: case FCMPEQ:
334: return (fpu_insn_fcmp(fs, fe, instr, 1));
335:
336: case FMVFC0S: case FMVFC0D: case FMVFC0Q:
337: case FMVFC1S: case FMVFC1D: case FMVFC1Q:
338: case FMVFC2S: case FMVFC2D: case FMVFC2Q:
339: case FMVFC3S: case FMVFC3D: case FMVFC3Q:
340: case FMVICS: case FMVICD: case FMVICQ:
341: case FMVXCS: case FMVXCD: case FMVXCQ:
342: return (fpu_insn_fmovcc(fpproc, fs, instr));
343:
344: case FMOVZS: case FMOVZD: case FMOVZQ:
345: case FMOVLEZS: case FMOVLEZD: case FMOVLEZQ:
346: case FMOVLZS: case FMOVLZD: case FMOVLZQ:
347: case FMOVNZS: case FMOVNZD: case FMOVNZQ:
348: case FMOVGZS: case FMOVGZD: case FMOVGZQ:
349: case FMOVGEZS: case FMOVGEZD: case FMOVGEZQ:
350: return (fpu_insn_fmovr(fpproc, fs, instr));
351: }
352: return (NOTFPU);
353: }
354:
355: if (instr.i_opf.i_op3 != IOP3_FPop1)
356: return (NOTFPU);
357:
358: switch (instr.i_opf.i_opf) {
359: case FSTOX: case FDTOX: case FQTOX:
360: rdtype = FTYPE_LNG;
361: if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0)
362: return (err);
363: break;
364:
365: case FSTOI: case FDTOI: case FQTOI:
366: rdtype = FTYPE_INT;
367: if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0)
368: return (err);
369: break;
370:
371: case FITOS: case FITOD: case FITOQ:
372: if ((err = fpu_insn_itof(fe, instr, FTYPE_INT, &rd,
373: &rdtype, space)) != 0)
374: return (err);
375: break;
376:
377: case FXTOS: case FXTOD: case FXTOQ:
378: if ((err = fpu_insn_itof(fe, instr, FTYPE_LNG, &rd,
379: &rdtype, space)) != 0)
380: return (err);
381: break;
382:
383: case FSTOD: case FSTOQ:
384: case FDTOS: case FDTOQ:
385: case FQTOS: case FQTOD:
386: if ((err = fpu_insn_ftof(fe, instr, &rd, &rdtype, space)) != 0)
387: return (err);
388: break;
389:
390: case FMOVS: case FMOVD: case FMOVQ:
391: return (fpu_insn_fmov(fs, fe, instr));
392:
393: case FNEGS: case FNEGD: case FNEGQ:
394: return (fpu_insn_fneg(fs, fe, instr));
395:
396: case FABSS: case FABSD: case FABSQ:
397: return (fpu_insn_fabs(fs, fe, instr));
398:
399: case FSQRTS: case FSQRTD: case FSQRTQ:
400: if ((err = fpu_insn_fsqrt(fe, instr, &rd, &rdtype, space)) != 0)
401: return (err);
402: break;
403:
404: case FMULS: case FMULD: case FMULQ:
405: if ((err = fpu_insn_fmul(fe, instr, &rd, &rdtype, space)) != 0)
406: return (err);
407: break;
408:
409: case FDIVS: case FDIVD: case FDIVQ:
410: if ((err = fpu_insn_fdiv(fe, instr, &rd, &rdtype, space)) != 0)
411: return (err);
412: break;
413:
414: case FSMULD: case FDMULQ:
415: if ((err = fpu_insn_fmulx(fe, instr, &rd, &rdtype, space)) != 0)
416: return (err);
417: break;
418:
419: case FADDS: case FADDD: case FADDQ:
420: if ((err = fpu_insn_fadd(fe, instr, &rd, &rdtype, space)) != 0)
421: return (err);
422: break;
423:
424: case FSUBS: case FSUBD: case FSUBQ:
425: if ((err = fpu_insn_fsub(fe, instr, &rd, &rdtype, space)) != 0)
426: return (err);
427: break;
428: default:
429: return (NOTFPU);
430: }
431:
432: cx = fe->fe_cx;
433: fsr = fe->fe_fsr;
434: if (cx != 0) {
435: mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK;
436: if (cx & mask) {
437: /* not accrued??? */
438: fs->fs_fsr = (fsr & ~FSR_FTT) |
439: (FSR_TT_IEEE << FSR_FTT_SHIFT) |
440: (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT);
441: return (FPE);
442: }
443: fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT);
444: }
445: fs->fs_fsr = fsr;
446: fpu_fcopy(space, fs->fs_regs + rd, rdtype);
447: DPRINTF(FPE_STATE, ("AFTER:\n"));
448: DUMPSTATE(FPE_STATE, fs);
449: return (0);
450: }
451:
452: /*
453: * Handler for FMOV[SDQ] emulation.
454: */
455: int
456: fpu_insn_fmov(fs, fe, instr)
457: struct fpstate64 *fs;
458: struct fpemu *fe;
459: union instr instr;
460: {
461: int opf = instr.i_opf.i_opf, rs, rd, rtype;
462:
463: rtype = opf & 3;
464: if (rtype == 0)
465: return (NOTFPU);
466: if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
467: return (NOTFPU);
468: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
469: return (NOTFPU);
470: fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
471: fs->fs_fsr = fe->fe_fsr;
472: return (0);
473: }
474:
475: /*
476: * Handler for FABS[SDQ] emulation.
477: */
478: int
479: fpu_insn_fabs(fs, fe, instr)
480: struct fpstate64 *fs;
481: struct fpemu *fe;
482: union instr instr;
483: {
484: int opf = instr.i_opf.i_opf, rs, rd, rtype;
485:
486: rtype = opf & 3;
487: if (rtype == 0)
488: return (NOTFPU);
489: if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
490: return (NOTFPU);
491: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
492: return (NOTFPU);
493: fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
494: fs->fs_regs[rd] = fs->fs_regs[rd] & ~(1 << 31);
495: fs->fs_fsr = fe->fe_fsr;
496: return (0);
497: }
498:
499: /*
500: * Handler for FNEG[SDQ] emulation.
501: */
502: int
503: fpu_insn_fneg(fs, fe, instr)
504: struct fpstate64 *fs;
505: struct fpemu *fe;
506: union instr instr;
507: {
508: int opf = instr.i_opf.i_opf, rs, rd, rtype;
509:
510: rtype = opf & 3;
511: if (rtype == 0)
512: return (NOTFPU);
513: if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
514: return (NOTFPU);
515: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
516: return (NOTFPU);
517: fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
518: fs->fs_regs[rd] = fs->fs_regs[rd] ^ (1 << 31);
519: fs->fs_fsr = fe->fe_fsr;
520: return (0);
521: }
522:
523: /*
524: * Handler for F[XI]TO[SDQ] emulation.
525: */
526: int
527: fpu_insn_itof(fe, instr, rstype, rdp, rdtypep, space)
528: struct fpemu *fe;
529: union instr instr;
530: u_int *space;
531: int rstype, *rdp, *rdtypep;
532: {
533: int opf = instr.i_opf.i_opf, rs, rd, rdtype;
534:
535: if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
536: return (NOTFPU);
537:
538: rdtype = (opf >> 2) & 3;
539: if (rdtype == 0)
540: return (NOTFPU);
541: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
542: return (NOTFPU);
543:
544: DPRINTF(FPE_INSN, ("itof %%f%d(%d, %d) -> %%f%d(%d, %d)\n",
545: rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd));
546: fpu_explode(fe, &fe->fe_f1, rstype, rs);
547: fpu_implode(fe, &fe->fe_f1, rdtype, space);
548: *rdp = rd;
549: *rdtypep = rdtype;
550: return (0);
551: }
552:
553: /*
554: * Handler for F[SDQ]TO[XI] emulation.
555: */
556: int
557: fpu_insn_ftoi(fe, instr, rdp, rdtype, space)
558: struct fpemu *fe;
559: union instr instr;
560: u_int *space;
561: int *rdp, rdtype;
562: {
563: int opf = instr.i_opf.i_opf, rd, rstype, rs;
564:
565: rstype = opf & 3;
566: if (rstype == 0)
567: return (NOTFPU);
568: if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
569: return (NOTFPU);
570: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
571: return (NOTFPU);
572:
573: fpu_explode(fe, &fe->fe_f1, rstype, rs);
574: fpu_implode(fe, &fe->fe_f1, rdtype, space);
575: *rdp = rd;
576: return (0);
577: }
578:
579: /*
580: * Handler for F[SDQ]TO[SDQ] emulation.
581: */
582: int
583: fpu_insn_ftof(fe, instr, rdp, rdtypep, space)
584: struct fpemu *fe;
585: union instr instr;
586: u_int *space;
587: int *rdp, *rdtypep;
588: {
589: int opf = instr.i_opf.i_opf, rd, rs, rdtype, rstype;
590:
591: rstype = opf & 3;
592: rdtype = (opf >> 2) & 3;
593:
594: if ((rstype == rdtype) || (rstype == 0) || (rdtype == 0))
595: return (NOTFPU);
596:
597: if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
598: return (NOTFPU);
599: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
600: return (NOTFPU);
601:
602: DPRINTF(FPE_INSN, ("ftof %%f%d(%d, %d) -> %%f%d(%d, %d)\n",
603: rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd));
604:
605: fpu_explode(fe, &fe->fe_f1, rstype, rs);
606: fpu_implode(fe, &fe->fe_f1, rdtype, space);
607: *rdp = rd;
608: *rdtypep = rdtype;
609: return (0);
610: }
611:
612: /*
613: * Handler for FQSRT[SDQ] emulation.
614: */
615: int
616: fpu_insn_fsqrt(fe, instr, rdp, rdtypep, space)
617: struct fpemu *fe;
618: union instr instr;
619: u_int *space;
620: int *rdp, *rdtypep;
621: {
622: int opf = instr.i_opf.i_opf, rd, rs, rtype;
623: struct fpn *fp;
624:
625: rtype = opf & 3;
626: if (rtype == 0)
627: return (NOTFPU);
628: if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
629: return (NOTFPU);
630: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
631: return (NOTFPU);
632:
633: fpu_explode(fe, &fe->fe_f1, rtype, rs);
634: fp = fpu_sqrt(fe);
635: fpu_implode(fe, fp, rtype, space);
636: *rdp = rd;
637: *rdtypep = rtype;
638: return (0);
639: }
640:
641: /*
642: * Handler for FCMP{E}[SDQ] emulation.
643: */
644: int
645: fpu_insn_fcmp(fs, fe, instr, cmpe)
646: struct fpstate64 *fs;
647: struct fpemu *fe;
648: union instr instr;
649: int cmpe;
650: {
651: int opf = instr.i_opf.i_opf, rs1, rs2, rtype, cx, fsr;
652:
653: rtype = opf & 3;
654: if (rtype == 0)
655: return (NOTFPU);
656: if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
657: return (NOTFPU);
658: if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
659: return (NOTFPU);
660:
661: fpu_explode(fe, &fe->fe_f1, rtype, rs1);
662: fpu_explode(fe, &fe->fe_f2, rtype, rs2);
663: fpu_compare(fe, cmpe);
664:
665: /*
666: * The only possible exception here is NV; catch it early
667: * and get out, as there is no result register.
668: */
669: cx = fe->fe_cx;
670: fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT);
671: if (cx != 0) {
672: if (fsr & (FSR_NV << FSR_TEM_SHIFT)) {
673: fs->fs_fsr = (fsr & ~FSR_FTT) |
674: (FSR_TT_IEEE << FSR_FTT_SHIFT);
675: return (FPE);
676: }
677: fsr |= FSR_NV << FSR_AX_SHIFT;
678: }
679: fs->fs_fsr = fsr;
680: return (0);
681: }
682:
683: /*
684: * Handler for FMUL[SDQ] emulation.
685: */
686: int
687: fpu_insn_fmul(fe, instr, rdp, rdtypep, space)
688: struct fpemu *fe;
689: union instr instr;
690: int *rdp, *rdtypep;
691: u_int *space;
692: {
693: struct fpn *fp;
694: int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
695:
696: rtype = opf & 3;
697: if (rtype == 0)
698: return (NOTFPU);
699: if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
700: return (NOTFPU);
701: if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
702: return (NOTFPU);
703: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
704: return (NOTFPU);
705:
706: fpu_explode(fe, &fe->fe_f1, rtype, rs1);
707: fpu_explode(fe, &fe->fe_f2, rtype, rs2);
708: fp = fpu_mul(fe);
709: fpu_implode(fe, fp, rtype, space);
710: *rdp = rd;
711: *rdtypep = rtype;
712: return (0);
713: }
714:
715: /*
716: * Handler for FSMULD, FDMULQ emulation.
717: */
718: int
719: fpu_insn_fmulx(fe, instr, rdp, rdtypep, space)
720: struct fpemu *fe;
721: union instr instr;
722: int *rdp, *rdtypep;
723: u_int *space;
724: {
725: struct fpn *fp;
726: int opf = instr.i_opf.i_opf, rd, rdtype, rstype, rs1, rs2;
727:
728: rstype = opf & 3;
729: rdtype = (opf >> 2) & 3;
730: if ((rstype != rdtype + 1) || (rstype == 0) || (rdtype == 0))
731: return (NOTFPU);
732: if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rstype)) < 0)
733: return (NOTFPU);
734: if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
735: return (NOTFPU);
736: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
737: return (NOTFPU);
738:
739: fpu_explode(fe, &fe->fe_f1, rstype, rs1);
740: fpu_explode(fe, &fe->fe_f2, rstype, rs2);
741: fp = fpu_mul(fe);
742: fpu_implode(fe, fp, rdtype, space);
743: *rdp = rd;
744: *rdtypep = rdtype;
745: return (0);
746: }
747:
748: /*
749: * Handler for FDIV[SDQ] emulation.
750: */
751: int
752: fpu_insn_fdiv(fe, instr, rdp, rdtypep, space)
753: struct fpemu *fe;
754: union instr instr;
755: int *rdp, *rdtypep;
756: u_int *space;
757: {
758: struct fpn *fp;
759: int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
760:
761: rtype = opf & 3;
762: if (rtype == 0)
763: return (NOTFPU);
764: if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
765: return (NOTFPU);
766: if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
767: return (NOTFPU);
768: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
769: return (NOTFPU);
770:
771: fpu_explode(fe, &fe->fe_f1, rtype, rs1);
772: fpu_explode(fe, &fe->fe_f2, rtype, rs2);
773: fp = fpu_div(fe);
774: fpu_implode(fe, fp, rtype, space);
775: *rdp = rd;
776: *rdtypep = rtype;
777: return (0);
778: }
779:
780: /*
781: * Handler for FADD[SDQ] emulation.
782: */
783: int
784: fpu_insn_fadd(fe, instr, rdp, rdtypep, space)
785: struct fpemu *fe;
786: union instr instr;
787: int *rdp, *rdtypep;
788: u_int *space;
789: {
790: struct fpn *fp;
791: int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
792:
793: rtype = opf & 3;
794: if (rtype == 0)
795: return (NOTFPU);
796: if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
797: return (NOTFPU);
798: if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
799: return (NOTFPU);
800: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
801: return (NOTFPU);
802:
803: fpu_explode(fe, &fe->fe_f1, rtype, rs1);
804: fpu_explode(fe, &fe->fe_f2, rtype, rs2);
805: fp = fpu_add(fe);
806: fpu_implode(fe, fp, rtype, space);
807: *rdp = rd;
808: *rdtypep = rtype;
809: return (0);
810: }
811:
812: /*
813: * Handler for FSUB[SDQ] emulation.
814: */
815: int
816: fpu_insn_fsub(fe, instr, rdp, rdtypep, space)
817: struct fpemu *fe;
818: union instr instr;
819: int *rdp, *rdtypep;
820: u_int *space;
821: {
822: struct fpn *fp;
823: int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
824:
825: rtype = opf & 3;
826: if (rtype == 0)
827: return (NOTFPU);
828: if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
829: return (NOTFPU);
830: if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
831: return (NOTFPU);
832: if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
833: return (NOTFPU);
834:
835: fpu_explode(fe, &fe->fe_f1, rtype, rs1);
836: fpu_explode(fe, &fe->fe_f2, rtype, rs2);
837: fp = fpu_sub(fe);
838: fpu_implode(fe, fp, rtype, space);
839: *rdp = rd;
840: *rdtypep = rtype;
841: return (0);
842: }
843:
844: /*
845: * Handler for FMOV[SDQ][cond] emulation.
846: */
847: int
848: fpu_insn_fmovcc(fpproc, fs, instr)
849: struct proc *fpproc;
850: struct fpstate64 *fs;
851: union instr instr;
852: {
853: int rtype, rd, rs, cond;
854:
855: rtype = instr.i_fmovcc.i_opf_low & 3;
856: if ((rtype == 0) || (instr.i_int & 0x00040000))
857: return (NOTFPU);
858:
859: if ((rd = fpu_regoffset(instr.i_fmovcc.i_rd, rtype)) < 0)
860: return (NOTFPU);
861: if ((rs = fpu_regoffset(instr.i_fmovcc.i_rs2, rtype)) < 0)
862: return (NOTFPU);
863:
864: switch (instr.i_fmovcc.i_opf_cc) {
865: case 0:
866: cond = (fs->fs_fsr >> FSR_FCC_SHIFT) & FSR_FCC_MASK;
867: break;
868: case 1:
869: cond = (fs->fs_fsr >> FSR_FCC1_SHIFT) & FSR_FCC_MASK;
870: break;
871: case 2:
872: cond = (fs->fs_fsr >> FSR_FCC2_SHIFT) & FSR_FCC_MASK;
873: break;
874: case 3:
875: cond = (fs->fs_fsr >> FSR_FCC3_SHIFT) & FSR_FCC_MASK;
876: break;
877: case 4:
878: cond = (fpproc->p_md.md_tf->tf_tstate >> TSTATE_CCR_SHIFT) &
879: PSR_ICC;
880: break;
881: case 6:
882: cond = (fpproc->p_md.md_tf->tf_tstate >>
883: (TSTATE_CCR_SHIFT + XCC_SHIFT)) & PSR_ICC;
884: break;
885: default:
886: return (NOTFPU);
887: }
888:
889: if (instr.i_fmovcc.i_cond != cond)
890: return (0);
891:
892: fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
893: return (0);
894: }
895:
896: /*
897: * Handler for FMOVR[icond][SDQ] emulation.
898: */
899: int
900: fpu_insn_fmovr(fpproc, fs, instr)
901: struct proc *fpproc;
902: struct fpstate64 *fs;
903: union instr instr;
904: {
905: int rtype, rd, rs2, rs1;
906:
907: rtype = instr.i_fmovcc.i_opf_low & 3;
908: if ((rtype == 0) || (instr.i_int & 0x00002000))
909: return (NOTFPU);
910:
911: if ((rd = fpu_regoffset(instr.i_fmovr.i_rd, rtype)) < 0)
912: return (NOTFPU);
913: if ((rs2 = fpu_regoffset(instr.i_fmovr.i_rs2, rtype)) < 0)
914: return (NOTFPU);
915: rs1 = instr.i_fmovr.i_rs1;
916:
917: switch (instr.i_fmovr.i_rcond) {
918: case 1: /* Z */
919: if (rs1 != 0 &&
920: (int64_t)fpproc->p_md.md_tf->tf_global[rs1] != 0)
921: return (0);
922: break;
923: case 2: /* LEZ */
924: if (rs1 != 0 &&
925: (int64_t)fpproc->p_md.md_tf->tf_global[rs1] > 0)
926: return (0);
927: break;
928: case 3: /* LZ */
929: if (rs1 == 0 ||
930: (int64_t)fpproc->p_md.md_tf->tf_global[rs1] >= 0)
931: return (0);
932: break;
933: case 5: /* NZ */
934: if (rs1 == 0 ||
935: (int64_t)fpproc->p_md.md_tf->tf_global[rs1] == 0)
936: return (0);
937: break;
938: case 6: /* NGZ */
939: if (rs1 == 0 ||
940: (int64_t)fpproc->p_md.md_tf->tf_global[rs1] <= 0)
941: return (0);
942: break;
943: case 7: /* NGEZ */
944: if (rs1 != 0 &&
945: (int64_t)fpproc->p_md.md_tf->tf_global[rs1] < 0)
946: return (0);
947: break;
948: default:
949: return (NOTFPU);
950: }
951:
952: fpu_fcopy(fs->fs_regs + rs2, fs->fs_regs + rd, rtype);
953: return (0);
954: }
CVSweb