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