home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Boot_Images / 2.11_on_rl02 / pdpsim.tz / pdpsim / pdp11_fp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-29  |  30.4 KB  |  959 lines

  1. /* pdp11_fp.c: PDP-11 floating point simulator (32b version)
  2.  
  3.    Copyright (c) 1993, 1994, Robert M Supnik, Digital Equipment Corporation
  4.    Commercial use prohibited
  5.  
  6.    This module simulates the PDP-11 floating point unit (FP11 series).
  7.    It is called from the instruction decoder for opcodes 170000:177777.
  8.  
  9.    The floating point unit recognizes three instruction formats:
  10.  
  11.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    no operand
  12.    | 1  1  1  1| 0  0  0  0  0  0|      opcode     |    170000:
  13.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    170077
  14.  
  15.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    one operand
  16.    | 1  1  1  1| 0  0  0| opcode |    dest spec    |    170100:
  17.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    170777
  18.  
  19.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    register + operand
  20.    | 1  1  1  1|   opcode  | fac |    dest spec    |    171000:
  21.    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    177777
  22.  
  23.    The instruction space is further extended through use of the floating
  24.    point status register (FPS) mode bits.  Three mode bits affect how
  25.    instructions are interpreted:
  26.  
  27.     FPS_D        if 0, floating registers are single precision
  28.             if 1, floating registers are double precision
  29.  
  30.     FPS_L        if 0, integer operands are word
  31.             if 1, integer operands are longword
  32.  
  33.     FPS_T        if 0, floating operations are rounded
  34.             if 1, floating operations are truncated
  35.  
  36.    FPS also contains the condition codes for the floating point unit,
  37.    and exception enable bits for individual error conditions.  Exceptions
  38.    cause a trap through 0244, unless the individual exception, or all
  39.    exceptions, are disabled.  Illegal address mode, undefined variable,
  40.    and divide by zero abort the current instruction; all other exceptions
  41.    permit the instruction to complete.  (Aborts are implemented as traps
  42.    that request an "interrupt" trap.  If an interrupt is pending, it is
  43.    serviced; if not, trap_req is updated and processing continues.)
  44.  
  45.    Floating point specifiers are similar to integer specifiers, with
  46.    the length of the operand being up to 8 bytes.  In two specific cases,
  47.    the floating point unit reads or writes only two bytes, rather than
  48.    the length specified by the operand type:
  49.  
  50.     register    for integers, only 16b are accessed; if the
  51.             operand is 32b, these are the high order 16b
  52.             of the operand
  53.  
  54.     immediate    for integers or floating point, only 16b are
  55.             accessed;  if the operand is 32b or 64b, these
  56.             are the high order 16b of the operand
  57. */
  58.  
  59. #include "pdp11_defs.h"
  60.  
  61. /* Floating point status register */
  62.  
  63. #define FPS_ER        (1u << FPS_V_ER)        /* error */
  64. #define FPS_ID        (1u << FPS_V_ID)        /* interrupt disable */
  65. #define FPS_IUV        (1u << FPS_V_IUV)        /* int on undef var */
  66. #define FPS_IU        (1u << FPS_V_IU)        /* int on underflow */
  67. #define FPS_IV        (1u << FPS_V_IV)        /* int on overflow */
  68. #define FPS_IC        (1u << FPS_V_IC)        /* int on conv error */
  69. #define FPS_D        (1u << FPS_V_D)            /* single/double */
  70. #define FPS_L        (1u << FPS_V_L)            /* word/long */
  71. #define FPS_T        (1u << FPS_V_T)            /* round/truncate */
  72. #define FPS_N        (1u << FPS_V_N)
  73. #define FPS_Z        (1u << FPS_V_Z)
  74. #define FPS_V        (1u << FPS_V_V)
  75. #define FPS_C        (1u << FPS_V_C)
  76. #define FPS_CC        (FPS_N + FPS_Z + FPS_V + FPS_C)
  77. #define FPS_RW        (FPS_ER + FPS_ID + FPS_IUV + FPS_IU + FPS_IV + \
  78.             FPS_IC + FPS_D + FPS_L + FPS_T + FPS_CC)
  79.  
  80. /* Floating point exception codes */
  81.  
  82. #define FEC_OP        2                /* illegal op/mode */
  83. #define FEC_DZRO    4                /* divide by zero */
  84. #define FEC_ICVT    6                /* conversion error */
  85. #define FEC_OVFLO    8                /* overflow */
  86. #define FEC_UNFLO    10                /* underflow */
  87. #define FEC_UNDFV    12                /* undef variable */
  88.  
  89. /* Floating point format, all assignments 32b relative */
  90.  
  91. #define FP_V_SIGN    (63 - 32)            /* high lw: sign */
  92. #define FP_V_EXP    (55 - 32)            /* exponent */
  93. #define FP_V_HB        FP_V_EXP            /* hidden bit */
  94. #define FP_V_F0        (48 - 32)            /* fraction 0 */
  95. #define FP_V_F1        (32 - 32)            /* fraction 1 */
  96. #define FP_V_FROUND    (31 - 32)            /* f round point */
  97. #define FP_V_F2        16                /* low lw: fraction 2 */
  98. #define FP_V_F3        0                /* fraction 3 */
  99. #define FP_V_DROUND    (-1)                /* d round point */
  100. #define FP_M_EXP    0377
  101. #define FP_SIGN        (1u << FP_V_SIGN)
  102. #define FP_EXP        (FP_M_EXP << FP_V_EXP)
  103. #define FP_HB        (1u << FP_V_HB)
  104. #define FP_FRACH    ((1u << FP_V_HB) - 1)
  105. #define FP_FRACL    0xFFFFFFFF
  106. #define FP_BIAS        0200                /* exponent bias */
  107. #define FP_GUARD    3                /* guard bits */
  108.  
  109. /* Data lengths */
  110.  
  111. #define WORD        2
  112. #define LONG        4
  113. #define QUAD        8
  114.  
  115. /* Double precision operations on 64b quantities */
  116.  
  117. #define F_LOAD(qd,ac,ds) ds.h = ac.h; ds.l = (qd)? ac.l: 0
  118. #define F_LOAD_P(qd,ac,ds) ds -> h = ac.h; ds -> l = (qd)? ac.l: 0
  119. #define F_LOAD_FRAC(qd,ac,ds) ds.h = (ac.h & FP_FRACH) | FP_HB; \
  120.     ds.l = (qd)? ac.l: 0
  121. #define F_STORE(qd,sr,ac) ac.h = sr.h; if ((qd)) ac.l = sr.l
  122. #define F_STORE_P(qd,sr,ac) ac.h = sr -> h; if ((qd)) ac.l = sr -> l
  123. #define F_GET_FRAC_P(sr,ds) ds.l = sr -> l; \
  124.     ds.h = (sr -> h & FP_FRACH) | FP_HB
  125. #define F_ADD(s2,s1,ds) ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \
  126.     ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF
  127. #define F_SUB(s2,s1,ds) ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \
  128.     ds.l = (s1.l - s2.l) & 0xFFFFFFFF
  129. #define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l)))
  130. #define F_LT_AP(x,y) (((x -> h & ~FP_SIGN) < (y -> h & ~FP_SIGN)) || \
  131.     (((x -> h & ~FP_SIGN) == (y -> h & ~FP_SIGN)) && (x -> l < y -> l)))
  132. #define F_LSH_V(sr,n,ds) \
  133.     ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \
  134.         (sr.h << (n)) | ((sr.l >> (32 - (n))) & ((1u << (n)) - 1))) \
  135.         & 0xFFFFFFFF; \
  136.     ds.l = ((n) >= 32)? 0: (sr.l << (n)) & 0xFFFFFFFF
  137. #define F_RSH_V(sr,n,ds) \
  138.     ds.l = (((n) >= 32)? (sr.h >> ((n) - 32)) & ((1u << (64 - (n))) - 1): \
  139.         ((sr.l >> (n)) & ((1u << (32 - (n))) - 1)) | \
  140.         (sr.h << (32 - (n)))) & 0xFFFFFFFF; \
  141.     ds.h = ((n) >= 32)? 0: \
  142.         ((sr.h >> (n)) & ((1u << (32 - (n))) - 1)) & 0xFFFFFFFF
  143.  
  144. /* For the constant shift macro, arguments must in the range [2,31] */
  145.  
  146. #define F_LSH_1(ds) ds.h = ((ds.h << 1) | ((ds.l >> 31) & 1)) & 0xFFFFFFFF; \
  147.     ds.l = (ds.l << 1) & 0xFFFFFFFF
  148. #define F_RSH_1(ds) ds.l = ((ds.l >> 1) & 0x7FFFFFFF) | ((ds.h & 1) << 31); \
  149.     ds.h = ((ds.h >> 1) & 0x7FFFFFFF)
  150. #define F_LSH_K(sr,n,ds) \
  151.     ds.h =     ((sr.h << (n)) | ((sr.l >> (32 - (n))) & ((1u << (n)) - 1))) \
  152.         & 0xFFFFFFFF; \
  153.     ds.l = (sr.l << (n)) & 0xFFFFFFFF
  154. #define F_RSH_K(sr,n,ds) \
  155.     ds.l =     (((sr.l >> (n)) & ((1u << (32 - (n))) - 1)) | \
  156.         (sr.h << (32 - (n)))) & 0xFFFFFFFF; \
  157.     ds.h =     ((sr.h >> (n)) & ((1u << (32 - (n))) - 1)) & 0xFFFFFFFF
  158. #define F_LSH_GUARD(ds) F_LSH_K(ds,FP_GUARD,ds)
  159. #define F_RSH_GUARD(ds) F_RSH_K(ds,FP_GUARD,ds)
  160.  
  161. #define GET_BIT(ir,n) (((ir) >> n) & 1)
  162. #define GET_SIGN(ir) GET_BIT((ir), FP_V_SIGN)
  163. #define GET_EXP(ir) (((ir) >> FP_V_EXP) & FP_M_EXP)
  164. #define GET_SIGN_L(ir) GET_BIT((ir), 31)
  165. #define GET_SIGN_W(ir) GET_BIT((ir), 15)
  166.  
  167. extern jmp_buf save_env;
  168. extern int FEC, FEA, FPS;
  169. extern int CPUERR, trap_req;
  170. extern int N, Z, V, C;
  171. extern int R[8];
  172. extern fpac_t FR[6];
  173. extern int GeteaW (int spec);
  174. extern int ReadW (int addr);
  175. extern void WriteW (int data, int addr);
  176. fpac_t zero_fac = { 0, 0 };
  177. fpac_t one_fac = { 1, 0 };
  178. fpac_t fround_fac = { (1u << (FP_V_FROUND + 32)), 0 };
  179. fpac_t fround_guard_fac = { 0, (1u << (FP_V_FROUND + FP_GUARD)) };
  180. fpac_t dround_guard_fac = { (1u << (FP_V_DROUND + FP_GUARD)), 0 };
  181. fpac_t fmask_fac = { 0xFFFFFFFF, (1u << (FP_V_HB + FP_GUARD + 1)) - 1 };
  182. int backup_PC;
  183. int fpnotrap (int code);
  184. int GeteaFP (int spec, int len);
  185. unsigned int ReadI (int addr, int spec, int len);
  186. void ReadFP (fpac_t *fac, int addr, int spec, int len);
  187. void WriteI (int data, int addr, int spec, int len);
  188. void WriteFP (fpac_t *data, int addr, int spec, int len);
  189. int setfcc (int old_status, int result_high, int newV);
  190. int addfp11 (fpac_t *src1, fpac_t *src2);
  191. int mulfp11 (fpac_t *src1, fpac_t *src2);
  192. int divfp11 (fpac_t *src1, fpac_t *src2);
  193. int modfp11 (fpac_t *src1, fpac_t *src2, fpac_t *frac);
  194. void frac_mulfp11 (fpac_t *src1, fpac_t *src2);
  195. int roundfp11 (fpac_t *src);
  196. int round_and_pack (fpac_t *fac, int exp, fpac_t *frac);
  197.  
  198. /* Set up for instruction decode and execution */
  199.  
  200. void fp11 (int IR)
  201. {
  202. int dst, ea, ac, dstspec;
  203. int i, qdouble, lenf, leni;
  204. int newV, exp, sign;
  205. fpac_t fac, fsrc, modfrac;
  206. static const unsigned int i_limit[2][2] =
  207.     { { 0x80000000, 0x80010000 }, { 0x80000000, 0x80000001 } };
  208.  
  209. backup_PC = PC;                        /* save PC for FEA */
  210. ac = (IR >> 6) & 03;                    /* fac is IR<7:6> */
  211. dstspec = IR & 077;
  212. qdouble = FPS & FPS_D;
  213. lenf = qdouble? QUAD: LONG;
  214. switch ((IR >> 8) & 017) {                /* decode IR<11:8> */
  215. case 0:
  216.     switch (ac) {                    /* decode IR<7:6> */
  217.     case 0:                        /* specials */
  218.         if (IR == 0170000) {            /* CFCC */
  219.             N = (FPS >> PSW_V_N) & 1;
  220.             Z = (FPS >> PSW_V_Z) & 1;
  221.             V = (FPS >> PSW_V_V) & 1;
  222.             C = (FPS >> PSW_V_C) & 1;  }
  223.         else if (IR == 0170001)            /* SETF */
  224.             FPS = FPS & ~FPS_D;
  225.         else if (IR == 0170002)            /* SETI */
  226.             FPS = FPS & ~FPS_L;
  227.         else if (IR == 0170011)            /* SETD */
  228.             FPS = FPS | FPS_D;
  229.         else if (IR == 0170012)            /* SETL */
  230.             FPS = FPS | FPS_L;
  231.         else fpnotrap (FEC_OP);
  232.         break;
  233.     case 1:                        /* LDFPS */
  234.         dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaW (dstspec));
  235.         FPS = dst & FPS_RW;
  236.         break;
  237.     case 2:                        /* STFPS */
  238.         FPS = FPS & FPS_RW;
  239.         if (dstspec <= 07) R[dstspec] = FPS;
  240.         else WriteW (FPS, GeteaW (dstspec));
  241.         break;
  242.     case 3:                        /* STST */
  243.         if (dstspec <= 07) R[dstspec] = FEC;
  244.         else WriteI ((FEC << 16) | FEA, GeteaFP (dstspec, LONG),
  245.              dstspec, LONG);
  246.         break;  }                /* end switch <7:6> */
  247.     break;                        /* end case 0 */
  248.  
  249. /* "Easy" instructions */
  250.  
  251. case 1:
  252.     switch (ac) {                    /* decode IR<7:6> */
  253.     case 0:                        /* CLRf */
  254.         WriteFP (&zero_fac, GeteaFP (dstspec, lenf), dstspec, lenf);
  255.         FPS = (FPS & ~FPS_CC) | FPS_Z;
  256.         break;
  257.     case 1:                        /* TSTf */
  258.         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  259.         FPS = setfcc (FPS, fsrc.h, 0);
  260.         break;
  261.     case 2:                        /* ABSf */
  262.         ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
  263.         if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
  264.         else fsrc.h = fsrc.h & ~FP_SIGN;
  265.         WriteFP (&fsrc, ea, dstspec, lenf);
  266.         FPS = setfcc (FPS, fsrc.h, 0);
  267.         break;
  268.     case 3:                        /* NEGf */
  269.         ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
  270.         if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
  271.         else fsrc.h = fsrc.h ^ FP_SIGN;
  272.         WriteFP (&fsrc, ea, dstspec, lenf);
  273.         FPS = setfcc (FPS, fsrc.h, 0);
  274.         break;  }                /* end switch <7:6> */
  275.     break;                        /* end case 1 */
  276. case 5:                            /* LDf */
  277.     ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  278.     F_STORE (qdouble, fsrc, FR[ac]);
  279.     FPS = setfcc (FPS, fsrc.h, 0);
  280.     break;
  281. case 010:                        /* STf */
  282.     F_LOAD (qdouble, FR[ac], fac);
  283.     WriteFP (&fac, GeteaFP (dstspec, lenf), dstspec, lenf);
  284.     break;
  285. case 017:                        /* LDCff' */
  286.     ReadFP (&fsrc, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf);
  287.     if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
  288.     if ((FPS & (FPS_D + FPS_T)) == 0) newV = roundfp11 (&fsrc);
  289.     else newV = 0;
  290.     F_STORE (qdouble, fsrc, FR[ac]);
  291.     FPS = setfcc (FPS, fsrc.h, newV);
  292.     break;
  293. case 014:                        /* STCff' */
  294.     F_LOAD (qdouble, FR[ac], fac);
  295.     if (GET_EXP (fac.h) == 0) fac = zero_fac;
  296.     if ((FPS & (FPS_D + FPS_T)) == FPS_D) newV = roundfp11 (&fac);
  297.     else newV = 0;
  298.     WriteFP (&fac, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf);
  299.     FPS = setfcc (FPS, fac.h, newV);
  300.     break;
  301.  
  302. /* Compare instruction */
  303.  
  304. case 7:                            /* CMPf */
  305.     ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  306.     F_LOAD (qdouble, FR[ac], fac);
  307.     if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
  308.     if (GET_EXP (fac.h) == 0) fac = zero_fac;
  309.     if ((fsrc.h == fac.h) && (fsrc.l == fac.l)) {    /* equal? */
  310.         FPS = (FPS & ~FPS_CC) | FPS_Z;
  311.         if ((fsrc.h | fsrc.l) == 0) {        /* zero? */
  312.             F_STORE (qdouble, zero_fac, FR[ac]);  }
  313.         break;  }
  314.     FPS = (FPS & ~FPS_CC) | ((fsrc.h >> (FP_V_SIGN - PSW_V_N)) & FPS_N);
  315.     if ((GET_SIGN (fsrc.h ^ fac.h) == 0) && (fac.h != 0) &&
  316.         F_LT (fsrc, fac)) FPS = FPS ^ FPS_N;
  317.     break;
  318.  
  319. /* Load and store exponent instructions */
  320.  
  321. case 015:                        /* LDEXP */
  322.     dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaW (dstspec));
  323.     F_LOAD (qdouble, FR[ac], fac);
  324.     fac.h = (fac.h & ~FP_EXP) | (((dst + FP_BIAS) & FP_M_EXP) << FP_V_EXP);
  325.     newV = 0;
  326.     if ((dst > 0177) || (dst <= 0177600)) {
  327.         if (dst < 0100000) {
  328.             if (fpnotrap (FEC_OVFLO)) fac = zero_fac;
  329.             newV = FPS_V;  }
  330.         else {    if (fpnotrap (FEC_UNFLO)) fac = zero_fac;  }  }
  331.     F_STORE (qdouble, fac, FR[ac]);
  332.     FPS = setfcc (FPS, fac.h, newV);
  333.     break;    
  334. case 012:                        /* STEXP */
  335.     dst = (GET_EXP (FR[ac].h) - FP_BIAS) & 0177777;
  336.     N = GET_SIGN_W (dst);
  337.     Z = (dst == 0);
  338.     V = 0;
  339.     C = 0;
  340.     FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) | (Z << PSW_V_N);
  341.     if (dstspec <= 07) R[dstspec] = dst;
  342.     else WriteW (dst, GeteaW (dstspec));
  343.     break;
  344.  
  345. /* Integer convert instructions */
  346.  
  347. case 016:                        /* LDCif */
  348.     leni = FPS & FPS_L? LONG: WORD;
  349.     if (dstspec <= 07) fac.l = R[dstspec] << 16;
  350.     else fac.l = ReadI (GeteaFP (dstspec, leni), dstspec, leni);
  351.     fac.h = 0;
  352.     if (fac.l) {
  353.         if (sign = GET_SIGN_L (fac.l)) fac.l = -fac.l;
  354.         for (i = 0; GET_SIGN_L (fac.l) == 0; i++) fac.l = fac.l << 1;
  355.         exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i;
  356.         fac.h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) |
  357.           ((fac.l >> (31 - FP_V_HB)) & FP_FRACH);
  358.         fac.l = (fac.l << (FP_V_HB + 1)) & FP_FRACL;
  359.         if ((FPS & (FPS_D + FPS_T)) == 0) roundfp11 (&fac);  }
  360.     F_STORE (qdouble, fac, FR[ac]);
  361.     FPS = setfcc (FPS, fac.h, 0);
  362.     break;
  363. case 013:                        /* STCfi */
  364.     sign = GET_SIGN (FR[ac].h);            /* get sign, */
  365.     exp = GET_EXP (FR[ac].h);            /* exponent, */
  366.     F_LOAD_FRAC (qdouble, FR[ac], fac);        /* fraction */
  367.     if (FPS & FPS_L) {
  368.         leni = LONG;
  369.         i = FP_BIAS + 32;  }
  370.     else {    leni = WORD;
  371.         i = FP_BIAS + 16;  }
  372.     C = 0;
  373.     if (exp <= FP_BIAS) dst = 0;
  374.     else if (exp > i) {
  375.         dst = 0;
  376.         C = 1;  }
  377.     else {    F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc);
  378.         dst = fsrc.l;
  379.         if (fsrc.l >= i_limit[leni == LONG][sign]) {
  380.             dst = 0;
  381.             C = 1;  }
  382.         else if (sign) dst = (-dst);  }
  383.     N = GET_SIGN_L (dst);
  384.     Z = (dst == 0);
  385.     V = 0;
  386.     if (C) fpnotrap (FEC_ICVT);
  387.     FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) |
  388.         (Z << PSW_V_N) | (C << PSW_V_C);
  389.     if (dstspec <= 07) R[dstspec] = (dst >> 16) & 0177777;
  390.     else WriteI (dst, GeteaFP (dstspec, leni), dstspec, leni);
  391.     break;
  392.  
  393. /* Calculation instructions */
  394.  
  395. case 2:                            /* MULf */
  396.     ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  397.     F_LOAD (qdouble, FR[ac], fac);
  398.     newV = mulfp11 (&fac, &fsrc);
  399.     F_STORE (qdouble, fac, FR[ac]);
  400.     FPS = setfcc (FPS, fac.h, newV);
  401.     break;
  402. case 3:                            /* MODf */
  403.     ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  404.     F_LOAD (qdouble, FR[ac], fac);
  405.     newV = modfp11 (&fac, &fsrc, &modfrac);
  406.     F_STORE (qdouble, fac, FR[ac | 1]);
  407.     F_STORE (qdouble, modfrac, FR[ac]);
  408.     FPS = setfcc (FPS, fac.h, newV);
  409.     break;
  410. case 4:                            /* ADDf */
  411.     ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  412.     F_LOAD (qdouble, FR[ac], fac);
  413.     newV = addfp11 (&fac, &fsrc);
  414.     F_STORE (qdouble, fac, FR[ac]);
  415.     FPS = setfcc (FPS, fac.h, newV);
  416.     break;
  417. case 6:                            /* SUBf */
  418.     ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  419.     F_LOAD (qdouble, FR[ac], fac);
  420.     if (GET_EXP (fsrc.h) != 0) fsrc.h = fsrc.h ^ FP_SIGN;
  421.     newV = addfp11 (&fac, &fsrc);
  422.     F_STORE (qdouble, fac, FR[ac]);
  423.     FPS = setfcc (FPS, fac.h, newV);
  424.     break;
  425. case 011:                        /* DIVf */
  426.     ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
  427.     F_LOAD (qdouble, FR[ac], fac);
  428.     newV = divfp11 (&fac, &fsrc);
  429.     F_STORE (qdouble, fac, FR[ac]);
  430.     FPS = setfcc (FPS, fac.h, newV);
  431.     break;  }                    /* end switch fop */
  432. return;
  433. }                            /* end fp11 */
  434.  
  435. /* Effective address calculation for fp operands
  436.  
  437.    Inputs:
  438.     spec    =    specifier
  439.     len    =    length
  440.    Outputs:
  441.     VA    =    virtual address
  442.  
  443.    Warnings:
  444.     - Do not call this routine for integer mode 0 operands
  445.     - Do not call this routine more than once per instruction
  446. */
  447.  
  448. int GeteaFP (int spec, int len)
  449. {
  450. int adr, reg, ds;
  451. extern int cm, isenable, dsenable, MMR0, MMR1;
  452.  
  453. reg = spec & 07;                    /* reg number */
  454. ds = (reg == 7)? isenable: dsenable;            /* dspace if not PC */
  455. switch (spec >> 3) {                    /* case on spec */
  456. case 0:                            /* floating AC */
  457.     if (reg >= 06) { fpnotrap (FEC_OP); ABORT (TRAP_INT);  }
  458.     return 0;
  459. case 1:                            /* (R) */
  460.     return (R[reg] | ds);
  461. case 2:                            /* (R)+ */
  462.     if (reg == 7) len = 2;
  463.     R[reg] = ((adr = R[reg]) + len) & 0177777;
  464.     if (update_MM) MMR1 = (len << 3) | reg;
  465.     return (adr | ds);
  466. case 3:                            /* @(R)+ */
  467.     R[reg] = ((adr = R[reg]) + 2) & 0177777;
  468.     if (update_MM) MMR1 = 020 | reg;
  469.     adr = ReadW (adr | ds);
  470.     return (adr | dsenable);
  471. case 4:                            /* -(R) */
  472.     adr = R[reg] = (R[reg] - len) & 0177777;
  473.     if (update_MM) MMR1 = (((-len) & 037) << 3) | reg;
  474.     if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
  475.         setTRAP (TRAP_YEL);
  476.         setCPUERR (CPUE_YEL);  }
  477.     return (adr | ds);
  478. case 5:                            /* @-(R) */
  479.     adr = R[reg] = (R[reg] - 2) & 0177777;
  480.     if (update_MM) MMR1 = 0360 | reg;
  481.     if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
  482.         setTRAP (TRAP_YEL);
  483.         setCPUERR (CPUE_YEL);  }
  484.     adr = ReadW (adr | ds);
  485.     return (adr | dsenable);
  486. case 6:                            /* d(r) */
  487.     adr = ReadW (PC | isenable);
  488.     PC = (PC + 2) & 0177777;
  489.     return (((R[reg] + adr) & 0177777) | dsenable);
  490. case 7:                            /* @d(R) */
  491.     adr = ReadW (PC | isenable);
  492.     PC = (PC + 2) & 0177777;
  493.     adr = ReadW (((R[reg] + adr) & 0177777) | dsenable);
  494.     return (adr | dsenable);  }            /* end switch */
  495. }                            /* end GeteaFP */
  496.  
  497. /* Read integer operand
  498.  
  499.    Inputs:
  500.     VA    =    virtual address, VA<18:16> = mode, I/D space
  501.     spec    =    specifier
  502.     len    =    length (2/4 bytes)
  503.    Outputs:
  504.     data    =    data read from memory or I/O space
  505. */
  506.  
  507. unsigned int ReadI (int VA, int spec, int len)
  508. {
  509. if ((len == WORD) || (spec == 027)) return (ReadW (VA) << 16);
  510. return ((ReadW (VA) << 16) | ReadW ((VA & ~0177777) | ((VA + 2) & 0177777)));
  511. }
  512.  
  513. /* Read floating operand
  514.  
  515.    Inputs:
  516.     fptr    =    pointer to output
  517.     VA    =    virtual address, VA<18:16> = mode, I/D space
  518.     spec    =    specifier
  519.     len    =    length (4/8 bytes)
  520. */
  521.  
  522. void ReadFP (fpac_t *fptr, int VA, int spec, int len)
  523. {
  524. int exta;
  525.  
  526. if (spec <= 07) {
  527.     F_LOAD_P (len == QUAD, FR[spec], fptr);
  528.     return;  }
  529. if (spec == 027) {
  530.     fptr -> h = (ReadW (VA) << FP_V_F0);
  531.     fptr -> l = 0;  }
  532. else {    exta = VA & ~0177777;
  533.     fptr -> h = (ReadW (VA) << FP_V_F0) |
  534.         (ReadW (exta | ((VA + 2) & 0177777)) << FP_V_F1);
  535.     if (len == QUAD) fptr -> l = 
  536.         (ReadW (exta | ((VA + 4) & 0177777)) << FP_V_F2) |
  537.         (ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3);
  538.     else fptr -> l = 0;  }
  539. if ((GET_SIGN (fptr -> h) != 0) && (GET_EXP (fptr -> h) == 0) &&
  540.     (fpnotrap (FEC_UNDFV) == 0)) ABORT (TRAP_INT);
  541. return;
  542. }
  543.  
  544. /* Write integer result
  545.  
  546.    Inputs:
  547.     data    =    data to be written
  548.     VA    =    virtual address, VA<18:16> = mode, I/D space
  549.     spec    =    specifier
  550.     len    =    length
  551.    Outputs: none
  552. */
  553.  
  554. void WriteI (int data, int VA, int spec, int len)
  555. {
  556. WriteW ((data >> 16) & 0177777, VA);
  557. if ((len == WORD) || (spec == 027)) return;
  558. WriteW (data & 0177777, (VA & ~0177777) | ((VA + 2) & 0177777));
  559. return;
  560. }
  561.  
  562. /* Write floating result
  563.  
  564.    Inputs:
  565.     fptr    =    pointer to data to be written
  566.     VA    =    virtual address, VA<18:16> = mode, I/D space
  567.     spec    =    specifier
  568.     len    =    length
  569.    Outputs: none
  570. */
  571.  
  572. void WriteFP (fpac_t *fptr, int VA, int spec, int len)
  573. {
  574. int exta;
  575.  
  576. if (spec <= 07) {
  577.     F_STORE_P (len == QUAD, fptr, FR[spec]);
  578.     return;  }
  579. WriteW ((fptr -> h >> FP_V_F0) & 0177777, VA);
  580. if (spec == 027) return;
  581. exta = VA & ~0177777;
  582. WriteW ((fptr -> h >> FP_V_F1) & 0177777, exta | ((VA + 2) & 0177777));
  583. if (len == LONG) return;
  584. WriteW ((fptr -> l >> FP_V_F2) & 0177777, exta | ((VA + 4) & 0177777));
  585. WriteW ((fptr -> l >> FP_V_F3) & 0177777, exta | ((VA + 6) & 0177777));
  586. return;
  587. }
  588.  
  589. /* Floating point add
  590.  
  591.    Inputs:
  592.     facp    =    pointer to src1 (output)
  593.     fsrcp    =    pointer to src2
  594.    Outputs:
  595.     ovflo    =    overflow variable
  596. */
  597.  
  598. int addfp11 (fpac_t *facp, fpac_t *fsrcp)
  599. {
  600. int facexp, fsrcexp, ediff;
  601. fpac_t facfrac, fsrcfrac;
  602.  
  603. if (F_LT_AP (facp, fsrcp)) {                /* if !fac! < !fsrc! */
  604.     facfrac = *facp;
  605.     *facp = *fsrcp;                    /* swap operands */
  606.     *fsrcp = facfrac;  }
  607. facexp = GET_EXP (facp -> h);                /* get exponents */
  608. fsrcexp = GET_EXP (fsrcp -> h);
  609. if (facexp == 0) {                    /* fac = 0? */
  610.     *facp = fsrcexp? *fsrcp: zero_fac;        /* result fsrc or 0 */
  611.     return 0;  }
  612. if (fsrcexp == 0) return 0;                /* fsrc = 0? no op */
  613. ediff = facexp - fsrcexp;                /* exponent diff */
  614. if (ediff >= 60) return 0;                /* too big? no op */
  615. F_GET_FRAC_P (facp, facfrac);                /* get fractions */
  616. F_GET_FRAC_P (fsrcp, fsrcfrac);
  617. F_LSH_GUARD (facfrac);                    /* guard fractions */
  618. F_LSH_GUARD (fsrcfrac);
  619. if (GET_SIGN (facp -> h) != GET_SIGN (fsrcp -> h)) {    /* signs different? */
  620.     if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac);  } /* sub, shf fsrc */
  621.     F_SUB (fsrcfrac, facfrac, facfrac);        /* sub fsrc from fac */
  622.     if ((facfrac.h | facfrac.l) == 0)  {         /* result zero? */
  623.         *facp = zero_fac;            /* no overflow */
  624.         return 0;  }
  625.     if (ediff <= 1) {                /* big normalize? */
  626.         if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
  627.             F_LSH_K (facfrac, 24, facfrac);
  628.             facexp = facexp - 24;  }
  629.         if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
  630.             F_LSH_K (facfrac, 12, facfrac);
  631.             facexp = facexp - 12;  }
  632.         if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
  633.             F_LSH_K (facfrac, 6, facfrac);
  634.             facexp = facexp - 6;  }  }
  635.     while (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
  636.         F_LSH_1 (facfrac);
  637.         facexp = facexp - 1;  }  }
  638. else {    if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac);  } /* add, shf fsrc */
  639.     F_ADD (fsrcfrac, facfrac, facfrac);        /* add fsrc to fac */
  640.     if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD + 1)) {
  641.         F_RSH_1 (facfrac);            /* carry out, shift */
  642.         facexp = facexp + 1;  }  }
  643. return round_and_pack (facp, facexp, &facfrac);
  644. }                            /* end addfp11 */
  645.  
  646. /* Floating point multiply
  647.  
  648.    Inputs:
  649.     facp    =    pointer to src1 (output)
  650.     fsrcp    =    pointer to src2
  651.    Outputs:
  652.     ovflo    =    overflow indicator
  653. */
  654.  
  655. int mulfp11 (fpac_t *facp, fpac_t *fsrcp)
  656. {
  657. int facexp, fsrcexp;
  658. fpac_t facfrac, fsrcfrac;
  659.  
  660. facexp = GET_EXP (facp -> h);                /* get exponents */
  661. fsrcexp = GET_EXP (fsrcp -> h);
  662. if ((facexp == 0) || (fsrcexp == 0)) {            /* test for zero */
  663.     *facp = zero_fac;
  664.     return 0;  }
  665. F_GET_FRAC_P (facp, facfrac);                /* get fractions */
  666. F_GET_FRAC_P (fsrcp, fsrcfrac);
  667. facexp = facexp + fsrcexp - FP_BIAS;            /* calculate exp */
  668. facp -> h = facp -> h  ^ fsrcp -> h;            /* calculate sign */
  669. frac_mulfp11 (&facfrac, &fsrcfrac);            /* multiply fracs */
  670.  
  671. /* Multiplying two numbers in the range [.5,1) produces a result in the
  672.    range [.25,1).  Therefore, at most one bit of normalization is required
  673.    to bring the result back to the range [.5,1).
  674. */
  675.  
  676. if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
  677.     F_LSH_1 (facfrac);
  678.     facexp = facexp - 1;  }
  679. return round_and_pack (facp, facexp, &facfrac);
  680. }                            /* end mulfp11 */
  681.  
  682. /* Floating point mod
  683.  
  684.    Inputs:
  685.     facp    =    pointer to src1 (integer result)
  686.     fsrcp    =    pointer to src2
  687.     fracp    =    pointer to fractional result
  688.    Outputs:
  689.     ovflo    =    overflow indicator
  690.  
  691.    See notes on multiply for initial operation
  692. */
  693.  
  694. int modfp11 (fpac_t *facp, fpac_t *fsrcp, fpac_t *fracp)
  695. {
  696. int facexp, fsrcexp;
  697. fpac_t facfrac, fsrcfrac, fmask;
  698.  
  699. facexp = GET_EXP (facp -> h);                /* get exponents */
  700. fsrcexp = GET_EXP (fsrcp -> h);
  701. if ((facexp == 0) || (fsrcexp == 0)) {            /* test for zero */
  702.     *fracp = zero_fac;
  703.     *facp = zero_fac;
  704.     return 0;  }
  705. F_GET_FRAC_P (facp, facfrac);                /* get fractions */
  706. F_GET_FRAC_P (fsrcp, fsrcfrac);
  707. facexp = facexp + fsrcexp - FP_BIAS;            /* calculate exp */
  708. fracp -> h = facp -> h = facp -> h ^ fsrcp -> h;    /* calculate sign */
  709. frac_mulfp11 (&facfrac, &fsrcfrac);            /* multiply fracs */
  710.  
  711. /* Multiplying two numbers in the range [.5,1) produces a result in the
  712.    range [.25,1).  Therefore, at most one bit of normalization is required
  713.    to bring the result back to the range [.5,1).
  714. */
  715.  
  716. if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
  717.     F_LSH_1 (facfrac);
  718.     facexp = facexp - 1;  }
  719.  
  720. /* There are three major cases of MODf:
  721.  
  722.    1. Exp <= FP_BIAS (all fraction).  Return 0 as integer, product as
  723.       fraction.  Underflow can occur.
  724.    2. Exp > FP_BIAS + #fraction bits (all integer).  Return product as
  725.       integer, 0 as fraction.  Overflow can occur.
  726.    3. FP_BIAS < exp <= FP_BIAS + #fraction bits.  Separate integer and
  727.       fraction and return both.  Neither overflow nor underflow can occur.
  728. */
  729.  
  730.     if (facexp <= FP_BIAS) {            /* case 1 */
  731.         *facp = zero_fac;
  732.         return round_and_pack (fracp, facexp, &facfrac);  }
  733.     if (facexp > ((FPS & FPS_D)? FP_BIAS + 56: FP_BIAS + 24)) {
  734.         *fracp = zero_fac;            /* case 2 */
  735.         return round_and_pack (facp, facexp, &facfrac);  }
  736.     F_RSH_V (fmask_fac, facexp - FP_BIAS, fmask);    /* shift mask */
  737.     fsrcfrac.l = facfrac.l & fmask.l;        /* extract fraction */
  738.     fsrcfrac.h = facfrac.h & fmask.h;
  739.     if ((fsrcfrac.h | fsrcfrac.l) == 0) *fracp = zero_fac;
  740.     else {    F_LSH_V (fsrcfrac, facexp - FP_BIAS, fsrcfrac);
  741.         fsrcexp = FP_BIAS;
  742.         if ((fsrcfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
  743.             F_LSH_K (fsrcfrac, 24, fsrcfrac);
  744.             fsrcexp = fsrcexp - 24;  }
  745.         if ((fsrcfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
  746.             F_LSH_K (fsrcfrac, 12, fsrcfrac);
  747.             fsrcexp = fsrcexp - 12;  }
  748.         if ((fsrcfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
  749.             F_LSH_K (fsrcfrac, 6, fsrcfrac);
  750.             fsrcexp = fsrcexp - 6;  }
  751.         while (GET_BIT (fsrcfrac.h, FP_V_HB + FP_GUARD) == 0) {
  752.             F_LSH_1 (fsrcfrac);
  753.             fsrcexp = fsrcexp - 1;  }
  754.         round_and_pack (fracp, fsrcexp, &fsrcfrac);  }
  755.     facfrac.l = facfrac.l & ~fmask.l;
  756.     facfrac.h = facfrac.h & ~fmask.h;
  757.     return round_and_pack (facp, facexp, &facfrac);
  758. }
  759.  
  760. /* Fraction multiply
  761.  
  762.    Inputs:
  763.     f1p    =    pointer to multiplier (output)
  764.     f2p    =    pointer to multiplicand fraction
  765.  
  766.    Note: the inputs are unguarded; the output is guarded.
  767.  
  768.    This routine performs a classic shift-and-add multiply.  The low
  769.    order bit of the multiplier is tested; if 1, the multiplicand is
  770.    added into the high part of the double precision result.  The
  771.    result and the multiplier are both shifted right 1.
  772.  
  773.    For the 24b x 24b case, this routine develops 48b of result.
  774.    For the 56b x 56b case, this routine only develops the top 64b
  775.    of the the result.  Because the inputs are normalized fractions,
  776.    the interesting part of the result is the high 56+guard bits.
  777.    Everything shifted off to the right, beyond 64b, plays no part
  778.    in rounding or the result.
  779.  
  780.    There are many possible optimizations in this routine: scanning
  781.    for groups of zeroes, particularly in the 56b x 56b case; using
  782.    "extended multiply" capability if available in the hardware.
  783. */
  784.  
  785. void frac_mulfp11 (fpac_t *f1p, fpac_t *f2p)
  786. {
  787. fpac_t result, mpy, mpc;
  788. int i;
  789.  
  790. result = zero_fac;                    /* clear result */
  791. mpy = *f1p;                        /* get operands */
  792. mpc = *f2p;
  793. F_LSH_GUARD (mpc);                    /* guard multipicand */
  794. if ((mpy.l | mpc.l) == 0) {                /* 24b x 24b? */
  795.     for (i = 0; i < 24; i++) {
  796.         if (mpy.h & 1) result.h = result.h + mpc.h;
  797.         F_RSH_1 (result);
  798.         mpy.h = mpy.h >> 1;  }  }
  799. else {    if (mpy.l != 0) {                /* 24b x 56b? */
  800.         for (i = 0; i < 32; i++) {
  801.             if (mpy.l & 1) { F_ADD (mpc, result, result);  }
  802.             F_RSH_1 (result);
  803.             mpy.l = mpy.l >> 1;  }  }
  804.     for (i = 0; i < 24; i++) {
  805.         if (mpy.h & 1) { F_ADD (mpc, result, result);  }
  806.         F_RSH_1 (result);
  807.         mpy.h = mpy.h >> 1;  }  }
  808. *f1p = result;
  809. return;
  810. }
  811.  
  812. /* Floating point divide
  813.  
  814.    Inputs:
  815.     facp    =    pointer to dividend (output)
  816.     fsrcp    =    pointer to divisor
  817.    Outputs:
  818.     ovflo    =    overflow indicator
  819. */
  820.  
  821. int divfp11 (fpac_t *facp, fpac_t *fsrcp)
  822. {
  823. int facexp, fsrcexp, i, count, qd;
  824. fpac_t facfrac, fsrcfrac, quo;
  825.  
  826. fsrcexp = GET_EXP (fsrcp -> h);                /* get divisor exp */
  827. if (fsrcexp == 0) {                    /* divide by zero? */
  828.     fpnotrap (FEC_DZRO);
  829.     ABORT (TRAP_INT);  }
  830. facexp = GET_EXP (facp -> h);                /* get dividend exp */
  831. if (facexp == 0) {                    /* test for zero */
  832.     *facp = zero_fac;                /* result zero */
  833.     return 0;  }
  834. F_GET_FRAC_P (facp, facfrac);                /* get fractions */
  835. F_GET_FRAC_P (fsrcp, fsrcfrac);
  836. F_LSH_GUARD (facfrac);                    /* guard fractions */
  837. F_LSH_GUARD (fsrcfrac);
  838. facexp = facexp - fsrcexp + FP_BIAS + 1;        /* calculate exp */
  839. facp -> h = facp -> h ^ fsrcp -> h;            /* calculate sign */
  840. qd = FPS & FPS_D;
  841. count = FP_V_HB + FP_GUARD + (qd? 33: 1);        /* count = 56b/24b */
  842.  
  843. quo = zero_fac;
  844. for (i = count; (i > 0) && ((facfrac.h | facfrac.l) != 0); i--) {
  845.     F_LSH_1 (quo);                    /* shift quotient */
  846.     if (!F_LT (facfrac, fsrcfrac)) {        /* divd >= divr? */
  847.         F_SUB (fsrcfrac, facfrac, facfrac);    /* divd - divr */
  848.         if (qd) quo.l = quo.l | 1;        /* double or single? */
  849.         else quo.h = quo.h | 1;  }
  850.     F_LSH_1 (facfrac);  }                /* shift divd */
  851. if (i > 0) { F_LSH_V (quo, i, quo);  }            /* early exit? */
  852.  
  853. /* Dividing two numbers in the range [.5,1) produces a result in the
  854.    range [.5,2).  Therefore, at most one bit of normalization is required
  855.    to bring the result back to the range [.5,1).  The choice of counts
  856.    and quotient bit positions makes this work correctly.
  857. */
  858.  
  859. if (GET_BIT (quo.h, FP_V_HB + FP_GUARD) == 0) {
  860.     F_LSH_1 (quo);
  861.     facexp = facexp - 1;  }
  862. return round_and_pack (facp, facexp, &quo);
  863. }                            /* end divfp11 */
  864.  
  865. /* Update floating condition codes
  866.    Note that FC is only set by STCfi via the integer condition codes
  867.  
  868.    Inputs:
  869.     oldst    =    current status
  870.     result    =    high result
  871.     newV    =    new V
  872.    Outputs:
  873.     newst    =    new status
  874. */
  875.  
  876. int setfcc (int oldst, int result, int newV)
  877. {
  878. oldst = (oldst & ~FPS_CC) | newV;
  879. if (GET_SIGN (result)) oldst = oldst | FPS_N;
  880. if (GET_EXP (result) == 0) oldst = oldst | FPS_Z;
  881. return oldst;
  882. }
  883.  
  884. /* Round (in place) floating point number to f_floating
  885.  
  886.    Inputs:
  887.     fptr    =    pointer to floating number
  888.    Outputs:
  889.     ovflow    =    overflow
  890. */
  891.  
  892. int roundfp11 (fpac_t *fptr)
  893. {
  894. fpac_t outf;
  895.  
  896. outf = *fptr;                        /* get argument */
  897. F_ADD (fround_fac, outf, outf);                /* round */
  898. if (GET_SIGN (outf.h ^ fptr -> h)) {            /* flipped sign? */
  899.     outf.h = (outf.h ^ FP_SIGN) & 0xFFFFFFFF;    /* restore sign */
  900.     if (fpnotrap (FEC_OVFLO)) *fptr = zero_fac;     /* if no int, clear */
  901.     else *fptr = outf;                /* return rounded */
  902.     return FPS_V;  }                /* overflow */
  903. else {    *fptr = outf;                    /* round was ok */
  904.     return 0;  }                    /* no overflow */
  905. }
  906.  
  907. /* Round result of calculation, test overflow, pack
  908.  
  909.    Input:
  910.     facp    =    pointer to result, sign in place
  911.     exp    =    result exponent, right justified
  912.     fracp    =    pointer to result fraction, right justified with
  913.             guard bits
  914.    Outputs:
  915.     ovflo    =    overflow indicator
  916. */
  917.  
  918. int round_and_pack (fpac_t *facp, int exp, fpac_t *fracp)
  919. {
  920. fpac_t frac;
  921.  
  922. frac = *fracp;                        /* get fraction */
  923. if ((FPS & FPS_T) == 0) { 
  924.     if (FPS & FPS_D) { F_ADD (dround_guard_fac, frac, frac);  }
  925.     else { F_ADD (fround_guard_fac, frac, frac);  }
  926.     if (GET_BIT (frac.h, FP_V_HB + FP_GUARD + 1)) {
  927.         F_RSH_1 (frac);
  928.         exp = exp + 1;  }  }
  929. F_RSH_GUARD (frac);
  930. facp -> l = frac.l & FP_FRACL;
  931. facp -> h = (facp -> h & FP_SIGN) | (exp << FP_V_EXP) | (frac.h & FP_FRACH);
  932. if (exp > 0377) {
  933.     if (fpnotrap (FEC_OVFLO)) *facp = zero_fac;
  934.     return FPS_V;  }
  935. if ((exp <= 0) && (fpnotrap (FEC_UNFLO))) *facp = zero_fac;
  936. return 0;
  937. }
  938.  
  939. /* Process floating point exception
  940.  
  941.    Inputs:
  942.     code    =    exception code
  943.    Outputs:
  944.     int    =    FALSE if interrupt enabled, TRUE if disabled
  945. */
  946.  
  947. int fpnotrap (int code)
  948. {
  949. static const int test_code[] = { 0, 0, 0, FPS_IC, FPS_IV, FPS_IU, FPS_IUV };
  950.  
  951. if ((code >= FEC_ICVT) && (code <= FEC_UNDFV) &&
  952.     ((FPS & test_code[code >> 1]) == 0)) return TRUE;
  953. FPS = FPS | FPS_ER;
  954. FEC = code;
  955. FEA = (backup_PC - 2) & 0177777;
  956. if ((FPS & FPS_ID) == 0) setTRAP (TRAP_FPE);
  957. return FALSE;
  958. }
  959.