/******************************
Intel Confidential
******************************/

// MACH
#include "ki.h"

#ifndef WIN32_OR_WIN64
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#endif

#include "fepublic.h"
#include "fehelper.h"
#include "festate.h"

// MACH #ifdef WIN32_OR_WIN64
// MACH #include <process.h>
// MACH #endif

// *************************************************************
// The functions fp_reg_read_hi() and fp_reg_read_lo()
// Take a packed floating-point register, 
// Reads the hi (or lo) part
// Returns a register-biased number with implicit made explicit.
// *************************************************************
EM_uint64_t
fp_concatenate(EM_uint_t hi_val, EM_uint_t lo_val) {
   return(  ((EM_uint64_t)hi_val <<32)
          | ((EM_uint64_t)lo_val & CONST_FORMAT(0x00000000FFFFFFFF )) );
}


EM_uint_t 
fp_extract_bits(
   EM_uint64_t  input_value, 
   unsigned int hi_bound, 
   unsigned int lo_bound)
{
EM_uint64_t value;
   if(lo_bound >63) return(0x00000000);

   value = (input_value >> lo_bound) &
           ~(CONST_FORMAT(0xFFFFFFFFFFFFFFFF) << (hi_bound - lo_bound + 1));

   return((EM_uint_t)value);
}


INLINE EM_fp_reg_type
fp_reg_read_hi(EM_uint_t freg)
{
EM_fp_reg_type tmp_freg = FR[freg];
EM_memory_type mem;

    if (freg == 0)
        return (FP_ZERO);
    else if (freg == 1) {
        return (FP_NEG_ZERO);
    }
    else {
        mem.uint_32.uvalue = (EM_uint_t)(tmp_freg.significand >> 32);
        tmp_freg = fp_mem_to_fr_format(mem, 4, 0);
        return (tmp_freg);
    }
}

INLINE EM_fp_reg_type
fp_reg_read_lo(EM_uint_t freg)
{
EM_fp_reg_type tmp_freg = FR[freg];
EM_memory_type mem;
EM_uint64_t tmp_val;
EM_uint_t   tmp32_val;

    if (freg == 0)
        return (FP_ZERO);
    else if (freg == 1) {
        return (FP_ZERO);
    }
    else {
        tmp_val = (tmp_freg.significand & CONST_FORMAT(0x00000000ffffffff));
        tmp32_val = (EM_uint_t)tmp_val;
        mem.uint_32.uvalue = tmp32_val;
        tmp_freg = fp_mem_to_fr_format(mem, 4, 0);
        return (tmp_freg);
    }
}


#undef fp_reg_read_hi
#undef fp_reg_read_lo

#define fp_reg_read_hi(f2)            fp82_reg_read_hi(ps,f2)
#define fp_reg_read_lo(f3)            fp82_reg_read_lo(ps,f3)


// ***********************************************************
// fp_fr_to_mem_format()
// ************************************************************
EM_memory_type
fp_fr_to_mem_format(
    EM_fp_reg_type freg,
    EM_uint_t      size,
    EM_uint_t      integer_form)
{
EM_memory_type tmp_mem;
EM_uint64_t    tmp_significand;

    switch(size) {
        case 4:
            tmp_mem.fp_single.sign = freg.sign;
            if (freg.exponent == 0)
                tmp_mem.fp_single.exponent = 0;
            else if ((freg.significand>>63) == 0)
                tmp_mem.fp_single.exponent = 0;
            else if (freg.exponent == FP_REG_EXP_ONES)
                tmp_mem.fp_single.exponent = FP_SGL_EXP_ONES;
            else 
                tmp_mem.fp_single.exponent    = 
                                         ((freg.exponent 
                                           >> (FP_REG_EXP_WIDTH-1) & 1) 
                                           << (FP_SGL_EXP_WIDTH-1))
                                        |( freg.exponent & FP_SGL_BIAS);

            tmp_mem.fp_single.significand =
                    (EM_uint_t)((freg.significand <<1) >>(63-22));
            break;

        case 8: /* double */
            if (integer_form)
                tmp_mem.uint_64.uvalue = freg.significand;

            else { /* !integer_form */
                tmp_mem.fp_double.sign = freg.sign;
                if (freg.exponent == 0)
                    tmp_mem.fp_double.exponent = 0;
                else if ((freg.significand>>63) == 0)
                    tmp_mem.fp_double.exponent = 0;
                else if (freg.exponent == FP_REG_EXP_ONES)
                    tmp_mem.fp_double.exponent = FP_DBL_EXP_ONES;
                else
                    tmp_mem.fp_double.exponent    = 
                                         ((freg.exponent 
                                           >> (FP_REG_EXP_WIDTH-1) & 1) 
                                           << (FP_DBL_EXP_WIDTH-1))
                                        |( freg.exponent & FP_DBL_BIAS);

                tmp_significand = 
                        (freg.significand <<1) >> (63-51);

                tmp_mem.fp_double.significand_hi = 
                  (EM_uint_t)((tmp_significand >> 32) & CONST_FORMAT( 0x00000000ffffffff));
                tmp_mem.fp_double.significand_lo = 
                  (EM_uint_t)(tmp_significand & CONST_FORMAT( 0x00000000ffffffff));
            }    
            break;

        case 10: /* double extended */
          tmp_mem.fp_double_extended.sign = freg.sign;
            if (freg.exponent == 0) {
                    /* Zero or (Pseudo-)Denormal */
                tmp_mem.fp_double_extended.exponent = 0;
            } else if (freg.exponent == FP_REG_EXP_ONES) {
                    /* Inf/NaN/NatVAL */
                tmp_mem.fp_double_extended.exponent = FP_EXT_EXP_ONES;
            } else {
                    /* Normal or Unnormal */
                    tmp_mem.fp_double_extended.exponent    = 
                                         ((freg.exponent 
                                           >> (FP_REG_EXP_WIDTH-1) & 1) 
                                           << (FP_EXT_EXP_WIDTH-1))
                                        |( freg.exponent & FP_EXT_BIAS);

            }
	    memcpy(tmp_mem.fp_double_extended.significand,
		    &freg.significand, 8);

            break;

        case 16: /* spill */
            tmp_mem.fp_spill_fill.reserved1    = 0;
            tmp_mem.fp_spill_fill.reserved2    = 0;
            tmp_mem.fp_spill_fill.sign         = freg.sign;
            tmp_mem.fp_spill_fill.exponent     = freg.exponent;
            tmp_mem.fp_spill_fill.significand  = freg.significand;
            break;
    }
    return (tmp_mem);
}


INLINE EM_memory_type
fr_to_mem4_bias_adjust(EM_fp_reg_type freg)
{
EM_memory_type tmp_mem;

   tmp_mem.fp_single.sign = freg.sign;
   if (freg.exponent == 0)
      tmp_mem.fp_single.exponent = 0;
   else if (freg.exponent == FP_REG_EXP_ONES)
      tmp_mem.fp_single.exponent = FP_SGL_EXP_ONES;
   else if ((freg.significand>>63) == 0)
      tmp_mem.fp_single.exponent = (EM_uint_t)
                                 (((EM_int_t)freg.exponent)
                                 - FP_REG_BIAS + FP_SGL_BIAS - 1);
   else
      tmp_mem.fp_single.exponent = (EM_uint_t)
                                 (((EM_int_t)freg.exponent)
                                 - FP_REG_BIAS + FP_SGL_BIAS);
      tmp_mem.fp_single.significand = (EM_uint_t) (
                    (freg.significand<<(64-62-1))>>(40+64-62-1));

    return (tmp_mem);
}




// *****************************************************
// helper functions definitions 
// *****************************************************

INLINE EM_boolean_t
fp_equal(EM_fp_reg_type fr1, EM_fp_reg_type fr2)
{
    EM_fp_dp_type fp_dp1;
    EM_fp_dp_type fp_dp2;

    if (   fp_is_nan(fr1)         || fp_is_nan(fr2)
        || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) )
        return (0);

    fp_dp1 = fp_fr_to_dp(fr1);
    fp_dp2 = fp_fr_to_dp(fr2);

    if (   (fp_dp1.sign           == fp_dp2.sign          )
        && (fp_dp1.exponent       == fp_dp2.exponent      )
        && (fp_dp1.significand.hi == fp_dp2.significand.hi)
        && (fp_dp1.significand.lo == fp_dp2.significand.lo) )
        return (1);
    else if ( fp_is_zero_dp(fp_dp1) && fp_is_zero_dp(fp_dp2) )
        return (1);
    else
        return (0);
}


INLINE EM_boolean_t
fp_less_than(
   EM_fp_reg_type fr1, 
   EM_fp_reg_type fr2) 
{
EM_fp_dp_type fp_dp1;
EM_fp_dp_type fp_dp2;

    if (   fp_is_nan(fr1)         || fp_is_nan(fr2)
        || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) )
        return (0);

    fp_dp1 = fp_fr_to_dp(fr1);
    fp_dp2 = fp_fr_to_dp(fr2);

    if (fp_is_neg_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) {
        if (!fp_is_zero_dp(fp_dp1) || !fp_is_zero_dp(fp_dp2) )
            return (1);             /* for non-zero's neg is lt pos */
        else
            return (0);             /* zeros are equal */
    } else if (fp_is_pos_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) {
        return (0);                 /* pos is not lt neg */
    } else if (fp_is_neg_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) {
        if (fp_dp1.exponent > fp_dp2.exponent)
            return (1);             /* fp_dp1 much less than fp_dp2 */
        else if ((fp_dp1.exponent == fp_dp2.exponent)
                && (fp_U128_gt(fp_dp1.significand, fp_dp2.significand)))
            return (1);             /* fp_dp1 just less than fp_dp2 */
        else
            return (0);
    } else if (fp_is_pos_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) {
        if (fp_dp1.exponent < fp_dp2.exponent)
                return (1);         /* fp_dp1 much less than fp_dp2 */
        else if ((fp_dp1.exponent == fp_dp2.exponent)
                && (fp_U128_lt(fp_dp1.significand, fp_dp2.significand)))
            return (1);             /* fp_dp1 just less than fp_dp2 */
        else
            return (0);
    } else {
      return (0); // MACH ADDED
    }
}

INLINE EM_boolean_t
fp_lesser_or_equal(EM_fp_reg_type fr1, EM_fp_reg_type fr2)
{
    EM_fp_dp_type fp_dp1;
    EM_fp_dp_type fp_dp2;

    if (   fp_is_nan(fr1)         || fp_is_nan(fr2)
        || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) )
        return (0);

    fp_dp1 = fp_fr_to_dp(fr1);
    fp_dp2 = fp_fr_to_dp(fr2);

    if (fp_is_neg_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) {
        return (1);              /* for non-zero's and zeros's neg is le pos */
    } else if (fp_is_pos_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) {
        if (fp_is_zero_dp(fp_dp1) && fp_is_zero_dp(fp_dp2))
            return (1);          /* zero's are le */
        else
            return (0);          /* pos is not lt neg */
    } else if (fp_is_neg_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) {
        if (fp_dp1.exponent > fp_dp2.exponent)
            return (1);          /* fp_dp1 much less than fp_dp2 */
        else if ((fp_dp1.exponent == fp_dp2.exponent)
                && (fp_U128_ge(fp_dp1.significand, fp_dp2.significand)))
            return (1);          /* fp_dp1 just less than or equal fp_dp2 */
        else
            return (0);
    } else if (fp_is_pos_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) {
        if (fp_dp1.exponent < fp_dp2.exponent)
                return (1);      /* fp_dp1 much less than fp_dp2 */
        else if ((fp_dp1.exponent == fp_dp2.exponent)
                && (fp_U128_le(fp_dp1.significand, fp_dp2.significand)))
            return (1);          /* fp_dp1 just less than or equal fp_dp2 */
        else
            return (0);
    } else {
      return (0); // MACH ADDED
    }
}

INLINE EM_boolean_t
fp_unordered(EM_fp_reg_type fr1, EM_fp_reg_type fr2)
{
    if (   fp_is_nan(fr1)         || fp_is_nan(fr2)
        || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) )
        return (1);
    else 
        return (0);

}

EM_uint_t
fp82_fp_decode_fault(EM_tmp_fp_env_type tmp_fp_env)
{
EM_uint_t tmp_ret = 0;

    if (!tmp_fp_env.simd) { // MACH ADDED

      if (tmp_fp_env.em_faults.swa)
          return (8);
      else if (tmp_fp_env.em_faults.v)
          return (1);
      else if (tmp_fp_env.em_faults.z)
          return (4);
      else if (tmp_fp_env.em_faults.d)
          return (2);
      else {
          tmp_ret = 0;
          return (0); // MACH ADDED
      }

   } else {

// ****************************************************
// hi_faults are recorded in the low  four bits of temp_ret.
// lo_faults are recorded in the high four bits of temp_ret.
// ****************************************************

        if (tmp_fp_env.hi_faults.swa)
            tmp_ret = 8;
        else if (tmp_fp_env.hi_faults.v)
            tmp_ret = 1;
        else if (tmp_fp_env.hi_faults.z)
            tmp_ret = 4;
        else if (tmp_fp_env.hi_faults.d)
            tmp_ret = 2;

        if (tmp_fp_env.lo_faults.swa)
            tmp_ret |= 8<<4;
        else if (tmp_fp_env.lo_faults.v)
            tmp_ret |= 1<<4;
        else if (tmp_fp_env.lo_faults.z)
            tmp_ret |= 4<<4;
        else if (tmp_fp_env.lo_faults.d)
            tmp_ret |= 2<<4;
        return (tmp_ret);
    }
}


EM_uint_t
fp82_fp_decode_trap(EM_tmp_fp_env_type tmp_fp_env)
{
EM_uint_t tmp_ret;

    if (!tmp_fp_env.simd) {
        tmp_ret  = (tmp_fp_env.ebc       <<15
                  | tmp_fp_env.fpa       <<14
                  | tmp_fp_env.em_traps.i<<13
                  | tmp_fp_env.em_traps.un<<12
                  | tmp_fp_env.em_traps.o<<11 ); // MACH
    } 
    else {
       tmp_ret = 0;
       if(tmp_fp_env.hi_traps.i || 
          tmp_fp_env.hi_traps.un || 
          tmp_fp_env.hi_traps.o ) { // MACH
       
          tmp_ret  = tmp_fp_env.hi_fpa    <<14
                   | tmp_fp_env.hi_traps.i<<13
                   | tmp_fp_env.hi_flags.i<<13
                   | tmp_fp_env.hi_traps.un<<12
                   | tmp_fp_env.hi_traps.o<<11; // MACH
       }
       
       if(tmp_fp_env.lo_traps.i || 
          tmp_fp_env.lo_traps.un || 
          tmp_fp_env.lo_traps.o ) { // MACH

          tmp_ret |= tmp_fp_env.lo_fpa    <<10
                   | tmp_fp_env.lo_traps.i<<9
                   | tmp_fp_env.lo_flags.i<<9
                   | tmp_fp_env.lo_traps.un<<8
                   | tmp_fp_env.lo_traps.o<<7; // MACH
      }
    } 
    return (tmp_ret);
}


