mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-13 07:25:22 +02:00
4716 lines
179 KiB
C
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 */
|