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