/* DFP.C        (c) Copyright Roger Bowler, 2007-2009                */
/*              Decimal Floating Point instructions                  */

// $Id: dfp.c 5125 2009-01-23 12:01:44Z bernard $

/*-------------------------------------------------------------------*/
/* 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.   */
/*-------------------------------------------------------------------*/

// $Log$
// Revision 1.70  2008/11/23 11:18:50  rbowler
// Fix signed/unsigned mismatch caused by previous fix
//
// Revision 1.69  2008/11/23 11:11:54  rbowler
// Fix warning C4267 conversion from 'size_t' to 'int' in win64
//
// Revision 1.68  2008/11/23 11:06:04  rbowler
// Cosmetic: remove extraneous trailing blanks from dfp.c
//
// Revision 1.67  2007/11/23 12:28:07  rbowler
// Correct CPSDR when R1 and R3 are same register (2nd attempt)
//
// Revision 1.66  2007/11/15 22:11:26  rbowler
// Correct CPSDR when R1 and R3 are same register
//
// Revision 1.65  2007/06/23 00:04:08  ivan
// Update copyright notices to include current year (2007)
//
// Revision 1.64  2007/04/25 12:33:20  rbowler
// Move SRNMT to Floating-point-support-enhancement facility
//
// Revision 1.63  2007/04/25 12:10:27  rbowler
// Move LFAS,SFASR to IEEE-exception-simulation facility
//
// Revision 1.62  2007/03/13 01:52:42  gsmith
// Fix unsigned char (BYTE) vs char warnings for decNumberFromString
//
// Revision 1.61  2007/01/30 16:43:28  rbowler
// Activate Decimal Floating Point Facility
//
// Revision 1.10  2006/12/08 09:43:20  jj
// Add CVS message log
//

#include "hstdinc.h"

#if !defined(_HENGINE_DLL_)
#define _HENGINE_DLL_
#endif

#if !defined(_DFP_C_)
#define _DFP_C_
#endif

#include "hercules.h"
#include "opcode.h"
#include "inline.h"

#if defined(FEATURE_DECIMAL_FLOATING_POINT)
#include "decimal128.h"
#include "decimal64.h"
#include "decimal32.h"
#include "decPacked.h"
#endif /*defined(FEATURE_DECIMAL_FLOATING_POINT)*/

#if defined(FEATURE_FPS_ENHANCEMENT)
/*===================================================================*/
/* FLOATING POINT SUPPORT INSTRUCTIONS                               */
/*===================================================================*/
/* Note: the Floating Point Support instructions use the HFPREG_CHECK
   and HFPREG2_CHECK macros to enforce an AFP-register data exception
   if an FPS instruction attempts to use one of the 12 additional FPR
   registers when the AFP-register-control bit in CR0 is zero. */

/*-------------------------------------------------------------------*/
/* B370 LPDFR - Load Positive FPR Long Register                [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_positive_fpr_long_reg)
{
int     r1, r2;                         /* Values of R fields        */
int     i1, i2;                         /* FP register subscripts    */

    RRE(inst, regs, r1, r2);
    HFPREG2_CHECK(r1, r2, regs);
    i1 = FPR2I(r1);
    i2 = FPR2I(r2);

    /* Copy register contents, clear the sign bit */
    regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF;
    regs->fpr[i1+1] = regs->fpr[i2+1];

} /* end DEF_INST(load_positive_fpr_long_reg) */


/*-------------------------------------------------------------------*/
/* B371 LNDFR - Load Negative FPR Long Register                [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_negative_fpr_long_reg)
{
int     r1, r2;                         /* Values of R fields        */
int     i1, i2;                         /* FP register subscripts    */

    RRE(inst, regs, r1, r2);
    HFPREG2_CHECK(r1, r2, regs);
    i1 = FPR2I(r1);
    i2 = FPR2I(r2);

    /* Copy register contents, set the sign bit */
    regs->fpr[i1] = regs->fpr[i2] | 0x80000000;
    regs->fpr[i1+1] = regs->fpr[i2+1];

} /* end DEF_INST(load_negative_fpr_long_reg) */


