mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-17 01:15:26 +02:00
6142 lines
197 KiB
C
6142 lines
197 KiB
C
/* FLOAT.C (c) Copyright Peter Kuschnerus, 2000-2003 */
|
|
/* ESA/390 Hex Floatingpoint Instructions */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* This module implements the ESA/390 Hex Floatingpoint Instructions */
|
|
/* described in the manual ESA/390 Principles of Operation. */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Incorporated all floating point instructions from cpu.c in order */
|
|
/* to implement revised instruction decoding. */
|
|
/* Jan Jaeger 01/07/00 */
|
|
/* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2003 */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Added the square-root-facility (instructions SQDR, SQER). */
|
|
/* Peter Kuschnerus 01/09/00 */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Added the HFP-extension-facility (26 additional instructions). */
|
|
/* Added the AFP-Registers-facility (additional float registers). */
|
|
/* Peter Kuschnerus 13/12/00 */
|
|
/* Long Displacement Facility: LDY,LEY,STDY,STEY R.Bowler 29/06/03 */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
|
|
#include "hercules.h"
|
|
#include "opcode.h"
|
|
#include "inline.h"
|
|
|
|
|
|
#if defined(FEATURE_HEXADECIMAL_FLOATING_POINT)
|
|
|
|
/* Rename all inline functions for multi architectural support *JJ */
|
|
#undef get_sf
|
|
#undef store_sf
|
|
#undef get_lf
|
|
#undef store_lf
|
|
#undef get_ef
|
|
#undef store_ef
|
|
#undef vfetch_sf
|
|
#undef vfetch_lf
|
|
#undef normal_sf
|
|
#undef normal_lf
|
|
#undef normal_ef
|
|
#undef overflow_sf
|
|
#undef overflow_lf
|
|
#undef overflow_ef
|
|
#undef underflow_sf
|
|
#undef underflow_lf
|
|
#undef underflow_ef
|
|
#undef over_under_flow_sf
|
|
#undef over_under_flow_lf
|
|
#undef over_under_flow_ef
|
|
#undef significance_sf
|
|
#undef significance_lf
|
|
#undef significance_ef
|
|
#undef add_ef
|
|
#undef add_lf
|
|
#undef add_sf
|
|
#undef cmp_lf
|
|
#undef cmp_sf
|
|
#undef div_U128
|
|
#undef div_U256
|
|
#undef div_ef
|
|
#undef div_lf
|
|
#undef div_sf
|
|
#undef mul_ef
|
|
#undef mul_sf
|
|
#undef mul_lf
|
|
#undef mul_lf_to_ef
|
|
#undef mul_sf_to_lf
|
|
#undef square_root_fraction
|
|
#undef sq_sf
|
|
#undef sq_lf
|
|
#if __GEN_ARCH == 370
|
|
#define get_ef s370_get_ef
|
|
#define get_lf s370_get_lf
|
|
#define get_sf s370_get_sf
|
|
#define normal_ef s370_normal_ef
|
|
#define normal_lf s370_normal_lf
|
|
#define normal_sf s370_normal_sf
|
|
#define over_under_flow_ef s370_over_under_flow_ef
|
|
#define over_under_flow_lf s370_over_under_flow_lf
|
|
#define over_under_flow_sf s370_over_under_flow_sf
|
|
#define overflow_ef s370_overflow_ef
|
|
#define overflow_lf s370_overflow_lf
|
|
#define overflow_sf s370_overflow_sf
|
|
#define significance_ef s370_significance_ef
|
|
#define significance_lf s370_significance_lf
|
|
#define significance_sf s370_significance_sf
|
|
#define store_ef s370_store_ef
|
|
#define store_lf s370_store_lf
|
|
#define store_sf s370_store_sf
|
|
#define underflow_ef s370_underflow_ef
|
|
#define underflow_lf s370_underflow_lf
|
|
#define underflow_sf s370_underflow_sf
|
|
#define vfetch_lf s370_vfetch_lf
|
|
#define vfetch_sf s370_vfetch_sf
|
|
#define add_ef s370_add_ef
|
|
#define add_lf s370_add_lf
|
|
#define add_sf s370_add_sf
|
|
#define cmp_lf s370_cmp_lf
|
|
#define cmp_sf s370_cmp_sf
|
|
#define div_U128 s370_div_U128
|
|
#define div_U256 s370_div_U256
|
|
#define div_ef s370_div_ef
|
|
#define div_lf s370_div_lf
|
|
#define div_sf s370_div_sf
|
|
#define mul_ef s370_mul_ef
|
|
#define mul_sf s370_mul_sf
|
|
#define mul_lf s370_mul_lf
|
|
#define mul_lf_to_ef s370_mul_lf_to_ef
|
|
#define mul_sf_to_lf s370_mul_sf_to_lf
|
|
#define square_root_fraction s370_square_root_fraction
|
|
#define sq_sf s370_sq_sf
|
|
#define sq_lf s370_sq_lf
|
|
#elif __GEN_ARCH == 390
|
|
#define get_ef s390_get_ef
|
|
#define get_lf s390_get_lf
|
|
#define get_sf s390_get_sf
|
|
#define normal_ef s390_normal_ef
|
|
#define normal_lf s390_normal_lf
|
|
#define normal_sf s390_normal_sf
|
|
#define over_under_flow_ef s390_over_under_flow_ef
|
|
#define over_under_flow_lf s390_over_under_flow_lf
|
|
#define over_under_flow_sf s390_over_under_flow_sf
|
|
#define overflow_ef s390_overflow_ef
|
|
#define overflow_lf s390_overflow_lf
|
|
#define overflow_sf s390_overflow_sf
|
|
#define significance_ef s390_significance_ef
|
|
#define significance_lf s390_significance_lf
|
|
#define significance_sf s390_significance_sf
|
|
#define store_ef s390_store_ef
|
|
#define store_lf s390_store_lf
|
|
#define store_sf s390_store_sf
|
|
#define underflow_ef s390_underflow_ef
|
|
#define underflow_lf s390_underflow_lf
|
|
#define underflow_sf s390_underflow_sf
|
|
#define vfetch_lf s390_vfetch_lf
|
|
#define vfetch_sf s390_vfetch_sf
|
|
#define add_ef s390_add_ef
|
|
#define add_lf s390_add_lf
|
|
#define add_sf s390_add_sf
|
|
#define cmp_lf s390_cmp_lf
|
|
#define cmp_sf s390_cmp_sf
|
|
#define div_U128 s390_div_U128
|
|
#define div_U256 s390_div_U256
|
|
#define div_ef s390_div_ef
|
|
#define div_lf s390_div_lf
|
|
#define div_sf s390_div_sf
|
|
#define mul_ef s390_mul_ef
|
|
#define mul_sf s390_mul_sf
|
|
#define mul_lf s390_mul_lf
|
|
#define mul_lf_to_ef s390_mul_lf_to_ef
|
|
#define mul_sf_to_lf s390_mul_sf_to_lf
|
|
#define square_root_fraction s390_square_root_fraction
|
|
#define sq_sf s390_sq_sf
|
|
#define sq_lf s390_sq_lf
|
|
#elif __GEN_ARCH == 900
|
|
#define get_ef z900_get_ef
|
|
#define get_lf z900_get_lf
|
|
#define get_sf z900_get_sf
|
|
#define normal_ef z900_normal_ef
|
|
#define normal_lf z900_normal_lf
|
|
#define normal_sf z900_normal_sf
|
|
#define over_under_flow_ef z900_over_under_flow_ef
|
|
#define over_under_flow_lf z900_over_under_flow_lf
|
|
#define over_under_flow_sf z900_over_under_flow_sf
|
|
#define overflow_ef z900_overflow_ef
|
|
#define overflow_lf z900_overflow_lf
|
|
#define overflow_sf z900_overflow_sf
|
|
#define significance_ef z900_significance_ef
|
|
#define significance_lf z900_significance_lf
|
|
#define significance_sf z900_significance_sf
|
|
#define store_ef z900_store_ef
|
|
#define store_lf z900_store_lf
|
|
#define store_sf z900_store_sf
|
|
#define underflow_ef z900_underflow_ef
|
|
#define underflow_lf z900_underflow_lf
|
|
#define underflow_sf z900_underflow_sf
|
|
#define vfetch_lf z900_vfetch_lf
|
|
#define vfetch_sf z900_vfetch_sf
|
|
#define add_ef z900_add_ef
|
|
#define add_lf z900_add_lf
|
|
#define add_sf z900_add_sf
|
|
#define cmp_lf z900_cmp_lf
|
|
#define cmp_sf z900_cmp_sf
|
|
#define div_U128 z900_div_U128
|
|
#define div_U256 z900_div_U256
|
|
#define div_ef z900_div_ef
|
|
#define div_lf z900_div_lf
|
|
#define div_sf z900_div_sf
|
|
#define mul_ef z900_mul_ef
|
|
#define mul_sf z900_mul_sf
|
|
#define mul_lf z900_mul_lf
|
|
#define mul_lf_to_ef z900_mul_lf_to_ef
|
|
#define mul_sf_to_lf z900_mul_sf_to_lf
|
|
#define square_root_fraction z900_square_root_fraction
|
|
#define sq_sf z900_sq_sf
|
|
#define sq_lf z900_sq_lf
|
|
#else
|
|
#error Unable to determine GEN_ARCH
|
|
#endif
|
|
|
|
#if !defined(_FLOAT_C)
|
|
|
|
#define _FLOAT_C
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Definitions */
|
|
/*-------------------------------------------------------------------*/
|
|
#define POS 0 /* Positive value of sign */
|
|
#define NEG 1 /* Negative value of sign */
|
|
#define UNNORMAL 0 /* Without normalisation */
|
|
#define NORMAL 1 /* With normalisation */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Add 128 bit unsigned integer */
|
|
/* The result is placed in operand a */
|
|
/* */
|
|
/* msa most significant 64 bit of operand a */
|
|
/* lsa least significant 64 bit of operand a */
|
|
/* msb most significant 64 bit of operand b */
|
|
/* lsb least significant 64 bit of operand b */
|
|
/* */
|
|
/* all operands are expected to be defined as U64 */
|
|
/*-------------------------------------------------------------------*/
|
|
#define add_U128(msa, lsa, msb, lsb) \
|
|
(lsa) += (lsb); \
|
|
(msa) += (msb); \
|
|
if ((lsa) < (lsb)) \
|
|
(msa)++
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Subtract 128 bit unsigned integer */
|
|
/* The operand b is subtracted from operand a */
|
|
/* The result is placed in operand a */
|
|
/* */
|
|
/* msa most significant 64 bit of operand a */
|
|
/* lsa least significant 64 bit of operand a */
|
|
/* msb most significant 64 bit of operand b */
|
|
/* lsb least significant 64 bit of operand b */
|
|
/* */
|
|
/* all operands are expected to be defined as U64 */
|
|
/*-------------------------------------------------------------------*/
|
|
#define sub_U128(msa, lsa, msb, lsb) \
|
|
(msa) -= (msb); \
|
|
if ((lsa) < (lsb)) \
|
|
(msa)--; \
|
|
(lsa) -= (lsb)
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Subtract 128 bit unsigned integer reverse */
|
|
/* The operand a is subtracted from operand b */
|
|
/* The result is placed in operand a */
|
|
/* */
|
|
/* msa most significant 64 bit of operand a */
|
|
/* lsa least significant 64 bit of operand a */
|
|
/* msb most significant 64 bit of operand b */
|
|
/* lsb least significant 64 bit of operand b */
|
|
/* */
|
|
/* all operands are expected to be defined as U64 */
|
|
/*-------------------------------------------------------------------*/
|
|
#define sub_reverse_U128(msa, lsa, msb, lsb) \
|
|
(msa) = (msb) - (msa); \
|
|
if ((lsb) < (lsa)) \
|
|
(msa)--; \
|
|
(lsa) = (lsb) - (lsa)
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Shift 128 bit one bit right */
|
|
/* */
|
|
/* ms most significant 64 bit of operand */
|
|
/* ls least significant 64 bit of operand */
|
|
/* */
|
|
/* all operands are expected to be defined as U64 */
|
|
/*-------------------------------------------------------------------*/
|
|
#define shift_right_U128(ms, ls) \
|
|
(ls) = ((ls) >> 1) | ((ms) << 63); \
|
|
(ms) >>= 1
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Shift 128 bit one bit left */
|
|
/* */
|
|
/* ms most significant 64 bit of operand */
|
|
/* ls least significant 64 bit of operand */
|
|
/* */
|
|
/* all operands are expected to be defined as U64 */
|
|
/*-------------------------------------------------------------------*/
|
|
#define shift_left_U128(ms, ls) \
|
|
(ms) = ((ms) << 1) | ((ls) >> 63); \
|
|
(ls) <<= 1
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Shift 256 bit one bit left */
|
|
/* */
|
|
/* mms most significant 64 bit of operand */
|
|
/* ms more significant 64 bit of operand */
|
|
/* ls less significant 64 bit of operand */
|
|
/* lls least significant 64 bit of operand */
|
|
/* */
|
|
/* all operands are expected to be defined as U64 */
|
|
/*-------------------------------------------------------------------*/
|
|
#define shift_left_U256(mms, ms, ls, lls) \
|
|
(mms) = ((mms) << 1) | ((ms) >> 63); \
|
|
(ms) = ((ms) << 1) | ((ls) >> 63); \
|
|
(ls) = ((ls) << 1) | ((lls) >> 63); \
|
|
(lls) <<= 1
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Structure definition for internal short floatingpoint format */
|
|
/*-------------------------------------------------------------------*/
|
|
typedef struct _SHORT_FLOAT {
|
|
U32 short_fract; /* Fraction */
|
|
short expo; /* Exponent + 64 */
|
|
BYTE sign; /* Sign */
|
|
} SHORT_FLOAT;
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Structure definition for internal long floatingpoint format */
|
|
/*-------------------------------------------------------------------*/
|
|
typedef struct _LONG_FLOAT {
|
|
U64 long_fract; /* Fraction */
|
|
short expo; /* Exponent + 64 */
|
|
BYTE sign; /* Sign */
|
|
} LONG_FLOAT;
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Structure definition for internal extended floatingpoint format */
|
|
/*-------------------------------------------------------------------*/
|
|
typedef struct _EXTENDED_FLOAT {
|
|
U64 ms_fract, ls_fract; /* Fraction */
|
|
short expo; /* Exponent + 64 */
|
|
BYTE sign; /* Sign */
|
|
} EXTENDED_FLOAT;
|
|
|
|
|
|
#endif /*!defined(_FLOAT_C)*/
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Static inline functions */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Get short float from register */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted to */
|
|
/* fpr Pointer to register to be converted from */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void get_sf( SHORT_FLOAT *fl, U32 *fpr )
|
|
{
|
|
fl->sign = *fpr >> 31;
|
|
fl->expo = (*fpr >> 24) & 0x007F;
|
|
fl->short_fract = *fpr & 0x00FFFFFF;
|
|
|
|
} /* end function get_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Store short float to register */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted from */
|
|
/* fpr Pointer to register to be converted to */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void store_sf( SHORT_FLOAT *fl, U32 *fpr )
|
|
{
|
|
*fpr = ((U32)fl->sign << 31)
|
|
| ((U32)fl->expo << 24)
|
|
| (fl->short_fract);
|
|
|
|
} /* end function store_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Get long float from register */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted to */
|
|
/* fpr Pointer to register to be converted from */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void get_lf( LONG_FLOAT *fl, U32 *fpr )
|
|
{
|
|
fl->sign = *fpr >> 31;
|
|
fl->expo = (*fpr >> 24) & 0x007F;
|
|
fl->long_fract = ((U64)(fpr[0] & 0x00FFFFFF) << 32)
|
|
| fpr[1];
|
|
|
|
} /* end function get_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Store long float to register */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted from */
|
|
/* fpr Pointer to register to be converted to */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void store_lf( LONG_FLOAT *fl, U32 *fpr )
|
|
{
|
|
fpr[0] = ((U32)fl->sign << 31)
|
|
| ((U32)fl->expo << 24)
|
|
| (fl->long_fract >> 32);
|
|
fpr[1] = fl->long_fract;
|
|
|
|
} /* end function store_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Get extended float from register */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted to */
|
|
/* fpr Pointer to register to be converted from */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void get_ef( EXTENDED_FLOAT *fl, U32 *fpr )
|
|
{
|
|
fl->sign = *fpr >> 31;
|
|
fl->expo = (*fpr >> 24) & 0x007F;
|
|
fl->ms_fract = ((U64)(fpr[0] & 0x00FFFFFF) << 24)
|
|
| (fpr[1] >> 8);
|
|
fl->ls_fract = (((U64)fpr[1]) << 56)
|
|
| (((U64)(fpr[FPREX] & 0x00FFFFFF)) << 32)
|
|
| fpr[FPREX+1];
|
|
|
|
} /* end function get_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Store extended float to register */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted from */
|
|
/* fpr Pointer to register to be converted from */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void store_ef( EXTENDED_FLOAT *fl, U32 *fpr )
|
|
{
|
|
fpr[0] = ((U32)fl->sign << 31)
|
|
| ((U32)fl->expo << 24)
|
|
| (fl->ms_fract >> 24);
|
|
fpr[1] = (fl->ms_fract << 8)
|
|
| (fl->ls_fract >> 56);
|
|
fpr[FPREX] = ((U32)fl->sign << 31)
|
|
| ((fl->ls_fract >> 32) & 0x00FFFFFF);
|
|
fpr[FPREX+1] = fl->ls_fract;
|
|
|
|
if ( fpr[0]
|
|
|| fpr[1]
|
|
|| fpr[FPREX]
|
|
|| fpr[FPREX+1] ) {
|
|
fpr[FPREX] |= ((((U32)fl->expo - 14) << 24) & 0x7f000000);
|
|
}
|
|
|
|
} /* end function store_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Fetch a short floatingpoint operand from virtual storage */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format */
|
|
/* addr Logical address of leftmost byte of operand */
|
|
/* arn Access register number */
|
|
/* regs CPU register context */
|
|
/* */
|
|
/* A program check may be generated if the logical address */
|
|
/* causes an addressing, translation, or fetch protection */
|
|
/* exception, and in this case the function does not return. */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void vfetch_sf( SHORT_FLOAT *fl, VADR addr, int arn,
|
|
REGS *regs )
|
|
{
|
|
U32 value; /* Operand value */
|
|
|
|
/* Fetch 4 bytes from operand address */
|
|
value = ARCH_DEP(vfetch4) (addr, arn, regs);
|
|
|
|
/* Extract sign and exponent from high-order byte */
|
|
fl->sign = value >> 31;
|
|
fl->expo = (value >> 24) & 0x007F;
|
|
|
|
/* Extract fraction from low-order 3 bytes */
|
|
fl->short_fract = value & 0x00FFFFFF;
|
|
|
|
} /* end function vfetch_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Fetch a long floatingpoint operand from virtual storage */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format */
|
|
/* addr Logical address of leftmost byte of operand */
|
|
/* arn Access register number */
|
|
/* regs CPU register context */
|
|
/* */
|
|
/* A program check may be generated if the logical address */
|
|
/* causes an addressing, translation, or fetch protection */
|
|
/* exception, and in this case the function does not return. */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void vfetch_lf( LONG_FLOAT *fl, VADR addr, int arn,
|
|
REGS *regs )
|
|
{
|
|
U64 value; /* Operand value */
|
|
|
|
/* Fetch 8 bytes from operand address */
|
|
value = ARCH_DEP(vfetch8) (addr, arn, regs);
|
|
|
|
/* Extract sign and exponent from high-order byte */
|
|
fl->sign = value >> 63;
|
|
fl->expo = (value >> 56) & 0x007F;
|
|
|
|
/* Extract fraction from low-order 7 bytes */
|
|
fl->long_fract = value & 0x00FFFFFFFFFFFFFFULL;
|
|
|
|
} /* end function vfetch_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Normalize short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void normal_sf( SHORT_FLOAT *fl )
|
|
{
|
|
if (fl->short_fract) {
|
|
if ((fl->short_fract & 0x00FFFF00) == 0) {
|
|
fl->short_fract <<= 16;
|
|
fl->expo -= 4;
|
|
}
|
|
if ((fl->short_fract & 0x00FF0000) == 0) {
|
|
fl->short_fract <<= 8;
|
|
fl->expo -= 2;
|
|
}
|
|
if ((fl->short_fract & 0x00F00000) == 0) {
|
|
fl->short_fract <<= 4;
|
|
(fl->expo)--;
|
|
}
|
|
} else {
|
|
fl->sign = POS;
|
|
fl->expo = 0;
|
|
}
|
|
|
|
} /* end function normal_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Normalize long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void normal_lf( LONG_FLOAT *fl )
|
|
{
|
|
if (fl->long_fract) {
|
|
if ((fl->long_fract & 0x00FFFFFFFF000000ULL) == 0) {
|
|
fl->long_fract <<= 32;
|
|
fl->expo -= 8;
|
|
}
|
|
if ((fl->long_fract & 0x00FFFF0000000000ULL) == 0) {
|
|
fl->long_fract <<= 16;
|
|
fl->expo -= 4;
|
|
}
|
|
if ((fl->long_fract & 0x00FF000000000000ULL) == 0) {
|
|
fl->long_fract <<= 8;
|
|
fl->expo -= 2;
|
|
}
|
|
if ((fl->long_fract & 0x00F0000000000000ULL) == 0) {
|
|
fl->long_fract <<= 4;
|
|
(fl->expo)--;
|
|
}
|
|
} else {
|
|
fl->sign = POS;
|
|
fl->expo = 0;
|
|
}
|
|
|
|
} /* end function normal_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Normalize extended float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void normal_ef( EXTENDED_FLOAT *fl )
|
|
{
|
|
if (fl->ms_fract
|
|
|| fl->ls_fract) {
|
|
if (fl->ms_fract == 0) {
|
|
fl->ms_fract = fl->ls_fract >> 16;
|
|
fl->ls_fract <<= 48;
|
|
fl->expo -= 12;
|
|
}
|
|
if ((fl->ms_fract & 0x0000FFFFFFFF0000ULL) == 0) {
|
|
if (fl->ls_fract) {
|
|
fl->ms_fract = (fl->ms_fract << 32)
|
|
| (fl->ls_fract >> 32);
|
|
fl->ls_fract <<= 32;
|
|
} else {
|
|
fl->ms_fract <<= 32;
|
|
}
|
|
fl->expo -= 8;
|
|
}
|
|
if ((fl->ms_fract & 0x0000FFFF00000000ULL) == 0) {
|
|
if (fl->ls_fract) {
|
|
fl->ms_fract = (fl->ms_fract << 16)
|
|
| (fl->ls_fract >> 48);
|
|
fl->ls_fract <<= 16;
|
|
} else {
|
|
fl->ms_fract <<= 16;
|
|
}
|
|
fl->expo -= 4;
|
|
}
|
|
if ((fl->ms_fract & 0x0000FF0000000000ULL) == 0) {
|
|
if (fl->ls_fract) {
|
|
fl->ms_fract = (fl->ms_fract << 8)
|
|
| (fl->ls_fract >> 56);
|
|
fl->ls_fract <<= 8;
|
|
} else {
|
|
fl->ms_fract <<= 8;
|
|
}
|
|
fl->expo -= 2;
|
|
}
|
|
if ((fl->ms_fract & 0x0000F00000000000ULL) == 0) {
|
|
if (fl->ls_fract) {
|
|
fl->ms_fract = (fl->ms_fract << 4)
|
|
| (fl->ls_fract >> 60);
|
|
fl->ls_fract <<= 4;
|
|
} else {
|
|
fl->ms_fract <<= 4;
|
|
}
|
|
(fl->expo)--;
|
|
}
|
|
} else {
|
|
fl->sign = POS;
|
|
fl->expo = 0;
|
|
}
|
|
|
|
} /* end function normal_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Overflow of short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int overflow_sf( SHORT_FLOAT *fl, REGS *regs )
|
|
{
|
|
UNREFERENCED(regs);
|
|
|
|
if (fl->expo > 127) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_OVERFLOW_EXCEPTION);
|
|
}
|
|
return(0);
|
|
|
|
} /* end function overflow_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Overflow of long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int overflow_lf( LONG_FLOAT *fl, REGS *regs )
|
|
{
|
|
UNREFERENCED(regs);
|
|
|
|
if (fl->expo > 127) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_OVERFLOW_EXCEPTION);
|
|
}
|
|
return(0);
|
|
|
|
} /* end function overflow_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Overflow of extended float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int overflow_ef( EXTENDED_FLOAT *fl, REGS *regs )
|
|
{
|
|
UNREFERENCED(regs);
|
|
|
|
if (fl->expo > 127) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_OVERFLOW_EXCEPTION);
|
|
}
|
|
return(0);
|
|
|
|
} /* end function overflow_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Underflow of short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int underflow_sf( SHORT_FLOAT *fl, REGS *regs )
|
|
{
|
|
if (fl->expo < 0) {
|
|
if (regs->psw.eumask) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_UNDERFLOW_EXCEPTION);
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->short_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
}
|
|
return(0);
|
|
|
|
} /* end function underflow_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Underflow of long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int underflow_lf( LONG_FLOAT *fl, REGS *regs )
|
|
{
|
|
if (fl->expo < 0) {
|
|
if (regs->psw.eumask) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_UNDERFLOW_EXCEPTION);
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->long_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
}
|
|
return(0);
|
|
|
|
} /* end function underflow_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Underflow of extended float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* fpr Pointer to register to be stored to */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int underflow_ef( EXTENDED_FLOAT *fl, U32 *fpr,
|
|
REGS *regs )
|
|
{
|
|
if (fl->expo < 0) {
|
|
if (regs->psw.eumask) {
|
|
fl->expo &= 0x007F;
|
|
store_ef( fl, fpr );
|
|
return(PGM_EXPONENT_UNDERFLOW_EXCEPTION);
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fpr[0] = 0;
|
|
fpr[1] = 0;
|
|
fpr[FPREX] = 0;
|
|
fpr[FPREX+1] = 0;
|
|
fl->ms_fract = 0;
|
|
fl->ls_fract = 0;
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
store_ef( fl, fpr );
|
|
return(0);
|
|
|
|
} /* end function underflow_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Overflow and underflow of short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int over_under_flow_sf( SHORT_FLOAT *fl, REGS *regs )
|
|
{
|
|
if (fl->expo > 127) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_OVERFLOW_EXCEPTION);
|
|
} else {
|
|
if (fl->expo < 0) {
|
|
if (regs->psw.eumask) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_UNDERFLOW_EXCEPTION);
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->short_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
|
|
} /* end function over_under_flow_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Overflow and underflow of long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int over_under_flow_lf( LONG_FLOAT *fl, REGS *regs )
|
|
{
|
|
if (fl->expo > 127) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_OVERFLOW_EXCEPTION);
|
|
} else {
|
|
if (fl->expo < 0) {
|
|
if (regs->psw.eumask) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_UNDERFLOW_EXCEPTION);
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->long_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
|
|
} /* end function over_under_flow_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Overflow and underflow of extended float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int over_under_flow_ef( EXTENDED_FLOAT *fl, REGS *regs )
|
|
{
|
|
if (fl->expo > 127) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_OVERFLOW_EXCEPTION);
|
|
} else {
|
|
if (fl->expo < 0) {
|
|
if (regs->psw.eumask) {
|
|
fl->expo &= 0x007F;
|
|
return(PGM_EXPONENT_UNDERFLOW_EXCEPTION);
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->ms_fract = 0;
|
|
fl->ls_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
|
|
} /* end function over_under_flow_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Significance of short float */
|
|
/* The fraction is expected to be zero */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int significance_sf( SHORT_FLOAT *fl, REGS *regs )
|
|
{
|
|
fl->sign = POS;
|
|
if (regs->psw.sgmask) {
|
|
return(PGM_SIGNIFICANCE_EXCEPTION);
|
|
}
|
|
/* set true 0 */
|
|
|
|
fl->expo = 0;
|
|
return(0);
|
|
|
|
} /* end function significance_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Significance of long float */
|
|
/* The fraction is expected to be zero */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int significance_lf( LONG_FLOAT *fl, REGS *regs )
|
|
{
|
|
fl->sign = POS;
|
|
if (regs->psw.sgmask) {
|
|
return(PGM_SIGNIFICANCE_EXCEPTION);
|
|
}
|
|
/* set true 0 */
|
|
|
|
fl->expo = 0;
|
|
return(0);
|
|
|
|
} /* end function significance_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Significance of extended float */
|
|
/* The fraction is expected to be zero */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float */
|
|
/* fpr Pointer to register to be stored to */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int significance_ef( EXTENDED_FLOAT *fl, U32 *fpr,
|
|
REGS *regs )
|
|
{
|
|
fpr[1] = 0;
|
|
fpr[FPREX+1] = 0;
|
|
|
|
if (regs->psw.sgmask) {
|
|
fpr[0] = (U32)fl->expo << 24;
|
|
fpr[FPREX] = (((U32)fl->expo - 14) << 24) & 0x7f000000;
|
|
return(PGM_SIGNIFICANCE_EXCEPTION);
|
|
}
|
|
/* set true 0 */
|
|
|
|
fpr[0] = 0;
|
|
fpr[FPREX] = 0;
|
|
return(0);
|
|
|
|
} /* end function significance_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Static functions */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Add short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Float */
|
|
/* add_fl Float to be added */
|
|
/* normal Normalize if true */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int add_sf( SHORT_FLOAT *fl, SHORT_FLOAT *add_fl, BYTE normal,
|
|
REGS *regs )
|
|
{
|
|
int pgm_check;
|
|
BYTE shift;
|
|
|
|
pgm_check = 0;
|
|
if (add_fl->short_fract
|
|
|| add_fl->expo) { /* add_fl not 0 */
|
|
if (fl->short_fract
|
|
|| fl->expo) { /* fl not 0 */
|
|
/* both not 0 */
|
|
|
|
if (fl->expo == add_fl->expo) {
|
|
/* expo equal */
|
|
|
|
/* both guard digits */
|
|
fl->short_fract <<= 4;
|
|
add_fl->short_fract <<= 4;
|
|
} else {
|
|
/* expo not equal, denormalize */
|
|
|
|
if (fl->expo < add_fl->expo) {
|
|
/* shift minus guard digit */
|
|
shift = add_fl->expo - fl->expo - 1;
|
|
fl->expo = add_fl->expo;
|
|
|
|
if (shift) {
|
|
if (shift >= 6
|
|
|| ((fl->short_fract >>= (shift * 4)) == 0)) {
|
|
/* 0, copy summand */
|
|
|
|
fl->sign = add_fl->sign;
|
|
fl->short_fract = add_fl->short_fract;
|
|
|
|
if (fl->short_fract == 0) {
|
|
pgm_check = significance_sf(fl, regs);
|
|
} else {
|
|
if (normal == NORMAL) {
|
|
normal_sf(fl);
|
|
pgm_check = underflow_sf(fl, regs);
|
|
}
|
|
}
|
|
return(pgm_check);
|
|
}
|
|
}
|
|
/* guard digit */
|
|
add_fl->short_fract <<= 4;
|
|
} else {
|
|
/* shift minus guard digit */
|
|
shift = fl->expo - add_fl->expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 6
|
|
|| ((add_fl->short_fract >>= (shift * 4)) == 0)) {
|
|
/* 0, nothing to add */
|
|
|
|
if (fl->short_fract == 0) {
|
|
pgm_check = significance_sf(fl, regs);
|
|
} else {
|
|
if (normal == NORMAL) {
|
|
normal_sf(fl);
|
|
pgm_check = underflow_sf(fl, regs);
|
|
}
|
|
}
|
|
return(pgm_check);
|
|
}
|
|
}
|
|
/* guard digit */
|
|
fl->short_fract <<= 4;
|
|
}
|
|
}
|
|
|
|
/* compute with guard digit */
|
|
if (fl->sign == add_fl->sign) {
|
|
fl->short_fract += add_fl->short_fract;
|
|
} else {
|
|
if (fl->short_fract == add_fl->short_fract) {
|
|
/* true 0 */
|
|
|
|
fl->short_fract = 0;
|
|
return( significance_sf(fl, regs) );
|
|
|
|
} else if (fl->short_fract > add_fl->short_fract) {
|
|
fl->short_fract -= add_fl->short_fract;
|
|
} else {
|
|
fl->short_fract = add_fl->short_fract - fl->short_fract;
|
|
fl->sign = add_fl->sign;
|
|
}
|
|
}
|
|
|
|
/* handle overflow with guard digit */
|
|
if (fl->short_fract & 0xF0000000) {
|
|
fl->short_fract >>= 8;
|
|
(fl->expo)++;
|
|
pgm_check = overflow_sf(fl, regs);
|
|
} else {
|
|
|
|
if (normal == NORMAL) {
|
|
/* normalize with guard digit */
|
|
if (fl->short_fract) {
|
|
/* not 0 */
|
|
|
|
if (fl->short_fract & 0x0F000000) {
|
|
/* not normalize, just guard digit */
|
|
fl->short_fract >>= 4;
|
|
} else {
|
|
(fl->expo)--;
|
|
normal_sf(fl);
|
|
pgm_check = underflow_sf(fl, regs);
|
|
}
|
|
} else {
|
|
/* true 0 */
|
|
|
|
pgm_check = significance_sf(fl, regs);
|
|
}
|
|
} else {
|
|
/* not normalize, just guard digit */
|
|
fl->short_fract >>= 4;
|
|
if (fl->short_fract == 0) {
|
|
pgm_check = significance_sf(fl, regs);
|
|
}
|
|
}
|
|
}
|
|
return(pgm_check);
|
|
} else { /* fl 0, add_fl not 0 */
|
|
/* copy summand */
|
|
|
|
fl->expo = add_fl->expo;
|
|
fl->sign = add_fl->sign;
|
|
fl->short_fract = add_fl->short_fract;
|
|
if (fl->short_fract == 0) {
|
|
return( significance_sf(fl, regs) );
|
|
}
|
|
}
|
|
} else { /* add_fl 0 */
|
|
if (fl->short_fract == 0) { /* fl 0 */
|
|
/* both 0 */
|
|
|
|
return( significance_sf(fl, regs) );
|
|
}
|
|
}
|
|
if (normal == NORMAL) {
|
|
normal_sf(fl);
|
|
pgm_check = underflow_sf(fl, regs);
|
|
}
|
|
return(pgm_check);
|
|
|
|
} /* end function add_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Add long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Float */
|
|
/* add_fl Float to be added */
|
|
/* normal Normalize if true */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int add_lf( LONG_FLOAT *fl, LONG_FLOAT *add_fl, BYTE normal,
|
|
REGS *regs )
|
|
{
|
|
int pgm_check;
|
|
BYTE shift;
|
|
|
|
pgm_check = 0;
|
|
if (add_fl->long_fract
|
|
|| add_fl->expo) { /* add_fl not 0 */
|
|
if (fl->long_fract
|
|
|| fl->expo) { /* fl not 0 */
|
|
/* both not 0 */
|
|
|
|
if (fl->expo == add_fl->expo) {
|
|
/* expo equal */
|
|
|
|
/* both guard digits */
|
|
fl->long_fract <<= 4;
|
|
add_fl->long_fract <<= 4;
|
|
} else {
|
|
/* expo not equal, denormalize */
|
|
|
|
if (fl->expo < add_fl->expo) {
|
|
/* shift minus guard digit */
|
|
shift = add_fl->expo - fl->expo - 1;
|
|
fl->expo = add_fl->expo;
|
|
|
|
if (shift) {
|
|
if (shift >= 14
|
|
|| ((fl->long_fract >>= (shift * 4)) == 0)) {
|
|
/* 0, copy summand */
|
|
|
|
fl->sign = add_fl->sign;
|
|
fl->long_fract = add_fl->long_fract;
|
|
|
|
if (fl->long_fract == 0) {
|
|
pgm_check = significance_lf(fl, regs);
|
|
} else {
|
|
if (normal == NORMAL) {
|
|
normal_lf(fl);
|
|
pgm_check = underflow_lf(fl, regs);
|
|
}
|
|
}
|
|
return(pgm_check);
|
|
}
|
|
}
|
|
/* guard digit */
|
|
add_fl->long_fract <<= 4;
|
|
} else {
|
|
/* shift minus guard digit */
|
|
shift = fl->expo - add_fl->expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 14
|
|
|| ((add_fl->long_fract >>= (shift * 4)) == 0)) {
|
|
/* 0, nothing to add */
|
|
|
|
if (fl->long_fract == 0) {
|
|
pgm_check = significance_lf(fl, regs);
|
|
} else {
|
|
if (normal == NORMAL) {
|
|
normal_lf(fl);
|
|
pgm_check = underflow_lf(fl, regs);
|
|
}
|
|
}
|
|
return(pgm_check);
|
|
}
|
|
}
|
|
/* guard digit */
|
|
fl->long_fract <<= 4;
|
|
}
|
|
}
|
|
|
|
/* compute with guard digit */
|
|
if (fl->sign == add_fl->sign) {
|
|
fl->long_fract += add_fl->long_fract;
|
|
} else {
|
|
if (fl->long_fract == add_fl->long_fract) {
|
|
/* true 0 */
|
|
|
|
fl->long_fract = 0;
|
|
return( significance_lf(fl, regs) );
|
|
|
|
} else if (fl->long_fract > add_fl->long_fract) {
|
|
fl->long_fract -= add_fl->long_fract;
|
|
} else {
|
|
fl->long_fract = add_fl->long_fract - fl->long_fract;
|
|
fl->sign = add_fl->sign;
|
|
}
|
|
}
|
|
|
|
/* handle overflow with guard digit */
|
|
if (fl->long_fract & 0xF000000000000000ULL) {
|
|
fl->long_fract >>= 8;
|
|
(fl->expo)++;
|
|
pgm_check = overflow_lf(fl, regs);
|
|
} else {
|
|
|
|
if (normal == NORMAL) {
|
|
/* normalize with guard digit */
|
|
if (fl->long_fract) {
|
|
/* not 0 */
|
|
|
|
if (fl->long_fract & 0x0F00000000000000ULL) {
|
|
/* not normalize, just guard digit */
|
|
fl->long_fract >>= 4;
|
|
} else {
|
|
(fl->expo)--;
|
|
normal_lf(fl);
|
|
pgm_check = underflow_lf(fl, regs);
|
|
}
|
|
} else {
|
|
/* true 0 */
|
|
|
|
pgm_check = significance_lf(fl, regs);
|
|
}
|
|
} else {
|
|
/* not normalize, just guard digit */
|
|
fl->long_fract >>= 4;
|
|
if (fl->long_fract == 0) {
|
|
pgm_check = significance_lf(fl, regs);
|
|
}
|
|
}
|
|
}
|
|
return(pgm_check);
|
|
} else { /* fl 0, add_fl not 0 */
|
|
/* copy summand */
|
|
|
|
fl->expo = add_fl->expo;
|
|
fl->sign = add_fl->sign;
|
|
fl->long_fract = add_fl->long_fract;
|
|
if (fl->long_fract == 0) {
|
|
return( significance_lf(fl, regs) );
|
|
}
|
|
}
|
|
} else { /* add_fl 0 */
|
|
if (fl->long_fract == 0) { /* fl 0 */
|
|
/* both 0 */
|
|
|
|
return( significance_lf(fl, regs) );
|
|
}
|
|
}
|
|
if (normal == NORMAL) {
|
|
normal_lf(fl);
|
|
pgm_check = underflow_lf(fl, regs);
|
|
}
|
|
return(pgm_check);
|
|
|
|
} /* end function add_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Add extended float normalized */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Float */
|
|
/* add_fl Float to be added */
|
|
/* fpr Pointer to register */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int add_ef( EXTENDED_FLOAT *fl, EXTENDED_FLOAT *add_fl,
|
|
U32 *fpr, REGS *regs )
|
|
{
|
|
int pgm_check;
|
|
BYTE shift;
|
|
|
|
pgm_check = 0;
|
|
if (add_fl->ms_fract
|
|
|| add_fl->ls_fract
|
|
|| add_fl->expo) { /* add_fl not 0 */
|
|
if (fl->ms_fract
|
|
|| fl->ls_fract
|
|
|| fl->expo) { /* fl not 0 */
|
|
/* both not 0 */
|
|
|
|
if (fl->expo == add_fl->expo) {
|
|
/* expo equal */
|
|
|
|
/* both guard digits */
|
|
fl->ms_fract = (fl->ms_fract << 4)
|
|
| (fl->ls_fract >> 60);
|
|
fl->ls_fract <<= 4;
|
|
add_fl->ms_fract = (add_fl->ms_fract << 4)
|
|
| (add_fl->ls_fract >> 60);
|
|
add_fl->ls_fract <<= 4;
|
|
} else {
|
|
/* expo not equal, denormalize */
|
|
|
|
if (fl->expo < add_fl->expo) {
|
|
/* shift minus guard digit */
|
|
shift = add_fl->expo - fl->expo - 1;
|
|
fl->expo = add_fl->expo;
|
|
|
|
if (shift) {
|
|
if (shift >= 28) {
|
|
/* 0, copy summand */
|
|
|
|
fl->sign = add_fl->sign;
|
|
fl->ms_fract = add_fl->ms_fract;
|
|
fl->ls_fract = add_fl->ls_fract;
|
|
|
|
if ((fl->ms_fract == 0)
|
|
&& (fl->ls_fract == 0)) {
|
|
pgm_check = significance_ef(fl, fpr, regs);
|
|
} else {
|
|
normal_ef(fl);
|
|
pgm_check = underflow_ef(fl, fpr, regs);
|
|
}
|
|
return(pgm_check);
|
|
} else if (shift >= 16) {
|
|
fl->ls_fract = fl->ms_fract;
|
|
if (shift > 16) {
|
|
fl->ls_fract >>= (shift - 16) * 4;
|
|
}
|
|
fl->ms_fract = 0;
|
|
} else {
|
|
shift *= 4;
|
|
fl->ls_fract = fl->ms_fract << (64 - shift)
|
|
| fl->ls_fract >> shift;
|
|
fl->ms_fract >>= shift;
|
|
}
|
|
|
|
if ((fl->ms_fract == 0)
|
|
&& (fl->ls_fract == 0)) {
|
|
/* 0, copy summand */
|
|
|
|
fl->sign = add_fl->sign;
|
|
fl->ms_fract = add_fl->ms_fract;
|
|
fl->ls_fract = add_fl->ls_fract;
|
|
|
|
if ((fl->ms_fract == 0)
|
|
&& (fl->ls_fract == 0)) {
|
|
pgm_check = significance_ef(fl, fpr, regs);
|
|
} else {
|
|
normal_ef(fl);
|
|
pgm_check = underflow_ef(fl, fpr, regs);
|
|
}
|
|
return(pgm_check);
|
|
}
|
|
}
|
|
/* guard digit */
|
|
add_fl->ms_fract = (add_fl->ms_fract << 4)
|
|
| (add_fl->ls_fract >> 60);
|
|
add_fl->ls_fract <<= 4;
|
|
} else {
|
|
/* shift minus guard digit */
|
|
shift = fl->expo - add_fl->expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 28) {
|
|
/* 0, nothing to add */
|
|
|
|
if ((fl->ms_fract == 0)
|
|
&& (fl->ls_fract == 0)) {
|
|
pgm_check = significance_ef(fl, fpr, regs);
|
|
} else {
|
|
normal_ef(fl);
|
|
pgm_check = underflow_ef(fl, fpr, regs);
|
|
}
|
|
return(pgm_check);
|
|
} else if (shift >= 16) {
|
|
add_fl->ls_fract = add_fl->ms_fract;
|
|
if (shift > 16) {
|
|
add_fl->ls_fract >>= (shift - 16) * 4;
|
|
}
|
|
add_fl->ms_fract = 0;
|
|
} else {
|
|
shift *= 4;
|
|
add_fl->ls_fract = add_fl->ms_fract << (64 - shift)
|
|
| add_fl->ls_fract >> shift;
|
|
add_fl->ms_fract >>= shift;
|
|
}
|
|
|
|
if ((add_fl->ms_fract == 0)
|
|
&& (add_fl->ls_fract == 0)) {
|
|
/* 0, nothing to add */
|
|
|
|
if ((fl->ms_fract == 0)
|
|
&& (fl->ls_fract == 0)) {
|
|
pgm_check = significance_ef(fl, fpr, regs);
|
|
} else {
|
|
normal_ef(fl);
|
|
pgm_check = underflow_ef(fl, fpr, regs);
|
|
}
|
|
return(pgm_check);
|
|
}
|
|
}
|
|
/* guard digit */
|
|
fl->ms_fract = (fl->ms_fract << 4)
|
|
| (fl->ls_fract >> 60);
|
|
fl->ls_fract <<= 4;
|
|
}
|
|
}
|
|
|
|
/* compute with guard digit */
|
|
if (fl->sign == add_fl->sign) {
|
|
add_U128(fl->ms_fract, fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract);
|
|
} else {
|
|
if ((fl->ms_fract == add_fl->ms_fract)
|
|
&& (fl->ls_fract == add_fl->ls_fract)) {
|
|
/* true 0 */
|
|
|
|
fl->ms_fract = 0;
|
|
fl->ls_fract = 0;
|
|
return( significance_ef(fl, fpr, regs) );
|
|
|
|
} else if ( (fl->ms_fract > add_fl->ms_fract)
|
|
|| ( (fl->ms_fract == add_fl->ms_fract)
|
|
&& (fl->ls_fract > add_fl->ls_fract))) {
|
|
sub_U128(fl->ms_fract, fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract);
|
|
} else {
|
|
sub_reverse_U128(fl->ms_fract, fl->ls_fract, add_fl->ms_fract, add_fl->ls_fract);
|
|
fl->sign = add_fl->sign;
|
|
}
|
|
}
|
|
|
|
/* handle overflow with guard digit */
|
|
if (fl->ms_fract & 0x00F0000000000000ULL) {
|
|
fl->ls_fract = (fl->ms_fract << 56)
|
|
| (fl->ls_fract >> 8);
|
|
fl->ms_fract >>= 8;
|
|
(fl->expo)++;
|
|
pgm_check = overflow_ef(fl, regs);
|
|
store_ef( fl, fpr );
|
|
} else {
|
|
/* normalize with guard digit */
|
|
if (fl->ms_fract
|
|
|| fl->ls_fract) {
|
|
/* not 0 */
|
|
|
|
if (fl->ms_fract & 0x000F000000000000ULL) {
|
|
/* not normalize, just guard digit */
|
|
fl->ls_fract = (fl->ms_fract << 60)
|
|
| (fl->ls_fract >> 4);
|
|
fl->ms_fract >>= 4;
|
|
store_ef( fl, fpr );
|
|
} else {
|
|
(fl->expo)--;
|
|
normal_ef(fl);
|
|
pgm_check = underflow_ef(fl, fpr, regs);
|
|
}
|
|
} else {
|
|
/* true 0 */
|
|
|
|
pgm_check = significance_ef(fl, fpr, regs);
|
|
}
|
|
}
|
|
return(pgm_check);
|
|
} else { /* fl 0, add_fl not 0 */
|
|
/* copy summand */
|
|
|
|
fl->expo = add_fl->expo;
|
|
fl->sign = add_fl->sign;
|
|
fl->ms_fract = add_fl->ms_fract;
|
|
fl->ls_fract = add_fl->ls_fract;
|
|
if ((fl->ms_fract == 0)
|
|
&& (fl->ls_fract == 0)) {
|
|
return( significance_ef(fl, fpr, regs) );
|
|
}
|
|
}
|
|
} else { /* add_fl 0*/
|
|
if ((fl->ms_fract == 0)
|
|
&& (fl->ls_fract == 0)) { /* fl 0 */
|
|
/* both 0 */
|
|
|
|
return( significance_ef(fl, fpr, regs) );
|
|
}
|
|
}
|
|
normal_ef(fl);
|
|
return( underflow_ef(fl, fpr, regs) );
|
|
|
|
} /* end function add_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Compare short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Float */
|
|
/* cmp_fl Float to be compared */
|
|
/* regs CPU register context */
|
|
/*-------------------------------------------------------------------*/
|
|
static void cmp_sf( SHORT_FLOAT *fl, SHORT_FLOAT *cmp_fl, REGS *regs )
|
|
{
|
|
BYTE shift;
|
|
|
|
if (cmp_fl->short_fract
|
|
|| cmp_fl->expo) { /* cmp_fl not 0 */
|
|
if (fl->short_fract
|
|
|| fl->expo) { /* fl not 0 */
|
|
/* both not 0 */
|
|
|
|
if (fl->expo == cmp_fl->expo) {
|
|
/* expo equal */
|
|
|
|
/* both guard digits */
|
|
fl->short_fract <<= 4;
|
|
cmp_fl->short_fract <<= 4;
|
|
} else {
|
|
/* expo not equal, denormalize */
|
|
|
|
if (fl->expo < cmp_fl->expo) {
|
|
/* shift minus guard digit */
|
|
shift = cmp_fl->expo - fl->expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 6
|
|
|| ((fl->short_fract >>= (shift * 4)) == 0)) {
|
|
/* Set condition code */
|
|
if (cmp_fl->short_fract) {
|
|
regs->psw.cc = cmp_fl->sign ? 2 : 1;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
/* guard digit */
|
|
cmp_fl->short_fract <<= 4;
|
|
} else {
|
|
/* shift minus guard digit */
|
|
shift = fl->expo - cmp_fl->expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 6
|
|
|| ((cmp_fl->short_fract >>= (shift * 4)) == 0)) {
|
|
/* Set condition code */
|
|
if (fl->short_fract) {
|
|
regs->psw.cc = fl->sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
/* guard digit */
|
|
fl->short_fract <<= 4;
|
|
}
|
|
}
|
|
|
|
/* compute with guard digit */
|
|
if (fl->sign != cmp_fl->sign) {
|
|
fl->short_fract += cmp_fl->short_fract;
|
|
} else if (fl->short_fract >= cmp_fl->short_fract) {
|
|
fl->short_fract -= cmp_fl->short_fract;
|
|
} else {
|
|
fl->short_fract = cmp_fl->short_fract - fl->short_fract;
|
|
fl->sign = ! (cmp_fl->sign);
|
|
}
|
|
|
|
/* handle overflow with guard digit */
|
|
if (fl->short_fract & 0xF0000000) {
|
|
fl->short_fract >>= 4;
|
|
}
|
|
|
|
/* Set condition code */
|
|
if (fl->short_fract) {
|
|
regs->psw.cc = fl->sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
} else { /* fl 0, cmp_fl not 0 */
|
|
/* Set condition code */
|
|
if (cmp_fl->short_fract) {
|
|
regs->psw.cc = cmp_fl->sign ? 2 : 1;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
} else { /* cmp_fl 0 */
|
|
/* Set condition code */
|
|
if (fl->short_fract) {
|
|
regs->psw.cc = fl->sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
} /* end function cmp_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Compare long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Float */
|
|
/* cmp_fl Float to be compared */
|
|
/* regs CPU register context */
|
|
/*-------------------------------------------------------------------*/
|
|
static void cmp_lf( LONG_FLOAT *fl, LONG_FLOAT *cmp_fl, REGS *regs )
|
|
{
|
|
BYTE shift;
|
|
|
|
if (cmp_fl->long_fract
|
|
|| cmp_fl->expo) { /* cmp_fl not 0 */
|
|
if (fl->long_fract
|
|
|| fl->expo) { /* fl not 0 */
|
|
/* both not 0 */
|
|
|
|
if (fl->expo == cmp_fl->expo) {
|
|
/* expo equal */
|
|
|
|
/* both guard digits */
|
|
fl->long_fract <<= 4;
|
|
cmp_fl->long_fract <<= 4;
|
|
} else {
|
|
/* expo not equal, denormalize */
|
|
|
|
if (fl->expo < cmp_fl->expo) {
|
|
/* shift minus guard digit */
|
|
shift = cmp_fl->expo - fl->expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 14
|
|
|| ((fl->long_fract >>= (shift * 4)) == 0)) {
|
|
/* Set condition code */
|
|
if (cmp_fl->long_fract) {
|
|
regs->psw.cc = cmp_fl->sign ? 2 : 1;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
/* guard digit */
|
|
cmp_fl->long_fract <<= 4;
|
|
} else {
|
|
/* shift minus guard digit */
|
|
shift = fl->expo - cmp_fl->expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 14
|
|
|| ((cmp_fl->long_fract >>= (shift * 4)) == 0)) {
|
|
/* Set condition code */
|
|
if (fl->long_fract) {
|
|
regs->psw.cc = fl->sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
/* guard digit */
|
|
fl->long_fract <<= 4;
|
|
}
|
|
}
|
|
|
|
/* compute with guard digit */
|
|
if (fl->sign != cmp_fl->sign) {
|
|
fl->long_fract += cmp_fl->long_fract;
|
|
} else if (fl->long_fract >= cmp_fl->long_fract) {
|
|
fl->long_fract -= cmp_fl->long_fract;
|
|
} else {
|
|
fl->long_fract = cmp_fl->long_fract - fl->long_fract;
|
|
fl->sign = ! (cmp_fl->sign);
|
|
}
|
|
|
|
/* handle overflow with guard digit */
|
|
if (fl->long_fract & 0xF0000000) {
|
|
fl->long_fract >>= 4;
|
|
}
|
|
|
|
/* Set condition code */
|
|
if (fl->long_fract) {
|
|
regs->psw.cc = fl->sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
} else { /* fl 0, cmp_fl not 0 */
|
|
/* Set condition code */
|
|
if (cmp_fl->long_fract) {
|
|
regs->psw.cc = cmp_fl->sign ? 2 : 1;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
} else { /* cmp_fl 0 */
|
|
/* Set condition code */
|
|
if (fl->long_fract) {
|
|
regs->psw.cc = fl->sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
} /* end function cmp_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Multiply short float to long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Multiplicand short float */
|
|
/* mul_fl Multiplicator short float */
|
|
/* result_fl Result long float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int mul_sf_to_lf( SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl,
|
|
LONG_FLOAT *result_fl, REGS *regs )
|
|
{
|
|
if (fl->short_fract
|
|
&& mul_fl->short_fract) {
|
|
/* normalize operands */
|
|
normal_sf( fl );
|
|
normal_sf( mul_fl );
|
|
|
|
/* multiply fracts */
|
|
result_fl->long_fract = (U64) fl->short_fract * mul_fl->short_fract;
|
|
|
|
/* normalize result and compute expo */
|
|
if (result_fl->long_fract & 0x0000F00000000000ULL) {
|
|
result_fl->long_fract <<= 8;
|
|
result_fl->expo = fl->expo + mul_fl->expo - 64;
|
|
} else {
|
|
result_fl->long_fract <<= 12;
|
|
result_fl->expo = fl->expo + mul_fl->expo - 65;
|
|
}
|
|
|
|
/* determine sign */
|
|
result_fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return( over_under_flow_lf(result_fl, regs) );
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
result_fl->long_fract = 0;
|
|
result_fl->expo = 0;
|
|
result_fl->sign = POS;
|
|
return(0);
|
|
}
|
|
|
|
} /* end function mul_sf_to_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Multiply long float to extended float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Multiplicand long float */
|
|
/* mul_fl Multiplicator long float */
|
|
/* result_fl Result extended float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int mul_lf_to_ef( LONG_FLOAT *fl, LONG_FLOAT *mul_fl,
|
|
EXTENDED_FLOAT *result_fl, REGS *regs )
|
|
{
|
|
U64 wk;
|
|
|
|
if (fl->long_fract
|
|
&& mul_fl->long_fract) {
|
|
/* normalize operands */
|
|
normal_lf( fl );
|
|
normal_lf( mul_fl );
|
|
|
|
/* multiply fracts by sum of partial multiplications */
|
|
wk = (fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL);
|
|
result_fl->ls_fract = wk & 0x00000000FFFFFFFFULL;
|
|
|
|
wk >>= 32;
|
|
wk += ((fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract >> 32));
|
|
wk += ((fl->long_fract >> 32) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL));
|
|
result_fl->ls_fract |= wk << 32;
|
|
|
|
result_fl->ms_fract = (wk >> 32) + ((fl->long_fract >> 32) * (mul_fl->long_fract >> 32));
|
|
|
|
/* normalize result and compute expo */
|
|
if (result_fl->ms_fract & 0x0000F00000000000ULL) {
|
|
result_fl->expo = fl->expo + mul_fl->expo - 64;
|
|
} else {
|
|
result_fl->ms_fract = (result_fl->ms_fract << 4)
|
|
| (result_fl->ls_fract >> 60);
|
|
result_fl->ls_fract <<= 4;
|
|
result_fl->expo = fl->expo + mul_fl->expo - 65;
|
|
}
|
|
|
|
/* determine sign */
|
|
result_fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return( over_under_flow_ef(result_fl, regs) );
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
result_fl->ms_fract = 0;
|
|
result_fl->ls_fract = 0;
|
|
result_fl->expo = 0;
|
|
result_fl->sign = POS;
|
|
return(0);
|
|
}
|
|
|
|
} /* end function mul_lf_to_ef */
|
|
|
|
|
|
#if defined (FEATURE_HFP_EXTENSIONS)
|
|
/*-------------------------------------------------------------------*/
|
|
/* Multiply short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Multiplicand short float */
|
|
/* mul_fl Multiplicator short float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int mul_sf( SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl, REGS *regs )
|
|
{
|
|
U64 wk;
|
|
|
|
if (fl->short_fract
|
|
&& mul_fl->short_fract) {
|
|
/* normalize operands */
|
|
normal_sf( fl );
|
|
normal_sf( mul_fl );
|
|
|
|
/* multiply fracts */
|
|
wk = (U64) fl->short_fract * mul_fl->short_fract;
|
|
|
|
/* normalize result and compute expo */
|
|
if (wk & 0x0000F00000000000ULL) {
|
|
fl->short_fract = wk >> 24;
|
|
fl->expo = fl->expo + mul_fl->expo - 64;
|
|
} else {
|
|
fl->short_fract = wk >> 20;
|
|
fl->expo = fl->expo + mul_fl->expo - 65;
|
|
}
|
|
|
|
/* determine sign */
|
|
fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return( over_under_flow_sf(fl, regs) );
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->short_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
return(0);
|
|
}
|
|
|
|
} /* end function mul_sf */
|
|
#endif /* FEATURE_HFP_EXTENSIONS */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Multiply long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Multiplicand long float */
|
|
/* mul_fl Multiplicator long float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int mul_lf( LONG_FLOAT *fl, LONG_FLOAT *mul_fl, REGS *regs )
|
|
{
|
|
U64 wk;
|
|
U32 v;
|
|
|
|
if (fl->long_fract
|
|
&& mul_fl->long_fract) {
|
|
/* normalize operands */
|
|
normal_lf( fl );
|
|
normal_lf( mul_fl );
|
|
|
|
/* multiply fracts by sum of partial multiplications */
|
|
wk = ((fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL)) >> 32;
|
|
|
|
wk += ((fl->long_fract & 0x00000000FFFFFFFFULL) * (mul_fl->long_fract >> 32));
|
|
wk += ((fl->long_fract >> 32) * (mul_fl->long_fract & 0x00000000FFFFFFFFULL));
|
|
v = wk;
|
|
|
|
fl->long_fract = (wk >> 32) + ((fl->long_fract >> 32) * (mul_fl->long_fract >> 32));
|
|
|
|
/* normalize result and compute expo */
|
|
if (fl->long_fract & 0x0000F00000000000ULL) {
|
|
fl->long_fract = (fl->long_fract << 8)
|
|
| (v >> 24);
|
|
fl->expo = fl->expo + mul_fl->expo - 64;
|
|
} else {
|
|
fl->long_fract = (fl->long_fract << 12)
|
|
| (v >> 20);
|
|
fl->expo = fl->expo + mul_fl->expo - 65;
|
|
}
|
|
|
|
/* determine sign */
|
|
fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return( over_under_flow_lf(fl, regs) );
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->long_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
return(0);
|
|
}
|
|
|
|
} /* end function mul_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Multiply extended float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Multiplicand extended float */
|
|
/* mul_fl Multiplicator extended float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int mul_ef( EXTENDED_FLOAT *fl, EXTENDED_FLOAT *mul_fl,
|
|
REGS *regs )
|
|
{
|
|
U64 wk1;
|
|
U64 wk2;
|
|
U64 wk3;
|
|
U64 wk4;
|
|
U64 wk;
|
|
U32 wk0;
|
|
U32 v;
|
|
|
|
if ((fl->ms_fract
|
|
|| fl->ls_fract)
|
|
&& (mul_fl->ms_fract
|
|
|| mul_fl->ls_fract)) {
|
|
/* normalize operands */
|
|
normal_ef ( fl );
|
|
normal_ef ( mul_fl );
|
|
|
|
/* multiply fracts by sum of partial multiplications */
|
|
wk0 = ((fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL)) >> 32;
|
|
|
|
wk1 = (fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract >> 32);
|
|
wk2 = (fl->ls_fract >> 32) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL);
|
|
wk = wk0 + (wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL);
|
|
wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32);
|
|
|
|
wk1 = (fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL);
|
|
wk2 = (fl->ls_fract >> 32) * (mul_fl->ls_fract >> 32);
|
|
wk3 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL);
|
|
wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL) + (wk3 & 0x00000000FFFFFFFFULL));
|
|
wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32) + (wk3 >> 32);
|
|
|
|
wk1 = (fl->ls_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract >> 32);
|
|
wk2 = (fl->ls_fract >> 32) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL);
|
|
wk3 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ls_fract >> 32);
|
|
wk4 = (fl->ms_fract >> 32) * (mul_fl->ls_fract & 0x00000000FFFFFFFFULL);
|
|
wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL) + (wk3 & 0x00000000FFFFFFFFULL) + (wk4 & 0x00000000FFFFFFFFULL));
|
|
v = wk;
|
|
wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32) + (wk3 >> 32) + (wk4 >> 32);
|
|
|
|
wk1 = (fl->ls_fract >> 32) * (mul_fl->ms_fract >> 32);
|
|
wk2 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL);
|
|
wk3 = (fl->ms_fract >> 32) * (mul_fl->ls_fract >> 32);
|
|
wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL) + (wk3 & 0x00000000FFFFFFFFULL));
|
|
fl->ls_fract = wk & 0x00000000FFFFFFFFULL;
|
|
wk = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32) + (wk3 >> 32);
|
|
|
|
wk1 = (fl->ms_fract & 0x00000000FFFFFFFFULL) * (mul_fl->ms_fract >> 32);
|
|
wk2 = (fl->ms_fract >> 32) * (mul_fl->ms_fract & 0x00000000FFFFFFFFULL);
|
|
wk += ((wk1 & 0x00000000FFFFFFFFULL) + (wk2 & 0x00000000FFFFFFFFULL));
|
|
fl->ls_fract |= wk << 32;
|
|
wk0 = (wk >> 32) + (wk1 >> 32) + (wk2 >> 32);
|
|
|
|
wk0 += ((fl->ms_fract >> 32) * (mul_fl->ms_fract >> 32));
|
|
fl->ms_fract = wk0;
|
|
|
|
/* normalize result and compute expo */
|
|
if (wk0 & 0xF0000000UL) {
|
|
fl->ms_fract = (fl->ms_fract << 16)
|
|
| (fl->ls_fract >> 48);
|
|
fl->ls_fract = (fl->ls_fract << 16)
|
|
| (v >> 16);
|
|
fl->expo = fl->expo + mul_fl->expo - 64;
|
|
} else {
|
|
fl->ms_fract = (fl->ms_fract << 20)
|
|
| (fl->ls_fract >> 44);
|
|
fl->ls_fract = (fl->ls_fract << 20)
|
|
| (v >> 12);
|
|
fl->expo = fl->expo + mul_fl->expo - 65;
|
|
}
|
|
|
|
/* determine sign */
|
|
fl->sign = (fl->sign == mul_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return ( over_under_flow_ef (fl, regs) );
|
|
} else {
|
|
/* set true 0 */
|
|
|
|
fl->ms_fract = 0;
|
|
fl->ls_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
return (0);
|
|
}
|
|
|
|
} /* end function mul_ef */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Divide short float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Dividend short float */
|
|
/* div_fl Divisor short float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int div_sf( SHORT_FLOAT *fl, SHORT_FLOAT *div_fl, REGS *regs )
|
|
{
|
|
U64 wk;
|
|
|
|
if (div_fl->short_fract) {
|
|
if (fl->short_fract) {
|
|
/* normalize operands */
|
|
normal_sf( fl );
|
|
normal_sf( div_fl );
|
|
|
|
/* position fracts and compute expo */
|
|
if (fl->short_fract < div_fl->short_fract) {
|
|
wk = (U64) fl->short_fract << 24;
|
|
fl->expo = fl->expo - div_fl->expo + 64;
|
|
} else {
|
|
wk = (U64) fl->short_fract << 20;
|
|
fl->expo = fl->expo - div_fl->expo + 65;
|
|
}
|
|
/* divide fractions */
|
|
fl->short_fract = wk / div_fl->short_fract;
|
|
|
|
/* determine sign */
|
|
fl->sign = (fl->sign == div_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return( over_under_flow_sf(fl, regs) );
|
|
} else {
|
|
/* fraction of dividend 0, set true 0 */
|
|
|
|
fl->short_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
} else {
|
|
/* divisor 0 */
|
|
|
|
ARCH_DEP(program_interrupt) (regs, PGM_FLOATING_POINT_DIVIDE_EXCEPTION);
|
|
}
|
|
return(0);
|
|
|
|
} /* end function div_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Divide long float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Dividend long float */
|
|
/* div_fl Divisor long float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int div_lf( LONG_FLOAT *fl, LONG_FLOAT *div_fl, REGS *regs )
|
|
{
|
|
U64 wk;
|
|
U64 wk2;
|
|
int i;
|
|
|
|
if (div_fl->long_fract) {
|
|
if (fl->long_fract) {
|
|
/* normalize operands */
|
|
normal_lf( fl );
|
|
normal_lf( div_fl );
|
|
|
|
/* position fracts and compute expo */
|
|
if (fl->long_fract < div_fl->long_fract) {
|
|
fl->expo = fl->expo - div_fl->expo + 64;
|
|
} else {
|
|
fl->expo = fl->expo - div_fl->expo + 65;
|
|
div_fl->long_fract <<= 4;
|
|
}
|
|
|
|
/* partial divide first hex digit */
|
|
wk2 = fl->long_fract / div_fl->long_fract;
|
|
wk = (fl->long_fract % div_fl->long_fract) << 4;
|
|
|
|
/* partial divide middle hex digits */
|
|
i = 13;
|
|
while (i--) {
|
|
wk2 = (wk2 << 4)
|
|
| (wk / div_fl->long_fract);
|
|
wk = (wk % div_fl->long_fract) << 4;
|
|
}
|
|
|
|
/* partial divide last hex digit */
|
|
fl->long_fract = (wk2 << 4)
|
|
| (wk / div_fl->long_fract);
|
|
|
|
/* determine sign */
|
|
fl->sign = (fl->sign == div_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return( over_under_flow_lf(fl, regs) );
|
|
} else {
|
|
/* fraction of dividend 0, set true 0 */
|
|
|
|
fl->long_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
} else {
|
|
/* divisor 0 */
|
|
|
|
ARCH_DEP(program_interrupt) (regs, PGM_FLOATING_POINT_DIVIDE_EXCEPTION);
|
|
}
|
|
return(0);
|
|
|
|
} /* end function div_lf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Divide extended float */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Dividend extended float */
|
|
/* div_fl Divisor extended float */
|
|
/* regs CPU register context */
|
|
/* Value: */
|
|
/* exeption */
|
|
/*-------------------------------------------------------------------*/
|
|
static int div_ef( EXTENDED_FLOAT *fl, EXTENDED_FLOAT *div_fl,
|
|
REGS *regs )
|
|
{
|
|
U64 wkm;
|
|
U64 wkl;
|
|
int i;
|
|
|
|
if (div_fl->ms_fract
|
|
|| div_fl->ls_fract) {
|
|
if (fl->ms_fract
|
|
|| fl->ls_fract) {
|
|
/* normalize operands */
|
|
normal_ef( fl );
|
|
normal_ef( div_fl );
|
|
|
|
/* position fracts and compute expo */
|
|
if ((fl->ms_fract < div_fl->ms_fract)
|
|
|| ((fl->ms_fract == div_fl->ms_fract)
|
|
&& (fl->ls_fract < div_fl->ls_fract))) {
|
|
fl->expo = fl->expo - div_fl->expo + 64;
|
|
} else {
|
|
fl->expo = fl->expo - div_fl->expo + 65;
|
|
div_fl->ms_fract = (div_fl->ms_fract << 4)
|
|
| (div_fl->ls_fract >> 60);
|
|
div_fl->ls_fract <<= 4;
|
|
}
|
|
|
|
/* divide fractions */
|
|
|
|
/* the first binary digit */
|
|
wkm = fl->ms_fract;
|
|
wkl = fl->ls_fract;
|
|
sub_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract);
|
|
wkm = (wkm << 1)
|
|
| (wkl >> 63);
|
|
wkl <<= 1;
|
|
fl->ms_fract = 0;
|
|
if (((S64)wkm) >= 0) {
|
|
fl->ls_fract = 1;
|
|
sub_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract);
|
|
} else {
|
|
fl->ls_fract = 0;
|
|
add_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract);
|
|
}
|
|
|
|
/* the middle binary digits */
|
|
i = 111;
|
|
while (i--) {
|
|
wkm = (wkm << 1)
|
|
| (wkl >> 63);
|
|
wkl <<= 1;
|
|
|
|
fl->ms_fract = (fl->ms_fract << 1)
|
|
| (fl->ls_fract >> 63);
|
|
fl->ls_fract <<= 1;
|
|
if (((S64)wkm) >= 0) {
|
|
fl->ls_fract |= 1;
|
|
sub_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract);
|
|
} else {
|
|
add_U128(wkm, wkl, div_fl->ms_fract, div_fl->ls_fract);
|
|
}
|
|
}
|
|
|
|
/* the last binary digit */
|
|
fl->ms_fract = (fl->ms_fract << 1)
|
|
| (fl->ls_fract >> 63);
|
|
fl->ls_fract <<= 1;
|
|
if (((S64)wkm) >= 0) {
|
|
fl->ls_fract |= 1;
|
|
}
|
|
|
|
/* determine sign */
|
|
fl->sign = (fl->sign == div_fl->sign) ? POS : NEG;
|
|
|
|
/* handle overflow and underflow */
|
|
return( over_under_flow_ef(fl, regs) );
|
|
} else {
|
|
/* fraction of dividend 0, set true 0 */
|
|
|
|
fl->ms_fract = 0;
|
|
fl->ls_fract = 0;
|
|
fl->expo = 0;
|
|
fl->sign = POS;
|
|
}
|
|
} else {
|
|
/* divisor 0 */
|
|
|
|
ARCH_DEP(program_interrupt) (regs, PGM_FLOATING_POINT_DIVIDE_EXCEPTION);
|
|
}
|
|
return(0);
|
|
|
|
} /* end function div_ef */
|
|
|
|
|
|
#if defined (FEATURE_SQUARE_ROOT)
|
|
/*-------------------------------------------------------------------*/
|
|
/* Square root of fraction */
|
|
/* This routine uses the Newton-Iteration-Method */
|
|
/* The iteration is startet with a table look up */
|
|
/* */
|
|
/* Input: */
|
|
/* a short fraction expanded to U64 */
|
|
/* Value: */
|
|
/* square root as U32 */
|
|
/*-------------------------------------------------------------------*/
|
|
static U32 square_root_fraction( U64 a )
|
|
{
|
|
U32 xi;
|
|
U32 xj;
|
|
static const unsigned short sqtab[] = {
|
|
/* 0 */ 0,
|
|
/* 1 */ 304,
|
|
/* 2 */ 401,
|
|
/* 3 */ 476,
|
|
/* 4 */ 541,
|
|
/* 5 */ 599,
|
|
/* 6 */ 652,
|
|
/* 7 */ 700,
|
|
/* 8 */ 746,
|
|
/* 9 */ 788,
|
|
/* 10 */ 829,
|
|
/* 11 */ 868,
|
|
/* 12 */ 905,
|
|
/* 13 */ 940,
|
|
/* 14 */ 975,
|
|
/* 15 */ 1008,
|
|
/* 16 */ 1040,
|
|
/* 17 */ 1071,
|
|
/* 18 */ 1101,
|
|
/* 19 */ 1130,
|
|
/* 20 */ 1159,
|
|
/* 21 */ 1187,
|
|
/* 22 */ 1214,
|
|
/* 23 */ 1241,
|
|
/* 24 */ 1267,
|
|
/* 25 */ 1293,
|
|
/* 26 */ 1318,
|
|
/* 27 */ 1342,
|
|
/* 28 */ 1367,
|
|
/* 29 */ 1390,
|
|
/* 30 */ 1414,
|
|
/* 31 */ 1437,
|
|
/* 32 */ 1459,
|
|
/* 33 */ 1482,
|
|
/* 34 */ 1504,
|
|
/* 35 */ 1525,
|
|
/* 36 */ 1547,
|
|
/* 37 */ 1568,
|
|
/* 38 */ 1588,
|
|
/* 39 */ 1609,
|
|
/* 40 */ 1629,
|
|
/* 41 */ 1649,
|
|
/* 42 */ 1669,
|
|
/* 43 */ 1688,
|
|
/* 44 */ 1708,
|
|
/* 45 */ 1727,
|
|
/* 46 */ 1746,
|
|
/* 47 */ 1764,
|
|
/* 48 */ 1783,
|
|
/* 49 */ 1801,
|
|
/* 50 */ 1819,
|
|
/* 51 */ 1837,
|
|
/* 52 */ 1855,
|
|
/* 53 */ 1872,
|
|
/* 54 */ 1890,
|
|
/* 55 */ 1907,
|
|
/* 56 */ 1924,
|
|
/* 57 */ 1941,
|
|
/* 58 */ 1958,
|
|
/* 59 */ 1975,
|
|
/* 60 */ 1991,
|
|
/* 61 */ 2008,
|
|
/* 62 */ 2024,
|
|
/* 63 */ 2040,
|
|
/* 64 */ 2056,
|
|
/* 65 */ 2072,
|
|
/* 66 */ 2088,
|
|
/* 67 */ 2103,
|
|
/* 68 */ 2119,
|
|
/* 69 */ 2134,
|
|
/* 70 */ 2149,
|
|
/* 71 */ 2165,
|
|
/* 72 */ 2180,
|
|
/* 73 */ 2195,
|
|
/* 74 */ 2210,
|
|
/* 75 */ 2224,
|
|
/* 76 */ 2239,
|
|
/* 77 */ 2254,
|
|
/* 78 */ 2268,
|
|
/* 79 */ 2283,
|
|
/* 80 */ 2297,
|
|
/* 81 */ 2311,
|
|
/* 82 */ 2325,
|
|
/* 83 */ 2339,
|
|
/* 84 */ 2353,
|
|
/* 85 */ 2367,
|
|
/* 86 */ 2381,
|
|
/* 87 */ 2395,
|
|
/* 88 */ 2408,
|
|
/* 89 */ 2422,
|
|
/* 90 */ 2435,
|
|
/* 91 */ 2449,
|
|
/* 92 */ 2462,
|
|
/* 93 */ 2475,
|
|
/* 94 */ 2489,
|
|
/* 95 */ 2502,
|
|
/* 96 */ 2515,
|
|
/* 97 */ 2528,
|
|
/* 98 */ 2541,
|
|
/* 99 */ 2554,
|
|
/* 100 */ 2566,
|
|
/* 101 */ 2579,
|
|
/* 102 */ 2592,
|
|
/* 103 */ 2604,
|
|
/* 104 */ 2617,
|
|
/* 105 */ 2629,
|
|
/* 106 */ 2642,
|
|
/* 107 */ 2654,
|
|
/* 108 */ 2667,
|
|
/* 109 */ 2679,
|
|
/* 110 */ 2691,
|
|
/* 111 */ 2703,
|
|
/* 112 */ 2715,
|
|
/* 113 */ 2727,
|
|
/* 114 */ 2739,
|
|
/* 115 */ 2751,
|
|
/* 116 */ 2763,
|
|
/* 117 */ 2775,
|
|
/* 118 */ 2787,
|
|
/* 119 */ 2798,
|
|
/* 120 */ 2810,
|
|
/* 121 */ 2822,
|
|
/* 122 */ 2833,
|
|
/* 123 */ 2845,
|
|
/* 124 */ 2856,
|
|
/* 125 */ 2868,
|
|
/* 126 */ 2879,
|
|
/* 127 */ 2891,
|
|
/* 128 */ 2902,
|
|
/* 129 */ 2913,
|
|
/* 130 */ 2924,
|
|
/* 131 */ 2936,
|
|
/* 132 */ 2947,
|
|
/* 133 */ 2958,
|
|
/* 134 */ 2969,
|
|
/* 135 */ 2980,
|
|
/* 136 */ 2991,
|
|
/* 137 */ 3002,
|
|
/* 138 */ 3013,
|
|
/* 139 */ 3024,
|
|
/* 140 */ 3034,
|
|
/* 141 */ 3045,
|
|
/* 142 */ 3056,
|
|
/* 143 */ 3067,
|
|
/* 144 */ 3077,
|
|
/* 145 */ 3088,
|
|
/* 146 */ 3099,
|
|
/* 147 */ 3109,
|
|
/* 148 */ 3120,
|
|
/* 149 */ 3130,
|
|
/* 150 */ 3141,
|
|
/* 151 */ 3151,
|
|
/* 152 */ 3161,
|
|
/* 153 */ 3172,
|
|
/* 154 */ 3182,
|
|
/* 155 */ 3192,
|
|
/* 156 */ 3203,
|
|
/* 157 */ 3213,
|
|
/* 158 */ 3223,
|
|
/* 159 */ 3233,
|
|
/* 160 */ 3243,
|
|
/* 161 */ 3253,
|
|
/* 162 */ 3263,
|
|
/* 163 */ 3273,
|
|
/* 164 */ 3283,
|
|
/* 165 */ 3293,
|
|
/* 166 */ 3303,
|
|
/* 167 */ 3313,
|
|
/* 168 */ 3323,
|
|
/* 169 */ 3333,
|
|
/* 170 */ 3343,
|
|
/* 171 */ 3353,
|
|
/* 172 */ 3362,
|
|
/* 173 */ 3372,
|
|
/* 174 */ 3382,
|
|
/* 175 */ 3391,
|
|
/* 176 */ 3401,
|
|
/* 177 */ 3411,
|
|
/* 178 */ 3420,
|
|
/* 179 */ 3430,
|
|
/* 180 */ 3439,
|
|
/* 181 */ 3449,
|
|
/* 182 */ 3458,
|
|
/* 183 */ 3468,
|
|
/* 184 */ 3477,
|
|
/* 185 */ 3487,
|
|
/* 186 */ 3496,
|
|
/* 187 */ 3505,
|
|
/* 188 */ 3515,
|
|
/* 189 */ 3524,
|
|
/* 190 */ 3533,
|
|
/* 191 */ 3543,
|
|
/* 192 */ 3552,
|
|
/* 193 */ 3561,
|
|
/* 194 */ 3570,
|
|
/* 195 */ 3579,
|
|
/* 196 */ 3589,
|
|
/* 197 */ 3598,
|
|
/* 198 */ 3607,
|
|
/* 199 */ 3616,
|
|
/* 200 */ 3625,
|
|
/* 201 */ 3634,
|
|
/* 202 */ 3643,
|
|
/* 203 */ 3652,
|
|
/* 204 */ 3661,
|
|
/* 205 */ 3670,
|
|
/* 206 */ 3679,
|
|
/* 207 */ 3688,
|
|
/* 208 */ 3697,
|
|
/* 209 */ 3705,
|
|
/* 210 */ 3714,
|
|
/* 211 */ 3723,
|
|
/* 212 */ 3732,
|
|
/* 213 */ 3741,
|
|
/* 214 */ 3749,
|
|
/* 215 */ 3758,
|
|
/* 216 */ 3767,
|
|
/* 217 */ 3775,
|
|
/* 218 */ 3784,
|
|
/* 219 */ 3793,
|
|
/* 220 */ 3801,
|
|
/* 221 */ 3810,
|
|
/* 222 */ 3819,
|
|
/* 223 */ 3827,
|
|
/* 224 */ 3836,
|
|
/* 225 */ 3844,
|
|
/* 226 */ 3853,
|
|
/* 227 */ 3861,
|
|
/* 228 */ 3870,
|
|
/* 229 */ 3878,
|
|
/* 230 */ 3887,
|
|
/* 231 */ 3895,
|
|
/* 232 */ 3903,
|
|
/* 233 */ 3912,
|
|
/* 234 */ 3920,
|
|
/* 235 */ 3929,
|
|
/* 236 */ 3937,
|
|
/* 237 */ 3945,
|
|
/* 238 */ 3954,
|
|
/* 239 */ 3962,
|
|
/* 240 */ 3970,
|
|
/* 241 */ 3978,
|
|
/* 242 */ 3987,
|
|
/* 243 */ 3995,
|
|
/* 244 */ 4003,
|
|
/* 245 */ 4011,
|
|
/* 246 */ 4019,
|
|
/* 247 */ 4027,
|
|
/* 248 */ 4036,
|
|
/* 249 */ 4044,
|
|
/* 250 */ 4052,
|
|
/* 251 */ 4060,
|
|
/* 252 */ 4068,
|
|
/* 253 */ 4076,
|
|
/* 254 */ 4084,
|
|
/* 255 */ 4092 };
|
|
|
|
/* initial table look up */
|
|
xi = ((U32) sqtab[a >> 48]) << 16;
|
|
|
|
if (xi == 0)
|
|
return(xi);
|
|
|
|
/* iterate */
|
|
/* exit iteration when xi, xj equal or differ by 1 */
|
|
for (;;) {
|
|
xj = (((U32)(a / xi)) + xi) >> 1;
|
|
|
|
if ((xj == xi) || (abs(xj - xi) == 1)) {
|
|
break;
|
|
}
|
|
xi = xj;
|
|
}
|
|
|
|
return(xj);
|
|
|
|
} /* end function square_root_fraction */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Divide 128 bit integer by 64 bit integer */
|
|
/* The result is returned as 64 bit integer */
|
|
/* */
|
|
/* Input: */
|
|
/* msa most significant 64 bit of dividend */
|
|
/* lsa least significant 64 bit of dividend */
|
|
/* div divisor */
|
|
/* Value: */
|
|
/* quotient */
|
|
/*-------------------------------------------------------------------*/
|
|
static U64 div_U128( U64 msa, U64 lsa, U64 div )
|
|
{
|
|
U64 q;
|
|
int i;
|
|
|
|
/* the first binary digit */
|
|
msa -= div;
|
|
shift_left_U128(msa, lsa);
|
|
|
|
if (((S64)msa) >= 0) {
|
|
q = 1;
|
|
msa -= div;
|
|
} else {
|
|
q = 0;
|
|
msa += div;
|
|
}
|
|
|
|
/* the middle binary digits */
|
|
i = 63;
|
|
while (i--) {
|
|
shift_left_U128(msa, lsa);
|
|
|
|
q <<= 1;
|
|
if (((S64)msa) >= 0) {
|
|
q |= 1;
|
|
msa -= div;
|
|
} else {
|
|
msa += div;
|
|
}
|
|
}
|
|
|
|
/* the last binary digit */
|
|
q <<= 1;
|
|
if (((S64)msa) >= 0) {
|
|
q |= 1;
|
|
}
|
|
|
|
return(q);
|
|
|
|
} /* end function div_U128 */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Square root short float */
|
|
/* */
|
|
/* Input: */
|
|
/* sq_fl Result short float */
|
|
/* fl Input short float */
|
|
/* regs CPU register context */
|
|
/*-------------------------------------------------------------------*/
|
|
static void sq_sf( SHORT_FLOAT *sq_fl, SHORT_FLOAT *fl, REGS *regs )
|
|
{
|
|
U64 a;
|
|
U32 x;
|
|
|
|
if (fl->short_fract) {
|
|
if (fl->sign) {
|
|
/* less than zero */
|
|
|
|
ARCH_DEP(program_interrupt) (regs, PGM_SQUARE_ROOT_EXCEPTION);
|
|
} else {
|
|
/* normalize operand */
|
|
normal_sf(fl);
|
|
|
|
if (fl->expo & 1) {
|
|
/* odd */
|
|
|
|
/* compute characteristic */
|
|
sq_fl->expo = (fl->expo + 65) >> 1;
|
|
|
|
/* with guard digit */
|
|
a = (U64) fl->short_fract << 28;
|
|
} else {
|
|
/* even */
|
|
|
|
/* compute characteristic */
|
|
sq_fl->expo = (fl->expo + 64) >> 1;
|
|
|
|
/* without guard digit */
|
|
a = (U64) fl->short_fract << 32;
|
|
}
|
|
|
|
/* square root of fraction */
|
|
/* common subroutine of all square root */
|
|
x = square_root_fraction(a);
|
|
|
|
/* round with guard digit */
|
|
sq_fl->short_fract = (x + 8) >> 4;
|
|
}
|
|
} else {
|
|
/* true zero */
|
|
sq_fl->short_fract = 0;
|
|
sq_fl->expo = 0;
|
|
}
|
|
/* all results positive */
|
|
sq_fl->sign = POS;
|
|
|
|
} /* end function sq_sf */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Square root long float */
|
|
/* */
|
|
/* Input: */
|
|
/* sq_fl Result long float */
|
|
/* fl Input long float */
|
|
/* regs CPU register context */
|
|
/*-------------------------------------------------------------------*/
|
|
static void sq_lf( LONG_FLOAT *sq_fl, LONG_FLOAT *fl, REGS *regs )
|
|
{
|
|
U64 msa, lsa;
|
|
U64 xi;
|
|
U64 xj;
|
|
|
|
if (fl->long_fract) {
|
|
if (fl->sign) {
|
|
/* less than zero */
|
|
|
|
ARCH_DEP(program_interrupt) (regs, PGM_SQUARE_ROOT_EXCEPTION);
|
|
} else {
|
|
/* normalize operand */
|
|
normal_lf(fl);
|
|
|
|
if (fl->expo & 1) {
|
|
/* odd */
|
|
|
|
/* compute characteristic */
|
|
sq_fl->expo = (fl->expo + 65) >> 1;
|
|
|
|
/* with guard digit */
|
|
msa = fl->long_fract >> 4;
|
|
lsa = fl->long_fract << 60;
|
|
} else {
|
|
/* even */
|
|
|
|
/* compute characteristic */
|
|
sq_fl->expo = (fl->expo + 64) >> 1;
|
|
|
|
/* without guard digit */
|
|
msa = fl->long_fract;
|
|
lsa = 0;
|
|
}
|
|
|
|
/* square root of fraction low precision */
|
|
/* common subroutine of all square root */
|
|
xi = ((U64) (square_root_fraction(msa & 0xFFFFFFFFFFFFFFFEULL)) << 32)
|
|
| 0x80000000UL;
|
|
|
|
/* continue iteration for high precision */
|
|
for (;;) {
|
|
xj = (div_U128(msa, lsa, xi) + xi) >> 1;
|
|
|
|
if (xj == xi) {
|
|
break;
|
|
}
|
|
xi = xj;
|
|
}
|
|
|
|
/* round with guard digit */
|
|
sq_fl->long_fract = (xi + 8) >> 4;
|
|
}
|
|
} else {
|
|
/* true zero */
|
|
sq_fl->long_fract = 0;
|
|
sq_fl->expo = 0;
|
|
}
|
|
/* all results positive */
|
|
sq_fl->sign = POS;
|
|
|
|
} /* end function sq_lf */
|
|
#endif /* FEATURE_SQUARE_ROOT */
|
|
|
|
|
|
#if defined (FEATURE_HFP_EXTENSIONS)
|
|
/*-------------------------------------------------------------------*/
|
|
/* Divide 256 bit integer by 128 bit integer */
|
|
/* The result is returned as 128 bit integer */
|
|
/* */
|
|
/* Input: */
|
|
/* mmsa most significant 64 bit of dividend */
|
|
/* msa more significant 64 bit of dividend */
|
|
/* lsa less significant 64 bit of dividend */
|
|
/* llsa least significant 64 bit of dividend */
|
|
/* msd most significant 64 bit of divisor */
|
|
/* lsd least significant 64 bit of divisor */
|
|
/* msq most significant 64 bit of quotient */
|
|
/* lsq least significant 64 bit of quotient */
|
|
/*-------------------------------------------------------------------*/
|
|
static void div_U256( U64 mmsa, U64 msa, U64 lsa, U64 llsa, U64 msd,
|
|
U64 lsd, U64 *msq, U64 *lsq )
|
|
{
|
|
int i;
|
|
|
|
/* the first binary digit */
|
|
sub_U128(mmsa, msa, msd, lsd);
|
|
shift_left_U256(mmsa, msa, lsa, llsa);
|
|
|
|
*msq = 0;
|
|
if (((S64)mmsa) >= 0) {
|
|
*lsq = 1;
|
|
sub_U128(mmsa, msa, msd, lsd);
|
|
} else {
|
|
*lsq = 0;
|
|
add_U128(mmsa, msa, msd, lsd);
|
|
}
|
|
|
|
/* the middle binary digits */
|
|
i = 127;
|
|
while (i--) {
|
|
shift_left_U256(mmsa, msa, lsa, llsa);
|
|
|
|
shift_left_U128(*msq, *lsq);
|
|
if (((S64)mmsa) >= 0) {
|
|
*lsq |= 1;
|
|
sub_U128(mmsa, msa, msd, lsd);
|
|
} else {
|
|
add_U128(mmsa, msa, msd, lsd);
|
|
}
|
|
}
|
|
|
|
/* the last binary digit */
|
|
shift_left_U128(*msq, *lsq);
|
|
if (((S64)mmsa) >= 0) {
|
|
*lsq |= 1;
|
|
}
|
|
|
|
} /* end function div_U256 */
|
|
#endif /* FEATURE_HFP_EXTENSIONS */
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Extern functions */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 20 LPDR - Load Positive Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_positive_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
/* Copy register contents, clear the sign bit */
|
|
regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF;
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = ((regs->fpr[i1] & 0x00FFFFFF)
|
|
|| regs->fpr[i1+1]) ? 2 : 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 21 LNDR - Load Negative Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_negative_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
/* Copy register contents, set the sign bit */
|
|
regs->fpr[i1] = regs->fpr[i2]
|
|
| 0x80000000;
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = ((regs->fpr[i1] & 0x00FFFFFF)
|
|
|| regs->fpr[i1+1]) ? 1 : 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 22 LTDR - Load and Test Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_and_test_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
/* Copy register contents */
|
|
regs->fpr[i1] = regs->fpr[i2];
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Set condition code */
|
|
if ((regs->fpr[i1] & 0x00FFFFFF)
|
|
|| regs->fpr[i1+1]) {
|
|
regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 23 LCDR - Load Complement Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_complement_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
/* Copy register contents, invert sign bit */
|
|
regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000;
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Set condition code */
|
|
if ((regs->fpr[i1] & 0x00FFFFFF)
|
|
|| regs->fpr[i1+1]) {
|
|
regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 24 HDR - Halve Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(halve_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
LONG_FLOAT fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Get register content */
|
|
get_lf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Halve the value */
|
|
if (fl.long_fract & 0x00E0000000000000ULL) {
|
|
fl.long_fract >>= 1;
|
|
pgm_check = 0;
|
|
} else {
|
|
fl.long_fract <<= 3;
|
|
(fl.expo)--;
|
|
normal_lf(&fl);
|
|
pgm_check = underflow_lf(&fl, regs);
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + FPR2I(r1));
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 25 LDXR - Load Rounded Floating Point Long Register [RR] */
|
|
/* Older mnemonic of this instruction is LRDR */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(round_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
LONG_FLOAT fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
|
|
HFPREG_CHECK(r1, regs);
|
|
HFPODD_CHECK(r2, regs);
|
|
|
|
/* Get register content */
|
|
get_lf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Rounding */
|
|
fl.long_fract += ((regs->fpr[FPR2I(r2 + 2)] >> 23) & 1);
|
|
|
|
/* Handle overflow */
|
|
if (fl.long_fract & 0x0F00000000000000ULL) {
|
|
fl.long_fract >>= 4;
|
|
(fl.expo)++;
|
|
pgm_check = overflow_lf(&fl, regs);
|
|
} else {
|
|
pgm_check = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + FPR2I(r1));
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 26 MXR - Multiply Floating Point Extended Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
EXTENDED_FLOAT fl;
|
|
EXTENDED_FLOAT mul_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_ef(&fl, regs->fpr + i1);
|
|
get_ef(&mul_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* multiply extended */
|
|
pgm_check = mul_ef(&fl, &mul_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_ef(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 27 MXDR - Multiply Floating Point Long to Extended Reg. [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_long_to_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT mul_fl;
|
|
EXTENDED_FLOAT result_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
|
|
HFPODD_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
HFPREG_CHECK(r2, regs);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
get_lf(&mul_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* multiply long to extended */
|
|
pgm_check = mul_lf_to_ef(&fl, &mul_fl, &result_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_ef(&result_fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 28 LDR - Load Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
/* Copy register contents */
|
|
regs->fpr[i1] = regs->fpr[i2];
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 29 CDR - Compare Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(compare_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT cmp_fl;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + FPR2I(r1));
|
|
get_lf(&cmp_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Compare long */
|
|
cmp_lf(&fl, &cmp_fl, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 2A ADR - Add Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
get_lf(&add_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Add long with normalization */
|
|
pgm_check = add_lf(&fl, &add_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 2B SDR - Subtract Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
get_lf(&sub_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add long with normalization */
|
|
pgm_check = add_lf(&fl, &sub_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 2C MDR - Multiply Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT mul_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
get_lf(&mul_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* multiply long */
|
|
pgm_check = mul_lf(&fl, &mul_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 2D DDR - Divide Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(divide_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT div_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
get_lf(&div_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* divide long */
|
|
pgm_check = div_lf(&fl, &div_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 2E AWR - Add Unnormalized Floating Point Long Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_unnormal_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
get_lf(&add_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Add long without normalization */
|
|
pgm_check = add_lf(&fl, &add_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 2F SWR - Subtract Unnormalized Floating Point Long Reg. [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_unnormal_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
get_lf(&sub_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add long without normalization */
|
|
pgm_check = add_lf(&fl, &sub_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 30 LPER - Load Positive Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_positive_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Copy register contents, clear sign bit */
|
|
regs->fpr[i1] = regs->fpr[FPR2I(r2)] & 0x7FFFFFFF;
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = (regs->fpr[i1] & 0x00FFFFFF) ? 2 : 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 31 LNER - Load Negative Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_negative_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Copy register contents, set sign bit */
|
|
regs->fpr[i1] = regs->fpr[FPR2I(r2)]
|
|
| 0x80000000;
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = (regs->fpr[i1] & 0x00FFFFFF) ? 1 : 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 32 LTER - Load and Test Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_and_test_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Copy register contents */
|
|
regs->fpr[i1] = regs->fpr[FPR2I(r2)];
|
|
|
|
/* Set condition code */
|
|
if (regs->fpr[i1] & 0x00FFFFFF) {
|
|
regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 33 LCER - Load Complement Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_complement_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Copy register contents, invert sign bit */
|
|
regs->fpr[i1] = regs->fpr[FPR2I(r2)] ^ 0x80000000;
|
|
|
|
/* Set condition code */
|
|
if (regs->fpr[i1] & 0x00FFFFFF) {
|
|
regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 34 HER - Halve Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(halve_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
SHORT_FLOAT fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Get register content */
|
|
get_sf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Halve the value */
|
|
if (fl.short_fract & 0x00E00000) {
|
|
fl.short_fract >>= 1;
|
|
pgm_check = 0;
|
|
} else {
|
|
fl.short_fract <<= 3;
|
|
(fl.expo)--;
|
|
normal_sf(&fl);
|
|
pgm_check = underflow_sf(&fl, regs);
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + FPR2I(r1));
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 35 LEDR - Load Rounded Floating Point Short Register [RR] */
|
|
/* Older mnemonic of this instruction is LRER */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(round_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
LONG_FLOAT from_fl;
|
|
SHORT_FLOAT to_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Get register content */
|
|
get_lf(&from_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Rounding */
|
|
to_fl.short_fract = (from_fl.long_fract + 0x0000000080000000ULL) >> 32;
|
|
to_fl.sign = from_fl.sign;
|
|
to_fl.expo = from_fl.expo;
|
|
|
|
/* Handle overflow */
|
|
if (to_fl.short_fract & 0x0F000000) {
|
|
to_fl.short_fract >>= 4;
|
|
(to_fl.expo)++;
|
|
pgm_check = overflow_sf(&to_fl, regs);
|
|
} else {
|
|
pgm_check = 0;
|
|
}
|
|
|
|
/* To register */
|
|
store_sf(&to_fl, regs->fpr + FPR2I(r1));
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 36 AXR - Add Floating Point Extended Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
EXTENDED_FLOAT fl;
|
|
EXTENDED_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_ef(&fl, regs->fpr + i1);
|
|
get_ef(&add_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Add extended */
|
|
pgm_check = add_ef(&fl, &add_fl, regs->fpr + i1, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 37 SXR - Subtract Floating Point Extended Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
EXTENDED_FLOAT fl;
|
|
EXTENDED_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_ef(&fl, regs->fpr + i1);
|
|
get_ef(&sub_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add extended */
|
|
pgm_check = add_ef(&fl, &sub_fl, regs->fpr + i1, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 38 LER - Load Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Copy register content */
|
|
regs->fpr[FPR2I(r1)] = regs->fpr[FPR2I(r2)];
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 39 CER - Compare Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(compare_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT cmp_fl;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + FPR2I(r1));
|
|
get_sf(&cmp_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Compare short */
|
|
cmp_sf(&fl, &cmp_fl, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 3A AER - Add Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
get_sf(&add_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Add short with normalization */
|
|
pgm_check = add_sf(&fl, &add_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 3B SER - Subtract Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
get_sf(&sub_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Subtract short with normalization */
|
|
pgm_check = add_sf(&fl, &sub_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 3C MER - Multiply Short to Long Floating Point Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_short_to_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT mul_fl;
|
|
LONG_FLOAT result_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
get_sf(&mul_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* multiply short to long */
|
|
pgm_check = mul_sf_to_lf(&fl, &mul_fl, &result_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&result_fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 3D DER - Divide Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(divide_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT div_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
get_sf(&div_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* divide short */
|
|
pgm_check = div_sf(&fl, &div_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 3E AUR - Add Unnormalized Floating Point Short Register [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_unnormal_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
get_sf(&add_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Add short without normalization */
|
|
pgm_check = add_sf(&fl, &add_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 3F SUR - Subtract Unnormalized Floating Point Short Reg. [RR] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_unnormal_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RR(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
get_sf(&sub_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add short without normalization */
|
|
pgm_check = add_sf(&fl, &sub_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 60 STD - Store Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(store_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
U64 dreg; /* Double word workarea */
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Store register contents at operand address */
|
|
dreg = ((U64)regs->fpr[i1] << 32)
|
|
| regs->fpr[i1+1];
|
|
ARCH_DEP(vstore8) (dreg, effective_addr2, b2, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 67 MXD - Multiply Floating Point Long to Extended [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_long_to_ext)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT mul_fl;
|
|
EXTENDED_FLOAT result_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPODD_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
vfetch_lf(&mul_fl, effective_addr2, b2, regs );
|
|
|
|
/* multiply long to extended */
|
|
pgm_check = mul_lf_to_ef(&fl, &mul_fl, &result_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_ef(&result_fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 68 LD - Load Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
U64 dreg; /* Double word workarea */
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Fetch value from operand address */
|
|
dreg = ARCH_DEP(vfetch8) (effective_addr2, b2, regs);
|
|
|
|
/* Update register contents */
|
|
regs->fpr[i1] = dreg >> 32;
|
|
regs->fpr[i1+1] = dreg;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 69 CD - Compare Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(compare_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT cmp_fl;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + FPR2I(r1));
|
|
vfetch_lf(&cmp_fl, effective_addr2, b2, regs );
|
|
|
|
/* Compare long */
|
|
cmp_lf(&fl, &cmp_fl, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 6A AD - Add Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
vfetch_lf(&add_fl, effective_addr2, b2, regs );
|
|
|
|
/* Add long with normalization */
|
|
pgm_check = add_lf(&fl, &add_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 6B SD - Subtract Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
vfetch_lf(&sub_fl, effective_addr2, b2, regs );
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add long with normalization */
|
|
pgm_check = add_lf(&fl, &sub_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 6C MD - Multiply Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT mul_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
vfetch_lf(&mul_fl, effective_addr2, b2, regs );
|
|
|
|
/* multiply long */
|
|
pgm_check = mul_lf(&fl, &mul_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 6D DD - Divide Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(divide_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT div_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
vfetch_lf(&div_fl, effective_addr2, b2, regs );
|
|
|
|
/* divide long */
|
|
pgm_check = div_lf(&fl, &div_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 6E AW - Add Unnormalized Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_unnormal_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
vfetch_lf(&add_fl, effective_addr2, b2, regs );
|
|
|
|
/* Add long without normalization */
|
|
pgm_check = add_lf(&fl, &add_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 6F SW - Subtract Unnormalized Floating Point Long [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_unnormal_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT fl;
|
|
LONG_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_lf(&fl, regs->fpr + i1);
|
|
vfetch_lf(&sub_fl, effective_addr2, b2, regs );
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add long without normalization */
|
|
pgm_check = add_lf(&fl, &sub_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.long_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 70 STE - Store Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(store_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Store register contents at operand address */
|
|
ARCH_DEP(vstore4) (regs->fpr[FPR2I(r1)], effective_addr2, b2, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 78 LE - Load Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Update first 32 bits of register from operand address */
|
|
regs->fpr[FPR2I(r1)] = ARCH_DEP(vfetch4) (effective_addr2, b2, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 79 CE - Compare Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(compare_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT cmp_fl;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + FPR2I(r1));
|
|
vfetch_sf(&cmp_fl, effective_addr2, b2, regs );
|
|
|
|
/* Compare long */
|
|
cmp_sf(&fl, &cmp_fl, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 7A AE - Add Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
vfetch_sf(&add_fl, effective_addr2, b2, regs );
|
|
|
|
/* Add short with normalization */
|
|
pgm_check = add_sf(&fl, &add_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 7B SE - Subtract Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
vfetch_sf(&sub_fl, effective_addr2, b2, regs );
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add short with normalization */
|
|
pgm_check = add_sf(&fl, &sub_fl, NORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 7C MDE - Multiply Floating Point Short to Long [RX] */
|
|
/* Older mnemonic of this instruction ME */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_short_to_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT mul_fl;
|
|
LONG_FLOAT result_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
vfetch_sf(&mul_fl, effective_addr2, b2, regs );
|
|
|
|
/* multiply short to long */
|
|
pgm_check = mul_sf_to_lf(&fl, &mul_fl, &result_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&result_fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 7D DE - Divide Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(divide_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT div_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
vfetch_sf(&div_fl, effective_addr2, b2, regs );
|
|
|
|
/* divide short */
|
|
pgm_check = div_sf(&fl, &div_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 7E AU - Add Unnormalized Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(add_unnormal_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT add_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
vfetch_sf(&add_fl, effective_addr2, b2, regs );
|
|
|
|
/* Add short without normalization */
|
|
pgm_check = add_sf(&fl, &add_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 7F SU - Subtract Unnormalized Floating Point Short [RX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(subtract_unnormal_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT sub_fl;
|
|
int pgm_check;
|
|
|
|
RX(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
vfetch_sf(&sub_fl, effective_addr2, b2, regs );
|
|
|
|
/* Invert the sign of 2nd operand */
|
|
sub_fl.sign = ! (sub_fl.sign);
|
|
|
|
/* Add short without normalization */
|
|
pgm_check = add_sf(&fl, &sub_fl, UNNORMAL, regs);
|
|
|
|
/* Set condition code */
|
|
if (fl.short_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B22D DXR - Divide Floating Point Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(divide_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
EXTENDED_FLOAT fl;
|
|
EXTENDED_FLOAT div_fl;
|
|
int pgm_check;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_ef(&fl, regs->fpr + i1);
|
|
get_ef(&div_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* divide extended */
|
|
pgm_check = div_ef(&fl, &div_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_ef(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
#if defined (FEATURE_SQUARE_ROOT)
|
|
/*-------------------------------------------------------------------*/
|
|
/* B244 SQDR - Square Root Floating Point Long Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(squareroot_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
LONG_FLOAT sq_fl;
|
|
LONG_FLOAT fl;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Get the 2nd operand */
|
|
get_lf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* square root long */
|
|
sq_lf(&sq_fl, &fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&sq_fl, regs->fpr + FPR2I(r1));
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B245 SQER - Square Root Floating Point Short Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(squareroot_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
SHORT_FLOAT sq_fl;
|
|
SHORT_FLOAT fl;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
|
|
/* Get the 2nd operand */
|
|
get_sf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* square root short */
|
|
sq_sf(&sq_fl, &fl, regs);
|
|
|
|
/* Back to register */
|
|
store_sf(&sq_fl, regs->fpr + FPR2I(r1));
|
|
}
|
|
#endif /* FEATURE_SQUARE_ROOT */
|
|
|
|
|
|
#if defined (FEATURE_HFP_EXTENSIONS)
|
|
/*-------------------------------------------------------------------*/
|
|
/* B324 LDER - Load Length. Float. Short to Long Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(loadlength_float_short_to_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Copy register content */
|
|
regs->fpr[i1] = regs->fpr[FPR2I(r2)];
|
|
|
|
/* Clear register */
|
|
regs->fpr[i1+1] = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B325 LXDR - Load Length. Float. Long to Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(loadlength_float_long_to_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
|
|
HFPODD_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
HFPREG_CHECK(r2, regs);
|
|
i2 = FPR2I(r2);
|
|
|
|
if ((regs->fpr[i2] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+1]) {
|
|
/* Copy register contents */
|
|
regs->fpr[i1] = regs->fpr[i2];
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = (regs->fpr[i2] & 0x80000000)
|
|
| ((regs->fpr[i2] - (14 << 24)) & 0x7F000000);
|
|
} else {
|
|
/* true zero with sign */
|
|
regs->fpr[i1] = regs->fpr[i2] & 0x80000000;
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX] = regs->fpr[i1];
|
|
}
|
|
/* Clear register */
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B326 LXER - Load Length. Float. Short to Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(loadlength_float_short_to_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
|
|
HFPODD_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
HFPREG_CHECK(r2, regs);
|
|
i2 = FPR2I(r2);
|
|
|
|
if (regs->fpr[i2] & 0x00FFFFFF) {
|
|
/* Copy register content */
|
|
regs->fpr[i1] = regs->fpr[i2];
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = (regs->fpr[i2] & 0x80000000)
|
|
| ((regs->fpr[i2] - (14 << 24)) & 0x7F000000);
|
|
} else {
|
|
/* true zero with sign */
|
|
regs->fpr[i1] = regs->fpr[i2] & 0x80000000;
|
|
regs->fpr[i1+FPREX] = regs->fpr[i1];
|
|
}
|
|
/* Clear register */
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B336 SQXR - Square Root Floating Point Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(squareroot_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
EXTENDED_FLOAT sq_fl;
|
|
EXTENDED_FLOAT fl;
|
|
U64 mmsa, msa, lsa, llsa;
|
|
U64 xi;
|
|
U64 xj;
|
|
U64 msi, lsi;
|
|
U64 msj, lsj;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
|
|
/* Get the 2nd operand */
|
|
get_ef(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
if ((fl.ms_fract)
|
|
|| (fl.ls_fract)) {
|
|
if (fl.sign) {
|
|
/* less than zero */
|
|
|
|
ARCH_DEP(program_interrupt) (regs, PGM_SQUARE_ROOT_EXCEPTION);
|
|
} else {
|
|
/* normalize operand */
|
|
normal_ef(&fl);
|
|
|
|
if (fl.expo & 1) {
|
|
/* odd */
|
|
|
|
/* compute characteristic */
|
|
sq_fl.expo = (fl.expo + 65) >> 1;
|
|
|
|
/* with guard digit */
|
|
mmsa = fl.ms_fract >> 4;
|
|
msa = (fl.ms_fract << 60)
|
|
| (fl.ls_fract >> 4);
|
|
lsa = fl.ls_fract << 60;
|
|
llsa = 0;
|
|
} else {
|
|
/* even */
|
|
|
|
/* compute characteristic */
|
|
sq_fl.expo = (fl.expo + 64) >> 1;
|
|
|
|
/* without guard digit */
|
|
mmsa = fl.ms_fract;
|
|
msa = fl.ls_fract;
|
|
lsa = 0;
|
|
llsa = 0;
|
|
}
|
|
|
|
/* square root of fraction low precision */
|
|
/* common subroutine of all square root */
|
|
xi = ((U64) (square_root_fraction(mmsa & 0xFFFFFFFFFFFFFFFEULL)) << 32)
|
|
| 0x80000000UL;
|
|
|
|
/* continue iteration for high precision */
|
|
/* done iteration when xi, xj equal or differ by 1 */
|
|
for (;;) {
|
|
xj = (div_U128(mmsa, msa, xi) + xi) >> 1;
|
|
|
|
if ((xj == xi) || (abs(xj - xi) == 1)) {
|
|
break;
|
|
}
|
|
xi = xj;
|
|
}
|
|
|
|
msi = xi;
|
|
lsi = 0x8000000000000000ULL;
|
|
|
|
/* continue iteration for extended precision */
|
|
for (;;) {
|
|
div_U256(mmsa, msa, lsa, llsa, msi, lsi, &msj, &lsj);
|
|
add_U128(msj, lsj, msi, lsi);
|
|
shift_right_U128(msj, lsj);
|
|
|
|
if ((msj == msi)
|
|
&& (lsj == lsi)) {
|
|
break;
|
|
}
|
|
msi = msj;
|
|
lsi = lsj;
|
|
}
|
|
/* round with guard digit */
|
|
add_U128(msi, lsi, 0, 0x80);
|
|
|
|
sq_fl.ls_fract = (lsi >> 8)
|
|
| (msi << 56);
|
|
sq_fl.ms_fract = msi >> 8;
|
|
}
|
|
} else {
|
|
/* true zero */
|
|
sq_fl.ms_fract = 0;
|
|
sq_fl.ls_fract = 0;
|
|
sq_fl.expo = 0;
|
|
}
|
|
/* all results positive */
|
|
sq_fl.sign = POS;
|
|
|
|
/* Back to register */
|
|
store_ef(&sq_fl, regs->fpr + FPR2I(r1));
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B337 MEER - Multiply Floating Point Short Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT mul_fl;
|
|
int pgm_check;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
get_sf(&mul_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* multiply short to long */
|
|
pgm_check = mul_sf(&fl, &mul_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B360 LPXR - Load Positive Floating Point Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_positive_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
if ((regs->fpr[i2] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+1]
|
|
|| (regs->fpr[i2+FPREX] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+FPREX+1]) {
|
|
/* Copy register contents, clear the sign bit */
|
|
regs->fpr[i1] = regs->fpr[i2] & 0x7FFFFFFF;
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = (((regs->fpr[i2] - (14 << 24)) & 0x7F000000))
|
|
| (regs->fpr[i2+FPREX] & 0x00FFFFFF);
|
|
regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1];
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = 2;
|
|
} else {
|
|
/* true zero */
|
|
regs->fpr[i1] = 0;
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B361 LNXR - Load Negative Floating Point Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_negative_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
if ((regs->fpr[i2] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+1]
|
|
|| (regs->fpr[i2+FPREX] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+FPREX+1]) {
|
|
/* Copy register contents, set the sign bit */
|
|
regs->fpr[i1] = 0x80000000
|
|
| regs->fpr[i2];
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = 0x80000000
|
|
| (((regs->fpr[i2] - (14 << 24)) & 0x7F000000))
|
|
| (regs->fpr[i2+FPREX] & 0x00FFFFFF);
|
|
regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1];
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = 1;
|
|
} else {
|
|
/* true zero with sign */
|
|
regs->fpr[i1] = 0x80000000;
|
|
regs->fpr[i1+FPREX] = 0x80000000;
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B362 LTXR - Load and Test Floating Point Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_and_test_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
if ((regs->fpr[i2] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+1]
|
|
|| (regs->fpr[i2+FPREX] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+FPREX+1]) {
|
|
/* Copy register contents */
|
|
regs->fpr[i1] = regs->fpr[i2];
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = (regs->fpr[i2] & 0x80000000)
|
|
| ((regs->fpr[i2] - (14 << 24)) & 0x7F000000)
|
|
| (regs->fpr[i2+FPREX] & 0x00FFFFFF);
|
|
regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1];
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = (regs->fpr[i2] & 0x80000000) ? 1 : 2;
|
|
} else {
|
|
/* true zero with sign */
|
|
regs->fpr[i1] = regs->fpr[i2] & 0x80000000;
|
|
regs->fpr[i1+FPREX] = regs->fpr[i1];
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B363 LCXR - Load Complement Float. Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_complement_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1, i2;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
i2 = FPR2I(r2);
|
|
|
|
if ((regs->fpr[i2] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+1]
|
|
|| (regs->fpr[i2+FPREX] & 0x00FFFFFF)
|
|
|| regs->fpr[i2+FPREX+1]) {
|
|
/* Copy register contents, invert sign bit */
|
|
regs->fpr[i1] = regs->fpr[i2] ^ 0x80000000;
|
|
regs->fpr[i1+1] = regs->fpr[i2+1];
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = (regs->fpr[i1] & 0x80000000)
|
|
|(((regs->fpr[i1] & 0x7F000000) - 0x0E000000) & 0x7F000000)
|
|
| (regs->fpr[i2+FPREX] & 0x00FFFFFF);
|
|
regs->fpr[i1+FPREX+1] = regs->fpr[i2+FPREX+1];
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = (regs->fpr[i1] & 0x80000000) ? 1 : 2;
|
|
} else {
|
|
/* true zero with sign */
|
|
regs->fpr[i1] = (regs->fpr[i2] ^ 0x80000000) & 0x80000000;
|
|
regs->fpr[i1+FPREX] = regs->fpr[i1];
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
|
|
/* Set condition code */
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B366 LEXR - Load Rounded Float. Extended to Short Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(round_float_ext_to_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
EXTENDED_FLOAT from_fl;
|
|
SHORT_FLOAT to_fl;
|
|
int pgm_check;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
|
|
HFPREG_CHECK(r1, regs);
|
|
HFPODD_CHECK(r2, regs);
|
|
|
|
/* Get register content */
|
|
get_ef(&from_fl, regs->fpr + FPR2I(r2));
|
|
|
|
/* Rounding (herc ms fract is 12 digits) */
|
|
to_fl.short_fract = (from_fl.ms_fract + 0x0000000000800000ULL) >> 24;
|
|
to_fl.sign = from_fl.sign;
|
|
to_fl.expo = from_fl.expo;
|
|
|
|
/* Handle overflow */
|
|
if (to_fl.short_fract & 0x0F000000) {
|
|
to_fl.short_fract >>= 4;
|
|
(to_fl.expo)++;
|
|
pgm_check = overflow_sf(&to_fl, regs);
|
|
} else {
|
|
pgm_check = 0;
|
|
}
|
|
|
|
/* To register */
|
|
store_sf(&to_fl, regs->fpr + FPR2I(r1));
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B367 FIXR - Load FP Integer Float. Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_fp_int_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
EXTENDED_FLOAT fl;
|
|
BYTE shift;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get register content */
|
|
get_ef(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
if (fl.expo > 64) {
|
|
if (fl.expo < 92) {
|
|
/* Denormalize */
|
|
shift = (92 - fl.expo) * 4;
|
|
if (shift > 64) {
|
|
fl.ls_fract = fl.ms_fract >> (shift - 64);
|
|
fl.ms_fract = 0;
|
|
} else if (shift == 64) {
|
|
fl.ls_fract = fl.ms_fract;
|
|
fl.ms_fract = 0;
|
|
} else {
|
|
fl.ls_fract = (fl.ls_fract >> shift)
|
|
| (fl.ms_fract << (64 - shift));
|
|
fl.ms_fract >>= shift;
|
|
}
|
|
fl.expo = 92;
|
|
}
|
|
|
|
/* Normalize result */
|
|
normal_ef(&fl);
|
|
|
|
/* To register */
|
|
store_ef(&fl, regs->fpr + i1);
|
|
} else {
|
|
/* True zero */
|
|
regs->fpr[i1] = 0;
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B369 CXR - Compare Floating Point Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(compare_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
EXTENDED_FLOAT fl;
|
|
EXTENDED_FLOAT cmp_fl;
|
|
BYTE shift;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD2_CHECK(r1, r2, regs);
|
|
|
|
/* Get the operands */
|
|
get_ef(&fl, regs->fpr + FPR2I(r1));
|
|
get_ef(&cmp_fl, regs->fpr + FPR2I(r2));;
|
|
|
|
if (cmp_fl.ms_fract
|
|
|| cmp_fl.ls_fract
|
|
|| cmp_fl.expo) { /* cmp_fl not 0 */
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract
|
|
|| fl.expo) { /* fl not 0 */
|
|
/* both not 0 */
|
|
|
|
if (fl.expo == cmp_fl.expo) {
|
|
/* expo equal */
|
|
|
|
/* both guard digits */
|
|
fl.ms_fract = (fl.ms_fract << 4)
|
|
| (fl.ls_fract >> 60);
|
|
fl.ls_fract <<= 4;
|
|
cmp_fl.ms_fract = (cmp_fl.ms_fract << 4)
|
|
| (cmp_fl.ls_fract >> 60);
|
|
cmp_fl.ls_fract <<= 4;
|
|
} else {
|
|
/* expo not equal, denormalize */
|
|
|
|
if (fl.expo < cmp_fl.expo) {
|
|
/* shift minus guard digit */
|
|
shift = cmp_fl.expo - fl.expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 28) {
|
|
/* Set condition code */
|
|
if (cmp_fl.ms_fract
|
|
|| cmp_fl.ls_fract) {
|
|
regs->psw.cc = cmp_fl.sign ? 2 : 1;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
} else if (shift >= 16) {
|
|
fl.ls_fract = fl.ms_fract;
|
|
if (shift > 16) {
|
|
fl.ls_fract >>= (shift - 16) * 4;
|
|
}
|
|
fl.ms_fract = 0;
|
|
} else {
|
|
shift *= 4;
|
|
fl.ls_fract = fl.ms_fract << (64 - shift)
|
|
| fl.ls_fract >> shift;
|
|
fl.ms_fract >>= shift;
|
|
}
|
|
if ((fl.ms_fract == 0)
|
|
&& (fl.ls_fract == 0)) {
|
|
/* Set condition code */
|
|
if (cmp_fl.ms_fract
|
|
|| cmp_fl.ls_fract) {
|
|
regs->psw.cc = cmp_fl.sign ? 2 : 1;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
/* guard digit */
|
|
cmp_fl.ms_fract = (cmp_fl.ms_fract << 4)
|
|
| (cmp_fl.ls_fract >> 60);
|
|
cmp_fl.ls_fract <<= 4;
|
|
} else {
|
|
/* shift minus guard digit */
|
|
shift = fl.expo - cmp_fl.expo - 1;
|
|
|
|
if (shift) {
|
|
if (shift >= 28) {
|
|
/* Set condition code */
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
} else if (shift >= 16) {
|
|
cmp_fl.ls_fract = cmp_fl.ms_fract;
|
|
if (shift > 16) {
|
|
cmp_fl.ls_fract >>= (shift - 16) * 4;
|
|
}
|
|
cmp_fl.ms_fract = 0;
|
|
} else {
|
|
shift *= 4;
|
|
cmp_fl.ls_fract = cmp_fl.ms_fract << (64 - shift)
|
|
| cmp_fl.ls_fract >> shift;
|
|
cmp_fl.ms_fract >>= shift;
|
|
}
|
|
if ((cmp_fl.ms_fract == 0)
|
|
&& (cmp_fl.ls_fract == 0)) {
|
|
/* Set condition code */
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
/* guard digit */
|
|
fl.ms_fract = (fl.ms_fract << 4)
|
|
| (fl.ls_fract >> 60);
|
|
fl.ls_fract <<= 4;
|
|
}
|
|
}
|
|
|
|
/* compute with guard digit */
|
|
if (fl.sign != cmp_fl.sign) {
|
|
add_U128(fl.ms_fract, fl.ls_fract, cmp_fl.ms_fract, cmp_fl.ls_fract);
|
|
} else if ((fl.ms_fract > cmp_fl.ms_fract)
|
|
|| ((fl.ms_fract == cmp_fl.ms_fract)
|
|
&& (fl.ls_fract >= cmp_fl.ls_fract))) {
|
|
sub_U128(fl.ms_fract, fl.ls_fract, cmp_fl.ms_fract, cmp_fl.ls_fract);
|
|
} else {
|
|
sub_reverse_U128(fl.ms_fract, fl.ls_fract, cmp_fl.ms_fract, cmp_fl.ls_fract);
|
|
fl.sign = ! (cmp_fl.sign);
|
|
}
|
|
|
|
/* handle overflow with guard digit */
|
|
if (fl.ms_fract & 0x00F0000000000000ULL) {
|
|
fl.ls_fract = (fl.ms_fract << 60)
|
|
| (fl.ls_fract >> 4);
|
|
fl.ms_fract >>= 4;
|
|
}
|
|
|
|
/* Set condition code */
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
} else { /* fl 0, cmp_fl not 0 */
|
|
/* Set condition code */
|
|
if (cmp_fl.ms_fract
|
|
|| cmp_fl.ls_fract) {
|
|
regs->psw.cc = cmp_fl.sign ? 2 : 1;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
} else { /* cmp_fl 0 */
|
|
/* Set condition code */
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract) {
|
|
regs->psw.cc = fl.sign ? 1 : 2;
|
|
} else {
|
|
regs->psw.cc = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B377 FIER - Load FP Integer Floating Point Short Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_fp_int_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
SHORT_FLOAT fl;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get register content */
|
|
get_sf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
if (fl.expo > 64) {
|
|
if (fl.expo < 70) {
|
|
/* Denormalize */
|
|
fl.short_fract >>= ((70 - fl.expo) * 4);
|
|
fl.expo = 70;
|
|
}
|
|
|
|
/* Normalize result */
|
|
normal_sf(&fl);
|
|
|
|
/* To register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
} else {
|
|
/* True zero */
|
|
regs->fpr[i1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B37F FIDR - Load FP Integer Floating Point Long Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_fp_int_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG2_CHECK(r1, r2, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get register content */
|
|
get_lf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
if (fl.expo > 64) {
|
|
if (fl.expo < 78) {
|
|
/* Denormalize */
|
|
fl.long_fract >>= ((78 - fl.expo) * 4);
|
|
fl.expo = 78;
|
|
}
|
|
|
|
/* Normalize result */
|
|
normal_lf(&fl);
|
|
|
|
/* To register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
} else {
|
|
/* True zero */
|
|
regs->fpr[i1] = 0;
|
|
regs->fpr[i1+1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B3B4 CEFR - Convert from Fixed to Float. Short Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(convert_fixed_to_float_short_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
S64 fix;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* get fixed value */
|
|
fix = regs->GR_L(r2);
|
|
if (fix & 0x0000000080000000)
|
|
fix |= 0xFFFFFFFF00000000ULL;
|
|
|
|
if (fix) {
|
|
if (fix < 0) {
|
|
fl.sign = NEG;
|
|
fl.long_fract = (-fix);
|
|
} else {
|
|
fl.sign = POS;
|
|
fl.long_fract = fix;
|
|
}
|
|
fl.expo = 78;
|
|
|
|
/* Normalize result */
|
|
normal_lf(&fl);
|
|
|
|
/* To register (converting to short float) */
|
|
regs->fpr[i1] = ((U32)fl.sign << 31)
|
|
| ((U32)fl.expo << 24)
|
|
| (fl.long_fract >> 32);
|
|
} else {
|
|
/* true zero */
|
|
regs->fpr[i1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B3B5 CDFR - Convert from Fixed to Float. Long Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(convert_fixed_to_float_long_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
LONG_FLOAT fl;
|
|
S64 fix;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* get fixed value */
|
|
fix = regs->GR_L(r2);
|
|
if (fix & 0x0000000080000000)
|
|
fix |= 0xFFFFFFFF00000000ULL;
|
|
|
|
if (fix) {
|
|
if (fix < 0) {
|
|
fl.sign = NEG;
|
|
fl.long_fract = (-fix);
|
|
} else {
|
|
fl.sign = POS;
|
|
fl.long_fract = fix;
|
|
}
|
|
fl.expo = 78;
|
|
|
|
/* Normalize result */
|
|
normal_lf(&fl);
|
|
|
|
/* To register */
|
|
store_lf(&fl, regs->fpr + i1);
|
|
} else {
|
|
/* true zero */
|
|
regs->fpr[i1] = 0;
|
|
regs->fpr[i1+1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B3B6 CXFR - Convert from Fixed to Float. Extended Register [RRE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(convert_fixed_to_float_ext_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int i1;
|
|
EXTENDED_FLOAT fl;
|
|
S64 fix;
|
|
|
|
RRE(inst, execflag, regs, r1, r2);
|
|
HFPODD_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* get fixed value */
|
|
fix = regs->GR_L(r2);
|
|
if (fix & 0x0000000080000000)
|
|
fix |= 0xFFFFFFFF00000000ULL;
|
|
|
|
if (fix) {
|
|
if (fix < 0) {
|
|
fl.sign = NEG;
|
|
fl.ms_fract = (-fix);
|
|
} else {
|
|
fl.sign = POS;
|
|
fl.ms_fract = fix;
|
|
}
|
|
fl.ls_fract = 0;
|
|
fl.expo = 76; /* 64 + 12 (Herc ms fract is 12 digits) */
|
|
|
|
/* Normalize result */
|
|
normal_ef(&fl);
|
|
|
|
/* To register */
|
|
store_ef(&fl, regs->fpr + i1);
|
|
} else {
|
|
/* true zero */
|
|
regs->fpr[i1] = 0;
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B3B8 CFER - Convert from Float. Short to Fixed Register [RRF] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(convert_float_short_to_fixed_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int m3;
|
|
SHORT_FLOAT fl;
|
|
BYTE shift;
|
|
U32 lsfract;
|
|
|
|
RRF_M(inst, execflag, regs, r1, r2, m3);
|
|
HFPM_CHECK(m3, regs);
|
|
HFPREG_CHECK(r2, regs);
|
|
|
|
/* Get register content */
|
|
get_sf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
if (fl.short_fract) {
|
|
/* not zero */
|
|
normal_sf(&fl);
|
|
|
|
if (fl.expo > 72) {
|
|
/* exeeds range by exponent */
|
|
regs->GR_L(r1) = fl.sign ? 0x80000000UL : 0x7FFFFFFFUL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
if (fl.expo > 70) {
|
|
/* to be left shifted */
|
|
fl.short_fract <<= ((fl.expo - 70) * 4);
|
|
if (fl.sign) {
|
|
/* negative */
|
|
if (fl.short_fract > 0x80000000UL) {
|
|
/* exeeds range by value */
|
|
regs->GR_L(r1) = 0x80000000UL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
} else {
|
|
/* positive */
|
|
if (fl.short_fract > 0x7FFFFFFFUL) {
|
|
/* exeeds range by value */
|
|
regs->GR_L(r1) = 0x7FFFFFFFUL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
}
|
|
} else if ((fl.expo > 64)
|
|
&& (fl.expo < 70)) {
|
|
/* to be right shifted and to be rounded */
|
|
shift = ((70 - fl.expo) * 4);
|
|
lsfract = fl.short_fract << (32 - shift);
|
|
fl.short_fract >>= shift;
|
|
|
|
if (m3 == 1) {
|
|
/* biased round to nearest */
|
|
if (lsfract & 0x80000000UL) {
|
|
fl.short_fract++;
|
|
}
|
|
} else if (m3 == 4) {
|
|
/* round to nearest */
|
|
if ((lsfract > 0x80000000UL)
|
|
|| ((fl.short_fract & 0x00000001UL)
|
|
&& (lsfract == 0x80000000UL))) {
|
|
fl.short_fract++;
|
|
}
|
|
} else if (m3 == 6) {
|
|
/* round toward + */
|
|
if ((fl.sign == POS)
|
|
&& lsfract) {
|
|
fl.short_fract++;
|
|
}
|
|
} else if (m3 == 7) {
|
|
/* round toward - */
|
|
if ((fl.sign == NEG)
|
|
&& lsfract) {
|
|
fl.short_fract++;
|
|
}
|
|
}
|
|
} else if (fl.expo == 64) {
|
|
/* to be rounded */
|
|
lsfract = fl.short_fract << 8;
|
|
fl.short_fract = 0;
|
|
|
|
if (m3 == 1) {
|
|
/* biased round to nearest */
|
|
if (lsfract & 0x80000000UL) {
|
|
fl.short_fract++;
|
|
}
|
|
} else if (m3 == 4) {
|
|
/* round to nearest */
|
|
if (lsfract > 0x80000000UL) {
|
|
fl.short_fract++;
|
|
}
|
|
} else if (m3 == 6) {
|
|
/* round toward + */
|
|
if ((fl.sign == POS)
|
|
&& lsfract) {
|
|
fl.short_fract++;
|
|
}
|
|
} else if (m3 == 7) {
|
|
/* round toward - */
|
|
if ((fl.sign == NEG)
|
|
&& lsfract) {
|
|
fl.short_fract++;
|
|
}
|
|
}
|
|
} else if (fl.expo < 64) {
|
|
fl.short_fract = 0;
|
|
if (((m3 == 6)
|
|
&& (fl.sign == POS))
|
|
|| ((m3 == 7)
|
|
&& (fl.sign == NEG))) {
|
|
fl.short_fract++;
|
|
}
|
|
}
|
|
if (fl.sign) {
|
|
/* negative */
|
|
regs->GR_L(r1) = -((S32) fl.short_fract);
|
|
regs->psw.cc = 1;
|
|
} else {
|
|
/* positive */
|
|
regs->GR_L(r1) = fl.short_fract;
|
|
regs->psw.cc = 2;
|
|
}
|
|
} else {
|
|
/* zero */
|
|
regs->GR_L(r1) = 0;
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B3B9 CFDR - Convert from Float. Long to Fixed Register [RRF] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(convert_float_long_to_fixed_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int m3;
|
|
LONG_FLOAT fl;
|
|
BYTE shift;
|
|
U64 lsfract;
|
|
|
|
RRF_M(inst, execflag, regs, r1, r2, m3);
|
|
HFPM_CHECK(m3, regs);
|
|
HFPREG_CHECK(r2, regs);
|
|
|
|
/* Get register content */
|
|
get_lf(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
if (fl.long_fract) {
|
|
/* not zero */
|
|
normal_lf(&fl);
|
|
|
|
if (fl.expo > 72) {
|
|
/* exeeds range by exponent */
|
|
regs->GR_L(r1) = fl.sign ? 0x80000000UL : 0x7FFFFFFFUL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
if (fl.expo > 64) {
|
|
/* to be right shifted and to be rounded */
|
|
shift = ((78 - fl.expo) * 4);
|
|
lsfract = fl.long_fract << (64 - shift);
|
|
fl.long_fract >>= shift;
|
|
|
|
if (m3 == 1) {
|
|
/* biased round to nearest */
|
|
if (lsfract & 0x8000000000000000ULL) {
|
|
fl.long_fract++;
|
|
}
|
|
} else if (m3 == 4) {
|
|
/* round to nearest */
|
|
if ((lsfract > 0x8000000000000000ULL)
|
|
|| ((fl.long_fract & 0x0000000000000001ULL)
|
|
&& (lsfract == 0x8000000000000000ULL))) {
|
|
fl.long_fract++;
|
|
}
|
|
} else if (m3 == 6) {
|
|
/* round toward + */
|
|
if ((fl.sign == POS)
|
|
&& lsfract) {
|
|
fl.long_fract++;
|
|
}
|
|
} else if (m3 == 7) {
|
|
/* round toward - */
|
|
if ((fl.sign == NEG)
|
|
&& lsfract) {
|
|
fl.long_fract++;
|
|
}
|
|
}
|
|
if (fl.expo == 72) {
|
|
if (fl.sign) {
|
|
/* negative */
|
|
if (fl.long_fract > 0x80000000UL) {
|
|
/* exeeds range by value */
|
|
regs->GR_L(r1) = 0x80000000UL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
} else {
|
|
/* positive */
|
|
if (fl.long_fract > 0x7FFFFFFFUL) {
|
|
/* exeeds range by value */
|
|
regs->GR_L(r1) = 0x7FFFFFFFUL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
} else if (fl.expo == 64) {
|
|
/* to be rounded */
|
|
lsfract = fl.long_fract << 8;
|
|
fl.long_fract = 0;
|
|
|
|
if (m3 == 1) {
|
|
/* biased round to nearest */
|
|
if (lsfract & 0x8000000000000000ULL) {
|
|
fl.long_fract++;
|
|
}
|
|
} else if (m3 == 4) {
|
|
/* round to nearest */
|
|
if (lsfract > 0x8000000000000000ULL) {
|
|
fl.long_fract++;
|
|
}
|
|
} else if (m3 == 6) {
|
|
/* round toward + */
|
|
if ((fl.sign == POS)
|
|
&& lsfract) {
|
|
fl.long_fract++;
|
|
}
|
|
} else if (m3 == 7) {
|
|
/* round toward - */
|
|
if ((fl.sign == NEG)
|
|
&& lsfract) {
|
|
fl.long_fract++;
|
|
}
|
|
}
|
|
} else {
|
|
/* fl.expo < 64 */
|
|
fl.long_fract = 0;
|
|
if (((m3 == 6)
|
|
&& (fl.sign == POS))
|
|
|| ((m3 == 7)
|
|
&& (fl.sign == NEG))) {
|
|
fl.long_fract++;
|
|
}
|
|
}
|
|
if (fl.sign) {
|
|
/* negative */
|
|
regs->GR_L(r1) = -((S32) fl.long_fract);
|
|
regs->psw.cc = 1;
|
|
} else {
|
|
/* positive */
|
|
regs->GR_L(r1) = fl.long_fract;
|
|
regs->psw.cc = 2;
|
|
}
|
|
} else {
|
|
/* zero */
|
|
regs->GR_L(r1) = 0;
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* B3BA CFXR - Convert from Float. Extended to Fixed Register [RRF] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(convert_float_ext_to_fixed_reg)
|
|
{
|
|
int r1, r2; /* Values of R fields */
|
|
int m3;
|
|
EXTENDED_FLOAT fl;
|
|
BYTE shift;
|
|
U64 lsfract;
|
|
|
|
RRF_M(inst, execflag, regs, r1, r2, m3);
|
|
HFPM_CHECK(m3, regs);
|
|
HFPODD_CHECK(r2, regs);
|
|
|
|
/* Get register content */
|
|
get_ef(&fl, regs->fpr + FPR2I(r2));
|
|
|
|
if (fl.ms_fract
|
|
|| fl.ls_fract) {
|
|
/* not zero */
|
|
normal_ef(&fl);
|
|
|
|
if (fl.expo > 72) {
|
|
/* exeeds range by exponent */
|
|
regs->GR_L(r1) = fl.sign ? 0x80000000UL : 0x7FFFFFFFUL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
if (fl.expo > 64) {
|
|
/* to be right shifted and to be rounded */
|
|
shift = ((92 - fl.expo - 16) * 4);
|
|
lsfract = fl.ms_fract << (64 - shift);
|
|
fl.ms_fract >>= shift;
|
|
|
|
if (m3 == 1) {
|
|
/* biased round to nearest */
|
|
if (lsfract & 0x8000000000000000ULL) {
|
|
fl.ms_fract++;
|
|
}
|
|
} else if (m3 == 4) {
|
|
/* round to nearest */
|
|
if (((lsfract & 0x8000000000000000ULL)
|
|
&& ((lsfract & 0x7FFFFFFFFFFFFFFFULL)
|
|
|| fl.ls_fract))
|
|
|| ( (fl.ms_fract & 0x0000000000000001ULL)
|
|
&& (lsfract == 0x8000000000000000ULL)
|
|
&& (fl.ls_fract == 0))) {
|
|
fl.ms_fract++;
|
|
}
|
|
} else if (m3 == 6) {
|
|
/* round toward + */
|
|
if ((fl.sign == POS)
|
|
&& (lsfract
|
|
|| fl.ls_fract)) {
|
|
fl.ms_fract++;
|
|
}
|
|
} else if (m3 == 7) {
|
|
/* round toward - */
|
|
if ((fl.sign == NEG)
|
|
&& (lsfract
|
|
|| fl.ls_fract)) {
|
|
fl.ms_fract++;
|
|
}
|
|
}
|
|
} else if (fl.expo == 64) {
|
|
/* to be rounded */
|
|
lsfract = fl.ms_fract << 16;
|
|
fl.ms_fract = 0;
|
|
|
|
if (m3 == 1) {
|
|
/* biased round to nearest */
|
|
if (lsfract & 0x8000000000000000ULL) {
|
|
fl.ms_fract++;
|
|
}
|
|
} else if (m3 == 4) {
|
|
/* round to nearest */
|
|
if ((lsfract & 0x8000000000000000ULL)
|
|
&& ((lsfract & 0x7FFFFFFFFFFFFFFFULL)
|
|
|| fl.ls_fract)) {
|
|
fl.ms_fract++;
|
|
}
|
|
} else if (m3 == 6) {
|
|
/* round toward + */
|
|
if ((fl.sign == POS)
|
|
&& (lsfract
|
|
|| fl.ls_fract)) {
|
|
fl.ms_fract++;
|
|
}
|
|
} else if (m3 == 7) {
|
|
/* round toward - */
|
|
if ((fl.sign == NEG)
|
|
&& (lsfract
|
|
|| fl.ls_fract)) {
|
|
fl.ms_fract++;
|
|
}
|
|
}
|
|
} else {
|
|
/* fl.expo < 64 */
|
|
fl.ms_fract = 0;
|
|
if (((m3 == 6)
|
|
&& (fl.sign == POS))
|
|
|| ((m3 == 7)
|
|
&& (fl.sign == NEG))) {
|
|
fl.ms_fract++;
|
|
}
|
|
}
|
|
if (fl.sign) {
|
|
/* negative */
|
|
if (fl.ms_fract > 0x80000000UL) {
|
|
/* exeeds range by value */
|
|
regs->GR_L(r1) = 0x80000000UL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
regs->GR_L(r1) = -((S32) fl.ms_fract);
|
|
regs->psw.cc = 1;
|
|
} else {
|
|
/* positive */
|
|
if (fl.ms_fract > 0x7FFFFFFFUL) {
|
|
/* exeeds range by value */
|
|
regs->GR_L(r1) = 0x7FFFFFFFUL;
|
|
regs->psw.cc = 3;
|
|
return;
|
|
}
|
|
regs->GR_L(r1) = fl.ms_fract;
|
|
regs->psw.cc = 2;
|
|
}
|
|
} else {
|
|
/* zero */
|
|
regs->GR_L(r1) = 0;
|
|
regs->psw.cc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED24 LDE - Load Lengthened Floating Point Short to Long [RXE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(loadlength_float_short_to_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
RXE(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Update first 32 bits of register from operand address */
|
|
regs->fpr[i1] = ARCH_DEP(vfetch4) (effective_addr2, b2, regs);
|
|
|
|
/* Zero register content */
|
|
regs->fpr[i1+1] = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED25 LXD - Load Lengthened Floating Point Long to Extended [RXE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(loadlength_float_long_to_ext)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
U32 wk;
|
|
U64 wkd;
|
|
|
|
RXE(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPODD_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the 2nd operand */
|
|
wkd = ARCH_DEP(vfetch8) (effective_addr2, b2, regs);
|
|
wk = wkd >> 32;
|
|
|
|
if (wkd & 0x00FFFFFFFFFFFFFFULL) {
|
|
/* Back to register */
|
|
regs->fpr[i1] = wk;
|
|
regs->fpr[i1+1] = wkd;
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = (wk & 0x80000000)
|
|
| ((wk - (14 << 24)) & 0x7F000000);
|
|
} else {
|
|
/* true zero with sign */
|
|
regs->fpr[i1] = (wk & 0x80000000);
|
|
regs->fpr[i1+FPREX] = regs->fpr[i1];
|
|
regs->fpr[i1+1] = 0;
|
|
}
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED26 LXE - Load Lengthened Float. Short to Extended [RXE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(loadlength_float_short_to_ext)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
U32 wk;
|
|
|
|
RXE(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPODD_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the 2nd operand */
|
|
wk = ARCH_DEP(vfetch4) (effective_addr2, b2, regs);
|
|
|
|
if (wk & 0x00FFFFFF) {
|
|
/* Back to register */
|
|
regs->fpr[i1] = wk;
|
|
|
|
/* Zero register content */
|
|
regs->fpr[i1+1] = 0;
|
|
|
|
/* Low order register */
|
|
regs->fpr[i1+FPREX] = (wk & 0x80000000)
|
|
| ((wk - (14 << 24)) & 0x7F000000);
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
} else {
|
|
/* true zero with sign */
|
|
regs->fpr[i1] = (wk & 0x80000000);
|
|
regs->fpr[i1+FPREX] = regs->fpr[i1];
|
|
regs->fpr[i1+1] = 0;
|
|
regs->fpr[i1+FPREX+1] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED34 SQE - Square Root Floating Point Short [RXE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(squareroot_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT sq_fl;
|
|
SHORT_FLOAT fl;
|
|
|
|
RXE(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Get the 2nd operand */
|
|
vfetch_sf(&fl, effective_addr2, b2, regs );
|
|
|
|
/* short square root subroutine */
|
|
sq_sf(&sq_fl, &fl, regs);
|
|
|
|
/* Back to register */
|
|
store_sf(&sq_fl, regs->fpr + FPR2I(r1));
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED35 SQD - Square Root Floating Point Long [RXE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(squareroot_float_long)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
LONG_FLOAT sq_fl;
|
|
LONG_FLOAT fl;
|
|
|
|
RXE(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Get the 2nd operand */
|
|
vfetch_lf(&fl, effective_addr2, b2, regs );
|
|
|
|
/* long square root subroutine */
|
|
sq_lf(&sq_fl, &fl, regs);
|
|
|
|
/* Back to register */
|
|
store_lf(&sq_fl, regs->fpr + FPR2I(r1));
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED37 MEE - Multiply Floating Point Short [RXE] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(multiply_float_short)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1;
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
SHORT_FLOAT fl;
|
|
SHORT_FLOAT mul_fl;
|
|
int pgm_check;
|
|
|
|
RXE(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Get the operands */
|
|
get_sf(&fl, regs->fpr + i1);
|
|
vfetch_sf(&mul_fl, effective_addr2, b2, regs );
|
|
|
|
/* multiply short to long */
|
|
pgm_check = mul_sf(&fl, &mul_fl, regs);
|
|
|
|
/* Back to register */
|
|
store_sf(&fl, regs->fpr + i1);
|
|
|
|
/* Program check ? */
|
|
if (pgm_check) {
|
|
ARCH_DEP(program_interrupt) (regs, pgm_check);
|
|
}
|
|
}
|
|
#endif /* FEATURE_HFP_EXTENSIONS */
|
|
|
|
|
|
#if defined(FEATURE_LONG_DISPLACEMENT)
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED64 LEY - Load Floating Point Short (Long Displacement) [RXY] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_float_short_y)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
RXY(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Update first 32 bits of register from operand address */
|
|
regs->fpr[FPR2I(r1)] = ARCH_DEP(vfetch4) (effective_addr2, b2, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED65 LDY - Load Floating Point Long (Long Displacement) [RXY] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(load_float_long_y)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1; /* Index of r1 in fpr array */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
U64 dreg; /* Double word workarea */
|
|
|
|
RXY(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Fetch value from operand address */
|
|
dreg = ARCH_DEP(vfetch8) (effective_addr2, b2, regs);
|
|
|
|
/* Update register contents */
|
|
regs->fpr[i1] = dreg >> 32;
|
|
regs->fpr[i1+1] = dreg;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED66 STEY - Store Floating Point Short (Long Displacement) [RXY] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(store_float_short_y)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
RXY(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
|
|
/* Store register contents at operand address */
|
|
ARCH_DEP(vstore4) (regs->fpr[FPR2I(r1)], effective_addr2, b2, regs);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ED67 STDY - Store Floating Point Long (Long Displacement) [RXY] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(store_float_long_y)
|
|
{
|
|
int r1; /* Value of R field */
|
|
int i1; /* Index of r1 in fpr array */
|
|
int b2; /* Base of effective addr */
|
|
VADR effective_addr2; /* Effective address */
|
|
U64 dreg; /* Double word workarea */
|
|
|
|
RXY(inst, execflag, regs, r1, b2, effective_addr2);
|
|
HFPREG_CHECK(r1, regs);
|
|
i1 = FPR2I(r1);
|
|
|
|
/* Store register contents at operand address */
|
|
dreg = ((U64)regs->fpr[i1] << 32)
|
|
| regs->fpr[i1+1];
|
|
ARCH_DEP(vstore8) (dreg, effective_addr2, b2, regs);
|
|
}
|
|
#endif /*defined(FEATURE_LONG_DISPLACEMENT)*/
|
|
|
|
|
|
#endif /* FEATURE_HEXADECIMAL_FLOATING_POINT */
|
|
|
|
#if !defined(_GEN_ARCH)
|
|
|
|
#if defined(_ARCHMODE2)
|
|
#define _GEN_ARCH _ARCHMODE2
|
|
#include "float.c"
|
|
#endif
|
|
|
|
#if defined(_ARCHMODE3)
|
|
#undef _GEN_ARCH
|
|
#define _GEN_ARCH _ARCHMODE3
|
|
#include "float.c"
|
|
#endif
|
|
|
|
#endif /*!defined(_GEN_ARCH)*/
|
|
|
|
|
|
/* end of float.c */
|