Files
org-hyperion-cules/dfp.c
Jan Jaeger 439bdbca92 Remove subversion $Id$ tag
Update copyright statement to 2012
2012-03-24 18:41:51 +11:00

4716 lines
179 KiB
C

/* DFP.C (c) Copyright Roger Bowler, 2007-2012 */
/* Decimal Floating Point instructions */
/* */
/* Released under "The Q Public License Version 1" */
/* (http://www.hercules-390.org/herclic.html) as modifications to */
/* Hercules. */
/*-------------------------------------------------------------------*/
/* 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"
#define _DFP_C_
#define _HENGINE_DLL_
#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)
{
size_t len; /* String length */
size_t 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 = 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)
{
/* If rounded value is greater than maximum positive number
then set invalid operation otherwise set inexact */
decNumberCompare(&c, &p, &mp32dn, 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 (S32)mp32;
}
/* 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 32-bit signed result */
return n;
} /* end function dfp_number_to_fix32 */
/*-------------------------------------------------------------------*/
/* Convert decimal number to 32-bit unsigned binary integer */
/* */
/* This subroutine is called by the CLFDTR and CLFXTR instructions. */
/* It converts a decimal number structure to a 32-bit unsigned */
/* 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 unsigned int. */
/* */
/* Input: */
/* b Pointer to decimal number structure */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The return value is the 32-bit unsigned integer result */
/*-------------------------------------------------------------------*/
static U32
dfp_number_to_u32(decNumber *b, decContext *pset)
{
U32 n; /* 32-bit unsigned 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 mu32 = 0xFFFFFFFFUL; /* Max unsigned integer */
static char mu32zd[]="4294967295"; /* Max unsigned zoned dec */
static BYTE mu32flag = 0; /* 1=mu32dn is initialized */
static decNumber mu32dn; /* Decimal maximum unsigned */
decContext setmax; /* Working context */
/* Prime the decimal number structure representing the maximum
unsigned number representable in 32 bits. Use a 64-bit DFP
working context because this number is too big to be
represented in the 32-bit DFP format */
if (mu32flag == 0)
{
decContextDefault(&setmax, DEC_INIT_DECIMAL64);
decNumberFromString(&mu32dn, mu32zd, &setmax);
mu32flag = 1;
}
/* If operand is a NaN then set invalid operation
and return zero result */
if (decNumberIsNaN(b))
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (U32)0;
}
/* Round decimal number to integer using current rounding mode */
decNumberToIntegralValue(&p, b, pset);
/* If rounded value is less than zero then set invalid operation
and return zero result */
if (decNumberIsNegative(&p))
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (U32)0;
}
/* If rounded value is greater than maximum unsigned number
(including where operand is positive infinity) then set
invalid operation and return maximum unsigned result */
decNumberCompare(&c, &p, &mu32dn, pset);
if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0)
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (U32)mu32;
}
/* 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;
/* Return 32-bit unsigned result */
return n;
} /* end function dfp_number_to_u32 */
/*-------------------------------------------------------------------*/
/* Convert decimal number to 64-bit unsigned binary integer */
/* */
/* This subroutine is called by the CLGDTR and CLGXTR instructions. */
/* It converts a decimal number structure to a 64-bit unsigned */
/* 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 unsigned int. */
/* */
/* Input: */
/* b Pointer to decimal number structure */
/* pset Pointer to decimal number context structure */
/* Output: */
/* The return value is the 64-bit unsigned integer result */
/*-------------------------------------------------------------------*/
static U64
dfp_number_to_u64(decNumber *b, decContext *pset)
{
U64 n; /* 64-bit unsigned 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 mu64 = 0xFFFFFFFFFFFFFFFFULL; /* Max unsigned int */
static char mu64zd[]="18446744073709551615"; /* Max zoned dec */
static BYTE mu64flag = 0; /* 1=mu64dn is initialized */
static decNumber mu64dn; /* Decimal maximum unsigned */
decContext setmax; /* Working context */
/* Prime the decimal number structure representing the maximum
unsigned number representable in 64 bits. Use a 128-bit DFP
working context because this number is too big to be
represented in the 32-bit or 64-bit DFP format */
if (mu64flag == 0)
{
decContextDefault(&setmax, DEC_INIT_DECIMAL128);
decNumberFromString(&mu64dn, mu64zd, &setmax);
mu64flag = 1;
}
/* If operand is a NaN then set invalid operation
and return zero result */
if (decNumberIsNaN(b))
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (U64)0;
}
/* Round decimal number to integer using current rounding mode */
decNumberToIntegralValue(&p, b, pset);
/* If rounded value is less than zero then set invalid operation
and return zero result */
if (decNumberIsNegative(&p))
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (U64)0;
}
/* If rounded value is greater than maximum unsigned number
(including where operand is positive infinity) then set
invalid operation and return maximum unsigned result */
decNumberCompare(&c, &p, &mu64dn, pset);
if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0)
{
pset->status |= DEC_IEEE_854_Invalid_operation;
return (U64)mu64;
}
/* 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;
/* Return 64-bit unsigned result */
return n;
} /* end function dfp_number_to_u64 */
#define _DFP_FPE_ARCH_INDEPENDENT_
#endif /*!defined(_DFP_FPE_ARCH_INDEPENDENT_)*/
#endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/
/*-------------------------------------------------------------------*/
/* Set rounding mode in decimal context structure */
/* */
/* Input: */
/* pset Pointer to decimal number context structure */
/* mask 4-bit mask value */
/* regs CPU register context */
/* Output: */
/* If mask bit X'08' is one then the rounding mode in the */
/* context structure is set according to the value (0 to 7) */
/* indicated by the low-order three bits of the mask. */
/* If mask bit X'08' is zero then the rounding mode in the */
/* context structure is set according to the value (0 to 7) */
/* of the DRM field in the FPC register. */
/*-------------------------------------------------------------------*/
static inline void
ARCH_DEP(dfp_rounding_mode) (decContext *pset, int mask, REGS *regs)
{
BYTE drm; /* Decimal rounding mode */
/* Load DRM from mask or from FPC register */
if (mask & 0x08)
drm = mask & 0x07;
else
drm = (regs->fpc & FPC_DRM) >> FPC_DRM_SHIFT;
/* Set rounding mode according to DRM value */
switch (drm) {
case DRM_RNE: pset->round = DEC_ROUND_HALF_EVEN; break;
case DRM_RTZ: pset->round = DEC_ROUND_DOWN; break;
case DRM_RTPI: pset->round = DEC_ROUND_CEILING; break;
case DRM_RTMI: pset->round = DEC_ROUND_FLOOR; break;
case DRM_RNAZ: pset->round = DEC_ROUND_HALF_UP; break;
case DRM_RNTZ: pset->round = DEC_ROUND_HALF_DOWN; break;
case DRM_RAFZ: pset->round = DEC_ROUND_UP; break;
case DRM_RFSP:
/* Rounding mode DRM_RFSP is not supported by
the decNumber library, so we arbitrarily
convert it to another mode instead... */
pset->round = DEC_ROUND_DOWN; break;
} /* end switch(drm) */
} /* end function dfp_rounding_mode */
/*-------------------------------------------------------------------*/
/* Copy a DFP short register into a decimal32 structure */
/* */
/* Input: */
/* rn FP register number */
/* xp Pointer to decimal32 structure */
/* regs CPU register context */
/*-------------------------------------------------------------------*/
static inline void
ARCH_DEP(dfp_reg_to_decimal32) (int rn, decimal32 *xp, REGS *regs)
{
int i; /* FP register subscript */
FW *fwp; /* Fullword pointer */
i = FPR2I(rn); /* Register index */
fwp = (FW*)xp; /* Convert to FW pointer */
fwp->F = regs->fpr[i]; /* Copy FPR bits 0-31 */
} /* end function dfp_reg_to_decimal32 */
/*-------------------------------------------------------------------*/
/* Load a DFP short register from a decimal32 structure */
/* */
/* Input: */
/* rn FP register number (left register of pair) */
/* xp Pointer to decimal32 structure */
/* regs CPU register context */
/*-------------------------------------------------------------------*/
static inline void
ARCH_DEP(dfp_reg_from_decimal32) (int rn, decimal32 *xp, REGS *regs)
{
int i; /* FP register subscript */
FW *fwp; /* Fullword pointer */
i = FPR2I(rn); /* Register index */
fwp = (FW*)xp; /* Convert to FW pointer */
regs->fpr[i] = fwp->F; /* Load FPR bits 0-31 */
} /* end function dfp_reg_from_decimal32 */
/*-------------------------------------------------------------------*/
/* Copy a DFP long register into a decimal64 structure */
/* */
/* Input: */
/* rn FP register number */
/* xp Pointer to decimal64 structure */
/* regs CPU register context */
/*-------------------------------------------------------------------*/
static inline void
ARCH_DEP(dfp_reg_to_decimal64) (int rn, decimal64 *xp, REGS *regs)
{
int i; /* FP register subscript */
DW *dwp; /* Doubleword pointer */
i = FPR2I(rn); /* Register index */
dwp = (DW*)xp; /* Convert to DW pointer */
dwp->F.H.F = regs->fpr[i]; /* Copy FPR bits 0-31 */
dwp->F.L.F = regs->fpr[i+1]; /* Copy FPR bits 32-63 */
} /* end function dfp_reg_to_decimal64 */
/*-------------------------------------------------------------------*/
/* Load a DFP long register from a decimal64 structure */
/* */
/* Input: */
/* rn FP register number (left register of pair) */
/* xp Pointer to decimal64 structure */
/* regs CPU register context */
/*-------------------------------------------------------------------*/
static inline void
ARCH_DEP(dfp_reg_from_decimal64) (int rn, decimal64 *xp, REGS *regs)
{
int i; /* FP register subscript */
DW *dwp; /* Doubleword pointer */
i = FPR2I(rn); /* Register index */
dwp = (DW*)xp; /* Convert to DW pointer */
regs->fpr[i] = dwp->F.H.F; /* Load FPR bits 0-31 */
regs->fpr[i+1] = dwp->F.L.F; /* Load FPR bits 32-63 */
} /* end function dfp_reg_from_decimal64 */
/*-------------------------------------------------------------------*/
/* Copy a DFP extended register into a decimal128 structure */
/* */
/* Input: */
/* rn FP register number (left register of pair) */
/* xp Pointer to decimal128 structure */
/* regs CPU register context */
/*-------------------------------------------------------------------*/
static inline void
ARCH_DEP(dfp_reg_to_decimal128) (int rn, decimal128 *xp, REGS *regs)
{
int i, j; /* FP register subscripts */
QW *qwp; /* Quadword pointer */
i = FPR2I(rn); /* Left register index */
j = i + FPREX; /* Right register index */
qwp = (QW*)xp; /* Convert to QW pointer */
qwp->F.HH.F = regs->fpr[i]; /* Copy FPR bits 0-31 */
qwp->F.HL.F = regs->fpr[i+1]; /* Copy FPR bits 32-63 */
qwp->F.LH.F = regs->fpr[j]; /* Copy FPR bits 64-95 */
qwp->F.LL.F = regs->fpr[j+1]; /* Copy FPR bits 96-127 */
} /* end function dfp_reg_to_decimal128 */
/*-------------------------------------------------------------------*/
/* Load a DFP extended register from a decimal128 structure */
/* */
/* Input: */
/* rn FP register number (left register of pair) */
/* xp Pointer to decimal128 structure */
/* regs CPU register context */
/*-------------------------------------------------------------------*/
static inline void
ARCH_DEP(dfp_reg_from_decimal128) (int rn, decimal128 *xp, REGS *regs)
{
int i, j; /* FP register subscripts */
QW *qwp; /* Quadword pointer */
i = FPR2I(rn); /* Left register index */
j = i + FPREX; /* Right register index */
qwp = (QW*)xp; /* Convert to QW pointer */
regs->fpr[i] = qwp->F.HH.F; /* Load FPR bits 0-31 */
regs->fpr[i+1] = qwp->F.HL.F; /* Load FPR bits 32-63 */
regs->fpr[j] = qwp->F.LH.F; /* Load FPR bits 64-95 */
regs->fpr[j+1] = qwp->F.LL.F; /* Load FPR bits 96-127 */
} /* end function dfp_reg_from_decimal128 */
/*-------------------------------------------------------------------*/
/* Check for DFP exception conditions */
/* */
/* This subroutine is called by the DFP instruction processing */
/* routines after the calculation has been performed but before */
/* the result is loaded into the result register (or before any */
/* storage location is updated, as the case may be). */
/* */
/* The purpose of this subroutine is to check whether any DFP */
/* exception conditions are indicated by the decimal context */
/* structure, and to initiate the appropriate action if so. */
/* */
/* Input: */
/* set Decimal number context */
/* regs CPU register context */
/* */
/* Output: */
/* Return value is DXC (data exception code) or zero. */
/* */
/* When no exception conditions are indicated, the return value */
/* is zero indicating that the instruction may proceed normally. */
/* */
/* When an exception condition exists and the corresponding mask */
/* bit in the FPC register is zero, then the corresponding flag */
/* bit is set in the FPC register. The return value is zero to */
/* indicate that the instruction may proceed normally. */
/* */
/* When an exception condition exists and the corresponding mask */
/* bit in the FPC register is one, then the DXC is set according */
/* to the type of exception, and one of two actions is taken: */
/* - if the exception is of a type which causes the instruction */
/* to be suppressed, then this subroutine raises a program */
/* exception and does not return to the calling instruction */
/* - if the exception is of a type which causes the instruction */
/* to be completed, then this subroutine returns with the */
/* DXC code as its return value. The calling instruction will */
/* then raise a program exception after storing its results. */
/*-------------------------------------------------------------------*/
static BYTE
ARCH_DEP(dfp_status_check) (decContext *pset, REGS *regs)
{
BYTE dxc = 0; /* Data exception code */
int suppress = 0; /* 1=suppress, 0=complete */
if (pset->status & DEC_IEEE_854_Invalid_operation)
{
/* An IEEE-invalid-operation condition was recognized */
if ((regs->fpc & FPC_MASK_IMI) == 0)
{
regs->fpc |= FPC_FLAG_SFI;
}
else
{
dxc = DXC_IEEE_INVALID_OP;
suppress = 1;
}
}
else if (pset->status & DEC_IEEE_854_Division_by_zero)
{
/* An IEEE-division-by-zero condition was recognized */
if ((regs->fpc & FPC_MASK_IMZ) == 0)
{
/* Division-by-zero mask is zero */
regs->fpc |= FPC_FLAG_SFZ;
}
else
{
/* Division-by-zero mask is one */
dxc = DXC_IEEE_DIV_ZERO;
suppress = 1;
}
}
else if (pset->status & DEC_IEEE_854_Overflow)
{
/* An IEEE-overflow condition was recognized */
if ((regs->fpc & FPC_MASK_IMO) == 0)
{
/* Overflow mask is zero */
regs->fpc |= FPC_FLAG_SFO;
}
else
{
/* Overflow mask is one */
dxc = (pset->status & DEC_IEEE_854_Inexact) ?
((pset->status & DEC_Rounded) ?
DXC_IEEE_OF_INEX_INCR :
DXC_IEEE_OF_INEX_TRUNC ) :
DXC_IEEE_OF_EXACT ;
}
}
else if (pset->status & DEC_IEEE_854_Underflow)
{
/* An IEEE-underflow condition was recognized */
if ((regs->fpc & FPC_MASK_IMU) == 0)
{
/* Underflow mask is zero */
if (pset->status & DEC_IEEE_854_Inexact)
{
if ((regs->fpc & FPC_MASK_IMX) == 0)
{
/* Inexact result with inexact mask zero */
regs->fpc |= (FPC_FLAG_SFU | FPC_FLAG_SFX);
}
else
{
/* Inexact result with inexact mask one */
regs->fpc |= FPC_FLAG_SFU;
dxc = (pset->status & DEC_Rounded) ?
DXC_IEEE_INEXACT_INCR :
DXC_IEEE_INEXACT_TRUNC ;
}
}
}
else
{
/* Underflow mask is one */
if (pset->status & DEC_IEEE_854_Inexact)
{
/* Underflow with inexact result */
dxc = (pset->status & DEC_Rounded) ?
DXC_IEEE_UF_INEX_INCR :
DXC_IEEE_UF_INEX_TRUNC ;
}
else
{
/* Underflow with exact result */
dxc = DXC_IEEE_UF_EXACT;
}
}
}
else if (pset->status & DEC_IEEE_854_Inexact)
{
/* An IEEE-inexact condition was recognized */
if ((regs->fpc & FPC_MASK_IMX) == 0)
{
/* Inexact mask is zero */
regs->fpc |= FPC_FLAG_SFX;
}
else
{
/* Inexact mask is one */
dxc = (pset->status & DEC_Rounded) ?
DXC_IEEE_INEXACT_INCR :
DXC_IEEE_INEXACT_TRUNC ;
}
}
/* If suppression is indicated, raise a data exception */
if (suppress)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
/* Otherwise return to complete the instruction */
return dxc;
} /* end function dfp_status_check */
/*-------------------------------------------------------------------*/
/* B3DA AXTR - Add DFP Extended Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(add_dfp_ext_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal128 x1, x2, x3; /* Extended DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
DFPREGPAIR3_CHECK(r1, r2, r3, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Add FP register r3 to FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
decimal128ToNumber(&x2, &d2);
decimal128ToNumber(&x3, &d3);
decNumberAdd(&d1, &d2, &d3, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&d1) ? 3 :
decNumberIsZero(&d1) ? 0 :
decNumberIsNegative(&d1) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(add_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3D2 ADTR - Add DFP Long Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(add_dfp_long_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal64 x1, x2, x3; /* Long DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Add FP register r3 to FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
decimal64ToNumber(&x2, &d2);
decimal64ToNumber(&x3, &d3);
decNumberAdd(&d1, &d2, &d3, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&d1) ? 3 :
decNumberIsZero(&d1) ? 0 :
decNumberIsNegative(&d1) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(add_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3EC CXTR - Compare DFP Extended Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(compare_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
decimal128 x1, x2; /* Extended DFP values */
decNumber d1, d2, dr; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Compare FP register r1 with FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x1, &d1);
decimal128ToNumber(&x2, &d2);
decNumberCompare(&dr, &d1, &d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&dr) ? 3 :
decNumberIsZero(&dr) ? 0 :
decNumberIsNegative(&dr) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(compare_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3E4 CDTR - Compare DFP Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(compare_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
decimal64 x1, x2; /* Long DFP values */
decNumber d1, d2, dr; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Compare FP register r1 with FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x1, &d1);
decimal64ToNumber(&x2, &d2);
decNumberCompare(&dr, &d1, &d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&dr) ? 3 :
decNumberIsZero(&dr) ? 0 :
decNumberIsNegative(&dr) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(compare_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3E8 KXTR - Compare and Signal DFP Extended Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(compare_and_signal_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
decimal128 x1, x2; /* Extended DFP values */
decNumber d1, d2, dr; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Compare FP register r1 with FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x1, &d1);
decimal128ToNumber(&x2, &d2);
decNumberCompare(&dr, &d1, &d2, &set);
/* Force signaling condition if result is a NaN */
if (decNumberIsNaN(&dr))
set.status |= DEC_IEEE_854_Invalid_operation;
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&dr) ? 3 :
decNumberIsZero(&dr) ? 0 :
decNumberIsNegative(&dr) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(compare_and_signal_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3E0 KDTR - Compare and Signal DFP Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(compare_and_signal_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
decimal64 x1, x2; /* Long DFP values */
decNumber d1, d2, dr; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Compare FP register r1 with FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x1, &d1);
decimal64ToNumber(&x2, &d2);
decNumberCompare(&dr, &d1, &d2, &set);
/* Force signaling condition if result is a NaN */
if (decNumberIsNaN(&dr))
set.status |= DEC_IEEE_854_Invalid_operation;
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&dr) ? 3 :
decNumberIsZero(&dr) ? 0 :
decNumberIsNegative(&dr) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(compare_and_signal_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3FC CEXTR - Compare Exponent DFP Extended Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(compare_exponent_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
decimal128 x1, x2; /* Extended DFP values */
decNumber d1, d2; /* Working decimal numbers */
decContext set; /* Working context */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Convert FP register values to numbers */
ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x1, &d1);
decimal128ToNumber(&x2, &d2);
/* Compare exponents and set condition code */
regs->psw.cc = dfp_compare_exponent(&d1, &d2);
} /* end DEF_INST(compare_exponent_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3F4 CEDTR - Compare Exponent DFP Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(compare_exponent_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
decimal64 x1, x2; /* Long DFP values */
decNumber d1, d2; /* Working decimal numbers */
decContext set; /* Working context */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Convert FP register values to numbers */
ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x1, &d1);
decimal64ToNumber(&x2, &d2);
/* Compare exponents and set condition code */
regs->psw.cc = dfp_compare_exponent(&d1, &d2);
} /* end DEF_INST(compare_exponent_dfp_long_reg) */
#if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/
/*-------------------------------------------------------------------*/
/* B959 CXFTR - Convert from fixed 32 to DFP Extended Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_fix32_to_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
S32 n2; /* Value of R2 register */
decimal128 x1; /* Extended DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load 32-bit binary integer value from r2 register */
n2 = (S32)(regs->GR_L(r2));
/* Convert binary integer to extended DFP format */
dfp_number_from_fix32(&d1, n2, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(convert_fix32_to_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B951 CDFTR - Convert from fixed 32 to DFP Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_fix32_to_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
S32 n2; /* Value of R2 register */
decimal64 x1; /* Long DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load 32-bit binary integer value from r2 register */
n2 = (S32)(regs->GR_L(r2));
/* Convert binary integer to long DFP format */
dfp_number_from_fix32(&d1, n2, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(convert_fix32_to_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B95B CXLFTR - Convert from unsigned 32 to DFP Ext Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_u32_to_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U32 n2; /* Value of R2 register */
decimal128 x1; /* Extended DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load 32-bit unsigned value from r2 register */
n2 = regs->GR_L(r2);
/* Convert unsigned binary integer to extended DFP format */
dfp_number_from_u32(&d1, n2, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(convert_u32_to_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B953 CDLFTR - Convert from unsigned 32 to DFP Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_u32_to_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U32 n2; /* Value of R2 register */
decimal64 x1; /* Long DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load 32-bit unsigned value from r2 register */
n2 = regs->GR_L(r2);
/* Convert unsigned binary integer to long DFP format */
dfp_number_from_u32(&d1, n2, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(convert_u32_to_dfp_long_reg) */
#endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/
/*-------------------------------------------------------------------*/
/* B3F9 CXGTR - Convert from fixed 64 to DFP Extended Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_fix64_to_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
S64 n2; /* Value of R2 register */
decimal128 x1; /* Extended DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Load 64-bit binary integer value from r2 register */
n2 = (S64)(regs->GR_G(r2));
/* Convert binary integer to extended DFP format */
dfp_number_from_fix64(&d1, n2, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(convert_fix64_to_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3F1 CDGTR - Convert from fixed 64 to DFP Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_fix64_to_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
S64 n2; /* Value of R2 register */
decimal64 x1; /* Long DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Load 64-bit binary integer value from r2 register */
n2 = (S64)(regs->GR_G(r2));
/* Convert binary integer to long DFP format */
dfp_number_from_fix64(&d1, n2, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_fix64_to_dfp_long_reg) */
#if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/
/*-------------------------------------------------------------------*/
/* B95A CXLGTR - Convert from unsigned 64 to DFP Ext Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_u64_to_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U64 n2; /* Value of R2 register */
decimal128 x1; /* Extended DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load 64-bit unsigned value from r2 register */
n2 = regs->GR_G(r2);
/* Convert unsigned binary integer to extended DFP format */
dfp_number_from_u64(&d1, n2, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(convert_u64_to_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B952 CDLGTR - Convert from unsigned 64 to DFP Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_u64_to_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U64 n2; /* Value of R2 register */
decimal64 x1; /* Long DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load 64-bit unsigned value from r2 register */
n2 = regs->GR_G(r2);
/* Convert unsigned binary integer to long DFP format */
dfp_number_from_u64(&d1, n2, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(convert_u64_to_dfp_long_reg) */
#endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/
/*-------------------------------------------------------------------*/
/* B3FB CXSTR - Convert from signed BCD (128-bit to DFP ext) [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_sbcd128_to_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
decimal128 x1; /* Extended DFP values */
decNumber dwork, *dp; /* Working decimal numbers */
decContext set; /* Working context */
BYTE pwork[16]; /* 31-digit packed work area */
int32_t scale = 0; /* Scaling factor */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
ODD_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Store general register pair in work area */
STORE_DW(pwork, regs->GR_G(r2));
STORE_DW(pwork+8, regs->GR_G(r2+1));
/* Convert signed BCD to internal number format */
dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Data exception if digits or sign was invalid */
if (dp == NULL)
{
regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
/* Convert internal number to DFP extended format */
decimal128FromNumber(&x1, &dwork, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(convert_sbcd128_to_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3F3 CDSTR - Convert from signed BCD (64-bit to DFP long) [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_sbcd64_to_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
decimal64 x1; /* Long DFP values */
decNumber dwork, *dp; /* Working decimal numbers */
decContext set; /* Working context */
BYTE pwork[8]; /* 15-digit packed work area */
int32_t scale = 0; /* Scaling factor */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Store general register in work area */
STORE_DW(pwork, regs->GR_G(r2));
/* Convert signed BCD to internal number format */
dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Data exception if digits or sign was invalid */
if (dp == NULL)
{
regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
/* Convert internal number to DFP long format */
decimal64FromNumber(&x1, &dwork, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(convert_sbcd64_to_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3FA CXUTR - Convert from unsigned BCD (128-bit to DFP ext) [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_ubcd128_to_dfp_ext_reg)
{
unsigned i; /* Array subscript */
int r1, r2; /* Values of R fields */
decimal128 x1; /* Extended DFP values */
decNumber dwork, *dp; /* Working decimal numbers */
decContext set; /* Working context */
BYTE pwork[17]; /* 33-digit packed work area */
int32_t scale = 0; /* Scaling factor */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
ODD_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Store general register pair in work area */
pwork[0] = 0;
STORE_DW(pwork+1, regs->GR_G(r2));
STORE_DW(pwork+9, regs->GR_G(r2+1));
/* Convert unsigned BCD to signed BCD */
for (i = 0; i < sizeof(pwork)-1; i++)
pwork[i] = ((pwork[i] & 0x0F) << 4) | (pwork[i+1] >> 4);
pwork[i] = ((pwork[i] & 0x0F) << 4) | 0x0F;
/* Convert signed BCD to internal number format */
dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Data exception if digits invalid */
if (dp == NULL)
{
regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
/* Convert internal number to DFP extended format */
decimal128FromNumber(&x1, &dwork, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(convert_ubcd128_to_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3F2 CDUTR - Convert from unsigned BCD (64-bit to DFP long) [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_ubcd64_to_dfp_long_reg)
{
unsigned i; /* Array subscript */
int r1, r2; /* Values of R fields */
decimal64 x1; /* Long DFP values */
decNumber dwork, *dp; /* Working decimal numbers */
decContext set; /* Working context */
BYTE pwork[9]; /* 17-digit packed work area */
int32_t scale = 0; /* Scaling factor */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Store general register in work area */
pwork[0] = 0;
STORE_DW(pwork+1, regs->GR_G(r2));
/* Convert unsigned BCD to signed BCD */
for (i = 0; i < sizeof(pwork)-1; i++)
pwork[i] = ((pwork[i] & 0x0F) << 4) | (pwork[i+1] >> 4);
pwork[i] = ((pwork[i] & 0x0F) << 4) | 0x0F;
/* Convert signed BCD to internal number format */
dp = decPackedToNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Data exception if digits or sign was invalid */
if (dp == NULL)
{
regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
/* Convert internal number to DFP long format */
decimal64FromNumber(&x1, &dwork, &set);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(convert_ubcd64_to_dfp_long_reg) */
#if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/
/*-------------------------------------------------------------------*/
/* B949 CFXTR - Convert from DFP Extended Register to fixed 32 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_ext_to_fix32_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
S32 n1; /* Result value */
decimal128 x2; /* Extended DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load extended DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &d2);
/* Convert decimal number to 32-bit binary integer */
n1 = dfp_number_to_fix32(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_L(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_ext_to_fix32_reg) */
/*-------------------------------------------------------------------*/
/* B941 CFDTR - Convert from DFP Long Register to fixed 32 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_long_to_fix32_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
S32 n1; /* Result value */
decimal64 x2; /* Long DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load long DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d2);
/* Convert decimal number to 32-bit binary integer */
n1 = dfp_number_to_fix32(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_L(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_long_to_fix32_reg) */
/*-------------------------------------------------------------------*/
/* B94B CLFXTR - Convert from DFP Ext Register to unsigned 32 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_ext_to_u32_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U32 n1; /* Result value */
decimal128 x2; /* Extended DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load extended DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &d2);
/* Convert decimal number to 32-bit unsigned integer */
n1 = dfp_number_to_u32(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_L(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_ext_to_u32_reg) */
/*-------------------------------------------------------------------*/
/* B943 CLFDTR - Convert from DFP Long Register to unsigned 32 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_long_to_u32_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U32 n1; /* Result value */
decimal64 x2; /* Long DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load long DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d2);
/* Convert decimal number to 32-bit unsigned integer */
n1 = dfp_number_to_u32(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_L(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_long_to_u32_reg) */
#endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/
/*-------------------------------------------------------------------*/
/* B3E9 CGXTR - Convert from DFP Extended Register to fixed 64 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_ext_to_fix64_reg)
{
int r1, r2; /* Values of R fields */
int m3; /* Values of M fields */
S64 n1; /* Result value */
decimal128 x2; /* Extended DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_M(inst, regs, r1, r2, m3);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load extended DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &d2);
/* Convert decimal number to 64-bit binary integer */
n1 = dfp_number_to_fix64(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_G(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_ext_to_fix64_reg) */
/*-------------------------------------------------------------------*/
/* B3E1 CGDTR - Convert from DFP Long Register to fixed 64 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_long_to_fix64_reg)
{
int r1, r2; /* Values of R fields */
int m3; /* Values of M fields */
S64 n1; /* Result value */
decimal64 x2; /* Long DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_M(inst, regs, r1, r2, m3);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load long DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d2);
/* Convert decimal number to 64-bit binary integer */
n1 = dfp_number_to_fix64(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_G(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_long_to_fix64_reg) */
#if defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY) /*810*/
/*-------------------------------------------------------------------*/
/* B94A CLGXTR - Convert from DFP Ext Register to unsigned 64 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_ext_to_u64_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U64 n1; /* Result value */
decimal128 x2; /* Extended DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load extended DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &d2);
/* Convert decimal number to 64-bit unsigned integer */
n1 = dfp_number_to_u64(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_G(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_ext_to_u64_reg) */
/*-------------------------------------------------------------------*/
/* B942 CLGDTR - Convert from DFP Long Register to unsigned 64 [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_long_to_u64_reg)
{
int r1, r2; /* Values of R fields */
int m3, m4; /* Values of M fields */
U64 n1; /* Result value */
decimal64 x2; /* Long DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load long DFP value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d2);
/* Convert decimal number to 64-bit unsigned integer */
n1 = dfp_number_to_u64(&d2, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into general register r1 */
regs->GR_G(r1) = n1;
/* Set condition code */
regs->psw.cc = (set.status & DEC_IEEE_854_Invalid_operation) ? 3 :
decNumberIsZero(&d2) ? 0 :
decNumberIsNegative(&d2) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(convert_dfp_long_to_u64_reg) */
#endif /*defined(FEATURE_FLOATING_POINT_EXTENSION_FACILITY)*/ /*810*/
/*-------------------------------------------------------------------*/
/* B3EB CSXTR - Convert to signed BCD (DFP ext to 128-bit) [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_ext_to_sbcd128_reg)
{
int r1, r2; /* Values of R fields */
int m4; /* Values of M fields */
decimal128 x2; /* Extended DFP values */
decNumber dwork; /* Working decimal number */
decContext set; /* Working context */
int32_t scale; /* Scaling factor */
BYTE pwork[17]; /* 33-digit packed work area */
RRF_M4(inst, regs, r1, r2, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
ODD_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP extended number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &dwork);
/* If NaN or Inf then use coefficient only */
if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork)))
{
dfp128_clear_cf_and_bxcf(&x2);
decimal128ToNumber(&x2, &dwork);
}
/* Convert number to signed BCD in work area */
decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Make the plus-sign X'F' if m4 bit 3 is one */
if ((m4 & 0x01) && !decNumberIsNegative(&dwork))
pwork[sizeof(pwork)-1] |= 0x0F;
/* Load general register pair r1 and r1+1 from
rightmost 31 packed decimal digits of work area */
FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-16);
FETCH_DW(regs->GR_G(r1+1), pwork+sizeof(pwork)-8);
} /* end DEF_INST(convert_dfp_ext_to_sbcd128_reg) */
/*-------------------------------------------------------------------*/
/* B3E3 CSDTR - Convert to signed BCD (DFP long to 64-bit) [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_long_to_sbcd64_reg)
{
int r1, r2; /* Values of R fields */
int m4; /* Values of M fields */
decimal64 x2; /* Long DFP values */
decNumber dwork; /* Working decimal number */
decContext set; /* Working context */
int32_t scale; /* Scaling factor */
BYTE pwork[9]; /* 17-digit packed work area */
RRF_M4(inst, regs, r1, r2, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP long number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &dwork);
/* If NaN or Inf then use coefficient only */
if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork)))
{
dfp64_clear_cf_and_bxcf(&x2);
decimal64ToNumber(&x2, &dwork);
}
/* Convert number to signed BCD in work area */
decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Make the plus-sign X'F' if m4 bit 3 is one */
if ((m4 & 0x01) && !decNumberIsNegative(&dwork))
pwork[sizeof(pwork)-1] |= 0x0F;
/* Load general register r1 from rightmost
15 packed decimal digits of work area */
FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-8);
} /* end DEF_INST(convert_dfp_long_to_sbcd64_reg) */
/*-------------------------------------------------------------------*/
/* B3EA CUXTR - Convert to unsigned BCD (DFP ext to 128-bit) [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_ext_to_ubcd128_reg)
{
int i; /* Array subscript */
int r1, r2; /* Values of R fields */
decimal128 x2; /* Extended DFP values */
decNumber dwork; /* Working decimal number */
decContext set; /* Working context */
int32_t scale; /* Scaling factor */
BYTE pwork[17]; /* 33-digit packed work area */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
ODD_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP extended number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &dwork);
/* If NaN or Inf then use coefficient only */
if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork)))
{
dfp128_clear_cf_and_bxcf(&x2);
decimal128ToNumber(&x2, &dwork);
}
/* Convert number to signed BCD in work area */
decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Convert signed BCD to unsigned BCD */
for (i = sizeof(pwork)-1; i > 0; i--)
pwork[i] = (pwork[i] >> 4) | ((pwork[i-1] & 0x0F) << 4);
/* Load general register pair r1 and r1+1 from
rightmost 32 packed decimal digits of work area */
FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-16);
FETCH_DW(regs->GR_G(r1+1), pwork+sizeof(pwork)-8);
} /* end DEF_INST(convert_dfp_ext_to_ubcd128_reg) */
/*-------------------------------------------------------------------*/
/* B3E2 CUDTR - Convert to unsigned BCD (DFP long to 64-bit) [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(convert_dfp_long_to_ubcd64_reg)
{
int i; /* Array subscript */
int r1, r2; /* Values of R fields */
decimal64 x2; /* Long DFP values */
decNumber dwork; /* Working decimal number */
decContext set; /* Working context */
int32_t scale; /* Scaling factor */
BYTE pwork[9]; /* 17-digit packed work area */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP long number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &dwork);
/* If NaN or Inf then use coefficient only */
if (decNumberIsNaN(&dwork) || (decNumberIsInfinite(&dwork)))
{
dfp64_clear_cf_and_bxcf(&x2);
decimal64ToNumber(&x2, &dwork);
}
/* Convert number to signed BCD in work area */
decPackedFromNumber(pwork, sizeof(pwork), &scale, &dwork);
/* Convert signed BCD to unsigned BCD */
for (i = sizeof(pwork)-1; i > 0; i--)
pwork[i] = (pwork[i] >> 4) | ((pwork[i-1] & 0x0F) << 4);
/* Load general register r1 from rightmost
16 packed decimal digits of work area */
FETCH_DW(regs->GR_G(r1), pwork+sizeof(pwork)-8);
} /* end DEF_INST(convert_dfp_long_to_ubcd64_reg) */
/*-------------------------------------------------------------------*/
/* B3D9 DXTR - Divide DFP Extended Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(divide_dfp_ext_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal128 x1, x2, x3; /* Extended DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
DFPREGPAIR3_CHECK(r1, r2, r3, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Divide FP register r2 by FP register r3 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
decimal128ToNumber(&x2, &d2);
decimal128ToNumber(&x3, &d3);
decNumberDivide(&d1, &d2, &d3, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(divide_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3D1 DDTR - Divide DFP Long Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(divide_dfp_long_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal64 x1, x2, x3; /* Long DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Divide FP register r2 by FP register r3 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
decimal64ToNumber(&x2, &d2);
decimal64ToNumber(&x3, &d3);
decNumberDivide(&d1, &d2, &d3, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(divide_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3ED EEXTR - Extract Biased Exponent DFP Extended Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(extract_biased_exponent_dfp_ext_to_fix64_reg)
{
int r1, r2; /* Values of R fields */
decimal128 x2; /* Extended DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
S64 exponent; /* Biased exponent */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP extended number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
/* Convert to internal decimal number format */
decimal128ToNumber(&x2, &d2);
/* Calculate the biased exponent */
if (decNumberIsInfinite(&d2))
exponent = -1;
else if (decNumberIsQNaN(&d2))
exponent = -2;
else if (decNumberIsSNaN(&d2))
exponent = -3;
else
exponent = d2.exponent + DECIMAL128_Bias;
/* Load result into general register r1 */
regs->GR(r1) = exponent;
} /* end DEF_INST(extract_biased_exponent_dfp_ext_to_fix64_reg) */
/*-------------------------------------------------------------------*/
/* B3E5 EEDTR - Extract Biased Exponent DFP Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(extract_biased_exponent_dfp_long_to_fix64_reg)
{
int r1, r2; /* Values of R fields */
decimal64 x2; /* Long DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
S64 exponent; /* Biased exponent */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP long number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
/* Convert to internal decimal number format */
decimal64ToNumber(&x2, &d2);
/* Calculate the biased exponent */
if (decNumberIsInfinite(&d2))
exponent = -1;
else if (decNumberIsQNaN(&d2))
exponent = -2;
else if (decNumberIsSNaN(&d2))
exponent = -3;
else
exponent = d2.exponent + DECIMAL64_Bias;
/* Load result into general register r1 */
regs->GR(r1) = exponent;
} /* end DEF_INST(extract_biased_exponent_dfp_long_to_fix64_reg) */
/*-------------------------------------------------------------------*/
/* B3EF ESXTR - Extract Significance DFP Extended Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(extract_significance_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
decimal128 x2; /* Extended DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
S64 digits; /* Number of decimal digits */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP extended number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
/* Convert to internal decimal number format */
decimal128ToNumber(&x2, &d2);
/* Calculate number of significant digits */
if (decNumberIsZero(&d2))
digits = 0;
else if (decNumberIsInfinite(&d2))
digits = -1;
else if (decNumberIsQNaN(&d2))
digits = -2;
else if (decNumberIsSNaN(&d2))
digits = -3;
else
digits = d2.digits;
/* Load result into general register r1 */
regs->GR(r1) = digits;
} /* end DEF_INST(extract_significance_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3E7 ESDTR - Extract Significance DFP Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(extract_significance_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
decimal64 x2; /* Long DFP value */
decNumber d2; /* Working decimal number */
decContext set; /* Working context */
S64 digits; /* Number of decimal digits */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP long number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
/* Convert to internal decimal number format */
decimal64ToNumber(&x2, &d2);
/* Calculate number of significant digits */
if (decNumberIsZero(&d2))
digits = 0;
else if (decNumberIsInfinite(&d2))
digits = -1;
else if (decNumberIsQNaN(&d2))
digits = -2;
else if (decNumberIsSNaN(&d2))
digits = -3;
else
digits = d2.digits;
/* Load result into general register r1 */
regs->GR(r1) = digits;
} /* end DEF_INST(extract_significance_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3FE IEXTR - Insert Biased Exponent DFP Extended Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(insert_biased_exponent_fix64_to_dfp_ext_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal128 x1, x3; /* Extended DFP values */
decNumber d; /* Working decimal number */
decContext set; /* Working context */
S64 bexp; /* Biased exponent */
RRF_M(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r3, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load biased exponent from general register r2 */
bexp = (S64)(regs->GR(r2));
/* Load DFP extended number from FP register r3 */
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
/* Insert biased exponent into number */
if (bexp > DECIMAL128_Ehigh || bexp == -2 || bexp <= -4)
{
/* Result is a QNaN with re-encoded coefficient-continuation */
dfp128_clear_cf_and_bxcf(&x3);
decimal128ToNumber(&x3, &d);
decimal128FromNumber(&x1, &d, &set);
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
}
else if (bexp == -3)
{
/* Result is a SNaN with re-encoded coefficient-continuation */
dfp128_clear_cf_and_bxcf(&x3);
decimal128ToNumber(&x3, &d);
decimal128FromNumber(&x1, &d, &set);
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
}
else if (bexp == -1) /* Infinity */
{
/* Result is Infinity with re-encoded coefficient-continuation */
dfp128_clear_cf_and_bxcf(&x3);
decimal128ToNumber(&x3, &d);
decimal128FromNumber(&x1, &d, &set);
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF);
}
else
{
decimal128ToNumber(&x3, &d);
/* Clear CF and BXCF if source is Infinity or NaN */
if (decNumberIsInfinite(&d) || decNumberIsNaN(&d))
{
dfp128_clear_cf_and_bxcf(&x3);
decimal128ToNumber(&x3, &d);
}
/* Update exponent and re-encode coefficient-continuation */
d.exponent = bexp - DECIMAL128_Bias;
decimal128FromNumber(&x1, &d, &set);
}
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(insert_biased_exponent_fix64_to_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3F6 IEDTR - Insert Biased Exponent DFP Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(insert_biased_exponent_fix64_to_dfp_long_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal64 x1, x3; /* Long DFP values */
decNumber d; /* Working decimal number */
decContext set; /* Working context */
S64 bexp; /* Biased exponent */
RRF_M(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load biased exponent from general register r2 */
bexp = (S64)(regs->GR(r2));
/* Load DFP long number from FP register r3 */
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
/* Insert biased exponent into number */
if (bexp > DECIMAL64_Ehigh || bexp == -2 || bexp <= -4)
{
/* Result is a QNaN with re-encoded coefficient-continuation */
dfp64_clear_cf_and_bxcf(&x3);
decimal64ToNumber(&x3, &d);
decimal64FromNumber(&x1, &d, &set);
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
}
else if (bexp == -3)
{
/* Result is a SNaN with re-encoded coefficient-continuation */
dfp64_clear_cf_and_bxcf(&x3);
decimal64ToNumber(&x3, &d);
decimal64FromNumber(&x1, &d, &set);
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
}
else if (bexp == -1) /* Infinity */
{
/* Result is Infinity with re-encoded coefficient-continuation */
dfp64_clear_cf_and_bxcf(&x3);
decimal64ToNumber(&x3, &d);
decimal64FromNumber(&x1, &d, &set);
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF);
}
else
{
decimal64ToNumber(&x3, &d);
/* Clear CF and BXCF if source is Infinity or NaN */
if (decNumberIsInfinite(&d) || decNumberIsNaN(&d))
{
dfp64_clear_cf_and_bxcf(&x3);
decimal64ToNumber(&x3, &d);
}
/* Update exponent and re-encode coefficient-continuation */
d.exponent = bexp - DECIMAL64_Bias;
decimal64FromNumber(&x1, &d, &set);
}
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(insert_biased_exponent_fix64_to_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3DE LTXTR - Load and Test DFP Extended Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_and_test_dfp_ext_reg)
{
int r1, r2; /* Values of R fields */
decimal128 x1, x2; /* Extended DFP values */
decNumber d; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &d);
/* For SNaN, force signaling condition and convert to QNaN */
if (decNumberIsSNaN(&d))
{
set.status |= DEC_IEEE_854_Invalid_operation;
d.bits &= ~DECSNAN;
d.bits |= DECNAN;
}
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Reencode value and load into FP register r1 */
decimal128FromNumber(&x1, &d, &set);
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&d) ? 3 :
decNumberIsZero(&d) ? 0 :
decNumberIsNegative(&d) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_and_test_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3D6 LTDTR - Load and Test DFP Long Register [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_and_test_dfp_long_reg)
{
int r1, r2; /* Values of R fields */
decimal64 x1, x2; /* Long DFP values */
decNumber d; /* Working decimal number */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRE(inst, regs, r1, r2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load value from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d);
/* For SNaN, force signaling condition and convert to QNaN */
if (decNumberIsSNaN(&d))
{
set.status |= DEC_IEEE_854_Invalid_operation;
d.bits &= ~DECSNAN;
d.bits |= DECNAN;
}
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Reencode value and load into FP register r1 */
decimal64FromNumber(&x1, &d, &set);
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&d) ? 3 :
decNumberIsZero(&d) ? 0 :
decNumberIsNegative(&d) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_and_test_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3DF FIXTR - Load FP Integer DFP Extended Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(load_fp_int_dfp_ext_reg)
{
int r1, r2, m3, m4; /* Values of R and M fields */
decimal128 x1, x2; /* Extended DFP values */
decNumber d1, d2, dc; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load decimal number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &d2);
if (decNumberIsInfinite(&d2) == 0 && decNumberIsNaN(&d2) == 0)
{
/* Remove fractional part of decimal number */
decNumberToIntegralValue(&d1, &d2, &set);
/* Raise inexact condition if M4 bit 1 is zero and
result differs in value from original value */
if ((m4 & 0x04) == 0)
{
decNumberCompare(&dc, &d1, &d2, &set);
if (decNumberIsZero(&dc) == 0)
{
set.status |= DEC_IEEE_854_Inexact;
if (decNumberIsNegative(&dc) == decNumberIsNegative(&d2))
set.status |= DEC_Rounded;
}
}
}
else
{
/* Propagate NaN or default infinity */
decNumberCopy(&d1, &d2);
/* For SNaN, force signaling condition and convert to QNaN */
if (decNumberIsSNaN(&d2))
{
set.status |= DEC_IEEE_854_Invalid_operation;
d1.bits &= ~DECSNAN;
d1.bits |= DECNAN;
}
}
/* Convert result to extended DFP format */
decimal128FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_fp_int_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3D7 FIDTR - Load FP Integer DFP Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(load_fp_int_dfp_long_reg)
{
int r1, r2, m3, m4; /* Values of R and M fields */
decimal64 x1, x2; /* Long DFP values */
decNumber d1, d2, dc; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load decimal number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d2);
if (decNumberIsInfinite(&d2) == 0 && decNumberIsNaN(&d2) == 0)
{
/* Remove fractional part of decimal number */
decNumberToIntegralValue(&d1, &d2, &set);
/* Raise inexact condition if M4 bit 1 is zero and
result differs in value from original value */
if ((m4 & 0x04) == 0)
{
decNumberCompare(&dc, &d1, &d2, &set);
if (decNumberIsZero(&dc) == 0)
{
set.status |= DEC_IEEE_854_Inexact;
if (decNumberIsNegative(&dc) == decNumberIsNegative(&d2))
set.status |= DEC_Rounded;
}
}
}
else
{
/* Propagate NaN or default infinity */
decNumberCopy(&d1, &d2);
/* For SNaN, force signaling condition and convert to QNaN */
if (decNumberIsSNaN(&d2))
{
set.status |= DEC_IEEE_854_Invalid_operation;
d1.bits &= ~DECSNAN;
d1.bits |= DECNAN;
}
}
/* Convert result to long DFP format */
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_fp_int_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3DC LXDTR - Load Lengthened DFP Long to Extended Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(load_lengthened_dfp_long_to_ext_reg)
{
int r1, r2, m4; /* Values of R and M fields */
decimal128 x1; /* Extended DFP value */
decimal64 x2; /* Long DFP value */
decNumber d1, d2; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_M4(inst, regs, r1, r2, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP long number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d2);
/* Convert number to DFP extended format */
if (decNumberIsInfinite(&d2) && (m4 & 0x08))
{
/* For Inf with mask bit 0 set, propagate the digits */
dfp64_clear_cf_and_bxcf(&x2);
decimal64ToNumber(&x2, &d1);
decimal128FromNumber(&x1, &d1, &set);
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF);
}
else if (decNumberIsNaN(&d2))
{
decimal64ToNumber(&x2, &d1);
/* For SNaN with mask bit 0 off, convert to a QNaN
and raise signaling condition */
if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0)
{
set.status |= DEC_IEEE_854_Invalid_operation;
d1.bits &= ~DECSNAN;
d1.bits |= DECNAN;
}
decimal128FromNumber(&x1, &d1, &set);
}
else
{
decNumberCopy(&d1, &d2);
decimal128FromNumber(&x1, &d1, &set);
}
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_lengthened_dfp_long_to_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3D4 LDETR - Load Lengthened DFP Short to Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(load_lengthened_dfp_short_to_long_reg)
{
int r1, r2, m4; /* Values of R and M fields */
decimal64 x1; /* Long DFP value */
decimal32 x2; /* Short DFP value */
decNumber d1, d2; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_M4(inst, regs, r1, r2, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP short number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal32)(r2, &x2, regs);
decimal32ToNumber(&x2, &d2);
/* Convert number to DFP long format */
if (decNumberIsInfinite(&d2) && (m4 & 0x08))
{
/* For Inf with mask bit 0 set, propagate the digits */
dfp32_clear_cf_and_bxcf(&x2);
decimal32ToNumber(&x2, &d1);
decimal64FromNumber(&x1, &d1, &set);
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF);
}
else if (decNumberIsNaN(&d2))
{
decimal32ToNumber(&x2, &d1);
/* For SNaN with mask bit 0 off, convert to a QNaN
and raise signaling condition */
if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0)
{
set.status |= DEC_IEEE_854_Invalid_operation;
d1.bits &= ~DECSNAN;
d1.bits |= DECNAN;
}
decimal64FromNumber(&x1, &d1, &set);
}
else
{
decNumberCopy(&d1, &d2);
decimal64FromNumber(&x1, &d1, &set);
}
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_lengthened_dfp_short_to_long_reg) */
/*-------------------------------------------------------------------*/
/* B3DD LDXTR - Load Rounded DFP Extended to Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(load_rounded_dfp_ext_to_long_reg)
{
int r1, r2, m3, m4; /* Values of R and M fields */
decimal64 x1; /* Long DFP value */
decimal128 x2; /* Extended DFP value */
decNumber d1, d2; /* Working decimal numbers */
decContext set; /* Working context */
int32_t scale; /* Scaling factor */
BYTE pwork[17]; /* 33-digit packed work area */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r2, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load DFP extended number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
decimal128ToNumber(&x2, &d2);
/* Convert number to DFP long format */
if ((decNumberIsInfinite(&d2) && (m4 & 0x08))
|| decNumberIsNaN(&d2))
{
/* For Inf with mask bit 0 set, or for QNan or SNan,
propagate the low 15 digits */
dfp128_clear_cf_and_bxcf(&x2);
decimal128ToNumber(&x2, &d1);
decPackedFromNumber(pwork, sizeof(pwork), &scale, &d1);
scale = 0;
decPackedToNumber(pwork+sizeof(pwork)-8, 8, &scale, &d1);
decimal64FromNumber(&x1, &d1, &set);
if (decNumberIsInfinite(&d2))
{
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF);
}
else if (decNumberIsQNaN(&d2))
{
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
}
else /* it is an SNaN */
{
/* For SNaN with mask bit 0 off, convert to a QNaN
and raise signaling condition */
if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0)
{
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
set.status |= DEC_IEEE_854_Invalid_operation;
}
else
{
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
}
}
}
else
{
/* For finite number, load value rounded to long DFP format,
or for Inf with mask bit 0 not set, load default infinity */
decNumberCopy(&d1, &d2);
decimal64FromNumber(&x1, &d1, &set);
}
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_rounded_dfp_ext_to_long_reg) */
/*-------------------------------------------------------------------*/
/* B3D5 LEDTR - Load Rounded DFP Long to Short Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(load_rounded_dfp_long_to_short_reg)
{
int r1, r2, m3, m4; /* Values of R and M fields */
decimal32 x1; /* Short DFP value */
decimal64 x2; /* Long DFP value */
decNumber d1, d2; /* Working decimal numbers */
decContext set; /* Working context */
int32_t scale; /* Scaling factor */
BYTE pwork[9]; /* 17-digit packed work area */
BYTE dxc; /* Data exception code */
RRF_MM(inst, regs, r1, r2, m3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m3, regs);
/* Load DFP long number from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
decimal64ToNumber(&x2, &d2);
/* Convert number to DFP short format */
if ((decNumberIsInfinite(&d2) && (m4 & 0x08))
|| decNumberIsNaN(&d2))
{
/* For Inf with mask bit 0 set, or for QNan or SNan,
propagate the low 6 digits */
dfp64_clear_cf_and_bxcf(&x2);
decimal64ToNumber(&x2, &d1);
decPackedFromNumber(pwork, sizeof(pwork), &scale, &d1);
scale = 0;
decPackedToNumber(pwork+sizeof(pwork)-4, 4, &scale, &d1);
decimal32FromNumber(&x1, &d1, &set);
if (decNumberIsInfinite(&d2))
{
dfp32_set_cf_and_bxcf(&x1, DFP_CFS_INF);
}
else if (decNumberIsQNaN(&d2))
{
dfp32_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
}
else /* it is an SNaN */
{
/* For SNaN with mask bit 0 off, convert to a QNaN
and raise signaling condition */
if (decNumberIsSNaN(&d2) && (m4 & 0x08) == 0)
{
dfp32_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
set.status |= DEC_IEEE_854_Invalid_operation;
}
else
{
dfp32_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
}
}
}
else
{
/* For finite number, load value rounded to short DFP format,
or for Inf with mask bit 0 not set, load default infinity */
decNumberCopy(&d1, &d2);
decimal32FromNumber(&x1, &d1, &set);
}
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal32)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(load_rounded_dfp_long_to_short_reg) */
/*-------------------------------------------------------------------*/
/* B3D8 MXTR - Multiply DFP Extended Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(multiply_dfp_ext_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal128 x1, x2, x3; /* Extended DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
DFPREGPAIR3_CHECK(r1, r2, r3, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Multiply FP register r2 by FP register r3 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
decimal128ToNumber(&x2, &d2);
decimal128ToNumber(&x3, &d3);
decNumberMultiply(&d1, &d2, &d3, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(multiply_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3D0 MDTR - Multiply DFP Long Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(multiply_dfp_long_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal64 x1, x2, x3; /* Long DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Multiply FP register r2 by FP register r3 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
decimal64ToNumber(&x2, &d2);
decimal64ToNumber(&x3, &d3);
decNumberMultiply(&d1, &d2, &d3, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(multiply_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3FD QAXTR - Quantize DFP Extended Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(quantize_dfp_ext_reg)
{
int r1, r2, r3, m4; /* Values of R and M fields */
decimal128 x1, x2, x3; /* Extended DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_RM(inst, regs, r1, r2, r3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR3_CHECK(r1, r2, r3, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m4, regs);
/* Quantize FP register r3 using FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
decimal128ToNumber(&x2, &d2);
decimal128ToNumber(&x3, &d3);
decNumberQuantize(&d1, &d2, &d3, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(quantize_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3F5 QADTR - Quantize DFP Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(quantize_dfp_long_reg)
{
int r1, r2, r3, m4; /* Values of R and M fields */
decimal64 x1, x2, x3; /* Long DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_RM(inst, regs, r1, r2, r3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m4, regs);
/* Quantize FP register r3 using FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
decimal64ToNumber(&x2, &d2);
decimal64ToNumber(&x3, &d3);
decNumberQuantize(&d1, &d2, &d3, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(quantize_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* B3FF RRXTR - Reround DFP Extended Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(reround_dfp_ext_reg)
{
int signif; /* Requested significance */
int r1, r2, r3, m4; /* Values of R and M fields */
decimal128 x1, x3; /* Extended DFP values */
decNumber d1, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_RM(inst, regs, r1, r2, r3, m4);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r3, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, m4, regs);
/* Load significance from bits 58-63 of general register r2 */
signif = regs->GR_L(r2) & 0x3F;
/* Reround FP register r3 */
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
decimal128ToNumber(&x3, &d3);
if (decNumberIsInfinite(&d3) || decNumberIsNaN(&d3)
|| decNumberIsZero(&d3)
|| signif == 0 || d3.digits <= signif)
{
decNumberCopy(&d1, &d3);
}
else
{
set.digits = signif;
decNumberPlus(&d1, &d3, &set);
}
decimal128FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(reround_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3F7 RRDTR - Reround DFP Long Register [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(reround_dfp_long_reg)
{
int signif; /* Requested significance */
int r1, r2, r3, m4; /* Values of R and M fields */
decimal64 x1, x3; /* Long DFP values */
decNumber d1, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRF_RM(inst, regs, r1, r2, r3, m4);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, m4, regs);
/* Load significance from bits 58-63 of general register r2 */
signif = regs->GR_L(r2) & 0x3F;
/* Reround FP register r3 */
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
decimal64ToNumber(&x3, &d3);
if (decNumberIsInfinite(&d3) || decNumberIsNaN(&d3)
|| decNumberIsZero(&d3)
|| signif == 0 || d3.digits <= signif)
{
decNumberCopy(&d1, &d3);
}
else
{
set.digits = signif;
decNumberPlus(&d1, &d3, &set);
}
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(reround_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* ED48 SLXT - Shift Coefficient Left DFP Extended [RXF] */
/*-------------------------------------------------------------------*/
DEF_INST(shift_coefficient_left_dfp_ext)
{
int r1, r3; /* Values of R fields */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal128 x1, x3; /* Extended DFP values */
decNumber d1, d3; /* Working decimal numbers */
decContext set; /* Working context */
int n; /* Number of bits to shift */
RXF(inst, regs, r1, r3, b2, effective_addr2);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r3, regs);
/* Isolate rightmost 6 bits of second operand address */
n = effective_addr2 & 0x3F;
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP extended number from FP register r3 */
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
/* Convert to internal decimal number format */
decimal128ToNumber(&x3, &d3);
/* For NaN and Inf use coefficient continuation digits only */
if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3))
{
dfp128_clear_cf_and_bxcf(&x3);
decimal128ToNumber(&x3, &d1);
}
else
{
decNumberCopy(&d1, &d3);
}
/* Shift coefficient left n digit positions */
dfp_shift_coeff(&set, &d1, n);
/* Convert result to DFP extended format */
decimal128FromNumber(&x1, &d1, &set);
/* Restore Nan or Inf indicators in the result */
if (decNumberIsQNaN(&d3))
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
else if (decNumberIsSNaN(&d3))
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
else if (decNumberIsInfinite(&d3))
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(shift_coefficient_left_dfp_ext) */
/*-------------------------------------------------------------------*/
/* ED40 SLDT - Shift Coefficient Left DFP Long [RXF] */
/*-------------------------------------------------------------------*/
DEF_INST(shift_coefficient_left_dfp_long)
{
int r1, r3; /* Values of R fields */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal64 x1, x3; /* Long DFP values */
decNumber d1, d3; /* Working decimal numbers */
decContext set; /* Working context */
int n; /* Number of bits to shift */
RXF(inst, regs, r1, r3, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Isolate rightmost 6 bits of second operand address */
n = effective_addr2 & 0x3F;
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP long number from FP register r3 */
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
/* Convert to internal decimal number format */
decimal64ToNumber(&x3, &d3);
/* For NaN and Inf use coefficient continuation digits only */
if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3))
{
dfp64_clear_cf_and_bxcf(&x3);
decimal64ToNumber(&x3, &d1);
}
else
{
decNumberCopy(&d1, &d3);
}
/* Shift coefficient left n digit positions */
dfp_shift_coeff(&set, &d1, n);
/* Convert result to DFP long format */
decimal64FromNumber(&x1, &d1, &set);
/* Restore Nan or Inf indicators in the result */
if (decNumberIsQNaN(&d3))
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
else if (decNumberIsSNaN(&d3))
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
else if (decNumberIsInfinite(&d3))
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(shift_coefficient_left_dfp_long) */
/*-------------------------------------------------------------------*/
/* ED49 SRXT - Shift Coefficient Right DFP Extended [RXF] */
/*-------------------------------------------------------------------*/
DEF_INST(shift_coefficient_right_dfp_ext)
{
int r1, r3; /* Values of R fields */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal128 x1, x3; /* Extended DFP values */
decNumber d1, d3; /* Working decimal numbers */
decContext set; /* Working context */
int n; /* Number of bits to shift */
RXF(inst, regs, r1, r3, b2, effective_addr2);
DFPINST_CHECK(regs);
DFPREGPAIR2_CHECK(r1, r3, regs);
/* Isolate rightmost 6 bits of second operand address */
n = effective_addr2 & 0x3F;
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP extended number from FP register r3 */
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
/* Convert to internal decimal number format */
decimal128ToNumber(&x3, &d3);
/* For NaN and Inf use coefficient continuation digits only */
if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3))
{
dfp128_clear_cf_and_bxcf(&x3);
decimal128ToNumber(&x3, &d1);
}
else
{
decNumberCopy(&d1, &d3);
}
/* Shift coefficient right n digit positions */
dfp_shift_coeff(&set, &d1, -n);
/* Convert result to DFP extended format */
decimal128FromNumber(&x1, &d1, &set);
/* Restore Nan or Inf indicators in the result */
if (decNumberIsQNaN(&d3))
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
else if (decNumberIsSNaN(&d3))
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
else if (decNumberIsInfinite(&d3))
dfp128_set_cf_and_bxcf(&x1, DFP_CFS_INF);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
} /* end DEF_INST(shift_coefficient_right_dfp_ext) */
/*-------------------------------------------------------------------*/
/* ED41 SRDT - Shift Coefficient Right DFP Long [RXF] */
/*-------------------------------------------------------------------*/
DEF_INST(shift_coefficient_right_dfp_long)
{
int r1, r3; /* Values of R fields */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal64 x1, x3; /* Long DFP values */
decNumber d1, d3; /* Working decimal numbers */
decContext set; /* Working context */
int n; /* Number of bits to shift */
RXF(inst, regs, r1, r3, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Isolate rightmost 6 bits of second operand address */
n = effective_addr2 & 0x3F;
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP long number from FP register r3 */
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
/* Convert to internal decimal number format */
decimal64ToNumber(&x3, &d3);
/* For NaN and Inf use coefficient continuation digits only */
if (decNumberIsNaN(&d3) || decNumberIsInfinite(&d3))
{
dfp64_clear_cf_and_bxcf(&x3);
decimal64ToNumber(&x3, &d1);
}
else
{
decNumberCopy(&d1, &d3);
}
/* Shift coefficient right n digit positions */
dfp_shift_coeff(&set, &d1, -n);
/* Convert result to DFP long format */
decimal64FromNumber(&x1, &d1, &set);
/* Restore Nan or Inf indicators in the result */
if (decNumberIsQNaN(&d3))
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_QNAN);
else if (decNumberIsSNaN(&d3))
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_SNAN);
else if (decNumberIsInfinite(&d3))
dfp64_set_cf_and_bxcf(&x1, DFP_CFS_INF);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
} /* end DEF_INST(shift_coefficient_right_dfp_long) */
/*-------------------------------------------------------------------*/
/* B3DB SXTR - Subtract DFP Extended Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(subtract_dfp_ext_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal128 x1, x2, x3; /* Extended DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
DFPREGPAIR3_CHECK(r1, r2, r3, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Subtract FP register r3 from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal128)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal128)(r3, &x3, regs);
decimal128ToNumber(&x2, &d2);
decimal128ToNumber(&x3, &d3);
decNumberSubtract(&d1, &d2, &d3, &set);
decimal128FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal128)(r1, &x1, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&d1) ? 3 :
decNumberIsZero(&d1) ? 0 :
decNumberIsNegative(&d1) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(subtract_dfp_ext_reg) */
/*-------------------------------------------------------------------*/
/* B3D3 SDTR - Subtract DFP Long Register [RRR] */
/*-------------------------------------------------------------------*/
DEF_INST(subtract_dfp_long_reg)
{
int r1, r2, r3; /* Values of R fields */
decimal64 x1, x2, x3; /* Long DFP values */
decNumber d1, d2, d3; /* Working decimal numbers */
decContext set; /* Working context */
BYTE dxc; /* Data exception code */
RRR(inst, regs, r1, r2, r3);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
ARCH_DEP(dfp_rounding_mode)(&set, 0, regs);
/* Subtract FP register r3 from FP register r2 */
ARCH_DEP(dfp_reg_to_decimal64)(r2, &x2, regs);
ARCH_DEP(dfp_reg_to_decimal64)(r3, &x3, regs);
decimal64ToNumber(&x2, &d2);
decimal64ToNumber(&x3, &d3);
decNumberSubtract(&d1, &d2, &d3, &set);
decimal64FromNumber(&x1, &d1, &set);
/* Check for exception condition */
dxc = ARCH_DEP(dfp_status_check)(&set, regs);
/* Load result into FP register r1 */
ARCH_DEP(dfp_reg_from_decimal64)(r1, &x1, regs);
/* Set condition code */
regs->psw.cc = decNumberIsNaN(&d1) ? 3 :
decNumberIsZero(&d1) ? 0 :
decNumberIsNegative(&d1) ? 1 : 2;
/* Raise data exception if error occurred */
if (dxc != 0)
{
regs->dxc = dxc;
ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
}
} /* end DEF_INST(subtract_dfp_long_reg) */
/*-------------------------------------------------------------------*/
/* ED58 TDCXT - Test Data Class DFP Extended [RXE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_data_class_dfp_ext)
{
int r1; /* Value of R field */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal128 x1; /* Extended DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
U32 bits; /* Low 12 bits of address */
RXE(inst, regs, r1, b2, effective_addr2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Convert FP register r1 to decimal number format */
ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs);
decimal128ToNumber(&x1, &d1);
/* Isolate rightmost 12 bits of second operand address */
bits = effective_addr2 & 0xFFF;
/* Test data class and set condition code */
regs->psw.cc = dfp_test_data_class(&set, &d1, bits);
} /* end DEF_INST(test_data_class_dfp_ext) */
/*-------------------------------------------------------------------*/
/* ED54 TDCDT - Test Data Class DFP Long [RXE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_data_class_dfp_long)
{
int r1; /* Value of R field */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal64 x1; /* Long DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
U32 bits; /* Low 12 bits of address */
RXE(inst, regs, r1, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Convert FP register r1 to decimal number format */
ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs);
decimal64ToNumber(&x1, &d1);
/* Isolate rightmost 12 bits of second operand address */
bits = effective_addr2 & 0xFFF;
/* Test data class and set condition code */
regs->psw.cc = dfp_test_data_class(&set, &d1, bits);
} /* end DEF_INST(test_data_class_dfp_long) */
/*-------------------------------------------------------------------*/
/* ED50 TDCET - Test Data Class DFP Short [RXE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_data_class_dfp_short)
{
int r1; /* Value of R field */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal32 x1; /* Short DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
U32 bits; /* Low 12 bits of address */
RXE(inst, regs, r1, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Initialise the context for short DFP */
decContextDefault(&set, DEC_INIT_DECIMAL32);
/* Convert FP register r1 to decimal number format */
ARCH_DEP(dfp_reg_to_decimal32)(r1, &x1, regs);
decimal32ToNumber(&x1, &d1);
/* Isolate rightmost 12 bits of second operand address */
bits = effective_addr2 & 0xFFF;
/* Test data class and set condition code */
regs->psw.cc = dfp_test_data_class(&set, &d1, bits);
} /* end DEF_INST(test_data_class_dfp_short) */
/*-------------------------------------------------------------------*/
/* ED59 TDGXT - Test Data Group DFP Extended [RXE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_data_group_dfp_ext)
{
int r1; /* Value of R field */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal128 x1; /* Extended DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
U32 bits; /* Low 12 bits of address */
int lmd; /* Leftmost digit */
RXE(inst, regs, r1, b2, effective_addr2);
DFPINST_CHECK(regs);
DFPREGPAIR_CHECK(r1, regs);
/* Initialise the context for extended DFP */
decContextDefault(&set, DEC_INIT_DECIMAL128);
/* Load DFP extended number from FP register r1 */
ARCH_DEP(dfp_reg_to_decimal128)(r1, &x1, regs);
/* Extract the leftmost digit from FP register r1 */
lmd = dfp128_extract_lmd(&x1);
/* Convert to internal decimal number format */
decimal128ToNumber(&x1, &d1);
/* Isolate rightmost 12 bits of second operand address */
bits = effective_addr2 & 0xFFF;
/* Test data group and set condition code */
regs->psw.cc = dfp_test_data_group(&set, &d1, lmd, bits);
} /* end DEF_INST(test_data_group_dfp_ext) */
/*-------------------------------------------------------------------*/
/* ED55 TDGDT - Test Data Group DFP Long [RXE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_data_group_dfp_long)
{
int r1; /* Value of R field */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal64 x1; /* Long DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
U32 bits; /* Low 12 bits of address */
int lmd; /* Leftmost digit */
RXE(inst, regs, r1, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Initialise the context for long DFP */
decContextDefault(&set, DEC_INIT_DECIMAL64);
/* Load DFP long number from FP register r1 */
ARCH_DEP(dfp_reg_to_decimal64)(r1, &x1, regs);
/* Extract the leftmost digit from FP register r1 */
lmd = dfp64_extract_lmd(&x1);
/* Convert to internal decimal number format */
decimal64ToNumber(&x1, &d1);
/* Isolate rightmost 12 bits of second operand address */
bits = effective_addr2 & 0xFFF;
/* Test data group and set condition code */
regs->psw.cc = dfp_test_data_group(&set, &d1, lmd, bits);
} /* end DEF_INST(test_data_group_dfp_long) */
/*-------------------------------------------------------------------*/
/* ED51 TDGET - Test Data Group DFP Short [RXE] */
/*-------------------------------------------------------------------*/
DEF_INST(test_data_group_dfp_short)
{
int r1; /* Value of R field */
int b2; /* Base of effective addr */
VADR effective_addr2; /* Effective address */
decimal32 x1; /* Short DFP value */
decNumber d1; /* Working decimal number */
decContext set; /* Working context */
U32 bits; /* Low 12 bits of address */
int lmd; /* Leftmost digit */
RXE(inst, regs, r1, b2, effective_addr2);
DFPINST_CHECK(regs);
/* Initialise the context for short DFP */
decContextDefault(&set, DEC_INIT_DECIMAL32);
/* Load DFP short number from FP register r1 */
ARCH_DEP(dfp_reg_to_decimal32)(r1, &x1, regs);
/* Extract the leftmost digit from FP register r1 */
lmd = dfp32_extract_lmd(&x1);
/* Convert to internal decimal number format */
decimal32ToNumber(&x1, &d1);
/* Isolate rightmost 12 bits of second operand address */
bits = effective_addr2 & 0xFFF;
/* Test data group and set condition code */
regs->psw.cc = dfp_test_data_group(&set, &d1, lmd, bits);
} /* end DEF_INST(test_data_group_dfp_short) */
#endif /*defined(FEATURE_DECIMAL_FLOATING_POINT)*/
#if !defined(_GEN_ARCH)
#if defined(_ARCHMODE2)
#define _GEN_ARCH _ARCHMODE2
#include "dfp.c"
#endif
#if defined(_ARCHMODE3)
#undef _GEN_ARCH
#define _GEN_ARCH _ARCHMODE3
#include "dfp.c"
#endif
#endif /*!defined(_GEN_ARCH)*/
/* end of dfp.c */