/*-------------------------------------------------------------------*/
/* B372 CPSDR - Copy Sign FPR Long Register                    [RRF] */
/*-------------------------------------------------------------------*/
DEF_INST(copy_sign_fpr_long_reg)
{
int     r1, r2, r3;                     /* Values of R fields        */
int     i1, i2, i3;                     /* FP register subscripts    */
U32     sign;                           /* Work area for sign bit    */

    RRF_M(inst, regs, r1, r2, r3);
    HFPREG2_CHECK(r1, r2, regs);
    HFPREG_CHECK(r3, regs);
    i1 = FPR2I(r1);
    i2 = FPR2I(r2);
    i3 = FPR2I(r3);

    /* Copy the sign bit from r3 register */
    sign = regs->fpr[i3] & 0x80000000;

    /* Copy r2 register contents to r1 register */
    regs->fpr[i1] = regs->fpr[i2];
    regs->fpr[i1+1] = regs->fpr[i2+1];

    /* Insert the sign bit into r1 register */
    regs->fpr[i1] &= 0x7FFFFFFF;
    regs->fpr[i1] |= sign;

} /* end DEF_INST(copy_sign_fpr_long_reg) */


/*-------------------------------------------------------------------*/
/* B373 LCDFR - Load Complement FPR Long Register              [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_complement_fpr_long_reg)
{
int     r1, r2;                         /* Values of R fields        */
int     i1, i2;                         /* FP register subscripts    */

    RRE(inst, regs, r1, r2);
    HFPREG2_CHECK(r1, r2, regs);
    i1 = FPR2I(r1);
    i2 = FPR2I(r2);

    /* Copy register contents, invert sign bit */
    regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000;
    regs->fpr[i1+1] = regs->fpr[i2+1];

} /* end DEF_INST(load_complement_fpr_long_reg) */


/*-------------------------------------------------------------------*/
/* B3C1 LDGR  - Load FPR from GR Long Register                 [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_fpr_from_gr_long_reg)
{
int     r1, r2;                         /* Values of R fields        */
int     i1;                             /* FP register subscript     */

    RRE(inst, regs, r1, r2);
    HFPREG_CHECK(r1, regs);
    i1 = FPR2I(r1);

    /* Load FP register contents from general register */
    regs->fpr[i1] = regs->GR_H(r2);
    regs->fpr[i1+1] = regs->GR_L(r2);

} /* end DEF_INST(load_fpr_from_gr_long_reg) */


/*-------------------------------------------------------------------*/
/* B3CD LGDR  - Load GR from FPR Long Register                 [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(load_gr_from_fpr_long_reg)
{
int     r1, r2;                         /* Values of R fields        */
int     i2;                             /* FP register subscript     */

    RRE(inst, regs, r1, r2);
    HFPREG_CHECK(r2, regs);
    i2 = FPR2I(r2);

    /* Load general register contents from FP register */
    regs->GR_H(r1) = regs->fpr[i2];
    regs->GR_L(r1) = regs->fpr[i2+1];

} /* end DEF_INST(load_gr_from_fpr_long_reg) */


/*-------------------------------------------------------------------*/
/* B2B9 SRNMT - Set DFP Rounding Mode                            [S] */
/*-------------------------------------------------------------------*/
DEF_INST(set_dfp_rounding_mode)
{
int             b2;                     /* Base of effective addr    */
VADR            effective_addr2;        /* Effective address         */

    S(inst, regs, b2, effective_addr2);

    DFPINST_CHECK(regs);

    /* Set DFP rounding mode in FPC register from address bits 61-63 */
    regs->fpc &= ~(FPC_DRM);
    regs->fpc |= ((effective_addr2 << FPC_DRM_SHIFT) & FPC_DRM);

} /* end DEF_INST(set_dfp_rounding_mode) */


