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