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