#endif /*defined(FEATURE_FPS_ENHANCEMENT)*/


#if defined(FEATURE_IEEE_EXCEPTION_SIMULATION)
/*===================================================================*/
/* IEEE-EXCEPTION-SIMULATION FACILITY INSTRUCTIONS                   */
/*===================================================================*/

#if !defined(_IXS_ARCH_INDEPENDENT_)
/*-------------------------------------------------------------------*/
/* Check if a simulated-IEEE-exception event is to be recognized     */
/*                                                                   */
/* This subroutine is called by the LFAS and SFASR instructions to   */
/* determine whether the instruction should raise a data exception   */
/* at the end of the instruction and, if so, the DXC code to be set. */
/*                                                                   */
/* Input:                                                            */
/*      cur_fpc         Current value of the FPC register            */
/*      src_fpc         Value of instruction source operand          */
/* Output:                                                           */
/*      The return value is the data exception code (DXC), or        */
/*      zero if no simulated-IEEE-exception event is recognized      */
/*-------------------------------------------------------------------*/
static BYTE
fpc_signal_check(U32 cur_fpc, U32 src_fpc)
{
U32             ff, sm, enabled_flags;  /* Mask and flag work areas  */
BYTE            dxc;                    /* Data exception code or 0  */

    /* AND the current FPC flags with the source FPC mask */
    ff = (cur_fpc & FPC_FLAG) >> FPC_FLAG_SHIFT;
    sm = (src_fpc & FPC_MASK) >> FPC_MASK_SHIFT;
    enabled_flags = (ff & sm) << FPC_FLAG_SHIFT;

    /* A simulated-IEEE-exception event is recognized
       if any current flag corresponds to the source mask */
    if (enabled_flags & FPC_FLAG_SFI)
    {
        dxc = DXC_IEEE_INV_OP_IISE;
    }
    else if (enabled_flags & FPC_FLAG_SFZ)
    {
        dxc = DXC_IEEE_DIV_ZERO_IISE;
    }
    else if (enabled_flags & FPC_FLAG_SFO)
    {
        dxc = (cur_fpc & FPC_FLAG_SFX) ?
                DXC_IEEE_OF_INEX_IISE :
                DXC_IEEE_OF_EXACT_IISE;
    }
    else if (enabled_flags & FPC_FLAG_SFU)
    {
        dxc = (cur_fpc & FPC_FLAG_SFX) ?
                DXC_IEEE_UF_INEX_IISE :
                DXC_IEEE_UF_EXACT_IISE;
    }
    else if (enabled_flags & FPC_FLAG_SFX)
    {
        dxc = DXC_IEEE_INEXACT_IISE;
    }
    else
    {
        dxc = 0;
    }

    /* Return data exception code or zero */
    return dxc;
} /* end function fpc_signal_check */
#define _IXS_ARCH_INDEPENDENT_
#endif /*!defined(_IXS_ARCH_INDEPENDENT_)*/


/*-------------------------------------------------------------------*/
/* B2BD LFAS  - Load FPC and Signal                              [S] */
/*-------------------------------------------------------------------*/
DEF_INST(load_fpc_and_signal)
{
int             b2;                     /* Base of effective addr    */
VADR            effective_addr2;        /* Effective address         */
U32             src_fpc, new_fpc;       /* New value for FPC         */
BYTE            dxc;                    /* Data exception code       */

    S(inst, regs, b2, effective_addr2);

    DFPINST_CHECK(regs);

    /* Load new FPC register contents from operand location */
    src_fpc = ARCH_DEP(vfetch4) (effective_addr2, b2, regs);

    /* Program check if reserved bits are non-zero */
    FPC_CHECK(src_fpc, regs);

    /* OR the flags from the current FPC register */
    new_fpc = src_fpc | (regs->fpc & FPC_FLAG);

    /* Determine whether an event is to be signaled */
    dxc = fpc_signal_check(regs->fpc, src_fpc);

    /* Update the FPC register */
    regs->fpc = new_fpc;

    /* Signal a simulated-IEEE-exception event if needed */
    if (dxc != 0)
    {
        regs->dxc = dxc;
        ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
    }

} /* end DEF_INST(load_fpc_and_signal) */


