1 /* $NetBSD: fpu_emu.c,v 1.3 2001/07/22 11:29:44 wiz Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Copyright (c) 1992, 1993 40 * The Regents of the University of California. All rights reserved. 41 * 42 * This software was developed by the Computer Systems Engineering group 43 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 44 * contributed to Berkeley. 45 * 46 * All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the University of 49 * California, Lawrence Berkeley Laboratory. 50 * 51 * Redistribution and use in source and binary forms, with or without 52 * modification, are permitted provided that the following conditions 53 * are met: 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. All advertising materials mentioning features or use of this software 60 * must display the following acknowledgement: 61 * This product includes software developed by the University of 62 * California, Berkeley and its contributors. 63 * 4. Neither the name of the University nor the names of its contributors 64 * may be used to endorse or promote products derived from this software 65 * without specific prior written permission. 66 * 67 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 68 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 69 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 70 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 71 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 72 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 73 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 74 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 75 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 76 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 77 * SUCH DAMAGE. 78 * 79 * @(#)fpu.c 8.1 (Berkeley) 6/11/93 80 */ 81 82 #include "opt_ddb.h" 83 84 #include <sys/param.h> 85 #include <sys/proc.h> 86 #include <sys/signal.h> 87 #include <sys/systm.h> 88 #include <sys/syslog.h> 89 #include <sys/signalvar.h> 90 91 #include <powerpc/instr.h> 92 #include <machine/reg.h> 93 #include <machine/fpu.h> 94 95 #include <powerpc/fpu/fpu_emu.h> 96 #include <powerpc/fpu/fpu_extern.h> 97 98 99 /* FPSR exception masks */ 100 #define FPSR_EX_MSK (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX| \ 101 FPSCR_XX|FPSCR_VXSNAN|FPSCR_VXISI|FPSCR_VXIDI| \ 102 FPSCR_VXZDZ|FPSCR_VXIMZ|FPSCR_VXVC|FPSCR_VXSOFT|\ 103 FPSCR_VXSQRT|FPSCR_VXCVI) 104 #define FPSR_EX (FPSCR_VE|FPSCR_OE|FPSCR_UE|FPSCR_ZE|FPSCR_XE) 105 #define FPSR_EXOP (FPSR_EX_MSK&(~FPSR_EX)) 106 107 108 int fpe_debug = 0; 109 110 #ifdef DDB 111 extern vaddr_t opc_disasm(vaddr_t loc, int opcode); 112 #endif 113 114 #ifdef DEBUG 115 /* 116 * Dump a `fpn' structure. 117 */ 118 void 119 fpu_dumpfpn(struct fpn *fp) 120 { 121 static char *class[] = { 122 "SNAN", "QNAN", "ZERO", "NUM", "INF" 123 }; 124 125 printf("%s %c.%x %x %x %xE%d", class[fp->fp_class + 2], 126 fp->fp_sign ? '-' : ' ', 127 fp->fp_mant[0], fp->fp_mant[1], 128 fp->fp_mant[2], fp->fp_mant[3], 129 fp->fp_exp); 130 } 131 #endif 132 133 /* 134 * fpu_execute returns the following error numbers (0 = no error): 135 */ 136 #define FPE 1 /* take a floating point exception */ 137 #define NOTFPU 2 /* not an FPU instruction */ 138 #define FAULT 3 139 140 141 /* 142 * Emulate a floating-point instruction. 143 * Return zero for success, else signal number. 144 * (Typically: zero, SIGFPE, SIGILL, SIGSEGV) 145 */ 146 int 147 fpu_emulate(struct trapframe *frame, struct fpreg *fpf) 148 { 149 static union instr insn; 150 static struct fpemu fe; 151 static int lastill = 0; 152 int sig; 153 154 /* initialize insn.is_datasize to tell it is *not* initialized */ 155 fe.fe_fpstate = fpf; 156 fe.fe_cx = 0; 157 158 /* always set this (to avoid a warning) */ 159 160 if (copyin((void *) (frame->srr0), &insn.i_int, sizeof (insn.i_int))) { 161 #ifdef DEBUG 162 printf("fpu_emulate: fault reading opcode\n"); 163 #endif 164 return SIGSEGV; 165 } 166 167 DPRINTF(FPE_EX, ("fpu_emulate: emulating insn %x at %p\n", 168 insn.i_int, (void *)frame->srr0)); 169 170 171 if ((insn.i_any.i_opcd == OPC_TWI) || 172 ((insn.i_any.i_opcd == OPC_integer_31) && 173 (insn.i_x.i_xo == OPC31_TW))) { 174 /* Check for the two trap insns. */ 175 DPRINTF(FPE_EX, ("fpu_emulate: SIGTRAP\n")); 176 return (SIGTRAP); 177 } 178 sig = 0; 179 switch (fpu_execute(frame, &fe, &insn)) { 180 case 0: 181 DPRINTF(FPE_EX, ("fpu_emulate: success\n")); 182 frame->srr0 += 4; 183 break; 184 185 case FPE: 186 DPRINTF(FPE_EX, ("fpu_emulate: SIGFPE\n")); 187 sig = SIGFPE; 188 break; 189 190 case FAULT: 191 DPRINTF(FPE_EX, ("fpu_emulate: SIGSEGV\n")); 192 sig = SIGSEGV; 193 break; 194 195 case NOTFPU: 196 default: 197 DPRINTF(FPE_EX, ("fpu_emulate: SIGILL\n")); 198 #ifdef DEBUG 199 if (fpe_debug & FPE_EX) { 200 printf("fpu_emulate: illegal insn %x at %p:", 201 insn.i_int, (void *) (frame->srr0)); 202 opc_disasm((vaddr_t)(frame->srr0), insn.i_int); 203 } 204 #endif 205 /* 206 * XXXX retry an illegal insn once due to cache issues. 207 */ 208 if (lastill == frame->srr0) { 209 sig = SIGILL; 210 #ifdef DEBUG 211 if (fpe_debug & FPE_EX) 212 Debugger(); 213 #endif 214 } 215 lastill = frame->srr0; 216 break; 217 } 218 219 return (sig); 220 } 221 222 /* 223 * Execute an FPU instruction (one that runs entirely in the FPU; not 224 * FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be 225 * modified to reflect the setting the hardware would have left. 226 * 227 * Note that we do not catch all illegal opcodes, so you can, for instance, 228 * multiply two integers this way. 229 */ 230 int 231 fpu_execute(struct trapframe *tf, struct fpemu *fe, union instr *insn) 232 { 233 struct fpn *fp; 234 union instr instr = *insn; 235 int *a; 236 vaddr_t addr; 237 int ra, rb, rc, rt, type, mask, fsr, cx, bf, setcr, cond; 238 struct fpreg *fs; 239 240 /* Setup work. */ 241 fp = NULL; 242 fs = fe->fe_fpstate; 243 fe->fe_fpscr = ((int *)&fs->fpscr)[1]; 244 245 /* 246 * On PowerPC all floating point values are stored in registers 247 * as doubles, even when used for single precision operations. 248 */ 249 type = FTYPE_DBL; 250 cond = instr.i_any.i_rc; 251 setcr = 0; 252 253 #if defined(DDB) && defined(DEBUG) 254 if (fpe_debug & FPE_EX) { 255 vaddr_t loc = tf->srr0; 256 257 printf("Trying to emulate: %p ", (void *)loc); 258 opc_disasm(loc, instr.i_int); 259 } 260 #endif 261 262 /* 263 * `Decode' and execute instruction. 264 */ 265 266 if ((instr.i_any.i_opcd >= OPC_LFS && instr.i_any.i_opcd <= OPC_STFDU) || 267 instr.i_any.i_opcd == OPC_integer_31) { 268 /* 269 * Handle load/store insns: 270 * 271 * Convert to/from single if needed, calculate addr, 272 * and update index reg if needed. 273 */ 274 double buf; 275 size_t size = sizeof(float); 276 int store, update; 277 278 cond = 0; /* ld/st never set condition codes */ 279 280 281 if (instr.i_any.i_opcd == OPC_integer_31) { 282 if (instr.i_x.i_xo == OPC31_STFIWX) { 283 /* Store as integer */ 284 ra = instr.i_x.i_ra; 285 rb = instr.i_x.i_rb; 286 DPRINTF(FPE_INSN, ("reg %d has %x reg %d has %x\n", 287 ra, tf->fixreg[ra], rb, tf->fixreg[rb])); 288 289 addr = tf->fixreg[rb]; 290 if (ra != 0) 291 addr += tf->fixreg[ra]; 292 rt = instr.i_x.i_rt; 293 a = (int *)&fs->fpreg[rt]; 294 DPRINTF(FPE_INSN, 295 ("fpu_execute: Store INT %x at %p\n", 296 a[1], (void *)addr)); 297 if (copyout(&a[1], (void *)addr, sizeof(int))) 298 return (FAULT); 299 return (0); 300 } 301 302 if ((instr.i_x.i_xo & OPC31_FPMASK) != OPC31_FPOP) 303 /* Not an indexed FP load/store op */ 304 return (NOTFPU); 305 306 store = (instr.i_x.i_xo & 0x80); 307 if (instr.i_x.i_xo & 0x40) 308 size = sizeof(double); 309 else 310 type = FTYPE_SNG; 311 update = (instr.i_x.i_xo & 0x20); 312 313 /* calculate EA of load/store */ 314 ra = instr.i_x.i_ra; 315 rb = instr.i_x.i_rb; 316 DPRINTF(FPE_INSN, ("reg %d has %x reg %d has %x\n", 317 ra, tf->fixreg[ra], rb, tf->fixreg[rb])); 318 addr = tf->fixreg[rb]; 319 if (ra != 0) 320 addr += tf->fixreg[ra]; 321 rt = instr.i_x.i_rt; 322 } else { 323 store = instr.i_d.i_opcd & 0x4; 324 if (instr.i_d.i_opcd & 0x2) 325 size = sizeof(double); 326 else 327 type = FTYPE_SNG; 328 update = instr.i_d.i_opcd & 0x1; 329 330 /* calculate EA of load/store */ 331 ra = instr.i_d.i_ra; 332 addr = instr.i_d.i_d; 333 DPRINTF(FPE_INSN, ("reg %d has %x displ %lx\n", 334 ra, tf->fixreg[ra], addr)); 335 if (ra != 0) 336 addr += tf->fixreg[ra]; 337 rt = instr.i_d.i_rt; 338 } 339 340 if (update && ra == 0) 341 return (NOTFPU); 342 343 if (store) { 344 /* Store */ 345 if (type != FTYPE_DBL) { 346 DPRINTF(FPE_INSN, 347 ("fpu_execute: Store SNG at %p\n", 348 (void *)addr)); 349 fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL, rt); 350 fpu_implode(fe, fp, type, (u_int *)&buf); 351 if (copyout(&buf, (void *)addr, size)) 352 return (FAULT); 353 } else { 354 DPRINTF(FPE_INSN, 355 ("fpu_execute: Store DBL at %p\n", 356 (void *)addr)); 357 if (copyout(&fs->fpreg[rt], (void *)addr, size)) 358 return (FAULT); 359 } 360 } else { 361 /* Load */ 362 DPRINTF(FPE_INSN, ("fpu_execute: Load from %p\n", 363 (void *)addr)); 364 if (copyin((const void *)addr, &fs->fpreg[rt], size)) 365 return (FAULT); 366 if (type != FTYPE_DBL) { 367 fpu_explode(fe, fp = &fe->fe_f1, type, rt); 368 fpu_implode(fe, fp, FTYPE_DBL, 369 (u_int *)&fs->fpreg[rt]); 370 } 371 } 372 if (update) 373 tf->fixreg[ra] = addr; 374 /* Complete. */ 375 return (0); 376 #ifdef notyet 377 } else if (instr.i_any.i_opcd == OPC_load_st_62) { 378 /* These are 64-bit extenstions */ 379 return (NOTFPU); 380 #endif 381 } else if (instr.i_any.i_opcd == OPC_sp_fp_59 || 382 instr.i_any.i_opcd == OPC_dp_fp_63) { 383 384 385 if (instr.i_any.i_opcd == OPC_dp_fp_63 && 386 !(instr.i_a.i_xo & OPC63M_MASK)) { 387 /* Format X */ 388 rt = instr.i_x.i_rt; 389 ra = instr.i_x.i_ra; 390 rb = instr.i_x.i_rb; 391 392 393 /* One of the special opcodes.... */ 394 switch (instr.i_x.i_xo) { 395 case OPC63_FCMPU: 396 DPRINTF(FPE_INSN, ("fpu_execute: FCMPU\n")); 397 rt >>= 2; 398 fpu_explode(fe, &fe->fe_f1, type, ra); 399 fpu_explode(fe, &fe->fe_f2, type, rb); 400 fpu_compare(fe, 0); 401 /* Make sure we do the condition regs. */ 402 cond = 0; 403 /* N.B.: i_rs is already left shifted by two. */ 404 bf = instr.i_x.i_rs & 0xfc; 405 setcr = 1; 406 break; 407 408 case OPC63_FRSP: 409 /* 410 * Convert to single: 411 * 412 * PowerPC uses this to round a double 413 * precision value to single precision, 414 * but values in registers are always 415 * stored in double precision format. 416 */ 417 DPRINTF(FPE_INSN, ("fpu_execute: FRSP\n")); 418 fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL, rb); 419 fpu_implode(fe, fp, FTYPE_SNG, 420 (u_int *)&fs->fpreg[rt]); 421 fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt); 422 type = FTYPE_DBL; 423 break; 424 case OPC63_FCTIW: 425 case OPC63_FCTIWZ: 426 DPRINTF(FPE_INSN, ("fpu_execute: FCTIW\n")); 427 fpu_explode(fe, fp = &fe->fe_f1, type, rb); 428 type = FTYPE_INT; 429 break; 430 case OPC63_FCMPO: 431 DPRINTF(FPE_INSN, ("fpu_execute: FCMPO\n")); 432 rt >>= 2; 433 fpu_explode(fe, &fe->fe_f1, type, ra); 434 fpu_explode(fe, &fe->fe_f2, type, rb); 435 fpu_compare(fe, 1); 436 /* Make sure we do the condition regs. */ 437 cond = 0; 438 /* N.B.: i_rs is already left shifted by two. */ 439 bf = instr.i_x.i_rs & 0xfc; 440 setcr = 1; 441 break; 442 case OPC63_MTFSB1: 443 DPRINTF(FPE_INSN, ("fpu_execute: MTFSB1\n")); 444 fe->fe_fpscr |= 445 (~(FPSCR_VX|FPSR_EX) & (1<<(31-rt))); 446 break; 447 case OPC63_FNEG: 448 DPRINTF(FPE_INSN, ("fpu_execute: FNEGABS\n")); 449 memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 450 sizeof(double)); 451 a = (int *)&fs->fpreg[rt]; 452 *a ^= (1 << 31); 453 break; 454 case OPC63_MCRFS: 455 DPRINTF(FPE_INSN, ("fpu_execute: MCRFS\n")); 456 cond = 0; 457 rt &= 0x1c; 458 ra &= 0x1c; 459 /* Extract the bits we want */ 460 mask = (fe->fe_fpscr >> (28 - ra)) & 0xf; 461 /* Clear the bits we copied. */ 462 fe->fe_cx = 463 (FPSR_EX_MSK | (0xf << (28 - ra))); 464 fe->fe_fpscr &= fe->fe_cx; 465 /* Now shove them in the right part of cr */ 466 tf->cr &= ~(0xf << (28 - rt)); 467 tf->cr |= (mask << (28 - rt)); 468 break; 469 case OPC63_MTFSB0: 470 DPRINTF(FPE_INSN, ("fpu_execute: MTFSB0\n")); 471 fe->fe_fpscr &= 472 ((FPSCR_VX|FPSR_EX) & ~(1<<(31-rt))); 473 break; 474 case OPC63_FMR: 475 DPRINTF(FPE_INSN, ("fpu_execute: FMR\n")); 476 memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 477 sizeof(double)); 478 break; 479 case OPC63_MTFSFI: 480 DPRINTF(FPE_INSN, ("fpu_execute: MTFSFI\n")); 481 rb >>= 1; 482 rt &= 0x1c; /* Already left-shifted 4 */ 483 fe->fe_cx = rb << (28 - rt); 484 mask = 0xf<<(28 - rt); 485 fe->fe_fpscr = (fe->fe_fpscr & ~mask) | 486 fe->fe_cx; 487 /* XXX weird stuff about OX, FX, FEX, and VX should be handled */ 488 break; 489 case OPC63_FNABS: 490 DPRINTF(FPE_INSN, ("fpu_execute: FABS\n")); 491 memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 492 sizeof(double)); 493 a = (int *)&fs->fpreg[rt]; 494 *a |= (1 << 31); 495 break; 496 case OPC63_FABS: 497 DPRINTF(FPE_INSN, ("fpu_execute: FABS\n")); 498 memcpy(&fs->fpreg[rt], &fs->fpreg[rb], 499 sizeof(double)); 500 a = (int *)&fs->fpreg[rt]; 501 *a &= ~(1 << 31); 502 break; 503 case OPC63_MFFS: 504 DPRINTF(FPE_INSN, ("fpu_execute: MFFS\n")); 505 memcpy(&fs->fpreg[rt], &fs->fpscr, 506 sizeof(fs->fpscr)); 507 break; 508 case OPC63_MTFSF: 509 DPRINTF(FPE_INSN, ("fpu_execute: MTFSF\n")); 510 if ((rt = instr.i_xfl.i_flm) == -1) 511 mask = -1; 512 else { 513 mask = 0; 514 /* Convert 1 bit -> 4 bits */ 515 for (ra = 0; ra < 8; ra ++) 516 if (rt & (1<<ra)) 517 mask |= (0xf<<(4*ra)); 518 } 519 a = (int *)&fs->fpreg[rt]; 520 fe->fe_cx = mask & a[1]; 521 fe->fe_fpscr = (fe->fe_fpscr&~mask) | 522 (fe->fe_cx); 523 /* XXX weird stuff about OX, FX, FEX, and VX should be handled */ 524 break; 525 case OPC63_FCTID: 526 case OPC63_FCTIDZ: 527 DPRINTF(FPE_INSN, ("fpu_execute: FCTID\n")); 528 fpu_explode(fe, fp = &fe->fe_f1, type, rb); 529 type = FTYPE_LNG; 530 break; 531 case OPC63_FCFID: 532 DPRINTF(FPE_INSN, ("fpu_execute: FCFID\n")); 533 type = FTYPE_LNG; 534 fpu_explode(fe, fp = &fe->fe_f1, type, rb); 535 type = FTYPE_DBL; 536 break; 537 default: 538 return (NOTFPU); 539 break; 540 } 541 } else { 542 /* Format A */ 543 rt = instr.i_a.i_frt; 544 ra = instr.i_a.i_fra; 545 rb = instr.i_a.i_frb; 546 rc = instr.i_a.i_frc; 547 548 type = FTYPE_SNG; 549 if (instr.i_any.i_opcd & 0x4) 550 type = FTYPE_DBL; 551 switch ((unsigned int)instr.i_a.i_xo) { 552 case OPC59_FDIVS: 553 DPRINTF(FPE_INSN, ("fpu_execute: FDIV\n")); 554 fpu_explode(fe, &fe->fe_f1, type, ra); 555 fpu_explode(fe, &fe->fe_f2, type, rb); 556 fp = fpu_div(fe); 557 break; 558 case OPC59_FSUBS: 559 DPRINTF(FPE_INSN, ("fpu_execute: FSUB\n")); 560 fpu_explode(fe, &fe->fe_f1, type, ra); 561 fpu_explode(fe, &fe->fe_f2, type, rb); 562 fp = fpu_sub(fe); 563 break; 564 case OPC59_FADDS: 565 DPRINTF(FPE_INSN, ("fpu_execute: FADD\n")); 566 fpu_explode(fe, &fe->fe_f1, type, ra); 567 fpu_explode(fe, &fe->fe_f2, type, rb); 568 fp = fpu_add(fe); 569 break; 570 case OPC59_FSQRTS: 571 DPRINTF(FPE_INSN, ("fpu_execute: FSQRT\n")); 572 fpu_explode(fe, &fe->fe_f1, type, rb); 573 fp = fpu_sqrt(fe); 574 break; 575 case OPC63M_FSEL: 576 DPRINTF(FPE_INSN, ("fpu_execute: FSEL\n")); 577 a = (int *)&fe->fe_fpstate->fpreg[ra]; 578 if ((*a & 0x80000000) && (*a & 0x7fffffff)) 579 /* fra < 0 */ 580 rc = rb; 581 DPRINTF(FPE_INSN, ("f%d => f%d\n", rc, rt)); 582 memcpy(&fs->fpreg[rt], &fs->fpreg[rc], 583 sizeof(double)); 584 break; 585 case OPC59_FRES: 586 DPRINTF(FPE_INSN, ("fpu_execute: FPRES\n")); 587 fpu_explode(fe, &fe->fe_f1, type, rb); 588 fp = fpu_sqrt(fe); 589 /* now we've gotta overwrite the dest reg */ 590 *((int *)&fe->fe_fpstate->fpreg[rt]) = 1; 591 fpu_explode(fe, &fe->fe_f1, FTYPE_INT, rt); 592 fpu_div(fe); 593 break; 594 case OPC59_FMULS: 595 DPRINTF(FPE_INSN, ("fpu_execute: FMUL\n")); 596 fpu_explode(fe, &fe->fe_f1, type, ra); 597 fpu_explode(fe, &fe->fe_f2, type, rc); 598 fp = fpu_mul(fe); 599 break; 600 case OPC63M_FRSQRTE: 601 /* Reciprocal sqrt() estimate */ 602 DPRINTF(FPE_INSN, ("fpu_execute: FRSQRTE\n")); 603 fpu_explode(fe, &fe->fe_f1, type, rb); 604 fe->fe_f2 = *fp; 605 /* now we've gotta overwrite the dest reg */ 606 *((int *)&fe->fe_fpstate->fpreg[rt]) = 1; 607 fpu_explode(fe, &fe->fe_f1, FTYPE_INT, rt); 608 fpu_div(fe); 609 break; 610 case OPC59_FMSUBS: 611 DPRINTF(FPE_INSN, ("fpu_execute: FMULSUB\n")); 612 fpu_explode(fe, &fe->fe_f1, type, ra); 613 fpu_explode(fe, &fe->fe_f2, type, rc); 614 fp = fpu_mul(fe); 615 fe->fe_f1 = *fp; 616 fpu_explode(fe, &fe->fe_f2, type, rb); 617 fp = fpu_sub(fe); 618 break; 619 case OPC59_FMADDS: 620 DPRINTF(FPE_INSN, ("fpu_execute: FMULADD\n")); 621 fpu_explode(fe, &fe->fe_f1, type, ra); 622 fpu_explode(fe, &fe->fe_f2, type, rc); 623 fp = fpu_mul(fe); 624 fe->fe_f1 = *fp; 625 fpu_explode(fe, &fe->fe_f2, type, rb); 626 fp = fpu_add(fe); 627 break; 628 case OPC59_FNMSUBS: 629 DPRINTF(FPE_INSN, ("fpu_execute: FNMSUB\n")); 630 fpu_explode(fe, &fe->fe_f1, type, ra); 631 fpu_explode(fe, &fe->fe_f2, type, rc); 632 fp = fpu_mul(fe); 633 fe->fe_f1 = *fp; 634 fpu_explode(fe, &fe->fe_f2, type, rb); 635 fp = fpu_sub(fe); 636 /* Negate */ 637 fp->fp_sign ^= 1; 638 break; 639 case OPC59_FNMADDS: 640 DPRINTF(FPE_INSN, ("fpu_execute: FNMADD\n")); 641 fpu_explode(fe, &fe->fe_f1, type, ra); 642 fpu_explode(fe, &fe->fe_f2, type, rc); 643 fp = fpu_mul(fe); 644 fe->fe_f1 = *fp; 645 fpu_explode(fe, &fe->fe_f2, type, rb); 646 fp = fpu_add(fe); 647 /* Negate */ 648 fp->fp_sign ^= 1; 649 break; 650 default: 651 return (NOTFPU); 652 break; 653 } 654 } 655 } else { 656 return (NOTFPU); 657 } 658 659 /* 660 * ALU operation is complete. Collapse the result and then check 661 * for exceptions. If we got any, and they are enabled, do not 662 * alter the destination register, just stop with an exception. 663 * Otherwise set new current exceptions and accrue. 664 */ 665 if (fp) 666 fpu_implode(fe, fp, type, (u_int *)&fs->fpreg[rt]); 667 cx = fe->fe_cx; 668 fsr = fe->fe_fpscr; 669 if (cx != 0) { 670 fsr &= ~FPSCR_FX; 671 if ((cx^fsr)&FPSR_EX_MSK) 672 fsr |= FPSCR_FX; 673 mask = fsr & FPSR_EX; 674 mask <<= (25-3); 675 if (cx & mask) 676 fsr |= FPSCR_FEX; 677 if (cx & FPSCR_FPRF) { 678 /* Need to replace CC */ 679 fsr &= ~FPSCR_FPRF; 680 } 681 if (cx & (FPSR_EXOP)) 682 fsr |= FPSCR_VX; 683 fsr |= cx; 684 DPRINTF(FPE_INSN, ("fpu_execute: cx %x, fsr %x\n", cx, fsr)); 685 } 686 687 if (cond) { 688 cond = fsr & 0xf0000000; 689 /* Isolate condition codes */ 690 cond >>= 28; 691 /* Move fpu condition codes to cr[1] */ 692 tf->cr &= (0x0f000000); 693 tf->cr |= (cond<<24); 694 DPRINTF(FPE_INSN, ("fpu_execute: cr[1] <= %x\n", cond)); 695 } 696 697 if (setcr) { 698 cond = fsr & FPSCR_FPCC; 699 /* Isolate condition codes */ 700 cond <<= 16; 701 /* Move fpu condition codes to cr[1] */ 702 tf->cr &= ~(0xf0000000>>bf); 703 tf->cr |= (cond>>bf); 704 DPRINTF(FPE_INSN, ("fpu_execute: cr[%d] (cr=%x) <= %x\n", bf/4, tf->cr, cond)); 705 } 706 707 ((int *)&fs->fpscr)[1] = fsr; 708 if (fsr & FPSCR_FEX) 709 return(FPE); 710 return (0); /* success */ 711 } 712