xref: /onnv-gate/usr/src/uts/sparc/fpu/fpu_simulator.c (revision 10271:7c80b70bb8de)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51772Sjl139090  * Common Development and Distribution License (the "License").
61772Sjl139090  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
228829SSree.Vemuri@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /* Main procedures for sparc FPU simulator. */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h>
290Sstevel@tonic-gate #include <sys/fpu/globals.h>
300Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
310Sstevel@tonic-gate #include <sys/proc.h>
320Sstevel@tonic-gate #include <sys/signal.h>
330Sstevel@tonic-gate #include <sys/siginfo.h>
340Sstevel@tonic-gate #include <sys/thread.h>
350Sstevel@tonic-gate #include <sys/cpuvar.h>
360Sstevel@tonic-gate #include <sys/cmn_err.h>
370Sstevel@tonic-gate #include <sys/atomic.h>
380Sstevel@tonic-gate #include <sys/privregs.h>
390Sstevel@tonic-gate #include <sys/vis_simulator.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	FPUINFO_KSTAT(opcode)	{					\
420Sstevel@tonic-gate 	extern void __dtrace_probe___fpuinfo_##opcode(uint64_t *);	\
430Sstevel@tonic-gate 	uint64_t *stataddr = &fpuinfo.opcode.value.ui64;		\
440Sstevel@tonic-gate 	__dtrace_probe___fpuinfo_##opcode(stataddr);			\
450Sstevel@tonic-gate 	atomic_add_64(&fpuinfo.opcode.value.ui64, 1);			\
460Sstevel@tonic-gate }
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	FPUINFO_KSTAT_PREC(prec, kstat_s, kstat_d, kstat_q)		\
490Sstevel@tonic-gate 	if (prec < 2) {							\
500Sstevel@tonic-gate 		FPUINFO_KSTAT(kstat_s);					\
510Sstevel@tonic-gate 	} else if (prec == 2) {						\
520Sstevel@tonic-gate 		FPUINFO_KSTAT(kstat_d);					\
530Sstevel@tonic-gate 	} else {							\
540Sstevel@tonic-gate 		FPUINFO_KSTAT(kstat_q);					\
550Sstevel@tonic-gate 	}
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * FPU simulator global kstat data
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate struct fpuinfo_kstat fpuinfo = {
610Sstevel@tonic-gate 	{ "fpu_sim_fmovs",		KSTAT_DATA_UINT64},
620Sstevel@tonic-gate 	{ "fpu_sim_fmovd",		KSTAT_DATA_UINT64},
630Sstevel@tonic-gate 	{ "fpu_sim_fmovq",		KSTAT_DATA_UINT64},
640Sstevel@tonic-gate 	{ "fpu_sim_fnegs",		KSTAT_DATA_UINT64},
650Sstevel@tonic-gate 	{ "fpu_sim_fnegd",		KSTAT_DATA_UINT64},
660Sstevel@tonic-gate 	{ "fpu_sim_fnegq",		KSTAT_DATA_UINT64},
670Sstevel@tonic-gate 	{ "fpu_sim_fabss",		KSTAT_DATA_UINT64},
680Sstevel@tonic-gate 	{ "fpu_sim_fabsd",		KSTAT_DATA_UINT64},
690Sstevel@tonic-gate 	{ "fpu_sim_fabsq",		KSTAT_DATA_UINT64},
700Sstevel@tonic-gate 	{ "fpu_sim_fsqrts",		KSTAT_DATA_UINT64},
710Sstevel@tonic-gate 	{ "fpu_sim_fsqrtd",		KSTAT_DATA_UINT64},
720Sstevel@tonic-gate 	{ "fpu_sim_fsqrtq",		KSTAT_DATA_UINT64},
730Sstevel@tonic-gate 	{ "fpu_sim_fadds",		KSTAT_DATA_UINT64},
740Sstevel@tonic-gate 	{ "fpu_sim_faddd",		KSTAT_DATA_UINT64},
750Sstevel@tonic-gate 	{ "fpu_sim_faddq",		KSTAT_DATA_UINT64},
760Sstevel@tonic-gate 	{ "fpu_sim_fsubs",		KSTAT_DATA_UINT64},
770Sstevel@tonic-gate 	{ "fpu_sim_fsubd",		KSTAT_DATA_UINT64},
780Sstevel@tonic-gate 	{ "fpu_sim_fsubq",		KSTAT_DATA_UINT64},
790Sstevel@tonic-gate 	{ "fpu_sim_fmuls",		KSTAT_DATA_UINT64},
800Sstevel@tonic-gate 	{ "fpu_sim_fmuld",		KSTAT_DATA_UINT64},
810Sstevel@tonic-gate 	{ "fpu_sim_fmulq",		KSTAT_DATA_UINT64},
820Sstevel@tonic-gate 	{ "fpu_sim_fdivs",		KSTAT_DATA_UINT64},
830Sstevel@tonic-gate 	{ "fpu_sim_fdivd",		KSTAT_DATA_UINT64},
840Sstevel@tonic-gate 	{ "fpu_sim_fdivq",		KSTAT_DATA_UINT64},
850Sstevel@tonic-gate 	{ "fpu_sim_fcmps",		KSTAT_DATA_UINT64},
860Sstevel@tonic-gate 	{ "fpu_sim_fcmpd",		KSTAT_DATA_UINT64},
870Sstevel@tonic-gate 	{ "fpu_sim_fcmpq",		KSTAT_DATA_UINT64},
880Sstevel@tonic-gate 	{ "fpu_sim_fcmpes",		KSTAT_DATA_UINT64},
890Sstevel@tonic-gate 	{ "fpu_sim_fcmped",		KSTAT_DATA_UINT64},
900Sstevel@tonic-gate 	{ "fpu_sim_fcmpeq",		KSTAT_DATA_UINT64},
910Sstevel@tonic-gate 	{ "fpu_sim_fsmuld",		KSTAT_DATA_UINT64},
920Sstevel@tonic-gate 	{ "fpu_sim_fdmulx",		KSTAT_DATA_UINT64},
930Sstevel@tonic-gate 	{ "fpu_sim_fstox",		KSTAT_DATA_UINT64},
940Sstevel@tonic-gate 	{ "fpu_sim_fdtox",		KSTAT_DATA_UINT64},
950Sstevel@tonic-gate 	{ "fpu_sim_fqtox",		KSTAT_DATA_UINT64},
960Sstevel@tonic-gate 	{ "fpu_sim_fxtos",		KSTAT_DATA_UINT64},
970Sstevel@tonic-gate 	{ "fpu_sim_fxtod",		KSTAT_DATA_UINT64},
980Sstevel@tonic-gate 	{ "fpu_sim_fxtoq",		KSTAT_DATA_UINT64},
990Sstevel@tonic-gate 	{ "fpu_sim_fitos",		KSTAT_DATA_UINT64},
1000Sstevel@tonic-gate 	{ "fpu_sim_fitod",		KSTAT_DATA_UINT64},
1010Sstevel@tonic-gate 	{ "fpu_sim_fitoq",		KSTAT_DATA_UINT64},
1020Sstevel@tonic-gate 	{ "fpu_sim_fstoi",		KSTAT_DATA_UINT64},
1030Sstevel@tonic-gate 	{ "fpu_sim_fdtoi",		KSTAT_DATA_UINT64},
1040Sstevel@tonic-gate 	{ "fpu_sim_fqtoi",		KSTAT_DATA_UINT64},
1050Sstevel@tonic-gate 	{ "fpu_sim_fmovcc",		KSTAT_DATA_UINT64},
1060Sstevel@tonic-gate 	{ "fpu_sim_fmovr",		KSTAT_DATA_UINT64},
1071772Sjl139090 	{ "fpu_sim_fmadds",		KSTAT_DATA_UINT64},
1081772Sjl139090 	{ "fpu_sim_fmaddd",		KSTAT_DATA_UINT64},
1091772Sjl139090 	{ "fpu_sim_fmsubs",		KSTAT_DATA_UINT64},
1101772Sjl139090 	{ "fpu_sim_fmsubd",		KSTAT_DATA_UINT64},
1111772Sjl139090 	{ "fpu_sim_fnmadds",		KSTAT_DATA_UINT64},
1121772Sjl139090 	{ "fpu_sim_fnmaddd",		KSTAT_DATA_UINT64},
1131772Sjl139090 	{ "fpu_sim_fnmsubs",		KSTAT_DATA_UINT64},
1141772Sjl139090 	{ "fpu_sim_fnmsubd",		KSTAT_DATA_UINT64},
1151772Sjl139090 	{ "fpu_sim_invalid",		KSTAT_DATA_UINT64},
1160Sstevel@tonic-gate };
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate struct visinfo_kstat visinfo = {
1190Sstevel@tonic-gate 	{ "vis_edge8",		KSTAT_DATA_UINT64},
1200Sstevel@tonic-gate 	{ "vis_edge8n",		KSTAT_DATA_UINT64},
1210Sstevel@tonic-gate 	{ "vis_edge8l",		KSTAT_DATA_UINT64},
1220Sstevel@tonic-gate 	{ "vis_edge8ln",	KSTAT_DATA_UINT64},
1230Sstevel@tonic-gate 	{ "vis_edge16",		KSTAT_DATA_UINT64},
1240Sstevel@tonic-gate 	{ "vis_edge16n",	KSTAT_DATA_UINT64},
1250Sstevel@tonic-gate 	{ "vis_edge16l",	KSTAT_DATA_UINT64},
1260Sstevel@tonic-gate 	{ "vis_edge16ln",	KSTAT_DATA_UINT64},
1270Sstevel@tonic-gate 	{ "vis_edge32",		KSTAT_DATA_UINT64},
1280Sstevel@tonic-gate 	{ "vis_edge32n",	KSTAT_DATA_UINT64},
1290Sstevel@tonic-gate 	{ "vis_edge32l",	KSTAT_DATA_UINT64},
1300Sstevel@tonic-gate 	{ "vis_edge32ln",	KSTAT_DATA_UINT64},
1310Sstevel@tonic-gate 	{ "vis_array8",		KSTAT_DATA_UINT64},
1320Sstevel@tonic-gate 	{ "vis_array16",	KSTAT_DATA_UINT64},
1330Sstevel@tonic-gate 	{ "vis_array32",	KSTAT_DATA_UINT64},
1340Sstevel@tonic-gate 	{ "vis_bmask",		KSTAT_DATA_UINT64},
1350Sstevel@tonic-gate 	{ "vis_fcmple16",	KSTAT_DATA_UINT64},
1360Sstevel@tonic-gate 	{ "vis_fcmpne16",	KSTAT_DATA_UINT64},
1370Sstevel@tonic-gate 	{ "vis_fcmpgt16",	KSTAT_DATA_UINT64},
1380Sstevel@tonic-gate 	{ "vis_fcmpeq16",	KSTAT_DATA_UINT64},
1390Sstevel@tonic-gate 	{ "vis_fcmple32",	KSTAT_DATA_UINT64},
1400Sstevel@tonic-gate 	{ "vis_fcmpne32",	KSTAT_DATA_UINT64},
1410Sstevel@tonic-gate 	{ "vis_fcmpgt32",	KSTAT_DATA_UINT64},
1420Sstevel@tonic-gate 	{ "vis_fcmpeq32",	KSTAT_DATA_UINT64},
1430Sstevel@tonic-gate 	{ "vis_fmul8x16",	KSTAT_DATA_UINT64},
1440Sstevel@tonic-gate 	{ "vis_fmul8x16au",	KSTAT_DATA_UINT64},
1450Sstevel@tonic-gate 	{ "vis_fmul8x16al",	KSTAT_DATA_UINT64},
1460Sstevel@tonic-gate 	{ "vis_fmul8sux16",	KSTAT_DATA_UINT64},
1470Sstevel@tonic-gate 	{ "vis_fmul8ulx16",	KSTAT_DATA_UINT64},
1480Sstevel@tonic-gate 	{ "vis_fmuld8sux16",	KSTAT_DATA_UINT64},
1490Sstevel@tonic-gate 	{ "vis_fmuld8ulx16",	KSTAT_DATA_UINT64},
1500Sstevel@tonic-gate 	{ "vis_fpack16",	KSTAT_DATA_UINT64},
1510Sstevel@tonic-gate 	{ "vis_fpack32",	KSTAT_DATA_UINT64},
1520Sstevel@tonic-gate 	{ "vis_fpackfix",	KSTAT_DATA_UINT64},
1530Sstevel@tonic-gate 	{ "vis_fexpand",	KSTAT_DATA_UINT64},
1540Sstevel@tonic-gate 	{ "vis_fpmerge",	KSTAT_DATA_UINT64},
1550Sstevel@tonic-gate 	{ "vis_pdist",		KSTAT_DATA_UINT64},
1568829SSree.Vemuri@Sun.COM 	{ "vis_pdistn",		KSTAT_DATA_UINT64},
1570Sstevel@tonic-gate 	{ "vis_bshuffle",	KSTAT_DATA_UINT64},
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate };
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /* PUBLIC FUNCTIONS */
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate int fp_notp = 1;	/* fp checking not a problem */
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /* ARGSUSED */
1660Sstevel@tonic-gate static enum ftt_type
_fp_fpu_simulator(fp_simd_type * pfpsd,fp_inst_type inst,fsr_type * pfsr,uint64_t gsr)1670Sstevel@tonic-gate _fp_fpu_simulator(
1680Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to fpu simulator data */
1690Sstevel@tonic-gate 	fp_inst_type	inst,	/* FPU instruction to simulate. */
1700Sstevel@tonic-gate 	fsr_type	*pfsr,	/* Pointer to image of FSR to read and write. */
1710Sstevel@tonic-gate 	uint64_t	gsr)	/* Image of GSR to read */
1720Sstevel@tonic-gate {
1730Sstevel@tonic-gate 	unpacked	us1, us2, ud;	/* Unpacked operands and result. */
1740Sstevel@tonic-gate 	uint32_t	nrs1, nrs2, nrd; /* Register number fields. */
1750Sstevel@tonic-gate 	uint32_t	usr, andexcep;
1760Sstevel@tonic-gate 	fsr_type	fsr;
1770Sstevel@tonic-gate 	enum fcc_type	cc;
1780Sstevel@tonic-gate 	uint32_t	nfcc;		/* fcc number field. */
1790Sstevel@tonic-gate 	uint64_t	lusr;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	nrs1 = inst.rs1;
1820Sstevel@tonic-gate 	nrs2 = inst.rs2;
1830Sstevel@tonic-gate 	nrd = inst.rd;
1840Sstevel@tonic-gate 	fsr = *pfsr;
1850Sstevel@tonic-gate 	pfpsd->fp_current_exceptions = 0;	/* Init current exceptions. */
1860Sstevel@tonic-gate 	pfpsd->fp_fsrtem    = fsr.tem;		/* Obtain fsr's tem */
1870Sstevel@tonic-gate 	/*
1880Sstevel@tonic-gate 	 * Obtain rounding direction and precision
1890Sstevel@tonic-gate 	 */
1900Sstevel@tonic-gate 	pfpsd->fp_direction = GSR_IM(gsr) ? GSR_IRND(gsr) : fsr.rnd;
1910Sstevel@tonic-gate 	pfpsd->fp_precision = fsr.rnp;
1921772Sjl139090 
193*10271SJason.Beloro@Sun.COM 	if (inst.op3 == 0x37) { /* IMPDEP2B FMA-fused opcode */
1941772Sjl139090 		fp_fma_inst_type *fma_inst;
1951772Sjl139090 		uint32_t	nrs3;
1961772Sjl139090 		unpacked	us3;
1971772Sjl139090 		unpacked	ust;
1981772Sjl139090 		fma_inst = (fp_fma_inst_type *) &inst;
1991772Sjl139090 		nrs2 = fma_inst->rs2;
2001772Sjl139090 		nrs3 = fma_inst->rs3;
2011772Sjl139090 		switch (fma_inst->var) {
2021772Sjl139090 		case fmadd:
2031772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
2041772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
2051772Sjl139090 			_fp_mul(pfpsd, &us1, &us2, &ust);
2061772Sjl139090 			if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
2071772Sjl139090 				_fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
2081772Sjl139090 				_fp_add(pfpsd, &ust, &us3, &ud);
2091772Sjl139090 				_fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
2101772Sjl139090 			}
2111772Sjl139090 			FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmadds,
2127718SJason.Beloro@Sun.COM 			    fpu_sim_fmaddd, fpu_sim_invalid);
2131772Sjl139090 			break;
2141772Sjl139090 		case fmsub:
2151772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
2161772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
2171772Sjl139090 			_fp_mul(pfpsd, &us1, &us2, &ust);
2181772Sjl139090 			if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
2191772Sjl139090 				_fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
2201772Sjl139090 				_fp_sub(pfpsd, &ust, &us3, &ud);
2211772Sjl139090 				_fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
2221772Sjl139090 			}
2231772Sjl139090 			FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmsubs,
2247718SJason.Beloro@Sun.COM 			    fpu_sim_fmsubd, fpu_sim_invalid);
2251772Sjl139090 			break;
2261772Sjl139090 		case fnmadd:
2271772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
2281772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
2291772Sjl139090 			_fp_mul(pfpsd, &us1, &us2, &ust);
2301772Sjl139090 			if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
2311921Shyw 				_fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
2321921Shyw 				if (ust.fpclass != fp_quiet &&
2331921Shyw 				    ust.fpclass != fp_signaling)
2341921Shyw 					ust.sign ^= 1;
2351921Shyw 				_fp_sub(pfpsd, &ust, &us3, &ud);
2361921Shyw 				_fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
2371772Sjl139090 			}
2381772Sjl139090 			FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmadds,
2397718SJason.Beloro@Sun.COM 			    fpu_sim_fnmaddd, fpu_sim_invalid);
2401772Sjl139090 			break;
2411772Sjl139090 		case fnmsub:
2421772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
2431772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
2441772Sjl139090 			_fp_mul(pfpsd, &us1, &us2, &ust);
2451772Sjl139090 			if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
2461921Shyw 				_fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
2471921Shyw 				if (ust.fpclass != fp_quiet &&
2481921Shyw 				    ust.fpclass != fp_signaling)
2491921Shyw 					ust.sign ^= 1;
2501921Shyw 				_fp_add(pfpsd, &ust, &us3, &ud);
2511921Shyw 				_fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
2521772Sjl139090 			}
2531772Sjl139090 			FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmsubs,
2547718SJason.Beloro@Sun.COM 			    fpu_sim_fnmsubd, fpu_sim_invalid);
2557718SJason.Beloro@Sun.COM 		}
2561772Sjl139090 	} else {
2571772Sjl139090 		nfcc = nrd & 0x3;
2581772Sjl139090 		if (inst.op3 == 0x35) {		/* fpop2 */
2591772Sjl139090 			fsr.cexc = 0;
2601772Sjl139090 			*pfsr = fsr;
2611772Sjl139090 			if ((inst.opcode & 0xf) == 0) {
2621772Sjl139090 				if ((fp_notp) && (inst.prec == 0))
2631772Sjl139090 					return (ftt_unimplemented);
2641772Sjl139090 				FPUINFO_KSTAT(fpu_sim_fmovcc);
2651772Sjl139090 				return (fmovcc(pfpsd, inst, pfsr)); /* fmovcc */
2661772Sjl139090 			} else if ((inst.opcode & 0x7) == 1) {
2671772Sjl139090 				if ((fp_notp) && (inst.prec == 0))
2681772Sjl139090 					return (ftt_unimplemented);
2691772Sjl139090 				FPUINFO_KSTAT(fpu_sim_fmovr);
2701772Sjl139090 				return (fmovr(pfpsd, inst));	/* fmovr */
2710Sstevel@tonic-gate 			}
2720Sstevel@tonic-gate 		}
2731772Sjl139090 		/* ibit not valid for fpop1 instructions */
2741772Sjl139090 		if ((fp_notp) && (inst.ibit != 0))
2751772Sjl139090 			return (ftt_unimplemented);
2761772Sjl139090 		if ((fp_notp) && (inst.prec == 0)) { /* fxto[sdq], fito[sdq] */
2771772Sjl139090 			if ((inst.opcode != flltos) &&
2781772Sjl139090 			    (inst.opcode != flltod) &&
2791772Sjl139090 			    (inst.opcode != flltox) &&
2801772Sjl139090 			    (inst.opcode != fitos) &&
2811772Sjl139090 			    (inst.opcode != fitod) &&
2821772Sjl139090 			    (inst.opcode != fitox)) {
2831772Sjl139090 				return (ftt_unimplemented);
2840Sstevel@tonic-gate 			}
2850Sstevel@tonic-gate 		}
2861772Sjl139090 		switch (inst.opcode) {
2871772Sjl139090 		case fmovs:		/* also covers fmovd, fmovq */
2881772Sjl139090 			if (inst.prec < 2) {	/* fmovs */
2891772Sjl139090 				_fp_unpack_word(pfpsd, &usr, nrs2);
2901772Sjl139090 				_fp_pack_word(pfpsd, &usr, nrd);
2911772Sjl139090 				FPUINFO_KSTAT(fpu_sim_fmovs);
2921772Sjl139090 			} else {		/* fmovd */
2931772Sjl139090 				_fp_unpack_extword(pfpsd, &lusr, nrs2);
2941772Sjl139090 				_fp_pack_extword(pfpsd, &lusr, nrd);
2951772Sjl139090 				if (inst.prec > 2) {		/* fmovq */
2967718SJason.Beloro@Sun.COM 					_fp_unpack_extword(pfpsd, &lusr,
2977718SJason.Beloro@Sun.COM 					    nrs2+2);
2987718SJason.Beloro@Sun.COM 					_fp_pack_extword(pfpsd, &lusr, nrd+2);
2997718SJason.Beloro@Sun.COM 					FPUINFO_KSTAT(fpu_sim_fmovq);
3001772Sjl139090 				} else {
3017718SJason.Beloro@Sun.COM 					FPUINFO_KSTAT(fpu_sim_fmovd);
3021772Sjl139090 				}
3031772Sjl139090 			}
3041772Sjl139090 			break;
3051772Sjl139090 		case fabss:		/* also covers fabsd, fabsq */
3061772Sjl139090 			if (inst.prec < 2) {	/* fabss */
3071772Sjl139090 				_fp_unpack_word(pfpsd, &usr, nrs2);
3081772Sjl139090 				usr &= 0x7fffffff;
3091772Sjl139090 				_fp_pack_word(pfpsd, &usr, nrd);
3101772Sjl139090 				FPUINFO_KSTAT(fpu_sim_fabss);
3111772Sjl139090 			} else {		/* fabsd */
3121772Sjl139090 				_fp_unpack_extword(pfpsd, &lusr, nrs2);
3131772Sjl139090 				lusr &= 0x7fffffffffffffff;
3141772Sjl139090 				_fp_pack_extword(pfpsd, &lusr, nrd);
3151772Sjl139090 				if (inst.prec > 2) {		/* fabsq */
3167718SJason.Beloro@Sun.COM 					_fp_unpack_extword(pfpsd, &lusr,
3177718SJason.Beloro@Sun.COM 					    nrs2+2);
3187718SJason.Beloro@Sun.COM 					_fp_pack_extword(pfpsd, &lusr, nrd+2);
3197718SJason.Beloro@Sun.COM 					FPUINFO_KSTAT(fpu_sim_fabsq);
3201772Sjl139090 				} else {
3217718SJason.Beloro@Sun.COM 					FPUINFO_KSTAT(fpu_sim_fabsd);
3221772Sjl139090 				}
3231772Sjl139090 			}
3241772Sjl139090 			break;
3251772Sjl139090 		case fnegs:		/* also covers fnegd, fnegq */
3261772Sjl139090 			if (inst.prec < 2) {	/* fnegs */
3271772Sjl139090 				_fp_unpack_word(pfpsd, &usr, nrs2);
3281772Sjl139090 				usr ^= 0x80000000;
3291772Sjl139090 				_fp_pack_word(pfpsd, &usr, nrd);
3301772Sjl139090 				FPUINFO_KSTAT(fpu_sim_fnegs);
3311772Sjl139090 			} else {		/* fnegd */
3321772Sjl139090 				_fp_unpack_extword(pfpsd, &lusr, nrs2);
3331772Sjl139090 				lusr ^= 0x8000000000000000;
3341772Sjl139090 				_fp_pack_extword(pfpsd, &lusr, nrd);
3351772Sjl139090 				if (inst.prec > 2) {		/* fnegq */
3367718SJason.Beloro@Sun.COM 					_fp_unpack_extword(pfpsd, &lusr,
3377718SJason.Beloro@Sun.COM 					    nrs2+2);
3387718SJason.Beloro@Sun.COM 					lusr ^= 0x0000000000000000;
3397718SJason.Beloro@Sun.COM 					_fp_pack_extword(pfpsd, &lusr, nrd+2);
3407718SJason.Beloro@Sun.COM 					FPUINFO_KSTAT(fpu_sim_fnegq);
3411772Sjl139090 				} else {
3427718SJason.Beloro@Sun.COM 					FPUINFO_KSTAT(fpu_sim_fnegd);
3431772Sjl139090 				}
3440Sstevel@tonic-gate 			}
3451772Sjl139090 			break;
3461772Sjl139090 		case fadd:
3471772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
3481772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
3491772Sjl139090 			_fp_add(pfpsd, &us1, &us2, &ud);
3501772Sjl139090 			_fp_pack(pfpsd, &ud, nrd, inst.prec);
3511772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fadds,
3521772Sjl139090 			    fpu_sim_faddd, fpu_sim_faddq);
3531772Sjl139090 			break;
3541772Sjl139090 		case fsub:
3551772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
3561772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
3571772Sjl139090 			_fp_sub(pfpsd, &us1, &us2, &ud);
3581772Sjl139090 			_fp_pack(pfpsd, &ud, nrd, inst.prec);
3591772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsubs,
3601772Sjl139090 			    fpu_sim_fsubd, fpu_sim_fsubq);
3611772Sjl139090 			break;
3621772Sjl139090 		case fmul:
3631772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
3641772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
3651772Sjl139090 			_fp_mul(pfpsd, &us1, &us2, &ud);
3661772Sjl139090 			_fp_pack(pfpsd, &ud, nrd, inst.prec);
3671772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fmuls,
3681772Sjl139090 			    fpu_sim_fmuld, fpu_sim_fmulq);
3691772Sjl139090 			break;
3701772Sjl139090 		case fsmuld:
3711772Sjl139090 			if ((fp_notp) && (inst.prec != 1))
3721772Sjl139090 				return (ftt_unimplemented);
3731772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
3741772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
3751772Sjl139090 			_fp_mul(pfpsd, &us1, &us2, &ud);
3761772Sjl139090 			_fp_pack(pfpsd, &ud, nrd,
3777718SJason.Beloro@Sun.COM 			    (enum fp_op_type) ((int)inst.prec+1));
3781772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fsmuld);
3791772Sjl139090 			break;
3801772Sjl139090 		case fdmulx:
3811772Sjl139090 			if ((fp_notp) && (inst.prec != 2))
3821772Sjl139090 				return (ftt_unimplemented);
3831772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
3841772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
3851772Sjl139090 			_fp_mul(pfpsd, &us1, &us2, &ud);
3861772Sjl139090 			_fp_pack(pfpsd, &ud, nrd,
3877718SJason.Beloro@Sun.COM 			    (enum fp_op_type) ((int)inst.prec+1));
3881772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fdmulx);
3891772Sjl139090 			break;
3901772Sjl139090 		case fdiv:
3911772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
3921772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
3931772Sjl139090 			_fp_div(pfpsd, &us1, &us2, &ud);
3941772Sjl139090 			_fp_pack(pfpsd, &ud, nrd, inst.prec);
3951772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fdivs,
3961772Sjl139090 			    fpu_sim_fdivd, fpu_sim_fdivq);
3971772Sjl139090 			break;
3981772Sjl139090 		case fcmp:
3991772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
4001772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
4011772Sjl139090 			cc = _fp_compare(pfpsd, &us1, &us2, 0);
4021772Sjl139090 			if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
4031772Sjl139090 				switch (nfcc) {
4041772Sjl139090 				case fcc_0:
4051772Sjl139090 					fsr.fcc0 = cc;
4061772Sjl139090 					break;
4071772Sjl139090 				case fcc_1:
4081772Sjl139090 					fsr.fcc1 = cc;
4091772Sjl139090 					break;
4101772Sjl139090 				case fcc_2:
4111772Sjl139090 					fsr.fcc2 = cc;
4121772Sjl139090 					break;
4131772Sjl139090 				case fcc_3:
4141772Sjl139090 					fsr.fcc3 = cc;
4151772Sjl139090 					break;
4161772Sjl139090 				}
4171772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmps,
4181772Sjl139090 			    fpu_sim_fcmpd, fpu_sim_fcmpq);
4191772Sjl139090 			break;
4201772Sjl139090 		case fcmpe:
4211772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
4221772Sjl139090 			_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
4231772Sjl139090 			cc = _fp_compare(pfpsd, &us1, &us2, 1);
4241772Sjl139090 			if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
4251772Sjl139090 				switch (nfcc) {
4261772Sjl139090 				case fcc_0:
4271772Sjl139090 					fsr.fcc0 = cc;
4281772Sjl139090 					break;
4291772Sjl139090 				case fcc_1:
4301772Sjl139090 					fsr.fcc1 = cc;
4311772Sjl139090 					break;
4321772Sjl139090 				case fcc_2:
4331772Sjl139090 					fsr.fcc2 = cc;
4341772Sjl139090 					break;
4351772Sjl139090 				case fcc_3:
4361772Sjl139090 					fsr.fcc3 = cc;
4371772Sjl139090 					break;
4381772Sjl139090 				}
4391772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmpes,
4407718SJason.Beloro@Sun.COM 			    fpu_sim_fcmped, fpu_sim_fcmpeq);
4411772Sjl139090 			break;
4421772Sjl139090 		case fsqrt:
4431772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
4441772Sjl139090 			_fp_sqrt(pfpsd, &us1, &ud);
4451772Sjl139090 			_fp_pack(pfpsd, &ud, nrd, inst.prec);
4461772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsqrts,
4471772Sjl139090 			    fpu_sim_fsqrtd, fpu_sim_fsqrtq);
4481772Sjl139090 			break;
4491772Sjl139090 		case ftoi:
4501772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
4511772Sjl139090 			pfpsd->fp_direction = fp_tozero;
4521772Sjl139090 			/* Force rounding toward zero. */
4531772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_int32);
4541772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstoi,
4551772Sjl139090 			    fpu_sim_fdtoi, fpu_sim_fqtoi);
4561772Sjl139090 			break;
4571772Sjl139090 		case ftoll:
4581772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
4591772Sjl139090 			pfpsd->fp_direction = fp_tozero;
4601772Sjl139090 			/* Force rounding toward zero. */
4611772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_int64);
4621772Sjl139090 			FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstox,
4631772Sjl139090 			    fpu_sim_fdtox, fpu_sim_fqtox);
4641772Sjl139090 			break;
4651772Sjl139090 		case flltos:
4661772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
4671772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_single);
4681772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fxtos);
4691772Sjl139090 			break;
4701772Sjl139090 		case flltod:
4711772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
4721772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_double);
4731772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fxtod);
4741772Sjl139090 			break;
4751772Sjl139090 		case flltox:
4761772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
4771772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_extended);
4781772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fxtoq);
4791772Sjl139090 			break;
4801772Sjl139090 		case fitos:
4811772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
4821772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_single);
4831772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fitos);
4841772Sjl139090 			break;
4851772Sjl139090 		case fitod:
4861772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
4871772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_double);
4881772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fitod);
4891772Sjl139090 			break;
4901772Sjl139090 		case fitox:
4911772Sjl139090 			_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
4921772Sjl139090 			_fp_pack(pfpsd, &us1, nrd, fp_op_extended);
4931772Sjl139090 			FPUINFO_KSTAT(fpu_sim_fitoq);
4941772Sjl139090 			break;
4951772Sjl139090 		default:
4961772Sjl139090 			return (ftt_unimplemented);
4971772Sjl139090 		}
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 	fsr.cexc = pfpsd->fp_current_exceptions;
5007718SJason.Beloro@Sun.COM 	andexcep = pfpsd->fp_current_exceptions & fsr.tem;
5017718SJason.Beloro@Sun.COM 	if (andexcep != 0) {	/* Signal an IEEE SIGFPE here. */
5027718SJason.Beloro@Sun.COM 		if (andexcep & (1 << fp_invalid)) {
5037718SJason.Beloro@Sun.COM 			pfpsd->fp_trapcode = FPE_FLTINV;
5047718SJason.Beloro@Sun.COM 			fsr.cexc = FSR_CEXC_NV;
5057718SJason.Beloro@Sun.COM 		} else if (andexcep & (1 << fp_overflow)) {
5067718SJason.Beloro@Sun.COM 			pfpsd->fp_trapcode = FPE_FLTOVF;
5077718SJason.Beloro@Sun.COM 			fsr.cexc = FSR_CEXC_OF;
5087718SJason.Beloro@Sun.COM 		} else if (andexcep & (1 << fp_underflow)) {
5097718SJason.Beloro@Sun.COM 			pfpsd->fp_trapcode = FPE_FLTUND;
5107718SJason.Beloro@Sun.COM 			fsr.cexc = FSR_CEXC_UF;
5117718SJason.Beloro@Sun.COM 		} else if (andexcep & (1 << fp_division)) {
5127718SJason.Beloro@Sun.COM 			pfpsd->fp_trapcode = FPE_FLTDIV;
5137718SJason.Beloro@Sun.COM 			fsr.cexc = FSR_CEXC_DZ;
5147718SJason.Beloro@Sun.COM 		} else if (andexcep & (1 << fp_inexact)) {
5157718SJason.Beloro@Sun.COM 			pfpsd->fp_trapcode = FPE_FLTRES;
5167718SJason.Beloro@Sun.COM 			fsr.cexc = FSR_CEXC_NX;
5177718SJason.Beloro@Sun.COM 		} else {
5187718SJason.Beloro@Sun.COM 			pfpsd->fp_trapcode = 0;
5190Sstevel@tonic-gate 		}
5207718SJason.Beloro@Sun.COM 		*pfsr = fsr;
5217718SJason.Beloro@Sun.COM 		return (ftt_ieee);
5227718SJason.Beloro@Sun.COM 	} else {	/* Just set accrued exception field. */
523*10271SJason.Beloro@Sun.COM 		fsr.aexc |= pfpsd->fp_current_exceptions;
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 	*pfsr = fsr;
5260Sstevel@tonic-gate 	return (ftt_none);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate /*
5300Sstevel@tonic-gate  * fpu_vis_sim simulates fpu and vis instructions;
5310Sstevel@tonic-gate  * It can work with both real and pcb image registers.
5320Sstevel@tonic-gate  */
5330Sstevel@tonic-gate enum ftt_type
fpu_vis_sim(fp_simd_type * pfpsd,fp_inst_type * pinst,struct regs * pregs,fsr_type * pfsr,uint64_t gsr,uint32_t inst)5340Sstevel@tonic-gate fpu_vis_sim(
5350Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to simulator data */
5360Sstevel@tonic-gate 	fp_inst_type	*pinst,	/* Address of FPU instruction to simulate */
5370Sstevel@tonic-gate 	struct regs	*pregs,	/* Pointer to PCB image of registers. */
5380Sstevel@tonic-gate 	fsr_type	*pfsr,	/* Pointer to image of FSR to read and write */
5390Sstevel@tonic-gate 	uint64_t	gsr,	/* Image of GSR to read */
5400Sstevel@tonic-gate 	uint32_t	inst)	/* The FPU instruction to simulate */
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
5430Sstevel@tonic-gate 	union {
5440Sstevel@tonic-gate 		uint32_t	i;
5450Sstevel@tonic-gate 		fp_inst_type	inst;
5460Sstevel@tonic-gate 	} fp;
5470Sstevel@tonic-gate 	kfpu_t *pfp = lwptofpu(lwp);
5480Sstevel@tonic-gate 	enum ftt_type ftt;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	fp.i = inst;
5510Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst;
5520Sstevel@tonic-gate 	if (fpu_exists) {
5530Sstevel@tonic-gate 		pfpsd->fp_current_read_freg = _fp_read_pfreg;
5540Sstevel@tonic-gate 		pfpsd->fp_current_write_freg = _fp_write_pfreg;
5550Sstevel@tonic-gate 		pfpsd->fp_current_read_dreg = _fp_read_pdreg;
5560Sstevel@tonic-gate 		pfpsd->fp_current_write_dreg = _fp_write_pdreg;
5577Sdf157793 		pfpsd->fp_current_read_gsr = _fp_read_pgsr;
5587Sdf157793 		pfpsd->fp_current_write_gsr = _fp_write_pgsr;
5590Sstevel@tonic-gate 	} else {
5600Sstevel@tonic-gate 		pfpsd->fp_current_pfregs = pfp;
5610Sstevel@tonic-gate 		pfpsd->fp_current_read_freg = _fp_read_vfreg;
5620Sstevel@tonic-gate 		pfpsd->fp_current_write_freg = _fp_write_vfreg;
5630Sstevel@tonic-gate 		pfpsd->fp_current_read_dreg = _fp_read_vdreg;
5640Sstevel@tonic-gate 		pfpsd->fp_current_write_dreg = _fp_write_vdreg;
5657Sdf157793 		pfpsd->fp_current_read_gsr = get_gsr;
5667Sdf157793 		pfpsd->fp_current_write_gsr = set_gsr;
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
5700Sstevel@tonic-gate 			ftt = vis_fpu_simulator(pfpsd, fp.inst,
5717718SJason.Beloro@Sun.COM 			    pregs, (ulong_t *)pregs->r_sp, pfp);
5720Sstevel@tonic-gate 			return (ftt);
5730Sstevel@tonic-gate 	} else if ((fp.inst.hibits == 2) &&
5741772Sjl139090 	    ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) ||
575*10271SJason.Beloro@Sun.COM 	    (fp.inst.op3 == 0x37))) {
5760Sstevel@tonic-gate 		ftt =  _fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr);
5770Sstevel@tonic-gate 		if (ftt == ftt_none || ftt == ftt_ieee) {
5780Sstevel@tonic-gate 			pregs->r_pc = pregs->r_npc;
5790Sstevel@tonic-gate 			pregs->r_npc += 4;
5800Sstevel@tonic-gate 		}
5810Sstevel@tonic-gate 		return (ftt);
5820Sstevel@tonic-gate 	} else {
5830Sstevel@tonic-gate 		ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs,
5840Sstevel@tonic-gate 		    (ulong_t *)pregs->r_sp, pfp);
5850Sstevel@tonic-gate 		return (ftt);
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate /*
5900Sstevel@tonic-gate  * fpu_simulator simulates FPU instructions only;
5910Sstevel@tonic-gate  * reads and writes FPU data registers directly.
5920Sstevel@tonic-gate  */
5930Sstevel@tonic-gate enum ftt_type
fpu_simulator(fp_simd_type * pfpsd,fp_inst_type * pinst,fsr_type * pfsr,uint64_t gsr,uint32_t inst)5940Sstevel@tonic-gate fpu_simulator(
5950Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to simulator data */
5960Sstevel@tonic-gate 	fp_inst_type	*pinst,	/* Address of FPU instruction to simulate */
5970Sstevel@tonic-gate 	fsr_type	*pfsr,	/* Pointer to image of FSR to read and write */
5980Sstevel@tonic-gate 	uint64_t	gsr,	/* Image of GSR to read */
5990Sstevel@tonic-gate 	uint32_t	inst)	/* The FPU instruction to simulate */
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate 	union {
6020Sstevel@tonic-gate 		uint32_t	i;
6030Sstevel@tonic-gate 		fp_inst_type	inst;
6040Sstevel@tonic-gate 	} fp;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	fp.i = inst;
6070Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst;
6080Sstevel@tonic-gate 	pfpsd->fp_current_read_freg = _fp_read_pfreg;
6090Sstevel@tonic-gate 	pfpsd->fp_current_write_freg = _fp_write_pfreg;
6100Sstevel@tonic-gate 	pfpsd->fp_current_read_dreg = _fp_read_pdreg;
6110Sstevel@tonic-gate 	pfpsd->fp_current_write_dreg = _fp_write_pdreg;
6127Sdf157793 	pfpsd->fp_current_read_gsr = _fp_read_pgsr;
6137Sdf157793 	pfpsd->fp_current_write_gsr = _fp_write_pgsr;
6140Sstevel@tonic-gate 	return (_fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr));
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /*
6180Sstevel@tonic-gate  * fp_emulator simulates FPU and CPU-FPU instructions; reads and writes FPU
6190Sstevel@tonic-gate  * data registers from image in pfpu.
6200Sstevel@tonic-gate  */
6210Sstevel@tonic-gate enum ftt_type
fp_emulator(fp_simd_type * pfpsd,fp_inst_type * pinst,struct regs * pregs,void * prw,kfpu_t * pfpu)6220Sstevel@tonic-gate fp_emulator(
6230Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to simulator data */
6240Sstevel@tonic-gate 	fp_inst_type	*pinst,	/* Pointer to FPU instruction to simulate. */
6250Sstevel@tonic-gate 	struct regs	*pregs,	/* Pointer to PCB image of registers. */
6260Sstevel@tonic-gate 	void		*prw,	/* Pointer to locals and ins. */
6270Sstevel@tonic-gate 	kfpu_t		*pfpu)	/* Pointer to FPU register block. */
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
6300Sstevel@tonic-gate 	union {
6310Sstevel@tonic-gate 		uint32_t	i;
6320Sstevel@tonic-gate 		fp_inst_type	inst;
6330Sstevel@tonic-gate 	} fp;
6340Sstevel@tonic-gate 	enum ftt_type	ftt;
6350Sstevel@tonic-gate 	uint64_t gsr = get_gsr(pfpu);
6360Sstevel@tonic-gate 	kfpu_t *pfp = lwptofpu(lwp);
6370Sstevel@tonic-gate 	uint64_t	tfsr;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	tfsr = pfpu->fpu_fsr;
6400Sstevel@tonic-gate 	pfpsd->fp_current_pfregs = pfpu;
6410Sstevel@tonic-gate 	pfpsd->fp_current_read_freg = _fp_read_vfreg;
6420Sstevel@tonic-gate 	pfpsd->fp_current_write_freg = _fp_write_vfreg;
6430Sstevel@tonic-gate 	pfpsd->fp_current_read_dreg = _fp_read_vdreg;
6440Sstevel@tonic-gate 	pfpsd->fp_current_write_dreg = _fp_write_vdreg;
6457Sdf157793 	pfpsd->fp_current_read_gsr = get_gsr;
6467Sdf157793 	pfpsd->fp_current_write_gsr = set_gsr;
6470Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */
6480Sstevel@tonic-gate 	ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd);
6490Sstevel@tonic-gate 	if (ftt != ftt_none)
6500Sstevel@tonic-gate 		return (ftt);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	if ((fp.inst.hibits == 2) &&
6531772Sjl139090 	    ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) ||
654*10271SJason.Beloro@Sun.COM 	    (fp.inst.op3 == 0x37))) {
6550Sstevel@tonic-gate 		ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr);
6560Sstevel@tonic-gate 		/* Do not retry emulated instruction. */
6570Sstevel@tonic-gate 		pregs->r_pc = pregs->r_npc;
6580Sstevel@tonic-gate 		pregs->r_npc += 4;
6590Sstevel@tonic-gate 		pfpu->fpu_fsr = tfsr;
6600Sstevel@tonic-gate 		if (ftt != ftt_none) {
6610Sstevel@tonic-gate 			/*
6620Sstevel@tonic-gate 			 * Simulation generated an exception of some kind,
6630Sstevel@tonic-gate 			 * simulate the fp queue for a signal.
6640Sstevel@tonic-gate 			 */
6650Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst;
6660Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i;
6670Sstevel@tonic-gate 			pfpu->fpu_qcnt = 1;
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 	} else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
6700Sstevel@tonic-gate 			ftt = vis_fpu_simulator(pfpsd, fp.inst,
6710Sstevel@tonic-gate 			    pregs, prw, pfp);
6720Sstevel@tonic-gate 	} else
6730Sstevel@tonic-gate 		ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (ftt != ftt_none)
6760Sstevel@tonic-gate 		return (ftt);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	/*
6790Sstevel@tonic-gate 	 * If we are single-stepping, don't emulate any more instructions.
6800Sstevel@tonic-gate 	 */
6810Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
6820Sstevel@tonic-gate 		return (ftt);
6830Sstevel@tonic-gate again:
6840Sstevel@tonic-gate 	/*
6850Sstevel@tonic-gate 	 * now read next instruction and see if it can be emulated
6860Sstevel@tonic-gate 	 */
6870Sstevel@tonic-gate 	pinst = (fp_inst_type *)pregs->r_pc;
6880Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */
6890Sstevel@tonic-gate 	ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd);
6900Sstevel@tonic-gate 	if (ftt != ftt_none)
6910Sstevel@tonic-gate 		return (ftt);
6920Sstevel@tonic-gate 	if ((fp.inst.hibits == 2) &&		/* fpops */
6931772Sjl139090 	    ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) ||
694*10271SJason.Beloro@Sun.COM 	    (fp.inst.op3 == 0x37))) {
6950Sstevel@tonic-gate 		ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr);
6960Sstevel@tonic-gate 		/* Do not retry emulated instruction. */
6970Sstevel@tonic-gate 		pfpu->fpu_fsr = tfsr;
6980Sstevel@tonic-gate 		pregs->r_pc = pregs->r_npc;
6990Sstevel@tonic-gate 		pregs->r_npc += 4;
7000Sstevel@tonic-gate 		if (ftt != ftt_none) {
7010Sstevel@tonic-gate 			/*
7020Sstevel@tonic-gate 			 * Simulation generated an exception of some kind,
7030Sstevel@tonic-gate 			 * simulate the fp queue for a signal.
7040Sstevel@tonic-gate 			 */
7050Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst;
7060Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i;
7070Sstevel@tonic-gate 			pfpu->fpu_qcnt = 1;
7080Sstevel@tonic-gate 		}
7090Sstevel@tonic-gate 	} else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
7100Sstevel@tonic-gate 			ftt = vis_fpu_simulator(pfpsd, fp.inst,
7117718SJason.Beloro@Sun.COM 			    pregs, prw, pfp);
7120Sstevel@tonic-gate 	} else if (
7130Sstevel@tonic-gate 						/* rd %gsr */
7140Sstevel@tonic-gate 	    ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x28) &&
7157718SJason.Beloro@Sun.COM 	    (fp.inst.rs1 == 0x13)) ||
7160Sstevel@tonic-gate 						/* wr %gsr */
7170Sstevel@tonic-gate 	    ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x30) &&
7187718SJason.Beloro@Sun.COM 	    (fp.inst.rd == 0x13)) ||
7190Sstevel@tonic-gate 						/* movcc */
7200Sstevel@tonic-gate 	    ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x2c) &&
7217718SJason.Beloro@Sun.COM 	    (((fp.i>>18) & 0x1) == 0)) ||
7220Sstevel@tonic-gate 						/* fbpcc */
7230Sstevel@tonic-gate 	    ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 5)) ||
7240Sstevel@tonic-gate 						/* fldst */
7250Sstevel@tonic-gate 	    ((fp.inst.hibits == 3) && ((fp.inst.op3 & 0x38) == 0x20)) ||
7260Sstevel@tonic-gate 						/* fbcc */
7270Sstevel@tonic-gate 	    ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 6))) {
7280Sstevel@tonic-gate 		ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu);
7290Sstevel@tonic-gate 	} else
7300Sstevel@tonic-gate 		return (ftt);
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (ftt != ftt_none)
7330Sstevel@tonic-gate 		return (ftt);
7340Sstevel@tonic-gate 	else
7350Sstevel@tonic-gate 		goto again;
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate  * FPU simulator global kstat data
7400Sstevel@tonic-gate  */
7410Sstevel@tonic-gate struct fpustat_kstat fpustat = {
7420Sstevel@tonic-gate 	{ "fpu_ieee_traps",		KSTAT_DATA_UINT64 },
7430Sstevel@tonic-gate 	{ "fpu_unfinished_traps",	KSTAT_DATA_UINT64 },
7440Sstevel@tonic-gate 	{ "fpu_unimplemented",		KSTAT_DATA_UINT64 },
7450Sstevel@tonic-gate };
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate kstat_t *fpu_kstat = NULL;
7480Sstevel@tonic-gate kstat_t *fpuinfo_kstat = NULL;
7490Sstevel@tonic-gate kstat_t *visinfo_kstat = NULL;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate void
fp_kstat_init(void)7520Sstevel@tonic-gate fp_kstat_init(void)
7530Sstevel@tonic-gate {
7540Sstevel@tonic-gate 	const uint_t fpustat_ndata = sizeof (fpustat) / sizeof (kstat_named_t);
7550Sstevel@tonic-gate 	const uint_t fpuinfo_ndata = sizeof (fpuinfo) / sizeof (kstat_named_t);
7560Sstevel@tonic-gate 	const uint_t visinfo_ndata = sizeof (visinfo) /sizeof (kstat_named_t);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	ASSERT(fpu_kstat == NULL);
7590Sstevel@tonic-gate 	if ((fpu_kstat = kstat_create("unix", 0, "fpu_traps", "misc",
7600Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, fpustat_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
7610Sstevel@tonic-gate 		cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_traps failed",
7620Sstevel@tonic-gate 		    CPU->cpu_id);
7630Sstevel@tonic-gate 	} else {
7640Sstevel@tonic-gate 		fpu_kstat->ks_data = (void *)&fpustat;
7650Sstevel@tonic-gate 		kstat_install(fpu_kstat);
7660Sstevel@tonic-gate 	}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	ASSERT(fpuinfo_kstat == NULL);
7690Sstevel@tonic-gate 	if ((fpuinfo_kstat = kstat_create("unix", 0, "fpu_info", "misc",
7700Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, fpuinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
7710Sstevel@tonic-gate 		cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_info failed",
7720Sstevel@tonic-gate 		    CPU->cpu_id);
7730Sstevel@tonic-gate 	} else {
7740Sstevel@tonic-gate 		fpuinfo_kstat->ks_data = (void *)&fpuinfo;
7750Sstevel@tonic-gate 		kstat_install(fpuinfo_kstat);
7760Sstevel@tonic-gate 	}
7770Sstevel@tonic-gate 	ASSERT(visinfo_kstat == NULL);
7780Sstevel@tonic-gate 	if ((visinfo_kstat = kstat_create("unix", 0, "vis_info", "misc",
7790Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, visinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
7800Sstevel@tonic-gate 		cmn_err(CE_WARN, "CPU%d: kstat_create for vis_info failed",
7810Sstevel@tonic-gate 		    CPU->cpu_id);
7820Sstevel@tonic-gate 	} else {
7830Sstevel@tonic-gate 		visinfo_kstat->ks_data = (void *)&visinfo;
7840Sstevel@tonic-gate 		kstat_install(visinfo_kstat);
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate void
fp_kstat_update(enum ftt_type ftt)7890Sstevel@tonic-gate fp_kstat_update(enum ftt_type ftt)
7900Sstevel@tonic-gate {
7910Sstevel@tonic-gate 	ASSERT((ftt == ftt_ieee) || (ftt == ftt_unfinished) ||
7920Sstevel@tonic-gate 	    (ftt == ftt_unimplemented));
7930Sstevel@tonic-gate 	if (ftt == ftt_ieee)
7940Sstevel@tonic-gate 		atomic_add_64(&fpustat.fpu_ieee_traps.value.ui64, 1);
7950Sstevel@tonic-gate 	else if (ftt == ftt_unfinished)
7960Sstevel@tonic-gate 		atomic_add_64(&fpustat.fpu_unfinished_traps.value.ui64, 1);
7970Sstevel@tonic-gate 	else if (ftt == ftt_unimplemented)
7980Sstevel@tonic-gate 		atomic_add_64(&fpustat.fpu_unimplemented_traps.value.ui64, 1);
7990Sstevel@tonic-gate }
800