Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 1 | /* pdp10_mdfp.c: PDP-10 multiply/divide and floating point simulator
|
| 2 |
|
Mark Pizzolato | 820d77e | 2016-05-05 03:50:21 -0700 | [diff] [blame] | 3 | Copyright (c) 1993-2016, Robert M Supnik
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 4 |
|
| 5 | Permission is hereby granted, free of charge, to any person obtaining a
|
| 6 | copy of this software and associated documentation files (the "Software"),
|
| 7 | to deal in the Software without restriction, including without limitation
|
| 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
| 9 | and/or sell copies of the Software, and to permit persons to whom the
|
| 10 | Software is furnished to do so, subject to the following conditions:
|
| 11 |
|
| 12 | The above copyright notice and this permission notice shall be included in
|
| 13 | all copies or substantial portions of the Software.
|
| 14 |
|
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
| 18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
| 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
| 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
| 21 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 22 | Except as contained in this notice, the name of Robert M Supnik shall not be
|
| 23 | used in advertising or otherwise to promote the sale, use or other dealings
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 24 | in this Software without prior written authorization from Robert M Supnik.
|
Bob Supnik | 26aa6de | 2004-04-06 05:17:00 -0700 | [diff] [blame] | 25 |
|
Mark Pizzolato | 820d77e | 2016-05-05 03:50:21 -0700 | [diff] [blame] | 26 | 05-May-16 RMS Fixed bug in DMUL carry (Mark Pizzolato)
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 27 | 2-Apr-04 RMS Fixed bug in floating point unpack
|
| 28 | Fixed bug in FIXR (found by Phil Stone, fixed by
|
| 29 | Chris Smith)
|
| 30 | 31-Aug-01 RMS Changed int64 to t_int64 for Windoze
|
| 31 | 10-Aug-01 RMS Removed register in declarations
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 32 |
|
| 33 | Instructions handled in this module:
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 34 | imul integer multiply
|
| 35 | idiv integer divide
|
| 36 | mul multiply
|
| 37 | div divide
|
| 38 | dmul double precision multiply
|
| 39 | ddiv double precision divide
|
| 40 | fad(r) floating add (and round)
|
| 41 | fsb(r) floating subtract (and round)
|
| 42 | fmp(r) floating multiply (and round)
|
| 43 | fdv(r) floating divide and round
|
| 44 | fsc floating scale
|
| 45 | fix(r) floating to fixed (and round)
|
| 46 | fltr fixed to floating and round
|
| 47 | dfad double precision floating add/subtract
|
| 48 | dfmp double precision floating multiply
|
| 49 | dfdv double precision floating divide
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 50 |
|
| 51 | The PDP-10 stores double (quad) precision integers in sequential
|
| 52 | AC's or memory locations. Integers are stored in 2's complement
|
| 53 | form. Only the sign of the high order word matters; the signs
|
| 54 | in low order words are ignored on input and set to the sign of
|
| 55 | the result on output. Quad precision integers exist only in the
|
| 56 | AC's as the result of a DMUL or the dividend of a DDIV.
|
| 57 |
|
| 58 | 0 00000000011111111112222222222333333
|
| 59 | 0 12345678901234567890123456789012345
|
| 60 | +-+-----------------------------------+
|
| 61 | |S| high order integer | AC(n), A
|
| 62 | +-+-----------------------------------+
|
| 63 | |S| low order integer | AC(n + 1), A + 1
|
| 64 | +-+-----------------------------------+
|
| 65 | |S| low order integer | AC(n + 2)
|
| 66 | +-+-----------------------------------+
|
| 67 | |S| low order integer | AC(n + 3)
|
| 68 | +-+-----------------------------------+
|
| 69 |
|
| 70 | The PDP-10 supports two floating point formats: single and double
|
| 71 | precision. In both, the exponent is 8 bits, stored in excess
|
| 72 | 128 notation. The fraction is expected to be normalized. A
|
| 73 | single precision floating point number has 27 bits of fraction;
|
| 74 | a double precision number has 62 bits of fraction (the sign
|
| 75 | bit of the second word is ignored and is set to zero).
|
| 76 |
|
| 77 | In a negative floating point number, the exponent is stored in
|
| 78 | one's complement form, the fraction in two's complement form.
|
| 79 |
|
| 80 | 0 00000000 011111111112222222222333333
|
| 81 | 0 12345678 901234567890123456789012345
|
| 82 | +-+--------+---------------------------+
|
| 83 | |S|exponent| high order fraction | AC(n), A
|
| 84 | +-+--------+---------------------------+
|
| 85 | |0| low order fraction | AC(n + 1), A + 1
|
| 86 | +-+------------------------------------+
|
| 87 |
|
| 88 | Note that treatment of the sign is different for double precision
|
| 89 | integers and double precision floating point. DMOVN (implemented
|
| 90 | as an inline macro) follows floating point conventions.
|
| 91 |
|
| 92 | The original PDP-10 CPU (KA10) used a different format for double
|
| 93 | precision numbers and included certain instructions to make
|
| 94 | software support easier. These instructions were phased out in
|
| 95 | the KL10 and KS10 and are treated as MUUO's.
|
| 96 |
|
| 97 | The KL10 added extended precision (11-bit exponent) floating point
|
| 98 | format (so-called G floating). These instructions were not
|
| 99 | implemented in the KS10 and are treated as MUUO's.
|
| 100 | */
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 101 |
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 102 | #include "pdp10_defs.h"
|
| 103 | #include <setjmp.h>
|
| 104 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 105 | typedef struct { /* unpacked fp number */
|
| 106 | int32 sign; /* sign */
|
| 107 | int32 exp; /* exponent */
|
| 108 | t_uint64 fhi; /* fraction high */
|
| 109 | t_uint64 flo; /* for double prec */
|
| 110 | } UFP;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 111 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 112 | #define MSK32 0xFFFFFFFF
|
| 113 | #define FIT27 (DMASK - 0x07FFFFFF)
|
| 114 | #define FIT32 (DMASK - MSK32)
|
| 115 | #define SFRC TRUE /* frac 2's comp */
|
| 116 | #define AFRC FALSE /* frac abs value */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 117 |
|
| 118 | /* In packed floating point number */
|
| 119 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 120 | #define FP_BIAS 0200 /* exponent bias */
|
| 121 | #define FP_N_FHI 27 /* # of hi frac bits */
|
| 122 | #define FP_V_FHI 0 /* must be zero */
|
Mark Pizzolato | c93658f | 2013-04-05 12:34:37 -0700 | [diff] [blame] | 123 | #define FP_M_FHI INT64_C(0000777777777)
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 124 | #define FP_N_EXP 8 /* # of exp bits */
|
| 125 | #define FP_V_EXP (FP_V_FHI + FP_N_FHI)
|
| 126 | #define FP_M_EXP 0377
|
| 127 | #define FP_V_SIGN (FP_V_EXP + FP_N_EXP) /* sign */
|
| 128 | #define FP_N_FLO 35 /* # of lo frac bits */
|
| 129 | #define FP_V_FLO 0 /* must be zero */
|
Mark Pizzolato | c93658f | 2013-04-05 12:34:37 -0700 | [diff] [blame] | 130 | #define FP_M_FLO INT64_C(0377777777777)
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 131 | #define GET_FPSIGN(x) ((int32) (((x) >> FP_V_SIGN) & 1))
|
| 132 | #define GET_FPEXP(x) ((int32) (((x) >> FP_V_EXP) & FP_M_EXP))
|
| 133 | #define GET_FPHI(x) ((x) & FP_M_FHI)
|
| 134 | #define GET_FPLO(x) ((x) & FP_M_FLO)
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 135 |
|
| 136 | /* In unpacked floating point number */
|
| 137 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 138 | #define FP_N_GUARD 1 /* # of guard bits */
|
| 139 | #define FP_V_UFLO FP_N_GUARD /* <35:1> */
|
| 140 | #define FP_V_URNDD (FP_V_UFLO - 1) /* dp round bit */
|
| 141 | #define FP_V_UFHI (FP_V_UFLO + FP_N_FLO) /* <62:36> */
|
| 142 | #define FP_V_URNDS (FP_V_UFHI - 1) /* sp round bit */
|
| 143 | #define FP_V_UCRY (FP_V_UFHI + FP_N_FHI) /* <63> */
|
| 144 | #define FP_V_UNORM (FP_V_UCRY - 1) /* normalized bit */
|
Mark Pizzolato | c93658f | 2013-04-05 12:34:37 -0700 | [diff] [blame] | 145 | #define FP_UFHI INT64_C(0x7FFFFFF000000000)
|
| 146 | #define FP_UFLO INT64_C(0x0000000FFFFFFFFE)
|
| 147 | #define FP_UFRAC INT64_C(0x7FFFFFFFFFFFFFFE)
|
| 148 | #define FP_URNDD INT64_C(0x0000000000000001)
|
| 149 | #define FP_URNDS INT64_C(0x0000000800000000)
|
| 150 | #define FP_UNORM INT64_C(0x4000000000000000)
|
| 151 | #define FP_UCRY INT64_C(0x8000000000000000)
|
| 152 | #define FP_ONES INT64_C(0xFFFFFFFFFFFFFFFF)
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 153 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 154 | #define UNEG(x) ((~x) + 1)
|
| 155 | #define DUNEG(x) x.flo = UNEG (x.flo); x.fhi = ~x.fhi + (x.flo == 0)
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 156 |
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 157 | void mul (d10 a, d10 b, d10 *rs);
|
| 158 | void funpack (d10 h, d10 l, UFP *r, t_bool sgn);
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 159 | void fnorm (UFP *r, t_int64 rnd);
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 160 | d10 fpack (UFP *r, d10 *lo, t_bool fdvneg);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 161 |
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 162 | /* Integer multiply - checked against KS-10 ucode */
|
| 163 |
|
| 164 | d10 imul (d10 a, d10 b)
|
| 165 | {
|
| 166 | d10 rs[2];
|
| 167 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 168 | if ((a == SIGN) && (b == SIGN)) { /* KS10 hack */
|
| 169 | SETF (F_AOV | F_T1); /* -2**35 squared */
|
| 170 | return SIGN;
|
| 171 | }
|
| 172 | mul (a, b, rs); /* mpy, dprec result */
|
| 173 | if (rs[0] && (rs[0] != ONES)) { /* high not all sign? */
|
| 174 | rs[1] = TSTS (a ^ b)? SETS (rs[1]): CLRS (rs[1]); /* set sign */
|
| 175 | SETF (F_AOV | F_T1); /* overflow */
|
| 176 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 177 | return rs[1];
|
| 178 | }
|
| 179 |
|
| 180 | /* Integer divide, return quotient, remainder - checked against KS10 ucode
|
| 181 | The KS10 does not recognize -2^35/-1 as an error. Instead, it produces
|
| 182 | 2^35 (that is, -2^35) as the incorrect result.
|
| 183 | */
|
| 184 |
|
| 185 | t_bool idiv (d10 a, d10 b, d10 *rs)
|
| 186 | {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 187 | d10 dvd = ABS (a); /* make ops positive */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 188 | d10 dvr = ABS (b);
|
| 189 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 190 | if (dvr == 0) { /* divide by 0? */
|
| 191 | SETF (F_DCK | F_AOV | F_T1); /* set flags, return */
|
| 192 | return FALSE;
|
| 193 | }
|
| 194 | rs[0] = dvd / dvr; /* get quotient */
|
| 195 | rs[1] = dvd % dvr; /* get remainder */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 196 | if (TSTS (a ^ b)) /* sign of result */
|
| 197 | rs[0] = NEG (rs[0]);
|
| 198 | if (TSTS (a)) /* sign of remainder */
|
| 199 | rs[1] = NEG (rs[1]);
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 200 | return TRUE;
|
| 201 | }
|
| 202 |
|
| 203 | /* Multiply, return double precision result - checked against KS10 ucode */
|
| 204 |
|
| 205 | void mul (d10 s1, d10 s2, d10 *rs)
|
| 206 | {
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 207 | t_uint64 a = ABS (s1);
|
| 208 | t_uint64 b = ABS (s2);
|
| 209 | t_uint64 t, u, r;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 210 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 211 | if ((a == 0) || (b == 0)) { /* operand = 0? */
|
| 212 | rs[0] = rs[1] = 0; /* result 0 */
|
| 213 | return;
|
| 214 | }
|
| 215 | if ((a & FIT32) || (b & FIT32)) { /* fit in 64b? */
|
| 216 | t = a >> 18; /* no, split in half */
|
| 217 | a = a & RMASK; /* "dp" multiply */
|
| 218 | u = b >> 18;
|
| 219 | b = b & RMASK;
|
| 220 | r = (a * b) + (((a * u) + (b * t)) << 18); /* low is only 35b */
|
| 221 | rs[0] = ((t * u) << 1) + (r >> 35); /* so lsh hi 1 */
|
| 222 | rs[1] = r & MMASK;
|
| 223 | }
|
| 224 | else {
|
| 225 | r = a * b; /* fits, native mpy */
|
| 226 | rs[0] = r >> 35; /* split at bit 35 */
|
| 227 | rs[1] = r & MMASK;
|
| 228 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 229 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 230 | if (TSTS (s1 ^ s2)) { /* result -? */
|
| 231 | MKDNEG (rs);
|
| 232 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 233 | else if (TSTS (rs[0])) { /* result +, 2**70? */
|
| 234 | SETF (F_AOV | F_T1); /* overflow */
|
| 235 | rs[1] = SETS (rs[1]); /* consistent - */
|
| 236 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 237 | return;
|
| 238 | }
|
| 239 |
|
| 240 | /* Divide, return quotient and remainder - checked against KS10 ucode
|
| 241 | Note that the initial divide check catches the case -2^70/-2^35;
|
| 242 | thus, the quotient can have at most 35 bits.
|
| 243 | */
|
| 244 |
|
| 245 | t_bool divi (int32 ac, d10 b, d10 *rs)
|
| 246 | {
|
Bob Supnik | 89bcd02 | 2001-11-06 20:58:00 -0800 | [diff] [blame] | 247 | int32 p1 = ADDAC (ac, 1);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 248 | d10 dvr = ABS (b); /* make divr positive */
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 249 | t_int64 t;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 250 | int32 i;
|
| 251 | d10 dvd[2];
|
| 252 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 253 | dvd[0] = AC(ac); /* divd high */
|
| 254 | dvd[1] = CLRS (AC(p1)); /* divd lo, clr sgn */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 255 | if (TSTS (AC(ac))) { /* make divd positive */
|
| 256 | DMOVN (dvd);
|
| 257 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 258 | if (dvd[0] >= dvr) { /* divide fail? */
|
| 259 | SETF (F_AOV | F_DCK | F_T1); /* set flags, return */
|
| 260 | return FALSE;
|
| 261 | }
|
| 262 | if (dvd[0] & FIT27) { /* fit in 63b? */
|
| 263 | for (i = 0, rs[0] = 0; i < 35; i++) { /* 35 quotient bits */
|
| 264 | dvd[0] = (dvd[0] << 1) | ((dvd[1] >> 34) & 1);
|
| 265 | dvd[1] = (dvd[1] << 1) & MMASK; /* shift dividend */
|
| 266 | rs[0] = rs[0] << 1; /* shift quotient */
|
| 267 | if (dvd[0] >= dvr) { /* subtract work? */
|
| 268 | dvd[0] = dvd[0] - dvr; /* quo bit is 1 */
|
| 269 | rs[0] = rs[0] + 1;
|
| 270 | }
|
| 271 | }
|
| 272 | rs[1] = dvd[0]; /* store remainder */
|
| 273 | }
|
| 274 | else {
|
| 275 | t = (dvd[0] << 35) | dvd[1]; /* concatenate */
|
| 276 | rs[0] = t / dvr; /* quotient */
|
| 277 | rs[1] = t % dvr; /* remainder */
|
| 278 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 279 | if (TSTS (AC(ac) ^ b)) /* sign of result */
|
| 280 | rs[0] = NEG (rs[0]);
|
| 281 | if (TSTS (AC(ac))) /* sign of remainder */
|
| 282 | rs[1] = NEG (rs[1]);
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 283 | return TRUE;
|
| 284 | }
|
| 285 |
|
| 286 | /* Double precision multiply. This is done the old fashioned way. Cross
|
| 287 | product multiplies would be a lot faster but would require more code.
|
| 288 | */
|
| 289 |
|
| 290 | void dmul (int32 ac, d10 *mpy)
|
| 291 | {
|
| 292 | int32 p1 = ADDAC (ac, 1);
|
| 293 | int32 p2 = ADDAC (ac, 2);
|
| 294 | int32 p3 = ADDAC (ac, 3);
|
| 295 | int32 i;
|
| 296 | d10 mpc[2], sign;
|
| 297 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 298 | mpc[0] = AC(ac); /* mplcnd hi */
|
| 299 | mpc[1] = CLRS (AC(p1)); /* mplcnd lo, clr sgn */
|
| 300 | sign = mpc[0] ^ mpy[0]; /* sign of result */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 301 | if (TSTS (mpc[0])) { /* get abs (mpcnd) */
|
| 302 | DMOVN (mpc);
|
| 303 | }
|
| 304 | if (TSTS (mpy[0])) { /* get abs (mpyer) */
|
| 305 | DMOVN (mpy);
|
| 306 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 307 | else mpy[1] = CLRS (mpy[1]); /* clear mpy lo sign */
|
| 308 | AC(ac) = AC(p1) = AC(p2) = AC(p3) = 0; /* clear AC's */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 309 | if (((mpy[0] | mpy[1]) == 0) || ((mpc[0] | mpc[1]) == 0))
|
| 310 | return;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 311 | for (i = 0; i < 71; i++) { /* 71 mpyer bits */
|
| 312 | if (i) { /* shift res, mpy */
|
| 313 | AC(p3) = (AC(p3) >> 1) | ((AC(p2) & 1) << 34);
|
| 314 | AC(p2) = (AC(p2) >> 1) | ((AC(p1) & 1) << 34);
|
| 315 | AC(p1) = (AC(p1) >> 1) | ((AC(ac) & 1) << 34);
|
| 316 | AC(ac) = AC(ac) >> 1;
|
| 317 | mpy[1] = (mpy[1] >> 1) | ((mpy[0] & 1) << 34);
|
| 318 | mpy[0] = mpy[0] >> 1;
|
| 319 | }
|
| 320 | if (mpy[1] & 1) { /* if mpy lo bit = 1 */
|
| 321 | AC(p1) = AC(p1) + mpc[1];
|
Mark Pizzolato | 820d77e | 2016-05-05 03:50:21 -0700 | [diff] [blame] | 322 | AC(ac) = AC(ac) + mpc[0] + (TSTS (AC(p1)) != 0);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 323 | AC(p1) = CLRS (AC(p1));
|
| 324 | }
|
| 325 | }
|
| 326 | if (TSTS (sign)) { /* result minus? */
|
| 327 | AC(p3) = (-AC(p3)) & MMASK; /* quad negate */
|
| 328 | AC(p2) = (~AC(p2) + (AC(p3) == 0)) & MMASK;
|
| 329 | AC(p1) = (~AC(p1) + (AC(p2) == 0)) & MMASK;
|
| 330 | AC(ac) = (~AC(ac) + (AC(p1) == 0)) & DMASK;
|
| 331 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 332 | else if (TSTS (AC(ac))) /* wrong sign */
|
| 333 | SETF (F_AOV | F_T1);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 334 | if (TSTS (AC(ac))) { /* if result - */
|
| 335 | AC(p1) = SETS (AC(p1)); /* make signs consistent */
|
| 336 | AC(p2) = SETS (AC(p2));
|
| 337 | AC(p3) = SETS (AC(p3));
|
| 338 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 339 | return;
|
| 340 | }
|
| 341 |
|
| 342 | /* Double precision divide - checked against KS10 ucode */
|
| 343 |
|
| 344 | void ddiv (int32 ac, d10 *dvr)
|
| 345 | {
|
| 346 | int32 i, cryin;
|
| 347 | d10 sign, qu[2], dvd[4];
|
| 348 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 349 | dvd[0] = AC(ac); /* save dividend */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 350 | for (i = 1; i < 4; i++)
|
| 351 | dvd[i] = CLRS (AC(ADDAC (ac, i)));
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 352 | sign = AC(ac) ^ dvr[0]; /* sign of result */
|
| 353 | if (TSTS (AC(ac))) { /* get abs (dividend) */
|
| 354 | for (i = 3, cryin = 1; i > 0; i--) { /* negate quad */
|
| 355 | dvd[i] = (~dvd[i] + cryin) & MMASK; /* comp + carry in */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 356 | if (dvd[i]) /* next carry in */
|
| 357 | cryin = 0;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 358 | }
|
| 359 | dvd[0] = (~dvd[0] + cryin) & DMASK;
|
| 360 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 361 | if (TSTS (dvr[0])) { /* get abs (divisor) */
|
| 362 | DMOVN (dvr);
|
| 363 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 364 | else dvr[1] = CLRS (dvr[1]);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 365 | if (DCMPGE (dvd, dvr)) { /* will divide work? */
|
| 366 | SETF (F_AOV | F_DCK | F_T1); /* no, set flags */
|
| 367 | return;
|
| 368 | }
|
| 369 | qu[0] = qu[1] = 0; /* clear quotient */
|
| 370 | for (i = 0; i < 70; i++) { /* 70 quotient bits */
|
| 371 | dvd[0] = ((dvd[0] << 1) | ((dvd[1] >> 34) & 1)) & DMASK;;
|
| 372 | dvd[1] = ((dvd[1] << 1) | ((dvd[2] >> 34) & 1)) & MMASK;
|
| 373 | dvd[2] = ((dvd[2] << 1) | ((dvd[3] >> 34) & 1)) & MMASK;
|
| 374 | dvd[3] = (dvd[3] << 1) & MMASK; /* shift dividend */
|
| 375 | qu[0] = (qu[0] << 1) | ((qu[1] >> 34) & 1); /* shift quotient */
|
| 376 | qu[1] = (qu[1] << 1) & MMASK;
|
| 377 | if (DCMPGE (dvd, dvr)) { /* subtract work? */
|
| 378 | dvd[0] = dvd[0] - dvr[0] - (dvd[1] < dvr[1]);
|
| 379 | dvd[1] = (dvd[1] - dvr[1]) & MMASK; /* do subtract */
|
| 380 | qu[1] = qu[1] + 1; /* set quotient bit */
|
| 381 | }
|
| 382 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 383 | if (TSTS (sign) && (qu[0] | qu[1])) {
|
| 384 | MKDNEG (qu);
|
| 385 | }
|
| 386 | if (TSTS (AC(ac)) && (dvd[0] | dvd[1])) {
|
| 387 | MKDNEG (dvd);
|
| 388 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 389 | AC(ac) = qu[0]; /* quotient */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 390 | AC(ADDAC(ac, 1)) = qu[1];
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 391 | AC(ADDAC(ac, 2)) = dvd[0]; /* remainder */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 392 | AC(ADDAC(ac, 3)) = dvd[1];
|
| 393 | return;
|
| 394 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 395 |
|
Bob Supnik | 26aa6de | 2004-04-06 05:17:00 -0700 | [diff] [blame] | 396 | /* Single precision floating add/subtract - checked against KS10 ucode
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 397 | The KS10 shifts the smaller operand regardless of the exponent diff.
|
| 398 | This code will not shift more than 63 places; shifts beyond that
|
| 399 | cannot change the value of the smaller operand.
|
| 400 |
|
| 401 | If the signs of the operands are the same, the result sign is the
|
| 402 | same as the source sign; the sign of the result fraction is actually
|
| 403 | part of the data. If the signs of the operands are different, the
|
| 404 | result sign is determined by the fraction sign.
|
| 405 | */
|
| 406 |
|
| 407 | d10 fad (d10 op1, d10 op2, t_bool rnd, int32 inv)
|
| 408 | {
|
Bob Supnik | 89bcd02 | 2001-11-06 20:58:00 -0800 | [diff] [blame] | 409 | int32 ediff;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 410 | UFP a, b, t;
|
| 411 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 412 | if (inv) /* subtract? -b */
|
| 413 | op2 = NEG (op2);
|
| 414 | if (op1 == 0) /* a = 0? result is b */
|
| 415 | funpack (op2, 0, &a, AFRC);
|
| 416 | else if (op2 == 0) /* b = 0? result is a */
|
| 417 | funpack (op1, 0, &a, AFRC);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 418 | else {
|
| 419 | funpack (op1, 0, &a, SFRC); /* unpack operands */
|
| 420 | funpack (op2, 0, &b, SFRC); /* fracs are 2's comp */
|
| 421 | ediff = a.exp - b.exp; /* get exp diff */
|
| 422 | if (ediff < 0) { /* a < b? switch */
|
| 423 | t = a;
|
| 424 | a = b;
|
| 425 | b = t;
|
| 426 | ediff = -ediff;
|
| 427 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 428 | if (ediff > 63) /* cap diff at 63 */
|
| 429 | ediff = 63;
|
| 430 | if (ediff) /* shift b (signed) */
|
| 431 | b.fhi = (t_int64) b.fhi >> ediff;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 432 | a.fhi = a.fhi + b.fhi; /* add fractions */
|
| 433 | if (a.sign ^ b.sign) { /* add or subtract? */
|
| 434 | if (a.fhi & FP_UCRY) { /* subtract, frac -? */
|
| 435 | a.fhi = UNEG (a.fhi); /* complement result */
|
| 436 | a.sign = 1; /* result is - */
|
| 437 | }
|
| 438 | else a.sign = 0; /* result is + */
|
| 439 | }
|
| 440 | else {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 441 | if (a.sign) /* add, src -? comp */
|
| 442 | a.fhi = UNEG (a.fhi);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 443 | if (a.fhi & FP_UCRY) { /* check for carry */
|
| 444 | a.fhi = a.fhi >> 1; /* flo won't be used */
|
| 445 | a.exp = a.exp + 1;
|
| 446 | }
|
| 447 | }
|
| 448 | }
|
| 449 | fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 450 | return fpack (&a, NULL, FALSE);
|
| 451 | }
|
| 452 |
|
| 453 | /* Single precision floating multiply. Because the fractions are 27b,
|
| 454 | a 64b multiply can be used for the fraction multiply. The 27b
|
| 455 | fractions are positioned 0'frac'0000, resulting in 00'hifrac'0..0.
|
| 456 | The extra 0 is accounted for by biasing the result exponent.
|
| 457 | */
|
| 458 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 459 | #define FP_V_SPM (FP_V_UFHI - (32 - FP_N_FHI - 1))
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 460 | d10 fmp (d10 op1, d10 op2, t_bool rnd)
|
| 461 | {
|
| 462 | UFP a, b;
|
| 463 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 464 | funpack (op1, 0, &a, AFRC); /* unpack operands */
|
| 465 | funpack (op2, 0, &b, AFRC); /* fracs are abs val */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 466 | if ((a.fhi == 0) || (b.fhi == 0)) /* either 0? */
|
| 467 | return 0;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 468 | a.sign = a.sign ^ b.sign; /* result sign */
|
| 469 | a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
|
| 470 | a.fhi = (a.fhi >> FP_V_SPM) * (b.fhi >> FP_V_SPM); /* high 27b of result */
|
| 471 | fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 472 | return fpack (&a, NULL, FALSE);
|
| 473 | }
|
| 474 |
|
| 475 | /* Single precision floating divide. Because the fractions are 27b, a
|
| 476 | 64b divide can be used for the fraction divide. Note that 28b-29b
|
| 477 | of fraction are developed; the code will do one special normalize to
|
| 478 | make sure that the 28th bit is not lost. Also note the special
|
| 479 | treatment of negative quotients with non-zero remainders; this
|
| 480 | implements the note on p2-23 of the Processor Reference Manual.
|
| 481 | */
|
| 482 |
|
| 483 | t_bool fdv (d10 op1, d10 op2, d10 *rs, t_bool rnd)
|
| 484 | {
|
| 485 | UFP a, b;
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 486 | t_uint64 savhi;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 487 | t_bool rem = FALSE;
|
| 488 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 489 | funpack (op1, 0, &a, AFRC); /* unpack operands */
|
| 490 | funpack (op2, 0, &b, AFRC); /* fracs are abs val */
|
| 491 | if (a.fhi >= 2 * b.fhi) { /* will divide work? */
|
| 492 | SETF (F_AOV | F_DCK | F_FOV | F_T1);
|
| 493 | return FALSE;
|
| 494 | }
|
Mark Pizzolato | 0f8e6cf | 2012-04-29 11:59:44 -0700 | [diff] [blame] | 495 | if ((savhi = a.fhi)) { /* dvd = 0? quo = 0 */
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 496 | a.sign = a.sign ^ b.sign; /* result sign */
|
| 497 | a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
|
| 498 | a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */
|
| 499 | if (a.sign && (savhi != (a.fhi * (b.fhi >> (FP_N_FHI + 1)))))
|
| 500 | rem = TRUE; /* KL/KS hack */
|
| 501 | a.fhi = a.fhi << (FP_V_UNORM - FP_N_FHI - 1); /* put quo in place */
|
| 502 | if ((a.fhi & FP_UNORM) == 0) { /* normalize 1b */
|
| 503 | a.fhi = a.fhi << 1; /* before masking */
|
| 504 | a.exp = a.exp - 1;
|
| 505 | }
|
| 506 | a.fhi = a.fhi & (FP_UFHI | FP_URNDS); /* mask quo to 28b */
|
| 507 | }
|
| 508 | fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
|
| 509 | *rs = fpack (&a, NULL, rem); /* pack result */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 510 | return TRUE;
|
| 511 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 512 |
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 513 | /* Single precision floating scale. */
|
| 514 |
|
| 515 | d10 fsc (d10 val, a10 ea)
|
| 516 | {
|
| 517 | int32 sc = LIT8 (ea);
|
| 518 | UFP a;
|
| 519 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 520 | if (val == 0)
|
| 521 | return 0;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 522 | funpack (val, 0, &a, AFRC); /* unpack operand */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 523 | if (ea & RSIGN) /* adjust exponent */
|
| 524 | a.exp = a.exp - sc;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 525 | else a.exp = a.exp + sc;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 526 | fnorm (&a, 0); /* renormalize */
|
| 527 | return fpack (&a, NULL, FALSE); /* pack result */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 528 | }
|
| 529 |
|
| 530 | /* Float integer operand and round */
|
| 531 |
|
| 532 | d10 fltr (d10 mb)
|
| 533 | {
|
| 534 | UFP a;
|
| 535 | d10 val = ABS (mb);
|
| 536 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 537 | a.sign = GET_FPSIGN (mb); /* get sign */
|
| 538 | a.exp = FP_BIAS + 36; /* initial exponent */
|
| 539 | a.fhi = val << (FP_V_UNORM - 35); /* left justify op */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 540 | a.flo = 0;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 541 | fnorm (&a, FP_URNDS); /* normalize, round */
|
| 542 | return fpack (&a, NULL, FALSE); /* pack result */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 543 | }
|
| 544 |
|
| 545 | /* Fix and truncate/round floating operand */
|
| 546 |
|
| 547 | void fix (int32 ac, d10 mb, t_bool rnd)
|
| 548 | {
|
| 549 | int32 sc;
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 550 | t_uint64 so;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 551 | UFP a;
|
| 552 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 553 | funpack (mb, 0, &a, AFRC); /* unpack operand */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 554 | if (a.exp > (FP_BIAS + FP_N_FHI + FP_N_EXP))
|
| 555 | SETF (F_AOV | F_T1);
|
| 556 | else if (a.exp < FP_BIAS) /* < 1/2? */
|
| 557 | AC(ac) = 0;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 558 | else {
|
| 559 | sc = FP_V_UNORM - (a.exp - FP_BIAS) + 1;
|
| 560 | AC(ac) = a.fhi >> sc;
|
| 561 | if (rnd) {
|
| 562 | so = a.fhi << (64 - sc);
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 563 | if (so >= (0x8000000000000000 + a.sign))
|
| 564 | AC(ac) = AC(ac) + 1;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 565 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 566 | if (a.sign)
|
| 567 | AC(ac) = NEG (AC(ac));
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 568 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 569 | return;
|
| 570 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 571 |
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 572 | /* Double precision floating add/subtract
|
| 573 | Since a.flo is 0, adding b.flo is just a copy - this is incorporated into
|
| 574 | the denormalization step. If there's no denormalization, bflo is zero too.
|
| 575 | */
|
| 576 |
|
| 577 | void dfad (int32 ac, d10 *rs, int32 inv)
|
| 578 | {
|
| 579 | int32 p1 = ADDAC (ac, 1);
|
Bob Supnik | 89bcd02 | 2001-11-06 20:58:00 -0800 | [diff] [blame] | 580 | int32 ediff;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 581 | UFP a, b, t;
|
| 582 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 583 | if (inv) { /* subtract? -b */
|
| 584 | DMOVN (rs);
|
| 585 | }
|
| 586 | if ((AC(ac) | AC(p1)) == 0) /* a == 0? sum = b */
|
| 587 | funpack (rs[0], rs[1], &a, AFRC);
|
| 588 | else if ((rs[0] | rs[1]) == 0) /* b == 0? sum = a */
|
| 589 | funpack (AC(ac), AC(p1), &a, AFRC);
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 590 | else {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 591 | funpack (AC(ac), AC(p1), &a, SFRC); /* unpack operands */
|
| 592 | funpack (rs[0], rs[1], &b, SFRC);
|
| 593 | ediff = a.exp - b.exp; /* get exp diff */
|
| 594 | if (ediff < 0) { /* a < b? switch */
|
| 595 | t = a;
|
| 596 | a = b;
|
| 597 | b = t;
|
| 598 | ediff = -ediff;
|
| 599 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 600 | if (ediff > 127) /* cap diff at 127 */
|
| 601 | ediff = 127;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 602 | if (ediff > 63) { /* diff > 63? */
|
| 603 | a.flo = (t_int64) b.fhi >> (ediff - 64); /* b hi to a lo */
|
| 604 | b.fhi = b.sign? FP_ONES: 0; /* hi = all sign */
|
| 605 | }
|
| 606 | else if (ediff) { /* diff <= 63 */
|
| 607 | a.flo = (b.flo >> ediff) | (b.fhi << (64 - ediff));
|
| 608 | b.fhi = (t_int64) b.fhi >> ediff; /* shift b (signed) */
|
| 609 | }
|
| 610 | a.fhi = a.fhi + b.fhi; /* do add */
|
| 611 | if (a.sign ^ b.sign) { /* add or subtract? */
|
| 612 | if (a.fhi & FP_UCRY) { /* subtract, frac -? */
|
| 613 | DUNEG (a); /* complement result */
|
| 614 | a.sign = 1; /* result is - */
|
| 615 | }
|
| 616 | else a.sign = 0; /* result is + */
|
| 617 | }
|
| 618 | else {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 619 | if (a.sign) { /* add, src -? comp */
|
| 620 | DUNEG (a);
|
| 621 | };
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 622 | if (a.fhi & FP_UCRY) { /* check for carry */
|
| 623 | a.fhi = a.fhi >> 1; /* flo won't be used */
|
| 624 | a.exp = a.exp + 1;
|
| 625 | }
|
| 626 | }
|
| 627 | }
|
| 628 | fnorm (&a, FP_URNDD); /* normalize, round */
|
| 629 | AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 630 | return;
|
| 631 | }
|
| 632 |
|
| 633 | /* Double precision floating multiply
|
| 634 | The 62b fractions are multiplied, with cross products, to produce a
|
| 635 | 124b fraction with two leading and two trailing 0's. Because the
|
| 636 | product has 2 leading 0's, instead of the normal 1, an extra
|
| 637 | normalization step is needed. Accordingly, the exponent calculation
|
| 638 | increments the result exponent, to compensate for normalization.
|
| 639 | */
|
| 640 |
|
| 641 | void dfmp (int32 ac, d10 *rs)
|
| 642 | {
|
| 643 | int32 p1 = ADDAC (ac, 1);
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 644 | t_uint64 xh, xl, yh, yl, mid;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 645 | UFP a, b;
|
| 646 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 647 | funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 648 | funpack (rs[0], rs[1], &b, AFRC);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 649 | if ((a.fhi == 0) || (b.fhi == 0)) { /* either 0? result 0 */
|
| 650 | AC(ac) = AC(p1) = 0;
|
| 651 | return;
|
| 652 | }
|
| 653 | a.sign = a.sign ^ b.sign; /* result sign */
|
| 654 | a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
|
| 655 | xh = a.fhi >> 32; /* split 62b fracs */
|
| 656 | xl = a.fhi & MSK32; /* into 32b halves */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 657 | yh = b.fhi >> 32;
|
| 658 | yl = b.fhi & MSK32;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 659 | a.fhi = xh * yh; /* hi xproduct */
|
| 660 | a.flo = xl * yl; /* low xproduct */
|
| 661 | mid = (xh * yl) + (yh * xl); /* fits in 64b */
|
| 662 | a.flo = a.flo + (mid << 32); /* add mid lo to lo */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 663 | a.fhi = a.fhi + ((mid >> 32) & MSK32) + (a.flo < (mid << 32));
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 664 | fnorm (&a, FP_URNDD); /* normalize, round */
|
| 665 | AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 666 | return;
|
| 667 | }
|
| 668 |
|
| 669 | /* Double precision floating divide
|
| 670 | This algorithm develops a full 62 bits of quotient, plus one rounding
|
| 671 | bit, in the low order 63b of a 64b number. To do this, we must assure
|
| 672 | that the initial divide step generates a 1. If it would fail, shift
|
| 673 | the dividend left and decrement the result exponent accordingly.
|
| 674 | */
|
| 675 |
|
| 676 | void dfdv (int32 ac, d10 *rs)
|
| 677 | {
|
| 678 | int32 p1 = ADDAC (ac, 1);
|
| 679 | int32 i;
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 680 | t_uint64 qu = 0;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 681 | UFP a, b;
|
| 682 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 683 | funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 684 | funpack (rs[0], rs[1], &b, AFRC);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 685 | if (a.fhi >= 2 * b.fhi) { /* will divide work? */
|
| 686 | SETF (F_AOV | F_DCK | F_FOV | F_T1);
|
| 687 | return;
|
| 688 | }
|
| 689 | if (a.fhi) { /* dvd = 0? quo = 0 */
|
| 690 | a.sign = a.sign ^ b.sign; /* result sign */
|
| 691 | a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
|
| 692 | if (a.fhi < b.fhi) { /* make sure initial */
|
| 693 | a.fhi = a.fhi << 1; /* divide step will work */
|
| 694 | a.exp = a.exp - 1;
|
| 695 | }
|
| 696 | for (i = 0; i < 63; i++) { /* 63b of quotient */
|
| 697 | qu = qu << 1; /* shift quotient */
|
| 698 | if (a.fhi >= b.fhi) { /* will div work? */
|
| 699 | a.fhi = a.fhi - b.fhi; /* sub, quo = 1 */
|
| 700 | qu = qu + 1;
|
| 701 | }
|
| 702 | a.fhi = a.fhi << 1; /* shift dividend */
|
| 703 | }
|
| 704 | a.fhi = qu;
|
| 705 | }
|
| 706 | fnorm (&a, FP_URNDD); /* normalize, round */
|
| 707 | AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 708 | return;
|
| 709 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 710 |
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 711 | /* Unpack floating point operand */
|
| 712 |
|
| 713 | void funpack (d10 h, d10 l, UFP *r, t_bool sgn)
|
| 714 | {
|
| 715 | d10 fphi, fplo;
|
| 716 |
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 717 | r->sign = GET_FPSIGN (h);
|
| 718 | r->exp = GET_FPEXP (h);
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 719 | fphi = GET_FPHI (h);
|
| 720 | fplo = GET_FPLO (l);
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 721 | r->fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO);
|
| 722 | r->flo = 0;
|
| 723 | if (r->sign) {
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 724 | r->exp = r->exp ^ FP_M_EXP; /* 1s comp exp */
|
| 725 | if (sgn) { /* signed frac? */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 726 | if (r->fhi) /* extend sign */
|
| 727 | r->fhi = r->fhi | FP_UCRY;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 728 | else {
|
| 729 | r->exp = r->exp + 1;
|
Mark Pizzolato | 02cb5c2 | 2014-02-14 17:07:45 -0800 | [diff] [blame] | 730 | r->fhi = (t_uint64)(FP_UCRY | FP_UNORM);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 731 | }
|
| 732 | }
|
| 733 | else { /* abs frac */
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 734 | if (r->fhi)
|
| 735 | r->fhi = UNEG (r->fhi) & FP_UFRAC;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 736 | else {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 737 | r->exp = r->exp + 1;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 738 | r->fhi = FP_UNORM;
|
| 739 | }
|
| 740 | }
|
| 741 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 742 | return;
|
| 743 | }
|
| 744 |
|
| 745 | /* Normalize and optionally round floating point operand */
|
| 746 |
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 747 | void fnorm (UFP *a, t_int64 rnd)
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 748 | {
|
| 749 | int32 i;
|
Bob Supnik | 654937f | 2001-11-06 21:02:00 -0800 | [diff] [blame] | 750 | static t_uint64 normmask[6] = {
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 751 | 0x6000000000000000, 0x7800000000000000, 0x7F80000000000000,
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 752 | 0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF
|
| 753 | };
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 754 | static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 };
|
Bob Supnik | 26aa6de | 2004-04-06 05:17:00 -0700 | [diff] [blame] | 755 | extern a10 pager_PC;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 756 |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 757 | if (a->fhi & FP_UCRY) { /* carry set? */
|
Mark Pizzolato | 995ab8f | 2014-10-24 14:37:37 -0700 | [diff] [blame] | 758 | sim_printf ("%%PDP-10 FP: carry bit set at normalization, PC = %o\n", pager_PC);
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 759 | a->flo = (a->flo >> 1) | ((a->fhi & 1) << 63); /* try to recover */
|
| 760 | a->fhi = a->fhi >> 1; /* but root cause */
|
| 761 | a->exp = a->exp + 1; /* should be fixed! */
|
| 762 | }
|
| 763 | if ((a->fhi | a->flo) == 0) { /* if fraction = 0 */
|
| 764 | a->sign = a->exp = 0; /* result is 0 */
|
| 765 | return;
|
| 766 | }
|
| 767 | while ((a->fhi & FP_UNORM) == 0) { /* normalized? */
|
| 768 | for (i = 0; i < 6; i++) {
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 769 | if (a->fhi & normmask[i])
|
| 770 | break;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 771 | }
|
| 772 | a->fhi = (a->fhi << normtab[i]) | (a->flo >> (64 - normtab[i]));
|
| 773 | a->flo = a->flo << normtab[i];
|
| 774 | a->exp = a->exp - normtab[i];
|
| 775 | }
|
| 776 | if (rnd) { /* rounding? */
|
| 777 | a->fhi = a->fhi + rnd; /* add round const */
|
| 778 | if (a->fhi & FP_UCRY) { /* if carry out, */
|
| 779 | a->fhi = a->fhi >> 1; /* renormalize */
|
| 780 | a->exp = a->exp + 1;
|
| 781 | }
|
| 782 | }
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 783 | return;
|
| 784 | }
|
| 785 |
|
| 786 | /* Pack floating point result */
|
| 787 |
|
| 788 | d10 fpack (UFP *r, d10 *lo, t_bool fdvneg)
|
| 789 | {
|
| 790 | d10 val[2];
|
| 791 |
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 792 | if (r->exp < 0)
|
| 793 | SETF (F_AOV | F_FOV | F_FXU | F_T1);
|
| 794 | else if (r->exp > FP_M_EXP)
|
| 795 | SETF (F_AOV | F_FOV | F_T1);
|
Bob Supnik | 2c2dd5e | 2002-11-17 15:54:00 -0800 | [diff] [blame] | 796 | val[0] = (((((d10) r->exp) & FP_M_EXP) << FP_V_EXP) |
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 797 | ((r->fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK;
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 798 | if (lo)
|
| 799 | val[1] = ((r->fhi & FP_UFLO) >> FP_V_UFLO) & MMASK;
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 800 | else val[1] = 0;
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 801 | if (r->sign) { /* negate? */
|
| 802 | if (fdvneg) { /* fdvr special? */
|
| 803 | val[1] = ~val[1] & MMASK; /* 1's comp */
|
| 804 | val[0] = ~val[0] & DMASK;
|
Mark Pizzolato | 651780c | 2013-06-03 06:29:01 -0700 | [diff] [blame] | 805 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 806 | else { /* 2's comp */
|
| 807 | DMOVN (val);
|
| 808 | }
|
Bob Supnik | b7c1eae | 2005-09-09 18:09:00 -0700 | [diff] [blame] | 809 | }
|
Bob Supnik | 9c4779c | 2009-02-08 09:06:00 -0800 | [diff] [blame] | 810 | if (lo)
|
| 811 | *lo = val[1];
|
Bob Supnik | 4d6dfa4 | 2001-11-06 20:50:00 -0800 | [diff] [blame] | 812 | return val[0];
|
| 813 | }
|