1 /* $NetBSD: fpu.c,v 1.26 2009/11/21 04:16:51 rmind Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)fpu.c 8.1 (Berkeley) 6/11/93 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.26 2009/11/21 04:16:51 rmind Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/proc.h> 48 #include <sys/signal.h> 49 #include <sys/systm.h> 50 #include <sys/syslog.h> 51 #include <sys/signalvar.h> 52 53 #include <machine/instr.h> 54 #include <machine/reg.h> 55 56 #include <sparc/fpu/fpu_emu.h> 57 #include <sparc/fpu/fpu_extern.h> 58 59 int fpe_debug = 0; 60 61 #ifdef DEBUG 62 /* 63 * Dump a `fpn' structure. 64 */ 65 void 66 fpu_dumpfpn(struct fpn *fp) 67 { 68 static const char *class[] = { 69 "SNAN", "QNAN", "ZERO", "NUM", "INF" 70 }; 71 72 printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2], 73 fp->fp_sign ? '-' : ' ', 74 fp->fp_mant[0], fp->fp_mant[1], 75 fp->fp_mant[2], fp->fp_mant[3], 76 fp->fp_exp); 77 } 78 #endif 79 80 /* 81 * fpu_execute returns the following error numbers (0 = no error): 82 */ 83 #define FPE 1 /* take a floating point exception */ 84 #define NOTFPU 2 /* not an FPU instruction */ 85 86 /* 87 * Translate current exceptions into `first' exception. The 88 * bits go the wrong way for ffs() (0x10 is most important, etc). 89 * There are only 5, so do it the obvious way. 90 */ 91 #define X1(x) x 92 #define X2(x) x,x 93 #define X4(x) x,x,x,x 94 #define X8(x) X4(x),X4(x) 95 #define X16(x) X8(x),X8(x) 96 97 static char cx_to_trapx[] = { 98 X1(FSR_NX), 99 X2(FSR_DZ), 100 X4(FSR_UF), 101 X8(FSR_OF), 102 X16(FSR_NV) 103 }; 104 static u_char fpu_codes_native[] = { 105 X1(FPE_FLTRES), 106 X2(FPE_FLTDIV), 107 X4(FPE_FLTUND), 108 X8(FPE_FLTOVF), 109 X16(FPE_FLTINV) 110 }; 111 #if defined(COMPAT_SUNOS) 112 static u_char fpu_codes_sunos[] = { 113 X1(FPE_FLTINEX_TRAP), 114 X2(FPE_FLTDIV_TRAP), 115 X4(FPE_FLTUND_TRAP), 116 X8(FPE_FLTOVF_TRAP), 117 X16(FPE_FLTOPERR_TRAP) 118 }; 119 extern struct emul emul_sunos; 120 #endif /* SUNOS_COMPAT */ 121 /* Note: SVR4(Solaris) FPE_* codes happen to be compatible with ours */ 122 123 /* 124 * The FPU gave us an exception. Clean up the mess. Note that the 125 * fp queue can only have FPops in it, never load/store FP registers 126 * nor FBfcc instructions. Experiments with `crashme' prove that 127 * unknown FPops do enter the queue, however. 128 */ 129 int 130 fpu_cleanup(l, fs) 131 struct lwp *l; 132 #ifndef SUN4U 133 struct fpstate *fs; 134 #else /* SUN4U */ 135 struct fpstate64 *fs; 136 #endif /* SUN4U */ 137 { 138 int i, fsr = fs->fs_fsr, error; 139 struct proc *p = l->l_proc; 140 union instr instr; 141 struct fpemu fe; 142 u_char *fpu_codes; 143 int code = 0; 144 145 fpu_codes = 146 #ifdef COMPAT_SUNOS 147 (p->p_emul == &emul_sunos) ? fpu_codes_sunos : 148 #endif 149 fpu_codes_native; 150 151 switch ((fsr >> FSR_FTT_SHIFT) & FSR_FTT_MASK) { 152 153 case FSR_TT_NONE: 154 panic("fpu_cleanup: No fault"); /* ??? */ 155 break; 156 157 case FSR_TT_IEEE: 158 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_IEEE\n")); 159 /* XXX missing trap address! */ 160 if ((i = fsr & FSR_CX) == 0) 161 panic("fpu ieee trap, but no exception"); 162 code = fpu_codes[i - 1]; 163 break; /* XXX should return, but queue remains */ 164 165 case FSR_TT_UNFIN: 166 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_UNFIN\n")); 167 #ifdef SUN4U 168 if (fs->fs_qsize == 0) { 169 printf("fpu_cleanup: unfinished fpop"); 170 /* The book sez reexecute or emulate. */ 171 return (0); 172 } 173 break; 174 175 #endif /* SUN4U */ 176 case FSR_TT_UNIMP: 177 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_UNIMP\n")); 178 if (fs->fs_qsize == 0) 179 panic("fpu_cleanup: unimplemented fpop"); 180 break; 181 182 case FSR_TT_SEQ: 183 panic("fpu sequence error"); 184 /* NOTREACHED */ 185 186 case FSR_TT_HWERR: 187 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_HWERR\n")); 188 log(LOG_ERR, "fpu hardware error (%s[%d])\n", 189 p->p_comm, p->p_pid); 190 uprintf("%s[%d]: fpu hardware error\n", p->p_comm, p->p_pid); 191 code = SI_NOINFO; 192 goto out; 193 194 default: 195 printf("fsr=0x%x\n", fsr); 196 panic("fpu error"); 197 } 198 199 /* emulate the instructions left in the queue */ 200 fe.fe_fpstate = fs; 201 for (i = 0; i < fs->fs_qsize; i++) { 202 instr.i_int = fs->fs_queue[i].fq_instr; 203 if (instr.i_any.i_op != IOP_reg || 204 (instr.i_op3.i_op3 != IOP3_FPop1 && 205 instr.i_op3.i_op3 != IOP3_FPop2)) 206 panic("bogus fpu queue"); 207 error = fpu_execute(&fe, instr); 208 if (error == 0) 209 continue; 210 211 switch (error) { 212 case FPE: 213 code = fpu_codes[(fs->fs_fsr & FSR_CX) - 1]; 214 break; 215 216 case NOTFPU: 217 #ifdef SUN4U 218 #ifdef DEBUG 219 printf("fpu_cleanup: not an FPU error -- sending SIGILL\n"); 220 #endif 221 #endif /* SUN4U */ 222 code = SI_NOINFO; 223 break; 224 225 default: 226 panic("fpu_cleanup 3"); 227 /* NOTREACHED */ 228 } 229 /* XXX should stop here, but queue remains */ 230 } 231 out: 232 fs->fs_qsize = 0; 233 return (code); 234 } 235 236 #ifdef notyet 237 /* 238 * If we have no FPU at all (are there any machines like this out 239 * there!?) we have to emulate each instruction, and we need a pointer 240 * to the trapframe so that we can step over them and do FBfcc's. 241 * We know the `queue' is empty, though; we just want to emulate 242 * the instruction at tf->tf_pc. 243 */ 244 fpu_emulate(l, tf, fs) 245 struct lwp *l; 246 struct trapframe *tf; 247 #ifndef SUN4U 248 struct fpstate *fs; 249 #else /* SUN4U */ 250 struct fpstate64 *fs; 251 #endif /* SUN4U */ 252 { 253 254 do { 255 fetch instr from pc 256 decode 257 if (integer instr) { 258 struct pcb *pcb = lwp_getpcb(l); 259 /* 260 * We do this here, rather than earlier, to avoid 261 * losing even more badly than usual. 262 */ 263 if (pcb->pcb_uw) { 264 write_user_windows(); 265 if (rwindow_save(l)) 266 sigexit(l, SIGILL); 267 } 268 if (loadstore) { 269 do_it; 270 pc = npc, npc += 4 271 } else if (fbfcc) { 272 do_annul_stuff; 273 } else 274 return; 275 } else if (fpu instr) { 276 fe.fe_fsr = fs->fs_fsr &= ~FSR_CX; 277 error = fpu_execute(&fe, fs, instr); 278 switch (error) { 279 etc; 280 } 281 } else 282 return; 283 if (want to reschedule) 284 return; 285 } while (error == 0); 286 } 287 #endif 288 289 /* 290 * Execute an FPU instruction (one that runs entirely in the FPU; not 291 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 292 * modified to reflect the setting the hardware would have left. 293 * 294 * Note that we do not catch all illegal opcodes, so you can, for instance, 295 * multiply two integers this way. 296 */ 297 int 298 fpu_execute(struct fpemu *fe, union instr instr) 299 { 300 struct fpn *fp; 301 #ifndef SUN4U 302 int opf, rs1, rs2, rd, type, mask, fsr, cx; 303 struct fpstate *fs; 304 #else /* SUN4U */ 305 int opf, rs1, rs2, rd, type, mask, fsr, cx, i, cond; 306 struct fpstate64 *fs; 307 #endif /* SUN4U */ 308 u_int space[4]; 309 310 /* 311 * `Decode' and execute instruction. Start with no exceptions. 312 * The type of any i_opf opcode is in the bottom two bits, so we 313 * squish them out here. 314 */ 315 opf = instr.i_opf.i_opf; 316 /* 317 * The low two bits of the opf field for floating point insns usually 318 * correspond to the operation width: 319 * 320 * 0: Invalid 321 * 1: Single precision float 322 * 2: Double precision float 323 * 3: Quad precision float 324 * 325 * The exceptions are the integer to float conversion instructions. 326 * 327 * For double and quad precision, the low bit if the rs or rd field 328 * is actually the high bit of the register number. 329 */ 330 331 type = opf & 3; 332 mask = 0x3 >> (3 - type); 333 334 rs1 = instr.i_opf.i_rs1; 335 rs1 = (rs1 & ~mask) | ((rs1 & mask & 0x1) << 5); 336 rs2 = instr.i_opf.i_rs2; 337 rs2 = (rs2 & ~mask) | ((rs2 & mask & 0x1) << 5); 338 rd = instr.i_opf.i_rd; 339 rd = (rd & ~mask) | ((rd & mask & 0x1) << 5); 340 #ifdef DIAGNOSTIC 341 if ((rs1 | rs2 | rd) & mask) 342 /* This may be an FPU insn but it is illegal. */ 343 return (NOTFPU); 344 #endif 345 fs = fe->fe_fpstate; 346 fe->fe_fsr = fs->fs_fsr & ~FSR_CX; 347 fe->fe_cx = 0; 348 #ifdef SUN4U 349 /* 350 * Check to see if we're dealing with a fancy cmove and handle 351 * it first. 352 */ 353 if (instr.i_op3.i_op3 == IOP3_FPop2 && (opf&0xff0) != (FCMP&0xff0)) { 354 switch (opf >>= 2) { 355 case FMVFC0 >> 2: 356 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC0\n")); 357 cond = (fs->fs_fsr>>FSR_FCC_SHIFT)&FSR_FCC_MASK; 358 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 359 rs1 = fs->fs_regs[rs2]; 360 goto mov; 361 case FMVFC1 >> 2: 362 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC1\n")); 363 cond = (fs->fs_fsr>>FSR_FCC1_SHIFT)&FSR_FCC_MASK; 364 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 365 rs1 = fs->fs_regs[rs2]; 366 goto mov; 367 case FMVFC2 >> 2: 368 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC2\n")); 369 cond = (fs->fs_fsr>>FSR_FCC2_SHIFT)&FSR_FCC_MASK; 370 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 371 rs1 = fs->fs_regs[rs2]; 372 goto mov; 373 case FMVFC3 >> 2: 374 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC3\n")); 375 cond = (fs->fs_fsr>>FSR_FCC3_SHIFT)&FSR_FCC_MASK; 376 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 377 rs1 = fs->fs_regs[rs2]; 378 goto mov; 379 case FMVIC >> 2: 380 /* Presume we're curlwp */ 381 DPRINTF(FPE_INSN, ("fpu_execute: FMVIC\n")); 382 cond = (curlwp->l_md.md_tf->tf_tstate>>TSTATE_CCR_SHIFT)&PSR_ICC; 383 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 384 rs1 = fs->fs_regs[rs2]; 385 goto mov; 386 case FMVXC >> 2: 387 /* Presume we're curlwp */ 388 DPRINTF(FPE_INSN, ("fpu_execute: FMVXC\n")); 389 cond = (curlwp->l_md.md_tf->tf_tstate>>(TSTATE_CCR_SHIFT+XCC_SHIFT))&PSR_ICC; 390 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 391 rs1 = fs->fs_regs[rs2]; 392 goto mov; 393 case FMVRZ >> 2: 394 /* Presume we're curlwp */ 395 DPRINTF(FPE_INSN, ("fpu_execute: FMVRZ\n")); 396 rs1 = instr.i_fmovr.i_rs1; 397 if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] != 0) 398 return (0); /* success */ 399 rs1 = fs->fs_regs[rs2]; 400 goto mov; 401 case FMVRLEZ >> 2: 402 /* Presume we're curlwp */ 403 DPRINTF(FPE_INSN, ("fpu_execute: FMVRLEZ\n")); 404 rs1 = instr.i_fmovr.i_rs1; 405 if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] > 0) 406 return (0); /* success */ 407 rs1 = fs->fs_regs[rs2]; 408 goto mov; 409 case FMVRLZ >> 2: 410 /* Presume we're curlwp */ 411 DPRINTF(FPE_INSN, ("fpu_execute: FMVRLZ\n")); 412 rs1 = instr.i_fmovr.i_rs1; 413 if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] >= 0) 414 return (0); /* success */ 415 rs1 = fs->fs_regs[rs2]; 416 goto mov; 417 case FMVRNZ >> 2: 418 /* Presume we're curlwp */ 419 DPRINTF(FPE_INSN, ("fpu_execute: FMVRNZ\n")); 420 rs1 = instr.i_fmovr.i_rs1; 421 if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] == 0) 422 return (0); /* success */ 423 rs1 = fs->fs_regs[rs2]; 424 goto mov; 425 case FMVRGZ >> 2: 426 /* Presume we're curlwp */ 427 DPRINTF(FPE_INSN, ("fpu_execute: FMVRGZ\n")); 428 rs1 = instr.i_fmovr.i_rs1; 429 if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] <= 0) 430 return (0); /* success */ 431 rs1 = fs->fs_regs[rs2]; 432 goto mov; 433 case FMVRGEZ >> 2: 434 /* Presume we're curlwp */ 435 DPRINTF(FPE_INSN, ("fpu_execute: FMVRGEZ\n")); 436 rs1 = instr.i_fmovr.i_rs1; 437 if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] < 0) 438 return (0); /* success */ 439 rs1 = fs->fs_regs[rs2]; 440 goto mov; 441 default: 442 DPRINTF(FPE_INSN, 443 ("fpu_execute: unknown v9 FP inst %x opf %x\n", 444 instr.i_int, opf)); 445 return (NOTFPU); 446 } 447 } 448 #endif /* SUN4U */ 449 switch (opf >>= 2) { 450 451 default: 452 DPRINTF(FPE_INSN, 453 ("fpu_execute: unknown basic FP inst %x opf %x\n", 454 instr.i_int, opf)); 455 return (NOTFPU); 456 457 case FMOV >> 2: /* these should all be pretty obvious */ 458 DPRINTF(FPE_INSN, ("fpu_execute: FMOV\n")); 459 rs1 = fs->fs_regs[rs2]; 460 goto mov; 461 462 case FNEG >> 2: 463 DPRINTF(FPE_INSN, ("fpu_execute: FNEG\n")); 464 rs1 = fs->fs_regs[rs2] ^ (1 << 31); 465 goto mov; 466 467 case FABS >> 2: 468 DPRINTF(FPE_INSN, ("fpu_execute: FABS\n")); 469 rs1 = fs->fs_regs[rs2] & ~(1 << 31); 470 mov: 471 #ifndef SUN4U 472 fs->fs_regs[rd] = rs1; 473 #else /* SUN4U */ 474 i = 1<<(type-1); 475 fs->fs_regs[rd++] = rs1; 476 while (--i > 0) 477 fs->fs_regs[rd++] = fs->fs_regs[++rs2]; 478 #endif /* SUN4U */ 479 fs->fs_fsr = fe->fe_fsr; 480 return (0); /* success */ 481 482 case FSQRT >> 2: 483 DPRINTF(FPE_INSN, ("fpu_execute: FSQRT\n")); 484 fpu_explode(fe, &fe->fe_f1, type, rs2); 485 fp = fpu_sqrt(fe); 486 break; 487 488 case FADD >> 2: 489 DPRINTF(FPE_INSN, ("fpu_execute: FADD\n")); 490 fpu_explode(fe, &fe->fe_f1, type, rs1); 491 fpu_explode(fe, &fe->fe_f2, type, rs2); 492 fp = fpu_add(fe); 493 break; 494 495 case FSUB >> 2: 496 DPRINTF(FPE_INSN, ("fpu_execute: FSUB\n")); 497 fpu_explode(fe, &fe->fe_f1, type, rs1); 498 fpu_explode(fe, &fe->fe_f2, type, rs2); 499 fp = fpu_sub(fe); 500 break; 501 502 case FMUL >> 2: 503 DPRINTF(FPE_INSN, ("fpu_execute: FMUL\n")); 504 fpu_explode(fe, &fe->fe_f1, type, rs1); 505 fpu_explode(fe, &fe->fe_f2, type, rs2); 506 fp = fpu_mul(fe); 507 break; 508 509 case FDIV >> 2: 510 DPRINTF(FPE_INSN, ("fpu_execute: FDIV\n")); 511 fpu_explode(fe, &fe->fe_f1, type, rs1); 512 fpu_explode(fe, &fe->fe_f2, type, rs2); 513 fp = fpu_div(fe); 514 break; 515 516 case FCMP >> 2: 517 DPRINTF(FPE_INSN, ("fpu_execute: FCMP\n")); 518 fpu_explode(fe, &fe->fe_f1, type, rs1); 519 fpu_explode(fe, &fe->fe_f2, type, rs2); 520 fpu_compare(fe, 0); 521 goto cmpdone; 522 523 case FCMPE >> 2: 524 DPRINTF(FPE_INSN, ("fpu_execute: FCMPE\n")); 525 fpu_explode(fe, &fe->fe_f1, type, rs1); 526 fpu_explode(fe, &fe->fe_f2, type, rs2); 527 fpu_compare(fe, 1); 528 cmpdone: 529 /* 530 * The only possible exception here is NV; catch it 531 * early and get out, as there is no result register. 532 */ 533 cx = fe->fe_cx; 534 fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT); 535 if (cx != 0) { 536 if (fsr & (FSR_NV << FSR_TEM_SHIFT)) { 537 fs->fs_fsr = (fsr & ~FSR_FTT) | 538 (FSR_TT_IEEE << FSR_FTT_SHIFT); 539 return (FPE); 540 } 541 fsr |= FSR_NV << FSR_AX_SHIFT; 542 } 543 fs->fs_fsr = fsr; 544 return (0); 545 546 case FSMULD >> 2: 547 case FDMULX >> 2: 548 DPRINTF(FPE_INSN, ("fpu_execute: FSMULx\n")); 549 if (type == FTYPE_EXT) 550 return (NOTFPU); 551 fpu_explode(fe, &fe->fe_f1, type, rs1); 552 fpu_explode(fe, &fe->fe_f2, type, rs2); 553 type++; /* single to double, or double to quad */ 554 fp = fpu_mul(fe); 555 break; 556 557 #ifdef SUN4U 558 case FXTOS >> 2: 559 case FXTOD >> 2: 560 case FXTOQ >> 2: 561 DPRINTF(FPE_INSN, ("fpu_execute: FXTOx\n")); 562 type = FTYPE_LNG; 563 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 564 type = opf & 3; /* sneaky; depends on instruction encoding */ 565 break; 566 567 case FTOX >> 2: 568 DPRINTF(FPE_INSN, ("fpu_execute: FTOX\n")); 569 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 570 type = FTYPE_LNG; 571 /* Recalculate destination register */ 572 rd = instr.i_opf.i_rd; 573 break; 574 575 #endif /* SUN4U */ 576 case FTOI >> 2: 577 DPRINTF(FPE_INSN, ("fpu_execute: FTOI\n")); 578 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 579 type = FTYPE_INT; 580 /* Recalculate destination register */ 581 rd = instr.i_opf.i_rd; 582 break; 583 584 case FTOS >> 2: 585 case FTOD >> 2: 586 case FTOQ >> 2: 587 DPRINTF(FPE_INSN, ("fpu_execute: FTOx\n")); 588 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 589 /* Recalculate rd with correct type info. */ 590 type = opf & 3; /* sneaky; depends on instruction encoding */ 591 mask = 0x3 >> (3 - type); 592 rd = instr.i_opf.i_rd; 593 rd = (rd & ~mask) | ((rd & mask & 0x1) << 5); 594 break; 595 } 596 597 /* 598 * ALU operation is complete. Collapse the result and then check 599 * for exceptions. If we got any, and they are enabled, do not 600 * alter the destination register, just stop with an exception. 601 * Otherwise set new current exceptions and accrue. 602 */ 603 fpu_implode(fe, fp, type, space); 604 cx = fe->fe_cx; 605 fsr = fe->fe_fsr; 606 if (cx != 0) { 607 mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK; 608 if (cx & mask) { 609 /* not accrued??? */ 610 fs->fs_fsr = (fsr & ~FSR_FTT) | 611 (FSR_TT_IEEE << FSR_FTT_SHIFT) | 612 (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT); 613 return (FPE); 614 } 615 fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT); 616 } 617 fs->fs_fsr = fsr; 618 DPRINTF(FPE_REG, ("-> %c%d\n", (type == FTYPE_LNG) ? 'x' : 619 ((type == FTYPE_INT) ? 'i' : 620 ((type == FTYPE_SNG) ? 's' : 621 ((type == FTYPE_DBL) ? 'd' : 622 ((type == FTYPE_EXT) ? 'q' : '?')))), 623 rd)); 624 fs->fs_regs[rd] = space[0]; 625 if (type >= FTYPE_DBL || type == FTYPE_LNG) { 626 fs->fs_regs[rd + 1] = space[1]; 627 if (type > FTYPE_DBL) { 628 fs->fs_regs[rd + 2] = space[2]; 629 fs->fs_regs[rd + 3] = space[3]; 630 } 631 } 632 return (0); /* success */ 633 } 634