First Commit of my working state
[simh.git] / PDP11 / pdp11_fp.c
1 /* pdp11_fp.c: PDP-11 floating point simulator (32b version)
2
3 Copyright (c) 1993-2005, 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 (from 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
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) R[dstspec] = FPS;
303 else WriteW (FPS, GeteaW (dstspec));
304 break;
305
306 case 3: /* STST */
307 if (dstspec <= 07) R[dstspec] = FEC;
308 else WriteI ((FEC << 16) | FEA, GeteaFP (dstspec, LONG),
309 dstspec, LONG);
310 break;
311 } /* end switch <7:6> */
312 break; /* end case 0 */
313
314 case 001:
315 switch (ac) { /* decode IR<7:6> */
316
317 case 0: /* CLRf */
318 WriteFP (&zero_fac, GeteaFP (dstspec, lenf), dstspec, lenf);
319 FPS = (FPS & ~FPS_CC) | FPS_Z;
320 break;
321
322 case 1: /* TSTf */
323 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
324 FPS = setfcc (FPS, fsrc.h, 0);
325 break;
326
327 case 2: /* ABSf */
328 ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
329 if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
330 else fsrc.h = fsrc.h & ~FP_SIGN;
331 WriteFP (&fsrc, ea, dstspec, lenf);
332 FPS = setfcc (FPS, fsrc.h, 0);
333 break;
334
335 case 3: /* NEGf */
336 ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
337 if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
338 else fsrc.h = fsrc.h ^ FP_SIGN;
339 WriteFP (&fsrc, ea, dstspec, lenf);
340 FPS = setfcc (FPS, fsrc.h, 0);
341 break;
342 } /* end switch <7:6> */
343 break; /* end case 1 */
344
345 case 005: /* LDf */
346 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
347 F_STORE (qdouble, fsrc, FR[ac]);
348 FPS = setfcc (FPS, fsrc.h, 0);
349 break;
350
351 case 010: /* STf */
352 F_LOAD (qdouble, FR[ac], fac);
353 WriteFP (&fac, GeteaFP (dstspec, lenf), dstspec, lenf);
354 break;
355
356 case 017: /* LDCff' */
357 ReadFP (&fsrc, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf);
358 if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
359 if ((FPS & (FPS_D + FPS_T)) == 0) newV = roundfp11 (&fsrc);
360 else newV = 0;
361 F_STORE (qdouble, fsrc, FR[ac]);
362 FPS = setfcc (FPS, fsrc.h, newV);
363 break;
364
365 case 014: /* STCff' */
366 F_LOAD (qdouble, FR[ac], fac);
367 if (GET_EXP (fac.h) == 0) fac = zero_fac;
368 if ((FPS & (FPS_D + FPS_T)) == FPS_D) newV = roundfp11 (&fac);
369 else newV = 0;
370 WriteFP (&fac, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf);
371 FPS = setfcc (FPS, fac.h, newV);
372 break;
373
374 case 007: /* CMPf */
375 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
376 F_LOAD (qdouble, FR[ac], fac);
377 if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
378 if (GET_EXP (fac.h) == 0) fac = zero_fac;
379 if ((fsrc.h == fac.h) && (fsrc.l == fac.l)) { /* equal? */
380 FPS = (FPS & ~FPS_CC) | FPS_Z;
381 if ((fsrc.h | fsrc.l) == 0) { /* zero? */
382 F_STORE (qdouble, zero_fac, FR[ac]);
383 }
384 break;
385 }
386 FPS = (FPS & ~FPS_CC) | ((fsrc.h >> (FP_V_SIGN - PSW_V_N)) & FPS_N);
387 if ((GET_SIGN (fsrc.h ^ fac.h) == 0) && (fac.h != 0) &&
388 F_LT (fsrc, fac)) FPS = FPS ^ FPS_N;
389 break;
390
391 case 015: /* LDEXP */
392 dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaW (dstspec));
393 F_LOAD (qdouble, FR[ac], fac);
394 fac.h = (fac.h & ~FP_EXP) | (((dst + FP_BIAS) & FP_M_EXP) << FP_V_EXP);
395 newV = 0;
396 if ((dst > 0177) && (dst <= 0177600)) {
397 if (dst < 0100000) {
398 if (fpnotrap (FEC_OVFLO)) fac = zero_fac;
399 newV = FPS_V;
400 }
401 else {
402 if (fpnotrap (FEC_UNFLO)) fac = zero_fac;
403 }
404 }
405 F_STORE (qdouble, fac, FR[ac]);
406 FPS = setfcc (FPS, fac.h, newV);
407 break;
408
409 case 012: /* STEXP */
410 dst = (GET_EXP (FR[ac].h) - FP_BIAS) & 0177777;
411 N = GET_SIGN_W (dst);
412 Z = (dst == 0);
413 V = 0;
414 C = 0;
415 FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) | (Z << PSW_V_Z);
416 if (dstspec <= 07) R[dstspec] = dst;
417 else WriteW (dst, GeteaW (dstspec));
418 break;
419
420 case 016: /* LDCif */
421 leni = FPS & FPS_L? LONG: WORD;
422 if (dstspec <= 07) fac.l = R[dstspec] << 16;
423 else fac.l = ReadI (GeteaFP (dstspec, leni), dstspec, leni);
424 fac.h = 0;
425 if (fac.l) {
426 if (sign = GET_SIGN_L (fac.l)) fac.l = (fac.l ^ 0xFFFFFFFF) + 1;
427 for (i = 0; GET_SIGN_L (fac.l) == 0; i++) fac.l = fac.l << 1;
428 exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i;
429 fac.h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) |
430 ((fac.l >> (31 - FP_V_HB)) & FP_FRACH);
431 fac.l = (fac.l << (FP_V_HB + 1)) & FP_FRACL;
432 if ((FPS & (FPS_D + FPS_T)) == 0) roundfp11 (&fac);
433 }
434 F_STORE (qdouble, fac, FR[ac]);
435 FPS = setfcc (FPS, fac.h, 0);
436 break;
437
438 case 013: /* STCfi */
439 sign = GET_SIGN (FR[ac].h); /* get sign, */
440 exp = GET_EXP (FR[ac].h); /* exponent, */
441 F_LOAD_FRAC (qdouble, FR[ac], fac); /* fraction */
442 if (FPS & FPS_L) {
443 leni = LONG;
444 i = FP_BIAS + 32;
445 }
446 else {
447 leni = WORD;
448 i = FP_BIAS + 16;
449 }
450 C = 0;
451 if (exp <= FP_BIAS) dst = 0;
452 else if (exp > i) {
453 dst = 0;
454 C = 1;
455 }
456 else {
457 F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc);
458 if (leni == WORD) fsrc.l = fsrc.l & ~0177777;
459 if (fsrc.l >= i_limit[leni == LONG][sign]) {
460 dst = 0;
461 C = 1;
462 }
463 else {
464 dst = fsrc.l;
465 if (sign) dst = -dst;
466 }
467 }
468 N = GET_SIGN_L (dst);
469 Z = (dst == 0);
470 V = 0;
471 if (C) fpnotrap (FEC_ICVT);
472 FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) |
473 (Z << PSW_V_Z) | (C << PSW_V_C);
474 if (dstspec <= 07) R[dstspec] = (dst >> 16) & 0177777;
475 else WriteI (dst, GeteaFP (dstspec, leni), dstspec, leni);
476 break;
477
478 case 002: /* MULf */
479 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
480 F_LOAD (qdouble, FR[ac], fac);
481 newV = mulfp11 (&fac, &fsrc);
482 F_STORE (qdouble, fac, FR[ac]);
483 FPS = setfcc (FPS, fac.h, newV);
484 break;
485
486 case 003: /* MODf */
487 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
488 F_LOAD (qdouble, FR[ac], fac);
489 newV = modfp11 (&fac, &fsrc, &modfrac);
490 F_STORE (qdouble, fac, FR[ac | 1]);
491 F_STORE (qdouble, modfrac, FR[ac]);
492 FPS = setfcc (FPS, modfrac.h, newV);
493 break;
494
495 case 004: /* ADDf */
496 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
497 F_LOAD (qdouble, FR[ac], fac);
498 newV = addfp11 (&fac, &fsrc);
499 F_STORE (qdouble, fac, FR[ac]);
500 FPS = setfcc (FPS, fac.h, newV);
501 break;
502
503 case 006: /* SUBf */
504 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
505 F_LOAD (qdouble, FR[ac], fac);
506 if (GET_EXP (fsrc.h) != 0) fsrc.h = fsrc.h ^ FP_SIGN;
507 newV = addfp11 (&fac, &fsrc);
508 F_STORE (qdouble, fac, FR[ac]);
509 FPS = setfcc (FPS, fac.h, newV);
510 break;
511
512 case 011: /* DIVf */
513 ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
514 F_LOAD (qdouble, FR[ac], fac);
515 if (GET_EXP (fsrc.h) == 0) { /* divide by zero? */
516 fpnotrap (FEC_DZRO);
517 ABORT (TRAP_INT);
518 }
519 newV = divfp11 (&fac, &fsrc);
520 F_STORE (qdouble, fac, FR[ac]);
521 FPS = setfcc (FPS, fac.h, newV);
522 break;
523 } /* end switch fop */
524
525 return;
526 }
527
528 /* Effective address calculation for fp operands
529
530 Inputs:
531 spec = specifier
532 len = length
533 Outputs:
534 VA = virtual address
535
536 Warnings:
537 - Do not call this routine for integer mode 0 operands
538 - Do not call this routine more than once per instruction
539 */
540
541 int32 GeteaFP (int32 spec, int32 len)
542 {
543 int32 adr, reg, ds;
544
545 reg = spec & 07; /* reg number */
546 ds = (reg == 7)? isenable: dsenable; /* dspace if not PC */
547 switch (spec >> 3) { /* case on spec */
548
549 case 0: /* floating AC */
550 if (reg >= 06) {
551 fpnotrap (FEC_OP);
552 ABORT (TRAP_INT);
553 }
554 return 0;
555
556 case 1: /* (R) */
557 return (R[reg] | ds);
558
559 case 2: /* (R)+ */
560 if (reg == 7) len = 2;
561 R[reg] = ((adr = R[reg]) + len) & 0177777;
562 if (update_MM) MMR1 = (len << 3) | reg;
563 return (adr | ds);
564
565 case 3: /* @(R)+ */
566 R[reg] = ((adr = R[reg]) + 2) & 0177777;
567 if (update_MM) MMR1 = 020 | reg;
568 adr = ReadW (adr | ds);
569 return (adr | dsenable);
570
571 case 4: /* -(R) */
572 adr = R[reg] = (R[reg] - len) & 0177777;
573 if (update_MM) MMR1 = (((-len) & 037) << 3) | reg;
574 if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
575 set_stack_trap (adr);
576 return (adr | ds);
577
578 case 5: /* @-(R) */
579 adr = R[reg] = (R[reg] - 2) & 0177777;
580 if (update_MM) MMR1 = 0360 | reg;
581 if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
582 set_stack_trap (adr);
583 adr = ReadW (adr | ds);
584 return (adr | dsenable);
585
586 case 6: /* d(r) */
587 adr = ReadW (PC | isenable);
588 PC = (PC + 2) & 0177777;
589 return (((R[reg] + adr) & 0177777) | dsenable);
590
591 case 7: /* @d(R) */
592 adr = ReadW (PC | isenable);
593 PC = (PC + 2) & 0177777;
594 adr = ReadW (((R[reg] + adr) & 0177777) | dsenable);
595 return (adr | dsenable);
596 } /* end switch */
597
598 return 0;
599 }
600
601 /* Read integer operand
602
603 Inputs:
604 VA = virtual address, VA<18:16> = mode, I/D space
605 spec = specifier
606 len = length (2/4 bytes)
607 Outputs:
608 data = data read from memory or I/O space
609 */
610
611 uint32 ReadI (int32 VA, int32 spec, int32 len)
612 {
613 if ((len == WORD) || (spec == 027)) return (ReadW (VA) << 16);
614 return ((ReadW (VA) << 16) |
615 ReadW ((VA & ~0177777) | ((VA + 2) & 0177777)));
616 }
617
618 /* Read floating operand
619
620 Inputs:
621 fptr = pointer to output
622 VA = virtual address, VA<18:16> = mode, I/D space
623 spec = specifier
624 len = length (4/8 bytes)
625 */
626
627 void ReadFP (fpac_t *fptr, int32 VA, int32 spec, int32 len)
628 {
629 int32 exta;
630
631 if (spec <= 07) {
632 F_LOAD_P (len == QUAD, FR[spec], fptr);
633 return;
634 }
635 if (spec == 027) {
636 fptr->h = (ReadW (VA) << FP_V_F0);
637 fptr->l = 0;
638 }
639 else {
640 exta = VA & ~0177777;
641 fptr->h = (ReadW (VA) << FP_V_F0) |
642 (ReadW (exta | ((VA + 2) & 0177777)) << FP_V_F1);
643 if (len == QUAD) fptr->l =
644 (ReadW (exta | ((VA + 4) & 0177777)) << FP_V_F2) |
645 (ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3);
646 else fptr->l = 0;
647 }
648 if ((GET_SIGN (fptr->h) != 0) && (GET_EXP (fptr->h) == 0) &&
649 (fpnotrap (FEC_UNDFV) == 0)) ABORT (TRAP_INT);
650 return;
651 }
652
653 /* Write integer result
654
655 Inputs:
656 data = data to be written
657 VA = virtual address, VA<18:16> = mode, I/D space
658 spec = specifier
659 len = length
660 Outputs: none
661 */
662
663 void WriteI (int32 data, int32 VA, int32 spec, int32 len)
664 {
665 WriteW ((data >> 16) & 0177777, VA);
666 if ((len == WORD) || (spec == 027)) return;
667 WriteW (data & 0177777, (VA & ~0177777) | ((VA + 2) & 0177777));
668 return;
669 }
670
671 /* Write floating result
672
673 Inputs:
674 fptr = pointer to data to be written
675 VA = virtual address, VA<18:16> = mode, I/D space
676 spec = specifier
677 len = length
678 Outputs: none
679 */
680
681 void WriteFP (fpac_t *fptr, int32 VA, int32 spec, int32 len)
682 {
683 int32 exta;
684
685 if (spec <= 07) {
686 F_STORE_P (len == QUAD, fptr, FR[spec]);
687 return;
688 }
689 WriteW ((fptr->h >> FP_V_F0) & 0177777, VA);
690 if (spec == 027) return;
691 exta = VA & ~0177777;
692 WriteW ((fptr->h >> FP_V_F1) & 0177777, exta | ((VA + 2) & 0177777));
693 if (len == LONG) return;
694 WriteW ((fptr->l >> FP_V_F2) & 0177777, exta | ((VA + 4) & 0177777));
695 WriteW ((fptr->l >> FP_V_F3) & 0177777, exta | ((VA + 6) & 0177777));
696 return;
697 }
698
699 /* FIS instructions */
700
701 t_stat fis11 (int32 IR)
702 {
703 int32 reg, exta;
704 fpac_t fac, fsrc;
705
706 reg = IR & 07; /* isolate reg */
707 if (reg == 7) exta = isenable; /* choose I,D */
708 else exta = dsenable;
709 if (IR & 000740) { /* defined? */
710 if (CPUT (CPUT_03)) ReadW (exta | R[reg]); /* 11/03 reads word */
711 ABORT (TRAP_ILL);
712 }
713 FEC = 0; /* no errors */
714 FPS = FPS_IU|FPS_IV; /* trap ovf,unf */
715
716 fsrc.h = (ReadW (exta | R[reg]) << FP_V_F0) |
717 (ReadW (exta | ((R[reg] + 2) & 0177777)) << FP_V_F1);
718 fsrc.l = 0;
719 fac.h = (ReadW (exta | ((R[reg] + 4) & 0177777)) << FP_V_F0) |
720 (ReadW (exta | ((R[reg] + 6) & 0177777)) << FP_V_F1);
721 fac.l = 0;
722 if (GET_SIGN (fsrc.h) && (GET_EXP (fsrc.h) == 0)) /* clean 0's */
723 fsrc.h = fsrc.l = 0;
724 if (GET_SIGN (fac.h) && (GET_EXP (fac.l) == 0))
725 fac.h = fac.l = 0;
726
727 N = Z = V = C = 0; /* clear cc's */
728 switch ((IR >> 3) & 3) { /* case IR<5:3> */
729
730 case 0: /* FAD */
731 addfp11 (&fac, &fsrc);
732 break;
733
734 case 1: /* FSUB */
735 if (fsrc.h != 0) fsrc.h = fsrc.h ^ FP_SIGN; /* invert sign */
736 addfp11 (&fac, &fsrc);
737 break;
738
739 case 2: /* FMUL */
740 mulfp11 (&fac, &fsrc);
741 break;
742
743 case 3: /* FDIV */
744 if (fsrc.h == 0) { /* div by 0? */
745 V = N = C = 1; /* set cc's */
746 setTRAP (TRAP_FPE); /* set trap */
747 return SCPE_OK;
748 }
749 else divfp11 (&fac, &fsrc);
750 break;
751 }
752
753 if (FEC == 0) { /* no err? */
754 WriteW ((fac.h >> FP_V_F0) & 0177777, exta | ((R[reg] + 4) & 0177777));
755 WriteW ((fac.h >> FP_V_F1) & 0177777, exta | ((R[reg] + 6) & 0177777));
756 R[reg] = (R[reg] + 4) & 0177777; /* pop stack */
757 N = (GET_SIGN (fac.h) != 0); /* set N,Z */
758 Z = (fac.h == 0);
759 }
760 else if (FEC == FEC_OVFLO) V = 1; /* ovf? trap set */
761 else if (FEC == FEC_UNFLO) V = N = 1; /* unf? trap set */
762 else return SCPE_IERR; /* what??? */
763 return SCPE_OK;
764 }
765
766 /* Floating point add
767
768 Inputs:
769 facp = pointer to src1 (output)
770 fsrcp = pointer to src2
771 Outputs:
772 ovflo = overflow variable
773 */
774
775 int32 addfp11 (fpac_t *facp, fpac_t *fsrcp)
776 {
777 int32 facexp, fsrcexp, ediff;
778 fpac_t facfrac, fsrcfrac;
779
780 if (F_LT_AP (facp, fsrcp)) { /* if !fac! < !fsrc! */
781 facfrac = *facp;
782 *facp = *fsrcp; /* swap operands */
783 *fsrcp = facfrac;
784 }
785 facexp = GET_EXP (facp->h); /* get exponents */
786 fsrcexp = GET_EXP (fsrcp->h);
787 if (facexp == 0) { /* fac = 0? */
788 *facp = fsrcexp? *fsrcp: zero_fac; /* result fsrc or 0 */
789 return 0;
790 }
791 if (fsrcexp == 0) return 0; /* fsrc = 0? no op */
792 ediff = facexp - fsrcexp; /* exponent diff */
793 if (ediff >= 60) return 0; /* too big? no op */
794 F_GET_FRAC_P (facp, facfrac); /* get fractions */
795 F_GET_FRAC_P (fsrcp, fsrcfrac);
796 F_LSH_GUARD (facfrac); /* guard fractions */
797 F_LSH_GUARD (fsrcfrac);
798 if (GET_SIGN (facp->h) != GET_SIGN (fsrcp->h)) { /* signs different? */
799 if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac); } /* sub, shf fsrc */
800 F_SUB (fsrcfrac, facfrac, facfrac); /* sub fsrc from fac */
801 if ((facfrac.h | facfrac.l) == 0) { /* result zero? */
802 *facp = zero_fac; /* no overflow */
803 return 0;
804 }
805 if (ediff <= 1) { /* big normalize? */
806 if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
807 F_LSH_K (facfrac, 24, facfrac);
808 facexp = facexp - 24;
809 }
810 if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
811 F_LSH_K (facfrac, 12, facfrac);
812 facexp = facexp - 12;
813 }
814 if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
815 F_LSH_K (facfrac, 6, facfrac);
816 facexp = facexp - 6;
817 }
818 }
819 while (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
820 F_LSH_1 (facfrac);
821 facexp = facexp - 1;
822 }
823 }
824 else {
825 if (ediff) {
826 F_RSH_V (fsrcfrac, ediff, fsrcfrac); /* add, shf fsrc */
827 }
828 F_ADD (fsrcfrac, facfrac, facfrac); /* add fsrc to fac */
829 if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD + 1)) {
830 F_RSH_1 (facfrac); /* carry out, shift */
831 facexp = facexp + 1;
832 }
833 }
834 return round_and_pack (facp, facexp, &facfrac, 1);
835 }
836
837 /* Floating point multiply
838
839 Inputs:
840 facp = pointer to src1 (output)
841 fsrcp = pointer to src2
842 Outputs:
843 ovflo = overflow indicator
844 */
845
846 int32 mulfp11 (fpac_t *facp, fpac_t *fsrcp)
847 {
848 int32 facexp, fsrcexp;
849 fpac_t facfrac, fsrcfrac;
850
851 facexp = GET_EXP (facp->h); /* get exponents */
852 fsrcexp = GET_EXP (fsrcp->h);
853 if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */
854 *facp = zero_fac;
855 return 0;
856 }
857 F_GET_FRAC_P (facp, facfrac); /* get fractions */
858 F_GET_FRAC_P (fsrcp, fsrcfrac);
859 facexp = facexp + fsrcexp - FP_BIAS; /* calculate exp */
860 facp->h = facp->h ^ fsrcp->h; /* calculate sign */
861 frac_mulfp11 (&facfrac, &fsrcfrac); /* multiply fracs */
862
863 /* Multiplying two numbers in the range [.5,1) produces a result in the
864 range [.25,1). Therefore, at most one bit of normalization is required
865 to bring the result back to the range [.5,1).
866 */
867
868 if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
869 F_LSH_1 (facfrac);
870 facexp = facexp - 1;
871 }
872 return round_and_pack (facp, facexp, &facfrac, 1);
873 }
874
875 /* Floating point mod
876
877 Inputs:
878 facp = pointer to src1 (integer result)
879 fsrcp = pointer to src2
880 fracp = pointer to fractional result
881 Outputs:
882 ovflo = overflow indicator
883
884 See notes on multiply for initial operation
885 */
886
887 int32 modfp11 (fpac_t *facp, fpac_t *fsrcp, fpac_t *fracp)
888 {
889 int32 facexp, fsrcexp;
890 fpac_t facfrac, fsrcfrac, fmask;
891
892 facexp = GET_EXP (facp->h); /* get exponents */
893 fsrcexp = GET_EXP (fsrcp->h);
894 if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */
895 *fracp = zero_fac;
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 fracp->h = 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
915 /* There are three major cases of MODf:
916
917 1. Exp <= FP_BIAS (all fraction). Return 0 as integer, product as
918 fraction. Underflow can occur.
919 2. Exp > FP_BIAS + #fraction bits (all integer). Return product as
920 integer, 0 as fraction. Overflow can occur.
921 3. FP_BIAS < exp <= FP_BIAS + #fraction bits. Separate integer and
922 fraction and return both. Neither overflow nor underflow can occur.
923 */
924
925 if (facexp <= FP_BIAS) { /* case 1 */
926 *facp = zero_fac;
927 return round_and_pack (fracp, facexp, &facfrac, 1);
928 }
929 if (facexp > ((FPS & FPS_D)? FP_BIAS + 56: FP_BIAS + 24)) {
930 *fracp = zero_fac; /* case 2 */
931 return round_and_pack (facp, facexp, &facfrac, 0);
932 }
933 F_RSH_V (fmask_fac, facexp - FP_BIAS, fmask); /* shift mask */
934 fsrcfrac.l = facfrac.l & fmask.l; /* extract fraction */
935 fsrcfrac.h = facfrac.h & fmask.h;
936 if ((fsrcfrac.h | fsrcfrac.l) == 0) *fracp = zero_fac;
937 else {
938 F_LSH_V (fsrcfrac, facexp - FP_BIAS, fsrcfrac);
939 fsrcexp = FP_BIAS;
940 if ((fsrcfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
941 F_LSH_K (fsrcfrac, 24, fsrcfrac);
942 fsrcexp = fsrcexp - 24;
943 }
944 if ((fsrcfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
945 F_LSH_K (fsrcfrac, 12, fsrcfrac);
946 fsrcexp = fsrcexp - 12;
947 }
948 if ((fsrcfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
949 F_LSH_K (fsrcfrac, 6, fsrcfrac);
950 fsrcexp = fsrcexp - 6;
951 }
952 while (GET_BIT (fsrcfrac.h, FP_V_HB + FP_GUARD) == 0) {
953 F_LSH_1 (fsrcfrac);
954 fsrcexp = fsrcexp - 1;
955 }
956 round_and_pack (fracp, fsrcexp, &fsrcfrac, 1);
957 }
958 facfrac.l = facfrac.l & ~fmask.l;
959 facfrac.h = facfrac.h & ~fmask.h;
960 return round_and_pack (facp, facexp, &facfrac, 0);
961 }
962
963 /* Fraction multiply
964
965 Inputs:
966 f1p = pointer to multiplier (output)
967 f2p = pointer to multiplicand fraction
968
969 Note: the inputs are unguarded; the output is guarded.
970
971 This routine performs a classic shift-and-add multiply. The low
972 order bit of the multiplier is tested; if 1, the multiplicand is
973 added into the high part of the double precision result. The
974 result and the multiplier are both shifted right 1.
975
976 For the 24b x 24b case, this routine develops 48b of result.
977 For the 56b x 56b case, this routine only develops the top 64b
978 of the the result. Because the inputs are normalized fractions,
979 the interesting part of the result is the high 56+guard bits.
980 Everything shifted off to the right, beyond 64b, plays no part
981 in rounding or the result.
982
983 There are many possible optimizations in this routine: scanning
984 for groups of zeroes, particularly in the 56b x 56b case; using
985 "extended multiply" capability if available in the hardware.
986 */
987
988 void frac_mulfp11 (fpac_t *f1p, fpac_t *f2p)
989 {
990 fpac_t result, mpy, mpc;
991 int32 i;
992
993 result = zero_fac; /* clear result */
994 mpy = *f1p; /* get operands */
995 mpc = *f2p;
996 F_LSH_GUARD (mpc); /* guard multipicand */
997 if ((mpy.l | mpc.l) == 0) { /* 24b x 24b? */
998 for (i = 0; i < 24; i++) {
999 if (mpy.h & 1) result.h = result.h + mpc.h;
1000 F_RSH_1 (result);
1001 mpy.h = mpy.h >> 1;
1002 }
1003 }
1004 else {
1005 if (mpy.l != 0) { /* 24b x 56b? */
1006 for (i = 0; i < 32; i++) {
1007 if (mpy.l & 1) {
1008 F_ADD (mpc, result, result);
1009 }
1010 F_RSH_1 (result);
1011 mpy.l = mpy.l >> 1;
1012 }
1013 }
1014 for (i = 0; i < 24; i++) {
1015 if (mpy.h & 1) {
1016 F_ADD (mpc, result, result);
1017 }
1018 F_RSH_1 (result);
1019 mpy.h = mpy.h >> 1;
1020 }
1021 }
1022 *f1p = result;
1023 return;
1024 }
1025
1026 /* Floating point divide
1027
1028 Inputs:
1029 facp = pointer to dividend (output)
1030 fsrcp = pointer to divisor
1031 Outputs:
1032 ovflo = overflow indicator
1033
1034 Source operand must be checked for zero by caller!
1035 */
1036
1037 int32 divfp11 (fpac_t *facp, fpac_t *fsrcp)
1038 {
1039 int32 facexp, fsrcexp, i, count, qd;
1040 fpac_t facfrac, fsrcfrac, quo;
1041
1042 fsrcexp = GET_EXP (fsrcp->h); /* get divisor exp */
1043 facexp = GET_EXP (facp->h); /* get dividend exp */
1044 if (facexp == 0) { /* test for zero */
1045 *facp = zero_fac; /* result zero */
1046 return 0;
1047 }
1048 F_GET_FRAC_P (facp, facfrac); /* get fractions */
1049 F_GET_FRAC_P (fsrcp, fsrcfrac);
1050 F_LSH_GUARD (facfrac); /* guard fractions */
1051 F_LSH_GUARD (fsrcfrac);
1052 facexp = facexp - fsrcexp + FP_BIAS + 1; /* calculate exp */
1053 facp->h = facp->h ^ fsrcp->h; /* calculate sign */
1054 qd = FPS & FPS_D;
1055 count = FP_V_HB + FP_GUARD + (qd? 33: 1); /* count = 56b/24b */
1056
1057 quo = zero_fac;
1058 for (i = count; (i > 0) && ((facfrac.h | facfrac.l) != 0); i--) {
1059 F_LSH_1 (quo); /* shift quotient */
1060 if (!F_LT (facfrac, fsrcfrac)) { /* divd >= divr? */
1061 F_SUB (fsrcfrac, facfrac, facfrac); /* divd - divr */
1062 if (qd) quo.l = quo.l | 1; /* double or single? */
1063 else quo.h = quo.h | 1;
1064 }
1065 F_LSH_1 (facfrac); /* shift divd */
1066 }
1067 if (i > 0) { /* early exit? */
1068 F_LSH_V (quo, i, quo);
1069 }
1070
1071 /* Dividing two numbers in the range [.5,1) produces a result in the
1072 range [.5,2). Therefore, at most one bit of normalization is required
1073 to bring the result back to the range [.5,1). The choice of counts
1074 and quotient bit positions makes this work correctly.
1075 */
1076
1077 if (GET_BIT (quo.h, FP_V_HB + FP_GUARD) == 0) {
1078 F_LSH_1 (quo);
1079 facexp = facexp - 1;
1080 }
1081 return round_and_pack (facp, facexp, &quo, 1);
1082 }
1083
1084 /* Update floating condition codes
1085 Note that FC is only set by STCfi via the integer condition codes
1086
1087 Inputs:
1088 oldst = current status
1089 result = high result
1090 newV = new V
1091 Outputs:
1092 newst = new status
1093 */
1094
1095 int32 setfcc (int32 oldst, int32 result, int32 newV)
1096 {
1097 oldst = (oldst & ~FPS_CC) | newV;
1098 if (GET_SIGN (result)) oldst = oldst | FPS_N;
1099 if (GET_EXP (result) == 0) oldst = oldst | FPS_Z;
1100 return oldst;
1101 }
1102
1103 /* Round (in place) floating point number to f_floating
1104
1105 Inputs:
1106 fptr = pointer to floating number
1107 Outputs:
1108 ovflow = overflow
1109 */
1110
1111 int32 roundfp11 (fpac_t *fptr)
1112 {
1113 fpac_t outf;
1114
1115 outf = *fptr; /* get argument */
1116 F_ADD (fround_fac, outf, outf); /* round */
1117 if (GET_SIGN (outf.h ^ fptr->h)) { /* flipped sign? */
1118 outf.h = (outf.h ^ FP_SIGN) & 0xFFFFFFFF; /* restore sign */
1119 if (fpnotrap (FEC_OVFLO)) *fptr = zero_fac; /* if no int, clear */
1120 else *fptr = outf; /* return rounded */
1121 return FPS_V; /* overflow */
1122 }
1123 *fptr = outf; /* round was ok */
1124 return 0; /* no overflow */
1125 }
1126
1127 /* Round result of calculation, test overflow, pack
1128
1129 Input:
1130 facp = pointer to result, sign in place
1131 exp = result exponent, right justified
1132 fracp = pointer to result fraction, right justified with
1133 guard bits
1134 r = round (1) or truncate (0)
1135 Outputs:
1136 ovflo = overflow indicator
1137 */
1138
1139 int32 round_and_pack (fpac_t *facp, int32 exp, fpac_t *fracp, int r)
1140 {
1141 fpac_t frac;
1142
1143 frac = *fracp; /* get fraction */
1144 if (r && ((FPS & FPS_T) == 0)) {
1145 if (FPS & FPS_D) {
1146 F_ADD (dround_guard_fac, frac, frac);
1147 }
1148 else {
1149 F_ADD (fround_guard_fac, frac, frac);
1150 }
1151 if (GET_BIT (frac.h, FP_V_HB + FP_GUARD + 1)) {
1152 F_RSH_1 (frac);
1153 exp = exp + 1;
1154 }
1155 }
1156 F_RSH_GUARD (frac);
1157 facp->l = frac.l & FP_FRACL;
1158 facp->h = (facp->h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) |
1159 (frac.h & FP_FRACH);
1160 if (exp > 0377) {
1161 if (fpnotrap (FEC_OVFLO)) *facp = zero_fac;
1162 return FPS_V;
1163 }
1164 if ((exp <= 0) && (fpnotrap (FEC_UNFLO))) *facp = zero_fac;
1165 return 0;
1166 }
1167
1168 /* Process floating point exception
1169
1170 Inputs:
1171 code = exception code
1172 Outputs:
1173 int = FALSE if interrupt enabled, TRUE if disabled
1174 */
1175
1176 int32 fpnotrap (int32 code)
1177 {
1178 static const int32 test_code[] = { 0, 0, 0, FPS_IC, FPS_IV, FPS_IU, FPS_IUV };
1179
1180 if ((code >= FEC_ICVT) && (code <= FEC_UNDFV) &&
1181 ((FPS & test_code[code >> 1]) == 0)) return TRUE;
1182 FPS = FPS | FPS_ER;
1183 FEC = code;
1184 FEA = (backup_PC - 2) & 0177777;
1185 if ((FPS & FPS_ID) == 0) setTRAP (TRAP_FPE);
1186 return FALSE;
1187 }