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 } 800