void
fp_decode_environment(
    EM_opcode_pc_type pc,
    EM_opcode_sf_type sf,
    EM_tmp_fp_env_type *tmp_fp_env)
{
EM_sf_type         tmp_sf;

    if (sf == sfS0) {
        tmp_sf.controls.ftz = FPSR.sf0_controls_ftz;
        tmp_sf.controls.wre = FPSR.sf0_controls_wre;
        tmp_sf.controls.pc  = FPSR.sf0_controls_pc;
        tmp_sf.controls.rc  = FPSR.sf0_controls_rc;
        tmp_sf.controls.td  = FPSR.sf0_controls_td;
    } else if (sf == sfS1) {
        tmp_sf.controls.ftz = FPSR.sf1_controls_ftz;
        tmp_sf.controls.wre = FPSR.sf1_controls_wre;
        tmp_sf.controls.pc  = FPSR.sf1_controls_pc;
        tmp_sf.controls.rc  = FPSR.sf1_controls_rc;
        tmp_sf.controls.td  = FPSR.sf1_controls_td;
    } else if (sf == sfS2) {
        tmp_sf.controls.ftz = FPSR.sf2_controls_ftz;
        tmp_sf.controls.wre = FPSR.sf2_controls_wre;
        tmp_sf.controls.pc  = FPSR.sf2_controls_pc;
        tmp_sf.controls.rc  = FPSR.sf2_controls_rc;
        tmp_sf.controls.td  = FPSR.sf2_controls_td;
    } else if (sf == sfS3) {
        tmp_sf.controls.ftz = FPSR.sf3_controls_ftz;
        tmp_sf.controls.wre = FPSR.sf3_controls_wre;
        tmp_sf.controls.pc  = FPSR.sf3_controls_pc;
        tmp_sf.controls.rc  = FPSR.sf3_controls_rc;
        tmp_sf.controls.td  = FPSR.sf3_controls_td;
    } else {
        tmp_sf.controls.ftz = 0;
        tmp_sf.controls.wre = 1;
        tmp_sf.controls.pc  = sf_double_extended;
        tmp_sf.controls.rc  = rc_rn;
        tmp_sf.controls.td  = 1;
    }

    if (sf == sf_none) {
        tmp_fp_env->controls.vd = 0;
        tmp_fp_env->controls.dd = 0;
        tmp_fp_env->controls.zd = 0;
        tmp_fp_env->controls.od = 0;
        tmp_fp_env->controls.ud = 0;
        tmp_fp_env->controls.id = 0;

    } else if (tmp_sf.controls.td )  {
        tmp_fp_env->controls.vd = 1;
        tmp_fp_env->controls.dd = 1;
        tmp_fp_env->controls.zd = 1;
        tmp_fp_env->controls.od = 1;
        tmp_fp_env->controls.ud = 1;
        tmp_fp_env->controls.id = 1;

    } else {
        tmp_fp_env->controls.vd = FPSR.traps_vd;
        tmp_fp_env->controls.dd = FPSR.traps_dd;
        tmp_fp_env->controls.zd = FPSR.traps_zd;
        tmp_fp_env->controls.od = FPSR.traps_od;
        tmp_fp_env->controls.ud = FPSR.traps_ud;
        tmp_fp_env->controls.id = FPSR.traps_id;
    }

    if (pc == pc_none) {
        tmp_fp_env->ss = ss_double_extended_64;
        tmp_fp_env->es = es_seventeen_bits;
        tmp_fp_env->simd = 0;

    } else if (pc == pc_simd) {
        tmp_fp_env->ss = ss_single_24;
        tmp_fp_env->es = es_eight_bits;
        tmp_fp_env->simd = 1;
        if (tmp_sf.controls.wre)
            tmp_sf.controls.wre = 0;
        tmp_fp_env->hi_flags.v = 0;
        tmp_fp_env->hi_flags.d = 0;
        tmp_fp_env->hi_flags.z = 0;
        tmp_fp_env->hi_flags.o = 0;
        tmp_fp_env->hi_flags.un = 0; 
        tmp_fp_env->hi_flags.i = 0;
        tmp_fp_env->lo_flags.v = 0;
        tmp_fp_env->lo_flags.d = 0;
        tmp_fp_env->lo_flags.z = 0;
        tmp_fp_env->lo_flags.o = 0;
        tmp_fp_env->lo_flags.un = 0; 
        tmp_fp_env->lo_flags.i = 0;

    } else if (pc == pc_s) {
        tmp_fp_env->ss = ss_single_24;
        tmp_fp_env->simd = 0;
        if (tmp_sf.controls.wre)
            tmp_fp_env->es = es_seventeen_bits;
        else
            tmp_fp_env->es = es_eight_bits;

    } else if (pc == pc_d) {
        tmp_fp_env->ss = ss_double_53;
        tmp_fp_env->simd = 0;
        if (tmp_sf.controls.wre)
            tmp_fp_env->es = es_seventeen_bits;
        else
            tmp_fp_env->es = es_eleven_bits;

    } else if (pc == pc_sf) {
        tmp_fp_env->simd = 0;
        if (tmp_sf.controls.pc == sf_single)
            tmp_fp_env->ss = ss_single_24;
        else if (tmp_sf.controls.pc == sf_double)
            tmp_fp_env->ss = ss_double_53;
        else if (tmp_sf.controls.pc == sf_double_extended)
            tmp_fp_env->ss = ss_double_extended_64;

        if (tmp_sf.controls.wre)
            tmp_fp_env->es = es_seventeen_bits;
        else
            tmp_fp_env->es = es_fifteen_bits;
    }

    if (sf == sf_none) {
        tmp_fp_env->rc  = rc_rz;
        tmp_fp_env->ftz = 0;
    } else {
        tmp_fp_env->rc  = tmp_sf.controls.rc;
        tmp_fp_env->ftz = tmp_sf.controls.ftz && tmp_fp_env->controls.ud;
    }

    tmp_fp_env->flags.v       = 0;
    tmp_fp_env->flags.d       = 0;
    tmp_fp_env->flags.z       = 0;
    tmp_fp_env->flags.o       = 0;
    tmp_fp_env->flags.un       = 0; 
    tmp_fp_env->flags.i       = 0;
    tmp_fp_env->ebc           = 0;
    tmp_fp_env->mdl           = 0;
    tmp_fp_env->mdh           = 0;

    tmp_fp_env->em_faults.v   = 0;
    tmp_fp_env->em_faults.d   = 0;
    tmp_fp_env->em_faults.z   = 0;
    tmp_fp_env->em_faults.swa = 0;
    tmp_fp_env->em_traps.i    = 0;
    tmp_fp_env->em_traps.o    = 0;
    tmp_fp_env->em_traps.un    = 0; 
    tmp_fp_env->fpa           = 0;

    tmp_fp_env->hi_faults.v   = 0;
    tmp_fp_env->hi_faults.d   = 0;
    tmp_fp_env->hi_faults.z   = 0;
    tmp_fp_env->hi_faults.swa = 0;
    tmp_fp_env->hi_traps.i    = 0;
    tmp_fp_env->hi_traps.o    = 0;
    tmp_fp_env->hi_traps.un    = 0; 
    tmp_fp_env->hi_fpa        = 0;

    tmp_fp_env->lo_faults.v   = 0;
    tmp_fp_env->lo_faults.d   = 0;
    tmp_fp_env->lo_faults.z   = 0;
    tmp_fp_env->lo_faults.swa = 0;
    tmp_fp_env->lo_traps.i    = 0;
    tmp_fp_env->lo_traps.o    = 0;
    tmp_fp_env->lo_traps.un    = 0; 
    tmp_fp_env->lo_fpa        = 0;

    return;
}

#undef  fp_decode_environment
#define fp_decode_environment(arg1, arg2, arg3) \
        fp82_fp_decode_environment(ps, arg1, arg2, arg3)
      


// ****************************************************
// Returns
//   1: if a specified register is <= disabled limit and dfl is 1
//   0: if a specified register is >  disabled limit and dfh is 1
// The disabled limit is 31 after ACR106.
// *****************************************************
EM_uint_t
fp_reg_disabled(
    EM_uint_t f1,
    EM_uint_t f2,
    EM_uint_t f3,
    EM_uint_t f4)
{
EM_uint_t tmp_ret;
EM_uint_t disabled_limit;

   tmp_ret=0;
   disabled_limit = 31;

    if (    ((f1 >= 2) && (f1 <=disabled_limit) && (PSR.dfl))
        ||  ((f2 >= 2) && (f2 <=disabled_limit) && (PSR.dfl))
        ||  ((f3 >= 2) && (f3 <=disabled_limit) && (PSR.dfl))
        ||  ((f4 >= 2) && (f4 <=disabled_limit) && (PSR.dfl))
       )
        tmp_ret |= (1<<0);
    if (    ((f1 > disabled_limit) && (f1 <= 127) && (PSR.dfh))
        ||  ((f2 > disabled_limit) && (f2 <= 127) && (PSR.dfh))
        ||  ((f3 > disabled_limit) && (f3 <= 127) && (PSR.dfh))
        ||  ((f4 > disabled_limit) && (f4 <= 127) && (PSR.dfh))
       )
        tmp_ret |= (1<<1);
    return(tmp_ret);
}

INLINE EM_boolean_t
fp_is_nan_or_inf(EM_fp_reg_type tmp_res)
{
    if (fp_is_nan(tmp_res) || fp_is_inf(tmp_res))
        return (1);
    else
        return (0);
}


INLINE EM_fp_reg_type
fp_dp_to_fr(EM_fp_dp_type tmp_res)
{
    EM_fp_reg_type tmp_ret;
    /* MACH FIX CMPLR BUG tmp_ret.sign = tmp_res.sign; */
    if (tmp_res.exponent == FP_DP_EXP_ONES)
        tmp_ret.exponent = FP_REG_EXP_ONES;
    else if (tmp_res.exponent == 0)
        tmp_ret.exponent = 0;
    else 
        tmp_ret.exponent = (EM_uint_t)(((EM_int_t)tmp_res.exponent)
                                   - FP_DP_BIAS + FP_REG_BIAS);
    tmp_ret.sign = tmp_res.sign; /* MACH FIX CMPLR BUG */
    tmp_ret.significand = tmp_res.significand.hi;
    return (tmp_ret);
}


// ***************************************************************
// fp_add()
// Adds a dp value to an freg value
// Returns a dp value
// ***************************************************************
INLINE EM_fp_dp_type
fp_add(EM_fp_dp_type fp_dp, EM_fp_reg_type fr2, EM_tmp_fp_env_type tmp_fp_env)
// fp_dp has been normalized and fr2 may not be normalized 
{
    EM_fp_dp_type tmp_res;
    EM_uint256_t tmp_a, tmp_b, tmp_c;
    EM_int_t exp_diff;
    EM_uint_t normalize_count;

//     all cases which might have faulted have been screened out 
//     we still may trap on overflow, underflow and/or inexact later 

    if (fp_is_zero_dp(fp_dp) && (fp_is_zero(fr2) || fp_is_pseudo_zero(fr2))) {
        /* correctly signed zero */
        tmp_res = fp_fr_to_dp(FP_ZERO);
        if (fp_dp.sign == fr2.sign) {
            tmp_res.sign = fr2.sign;
        } else if (tmp_fp_env.rc == rc_rm) {
            tmp_res.sign = 1;
        } else {
            tmp_res.sign = 0;
        }
        return(tmp_res);
    } else if (fp_is_inf_dp(fp_dp)) {
        /* correctly signed infinity */
        return(fp_dp);
    } else if (fp_is_inf(fr2)) {
        /* correctly signed infinity */
        return(fp_fr_to_dp(fr2));
    } else if( fp_is_zero_dp(fp_dp)) {
        return(fp_fr_to_dp(fr2));
    } else if( fp_is_zero(fr2) || fp_is_pseudo_zero(fr2) ) {
        return(fp_dp);
    } else {
        /* we have non-all-zeros and non-all-ones exponents in both operands */
        exp_diff = (((EM_int_t)fp_dp.exponent) - FP_DP_BIAS )
                 - (((EM_int_t)fr2.exponent)  -  FP_REG_BIAS);

        tmp_res.sign = fp_dp.sign;

        tmp_a = fp_U128_to_U256(fp_dp.significand);
        tmp_a = fp_U256_lsh(tmp_a,64);

        tmp_b = fp_U64_to_U256(fr2.significand);
        tmp_b = fp_U256_lsh(tmp_b,128);

        if (exp_diff >= 0) {
            tmp_res.exponent = fp_dp.exponent;

            tmp_c = fp_U256_rsh(tmp_b,exp_diff);
            tmp_res.sticky = !fp_U256_eq(tmp_b,fp_U256_lsh(tmp_c,exp_diff));
            tmp_b = tmp_c;

            if(fp_dp.sign != fr2.sign) {
                /* add sticky */
                if (tmp_res.sticky)
                    tmp_b = fp_U256_inc(tmp_b);
                if (fp_dp.sign)
                    tmp_a = fp_U256_neg(tmp_a);
                if (fr2.sign)
                    tmp_b = fp_U256_neg(tmp_b);
            }
        } else {
            tmp_res.exponent = fp_dp.exponent - exp_diff;

            tmp_c = fp_U256_rsh(tmp_a,-exp_diff);
            tmp_res.sticky = !fp_U256_eq(tmp_a,fp_U256_lsh(tmp_c,-exp_diff));
            tmp_a = tmp_c;

            if(fp_dp.sign != fr2.sign) {
                /* add sticky */
                if (tmp_res.sticky)
                    tmp_a = fp_U256_inc(tmp_a);
                if (fp_dp.sign)
                    tmp_a = fp_U256_neg(tmp_a);
                if (fr2.sign)
                    tmp_b = fp_U256_neg(tmp_b);
            }
        }

        tmp_c = fp_U256_add(tmp_a, tmp_b);


        if (fp_dp.sign != fr2.sign) {
            if (tmp_c.hh != 0) {
                tmp_res.sign = 1;
                tmp_c = fp_U256_neg(tmp_c);
            } else {
                tmp_res.sign = 0;
            }
        }

        if (!fp_U256_eq(tmp_c,U256_0)) {
            normalize_count = fp_U256_lead0(tmp_c);
            tmp_res.exponent -= (normalize_count - 64);
            tmp_res.significand = fp_U256_to_U128(
                                      fp_U256_rsh(
                                          fp_U256_lsh(tmp_c, normalize_count),
                                          128
                                      )
                                  );

            if(normalize_count > 128) {
               tmp_res.sticky |= !fp_U256_eq(
                                     fp_U256_rsh(
                                         fp_U128_to_U256(tmp_res.significand),
                                         normalize_count-128
                                     ),
                                     tmp_c
                                 );
            } else {
               tmp_res.sticky |= !fp_U256_eq(
                                     fp_U256_lsh(
                                         fp_U128_to_U256(tmp_res.significand),
                                         128-normalize_count
                                     ),
                                     tmp_c
                                 );
            }

        } else {
             if (fp_dp.sign == fr2.sign)
                 tmp_res.sign = fp_dp.sign;
             else if (tmp_fp_env.rc == rc_rm)
                 tmp_res.sign = 1;
             else
                 tmp_res.sign = 0;
             tmp_res.exponent = 0;
             tmp_res.significand = U128_0;
        }
        return(tmp_res);
    }
}



// *******************************************************************
// IEEE rounds
// *******************************************************************


INLINE EM_uint_t
fp_single(EM_fp_reg_type freg)
{
EM_memory_type tmp_mem;
    tmp_mem = fp_fr_to_mem_format(freg, 4, 0);
    return (tmp_mem.uint_32.uvalue);
}

INLINE void
fp_ieee_to_hilo(
    EM_simd_hilo hilo,
    EM_tmp_fp_env_type *tmp_fp_env)
{
    if(hilo == high) {
       tmp_fp_env->hi_flags.o = tmp_fp_env->flags.o;
       tmp_fp_env->flags.o    = 0;

       tmp_fp_env->hi_flags.un = tmp_fp_env->flags.un; // MACH
       tmp_fp_env->flags.un    = 0; // MACH

       tmp_fp_env->hi_flags.i = tmp_fp_env->flags.i;
       tmp_fp_env->flags.i    = 0;


       tmp_fp_env->hi_traps.o = tmp_fp_env->em_traps.o;
       tmp_fp_env->em_traps.o = 0;

       tmp_fp_env->hi_traps.un = tmp_fp_env->em_traps.un; // MACH
       tmp_fp_env->em_traps.un = 0; // MACH

       tmp_fp_env->hi_traps.i = tmp_fp_env->em_traps.i;
       tmp_fp_env->em_traps.i = 0;

       tmp_fp_env->hi_faults.d = tmp_fp_env->em_faults.d;
       tmp_fp_env->em_faults.d = 0;

       tmp_fp_env->hi_faults.z = tmp_fp_env->em_faults.z;
       tmp_fp_env->em_faults.z = 0;

       tmp_fp_env->hi_faults.v = tmp_fp_env->em_faults.v;
       tmp_fp_env->em_faults.v = 0;

       tmp_fp_env->hi_fpa = tmp_fp_env->fpa;
       tmp_fp_env->fpa = 0;

    } else {
       tmp_fp_env->lo_flags.o = tmp_fp_env->flags.o;
       tmp_fp_env->flags.o    = 0;

       tmp_fp_env->lo_flags.un = tmp_fp_env->flags.un; // MACH
       tmp_fp_env->flags.un    = 0; // MACH

       tmp_fp_env->lo_flags.i = tmp_fp_env->flags.i;
       tmp_fp_env->flags.i    = 0;


       tmp_fp_env->lo_traps.o = tmp_fp_env->em_traps.o;
       tmp_fp_env->em_traps.o = 0;

       tmp_fp_env->lo_traps.un = tmp_fp_env->em_traps.un; // MACH
       tmp_fp_env->em_traps.un = 0; // MACH

       tmp_fp_env->lo_traps.i = tmp_fp_env->em_traps.i;
       tmp_fp_env->em_traps.i = 0;

       tmp_fp_env->lo_faults.d = tmp_fp_env->em_faults.d;
       tmp_fp_env->em_faults.d = 0;

       tmp_fp_env->lo_faults.z = tmp_fp_env->em_faults.z;
       tmp_fp_env->em_faults.z = 0;

       tmp_fp_env->lo_faults.v = tmp_fp_env->em_faults.v;
       tmp_fp_env->em_faults.v = 0;

       tmp_fp_env->lo_fpa = tmp_fp_env->fpa;
       tmp_fp_env->fpa = 0;
    }
}