/*-------------------------------------------------------------------*/
/* B385 SFASR - Set FPC and Signal                             [RRE] */
/*-------------------------------------------------------------------*/
DEF_INST(set_fpc_and_signal)
{
int             r1, unused;             /* Values of R fields        */
U32             src_fpc, new_fpc;       /* New value for FPC         */
BYTE            dxc;                    /* Data exception code       */

    RRE(inst, regs, r1, unused);

    DFPINST_CHECK(regs);

    /* Load new FPC register contents from R1 register bits 32-63 */
    src_fpc = regs->GR_L(r1);

    /* Program check if reserved bits are non-zero */
    FPC_CHECK(src_fpc, regs);

    /* OR the flags from the current FPC register */
    new_fpc = src_fpc | (regs->fpc & FPC_FLAG);

    /* Determine whether an event is to be signaled */
    dxc = fpc_signal_check(regs->fpc, src_fpc);

    /* Update the FPC register */
    regs->fpc = new_fpc;

    /* Signal a simulated-IEEE-exception event if needed */
    if (dxc != 0)
    {
        regs->dxc = dxc;
        ARCH_DEP(program_interrupt) (regs, PGM_DATA_EXCEPTION);
    }

} /* end DEF_INST(set_fpc_and_signal) */
#endif /*defined(FEATURE_IEEE_EXCEPTION_SIMULATION)*/


#if defined(FEATURE_DECIMAL_FLOATING_POINT)
/*===================================================================*/
/* DECIMAL FLOATING POINT INSTRUCTIONS                               */
/*===================================================================*/
/* Note: the DFP instructions use the DFPINST_CHECK macro to check the
   setting of the AFP-register-control bit in CR0. If this bit is zero
   then the macro generates a DFP-instruction data exception. */

#if !defined(_DFP_ARCH_INDEPENDENT_)
/*-------------------------------------------------------------------*/
/* Extract the leftmost digit from a decimal32/64/128 structure      */
/*-------------------------------------------------------------------*/
static const int
dfp_lmdtable[32] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
                    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, 0, 0};

static inline int
dfp32_extract_lmd(decimal32 *xp)
{
    unsigned int cf = (((FW*)xp)->F & 0x7C000000) >> 26;
    return dfp_lmdtable[cf];
} /* end function dfp32_extract_lmd */

static inline int
dfp64_extract_lmd(decimal64 *xp)
{
    unsigned int cf = (((DW*)xp)->F.H.F & 0x7C000000) >> 26;
    return dfp_lmdtable[cf];
} /* end function dfp64_extract_lmd */

static inline int
dfp128_extract_lmd(decimal128 *xp)
{
    unsigned int cf = (((QW*)xp)->F.HH.F & 0x7C000000) >> 26;
    return dfp_lmdtable[cf];
} /* end function dfp128_extract_lmd */

/*-------------------------------------------------------------------*/
/* Clear the CF and BXCF fields of a decimal32/64/128 structure      */
/*-------------------------------------------------------------------*/
static inline void
dfp32_clear_cf_and_bxcf(decimal32 *xp)
{
    ((FW*)xp)->F &= 0x800FFFFF;         /* Clear CF and BXCF fields  */
} /* end function dfp32_clear_cf_and_bxcf */

static inline void
dfp64_clear_cf_and_bxcf(decimal64 *xp)
{
    ((DW*)xp)->F.H.F &= 0x8003FFFF;     /* Clear CF and BXCF fields  */
} /* end function dfp64_clear_cf_and_bxcf */

