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