EM_fp_reg_type
fp_ieee_round(
    EM_fp_dp_type      fp_dp,
    EM_tmp_fp_env_type *tmp_fp_env)
{
    const EM_uint_t FPA[64] = {
                        0,0,0,1,
                        0,0,1,1,
                        0,0,0,1,
                        0,0,1,1, /* Nearest */
                        0,0,0,0,
                        0,0,0,0,
                        0,1,1,1,
                        0,1,1,1, /* -inf */
                        0,1,1,1,
                        0,1,1,1,
                        0,0,0,0,
                        0,0,0,0, /* +inf */
                        0,0,0,0,
                        0,0,0,0,
                        0,0,0,0,
                        0,0,0,0, /* Zero */
    };

    EM_fp_reg_type tmp_rtn;
    EM_fp_dp_type  tmp_res, tmp_unbounded_round;
    EM_int_t       cnt, tmp_shift;

    EM_uint_t      e_max, e_min, 
                   tmp_unbounded_ebc = 0, tmp_unbounded_fpa = 0;

    EM_uint128_t significand_mask;
    EM_uint128_t significand_even;
    EM_uint128_t significand_round;
    EM_uint128_t significand_not_mask;
    EM_uint128_t significand_sticky;


/************************************************
SETUP
set e_max, e_min
Note that the exponents are still dp-biased.
*************************************************/
    if (tmp_fp_env->es == es_eight_bits) {
        e_max = FP_DP_BIAS + FP_SGL_BIAS;
        e_min = FP_DP_BIAS - FP_SGL_BIAS + 1;
    } else if (tmp_fp_env->es == es_eleven_bits) {
        e_max = FP_DP_BIAS + FP_DBL_BIAS;
        e_min = FP_DP_BIAS - FP_DBL_BIAS + 1;
    } else if (tmp_fp_env->es == es_fifteen_bits) {
        e_max = FP_DP_BIAS + FP_EXT_BIAS;
        e_min = FP_DP_BIAS - FP_EXT_BIAS + 1;
    } else if (tmp_fp_env->es == es_seventeen_bits) {
        e_max = FP_DP_BIAS + FP_REG_BIAS;
        e_min = FP_DP_BIAS - FP_REG_BIAS + 1;
    }

/************************************************
SETUP
set significand_mask, significand_even, significand_round
    significand_not_mask, significand_sticky
*************************************************/
   if( tmp_fp_env->ss == ss_single_24) {
        significand_mask     = U128_0xFFFFFF00000000000000000000000000;
        significand_even     = U128_0x00000100000000000000000000000000;
        significand_round    = U128_0x00000080000000000000000000000000;
        significand_not_mask = U128_0x000000FFFFFFFFFFFFFFFFFFFFFFFFFF;
        significand_sticky   = U128_0x0000007FFFFFFFFFFFFFFFFFFFFFFFFF;
    } else if( tmp_fp_env->ss == ss_double_53) {
        significand_mask     = U128_0xFFFFFFFFFFFFF8000000000000000000;
        significand_even     = U128_0x00000000000008000000000000000000;
        significand_round    = U128_0x00000000000004000000000000000000;
        significand_not_mask = U128_0x00000000000007FFFFFFFFFFFFFFFFFF;
        significand_sticky   = U128_0x00000000000003FFFFFFFFFFFFFFFFFF;
    } else if( tmp_fp_env->ss == ss_double_extended_64) {
        significand_mask     = U128_0xFFFFFFFFFFFFFFFF0000000000000000;
        significand_even     = U128_0x00000000000000010000000000000000;
        significand_round    = U128_0x00000000000000008000000000000000;
        significand_not_mask = U128_0x0000000000000000FFFFFFFFFFFFFFFF;
        significand_sticky   = U128_0x00000000000000007FFFFFFFFFFFFFFF;
    }

/***************************************************
INPUT CHECK
Inf?
****************************************************/
    if ( fp_is_inf_dp(fp_dp) ) {
        tmp_res             = fp_dp;
        tmp_res.significand = fp_U128_band(tmp_res.significand,
                                        significand_mask);
        tmp_rtn = fp_dp_to_fr(tmp_res);
        return(tmp_rtn);

/***************************************************
INPUT CHECK
Nan?
****************************************************/
   } else if ( fp_is_nan_dp(fp_dp) ) {
        tmp_res             = fp_dp;
        tmp_res.significand = fp_U128_band(tmp_res.significand,
                                        significand_mask);
        tmp_rtn = fp_dp_to_fr(tmp_res);
        return(tmp_rtn);

/***************************************************
INPUT CHECK
Zero?
****************************************************/
    } else if ( fp_is_zero_dp(fp_dp) ) {

        if (      (fp_dp.sticky) && (tmp_fp_env->rc == rc_rm) )
            tmp_rtn.sign = 1;
        else if ( (fp_dp.sticky) && (tmp_fp_env->rc != rc_rm) )
            tmp_rtn.sign = 0;
        else
            tmp_rtn.sign = fp_dp.sign;
        tmp_rtn.exponent    = fp_dp.exponent;
        tmp_rtn.significand = 0;
        return(tmp_rtn);

/******************************************************
INPUT CHECK
Answer is finite and non-zero.
*******************************************************/
    } else { 
        tmp_res.sign     = fp_dp.sign;
        tmp_res.exponent = fp_dp.exponent;
        tmp_res.sticky   = fp_dp.sticky;

/****************************************************** 
UNBOUNDED SETUP
Set cnt -- depends on rounding control, +/-, even/odd, round?, sticky?
Set sticky to be either round or sticky 
*******************************************************/
        cnt = (tmp_fp_env->rc<<4) | (fp_dp.sign<<3);
                        
        cnt |= !fp_U128_eq(U128_0, fp_U128_band(fp_dp.significand,
        /* even */                       significand_even))  << 2;
                        
        cnt |= !fp_U128_eq(U128_0, fp_U128_band(fp_dp.significand,
        /* round */                      significand_round)) << 1;
                        
        tmp_res.sticky |= !fp_U128_eq(U128_0, fp_U128_band(fp_dp.significand,
        /* sticky */                                significand_sticky));

        cnt |= tmp_res.sticky;
        tmp_res.sticky |= ((cnt&2) != 0); /* round and sticky */

/*************************************************************************
UNBOUNDED ROUNDING
If necessary, round the significand
   This is the FIRST (or UNBOUNDED) rounding
   If rounding the significand results in a carry out of
   the significand, inc exponent and set significand to 10..0
else
   mask out lower bits of significand
**************************************************************************/
        if (FPA[cnt]) {
            tmp_res.significand = fp_U128_bor(fp_dp.significand,
                                           significand_not_mask);
            tmp_res.significand = fp_U128_inc(tmp_res.significand);
            if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* carry out */
                tmp_res.exponent++;
                tmp_res.significand = U128_0x80000000000000000000000000000000;
            }
        } else {
            tmp_res.significand = fp_U128_band(fp_dp.significand,
                                            significand_mask);
        }

/*************************************************************************
UNBOUNDED ROUNDING
If significand = 0, set exponent to 0.
CAN THIS EVER HAPPEN IF tmp_res IS NORMALIZED?
**************************************************************************/
        if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* underflow -> zero */
                tmp_res.exponent = 0;
        }

/*************************************************************************
UNBOUNDED
Save the result of the FIRST ROUNDING in tmp_unbounded_round.
Then, set i flag.
**************************************************************************/        
        tmp_unbounded_round.sign            = tmp_res.sign;
        tmp_unbounded_round.significand     = tmp_res.significand;
        tmp_unbounded_round.exponent        = tmp_res.exponent;
        tmp_unbounded_round.sticky          = tmp_res.sticky;
        tmp_unbounded_fpa                   = FPA[cnt];
        
        if (  ((tmp_unbounded_round.exponent>>17)&1) 
            ^ ((tmp_unbounded_round.exponent>>16)&1) 
           )
                tmp_unbounded_ebc = 1;

        tmp_fp_env->flags.i   = tmp_res.sticky;


/************************************************************
HUGE
if HUGE, set o_flag; 
if o traps enabled, also set o_trap, ebc, fpa
   then if i_flag set, set i_trap and 
   return tmp_unbounded_round with mod17 exponent;
   the fp_dp_to_fr() mods the exponent.
   (sometimes inappropriately called the wrapped value)
else set set tmp_res to max or inf, set i_flag
   if i traps enabled, set i_trap, fpa
   return tmp_res 
*************************************************************/
        if ( tmp_res.exponent > e_max ) { /* huge */
          tmp_fp_env->flags.o = 1;

           if ( !tmp_fp_env->controls.od) {
               tmp_fp_env->ebc = tmp_unbounded_ebc;
               tmp_fp_env->fpa = tmp_unbounded_fpa;
               tmp_fp_env->em_traps.o = 1;
               if(tmp_fp_env->flags.i) {
                  tmp_fp_env->em_traps.i = 1;
               }
               return(fp_dp_to_fr(tmp_unbounded_round));      
 
          } else {
               tmp_res = fp_max_or_infinity(fp_dp.sign, tmp_fp_env,
                                            e_max, significand_mask);
               tmp_fp_env->flags.i = 1;
/****************************************************************
The IEEE standard specifies (7.5) that if you overflow without enabling
O traps, then inexact is always set. Hence, the above assignment.
*****************************************************************/

               if ( !tmp_fp_env->controls.id ) {
                   tmp_fp_env->em_traps.i = 1;
                   tmp_fp_env->fpa        = fp_is_inf_dp(tmp_res);
                   tmp_fp_env->ebc        = 0;
               }
               return(fp_dp_to_fr(tmp_res));
           }

/************************************************************
TINY
If MERCED_RTL, return unbounded, rounded result with mod17 exponent
*************************************************************/

        } else if ( tmp_res.exponent < e_min ) { /* tiny */

/************************************************************
TINY
Undo the rounding.
*************************************************************/

             tmp_res.sign     = fp_dp.sign;
             tmp_res.exponent = fp_dp.exponent;
             tmp_res.sticky   = fp_dp.sticky;

/************************************************************
TINY
Calculate the shift to bring exponent to e_min
if shift >=128 and significand is not zero, 
   set sticky and clear significand
else
   do the shift and set sticky if lost bits from significand
*************************************************************/
            tmp_shift = ((EM_int_t)e_min) - ((EM_int_t)fp_dp.exponent);
            tmp_res.exponent     += tmp_shift;

            if (tmp_shift >= 128) {
                tmp_res.sticky |= !fp_U128_eq( fp_dp.significand, U128_0);
                tmp_res.significand = U128_0;
            } else {
                tmp_res.sticky |= !fp_U128_eq( U128_0,
                                       fp_U128_lsh(
                                          fp_dp.significand,
                                          (128-tmp_shift)));
                tmp_res.significand  = fp_U128_rsh(fp_dp.significand,
                                                   tmp_shift);
            }

/****************************************************** 
TINY SETUP
Set cnt -- depends on rounding control, +/-, even/odd, round?, sticky?
Set sticky to be either round or sticky 
*******************************************************/
            cnt = (tmp_fp_env->rc<<4) | (tmp_res.sign<<3);
                            /* even */
            cnt |= !fp_U128_eq(U128_0, fp_U128_band(tmp_res.significand,
                                             significand_even))  << 2;
                            /* round */
            cnt |= !fp_U128_eq(U128_0, fp_U128_band(tmp_res.significand,
                                             significand_round)) << 1;
                            /* sticky */
            tmp_res.sticky |= !fp_U128_eq(U128_0, fp_U128_band(tmp_res.significand,
                                                        significand_sticky));
            cnt |= tmp_res.sticky;
            tmp_res.sticky |= ((cnt&2) != 0); /* round and sticky */

/*************************************************************************
TINY ROUNDING -- answer is in tmp_res
If necessary, round the significand
   This is the SECOND (as opposed to the FIRST or UNBOUNDED) rounding
   If rounding the significand results in a carry out of
   the significand, inc exponent and set significand to 10..0
else
   mask out lower bits of significand
**************************************************************************/
            if (FPA[cnt]) {
                tmp_res.significand = fp_U128_bor(tmp_res.significand,
                                               significand_not_mask);
                tmp_res.significand = fp_U128_inc(tmp_res.significand);
                if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* carry out */
                    tmp_res.exponent++;
                    tmp_res.significand =
                            U128_0x80000000000000000000000000000000;
                }
            } else {
                tmp_res.significand = fp_U128_band(tmp_res.significand,
                                                significand_mask);
            }


/******************************************************
TINY ROUNDING
If significand = 0, set exponent to 0.
Then, or in new sticky to the i flag 
*******************************************************/
           if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* underflow to 0 */
                tmp_res.exponent = 0;
            }

            tmp_fp_env->flags.i |= tmp_res.sticky;


/******************************************************
TINY
Set underflow, if inexact.
*******************************************************/
             if( tmp_fp_env->flags.i )
                 tmp_fp_env->flags.un = 1; /* tiny and inexact */ // MACH

/******************************************************
TINY
If u traps enabled, 
   set u_flag, u_trap, ebc, fpa, and possibly i_trap
   return unbounded result with mod17 exponent;
   the fp_dp_to_fr() mods the exponent.
else 
   if ftz
     set i_flag, set u_flag, clear ebc, clear fpa
     if inexact set i_trap
   else 
     if inexact trap and inexact
        set fpa, set i_trap
   set tmp_rtn (freg) to tmp_res (fp_dp).
   tmp_rtn now has the result of the SECOND rounding.
   Do not return tmp_res yet, because we may have to
   make a canonical double_ext denormal.
*******************************************************/
            tmp_fp_env->fpa        = FPA[cnt];
            if (!tmp_fp_env->controls.ud) {
                tmp_fp_env->flags.un    = 1; // MACH
                tmp_fp_env->em_traps.un = 1; // MACH
                tmp_fp_env->ebc        = tmp_unbounded_ebc;
                tmp_fp_env->fpa        = tmp_unbounded_fpa;
                tmp_fp_env->flags.i    = tmp_unbounded_round.sticky;
                if(tmp_fp_env->flags.i) {
                   tmp_fp_env->em_traps.i = 1; 
                }
                return(fp_dp_to_fr(tmp_unbounded_round));
            }
            else {
                if (tmp_fp_env->ftz) {
                   tmp_res.exponent    = 0;
                   tmp_res.significand = U128_0;
                   tmp_res.sticky      = 1;
                   tmp_fp_env->flags.i = 1;
                   tmp_fp_env->flags.un = 1; // MACH
                   tmp_fp_env->ebc     = 0;
                   tmp_fp_env->fpa     = 0;
                   if (!tmp_fp_env->controls.id) {
                      tmp_fp_env->em_traps.i = 1;
                   }
                } 
                else {
                   if (!tmp_fp_env->controls.id && tmp_fp_env->flags.i) {
                     tmp_fp_env->fpa        = FPA[cnt];
                     tmp_fp_env->em_traps.i = 1;
                   }
               }
            }

            tmp_rtn                = fp_dp_to_fr(tmp_res);

/******************************************************
TINY
if double_extended, set tmp_rtn to canonical denormal
return result of SECOND ROUNDING
*******************************************************/
            if (  (tmp_fp_env->es == es_fifteen_bits)
               && (tmp_rtn.exponent == 0x0C001)
               &&((tmp_rtn.significand & U64_0x8000000000000000) == 0) ) {
               /* canonical double-extended denormal */
                tmp_rtn.exponent = 0x00000;
            }

            return(tmp_rtn);

/******************************************************
NOT HUGE, NOT TINY
if i traps enabled and i flag, set i_trap 
set fpa
*******************************************************/
        } else { 
            if (!tmp_fp_env->controls.id && tmp_fp_env->flags.i) {
                tmp_fp_env->fpa        = tmp_unbounded_fpa;
                tmp_fp_env->em_traps.i = 1;
            }
            tmp_rtn  = fp_dp_to_fr(tmp_unbounded_round);

/******************************************************
NOT HUGE, NOT TINY
if double_extended, set tmp_rtn to canonical denormal
return result of FIRST rounding
*******************************************************/
            if (  (tmp_fp_env->es == es_fifteen_bits)
               && (tmp_rtn.exponent == 0x0C001)
               &&((tmp_rtn.significand & U64_0x8000000000000000) == 0) ) {
               /* canonical double-extended denormal */
                tmp_rtn.exponent = 0x00000;
            }

            return(tmp_rtn);
        } /* end of not huge, not tiny */
    } /* end of infinitely precise and nonzero */
}

#undef fp_ieee_round
#define fp_ieee_round(arg1, arg2)  fp82_fp_ieee_round(ps, arg1, arg2)

// *******************************************************************
// fp_ieee_round_sp()
// Takes a dp register value (which is the hi or lo of a simd)
// Rounds to single precision, setting flags
// Returns the value as a single-precision memory format value
// ********************************************************************
EM_uint_t
fp_ieee_round_sp(
    EM_fp_dp_type      fp_dp,
    EM_simd_hilo       hilo,
    EM_tmp_fp_env_type *tmp_fp_env)
{
EM_fp_reg_type fp_reg;
EM_memory_type tmp_mem;
    fp_reg = fp_ieee_round( fp_dp, tmp_fp_env);
    fp_ieee_to_hilo(hilo, tmp_fp_env);

    if( tmp_fp_env->hi_traps.un || tmp_fp_env->hi_traps.o ||
        tmp_fp_env->lo_traps.un || tmp_fp_env->lo_traps.o  ) { // MACH

       tmp_mem = fr_to_mem4_bias_adjust(fp_reg);
       return (tmp_mem.uint_32.uvalue);
    }
    else {   
     return (fp_single(fp_reg));
    }
}

#undef fp_ieee_round_sp
#define fp_ieee_round_sp(arg1, arg2, arg3) \
        fp82_fp_ieee_round_sp(ps, arg1, arg2, arg3) 


EM_fp_reg_type
fp_ieee_rnd_to_int(
    EM_fp_reg_type fr1,
    EM_tmp_fp_env_type *tmp_fp_env)
{
EM_fp_dp_type      tmp_res;
EM_tmp_fp_env_type tmp_fp_env_local;
    
    tmp_res = fp_fr_to_dp(fr1);
    memcpy ((char *)(&tmp_fp_env_local), (char *)tmp_fp_env,
        sizeof (EM_tmp_fp_env_type)); 

    if (tmp_res.exponent < FP_DP_INTEGER_EXP) {
        if (tmp_res.sign) {
            tmp_res = fp_add(tmp_res, FP_NEG_2_TO_63, *tmp_fp_env);
            tmp_res = fp_fr_to_dp(fp_ieee_round( tmp_res, tmp_fp_env));
            tmp_res = fp_add(tmp_res, FP_POS_2_TO_63, *tmp_fp_env);
            return(fp_ieee_round( tmp_res, &tmp_fp_env_local));
        } else {
            tmp_res = fp_add(tmp_res, FP_POS_2_TO_63, *tmp_fp_env);
            tmp_res = fp_fr_to_dp(fp_ieee_round( tmp_res, tmp_fp_env));
            tmp_res = fp_add(tmp_res, FP_NEG_2_TO_63, *tmp_fp_env);
            return(fp_ieee_round( tmp_res, &tmp_fp_env_local));
        }
    } else
        return (fr1);
}

#undef  fp_ieee_rnd_to_int
#define fp_ieee_rnd_to_int(arg1,arg2) \
        fp82_fp_ieee_rnd_to_int(ps, arg1, arg2)

EM_fp_reg_type
fp_ieee_rnd_to_int_sp(
    EM_fp_reg_type     fr1,
    EM_simd_hilo       hilo,
    EM_tmp_fp_env_type *tmp_fp_env)
{
EM_fp_reg_type      tmp_fix;
EM_tmp_fp_env_type  tmp_fp_env_save;

   tmp_fp_env_save  = *tmp_fp_env;
   tmp_fp_env->ss   = ss_double_extended_64;
   tmp_fp_env->es   = es_seventeen_bits;

   tmp_fix          = fp_ieee_rnd_to_int(fr1, tmp_fp_env);

   fp_ieee_to_hilo(hilo, tmp_fp_env);
   tmp_fp_env->ss   = tmp_fp_env_save.ss;
   tmp_fp_env->es   = tmp_fp_env_save.es;
   return(tmp_fix);
}


    
// ***************************************************************
// Exception fault checks
// *****************************************************************

// ****************************************************************
// fcmp_exception_fault_check()
// *****************************************************************
INLINE void
fcmp_exception_fault_check(
    EM_fp_reg_specifier f2,
    EM_fp_reg_specifier f3,
    EM_opcode_frel_type frel,
    EM_opcode_sf_type   sf,
    EM_tmp_fp_env_type  *tmp_fp_env)
{
EM_fp_reg_type fr2, fr3;

    fr2 = FR[f2];
    fr3 = FR[f3];

    fp_decode_environment( pc_none, sf, tmp_fp_env );

    if (fp_software_assistance_required(ps, op_fcmp, fr2, fr3)) {
        tmp_fp_env->em_faults.swa = 1;
    }

    if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3)) {
        tmp_fp_env->flags.v = 1;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }

    } else if (fp_is_nan(fr2) || fp_is_nan(fr3)) {
        if (fp_is_snan(fr2)   || fp_is_snan(fr3)     ||
           (frel == frelLT)  || (frel == frelNLT)  ||
           (frel == frelLE)  || (frel == frelNLE)) {
           tmp_fp_env->flags.v = 1;
           if (!tmp_fp_env->controls.vd) {
              tmp_fp_env->em_faults.v = 1;
           }
        }

    } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3)) {
        tmp_fp_env->flags.d = 1;
        if(!tmp_fp_env->controls.dd)
            tmp_fp_env->em_faults.d = 1;
    }

}

