xref: /openbsd/sys/arch/sparc64/fpu/fpu.c (revision 5dea098c)
1 /*	$OpenBSD: fpu.c,v 1.26 2024/03/29 21:14:31 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/fsr.h>
79 #include <machine/reg.h>
80 
81 #include <sparc64/fpu/fpu_emu.h>
82 #include <sparc64/fpu/fpu_extern.h>
83 
84 int fpu_regoffset(int, int);
85 int fpu_insn_fmov(struct fpstate *, struct fpemu *, union instr);
86 int fpu_insn_fabs(struct fpstate *, struct fpemu *, union instr);
87 int fpu_insn_fneg(struct fpstate *, struct fpemu *, union instr);
88 int fpu_insn_itof(struct fpemu *, union instr, int, int *,
89     int *, u_int *);
90 int fpu_insn_ftoi(struct fpemu *, union instr, int *, int, u_int *);
91 int fpu_insn_ftof(struct fpemu *, union instr, int *, int *, u_int *);
92 int fpu_insn_fsqrt(struct fpemu *, union instr, int *, int *, u_int *);
93 int fpu_insn_fcmp(struct fpstate *, struct fpemu *, union instr, int);
94 int fpu_insn_fmul(struct fpemu *, union instr, int *, int *, u_int *);
95 int fpu_insn_fmulx(struct fpemu *, union instr, int *, int *, u_int *);
96 int fpu_insn_fdiv(struct fpemu *, union instr, int *, int *, u_int *);
97 int fpu_insn_fadd(struct fpemu *, union instr, int *, int *, u_int *);
98 int fpu_insn_fsub(struct fpemu *, union instr, int *, int *, u_int *);
99 int fpu_insn_fmovcc(struct proc *, struct fpstate *, union instr);
100 int fpu_insn_fmovr(struct proc *, struct fpstate *, union instr);
101 void fpu_fcopy(u_int *, u_int *, int);
102 
103 #ifdef DEBUG
104 int fpe_debug = 0;
105 
106 /*
107  * Dump a `fpn' structure.
108  */
109 void
110 fpu_dumpfpn(struct fpn *fp)
111 {
112 	static char *class[] = { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
113 
114 	printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2],
115 	    fp->fp_sign ? '-' : ' ', fp->fp_mant[0], fp->fp_mant[1],
116 	    fp->fp_mant[2], fp->fp_mant[3], fp->fp_exp);
117 }
118 void
119 fpu_dumpstate(struct fpstate *fs)
120 {
121 	int i;
122 
123 	for (i = 0; i < 64; i++)
124 		printf("%%f%02d: %08x%s",
125 		    i, fs->fs_regs[i], ((i & 3) == 3) ? "\n" : "   ");
126 }
127 #endif
128 
129 /*
130  * fpu_execute returns the following error numbers (0 = no error):
131  */
132 #define	FPE		1	/* take a floating point exception */
133 #define	NOTFPU		2	/* not an FPU instruction */
134 
135 /*
136  * Translate current exceptions into `first' exception.  The
137  * bits go the wrong way for ffs() (0x10 is most important, etc).
138  * There are only 5, so do it the obvious way.
139  */
140 #define	X1(x) x
141 #define	X2(x) x,x
142 #define	X4(x) x,x,x,x
143 #define	X8(x) X4(x),X4(x)
144 #define	X16(x) X8(x),X8(x)
145 
146 static const char cx_to_trapx[] = {
147 	X1(FSR_NX),
148 	X2(FSR_DZ),
149 	X4(FSR_UF),
150 	X8(FSR_OF),
151 	X16(FSR_NV)
152 };
153 static const u_char fpu_codes[] = {
154 	X1(FPE_FLTINEX_TRAP),
155 	X2(FPE_FLTDIV_TRAP),
156 	X4(FPE_FLTUND_TRAP),
157 	X8(FPE_FLTOVF_TRAP),
158 	X16(FPE_FLTOPERR_TRAP)
159 };
160 
161 static const int fpu_types[] = {
162 	X1(FPE_FLTRES),
163 	X2(FPE_FLTDIV),
164 	X4(FPE_FLTUND),
165 	X8(FPE_FLTOVF),
166 	X16(FPE_FLTINV)
167 };
168 
169 void
170 fpu_fcopy(u_int *src, u_int *dst, int type)
171 {
172 	*dst++ = *src++;
173 	if (type == FTYPE_SNG || type == FTYPE_INT)
174 		return;
175 	*dst++ = *src++;
176 	if (type != FTYPE_EXT)
177 		return;
178 	*dst++ = *src++;
179 	*dst = *src;
180 }
181 
182 /*
183  * The FPU gave us an exception.  Clean up the mess.
184  */
185 void
186 fpu_cleanup(struct proc *p, struct fpstate *fs, union instr instr,
187     union sigval sv)
188 {
189 	int i, fsr = fs->fs_fsr, error;
190 	struct fpemu fe;
191 
192 	switch ((fsr >> FSR_FTT_SHIFT) & FSR_FTT_MASK) {
193 	case FSR_TT_NONE:
194 #ifdef DEBUG
195 		printf("fpu_cleanup: invoked although no exception\n");
196 #endif
197 		return;
198 	case FSR_TT_IEEE:
199 		if ((i = fsr & FSR_CX) == 0)
200 			panic("fpu ieee trap, but no exception");
201 		trapsignal(p, SIGFPE, fpu_codes[i - 1], fpu_types[i - 1], sv);
202 		return;
203 	case FSR_TT_UNFIN:
204 		if (instr.i_int == 0) {
205 #ifdef DEBUG
206 			printf("fpu_cleanup: unfinished fpop\n");
207 #endif
208 			return;
209 		}
210 		break;
211 	case FSR_TT_UNIMP:
212 		if (instr.i_int == 0)
213 			panic("fpu_cleanup: unimplemented fpop without insn");
214 		break;
215 	case FSR_TT_SEQ:
216 		panic("fpu sequence error");
217 		/* NOTREACHED */
218 	case FSR_TT_HWERR:
219 		log(LOG_ERR, "fpu hardware error (%s[%d])\n",
220 		    p->p_p->ps_comm, p->p_p->ps_pid);
221 		uprintf("%s[%d]: fpu hardware error\n",
222 		    p->p_p->ps_comm, p->p_p->ps_pid);
223 		trapsignal(p, SIGFPE, -1, FPE_FLTINV, sv);	/* ??? */
224 		return;
225 	default:
226 		printf("fsr=0x%x\n", fsr);
227 		panic("fpu error");
228 	}
229 
230 	/* emulate the instructions left in the queue */
231 	fe.fe_fpstate = fs;
232 	if (instr.i_any.i_op != IOP_reg ||
233 	    (instr.i_op3.i_op3 != IOP3_FPop1 &&
234 	     instr.i_op3.i_op3 != IOP3_FPop2))
235 		panic("bogus fpu instruction to emulate");
236 	error = fpu_execute(p, &fe, instr);
237 	switch (error) {
238 	case 0:
239 		break;
240 	case FPE:
241 		trapsignal(p, SIGFPE,
242 		    fpu_codes[(fs->fs_fsr & FSR_CX) - 1],
243 		    fpu_types[(fs->fs_fsr & FSR_CX) - 1], sv);
244 		break;
245 	case NOTFPU:
246 	default:
247 		trapsignal(p, SIGILL, 0, ILL_COPROC, sv);
248 		break;
249 	}
250 }
251 
252 /*
253  * Compute offset given a register and type.  For 32 bit sparc, bits 1 and 0
254  * must be zero for ext types, and bit 0 must be 0 for double and long types.
255  * For 64bit sparc, bit 1 must be zero for quad types, and bit 0 becomes bit
256  * 5 in the register offset for long, double, and quad types.
257  */
258 int
259 fpu_regoffset(int rx, int type)
260 {
261 	if (type == FTYPE_LNG || type == FTYPE_DBL || type == FTYPE_EXT) {
262 		rx |= (rx & 1) << 5;
263 		rx &= 0x3e;
264 		if ((type == FTYPE_EXT) && (rx & 2))
265 			return (-1);
266 	}
267 	return (rx);
268 }
269 
270 /*
271  * Execute an FPU instruction (one that runs entirely in the FPU; not
272  * FBfcc or STF, for instance).  On return, fe->fe_fs->fs_fsr will be
273  * modified to reflect the setting the hardware would have left.
274  */
275 int
276 fpu_execute(struct proc *p, struct fpemu *fe, union instr instr)
277 {
278 	struct fpstate *fs;
279 	int opf, rdtype, rd, err, mask, cx, fsr;
280 	u_int space[4];
281 
282 	DPRINTF(FPE_INSN, ("op3: %x, opf %x\n", instr.i_opf.i_op3,
283 	    instr.i_opf.i_opf));
284 	DPRINTF(FPE_STATE, ("BEFORE:\n"));
285 	DUMPSTATE(FPE_STATE, fe->fe_fpstate);
286 	opf = instr.i_opf.i_opf;
287 	fs = fe->fe_fpstate;
288 	fe->fe_fsr = fs->fs_fsr & ~FSR_CX;
289 	fe->fe_cx = 0;
290 
291 	if ((instr.i_int & 0xc0000000) != 0x80000000)
292 		return (NOTFPU);
293 
294 	if (instr.i_opf.i_op3 == IOP3_FPop2) {
295 		switch (opf) {
296 		case FCMPS: case FCMPD: case FCMPQ:
297 			return (fpu_insn_fcmp(fs, fe, instr, 0));
298 
299 		case FCMPES: case FCMPED: case FCMPEQ:
300 			return (fpu_insn_fcmp(fs, fe, instr, 1));
301 
302 		case FMVFC0S: case FMVFC0D: case FMVFC0Q:
303 		case FMVFC1S: case FMVFC1D: case FMVFC1Q:
304 		case FMVFC2S: case FMVFC2D: case FMVFC2Q:
305 		case FMVFC3S: case FMVFC3D: case FMVFC3Q:
306 		case FMVICS: case FMVICD: case FMVICQ:
307 		case FMVXCS: case FMVXCD: case FMVXCQ:
308 			return (fpu_insn_fmovcc(p, fs, instr));
309 
310 		case FMOVZS: case FMOVZD: case FMOVZQ:
311 		case FMOVLEZS: case FMOVLEZD: case FMOVLEZQ:
312 		case FMOVLZS: case FMOVLZD: case FMOVLZQ:
313 		case FMOVNZS: case FMOVNZD: case FMOVNZQ:
314 		case FMOVGZS: case FMOVGZD: case FMOVGZQ:
315 		case FMOVGEZS: case FMOVGEZD: case FMOVGEZQ:
316 			return (fpu_insn_fmovr(p, fs, instr));
317 		}
318 		return (NOTFPU);
319 	}
320 
321 	if (instr.i_opf.i_op3 != IOP3_FPop1)
322 		return (NOTFPU);
323 
324 	switch (instr.i_opf.i_opf) {
325 	case FSTOX: case FDTOX: case FQTOX:
326 		rdtype = FTYPE_LNG;
327 		if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0)
328 			return (err);
329 		break;
330 
331 	case FSTOI: case FDTOI: case FQTOI:
332 		rdtype = FTYPE_INT;
333 		if ((err = fpu_insn_ftoi(fe, instr, &rd, rdtype, space)) != 0)
334 			return (err);
335 		break;
336 
337 	case FITOS: case FITOD: case FITOQ:
338 		if ((err = fpu_insn_itof(fe, instr, FTYPE_INT, &rd,
339 		    &rdtype, space)) != 0)
340 			return (err);
341 		break;
342 
343 	case FXTOS: case FXTOD: case FXTOQ:
344 		if ((err = fpu_insn_itof(fe, instr, FTYPE_LNG, &rd,
345 		    &rdtype, space)) != 0)
346 			return (err);
347 		break;
348 
349 	case FSTOD: case FSTOQ:
350 	case FDTOS: case FDTOQ:
351 	case FQTOS: case FQTOD:
352 		if ((err = fpu_insn_ftof(fe, instr, &rd, &rdtype, space)) != 0)
353 			return (err);
354 		break;
355 
356 	case FMOVS: case FMOVD: case FMOVQ:
357 		return (fpu_insn_fmov(fs, fe, instr));
358 
359 	case FNEGS: case FNEGD: case FNEGQ:
360 		return (fpu_insn_fneg(fs, fe, instr));
361 
362 	case FABSS: case FABSD: case FABSQ:
363 		return (fpu_insn_fabs(fs, fe, instr));
364 
365 	case FSQRTS: case FSQRTD: case FSQRTQ:
366 		if ((err = fpu_insn_fsqrt(fe, instr, &rd, &rdtype, space)) != 0)
367 			return (err);
368 		break;
369 
370 	case FMULS: case FMULD: case FMULQ:
371 		if ((err = fpu_insn_fmul(fe, instr, &rd, &rdtype, space)) != 0)
372 			return (err);
373 		break;
374 
375 	case FDIVS: case FDIVD: case FDIVQ:
376 		if ((err = fpu_insn_fdiv(fe, instr, &rd, &rdtype, space)) != 0)
377 			return (err);
378 		break;
379 
380 	case FSMULD: case FDMULQ:
381 		if ((err = fpu_insn_fmulx(fe, instr, &rd, &rdtype, space)) != 0)
382 			return (err);
383 		break;
384 
385 	case FADDS: case FADDD: case FADDQ:
386 		if ((err = fpu_insn_fadd(fe, instr, &rd, &rdtype, space)) != 0)
387 			return (err);
388 		break;
389 
390 	case FSUBS: case FSUBD: case FSUBQ:
391 		if ((err = fpu_insn_fsub(fe, instr, &rd, &rdtype, space)) != 0)
392 			return (err);
393 		break;
394 	default:
395 		return (NOTFPU);
396 	}
397 
398 	cx = fe->fe_cx;
399 	fsr = fe->fe_fsr;
400 	if (cx != 0) {
401 		mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK;
402 		if (cx & mask) {
403 			/* not accrued??? */
404 			fs->fs_fsr = (fsr & ~FSR_FTT) |
405 			    (FSR_TT_IEEE << FSR_FTT_SHIFT) |
406 			    (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT);
407 			return (FPE);
408 		}
409 		fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT);
410 	}
411 	fs->fs_fsr = fsr;
412 	fpu_fcopy(space, fs->fs_regs + rd, rdtype);
413 	DPRINTF(FPE_STATE, ("AFTER:\n"));
414 	DUMPSTATE(FPE_STATE, fs);
415 	return (0);
416 }
417 
418 /*
419  * Handler for FMOV[SDQ] emulation.
420  */
421 int
422 fpu_insn_fmov(struct fpstate *fs, struct fpemu *fe, union instr instr)
423 {
424 	int opf = instr.i_opf.i_opf, rs, rd, rtype;
425 
426 	rtype = opf & 3;
427 	if (rtype == 0)
428 		return (NOTFPU);
429 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
430 		return (NOTFPU);
431 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
432 		return (NOTFPU);
433 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
434 	fs->fs_fsr = fe->fe_fsr;
435 	return (0);
436 }
437 
438 /*
439  * Handler for FABS[SDQ] emulation.
440  */
441 int
442 fpu_insn_fabs(struct fpstate *fs, struct fpemu *fe, union instr instr)
443 {
444 	int opf = instr.i_opf.i_opf, rs, rd, rtype;
445 
446 	rtype = opf & 3;
447 	if (rtype == 0)
448 		return (NOTFPU);
449 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
450 		return (NOTFPU);
451 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
452 		return (NOTFPU);
453 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
454 	fs->fs_regs[rd] = fs->fs_regs[rd] & ~(1U << 31);
455 	fs->fs_fsr = fe->fe_fsr;
456 	return (0);
457 }
458 
459 /*
460  * Handler for FNEG[SDQ] emulation.
461  */
462 int
463 fpu_insn_fneg(struct fpstate *fs, struct fpemu *fe, union instr instr)
464 {
465 	int opf = instr.i_opf.i_opf, rs, rd, rtype;
466 
467 	rtype = opf & 3;
468 	if (rtype == 0)
469 		return (NOTFPU);
470 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
471 		return (NOTFPU);
472 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
473 		return (NOTFPU);
474 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
475 	fs->fs_regs[rd] = fs->fs_regs[rd] ^ (1U << 31);
476 	fs->fs_fsr = fe->fe_fsr;
477 	return (0);
478 }
479 
480 /*
481  * Handler for F[XI]TO[SDQ] emulation.
482  */
483 int
484 fpu_insn_itof(struct fpemu *fe, union instr instr, int rstype, int *rdp,
485     int *rdtypep, u_int *space)
486 {
487 	int opf = instr.i_opf.i_opf, rs, rd, rdtype;
488 
489 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
490 		return (NOTFPU);
491 
492 	rdtype = (opf >> 2) & 3;
493 	if (rdtype == 0)
494 		return (NOTFPU);
495 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
496 		return (NOTFPU);
497 
498 	DPRINTF(FPE_INSN, ("itof %%f%d(%d, %d) -> %%f%d(%d, %d)\n",
499 	    rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd));
500 	fpu_explode(fe, &fe->fe_f1, rstype, rs);
501 	fpu_implode(fe, &fe->fe_f1, rdtype, space);
502 	*rdp = rd;
503 	*rdtypep = rdtype;
504 	return (0);
505 }
506 
507 /*
508  * Handler for F[SDQ]TO[XI] emulation.
509  */
510 int
511 fpu_insn_ftoi(struct fpemu *fe, union instr instr, int *rdp, int rdtype,
512     u_int *space)
513 {
514 	int opf = instr.i_opf.i_opf, rd, rstype, rs;
515 
516 	rstype = opf & 3;
517 	if (rstype == 0)
518 		return (NOTFPU);
519 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
520 		return (NOTFPU);
521 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
522 		return (NOTFPU);
523 
524 	fpu_explode(fe, &fe->fe_f1, rstype, rs);
525 	fpu_implode(fe, &fe->fe_f1, rdtype, space);
526 	*rdp = rd;
527 	return (0);
528 }
529 
530 /*
531  * Handler for F[SDQ]TO[SDQ] emulation.
532  */
533 int
534 fpu_insn_ftof(struct fpemu *fe, union instr instr, int *rdp, int *rdtypep,
535     u_int *space)
536 {
537 	int opf = instr.i_opf.i_opf, rd, rs, rdtype, rstype;
538 
539 	rstype = opf & 3;
540 	rdtype = (opf >> 2) & 3;
541 
542 	if ((rstype == rdtype) || (rstype == 0) || (rdtype == 0))
543 		return (NOTFPU);
544 
545 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
546 		return (NOTFPU);
547 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
548 		return (NOTFPU);
549 
550 	DPRINTF(FPE_INSN, ("ftof %%f%d(%d, %d) -> %%f%d(%d, %d)\n",
551 	    rs, rstype, instr.i_opf.i_rs2, rd, rdtype, instr.i_opf.i_rd));
552 
553 	fpu_explode(fe, &fe->fe_f1, rstype, rs);
554 	fpu_implode(fe, &fe->fe_f1, rdtype, space);
555 	*rdp = rd;
556 	*rdtypep = rdtype;
557 	return (0);
558 }
559 
560 /*
561  * Handler for FQSRT[SDQ] emulation.
562  */
563 int
564 fpu_insn_fsqrt(struct fpemu *fe, union instr instr, int *rdp, int *rdtypep,
565     u_int *space)
566 {
567 	int opf = instr.i_opf.i_opf, rd, rs, rtype;
568 	struct fpn *fp;
569 
570 	rtype = opf & 3;
571 	if (rtype == 0)
572 		return (NOTFPU);
573 	if ((rs = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
574 		return (NOTFPU);
575 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
576 		return (NOTFPU);
577 
578 	fpu_explode(fe, &fe->fe_f1, rtype, rs);
579 	fp = fpu_sqrt(fe);
580 	fpu_implode(fe, fp, rtype, space);
581 	*rdp = rd;
582 	*rdtypep = rtype;
583 	return (0);
584 }
585 
586 /*
587  * Handler for FCMP{E}[SDQ] emulation.
588  */
589 int
590 fpu_insn_fcmp(struct fpstate *fs, struct fpemu *fe, union instr instr,
591     int cmpe)
592 {
593 	int opf = instr.i_opf.i_opf, rs1, rs2, rtype, cx, fsr;
594 
595 	rtype = opf & 3;
596 	if (rtype == 0)
597 		return (NOTFPU);
598 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
599 		return (NOTFPU);
600 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
601 		return (NOTFPU);
602 
603 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
604 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
605 	fpu_compare(fe, cmpe);
606 
607 	/*
608 	 * The only possible exception here is NV; catch it early
609 	 * and get out, as there is no result register.
610 	 */
611 	cx = fe->fe_cx;
612 	fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT);
613 	if (cx != 0) {
614 		if (fsr & (FSR_NV << FSR_TEM_SHIFT)) {
615 			fs->fs_fsr = (fsr & ~FSR_FTT) |
616 			    (FSR_TT_IEEE << FSR_FTT_SHIFT);
617 			return (FPE);
618 		}
619 		fsr |= FSR_NV << FSR_AX_SHIFT;
620 	}
621 	fs->fs_fsr = fsr;
622 	return (0);
623 }
624 
625 /*
626  * Handler for FMUL[SDQ] emulation.
627  */
628 int
629 fpu_insn_fmul(struct fpemu *fe, union instr instr, int *rdp, int *rdtypep,
630     u_int *space)
631 {
632 	struct fpn *fp;
633 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
634 
635 	rtype = opf & 3;
636 	if (rtype == 0)
637 		return (NOTFPU);
638 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
639 		return (NOTFPU);
640 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
641 		return (NOTFPU);
642 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
643 		return (NOTFPU);
644 
645 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
646 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
647 	fp = fpu_mul(fe);
648 	fpu_implode(fe, fp, rtype, space);
649 	*rdp = rd;
650 	*rdtypep = rtype;
651 	return (0);
652 }
653 
654 /*
655  * Handler for FSMULD, FDMULQ emulation.
656  */
657 int
658 fpu_insn_fmulx(struct fpemu *fe, union instr instr, int *rdp, int *rdtypep,
659     u_int *space)
660 {
661 	struct fpn *fp;
662 	int opf = instr.i_opf.i_opf, rd, rdtype, rstype, rs1, rs2;
663 
664 	rstype = opf & 3;
665 	rdtype = (opf >> 2) & 3;
666 	if ((rstype != rdtype + 1) || (rstype == 0) || (rdtype == 0))
667 		return (NOTFPU);
668 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rstype)) < 0)
669 		return (NOTFPU);
670 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rstype)) < 0)
671 		return (NOTFPU);
672 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rdtype)) < 0)
673 		return (NOTFPU);
674 
675 	fpu_explode(fe, &fe->fe_f1, rstype, rs1);
676 	fpu_explode(fe, &fe->fe_f2, rstype, rs2);
677 	fp = fpu_mul(fe);
678 	fpu_implode(fe, fp, rdtype, space);
679 	*rdp = rd;
680 	*rdtypep = rdtype;
681 	return (0);
682 }
683 
684 /*
685  * Handler for FDIV[SDQ] emulation.
686  */
687 int
688 fpu_insn_fdiv(struct fpemu *fe, union instr instr, int *rdp, int *rdtypep,
689     u_int *space)
690 {
691 	struct fpn *fp;
692 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
693 
694 	rtype = opf & 3;
695 	if (rtype == 0)
696 		return (NOTFPU);
697 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
698 		return (NOTFPU);
699 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
700 		return (NOTFPU);
701 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
702 		return (NOTFPU);
703 
704 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
705 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
706 	fp = fpu_div(fe);
707 	fpu_implode(fe, fp, rtype, space);
708 	*rdp = rd;
709 	*rdtypep = rtype;
710 	return (0);
711 }
712 
713 /*
714  * Handler for FADD[SDQ] emulation.
715  */
716 int
717 fpu_insn_fadd(struct fpemu *fe, union instr instr, int *rdp, int *rdtypep,
718     u_int *space)
719 {
720 	struct fpn *fp;
721 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
722 
723 	rtype = opf & 3;
724 	if (rtype == 0)
725 		return (NOTFPU);
726 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
727 		return (NOTFPU);
728 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
729 		return (NOTFPU);
730 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
731 		return (NOTFPU);
732 
733 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
734 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
735 	fp = fpu_add(fe);
736 	fpu_implode(fe, fp, rtype, space);
737 	*rdp = rd;
738 	*rdtypep = rtype;
739 	return (0);
740 }
741 
742 /*
743  * Handler for FSUB[SDQ] emulation.
744  */
745 int
746 fpu_insn_fsub(struct fpemu *fe, union instr instr, int *rdp, int *rdtypep,
747     u_int *space)
748 {
749 	struct fpn *fp;
750 	int opf = instr.i_opf.i_opf, rd, rtype, rs1, rs2;
751 
752 	rtype = opf & 3;
753 	if (rtype == 0)
754 		return (NOTFPU);
755 	if ((rs1 = fpu_regoffset(instr.i_opf.i_rs1, rtype)) < 0)
756 		return (NOTFPU);
757 	if ((rs2 = fpu_regoffset(instr.i_opf.i_rs2, rtype)) < 0)
758 		return (NOTFPU);
759 	if ((rd = fpu_regoffset(instr.i_opf.i_rd, rtype)) < 0)
760 		return (NOTFPU);
761 
762 	fpu_explode(fe, &fe->fe_f1, rtype, rs1);
763 	fpu_explode(fe, &fe->fe_f2, rtype, rs2);
764 	fp = fpu_sub(fe);
765 	fpu_implode(fe, fp, rtype, space);
766 	*rdp = rd;
767 	*rdtypep = rtype;
768 	return (0);
769 }
770 
771 /*
772  * Handler for FMOV[SDQ][cond] emulation.
773  */
774 int
775 fpu_insn_fmovcc(struct proc *p, struct fpstate *fs, union instr instr)
776 {
777 	int rtype, rd, rs, cond;
778 
779 	rtype = instr.i_fmovcc.i_opf_low & 3;
780 	if ((rtype == 0) || (instr.i_int & 0x00040000))
781 		return (NOTFPU);
782 
783 	if ((rd = fpu_regoffset(instr.i_fmovcc.i_rd, rtype)) < 0)
784 		return (NOTFPU);
785 	if ((rs = fpu_regoffset(instr.i_fmovcc.i_rs2, rtype)) < 0)
786 		return (NOTFPU);
787 
788 	switch (instr.i_fmovcc.i_opf_cc) {
789 	case 0:
790 		cond = (fs->fs_fsr >> FSR_FCC_SHIFT) & FSR_FCC_MASK;
791 		break;
792 	case 1:
793 		cond = (fs->fs_fsr >> FSR_FCC1_SHIFT) & FSR_FCC_MASK;
794 		break;
795 	case 2:
796 		cond = (fs->fs_fsr >> FSR_FCC2_SHIFT) & FSR_FCC_MASK;
797 		break;
798 	case 3:
799 		cond = (fs->fs_fsr >> FSR_FCC3_SHIFT) & FSR_FCC_MASK;
800 		break;
801 	case 4:
802 		cond = (p->p_md.md_tf->tf_tstate >> TSTATE_CCR_SHIFT) &
803 		    PSR_ICC;
804 		break;
805 	case 6:
806 		cond = (p->p_md.md_tf->tf_tstate >>
807 		    (TSTATE_CCR_SHIFT + XCC_SHIFT)) & PSR_ICC;
808 		break;
809 	default:
810 		return (NOTFPU);
811 	}
812 
813 	if (instr.i_fmovcc.i_cond != cond)
814 		return (0);
815 
816 	fpu_fcopy(fs->fs_regs + rs, fs->fs_regs + rd, rtype);
817 	return (0);
818 }
819 
820 /*
821  * Handler for FMOVR[icond][SDQ] emulation.
822  */
823 int
824 fpu_insn_fmovr(struct proc *p, struct fpstate *fs, union instr instr)
825 {
826 	int rtype, rd, rs2, rs1;
827 
828 	rtype = instr.i_fmovcc.i_opf_low & 3;
829 	if ((rtype == 0) || (instr.i_int & 0x00002000))
830 		return (NOTFPU);
831 
832 	if ((rd = fpu_regoffset(instr.i_fmovr.i_rd, rtype)) < 0)
833 		return (NOTFPU);
834 	if ((rs2 = fpu_regoffset(instr.i_fmovr.i_rs2, rtype)) < 0)
835 		return (NOTFPU);
836 	rs1 = instr.i_fmovr.i_rs1;
837 
838 	switch (instr.i_fmovr.i_rcond) {
839 	case 1:	/* Z */
840 		if (rs1 != 0 &&
841 		    (int64_t)p->p_md.md_tf->tf_global[rs1] != 0)
842 			return (0);
843 		break;
844 	case 2: /* LEZ */
845 		if (rs1 != 0 &&
846 		    (int64_t)p->p_md.md_tf->tf_global[rs1] > 0)
847 			return (0);
848 		break;
849 	case 3: /* LZ */
850 		if (rs1 == 0 ||
851 		    (int64_t)p->p_md.md_tf->tf_global[rs1] >= 0)
852 			return (0);
853 		break;
854 	case 5:	/* NZ */
855 		if (rs1 == 0 ||
856 		    (int64_t)p->p_md.md_tf->tf_global[rs1] == 0)
857 			return (0);
858 		break;
859 	case 6: /* NGZ */
860 		if (rs1 == 0 ||
861 		    (int64_t)p->p_md.md_tf->tf_global[rs1] <= 0)
862 			return (0);
863 		break;
864 	case 7: /* NGEZ */
865 		if (rs1 != 0 &&
866 		    (int64_t)p->p_md.md_tf->tf_global[rs1] < 0)
867 			return (0);
868 		break;
869 	default:
870 		return (NOTFPU);
871 	}
872 
873 	fpu_fcopy(fs->fs_regs + rs2, fs->fs_regs + rd, rtype);
874 	return (0);
875 }
876