1/*	$NetBSD: fpu_emu.c,v 1.14 2005/12/11 12:18:42 christos Exp $ */
2
3/*-
4 * SPDX-License-Identifier: BSD-4-Clause
5 *
6 * Copyright 2001 Wasabi Systems, Inc.
7 * All rights reserved.
8 *
9 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *      This product includes software developed for the NetBSD Project by
22 *      Wasabi Systems, Inc.
23 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
24 *    or promote products derived from this software without specific prior
25 *    written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * Copyright (c) 1992, 1993
42 *	The Regents of the University of California.  All rights reserved.
43 *
44 * This software was developed by the Computer Systems Engineering group
45 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
46 * contributed to Berkeley.
47 *
48 * All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 *	This product includes software developed by the University of
51 *	California, Lawrence Berkeley Laboratory.
52 *
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions
55 * are met:
56 * 1. Redistributions of source code must retain the above copyright
57 *    notice, this list of conditions and the following disclaimer.
58 * 2. Redistributions in binary form must reproduce the above copyright
59 *    notice, this list of conditions and the following disclaimer in the
60 *    documentation and/or other materials provided with the distribution.
61 * 3. Neither the name of the University nor the names of its contributors
62 *    may be used to endorse or promote products derived from this software
63 *    without specific prior written permission.
64 *
65 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
66 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
69 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75 * SUCH DAMAGE.
76 */
77
78#include <sys/cdefs.h>
79#include "opt_ddb.h"
80
81#include <sys/param.h>
82#include <sys/systm.h>
83#include <sys/kdb.h>
84#include <sys/kernel.h>
85#include <sys/proc.h>
86#include <sys/sysctl.h>
87#include <sys/signal.h>
88#include <sys/syslog.h>
89#include <sys/signalvar.h>
90
91#include <machine/fpu.h>
92
93#include <powerpc/fpu/fpu_emu.h>
94#include <powerpc/fpu/fpu_extern.h>
95#include <powerpc/fpu/fpu_instr.h>
96
97static SYSCTL_NODE(_hw, OID_AUTO, fpu_emu, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
98    "FPU emulator");
99
100#define	FPU_EMU_EVCNT_DECL(name)					\
101static u_int fpu_emu_evcnt_##name;					\
102SYSCTL_INT(_hw_fpu_emu, OID_AUTO, evcnt_##name, CTLFLAG_RD,		\
103    &fpu_emu_evcnt_##name, 0, "")
104
105#define	FPU_EMU_EVCNT_INCR(name)	fpu_emu_evcnt_##name++
106
107FPU_EMU_EVCNT_DECL(stfiwx);
108FPU_EMU_EVCNT_DECL(fpstore);
109FPU_EMU_EVCNT_DECL(fpload);
110FPU_EMU_EVCNT_DECL(fcmpu);
111FPU_EMU_EVCNT_DECL(frsp);
112FPU_EMU_EVCNT_DECL(fctiw);
113FPU_EMU_EVCNT_DECL(fcmpo);
114FPU_EMU_EVCNT_DECL(mtfsb1);
115FPU_EMU_EVCNT_DECL(fnegabs);
116FPU_EMU_EVCNT_DECL(mcrfs);
117FPU_EMU_EVCNT_DECL(mtfsb0);
118FPU_EMU_EVCNT_DECL(fmr);
119FPU_EMU_EVCNT_DECL(mtfsfi);
120FPU_EMU_EVCNT_DECL(fnabs);
121FPU_EMU_EVCNT_DECL(fabs);
122FPU_EMU_EVCNT_DECL(mffs);
123FPU_EMU_EVCNT_DECL(mtfsf);
124FPU_EMU_EVCNT_DECL(fctid);
125FPU_EMU_EVCNT_DECL(fcfid);
126FPU_EMU_EVCNT_DECL(fdiv);
127FPU_EMU_EVCNT_DECL(fsub);
128FPU_EMU_EVCNT_DECL(fadd);
129FPU_EMU_EVCNT_DECL(fsqrt);
130FPU_EMU_EVCNT_DECL(fsel);
131FPU_EMU_EVCNT_DECL(fpres);
132FPU_EMU_EVCNT_DECL(fmul);
133FPU_EMU_EVCNT_DECL(frsqrte);
134FPU_EMU_EVCNT_DECL(fmulsub);
135FPU_EMU_EVCNT_DECL(fmuladd);
136FPU_EMU_EVCNT_DECL(fnmsub);
137FPU_EMU_EVCNT_DECL(fnmadd);
138
139/* FPSR exception masks */
140#define FPSR_EX_MSK	(FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX|		\
141			FPSCR_XX|FPSCR_VXSNAN|FPSCR_VXISI|FPSCR_VXIDI|	\
142			FPSCR_VXZDZ|FPSCR_VXIMZ|FPSCR_VXVC|FPSCR_VXSOFT|\
143			FPSCR_VXSQRT|FPSCR_VXCVI)
144#define	FPSR_EX		(FPSCR_VE|FPSCR_OE|FPSCR_UE|FPSCR_ZE|FPSCR_XE)
145#define	FPSR_EXOP	(FPSR_EX_MSK&(~FPSR_EX))
146
147int fpe_debug = 0;
148
149#ifdef DEBUG
150vm_offset_t opc_disasm(vm_offset_t, int);
151
152/*
153 * Dump a `fpn' structure.
154 */
155void
156fpu_dumpfpn(struct fpn *fp)
157{
158	static const char *class[] = {
159		"SNAN", "QNAN", "ZERO", "NUM", "INF"
160	};
161
162	printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2],
163		fp->fp_sign ? '-' : ' ',
164		fp->fp_mant[0],	fp->fp_mant[1],
165		fp->fp_mant[2], fp->fp_mant[3],
166		fp->fp_exp);
167}
168#endif
169
170/*
171 * fpu_execute returns the following error numbers (0 = no error):
172 */
173#define	FPE		1	/* take a floating point exception */
174#define	NOTFPU		2	/* not an FPU instruction */
175#define	FAULT		3
176
177/*
178 * Emulate a floating-point instruction.
179 * Return zero for success, else signal number.
180 * (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
181 */
182int
183fpu_emulate(struct trapframe *frame, struct fpu *fpf)
184{
185	union instr insn;
186	struct fpemu fe;
187	int sig;
188
189	/* initialize insn.is_datasize to tell it is *not* initialized */
190	fe.fe_fpstate = fpf;
191	fe.fe_cx = 0;
192
193	/* always set this (to avoid a warning) */
194
195	if (copyin((void *) (frame->srr0), &insn.i_int, sizeof (insn.i_int))) {
196#ifdef DEBUG
197		printf("fpu_emulate: fault reading opcode\n");
198#endif
199		return SIGSEGV;
200	}
201
202	DPRINTF(FPE_EX, ("fpu_emulate: emulating insn %x at %p\n",
203	    insn.i_int, (void *)frame->srr0));
204
205	if ((insn.i_any.i_opcd == OPC_TWI) ||
206	    ((insn.i_any.i_opcd == OPC_integer_31) &&
207	    (insn.i_x.i_xo == OPC31_TW))) {
208		/* Check for the two trap insns. */
209		DPRINTF(FPE_EX, ("fpu_emulate: SIGTRAP\n"));
210		return (SIGTRAP);
211	}
212	sig = 0;
213	switch (fpu_execute(frame, &fe, &insn)) {
214	case 0:
215		DPRINTF(FPE_EX, ("fpu_emulate: success\n"));
216		frame->srr0 += 4;
217		break;
218
219	case FPE:
220		DPRINTF(FPE_EX, ("fpu_emulate: SIGFPE\n"));
221		sig = SIGFPE;
222		break;
223
224	case FAULT:
225		DPRINTF(FPE_EX, ("fpu_emulate: SIGSEGV\n"));
226		sig = SIGSEGV;
227		break;
228
229	case NOTFPU:
230	default:
231		DPRINTF(FPE_EX, ("fpu_emulate: SIGILL\n"));
232#ifdef DEBUG
233		if (fpe_debug & FPE_EX) {
234			printf("fpu_emulate:  illegal insn %x at %p:",
235			insn.i_int, (void *) (frame->srr0));
236			opc_disasm(frame->srr0, insn.i_int);
237		}
238#endif
239		sig = SIGILL;
240#ifdef DEBUG
241		if (fpe_debug & FPE_EX)
242			kdb_enter(KDB_WHY_UNSET, "illegal instruction");
243#endif
244		break;
245	}
246
247	return (sig);
248}
249
250/*
251 * Execute an FPU instruction (one that runs entirely in the FPU; not
252 * FBfcc or STF, for instance).  On return, fe->fe_fs->fs_fsr will be
253 * modified to reflect the setting the hardware would have left.
254 *
255 * Note that we do not catch all illegal opcodes, so you can, for instance,
256 * multiply two integers this way.
257 */
258int
259fpu_execute(struct trapframe *tf, struct fpemu *fe, union instr *insn)
260{
261	struct fpn *fp;
262	union instr instr = *insn;
263	int *a;
264	vm_offset_t addr;
265	int ra, rb, rc, rt, type, mask, fsr, cx, bf, setcr;
266	unsigned int cond;
267	struct fpu *fs;
268
269	/* Setup work. */
270	fp = NULL;
271	fs = fe->fe_fpstate;
272	fe->fe_fpscr = ((int *)&fs->fpscr)[1];
273
274	/*
275	 * On PowerPC all floating point values are stored in registers
276	 * as doubles, even when used for single precision operations.
277	 */
278	type = FTYPE_DBL;
279	cond = instr.i_any.i_rc;
280	setcr = 0;
281	bf = 0;	/* XXX gcc */
282
283#if defined(DDB) && defined(DEBUG)
284	if (fpe_debug & FPE_EX) {
285		vm_offset_t loc = tf->srr0;
286
287		printf("Trying to emulate: %p ", (void *)loc);
288		opc_disasm(loc, instr.i_int);
289	}
290#endif
291
292	/*
293	 * `Decode' and execute instruction.
294	 */
295
296	if ((instr.i_any.i_opcd >= OPC_LFS && instr.i_any.i_opcd <= OPC_STFDU) ||
297	    instr.i_any.i_opcd == OPC_integer_31) {
298		/*
299		 * Handle load/store insns:
300		 *
301		 * Convert to/from single if needed, calculate addr,
302		 * and update index reg if needed.
303		 */
304		double buf;
305		size_t size = sizeof(float);
306		int store, update;
307
308		cond = 0; /* ld/st never set condition codes */
309
310		if (instr.i_any.i_opcd == OPC_integer_31) {
311			if (instr.i_x.i_xo == OPC31_STFIWX) {
312				FPU_EMU_EVCNT_INCR(stfiwx);
313
314				/* Store as integer */
315				ra = instr.i_x.i_ra;
316				rb = instr.i_x.i_rb;
317				DPRINTF(FPE_INSN,
318					("reg %d has %jx reg %d has %jx\n",
319					ra, (uintmax_t)tf->fixreg[ra], rb,
320					(uintmax_t)tf->fixreg[rb]));
321
322				addr = tf->fixreg[rb];
323				if (ra != 0)
324					addr += tf->fixreg[ra];
325				rt = instr.i_x.i_rt;
326				a = (int *)&fs->fpr[rt].fpr;
327				DPRINTF(FPE_INSN,
328					("fpu_execute: Store INT %x at %p\n",
329						a[1], (void *)addr));
330				if (copyout(&a[1], (void *)addr, sizeof(int)))
331					return (FAULT);
332				return (0);
333			}
334
335			if ((instr.i_x.i_xo & OPC31_FPMASK) != OPC31_FPOP)
336				/* Not an indexed FP load/store op */
337				return (NOTFPU);
338
339			store = (instr.i_x.i_xo & 0x80);
340			if (instr.i_x.i_xo & 0x40)
341				size = sizeof(double);
342			else
343				type = FTYPE_SNG;
344			update = (instr.i_x.i_xo & 0x20);
345
346			/* calculate EA of load/store */
347			ra = instr.i_x.i_ra;
348			rb = instr.i_x.i_rb;
349			DPRINTF(FPE_INSN, ("reg %d has %jx reg %d has %jx\n",
350				ra, (uintmax_t)tf->fixreg[ra], rb,
351				(uintmax_t)tf->fixreg[rb]));
352			addr = tf->fixreg[rb];
353			if (ra != 0)
354				addr += tf->fixreg[ra];
355			rt = instr.i_x.i_rt;
356		} else {
357			store = instr.i_d.i_opcd & 0x4;
358			if (instr.i_d.i_opcd & 0x2)
359				size = sizeof(double);
360			else
361				type = FTYPE_SNG;
362			update = instr.i_d.i_opcd & 0x1;
363
364			/* calculate EA of load/store */
365			ra = instr.i_d.i_ra;
366			addr = instr.i_d.i_d;
367			DPRINTF(FPE_INSN, ("reg %d has %jx displ %jx\n",
368				ra, (uintmax_t)tf->fixreg[ra],
369				(uintmax_t)addr));
370			if (ra != 0)
371				addr += tf->fixreg[ra];
372			rt = instr.i_d.i_rt;
373		}
374
375		if (update && ra == 0)
376			return (NOTFPU);
377
378		if (store) {
379			/* Store */
380			FPU_EMU_EVCNT_INCR(fpstore);
381			if (type != FTYPE_DBL) {
382				DPRINTF(FPE_INSN,
383					("fpu_execute: Store SNG at %p\n",
384						(void *)addr));
385				fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL, rt);
386				fpu_implode(fe, fp, type, (void *)&buf);
387				if (copyout(&buf, (void *)addr, size))
388					return (FAULT);
389			} else {
390				DPRINTF(FPE_INSN,
391					("fpu_execute: Store DBL at %p\n",
392						(void *)addr));
393				if (copyout(&fs->fpr[rt].fpr, (void *)addr,
394				    size))
395					return (FAULT);
396			}
397		} else {
398			/* Load */
399			FPU_EMU_EVCNT_INCR(fpload);
400			DPRINTF(FPE_INSN, ("fpu_execute: Load from %p\n",
401				(void *)addr));
402			if (copyin((const void *)addr, &fs->fpr[rt].fpr,
403			    size))
404				return (FAULT);
405			if (type != FTYPE_DBL) {
406				fpu_explode(fe, fp = &fe->fe_f1, type, rt);
407				fpu_implode(fe, fp, FTYPE_DBL,
408					(u_int *)&fs->fpr[rt].fpr);
409			}
410		}
411		if (update)
412			tf->fixreg[ra] = addr;
413		/* Complete. */
414		return (0);
415#ifdef notyet
416	} else if (instr.i_any.i_opcd == OPC_load_st_62) {
417		/* These are 64-bit extensions */
418		return (NOTFPU);
419#endif
420	} else if (instr.i_any.i_opcd == OPC_sp_fp_59 ||
421		instr.i_any.i_opcd == OPC_dp_fp_63) {
422		if (instr.i_any.i_opcd == OPC_dp_fp_63 &&
423		    !(instr.i_a.i_xo & OPC63M_MASK)) {
424			/* Format X */
425			rt = instr.i_x.i_rt;
426			ra = instr.i_x.i_ra;
427			rb = instr.i_x.i_rb;
428
429			/* One of the special opcodes.... */
430			switch (instr.i_x.i_xo) {
431			case	OPC63_FCMPU:
432				FPU_EMU_EVCNT_INCR(fcmpu);
433				DPRINTF(FPE_INSN, ("fpu_execute: FCMPU\n"));
434				rt >>= 2;
435				fpu_explode(fe, &fe->fe_f1, type, ra);
436				fpu_explode(fe, &fe->fe_f2, type, rb);
437				fpu_compare(fe, 0);
438				/* Make sure we do the condition regs. */
439				cond = 0;
440				/* N.B.: i_rs is already left shifted by two. */
441				bf = instr.i_x.i_rs & 0xfc;
442				setcr = 1;
443				break;
444
445			case	OPC63_FRSP:
446				/*
447				 * Convert to single:
448				 *
449				 * PowerPC uses this to round a double
450				 * precision value to single precision,
451				 * but values in registers are always
452				 * stored in double precision format.
453				 */
454				FPU_EMU_EVCNT_INCR(frsp);
455				DPRINTF(FPE_INSN, ("fpu_execute: FRSP\n"));
456				fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL, rb);
457				fpu_implode(fe, fp, FTYPE_SNG,
458					(u_int *)&fs->fpr[rt].fpr);
459				fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt);
460				type = FTYPE_DBL;
461				break;
462			case	OPC63_FCTIW:
463			case	OPC63_FCTIWZ:
464				FPU_EMU_EVCNT_INCR(fctiw);
465				DPRINTF(FPE_INSN, ("fpu_execute: FCTIW\n"));
466				fpu_explode(fe, fp = &fe->fe_f1, type, rb);
467				type = FTYPE_INT;
468				break;
469			case	OPC63_FCMPO:
470				FPU_EMU_EVCNT_INCR(fcmpo);
471				DPRINTF(FPE_INSN, ("fpu_execute: FCMPO\n"));
472				rt >>= 2;
473				fpu_explode(fe, &fe->fe_f1, type, ra);
474				fpu_explode(fe, &fe->fe_f2, type, rb);
475				fpu_compare(fe, 1);
476				/* Make sure we do the condition regs. */
477				cond = 0;
478				/* N.B.: i_rs is already left shifted by two. */
479				bf = instr.i_x.i_rs & 0xfc;
480				setcr = 1;
481				break;
482			case	OPC63_MTFSB1:
483				FPU_EMU_EVCNT_INCR(mtfsb1);
484				DPRINTF(FPE_INSN, ("fpu_execute: MTFSB1\n"));
485				fe->fe_fpscr |=
486					(~(FPSCR_VX|FPSR_EX) & (1<<(31-rt)));
487				break;
488			case	OPC63_FNEG:
489				FPU_EMU_EVCNT_INCR(fnegabs);
490				DPRINTF(FPE_INSN, ("fpu_execute: FNEGABS\n"));
491				memcpy(&fs->fpr[rt].fpr, &fs->fpr[rb].fpr,
492					sizeof(double));
493				a = (int *)&fs->fpr[rt].fpr;
494				*a ^= (1U << 31);
495				break;
496			case	OPC63_MCRFS:
497				FPU_EMU_EVCNT_INCR(mcrfs);
498				DPRINTF(FPE_INSN, ("fpu_execute: MCRFS\n"));
499				cond = 0;
500				rt &= 0x1c;
501				ra &= 0x1c;
502				/* Extract the bits we want */
503				mask = (fe->fe_fpscr >> (28 - ra)) & 0xf;
504				/* Clear the bits we copied. */
505				fe->fe_cx =
506					(FPSR_EX_MSK | (0xf << (28 - ra)));
507				fe->fe_fpscr &= fe->fe_cx;
508				/* Now shove them in the right part of cr */
509				tf->cr &= ~(0xf << (28 - rt));
510				tf->cr |= (mask << (28 - rt));
511				break;
512			case	OPC63_MTFSB0:
513				FPU_EMU_EVCNT_INCR(mtfsb0);
514				DPRINTF(FPE_INSN, ("fpu_execute: MTFSB0\n"));
515				fe->fe_fpscr &=
516					((FPSCR_VX|FPSR_EX) & ~(1<<(31-rt)));
517				break;
518			case	OPC63_FMR:
519				FPU_EMU_EVCNT_INCR(fmr);
520				DPRINTF(FPE_INSN, ("fpu_execute: FMR\n"));
521				memcpy(&fs->fpr[rt].fpr, &fs->fpr[rb].fpr,
522					sizeof(double));
523				break;
524			case	OPC63_MTFSFI:
525				FPU_EMU_EVCNT_INCR(mtfsfi);
526				DPRINTF(FPE_INSN, ("fpu_execute: MTFSFI\n"));
527				rb >>= 1;
528				rt &= 0x1c; /* Already left-shifted 4 */
529				fe->fe_cx = rb << (28 - rt);
530				mask = 0xf<<(28 - rt);
531				fe->fe_fpscr = (fe->fe_fpscr & ~mask) |
532					fe->fe_cx;
533/* XXX weird stuff about OX, FX, FEX, and VX should be handled */
534				break;
535			case	OPC63_FNABS:
536				FPU_EMU_EVCNT_INCR(fnabs);
537				DPRINTF(FPE_INSN, ("fpu_execute: FABS\n"));
538				memcpy(&fs->fpr[rt].fpr, &fs->fpr[rb].fpr,
539					sizeof(double));
540				a = (int *)&fs->fpr[rt].fpr;
541				*a |= (1U << 31);
542				break;
543			case	OPC63_FABS:
544				FPU_EMU_EVCNT_INCR(fabs);
545				DPRINTF(FPE_INSN, ("fpu_execute: FABS\n"));
546				memcpy(&fs->fpr[rt].fpr, &fs->fpr[rb].fpr,
547					sizeof(double));
548				a = (int *)&fs->fpr[rt].fpr;
549				*a &= ~(1U << 31);
550				break;
551			case	OPC63_MFFS:
552				FPU_EMU_EVCNT_INCR(mffs);
553				DPRINTF(FPE_INSN, ("fpu_execute: MFFS\n"));
554				memcpy(&fs->fpr[rt].fpr, &fs->fpscr,
555					sizeof(fs->fpscr));
556				break;
557			case	OPC63_MTFSF:
558				FPU_EMU_EVCNT_INCR(mtfsf);
559				DPRINTF(FPE_INSN, ("fpu_execute: MTFSF\n"));
560				if ((rt = instr.i_xfl.i_flm) == -1)
561					mask = -1;
562				else {
563					mask = 0;
564					/* Convert 1 bit -> 4 bits */
565					for (ra = 0; ra < 8; ra ++)
566						if (rt & (1<<ra))
567							mask |= (0xf<<(4*ra));
568				}
569				a = (int *)&fs->fpr[rt].fpr;
570				fe->fe_cx = mask & a[1];
571				fe->fe_fpscr = (fe->fe_fpscr&~mask) |
572					(fe->fe_cx);
573/* XXX weird stuff about OX, FX, FEX, and VX should be handled */
574				break;
575			case	OPC63_FCTID:
576			case	OPC63_FCTIDZ:
577				FPU_EMU_EVCNT_INCR(fctid);
578				DPRINTF(FPE_INSN, ("fpu_execute: FCTID\n"));
579				fpu_explode(fe, fp = &fe->fe_f1, type, rb);
580				type = FTYPE_LNG;
581				break;
582			case	OPC63_FCFID:
583				FPU_EMU_EVCNT_INCR(fcfid);
584				DPRINTF(FPE_INSN, ("fpu_execute: FCFID\n"));
585				type = FTYPE_LNG;
586				fpu_explode(fe, fp = &fe->fe_f1, type, rb);
587				type = FTYPE_DBL;
588				break;
589			default:
590				return (NOTFPU);
591				break;
592			}
593		} else {
594			/* Format A */
595			rt = instr.i_a.i_frt;
596			ra = instr.i_a.i_fra;
597			rb = instr.i_a.i_frb;
598			rc = instr.i_a.i_frc;
599
600			/*
601			 * All arithmetic operations work on registers, which
602			 * are stored as doubles.
603			 */
604			type = FTYPE_DBL;
605			switch ((unsigned int)instr.i_a.i_xo) {
606			case	OPC59_FDIVS:
607				FPU_EMU_EVCNT_INCR(fdiv);
608				DPRINTF(FPE_INSN, ("fpu_execute: FDIV\n"));
609				fpu_explode(fe, &fe->fe_f1, type, ra);
610				fpu_explode(fe, &fe->fe_f2, type, rb);
611				fp = fpu_div(fe);
612				break;
613			case	OPC59_FSUBS:
614				FPU_EMU_EVCNT_INCR(fsub);
615				DPRINTF(FPE_INSN, ("fpu_execute: FSUB\n"));
616				fpu_explode(fe, &fe->fe_f1, type, ra);
617				fpu_explode(fe, &fe->fe_f2, type, rb);
618				fp = fpu_sub(fe);
619				break;
620			case	OPC59_FADDS:
621				FPU_EMU_EVCNT_INCR(fadd);
622				DPRINTF(FPE_INSN, ("fpu_execute: FADD\n"));
623				fpu_explode(fe, &fe->fe_f1, type, ra);
624				fpu_explode(fe, &fe->fe_f2, type, rb);
625				fp = fpu_add(fe);
626				break;
627			case	OPC59_FSQRTS:
628				FPU_EMU_EVCNT_INCR(fsqrt);
629				DPRINTF(FPE_INSN, ("fpu_execute: FSQRT\n"));
630				fpu_explode(fe, &fe->fe_f1, type, rb);
631				fp = fpu_sqrt(fe);
632				break;
633			case	OPC63M_FSEL:
634				FPU_EMU_EVCNT_INCR(fsel);
635				DPRINTF(FPE_INSN, ("fpu_execute: FSEL\n"));
636				a = (int *)&fe->fe_fpstate->fpr[ra].fpr;
637				if ((*a & 0x80000000) && (*a & 0x7fffffff))
638					/* fra < 0 */
639					rc = rb;
640				DPRINTF(FPE_INSN, ("f%d => f%d\n", rc, rt));
641				memcpy(&fs->fpr[rt].fpr, &fs->fpr[rc].fpr,
642					sizeof(double));
643				break;
644			case	OPC59_FRES:
645				FPU_EMU_EVCNT_INCR(fpres);
646				DPRINTF(FPE_INSN, ("fpu_execute: FPRES\n"));
647				fpu_explode(fe, &fe->fe_f1, type, rb);
648				fp = fpu_sqrt(fe);
649				/* now we've gotta overwrite the dest reg */
650				*((int *)&fe->fe_fpstate->fpr[rt].fpr) = 1;
651				fpu_explode(fe, &fe->fe_f1, FTYPE_INT, rt);
652				fpu_div(fe);
653				break;
654			case	OPC59_FMULS:
655				FPU_EMU_EVCNT_INCR(fmul);
656				DPRINTF(FPE_INSN, ("fpu_execute: FMUL\n"));
657				fpu_explode(fe, &fe->fe_f1, type, ra);
658				fpu_explode(fe, &fe->fe_f2, type, rc);
659				fp = fpu_mul(fe);
660				break;
661			case	OPC63M_FRSQRTE:
662				/* Reciprocal sqrt() estimate */
663				FPU_EMU_EVCNT_INCR(frsqrte);
664				DPRINTF(FPE_INSN, ("fpu_execute: FRSQRTE\n"));
665				fpu_explode(fe, &fe->fe_f1, type, rb);
666				fp = fpu_sqrt(fe);
667				fe->fe_f2 = *fp;
668				/* now we've gotta overwrite the dest reg */
669				*((int *)&fe->fe_fpstate->fpr[rt].fpr) = 1;
670				fpu_explode(fe, &fe->fe_f1, FTYPE_INT, rt);
671				fpu_div(fe);
672				break;
673			case	OPC59_FMSUBS:
674				FPU_EMU_EVCNT_INCR(fmulsub);
675				DPRINTF(FPE_INSN, ("fpu_execute: FMULSUB\n"));
676				fpu_explode(fe, &fe->fe_f1, type, ra);
677				fpu_explode(fe, &fe->fe_f2, type, rc);
678				fp = fpu_mul(fe);
679				fe->fe_f1 = *fp;
680				fpu_explode(fe, &fe->fe_f2, type, rb);
681				fp = fpu_sub(fe);
682				break;
683			case	OPC59_FMADDS:
684				FPU_EMU_EVCNT_INCR(fmuladd);
685				DPRINTF(FPE_INSN, ("fpu_execute: FMULADD\n"));
686				fpu_explode(fe, &fe->fe_f1, type, ra);
687				fpu_explode(fe, &fe->fe_f2, type, rc);
688				fp = fpu_mul(fe);
689				fe->fe_f1 = *fp;
690				fpu_explode(fe, &fe->fe_f2, type, rb);
691				fp = fpu_add(fe);
692				break;
693			case	OPC59_FNMSUBS:
694				FPU_EMU_EVCNT_INCR(fnmsub);
695				DPRINTF(FPE_INSN, ("fpu_execute: FNMSUB\n"));
696				fpu_explode(fe, &fe->fe_f1, type, ra);
697				fpu_explode(fe, &fe->fe_f2, type, rc);
698				fp = fpu_mul(fe);
699				fe->fe_f1 = *fp;
700				fpu_explode(fe, &fe->fe_f2, type, rb);
701				fp = fpu_sub(fe);
702				/* Negate */
703				fp->fp_sign ^= 1;
704				break;
705			case	OPC59_FNMADDS:
706				FPU_EMU_EVCNT_INCR(fnmadd);
707				DPRINTF(FPE_INSN, ("fpu_execute: FNMADD\n"));
708				fpu_explode(fe, &fe->fe_f1, type, ra);
709				fpu_explode(fe, &fe->fe_f2, type, rc);
710				fp = fpu_mul(fe);
711				fe->fe_f1 = *fp;
712				fpu_explode(fe, &fe->fe_f2, type, rb);
713				fp = fpu_add(fe);
714				/* Negate */
715				fp->fp_sign ^= 1;
716				break;
717			default:
718				return (NOTFPU);
719				break;
720			}
721
722			/* If the instruction was single precision, round */
723			if (!(instr.i_any.i_opcd & 0x4)) {
724				fpu_implode(fe, fp, FTYPE_SNG,
725					(u_int *)&fs->fpr[rt].fpr);
726				fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt);
727			}
728		}
729	} else {
730		return (NOTFPU);
731	}
732
733	/*
734	 * ALU operation is complete.  Collapse the result and then check
735	 * for exceptions.  If we got any, and they are enabled, do not
736	 * alter the destination register, just stop with an exception.
737	 * Otherwise set new current exceptions and accrue.
738	 */
739	if (fp)
740		fpu_implode(fe, fp, type, (u_int *)&fs->fpr[rt].fpr);
741	cx = fe->fe_cx;
742	fsr = fe->fe_fpscr;
743	if (cx != 0) {
744		fsr &= ~FPSCR_FX;
745		if ((cx^fsr)&FPSR_EX_MSK)
746			fsr |= FPSCR_FX;
747		mask = fsr & FPSR_EX;
748		mask <<= (25-3);
749		if (cx & mask)
750			fsr |= FPSCR_FEX;
751		if (cx & FPSCR_FPRF) {
752			/* Need to replace CC */
753			fsr &= ~FPSCR_FPRF;
754		}
755		if (cx & (FPSR_EXOP))
756			fsr |= FPSCR_VX;
757		fsr |= cx;
758		DPRINTF(FPE_INSN, ("fpu_execute: cx %x, fsr %x\n", cx, fsr));
759	}
760
761	if (cond) {
762		cond = fsr & 0xf0000000;
763		/* Isolate condition codes */
764		cond >>= 28;
765		/* Move fpu condition codes to cr[1] */
766		tf->cr &= (0x0f000000);
767		tf->cr |= (cond<<24);
768		DPRINTF(FPE_INSN, ("fpu_execute: cr[1] <= %x\n", cond));
769	}
770
771	if (setcr) {
772		cond = fsr & FPSCR_FPCC;
773		/* Isolate condition codes */
774		cond <<= 16;
775		/* Move fpu condition codes to cr[1] */
776		tf->cr &= ~(0xf0000000>>bf);
777		tf->cr |= (cond>>bf);
778		DPRINTF(FPE_INSN, ("fpu_execute: cr[%d] (cr=%jx) <= %x\n",
779			bf/4, (uintmax_t)tf->cr, cond));
780	}
781
782	((int *)&fs->fpscr)[1] = fsr;
783	if (fsr & FPSCR_FEX)
784		return(FPE);
785	return (0);	/* success */
786}
787