forked from rbowler/spinhawk
-
Notifications
You must be signed in to change notification settings - Fork 3
/
dfp.c
5085 lines (4157 loc) · 194 KB
/
dfp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* DFP.C (c) Copyright Roger Bowler, 2007-2009 */
/* Decimal Floating Point instructions */
/*-------------------------------------------------------------------*/
/* This module implements the Decimal Floating Point instructions */
/* and the Floating Point Support Enhancement Facility instructions */
/* described in the z/Architecture Principles of Operation manual. */
/*-------------------------------------------------------------------*/
#include "hstdinc.h"
#if !defined(_HENGINE_DLL_)
#define _HENGINE_DLL_
#endif
#if !defined(_DFP_C_)
#define _DFP_C_
#endif
#include "hercules.h"
#include "opcode.h"
#include "inline.h"
#if defined(FEATURE_DECIMAL_FLOATING_POINT)
#include "decimal128.h"
#include "decimal64.h"
#include "decimal32.h"
#include "decPacked.h"
#endif /*defined(FEATURE_DECIMAL_FLOATING_POINT)*/
#if defined(FEATURE_FPS_ENHANCEMENT)
/*===================================================================*/
/* FLOATING POINT SUPPORT INSTRUCTIONS */
/*===================================================================*/
/* Note: the Floating Point Support instructions use the HFPREG_CHECK
and HFPREG2_CHECK macros to enforce an AFP-register data exception
if an FPS instruction attempts to use one of the 12 additional FPR
registers when the AFP-register-control bit in CR0 is zero. */
/*-------------------------------------------------------------------*/
/* B370 LPDFR - Load Positive FPR Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_positive_fpr_long_reg)
{
int r1, r2; /* Values of R fields */
int i1, i2; /* FP register subscripts */
RRE(inst, regs, r1, r2);
HFPREG2_CHECK(r1, r2, regs);
i1 = FPR2I(r1);
i2 = FPR2I(r2);
/* Copy register contents, clear the sign bit */
regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF;
regs->fpr[i1+1] = regs->fpr[i2+1];
} /* end DEF_INST(load_positive_fpr_long_reg) */
/*-------------------------------------------------------------------*/
/* B371 LNDFR - Load Negative FPR Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_negative_fpr_long_reg)
{
int r1, r2; /* Values of R fields */
int i1, i2; /* FP register subscripts */
RRE(inst, regs, r1, r2);
HFPREG2_CHECK(r1, r2, regs);
i1 = FPR2I(r1);
i2 = FPR2I(r2);
/* Copy register contents, set the sign bit */
regs->fpr[i1] = regs->fpr[i2] | 0x80000000;
regs->fpr[i1+1] = regs->fpr[i2+1];
} /* end DEF_INST(load_negative_fpr_long_reg) */
/*-------------------------------------------------------------------*/
/* B372 CPSDR - Copy Sign FPR Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(copy_sign_fpr_long_reg)
{
int r1, r2, r3; /* Values of R fields */
int i1, i2, i3; /* FP register subscripts */
U32 sign; /* Work area for sign bit */
RRF_M(inst, regs, r1, r2, r3);
HFPREG2_CHECK(r1, r2, regs);
HFPREG_CHECK(r3, regs);
i1 = FPR2I(r1);
i2 = FPR2I(r2);
i3 = FPR2I(r3);
/* Copy the sign bit from r3 register */
sign = regs->fpr[i3] & 0x80000000;
/* Copy r2 register contents to r1 register */
regs->fpr[i1] = regs->fpr[i2];
regs->fpr[i1+1] = regs->fpr[i2+1];
/* Insert the sign bit into r1 register */
regs->fpr[i1] &= 0x7FFFFFFF;
regs->fpr[i1] |= sign;
} /* end DEF_INST(copy_sign_fpr_long_reg) */
/*-------------------------------------------------------------------*/
/* B373 LCDFR - Load Complement FPR Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_complement_fpr_long_reg)
{
int r1, r2; /* Values of R fields */
int i1, i2; /* FP register subscripts */
RRE(inst, regs, r1, r2);
HFPREG2_CHECK(r1, r2, regs);
i1 = FPR2I(r1);
i2 = FPR2I(r2);
/* Copy register contents, invert sign bit */
regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000;
regs->fpr[i1+1] = regs->fpr[i2+1];
} /* end DEF_INST(load_complement_fpr_long_reg) */
/*-------------------------------------------------------------------*/
/* B3C1 LDGR - Load FPR from GR Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_fpr_from_gr_long_reg)
{
int r1, r2; /* Values of R fields */
int i1; /* FP register subscript */
RRE(inst, regs, r1, r2);
HFPREG_CHECK(r1, regs);
i1 = FPR2I(r1);
/* Load FP register contents from general register */
regs->fpr[i1] = regs->GR_H(r2);
regs->fpr[i1+1] = regs->GR_L(r2);
} /* end DEF_INST(load_fpr_from_gr_long_reg) */
/*-------------------------------------------------------------------*/
/* B3CD LGDR - Load GR from FPR Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_gr_from_fpr_long_reg)
{
int r1, r2; /* Values of R fields */
int i2; /* FP register subscript */
RRE(inst, regs, r1, r2);
HFPREG_CHECK(r2, regs);
i2 = FPR2I(r2);
/* Load general register contents from FP register */
regs->GR_H(r1) = regs->fpr[i2];
regs->GR_L(r1) = regs->fpr[i2+1];
} /* end DEF_INST(load_gr_from_fpr_long_reg) */
/*-------------------------------------------------------------------*/
/* B2B9 SRNMT - Set DFP Rounding Mode [S] */
/*-------------------------------------------------------------------*/
DEF_INST(set_dfp_rounding_mode)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
S(inst, regs, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Set DFP rounding mode in FPC register from address bits 61-63 */
regs->fpc &= ~(FPC_DRM);
regs->fpc |= ((effective_addr2 << FPC_DRM_SHIFT) & FPC_DRM);
} /* end DEF_INST(set_dfp_rounding_mode) */
#endif /*defined(FEATURE_FPS_ENHANCEMENT)*/
#if defined(FEATURE_IEEE_EXCEPTION_SIMULATION)
/*===================================================================*/
/* IEEE-EXCEPTION-SIMULATION FACILITY INSTRUCTIONS */
/*===================================================================*/
#if !defined(_IXS_ARCH_INDEPENDENT_)
/*-------------------------------------------------------------------*/
/* Check if a simulated-IEEE-exception event is to be recognized */
/* */
/* This subroutine is called by the LFAS and SFASR instructions to */
/* determine whether the instruction should raise a data exception */
/* at the end of the instruction and, if so, the DXC code to be set. */
/* */
/* Input: */
/* cur_fpc Current value of the FPC register */
/* src_fpc Value of instruction source operand */
/* Output: */
/* The return value is the data exception code (DXC), or */
/* zero if no simulated-IEEE-exception event is recognized */
/*-------------------------------------------------------------------*/
static BYTE
fpc_signal_check(U32 cur_fpc, U32 src_fpc)
{
U32 ff, sm, enabled_flags; /* Mask and flag work areas */
BYTE dxc; /* Data exception code or 0 */
/* AND the current FPC flags with the source FPC mask */
ff = (cur_fpc & FPC_FLAG) >> FPC_FLAG_SHIFT;
sm = (src_fpc & FPC_MASK) >> FPC_MASK_SHIFT;
enabled_flags = (ff & sm) << FPC_FLAG_SHIFT;
/* A simulated-IEEE-exception event is recognized
if any current flag corresponds to the source mask */
if (enabled_flags & FPC_FLAG_SFI)
{
dxc = DXC_IEEE_INV_OP_IISE;
}
else if (enabled_flags & FPC_FLAG_SFZ)
{
dxc = DXC_IEEE_DIV_ZERO_IISE;
}
else if (enabled_flags & FPC_FLAG_SFO)
{
dxc = (cur_fpc & FPC_FLAG_SFX) ?
DXC_IEEE_OF_INEX_IISE :
DXC_IEEE_OF_EXACT_IISE;
}
else if (enabled_flags & FPC_FLAG_SFU)
{
dxc = (cur_fpc & FPC_FLAG_SFX) ?
DXC_IEEE_UF_INEX_IISE :
DXC_IEEE_UF_EXACT_IISE;
}
else if (enabled_flags & FPC_FLAG_SFX)
{
dxc = DXC_IEEE_INEXACT_IISE;
}
else
{
dxc = 0;
}
/* Return data exception code or zero */
return dxc;
} /* end function fpc_signal_check */
#define _IXS_ARCH_INDEPENDENT_
#endif /*!defined(_IXS_ARCH_INDEPENDENT_)*/
/*-------------------------------------------------------------------*/
/* B2BD LFAS - Load FPC and Signal [S] */
/*-------------------------------------------------------------------*/
DEF_INST(load_fpc_and_signal)
{
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
U32 src_fpc, new_fpc; /* New value for FPC */
BYTE dxc; /* Data exception code */
S(inst, regs, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Load new FPC register contents from operand location */
src_fpc = ARCH_DEP(vfetch4) (effective_addr2, b2, regs);
/* Program check if reserved bits are non-zero */
FPC_CHECK(src_fpc, regs);
/* OR the flags from the current FPC register */
new_fpc = src_fpc | (regs->fpc & FPC_FLAG);
/* Determine whether an event is to be signaled */
dxc = fpc_signal_check(regs->fpc, src_fpc);
/* Update the FPC register */
regs->fpc = new_fpc;
/* Signal a simulated-IEEE-exception event if needed */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_fpc_and_signal) */
/*-------------------------------------------------------------------*/
/* B385 SFASR - Set FPC and Signal [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(set_fpc_and_signal)
{
int r1, unused; /* Values of R fields */
U32 src_fpc, new_fpc; /* New value for FPC */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, unused);
DFPINST_CHECK(regs);
/* Load new FPC register contents from R1 register bits 32-63 */
src_fpc = regs->GR_L(r1);
/* Program check if reserved bits are non-zero */
FPC_CHECK(src_fpc, regs);
/* OR the flags from the current FPC register */
new_fpc = src_fpc | (regs->fpc & FPC_FLAG);
/* Determine whether an event is to be signaled */
dxc = fpc_signal_check(regs->fpc, src_fpc);
/* Update the FPC register */
regs->fpc = new_fpc;
/* Signal a simulated-IEEE-exception event if needed */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(set_fpc_and_signal) */
#endif /*defined(FEATURE_IEEE_EXCEPTION_SIMULATION)*/
#if defined(FEATURE_DECIMAL_FLOATING_POINT)
/*===================================================================*/
/* DECIMAL FLOATING POINT INSTRUCTIONS */
/*===================================================================*/
/* Note: the DFP instructions use the DFPINST_CHECK macro to check the
setting of the AFP-register-control bit in CR0. If this bit is zero
then the macro generates a DFP-instruction data exception. */
#if !defined(_DFP_ARCH_INDEPENDENT_)
/*-------------------------------------------------------------------*/
/* Extract the leftmost digit from a decimal32/64/128 structure */
/*-------------------------------------------------------------------*/
static const int
dfp_lmdtable[32] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, 0, 0};
static inline int
dfp32_extract_lmd(decimal32 *xp)
{
unsigned int cf = (((FW*)xp)->F & 0x7C000000) >> 26;
return dfp_lmdtable[cf];
} /* end function dfp32_extract_lmd */
static inline int
dfp64_extract_lmd(decimal64 *xp)
{
unsigned int cf = (((DW*)xp)->F.H.F & 0x7C000000) >> 26;
return dfp_lmdtable[cf];
} /* end function dfp64_extract_lmd */
static inline int
dfp128_extract_lmd(decimal128 *xp)
{
unsigned int cf = (((QW*)xp)->F.HH.F & 0x7C000000) >> 26;
return dfp_lmdtable[cf];
} /* end function dfp128_extract_lmd */
/*-------------------------------------------------------------------*/
/* Clear the CF and BXCF fields of a decimal32/64/128 structure */
/*-------------------------------------------------------------------*/
static inline void
dfp32_clear_cf_and_bxcf(decimal32 *xp)
{
((FW*)xp)->F &= 0x800FFFFF; /* Clear CF and BXCF fields */
} /* end function dfp32_clear_cf_and_bxcf */
static inline void
dfp64_clear_cf_and_bxcf(decimal64 *xp)
{
((DW*)xp)->F.H.F &= 0x8003FFFF; /* Clear CF and BXCF fields */
} /* end function dfp64_clear_cf_and_bxcf */
static inline void
dfp128_clear_cf_and_bxcf(decimal128 *xp)
{
((QW*)xp)->F.HH.F &= 0x80003FFF; /* Clear CF and BXCF fields */
} /* end function dfp128_clear_cf_and_bxcf */
/*-------------------------------------------------------------------*/
/* Set the CF and BXCF fields of a decimal32/64/128 structure */
/* Input: */
/* xp Pointer to a decimal32/64/128 structure */
/* cfs A 32-bit value, of which bits 0-25 are ignored, */
/* bits 26-30 contain the new CF field value (5-bits), */
/* bit 31 is the new BXCF signaling indicator (1-bit). */
/* Output: */
/* The CF field and the high-order bit of the BXCF field in */
/* the decimal32/64/128 structure are set to the indicated */
/* values and the remaining bits of the BXCF field are cleared. */
/*-------------------------------------------------------------------*/
#define DFP_CFS_INF ((30<<1)|0) /* CF and BXCF-S for Inf */
#define DFP_CFS_QNAN ((31<<1)|0) /* CF and BXCF-S for QNaN */
#define DFP_CFS_SNAN ((31<<1)|1) /* CF and BXCF-S for SNaN */
static inline void
dfp32_set_cf_and_bxcf(decimal32 *xp, U32 cfs)
{
((FW*)xp)->F &= 0x800FFFFF; /* Clear CF and BXCF fields */
((FW*)xp)->F |= (cfs & 0x3F) << 25;
/* Set CF and BXCF S-bit */
} /* end function dfp32_set_cf_and_bxcf */
static inline void
dfp64_set_cf_and_bxcf(decimal64 *xp, U32 cfs)
{
((DW*)xp)->F.H.F &= 0x8003FFFF; /* Clear CF and BXCF fields */
((DW*)xp)->F.H.F |= (cfs & 0x3F) << 25;
/* Set CF and BXCF S-bit */
} /* end function dfp64_set_cf_and_bxcf */
static inline void
dfp128_set_cf_and_bxcf(decimal128 *xp, U32 cfs)
{
((QW*)xp)->F.HH.F &= 0x80003FFF; /* Clear CF and BXCF fields */
((QW*)xp)->F.HH.F |= (cfs & 0x3F) << 25;
/* Set CF and BXCF S-bit */
} /* end function dfp128_set_cf_and_bxcf */
/*-------------------------------------------------------------------*/
/* Compare exponent and return condition code */
/* */
/* This subroutine is called by the CEETR, CEDTR, and CEXTR */
/* instructions. It compares the exponents of two decimal */
/* numbers and returns a condition code. */
/* */
/* Input: */
/* d1,d2 Pointers to decimal number structures */
/* Output: */
/* The return value is the condition code */
/*-------------------------------------------------------------------*/
static inline int
dfp_compare_exponent(decNumber *d1, decNumber *d2)
{
int cc; /* Condition code */
if (decNumberIsNaN(d1) && decNumberIsNaN(d2))
cc = 0;
else if (decNumberIsNaN(d1) || decNumberIsNaN(d2))
cc = 3;
else if (decNumberIsInfinite(d1) && decNumberIsInfinite(d2))
cc = 0;
else if (decNumberIsInfinite(d1) || decNumberIsInfinite(d2))
cc = 3;
else
cc = (d1->exponent == d2->exponent) ? 0 :
(d1->exponent < d2->exponent) ? 1 : 2 ;
return cc;
} /* end function dfp_compare_exponent */
/*-------------------------------------------------------------------*/
/* Convert 64-bit signed binary integer to decimal number */
/* */
/* This subroutine is called by the CDGTR and CXGTR instructions. */
/* It converts a 64-bit signed binary integer value into a */
/* decimal number structure. The inexact condition will be set */
/* in the decimal context structure if the number is rounded to */
/* fit the maximum number of digits specified in the context. */
/* */
/* Input: */
/* dn Pointer to decimal number structure */
/* n 64-bit signed binary integer value */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The decimal number structure is updated. */
/*-------------------------------------------------------------------*/
static void
dfp_number_from_fix64(decNumber *dn, S64 n, decContext *pset)
{
int sign = 0; /* Sign of binary integer */
int i; /* Counter */
char zoned[32]; /* Zoned decimal work area */
static char maxnegzd[]="-9223372036854775808";
static U64 maxneg64 = 0x8000000000000000ULL;
/* Handle maximum negative number as special case */
if (n == (S64)maxneg64)
{
decNumberFromString(dn, maxnegzd, pset);
return;
}
/* Convert binary value to zoned decimal */
if (n < 0) { n = -n; sign = 1; }
i = sizeof(zoned) - 1;
zoned[i] = '\0';
do {
zoned[--i] = (n % 10) + '0';
n /= 10;
} while(i > 1 && n > 0);
if (sign) zoned[--i] = '-';
/* Convert zoned decimal value to decimal number structure */
decNumberFromString(dn, zoned+i, pset);
} /* end function dfp_number_from_fix64 */
/*-------------------------------------------------------------------*/
/* Convert decimal number to 64-bit signed binary integer */
/* */
/* This subroutine is called by the CGDTR and CGXTR instructions. */
/* It converts a decimal number structure to a 64-bit signed */
/* binary integer value. The inexact condition will be set in */
/* the decimal context structure if the number is rounded to */
/* an integer. The invalid operation condition will be set if */
/* the decimal value is outside the range of a 64-bit integer. */
/* */
/* Input: */
/* b Pointer to decimal number structure */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The return value is the 64-bit signed binary integer result */
/*-------------------------------------------------------------------*/
static S64
dfp_number_to_fix64(decNumber *b, decContext *pset)
{
S64 n; /* 64-bit signed result */
int32_t scale; /* Scaling factor */
unsigned i; /* Array subscript */
BYTE packed[17]; /* 33-digit packed work area */
decNumber p, c; /* Working decimal numbers */
static U64 mp64 = 0x7FFFFFFFFFFFFFFFULL; /* Max pos fixed 64 */
static U64 mn64 = 0x8000000000000000ULL; /* Max neg fixed 64 */
static char mpzd[]="9223372036854775807"; /* Max pos zoned dec */
static char mnzd[]="-9223372036854775808"; /* Max neg zoned dec */
static BYTE mpflag = 0; /* 1=mp,mn are initialized */
static decNumber mp, mn; /* Decimal maximum pos,neg */
decContext setmax; /* Working context for mp,mn */
/* Prime the decimal number structures representing the maximum
positive and negative numbers representable in 64 bits. Use
a 128-bit DFP working context because these numbers are too
big to be represented in the 32-bit and 64-bit DFP formats */
if (mpflag == 0)
{
decContextDefault(&setmax, DEC_INIT_DECIMAL128);
decNumberFromString(&mp, mpzd, &setmax);
decNumberFromString(&mn, mnzd, &setmax);
mpflag = 1;
}
/* If operand is a NaN then set invalid operation
and return maximum negative result */
if (decNumberIsNaN(b))
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (S64)mn64;
}
/* Remove fractional part of decimal number */
decNumberToIntegralValue(&p, b, pset);
/* Special case if operand is less than maximum negative
number (including where operand is negative infinity) */
decNumberCompare(&c, b, &mn, pset);
if (decNumberIsNegative(&c))
{
/* If rounded value is less than maximum negative number
then set invalid operation otherwise set inexact */
decNumberCompare(&c, &p, &mn, pset);
if (decNumberIsNegative(&c))
pset->status |= DEC_IEEE_854_Invalid_operation;
else
pset->status |= DEC_IEEE_854_Inexact;
/* Return maximum negative result */
return (S64)mn64;
}
/* Special case if operand is greater than maximum positive
number (including where operand is positive infinity) */
decNumberCompare(&c, b, &mp, pset);
if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0)
{
/* If rounded value is greater than maximum positive number
then set invalid operation otherwise set inexact */
decNumberCompare(&c, &p, &mp, pset);
if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0)
pset->status |= DEC_IEEE_854_Invalid_operation;
else
pset->status |= DEC_IEEE_854_Inexact;
/* Return maximum positive result */
return (S64)mp64;
}
/* Raise inexact condition if result was rounded */
decNumberCompare(&c, &p, b, pset);
if (decNumberIsZero(&c) == 0)
{
pset->status |= DEC_IEEE_854_Inexact;
if (decNumberIsNegative(&c) == decNumberIsNegative(b))
pset->status |= DEC_Rounded;
}
/* Convert decimal number structure to packed decimal */
decPackedFromNumber(packed, sizeof(packed), &scale, &p);
/* Convert packed decimal to binary value */
for (i = 0, n = 0; i < sizeof(packed)-1; i++)
{
n = n * 10 + ((packed[i] & 0xF0) >> 4);
n = n * 10 + (packed[i] & 0x0F);
}
n = n * 10 + ((packed[i] & 0xF0) >> 4);
while (scale++) n *= 10;
if ((packed[i] & 0x0F) == 0x0D) n = -n;
/* Return 64-bit signed result */
return n;
} /* end function dfp_number_to_fix64 */
#define MAXDECSTRLEN DECIMAL128_String /* Maximum string length */
/*-------------------------------------------------------------------*/
/* Shift decimal coefficient left or right */
/* */
/* This subroutine is called by the SLDT, SLXT, SRDT and SRXT */
/* instructions. It shifts the coefficient digits of a decimal */
/* number left or right. For a left shift, zeroes are appended */
/* to the coefficient. For a right shift, digits are dropped */
/* from the end of the coefficient. No rounding is performed. */
/* The sign and exponent of the number remain unchanged. */
/* */
/* Input: */
/* pset Pointer to decimal number context structure */
/* dn Pointer to decimal number structure to be shifted */
/* count Number of digits to shift (+ve=left, -ve=right) */
/* Output: */
/* The decimal number structure is updated. */
/*-------------------------------------------------------------------*/
static inline void
dfp_shift_coeff(decContext *pset, decNumber *dn, int count)
{
int len; /* String length */
int maxlen; /* Maximum coefficient length*/
int32_t exp; /* Original exponent */
uint8_t bits; /* Original flag bits */
char zd[MAXDECSTRLEN+64]; /* Zoned decimal work area */
/* Save original exponent and sign/Inf/NaN bits */
exp = dn->exponent;
bits = dn->bits;
/* Clear exponent and sign/Inf/NaN bits */
dn->exponent = 0;
dn->bits &= ~(DECNEG | DECSPECIAL);
/* Convert coefficient digits to zoned decimal */
decNumberToString(dn, zd);
len = (int)strlen(zd);
/* Shift zoned digits left or right */
if (count > 0)
memset(zd + len, '0', count);
len += count;
maxlen = (bits & DECSPECIAL) ? pset->digits - 1 : pset->digits;
if (len > maxlen)
{
memmove(zd, zd + len - maxlen, maxlen);
len = maxlen;
}
else if (len < 1)
{
zd[0] = '0';
len = 1;
}
zd[len] = '\0';
/* Convert shifted coefficient to decimal number structure */
decNumberFromString(dn, zd, pset);
/* Restore original exponent and sign/Inf/NaN bits */
dn->exponent = exp;
dn->bits |= bits & (DECNEG | DECSPECIAL);
} /* end function dfp_shift_coeff */
/* Bit numbers for Test Data Class instructions */
#define DFP_TDC_ZERO 52
#define DFP_TDC_SUBNORMAL 54
#define DFP_TDC_NORMAL 56
#define DFP_TDC_INFINITY 58
#define DFP_TDC_QUIET_NAN 60
#define DFP_TDC_SIGNALING_NAN 62
/*-------------------------------------------------------------------*/
/* Test data class and return condition code */
/* */
/* This subroutine is called by the TDCET, TDCDT, and TDCXT */
/* instructions. It tests the data class and sign of a decimal */
/* number. Each combination of data class and sign corresponds */
/* to one of 12 possible bits in a bitmask. The value (0 or 1) */
/* of the corresponding bit is returned. */
/* */
/* Input: */
/* pset Pointer to decimal number context structure */
/* dn Pointer to decimal number structure to be tested */
/* bits Bitmask in rightmost 12 bits */
/* Output: */
/* The return value is 0 or 1. */
/*-------------------------------------------------------------------*/
static inline int
dfp_test_data_class(decContext *pset, decNumber *dn, U32 bits)
{
int bitn; /* Bit number */
decNumber dm; /* Normalized value of dn */
if (decNumberIsZero(dn))
bitn = DFP_TDC_ZERO;
else if (decNumberIsInfinite(dn))
bitn = DFP_TDC_INFINITY;
else if (decNumberIsQNaN(dn))
bitn = DFP_TDC_QUIET_NAN;
else if (decNumberIsSNaN(dn))
bitn = DFP_TDC_SIGNALING_NAN;
else {
decNumberNormalize(&dm, dn, pset);
bitn = (dm.exponent < pset->emin) ?
DFP_TDC_SUBNORMAL :
DFP_TDC_NORMAL ;
}
if (decNumberIsNegative(dn)) bitn++;
return (bits >> (63 - bitn)) & 0x01;
} /* end function dfp_test_data_class */
/* Bit numbers for Test Data Group instructions */
#define DFP_TDG_SAFE_ZERO 52
#define DFP_TDG_EXTREME_ZERO 54
#define DFP_TDG_EXTREME_NONZERO 56
#define DFP_TDG_SAFE_NZ_LMD_Z 58
#define DFP_TDG_SAFE_NZ_LMD_NZ 60
#define DFP_TDG_SPECIAL 62
/*-------------------------------------------------------------------*/
/* Test data group and return condition code */
/* */
/* This subroutine is called by the TDGET, TDGDT, and TDGXT */
/* instructions. It tests the exponent and leftmost coefficient */
/* digit of a decimal number to determine which of 12 possible */
/* groups the number corresponds to. Each group corresponds to */
/* one of 12 possible bits in a bitmask. The value (0 or 1) of */
/* the corresponding bit is returned. */
/* */
/* Input: */
/* pset Pointer to decimal number context structure */
/* dn Pointer to decimal number structure to be tested */
/* lmd Leftmost digit of decimal FP number */
/* bits Bitmask in rightmost 12 bits */
/* Output: */
/* The return value is 0 or 1. */
/*-------------------------------------------------------------------*/
static inline int
dfp_test_data_group(decContext *pset, decNumber *dn, int lmd, U32 bits)
{
int bitn; /* Bit number */
int extreme; /* 1=exponent is min or max */
int exp; /* Adjusted exponent */
exp = dn->exponent + pset->digits - 1;
extreme = (exp == pset->emin) || (exp == pset->emax);
if (decNumberIsZero(dn))
bitn = extreme ?
DFP_TDG_EXTREME_ZERO :
DFP_TDG_SAFE_ZERO ;
else if (decNumberIsInfinite(dn) || decNumberIsNaN(dn))
bitn = DFP_TDG_SPECIAL;
else if (extreme)
bitn = DFP_TDG_EXTREME_NONZERO;
else {
bitn = (lmd == 0) ?
DFP_TDG_SAFE_NZ_LMD_Z :
DFP_TDG_SAFE_NZ_LMD_NZ ;
}
if (decNumberIsNegative(dn)) bitn++;
return (bits >> (63 - bitn)) & 0x01;
} /* end function dfp_test_data_group */
#define _DFP_ARCH_INDEPENDENT_
#endif /*!defined(_DFP_ARCH_INDEPENDENT_)*/
#if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/
#if !defined(_DFP_FPE_ARCH_INDEPENDENT_)
/*-------------------------------------------------------------------*/
/* Convert 32-bit signed binary integer to decimal number */
/* */
/* This subroutine is called by the CDFTR and CXFTR instructions. */
/* It converts a 32-bit signed binary integer value into a */
/* decimal number structure. The inexact condition will be set */
/* in the decimal context structure if the number is rounded to */
/* fit the maximum number of digits specified in the context. */
/* */
/* Input: */
/* dn Pointer to decimal number structure */
/* n 32-bit signed binary integer value */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The decimal number structure is updated. */
/*-------------------------------------------------------------------*/
static void
dfp_number_from_fix32(decNumber *dn, S32 n, decContext *pset)
{
int sign = 0; /* Sign of binary integer */
int i; /* Counter */
char zoned[32]; /* Zoned decimal work area */
static char maxnegzd[]="-2147483648";
static U32 maxneg32 = 0x80000000UL;
/* Handle maximum negative number as special case */
if (n == (S32)maxneg32)
{
decNumberFromString(dn, maxnegzd, pset);
return;
}
/* Convert binary value to zoned decimal */
if (n < 0) { n = -n; sign = 1; }
i = sizeof(zoned) - 1;
zoned[i] = '\0';
do {
zoned[--i] = (n % 10) + '0';
n /= 10;
} while(i > 1 && n > 0);
if (sign) zoned[--i] = '-';
/* Convert zoned decimal value to decimal number structure */
decNumberFromString(dn, zoned+i, pset);
} /* end function dfp_number_from_fix32 */
/*-------------------------------------------------------------------*/
/* Convert 32-bit unsigned binary integer to decimal number */
/* */
/* This subroutine is called by the CDLFTR and CXLFTR instructions. */
/* It converts a 32-bit unsigned binary integer value into a */
/* decimal number structure. The inexact condition will be set */
/* in the decimal context structure if the number is rounded to */
/* fit the maximum number of digits specified in the context. */
/* */
/* Input: */
/* dn Pointer to decimal number structure */
/* n 32-bit unsigned binary integer value */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The decimal number structure is updated. */
/*-------------------------------------------------------------------*/
static void
dfp_number_from_u32(decNumber *dn, U32 n, decContext *pset)
{
int i; /* Counter */
char zoned[32]; /* Zoned decimal work area */
/* Convert unsigned binary value to zoned decimal */
i = sizeof(zoned) - 1;
zoned[i] = '\0';
do {
zoned[--i] = (n % 10) + '0';
n /= 10;
} while(i > 1 && n > 0);
/* Convert zoned decimal value to decimal number structure */
decNumberFromString(dn, zoned+i, pset);
} /* end function dfp_number_from_u32 */
/*-------------------------------------------------------------------*/
/* Convert 64-bit unsigned binary integer to decimal number */
/* */
/* This subroutine is called by the CDLGTR and CXLGTR instructions. */
/* It converts a 64-bit unsigned binary integer value into a */
/* decimal number structure. The inexact condition will be set */
/* in the decimal context structure if the number is rounded to */
/* fit the maximum number of digits specified in the context. */
/* */
/* Input: */
/* dn Pointer to decimal number structure */
/* n 64-bit unsigned binary integer value */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The decimal number structure is updated. */
/*-------------------------------------------------------------------*/
static void
dfp_number_from_u64(decNumber *dn, U64 n, decContext *pset)
{
int i; /* Counter */
char zoned[32]; /* Zoned decimal work area */
/* Convert unsigned binary value to zoned decimal */
i = sizeof(zoned) - 1;
zoned[i] = '\0';
do {
zoned[--i] = (n % 10) + '0';
n /= 10;
} while(i > 1 && n > 0);
/* Convert zoned decimal value to decimal number structure */
decNumberFromString(dn, zoned+i, pset);
} /* end function dfp_number_from_u64 */
/*-------------------------------------------------------------------*/
/* Convert decimal number to 32-bit signed binary integer */
/* */
/* This subroutine is called by the CFDTR and CFXTR instructions. */
/* It converts a decimal number structure to a 32-bit signed */
/* binary integer value. The inexact condition will be set in */
/* the decimal context structure if the number is rounded to */
/* an integer. The invalid operation condition will be set if */
/* the decimal value is outside the range of a 32-bit integer. */
/* */
/* Input: */
/* b Pointer to decimal number structure */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The return value is the 32-bit signed binary integer result */
/*-------------------------------------------------------------------*/
static S32
dfp_number_to_fix32(decNumber *b, decContext *pset)
{
S32 n; /* 32-bit signed result */
int32_t scale; /* Scaling factor */
unsigned i; /* Array subscript */
BYTE packed[17]; /* 33-digit packed work area */
decNumber p, c; /* Working decimal numbers */
static U32 mp32 = 0x7FFFFFFFUL; /* Max positive fixed 32 */
static U32 mn32 = 0x80000000UL; /* Max negative fixed 32 */
static char mp32zd[]="2147483647"; /* Max positive zoned dec */
static char mn32zd[]="-2147483648"; /* Max negative zoned dec */
static BYTE mp32flag = 0; /* 1=mp32dn,mn32dn inited */
static decNumber mp32dn, mn32dn; /* Decimal maximum pos,neg */
decContext setmax; /* Working context */
/* Prime the decimal number structures representing the maximum
positive and negative numbers representable in 32 bits. Use
a 64-bit DFP working context because these numbers are too
big to be represented in the 32-bit DFP format */
if (mp32flag == 0)
{
decContextDefault(&setmax, DEC_INIT_DECIMAL64);
decNumberFromString(&mp32dn, mp32zd, &setmax);
decNumberFromString(&mn32dn, mn32zd, &setmax);
mp32flag = 1;
}
/* If operand is a NaN then set invalid operation
and return maximum negative result */
if (decNumberIsNaN(b))
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (S32)mn32;
}
/* Remove fractional part of decimal number */
decNumberToIntegralValue(&p, b, pset);
/* Special case if operand is less than maximum negative
number (including where operand is negative infinity) */
decNumberCompare(&c, b, &mn32dn, pset);
if (decNumberIsNegative(&c))
{
/* If rounded value is less than maximum negative number
then set invalid operation otherwise set inexact */
decNumberCompare(&c, &p, &mn32dn, pset);
if (decNumberIsNegative(&c))
pset->status |= DEC_IEEE_854_Invalid_operation;
else
pset->status |= DEC_IEEE_854_Inexact;
/* Return maximum negative result */
return (S32)mn32;
}
/* Special case if operand is greater than maximum positive
number (including where operand is positive infinity) */
decNumberCompare(&c, b, &mp32dn, pset);
if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0)
{