// ****************************************************************
// fpcmp_exception_fault_check()
// *****************************************************************
INLINE void 
fpcmp_exception_fault_check(
    EM_fp_reg_specifier f2,
    EM_fp_reg_specifier f3,
    EM_opcode_frel_type frel,
    EM_opcode_sf_type sf,
    EM_tmp_fp_env_type *tmp_fp_env)
{
EM_fp_reg_type      tmp_fr2 = FR[f2], tmp_fr3 = FR[f3];

    fp_decode_environment( pc_simd, sf, tmp_fp_env );

// ***********
// high
// ************
    tmp_fr2 = fp_reg_read_hi(f2);
    tmp_fr3 = fp_reg_read_hi(f3);

    if (fp_software_assistance_required(ps, op_fpcmp, tmp_fr2, tmp_fr3)) {
        tmp_fp_env->hi_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3))  {
        if ((fp_is_snan(tmp_fr2)  || fp_is_snan(tmp_fr3)   ||
           (frel == frelLT)      || (frel == frelNLT)    ||
           (frel == frelLE)      || (frel == frelNLE))) {
              tmp_fp_env->hi_flags.v = 1;
           if (!tmp_fp_env->controls.vd) {
               tmp_fp_env->hi_faults.v = 1;
           }
       }


    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->hi_flags.d = 1;
        if (!tmp_fp_env->controls.dd)
            tmp_fp_env->hi_faults.d = 1;
    }
    

// ***********
// low
// ************
    tmp_fr2 = fp_reg_read_lo(f2);
    tmp_fr3 = fp_reg_read_lo(f3);

    if (fp_software_assistance_required(ps, op_fpcmp, tmp_fr2, tmp_fr3)) {
        tmp_fp_env->lo_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) {
       if ((fp_is_snan(tmp_fr2)   || fp_is_snan(tmp_fr3)   ||
           (frel == frelLT)      || (frel == frelNLT)   ||
           (frel == frelLE)      || (frel == frelNLE))) {
              tmp_fp_env->lo_flags.v = 1;
           if (!tmp_fp_env->controls.vd) {
               tmp_fp_env->lo_faults.v = 1;
           }
       }


    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->lo_flags.d = 1;
        if (!tmp_fp_env->controls.dd)
            tmp_fp_env->lo_faults.d = 1;
    }
    return;
}

// *******************************************************************
// fcvt_exception_fault_check()
// ********************************************************************
INLINE EM_fp_reg_type
fcvt_exception_fault_check(
   EM_fp_reg_specifier f2,
   EM_opcode_sf_type sf,
   EM_boolean_t signed_form,
   EM_boolean_t trunc_form,
   EM_tmp_fp_env_type *tmp_fp_env)
{
   EM_fp_reg_type     tmp_res, fr2;
   EM_tmp_fp_env_type tmp_fp_env_local;

   fr2 = FR[f2];
   fp_decode_environment( pc_none, sf, tmp_fp_env );
   if (trunc_form)
       tmp_fp_env->rc = rc_rz;

   tmp_res          = fp_reg_read(fr2);
   memcpy ((char *)(&tmp_fp_env_local), (char *)tmp_fp_env,
       sizeof (EM_tmp_fp_env_type)); 
   tmp_res          = fp_ieee_rnd_to_int( tmp_res, &tmp_fp_env_local);

   if( signed_form && fp_software_assistance_required(ps, op_fcvt_fx, fr2)) {
       tmp_fp_env->em_faults.swa = 1;
       return (FP_ZERO);

   } else if( !signed_form  && fp_software_assistance_required(ps, op_fcvt_fxu, fr2)) {
       tmp_fp_env->em_faults.swa = 1;
       return (FP_ZERO);
   }

   if (fp_is_unsupported(fr2)) {
       tmp_fp_env->flags.v = 1;
       tmp_res             = FP_QNAN;
       if (!tmp_fp_env->controls.vd) {
           tmp_fp_env->em_faults.v = 1;
       }

   } else if (fp_is_nan(fr2)) {
       tmp_fp_env->flags.v = 1;
       if (!tmp_fp_env->controls.vd) {
           tmp_fp_env->em_faults.v = 1;
       }
       tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2;

   } else if ( signed_form                                     &&
               (!fp_lesser_or_equal(FP_NEG_2_TO_63, tmp_res) ||
                !fp_less_than(tmp_res,FP_POS_2_TO_63)) ) {
             tmp_fp_env->flags.v = 1;
             tmp_res             = FP_QNAN;
             if (!tmp_fp_env->controls.vd)
                 tmp_fp_env->em_faults.v = 1;

   } else if ( !signed_form                              &&
               (!fp_lesser_or_equal(FP_ZERO, tmp_res) ||
                !fp_less_than(tmp_res,FP_POS_2_TO_64)) ) {
             tmp_fp_env->flags.v = 1;
             if (!tmp_fp_env->controls.vd)
                tmp_fp_env->em_faults.v = 1;
             tmp_res = FP_QNAN;

   } else if (fp_is_unorm(fr2)) {
       tmp_fp_env->flags.d = 1;
       if( !tmp_fp_env->controls.dd)
          tmp_fp_env->em_faults.d = 1;
   }

   return (tmp_res);
}

// *******************************************************************
// fpcvt_exception_fault_check()
// ********************************************************************
EM_pair_fp_reg_type
fpcvt_exception_fault_check(
   EM_fp_reg_specifier f2,
   EM_opcode_sf_type   sf,
   EM_boolean_t        signed_form,
   EM_boolean_t        trunc_form,
   EM_tmp_fp_env_type *tmp_fp_env)
{
EM_tmp_fp_env_type  tmp_fp_env_local;
EM_pair_fp_reg_type tmp_reg_pair;
EM_fp_reg_type      tmp_fr2 = FR[f2];

    fp_decode_environment( pc_simd, sf, tmp_fp_env );

    tmp_reg_pair.hi = FP_ZERO;
    tmp_reg_pair.lo = FP_ZERO;

    if (trunc_form)
        tmp_fp_env->rc = rc_rz;

// *************
// high
// **************
    tmp_fr2             = fp_reg_read_hi(f2);
    tmp_fp_env_local    = *tmp_fp_env;
    tmp_fp_env_local.ss = ss_double_extended_64;
    tmp_fp_env_local.es = es_seventeen_bits;
    tmp_reg_pair.hi     = fp_ieee_rnd_to_int( tmp_fr2, &tmp_fp_env_local);

    if ( signed_form &&
         fp_software_assistance_required(ps, op_fpcvt_fx, tmp_fr2)) {
        tmp_fp_env->hi_faults.swa = 1;

    } else if( !signed_form &&
               fp_software_assistance_required(ps, op_fpcvt_fxu, tmp_fr2)) {
        tmp_fp_env->hi_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2)) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->hi_faults.v = 1;


    } else if (signed_form &&
               (!fp_lesser_or_equal(FP_NEG_2_TO_31, tmp_reg_pair.hi) ||
                !fp_less_than(tmp_reg_pair.hi,FP_POS_2_TO_31)) ) {
       tmp_fp_env->hi_flags.v = 1;
       tmp_reg_pair.hi = FP_QNAN;
       if (!tmp_fp_env->controls.vd)
          tmp_fp_env->hi_faults.v = 1;

    } else if (!signed_form &&
               (!fp_lesser_or_equal(FP_ZERO, tmp_reg_pair.hi) ||
                !fp_less_than(tmp_reg_pair.hi,FP_POS_2_TO_32)) ) {
       tmp_fp_env->hi_flags.v = 1;
       tmp_reg_pair.hi = FP_QNAN;
       if (!tmp_fp_env->controls.vd)
          tmp_fp_env->hi_faults.v = 1;

    } else if (fp_is_unorm(tmp_fr2)) {
            tmp_fp_env->hi_flags.d = 1;
            if (!tmp_fp_env->controls.dd)
                tmp_fp_env->hi_faults.d = 1;
    }

// *************
// low
// **************
    tmp_fr2             = fp_reg_read_lo(f2);
    tmp_fp_env_local    = *tmp_fp_env;
    tmp_fp_env_local.ss = ss_double_extended_64;
    tmp_fp_env_local.es = es_seventeen_bits;
    tmp_reg_pair.lo     = fp_ieee_rnd_to_int( tmp_fr2, &tmp_fp_env_local);

    if ( signed_form &&
         fp_software_assistance_required(ps, op_fpcvt_fx, tmp_fr2)) {
        tmp_fp_env->lo_faults.swa = 1;

    } else if( !signed_form &&
               fp_software_assistance_required(ps, op_fpcvt_fxu, tmp_fr2)) {
        tmp_fp_env->lo_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2)) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->lo_faults.v = 1;

    } else if (signed_form &&
               (!fp_lesser_or_equal(FP_NEG_2_TO_31, tmp_reg_pair.lo) ||
                !fp_less_than(tmp_reg_pair.lo,FP_POS_2_TO_31)) ) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
           tmp_fp_env->lo_faults.v = 1;

    } else if (!signed_form &&
               (!fp_lesser_or_equal(FP_ZERO, tmp_reg_pair.lo) ||
                !fp_less_than(tmp_reg_pair.lo,FP_POS_2_TO_32)) ) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
           tmp_fp_env->lo_faults.v = 1;

    } else if (fp_is_unorm(tmp_fr2)) {
            tmp_fp_env->lo_flags.d = 1;
            if (!tmp_fp_env->controls.dd)
                tmp_fp_env->lo_faults.d = 1;
    }

    return (tmp_reg_pair);
}

// *******************************************************************
// fma_exception_fault_check()
// ********************************************************************
EM_fp_reg_type
fma_exception_fault_check(
    EM_fp_reg_specifier f2,
    EM_fp_reg_specifier f3, 
    EM_fp_reg_specifier f4,
    EM_opcode_pc_type   pc,
    EM_opcode_sf_type   sf,
    EM_tmp_fp_env_type  *tmp_fp_env)
{
    EM_fp_reg_type tmp_res;
    EM_fp_reg_type fr2, fr3, fr4;
   
// printf ("MACH DEBUG: BEGIN fma_exception_fault_check\n");
    fr2 = FR[f2];
    fr3 = FR[f3];
    fr4 = FR[f4];
// printf ("MACH DEBUG: FR2 = %x %x "LX"\n", fr2.sign, fr2.exponent, fr2.significand);
// printf ("MACH DEBUG: FR3 = %x %x "LX"\n", fr3.sign, fr3.exponent, fr3.significand);
// printf ("MACH DEBUG: FR4 = %x %x "LX"\n", fr4.sign, fr4.exponent, fr4.significand);

    fp_decode_environment( pc, sf, tmp_fp_env );

    if(f4==1 && f2==0) {
       if (fp_software_assistance_required(ps, op_fnorm, fr3, *tmp_fp_env)) {
          tmp_fp_env->em_faults.swa = 1;
          return (FP_ZERO);
       }
    } else {
       if (fp_software_assistance_required(ps, op_fma, fr2, fr3, fr4)) {
          tmp_fp_env->em_faults.swa = 1;
          return (FP_ZERO);
       }
    }

    tmp_res = FP_ZERO;

    if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3) || fp_is_unsupported(fr4)) {
        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
            return (tmp_res);
        }

    } else if (fp_is_nan(fr2) || fp_is_nan(fr3) || fp_is_nan(fr4)) {
         if (fp_is_snan(fr2) || fp_is_snan(fr3) || fp_is_snan(fr4)) {
            tmp_fp_env->flags.v = 1;
            if (!tmp_fp_env->controls.vd) 
               tmp_fp_env->em_faults.v = 1;
         }

         if (fp_is_nan(fr4))
             tmp_res = fp_is_snan(fr4)?fp_make_quiet_nan(fr4):fr4;
         else if (fp_is_nan(fr2))
             tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2;
         else if (fp_is_nan(fr3))
             tmp_res = fp_is_snan(fr3)?fp_make_quiet_nan(fr3):fr3;

    } else if (( fp_is_pos_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_neg_inf(fr2) )
            || ( fp_is_pos_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_pos_inf(fr2) )
   
			|| ( fp_is_neg_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_pos_inf(fr2) )
            || ( fp_is_neg_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_neg_inf(fr2) )
 
			|| ( fp_is_pos_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_neg_inf(fr2) )
            || ( fp_is_pos_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_pos_inf(fr2) )

            || ( fp_is_neg_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_pos_inf(fr2) )
            || ( fp_is_neg_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_neg_inf(fr2) )) {

        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
            return (tmp_res);
        }

    } else if ((fp_is_inf(fr3) && fp_is_zero(fr4)) || (fp_is_zero(fr3) && fp_is_inf(fr4))) {
        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
            return (tmp_res);
        }

    
    } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3) || fp_is_unorm(fr4)) {
// printf ("MACH DEBUG: setting the D flag in fma_exception_fault_check\n");
        tmp_fp_env->flags.d = 1;
        if(!tmp_fp_env->controls.dd) { // MACH DEBUG
// printf ("MACH DEBUG: setting the D fault in fma_exception_fault_check\n");
            tmp_fp_env->em_faults.d = 1; 
      } // MACH DEBUG
    }

    return (tmp_res);
}

// *******************************************************************
// fpma_exception_fault_check()
// ********************************************************************
EM_pair_fp_reg_type
fpma_exception_fault_check(
    EM_fp_reg_specifier f2,
    EM_fp_reg_specifier f3,
    EM_fp_reg_specifier f4,
    EM_opcode_sf_type   sf,
    EM_tmp_fp_env_type  *tmp_fp_env)
{
EM_pair_fp_reg_type tmp_reg_pair;
EM_fp_reg_type      tmp_fr2 = FR[f2], tmp_fr3 = FR[f3], tmp_fr4 = FR[f4];

    fp_decode_environment( pc_simd, sf, tmp_fp_env );

    tmp_reg_pair.hi = FP_ZERO;
    tmp_reg_pair.lo = FP_ZERO;

// *********
// high
// *********
    tmp_fr2 = fp_reg_read_hi(f2);
    tmp_fr3 = fp_reg_read_hi(f3);
    tmp_fr4 = fp_reg_read_hi(f4);

    if (fp_software_assistance_required(ps, op_fpma, tmp_fr2, tmp_fr3, tmp_fr4)) {
        tmp_fp_env->hi_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) {
        if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) {
            tmp_fp_env->hi_flags.v = 1;
            if (!tmp_fp_env->controls.vd)
                tmp_fp_env->hi_faults.v = 1;
        }

         if (fp_is_nan(tmp_fr4))
             tmp_reg_pair.hi = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4;
         else if (fp_is_nan(tmp_fr2))
             tmp_reg_pair.hi = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2;
         else if (fp_is_nan(tmp_fr3))
             tmp_reg_pair.hi = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3;

    } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )

            || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )

            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )

            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->hi_faults.v = 1;

    } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4))
            || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->hi_faults.v = 1;


    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) {

        tmp_fp_env->hi_flags.d = 1;
        if (!tmp_fp_env->controls.dd)
            tmp_fp_env->hi_faults.d = 1;
    }

// *********
// low
// **********   
    tmp_fr2 = fp_reg_read_lo(f2);
    tmp_fr3 = fp_reg_read_lo(f3);
    tmp_fr4 = fp_reg_read_lo(f4);

    if (fp_software_assistance_required(ps, op_fpma, tmp_fr2, tmp_fr3, tmp_fr4)) {
        tmp_fp_env->lo_faults.swa = 1;
    }

    if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) {
        if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) {
            tmp_fp_env->lo_flags.v = 1;
            if (!tmp_fp_env->controls.vd)
                tmp_fp_env->lo_faults.v = 1;
        }

         if (fp_is_nan(tmp_fr4))
             tmp_reg_pair.lo = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4;
         else if (fp_is_nan(tmp_fr2))
             tmp_reg_pair.lo = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2;
         else if (fp_is_nan(tmp_fr3))
             tmp_reg_pair.lo = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3;

    } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )

            || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )

            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )

            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )) {

        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->lo_faults.v = 1;

    } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4))
            || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->lo_faults.v = 1;

    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) {
        tmp_fp_env->lo_flags.d = 1;
        if (!tmp_fp_env->controls.dd)
            tmp_fp_env->lo_faults.d = 1;
    }

    return (tmp_reg_pair);
}


// *******************************************************************
// fpminmax_exception_fault_check()
// No return value
// If input contains a NATVAL, just return.
// Otherwise set flags appropriately so that fpsr will
// be correct or a fault taken in caller.
// ********************************************************************
INLINE void 
fpminmax_exception_fault_check(
    EM_uint_t f2,
    EM_uint_t f3,
    EM_opcode_sf_type sf,
    EM_tmp_fp_env_type *tmp_fp_env)
{
EM_fp_reg_type      tmp_fr2 = FR[f2], tmp_fr3 = FR[f3];

// MACH
    fp_decode_environment( pc_simd, sf, tmp_fp_env );

// ************
// high
// ************

    tmp_fr2 = fp_reg_read_hi(f2);
    tmp_fr3 = fp_reg_read_hi(f3);

    if (fp_software_assistance_required(ps, op_fpminmax, tmp_fr2, tmp_fr3)) {
        tmp_fp_env->hi_faults.swa = 1; 

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) {
        tmp_fp_env->hi_flags.v = 1;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->hi_faults.v = 1;
        }

    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->hi_flags.d = 1;
        if (!tmp_fp_env->controls.dd) {
            tmp_fp_env->hi_faults.d = 1;
        }
    }

