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