1 /* vax_octa.c - VAX octaword and h_floating instructions
3 Copyright (c) 2004-2008, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 This module simulates the VAX h_floating instruction set.
28 28-May-08 RMS Inlined physical memory routines
29 10-May-06 RMS Fixed bug in reported VA on faulting cross-page write
30 03-May-06 RMS Fixed MNEGH to test negated sign, clear C
31 Fixed carry propagation in qp_inc, qp_neg, qp_add
32 Fixed pack routines to test for zero via fraction
33 Fixed ACBH to set cc's on result
34 Fixed POLYH to set R3 correctly
35 Fixed POLYH to not exit prematurely if arg = 0
36 Fixed POLYH to mask mul reslt to 127b
37 Fixed fp add routine to test for zero via fraction
38 to support "denormal" argument from POLYH
39 Fixed EMODH to concatenate 15b of 16b extension
40 (all reported by Tim Stark)
41 15-Jul-04 RMS Cloned from 32b VAX floating point implementation
46 #if defined (FULL_VAX)
52 extern jmp_buf save_env
;
54 extern int32
Test (uint32 va
, int32 acc
, int32
*status
);
56 #define WORDSWAP(x) ((((x) & WMASK) << 16) | (((x) >> 16) & WMASK))
71 #define UH_NM_H 0x80000000 /* normalized */
72 #define UH_FRND 0x00000080 /* F round */
73 #define UH_DRND 0x00000080 /* D round */
74 #define UH_GRND 0x00000400 /* G round */
75 #define UH_HRND 0x00004000 /* H round */
78 int32
op_tsth (int32 val
);
79 int32
op_cmph (int32
*hf1
, int32
*hf2
);
80 int32
op_cvtih (int32 val
, int32
*hf
);
81 int32
op_cvthi (int32
*hf
, int32
*flg
, int32 opc
);
82 int32
op_cvtfdh (int32 vl
, int32 vh
, int32
*hf
);
83 int32
op_cvtgh (int32 vl
, int32 vh
, int32
*hf
);
84 int32
op_cvthfd (int32
*hf
, int32
*vh
);
85 int32
op_cvthg (int32
*hf
, int32
*vh
);
86 int32
op_addh (int32
*opnd
, int32
*hf
, t_bool sub
);
87 int32
op_mulh (int32
*opnd
, int32
*hf
);
88 int32
op_divh (int32
*opnd
, int32
*hf
);
89 int32
op_emodh (int32
*opnd
, int32
*hflt
, int32
*intgr
, int32
*flg
);
90 void op_polyh (int32
*opnd
, int32 acc
);
91 void h_write_b (int32 spec
, int32 va
, int32 val
, int32 acc
);
92 void h_write_w (int32 spec
, int32 va
, int32 val
, int32 acc
);
93 void h_write_l (int32 spec
, int32 va
, int32 val
, int32 acc
);
94 void h_write_q (int32 spec
, int32 va
, int32 vl
, int32 vh
, int32 acc
);
95 void h_write_o (int32 spec
, int32 va
, int32
*val
, int32 acc
);
96 void vax_hadd (UFPH
*a
, UFPH
*b
);
97 void vax_hmul (UFPH
*a
, UFPH
*b
, uint32 mlo
);
98 void vax_hmod (UFPH
*a
, int32
*intgr
, int32
*flg
);
99 void vax_hdiv (UFPH
*a
, UFPH
*b
);
100 uint32
qp_add (UQP
*a
, UQP
*b
);
101 uint32
qp_sub (UQP
*a
, UQP
*b
);
102 void qp_inc (UQP
*a
);
103 void qp_lsh (UQP
*a
, uint32 sc
);
104 void qp_rsh (UQP
*a
, uint32 sc
);
105 void qp_rsh_s (UQP
*a
, uint32 sc
, uint32 neg
);
106 void qp_neg (UQP
*a
);
107 int32
qp_cmp (UQP
*a
, UQP
*b
);
108 void h_unpackfd (int32 hi
, int32 lo
, UFPH
*a
);
109 void h_unpackg (int32 hi
, int32 lo
, UFPH
*a
);
110 void h_unpackh (int32
*hflt
, UFPH
*a
);
111 void h_normh (UFPH
*a
);
112 int32
h_rpackfd (UFPH
*a
, int32
*rl
);
113 int32
h_rpackg (UFPH
*a
, int32
*rl
);
114 int32
h_rpackh (UFPH
*a
, int32
*hflt
);
116 static int32 z_octa
[4] = { 0, 0, 0, 0 };
118 /* Octaword instructions */
120 int32
op_octa (int32
*opnd
, int32 cc
, int32 opc
, int32 acc
, int32 spec
, int32 va
)
122 int32 r
, rh
, temp
, flg
;
133 Write (SP
- 4, opnd
[0], L_LONG
, WA
); /* push operand */
134 SP
= SP
- 4; /* decr stack ptr */
135 CC_IIZP_L (opnd
[0]); /* set cc's */
142 spec = last specifier
143 va = address if last specifier is memory
147 h_write_l (spec
, va
, opnd
[0], acc
); /* write operand */
148 CC_IIZP_L (opnd
[0]); /* set cc's */
154 spec = last specifier
155 va = address if last specifier is memory
159 h_write_o (spec
, va
, z_octa
, acc
); /* write 0's */
160 CC_ZZ1P
; /* set cc's */
169 r
= op_tsth (opnd
[0]); /* test for 0 */
170 CC_IIZZ_FP (r
); /* set cc's */
177 spec = last specifier
178 va = address if last specifier is memory
182 h_write_o (spec
, va
, opnd
, acc
); /* write src */
183 CC_IIZP_O (opnd
[0], opnd
[1], opnd
[2], opnd
[3]); /* set cc's */
187 if (r
= op_tsth (opnd
[0])) { /* test for 0 */
188 h_write_o (spec
, va
, opnd
, acc
); /* nz, write result */
189 CC_IIZP_FP (r
); /* set cc's */
192 h_write_o (spec
, va
, z_octa
, acc
); /* write 0 */
193 cc
= (cc
& CC_C
) | CC_Z
; /* set cc's */
198 if (r
= op_tsth (opnd
[0])) { /* test for 0 */
199 opnd
[0] = opnd
[0] ^ FPSIGN
; /* nz, invert sign */
200 h_write_o (spec
, va
, opnd
, acc
); /* write result */
201 CC_IIZZ_FP (opnd
[0]); /* set cc's */
204 h_write_o (spec
, va
, z_octa
, acc
); /* write 0 */
205 cc
= CC_Z
; /* set cc's */
216 cc
= op_cmph (opnd
+ 0, opnd
+ 4); /* set cc's */
219 /* CVTBH, CVTWH, CVTLH
223 spec = last specifier
224 va = address if last specifier is memory
228 r
= op_cvtih (SXTB (opnd
[0]), r_octa
); /* convert */
229 h_write_o (spec
, va
, r_octa
, acc
); /* write reslt */
230 CC_IIZZ_FP (r
); /* set cc's */
234 r
= op_cvtih (SXTW (opnd
[0]), r_octa
); /* convert */
235 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
236 CC_IIZZ_FP (r
); /* set cc's */
240 r
= op_cvtih (opnd
[0], r_octa
); /* convert */
241 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
242 CC_IIZZ_FP (r
); /* set cc's */
245 /* CVTHB, CVTHW, CVTHL, CVTRHL
249 spec = last specifier
250 va = address if last specifier is memory
254 r
= op_cvthi (opnd
, &flg
, opc
) & BMASK
; /* convert */
255 h_write_b (spec
, va
, r
, acc
); /* write result */
256 CC_IIZZ_B (r
); /* set cc's */
257 if (flg
) { V_INTOV
; }
261 r
= op_cvthi (opnd
, &flg
, opc
) & WMASK
; /* convert */
262 h_write_w (spec
, va
, r
, acc
); /* write result */
263 CC_IIZZ_W (r
); /* set cc's */
264 if (flg
) { V_INTOV
; }
267 case CVTHL
: case CVTRHL
:
268 r
= op_cvthi (opnd
, &flg
, opc
) & LMASK
; /* convert */
269 h_write_l (spec
, va
, r
, acc
); /* write result */
270 CC_IIZZ_L (r
); /* set cc's */
271 if (flg
) { V_INTOV
; }
278 spec = last specifier
279 va = address if last specifier is memory
283 r
= op_cvtfdh (opnd
[0], 0, r_octa
); /* convert */
284 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
285 CC_IIZZ_FP (r
); /* set cc's */
292 spec = last specifier
293 va = address if last specifier is memory
297 r
= op_cvtfdh (opnd
[0], opnd
[1], r_octa
); /* convert */
298 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
299 CC_IIZZ_FP (r
); /* set cc's */
303 r
= op_cvtgh (opnd
[0], opnd
[1], r_octa
); /* convert */
304 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
305 CC_IIZZ_FP (r
); /* set cc's */
308 /* CVTHF, CVTHD, CVTHG
312 spec = last specifier
313 va = address if last specifier is memory
317 r
= op_cvthfd (opnd
, NULL
); /* convert */
318 h_write_l (spec
, va
, r
, acc
); /* write result */
319 CC_IIZZ_FP (r
); /* set cc's */
323 r
= op_cvthfd (opnd
, &rh
); /* convert */
324 h_write_q (spec
, va
, r
, rh
, acc
); /* write result */
325 CC_IIZZ_FP (r
); /* set cc's */
329 r
= op_cvthg (opnd
, &rh
); /* convert */
330 h_write_q (spec
, va
, r
, rh
, acc
); /* write result */
331 CC_IIZZ_FP (r
); /* set cc's */
334 /* ADDH2, SUBH2, MULH2, DIVH2
338 spec = last specifier
339 va = address if last specifier is memory
341 ADDH3, SUBH3, MULH3, DIVH3
346 spec = last specifier
347 va = address if last specifier is memory
351 case ADDH2
: case ADDH3
:
352 r
= op_addh (opnd
, r_octa
, FALSE
); /* add */
353 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
354 CC_IIZZ_FP (r
); /* set cc's */
357 case SUBH2
: case SUBH3
:
358 r
= op_addh (opnd
, r_octa
, TRUE
); /* subtract */
359 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
360 CC_IIZZ_FP (r
); /* set cc's */
363 case MULH2
: case MULH3
:
364 r
= op_mulh (opnd
, r_octa
); /* multiply */
365 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
366 CC_IIZZ_FP (r
); /* set cc's */
369 case DIVH2
: case DIVH3
:
370 r
= op_divh (opnd
, r_octa
); /* divide */
371 h_write_o (spec
, va
, r_octa
, acc
); /* write result */
372 CC_IIZZ_FP (r
); /* set cc's */
379 opnd[8:11] = index.mh
380 spec = last specifier
382 brdest = branch destination
386 r
= op_addh (opnd
+ 4, r_octa
, FALSE
); /* add + index */
387 CC_IIZP_FP (r
); /* set cc's */
388 temp
= op_cmph (r_octa
, opnd
); /* result : limit */
389 h_write_o (spec
, va
, r_octa
, acc
); /* write 2nd */
390 if ((temp
& CC_Z
) || ((opnd
[4] & FPSIGN
)? /* test br cond */
391 !(temp
& CC_N
): (temp
& CC_N
)))
392 cc
= cc
| LSIGN
; /* hack for branch */
403 op_polyh (opnd
, acc
); /* eval polynomial */
404 CC_IIZZ_FP (R
[0]); /* set cc's */
409 opnd[0:3] = multiplier
411 opnd[5:8] = multiplicand
412 opnd[9:10] = integer destination (int.wl)
413 opnd[11:12] = floating destination (flt.wh)
414 spec = last specifier
415 va = address if last specifier is memory
419 r
= op_emodh (opnd
, r_octa
, &temp
, &flg
); /* extended mod */
420 if (opnd
[11] < 0) { /* 2nd memory? */
421 Read (opnd
[12], L_BYTE
, WA
); /* prove write */
422 Read ((opnd
[12] + 15) & LMASK
, L_BYTE
, WA
);
424 if (opnd
[9] >= 0) R
[opnd
[9]] = temp
; /* store 1st */
425 else Write (opnd
[10], temp
, L_LONG
, WA
);
426 h_write_o (spec
, va
, r_octa
, acc
); /* write 2nd */
427 CC_IIZZ_FP (r
); /* set cc's */
428 if (flg
) { V_INTOV
; } /* int ovflo? */
440 Note that only the high 32b is processed.
441 If the high 32b is not zero, the rest of the fraction is unchanged. */
443 int32
op_tsth (int32 val
)
445 if (val
& H_EXP
) return val
; /* non-zero? */
446 if (val
& FPSIGN
) RSVD_OPND_FAULT
; /* reserved? */
447 return 0; /* clean 0 */
450 /* Compare h_floating */
452 int32
op_cmph (int32
*hf1
, int32
*hf2
)
457 h_unpackh (hf1
, &a
); /* unpack op1 */
458 h_unpackh (hf2
, &b
); /* unpack op2 */
459 if (a
.sign
!= b
.sign
) return (a
.sign
? CC_N
: 0); /* opp signs? */
460 if (a
.exp
!= b
.exp
) r
= a
.exp
- b
.exp
; /* cmp exp */
461 else r
= qp_cmp (&a
.frac
, &b
.frac
); /* if =, cmp frac */
462 if (r
< 0) return (a
.sign
? 0: CC_N
); /* !=, maybe set N */
463 if (r
> 0) return (a
.sign
? CC_N
: 0);
464 return CC_Z
; /* =, set Z */
467 /* Integer to h_floating convert */
469 int32
op_cvtih (int32 val
, int32
*hf
)
473 if (val
== 0) { /* zero? */
474 hf
[0] = hf
[1] = hf
[2] = hf
[3] = 0; /* result is 0 */
477 if (val
< 0) { /* negative? */
478 a
.sign
= FPSIGN
; /* sign = - */
481 else a
.sign
= 0; /* else sign = + */
482 a
.exp
= 32 + H_BIAS
; /* initial exp */
483 a
.frac
.f3
= val
& LMASK
; /* fraction hi */
484 a
.frac
.f2
= a
.frac
.f1
= a
.frac
.f0
= 0;
485 h_normh (&a
); /* normalize */
486 return h_rpackh (&a
, hf
); /* round and pack */
489 /* H_floating to integer convert */
491 int32
op_cvthi (int32
*hf
, int32
*flg
, int32 opc
)
494 int32 lnt
= opc
& 03;
496 static uint32 maxv
[4] = { 0x7F, 0x7FFF, 0x7FFFFFFF, 0x7FFFFFFF };
498 *flg
= 0; /* clear ovflo */
499 h_unpackh (hf
, &a
); /* unpack */
500 ubexp
= a
.exp
- H_BIAS
; /* unbiased exp */
501 if ((a
.exp
== 0) || (ubexp
< 0)) return 0; /* true zero or frac? */
502 if (ubexp
<= UH_V_NM
) { /* exp in range? */
503 qp_rsh (&a
.frac
, UH_V_NM
- ubexp
); /* leave rnd bit */
504 if (lnt
== 03) qp_inc (&a
.frac
); /* if CVTR, round */
505 qp_rsh (&a
.frac
, 1); /* now justified */
506 if (a
.frac
.f3
|| a
.frac
.f2
|| a
.frac
.f1
||
507 (a
.frac
.f0
> (maxv
[lnt
] + (a
.sign
? 1: 0)))) *flg
= CC_V
;
510 *flg
= CC_V
; /* always ovflo */
511 if (ubexp
> (UH_V_NM
+ 32)) return 0; /* in ext range? */
512 qp_lsh (&a
.frac
, ubexp
- UH_V_NM
- 1); /* no rnd bit */
514 return (a
.sign
? NEG (a
.frac
.f0
): a
.frac
.f0
); /* return lo frac */
517 /* Floating to floating convert - F/D to H, G to H, H to F/D, H to G */
519 int32
op_cvtfdh (int32 vl
, int32 vh
, int32
*hflt
)
523 h_unpackfd (vl
, vh
, &a
); /* unpack f/d */
524 a
.exp
= a
.exp
- FD_BIAS
+ H_BIAS
; /* if nz, adjust exp */
525 return h_rpackh (&a
, hflt
); /* round and pack */
528 int32
op_cvtgh (int32 vl
, int32 vh
, int32
*hflt
)
532 h_unpackg (vl
, vh
, &a
); /* unpack g */
533 a
.exp
= a
.exp
- G_BIAS
+ H_BIAS
; /* if nz, adjust exp */
534 return h_rpackh (&a
, hflt
); /* round and pack */
537 int32
op_cvthfd (int32
*hflt
, int32
*rh
)
541 h_unpackh (hflt
, &a
); /* unpack h */
542 a
.exp
= a
.exp
- H_BIAS
+ FD_BIAS
; /* if nz, adjust exp */
543 return h_rpackfd (&a
, rh
); /* round and pack */
546 int32
op_cvthg (int32
*hflt
, int32
*rh
)
550 h_unpackh (hflt
, &a
); /* unpack h */
551 a
.exp
= a
.exp
- H_BIAS
+ G_BIAS
; /* if nz, adjust exp */
552 return h_rpackg (&a
, rh
); /* round and pack */
555 /* Floating add and subtract */
557 int32
op_addh (int32
*opnd
, int32
*hflt
, t_bool sub
)
561 h_unpackh (&opnd
[0], &a
); /* unpack s1, s2 */
562 h_unpackh (&opnd
[4], &b
);
563 if (sub
) a
.sign
= a
.sign
^ FPSIGN
; /* sub? -s1 */
564 vax_hadd (&a
, &b
); /* do add */
565 return h_rpackh (&a
, hflt
); /* round and pack */
568 /* Floating multiply */
570 int32
op_mulh (int32
*opnd
, int32
*hflt
)
574 h_unpackh (&opnd
[0], &a
); /* unpack s1, s2 */
575 h_unpackh (&opnd
[4], &b
);
576 vax_hmul (&a
, &b
, 0); /* do multiply */
577 return h_rpackh (&a
, hflt
); /* round and pack */
580 /* Floating divide */
582 int32
op_divh (int32
*opnd
, int32
*hflt
)
586 h_unpackh (&opnd
[0], &a
); /* unpack s1, s2 */
587 h_unpackh (&opnd
[4], &b
);
588 vax_hdiv (&a
, &b
); /* do divide */
589 return h_rpackh (&b
, hflt
); /* round and pack */
592 /* Polynomial evaluation
594 The most mis-implemented instruction in the VAX (probably here too).
595 POLY requires a precise combination of masking versus normalizing
596 to achieve the desired answer. In particular, both the multiply
597 and add steps are masked prior to normalization. In addition,
598 negative small fractions must not be treated as 0 during denorm. */
600 void op_polyh (int32
*opnd
, int32 acc
)
605 int32 i
, wd
[4], res
[4];
607 if (deg
> 31) RSVD_OPND_FAULT
; /* deg > 31? fault */
608 h_unpackh (&opnd
[0], &a
); /* unpack arg */
609 wd
[0] = Read (ptr
, L_LONG
, RD
); /* get C0 */
610 wd
[1] = Read (ptr
+ 4, L_LONG
, RD
);
611 wd
[2] = Read (ptr
+ 8, L_LONG
, RD
);
612 wd
[3] = Read (ptr
+ 12, L_LONG
, RD
);
613 ptr
= ptr
+ 16; /* adv ptr */
614 h_unpackh (wd
, &r
); /* unpack C0 */
615 h_rpackh (&r
, res
); /* first result */
616 for (i
= 0; i
< deg
; i
++) { /* loop */
617 h_unpackh (res
, &r
); /* unpack result */
618 vax_hmul (&r
, &a
, 1); /* r = r * arg */
619 wd
[0] = Read (ptr
, L_LONG
, RD
); /* get Cn */
620 wd
[1] = Read (ptr
+ 4, L_LONG
, RD
);
621 wd
[2] = Read (ptr
+ 8, L_LONG
, RD
);
622 wd
[3] = Read (ptr
+ 12, L_LONG
, RD
);
624 h_unpackh (wd
, &c
); /* unpack Cnext */
625 vax_hadd (&r
, &c
); /* r = r + Cnext */
626 h_rpackh (&r
, res
); /* round and pack */
628 R
[0] = res
[0]; /* result */
637 /* Extended modularize
639 EMOD presents two sets of complications. First, it requires an extended
640 fraction multiply, with precise (and unusual) truncation conditions.
641 Second, it has two write operands, a dubious distinction it shares
644 int32
op_emodh (int32
*opnd
, int32
*hflt
, int32
*intgr
, int32
*flg
)
648 h_unpackh (&opnd
[0], &a
); /* unpack operands */
649 h_unpackh (&opnd
[5], &b
);
650 a
.frac
.f0
= a
.frac
.f0
| (opnd
[4] >> 1); /* extend src1 */
651 vax_hmul (&a
, &b
, 0); /* multiply */
652 vax_hmod (&a
, intgr
, flg
); /* sep int & frac */
653 return h_rpackh (&a
, hflt
); /* round and pack frac */
656 /* Unpacked floating point routines */
660 void vax_hadd (UFPH
*a
, UFPH
*b
)
665 if ((a
->frac
.f3
== 0) && (a
->frac
.f2
== 0) && /* s1 = 0? */
666 (a
->frac
.f1
== 0) && (a
->frac
.f0
== 0)) {
667 *a
= *b
; /* result is s2 */
670 if ((b
->frac
.f3
== 0) && (b
->frac
.f2
== 0) && /* s2 = 0? */
671 (b
->frac
.f1
== 0) && (b
->frac
.f0
== 0))
673 if ((a
->exp
< b
->exp
) || /* |s1| < |s2|? */
674 ((a
->exp
== b
->exp
) && (qp_cmp (&a
->frac
, &b
->frac
) < 0))) {
679 ediff
= a
->exp
- b
->exp
; /* exp diff */
680 if (a
->sign
^ b
->sign
) { /* eff sub? */
681 qp_neg (&b
->frac
); /* negate fraction */
682 if (ediff
) qp_rsh_s (&b
->frac
, ediff
, 1); /* denormalize */
683 qp_add (&a
->frac
, &b
->frac
); /* "add" frac */
684 h_normh (a
); /* normalize */
687 if (ediff
) qp_rsh (&b
->frac
, ediff
); /* add, denormalize */
688 if (qp_add (&a
->frac
, &b
->frac
)) { /* add frac, carry? */
689 qp_rsh (&a
->frac
, 1); /* renormalize */
690 a
->frac
.f3
= a
->frac
.f3
| UH_NM_H
; /* add norm bit */
691 a
->exp
= a
->exp
+ 1; /* incr exp */
697 /* Floating multiply - 128b * 128b */
699 void vax_hmul (UFPH
*a
, UFPH
*b
, uint32 mlo
)
702 UQP accum
= { 0, 0, 0, 0 };
704 if ((a
->exp
== 0) || (b
->exp
== 0)) { /* zero argument? */
705 a
->frac
.f0
= a
->frac
.f1
= 0; /* result is zero */
706 a
->frac
.f2
= a
->frac
.f3
= 0;
707 a
->sign
= a
->exp
= 0;
710 a
->sign
= a
->sign
^ b
->sign
; /* sign of result */
711 a
->exp
= a
->exp
+ b
->exp
- H_BIAS
; /* add exponents */
712 for (i
= 0; i
< 128; i
++) { /* quad precision */
713 if (a
->frac
.f0
& 1) c
= qp_add (&accum
, &b
->frac
); /* mplr low? add */
715 qp_rsh (&accum
, 1); /* shift result */
716 if (c
) accum
.f3
= accum
.f3
| UH_NM_H
; /* add carry out */
717 qp_rsh (&a
->frac
, 1); /* shift mplr */
719 a
->frac
= accum
; /* result */
720 a
->frac
.f0
= a
->frac
.f0
& ~mlo
; /* mask low frac */
721 h_normh (a
); /* normalize */
725 /* Floating modulus - there are three cases
727 exp <= bias - integer is 0, fraction is input,
729 bias < exp <= bias+128 - separate integer and fraction,
730 integer overflow may occur
731 bias+128 < exp - result is integer, fraction is 0
735 void vax_hmod (UFPH
*a
, int32
*intgr
, int32
*flg
)
739 if (a
->exp
<= H_BIAS
) *intgr
= *flg
= 0; /* 0 or <1? int = 0 */
740 else if (a
->exp
<= (H_BIAS
+ 128)) { /* in range? */
742 qp_rsh (&ifr
, 128 - (a
->exp
- H_BIAS
)); /* separate integer */
743 if ((a
->exp
> (H_BIAS
+ 32)) || /* test ovflo */
744 ((a
->exp
== (H_BIAS
+ 32)) &&
745 (ifr
.f0
> (a
->sign
? 0x80000000: 0x7FFFFFFF))))
749 if (a
->sign
) *intgr
= -*intgr
; /* -? comp int */
750 qp_lsh (&a
->frac
, a
->exp
- H_BIAS
); /* excise integer */
754 *intgr
= 0; /* out of range */
755 a
->frac
.f0
= a
->frac
.f1
= 0; /* result 0 */
756 a
->frac
.f2
= a
->frac
.f3
= 0;
757 a
->sign
= a
->exp
= 0;
758 *flg
= CC_V
; /* overflow */
760 h_normh (a
); /* normalize */
766 Carried out to 128 bits, although fewer are required */
768 void vax_hdiv (UFPH
*a
, UFPH
*b
)
771 UQP quo
= { 0, 0, 0, 0 };
773 if (a
->exp
== 0) FLT_DZRO_FAULT
; /* divr = 0? */
774 if (b
->exp
== 0) return; /* divd = 0? */
775 b
->sign
= b
->sign
^ a
->sign
; /* result sign */
776 b
->exp
= b
->exp
- a
->exp
+ H_BIAS
+ 1; /* unbiased exp */
777 qp_rsh (&a
->frac
, 1); /* allow 1 bit left */
778 qp_rsh (&b
->frac
, 1);
779 for (i
= 0; i
< 128; i
++) { /* divide loop */
780 qp_lsh (&quo
, 1); /* shift quo */
781 if (qp_cmp (&b
->frac
, &a
->frac
) >= 0) { /* div step ok? */
782 qp_sub (&b
->frac
, &a
->frac
); /* subtract */
783 quo
.f0
= quo
.f0
+ 1; /* quo bit = 1 */
785 qp_lsh (&b
->frac
, 1); /* shift divd */
788 h_normh (b
); /* normalize */
792 /* Quad precision integer routines */
794 int32
qp_cmp (UQP
*a
, UQP
*b
)
796 if (a
->f3
< b
->f3
) return -1; /* compare hi */
797 if (a
->f3
> b
->f3
) return +1;
798 if (a
->f2
< b
->f2
) return -1; /* hi =, compare mid1 */
799 if (a
->f2
> b
->f2
) return +1;
800 if (a
->f1
< b
->f1
) return -1; /* mid1 =, compare mid2 */
801 if (a
->f1
> b
->f1
) return +1;
802 if (a
->f0
< b
->f0
) return -1; /* mid2 =, compare lo */
803 if (a
->f0
> b
->f0
) return +1;
804 return 0; /* all equal */
807 uint32
qp_add (UQP
*a
, UQP
*b
)
809 uint32 cry1
, cry2
, cry3
, cry4
;
811 a
->f0
= (a
->f0
+ b
->f0
) & LMASK
; /* add lo */
812 cry1
= (a
->f0
< b
->f0
); /* carry? */
813 a
->f1
= (a
->f1
+ b
->f1
+ cry1
) & LMASK
; /* add mid2 */
814 cry2
= (a
->f1
< b
->f1
) || (cry1
&& (a
->f1
== b
->f1
)); /* carry? */
815 a
->f2
= (a
->f2
+ b
->f2
+ cry2
) & LMASK
; /* add mid1 */
816 cry3
= (a
->f2
< b
->f2
) || (cry2
&& (a
->f2
== b
->f2
)); /* carry? */
817 a
->f3
= (a
->f3
+ b
->f3
+ cry3
) & LMASK
; /* add hi */
818 cry4
= (a
->f3
< b
->f3
) || (cry3
&& (a
->f3
== b
->f3
)); /* carry? */
819 return cry4
; /* return carry out */
824 a
->f0
= (a
->f0
+ 1) & LMASK
; /* inc lo */
825 if (a
->f0
== 0) { /* propagate carry */
826 a
->f1
= (a
->f1
+ 1) & LMASK
;
828 a
->f2
= (a
->f2
+ 1) & LMASK
;
830 a
->f3
= (a
->f3
+ 1) & LMASK
;
837 uint32
qp_sub (UQP
*a
, UQP
*b
)
839 uint32 brw1
, brw2
, brw3
, brw4
;
841 brw1
= (a
->f0
< b
->f0
); /* borrow? */
842 a
->f0
= (a
->f0
- b
->f0
) & LMASK
; /* sub lo */
843 brw2
= (a
->f1
< b
->f1
) || (brw1
&& (a
->f1
== b
->f1
)); /* borrow? */
844 a
->f1
= (a
->f1
- b
->f1
- brw1
) & LMASK
; /* sub mid1 */
845 brw3
= (a
->f2
< b
->f2
) || (brw2
&& (a
->f2
== b
->f2
)); /* borrow? */
846 a
->f2
= (a
->f2
- b
->f2
- brw2
) & LMASK
; /* sub mid2 */
847 brw4
= (a
->f3
< b
->f3
) || (brw3
&& (a
->f3
== b
->f3
)); /* borrow? */
848 a
->f3
= (a
->f3
- b
->f3
- brw3
) & LMASK
; /* sub high */
857 a
->f0
= (~a
->f0
+ cryin
) & LMASK
;
858 if (a
->f0
!= 0) cryin
= 0;
859 a
->f1
= (~a
->f1
+ cryin
) & LMASK
;
860 if (a
->f1
!= 0) cryin
= 0;
861 a
->f2
= (~a
->f2
+ cryin
) & LMASK
;
862 if (a
->f2
!= 0) cryin
= 0;
863 a
->f3
= (~a
->f3
+ cryin
) & LMASK
;
867 void qp_lsh (UQP
*r
, uint32 sc
)
869 if (sc
>= 128) r
->f3
= r
->f2
= r
->f1
= r
->f0
= 0; /* > 127? result 0 */
870 else if (sc
>= 96) { /* [96,127]? */
871 r
->f3
= (r
->f0
<< (sc
- 96)) & LMASK
;
872 r
->f2
= r
->f1
= r
->f0
= 0;
874 else if (sc
> 64) { /* [65,95]? */
875 r
->f3
= ((r
->f1
<< (sc
- 64)) | (r
->f0
>> (96 - sc
))) & LMASK
;
876 r
->f2
= (r
->f0
<< (sc
- 64)) & LMASK
;
879 else if (sc
== 64) { /* [64]? */
884 else if (sc
> 32) { /* [33,63]? */
885 r
->f3
= ((r
->f2
<< (sc
- 32)) | (r
->f1
>> (64 - sc
))) & LMASK
;
886 r
->f2
= ((r
->f1
<< (sc
- 32)) | (r
->f0
>> (64 - sc
))) & LMASK
;
887 r
->f1
= (r
->f0
<< (sc
- 32)) & LMASK
;
890 else if (sc
== 32) { /* [32]? */
896 else if (sc
!= 0) { /* [31,1]? */
897 r
->f3
= ((r
->f3
<< sc
) | (r
->f2
>> (32 - sc
))) & LMASK
;
898 r
->f2
= ((r
->f2
<< sc
) | (r
->f1
>> (32 - sc
))) & LMASK
;
899 r
->f1
= ((r
->f1
<< sc
) | (r
->f0
>> (32 - sc
))) & LMASK
;
900 r
->f0
= (r
->f0
<< sc
) & LMASK
;
905 void qp_rsh (UQP
*r
, uint32 sc
)
907 if (sc
>= 128) r
->f3
= r
->f2
= r
->f1
= r
->f0
= 0; /* > 127? result 0 */
908 else if (sc
>= 96) { /* [96,127]? */
909 r
->f0
= (r
->f3
>> (sc
- 96)) & LMASK
;
910 r
->f1
= r
->f2
= r
->f3
= 0;
912 else if (sc
> 64) { /* [65,95]? */
913 r
->f0
= ((r
->f2
>> (sc
- 64)) | (r
->f3
<< (96 - sc
))) & LMASK
;
914 r
->f1
= (r
->f3
>> (sc
- 64)) & LMASK
;
917 else if (sc
== 64) { /* [64]? */
922 else if (sc
> 32) { /* [33,63]? */
923 r
->f0
= ((r
->f1
>> (sc
- 32)) | (r
->f2
<< (64 - sc
))) & LMASK
;
924 r
->f1
= ((r
->f2
>> (sc
- 32)) | (r
->f3
<< (64 - sc
))) & LMASK
;
925 r
->f2
= (r
->f3
>> (sc
- 32)) & LMASK
;
928 else if (sc
== 32) { /* [32]? */
934 else if (sc
!= 0) { /* [31,1]? */
935 r
->f0
= ((r
->f0
>> sc
) | (r
->f1
<< (32 - sc
))) & LMASK
;
936 r
->f1
= ((r
->f1
>> sc
) | (r
->f2
<< (32 - sc
))) & LMASK
;
937 r
->f2
= ((r
->f2
>> sc
) | (r
->f3
<< (32 - sc
))) & LMASK
;
938 r
->f3
= (r
->f3
>> sc
) & LMASK
;
943 void qp_rsh_s (UQP
*r
, uint32 sc
, uint32 neg
)
945 qp_rsh (r
, sc
); /* do unsigned right */
946 if (neg
&& sc
) { /* negative? */
948 r
->f0
= r
->f1
= r
->f2
= r
->f3
= LMASK
; /* > 127? result -1 */
950 UQP ones
= { LMASK
, LMASK
, LMASK
, LMASK
};
951 qp_lsh (&ones
, 128 - sc
); /* shift ones */
952 r
->f0
= r
->f0
| ones
.f0
; /* or into result */
953 r
->f1
= r
->f1
| ones
.f1
;
954 r
->f2
= r
->f2
| ones
.f2
;
955 r
->f3
= r
->f3
| ones
.f3
;
961 /* Support routines */
963 void h_unpackfd (int32 hi
, int32 lo
, UFPH
*r
)
965 r
->sign
= hi
& FPSIGN
; /* get sign */
966 r
->exp
= FD_GETEXP (hi
); /* get exponent */
967 r
->frac
.f0
= r
->frac
.f1
= 0; /* low bits 0 */
968 if (r
->exp
== 0) { /* exp = 0? */
969 if (r
->sign
) RSVD_OPND_FAULT
; /* if -, rsvd op */
970 r
->frac
.f2
= r
->frac
.f3
= 0; /* else 0 */
973 r
->frac
.f3
= WORDSWAP ((hi
& ~(FPSIGN
| FD_EXP
)) | FD_HB
);
974 r
->frac
.f2
= WORDSWAP (lo
);
975 qp_lsh (&r
->frac
, FD_GUARD
);
979 void h_unpackg (int32 hi
, int32 lo
, UFPH
*r
)
981 r
->sign
= hi
& FPSIGN
; /* get sign */
982 r
->exp
= G_GETEXP (hi
); /* get exponent */
983 r
->frac
.f0
= r
->frac
.f1
= 0; /* low bits 0 */
984 if (r
->exp
== 0) { /* exp = 0? */
985 if (r
->sign
) RSVD_OPND_FAULT
; /* if -, rsvd op */
986 r
->frac
.f2
= r
->frac
.f3
= 0; /* else 0 */
989 r
->frac
.f3
= WORDSWAP ((hi
& ~(FPSIGN
| G_EXP
)) | G_HB
);
990 r
->frac
.f2
= WORDSWAP (lo
);
991 qp_lsh (&r
->frac
, G_GUARD
);
995 void h_unpackh (int32
*hflt
, UFPH
*r
)
997 r
->sign
= hflt
[0] & FPSIGN
; /* get sign */
998 r
->exp
= H_GETEXP (hflt
[0]); /* get exponent */
999 if (r
->exp
== 0) { /* exp = 0? */
1000 if (r
->sign
) RSVD_OPND_FAULT
; /* if -, rsvd op */
1001 r
->frac
.f0
= r
->frac
.f1
= 0; /* else 0 */
1002 r
->frac
.f2
= r
->frac
.f3
= 0;
1005 r
->frac
.f3
= WORDSWAP ((hflt
[0] & ~(FPSIGN
| H_EXP
)) | H_HB
);
1006 r
->frac
.f2
= WORDSWAP (hflt
[1]);
1007 r
->frac
.f1
= WORDSWAP (hflt
[2]);
1008 r
->frac
.f0
= WORDSWAP (hflt
[3]);
1009 qp_lsh (&r
->frac
, H_GUARD
);
1013 void h_normh (UFPH
*r
)
1016 static uint32 normmask
[5] = {
1017 0xc0000000, 0xf0000000, 0xff000000, 0xffff0000, 0xffffffff };
1018 static int32 normtab
[6] = { 1, 2, 4, 8, 16, 32};
1020 if ((r
->frac
.f0
== 0) && (r
->frac
.f1
== 0) &&
1021 (r
->frac
.f2
== 0) && (r
->frac
.f3
== 0)) { /* if fraction = 0 */
1022 r
->sign
= r
->exp
= 0; /* result is 0 */
1025 while ((r
->frac
.f3
& UH_NM_H
) == 0) { /* normalized? */
1026 for (i
= 0; i
< 5; i
++) { /* find first 1 */
1027 if (r
->frac
.f3
& normmask
[i
]) break;
1029 qp_lsh (&r
->frac
, normtab
[i
]); /* shift frac */
1030 r
->exp
= r
->exp
- normtab
[i
]; /* decr exp */
1035 int32
h_rpackfd (UFPH
*r
, int32
*rh
)
1037 static UQP f_round
= { 0, 0, 0, UH_FRND
};
1038 static UQP d_round
= { 0, 0, UH_DRND
, 0 };
1040 if (rh
) *rh
= 0; /* assume 0 */
1041 if ((r
->frac
.f3
== 0) && (r
->frac
.f2
== 0)) return 0; /* frac = 0? done */
1042 qp_add (&r
->frac
, rh
? &d_round
: &f_round
);
1043 if ((r
->frac
.f3
& UH_NM_H
) == 0) { /* carry out? */
1044 qp_rsh (&r
->frac
, 1); /* renormalize */
1045 r
->exp
= r
->exp
+ 1;
1047 if (r
->exp
> (int32
) FD_M_EXP
) FLT_OVFL_FAULT
; /* ovflo? fault */
1048 if (r
->exp
<= 0) { /* underflow? */
1049 if (PSL
& PSW_FU
) FLT_UNFL_FAULT
; /* fault if fu */
1050 return 0; /* else 0 */
1052 qp_rsh (&r
->frac
, FD_GUARD
); /* remove guard */
1053 if (rh
) *rh
= WORDSWAP (r
->frac
.f2
);
1054 return r
->sign
| (r
->exp
<< FD_V_EXP
) |
1055 (WORDSWAP (r
->frac
.f3
) & ~(FD_HB
| FPSIGN
| FD_EXP
));
1058 int32
h_rpackg (UFPH
*r
, int32
*rh
)
1060 static UQP g_round
= { 0, 0, UH_GRND
, 0 };
1062 *rh
= 0; /* assume 0 */
1063 if ((r
->frac
.f3
== 0) && (r
->frac
.f2
== 0)) return 0; /* frac = 0? done */
1064 qp_add (&r
->frac
, &g_round
); /* round */
1065 if ((r
->frac
.f3
& UH_NM_H
) == 0) { /* carry out? */
1066 qp_rsh (&r
->frac
, 1); /* renormalize */
1067 r
->exp
= r
->exp
+ 1;
1069 if (r
->exp
> (int32
) G_M_EXP
) FLT_OVFL_FAULT
; /* ovflo? fault */
1070 if (r
->exp
<= 0) { /* underflow? */
1071 if (PSL
& PSW_FU
) FLT_UNFL_FAULT
; /* fault if fu */
1072 return 0; /* else 0 */
1074 qp_rsh (&r
->frac
, G_GUARD
); /* remove guard */
1075 *rh
= WORDSWAP (r
->frac
.f2
); /* get low */
1076 return r
->sign
| (r
->exp
<< G_V_EXP
) |
1077 (WORDSWAP (r
->frac
.f3
) & ~(G_HB
| FPSIGN
| G_EXP
));
1080 int32
h_rpackh (UFPH
*r
, int32
*hflt
)
1082 static UQP h_round
= { UH_HRND
, 0, 0, 0 };
1084 hflt
[0] = hflt
[1] = hflt
[2] = hflt
[3] = 0; /* assume 0 */
1085 if ((r
->frac
.f3
== 0) && (r
->frac
.f2
== 0) && /* frac = 0? done */
1086 (r
->frac
.f1
== 0) && (r
->frac
.f0
== 0)) return 0;
1087 if (qp_add (&r
->frac
, &h_round
)) { /* round, carry out? */
1088 qp_rsh (&r
->frac
, 1); /* renormalize */
1089 r
->exp
= r
->exp
+ 1;
1091 if (r
->exp
> (int32
) H_M_EXP
) FLT_OVFL_FAULT
; /* ovflo? fault */
1092 if (r
->exp
<= 0) { /* underflow? */
1093 if (PSL
& PSW_FU
) FLT_UNFL_FAULT
; /* fault if fu */
1094 return 0; /* else 0 */
1096 qp_rsh (&r
->frac
, H_GUARD
); /* remove guard */
1097 hflt
[0] = r
->sign
| (r
->exp
<< H_V_EXP
) |
1098 (WORDSWAP (r
->frac
.f3
) & ~(H_HB
| FPSIGN
| H_EXP
));
1099 hflt
[1] = WORDSWAP (r
->frac
.f2
);
1100 hflt
[2] = WORDSWAP (r
->frac
.f1
);
1101 hflt
[3] = WORDSWAP (r
->frac
.f0
);
1105 void h_write_b (int32 spec
, int32 va
, int32 val
, int32 acc
)
1109 if (spec
> (GRN
| nPC
)) Write (va
, val
, L_BYTE
, WA
);
1112 R
[rn
] = (R
[rn
] & ~BMASK
) | val
;
1117 void h_write_w (int32 spec
, int32 va
, int32 val
, int32 acc
)
1121 if (spec
> (GRN
| nPC
)) Write (va
, val
, L_WORD
, WA
);
1124 R
[rn
] = (R
[rn
] & ~WMASK
) | val
;
1129 void h_write_l (int32 spec
, int32 va
, int32 val
, int32 acc
)
1131 if (spec
> (GRN
| nPC
)) Write (va
, val
, L_LONG
, WA
);
1132 else R
[spec
& 0xF] = val
;
1136 void h_write_q (int32 spec
, int32 va
, int32 vl
, int32 vh
, int32 acc
)
1140 if (spec
> (GRN
| nPC
)) {
1141 if ((Test (va
+ 7, WA
, &mstat
) >= 0) ||
1142 (Test (va
, WA
, &mstat
) < 0))
1143 Write (va
, vl
, L_LONG
, WA
);
1144 Write (va
+ 4, vh
, L_LONG
, WA
);
1148 if (rn
>= nSP
) RSVD_ADDR_FAULT
;
1155 void h_write_o (int32 spec
, int32 va
, int32
*val
, int32 acc
)
1159 if (spec
> (GRN
| nPC
)) {
1160 if ((Test (va
+ 15, WA
, &mstat
) >= 0) ||
1161 (Test (va
, WA
, &mstat
) < 0))
1162 Write (va
, val
[0], L_LONG
, WA
);
1163 Write (va
+ 4, val
[1], L_LONG
, WA
);
1164 Write (va
+ 8, val
[2], L_LONG
, WA
);
1165 Write (va
+ 12, val
[3], L_LONG
, WA
);
1169 if (rn
>= nAP
) RSVD_ADDR_FAULT
;
1180 extern jmp_buf save_env
;
1182 int32
op_octa (int32
*opnd
, int32 cc
, int32 opc
, int32 acc
, int32 spec
, int32 va
)