// ************
// low
// ************
    tmp_fr2 = fp_reg_read_lo(f2);
    tmp_fr3 = fp_reg_read_lo(f3);
 
    if (fp_software_assistance_required(ps, op_fpminmax, tmp_fr2, tmp_fr3)) {
        tmp_fp_env->lo_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) {
        tmp_fp_env->lo_flags.v = 1;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->lo_faults.v = 1;
        }


    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->lo_flags.d = 1;
        if (!tmp_fp_env->controls.dd)
            tmp_fp_env->lo_faults.d = 1;
    }

    return;
}

// *******************************************************************
// fminmax_exception_fault_check()
// *******************************************************************
INLINE void
fminmax_exception_fault_check(
    EM_fp_reg_specifier f2,
    EM_fp_reg_specifier f3,
    EM_opcode_sf_type sf,
    EM_tmp_fp_env_type *tmp_fp_env)
{
EM_fp_reg_type fr2, fr3;

    fr2 = FR[f2];
    fr3 = FR[f3];

    fp_decode_environment( pc_none, sf, tmp_fp_env );

    if (fp_software_assistance_required(ps, op_fminmax, fr2, fr3)) {
        tmp_fp_env->em_faults.swa = 1;
    }

    if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3)) {
        tmp_fp_env->flags.v = 1;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }

    } else if (fp_is_nan(fr2) || fp_is_nan(fr3)) {
        tmp_fp_env->flags.v = 1;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }


    } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3)) {
        tmp_fp_env->flags.d = 1;
        if (!tmp_fp_env->controls.dd)
           tmp_fp_env->em_faults.d = 1;
    }

}

// *******************************************************************
// fms_fnma_()
// *******************************************************************
EM_fp_reg_type
fms_fnma_exception_fault_check(
    EM_fp_reg_specifier f2,
    EM_fp_reg_specifier f3, 
    EM_fp_reg_specifier f4, 
    EM_opcode_pc_type   pc,
    EM_opcode_sf_type   sf,
    EM_tmp_fp_env_type  *tmp_fp_env)
{
EM_fp_reg_type fr2, fr3, fr4;
EM_fp_reg_type tmp_res;

    fr2 = FR[f2];
    fr3 = FR[f3];
    fr4 = FR[f4];

    fp_decode_environment( pc, sf, tmp_fp_env );

    if (fp_software_assistance_required(ps, op_fms_fnma, fr2, fr3, fr4)) {
        tmp_fp_env->em_faults.swa = 1;
        return (FP_ZERO);
    }

    tmp_res = FP_ZERO;

    if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3) || fp_is_unsupported(fr4)) {
        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
            return (tmp_res);
        }

    } else if (fp_is_nan(fr2) || fp_is_nan(fr3) || fp_is_nan(fr4)) {
         if (fp_is_snan(fr2) || fp_is_snan(fr3) || fp_is_snan(fr4)) {
            tmp_fp_env->flags.v = 1;
            if (!tmp_fp_env->controls.vd)  
               tmp_fp_env->em_faults.v = 1;
         }


         if (fp_is_nan(fr4))
             tmp_res = fp_is_snan(fr4)?fp_make_quiet_nan(fr4):fr4;
         else if (fp_is_nan(fr2))
             tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2;
         else if (fp_is_nan(fr3))
             tmp_res = fp_is_snan(fr3)?fp_make_quiet_nan(fr3):fr3;

    } else if (( fp_is_pos_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_pos_inf(fr2) )
            || ( fp_is_pos_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_neg_inf(fr2) )
            || ( fp_is_neg_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_neg_inf(fr2) )
            || ( fp_is_neg_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_pos_inf(fr2) )
            || ( fp_is_pos_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_pos_inf(fr2) )
            || ( fp_is_pos_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_neg_inf(fr2) )
            || ( fp_is_neg_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_neg_inf(fr2) )
            || ( fp_is_neg_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_pos_inf(fr2) )) {
        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
            return (tmp_res);
        }

    } else if ((fp_is_inf(fr3) && fp_is_zero(fr4)) || (fp_is_zero(fr3) && fp_is_inf(fr4))) {
        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
            return (tmp_res);
        }


    } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3) || fp_is_unorm(fr4)) {
        tmp_fp_env->flags.d = 1;
        if (!tmp_fp_env->controls.dd)
           tmp_fp_env->em_faults.d = 1;
    }

    return (tmp_res);
}

// *******************************************************************
// fpms_fpnma_exception_fault_check()
// ********************************************************************
EM_pair_fp_reg_type
fpms_fpnma_exception_fault_check(
    EM_fp_reg_specifier f2,
    EM_fp_reg_specifier f3,
    EM_fp_reg_specifier f4,
    EM_opcode_sf_type   sf,
    EM_tmp_fp_env_type  *tmp_fp_env)
{
EM_pair_fp_reg_type tmp_reg_pair;
EM_fp_reg_type      tmp_fr2 = FR[f2], tmp_fr3 = FR[f3], tmp_fr4 = FR[f4];

    fp_decode_environment( pc_simd, sf, tmp_fp_env );

    tmp_reg_pair.hi = FP_ZERO;
    tmp_reg_pair.lo = FP_ZERO;

// ***************
// high
// ***************
    tmp_fr2 = fp_reg_read_hi(f2);
    tmp_fr3 = fp_reg_read_hi(f3);
    tmp_fr4 = fp_reg_read_hi(f4);

    if (fp_software_assistance_required(ps, op_fpms_fpnma, tmp_fr2, tmp_fr3, tmp_fr4)) {
        tmp_fp_env->hi_faults.swa = 1;

    } else if (fp_is_unsupported(tmp_fr2) || fp_is_unsupported(tmp_fr3) || fp_is_unsupported(tmp_fr4)) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi        = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->hi_faults.v = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) {
        if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) {
            tmp_fp_env->hi_flags.v = 1;
            if (!tmp_fp_env->controls.vd)
                tmp_fp_env->hi_faults.v = 1;
        }

         if (fp_is_nan(tmp_fr4))
             tmp_reg_pair.hi = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4;
         else if (fp_is_nan(tmp_fr2))
             tmp_reg_pair.hi = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2;
         else if (fp_is_nan(tmp_fr3))
             tmp_reg_pair.hi = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3;

    } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi        = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->hi_faults.v = 1;

    } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4))
            || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->hi_faults.v = 1;

    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) {
        tmp_fp_env->hi_flags.d = 1;
        if (!tmp_fp_env->controls.dd)
            tmp_fp_env->hi_faults.d = 1;
    }

// ***************
// low
// ***************
    tmp_fr2 = fp_reg_read_lo(f2);
    tmp_fr3 = fp_reg_read_lo(f3);
    tmp_fr4 = fp_reg_read_lo(f4);

    if (fp_software_assistance_required(ps, op_fpms_fpnma, tmp_fr2, tmp_fr3, tmp_fr4)) {
        tmp_fp_env->lo_faults.swa = 1;

    } else if (fp_is_unsupported(tmp_fr2) || fp_is_unsupported(tmp_fr3) || fp_is_unsupported(tmp_fr4)) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->lo_faults.v = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) {
        if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) {
            tmp_fp_env->lo_flags.v = 1;
            if (!tmp_fp_env->controls.vd)
                tmp_fp_env->lo_faults.v = 1;
        }

         if (fp_is_nan(tmp_fr4))
             tmp_reg_pair.lo = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4;
         else if (fp_is_nan(tmp_fr2))
             tmp_reg_pair.lo = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2;
         else if (fp_is_nan(tmp_fr3))
             tmp_reg_pair.lo = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3;

    } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )
            || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4)
                                     && fp_is_neg_inf(tmp_fr2) )
            || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4)
                                     && fp_is_pos_inf(tmp_fr2) )) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->lo_faults.v = 1;

    } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4))
            || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd)
            tmp_fp_env->lo_faults.v = 1;

    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) {
        tmp_fp_env->lo_flags.d = 1;
        if (!tmp_fp_env->controls.dd)
            tmp_fp_env->lo_faults.d = 1;
    }

    return (tmp_reg_pair);
}



INLINE EM_fp_dp_type
fp_max_or_infinity(EM_uint_t sign, EM_tmp_fp_env_type *tmp_fp_env,
     EM_uint_t e_max, EM_uint128_t max_significand)
{
    EM_fp_dp_type tmp_res;
    tmp_res.sign = sign;

    if (tmp_fp_env->rc == rc_rm) {
        if (tmp_res.sign) {
            tmp_res.exponent    = FP_DP_EXP_ONES;
            tmp_res.significand = U128_0x80000000000000000000000000000000;
        }else {
            tmp_res.exponent    = e_max;
            tmp_res.significand = max_significand;
        }

    } else if (tmp_fp_env->rc == rc_rz) {
        tmp_res.exponent    = e_max;
        tmp_res.significand = max_significand;

    } else if (tmp_fp_env->rc == rc_rp) {
        if (tmp_res.sign) {
            tmp_res.exponent    = e_max;
            tmp_res.significand = max_significand;
        }else {
            tmp_res.exponent    = FP_DP_EXP_ONES;
            tmp_res.significand = U128_0x80000000000000000000000000000000;
        }

    } else {
        tmp_res.exponent    = FP_DP_EXP_ONES;
        tmp_res.significand = U128_0x80000000000000000000000000000000;
    }

    return(tmp_res);
}

INLINE EM_fp_dp_type
fp_mul(EM_fp_reg_type fr3, EM_fp_reg_type fr4)
{
    EM_fp_dp_type tmp_res;
    EM_int_t normalize_count;

// all cases which might have faulted have been screened out 
// we still may trap on overflow, underflow and/or inexact later

    if (fp_is_zero(fr3) || fp_is_zero(fr4)) {
            /* correctly signed zero */
        tmp_res = fp_fr_to_dp(FP_ZERO);
        tmp_res.sign = fr3.sign ^ fr4.sign;
    } else if (fp_is_inf(fr3) || fp_is_inf(fr4)) {
            /* correctly signed inf*/
        tmp_res = fp_fr_to_dp(FP_INFINITY);
        tmp_res.sign = fr3.sign ^ fr4.sign;
    } else if (fp_is_pseudo_zero(fr3) || fp_is_pseudo_zero(fr4)) {
            /* pseudo zero  if one operand is a pseudo-zero, return real zero.
               pz * NaN = Nan, but we already tested for Nan                   */
        tmp_res = fp_fr_to_dp(FP_ZERO);
        tmp_res.sign = fr3.sign ^ fr4.sign;
    } else {
            /* (un)normal * (un)normal */
        tmp_res.sign         = fr3.sign ^ fr4.sign;
        tmp_res.exponent     = (EM_uint_t)(
                                         (((EM_int_t)fr3.exponent)-FP_REG_BIAS)
                                       + (((EM_int_t)fr4.exponent)-FP_REG_BIAS)
                                       + FP_DP_BIAS);
                /* x.xxx (64-bits) * y.yyy (64-bits)
                => zz.zzzzzz (128-bits) */
        tmp_res.significand = fp_U64_x_U64_to_U128(fr3.significand,
                                                fr4.significand);
        if (fp_U128_lead0(tmp_res.significand) == 0) {
                /* 1.xxx (64-bits) * 1.yyy (64-bits)
                => 1z.zzzzzz (128-bits) */
            tmp_res.exponent += 1;
                /* 1z.zzzzzz
                => 1.zzzzzzz (128-bits) */
        } else if (fp_U128_lead0(tmp_res.significand) == 1) {
                /* 1.xxx (64-bits) * 1.yyy (64-bits)
                => 0z.zzzzzz (128-bits) */
            tmp_res.significand = fp_U128_lsh(tmp_res.significand,1);
                /* 0z.zzzzzz => z.zzzzzz0 (128-bits) */
        } else {
                /* 0.xxx (64-bits) * 0.yyy (64-bits)
                => 00.zzzzzz (128-bits) all unsigned int's */
            normalize_count = fp_U128_lead0(tmp_res.significand);
            tmp_res.exponent -= normalize_count-1;
            tmp_res.significand = fp_U128_lsh(tmp_res.significand,
                                                 normalize_count);
        }
    }
    tmp_res.sticky = 0;
    return(tmp_res);
}

INLINE EM_fp_reg_type
fp_normalize(EM_fp_reg_type freg)
{
    EM_int_t tmp_normalize_count;

    if (fp_is_nan(freg) || fp_is_inf(freg) || fp_is_normal(freg)
    || fp_is_unsupported(freg) || fp_is_zero(freg) || fp_is_natval(freg))
        return (freg);

    tmp_normalize_count = fp_U64_lead0(freg.significand);
    if (tmp_normalize_count == 64) { /* ftz pseudo-zero */
        if(freg.exponent)
            freg.exponent = 0;
        return (freg);
    } else if(freg.exponent == 1) {
        return(freg);


    } else if ((((EM_int_t)freg.exponent) - tmp_normalize_count) <= 0) {
        tmp_normalize_count = freg.exponent -1;
        freg.exponent       = 1;
        freg.significand  <<= tmp_normalize_count;
        return (freg);

    } else { /* normalize */
        freg.exponent -= tmp_normalize_count;
        freg.significand <<= tmp_normalize_count;
        return(freg);
    }
}

INLINE EM_fp_dp_type
fp_normalize_dp(EM_fp_dp_type fp_dp)
{
    EM_int_t tmp_normalize_count;

    if (fp_is_nan_dp(fp_dp) || fp_is_inf_dp(fp_dp) || fp_is_normal_dp(fp_dp)
    || fp_is_zero_dp(fp_dp))
        return (fp_dp);
    else if (fp_is_unsupported_dp(fp_dp)) /* unsupported are turned into nans */
        return (fp_fr_to_dp(FP_QNAN));
    tmp_normalize_count = fp_U128_lead0(fp_dp.significand);
    if (tmp_normalize_count == 128) { /* ftz pseudo-zero */
        if (fp_dp.exponent)
            fp_dp.exponent = 0;
        return (fp_dp);
        
    } else if ((((EM_int_t)fp_dp.exponent) - tmp_normalize_count) <= 0) {
        /* ftz register file format (pseudo-)denormals */
        fp_dp.exponent = 0;
        fp_dp.significand = U128_0;
        return (fp_dp);
    } else { /* normalize */
        fp_dp.exponent -= tmp_normalize_count;
        fp_dp.significand = fp_U128_lsh(fp_dp.significand,
                                           tmp_normalize_count);
        return(fp_dp);
    }
}


EM_fp_dp_type
fp82_fp_fr_to_dp(EM_fp_reg_type fr1)
{
    EM_fp_dp_type tmp_res;
    tmp_res.sign = fr1.sign;
    if (fr1.exponent == 0)
        tmp_res.exponent = 0;
    else if (fr1.exponent == FP_REG_EXP_ONES)
        tmp_res.exponent = FP_DP_EXP_ONES;
    else
        tmp_res.exponent = (EM_uint_t)(((EM_int_t)fr1.exponent)
                                   - FP_REG_BIAS + FP_DP_BIAS);

    tmp_res.significand.hi = fr1.significand;
    tmp_res.significand.lo = U64_0;
    tmp_res.sticky = 0;
    return(fp_normalize_dp(tmp_res));
}

// *******************************************************************
// frcpa_exception_fault_check()
// *******************************************************************
EM_fp_reg_type
frcpa_exception_fault_check(
   EM_fp_reg_specifier f2,
   EM_fp_reg_specifier f3, 
   EM_opcode_sf_type   sf,
   EM_tmp_fp_env_type  *tmp_fp_env)
{
    EM_fp_reg_type fr2, fr3;
    EM_fp_reg_type tmp_res;
    EM_int_t estimated_exponent;

    fr2 = FR[f2];
    fr3 = FR[f3];
    fp_decode_environment( pc_none, sf, tmp_fp_env );

    if (fp_software_assistance_required(ps, op_frcpa, fr2, fr3) ) {
        tmp_fp_env->em_faults.swa = 1;
        return (FP_ZERO);
    }

    tmp_res = FP_ZERO;

    if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3)) {
        tmp_fp_env->flags.v = 1;
        tmp_res             = FP_QNAN;

        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }

    } else if (fp_is_nan(fr2) || fp_is_nan(fr3)) {
         if (fp_is_snan(fr2) || fp_is_snan(fr3)) {
             tmp_fp_env->flags.v = 1;
             if (!tmp_fp_env->controls.vd) {
                 tmp_fp_env->em_faults.v = 1;
             }
         }
         if (fp_is_nan(fr2)) {
             tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2;
         } else if (fp_is_nan(fr3)) {
             tmp_res = fp_is_snan(fr3)?fp_make_quiet_nan(fr3):fr3;
         }

    } else if ( (fp_is_inf(fr2)  && fp_is_inf(fr3))
              || ( (fp_is_zero(fr2) || fp_is_pseudo_zero(fr2))
                && (fp_is_zero(fr3) || fp_is_pseudo_zero(fr3)) ) ) {
        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }

    } else if (  ( ( fp_is_normal(fr2) && !fp_is_zero(fr2) )
                || ( fp_is_unorm(fr2)  && !fp_is_pseudo_zero(fr2) ) )
              && (   fp_is_zero(fr3)   ||  fp_is_pseudo_zero(fr3) ) ) {
        tmp_fp_env->flags.z = 1;
        tmp_res = FP_INFINITY;
        tmp_res.sign = fr2.sign ^ fr3.sign;
        if (!tmp_fp_env->controls.zd) {
            tmp_fp_env->em_faults.z = 1;
        }


    } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3)) {
        tmp_fp_env->flags.d = 1;
        if (!tmp_fp_env->controls.dd) {
            tmp_fp_env->em_faults.d = 1;
        }
    } 
