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