xref: /openbsd/sys/arch/sparc64/fpu/fpu.c (revision 17df1aa7)
1 /*	$OpenBSD: fpu.c,v 1.14 2010/01/01 13:13:07 miod 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 		KERNEL_PROC_LOCK(p);
218 		trapsignal(p, SIGFPE, fpu_codes[i - 1], fpu_types[i - 1], sv);
219 		KERNEL_PROC_UNLOCK(p);
220 		break;		/* XXX should return, but queue remains */
221 
222 	case FSR_TT_UNFIN:
223 		if (fs->fs_qsize == 0) {
224 			printf("fpu_cleanup: unfinished fpop");
225 			/* The book says reexecute or emulate. */
226 			return;
227 		}
228 		break;
229 	case FSR_TT_UNIMP:
230 		if (fs->fs_qsize == 0)
231 			panic("fpu_cleanup: unimplemented fpop");
232 		break;
233 
234 	case FSR_TT_SEQ:
235 		panic("fpu sequence error");
236 		/* NOTREACHED */
237 
238 	case FSR_TT_HWERR:
239 		log(LOG_ERR, "fpu hardware error (%s[%d])\n",
240 		    p->p_comm, p->p_pid);
241 		uprintf("%s[%d]: fpu hardware error\n", p->p_comm, p->p_pid);
242 		KERNEL_PROC_LOCK(p);
243 		trapsignal(p, SIGFPE, -1, FPE_FLTINV, sv);	/* ??? */
244 		KERNEL_PROC_UNLOCK(p);
245 		goto out;
246 
247 	default:
248 		printf("fsr=0x%x\n", fsr);
249 		panic("fpu error");
250 	}
251 
252 	/* emulate the instructions left in the queue */
253 	fe.fe_fpstate = fs;
254 	for (i = 0; i < fs->fs_qsize; i++) {
255 		instr.i_int = fs->fs_queue[i].fq_instr;
256 		if (instr.i_any.i_op != IOP_reg ||
257 		    (instr.i_op3.i_op3 != IOP3_FPop1 &&
258 		     instr.i_op3.i_op3 != IOP3_FPop2))
259 			panic("bogus fpu queue");
260 		error = fpu_execute(p, &fe, instr);
261 		switch (error) {
262 
263 		case 0:
264 			continue;
265 
266 		case FPE:
267 			KERNEL_PROC_LOCK(p);
268 			trapsignal(p, SIGFPE,
269 			    fpu_codes[(fs->fs_fsr & FSR_CX) - 1],
270 			    fpu_types[(fs->fs_fsr & FSR_CX) - 1], sv);
271 			KERNEL_PROC_UNLOCK(p);
272 			break;
273 
274 		case NOTFPU:
275 			KERNEL_PROC_LOCK(p);
276 			trapsignal(p, SIGILL, 0, ILL_COPROC, sv);
277 			KERNEL_PROC_UNLOCK(p);
278 			break;
279 
280 		default:
281 			panic("fpu_cleanup 3");
282 			/* NOTREACHED */
283 		}
284 		/* XXX should stop here, but queue remains */
285 	}
286 out:
287 	fs->fs_qsize = 0;
288 }
289 
290 /*
291  * Compute offset given a register and type.  For 32 bit sparc, bits 1 and 0
292  * must be zero for ext types, and bit 0 must be 0 for double and long types.
293  * For 64bit sparc, bit 1 must be zero for quad types, and bit 0 becomes bit
294  * 5 in the register offset for long, double, and quad types.
295  */
296 int
297 fpu_regoffset(rx, type)
298 	int rx, type;
299 {
300 	if (type == FTYPE_LNG || type == FTYPE_DBL || type == FTYPE_EXT) {
301 		rx |= (rx & 1) << 5;
302 		rx &= 0x3e;
303 		if ((type == FTYPE_EXT) && (rx & 2))
304 			return (-1);
305 	}
306 	return (rx);
307 }
308 
309 /*
310  * Execute an FPU instruction (one that runs entirely in the FPU; not
311  * FBfcc or STF, for instance).  On return, fe->fe_fs->fs_fsr will be
312  * modified to reflect the setting the hardware would have left.
313  */
314 int
315 fpu_execute(p, fe, instr)
316 	struct proc *p;
317 	struct fpemu *fe;
318 	union instr instr;
319 {
320 	struct fpstate *fs;
321 	int opf, rdtype, rd, err, mask, cx, fsr;
322 	u_int space[4];
323 
324 	DPRINTF(FPE_INSN, ("op3: %x, opf %x\n", instr.i_opf.i_op3,
325 	    instr.i_opf.i_opf));
326 	DPRINTF(FPE_STATE, ("BEFORE:\n"));
327 	DUMPSTATE(FPE_STATE, fe->fe_fpstate);
328 	opf = instr.i_opf.i_opf;
329 	fs = fe->fe_fpstate;
330 	fe->fe_fsr = fs->fs_fsr & ~FSR_CX;
331 	fe->fe_cx = 0;
332 
333 	if ((instr.i_int & 0xc0000000) != 0x80000000)
334 		return (NOTFPU);
335 
336 	if (instr.i_opf.i_op3 == IOP3_FPop2) {
337 		switch (opf) {
338 		case FCMPS: case FCMPD: case FCMPQ:
339 			return (fpu_insn_fcmp(fs, fe, instr, 0));
340 
341 		case FCMPES: case FCMPED: case FCMPEQ:
342 			return (fpu_insn_fcmp(fs, fe, instr, 1));
343 
344 		case FMVFC0S: case FMVFC0D: case FMVFC0Q:
345 		case FMVFC1S: case FMVFC1D: case FMVFC1Q:
346 		case FMVFC2S: case FMVFC2D: case FMVFC2Q:
347 		case FMVFC3S: case FMVFC3D: case FMVFC3Q:
348 		case FMVICS: case FMVICD: case FMVICQ:
349 		case FMVXCS: case FMVXCD: case FMVXCQ:
350 			return (fpu_insn_fmovcc(p, fs, instr));
351 
352 		case FMOVZS: case FMOVZD: case FMOVZQ:
353 		case FMOVLEZS: case FMOVLEZD: case FMOVLEZQ:
354 		case FMOVLZS: case FMOVLZD: case FMOVLZQ:
355 		case FMOVNZS: case FMOVNZD: case FMOVNZQ:
356 		case FMOVGZS: case FMOVGZD: case FMOVGZQ:
357 		case FMOVGEZS: case FMOVGEZD: case FMOVGEZQ:
358 			return (fpu_insn_fmovr(p, fs, instr));
359 		}
360 		return (NOTFPU);
361 	}
362 
363 	if (instr.i_opf.i_op3 != IOP3_FPop1)
364 		return (NOTFPU);
365 
366 	switch (instr.i_opf.i_opf) {
367 	case FSTOX: case FDTOX: case FQTOX:
368 		rdtype = FTYPE_LNG;
369 		if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0)
370 			return (err);
371 		break;
372 
373 	case FSTOI: case FDTOI: case FQTOI:
374 		rdtype = FTYPE_INT;
375 		if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0)
376 			return (err);
377 		break;
378 
379 	case FITOS: case FITOD: case FITOQ:
380 		if ((err = fpu_insn_itof(fe, instr, FTYPE_INT, &rd,
381 		    &rdtype, space)) != 0)
382 			return (err);
383 		break;
384 
385 	case FXTOS: case FXTOD: case FXTOQ:
386 		if ((err = fpu_insn_itof(fe, instr, FTYPE_LNG, &rd,
387 		    &rdtype, space)) != 0)
388 			return (err);
389 		break;
390 
391 	case FSTOD: case FSTOQ:
392 	case FDTOS: case FDTOQ:
393 	case FQTOS: case FQTOD:
394 		if ((err = fpu_insn_ftof(fe, instr, &rd, &rdtype, space)) != 0)
395 			return (err);
396 		break;
397 
398 	case FMOVS: case FMOVD: case FMOVQ:
399 		return (fpu_insn_fmov(fs, fe, instr));
400 
401 	case FNEGS: case FNEGD: case FNEGQ:
402 		return (fpu_insn_fneg(fs, fe, instr));
403 
404 	case FABSS: case FABSD: case FABSQ:
405 		return (fpu_insn_fabs(fs, fe, instr));
406 
407 	case FSQRTS: case FSQRTD: case FSQRTQ:
408 		if ((err = fpu_insn_fsqrt(fe, instr, &rd, &rdtype, space)) != 0)
409 			return (err);
410 		break;
411 
412 	case FMULS: case FMULD: case FMULQ:
413 		if ((err = fpu_insn_fmul(fe, instr, &rd, &rdtype, space)) != 0)
414 			return (err);
415 		break;
416 
417 	case FDIVS: case FDIVD: case FDIVQ:
418 		if ((err = fpu_insn_fdiv(fe, instr, &rd, &rdtype, space)) != 0)
419 			return (err);
420 		break;
421 
422 	case FSMULD: case FDMULQ:
423 		if ((err = fpu_insn_fmulx(fe, instr, &rd, &rdtype, space)) != 0)
424 			return (err);
425 		break;
426 
427 	case FADDS: case FADDD: case FADDQ:
428 		if ((err = fpu_insn_fadd(fe, instr, &rd, &rdtype, space)) != 0)
429 			return (err);
430 		break;
431 
432 	case FSUBS: case FSUBD: case FSUBQ:
433 		if ((err = fpu_insn_fsub(fe, instr, &rd, &rdtype, space)) != 0)
434 			return (err);
435 		break;
436 	default:
437 		return (NOTFPU);
438 	}
439 
440 	cx = fe->fe_cx;
441 	fsr = fe->fe_fsr;
442 	if (cx != 0) {
443 		mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK;
444 		if (cx & mask) {
445 			/* not accrued??? */
446 			fs->fs_fsr = (fsr & ~FSR_FTT) |
447 			    (FSR_TT_IEEE << FSR_FTT_SHIFT) |
448 			    (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT);
449 			return (FPE);
450 		}
451 		fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT);
452 	}
453 	fs->fs_fsr = fsr;
454 	fpu_fcopy(space, fs->fs_regs + rd, rdtype);
455 	DPRINTF(FPE_STATE, ("AFTER:\n"));
456 	DUMPSTATE(FPE_STATE, fs);
457 	return (0);
458 }
459 
460 /*
461  * Handler for FMOV[SDQ] emulation.
462  */
463 int
464 fpu_insn_fmov(fs, fe, instr)
465 	struct fpstate64 *fs;
466 	struct fpemu *fe;
467 	union instr instr;
468 {
469 	int opf = instr.i_opf.i_opf, rs, rd, rtype;
470 
471 	rtype = opf & 3;
472 	if (rtype == 0)
473 		return (NOTFPU);
474 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
475 		return (NOTFPU);
476 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
477 		return (NOTFPU);
478 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
479 	fs->fs_fsr = fe->fe_fsr;
480 	return (0);
481 }
482 
483 /*
484  * Handler for FABS[SDQ] emulation.
485  */
486 int
487 fpu_insn_fabs(fs, fe, instr)
488 	struct fpstate64 *fs;
489 	struct fpemu *fe;
490 	union instr instr;
491 {
492 	int opf = instr.i_opf.i_opf, rs, rd, rtype;
493 
494 	rtype = opf & 3;
495 	if (rtype == 0)
496 		return (NOTFPU);
497 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
498 		return (NOTFPU);
499 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
500 		return (NOTFPU);
501 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
502 	fs->fs_regs[rd] = fs->fs_regs[rd] & ~(1 << 31);
503 	fs->fs_fsr = fe->fe_fsr;
504 	return (0);
505 }
506 
507 /*
508  * Handler for FNEG[SDQ] emulation.
509  */
510 int
511 fpu_insn_fneg(fs, fe, instr)
512 	struct fpstate64 *fs;
513 	struct fpemu *fe;
514 	union instr instr;
515 {
516 	int opf = instr.i_opf.i_opf, rs, rd, rtype;
517 
518 	rtype = opf & 3;
519 	if (rtype == 0)
520 		return (NOTFPU);
521 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
522 		return (NOTFPU);
523 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
524 		return (NOTFPU);
525 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
526 	fs->fs_regs[rd] = fs->fs_regs[rd] ^ (1 << 31);
527 	fs->fs_fsr = fe->fe_fsr;
528 	return (0);
529 }
530 
531 /*
532  * Handler for F[XI]TO[SDQ] emulation.
533  */
534 int
535 fpu_insn_itof(fe, instr, rstype, rdp, rdtypep, space)
536 	struct fpemu *fe;
537 	union instr instr;
538 	u_int *space;
539 	int rstype, *rdp, *rdtypep;
540 {
541 	int opf = instr.i_opf.i_opf, rs, rd, rdtype;
542 
543 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
544 		return (NOTFPU);
545 
546 	rdtype = (opf >> 2) & 3;
547 	if (rdtype == 0)
548 		return (NOTFPU);
549 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
550 		return (NOTFPU);
551 
552 	DPRINTF(FPE_INSN, ("itof %%f%d(%d, %d) -> %%f%d(%d, %d)\n",
553 	    rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd));
554 	fpu_explode(fe, &fe->fe_f1, rstype, rs);
555 	fpu_implode(fe, &fe->fe_f1, rdtype, space);
556 	*rdp = rd;
557 	*rdtypep = rdtype;
558 	return (0);
559 }
560 
561 /*
562  * Handler for F[SDQ]TO[XI] emulation.
563  */
564 int
565 fpu_insn_ftoi(fe, instr, rdp, rdtype, space)
566 	struct fpemu *fe;
567 	union instr instr;
568 	u_int *space;
569 	int *rdp, rdtype;
570 {
571 	int opf = instr.i_opf.i_opf, rd, rstype, rs;
572 
573 	rstype = opf & 3;
574 	if (rstype == 0)
575 		return (NOTFPU);
576 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
577 		return (NOTFPU);
578 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
579 		return (NOTFPU);
580 
581 	fpu_explode(fe, &fe->fe_f1, rstype, rs);
582 	fpu_implode(fe, &fe->fe_f1, rdtype, space);
583 	*rdp = rd;
584 	return (0);
585 }
586 
587 /*
588  * Handler for F[SDQ]TO[SDQ] emulation.
589  */
590 int
591 fpu_insn_ftof(fe, instr, rdp, rdtypep, space)
592 	struct fpemu *fe;
593 	union instr instr;
594 	u_int *space;
595 	int *rdp, *rdtypep;
596 {
597 	int opf = instr.i_opf.i_opf, rd, rs, rdtype, rstype;
598 
599 	rstype = opf & 3;
600 	rdtype = (opf >> 2) & 3;
601 
602 	if ((rstype == rdtype) || (rstype == 0) || (rdtype == 0))
603 		return (NOTFPU);
604 
605 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
606 		return (NOTFPU);
607 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
608 		return (NOTFPU);
609 
610 	DPRINTF(FPE_INSN, ("ftof %%f%d(%d, %d) -> %%f%d(%d, %d)\n",
611 	    rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd));
612 
613 	fpu_explode(fe, &fe->fe_f1, rstype, rs);
614 	fpu_implode(fe, &fe->fe_f1, rdtype, space);
615 	*rdp = rd;
616 	*rdtypep = rdtype;
617 	return (0);
618 }
619 
620 /*
621  * Handler for FQSRT[SDQ] emulation.
622  */
623 int
624 fpu_insn_fsqrt(fe, instr, rdp, rdtypep, space)
625 	struct fpemu *fe;
626 	union instr instr;
627 	u_int *space;
628 	int *rdp, *rdtypep;
629 {
630 	int opf = instr.i_opf.i_opf, rd, rs, rtype;
631 	struct fpn *fp;
632 
633 	rtype = opf & 3;
634 	if (rtype == 0)
635 		return (NOTFPU);
636 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
637 		return (NOTFPU);
638 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
639 		return (NOTFPU);
640 
641 	fpu_explode(fe, &fe->fe_f1, rtype, rs);
642 	fp = fpu_sqrt(fe);
643 	fpu_implode(fe, fp, rtype, space);
644 	*rdp = rd;
645 	*rdtypep = rtype;
646 	return (0);
647 }
648 
649 /*
650  * Handler for FCMP{E}[SDQ] emulation.
651  */
652 int
653 fpu_insn_fcmp(fs, fe, instr, cmpe)
654 	struct fpstate64 *fs;
655 	struct fpemu *fe;
656 	union instr instr;
657 	int cmpe;
658 {
659 	int opf = instr.i_opf.i_opf, rs1, rs2, rtype, cx, fsr;
660 
661 	rtype = opf & 3;
662 	if (rtype == 0)
663 		return (NOTFPU);
664 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
665 		return (NOTFPU);
666 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
667 		return (NOTFPU);
668 
669 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
670 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
671 	fpu_compare(fe, cmpe);
672 
673 	/*
674 	 * The only possible exception here is NV; catch it early
675 	 * and get out, as there is no result register.
676 	 */
677 	cx = fe->fe_cx;
678 	fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT);
679 	if (cx != 0) {
680 		if (fsr & (FSR_NV << FSR_TEM_SHIFT)) {
681 			fs->fs_fsr = (fsr & ~FSR_FTT) |
682 			    (FSR_TT_IEEE << FSR_FTT_SHIFT);
683 			return (FPE);
684 		}
685 		fsr |= FSR_NV << FSR_AX_SHIFT;
686 	}
687 	fs->fs_fsr = fsr;
688 	return (0);
689 }
690 
691 /*
692  * Handler for FMUL[SDQ] emulation.
693  */
694 int
695 fpu_insn_fmul(fe, instr, rdp, rdtypep, space)
696 	struct fpemu *fe;
697 	union instr instr;
698 	int *rdp, *rdtypep;
699 	u_int *space;
700 {
701 	struct fpn *fp;
702 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
703 
704 	rtype = opf & 3;
705 	if (rtype == 0)
706 		return (NOTFPU);
707 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
708 		return (NOTFPU);
709 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
710 		return (NOTFPU);
711 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
712 		return (NOTFPU);
713 
714 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
715 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
716 	fp = fpu_mul(fe);
717 	fpu_implode(fe, fp, rtype, space);
718 	*rdp = rd;
719 	*rdtypep = rtype;
720 	return (0);
721 }
722 
723 /*
724  * Handler for FSMULD, FDMULQ emulation.
725  */
726 int
727 fpu_insn_fmulx(fe, instr, rdp, rdtypep, space)
728 	struct fpemu *fe;
729 	union instr instr;
730 	int *rdp, *rdtypep;
731 	u_int *space;
732 {
733 	struct fpn *fp;
734 	int opf = instr.i_opf.i_opf, rd, rdtype, rstype, rs1, rs2;
735 
736 	rstype = opf & 3;
737 	rdtype = (opf >> 2) & 3;
738 	if ((rstype != rdtype + 1) || (rstype == 0) || (rdtype == 0))
739 		return (NOTFPU);
740 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rstype)) < 0)
741 		return (NOTFPU);
742 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
743 		return (NOTFPU);
744 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
745 		return (NOTFPU);
746 
747 	fpu_explode(fe, &fe->fe_f1, rstype, rs1);
748 	fpu_explode(fe, &fe->fe_f2, rstype, rs2);
749 	fp = fpu_mul(fe);
750 	fpu_implode(fe, fp, rdtype, space);
751 	*rdp = rd;
752 	*rdtypep = rdtype;
753 	return (0);
754 }
755 
756 /*
757  * Handler for FDIV[SDQ] emulation.
758  */
759 int
760 fpu_insn_fdiv(fe, instr, rdp, rdtypep, space)
761 	struct fpemu *fe;
762 	union instr instr;
763 	int *rdp, *rdtypep;
764 	u_int *space;
765 {
766 	struct fpn *fp;
767 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
768 
769 	rtype = opf & 3;
770 	if (rtype == 0)
771 		return (NOTFPU);
772 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
773 		return (NOTFPU);
774 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
775 		return (NOTFPU);
776 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
777 		return (NOTFPU);
778 
779 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
780 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
781 	fp = fpu_div(fe);
782 	fpu_implode(fe, fp, rtype, space);
783 	*rdp = rd;
784 	*rdtypep = rtype;
785 	return (0);
786 }
787 
788 /*
789  * Handler for FADD[SDQ] emulation.
790  */
791 int
792 fpu_insn_fadd(fe, instr, rdp, rdtypep, space)
793 	struct fpemu *fe;
794 	union instr instr;
795 	int *rdp, *rdtypep;
796 	u_int *space;
797 {
798 	struct fpn *fp;
799 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
800 
801 	rtype = opf & 3;
802 	if (rtype == 0)
803 		return (NOTFPU);
804 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
805 		return (NOTFPU);
806 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
807 		return (NOTFPU);
808 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
809 		return (NOTFPU);
810 
811 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
812 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
813 	fp = fpu_add(fe);
814 	fpu_implode(fe, fp, rtype, space);
815 	*rdp = rd;
816 	*rdtypep = rtype;
817 	return (0);
818 }
819 
820 /*
821  * Handler for FSUB[SDQ] emulation.
822  */
823 int
824 fpu_insn_fsub(fe, instr, rdp, rdtypep, space)
825 	struct fpemu *fe;
826 	union instr instr;
827 	int *rdp, *rdtypep;
828 	u_int *space;
829 {
830 	struct fpn *fp;
831 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
832 
833 	rtype = opf & 3;
834 	if (rtype == 0)
835 		return (NOTFPU);
836 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
837 		return (NOTFPU);
838 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
839 		return (NOTFPU);
840 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
841 		return (NOTFPU);
842 
843 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
844 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
845 	fp = fpu_sub(fe);
846 	fpu_implode(fe, fp, rtype, space);
847 	*rdp = rd;
848 	*rdtypep = rtype;
849 	return (0);
850 }
851 
852 /*
853  * Handler for FMOV[SDQ][cond] emulation.
854  */
855 int
856 fpu_insn_fmovcc(p, fs, instr)
857 	struct proc *p;
858 	struct fpstate64 *fs;
859 	union instr instr;
860 {
861 	int rtype, rd, rs, cond;
862 
863 	rtype = instr.i_fmovcc.i_opf_low & 3;
864 	if ((rtype == 0) || (instr.i_int & 0x00040000))
865 		return (NOTFPU);
866 
867 	if ((rd = fpu_regoffset(instr.i_fmovcc.i_rd, rtype)) < 0)
868 		return (NOTFPU);
869 	if ((rs = fpu_regoffset(instr.i_fmovcc.i_rs2, rtype)) < 0)
870 		return (NOTFPU);
871 
872 	switch (instr.i_fmovcc.i_opf_cc) {
873 	case 0:
874 		cond = (fs->fs_fsr >> FSR_FCC_SHIFT) & FSR_FCC_MASK;
875 		break;
876 	case 1:
877 		cond = (fs->fs_fsr >> FSR_FCC1_SHIFT) & FSR_FCC_MASK;
878 		break;
879 	case 2:
880 		cond = (fs->fs_fsr >> FSR_FCC2_SHIFT) & FSR_FCC_MASK;
881 		break;
882 	case 3:
883 		cond = (fs->fs_fsr >> FSR_FCC3_SHIFT) & FSR_FCC_MASK;
884 		break;
885 	case 4:
886 		cond = (p->p_md.md_tf->tf_tstate >> TSTATE_CCR_SHIFT) &
887 		    PSR_ICC;
888 		break;
889 	case 6:
890 		cond = (p->p_md.md_tf->tf_tstate >>
891 		    (TSTATE_CCR_SHIFT + XCC_SHIFT)) & PSR_ICC;
892 		break;
893 	default:
894 		return (NOTFPU);
895 	}
896 
897 	if (instr.i_fmovcc.i_cond != cond)
898 		return (0);
899 
900 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
901 	return (0);
902 }
903 
904 /*
905  * Handler for FMOVR[icond][SDQ] emulation.
906  */
907 int
908 fpu_insn_fmovr(p, fs, instr)
909 	struct proc *p;
910 	struct fpstate64 *fs;
911 	union instr instr;
912 {
913 	int rtype, rd, rs2, rs1;
914 
915 	rtype = instr.i_fmovcc.i_opf_low & 3;
916 	if ((rtype == 0) || (instr.i_int & 0x00002000))
917 		return (NOTFPU);
918 
919 	if ((rd = fpu_regoffset(instr.i_fmovr.i_rd, rtype)) < 0)
920 		return (NOTFPU);
921 	if ((rs2 = fpu_regoffset(instr.i_fmovr.i_rs2, rtype)) < 0)
922 		return (NOTFPU);
923 	rs1 = instr.i_fmovr.i_rs1;
924 
925 	switch (instr.i_fmovr.i_rcond) {
926 	case 1:	/* Z */
927 		if (rs1 != 0 &&
928 		    (int64_t)p->p_md.md_tf->tf_global[rs1] != 0)
929 			return (0);
930 		break;
931 	case 2: /* LEZ */
932 		if (rs1 != 0 &&
933 		    (int64_t)p->p_md.md_tf->tf_global[rs1] > 0)
934 			return (0);
935 		break;
936 	case 3: /* LZ */
937 		if (rs1 == 0 ||
938 		    (int64_t)p->p_md.md_tf->tf_global[rs1] >= 0)
939 			return (0);
940 		break;
941 	case 5:	/* NZ */
942 		if (rs1 == 0 ||
943 		    (int64_t)p->p_md.md_tf->tf_global[rs1] == 0)
944 			return (0);
945 		break;
946 	case 6: /* NGZ */
947 		if (rs1 == 0 ||
948 		    (int64_t)p->p_md.md_tf->tf_global[rs1] <= 0)
949 			return (0);
950 		break;
951 	case 7: /* NGEZ */
952 		if (rs1 != 0 &&
953 		    (int64_t)p->p_md.md_tf->tf_global[rs1] < 0)
954 			return (0);
955 		break;
956 	default:
957 		return (NOTFPU);
958 	}
959 
960 	fpu_fcopy(fs->fs_regs + rs2, fs->fs_regs + rd, rtype);
961 	return (0);
962 }
963