/************************************************************
This is the architecturally mandated swa fault check.

The precision of the working type is 17-bit exponent.
   fp_normalize() will normalize except in the case of a register denormal.
   In this context, fp_is_unorm() returns 1 if integer bit is 0
   and that occurs when fr3.exponent < emin.
Note that the estimated exponent is unbiased, because the bias
is subtracted out.
*************************************************************/
    if ( !fp_is_zero(fr2) && fp_is_finite(fr2) && !fp_is_pseudo_zero(fr2)
      && !fp_is_zero(fr3) && fp_is_finite(fr3) && !fp_is_pseudo_zero(fr3)
       ) {

        fr2 = fp_normalize(fp_reg_read(fr2));
        fr3 = fp_normalize(fp_reg_read(fr3));

        estimated_exponent = (EM_int_t)(fr2.exponent)
                           - (EM_int_t)(fr3.exponent);
        
	    if ( fp_is_unorm(fr3) 
          || ( fr3.exponent       >=  (FP_REG_BIAS+FP_REG_BIAS-2) )
          || ( estimated_exponent >=  ((EM_int_t)(FP_REG_BIAS)) )
          || ( estimated_exponent <= (2 - (EM_int_t)FP_REG_BIAS) )
          || ( fr2.exponent       <= (ss_double_extended_64)     )
           ) {
                 tmp_fp_env->em_faults.swa = 1; 
        }
    }
    return (tmp_res);
}

// *******************************************************************
// fprcpa_exception_fault_check()
// *******************************************************************
EM_pair_fp_reg_type
fprcpa_exception_fault_check(
   EM_fp_reg_specifier    f2,
   EM_fp_reg_specifier    f3,
   EM_opcode_sf_type      sf,
   EM_tmp_fp_env_type     *tmp_fp_env, 
   EM_limits_check_fprcpa  *limits_check)
{
EM_pair_fp_reg_type tmp_reg_pair;
EM_fp_reg_type      tmp_fr2 = FR[f2], tmp_fr3 = FR[f3];
EM_int_t            estimated_exponent;

    fp_decode_environment( pc_simd, sf, tmp_fp_env );

    tmp_reg_pair.hi = FP_ZERO;
    tmp_reg_pair.lo = FP_ZERO;

// ************
// high
// ************
    tmp_fr2 = fp_reg_read_hi(f2);
    tmp_fr3 = fp_reg_read_hi(f3);

    if (fp_software_assistance_required(ps, op_fprcpa, tmp_fr2, tmp_fr3)) {
        tmp_fp_env->hi_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) {
        if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3)) {
            tmp_fp_env->hi_flags.v = 1;
            if (!tmp_fp_env->controls.vd) {
                tmp_fp_env->hi_faults.v = 1;
            }
        }
        if (fp_is_nan(tmp_fr2)) {
            tmp_reg_pair.hi = fp_is_snan(tmp_fr2)
                            ? fp_make_quiet_nan(tmp_fr2) : tmp_fr2;
        } else if (fp_is_nan(tmp_fr3)) {
            tmp_reg_pair.hi = fp_is_snan(tmp_fr3)
                            ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3;
        }

/*******************************************************************************
(f2 and f3 are inf) or (f2 and f3 are 0); returns qnan
********************************************************************************/
    } else if ( (fp_is_inf(tmp_fr2)  && fp_is_inf(tmp_fr3)  )
             || (fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) ) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->hi_faults.v = 1;
        }
/*******************************************************************************
(f2 is non-zero (normal or denormal but not inf) and f3 is zero; returns inf
The reason for the "but not inf" is because inf/0 shoudl not set the
divide-by-zero flag.
********************************************************************************/
    } else if ( !fp_is_inf(tmp_fr2) && !fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) {
        tmp_fp_env->hi_flags.z = 1;
        tmp_reg_pair.hi        = FP_INFINITY;
        tmp_reg_pair.hi.sign   = tmp_fr2.sign ^ tmp_fr3.sign;
        if (!tmp_fp_env->controls.zd) {
            tmp_fp_env->hi_faults.z = 1;
        }

    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->hi_flags.d = 1;
        if (!tmp_fp_env->controls.dd) {
            tmp_fp_env->hi_faults.d = 1;
        }
    } 

    if ( !fp_is_zero(tmp_fr2) && fp_is_finite(tmp_fr2)
      && !fp_is_zero(tmp_fr3) && fp_is_finite(tmp_fr3) ) {

        tmp_fr2 = fp_normalize(tmp_fr2);

        if ( fp_is_unorm(tmp_fr3) ) {
            limits_check->hi_fr3        = 1; /* recip(fr3_hi) not rep. */
            tmp_reg_pair.hi             = FP_INFINITY;  
            tmp_reg_pair.hi.sign        = tmp_fr3.sign;
            tmp_fr3                     = fp_normalize(tmp_fr3);

        } else if ( tmp_fr3.exponent >= (FP_REG_BIAS+FP_SGL_BIAS-2) ) {
            limits_check->hi_fr3        = 1; /* recip(fr3_hi) not rep. */
            tmp_reg_pair.hi             = FP_ZERO;             
            tmp_reg_pair.hi.sign        = tmp_fr3.sign;
        }

        estimated_exponent = (EM_int_t)tmp_fr2.exponent
                           - (EM_int_t)tmp_fr3.exponent;


        if (  (estimated_exponent >= (((EM_int_t)(FP_SGL_BIAS)))          )
           || (estimated_exponent <= (2-((EM_int_t)FP_SGL_BIAS))            )
           || (tmp_fr2.exponent   <= (ss_single_24+FP_REG_BIAS-FP_SGL_BIAS) )
           ) {
            limits_check->hi_fr2_or_quot = 1; /* hi est. quot. or fr2_hi */
        }
    }

// ************
// low
// ************
    tmp_fr2 = fp_reg_read_lo(f2);
    tmp_fr3 = fp_reg_read_lo(f3);

    if (fp_software_assistance_required(ps, op_fprcpa, tmp_fr2, tmp_fr3)) {
        tmp_fp_env->lo_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) {
        if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3)) {
            tmp_fp_env->lo_flags.v = 1;
            if (!tmp_fp_env->controls.vd) {
                tmp_fp_env->lo_faults.v = 1;
            }
        }
        if (fp_is_nan(tmp_fr2)) {
            tmp_reg_pair.lo = fp_is_snan(tmp_fr2)
                            ? fp_make_quiet_nan(tmp_fr2) : tmp_fr2;
        } else if (fp_is_nan(tmp_fr3)) {
            tmp_reg_pair.lo = fp_is_snan(tmp_fr3)
                            ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3;
        }
/*******************************************************************************
(f2 and f3 are inf) or (f2 and f3 are 0); returns qnan
********************************************************************************/
   } else if ( ( fp_is_inf(tmp_fr2)  && fp_is_inf(tmp_fr3)  )
            || ( fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) ) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo        = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->lo_faults.v = 1;
        }
/*******************************************************************************
(f2 is non-zero (normal or denormal but not inf) and f3 is zero; returns inf
The reason for the "but not inf" is because inf/0 should not set the
divide-by-zero flag.
********************************************************************************/
    } else if ( !fp_is_inf(tmp_fr2) && !fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) {
        tmp_fp_env->lo_flags.z = 1;
        tmp_reg_pair.lo = FP_INFINITY;
        tmp_reg_pair.lo.sign = tmp_fr2.sign ^ tmp_fr3.sign;
        if (!tmp_fp_env->controls.zd) {
            tmp_fp_env->lo_faults.z = 1;
        }

    } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->lo_flags.d = 1;
        if (!tmp_fp_env->controls.dd) {
            tmp_fp_env->lo_faults.d = 1;
        }
    } 

    if ( !fp_is_zero(tmp_fr2) && fp_is_finite(tmp_fr2)
      && !fp_is_zero(tmp_fr3) && fp_is_finite(tmp_fr3) ) {

        tmp_fr2 = fp_normalize(tmp_fr2);

        if ( fp_is_unorm(tmp_fr3) ) {
            limits_check->lo_fr3 = 1; /* recip(fr3_lo) not rep. */
            tmp_reg_pair.lo      = FP_INFINITY;          
            tmp_reg_pair.lo.sign        = tmp_fr3.sign;
            tmp_fr3              = fp_normalize(tmp_fr3);

        } else if ( tmp_fr3.exponent >= (FP_REG_BIAS+FP_SGL_BIAS-2) ) {
            limits_check->lo_fr3 = 1; /* recip(fr3_lo) not rep. */
            tmp_reg_pair.lo      = FP_ZERO;             
            tmp_reg_pair.lo.sign        = tmp_fr3.sign;
        }

        estimated_exponent = (EM_int_t)tmp_fr2.exponent
                           - (EM_int_t)tmp_fr3.exponent;

        if (  (estimated_exponent >= (((EM_int_t)(FP_SGL_BIAS)))          )
           || (estimated_exponent <= (2-((EM_int_t)FP_SGL_BIAS))            )
           || (tmp_fr2.exponent   <= (ss_single_24+FP_REG_BIAS-FP_SGL_BIAS) )
           ) {
            limits_check->lo_fr2_or_quot = 1; /* lo est. quot. or fr2_lo */
        }
          
    }   

    return (tmp_reg_pair);
}

// *******************************************************************
// frsqrta_exception_fault_check()
// *******************************************************************
EM_fp_reg_type
frsqrta_exception_fault_check(
     EM_fp_reg_specifier f3,
     EM_opcode_sf_type   sf,
     EM_tmp_fp_env_type  *tmp_fp_env)
{
EM_fp_reg_type tmp_res, fr3;
    
    fr3 = FR[f3];
    fp_decode_environment( pc_none, sf, tmp_fp_env );

    if (fp_software_assistance_required(ps, op_frsqrta, fr3)) {
        tmp_fp_env->em_faults.swa = 1;
        return (FP_ZERO);
    }

    tmp_res = FP_ZERO;

    if (fp_is_unsupported(fr3)) {
        tmp_fp_env->flags.v = 1;
        tmp_res = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }

    } else if (fp_is_nan(fr3)) {
        if(fp_is_snan(fr3)){
           tmp_fp_env->flags.v = 1;
           if (!tmp_fp_env->controls.vd)  {
               tmp_fp_env->em_faults.v = 1;
           }
        }
        tmp_res = fp_is_snan(fr3)
                ? fp_make_quiet_nan(fr3) : fr3;

    } else if (fp_is_neg_inf(fr3)) {
        tmp_fp_env->flags.v = 1;
        tmp_res             = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }

    } else if ( fp_is_neg_non_zero(fr3) && !fp_is_pseudo_zero(fr3)) {
        tmp_fp_env->flags.v = 1;
        tmp_res             = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->em_faults.v = 1;
        }

 
    } else if (fp_is_unorm(fr3)) {
        tmp_fp_env->flags.d = 1;
        if( !tmp_fp_env->controls.dd) {
           tmp_fp_env->em_faults.d = 1;
        }
    }


    if( (fp_is_pos_non_zero(fr3) && !fp_is_pseudo_zero(fr3) )&& fp_is_finite(fr3)) {
       fr3 = fp_normalize(fp_reg_read(fr3));
       if(fr3.exponent <= ss_double_extended_64) {
          tmp_fp_env->em_faults.swa = 1; 
       } 
    }
 
    return (tmp_res);
}

// *******************************************************************
// fprsqrta_exception_fault_check()
// *******************************************************************
EM_pair_fp_reg_type
fprsqrta_exception_fault_check(
    EM_fp_reg_specifier      f3,
    EM_opcode_sf_type        sf,
    EM_tmp_fp_env_type       *tmp_fp_env, 
    EM_limits_check_fprsqrta *limits_check)
{
EM_pair_fp_reg_type tmp_reg_pair;
EM_fp_reg_type      tmp_fr3 = FR[f3];

    fp_decode_environment( pc_simd, sf, tmp_fp_env );

    tmp_reg_pair.hi = FP_ZERO;
    tmp_reg_pair.lo = FP_ZERO;

// ********
// high
// ********
    tmp_fr3 = fp_reg_read_hi(f3);
    if (fp_software_assistance_required(ps, op_fprsqrta, tmp_fr3)) {
        tmp_fp_env->hi_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr3)) {
        if (fp_is_snan(tmp_fr3)) {
            tmp_fp_env->hi_flags.v = 1;
            if (!tmp_fp_env->controls.vd) {
                tmp_fp_env->hi_faults.v = 1;
            }
        }
        tmp_reg_pair.hi = fp_is_snan(tmp_fr3)
                        ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3;

    } else if (fp_is_neg_inf(tmp_fr3)) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->hi_faults.v = 1;
        }
    } else if (fp_is_neg_non_zero(tmp_fr3)) {
        tmp_fp_env->hi_flags.v = 1;
        tmp_reg_pair.hi        = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->hi_faults.v = 1;
        }

    } else if (fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->hi_flags.d = 1;
        if (!tmp_fp_env->controls.dd) {
            tmp_fp_env->hi_faults.d = 1;
        }

    } 
    if(fp_is_pos_non_zero(tmp_fr3) && fp_is_finite(tmp_fr3)) {
       tmp_fr3 = fp_normalize(tmp_fr3);
       if (tmp_fr3.exponent <= (FP_REG_BIAS - FP_SGL_BIAS + ss_single_24)) {
            limits_check->hi = 1;
       } else {
            limits_check->hi = 0;
       }
    }

// ********
// low
// ********
    tmp_fr3 = fp_reg_read_lo(f3);

    if (fp_software_assistance_required(ps, op_fprsqrta, tmp_fr3)) {
        tmp_fp_env->lo_faults.swa = 1;

    } else if (fp_is_nan(tmp_fr3)) {
        if (fp_is_snan(tmp_fr3)) {
            tmp_fp_env->lo_flags.v = 1;
            if (!tmp_fp_env->controls.vd) {
                tmp_fp_env->lo_faults.v = 1;
            }
        }
        tmp_reg_pair.lo = fp_is_snan(tmp_fr3)
                        ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3;

    } else if (fp_is_neg_inf(tmp_fr3)) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->lo_faults.v = 1;
        }
    } else if (fp_is_neg_non_zero(tmp_fr3)) {
        tmp_fp_env->lo_flags.v = 1;
        tmp_reg_pair.lo = FP_QNAN;
        if (!tmp_fp_env->controls.vd) {
            tmp_fp_env->lo_faults.v = 1;
        }

    } else if (fp_is_unorm(tmp_fr3)) {
        tmp_fp_env->lo_flags.d = 1;
        if (!tmp_fp_env->controls.dd) {
            tmp_fp_env->lo_faults.d = 1;
        }
    }

    if(fp_is_pos_non_zero(tmp_fr3) && fp_is_finite(tmp_fr3)) {
       tmp_fr3 = fp_normalize(tmp_fr3);
       if (tmp_fr3.exponent <= (FP_REG_BIAS - FP_SGL_BIAS + ss_single_24)) {
            limits_check->lo = 1;
       } else {
            limits_check->lo = 0;
       }
    }


    return (tmp_reg_pair);
}



INLINE EM_boolean_t
fp_is_finite(EM_fp_reg_type freg)
{
    if ( fp_is_inf(freg) || fp_is_nan(freg) || fp_is_unsupported(freg) ) {
        return(0);
    } else {
        return(1);
    }
}

