1 /* pdp11_fp.c: PDP-11 floating point simulator (32b version)
2 
3    Copyright (c) 1993-2008, Robert M Supnik
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 
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
24    in this Software without prior written authorization from Robert M Supnik.
25 
26    22-Sep-05    RMS     Fixed declarations (Sterling Garwood)
27    04-Oct-04    RMS     Added FIS instructions
28    19-Jan-03    RMS     Changed mode definitions for Apple Dev Kit conflict
29    08-Oct-02    RMS     Fixed macro definitions
30    05-Jun-98    RMS     Fixed implementation specific shift bugs
31    20-Apr-98    RMS     Fixed bug in MODf integer truncation
32    17-Apr-98    RMS     Fixed bug in STCfi range check
33    16-Apr-98    RMS     Fixed bugs in STEXP, STCfi, round/pack
34    09-Apr-98    RMS     Fixed bug in LDEXP
35    04-Apr-98    RMS     Fixed bug in MODf condition codes
36 
37    This module simulates the PDP-11 floating point unit (FP11 series).
38    It is called from the instruction decoder for opcodes 170000:177777.
39 
40    The floating point unit recognizes three instruction formats:
41 
42    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    no operand
43    | 1  1  1  1| 0  0  0  0  0  0|      opcode     |    170000:
44    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    170077
45 
46    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    one operand
47    | 1  1  1  1| 0  0  0| opcode |    dest spec    |    170100:
48    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    170777
49 
50    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    register + operand
51    | 1  1  1  1|   opcode  | fac |    dest spec    |    171000:
52    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    177777
53 
54    The instruction space is further extended through use of the floating
55    point status register (FPS) mode bits.  Three mode bits affect how
56    instructions are interpreted:
57 
58         FPS_D           if 0, floating registers are single precision
59                         if 1, floating registers are double precision
60 
61         FPS_L           if 0, integer operands are word
62                         if 1, integer operands are longword
63 
64         FPS_T           if 0, floating operations are rounded
65                         if 1, floating operations are truncated
66 
67    FPS also contains the condition codes for the floating point unit,
68    and exception enable bits for individual error conditions.  Exceptions
69    cause a trap through 0244, unless the individual exception, or all
70    exceptions, are disabled.  Illegal address mode, undefined variable,
71    and divide by zero abort the current instruction; all other exceptions
72    permit the instruction to complete.  (Aborts are implemented as traps
73    that request an "interrupt" trap.  If an interrupt is pending, it is
74    serviced; if not, trap_req is updated and processing continues.)
75 
76    Floating point specifiers are similar to integer specifiers, with
77    the length of the operand being up to 8 bytes.  In two specific cases,
78    the floating point unit reads or writes only two bytes, rather than
79    the length specified by the operand type:
80 
81         register        for integers, only 16b are accessed; if the
82                         operand is 32b, these are the high order 16b
83                         of the operand
84 
85         immediate       for integers or floating point, only 16b are
86                         accessed;  if the operand is 32b or 64b, these
87                         are the high order 16b of the operand
88 */
89 
90 #include "pdp11_defs.h"
91 
92 /* Floating point status register */
93 
94 #define FPS_ER          (1u << FPS_V_ER)                /* error */
95 #define FPS_ID          (1u << FPS_V_ID)                /* interrupt disable */
96 #define FPS_IUV         (1u << FPS_V_IUV)               /* int on undef var */
97 #define FPS_IU          (1u << FPS_V_IU)                /* int on underflow */
98 #define FPS_IV          (1u << FPS_V_IV)                /* int on overflow */
99 #define FPS_IC          (1u << FPS_V_IC)                /* int on conv error */
100 #define FPS_D           (1u << FPS_V_D)                 /* single/double */
101 #define FPS_L           (1u << FPS_V_L)                 /* word/long */
102 #define FPS_T           (1u << FPS_V_T)                 /* round/truncate */
103 #define FPS_N           (1u << FPS_V_N)
104 #define FPS_Z           (1u << FPS_V_Z)
105 #define FPS_V           (1u << FPS_V_V)
106 #define FPS_C           (1u << FPS_V_C)
107 #define FPS_CC          (FPS_N + FPS_Z + FPS_V + FPS_C)
108 #define FPS_RW          (FPS_ER + FPS_ID + FPS_IUV + FPS_IU + FPS_IV + \
109                     FPS_IC + FPS_D + FPS_L + FPS_T + FPS_CC)
110 
111 /* Floating point exception codes */
112 
113 #define FEC_OP          2                               /* illegal op/mode */
114 #define FEC_DZRO        4                               /* divide by zero */
115 #define FEC_ICVT        6                               /* conversion error */
116 #define FEC_OVFLO       8                               /* overflow */
117 #define FEC_UNFLO       10                              /* underflow */
118 #define FEC_UNDFV       12                              /* undef variable */
119 
120 /* Floating point format, all assignments 32b relative */
121 
122 #define FP_V_SIGN       (63 - 32)                       /* high lw: sign */
123 #define FP_V_EXP        (55 - 32)                       /* exponent */
124 #define FP_V_HB         FP_V_EXP                        /* hidden bit */
125 #define FP_V_F0         (48 - 32)                       /* fraction 0 */
126 #define FP_V_F1         (32 - 32)                       /* fraction 1 */
127 #define FP_V_FROUND     (31 - 32)                       /* f round point */
128 #define FP_V_F2         16                              /* low lw: fraction 2 */
129 #define FP_V_F3         0                               /* fraction 3 */
130 #define FP_V_DROUND     (-1)                            /* d round point */
131 #define FP_M_EXP        0377
132 #define FP_SIGN         (1u << FP_V_SIGN)
133 #define FP_EXP          (FP_M_EXP << FP_V_EXP)
134 #define FP_HB           (1u << FP_V_HB)
135 #define FP_FRACH        ((1u << FP_V_HB) - 1)
136 #define FP_FRACL        0xFFFFFFFF
137 #define FP_BIAS         0200                            /* exponent bias */
138 #define FP_GUARD        3                               /* guard bits */
139 
140 /* Data lengths */
141 
142 #define WORD            2
143 #define LONG            4
144 #define QUAD            8
145 
146 /* Double precision operations on 64b quantities */
147 
148 #define F_LOAD(qd,ac,ds) \
149                         ds.h = ac.h; ds.l = (qd)? ac.l: 0
150 #define F_LOAD_P(qd,ac,ds) \
151                         ds->h = ac.h; ds->l = (qd)? ac.l: 0
152 #define F_LOAD_FRAC(qd,ac,ds) \
153                         ds.h = (ac.h & FP_FRACH) | FP_HB; \
154                         ds.l = (qd)? ac.l: 0
155 #define F_STORE(qd,sr,ac) \
156                         ac.h = sr.h; if ((qd)) ac.l = sr.l
157 #define F_STORE_P(qd,sr,ac) \
158                         ac.h = sr->h; if ((qd)) ac.l = sr->l
159 #define F_GET_FRAC_P(sr,ds) \
160                         ds.l = sr->l; \
161                         ds.h = (sr->h & FP_FRACH) | FP_HB
162 #define F_ADD(s2,s1,ds) \
163                         ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \
164                         ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF
165 #define F_SUB(s2,s1,ds) \
166                         ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \
167                         ds.l = (s1.l - s2.l) & 0xFFFFFFFF
168 #define F_LT(x,y)       ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l)))
169 #define F_LT_AP(x,y)    (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \
170                         (((x->h & ~FP_SIGN) == (y->h & ~FP_SIGN)) && (x->l < y->l)))
171 #define F_LSH_V(sr,n,ds) \
172                         ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \
173                                 (sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \
174                                 & 0xFFFFFFFF; \
175                         ds.l = ((n) >= 32)? 0: (sr.l << (n)) & 0xFFFFFFFF
176 #define F_RSH_V(sr,n,ds) \
177                         ds.l = (((n) >= 32)? (sr.h >> ((n) - 32)) & and_mask[64 - (n)]: \
178                                 ((sr.l >> (n)) & and_mask[32 - (n)]) | \
179                                 (sr.h << (32 - (n)))) & 0xFFFFFFFF; \
180                         ds.h = ((n) >= 32)? 0: \
181                                 ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF
182 
183 /* For the constant shift macro, arguments must in the range [2,31] */
184 
185 #define F_LSH_1(ds)     ds.h = ((ds.h << 1) | ((ds.l >> 31) & 1)) & 0xFFFFFFFF; \
186                         ds.l = (ds.l << 1) & 0xFFFFFFFF
187 #define F_RSH_1(ds)     ds.l = ((ds.l >> 1) & 0x7FFFFFFF) | ((ds.h & 1) << 31); \
188                         ds.h = ((ds.h >> 1) & 0x7FFFFFFF)
189 #define F_LSH_K(sr,n,ds) \
190                         ds.h = ((sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \
191                                 & 0xFFFFFFFF; \
192                         ds.l = (sr.l << (n)) & 0xFFFFFFFF
193 #define F_RSH_K(sr,n,ds) \
194                         ds.l = (((sr.l >> (n)) & and_mask[32 - (n)]) | \
195                                 (sr.h << (32 - (n)))) & 0xFFFFFFFF; \
196                         ds.h = ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF
197 #define F_LSH_GUARD(ds) F_LSH_K(ds,FP_GUARD,ds)
198 #define F_RSH_GUARD(ds) F_RSH_K(ds,FP_GUARD,ds)
199 
200 #define GET_BIT(ir,n)   (((ir) >> (n)) & 1)
201 #define GET_SIGN(ir)    GET_BIT((ir), FP_V_SIGN)
202 #define GET_EXP(ir)     (((ir) >> FP_V_EXP) & FP_M_EXP)
203 #define GET_SIGN_L(ir)  GET_BIT((ir), 31)
204 #define GET_SIGN_W(ir)  GET_BIT((ir), 15)
205 
206 extern jmp_buf save_env;
207 extern uint32 cpu_type;
208 extern int32 FEC, FEA, FPS;
209 extern int32 CPUERR, trap_req;
210 extern int32 N, Z, V, C;
211 extern int32 R[8];
212 extern int32 STKLIM;
213 extern int32 cm, isenable, dsenable, MMR0, MMR1;
214 extern fpac_t FR[6];
215 
216 fpac_t zero_fac = { 0, 0 };
217 fpac_t one_fac = { 1, 0 };
218 fpac_t fround_fac = { (1u << (FP_V_FROUND + 32)), 0 };
219 fpac_t fround_guard_fac = { 0, (1u << (FP_V_FROUND + FP_GUARD)) };
220 fpac_t dround_guard_fac = { (1u << (FP_V_DROUND + FP_GUARD)), 0 };
221 fpac_t fmask_fac = { 0xFFFFFFFF, (1u << (FP_V_HB + FP_GUARD + 1)) - 1 };
222 static const uint32 and_mask[33] = { 0,
223     0x1, 0x3, 0x7, 0xF,
224     0x1F, 0x3F, 0x7F, 0xFF,
225     0x1FF, 0x3FF, 0x7FF, 0xFFF,
226     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
227     0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
228     0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
229     0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
230     0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
231     };
232 int32 backup_PC;
233 int32 fpnotrap (int32 code);
234 int32 GeteaFP (int32 spec, int32 len);
235 
236 uint32 ReadI (int32 addr, int32 spec, int32 len);
237 void ReadFP (fpac_t *fac, int32 addr, int32 spec, int32 len);
238 void WriteI (int32 data, int32 addr, int32 spec, int32 len);
239 void WriteFP (fpac_t *data, int32 addr, int32 spec, int32 len);
240 int32 setfcc (int32 old_status, int32 result_high, int32 newV);
241 int32 addfp11 (fpac_t *src1, fpac_t *src2);
242 int32 mulfp11 (fpac_t *src1, fpac_t *src2);
243 int32 divfp11 (fpac_t *src1, fpac_t *src2);
244 int32 modfp11 (fpac_t *src1, fpac_t *src2, fpac_t *frac);
245 void frac_mulfp11 (fpac_t *src1, fpac_t *src2);
246 int32 roundfp11 (fpac_t *src);
247 int32 round_and_pack (fpac_t *fac, int32 exp, fpac_t *frac, int r);
248 
249 extern int32 GeteaW (int32 spec);
250 extern int32 ReadW (int32 addr);
251 extern void WriteW (int32 data, int32 addr);
252 extern void set_stack_trap (int32 adr);
253 
254 /* Set up for instruction decode and execution */
255 
fp11(int32 IR)256 void fp11 (int32 IR)
257 {
258 int32 dst, ea, ac, dstspec;
259 int32 i, qdouble, lenf, leni;
260 int32 newV, exp, sign;
261 fpac_t fac, fsrc, modfrac;
262 static const uint32 i_limit[2][2] = {
263     { 0x80000000, 0x80010000 },
264     { 0x80000000, 0x80000001 }
265     };
266 
267 backup_PC = PC;                                         /* save PC for FEA */
268 ac = (IR >> 6) & 03;                                    /* fac is IR<7:6> */
269 dstspec = IR & 077;
270 qdouble = FPS & FPS_D;
271 lenf = qdouble? QUAD: LONG;
272 switch ((IR >> 8) & 017) {                              /* decode IR<11:8> */
273 
274     case 000:
275         switch (ac) {                                   /* decode IR<7:6> */
276 
277         case 0:                                         /* specials */
278             if (IR == 0170000) {                        /* CFCC */
279                 N = (FPS >> PSW_V_N) & 1;
280                 Z = (FPS >> PSW_V_Z) & 1;
281                 V = (FPS >> PSW_V_V) & 1;
282                 C = (FPS >> PSW_V_C) & 1;
283                 }
284             else if (IR == 0170001)                     /* SETF */
285                 FPS = FPS & ~FPS_D;
286             else if (IR == 0170002)                     /* SETI */
287                 FPS = FPS & ~FPS_L;
288             else if (IR == 0170011)                     /* SETD */
289                 FPS = FPS | FPS_D;
290             else if (IR == 0170012)                     /* SETL */
291                 FPS = FPS | FPS_L;
292             else fpnotrap (FEC_OP);
293             break;
294 
295         case 1:                                         /* LDFPS */
296             dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaW (dstspec));
297             FPS = dst & FPS_RW;
298             break;
299 
300         case 2:                                         /* STFPS */
301             FPS = FPS & FPS_RW;
302             if (dstspec <= 07)
303                 R[dstspec] = FPS;
304             else WriteW (FPS, GeteaW (dstspec));
305             break;
306 
307         case 3:                                         /* STST */
308             if (dstspec <= 07)
309                 R[dstspec] = FEC;
310             else WriteI ((FEC << 16) | FEA, GeteaFP (dstspec, LONG),
311                  dstspec, LONG);
312             break;
313             }                                           /* end switch <7:6> */
314         break;                                          /* end case 0 */
315 
316     case 001:
317         switch (ac) {                                   /* decode IR<7:6> */
318 
319         case 0:                                         /* CLRf */
320             WriteFP (&zero_fac, GeteaFP (dstspec, lenf), dstspec, lenf);
321             FPS = (FPS & ~FPS_CC) | FPS_Z;
322             break;
323 
324         case 1:                                         /* TSTf */
325             ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
326             FPS = setfcc (FPS, fsrc.h, 0);
327             break;
328 
329         case 2:                                         /* ABSf */
330             ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
331             if (GET_EXP (fsrc.h) == 0)
332                 fsrc = zero_fac;
333             else fsrc.h = fsrc.h & ~FP_SIGN;
334             WriteFP (&fsrc, ea, dstspec, lenf);
335             FPS = setfcc (FPS, fsrc.h, 0);
336             break;
337 
338         case 3:                                         /* NEGf */
339             ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
340             if (GET_EXP (fsrc.h) == 0)
341                 fsrc = zero_fac;
342             else fsrc.h = fsrc.h ^ FP_SIGN;
343             WriteFP (&fsrc, ea, dstspec, lenf);
344             FPS = setfcc (FPS, fsrc.h, 0);
345             break;
346             }                                           /* end switch <7:6> */
347         break;                                          /* end case 1 */
348 
349     case 005:                                           /* LDf */
350         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
351         F_STORE (qdouble, fsrc, FR[ac]);
352         FPS = setfcc (FPS, fsrc.h, 0);
353         break;
354 
355     case 010:                                           /* STf */
356         F_LOAD (qdouble, FR[ac], fac);
357         WriteFP (&fac, GeteaFP (dstspec, lenf), dstspec, lenf);
358         break;
359 
360     case 017:                                           /* LDCff' */
361         ReadFP (&fsrc, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf);
362         if (GET_EXP (fsrc.h) == 0)
363             fsrc = zero_fac;
364         if ((FPS & (FPS_D + FPS_T)) == 0)
365             newV = roundfp11 (&fsrc);
366         else newV = 0;
367         F_STORE (qdouble, fsrc, FR[ac]);
368         FPS = setfcc (FPS, fsrc.h, newV);
369         break;
370 
371     case 014:                                           /* STCff' */
372         F_LOAD (qdouble, FR[ac], fac);
373         if (GET_EXP (fac.h) == 0)
374             fac = zero_fac;
375         if ((FPS & (FPS_D + FPS_T)) == FPS_D)
376             newV = roundfp11 (&fac);
377         else newV = 0;
378         WriteFP (&fac, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf);
379         FPS = setfcc (FPS, fac.h, newV);
380         break;
381 
382     case 007:                                           /* CMPf */
383         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
384         F_LOAD (qdouble, FR[ac], fac);
385         if (GET_EXP (fsrc.h) == 0)
386             fsrc = zero_fac;
387         if (GET_EXP (fac.h) == 0)
388             fac = zero_fac;
389         if ((fsrc.h == fac.h) && (fsrc.l == fac.l)) {   /* equal? */
390             FPS = (FPS & ~FPS_CC) | FPS_Z;
391             if ((fsrc.h | fsrc.l) == 0) {               /* zero? */
392                 F_STORE (qdouble, zero_fac, FR[ac]);
393                 }
394             break;
395             }
396         FPS = (FPS & ~FPS_CC) | ((fsrc.h >> (FP_V_SIGN - PSW_V_N)) & FPS_N);
397         if ((GET_SIGN (fsrc.h ^ fac.h) == 0) && (fac.h != 0) &&
398             F_LT (fsrc, fac))
399             FPS = FPS ^ FPS_N;
400         break;
401 
402     case 015:                                           /* LDEXP */
403         dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaW (dstspec));
404         F_LOAD (qdouble, FR[ac], fac);
405         fac.h = (fac.h & ~FP_EXP) | (((dst + FP_BIAS) & FP_M_EXP) << FP_V_EXP);
406         newV = 0;
407         if ((dst > 0177) && (dst <= 0177600)) {
408             if (dst < 0100000) {
409                 if (fpnotrap (FEC_OVFLO))
410                     fac = zero_fac;
411                 newV = FPS_V;
412                 }
413             else {
414                 if (fpnotrap (FEC_UNFLO))
415                     fac = zero_fac;
416                 }
417             }
418         F_STORE (qdouble, fac, FR[ac]);
419         FPS = setfcc (FPS, fac.h, newV);
420         break;
421 
422     case 012:                                           /* STEXP */
423         dst = (GET_EXP (FR[ac].h) - FP_BIAS) & 0177777;
424         N = GET_SIGN_W (dst);
425         Z = (dst == 0);
426         V = 0;
427         C = 0;
428         FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) | (Z << PSW_V_Z);
429         if (dstspec <= 07)
430             R[dstspec] = dst;
431         else WriteW (dst, GeteaW (dstspec));
432         break;
433 
434     case 016:                                           /* LDCif */
435         leni = FPS & FPS_L? LONG: WORD;
436         if (dstspec <= 07)
437             fac.l = R[dstspec] << 16;
438         else fac.l = ReadI (GeteaFP (dstspec, leni), dstspec, leni);
439         fac.h = 0;
440         if (fac.l) {
441             if ((sign = GET_SIGN_L (fac.l)))
442                 fac.l = (fac.l ^ 0xFFFFFFFF) + 1;
443             for (i = 0; GET_SIGN_L (fac.l) == 0; i++)
444                 fac.l = fac.l << 1;
445             exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i;
446             fac.h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) |
447                 ((fac.l >> (31 - FP_V_HB)) & FP_FRACH);
448             fac.l = (fac.l << (FP_V_HB + 1)) & FP_FRACL;
449             if ((FPS & (FPS_D + FPS_T)) == 0)
450                 roundfp11 (&fac);
451             }
452         F_STORE (qdouble, fac, FR[ac]);
453         FPS = setfcc (FPS, fac.h, 0);
454         break;
455 
456     case 013:                                           /* STCfi */
457         sign = GET_SIGN (FR[ac].h);                     /* get sign, */
458         exp = GET_EXP (FR[ac].h);                       /* exponent, */
459         F_LOAD_FRAC (qdouble, FR[ac], fac);             /* fraction */
460         if (FPS & FPS_L) {
461             leni = LONG;
462             i = FP_BIAS + 32;
463             }
464         else {
465             leni = WORD;
466             i = FP_BIAS + 16;
467             }
468         C = 0;
469         if (exp <= FP_BIAS)
470             dst = 0;
471         else if (exp > i) {
472             dst = 0;
473             C = 1;
474             }
475         else {
476             F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc);
477             if (leni == WORD)
478                 fsrc.l = fsrc.l & ~0177777;
479             if (fsrc.l >= i_limit[leni == LONG][sign]) {
480                 dst = 0;
481                 C = 1;
482                 }
483             else {
484                 dst = fsrc.l;
485                 if (sign)
486                     dst = -dst;
487                 }
488             }
489         N = GET_SIGN_L (dst);
490         Z = (dst == 0);
491         V = 0;
492         if (C)
493             fpnotrap (FEC_ICVT);
494         FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) |
495             (Z << PSW_V_Z) | (C << PSW_V_C);
496         if (dstspec <= 07)
497             R[dstspec] = (dst >> 16) & 0177777;
498         else WriteI (dst, GeteaFP (dstspec, leni), dstspec, leni);
499         break;
500 
501     case 002:                                           /* MULf */
502         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
503         F_LOAD (qdouble, FR[ac], fac);
504         newV = mulfp11 (&fac, &fsrc);
505         F_STORE (qdouble, fac, FR[ac]);
506         FPS = setfcc (FPS, fac.h, newV);
507         break;
508 
509     case 003:                                           /* MODf */
510         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
511         F_LOAD (qdouble, FR[ac], fac);
512         newV = modfp11 (&fac, &fsrc, &modfrac);
513         F_STORE (qdouble, fac, FR[ac | 1]);
514         F_STORE (qdouble, modfrac, FR[ac]);
515         FPS = setfcc (FPS, modfrac.h, newV);
516         break;
517 
518     case 004:                                           /* ADDf */
519         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
520         F_LOAD (qdouble, FR[ac], fac);
521         newV = addfp11 (&fac, &fsrc);
522         F_STORE (qdouble, fac, FR[ac]);
523         FPS = setfcc (FPS, fac.h, newV);
524         break;
525 
526     case 006:                                           /* SUBf */
527         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
528         F_LOAD (qdouble, FR[ac], fac);
529         if (GET_EXP (fsrc.h) != 0)
530             fsrc.h = fsrc.h ^ FP_SIGN;
531         newV = addfp11 (&fac, &fsrc);
532         F_STORE (qdouble, fac, FR[ac]);
533         FPS = setfcc (FPS, fac.h, newV);
534         break;
535 
536     case 011:                                           /* DIVf */
537         ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
538         F_LOAD (qdouble, FR[ac], fac);
539         if (GET_EXP (fsrc.h) == 0) {                    /* divide by zero? */
540             fpnotrap (FEC_DZRO);
541             ABORT (TRAP_INT);
542             }
543         newV = divfp11 (&fac, &fsrc);
544         F_STORE (qdouble, fac, FR[ac]);
545         FPS = setfcc (FPS, fac.h, newV);
546         break;
547         }                                               /* end switch fop */
548 
549 return;
550 }
551 
552 /* Effective address calculation for fp operands
553 
554    Inputs:
555         spec    =       specifier
556         len     =       length
557    Outputs:
558         VA      =       virtual address
559 
560    Warnings:
561         - Do not call this routine for integer mode 0 operands
562         - Do not call this routine more than once per instruction
563 */
564 
GeteaFP(int32 spec,int32 len)565 int32 GeteaFP (int32 spec, int32 len)
566 {
567 int32 adr, reg, ds;
568 
569 reg = spec & 07;                                        /* reg number */
570 ds = (reg == 7)? isenable: dsenable;                    /* dspace if not PC */
571 switch (spec >> 3) {                                    /* case on spec */
572 
573     case 0:                                             /* floating AC */
574         if (reg >= 06) {
575             fpnotrap (FEC_OP);
576             ABORT (TRAP_INT);
577             }
578         return 0;
579 
580     case 1:                                             /* (R) */
581         return (R[reg] | ds);
582 
583     case 2:                                             /* (R)+ */
584         if (reg == 7)
585             len = 2;
586         R[reg] = ((adr = R[reg]) + len) & 0177777;
587         if (update_MM)
588             MMR1 = (len << 3) | reg;
589         return (adr | ds);
590 
591     case 3:                                             /* @(R)+ */
592         R[reg] = ((adr = R[reg]) + 2) & 0177777;
593         if (update_MM)
594             MMR1 = 020 | reg;
595         adr = ReadW (adr | ds);
596         return (adr | dsenable);
597 
598     case 4:                                             /* -(R) */
599         adr = R[reg] = (R[reg] - len) & 0177777;
600         if (update_MM)
601             MMR1 = (((-len) & 037) << 3) | reg;
602         if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
603             set_stack_trap (adr);
604         return (adr | ds);
605 
606     case 5:                                             /* @-(R) */
607         adr = R[reg] = (R[reg] - 2) & 0177777;
608         if (update_MM)
609             MMR1 = 0360 | reg;
610         if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
611             set_stack_trap (adr);
612         adr = ReadW (adr | ds);
613         return (adr | dsenable);
614 
615     case 6:                                             /* d(r) */
616         adr = ReadW (PC | isenable);
617         PC = (PC + 2) & 0177777;
618         return (((R[reg] + adr) & 0177777) | dsenable);
619 
620     case 7:                                             /* @d(R) */
621         adr = ReadW (PC | isenable);
622         PC = (PC + 2) & 0177777;
623         adr = ReadW (((R[reg] + adr) & 0177777) | dsenable);
624         return (adr | dsenable);
625         }                                               /* end switch */
626 
627 return 0;
628 }
629 
630 /* Read integer operand
631 
632    Inputs:
633         VA      =       virtual address, VA<18:16> = mode, I/D space
634         spec    =       specifier
635         len     =       length (2/4 bytes)
636    Outputs:
637         data    =       data read from memory or I/O space
638 */
639 
ReadI(int32 VA,int32 spec,int32 len)640 uint32 ReadI (int32 VA, int32 spec, int32 len)
641 {
642 if ((len == WORD) || (spec == 027))
643     return (ReadW (VA) << 16);
644 return ((ReadW (VA) << 16) |
645          ReadW ((VA & ~0177777) | ((VA + 2) & 0177777)));
646 }
647 
648 /* Read floating operand
649 
650    Inputs:
651         fptr    =       pointer to output
652         VA      =       virtual address, VA<18:16> = mode, I/D space
653         spec    =       specifier
654         len     =       length (4/8 bytes)
655 */
656 
ReadFP(fpac_t * fptr,int32 VA,int32 spec,int32 len)657 void ReadFP (fpac_t *fptr, int32 VA, int32 spec, int32 len)
658 {
659 int32 exta;
660 
661 if (spec <= 07) {
662     F_LOAD_P (len == QUAD, FR[spec], fptr);
663     return;
664     }
665 if (spec == 027) {
666     fptr->h = (ReadW (VA) << FP_V_F0);
667     fptr->l = 0;
668     }
669 else {
670     exta = VA & ~0177777;
671     fptr->h = (ReadW (VA) << FP_V_F0) |
672         (ReadW (exta | ((VA + 2) & 0177777)) << FP_V_F1);
673     if (len == QUAD) fptr->l =
674         (ReadW (exta | ((VA + 4) & 0177777)) << FP_V_F2) |
675         (ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3);
676     else fptr->l = 0;
677     }
678 if ((GET_SIGN (fptr->h) != 0) && (GET_EXP (fptr->h) == 0) &&
679     (fpnotrap (FEC_UNDFV) == 0)) ABORT (TRAP_INT);
680 return;
681 }
682 
683 /* Write integer result
684 
685    Inputs:
686         data    =       data to be written
687         VA      =       virtual address, VA<18:16> = mode, I/D space
688         spec    =       specifier
689         len     =       length
690    Outputs: none
691 */
692 
WriteI(int32 data,int32 VA,int32 spec,int32 len)693 void WriteI (int32 data, int32 VA, int32 spec, int32 len)
694 {
695 WriteW ((data >> 16) & 0177777, VA);
696 if ((len == WORD) || (spec == 027))
697     return;
698 WriteW (data & 0177777, (VA & ~0177777) | ((VA + 2) & 0177777));
699 return;
700 }
701 
702 /* Write floating result
703 
704    Inputs:
705         fptr    =       pointer to data to be written
706         VA      =       virtual address, VA<18:16> = mode, I/D space
707         spec    =       specifier
708         len     =       length
709    Outputs: none
710 */
711 
WriteFP(fpac_t * fptr,int32 VA,int32 spec,int32 len)712 void WriteFP (fpac_t *fptr, int32 VA, int32 spec, int32 len)
713 {
714 int32 exta;
715 
716 if (spec <= 07) {
717     F_STORE_P (len == QUAD, fptr, FR[spec]);
718     return;
719     }
720 WriteW ((fptr->h >> FP_V_F0) & 0177777, VA);
721 if (spec == 027)
722     return;
723 exta = VA & ~0177777;
724 WriteW ((fptr->h >> FP_V_F1) & 0177777, exta | ((VA + 2) & 0177777));
725 if (len == LONG)
726     return;
727 WriteW ((fptr->l >> FP_V_F2) & 0177777, exta | ((VA + 4) & 0177777));
728 WriteW ((fptr->l >> FP_V_F3) & 0177777, exta | ((VA + 6) & 0177777));
729 return;
730 }
731 
732 /* FIS instructions */
733 
fis11(int32 IR)734 t_stat fis11 (int32 IR)
735 {
736 int32 reg, exta;
737 fpac_t fac, fsrc;
738 
739 reg = IR & 07;                                          /* isolate reg */
740 if (reg == 7)                                           /* choose I,D */
741     exta = isenable;
742 else exta = dsenable;
743 if (IR & 000740) {                                      /* defined? */
744     if (CPUT (CPUT_03))                                 /* 11/03 reads word */
745         ReadW (exta | R[reg]);
746     ABORT (TRAP_ILL);
747 	}
748 FEC = 0;                                                /* no errors */
749 FPS = FPS_IU|FPS_IV;                                    /* trap ovf,unf */
750 
751 fsrc.h = (ReadW (exta | R[reg]) << FP_V_F0) |
752     (ReadW (exta | ((R[reg] + 2) & 0177777)) << FP_V_F1);
753 fsrc.l = 0;
754 fac.h = (ReadW (exta | ((R[reg] + 4) & 0177777)) << FP_V_F0) |
755     (ReadW (exta | ((R[reg] + 6) & 0177777)) << FP_V_F1);
756 fac.l = 0;
757 if (GET_SIGN (fsrc.h) && (GET_EXP (fsrc.h) == 0))       /* clean 0's */
758     fsrc.h = fsrc.l = 0;
759 if (GET_SIGN (fac.h) && (GET_EXP (fac.l) == 0))
760     fac.h = fac.l = 0;
761 
762 N = Z = V = C = 0;                                      /* clear cc's */
763 switch ((IR >> 3) & 3) {                                /* case IR<5:3> */
764 
765     case 0:                                             /* FAD */
766         addfp11 (&fac, &fsrc);
767         break;
768 
769     case 1:                                             /* FSUB */
770         if (fsrc.h != 0)                                /* invert sign */
771             fsrc.h = fsrc.h ^ FP_SIGN;
772         addfp11 (&fac, &fsrc);
773         break;
774 
775     case 2:                                             /* FMUL */
776         mulfp11 (&fac, &fsrc);
777         break;
778 
779     case 3:                                             /* FDIV */
780         if (fsrc.h == 0) {                              /* div by 0? */
781             V = N = C = 1;                              /* set cc's */
782             setTRAP (TRAP_FPE);                         /* set trap */
783             return SCPE_OK;
784 			}
785         else divfp11 (&fac, &fsrc);
786         break;
787         }
788 
789 if (FEC == 0) {                                         /* no err? */
790     WriteW ((fac.h >> FP_V_F0) & 0177777, exta | ((R[reg] + 4) & 0177777));
791     WriteW ((fac.h >> FP_V_F1) & 0177777, exta | ((R[reg] + 6) & 0177777));
792     R[reg] = (R[reg] + 4) & 0177777;                    /* pop stack */
793     N = (GET_SIGN (fac.h) != 0);                        /* set N,Z */
794     Z = (fac.h == 0);
795     }
796 else if (FEC == FEC_OVFLO)                              /* ovf? trap set */
797     V = 1;
798 else if (FEC == FEC_UNFLO)                              /* unf? trap set */
799     V = N = 1;
800 else return SCPE_IERR;                                  /* what??? */
801 return SCPE_OK;
802 }
803 
804 /* Floating point add
805 
806    Inputs:
807         facp    =       pointer to src1 (output)
808         fsrcp   =       pointer to src2
809    Outputs:
810         ovflo   =       overflow variable
811 */
812 
addfp11(fpac_t * facp,fpac_t * fsrcp)813 int32 addfp11 (fpac_t *facp, fpac_t *fsrcp)
814 {
815 int32 facexp, fsrcexp, ediff;
816 fpac_t facfrac, fsrcfrac;
817 
818 if (F_LT_AP (facp, fsrcp)) {                            /* if !fac! < !fsrc! */
819     facfrac = *facp;
820     *facp = *fsrcp;                                     /* swap operands */
821     *fsrcp = facfrac;
822     }
823 facexp = GET_EXP (facp->h);                             /* get exponents */
824 fsrcexp = GET_EXP (fsrcp->h);
825 if (facexp == 0) {                                      /* fac = 0? */
826     *facp = fsrcexp? *fsrcp: zero_fac;                  /* result fsrc or 0 */
827     return 0;
828     }
829 if (fsrcexp == 0)                                       /* fsrc = 0? no op */
830     return 0;
831 ediff = facexp - fsrcexp;                               /* exponent diff */
832 if (ediff >= 60)                                        /* too big? no op */
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 if (GET_SIGN (facp->h) != GET_SIGN (fsrcp->h)) {        /* signs different? */
839     if (ediff) {                                        /* sub, shf fsrc */
840         F_RSH_V (fsrcfrac, ediff, fsrcfrac);
841         }
842     F_SUB (fsrcfrac, facfrac, facfrac);                 /* sub fsrc from fac */
843     if ((facfrac.h | facfrac.l) == 0)  {                /* result zero? */
844         *facp = zero_fac;                               /* no overflow */
845         return 0;
846         }
847     if (ediff <= 1) {                                   /* big normalize? */
848         if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
849             F_LSH_K (facfrac, 24, facfrac);
850             facexp = facexp - 24;
851             }
852         if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
853             F_LSH_K (facfrac, 12, facfrac);
854             facexp = facexp - 12;
855             }
856         if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
857             F_LSH_K (facfrac, 6, facfrac);
858             facexp = facexp - 6;
859             }
860         }
861     while (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
862         F_LSH_1 (facfrac);
863         facexp = facexp - 1;
864         }
865     }
866 else {
867     if (ediff) {
868         F_RSH_V (fsrcfrac, ediff, fsrcfrac);            /* add, shf fsrc */
869         }
870     F_ADD (fsrcfrac, facfrac, facfrac);                 /* add fsrc to fac */
871     if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD + 1)) {
872         F_RSH_1 (facfrac);                              /* carry out, shift */
873         facexp = facexp + 1;
874         }
875     }
876 return round_and_pack (facp, facexp, &facfrac, 1);
877 }
878 
879 /* Floating point multiply
880 
881    Inputs:
882         facp    =       pointer to src1 (output)
883         fsrcp   =       pointer to src2
884    Outputs:
885         ovflo   =       overflow indicator
886 */
887 
mulfp11(fpac_t * facp,fpac_t * fsrcp)888 int32 mulfp11 (fpac_t *facp, fpac_t *fsrcp)
889 {
890 int32 facexp, fsrcexp;
891 fpac_t facfrac, fsrcfrac;
892 
893 facexp = GET_EXP (facp->h);                             /* get exponents */
894 fsrcexp = GET_EXP (fsrcp->h);
895 if ((facexp == 0) || (fsrcexp == 0)) {                  /* test for zero */
896     *facp = zero_fac;
897     return 0;
898     }
899 F_GET_FRAC_P (facp, facfrac);                           /* get fractions */
900 F_GET_FRAC_P (fsrcp, fsrcfrac);
901 facexp = facexp + fsrcexp - FP_BIAS;                    /* calculate exp */
902 facp->h = facp->h  ^ fsrcp->h;                          /* calculate sign */
903 frac_mulfp11 (&facfrac, &fsrcfrac);                     /* multiply fracs */
904 
905 /* Multiplying two numbers in the range [.5,1) produces a result in the
906    range [.25,1).  Therefore, at most one bit of normalization is required
907    to bring the result back to the range [.5,1).
908 */
909 
910 if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
911     F_LSH_1 (facfrac);
912     facexp = facexp - 1;
913     }
914 return round_and_pack (facp, facexp, &facfrac, 1);
915 }
916 
917 /* Floating point mod
918 
919    Inputs:
920         facp    =       pointer to src1 (integer result)
921         fsrcp   =       pointer to src2
922         fracp   =       pointer to fractional result
923    Outputs:
924         ovflo   =       overflow indicator
925 
926    See notes on multiply for initial operation
927 */
928 
modfp11(fpac_t * facp,fpac_t * fsrcp,fpac_t * fracp)929 int32 modfp11 (fpac_t *facp, fpac_t *fsrcp, fpac_t *fracp)
930 {
931 int32 facexp, fsrcexp;
932 fpac_t facfrac, fsrcfrac, fmask;
933 
934 facexp = GET_EXP (facp->h);                             /* get exponents */
935 fsrcexp = GET_EXP (fsrcp->h);
936 if ((facexp == 0) || (fsrcexp == 0)) {                  /* test for zero */
937     *fracp = zero_fac;
938     *facp = zero_fac;
939     return 0;
940     }
941 F_GET_FRAC_P (facp, facfrac);                           /* get fractions */
942 F_GET_FRAC_P (fsrcp, fsrcfrac);
943 facexp = facexp + fsrcexp - FP_BIAS;                    /* calculate exp */
944 fracp->h = facp->h = facp->h ^ fsrcp->h;                /* calculate sign */
945 frac_mulfp11 (&facfrac, &fsrcfrac);                     /* multiply fracs */
946 
947 /* Multiplying two numbers in the range [.5,1) produces a result in the
948    range [.25,1).  Therefore, at most one bit of normalization is required
949    to bring the result back to the range [.5,1).
950 */
951 
952 if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
953     F_LSH_1 (facfrac);
954     facexp = facexp - 1;
955     }
956 
957 /* There are three major cases of MODf:
958 
959    1. Exp <= FP_BIAS (all fraction).  Return 0 as integer, product as
960       fraction.  Underflow can occur.
961    2. Exp > FP_BIAS + #fraction bits (all integer).  Return product as
962       integer, 0 as fraction.  Overflow can occur.
963    3. FP_BIAS < exp <= FP_BIAS + #fraction bits.  Separate integer and
964       fraction and return both.  Neither overflow nor underflow can occur.
965 */
966 
967 if (facexp <= FP_BIAS) {                                /* case 1 */
968     *facp = zero_fac;
969     return round_and_pack (fracp, facexp, &facfrac, 1);
970     }
971 if (facexp > ((FPS & FPS_D)? FP_BIAS + 56: FP_BIAS + 24)) {
972     *fracp = zero_fac;                                  /* case 2 */
973     return round_and_pack (facp, facexp, &facfrac, 0);
974     }
975 F_RSH_V (fmask_fac, facexp - FP_BIAS, fmask);           /* shift mask */
976 fsrcfrac.l = facfrac.l & fmask.l;                       /* extract fraction */
977 fsrcfrac.h = facfrac.h & fmask.h;
978 if ((fsrcfrac.h | fsrcfrac.l) == 0)
979     *fracp = zero_fac;
980 else {
981     F_LSH_V (fsrcfrac, facexp - FP_BIAS, fsrcfrac);
982     fsrcexp = FP_BIAS;
983     if ((fsrcfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
984         F_LSH_K (fsrcfrac, 24, fsrcfrac);
985         fsrcexp = fsrcexp - 24;
986         }
987     if ((fsrcfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
988         F_LSH_K (fsrcfrac, 12, fsrcfrac);
989         fsrcexp = fsrcexp - 12;
990         }
991     if ((fsrcfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
992         F_LSH_K (fsrcfrac, 6, fsrcfrac);
993         fsrcexp = fsrcexp - 6;
994         }
995     while (GET_BIT (fsrcfrac.h, FP_V_HB + FP_GUARD) == 0) {
996         F_LSH_1 (fsrcfrac);
997         fsrcexp = fsrcexp - 1;
998         }
999     round_and_pack (fracp, fsrcexp, &fsrcfrac, 1);
1000     }
1001 facfrac.l = facfrac.l & ~fmask.l;
1002 facfrac.h = facfrac.h & ~fmask.h;
1003 return round_and_pack (facp, facexp, &facfrac, 0);
1004 }
1005 
1006 /* Fraction multiply
1007 
1008    Inputs:
1009         f1p     =       pointer to multiplier (output)
1010         f2p     =       pointer to multiplicand fraction
1011 
1012    Note: the inputs are unguarded; the output is guarded.
1013 
1014    This routine performs a classic shift-and-add multiply.  The low
1015    order bit of the multiplier is tested; if 1, the multiplicand is
1016    added into the high part of the double precision result.  The
1017    result and the multiplier are both shifted right 1.
1018 
1019    For the 24b x 24b case, this routine develops 48b of result.
1020    For the 56b x 56b case, this routine only develops the top 64b
1021    of the the result.  Because the inputs are normalized fractions,
1022    the interesting part of the result is the high 56+guard bits.
1023    Everything shifted off to the right, beyond 64b, plays no part
1024    in rounding or the result.
1025 
1026    There are many possible optimizations in this routine: scanning
1027    for groups of zeroes, particularly in the 56b x 56b case; using
1028    "extended multiply" capability if available in the hardware.
1029 */
1030 
frac_mulfp11(fpac_t * f1p,fpac_t * f2p)1031 void frac_mulfp11 (fpac_t *f1p, fpac_t *f2p)
1032 {
1033 fpac_t result, mpy, mpc;
1034 int32 i;
1035 
1036 result = zero_fac;                                      /* clear result */
1037 mpy = *f1p;                                             /* get operands */
1038 mpc = *f2p;
1039 F_LSH_GUARD (mpc);                                      /* guard multipicand */
1040 if ((mpy.l | mpc.l) == 0) {                             /* 24b x 24b? */
1041     for (i = 0; i < 24; i++) {
1042         if (mpy.h & 1)
1043             result.h = result.h + mpc.h;
1044         F_RSH_1 (result);
1045         mpy.h = mpy.h >> 1;
1046         }
1047     }
1048 else {
1049     if (mpy.l != 0) {                                   /* 24b x 56b? */
1050         for (i = 0; i < 32; i++) {
1051             if (mpy.l & 1) {
1052                 F_ADD (mpc, result, result);
1053                 }
1054             F_RSH_1 (result);
1055             mpy.l = mpy.l >> 1;
1056             }
1057         }
1058     for (i = 0; i < 24; i++) {
1059         if (mpy.h & 1) {
1060             F_ADD (mpc, result, result);
1061             }
1062         F_RSH_1 (result);
1063         mpy.h = mpy.h >> 1;
1064         }
1065     }
1066 *f1p = result;
1067 return;
1068 }
1069 
1070 /* Floating point divide
1071 
1072    Inputs:
1073         facp    =       pointer to dividend (output)
1074         fsrcp   =       pointer to divisor
1075    Outputs:
1076         ovflo   =       overflow indicator
1077 
1078    Source operand must be checked for zero by caller!
1079 */
1080 
divfp11(fpac_t * facp,fpac_t * fsrcp)1081 int32 divfp11 (fpac_t *facp, fpac_t *fsrcp)
1082 {
1083 int32 facexp, fsrcexp, i, count, qd;
1084 fpac_t facfrac, fsrcfrac, quo;
1085 
1086 fsrcexp = GET_EXP (fsrcp->h);                           /* get divisor exp */
1087 facexp = GET_EXP (facp->h);                             /* get dividend exp */
1088 if (facexp == 0) {                                      /* test for zero */
1089     *facp = zero_fac;                                   /* result zero */
1090     return 0;
1091     }
1092 F_GET_FRAC_P (facp, facfrac);                           /* get fractions */
1093 F_GET_FRAC_P (fsrcp, fsrcfrac);
1094 F_LSH_GUARD (facfrac);                                  /* guard fractions */
1095 F_LSH_GUARD (fsrcfrac);
1096 facexp = facexp - fsrcexp + FP_BIAS + 1;                /* calculate exp */
1097 facp->h = facp->h ^ fsrcp->h;                           /* calculate sign */
1098 qd = FPS & FPS_D;
1099 count = FP_V_HB + FP_GUARD + (qd? 33: 1);               /* count = 56b/24b */
1100 
1101 quo = zero_fac;
1102 for (i = count; (i > 0) && ((facfrac.h | facfrac.l) != 0); i--) {
1103     F_LSH_1 (quo);                                      /* shift quotient */
1104     if (!F_LT (facfrac, fsrcfrac)) {                    /* divd >= divr? */
1105         F_SUB (fsrcfrac, facfrac, facfrac);             /* divd - divr */
1106         if (qd)                                         /* double or single? */
1107             quo.l = quo.l | 1;
1108         else quo.h = quo.h | 1;
1109         }
1110     F_LSH_1 (facfrac);                                  /* shift divd */
1111     }
1112 if (i > 0) {                                            /* early exit? */
1113     F_LSH_V (quo, i, quo);
1114     }
1115 
1116 /* Dividing two numbers in the range [.5,1) produces a result in the
1117    range [.5,2).  Therefore, at most one bit of normalization is required
1118    to bring the result back to the range [.5,1).  The choice of counts
1119    and quotient bit positions makes this work correctly.
1120 */
1121 
1122 if (GET_BIT (quo.h, FP_V_HB + FP_GUARD) == 0) {
1123     F_LSH_1 (quo);
1124     facexp = facexp - 1;
1125     }
1126 return round_and_pack (facp, facexp, &quo, 1);
1127 }
1128 
1129 /* Update floating condition codes
1130    Note that FC is only set by STCfi via the integer condition codes
1131 
1132    Inputs:
1133         oldst   =       current status
1134         result  =       high result
1135         newV    =       new V
1136    Outputs:
1137         newst   =       new status
1138 */
1139 
setfcc(int32 oldst,int32 result,int32 newV)1140 int32 setfcc (int32 oldst, int32 result, int32 newV)
1141 {
1142 oldst = (oldst & ~FPS_CC) | newV;
1143 if (GET_SIGN (result))
1144     oldst = oldst | FPS_N;
1145 if (GET_EXP (result) == 0)
1146     oldst = oldst | FPS_Z;
1147 return oldst;
1148 }
1149 
1150 /* Round (in place) floating point number to f_floating
1151 
1152    Inputs:
1153         fptr    =       pointer to floating number
1154    Outputs:
1155         ovflow  =       overflow
1156 */
1157 
roundfp11(fpac_t * fptr)1158 int32 roundfp11 (fpac_t *fptr)
1159 {
1160 fpac_t outf;
1161 
1162 outf = *fptr;                                           /* get argument */
1163 F_ADD (fround_fac, outf, outf);                         /* round */
1164 if (GET_SIGN (outf.h ^ fptr->h)) {                      /* flipped sign? */
1165     outf.h = (outf.h ^ FP_SIGN) & 0xFFFFFFFF;           /* restore sign */
1166     if (fpnotrap (FEC_OVFLO))                           /* if no int, clear */
1167         *fptr = zero_fac;
1168     else *fptr = outf;                                  /* return rounded */
1169     return FPS_V;                                       /* overflow */
1170     }
1171 *fptr = outf;                                           /* round was ok */
1172 return 0;                                               /* no overflow */
1173 }
1174 
1175 /* Round result of calculation, test overflow, pack
1176 
1177    Input:
1178         facp    =       pointer to result, sign in place
1179         exp     =       result exponent, right justified
1180         fracp   =       pointer to result fraction, right justified with
1181                         guard bits
1182         r       =       round (1) or truncate (0)
1183    Outputs:
1184         ovflo   =       overflow indicator
1185 */
1186 
round_and_pack(fpac_t * facp,int32 exp,fpac_t * fracp,int r)1187 int32 round_and_pack (fpac_t *facp, int32 exp, fpac_t *fracp, int r)
1188 {
1189 fpac_t frac;
1190 
1191 frac = *fracp;                                          /* get fraction */
1192 if (r && ((FPS & FPS_T) == 0)) {
1193     if (FPS & FPS_D) {
1194          F_ADD (dround_guard_fac, frac, frac);
1195          }
1196     else {
1197          F_ADD (fround_guard_fac, frac, frac);
1198          }
1199     if (GET_BIT (frac.h, FP_V_HB + FP_GUARD + 1)) {
1200         F_RSH_1 (frac);
1201         exp = exp + 1;
1202         }
1203     }
1204 F_RSH_GUARD (frac);
1205 facp->l = frac.l & FP_FRACL;
1206 facp->h = (facp->h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) |
1207     (frac.h & FP_FRACH);
1208 if (exp > 0377) {
1209     if (fpnotrap (FEC_OVFLO))
1210         *facp = zero_fac;
1211     return FPS_V;
1212     }
1213 if ((exp <= 0) && (fpnotrap (FEC_UNFLO)))
1214     *facp = zero_fac;
1215 return 0;
1216 }
1217 
1218 /* Process floating point exception
1219 
1220    Inputs:
1221         code    =       exception code
1222    Outputs:
1223         int     =       FALSE if interrupt enabled, TRUE if disabled
1224 */
1225 
fpnotrap(int32 code)1226 int32 fpnotrap (int32 code)
1227 {
1228 static const int32 test_code[] = { 0, 0, 0, FPS_IC, FPS_IV, FPS_IU, FPS_IUV };
1229 
1230 if ((code >= FEC_ICVT) && (code <= FEC_UNDFV) &&
1231     ((FPS & test_code[code >> 1]) == 0))
1232     return TRUE;
1233 FPS = FPS | FPS_ER;
1234 FEC = code;
1235 FEA = (backup_PC - 2) & 0177777;
1236 if ((FPS & FPS_ID) == 0)
1237     setTRAP (TRAP_FPE);
1238 return FALSE;
1239 }
1240