xref: /onnv-gate/usr/src/uts/sparc/fpu/fpu_simulator.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /* Main procedures for sparc FPU simulator. */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h>
32*0Sstevel@tonic-gate #include <sys/fpu/globals.h>
33*0Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
34*0Sstevel@tonic-gate #include <sys/proc.h>
35*0Sstevel@tonic-gate #include <sys/signal.h>
36*0Sstevel@tonic-gate #include <sys/siginfo.h>
37*0Sstevel@tonic-gate #include <sys/thread.h>
38*0Sstevel@tonic-gate #include <sys/cpuvar.h>
39*0Sstevel@tonic-gate #include <sys/cmn_err.h>
40*0Sstevel@tonic-gate #include <sys/atomic.h>
41*0Sstevel@tonic-gate #include <sys/privregs.h>
42*0Sstevel@tonic-gate #include <sys/vis_simulator.h>
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #define	FPUINFO_KSTAT(opcode)	{					\
46*0Sstevel@tonic-gate 	extern void __dtrace_probe___fpuinfo_##opcode(uint64_t *);	\
47*0Sstevel@tonic-gate 	uint64_t *stataddr = &fpuinfo.opcode.value.ui64;		\
48*0Sstevel@tonic-gate 	__dtrace_probe___fpuinfo_##opcode(stataddr);			\
49*0Sstevel@tonic-gate 	atomic_add_64(&fpuinfo.opcode.value.ui64, 1);			\
50*0Sstevel@tonic-gate }
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #define	FPUINFO_KSTAT_PREC(prec, kstat_s, kstat_d, kstat_q)		\
53*0Sstevel@tonic-gate 	if (prec < 2) {							\
54*0Sstevel@tonic-gate 		FPUINFO_KSTAT(kstat_s);					\
55*0Sstevel@tonic-gate 	} else if (prec == 2) {						\
56*0Sstevel@tonic-gate 		FPUINFO_KSTAT(kstat_d);					\
57*0Sstevel@tonic-gate 	} else {							\
58*0Sstevel@tonic-gate 		FPUINFO_KSTAT(kstat_q);					\
59*0Sstevel@tonic-gate 	}
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate  * FPU simulator global kstat data
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate struct fpuinfo_kstat fpuinfo = {
65*0Sstevel@tonic-gate 	{ "fpu_sim_fmovs",		KSTAT_DATA_UINT64},
66*0Sstevel@tonic-gate 	{ "fpu_sim_fmovd",		KSTAT_DATA_UINT64},
67*0Sstevel@tonic-gate 	{ "fpu_sim_fmovq",		KSTAT_DATA_UINT64},
68*0Sstevel@tonic-gate 	{ "fpu_sim_fnegs",		KSTAT_DATA_UINT64},
69*0Sstevel@tonic-gate 	{ "fpu_sim_fnegd",		KSTAT_DATA_UINT64},
70*0Sstevel@tonic-gate 	{ "fpu_sim_fnegq",		KSTAT_DATA_UINT64},
71*0Sstevel@tonic-gate 	{ "fpu_sim_fabss",		KSTAT_DATA_UINT64},
72*0Sstevel@tonic-gate 	{ "fpu_sim_fabsd",		KSTAT_DATA_UINT64},
73*0Sstevel@tonic-gate 	{ "fpu_sim_fabsq",		KSTAT_DATA_UINT64},
74*0Sstevel@tonic-gate 	{ "fpu_sim_fsqrts",		KSTAT_DATA_UINT64},
75*0Sstevel@tonic-gate 	{ "fpu_sim_fsqrtd",		KSTAT_DATA_UINT64},
76*0Sstevel@tonic-gate 	{ "fpu_sim_fsqrtq",		KSTAT_DATA_UINT64},
77*0Sstevel@tonic-gate 	{ "fpu_sim_fadds",		KSTAT_DATA_UINT64},
78*0Sstevel@tonic-gate 	{ "fpu_sim_faddd",		KSTAT_DATA_UINT64},
79*0Sstevel@tonic-gate 	{ "fpu_sim_faddq",		KSTAT_DATA_UINT64},
80*0Sstevel@tonic-gate 	{ "fpu_sim_fsubs",		KSTAT_DATA_UINT64},
81*0Sstevel@tonic-gate 	{ "fpu_sim_fsubd",		KSTAT_DATA_UINT64},
82*0Sstevel@tonic-gate 	{ "fpu_sim_fsubq",		KSTAT_DATA_UINT64},
83*0Sstevel@tonic-gate 	{ "fpu_sim_fmuls",		KSTAT_DATA_UINT64},
84*0Sstevel@tonic-gate 	{ "fpu_sim_fmuld",		KSTAT_DATA_UINT64},
85*0Sstevel@tonic-gate 	{ "fpu_sim_fmulq",		KSTAT_DATA_UINT64},
86*0Sstevel@tonic-gate 	{ "fpu_sim_fdivs",		KSTAT_DATA_UINT64},
87*0Sstevel@tonic-gate 	{ "fpu_sim_fdivd",		KSTAT_DATA_UINT64},
88*0Sstevel@tonic-gate 	{ "fpu_sim_fdivq",		KSTAT_DATA_UINT64},
89*0Sstevel@tonic-gate 	{ "fpu_sim_fcmps",		KSTAT_DATA_UINT64},
90*0Sstevel@tonic-gate 	{ "fpu_sim_fcmpd",		KSTAT_DATA_UINT64},
91*0Sstevel@tonic-gate 	{ "fpu_sim_fcmpq",		KSTAT_DATA_UINT64},
92*0Sstevel@tonic-gate 	{ "fpu_sim_fcmpes",		KSTAT_DATA_UINT64},
93*0Sstevel@tonic-gate 	{ "fpu_sim_fcmped",		KSTAT_DATA_UINT64},
94*0Sstevel@tonic-gate 	{ "fpu_sim_fcmpeq",		KSTAT_DATA_UINT64},
95*0Sstevel@tonic-gate 	{ "fpu_sim_fsmuld",		KSTAT_DATA_UINT64},
96*0Sstevel@tonic-gate 	{ "fpu_sim_fdmulx",		KSTAT_DATA_UINT64},
97*0Sstevel@tonic-gate 	{ "fpu_sim_fstox",		KSTAT_DATA_UINT64},
98*0Sstevel@tonic-gate 	{ "fpu_sim_fdtox",		KSTAT_DATA_UINT64},
99*0Sstevel@tonic-gate 	{ "fpu_sim_fqtox",		KSTAT_DATA_UINT64},
100*0Sstevel@tonic-gate 	{ "fpu_sim_fxtos",		KSTAT_DATA_UINT64},
101*0Sstevel@tonic-gate 	{ "fpu_sim_fxtod",		KSTAT_DATA_UINT64},
102*0Sstevel@tonic-gate 	{ "fpu_sim_fxtoq",		KSTAT_DATA_UINT64},
103*0Sstevel@tonic-gate 	{ "fpu_sim_fitos",		KSTAT_DATA_UINT64},
104*0Sstevel@tonic-gate 	{ "fpu_sim_fitod",		KSTAT_DATA_UINT64},
105*0Sstevel@tonic-gate 	{ "fpu_sim_fitoq",		KSTAT_DATA_UINT64},
106*0Sstevel@tonic-gate 	{ "fpu_sim_fstoi",		KSTAT_DATA_UINT64},
107*0Sstevel@tonic-gate 	{ "fpu_sim_fdtoi",		KSTAT_DATA_UINT64},
108*0Sstevel@tonic-gate 	{ "fpu_sim_fqtoi",		KSTAT_DATA_UINT64},
109*0Sstevel@tonic-gate 	{ "fpu_sim_fmovcc",		KSTAT_DATA_UINT64},
110*0Sstevel@tonic-gate 	{ "fpu_sim_fmovr",		KSTAT_DATA_UINT64},
111*0Sstevel@tonic-gate };
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate struct visinfo_kstat visinfo = {
114*0Sstevel@tonic-gate 	{ "vis_edge8",		KSTAT_DATA_UINT64},
115*0Sstevel@tonic-gate 	{ "vis_edge8n",		KSTAT_DATA_UINT64},
116*0Sstevel@tonic-gate 	{ "vis_edge8l",		KSTAT_DATA_UINT64},
117*0Sstevel@tonic-gate 	{ "vis_edge8ln",	KSTAT_DATA_UINT64},
118*0Sstevel@tonic-gate 	{ "vis_edge16",		KSTAT_DATA_UINT64},
119*0Sstevel@tonic-gate 	{ "vis_edge16n",	KSTAT_DATA_UINT64},
120*0Sstevel@tonic-gate 	{ "vis_edge16l",	KSTAT_DATA_UINT64},
121*0Sstevel@tonic-gate 	{ "vis_edge16ln",	KSTAT_DATA_UINT64},
122*0Sstevel@tonic-gate 	{ "vis_edge32",		KSTAT_DATA_UINT64},
123*0Sstevel@tonic-gate 	{ "vis_edge32n",	KSTAT_DATA_UINT64},
124*0Sstevel@tonic-gate 	{ "vis_edge32l",	KSTAT_DATA_UINT64},
125*0Sstevel@tonic-gate 	{ "vis_edge32ln",	KSTAT_DATA_UINT64},
126*0Sstevel@tonic-gate 	{ "vis_array8",		KSTAT_DATA_UINT64},
127*0Sstevel@tonic-gate 	{ "vis_array16",	KSTAT_DATA_UINT64},
128*0Sstevel@tonic-gate 	{ "vis_array32",	KSTAT_DATA_UINT64},
129*0Sstevel@tonic-gate 	{ "vis_bmask",		KSTAT_DATA_UINT64},
130*0Sstevel@tonic-gate 	{ "vis_fcmple16",	KSTAT_DATA_UINT64},
131*0Sstevel@tonic-gate 	{ "vis_fcmpne16",	KSTAT_DATA_UINT64},
132*0Sstevel@tonic-gate 	{ "vis_fcmpgt16",	KSTAT_DATA_UINT64},
133*0Sstevel@tonic-gate 	{ "vis_fcmpeq16",	KSTAT_DATA_UINT64},
134*0Sstevel@tonic-gate 	{ "vis_fcmple32",	KSTAT_DATA_UINT64},
135*0Sstevel@tonic-gate 	{ "vis_fcmpne32",	KSTAT_DATA_UINT64},
136*0Sstevel@tonic-gate 	{ "vis_fcmpgt32",	KSTAT_DATA_UINT64},
137*0Sstevel@tonic-gate 	{ "vis_fcmpeq32",	KSTAT_DATA_UINT64},
138*0Sstevel@tonic-gate 	{ "vis_fmul8x16",	KSTAT_DATA_UINT64},
139*0Sstevel@tonic-gate 	{ "vis_fmul8x16au",	KSTAT_DATA_UINT64},
140*0Sstevel@tonic-gate 	{ "vis_fmul8x16al",	KSTAT_DATA_UINT64},
141*0Sstevel@tonic-gate 	{ "vis_fmul8sux16",	KSTAT_DATA_UINT64},
142*0Sstevel@tonic-gate 	{ "vis_fmul8ulx16",	KSTAT_DATA_UINT64},
143*0Sstevel@tonic-gate 	{ "vis_fmuld8sux16",	KSTAT_DATA_UINT64},
144*0Sstevel@tonic-gate 	{ "vis_fmuld8ulx16",	KSTAT_DATA_UINT64},
145*0Sstevel@tonic-gate 	{ "vis_fpack16",	KSTAT_DATA_UINT64},
146*0Sstevel@tonic-gate 	{ "vis_fpack32",	KSTAT_DATA_UINT64},
147*0Sstevel@tonic-gate 	{ "vis_fpackfix",	KSTAT_DATA_UINT64},
148*0Sstevel@tonic-gate 	{ "vis_fexpand",	KSTAT_DATA_UINT64},
149*0Sstevel@tonic-gate 	{ "vis_fpmerge",	KSTAT_DATA_UINT64},
150*0Sstevel@tonic-gate 	{ "vis_pdist",		KSTAT_DATA_UINT64},
151*0Sstevel@tonic-gate 	{ "vis_bshuffle",	KSTAT_DATA_UINT64},
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate };
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate /* PUBLIC FUNCTIONS */
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate int fp_notp = 1;	/* fp checking not a problem */
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate /* ARGSUSED */
160*0Sstevel@tonic-gate static enum ftt_type
161*0Sstevel@tonic-gate _fp_fpu_simulator(
162*0Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to fpu simulator data */
163*0Sstevel@tonic-gate 	fp_inst_type	inst,	/* FPU instruction to simulate. */
164*0Sstevel@tonic-gate 	fsr_type	*pfsr,	/* Pointer to image of FSR to read and write. */
165*0Sstevel@tonic-gate 	uint64_t	gsr)	/* Image of GSR to read */
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	unpacked	us1, us2, ud;	/* Unpacked operands and result. */
168*0Sstevel@tonic-gate 	uint32_t	nrs1, nrs2, nrd; /* Register number fields. */
169*0Sstevel@tonic-gate 	uint32_t	usr, andexcep;
170*0Sstevel@tonic-gate 	fsr_type	fsr;
171*0Sstevel@tonic-gate 	enum fcc_type	cc;
172*0Sstevel@tonic-gate 	uint32_t	nfcc;		/* fcc number field. */
173*0Sstevel@tonic-gate 	uint64_t	lusr;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	nrs1 = inst.rs1;
176*0Sstevel@tonic-gate 	nrs2 = inst.rs2;
177*0Sstevel@tonic-gate 	nrd = inst.rd;
178*0Sstevel@tonic-gate 	fsr = *pfsr;
179*0Sstevel@tonic-gate 	pfpsd->fp_current_exceptions = 0;	/* Init current exceptions. */
180*0Sstevel@tonic-gate 	pfpsd->fp_fsrtem    = fsr.tem;		/* Obtain fsr's tem */
181*0Sstevel@tonic-gate 	/*
182*0Sstevel@tonic-gate 	 * Obtain rounding direction and precision
183*0Sstevel@tonic-gate 	 */
184*0Sstevel@tonic-gate 	pfpsd->fp_direction = GSR_IM(gsr) ? GSR_IRND(gsr) : fsr.rnd;
185*0Sstevel@tonic-gate 	pfpsd->fp_precision = fsr.rnp;
186*0Sstevel@tonic-gate 	nfcc = nrd & 0x3;
187*0Sstevel@tonic-gate 	if (inst.op3 == 0x35) {		/* fpop2 */
188*0Sstevel@tonic-gate 		fsr.cexc = 0;
189*0Sstevel@tonic-gate 		*pfsr = fsr;
190*0Sstevel@tonic-gate 		if ((inst.opcode & 0xf) == 0) {
191*0Sstevel@tonic-gate 			if ((fp_notp) && (inst.prec == 0))
192*0Sstevel@tonic-gate 				return (ftt_unimplemented);
193*0Sstevel@tonic-gate 			FPUINFO_KSTAT(fpu_sim_fmovcc);
194*0Sstevel@tonic-gate 			return (fmovcc(pfpsd, inst, pfsr));	/* fmovcc */
195*0Sstevel@tonic-gate 		} else if ((inst.opcode & 0x7) == 1) {
196*0Sstevel@tonic-gate 			if ((fp_notp) && (inst.prec == 0))
197*0Sstevel@tonic-gate 				return (ftt_unimplemented);
198*0Sstevel@tonic-gate 			FPUINFO_KSTAT(fpu_sim_fmovr);
199*0Sstevel@tonic-gate 			return (fmovr(pfpsd, inst));		/* fmovr */
200*0Sstevel@tonic-gate 		}
201*0Sstevel@tonic-gate 	}
202*0Sstevel@tonic-gate 	/* ibit not valid for fpop1 instructions */
203*0Sstevel@tonic-gate 	if ((fp_notp) && (inst.ibit != 0))
204*0Sstevel@tonic-gate 		return (ftt_unimplemented);
205*0Sstevel@tonic-gate 	if ((fp_notp) && (inst.prec == 0)) {	/* fxto[sdq], fito[sdq] */
206*0Sstevel@tonic-gate 		if ((inst.opcode != flltos) &&
207*0Sstevel@tonic-gate 		    (inst.opcode != flltod) &&
208*0Sstevel@tonic-gate 		    (inst.opcode != flltox) &&
209*0Sstevel@tonic-gate 		    (inst.opcode != fitos) &&
210*0Sstevel@tonic-gate 		    (inst.opcode != fitod) &&
211*0Sstevel@tonic-gate 		    (inst.opcode != fitox)) {
212*0Sstevel@tonic-gate 			return (ftt_unimplemented);
213*0Sstevel@tonic-gate 		}
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 	switch (inst.opcode) {
216*0Sstevel@tonic-gate 	case fmovs:		/* also covers fmovd, fmovq */
217*0Sstevel@tonic-gate 		if (inst.prec < 2) {	/* fmovs */
218*0Sstevel@tonic-gate 			_fp_unpack_word(pfpsd, &usr, nrs2);
219*0Sstevel@tonic-gate 			_fp_pack_word(pfpsd, &usr, nrd);
220*0Sstevel@tonic-gate 			FPUINFO_KSTAT(fpu_sim_fmovs);
221*0Sstevel@tonic-gate 		} else {		/* fmovd */
222*0Sstevel@tonic-gate 			_fp_unpack_extword(pfpsd, &lusr, nrs2);
223*0Sstevel@tonic-gate 			_fp_pack_extword(pfpsd, &lusr, nrd);
224*0Sstevel@tonic-gate 			if (inst.prec > 2) {		/* fmovq */
225*0Sstevel@tonic-gate 				_fp_unpack_extword(pfpsd, &lusr, nrs2+2);
226*0Sstevel@tonic-gate 				_fp_pack_extword(pfpsd, &lusr, nrd+2);
227*0Sstevel@tonic-gate 				FPUINFO_KSTAT(fpu_sim_fmovq);
228*0Sstevel@tonic-gate 			} else {
229*0Sstevel@tonic-gate 				FPUINFO_KSTAT(fpu_sim_fmovd);
230*0Sstevel@tonic-gate 			}
231*0Sstevel@tonic-gate 		}
232*0Sstevel@tonic-gate 		break;
233*0Sstevel@tonic-gate 	case fabss:		/* also covers fabsd, fabsq */
234*0Sstevel@tonic-gate 		if (inst.prec < 2) {	/* fabss */
235*0Sstevel@tonic-gate 			_fp_unpack_word(pfpsd, &usr, nrs2);
236*0Sstevel@tonic-gate 			usr &= 0x7fffffff;
237*0Sstevel@tonic-gate 			_fp_pack_word(pfpsd, &usr, nrd);
238*0Sstevel@tonic-gate 			FPUINFO_KSTAT(fpu_sim_fabss);
239*0Sstevel@tonic-gate 		} else {		/* fabsd */
240*0Sstevel@tonic-gate 			_fp_unpack_extword(pfpsd, &lusr, nrs2);
241*0Sstevel@tonic-gate 			lusr &= 0x7fffffffffffffff;
242*0Sstevel@tonic-gate 			_fp_pack_extword(pfpsd, &lusr, nrd);
243*0Sstevel@tonic-gate 			if (inst.prec > 2) {		/* fabsq */
244*0Sstevel@tonic-gate 				_fp_unpack_extword(pfpsd, &lusr, nrs2+2);
245*0Sstevel@tonic-gate 				_fp_pack_extword(pfpsd, &lusr, nrd+2);
246*0Sstevel@tonic-gate 				FPUINFO_KSTAT(fpu_sim_fabsq);
247*0Sstevel@tonic-gate 			} else {
248*0Sstevel@tonic-gate 				FPUINFO_KSTAT(fpu_sim_fabsd);
249*0Sstevel@tonic-gate 			}
250*0Sstevel@tonic-gate 		}
251*0Sstevel@tonic-gate 		break;
252*0Sstevel@tonic-gate 	case fnegs:		/* also covers fnegd, fnegq */
253*0Sstevel@tonic-gate 	if (inst.prec < 2) {	/* fnegs */
254*0Sstevel@tonic-gate 			_fp_unpack_word(pfpsd, &usr, nrs2);
255*0Sstevel@tonic-gate 			usr ^= 0x80000000;
256*0Sstevel@tonic-gate 			_fp_pack_word(pfpsd, &usr, nrd);
257*0Sstevel@tonic-gate 			FPUINFO_KSTAT(fpu_sim_fnegs);
258*0Sstevel@tonic-gate 		} else {		/* fnegd */
259*0Sstevel@tonic-gate 			_fp_unpack_extword(pfpsd, &lusr, nrs2);
260*0Sstevel@tonic-gate 			lusr ^= 0x8000000000000000;
261*0Sstevel@tonic-gate 			_fp_pack_extword(pfpsd, &lusr, nrd);
262*0Sstevel@tonic-gate 			if (inst.prec > 2) {		/* fnegq */
263*0Sstevel@tonic-gate 				_fp_unpack_extword(pfpsd, &lusr, nrs2+2);
264*0Sstevel@tonic-gate 				lusr ^= 0x0000000000000000;
265*0Sstevel@tonic-gate 				_fp_pack_extword(pfpsd, &lusr, nrd+2);
266*0Sstevel@tonic-gate 				FPUINFO_KSTAT(fpu_sim_fnegq);
267*0Sstevel@tonic-gate 			} else {
268*0Sstevel@tonic-gate 				FPUINFO_KSTAT(fpu_sim_fnegd);
269*0Sstevel@tonic-gate 			}
270*0Sstevel@tonic-gate 		}
271*0Sstevel@tonic-gate 		break;
272*0Sstevel@tonic-gate 	case fadd:
273*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
274*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
275*0Sstevel@tonic-gate 		_fp_add(pfpsd, &us1, &us2, &ud);
276*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &ud, nrd, inst.prec);
277*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fadds,
278*0Sstevel@tonic-gate 		    fpu_sim_faddd, fpu_sim_faddq);
279*0Sstevel@tonic-gate 		break;
280*0Sstevel@tonic-gate 	case fsub:
281*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
282*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
283*0Sstevel@tonic-gate 		_fp_sub(pfpsd, &us1, &us2, &ud);
284*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &ud, nrd, inst.prec);
285*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsubs,
286*0Sstevel@tonic-gate 		    fpu_sim_fsubd, fpu_sim_fsubq);
287*0Sstevel@tonic-gate 		break;
288*0Sstevel@tonic-gate 	case fmul:
289*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
290*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
291*0Sstevel@tonic-gate 		_fp_mul(pfpsd, &us1, &us2, &ud);
292*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &ud, nrd, inst.prec);
293*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fmuls,
294*0Sstevel@tonic-gate 		    fpu_sim_fmuld, fpu_sim_fmulq);
295*0Sstevel@tonic-gate 		break;
296*0Sstevel@tonic-gate 	case fsmuld:
297*0Sstevel@tonic-gate 		if ((fp_notp) && (inst.prec != 1))
298*0Sstevel@tonic-gate 			return (ftt_unimplemented);
299*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
300*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
301*0Sstevel@tonic-gate 		_fp_mul(pfpsd, &us1, &us2, &ud);
302*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &ud, nrd, (enum fp_op_type) ((int)inst.prec+1));
303*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fsmuld);
304*0Sstevel@tonic-gate 		break;
305*0Sstevel@tonic-gate 	case fdmulx:
306*0Sstevel@tonic-gate 		if ((fp_notp) && (inst.prec != 2))
307*0Sstevel@tonic-gate 			return (ftt_unimplemented);
308*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
309*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
310*0Sstevel@tonic-gate 		_fp_mul(pfpsd, &us1, &us2, &ud);
311*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &ud, nrd, (enum fp_op_type) ((int)inst.prec+1));
312*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fdmulx);
313*0Sstevel@tonic-gate 		break;
314*0Sstevel@tonic-gate 	case fdiv:
315*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
316*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
317*0Sstevel@tonic-gate 		_fp_div(pfpsd, &us1, &us2, &ud);
318*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &ud, nrd, inst.prec);
319*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fdivs,
320*0Sstevel@tonic-gate 		    fpu_sim_fdivd, fpu_sim_fdivq);
321*0Sstevel@tonic-gate 		break;
322*0Sstevel@tonic-gate 	case fcmp:
323*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
324*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
325*0Sstevel@tonic-gate 		cc = _fp_compare(pfpsd, &us1, &us2, 0);
326*0Sstevel@tonic-gate 		if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
327*0Sstevel@tonic-gate 			switch (nfcc) {
328*0Sstevel@tonic-gate 			case fcc_0:
329*0Sstevel@tonic-gate 				fsr.fcc0 = cc;
330*0Sstevel@tonic-gate 				break;
331*0Sstevel@tonic-gate 			case fcc_1:
332*0Sstevel@tonic-gate 				fsr.fcc1 = cc;
333*0Sstevel@tonic-gate 				break;
334*0Sstevel@tonic-gate 			case fcc_2:
335*0Sstevel@tonic-gate 				fsr.fcc2 = cc;
336*0Sstevel@tonic-gate 				break;
337*0Sstevel@tonic-gate 			case fcc_3:
338*0Sstevel@tonic-gate 				fsr.fcc3 = cc;
339*0Sstevel@tonic-gate 				break;
340*0Sstevel@tonic-gate 			}
341*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmps,
342*0Sstevel@tonic-gate 		    fpu_sim_fcmpd, fpu_sim_fcmpq);
343*0Sstevel@tonic-gate 		break;
344*0Sstevel@tonic-gate 	case fcmpe:
345*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs1, inst.prec);
346*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us2, nrs2, inst.prec);
347*0Sstevel@tonic-gate 		cc = _fp_compare(pfpsd, &us1, &us2, 1);
348*0Sstevel@tonic-gate 		if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
349*0Sstevel@tonic-gate 			switch (nfcc) {
350*0Sstevel@tonic-gate 			case fcc_0:
351*0Sstevel@tonic-gate 				fsr.fcc0 = cc;
352*0Sstevel@tonic-gate 				break;
353*0Sstevel@tonic-gate 			case fcc_1:
354*0Sstevel@tonic-gate 				fsr.fcc1 = cc;
355*0Sstevel@tonic-gate 				break;
356*0Sstevel@tonic-gate 			case fcc_2:
357*0Sstevel@tonic-gate 				fsr.fcc2 = cc;
358*0Sstevel@tonic-gate 				break;
359*0Sstevel@tonic-gate 			case fcc_3:
360*0Sstevel@tonic-gate 				fsr.fcc3 = cc;
361*0Sstevel@tonic-gate 				break;
362*0Sstevel@tonic-gate 			}
363*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmpes,
364*0Sstevel@tonic-gate 			fpu_sim_fcmped, fpu_sim_fcmpeq);
365*0Sstevel@tonic-gate 		break;
366*0Sstevel@tonic-gate 	case fsqrt:
367*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
368*0Sstevel@tonic-gate 		_fp_sqrt(pfpsd, &us1, &ud);
369*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &ud, nrd, inst.prec);
370*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsqrts,
371*0Sstevel@tonic-gate 		    fpu_sim_fsqrtd, fpu_sim_fsqrtq);
372*0Sstevel@tonic-gate 		break;
373*0Sstevel@tonic-gate 	case ftoi:
374*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
375*0Sstevel@tonic-gate 		pfpsd->fp_direction = fp_tozero;
376*0Sstevel@tonic-gate 		/* Force rounding toward zero. */
377*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_int32);
378*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstoi,
379*0Sstevel@tonic-gate 		    fpu_sim_fdtoi, fpu_sim_fqtoi);
380*0Sstevel@tonic-gate 		break;
381*0Sstevel@tonic-gate 	case ftoll:
382*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
383*0Sstevel@tonic-gate 		pfpsd->fp_direction = fp_tozero;
384*0Sstevel@tonic-gate 		/* Force rounding toward zero. */
385*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_int64);
386*0Sstevel@tonic-gate 		FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstox,
387*0Sstevel@tonic-gate 		    fpu_sim_fdtox, fpu_sim_fqtox);
388*0Sstevel@tonic-gate 		break;
389*0Sstevel@tonic-gate 	case flltos:
390*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
391*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_single);
392*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fxtos);
393*0Sstevel@tonic-gate 		break;
394*0Sstevel@tonic-gate 	case flltod:
395*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
396*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_double);
397*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fxtod);
398*0Sstevel@tonic-gate 		break;
399*0Sstevel@tonic-gate 	case flltox:
400*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
401*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_extended);
402*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fxtoq);
403*0Sstevel@tonic-gate 		break;
404*0Sstevel@tonic-gate 	case fitos:
405*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
406*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_single);
407*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fitos);
408*0Sstevel@tonic-gate 		break;
409*0Sstevel@tonic-gate 	case fitod:
410*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
411*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_double);
412*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fitod);
413*0Sstevel@tonic-gate 		break;
414*0Sstevel@tonic-gate 	case fitox:
415*0Sstevel@tonic-gate 		_fp_unpack(pfpsd, &us1, nrs2, inst.prec);
416*0Sstevel@tonic-gate 		_fp_pack(pfpsd, &us1, nrd, fp_op_extended);
417*0Sstevel@tonic-gate 		FPUINFO_KSTAT(fpu_sim_fitoq);
418*0Sstevel@tonic-gate 		break;
419*0Sstevel@tonic-gate 	default:
420*0Sstevel@tonic-gate 		return (ftt_unimplemented);
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 	fsr.cexc = pfpsd->fp_current_exceptions;
423*0Sstevel@tonic-gate 	if (pfpsd->fp_current_exceptions) {	/* Exception(s) occurred. */
424*0Sstevel@tonic-gate 		andexcep = pfpsd->fp_current_exceptions & fsr.tem;
425*0Sstevel@tonic-gate 		if (andexcep != 0) {	/* Signal an IEEE SIGFPE here. */
426*0Sstevel@tonic-gate 			if (andexcep & (1 << fp_invalid)) {
427*0Sstevel@tonic-gate 				pfpsd->fp_trapcode = FPE_FLTINV;
428*0Sstevel@tonic-gate 				fsr.cexc = FSR_CEXC_NV;
429*0Sstevel@tonic-gate 			} else if (andexcep & (1 << fp_overflow)) {
430*0Sstevel@tonic-gate 				pfpsd->fp_trapcode = FPE_FLTOVF;
431*0Sstevel@tonic-gate 				fsr.cexc = FSR_CEXC_OF;
432*0Sstevel@tonic-gate 			} else if (andexcep & (1 << fp_underflow)) {
433*0Sstevel@tonic-gate 				pfpsd->fp_trapcode = FPE_FLTUND;
434*0Sstevel@tonic-gate 				fsr.cexc = FSR_CEXC_UF;
435*0Sstevel@tonic-gate 			} else if (andexcep & (1 << fp_division)) {
436*0Sstevel@tonic-gate 				pfpsd->fp_trapcode = FPE_FLTDIV;
437*0Sstevel@tonic-gate 				fsr.cexc = FSR_CEXC_DZ;
438*0Sstevel@tonic-gate 			} else if (andexcep & (1 << fp_inexact)) {
439*0Sstevel@tonic-gate 				pfpsd->fp_trapcode = FPE_FLTRES;
440*0Sstevel@tonic-gate 				fsr.cexc = FSR_CEXC_NX;
441*0Sstevel@tonic-gate 			} else {
442*0Sstevel@tonic-gate 				pfpsd->fp_trapcode = 0;
443*0Sstevel@tonic-gate 			}
444*0Sstevel@tonic-gate 			*pfsr = fsr;
445*0Sstevel@tonic-gate 			return (ftt_ieee);
446*0Sstevel@tonic-gate 		} else {	/* Just set accrued exception field. */
447*0Sstevel@tonic-gate 			fsr.aexc |= pfpsd->fp_current_exceptions;
448*0Sstevel@tonic-gate 		}
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate 	*pfsr = fsr;
451*0Sstevel@tonic-gate 	return (ftt_none);
452*0Sstevel@tonic-gate }
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate /*
455*0Sstevel@tonic-gate  * fpu_vis_sim simulates fpu and vis instructions;
456*0Sstevel@tonic-gate  * It can work with both real and pcb image registers.
457*0Sstevel@tonic-gate  */
458*0Sstevel@tonic-gate enum ftt_type
459*0Sstevel@tonic-gate fpu_vis_sim(
460*0Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to simulator data */
461*0Sstevel@tonic-gate 	fp_inst_type	*pinst,	/* Address of FPU instruction to simulate */
462*0Sstevel@tonic-gate 	struct regs	*pregs,	/* Pointer to PCB image of registers. */
463*0Sstevel@tonic-gate 	fsr_type	*pfsr,	/* Pointer to image of FSR to read and write */
464*0Sstevel@tonic-gate 	uint64_t	gsr,	/* Image of GSR to read */
465*0Sstevel@tonic-gate 	uint32_t	inst)	/* The FPU instruction to simulate */
466*0Sstevel@tonic-gate {
467*0Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
468*0Sstevel@tonic-gate 	union {
469*0Sstevel@tonic-gate 		uint32_t	i;
470*0Sstevel@tonic-gate 		fp_inst_type	inst;
471*0Sstevel@tonic-gate 	} fp;
472*0Sstevel@tonic-gate 	kfpu_t *pfp = lwptofpu(lwp);
473*0Sstevel@tonic-gate 	enum ftt_type ftt;
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	fp.i = inst;
476*0Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst;
477*0Sstevel@tonic-gate 	if (fpu_exists) {
478*0Sstevel@tonic-gate 		pfpsd->fp_current_read_freg = _fp_read_pfreg;
479*0Sstevel@tonic-gate 		pfpsd->fp_current_write_freg = _fp_write_pfreg;
480*0Sstevel@tonic-gate 		pfpsd->fp_current_read_dreg = _fp_read_pdreg;
481*0Sstevel@tonic-gate 		pfpsd->fp_current_write_dreg = _fp_write_pdreg;
482*0Sstevel@tonic-gate 		pfpsd->get_gsr = get_phys_gsr;
483*0Sstevel@tonic-gate 		pfpsd->set_gsr = set_phys_gsr;
484*0Sstevel@tonic-gate 		pfpsd->get_ccr = get_ccr;
485*0Sstevel@tonic-gate 		pfpsd->set_ccr = set_ccr;
486*0Sstevel@tonic-gate 		pfpsd->get_pstate = get_pstate;
487*0Sstevel@tonic-gate 	} else {
488*0Sstevel@tonic-gate 		pfpsd->fp_current_pfregs = pfp;
489*0Sstevel@tonic-gate 		pfpsd->fp_current_read_freg = _fp_read_vfreg;
490*0Sstevel@tonic-gate 		pfpsd->fp_current_write_freg = _fp_write_vfreg;
491*0Sstevel@tonic-gate 		pfpsd->fp_current_read_dreg = _fp_read_vdreg;
492*0Sstevel@tonic-gate 		pfpsd->fp_current_write_dreg = _fp_write_vdreg;
493*0Sstevel@tonic-gate 		pfpsd->get_gsr = get_gsr;
494*0Sstevel@tonic-gate 		pfpsd->set_gsr = set_gsr;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 		/* There are no virtual routines */
497*0Sstevel@tonic-gate 		/* for getting/setting ccr and pstate */
498*0Sstevel@tonic-gate 		pfpsd->get_ccr = get_ccr;
499*0Sstevel@tonic-gate 		pfpsd->set_ccr = set_ccr;
500*0Sstevel@tonic-gate 		pfpsd->get_pstate = get_pstate;
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
504*0Sstevel@tonic-gate 			ftt = vis_fpu_simulator(pfpsd, fp.inst,
505*0Sstevel@tonic-gate 					pregs, (ulong_t *)pregs->r_sp, pfp);
506*0Sstevel@tonic-gate 			return (ftt);
507*0Sstevel@tonic-gate 	} else if ((fp.inst.hibits == 2) &&
508*0Sstevel@tonic-gate 	    ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) {
509*0Sstevel@tonic-gate 		ftt =  _fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr);
510*0Sstevel@tonic-gate 		if (ftt == ftt_none || ftt == ftt_ieee) {
511*0Sstevel@tonic-gate 			pregs->r_pc = pregs->r_npc;
512*0Sstevel@tonic-gate 			pregs->r_npc += 4;
513*0Sstevel@tonic-gate 		}
514*0Sstevel@tonic-gate 		return (ftt);
515*0Sstevel@tonic-gate 	} else {
516*0Sstevel@tonic-gate 		ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs,
517*0Sstevel@tonic-gate 		    (ulong_t *)pregs->r_sp, pfp);
518*0Sstevel@tonic-gate 		return (ftt);
519*0Sstevel@tonic-gate 	}
520*0Sstevel@tonic-gate }
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate /*
523*0Sstevel@tonic-gate  * fpu_simulator simulates FPU instructions only;
524*0Sstevel@tonic-gate  * reads and writes FPU data registers directly.
525*0Sstevel@tonic-gate  */
526*0Sstevel@tonic-gate enum ftt_type
527*0Sstevel@tonic-gate fpu_simulator(
528*0Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to simulator data */
529*0Sstevel@tonic-gate 	fp_inst_type	*pinst,	/* Address of FPU instruction to simulate */
530*0Sstevel@tonic-gate 	fsr_type	*pfsr,	/* Pointer to image of FSR to read and write */
531*0Sstevel@tonic-gate 	uint64_t	gsr,	/* Image of GSR to read */
532*0Sstevel@tonic-gate 	uint32_t	inst)	/* The FPU instruction to simulate */
533*0Sstevel@tonic-gate {
534*0Sstevel@tonic-gate 	union {
535*0Sstevel@tonic-gate 		uint32_t	i;
536*0Sstevel@tonic-gate 		fp_inst_type	inst;
537*0Sstevel@tonic-gate 	} fp;
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	fp.i = inst;
540*0Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst;
541*0Sstevel@tonic-gate 	pfpsd->fp_current_read_freg = _fp_read_pfreg;
542*0Sstevel@tonic-gate 	pfpsd->fp_current_write_freg = _fp_write_pfreg;
543*0Sstevel@tonic-gate 	pfpsd->fp_current_read_dreg = _fp_read_pdreg;
544*0Sstevel@tonic-gate 	pfpsd->fp_current_write_dreg = _fp_write_pdreg;
545*0Sstevel@tonic-gate 	pfpsd->get_gsr = get_phys_gsr;
546*0Sstevel@tonic-gate 	pfpsd->set_gsr = set_phys_gsr;
547*0Sstevel@tonic-gate 	pfpsd->get_ccr = get_ccr;
548*0Sstevel@tonic-gate 	pfpsd->set_ccr = set_ccr;
549*0Sstevel@tonic-gate 	pfpsd->get_pstate = get_pstate;
550*0Sstevel@tonic-gate 	return (_fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr));
551*0Sstevel@tonic-gate }
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate /*
554*0Sstevel@tonic-gate  * fp_emulator simulates FPU and CPU-FPU instructions; reads and writes FPU
555*0Sstevel@tonic-gate  * data registers from image in pfpu.
556*0Sstevel@tonic-gate  */
557*0Sstevel@tonic-gate enum ftt_type
558*0Sstevel@tonic-gate fp_emulator(
559*0Sstevel@tonic-gate 	fp_simd_type	*pfpsd,	/* Pointer to simulator data */
560*0Sstevel@tonic-gate 	fp_inst_type	*pinst,	/* Pointer to FPU instruction to simulate. */
561*0Sstevel@tonic-gate 	struct regs	*pregs,	/* Pointer to PCB image of registers. */
562*0Sstevel@tonic-gate 	void		*prw,	/* Pointer to locals and ins. */
563*0Sstevel@tonic-gate 	kfpu_t		*pfpu)	/* Pointer to FPU register block. */
564*0Sstevel@tonic-gate {
565*0Sstevel@tonic-gate 	klwp_id_t lwp = ttolwp(curthread);
566*0Sstevel@tonic-gate 	union {
567*0Sstevel@tonic-gate 		uint32_t	i;
568*0Sstevel@tonic-gate 		fp_inst_type	inst;
569*0Sstevel@tonic-gate 	} fp;
570*0Sstevel@tonic-gate 	enum ftt_type	ftt;
571*0Sstevel@tonic-gate 	uint64_t gsr = get_gsr(pfpu);
572*0Sstevel@tonic-gate 	kfpu_t *pfp = lwptofpu(lwp);
573*0Sstevel@tonic-gate 	uint64_t	tfsr;
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	tfsr = pfpu->fpu_fsr;
576*0Sstevel@tonic-gate 	pfpsd->fp_current_pfregs = pfpu;
577*0Sstevel@tonic-gate 	pfpsd->fp_current_read_freg = _fp_read_vfreg;
578*0Sstevel@tonic-gate 	pfpsd->fp_current_write_freg = _fp_write_vfreg;
579*0Sstevel@tonic-gate 	pfpsd->fp_current_read_dreg = _fp_read_vdreg;
580*0Sstevel@tonic-gate 	pfpsd->fp_current_write_dreg = _fp_write_vdreg;
581*0Sstevel@tonic-gate 	pfpsd->get_gsr = get_gsr;
582*0Sstevel@tonic-gate 	pfpsd->set_gsr = set_gsr;
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	/* There are no virtual routines */
585*0Sstevel@tonic-gate 	/* for getting/setting ccr and pstate */
586*0Sstevel@tonic-gate 	pfpsd->get_ccr = get_ccr;
587*0Sstevel@tonic-gate 	pfpsd->set_ccr = set_ccr;
588*0Sstevel@tonic-gate 	pfpsd->get_pstate = get_pstate;
589*0Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */
590*0Sstevel@tonic-gate 	ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd);
591*0Sstevel@tonic-gate 	if (ftt != ftt_none)
592*0Sstevel@tonic-gate 		return (ftt);
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	if ((fp.inst.hibits == 2) &&
595*0Sstevel@tonic-gate 	    ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) {
596*0Sstevel@tonic-gate 		ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr);
597*0Sstevel@tonic-gate 		/* Do not retry emulated instruction. */
598*0Sstevel@tonic-gate 		pregs->r_pc = pregs->r_npc;
599*0Sstevel@tonic-gate 		pregs->r_npc += 4;
600*0Sstevel@tonic-gate 		pfpu->fpu_fsr = tfsr;
601*0Sstevel@tonic-gate 		if (ftt != ftt_none) {
602*0Sstevel@tonic-gate 			/*
603*0Sstevel@tonic-gate 			 * Simulation generated an exception of some kind,
604*0Sstevel@tonic-gate 			 * simulate the fp queue for a signal.
605*0Sstevel@tonic-gate 			 */
606*0Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst;
607*0Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i;
608*0Sstevel@tonic-gate 			pfpu->fpu_qcnt = 1;
609*0Sstevel@tonic-gate 		}
610*0Sstevel@tonic-gate 	} else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
611*0Sstevel@tonic-gate 			ftt = vis_fpu_simulator(pfpsd, fp.inst,
612*0Sstevel@tonic-gate 			    pregs, prw, pfp);
613*0Sstevel@tonic-gate 	} else
614*0Sstevel@tonic-gate 		ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu);
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	if (ftt != ftt_none)
617*0Sstevel@tonic-gate 		return (ftt);
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	/*
620*0Sstevel@tonic-gate 	 * If we are single-stepping, don't emulate any more instructions.
621*0Sstevel@tonic-gate 	 */
622*0Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
623*0Sstevel@tonic-gate 		return (ftt);
624*0Sstevel@tonic-gate again:
625*0Sstevel@tonic-gate 	/*
626*0Sstevel@tonic-gate 	 * now read next instruction and see if it can be emulated
627*0Sstevel@tonic-gate 	 */
628*0Sstevel@tonic-gate 	pinst = (fp_inst_type *)pregs->r_pc;
629*0Sstevel@tonic-gate 	pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */
630*0Sstevel@tonic-gate 	ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd);
631*0Sstevel@tonic-gate 	if (ftt != ftt_none)
632*0Sstevel@tonic-gate 		return (ftt);
633*0Sstevel@tonic-gate 	if ((fp.inst.hibits == 2) &&		/* fpops */
634*0Sstevel@tonic-gate 	    ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) {
635*0Sstevel@tonic-gate 		ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr);
636*0Sstevel@tonic-gate 		/* Do not retry emulated instruction. */
637*0Sstevel@tonic-gate 		pfpu->fpu_fsr = tfsr;
638*0Sstevel@tonic-gate 		pregs->r_pc = pregs->r_npc;
639*0Sstevel@tonic-gate 		pregs->r_npc += 4;
640*0Sstevel@tonic-gate 		if (ftt != ftt_none) {
641*0Sstevel@tonic-gate 			/*
642*0Sstevel@tonic-gate 			 * Simulation generated an exception of some kind,
643*0Sstevel@tonic-gate 			 * simulate the fp queue for a signal.
644*0Sstevel@tonic-gate 			 */
645*0Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst;
646*0Sstevel@tonic-gate 			pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i;
647*0Sstevel@tonic-gate 			pfpu->fpu_qcnt = 1;
648*0Sstevel@tonic-gate 		}
649*0Sstevel@tonic-gate 	} else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
650*0Sstevel@tonic-gate 			ftt = vis_fpu_simulator(pfpsd, fp.inst,
651*0Sstevel@tonic-gate 						pregs, prw, pfp);
652*0Sstevel@tonic-gate 	} else if (
653*0Sstevel@tonic-gate 						/* rd %gsr */
654*0Sstevel@tonic-gate 	    ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x28) &&
655*0Sstevel@tonic-gate 			(fp.inst.rs1 == 0x13)) ||
656*0Sstevel@tonic-gate 						/* wr %gsr */
657*0Sstevel@tonic-gate 	    ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x30) &&
658*0Sstevel@tonic-gate 			(fp.inst.rd == 0x13)) ||
659*0Sstevel@tonic-gate 						/* movcc */
660*0Sstevel@tonic-gate 	    ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x2c) &&
661*0Sstevel@tonic-gate 			(((fp.i>>18) & 0x1) == 0)) ||
662*0Sstevel@tonic-gate 						/* fbpcc */
663*0Sstevel@tonic-gate 	    ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 5)) ||
664*0Sstevel@tonic-gate 						/* fldst */
665*0Sstevel@tonic-gate 	    ((fp.inst.hibits == 3) && ((fp.inst.op3 & 0x38) == 0x20)) ||
666*0Sstevel@tonic-gate 						/* fbcc */
667*0Sstevel@tonic-gate 	    ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 6))) {
668*0Sstevel@tonic-gate 		ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu);
669*0Sstevel@tonic-gate 	} else
670*0Sstevel@tonic-gate 		return (ftt);
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	if (ftt != ftt_none)
673*0Sstevel@tonic-gate 		return (ftt);
674*0Sstevel@tonic-gate 	else
675*0Sstevel@tonic-gate 		goto again;
676*0Sstevel@tonic-gate }
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate /*
679*0Sstevel@tonic-gate  * FPU simulator global kstat data
680*0Sstevel@tonic-gate  */
681*0Sstevel@tonic-gate struct fpustat_kstat fpustat = {
682*0Sstevel@tonic-gate 	{ "fpu_ieee_traps",		KSTAT_DATA_UINT64 },
683*0Sstevel@tonic-gate 	{ "fpu_unfinished_traps",	KSTAT_DATA_UINT64 },
684*0Sstevel@tonic-gate 	{ "fpu_unimplemented",		KSTAT_DATA_UINT64 },
685*0Sstevel@tonic-gate };
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate kstat_t *fpu_kstat = NULL;
688*0Sstevel@tonic-gate kstat_t *fpuinfo_kstat = NULL;
689*0Sstevel@tonic-gate kstat_t *visinfo_kstat = NULL;
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate void
692*0Sstevel@tonic-gate fp_kstat_init(void)
693*0Sstevel@tonic-gate {
694*0Sstevel@tonic-gate 	const uint_t fpustat_ndata = sizeof (fpustat) / sizeof (kstat_named_t);
695*0Sstevel@tonic-gate 	const uint_t fpuinfo_ndata = sizeof (fpuinfo) / sizeof (kstat_named_t);
696*0Sstevel@tonic-gate 	const uint_t visinfo_ndata = sizeof (visinfo) /sizeof (kstat_named_t);
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	ASSERT(fpu_kstat == NULL);
699*0Sstevel@tonic-gate 	if ((fpu_kstat = kstat_create("unix", 0, "fpu_traps", "misc",
700*0Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, fpustat_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
701*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_traps failed",
702*0Sstevel@tonic-gate 		    CPU->cpu_id);
703*0Sstevel@tonic-gate 	} else {
704*0Sstevel@tonic-gate 		fpu_kstat->ks_data = (void *)&fpustat;
705*0Sstevel@tonic-gate 		kstat_install(fpu_kstat);
706*0Sstevel@tonic-gate 	}
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	ASSERT(fpuinfo_kstat == NULL);
709*0Sstevel@tonic-gate 	if ((fpuinfo_kstat = kstat_create("unix", 0, "fpu_info", "misc",
710*0Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, fpuinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
711*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_info failed",
712*0Sstevel@tonic-gate 		    CPU->cpu_id);
713*0Sstevel@tonic-gate 	} else {
714*0Sstevel@tonic-gate 		fpuinfo_kstat->ks_data = (void *)&fpuinfo;
715*0Sstevel@tonic-gate 		kstat_install(fpuinfo_kstat);
716*0Sstevel@tonic-gate 	}
717*0Sstevel@tonic-gate 	ASSERT(visinfo_kstat == NULL);
718*0Sstevel@tonic-gate 	if ((visinfo_kstat = kstat_create("unix", 0, "vis_info", "misc",
719*0Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, visinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
720*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "CPU%d: kstat_create for vis_info failed",
721*0Sstevel@tonic-gate 		    CPU->cpu_id);
722*0Sstevel@tonic-gate 	} else {
723*0Sstevel@tonic-gate 		visinfo_kstat->ks_data = (void *)&visinfo;
724*0Sstevel@tonic-gate 		kstat_install(visinfo_kstat);
725*0Sstevel@tonic-gate 	}
726*0Sstevel@tonic-gate }
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate void
729*0Sstevel@tonic-gate fp_kstat_update(enum ftt_type ftt)
730*0Sstevel@tonic-gate {
731*0Sstevel@tonic-gate 	ASSERT((ftt == ftt_ieee) || (ftt == ftt_unfinished) ||
732*0Sstevel@tonic-gate 	    (ftt == ftt_unimplemented));
733*0Sstevel@tonic-gate 	if (ftt == ftt_ieee)
734*0Sstevel@tonic-gate 		atomic_add_64(&fpustat.fpu_ieee_traps.value.ui64, 1);
735*0Sstevel@tonic-gate 	else if (ftt == ftt_unfinished)
736*0Sstevel@tonic-gate 		atomic_add_64(&fpustat.fpu_unfinished_traps.value.ui64, 1);
737*0Sstevel@tonic-gate 	else if (ftt == ftt_unimplemented)
738*0Sstevel@tonic-gate 		atomic_add_64(&fpustat.fpu_unimplemented_traps.value.ui64, 1);
739*0Sstevel@tonic-gate }
740