INLINE EM_boolean_t
fp_is_inf(EM_fp_reg_type freg)
{
    if ( (freg.exponent == FP_REG_EXP_ONES)
       &&(freg.significand == U64_0x8000000000000000) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_inf_dp(EM_fp_dp_type tmp_res)
{
    if ( (tmp_res.exponent == FP_DP_EXP_ONES)
       && fp_U128_eq(tmp_res.significand,
                      U128_0x80000000000000000000000000000000) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_nan(EM_fp_reg_type freg)
{
    if (  (freg.exponent == FP_REG_EXP_ONES)
      && ((freg.significand & U64_0x8000000000000000) != 0)
      && ((freg.significand & U64_0x7FFFFFFFFFFFFFFF) != 0) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_nan_dp(EM_fp_dp_type tmp_res)
{
    if ( (tmp_res.exponent == FP_DP_EXP_ONES)
       && fp_U128_eq(U128_0x80000000000000000000000000000000,
                  fp_U128_band(tmp_res.significand,
                            U128_0x80000000000000000000000000000000))
       && !fp_U128_eq(U128_0,
                  fp_U128_band(tmp_res.significand,
                            U128_0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
       ) {
        return (1);
    } else {
        return (0);
    }
}

INLINE EM_boolean_t
fp_is_natval(EM_fp_reg_type freg)
{
    if ( (freg.sign == 0)
     && (freg.exponent == 0x1FFFE)
     && (freg.significand == U64_0) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_neg_dp(EM_fp_dp_type tmp_res)
{
    if (tmp_res.sign) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_neg_inf(EM_fp_reg_type freg)
{
    if ( (freg.sign == 1)
      && (freg.exponent == FP_REG_EXP_ONES)
      && (freg.significand == U64_0x8000000000000000) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_neg_non_zero(EM_fp_reg_type freg)
{
    if ( (freg.sign == 1) && !fp_is_zero(freg) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_normal(EM_fp_reg_type freg)
{
    if ( (freg.exponent != 0)
      && (freg.exponent != FP_REG_EXP_ONES)
      && ((freg.significand & U64_0x8000000000000000) != 0) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_normal_dp(EM_fp_dp_type tmp_res)
{
    if ( (tmp_res.exponent != 0)
      && (tmp_res.exponent != FP_DP_EXP_ONES)
      && fp_U128_eq(U128_0x80000000000000000000000000000000,
                 fp_U128_band(tmp_res.significand,
                           U128_0x80000000000000000000000000000000))
      ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_pos_dp(EM_fp_dp_type tmp_res)
{
    if (!tmp_res.sign) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_pos_inf(EM_fp_reg_type freg)
{
    if ( (freg.sign == 0)
      && (freg.exponent == FP_REG_EXP_ONES)
      && (freg.significand == U64_0x8000000000000000) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_pos_non_zero(EM_fp_reg_type freg)
{
    if ( (freg.sign == 0) && !fp_is_zero(freg) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_pseudo_zero(EM_fp_reg_type freg)
{
    if ( (freg.exponent != 0)
      && (freg.exponent != FP_REG_EXP_ONES)
      && (freg.significand == U64_0 && !fp_is_natval (freg)) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_qnan(EM_fp_reg_type freg)
{
    if ( (freg.exponent == FP_REG_EXP_ONES)
      &&((freg.significand & U64_0xC000000000000000) == U64_0xC000000000000000) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_snan(EM_fp_reg_type freg)
{
    if ( (freg.exponent == FP_REG_EXP_ONES)
      &&((freg.significand & U64_0xC000000000000000) == U64_0x8000000000000000)
      &&((freg.significand & U64_0x3FFFFFFFFFFFFFFF) != 0) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_unorm(EM_fp_reg_type freg)
{
    if ( ( (freg.exponent != 0)
        && (freg.exponent != FP_REG_EXP_ONES)
        &&((freg.significand & U64_0x8000000000000000) == 0) )
    /* double-extended pseudo-denormal or double-extended denormal */
      || ( (freg.exponent == 0) && (freg.significand != 0) ) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_unorm_dp(EM_fp_dp_type tmp_res)
{
    if ( (tmp_res.exponent != 0)
      && (tmp_res.exponent != FP_DP_EXP_ONES)
      &&((tmp_res.significand.hi & U64_0x8000000000000000) == 0) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_unsupported(EM_fp_reg_type freg)
{    
    if (  fp_is_natval(freg) || fp_is_nan(freg)   || fp_is_inf(freg)
       || fp_is_normal(freg) || fp_is_unorm(freg) || fp_is_zero(freg) ) {
        return(0);
    } else {
        return(1);
    }
}

INLINE EM_boolean_t
fp_is_unsupported_dp(EM_fp_dp_type tmp_res)
{
    if (  fp_is_nan_dp(tmp_res)    || fp_is_inf_dp(tmp_res)
       || fp_is_normal_dp(tmp_res) || fp_is_unorm_dp(tmp_res)
       || fp_is_zero_dp(tmp_res) ) {
        return(0);
    } else {
        return(1);
    }
}

INLINE EM_boolean_t
fp_is_zero(EM_fp_reg_type freg)
{
    if ( (freg.exponent == 0) && (freg.significand == U64_0) ) {
        return(1);
    } else {
        return(0);
    }
}

INLINE EM_boolean_t
fp_is_zero_dp(EM_fp_dp_type tmp_res)
{
    if ( (tmp_res.exponent == 0) && fp_U128_eq(tmp_res.significand, U128_0) ) {
        return(1);
    } else {
        return(0);
    }
}

EM_int_t
fp82_fp_U64_lead0(EM_uint64_t value)
{
EM_int_t tmp_i, offset=0;
EM_uint64_t tmp_mask;

    if( value == U64_0) 
       return(64);

    tmp_mask = U64_0x8000000000000000;

    if( (value & U64_0xFFFFFFFF00000000) != U64_0) {

       if( (value & U64_0xFFFF000000000000) != U64_0) {

         if( (value & U64_0xFF00000000000000) != U64_0) {
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i);
               }
            }
         }
         else { /* 0x00FF000000000000 */
            value  <<= 8;
            offset  += 8;
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i + offset);
               }
            }
         }
      } 
      else { /* 0x0000FFFF00000000 */
         value   <<= 16;
         offset   += 16;
         if( (value & U64_0xFF00000000000000) != U64_0) {
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i + offset);
               }
            }
         }
         else {
            value  <<= 8;
            offset  += 8;
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i + offset);
               }
            }
         }
      }
   }
   else { /*  0x00000000 FFFFFFFF */
      value  <<= 32;
      offset  += 32;
       if( (value & U64_0xFFFF000000000000) != U64_0) {

         if( (value & U64_0xFF00000000000000) != U64_0) {
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i + offset);
               }
            }
         }
         else { /* 0x00000000 00FF0000 */
            value  <<= 8;
            offset  += 8;
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i + offset);
               }
            }
         }
      } 
      else {   /* 0x00000000 0000FFFF */
         value   <<= 16;
         offset   += 16;
         if( (value & U64_0xFF00000000000000) != U64_0) {
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i + offset);
               }
            }
         }
         else {
            value  <<= 8;
            offset  += 8;
            for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) {
               if ( (value & tmp_mask) != U64_0 ) {
                  return(tmp_i + offset);
               }
            }
         }
      }
   }

   return(64); // MACH ADDED

}

EM_int_t
fp_U128_lead0(EM_uint128_t value)
{
    EM_int_t tmp_i;

    tmp_i = fp_U64_lead0(value.hi);
    if (tmp_i == 64) {
        tmp_i += fp_U64_lead0(value.lo);
    }
    return(tmp_i);
}

EM_int_t
fp82_fp_U256_lead0(EM_uint256_t value)
{
    EM_int_t tmp_i;

    tmp_i = fp_U64_lead0(value.hh);
    if (tmp_i == 64) {
        tmp_i += fp_U64_lead0(value.hl);
        if (tmp_i == 128) {
            tmp_i += fp_U64_lead0(value.lh);
            if (tmp_i == 192) {
                tmp_i += fp_U64_lead0(value.ll);
            }
        }
    }
    return(tmp_i);
}

// *******************************************************************
// fp_mem_to_fr_format()
// *******************************************************************
EM_fp_reg_type
fp_mem_to_fr_format(
    EM_memory_type mem,
    EM_uint_t      size,
    EM_uint_t      integer_form)
{

/******************************************************
integer_form = 0           floating point
integer_form = 1           simd, integer
*******************************************************/

    EM_fp_reg_type tmp_freg;
    EM_uint64_t    tmp_significand, tmp_significand_hi, tmp_significand_lo;

    switch (size) {
        case 4:/* single */
            tmp_freg.sign = mem.fp_single.sign;
            if ( (mem.fp_single.exponent    == 0)
              && (mem.fp_single.significand == 0) ) { /* zero */
                tmp_freg.exponent = 0;
            } else if (mem.fp_single.exponent == 0) { /* denormal */
                tmp_freg.exponent = (EM_uint_t)(FP_REG_BIAS - FP_SGL_BIAS + 1);
            } else if (mem.fp_single.exponent == FP_SGL_EXP_ONES) { /* Inf, NaN, NaTVal */
                tmp_freg.exponent = FP_REG_EXP_ONES;
            } else {
                tmp_freg.exponent = (EM_uint_t)
                                  (((EM_int_t)mem.fp_single.exponent)
                                  - FP_SGL_BIAS + FP_REG_BIAS);
            }
            tmp_freg.significand =
                    (((EM_uint64_t)mem.fp_single.significand)<<40)
#ifdef HPC_BUGS
                    | (((mem.fp_single.exponent != U64_0)?U64_1:U64_0)<<63);
#else
                    | (((mem.fp_single.exponent != 0)?U64_1:U64_0)<<63);
#endif

            break;

        case 8: /* double */
            if (integer_form) {
                tmp_freg.sign = 0;
                tmp_freg.significand = mem.uint_64.uvalue;
                tmp_freg.exponent    = FP_INTEGER_EXP;
            } else {
                tmp_freg.sign = mem.fp_double.sign;
                if ( (mem.fp_double.exponent    == 0)
                  && (mem.fp_double.significand_hi == 0) 
                  && (mem.fp_double.significand_lo == 0) ){    /* zero */
                    tmp_freg.exponent = 0;
                } else if (mem.fp_double.exponent == 0) {     /* denormal */
                     tmp_freg.exponent = (EM_uint_t)(FP_REG_BIAS - FP_DBL_BIAS + 1);
                } else if (mem.fp_double.exponent == FP_DBL_EXP_ONES) { /* Inf, NaN, NaTVal */
                    tmp_freg.exponent = FP_REG_EXP_ONES;
                } else {
                    tmp_freg.exponent = (EM_uint_t)
                                      (((EM_int_t)mem.fp_double.exponent)
                                      - FP_DBL_BIAS + FP_REG_BIAS);
                }
                tmp_significand_lo = ((EM_uint64_t)(mem.fp_double.significand_lo)) ;
                tmp_significand_hi = (((EM_uint64_t)(mem.fp_double.significand_hi)) << 32);
                tmp_significand = tmp_significand_lo | tmp_significand_hi;

                tmp_freg.significand =
                         (tmp_significand<<11)
#ifdef HPC_BUGS
                     | (((mem.fp_double.exponent != U64_0)?U64_1:U64_0)<<63);
#else
                     | (((mem.fp_double.exponent != 0)?U64_1:U64_0)<<63);
#endif
            }
            break;

        case 10: /* double extended */
            tmp_freg.sign = mem.fp_double_extended.sign;
            if (mem.fp_double_extended.exponent == 0) {
                    /* Zero or (Pseudo-)Denormal */
                tmp_freg.exponent = 0;
            } else if (mem.fp_double_extended.exponent == FP_EXT_EXP_ONES) {
                    /* Inf, NaN, NaTVal */
                tmp_freg.exponent = FP_REG_EXP_ONES;
            } else { /* Normal */
                tmp_freg.exponent = (EM_uint_t)
                                  (((EM_int_t)mem.fp_double_extended.exponent)
                                  - FP_EXT_BIAS + FP_REG_BIAS);
            }
	    memcpy(&tmp_freg.significand,
		    mem.fp_double_extended.significand, 8);
            break;

        case 16: /* fill */
            tmp_freg.sign        = mem.fp_spill_fill.sign;
            tmp_freg.exponent    = mem.fp_spill_fill.exponent;
            tmp_freg.significand = mem.fp_spill_fill.significand;
            break;
    }
    return (tmp_freg);
}


INLINE EM_fp_reg_type
fp_make_quiet_nan(EM_fp_reg_type freg)
{
    freg.significand |= U64_0x4000000000000000;
    return (freg);
}



EM_boolean_t
fp82_fp_raise_fault(EM_tmp_fp_env_type tmp_fp_env)
{
    if(tmp_fp_env.simd == 1) {
         if  (tmp_fp_env.lo_faults.swa || tmp_fp_env.lo_faults.v
         ||   tmp_fp_env.lo_faults.d   || tmp_fp_env.lo_faults.z 

         ||   tmp_fp_env.hi_faults.swa || tmp_fp_env.hi_faults.v 
         ||   tmp_fp_env.hi_faults.d   || tmp_fp_env.hi_faults.z )

          return(1);
    } else if ( tmp_fp_env.em_faults.swa || tmp_fp_env.em_faults.v
         ||   tmp_fp_env.em_faults.d   || tmp_fp_env.em_faults.z )
          return (1);
    return (0);
}


EM_boolean_t
fp82_fp_raise_traps(EM_tmp_fp_env_type tmp_fp_env)
{
    if(tmp_fp_env.simd == 1) {
       if   (tmp_fp_env.hi_traps.o || tmp_fp_env.hi_traps.un || tmp_fp_env.hi_traps.i
       ||    tmp_fp_env.lo_traps.o || tmp_fp_env.lo_traps.un || tmp_fp_env.lo_traps.i) // MACH
        return (1);
    } else if (tmp_fp_env.em_traps.o || tmp_fp_env.em_traps.un || tmp_fp_env.em_traps.i) // MACH
        return (1);
    return (0);
}


INLINE EM_fp_reg_type
fp_reg_read(EM_fp_reg_type freg)
{
    EM_fp_reg_type tmp_freg;
    tmp_freg = freg;
 /* insert true register file exponent for double-extended (pseudo-)denormal */
    if ((tmp_freg.exponent == 0) && (tmp_freg.significand != U64_0))
        tmp_freg.exponent=0x0C001;
    return (tmp_freg);
}



// *******************************************************************
// fp_update_fpsr()
// *******************************************************************
INLINE void
fp_update_fpsr(
    EM_opcode_sf_type  sf,
    EM_tmp_fp_env_type tmp_fp_env )
{
    if (sf == sf_none) {
        return;
    }
    else if (sf == sfS0) {

/*******************************************************************
SF0
*******************************************************************/
       if(tmp_fp_env.simd == 1) {

/* SF0 simd fault: if either hi or low is set, set the s0 flag */
         if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) {
            SET_STATUS_FLAG(FPSR.sf0_flags_v);
         }
         if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) {
            SET_STATUS_FLAG(FPSR.sf0_flags_d);
         }
         if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) {
            SET_STATUS_FLAG(FPSR.sf0_flags_z);
         }

/* SF0 simd trap: if either hi or low is set, set the s0 flag 
if the flag is over or underflow, also set inexact  */
         if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) {
            SET_STATUS_FLAG(FPSR.sf0_flags_o);
         }
         if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH
            SET_STATUS_FLAG(FPSR.sf0_flags_u);
         }
         if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) {
            SET_STATUS_FLAG(FPSR.sf0_flags_i);
         }
      } /* end of simd */

      else { /* not simd */

/* SF0 non-simd fault: if tmp flag is set and s0 flag is not, set the flag */
         if (tmp_fp_env.flags.v) {
            SET_STATUS_FLAG(FPSR.sf0_flags_v);
         }
         if (tmp_fp_env.flags.d) {
// printf ("MACH DEBUG: setting the D flag in update_fpsr ()\n");
            SET_STATUS_FLAG(FPSR.sf0_flags_d);
         }
         if (tmp_fp_env.flags.z) {
            SET_STATUS_FLAG(FPSR.sf0_flags_z);
         }
   
/* SF0 non-simd trap: if tmp flag is set, set the flag.
if the flag is over or underflow, also check inexact  */
         if (tmp_fp_env.flags.o) {
            SET_STATUS_FLAG(FPSR.sf0_flags_o);
            if ( tmp_fp_env.flags.i) {
               SET_STATUS_FLAG(FPSR.sf0_flags_i);
            }
          }
          else if (tmp_fp_env.flags.un) { // MACH
             SET_STATUS_FLAG(FPSR.sf0_flags_u);
             if ( tmp_fp_env.flags.i )  {
                SET_STATUS_FLAG(FPSR.sf0_flags_i);
             }
          }
          else if (tmp_fp_env.flags.i) {
             SET_STATUS_FLAG(FPSR.sf0_flags_i);
          }
       } /* end of not simd */
    } /* end of SF0 */

/*******************************************************************
SF1
*******************************************************************/
    else if (sf == sfS1) {
        if(tmp_fp_env.simd == 1) {

/* SF1 simd fault: if either hi or low is set, set the s1 flag
*/
           if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) {
              SET_STATUS_FLAG(FPSR.sf1_flags_v);
           }
           if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) {
              SET_STATUS_FLAG(FPSR.sf1_flags_d);
           }
           if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) {
              SET_STATUS_FLAG(FPSR.sf1_flags_z);
           }

/* SF1 simd trap: if either hi or low is set and the s1 flag is not, set the s1 flag 
If the flag is over or underflow, also check inexact  */
           if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) {
              SET_STATUS_FLAG(FPSR.sf1_flags_o);
           }
           if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH
              SET_STATUS_FLAG(FPSR.sf1_flags_u);
           }
           if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) {
                SET_STATUS_FLAG(FPSR.sf1_flags_i);
            }
        } /* end of simd SF1 */

        else { /* not simd SF1 */

/* SF1 non-simd fault: if tmp flag is set and s1 flag is not, set the flag 
*/
           if (tmp_fp_env.flags.v ) {
              SET_STATUS_FLAG(FPSR.sf1_flags_v);
           }
           if (tmp_fp_env.flags.d ) {
              SET_STATUS_FLAG(FPSR.sf1_flags_d);
           }
           if (tmp_fp_env.flags.z ) {
              SET_STATUS_FLAG(FPSR.sf1_flags_z);
           }
    
/* SF1 non-simd traps: if tmp flag is set and s1 flag is not, set the flag.
if the flag is over or underflow, also check inexact  */
           if ( tmp_fp_env.flags.o ) {
              SET_STATUS_FLAG(FPSR.sf1_flags_o);
              if ( tmp_fp_env.flags.i ) {
                 SET_STATUS_FLAG(FPSR.sf1_flags_i);
              }
           }
           else if (tmp_fp_env.flags.un ) { // MACH
              SET_STATUS_FLAG(FPSR.sf1_flags_u);
              if ( tmp_fp_env.flags.i ) {
                 SET_STATUS_FLAG(FPSR.sf1_flags_i);
              }
           }
           else if (tmp_fp_env.flags.i ) {
              SET_STATUS_FLAG(FPSR.sf1_flags_i);
           }
        } /*end of not simd  SF1 */
      } /* end of SF1 */

/*******************************************************************
SF2
*******************************************************************/
      else if (sf == sfS2) {
         if(tmp_fp_env.simd == 1) {

/* SF2 simd fault: if either hi or low is set and the s2 flag is not, set the s2 flag
*/
            if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) {
               SET_STATUS_FLAG(FPSR.sf2_flags_v);
            }
            if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) {
               SET_STATUS_FLAG(FPSR.sf2_flags_d);
            }
            if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) {
               SET_STATUS_FLAG(FPSR.sf2_flags_z);
            }

/* SF2 simd trap: if either hi or low is set and the s2 flag is not, set the s2 flag 
If the flag is over or underflow, also check inexact  */
            if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) {
                SET_STATUS_FLAG(FPSR.sf2_flags_o);
            }
            if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH
               SET_STATUS_FLAG(FPSR.sf2_flags_u);
            }
            if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) {
                SET_STATUS_FLAG(FPSR.sf2_flags_i);
            }
         } /* end of simd SF2 */

         else { /* not simd SF2 */

/* SF2 non-simd fault: if tmp flag is set and s2 flag is not, set the flag 
*/
            if (tmp_fp_env.flags.v ) {
               SET_STATUS_FLAG(FPSR.sf2_flags_v);
            }
            if (tmp_fp_env.flags.d ) {
               SET_STATUS_FLAG(FPSR.sf2_flags_d);
            }
            if (tmp_fp_env.flags.z ) {
               SET_STATUS_FLAG(FPSR.sf2_flags_z);
            }

/* SF2 non-simd traps: if tmp flag is set and s2 flag is not, set the flag.
if the flag is over or underflow, also check inexact  */
            if ( tmp_fp_env.flags.o ) {
               SET_STATUS_FLAG(FPSR.sf2_flags_o);
               if ( tmp_fp_env.flags.i ) {
                  SET_STATUS_FLAG(FPSR.sf2_flags_i);
               }
            }
            else if (tmp_fp_env.flags.un ) { // MACH
               SET_STATUS_FLAG(FPSR.sf2_flags_u);
               if ( tmp_fp_env.flags.i ) {
                    SET_STATUS_FLAG(FPSR.sf2_flags_i);
               }
            }
            else if (tmp_fp_env.flags.i ) {
               SET_STATUS_FLAG(FPSR.sf2_flags_i);
            }
       } /* end of not simd SF2 */
    } /* end of SF2 */

