1/* $NetBSD: fpu_emulate.c,v 1.35 2011/07/18 14:11:27 isaki Exp $ */ 2 3/* 4 * Copyright (c) 1995 Gordon W. Ross 5 * some portion Copyright (c) 1995 Ken Nakata 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 4. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Gordon Ross 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * mc68881 emulator 36 * XXX - Just a start at it for now... 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: fpu_emulate.c,v 1.35 2011/07/18 14:11:27 isaki Exp $"); 41 42#include <sys/param.h> 43#include <sys/types.h> 44#include <sys/signal.h> 45#include <sys/systm.h> 46#include <machine/frame.h> 47 48#if defined(DDB) && defined(DEBUG_FPE) 49# include <m68k/db_machdep.h> 50#endif 51 52#include "fpu_emulate.h" 53 54#define fpe_abort(tfp, ksi, signo, code) \ 55 do { \ 56 (ksi)->ksi_signo = (signo); \ 57 (ksi)->ksi_code = (code); \ 58 (ksi)->ksi_addr = (void *)(frame)->f_pc; \ 59 return -1; \ 60 } while (/* CONSTCOND */ 0) 61 62static int fpu_emul_fmovmcr(struct fpemu *, struct instruction *); 63static int fpu_emul_fmovm(struct fpemu *, struct instruction *); 64static int fpu_emul_arith(struct fpemu *, struct instruction *); 65static int fpu_emul_type1(struct fpemu *, struct instruction *); 66static int fpu_emul_brcc(struct fpemu *, struct instruction *); 67static int test_cc(struct fpemu *, int); 68 69#ifdef DEBUG_FPE 70#define DUMP_INSN(insn) \ 71 printf("%s: insn={adv=%d,siz=%d,op=%04x,w1=%04x}\n", \ 72 __func__, \ 73 (insn)->is_advance, (insn)->is_datasize, \ 74 (insn)->is_opcode, (insn)->is_word1) 75#define DPRINTF(x) printf x 76#else 77#define DUMP_INSN(insn) do {} while (/* CONSTCOND */ 0) 78#define DPRINTF(x) do {} while (/* CONSTCOND */ 0) 79#endif 80 81/* 82 * Emulate a floating-point instruction. 83 * Return zero for success, else signal number. 84 * (Typically: zero, SIGFPE, SIGILL, SIGSEGV) 85 */ 86int 87fpu_emulate(struct frame *frame, struct fpframe *fpf, ksiginfo_t *ksi) 88{ 89 static struct instruction insn; 90 static struct fpemu fe; 91 int word, optype, sig; 92 93 94 /* initialize insn.is_datasize to tell it is *not* initialized */ 95 insn.is_datasize = -1; 96 97 fe.fe_frame = frame; 98 fe.fe_fpframe = fpf; 99 fe.fe_fpsr = fpf->fpf_fpsr; 100 fe.fe_fpcr = fpf->fpf_fpcr; 101 102 DPRINTF(("%s: ENTERING: FPSR=%08x, FPCR=%08x\n", 103 __func__, fe.fe_fpsr, fe.fe_fpcr)); 104 105 /* always set this (to avoid a warning) */ 106 insn.is_pc = frame->f_pc; 107 insn.is_nextpc = 0; 108 if (frame->f_format == 4) { 109 /* 110 * A format 4 is generated by the 68{EC,LC}040. The PC is 111 * already set to the instruction following the faulting 112 * instruction. We need to calculate that, anyway. The 113 * fslw is the PC of the faulted instruction, which is what 114 * we expect to be in f_pc. 115 * 116 * XXX - This is a hack; it assumes we at least know the 117 * sizes of all instructions we run across. 118 * XXX TODO: This may not be true, so we might want to save 119 * the PC in order to restore it later. 120 */ 121#if 0 122 insn.is_nextpc = frame->f_pc; 123#endif 124 insn.is_pc = frame->f_fmt4.f_fslw; 125 frame->f_pc = insn.is_pc; 126 } 127 128 word = fusword((void *)(insn.is_pc)); 129 if (word < 0) { 130 DPRINTF(("%s: fault reading opcode\n", __func__)); 131 fpe_abort(frame, ksi, SIGSEGV, SEGV_ACCERR); 132 } 133 134 if ((word & 0xf000) != 0xf000) { 135 DPRINTF(("%s: not coproc. insn.: opcode=0x%x\n", 136 __func__, word)); 137 fpe_abort(frame, ksi, SIGILL, ILL_ILLOPC); 138 } 139 140 if ((word & 0x0E00) != 0x0200) { 141 DPRINTF(("%s: bad coproc. id: opcode=0x%x\n", __func__, word)); 142 fpe_abort(frame, ksi, SIGILL, ILL_ILLOPC); 143 } 144 145 insn.is_opcode = word; 146 optype = (word & 0x01C0); 147 148 word = fusword((void *)(insn.is_pc + 2)); 149 if (word < 0) { 150 DPRINTF(("%s: fault reading word1\n", __func__)); 151 fpe_abort(frame, ksi, SIGSEGV, SEGV_ACCERR); 152 } 153 insn.is_word1 = word; 154 /* all FPU instructions are at least 4-byte long */ 155 insn.is_advance = 4; 156 157 DUMP_INSN(&insn); 158 159 /* 160 * Which family (or type) of opcode is it? 161 * Tests ordered by likelihood (hopefully). 162 * Certainly, type 0 is the most common. 163 */ 164 if (optype == 0x0000) { 165 /* type=0: generic */ 166 if ((word & 0xc000) == 0xc000) { 167 DPRINTF(("%s: fmovm FPr\n", __func__)); 168 sig = fpu_emul_fmovm(&fe, &insn); 169 } else if ((word & 0xc000) == 0x8000) { 170 DPRINTF(("%s: fmovm FPcr\n", __func__)); 171 sig = fpu_emul_fmovmcr(&fe, &insn); 172 } else if ((word & 0xe000) == 0x6000) { 173 /* fstore = fmove FPn,mem */ 174 DPRINTF(("%s: fmove to mem\n", __func__)); 175 sig = fpu_emul_fstore(&fe, &insn); 176 } else if ((word & 0xfc00) == 0x5c00) { 177 /* fmovecr */ 178 DPRINTF(("%s: fmovecr\n", __func__)); 179 sig = fpu_emul_fmovecr(&fe, &insn); 180 } else if ((word & 0xa07f) == 0x26) { 181 /* fscale */ 182 DPRINTF(("%s: fscale\n", __func__)); 183 sig = fpu_emul_fscale(&fe, &insn); 184 } else { 185 DPRINTF(("%s: other type0\n", __func__)); 186 /* all other type0 insns are arithmetic */ 187 sig = fpu_emul_arith(&fe, &insn); 188 } 189 if (sig == 0) { 190 DPRINTF(("%s: type 0 returned 0\n", __func__)); 191 sig = fpu_upd_excp(&fe); 192 } 193 } else if (optype == 0x0080 || optype == 0x00C0) { 194 /* type=2 or 3: fbcc, short or long disp. */ 195 DPRINTF(("%s: fbcc %s\n", __func__, 196 (optype & 0x40) ? "long" : "short")); 197 sig = fpu_emul_brcc(&fe, &insn); 198 } else if (optype == 0x0040) { 199 /* type=1: fdbcc, fscc, ftrapcc */ 200 DPRINTF(("%s: type1\n", __func__)); 201 sig = fpu_emul_type1(&fe, &insn); 202 } else { 203 /* type=4: fsave (privileged) */ 204 /* type=5: frestore (privileged) */ 205 /* type=6: reserved */ 206 /* type=7: reserved */ 207 DPRINTF(("%s: bad opcode type: opcode=0x%x\n", __func__, 208 insn.is_opcode)); 209 sig = SIGILL; 210 } 211 212 DUMP_INSN(&insn); 213 214 /* 215 * XXX it is not clear to me, if we should progress the PC always, 216 * for SIGFPE || 0, or only for 0; however, without SIGFPE, we 217 * don't pass the signalling regression tests. -is 218 */ 219 if ((sig == 0) || (sig == SIGFPE)) 220 frame->f_pc += insn.is_advance; 221#if defined(DDB) && defined(DEBUG_FPE) 222 else { 223 printf("%s: sig=%d, opcode=%x, word1=%x\n", __func__, 224 sig, insn.is_opcode, insn.is_word1); 225 kdb_trap(-1, (db_regs_t *)&frame); 226 } 227#endif 228#if 0 /* XXX something is wrong */ 229 if (frame->f_format == 4) { 230 /* XXX Restore PC -- 68{EC,LC}040 only */ 231 if (insn.is_nextpc) 232 frame->f_pc = insn.is_nextpc; 233 } 234#endif 235 236 DPRINTF(("%s: EXITING: w/FPSR=%08x, FPCR=%08x\n", __func__, 237 fe.fe_fpsr, fe.fe_fpcr)); 238 239 if (sig) 240 fpe_abort(frame, ksi, sig, 0); 241 return sig; 242} 243 244/* update accrued exception bits and see if there's an FP exception */ 245int 246fpu_upd_excp(struct fpemu *fe) 247{ 248 u_int fpsr; 249 u_int fpcr; 250 251 fpsr = fe->fe_fpsr; 252 fpcr = fe->fe_fpcr; 253 /* 254 * update fpsr accrued exception bits; each insn doesn't have to 255 * update this 256 */ 257 if (fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR)) { 258 fpsr |= FPSR_AIOP; 259 } 260 if (fpsr & FPSR_OVFL) { 261 fpsr |= FPSR_AOVFL; 262 } 263 if ((fpsr & FPSR_UNFL) && (fpsr & FPSR_INEX2)) { 264 fpsr |= FPSR_AUNFL; 265 } 266 if (fpsr & FPSR_DZ) { 267 fpsr |= FPSR_ADZ; 268 } 269 if (fpsr & (FPSR_INEX1 | FPSR_INEX2 | FPSR_OVFL)) { 270 fpsr |= FPSR_AINEX; 271 } 272 273 fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr; 274 275 return (fpsr & fpcr & FPSR_EXCP) ? SIGFPE : 0; 276} 277 278/* update fpsr according to fp (= result of an fp op) */ 279u_int 280fpu_upd_fpsr(struct fpemu *fe, struct fpn *fp) 281{ 282 u_int fpsr; 283 284 DPRINTF(("%s: previous fpsr=%08x\n", __func__, fe->fe_fpsr)); 285 /* clear all condition code */ 286 fpsr = fe->fe_fpsr & ~FPSR_CCB; 287 288 DPRINTF(("%s: result is a ", __func__)); 289 if (fp->fp_sign) { 290 DPRINTF(("negative ")); 291 fpsr |= FPSR_NEG; 292 } else { 293 DPRINTF(("positive ")); 294 } 295 296 switch (fp->fp_class) { 297 case FPC_SNAN: 298 DPRINTF(("signaling NAN\n")); 299 fpsr |= (FPSR_NAN | FPSR_SNAN); 300 break; 301 case FPC_QNAN: 302 DPRINTF(("quiet NAN\n")); 303 fpsr |= FPSR_NAN; 304 break; 305 case FPC_ZERO: 306 DPRINTF(("Zero\n")); 307 fpsr |= FPSR_ZERO; 308 break; 309 case FPC_INF: 310 DPRINTF(("Inf\n")); 311 fpsr |= FPSR_INF; 312 break; 313 default: 314 DPRINTF(("Number\n")); 315 /* anything else is treated as if it is a number */ 316 break; 317 } 318 319 fe->fe_fpsr = fe->fe_fpframe->fpf_fpsr = fpsr; 320 321 DPRINTF(("%s: new fpsr=%08x\n", __func__, fe->fe_fpframe->fpf_fpsr)); 322 323 return fpsr; 324} 325 326static int 327fpu_emul_fmovmcr(struct fpemu *fe, struct instruction *insn) 328{ 329 struct frame *frame = fe->fe_frame; 330 struct fpframe *fpf = fe->fe_fpframe; 331 int sig; 332 int reglist; 333 int fpu_to_mem; 334 335 /* move to/from control registers */ 336 reglist = (insn->is_word1 & 0x1c00) >> 10; 337 /* Bit 13 selects direction (FPU to/from Mem) */ 338 fpu_to_mem = insn->is_word1 & 0x2000; 339 340 insn->is_datasize = 4; 341 insn->is_advance = 4; 342 sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode); 343 if (sig) 344 return sig; 345 346 if (reglist != 1 && reglist != 2 && reglist != 4 && 347 (insn->is_ea.ea_flags & EA_DIRECT)) { 348 /* attempted to copy more than one FPcr to CPU regs */ 349 DPRINTF(("%s: tried to copy too many FPcr\n", __func__)); 350 return SIGILL; 351 } 352 353 if (reglist & 4) { 354 /* fpcr */ 355 if ((insn->is_ea.ea_flags & EA_DIRECT) && 356 insn->is_ea.ea_regnum >= 8 /* address reg */) { 357 /* attempted to copy FPCR to An */ 358 DPRINTF(("%s: tried to copy FPCR from/to A%d\n", 359 __func__, insn->is_ea.ea_regnum & 7)); 360 return SIGILL; 361 } 362 if (fpu_to_mem) { 363 sig = fpu_store_ea(frame, insn, &insn->is_ea, 364 (char *)&fpf->fpf_fpcr); 365 } else { 366 sig = fpu_load_ea(frame, insn, &insn->is_ea, 367 (char *)&fpf->fpf_fpcr); 368 } 369 } 370 if (sig) 371 return sig; 372 373 if (reglist & 2) { 374 /* fpsr */ 375 if ((insn->is_ea.ea_flags & EA_DIRECT) && 376 insn->is_ea.ea_regnum >= 8 /* address reg */) { 377 /* attempted to copy FPSR to An */ 378 DPRINTF(("%s: tried to copy FPSR from/to A%d\n", 379 __func__, insn->is_ea.ea_regnum & 7)); 380 return SIGILL; 381 } 382 if (fpu_to_mem) { 383 sig = fpu_store_ea(frame, insn, &insn->is_ea, 384 (char *)&fpf->fpf_fpsr); 385 } else { 386 sig = fpu_load_ea(frame, insn, &insn->is_ea, 387 (char *)&fpf->fpf_fpsr); 388 } 389 } 390 if (sig) 391 return sig; 392 393 if (reglist & 1) { 394 /* fpiar - can be moved to/from An */ 395 if (fpu_to_mem) { 396 sig = fpu_store_ea(frame, insn, &insn->is_ea, 397 (char *)&fpf->fpf_fpiar); 398 } else { 399 sig = fpu_load_ea(frame, insn, &insn->is_ea, 400 (char *)&fpf->fpf_fpiar); 401 } 402 } 403 return sig; 404} 405 406/* 407 * type 0: fmovem 408 * Separated out of fpu_emul_type0 for efficiency. 409 * In this function, we know: 410 * (opcode & 0x01C0) == 0 411 * (word1 & 0x8000) == 0x8000 412 * 413 * No conversion or rounding is done by this instruction, 414 * and the FPSR is not affected. 415 */ 416static int 417fpu_emul_fmovm(struct fpemu *fe, struct instruction *insn) 418{ 419 struct frame *frame = fe->fe_frame; 420 struct fpframe *fpf = fe->fe_fpframe; 421 int word1, sig; 422 int reglist, regmask, regnum; 423 int fpu_to_mem, order; 424 int w1_post_incr; 425 int *fpregs; 426 427 insn->is_advance = 4; 428 insn->is_datasize = 12; 429 word1 = insn->is_word1; 430 431 /* Bit 13 selects direction (FPU to/from Mem) */ 432 fpu_to_mem = word1 & 0x2000; 433 434 /* 435 * Bits 12,11 select register list mode: 436 * 0,0: Static reg list, pre-decr. 437 * 0,1: Dynamic reg list, pre-decr. 438 * 1,0: Static reg list, post-incr. 439 * 1,1: Dynamic reg list, post-incr 440 */ 441 w1_post_incr = word1 & 0x1000; 442 if (word1 & 0x0800) { 443 /* dynamic reg list */ 444 reglist = frame->f_regs[(word1 & 0x70) >> 4]; 445 } else { 446 reglist = word1; 447 } 448 reglist &= 0xFF; 449 450 /* Get effective address. (modreg=opcode&077) */ 451 sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode); 452 if (sig) 453 return sig; 454 455 /* Get address of soft coprocessor regs. */ 456 fpregs = &fpf->fpf_regs[0]; 457 458 if (insn->is_ea.ea_flags & EA_PREDECR) { 459 regnum = 7; 460 order = -1; 461 } else { 462 regnum = 0; 463 order = 1; 464 } 465 466 regmask = 0x80; 467 while ((0 <= regnum) && (regnum < 8)) { 468 if (regmask & reglist) { 469 if (fpu_to_mem) { 470 sig = fpu_store_ea(frame, insn, &insn->is_ea, 471 (char *)&fpregs[regnum * 3]); 472 DPRINTF(("%s: FP%d (%08x,%08x,%08x) saved\n", 473 __func__, regnum, 474 fpregs[regnum * 3], 475 fpregs[regnum * 3 + 1], 476 fpregs[regnum * 3 + 2])); 477 } else { /* mem to fpu */ 478 sig = fpu_load_ea(frame, insn, &insn->is_ea, 479 (char *)&fpregs[regnum * 3]); 480 DPRINTF(("%s: FP%d (%08x,%08x,%08x) loaded\n", 481 __func__, regnum, 482 fpregs[regnum * 3], 483 fpregs[regnum * 3 + 1], 484 fpregs[regnum * 3 + 2])); 485 } 486 if (sig) 487 break; 488 } 489 regnum += order; 490 regmask >>= 1; 491 } 492 493 return sig; 494} 495 496struct fpn * 497fpu_cmp(struct fpemu *fe) 498{ 499 struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2; 500 501 /* take care of special cases */ 502 if (x->fp_class < 0 || y->fp_class < 0) { 503 /* if either of two is a SNAN, result is SNAN */ 504 x->fp_class = 505 (y->fp_class < x->fp_class) ? y->fp_class : x->fp_class; 506 } else if (x->fp_class == FPC_INF) { 507 if (y->fp_class == FPC_INF) { 508 /* both infinities */ 509 if (x->fp_sign == y->fp_sign) { 510 /* return a signed zero */ 511 x->fp_class = FPC_ZERO; 512 } else { 513 /* return a faked number w/x's sign */ 514 x->fp_class = FPC_NUM; 515 x->fp_exp = 16383; 516 x->fp_mant[0] = FP_1; 517 } 518 } else { 519 /* y is a number */ 520 /* return a forged number w/x's sign */ 521 x->fp_class = FPC_NUM; 522 x->fp_exp = 16383; 523 x->fp_mant[0] = FP_1; 524 } 525 } else if (y->fp_class == FPC_INF) { 526 /* x is a Num but y is an Inf */ 527 /* return a forged number w/y's sign inverted */ 528 x->fp_class = FPC_NUM; 529 x->fp_sign = !y->fp_sign; 530 x->fp_exp = 16383; 531 x->fp_mant[0] = FP_1; 532 } else { 533 /* 534 * x and y are both numbers or zeros, 535 * or pair of a number and a zero 536 */ 537 y->fp_sign = !y->fp_sign; 538 x = fpu_add(fe); /* (x - y) */ 539 /* 540 * FCMP does not set Inf bit in CC, so return a forged number 541 * (value doesn't matter) if Inf is the result of fsub. 542 */ 543 if (x->fp_class == FPC_INF) { 544 x->fp_class = FPC_NUM; 545 x->fp_exp = 16383; 546 x->fp_mant[0] = FP_1; 547 } 548 } 549 return x; 550} 551 552/* 553 * arithmetic oprations 554 */ 555static int 556fpu_emul_arith(struct fpemu *fe, struct instruction *insn) 557{ 558 struct frame *frame = fe->fe_frame; 559 u_int *fpregs = &(fe->fe_fpframe->fpf_regs[0]); 560 struct fpn *res; 561 int word1, sig = 0; 562 int regnum, format; 563 int discard_result = 0; 564 u_int buf[3]; 565#ifdef DEBUG_FPE 566 int flags; 567 char regname; 568#endif 569 570 fe->fe_fpsr &= ~FPSR_EXCP; 571 572 DUMP_INSN(insn); 573 574 DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__, 575 fe->fe_fpsr, fe->fe_fpcr)); 576 577 word1 = insn->is_word1; 578 format = (word1 >> 10) & 7; 579 regnum = (word1 >> 7) & 7; 580 581 /* fetch a source operand : may not be used */ 582 DPRINTF(("%s: dst/src FP%d=%08x,%08x,%08x\n", __func__, 583 regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1], 584 fpregs[regnum * 3 + 2])); 585 586 fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &fpregs[regnum * 3]); 587 588 DUMP_INSN(insn); 589 590 /* get the other operand which is always the source */ 591 if ((word1 & 0x4000) == 0) { 592 DPRINTF(("%s: FP%d op FP%d => FP%d\n", __func__, 593 format, regnum, regnum)); 594 DPRINTF(("%s: src opr FP%d=%08x,%08x,%08x\n", __func__, 595 format, fpregs[format * 3], fpregs[format * 3 + 1], 596 fpregs[format * 3 + 2])); 597 fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]); 598 } else { 599 /* the operand is in memory */ 600 if (format == FTYPE_DBL) { 601 insn->is_datasize = 8; 602 } else if (format == FTYPE_SNG || format == FTYPE_LNG) { 603 insn->is_datasize = 4; 604 } else if (format == FTYPE_WRD) { 605 insn->is_datasize = 2; 606 } else if (format == FTYPE_BYT) { 607 insn->is_datasize = 1; 608 } else if (format == FTYPE_EXT) { 609 insn->is_datasize = 12; 610 } else { 611 /* invalid or unsupported operand format */ 612 sig = SIGFPE; 613 return sig; 614 } 615 616 /* Get effective address. (modreg=opcode&077) */ 617 sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode); 618 if (sig) { 619 DPRINTF(("%s: error in fpu_decode_ea\n", __func__)); 620 return sig; 621 } 622 623 DUMP_INSN(insn); 624 625#ifdef DEBUG_FPE 626 printf("%s: addr mode = ", __func__); 627 flags = insn->is_ea.ea_flags; 628 regname = (insn->is_ea.ea_regnum & 8) ? 'a' : 'd'; 629 630 if (flags & EA_DIRECT) { 631 printf("%c%d\n", regname, insn->is_ea.ea_regnum & 7); 632 } else if (flags & EA_PC_REL) { 633 if (flags & EA_OFFSET) { 634 printf("pc@(%d)\n", insn->is_ea.ea_offset); 635 } else if (flags & EA_INDEXED) { 636 printf("pc@(...)\n"); 637 } 638 } else if (flags & EA_PREDECR) { 639 printf("%c%d@-\n", regname, insn->is_ea.ea_regnum & 7); 640 } else if (flags & EA_POSTINCR) { 641 printf("%c%d@+\n", regname, insn->is_ea.ea_regnum & 7); 642 } else if (flags & EA_OFFSET) { 643 printf("%c%d@(%d)\n", regname, 644 insn->is_ea.ea_regnum & 7, 645 insn->is_ea.ea_offset); 646 } else if (flags & EA_INDEXED) { 647 printf("%c%d@(...)\n", regname, 648 insn->is_ea.ea_regnum & 7); 649 } else if (flags & EA_ABS) { 650 printf("0x%08x\n", insn->is_ea.ea_absaddr); 651 } else if (flags & EA_IMMED) { 652 printf("#0x%08x,%08x,%08x\n", 653 insn->is_ea.ea_immed[0], 654 insn->is_ea.ea_immed[1], 655 insn->is_ea.ea_immed[2]); 656 } else { 657 printf("%c%d@\n", regname, insn->is_ea.ea_regnum & 7); 658 } 659#endif /* DEBUG_FPE */ 660 661 fpu_load_ea(frame, insn, &insn->is_ea, (char*)buf); 662 if (format == FTYPE_WRD) { 663 /* sign-extend */ 664 buf[0] &= 0xffff; 665 if (buf[0] & 0x8000) 666 buf[0] |= 0xffff0000; 667 format = FTYPE_LNG; 668 } else if (format == FTYPE_BYT) { 669 /* sign-extend */ 670 buf[0] &= 0xff; 671 if (buf[0] & 0x80) 672 buf[0] |= 0xffffff00; 673 format = FTYPE_LNG; 674 } 675 DPRINTF(("%s: src = %08x %08x %08x, siz = %d\n", __func__, 676 buf[0], buf[1], buf[2], insn->is_datasize)); 677 fpu_explode(fe, &fe->fe_f2, format, buf); 678 } 679 680 DUMP_INSN(insn); 681 682 /* 683 * An arithmetic instruction emulate function has a prototype of 684 * struct fpn *fpu_op(struct fpemu *); 685 * 686 * 1) If the instruction is monadic, then fpu_op() must use 687 * fe->fe_f2 as its operand, and return a pointer to the 688 * result. 689 * 690 * 2) If the instruction is diadic, then fpu_op() must use 691 * fe->fe_f1 and fe->fe_f2 as its two operands, and return a 692 * pointer to the result. 693 * 694 */ 695 res = NULL; 696 switch (word1 & 0x7f) { 697 case 0x00: /* fmove */ 698 res = &fe->fe_f2; 699 break; 700 701 case 0x01: /* fint */ 702 res = fpu_int(fe); 703 break; 704 705 case 0x02: /* fsinh */ 706 res = fpu_sinh(fe); 707 break; 708 709 case 0x03: /* fintrz */ 710 res = fpu_intrz(fe); 711 break; 712 713 case 0x04: /* fsqrt */ 714 res = fpu_sqrt(fe); 715 break; 716 717 case 0x06: /* flognp1 */ 718 res = fpu_lognp1(fe); 719 break; 720 721 case 0x08: /* fetoxm1 */ 722 res = fpu_etoxm1(fe); 723 break; 724 725 case 0x09: /* ftanh */ 726 res = fpu_tanh(fe); 727 break; 728 729 case 0x0A: /* fatan */ 730 res = fpu_atan(fe); 731 break; 732 733 case 0x0C: /* fasin */ 734 res = fpu_asin(fe); 735 break; 736 737 case 0x0D: /* fatanh */ 738 res = fpu_atanh(fe); 739 break; 740 741 case 0x0E: /* fsin */ 742 res = fpu_sin(fe); 743 break; 744 745 case 0x0F: /* ftan */ 746 res = fpu_tan(fe); 747 break; 748 749 case 0x10: /* fetox */ 750 res = fpu_etox(fe); 751 break; 752 753 case 0x11: /* ftwotox */ 754 res = fpu_twotox(fe); 755 break; 756 757 case 0x12: /* ftentox */ 758 res = fpu_tentox(fe); 759 break; 760 761 case 0x14: /* flogn */ 762 res = fpu_logn(fe); 763 break; 764 765 case 0x15: /* flog10 */ 766 res = fpu_log10(fe); 767 break; 768 769 case 0x16: /* flog2 */ 770 res = fpu_log2(fe); 771 break; 772 773 case 0x18: /* fabs */ 774 fe->fe_f2.fp_sign = 0; 775 res = &fe->fe_f2; 776 break; 777 778 case 0x19: /* fcosh */ 779 res = fpu_cosh(fe); 780 break; 781 782 case 0x1A: /* fneg */ 783 fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; 784 res = &fe->fe_f2; 785 break; 786 787 case 0x1C: /* facos */ 788 res = fpu_acos(fe); 789 break; 790 791 case 0x1D: /* fcos */ 792 res = fpu_cos(fe); 793 break; 794 795 case 0x1E: /* fgetexp */ 796 res = fpu_getexp(fe); 797 break; 798 799 case 0x1F: /* fgetman */ 800 res = fpu_getman(fe); 801 break; 802 803 case 0x20: /* fdiv */ 804 case 0x24: /* fsgldiv: cheating - better than nothing */ 805 res = fpu_div(fe); 806 break; 807 808 case 0x21: /* fmod */ 809 res = fpu_mod(fe); 810 break; 811 812 case 0x28: /* fsub */ 813 fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */ 814 /* FALLTHROUGH */ 815 case 0x22: /* fadd */ 816 res = fpu_add(fe); 817 break; 818 819 case 0x23: /* fmul */ 820 case 0x27: /* fsglmul: cheating - better than nothing */ 821 res = fpu_mul(fe); 822 break; 823 824 case 0x25: /* frem */ 825 res = fpu_rem(fe); 826 break; 827 828 case 0x26: 829 /* fscale is handled by a separate function */ 830 break; 831 832 case 0x30: 833 case 0x31: 834 case 0x32: 835 case 0x33: 836 case 0x34: 837 case 0x35: 838 case 0x36: 839 case 0x37: /* fsincos */ 840 res = fpu_sincos(fe, word1 & 7); 841 break; 842 843 case 0x38: /* fcmp */ 844 res = fpu_cmp(fe); 845 discard_result = 1; 846 break; 847 848 case 0x3A: /* ftst */ 849 res = &fe->fe_f2; 850 discard_result = 1; 851 break; 852 853 default: /* possibly 040/060 instructions */ 854 DPRINTF(("%s: bad opcode=0x%x, word1=0x%x\n", __func__, 855 insn->is_opcode, insn->is_word1)); 856 sig = SIGILL; 857 } 858 859 /* for sanity */ 860 if (res == NULL) 861 sig = SIGILL; 862 863 if (sig == 0) { 864 if (!discard_result) 865 fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]); 866 867 /* update fpsr according to the result of operation */ 868 fpu_upd_fpsr(fe, res); 869#ifdef DEBUG_FPE 870 if (!discard_result) { 871 printf("%s: %08x,%08x,%08x stored in FP%d\n", __func__, 872 fpregs[regnum * 3], 873 fpregs[regnum * 3 + 1], 874 fpregs[regnum * 3 + 2], 875 regnum); 876 } else { 877 static const char *class_name[] = 878 { "SNAN", "QNAN", "ZERO", "NUM", "INF" }; 879 printf("%s: result(%s,%c,%d,%08x,%08x,%08x) " 880 "discarded\n", __func__, 881 class_name[res->fp_class + 2], 882 res->fp_sign ? '-' : '+', res->fp_exp, 883 res->fp_mant[0], res->fp_mant[1], 884 res->fp_mant[2]); 885 } 886#endif 887 } else { 888 DPRINTF(("%s: received signal %d\n", __func__, sig)); 889 } 890 891 DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__, 892 fe->fe_fpsr, fe->fe_fpcr)); 893 894 DUMP_INSN(insn); 895 896 return sig; 897} 898 899/* 900 * test condition code according to the predicate in the opcode. 901 * returns -1 when the predicate evaluates to true, 0 when false. 902 * signal numbers are returned when an error is detected. 903 */ 904static int 905test_cc(struct fpemu *fe, int pred) 906{ 907 int result, sig_bsun, invert; 908 int fpsr; 909 910 fpsr = fe->fe_fpsr; 911 invert = 0; 912 fpsr &= ~FPSR_EXCP; /* clear all exceptions */ 913 DPRINTF(("%s: fpsr=0x%08x\n", __func__, fpsr)); 914 pred &= 0x3f; /* lowest 6 bits */ 915 916 DPRINTF(("%s: ", __func__)); 917 918 if (pred >= 0x20) { 919 DPRINTF(("Illegal condition code\n")); 920 return SIGILL; 921 } else if (pred & 0x10) { 922 /* IEEE nonaware tests */ 923 sig_bsun = 1; 924 pred &= 0x0f; /* lower 4 bits */ 925 } else { 926 /* IEEE aware tests */ 927 DPRINTF(("IEEE ")); 928 sig_bsun = 0; 929 } 930 931 if (pred & 0x08) { 932 DPRINTF(("Not ")); 933 /* predicate is "NOT ..." */ 934 pred ^= 0xf; /* invert */ 935 invert = -1; 936 } 937 switch (pred) { 938 case 0: /* (Signaling) False */ 939 DPRINTF(("False")); 940 result = 0; 941 break; 942 case 1: /* (Signaling) Equal */ 943 DPRINTF(("Equal")); 944 result = -((fpsr & FPSR_ZERO) == FPSR_ZERO); 945 break; 946 case 2: /* Greater Than */ 947 DPRINTF(("GT")); 948 result = -((fpsr & (FPSR_NAN|FPSR_ZERO|FPSR_NEG)) == 0); 949 break; 950 case 3: /* Greater or Equal */ 951 DPRINTF(("GE")); 952 result = -((fpsr & FPSR_ZERO) || 953 (fpsr & (FPSR_NAN|FPSR_NEG)) == 0); 954 break; 955 case 4: /* Less Than */ 956 DPRINTF(("LT")); 957 result = -((fpsr & (FPSR_NAN|FPSR_ZERO|FPSR_NEG)) == FPSR_NEG); 958 break; 959 case 5: /* Less or Equal */ 960 DPRINTF(("LE")); 961 result = -((fpsr & FPSR_ZERO) || 962 ((fpsr & (FPSR_NAN|FPSR_NEG)) == FPSR_NEG)); 963 break; 964 case 6: /* Greater or Less than */ 965 DPRINTF(("GLT")); 966 result = -((fpsr & (FPSR_NAN|FPSR_ZERO)) == 0); 967 break; 968 case 7: /* Greater, Less or Equal */ 969 DPRINTF(("GLE")); 970 result = -((fpsr & FPSR_NAN) == 0); 971 break; 972 default: 973 /* invalid predicate */ 974 DPRINTF(("Invalid predicate\n")); 975 return SIGILL; 976 } 977 /* if the predicate is "NOT ...", then invert the result */ 978 result ^= invert; 979 DPRINTF(("=> %s (%d)\n", result ? "true" : "false", result)); 980 /* if it's an IEEE unaware test and NAN is set, BSUN is set */ 981 if (sig_bsun && (fpsr & FPSR_NAN)) { 982 fpsr |= FPSR_BSUN; 983 } 984 985 /* put fpsr back */ 986 fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr; 987 988 return result; 989} 990 991/* 992 * type 1: fdbcc, fscc, ftrapcc 993 * In this function, we know: 994 * (opcode & 0x01C0) == 0x0040 995 */ 996static int 997fpu_emul_type1(struct fpemu *fe, struct instruction *insn) 998{ 999 struct frame *frame = fe->fe_frame; 1000 int advance, sig, branch, displ; 1001 1002 branch = test_cc(fe, insn->is_word1); 1003 fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr; 1004 1005 insn->is_advance = 4; 1006 sig = 0; 1007 1008 switch (insn->is_opcode & 070) { 1009 case 010: /* fdbcc */ 1010 if (branch == -1) { 1011 /* advance */ 1012 insn->is_advance = 6; 1013 } else if (!branch) { 1014 /* decrement Dn and if (Dn != -1) branch */ 1015 uint16_t count = frame->f_regs[insn->is_opcode & 7]; 1016 1017 if (count-- != 0) { 1018 displ = fusword((void *)(insn->is_pc + 1019 insn->is_advance)); 1020 if (displ < 0) { 1021 DPRINTF(("%s: fault reading " 1022 "displacement\n", __func__)); 1023 return SIGSEGV; 1024 } 1025 /* sign-extend the displacement */ 1026 displ &= 0xffff; 1027 if (displ & 0x8000) { 1028 displ |= 0xffff0000; 1029 } 1030 insn->is_advance += displ; 1031#if 0 /* XXX */ 1032 insn->is_nextpc = insn->is_pc + 1033 insn->is_advance; 1034#endif 1035 } else { 1036 insn->is_advance = 6; 1037 } 1038 /* write it back */ 1039 frame->f_regs[insn->is_opcode & 7] &= 0xffff0000; 1040 frame->f_regs[insn->is_opcode & 7] |= (uint32_t)count; 1041 } else { /* got a signal */ 1042 sig = SIGFPE; 1043 } 1044 break; 1045 1046 case 070: /* ftrapcc or fscc */ 1047 advance = 4; 1048 if ((insn->is_opcode & 07) >= 2) { 1049 switch (insn->is_opcode & 07) { 1050 case 3: /* long opr */ 1051 advance += 2; 1052 case 2: /* word opr */ 1053 advance += 2; 1054 case 4: /* no opr */ 1055 break; 1056 default: 1057 return SIGILL; 1058 break; 1059 } 1060 1061 if (branch == 0) { 1062 /* no trap */ 1063 insn->is_advance = advance; 1064 sig = 0; 1065 } else { 1066 /* trap */ 1067 sig = SIGFPE; 1068 } 1069 break; 1070 } 1071 1072 /* FALLTHROUGH */ 1073 default: /* fscc */ 1074 insn->is_advance = 4; 1075 insn->is_datasize = 1; /* always byte */ 1076 sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode); 1077 if (sig) { 1078 break; 1079 } 1080 if (branch == -1 || branch == 0) { 1081 /* set result */ 1082 sig = fpu_store_ea(frame, insn, &insn->is_ea, 1083 (char *)&branch); 1084 } else { 1085 /* got an exception */ 1086 sig = branch; 1087 } 1088 break; 1089 } 1090 return sig; 1091} 1092 1093/* 1094 * Type 2 or 3: fbcc (also fnop) 1095 * In this function, we know: 1096 * (opcode & 0x0180) == 0x0080 1097 */ 1098static int 1099fpu_emul_brcc(struct fpemu *fe, struct instruction *insn) 1100{ 1101 int displ, word2; 1102 int sig; 1103 1104 /* 1105 * Get branch displacement. 1106 */ 1107 insn->is_advance = 4; 1108 displ = insn->is_word1; 1109 1110 if (insn->is_opcode & 0x40) { 1111 word2 = fusword((void *)(insn->is_pc + insn->is_advance)); 1112 if (word2 < 0) { 1113 DPRINTF(("%s: fault reading word2\n", __func__)); 1114 return SIGSEGV; 1115 } 1116 displ <<= 16; 1117 displ |= word2; 1118 insn->is_advance += 2; 1119 } else { 1120 /* displacement is word sized */ 1121 if (displ & 0x8000) 1122 displ |= 0xFFFF0000; 1123 } 1124 1125 /* XXX: If CC, insn->is_pc += displ */ 1126 sig = test_cc(fe, insn->is_opcode); 1127 fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr; 1128 1129 if (fe->fe_fpsr & fe->fe_fpcr & FPSR_EXCP) { 1130 return SIGFPE; /* caught an exception */ 1131 } 1132 if (sig == -1) { 1133 /* 1134 * branch does take place; 2 is the offset to the 1st disp word 1135 */ 1136 insn->is_advance = displ + 2; 1137#if 0 /* XXX */ 1138 insn->is_nextpc = insn->is_pc + insn->is_advance; 1139#endif 1140 } else if (sig) 1141 return SIGILL; /* got a signal */ 1142 DPRINTF(("%s: %s insn @ %x (%x+%x) (disp=%x)\n", __func__, 1143 (sig == -1) ? "BRANCH to" : "NEXT", 1144 insn->is_pc + insn->is_advance, insn->is_pc, insn->is_advance, 1145 displ)); 1146 return 0; 1147} 1148