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