/*******************************************************************
SF3
*******************************************************************/
    else if (sf == sfS3) {
       if(tmp_fp_env.simd == 1) {

/* SF3 simd fault: if either hi or low is set and the s3 flag is not, set the s3 flag
*/
          if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) {
             SET_STATUS_FLAG(FPSR.sf3_flags_v);
          }
          if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) {
             SET_STATUS_FLAG(FPSR.sf3_flags_d);
          }
          if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) {
             SET_STATUS_FLAG(FPSR.sf3_flags_z);
          }

/* SF3 simd trap: if either hi or low is set and the s3 flag is not, set the s3 flag 
If the flag is over or underflow, also check inexact  */
          if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) {
             SET_STATUS_FLAG(FPSR.sf3_flags_o);
          }
          if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH
             SET_STATUS_FLAG(FPSR.sf3_flags_u);
          }
          if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) {
             SET_STATUS_FLAG(FPSR.sf3_flags_i);
          }
       } /* end of simd SF3 */

       else { /* not simd SF3 */

/* SF3 non-simd fault: if tmp flag is set and s3 flag is not, set the flag 
 */
          if (tmp_fp_env.flags.v ) {
             SET_STATUS_FLAG(FPSR.sf3_flags_v);
          }
          if (tmp_fp_env.flags.d ) {
             SET_STATUS_FLAG(FPSR.sf3_flags_d);
          }
          if (tmp_fp_env.flags.z ) {
             SET_STATUS_FLAG(FPSR.sf3_flags_z);
          }
    
/* SF3 non-simd traps: if tmp flag is set and s3 flag is not, set the flag.
if the flag is over or underflow, also check inexact  */
          if ( tmp_fp_env.flags.o ) {
             SET_STATUS_FLAG(FPSR.sf3_flags_o);
             if ( tmp_fp_env.flags.i ) {
                SET_STATUS_FLAG(FPSR.sf3_flags_i);
             }
          }
          else if (tmp_fp_env.flags.un ) { // MACH
             SET_STATUS_FLAG(FPSR.sf3_flags_u);
             if ( tmp_fp_env.flags.i ) {
                SET_STATUS_FLAG(FPSR.sf3_flags_i);
             }
          }
          else if (tmp_fp_env.flags.i ) {
             SET_STATUS_FLAG(FPSR.sf3_flags_i);
          }
       } /* end of not simd SF3 */
    } /* end of SF3 */
} /* end of fp_update_fpsr */

INLINE void
fp_update_psr(EM_uint_t dest_freg)
{
EM_uint_t disabled_limit = 31;

    if ( (dest_freg >= 2) && (dest_freg <= disabled_limit) ){
        SET_STATUS_FLAG(PSR.mfl);
    }
    else if ( (dest_freg > disabled_limit) ) {
        SET_STATUS_FLAG(PSR.mfh);
    }
}


/* EM_int64_t, EM_uint64_t, EM_uint128_t and EM_uint256_t support routines */

/* 128-bit unsigned int support routines */

EM_boolean_t
fp82_fp_U128_eq(EM_uint128_t value1, EM_uint128_t value2)
{
    if ( (value1.hi == value2.hi)
      && (value1.lo == value2.lo) )
        return (1);
    else
        return (0);
}

static INLINE EM_boolean_t
fp_U128_ge(EM_uint128_t value1, EM_uint128_t value2)
{
    if (value1.hi >  value2.hi)
        return (1);
    else if ( (value1.hi == value2.hi)
           && (value1.lo >= value2.lo) )
        return (1);
    else
        return (0);
}

static INLINE EM_boolean_t
fp_U128_gt(EM_uint128_t value1, EM_uint128_t value2)
{
    if (value1.hi > value2.hi)
        return (1);
    else if ( (value1.hi == value2.hi)
           && (value1.lo >  value2.lo) )
        return (1);
    else
        return (0);
}

static INLINE EM_boolean_t
fp_U128_le(EM_uint128_t value1, EM_uint128_t value2)
{
    if (value1.hi <  value2.hi)
        return (1);
    else if ( (value1.hi == value2.hi)
           && (value1.lo <= value2.lo) )
        return (1);
    else
        return (0);
}

EM_boolean_t
fp82_fp_U128_lt(EM_uint128_t value1, EM_uint128_t value2)
{
    if (value1.hi < value2.hi)
        return (1);
    else if ( (value1.hi == value2.hi)
           && (value1.lo <  value2.lo) )
        return (1);
    else
        return (0);
}

EM_uint128_t
fp82_fp_U128_lsh(EM_uint128_t value, EM_uint_t count)
{
EM_uint128_t tmp;

    if (count == 0) {
        return(value);
    } else if (count >= 128) {
        return (U128_0);

    } else if (count >  64) {
        tmp.lo  = U64_0;
        tmp.hi = (value.lo<<(count-64));
        return (tmp);
    } else if (count == 64) {
        tmp.lo  = U64_0;
        tmp.hi = value.lo;
        return (tmp);
    } else if (count >  0) {
        tmp.lo = (value.lo<<count);
        tmp.hi = (value.hi<<count) | (value.lo>>(64-count)) ;
        return (tmp);
    }
   return(value); // MACH ADDED
}

EM_uint128_t
fp82_fp_U128_rsh(EM_uint128_t value, EM_uint_t count)
{
EM_uint128_t tmp;

    if (count == 0) {
        return (value);
    } else if (count >= 128) {
        return (U128_0);

    } else if (count > 64) {
        tmp.lo = (value.hi>>(count-64));
        tmp.hi  = U64_0;
        return (tmp);
    } else if (count == 64) {
        tmp.lo = value.hi;
        tmp.hi  = U64_0;
        return (tmp);
    } else if (count >  0) {
        tmp.lo = (value.lo>>count) | (value.hi<<(64-count));
        tmp.hi = (value.hi>>count);
        return (tmp);
    } 
    return(U128_0); // MACH ADDED
}

EM_uint128_t
fp82_fp_U64_x_U64_to_U128(EM_uint64_t value1, EM_uint64_t value2)
{
    EM_uint128_t tmp_res;
    EM_uint64_t r0, s0, t0;
    EM_uint64_t r1, s1, t1;

    s0 = (value1<<32)>>32;
    s1 = (value1>>32);

    t0 = (value2<<32)>>32;
    t1 = (value2>>32);

#ifdef HPC_BUGS
    s0 = ((EM_uint64_t)( ( ( ((EM_int64_t)s0) << 32 ) >> 32 ) ));
    s1 = ((EM_uint64_t)( ( ( ((EM_int64_t)s1) << 32 ) >> 32 ) ));
    t0 = ((EM_uint64_t)( ( ( ((EM_int64_t)t0) << 32 ) >> 32 ) ));
    t1 = ((EM_uint64_t)( ( ( ((EM_int64_t)t1) << 32 ) >> 32 ) ));
#endif

    tmp_res.lo = s0 * t0;

#ifdef HPC_BUGS
    if(s0 & U64_0x0000000080000000)
        tmp_res.lo += t0<<32;
    if(t0 & U64_0x0000000080000000)
        tmp_res.lo += s0<<32;
#endif


    r0 = s0 * t1;

#ifdef HPC_BUGS
    if(s0 & U64_0x0000000080000000)
        r0 += t1<<32;
    if(t1 & U64_0x0000000080000000)
        r0 += s0<<32;
#endif


    r1 = s1 * t0;

#ifdef HPC_BUGS
    if(s1 & U64_0x0000000080000000)
        r1 += t0<<32;
    if(t0 & U64_0x0000000080000000)
        r1 += s1<<32;
#endif


    tmp_res.hi = s1 * t1;

#ifdef HPC_BUGS
    if(s1 & U64_0x0000000080000000)
        tmp_res.hi += t1<<32;
    if(t1 & U64_0x0000000080000000)
        tmp_res.hi += s1<<32;
#endif


    if ( (tmp_res.lo + (r0<<32)) < tmp_res.lo)
        tmp_res.hi++;

    tmp_res.lo += (r0<<32);

    if ( (tmp_res.lo + (r1<<32)) < tmp_res.lo)
        tmp_res.hi++;

    tmp_res.lo += (r1<<32);
    tmp_res.hi += (r0>>32);
    tmp_res.hi += (r1>>32);

    return (tmp_res);
}

INLINE EM_uint128_t
fp_I64_x_I64_to_I128(EM_uint64_t value1, EM_uint64_t value2)
{
    EM_uint128_t tmp_res;
    EM_uint128_t scratch;

    tmp_res = fp_U64_x_U64_to_U128(value1, value2);

    if (value1 & U64_0x8000000000000000) {
        scratch = fp_U64_to_U128(value2);
        scratch = fp_U128_lsh(scratch,64);
        scratch = fp_U128_neg(scratch);
        tmp_res = fp_U128_add(scratch, tmp_res);
    } 

    if (value2 & U64_0x8000000000000000) {
        scratch = fp_U64_to_U128(value1);
        scratch = fp_U128_lsh(scratch,64);
        scratch = fp_U128_neg(scratch);
        tmp_res = fp_U128_add(scratch, tmp_res);
    } 

    return (tmp_res);
}

EM_uint128_t
fp82_fp_U128_inc(EM_uint128_t value)
{
    EM_uint128_t tmp;
            /* add one */
    tmp.lo = value.lo + 1;
    tmp.hi = value.hi + (tmp.lo < value.lo);

    return (tmp);
}

static INLINE EM_uint128_t
fp_U128_neg(EM_uint128_t value)
{
    EM_uint128_t tmp;

            /* complement */
    value.lo = ~value.lo;
    value.hi = ~value.hi;
            /* add one */
    tmp.lo = value.lo + 1;
    tmp.hi = value.hi + (tmp.lo < value.lo);
    return (tmp);
}

EM_uint128_t
fp82_fp_U128_add(EM_uint128_t value1,
                 EM_uint128_t value2)
{
    EM_uint128_t tmp;

        /* sum  */
    value2.lo = value1.lo + value2.lo;
    value2.hi = value1.hi + value2.hi;
        /* carry */
    tmp.lo = 0;
    tmp.hi = (value2.lo < value1.lo);

        /* carry propagate adder */
    tmp.lo =  value2.lo;
    tmp.hi += value2.hi;
    return (tmp);
}

EM_uint128_t
fp82_fp_U128_bor(EM_uint128_t value1, EM_uint128_t value2)
{
    EM_uint128_t tmp_res;
    tmp_res.lo = value1.lo | value2.lo;
    tmp_res.hi = value1.hi | value2.hi;
    return (tmp_res);
}

EM_uint128_t
fp82_fp_U128_band(EM_uint128_t value1, EM_uint128_t value2)
{
    EM_uint128_t tmp_res;
    tmp_res.lo = value1.lo & value2.lo;
    tmp_res.hi = value1.hi & value2.hi;
    return (tmp_res);
}

/* 256-bit unsigned int support routines */

EM_boolean_t
fp82_fp_U256_eq(EM_uint256_t value1, EM_uint256_t value2)
{
    if ( (value1.hh == value2.hh)
      && (value1.hl == value2.hl )
      && (value1.lh == value2.lh )
      && (value1.ll == value2.ll ) )
        return (1);
    else
        return (0);
}


EM_uint256_t
fp82_fp_U256_lsh(EM_uint256_t value, EM_uint_t count)
{
EM_uint256_t tmp;
    if (count == 0) {
        return (value);
    } else if (count >= 256) {
        return (U256_0);

    } else if (count >  192) {
        tmp.ll  = U64_0;
        tmp.lh  = U64_0;
        tmp.hl  = U64_0;
        tmp.hh = (value.ll<<(count-192));
        return (tmp);
    } else if (count == 192) {
        tmp.ll  = U64_0;
        tmp.lh  = U64_0;
        tmp.hl  = U64_0;
        tmp.hh = value.ll;
        return (tmp);
    } else if (count >  128) {
        tmp.ll  = U64_0;
        tmp.lh  = U64_0;
        tmp.hl = (value.ll<<(count-128));
        tmp.hh = (value.lh<<(count-128)) | (value.ll>>(192-count));
        return (tmp);
    } else if (count == 128) {
        tmp.ll  = U64_0;
        tmp.lh  = U64_0;
        tmp.hl = value.ll;
        tmp.hh = value.lh;
        return (tmp);
    } else if (count >  64) {
        tmp.ll  = U64_0;
        tmp.lh = (value.ll<<(count-64));
        tmp.hl = (value.lh<<(count-64)) | (value.ll>>(128-count)) ;
        tmp.hh = (value.hl<<(count-64)) | (value.lh>>(128-count)) ;
        return (tmp);
    } else if (count == 64) {
        tmp.ll = 0;
        tmp.lh = value.ll;
        tmp.hl = value.lh;
        tmp.hh = value.hl;
        return (tmp);
    } else if (count >  0) {
        tmp.ll = (value.ll<<count);
        tmp.lh = (value.lh<<count) | (value.ll>>(64-count)) ;
        tmp.hl = (value.hl<<count) | (value.lh>>(64-count)) ;
        tmp.hh = (value.hh<<(count)) | (value.hl>>(64-count)) ;
        return (tmp);
    } 
    return(U256_0); // MACH ADDED

}

EM_uint256_t
fp82_fp_U256_rsh(EM_uint256_t value, EM_uint_t count)
{
EM_uint256_t tmp;
    if (count == 0) {
        return (value);
    } else if (count >= 256) {
        return (U256_0);

    } else if (count >  192) {
        tmp.ll = (value.hh>>(count-192));
        tmp.lh  = U64_0;
        tmp.hl  = U64_0;
        tmp.hh  = U64_0;
        return (tmp);
    } else if (count == 192) {
        tmp.ll = value.hh;
        tmp.lh  = U64_0;
        tmp.hl  = U64_0;
        tmp.hh  = U64_0;
        return (tmp);
    } else if (count >  128) {
        tmp.ll = (value.hl>>(count-128)) | (value.hh<<(192-count));
        tmp.lh = (value.hh>>(count-128));
        tmp.hl  = U64_0;
        tmp.hh  = U64_0;
        return (tmp);
    } else if (count == 128) {
        tmp.ll = value.hl;
        tmp.lh = value.hh;
        tmp.hl  = U64_0;
        tmp.hh  = U64_0;
        return (tmp);
    } else if (count >  64) {
        tmp.ll = (value.lh>>(count-64)) | (value.hl<<(128-count));
        tmp.lh = (value.hl>>(count-64)) | (value.hh<<(128-count));
        tmp.hl = (value.hh>>(count-64));
        tmp.hh  = U64_0;
        return (tmp);
    } else if (count == 64) {
        tmp.ll = value.lh;
        tmp.lh = value.hl;
        tmp.hl = value.hh;
        tmp.hh  = U64_0;
        return (tmp);
    } else if (count >  0) {
        tmp.ll = (value.ll>>count) | (value.lh<<(64-count));
        tmp.lh = (value.lh>>count) | (value.hl<<(64-count));
        tmp.hl = (value.hl>>count) | (value.hh<<(64-count));
        tmp.hh = (value.hh>>count);
        return (tmp);
    } 
    return(U256_0); // MACH ADDED

}

EM_uint256_t
fp82_fp_U256_inc(EM_uint256_t value)
{
    EM_uint256_t tmp;

            /* add one */
    tmp.ll = value.ll + 1;
    tmp.lh = value.lh + (tmp.ll < value.ll);
    tmp.hl = value.hl + (tmp.lh < value.lh);
    tmp.hh = value.hh + (tmp.hl < value.hl);
    return (tmp);
}

static INLINE EM_uint256_t
fp_U256_neg(EM_uint256_t value)
{
    EM_uint256_t tmp;

            /* complement */
    value.ll = ~value.ll;
    value.lh = ~value.lh;
    value.hl = ~value.hl;
    value.hh = ~value.hh;
            /* add one */
    tmp.ll = value.ll + 1;
    tmp.lh = value.lh + (tmp.ll < value.ll);
    tmp.hl = value.hl + (tmp.lh < value.lh);
    tmp.hh = value.hh + (tmp.hl < value.hl);
    return (tmp);
}

static INLINE EM_uint256_t
fp_U256_add(EM_uint256_t value1, EM_uint256_t value2)
{
    EM_uint256_t tmp;

        /* sum  */
    value2.ll = value1.ll + value2.ll;
    value2.lh = value1.lh + value2.lh;
    value2.hl = value1.hl + value2.hl;
    value2.hh = value1.hh + value2.hh;
        /* carry */
    tmp.ll = 0;
    tmp.lh = (value2.ll < value1.ll);
    tmp.hl = (value2.lh < value1.lh);
    tmp.hh = (value2.hl < value1.hl);
/*  c_out  = (value2.hh < value1.hh); */
        /* carry propagate adder */
    tmp.ll =  value2.ll;
    tmp.lh += value2.lh;
    tmp.hl += value2.hl + (tmp.lh < value2.lh);
    tmp.hh += value2.hh + (tmp.hl < value2.hl);
/*  c_out  +=             (tmp.hh < value2.hh); */
    return (tmp);
}

/* Basic Conversion Routines */

INLINE EM_uint128_t
fp_U64_to_U128(EM_uint64_t value)
{
    EM_uint128_t tmp;
    tmp.lo = value;
    tmp.hi = U64_0;
    return (tmp);
}

INLINE EM_uint64_t
fp_U128_to_U64(EM_uint128_t value)
{
    EM_uint64_t tmp;
    tmp = value.lo;
    return (tmp);
}

static INLINE EM_uint256_t
fp_U64_to_U256(EM_uint64_t value)
{
    EM_uint256_t tmp;
    tmp.ll = value;
    tmp.lh = U64_0;
    tmp.hl = U64_0;
    tmp.hh = U64_0;
    return (tmp);
}

static INLINE EM_uint64_t
fp_U256_to_U64(EM_uint256_t value)
{
    EM_uint64_t tmp;
    tmp = value.ll;
    return (tmp);
}

EM_uint256_t
fp82_fp_U128_to_U256(EM_uint128_t value)
{
    EM_uint256_t tmp;
    tmp.ll = value.lo;
    tmp.lh = value.hi;
    tmp.hl  = U64_0;
    tmp.hh  = U64_0;
    return (tmp);
}

static INLINE EM_uint128_t
fp_U256_to_U128(EM_uint256_t value)
{
    EM_uint128_t tmp;
    tmp.lo = value.ll;
    tmp.hi = value.lh;
    return (tmp);
}