home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / LINUX / MATH_EMU.ZIP / MATH_EMU / FPU_EMUL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1979-12-31  |  38.0 KB  |  1,293 lines

  1. /*        $NetBSD: fpu_emulate.c,v 1.2 1995/03/10 01:43:05 gwr 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.  
  40. #include "types.h"
  41. #include "signal.h"
  42. #include "frame.h"
  43.  
  44.  
  45. #include "fpu_emul.h"
  46.  
  47. static int fpu_emul_fmovmcr __P((struct fpemu *fe, struct instruction *insn));
  48. static int fpu_emul_fmovm __P((struct fpemu *fe, struct instruction *insn));
  49. static int fpu_emul_arith __P((struct fpemu *fe, struct instruction *insn));
  50. static int fpu_emul_type1 __P((struct fpemu *fe, struct instruction *insn));
  51. static int fpu_emul_brcc __P((struct fpemu *fe, struct instruction *insn));
  52. static int test_cc __P((struct fpemu *fe, int pred));
  53. static struct fpn *fpu_cmp __P((struct fpemu *fe));
  54.  
  55. #if !defined(DL_DEFAULT)
  56. #  if defined(DEBUG_WITH_FPU)
  57. #    define DL_DEFAULT DL_ALL
  58. #  else
  59. #    define DL_DEFAULT 0
  60. #  endif
  61. #endif
  62.  
  63. int fpu_debug_level;
  64. static int global_debug_level = DL_DEFAULT;
  65.  
  66. #ifdef DEBUG
  67. #define DUMP_INSN(insn) if (fpu_debug_level & DL_DUMPINSN) { printf("  fpu_emulate: insn={adv=%d,siz=%d,op=%04x,w1=%04x}\n", (insn)->is_advance, (insn)->is_datasize, (insn)->is_opcode, (insn)->is_word1); }
  68. #else
  69. #define DUMP_INSN(insn)  
  70. #endif
  71. #ifdef DEBUG_WITH_FPU
  72. /* mock fpframe for FPE - it's never overwritten by the real fpframe */
  73. struct fpframe mockfpf;
  74. #endif
  75.  
  76. extern struct fpframe globlfpframe;
  77. struct frame *globlframe;
  78.  
  79. /*
  80.  * Emulate a floating-point instruction.
  81.  * Return zero for success, else signal number.
  82.  * (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
  83.  */
  84.  
  85. int fpu_emulate(frame, fpf)
  86.      struct frame *frame;
  87.      struct fpframe *fpf;
  88. {
  89.     static struct instruction insn;
  90.     static struct fpemu fe;
  91.     int word, optype, sig;
  92.     int i;
  93.     u_int *pt;
  94.    
  95.  
  96.  
  97.     globlframe= frame;
  98.     
  99. #ifdef DEBUG
  100.     /* initialize insn.is_datasize to tell it is *not* initialized */
  101.     insn.is_datasize = -1;
  102. #endif
  103.     fe.fe_frame = frame;
  104. #ifdef DEBUG_WITH_FPU
  105.     fe.fe_fpframe = &mockfpf;
  106.     fe.fe_fpsr = mockfpf.fpf_fpsr;
  107.     fe.fe_fpcr = mockfpf.fpf_fpcr;
  108. #else
  109.     fe.fe_fpframe = fpf;
  110.     fe.fe_fpsr = fpf->fpf_fpsr;
  111.     fe.fe_fpcr = fpf->fpf_fpcr; 
  112. #endif
  113.  
  114. #ifdef DEBUG
  115.     if ((fpu_debug_level = (fe.fe_fpcr >> 16) & 0x0000ffff) == 0) {
  116.           /* set the default */
  117.           fpu_debug_level = global_debug_level;
  118.     }
  119.  
  120.     if (fpu_debug_level & DL_VERBOSE) {
  121.           printf("ENTERING fpu_emulate: FPSR=%08x, FPCR=%08x\n",
  122.                  fe.fe_fpsr, fe.fe_fpcr);
  123.     }
  124. #endif
  125.     word = fusword(frame->f_pc );
  126.     if (word < 0) {
  127. #ifdef DEBUG
  128.           printf("  fpu_emulate: fault reading opcode\n");
  129. #endif
  130.           return SIGSEGV;
  131.     }
  132.  
  133.     if ((word & 0xf000) != 0xf000) {
  134. #ifdef DEBUG
  135.           printf("  fpu_emulate: not coproc. insn.: opcode=0x%x\n", word);
  136. #endif
  137.           return SIGILL;
  138.     }
  139.  
  140.     if (
  141. #ifdef  DEBUG_WITH_FPU
  142.           (word & 0x0E00) != 0x0c00 /* accept fake ID == 6 */
  143. #else
  144.           (word & 0x0E00) != 0x0200
  145. #endif
  146.           ) {
  147. #ifdef DEBUG
  148.           printf("  fpu_emulate: bad coproc. id: opcode=0x%x\n", word);
  149. #endif
  150.           return SIGILL;
  151.     }
  152.  
  153.     insn.is_opcode = word;
  154.     optype = (word & 0x01C0);
  155.  
  156.     word = fusword(frame->f_pc + 2);
  157.     if (word < 0) {
  158. #ifdef DEBUG
  159.           printf("  fpu_emulate: fault reading word1\n");
  160. #endif
  161.           return SIGSEGV;
  162.     }
  163.     insn.is_word1 = word;
  164.     /* all FPU instructions are at least 4-byte long */
  165.     /* except FSAVE,FRESTORE */
  166.     insn.is_advance = 4;
  167.  
  168.     DUMP_INSN(&insn);
  169.  
  170.     /*
  171.      * Which family (or type) of opcode is it?
  172.      * Tests ordered by likelihood (hopefully).
  173.      * Certainly, type 0 is the most common.
  174.      */
  175.     if (optype == 0x0000) {
  176.           /* type=0: generic */
  177.           if ((word & 0xc000) == 0xc000) {
  178. #ifdef DEBUG
  179.               if (fpu_debug_level & DL_INSN)
  180.                     printf("  fpu_emulate: fmovm FPr\n");
  181. #endif
  182.               sig = fpu_emul_fmovm(&fe, &insn);
  183.           } else if ((word & 0xc000) == 0x8000) {
  184. #ifdef DEBUG
  185.               if (fpu_debug_level & DL_INSN)
  186.                     printf("  fpu_emulate: fmovm FPcr\n");
  187. #endif
  188.               sig = fpu_emul_fmovmcr(&fe, &insn);
  189.           } else if ((word & 0xe000) == 0x6000) {
  190.               /* fstore = fmove FPn,mem */
  191. #ifdef DEBUG
  192.               if (fpu_debug_level & DL_INSN)
  193.                     printf("  fpu_emulate: fmove to mem\n");
  194. #endif
  195.               sig = fpu_emul_fstore(&fe, &insn);
  196.           } else if ((word & 0xfc00) == 0x5c00) {
  197.               /* fmovecr */
  198. #ifdef DEBUG
  199.               if (fpu_debug_level & DL_INSN)
  200.                     printf("  fpu_emulate: fmovecr\n");
  201. #endif
  202.               sig = fpu_emul_fmovecr(&fe, &insn);
  203.           } else if ((word & 0xa07f) == 0x26) {
  204.               /* fscale */
  205. #ifdef DEBUG
  206.               if (fpu_debug_level & DL_INSN)
  207.                     printf("  fpu_emulate: fscale\n");
  208. #endif
  209.               sig = fpu_emul_fscale(&fe, &insn);
  210.           } else {
  211. #ifdef DEBUG
  212.               if (fpu_debug_level & DL_INSN)
  213.                     printf("  fpu_emulte: other type0\n");
  214. #endif
  215.               /* all other type0 insns are arithmetic */
  216.               sig = fpu_emul_arith(&fe, &insn);
  217.           }
  218.           if (sig == 0) {
  219. #ifdef DEBUG
  220.               if (fpu_debug_level & DL_VERBOSE)
  221.                     printf("  fpu_emulate: type 0 returned 0\n");
  222. #endif
  223.               sig = fpu_upd_excp(&fe);
  224.           }
  225.     } else if (optype == 0x0080 || optype == 0x00C0) {
  226.           /* type=2 or 3: fbcc, short or long disp. */
  227. #ifdef DEBUG
  228.           if (fpu_debug_level & DL_INSN)
  229.               printf("  fpu_emulate: fbcc %s\n",
  230.                        (optype & 0x40) ? "long" : "short");
  231. #endif
  232.           sig = fpu_emul_brcc(&fe, &insn);
  233.     } else if (optype == 0x0040) {
  234.           /* type=1: fdbcc, fscc, ftrapcc */
  235. #ifdef DEBUG
  236.           if (fpu_debug_level & DL_INSN)
  237.               printf("  fpu_emulate: type1\n");
  238. #endif
  239.           sig = fpu_emul_type1(&fe, &insn);
  240.     } else if (optype == 0x0100) {
  241.  
  242.  
  243.           /* type 4: fsave (privileged): store NULL frame */
  244.          if((frame->f_sr &0x2000) !=0) {
  245.             insn.is_advance = 2;  /* 2 bytes long */
  246.             sig=fpu_decode_ea(frame, &insn, &insn.is_ea0,insn.is_opcode);
  247.                     insn.is_datasize=0x1C;
  248.                     globlfpframe.fpf_version=0x1; /* fake 1.0 ? */
  249.                     globlfpframe.fpf_fsize=0x18; /* size of IDLE frame */
  250.             sig=fpu_store_ea(frame,&insn,&insn.is_ea0,(char*) &globlfpframe);
  251.         
  252.         } else {
  253.             sig=SIGPRIV;
  254.         
  255.         }
  256.     } else if (optype == 0x0140) {
  257.  
  258.       /* type 5: frestore(privileged) : read from memory */
  259.         if((frame->f_sr & 0x2000) != 0) {
  260.  
  261.             insn.is_advance = 2;   /* 2 bytes long */
  262.             sig=fpu_decode_ea(frame,&insn,&insn.is_ea0,insn.is_opcode);
  263.             insn.is_datasize=0x1C;
  264.             sig=fpu_load_ea(frame,&insn,&insn.is_ea0,(char*) &globlfpframe);
  265.         
  266.         } else {
  267.             sig=SIGPRIV;
  268.         }
  269.     } else {
  270.           /* type=6: reserved */
  271.           /* type=7: reserved */
  272. #ifdef DEBUG
  273.           printf(" fpu_emulate: bad opcode type: opcode=0x%x\n", insn.is_opcode);
  274. #endif
  275.           sig = SIGILL;
  276.     }
  277.  
  278.     DUMP_INSN(&insn);
  279.  
  280.     if (sig == 0) {
  281.           frame->f_pc += insn.is_advance;
  282.     }
  283. #if defined(DDB) && defined(DEBUG)
  284.     else {
  285.           printf(" fpu_emulate: sig=%d, opcode=%x, word1=%x\n",
  286.                  sig, insn.is_opcode, insn.is_word1);
  287.           kdb_trap(-1, frame);
  288.     }
  289. #endif
  290.  
  291. #ifdef DEBUG
  292.     if (fpu_debug_level & DL_VERBOSE)
  293.           printf("EXITING fpu_emulate: w/FPSR=%08x, FPCR=%08x\n",
  294.                  fe.fe_fpsr, fe.fe_fpcr);
  295. #endif
  296.     return (sig);
  297. }
  298.  
  299. /* update accrued exception bits and see if there's an FP exception */
  300. int
  301. fpu_upd_excp(fe)
  302.      struct fpemu *fe;
  303. {
  304.     u_int fpsr;
  305.     u_int fpcr;
  306.  
  307.     fpsr = fe->fe_fpsr;
  308.     fpcr = fe->fe_fpcr;
  309.     /* update fpsr accrued exception bits; each insn doesn't have to
  310.        update this */
  311.     if (fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR)) {
  312.           fpsr |= FPSR_AIOP;
  313.     }
  314.     if (fpsr & FPSR_OVFL) {
  315.           fpsr |= FPSR_AOVFL;
  316.     }
  317.     if ((fpsr & FPSR_UNFL) && (fpsr & FPSR_INEX2)) {
  318.           fpsr |= FPSR_AUNFL;
  319.     }
  320.     if (fpsr & FPSR_DZ) {
  321.           fpsr |= FPSR_ADZ;
  322.     }
  323.     if (fpsr & (FPSR_INEX1 | FPSR_INEX2 | FPSR_OVFL)) {
  324.           fpsr |= FPSR_AINEX;
  325.     }
  326.  
  327.     fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
  328.  
  329.     return (fpsr & fpcr & FPSR_EXCP) ? SIGFPE : 0;
  330. }
  331.  
  332. /* update fpsr according to fp (= result of an fp op) */
  333. u_int
  334. fpu_upd_fpsr(fe, fp)
  335.      struct fpemu *fe;
  336.      struct fpn *fp;
  337. {
  338.     u_int fpsr;
  339. #ifdef DEBUG
  340.     if (fpu_debug_level & DL_RESULT)
  341.           printf("  fpu_upd_fpsr: previous fpsr=%08x\n", fe->fe_fpsr);
  342. #endif
  343.     /* clear all condition code */
  344.     fpsr = fe->fe_fpsr & ~FPSR_CCB;
  345. #ifdef DEBUG
  346.     if (fpu_debug_level & DL_RESULT)
  347.           printf("  fpu_upd_fpsr: result is a ");
  348. #endif
  349.     if (fp->fp_sign) {
  350. #ifdef DEBUG
  351.           if (fpu_debug_level & DL_RESULT)
  352.               printf("negative ");
  353. #endif
  354.           fpsr |= FPSR_NEG;
  355.     } else {
  356. #ifdef DEBUG
  357.           if (fpu_debug_level & DL_RESULT)
  358.               printf("positive ");
  359. #endif
  360.     }
  361.  
  362.     switch (fp->fp_class) {
  363.     case FPC_SNAN:
  364. #ifdef DEBUG
  365.           if (fpu_debug_level & DL_RESULT)
  366.               printf("signaling NAN\n");
  367. #endif
  368.           fpsr |= (FPSR_NAN | FPSR_SNAN);
  369.           break;
  370.     case FPC_QNAN:
  371. #ifdef DEBUG
  372.           if (fpu_debug_level & DL_RESULT)
  373.               printf("quiet NAN\n");
  374. #endif
  375.           fpsr |= FPSR_NAN;
  376.           break;
  377.     case FPC_ZERO:
  378. #ifdef DEBUG
  379.           if (fpu_debug_level & DL_RESULT)
  380.               printf("Zero\n");
  381. #endif
  382.           fpsr |= FPSR_ZERO;
  383.           break;
  384.     case FPC_INF:
  385. #ifdef DEBUG
  386.           if (fpu_debug_level & DL_RESULT)
  387.               printf("Inf\n");
  388. #endif
  389.           fpsr |= FPSR_INF;
  390.           break;
  391.     default:
  392. #ifdef DEBUG
  393.           if (fpu_debug_level & DL_RESULT)
  394.               printf("Number\n");
  395. #endif
  396.           /* anything else is treated as if it is a number */
  397.           break;
  398.     }
  399.  
  400.     fe->fe_fpsr = fe->fe_fpframe->fpf_fpsr = fpsr;
  401. #ifdef DEBUG
  402.     if (fpu_debug_level & DL_RESULT)
  403.           printf("  fpu_upd_fpsr: new fpsr=%08x\n", fe->fe_fpframe->fpf_fpsr);
  404. #endif
  405.     return fpsr;
  406. }
  407.  
  408. static int
  409. fpu_emul_fmovmcr(fe, insn)
  410.      struct fpemu *fe;
  411.      struct instruction *insn;
  412. {
  413.     struct frame *frame = fe->fe_frame;
  414.     struct fpframe *fpf = fe->fe_fpframe;
  415.     int word1, sig;
  416.     int reglist, regmask, regnum;
  417.     int fpu_to_mem;
  418.  
  419.     /* move to/from control registers */
  420.     reglist = (insn->is_word1 & 0x1c00) >> 10;
  421.     /* Bit 13 selects direction (FPU to/from Mem) */
  422.     fpu_to_mem = insn->is_word1 & 0x2000;
  423.  
  424.     insn->is_datasize = 4;
  425.     insn->is_advance = 4;
  426.     sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
  427.     if (sig) { return sig; }
  428.  
  429.     if (reglist != 1 && reglist != 2 && reglist != 4 &&
  430.           (insn->is_ea0.ea_flags & EA_DIRECT)) {
  431.           /* attempted to copy more than one FPcr to CPU regs */
  432. #ifdef DEBUG
  433.           printf("  fpu_emul_fmovmcr: tried to copy too many FPcr\n");
  434. #endif
  435.           return SIGILL;
  436.     }
  437.  
  438.     if (reglist & 4) {
  439.           /* fpcr */
  440.           if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
  441.               insn->is_ea0.ea_regnum >= 8 /* address reg */) {
  442.               /* attempted to copy FPCR to An */
  443. #ifdef DEBUG
  444.               printf("  fpu_emul_fmovmcr: tried to copy FPCR from/to A%d\n",
  445.                        insn->is_ea0.ea_regnum & 7);
  446. #endif
  447.               return SIGILL;
  448.           }
  449.           if (fpu_to_mem) {
  450.               sig = fpu_store_ea(frame, insn, &insn->is_ea0,
  451.                                      (char *)&fpf->fpf_fpcr);
  452.           } else {
  453.               sig = fpu_load_ea(frame, insn, &insn->is_ea0,
  454.                                     (char *)&fpf->fpf_fpcr);
  455.           }
  456.     }
  457.     if (sig) { return sig; }
  458.  
  459.     if (reglist & 2) {
  460.           /* fpsr */
  461.           if ((insn->is_ea0.ea_flags & EA_DIRECT) &&
  462.               insn->is_ea0.ea_regnum >= 8 /* address reg */) {
  463.               /* attempted to copy FPSR to An */
  464. #ifdef DEBUG
  465.               printf("  fpu_emul_fmovmcr: tried to copy FPSR from/to A%d\n",
  466.                        insn->is_ea0.ea_regnum & 7);
  467. #endif
  468.               return SIGILL;
  469.           }
  470.           if (fpu_to_mem) {
  471.               sig = fpu_store_ea(frame, insn, &insn->is_ea0,
  472.                                      (char *)&fpf->fpf_fpsr);
  473.           } else {
  474.               sig = fpu_load_ea(frame, insn, &insn->is_ea0,
  475.                                     (char *)&fpf->fpf_fpsr);
  476.           }
  477.     }
  478.     if (sig) { return sig; }
  479.   
  480.     if (reglist & 1) {
  481.           /* fpiar - can be moved to/from An */
  482.           if (fpu_to_mem) {
  483.               sig = fpu_store_ea(frame, insn, &insn->is_ea0,
  484.                                      (char *)&fpf->fpf_fpiar);
  485.           } else {
  486.               sig = fpu_load_ea(frame, insn, &insn->is_ea0,
  487.                                     (char *)&fpf->fpf_fpiar);
  488.           }
  489.     }
  490.     return sig;
  491. }
  492.  
  493. /*
  494.  * type 0: fmovem
  495.  * Separated out of fpu_emul_type0 for efficiency.
  496.  * In this function, we know:
  497.  *   (opcode & 0x01C0) == 0
  498.  *   (word1 & 0x8000) == 0x8000
  499.  *
  500.  * No conversion or rounding is done by this instruction,
  501.  * and the FPSR is not affected.
  502.  */
  503. static int
  504. fpu_emul_fmovm(fe, insn)
  505.      struct fpemu *fe;
  506.      struct instruction *insn;
  507. {
  508.     struct frame *frame = fe->fe_frame;
  509.     struct fpframe *fpf = fe->fe_fpframe;
  510.     int word1, sig;
  511.     int reglist, regmask, regnum;
  512.     int fpu_to_mem, order;
  513.     int w1_post_incr;                   /* XXX - FP regs order? */
  514.     int *fpregs;
  515.  
  516.     insn->is_advance = 4;
  517.     insn->is_datasize = 12;
  518.     word1 = insn->is_word1;
  519.  
  520.     /* Bit 13 selects direction (FPU to/from Mem) */
  521.     fpu_to_mem = word1 & 0x2000;
  522.  
  523.     /*
  524.      * Bits 12,11 select register list mode:
  525.      * 0,0: Static  reg list, pre-decr.
  526.      * 0,1: Dynamic reg list, pre-decr.
  527.      * 1,0: Static  reg list, post-incr.
  528.      * 1,1: Dynamic reg list, post-incr
  529.      */
  530.     w1_post_incr = word1 & 0x1000;
  531.     if (word1 & 0x0800) {
  532.           /* dynamic reg list */
  533.           reglist = frame->f_regs[(word1 & 0x70) >> 4];
  534.     } else {
  535.           reglist = word1;
  536.     }
  537.     reglist &= 0xFF;
  538.  
  539.     /* Get effective address. (modreg=opcode&077) */
  540.     sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
  541.     if (sig) { return sig; }
  542.  
  543.     /* Get address of soft coprocessor regs. */
  544.     fpregs = &fpf->fpf_regs[0];
  545.  
  546.     if (insn->is_ea0.ea_flags & EA_PREDECR) {
  547.           regnum = 7;
  548.           order = -1;
  549.     } else {
  550.           regnum = 0;
  551.           order = 1;
  552.     }
  553.  
  554.     while ((0 <= regnum) && (regnum < 8)) {
  555.           regmask = 1 << regnum;
  556.           if (regmask & reglist) {
  557.               if (fpu_to_mem) {
  558.                     sig = fpu_store_ea(frame, insn, &insn->is_ea0,
  559.                                            (char*)&fpregs[regnum * 3]);
  560. #ifdef DEBUG
  561.                     if (fpu_debug_level & DL_RESULT)
  562.                         printf("  fpu_emul_fmovm: FP%d (%08x,%08x,%08x) saved\n",
  563.                                  regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
  564.                                  fpregs[regnum * 3 + 2]);
  565. #endif
  566.               } else {                  /* mem to fpu */
  567.                     sig = fpu_load_ea(frame, insn, &insn->is_ea0,
  568.                                           (char*)&fpregs[regnum * 3]);
  569. #ifdef DEBUG
  570.                     if (fpu_debug_level & DL_RESULT)
  571.                         printf("  fpu_emul_fmovm: FP%d (%08x,%08x,%08x) loaded\n",
  572.                                  regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
  573.                                  fpregs[regnum * 3 + 2]);
  574. #endif
  575.               }
  576.               if (sig) { break; }
  577.           }
  578.           regnum += order;
  579.     }
  580.  
  581.     return sig;
  582. }
  583.  
  584. static struct fpn *
  585. fpu_cmp(fe)
  586.      struct fpemu *fe;
  587. {
  588.     struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
  589.  
  590.     /* take care of special cases */
  591.     if (x->fp_class < 0 || y->fp_class < 0) {
  592.           /* if either of two is a SNAN, result is SNAN */
  593.           x->fp_class = (y->fp_class < x->fp_class) ? y->fp_class : x->fp_class;
  594.     } else if (x->fp_class == FPC_INF) {
  595.           if (y->fp_class == FPC_INF) {
  596.               /* both infinities */
  597.               if (x->fp_sign == y->fp_sign) {
  598.                     x->fp_class = FPC_ZERO;       /* return a signed zero */
  599.               } else {
  600.                     x->fp_class = FPC_NUM; /* return a faked number w/x's sign */
  601.                     x->fp_exp = 16383;
  602.                     x->fp_mant[0] = FP_1;
  603.               }
  604.           } else {
  605.               /* y is a number */
  606.               x->fp_class = FPC_NUM; /* return a forged number w/x's sign */
  607.               x->fp_exp = 16383;
  608.               x->fp_mant[0] = FP_1;
  609.           }
  610.     } else if (y->fp_class == FPC_INF) {
  611.           /* x is a Num but y is an Inf */
  612.           /* return a forged number w/y's sign inverted */
  613.           x->fp_class = FPC_NUM;
  614.           x->fp_sign = !y->fp_sign;
  615.           x->fp_exp = 16383;
  616.           x->fp_mant[0] = FP_1;
  617.     } else {
  618.           /* x and y are both numbers or zeros, or pair of a number and a zero */
  619.           y->fp_sign = !y->fp_sign;
  620.           x = fpu_add(fe);    /* (x - y) */
  621.           /*
  622.            * FCMP does not set Inf bit in CC, so return a forged number
  623.            * (value doesn't matter) if Inf is the result of fsub.
  624.            */
  625.           if (x->fp_class == FPC_INF) {
  626.               x->fp_class = FPC_NUM;
  627.               x->fp_exp = 16383;
  628.               x->fp_mant[0] = FP_1;
  629.           }
  630.     }
  631.     return x;
  632. }
  633.  
  634. /*
  635.  * arithmetic oprations
  636.  */
  637. static int
  638. fpu_emul_arith(fe, insn)
  639.      struct fpemu *fe;
  640.      struct instruction *insn;
  641. {
  642.     struct frame *frame = fe->fe_frame;
  643.     u_int *fpregs = &(fe->fe_fpframe->fpf_regs[0]);
  644.     struct fpn *res;
  645.     int word1, sig = 0;
  646.     int regnum, format;
  647.     int discard_result = 0;
  648.     u_int buf[3];
  649.     int flags;
  650.     char regname;
  651.  
  652.     DUMP_INSN(insn);
  653. #ifdef DEBUG
  654.     if (fpu_debug_level & DL_ARITH) {
  655.           printf("  fpu_emul_arith: FPSR = %08x, FPCR = %08x\n",
  656.                  fe->fe_fpsr, fe->fe_fpcr);
  657.     }
  658. #endif
  659.     word1 = insn->is_word1;
  660.     format = (word1 >> 10) & 7;
  661.     regnum = (word1 >> 7) & 7;
  662.  
  663.     /* fetch a source operand : may not be used */
  664. #ifdef DEBUG
  665.     if (fpu_debug_level & DL_ARITH) {
  666.           printf("  fpu_emul_arith: dst/src FP%d=%08x,%08x,%08x\n",
  667.                  regnum, fpregs[regnum*3], fpregs[regnum*3+1],
  668.                  fpregs[regnum*3+2]);
  669.     }
  670. #endif
  671.     fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &fpregs[regnum * 3]);
  672.  
  673.     DUMP_INSN(insn);
  674.  
  675.     /* get the other operand which is always the source */
  676.     if ((word1 & 0x4000) == 0) {
  677. #ifdef DEBUG
  678.           if (fpu_debug_level & DL_ARITH) {
  679.               printf("  fpu_emul_arith: FP%d op FP%d => FP%d\n",
  680.                        format, regnum, regnum);
  681.               printf("  fpu_emul_arith: src opr FP%d=%08x,%08x,%08x\n",
  682.                        format, fpregs[format*3], fpregs[format*3+1],
  683.                        fpregs[format*3+2]);
  684.           }
  685. #endif
  686.           fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
  687.     } else {
  688.           /* the operand is in memory */
  689.           if (format == FTYPE_DBL) {
  690.               insn->is_datasize = 8;
  691.           } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
  692.               insn->is_datasize = 4;
  693.           } else if (format == FTYPE_WRD) {
  694.               insn->is_datasize = 2;
  695.           } else if (format == FTYPE_BYT) {
  696.               insn->is_datasize = 1;
  697.           } else if (format == FTYPE_EXT) {
  698.               insn->is_datasize = 12;
  699.           } else {
  700.               /* invalid or unsupported operand format */
  701.               sig = SIGFPE;
  702.               return sig;
  703.           }
  704.  
  705.           /* Get effective address. (modreg=opcode&077) */
  706.           sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
  707.           if (sig) {
  708. #ifdef DEBUG
  709.               if (fpu_debug_level & DL_ARITH) {
  710.                     printf("  fpu_emul_arith: error in fpu_decode_ea\n");
  711.               }
  712. #endif
  713.               return sig;
  714.           }
  715.  
  716.           DUMP_INSN(insn);
  717. #ifdef DEBUG
  718.           if (fpu_debug_level & DL_ARITH) {
  719.               printf("  fpu_emul_arith: addr mode = ");
  720.               flags = insn->is_ea0.ea_flags;
  721.               regname = (insn->is_ea0.ea_regnum & 8) ? 'a' : 'd';
  722.  
  723.               if (flags & EA_DIRECT) {
  724.                     printf("%c%d\n",
  725.                            regname, insn->is_ea0.ea_regnum & 7);
  726.               } else if (flags & EA_PC_REL) {
  727.                     if (flags & EA_OFFSET) {
  728.                         printf("pc@(%d)\n", insn->is_ea0.ea_offset);
  729.                     } else if (flags & EA_INDEXED) {
  730.                         printf("pc@(...)\n");
  731.                     }
  732.               } else if (flags & EA_PREDECR) {
  733.                     printf("%c%d@-\n",
  734.                            regname, insn->is_ea0.ea_regnum & 7);
  735.               } else if (flags & EA_POSTINCR) {
  736.                     printf("%c%d@+\n", regname, insn->is_ea0.ea_regnum & 7);
  737.               } else if (flags & EA_OFFSET) {
  738.                     printf("%c%d@(%d)\n", regname, insn->is_ea0.ea_regnum & 7,
  739.                            insn->is_ea0.ea_offset);
  740.               } else if (flags & EA_INDEXED) {
  741.                     printf("%c%d@(...)\n", regname, insn->is_ea0.ea_regnum & 7);
  742.               } else if (flags & EA_ABS) {
  743.                     printf("0x%08x\n", insn->is_ea0.ea_absaddr);
  744.               } else if (flags & EA_IMMED) {
  745.  
  746.                     printf("#0x%08x,%08x,%08x\n", insn->is_ea0.ea_immed[0],
  747.                            insn->is_ea0.ea_immed[1], insn->is_ea0.ea_immed[2]);
  748.               } else {
  749.                     printf("%c%d@\n", regname, insn->is_ea0.ea_regnum & 7);
  750.               }
  751.           } /* if (fpu_debug_level & DL_ARITH) */
  752. #endif
  753.           fpu_load_ea(frame, insn, &insn->is_ea0, (char*)buf);
  754.           if (format == FTYPE_WRD) {
  755.               /* sign-extend */
  756.               buf[0] &= 0xffff;
  757.               if (buf[0] & 0x8000) {
  758.                     buf[0] |= 0xffff0000;
  759.               }
  760.               format = FTYPE_LNG;
  761.           } else if (format == FTYPE_BYT) {
  762.               /* sign-extend */
  763.               buf[0] &= 0xff;
  764.               if (buf[0] & 0x80) {
  765.                     buf[0] |= 0xffffff00;
  766.               }
  767.               format = FTYPE_LNG;
  768.           }
  769. #ifdef DEBUG
  770.           if (fpu_debug_level & DL_ARITH) {
  771.               printf("  fpu_emul_arith: src = %08x %08x %08x, siz = %d\n",
  772.                        buf[0], buf[1], buf[2], insn->is_datasize);
  773.           }
  774. #endif
  775.           fpu_explode(fe, &fe->fe_f2, format, buf);
  776.     }
  777.  
  778.     DUMP_INSN(insn);
  779.  
  780.     /* An arithmetic instruction emulate function has a prototype of
  781.      * struct fpn *fpu_op(struct fpemu *);
  782.      
  783.      * 1) If the instruction is monadic, then fpu_op() must use
  784.      * fe->fe_f2 as its operand, and return a pointer to the
  785.      * result.
  786.      
  787.      * 2) If the instruction is diadic, then fpu_op() must use
  788.      * fe->fe_f1 and fe->fe_f2 as its two operands, and return a
  789.      * pointer to the result.
  790.      
  791.      */
  792.     switch (word1 & 0x3f) {
  793.     case 0x00:                          /* fmove */
  794.           res = &fe->fe_f2;
  795.           break;
  796.  
  797.     case 0x01:                          /* fint */
  798.           res = fpu_int(fe);
  799.           break;
  800.  
  801.     case 0x02:                          /* fsinh */
  802.           res = fpu_sinh(fe);
  803.           break;
  804.  
  805.     case 0x03:                          /* fintrz */
  806.           res = fpu_intrz(fe);
  807.           break;
  808.  
  809.     case 0x04:                          /* fsqrt */
  810.           res = fpu_sqrt(fe);
  811.           break;
  812.  
  813.     case 0x06:                          /* flognp1 */
  814.           res = fpu_lognp1(fe);
  815.           break;
  816.  
  817.     case 0x08:                          /* fetoxm1 */
  818.           res = fpu_etoxm1(fe);
  819.           break;
  820.  
  821.     case 0x09:                          /* ftanh */
  822.           res = fpu_tanh(fe);
  823.           break;
  824.  
  825.     case 0x0A:                          /* fatan */
  826.           res = fpu_atan(fe);
  827.           break;
  828.  
  829.     case 0x0C:                          /* fasin */
  830.           res = fpu_asin(fe);
  831.           break;
  832.  
  833.     case 0x0D:                          /* fatanh */
  834.           res = fpu_atanh(fe);
  835.           break;
  836.  
  837.     case 0x0E:                          /* fsin */
  838.           res = fpu_sin(fe);
  839.           break;
  840.  
  841.     case 0x0F:                          /* ftan */
  842.           res = fpu_tan(fe);
  843.           break;
  844.  
  845.     case 0x10:                          /* fetox */
  846.           res = fpu_etox(fe);
  847.           break;
  848.  
  849.     case 0x11:                          /* ftwotox */
  850.           res = fpu_twotox(fe);
  851.           break;
  852.  
  853.     case 0x12:                          /* ftentox */
  854.           res = fpu_tentox(fe);
  855.           break;
  856.  
  857.     case 0x14:                          /* flogn */
  858.           res = fpu_logn(fe);
  859.           break;
  860.  
  861.     case 0x15:                          /* flog10 */
  862.           res = fpu_log10(fe);
  863.           break;
  864.  
  865.     case 0x16:                          /* flog2 */
  866.           res = fpu_log2(fe);
  867.           break;
  868.  
  869.     case 0x18:                          /* fabs */
  870.           fe->fe_f2.fp_sign = 0;
  871.           res = &fe->fe_f2;
  872.           break;
  873.  
  874.     case 0x19:                          /* fcosh */
  875.           res = fpu_cosh(fe);
  876.           break;
  877.  
  878.     case 0x1A:                          /* fneg */
  879.           fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
  880.           res = &fe->fe_f2;
  881.           break;
  882.  
  883.     case 0x1C:                          /* facos */
  884.           res = fpu_acos(fe);
  885.           break;
  886.  
  887.     case 0x1D:                          /* fcos */
  888.           res = fpu_cos(fe);
  889.           break;
  890.  
  891.     case 0x1E:                          /* fgetexp */
  892.           res = fpu_getexp(fe);
  893.           break;
  894.  
  895.     case 0x1F:                          /* fgetman */
  896.           res = fpu_getman(fe);
  897.           break;
  898.  
  899.     case 0x20:                          /* fdiv */
  900.     case 0x24:                          /* fsgldiv: cheating - better than nothing */
  901.           res = fpu_div(fe);
  902.           break;
  903.  
  904.     case 0x21:                          /* fmod */
  905.           res = fpu_mod(fe);
  906.           break;
  907.  
  908.     case 0x28:                          /* fsub */
  909.           fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
  910.     case 0x22:                          /* fadd */
  911.           res = fpu_add(fe);
  912.           break;
  913.  
  914.     case 0x23:                          /* fmul */
  915.     case 0x27:                          /* fsglmul: cheating - better than nothing */
  916.           res = fpu_mul(fe);
  917.           break;
  918.  
  919.     case 0x25:                          /* frem */
  920.           res = fpu_rem(fe);
  921.           break;
  922.  
  923.     case 0x26:
  924.           /* fscale is handled by a separate function */
  925.           break;
  926.  
  927.     case 0x30:
  928.     case 0x31:
  929.     case 0x32:
  930.     case 0x33:
  931.     case 0x34:
  932.     case 0x35:
  933.     case 0x36:
  934.     case 0x37:                          /* fsincos */
  935.           res = fpu_sincos(fe, word1 & 7);
  936.           break;
  937.  
  938.     case 0x38:                          /* fcmp */
  939.           res = fpu_cmp(fe);
  940.           discard_result = 1;
  941.           break;
  942.  
  943.     case 0x3A:                          /* ftst */
  944.           res = &fe->fe_f2;
  945.           discard_result = 1;
  946.           break;
  947.  
  948.     default:
  949. #ifdef DEBUG
  950.           printf("  fpu_emul_arith: bad opcode=0x%x, word1=0x%x\n",
  951.                  insn->is_opcode, insn->is_word1);
  952. #endif
  953.           sig = SIGILL;
  954.     } /* switch (word1 & 0x3f) */
  955.  
  956.     if (!discard_result && sig == 0) {
  957.           fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]);
  958. #ifdef DEBUG
  959.           if (fpu_debug_level & DL_ARITH) {
  960.               printf("  fpu_emul_arith: %08x,%08x,%08x stored in FP%d\n",
  961.                        fpregs[regnum*3], fpregs[regnum*3+1],
  962.                        fpregs[regnum*3+2], regnum);
  963.           }
  964. #endif
  965.     } else if (sig == 0 && fpu_debug_level & DL_ARITH) {
  966.           static char *class_name[] = { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
  967. #ifdef DEBUG
  968.           printf("  fpu_emul_arith: result(%s,%c,%d,%08x,%08x,%08x,%08x) discarded\n",
  969.                  class_name[res->fp_class + 2],
  970.                  res->fp_sign ? '-' : '+', res->fp_exp,
  971.                  res->fp_mant[0], res->fp_mant[1],
  972.                  res->fp_mant[2], res->fp_mant[3]);
  973. #endif
  974.     } else if (fpu_debug_level & DL_ARITH) {
  975. #ifdef DEBUG
  976.           printf("  fpu_emul_arith: received signal %d\n", sig);
  977. #endif
  978.     }
  979.  
  980.     /* update fpsr according to the result of operation */
  981.     fpu_upd_fpsr(fe, res);
  982. #ifdef DEBUG
  983.     if (fpu_debug_level & DL_ARITH) {
  984.           printf("  fpu_emul_arith: FPSR = %08x, FPCR = %08x\n",
  985.                  fe->fe_fpsr, fe->fe_fpcr);
  986.     }
  987. #endif
  988.  
  989.     DUMP_INSN(insn);
  990.  
  991.     return sig;
  992. }
  993.  
  994. /* test condition code according to the predicate in the opcode.
  995.  * returns -1 when the predicate evaluates to true, 0 when false.
  996.  * signal numbers are returned when an error is detected.
  997.  */
  998. static int
  999. test_cc(fe, pred)
  1000.      struct fpemu *fe;
  1001.      int pred;
  1002. {
  1003.     int result, sig_bsun, invert;
  1004.     int fpsr;
  1005.  
  1006.     fpsr = fe->fe_fpsr;
  1007.     invert = 0;
  1008.     fpsr &= ~FPSR_EXCP;                 /* clear all exceptions */
  1009. #ifdef DEBUG
  1010.     if (fpu_debug_level & DL_TESTCC) {
  1011.           printf("  test_cc: fpsr=0x%08x\n", fpsr);
  1012.     }
  1013. #endif
  1014.     pred &= 0x3f;             /* lowest 6 bits */
  1015. #ifdef DEBUG
  1016.     if (fpu_debug_level & DL_TESTCC) {
  1017.           printf("  test_cc: ");
  1018.     }
  1019. #endif
  1020.     if (pred >= 040) {
  1021.           return SIGILL;
  1022.     } else if (pred & 0x10) {
  1023.           /* IEEE nonaware tests */
  1024.           sig_bsun = 1;
  1025.           pred &= 017;                  /* lower 4 bits */
  1026.     } else {
  1027.           /* IEEE aware tests */
  1028. #ifdef DEBUG
  1029.           if (fpu_debug_level & DL_TESTCC) {
  1030.               printf("IEEE ");
  1031.           }
  1032. #endif
  1033.           sig_bsun = 0;
  1034.     }
  1035.  
  1036.     if (pred >= 010) {
  1037. #ifdef DEBUG
  1038.           if (fpu_debug_level & DL_TESTCC) {
  1039.               printf("Not ");
  1040.           }
  1041. #endif
  1042.           /* predicate is "NOT ..." */
  1043.           pred ^= 0xf;                  /* invert */
  1044.           invert = -1;
  1045.     }
  1046.     switch (pred) {
  1047.     case 0:                             /* (Signaling) False */
  1048. #ifdef DEBUG
  1049.           if (fpu_debug_level & DL_TESTCC) {
  1050.               printf("False");
  1051.           }
  1052. #endif
  1053.           result = 0;
  1054.           break;
  1055.     case 1:                             /* (Signaling) Equal */
  1056. #ifdef DEBUG
  1057.           if (fpu_debug_level & DL_TESTCC) {
  1058.               printf("Equal");
  1059.           }
  1060. #endif
  1061.           result = -((fpsr & FPSR_ZERO) == FPSR_ZERO);
  1062.           break;
  1063.     case 2:                             /* Greater Than */
  1064. #ifdef DEBUG
  1065.           if (fpu_debug_level & DL_TESTCC) {
  1066.               printf("GT");
  1067.           }
  1068. #endif
  1069.           result = -((fpsr & (FPSR_NAN|FPSR_ZERO|FPSR_NEG)) == 0);
  1070.           break;
  1071.     case 3:                             /* Greater or Equal */
  1072. #ifdef DEBUG
  1073.           if (fpu_debug_level & DL_TESTCC) {
  1074.               printf("GE");
  1075.           }
  1076. #endif
  1077.           result = -((fpsr & FPSR_ZERO) ||
  1078.                        (fpsr & (FPSR_NAN|FPSR_NEG)) == 0);
  1079.           break;
  1080.     case 4:                             /* Less Than */
  1081. #ifdef DEBUG
  1082.           if (fpu_debug_level & DL_TESTCC) {
  1083.               printf("LT");
  1084.           }
  1085. #endif
  1086.           result = -((fpsr & (FPSR_NAN|FPSR_ZERO|FPSR_NEG)) == FPSR_NEG);
  1087.           break;
  1088.     case 5:                             /* Less or Equal */
  1089. #ifdef DEBUG
  1090.           if (fpu_debug_level & DL_TESTCC) {
  1091.               printf("LE");
  1092.           }
  1093. #endif
  1094.           result = -((fpsr & FPSR_ZERO) ||
  1095.                        ((fpsr & (FPSR_NAN|FPSR_NEG)) == FPSR_NEG));
  1096.           break;
  1097.     case 6:                             /* Greater or Less than */
  1098. #ifdef DEBUG
  1099.           if (fpu_debug_level & DL_TESTCC) {
  1100.               printf("GLT");
  1101.           }
  1102. #endif
  1103.           result = -((fpsr & (FPSR_NAN|FPSR_ZERO)) == 0);
  1104.           break;
  1105.     case 7:                             /* Greater, Less or Equal */
  1106. #ifdef DEBUG
  1107.           if (fpu_debug_level & DL_TESTCC) {
  1108.               printf("GLE");
  1109.           }
  1110. #endif
  1111.           result = -((fpsr & FPSR_NAN) == 0);
  1112.           break;
  1113.     default:
  1114.           /* invalid predicate */
  1115.           return SIGILL;
  1116.     }
  1117.     result ^= invert;                   /* if the predicate is "NOT ...", then
  1118.                                            invert the result */
  1119. #ifdef DEBUG
  1120.     if (fpu_debug_level & DL_TESTCC) {
  1121.           printf(" => %s (%d)\n", result ? "true" : "false", result);
  1122.     }
  1123. #endif
  1124.     /* if it's an IEEE unaware test and NAN is set, BSUN is set */
  1125.     if (sig_bsun && (fpsr & FPSR_NAN)) {
  1126.           fpsr |= FPSR_BSUN;
  1127.     }
  1128.  
  1129.     /* put fpsr back */
  1130.     fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
  1131.  
  1132.     return result;
  1133. }
  1134.  
  1135. /*
  1136.  * type 1: fdbcc, fscc, ftrapcc
  1137.  * In this function, we know:
  1138.  *   (opcode & 0x01C0) == 0x0040
  1139.  */
  1140. static int
  1141. fpu_emul_type1(fe, insn)
  1142.      struct fpemu *fe;
  1143.      struct instruction *insn;
  1144. {
  1145.     struct frame *frame = fe->fe_frame;
  1146.     struct fpframe *fpf = fe->fe_fpframe;
  1147.     int advance, sig, branch, displ;
  1148.  
  1149.     branch = test_cc(fe, insn->is_word1);
  1150.     fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
  1151.  
  1152.     insn->is_advance = 4;
  1153.     sig = 0;
  1154.  
  1155.     switch (insn->is_opcode & 070) {
  1156.     case 010:                           /* fdbcc */
  1157.           if (branch == -1) {
  1158.               /* advance */
  1159.               insn->is_advance = 6;
  1160.           } else if (!branch) {
  1161.               /* decrement Dn and if (Dn != -1) branch */
  1162.               unsigned short count = frame->f_regs[insn->is_opcode & 7];
  1163.  
  1164.               if (count-- != 0) {
  1165.                     displ = fusword(frame->f_pc + insn->is_advance);
  1166.                     if (displ < 0) {
  1167. #ifdef DEBUG
  1168.                         printf("  fpu_emul_type1: fault reading displacement\n");
  1169. #endif
  1170.                         return SIGSEGV;
  1171.                     }
  1172.                     /* sign-extend the displacement */
  1173.                     displ &= 0xffff;
  1174.                     if (displ & 0x8000) {
  1175.                         displ |= 0xffff0000;
  1176.                     }
  1177.                     insn->is_advance += displ;
  1178.               } else {
  1179.                     insn->is_advance = 6;
  1180.               }
  1181.               /* write it back */
  1182.               frame->f_regs[insn->is_opcode & 7] &= 0xffff0000;
  1183.               frame->f_regs[insn->is_opcode & 7] |= (unsigned int)count;
  1184.           } else {            /* got a signal */
  1185.               sig = SIGFPE;
  1186.           }
  1187.           break;
  1188.  
  1189.     case 070:                           /* ftrapcc or fscc */
  1190.           advance = 4;
  1191.           if ((insn->is_opcode & 07) >= 2) {
  1192.               switch (insn->is_opcode & 07) {
  1193.               case 3:                   /* long opr */
  1194.                     advance += 2;
  1195.               case 2:                   /* word opr */
  1196.                     advance += 2;
  1197.               case 4:                   /* no opr */
  1198.                     break;
  1199.               default:
  1200.                     return SIGILL;
  1201.                     break;
  1202.               }
  1203.  
  1204.               if (branch == 0) {
  1205.                     /* no trap */
  1206.                     insn->is_advance = advance;
  1207.                     sig = 0;
  1208.               } else {
  1209.                     /* trap */
  1210.                     sig = SIGFPE;
  1211.               }
  1212.               break;
  1213.           } /* if ((insn->is_opcode & 7) < 2), fall through to FScc */
  1214.  
  1215.     default:                            /* fscc */
  1216.           insn->is_advance = 4;
  1217.           insn->is_datasize = 1;        /* always byte */
  1218.           sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);
  1219.           if (sig) {
  1220.               break;
  1221.           }
  1222.           if (branch == -1 || branch == 0) {
  1223.               /* set result */
  1224.               sig = fpu_store_ea(frame, insn, &insn->is_ea0, (char *)&branch);
  1225.           } else {
  1226.               /* got an exception */
  1227.               sig = branch;
  1228.           }
  1229.           break;
  1230.     }
  1231.     return sig;
  1232. }
  1233.  
  1234. /*
  1235.  * Type 2 or 3: fbcc (also fnop)
  1236.  * In this function, we know:
  1237.  *   (opcode & 0x0180) == 0x0080
  1238.  */
  1239. static int
  1240. fpu_emul_brcc(fe, insn)
  1241.      struct fpemu *fe;
  1242.      struct instruction *insn;
  1243. {
  1244.     struct frame *frame = fe->fe_frame;
  1245.     struct fpframe *fpf = fe->fe_fpframe;
  1246.     int displ, word2;
  1247.     int sig, advance;
  1248.  
  1249.     /*
  1250.      * Get branch displacement.
  1251.      */
  1252.     insn->is_advance = 4;
  1253.     displ = insn->is_word1;
  1254.  
  1255.     if (insn->is_opcode & 0x40) {
  1256.           word2 = fusword(frame->f_pc + insn->is_advance);
  1257.           if (word2 < 0) {
  1258. #ifdef DEBUG
  1259.               printf("  fpu_emul_brcc: fault reading word2\n");
  1260. #endif
  1261.               return SIGSEGV;
  1262.           }
  1263.           displ <<= 16;
  1264.           displ |= word2;
  1265.           insn->is_advance += 2;
  1266.     } else /* displacement is word sized */
  1267.         if (displ & 0x8000)
  1268.               displ |= 0xFFFF0000;
  1269.  
  1270.     /* XXX: If CC, frame->f_pc += displ */
  1271.     sig = test_cc(fe, insn->is_opcode);
  1272.     fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
  1273.  
  1274.     if (fe->fe_fpsr & fe->fe_fpcr & FPSR_EXCP) {
  1275.           return SIGFPE;                /* caught an exception */
  1276.     }
  1277.     if (sig == -1) {
  1278.           /* branch does take place; 2 is the offset to the 1st disp word */
  1279.           insn->is_advance = displ + 2;
  1280.     } else if (sig) {
  1281.           return SIGILL;                /* got a signal */
  1282.     }
  1283. #ifdef DEBUG
  1284.     if (fpu_debug_level & DL_BRANCH) {
  1285.           printf("  fpu_emul_brcc: %s insn @ %x (%x+%x) (disp=%x)\n",
  1286.                  (sig == -1) ? "BRANCH to" : "NEXT",
  1287.                  frame->f_pc + insn->is_advance, frame->f_pc, insn->is_advance,
  1288.                  displ);
  1289.     }
  1290. #endif
  1291.     return 0;
  1292. }
  1293.