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