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 59int fpe_debug = 0; 60 61#ifdef DEBUG 62/* 63 * Dump a `fpn' structure. 64 */ 65void 66fpu_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 97static 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}; 104static 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) 112static 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}; 119extern 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 */ 129int 130fpu_cleanup( 131 struct lwp *l, 132#ifndef SUN4U 133 struct fpstate *fs 134#else /* SUN4U */ 135 struct fpstate64 *fs 136#endif /* SUN4U */ 137 ) 138{ 139 int i, fsr = fs->fs_fsr, error; 140 struct proc *p = l->l_proc; 141 union instr instr; 142 struct fpemu fe; 143 u_char *fpu_codes; 144 int code = 0; 145 146 fpu_codes = 147#ifdef COMPAT_SUNOS 148 (p->p_emul == &emul_sunos) ? fpu_codes_sunos : 149#endif 150 fpu_codes_native; 151 152 switch ((fsr >> FSR_FTT_SHIFT) & FSR_FTT_MASK) { 153 154 case FSR_TT_NONE: 155 panic("fpu_cleanup: No fault"); /* ??? */ 156 break; 157 158 case FSR_TT_IEEE: 159 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_IEEE\n")); 160 /* XXX missing trap address! */ 161 if ((i = fsr & FSR_CX) == 0) 162 panic("fpu ieee trap, but no exception"); 163 code = fpu_codes[i - 1]; 164 break; /* XXX should return, but queue remains */ 165 166 case FSR_TT_UNFIN: 167 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_UNFIN\n")); 168#ifdef SUN4U 169 if (fs->fs_qsize == 0) { 170 printf("fpu_cleanup: unfinished fpop"); 171 /* The book sez reexecute or emulate. */ 172 return (0); 173 } 174 break; 175 176#endif /* SUN4U */ 177 case FSR_TT_UNIMP: 178 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_UNIMP\n")); 179 if (fs->fs_qsize == 0) 180 panic("fpu_cleanup: unimplemented fpop"); 181 break; 182 183 case FSR_TT_SEQ: 184 panic("fpu sequence error"); 185 /* NOTREACHED */ 186 187 case FSR_TT_HWERR: 188 DPRINTF(FPE_INSN, ("fpu_cleanup: FSR_TT_HWERR\n")); 189 log(LOG_ERR, "fpu hardware error (%s[%d])\n", 190 p->p_comm, p->p_pid); 191 uprintf("%s[%d]: fpu hardware error\n", p->p_comm, p->p_pid); 192 code = SI_NOINFO; 193 goto out; 194 195 default: 196 printf("fsr=0x%x\n", fsr); 197 panic("fpu error"); 198 } 199 200 /* emulate the instructions left in the queue */ 201 fe.fe_fpstate = fs; 202 for (i = 0; i < fs->fs_qsize; i++) { 203 instr.i_int = fs->fs_queue[i].fq_instr; 204 if (instr.i_any.i_op != IOP_reg || 205 (instr.i_op3.i_op3 != IOP3_FPop1 && 206 instr.i_op3.i_op3 != IOP3_FPop2)) 207 panic("bogus fpu queue"); 208 error = fpu_execute(&fe, instr); 209 if (error == 0) 210 continue; 211 212 switch (error) { 213 case FPE: 214 code = fpu_codes[(fs->fs_fsr & FSR_CX) - 1]; 215 break; 216 217 case NOTFPU: 218#ifdef SUN4U 219#ifdef DEBUG 220 printf("fpu_cleanup: not an FPU error -- sending SIGILL\n"); 221#endif 222#endif /* SUN4U */ 223 code = SI_NOINFO; 224 break; 225 226 default: 227 panic("fpu_cleanup 3"); 228 /* NOTREACHED */ 229 } 230 /* XXX should stop here, but queue remains */ 231 } 232out: 233 fs->fs_qsize = 0; 234 return (code); 235} 236 237#ifdef notyet 238/* 239 * If we have no FPU at all (are there any machines like this out 240 * there!?) we have to emulate each instruction, and we need a pointer 241 * to the trapframe so that we can step over them and do FBfcc's. 242 * We know the `queue' is empty, though; we just want to emulate 243 * the instruction at tf->tf_pc. 244 */ 245fpu_emulate(l, tf, fs) 246 struct lwp *l; 247 struct trapframe *tf; 248#ifndef SUN4U 249 struct fpstate *fs; 250#else /* SUN4U */ 251 struct fpstate64 *fs; 252#endif /* SUN4U */ 253{ 254 255 do { 256 fetch instr from pc 257 decode 258 if (integer instr) { 259 struct pcb *pcb = lwp_getpcb(l); 260 /* 261 * We do this here, rather than earlier, to avoid 262 * losing even more badly than usual. 263 */ 264 if (pcb->pcb_uw) { 265 write_user_windows(); 266 if (rwindow_save(l)) 267 sigexit(l, SIGILL); 268 } 269 if (loadstore) { 270 do_it; 271 pc = npc, npc += 4 272 } else if (fbfcc) { 273 do_annul_stuff; 274 } else 275 return; 276 } else if (fpu instr) { 277 fe.fe_fsr = fs->fs_fsr &= ~FSR_CX; 278 error = fpu_execute(&fe, fs, instr); 279 switch (error) { 280 etc; 281 } 282 } else 283 return; 284 if (want to reschedule) 285 return; 286 } while (error == 0); 287} 288#endif 289 290/* 291 * Execute an FPU instruction (one that runs entirely in the FPU; not 292 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 293 * modified to reflect the setting the hardware would have left. 294 * 295 * Note that we do not catch all illegal opcodes, so you can, for instance, 296 * multiply two integers this way. 297 */ 298int 299fpu_execute(struct fpemu *fe, union instr instr) 300{ 301 struct fpn *fp; 302#ifndef SUN4U 303 int opf, rs1, rs2, rd, type, mask, fsr, cx; 304 struct fpstate *fs; 305#else /* SUN4U */ 306 int opf, rs1, rs2, rd, type, mask, fsr, cx, i, cond; 307 struct fpstate64 *fs; 308#endif /* SUN4U */ 309 u_int space[4]; 310 311 /* 312 * `Decode' and execute instruction. Start with no exceptions. 313 * The type of any i_opf opcode is in the bottom two bits, so we 314 * squish them out here. 315 */ 316 opf = instr.i_opf.i_opf; 317 /* 318 * The low two bits of the opf field for floating point insns usually 319 * correspond to the operation width: 320 * 321 * 0: Invalid 322 * 1: Single precision float 323 * 2: Double precision float 324 * 3: Quad precision float 325 * 326 * The exceptions are the integer to float conversion instructions. 327 * 328 * For double and quad precision, the low bit if the rs or rd field 329 * is actually the high bit of the register number. 330 */ 331 332 type = opf & 3; 333 mask = 0x3 >> (3 - type); 334 335 rs1 = instr.i_opf.i_rs1; 336 rs1 = (rs1 & ~mask) | ((rs1 & mask & 0x1) << 5); 337 rs2 = instr.i_opf.i_rs2; 338 rs2 = (rs2 & ~mask) | ((rs2 & mask & 0x1) << 5); 339 rd = instr.i_opf.i_rd; 340 rd = (rd & ~mask) | ((rd & mask & 0x1) << 5); 341#ifdef DIAGNOSTIC 342 if ((rs1 | rs2 | rd) & mask) 343 /* This may be an FPU insn but it is illegal. */ 344 return (NOTFPU); 345#endif 346 fs = fe->fe_fpstate; 347 fe->fe_fsr = fs->fs_fsr & ~FSR_CX; 348 fe->fe_cx = 0; 349#ifdef SUN4U 350 /* 351 * Check to see if we're dealing with a fancy cmove and handle 352 * it first. 353 */ 354 if (instr.i_op3.i_op3 == IOP3_FPop2 && (opf&0xff0) != (FCMP&0xff0)) { 355 switch (opf >>= 2) { 356 case FMVFC0 >> 2: 357 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC0\n")); 358 cond = (fs->fs_fsr>>FSR_FCC_SHIFT)&FSR_FCC_MASK; 359 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 360 rs1 = fs->fs_regs[rs2]; 361 goto mov; 362 case FMVFC1 >> 2: 363 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC1\n")); 364 cond = (fs->fs_fsr>>FSR_FCC1_SHIFT)&FSR_FCC_MASK; 365 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 366 rs1 = fs->fs_regs[rs2]; 367 goto mov; 368 case FMVFC2 >> 2: 369 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC2\n")); 370 cond = (fs->fs_fsr>>FSR_FCC2_SHIFT)&FSR_FCC_MASK; 371 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 372 rs1 = fs->fs_regs[rs2]; 373 goto mov; 374 case FMVFC3 >> 2: 375 DPRINTF(FPE_INSN, ("fpu_execute: FMVFC3\n")); 376 cond = (fs->fs_fsr>>FSR_FCC3_SHIFT)&FSR_FCC_MASK; 377 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 378 rs1 = fs->fs_regs[rs2]; 379 goto mov; 380 case FMVIC >> 2: 381 /* Presume we're curlwp */ 382 DPRINTF(FPE_INSN, ("fpu_execute: FMVIC\n")); 383 cond = (curlwp->l_md.md_tf->tf_tstate>>TSTATE_CCR_SHIFT)&PSR_ICC; 384 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 385 rs1 = fs->fs_regs[rs2]; 386 goto mov; 387 case FMVXC >> 2: 388 /* Presume we're curlwp */ 389 DPRINTF(FPE_INSN, ("fpu_execute: FMVXC\n")); 390 cond = (curlwp->l_md.md_tf->tf_tstate>>(TSTATE_CCR_SHIFT+XCC_SHIFT))&PSR_ICC; 391 if (instr.i_fmovcc.i_cond != cond) return(0); /* success */ 392 rs1 = fs->fs_regs[rs2]; 393 goto mov; 394 case FMVRZ >> 2: 395 /* Presume we're curlwp */ 396 DPRINTF(FPE_INSN, ("fpu_execute: FMVRZ\n")); 397 rs1 = instr.i_fmovr.i_rs1; 398 if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] != 0) 399 return (0); /* success */ 400 rs1 = fs->fs_regs[rs2]; 401 goto mov; 402 case FMVRLEZ >> 2: 403 /* Presume we're curlwp */ 404 DPRINTF(FPE_INSN, ("fpu_execute: FMVRLEZ\n")); 405 rs1 = instr.i_fmovr.i_rs1; 406 if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] > 0) 407 return (0); /* success */ 408 rs1 = fs->fs_regs[rs2]; 409 goto mov; 410 case FMVRLZ >> 2: 411 /* Presume we're curlwp */ 412 DPRINTF(FPE_INSN, ("fpu_execute: FMVRLZ\n")); 413 rs1 = instr.i_fmovr.i_rs1; 414 if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] >= 0) 415 return (0); /* success */ 416 rs1 = fs->fs_regs[rs2]; 417 goto mov; 418 case FMVRNZ >> 2: 419 /* Presume we're curlwp */ 420 DPRINTF(FPE_INSN, ("fpu_execute: FMVRNZ\n")); 421 rs1 = instr.i_fmovr.i_rs1; 422 if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] == 0) 423 return (0); /* success */ 424 rs1 = fs->fs_regs[rs2]; 425 goto mov; 426 case FMVRGZ >> 2: 427 /* Presume we're curlwp */ 428 DPRINTF(FPE_INSN, ("fpu_execute: FMVRGZ\n")); 429 rs1 = instr.i_fmovr.i_rs1; 430 if (rs1 == 0 || (int64_t)curlwp->l_md.md_tf->tf_global[rs1] <= 0) 431 return (0); /* success */ 432 rs1 = fs->fs_regs[rs2]; 433 goto mov; 434 case FMVRGEZ >> 2: 435 /* Presume we're curlwp */ 436 DPRINTF(FPE_INSN, ("fpu_execute: FMVRGEZ\n")); 437 rs1 = instr.i_fmovr.i_rs1; 438 if (rs1 != 0 && (int64_t)curlwp->l_md.md_tf->tf_global[rs1] < 0) 439 return (0); /* success */ 440 rs1 = fs->fs_regs[rs2]; 441 goto mov; 442 default: 443 DPRINTF(FPE_INSN, 444 ("fpu_execute: unknown v9 FP inst %x opf %x\n", 445 instr.i_int, opf)); 446 return (NOTFPU); 447 } 448 } 449#endif /* SUN4U */ 450 switch (opf >>= 2) { 451 452 default: 453 DPRINTF(FPE_INSN, 454 ("fpu_execute: unknown basic FP inst %x opf %x\n", 455 instr.i_int, opf)); 456 return (NOTFPU); 457 458 case FMOV >> 2: /* these should all be pretty obvious */ 459 DPRINTF(FPE_INSN, ("fpu_execute: FMOV\n")); 460 rs1 = fs->fs_regs[rs2]; 461 goto mov; 462 463 case FNEG >> 2: 464 DPRINTF(FPE_INSN, ("fpu_execute: FNEG\n")); 465 rs1 = fs->fs_regs[rs2] ^ (1 << 31); 466 goto mov; 467 468 case FABS >> 2: 469 DPRINTF(FPE_INSN, ("fpu_execute: FABS\n")); 470 rs1 = fs->fs_regs[rs2] & ~(1 << 31); 471 mov: 472#ifndef SUN4U 473 fs->fs_regs[rd] = rs1; 474#else /* SUN4U */ 475 i = 1<<(type-1); 476 fs->fs_regs[rd++] = rs1; 477 while (--i > 0) 478 fs->fs_regs[rd++] = fs->fs_regs[++rs2]; 479#endif /* SUN4U */ 480 fs->fs_fsr = fe->fe_fsr; 481 return (0); /* success */ 482 483 case FSQRT >> 2: 484 DPRINTF(FPE_INSN, ("fpu_execute: FSQRT\n")); 485 fpu_explode(fe, &fe->fe_f1, type, rs2); 486 fp = fpu_sqrt(fe); 487 break; 488 489 case FADD >> 2: 490 DPRINTF(FPE_INSN, ("fpu_execute: FADD\n")); 491 fpu_explode(fe, &fe->fe_f1, type, rs1); 492 fpu_explode(fe, &fe->fe_f2, type, rs2); 493 fp = fpu_add(fe); 494 break; 495 496 case FSUB >> 2: 497 DPRINTF(FPE_INSN, ("fpu_execute: FSUB\n")); 498 fpu_explode(fe, &fe->fe_f1, type, rs1); 499 fpu_explode(fe, &fe->fe_f2, type, rs2); 500 fp = fpu_sub(fe); 501 break; 502 503 case FMUL >> 2: 504 DPRINTF(FPE_INSN, ("fpu_execute: FMUL\n")); 505 fpu_explode(fe, &fe->fe_f1, type, rs1); 506 fpu_explode(fe, &fe->fe_f2, type, rs2); 507 fp = fpu_mul(fe); 508 break; 509 510 case FDIV >> 2: 511 DPRINTF(FPE_INSN, ("fpu_execute: FDIV\n")); 512 fpu_explode(fe, &fe->fe_f1, type, rs1); 513 fpu_explode(fe, &fe->fe_f2, type, rs2); 514 fp = fpu_div(fe); 515 break; 516 517 case FCMP >> 2: 518 DPRINTF(FPE_INSN, ("fpu_execute: FCMP\n")); 519 fpu_explode(fe, &fe->fe_f1, type, rs1); 520 fpu_explode(fe, &fe->fe_f2, type, rs2); 521 fpu_compare(fe, 0); 522 goto cmpdone; 523 524 case FCMPE >> 2: 525 DPRINTF(FPE_INSN, ("fpu_execute: FCMPE\n")); 526 fpu_explode(fe, &fe->fe_f1, type, rs1); 527 fpu_explode(fe, &fe->fe_f2, type, rs2); 528 fpu_compare(fe, 1); 529 cmpdone: 530 /* 531 * The only possible exception here is NV; catch it 532 * early and get out, as there is no result register. 533 */ 534 cx = fe->fe_cx; 535 fsr = fe->fe_fsr | (cx << FSR_CX_SHIFT); 536 if (cx != 0) { 537 if (fsr & (FSR_NV << FSR_TEM_SHIFT)) { 538 fs->fs_fsr = (fsr & ~FSR_FTT) | 539 (FSR_TT_IEEE << FSR_FTT_SHIFT); 540 return (FPE); 541 } 542 fsr |= FSR_NV << FSR_AX_SHIFT; 543 } 544 fs->fs_fsr = fsr; 545 return (0); 546 547 case FSMULD >> 2: 548 case FDMULX >> 2: 549 DPRINTF(FPE_INSN, ("fpu_execute: FSMULx\n")); 550 if (type == FTYPE_EXT) 551 return (NOTFPU); 552 fpu_explode(fe, &fe->fe_f1, type, rs1); 553 fpu_explode(fe, &fe->fe_f2, type, rs2); 554 type++; /* single to double, or double to quad */ 555 fp = fpu_mul(fe); 556 break; 557 558#ifdef SUN4U 559 case FXTOS >> 2: 560 case FXTOD >> 2: 561 case FXTOQ >> 2: 562 DPRINTF(FPE_INSN, ("fpu_execute: FXTOx\n")); 563 type = FTYPE_LNG; 564 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 565 type = opf & 3; /* sneaky; depends on instruction encoding */ 566 break; 567 568 case FTOX >> 2: 569 DPRINTF(FPE_INSN, ("fpu_execute: FTOX\n")); 570 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 571 type = FTYPE_LNG; 572 /* Recalculate destination register */ 573 rd = instr.i_opf.i_rd; 574 break; 575 576#endif /* SUN4U */ 577 case FTOI >> 2: 578 DPRINTF(FPE_INSN, ("fpu_execute: FTOI\n")); 579 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 580 type = FTYPE_INT; 581 /* Recalculate destination register */ 582 rd = instr.i_opf.i_rd; 583 break; 584 585 case FTOS >> 2: 586 case FTOD >> 2: 587 case FTOQ >> 2: 588 DPRINTF(FPE_INSN, ("fpu_execute: FTOx\n")); 589 fpu_explode(fe, fp = &fe->fe_f1, type, rs2); 590 /* Recalculate rd with correct type info. */ 591 type = opf & 3; /* sneaky; depends on instruction encoding */ 592 mask = 0x3 >> (3 - type); 593 rd = instr.i_opf.i_rd; 594 rd = (rd & ~mask) | ((rd & mask & 0x1) << 5); 595 break; 596 } 597 598 /* 599 * ALU operation is complete. Collapse the result and then check 600 * for exceptions. If we got any, and they are enabled, do not 601 * alter the destination register, just stop with an exception. 602 * Otherwise set new current exceptions and accrue. 603 */ 604 fpu_implode(fe, fp, type, space); 605 cx = fe->fe_cx; 606 fsr = fe->fe_fsr; 607 if (cx != 0) { 608 mask = (fsr >> FSR_TEM_SHIFT) & FSR_TEM_MASK; 609 if (cx & mask) { 610 /* not accrued??? */ 611 fs->fs_fsr = (fsr & ~FSR_FTT) | 612 (FSR_TT_IEEE << FSR_FTT_SHIFT) | 613 (cx_to_trapx[(cx & mask) - 1] << FSR_CX_SHIFT); 614 return (FPE); 615 } 616 fsr |= (cx << FSR_CX_SHIFT) | (cx << FSR_AX_SHIFT); 617 } 618 fs->fs_fsr = fsr; 619 DPRINTF(FPE_REG, ("-> %c%d\n", (type == FTYPE_LNG) ? 'x' : 620 ((type == FTYPE_INT) ? 'i' : 621 ((type == FTYPE_SNG) ? 's' : 622 ((type == FTYPE_DBL) ? 'd' : 623 ((type == FTYPE_EXT) ? 'q' : '?')))), 624 rd)); 625 fs->fs_regs[rd] = space[0]; 626 if (type >= FTYPE_DBL || type == FTYPE_LNG) { 627 fs->fs_regs[rd + 1] = space[1]; 628 if (type > FTYPE_DBL) { 629 fs->fs_regs[rd + 2] = space[2]; 630 fs->fs_regs[rd + 3] = space[3]; 631 } 632 } 633 return (0); /* success */ 634} 635