static inline void
dfp128_clear_cf_and_bxcf(decimal128 *xp)
{
    ((QW*)xp)->F.HH.F &= 0x80003FFF;    /* Clear CF and BXCF fields  */
} /* end function dfp128_clear_cf_and_bxcf */

/*-------------------------------------------------------------------*/
/* Set the CF and BXCF fields of a decimal32/64/128 structure        */
/* Input:                                                            */
/*      xp      Pointer to a decimal32/64/128 structure              */
/*      cfs     A 32-bit value, of which bits 0-25 are ignored,      */
/*              bits 26-30 contain the new CF field value (5-bits),  */
/*              bit 31 is the new BXCF signaling indicator (1-bit).  */
/* Output:                                                           */
/*      The CF field and the high-order bit of the BXCF field in     */
/*      the decimal32/64/128 structure are set to the indicated      */
/*      values and the remaining bits of the BXCF field are cleared. */
/*-------------------------------------------------------------------*/
#define DFP_CFS_INF     ((30<<1)|0)     /* CF and BXCF-S for Inf     */
#define DFP_CFS_QNAN    ((31<<1)|0)     /* CF and BXCF-S for QNaN    */
#define DFP_CFS_SNAN    ((31<<1)|1)     /* CF and BXCF-S for SNaN    */

static inline void
dfp32_set_cf_and_bxcf(decimal32 *xp, U32 cfs)
{
    ((FW*)xp)->F &= 0x800FFFFF;         /* Clear CF and BXCF fields  */
    ((FW*)xp)->F |= (cfs & 0x3F) << 25;
                                        /* Set CF and BXCF S-bit     */
} /* end function dfp32_set_cf_and_bxcf */

static inline void
dfp64_set_cf_and_bxcf(decimal64 *xp, U32 cfs)
{
    ((DW*)xp)->F.H.F &= 0x8003FFFF;     /* Clear CF and BXCF fields  */
    ((DW*)xp)->F.H.F |= (cfs & 0x3F) << 25;
                                        /* Set CF and BXCF S-bit     */
} /* end function dfp64_set_cf_and_bxcf */

static inline void
dfp128_set_cf_and_bxcf(decimal128 *xp, U32 cfs)
{
    ((QW*)xp)->F.HH.F &= 0x80003FFF;    /* Clear CF and BXCF fields  */
    ((QW*)xp)->F.HH.F |= (cfs & 0x3F) << 25;
                                        /* Set CF and BXCF S-bit     */
} /* end function dfp128_set_cf_and_bxcf */

/*-------------------------------------------------------------------*/
/* Compare exponent and return condition code                        */
/*                                                                   */
/* This subroutine is called by the CEETR, CEDTR, and CEXTR          */
/* instructions. It compares the exponents of two decimal            */
/* numbers and returns a condition code.                             */
/*                                                                   */
/* Input:                                                            */
/*      d1,d2   Pointers to decimal number structures                */
/* Output:                                                           */
/*      The return value is the condition code                       */
/*-------------------------------------------------------------------*/
static inline int
dfp_compare_exponent(decNumber *d1, decNumber *d2)
{
int             cc;                     /* Condition code            */

    if (decNumberIsNaN(d1) && decNumberIsNaN(d2))
        cc = 0;
    else if (decNumberIsNaN(d1) || decNumberIsNaN(d2))
        cc = 3;
    else if (decNumberIsInfinite(d1) && decNumberIsInfinite(d2))
        cc = 0;
    else if (decNumberIsInfinite(d1) || decNumberIsInfinite(d2))
        cc = 3;
    else
        cc = (d1->exponent == d2->exponent) ? 0 :
                (d1->exponent < d2->exponent) ? 1 : 2 ;

    return cc;
} /* end function dfp_compare_exponent */

