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