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