/*-------------------------------------------------------------------*/
/* Convert 64-bit signed binary integer to decimal number            */
/*                                                                   */
/* This subroutine is called by the CDGTR and CXGTR instructions.    */
/* It converts a 64-bit signed binary integer value into a           */
/* decimal number structure. The inexact condition will be set       */
/* in the decimal context structure if the number is rounded to      */
/* fit the maximum number of digits specified in the context.        */
/*                                                                   */
/* Input:                                                            */
/*      dn      Pointer to decimal number structure                  */
/*      n       64-bit signed binary integer value                   */
/*      pset    Pointer to decimal number context structure          */
/* Output:                                                           */
/*      The decimal number structure is updated.                     */
/*-------------------------------------------------------------------*/
static void
dfp_number_from_fix64(decNumber *dn, S64 n, decContext *pset)
{
int             sign = 0;               /* Sign of binary integer    */
int             i;                      /* Counter                   */
char            zoned[32];              /* Zoned decimal work area   */
static char     maxnegzd[]="-9223372036854775808";
static U64      maxneg64 = 0x8000000000000000ULL;

    /* Handle maximum negative number as special case */
    if (n == (S64)maxneg64)
    {
        decNumberFromString(dn, maxnegzd, pset);
        return;
    }

    /* Convert binary value to zoned decimal */
    if (n < 0) { n = -n; sign = 1; }
    i = sizeof(zoned) - 1;
    zoned[i] = '\0';
    do {
        zoned[--i] = (n % 10) + '0';
        n /= 10;
    } while(i > 1 && n > 0);
    if (sign) zoned[--i] = '-';

    /* Convert zoned decimal value to decimal number structure */
    decNumberFromString(dn, zoned+i, pset);

} /* end function dfp_number_from_fix64 */

/*-------------------------------------------------------------------*/
/* Convert decimal number to 64-bit signed binary integer            */
/*                                                                   */
/* This subroutine is called by the CGDTR and CGXTR instructions.    */
/* It converts a decimal number structure to a 64-bit signed         */
/* binary integer value.  The inexact condition will be set in       */
/* the decimal context structure if the number is rounded to         */
/* an integer. The invalid operation condition will be set if        */
/* the decimal value is outside the range of a 64-bit integer.       */
/*                                                                   */
/* Input:                                                            */
/*      b       Pointer to decimal number structure                  */
/*      pset    Pointer to decimal number context structure          */
/* Output:                                                           */
/*      The return value is the 64-bit signed binary integer result  */
/*-------------------------------------------------------------------*/
static S64
dfp_number_to_fix64(decNumber *b, decContext *pset)
{
S64             n;                      /* 64-bit signed result      */
int32_t         scale;                  /* Scaling factor            */
unsigned        i;                      /* Array subscript           */
BYTE            packed[17];             /* 33-digit packed work area */
decNumber       p, c;                   /* Working decimal numbers   */
static U64      mp64 = 0x7FFFFFFFFFFFFFFFULL;   /* Max pos fixed 64  */
static U64      mn64 = 0x8000000000000000ULL;   /* Max neg fixed 64  */
static char     mpzd[]="9223372036854775807";   /* Max pos zoned dec */
static char     mnzd[]="-9223372036854775808";  /* Max neg zoned dec */
static BYTE     mpflag = 0;             /* 1=mp,mn are initialized   */
static decNumber mp, mn;                /* Decimal maximum pos,neg   */
decContext      setmax;                 /* Working context for mp,mn */

    /* Prime the decimal number structures representing the maximum
       positive and negative numbers representable in 64 bits. Use
       a 128-bit DFP working context because these numbers are too
       big to be represented in the 32-bit and 64-bit DFP formats */
    if (mpflag == 0)
    {
        decContextDefault(&setmax, DEC_INIT_DECIMAL128);
        decNumberFromString(&mp, mpzd, &setmax);
        decNumberFromString(&mn, mnzd, &setmax);
        mpflag = 1;
    }

    /* If operand is a NaN then set invalid operation
       and return maximum negative result */
    if (decNumberIsNaN(b))
    {
        pset->status |= DEC_IEEE_854_Invalid_operation;
        return (S64)mn64;
    }

    /* Remove fractional part of decimal number */
    decNumberToIntegralValue(&p, b, pset);

    /* Special case if operand is less than maximum negative
       number (including where operand is negative infinity) */
    decNumberCompare(&c, b, &mn, pset);
    if (decNumberIsNegative(&c))
    {
        /* If rounded value is less than maximum negative number
           then set invalid operation otherwise set inexact */
        decNumberCompare(&c, &p, &mn, pset);
        if (decNumberIsNegative(&c))
            pset->status |= DEC_IEEE_854_Invalid_operation;
        else
            pset->status |= DEC_IEEE_854_Inexact;

        /* Return maximum negative result */
        return (S64)mn64;
    }

    /* Special case if operand is greater than maximum positive
       number (including where operand is positive infinity) */
    decNumberCompare(&c, b, &mp, pset);
    if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0)
    {
        /* If rounded value is greater than maximum positive number
           then set invalid operation otherwise set inexact */
        decNumberCompare(&c, &p, &mp, pset);
        if (decNumberIsNegative(&c) == 0 && decNumberIsZero(&c) == 0)
            pset->status |= DEC_IEEE_854_Invalid_operation;
        else
            pset->status |= DEC_IEEE_854_Inexact;

        /* Return maximum positive result */
        return (S64)mp64;
    }

    /* Raise inexact condition if result was rounded */
    decNumberCompare(&c, &p, b, pset);
    if (decNumberIsZero(&c) == 0)
    {
        pset->status |= DEC_IEEE_854_Inexact;
        if (decNumberIsNegative(&c) == decNumberIsNegative(b))
            pset->status |= DEC_Rounded;
    }

    /* Convert decimal number structure to packed decimal */
    decPackedFromNumber(packed, sizeof(packed), &scale, &p);

    /* Convert packed decimal to binary value */
    for (i = 0, n = 0; i < sizeof(packed)-1; i++)
    {
        n = n * 10 + ((packed[i] & 0xF0) >> 4);
        n = n * 10 + (packed[i] & 0x0F);
    }
    n = n * 10 + ((packed[i] & 0xF0) >> 4);
    while (scale++) n *= 10;
    if ((packed[i] & 0x0F) == 0x0D) n = -n;

    /* Return 64-bit signed result */
    return n;

} /* end function dfp_number_to_fix64 */

#define MAXDECSTRLEN DECIMAL128_String  /* Maximum string length     */
/*-------------------------------------------------------------------*/
/* Shift decimal coefficient left or right                           */
/*                                                                   */
/* This subroutine is called by the SLDT, SLXT, SRDT and SRXT        */
/* instructions. It shifts the coefficient digits of a decimal       */
/* number left or right. For a left shift, zeroes are appended       */
/* to the coefficient. For a right shift, digits are dropped         */
/* from the end of the coefficient. No rounding is performed.        */
/* The sign and exponent of the number remain unchanged.             */
/*                                                                   */
/* Input:                                                            */
/*      pset    Pointer to decimal number context structure          */
/*      dn      Pointer to decimal number structure to be shifted    */
/*      count   Number of digits to shift (+ve=left, -ve=right)      */
/* Output:                                                           */
/*      The decimal number structure is updated.                     */
/*-------------------------------------------------------------------*/
static inline void
dfp_shift_coeff(decContext *pset, decNumber *dn, int count)
{
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_)*/

/*-------------------------------------------------------------------*/
/* 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) */


/*-------------------------------------------------------------------*/
/* 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) */


/*-------------------------------------------------------------------*/
/* 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) */


/*-------------------------------------------------------------------*/
/* 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) */


/*-------------------------------------------------------------------*/
/* 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 */
