mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-09 22:01:57 +02:00
5175 lines
199 KiB
C
5175 lines
199 KiB
C
/* ZVECTOR2.C (C) Copyright Jan Jaeger, 1999-2012 */
|
|
/* (C) Copyright Roger Bowler, 1999-2012 */
|
|
/* z/Arch Vector Operations */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
/* Interpretive Execution - (C) Copyright Jan Jaeger, 1999-2012 */
|
|
/* z/Architecture support - (C) Copyright Jan Jaeger, 1999-2012 */
|
|
|
|
/*-------------------------------------------------------------------------------------------------------------
|
|
James Wekel - June 2024
|
|
|
|
zvector2.c implements z/architecture E6xx instructions:
|
|
|
|
facility code test# Instruction op-code format
|
|
-------- ---- ----- ---------------------------------------------------- ------- ------
|
|
|
|
v2 x 01 E601 VECTOR LOAD BYTE REVERSED ELEMENT (16) VLEBRH VRX
|
|
v2 x 01 E602 VECTOR LOAD BYTE REVERSED ELEMENT (64) VLEBRG VRX
|
|
v2 x 01 E603 VECTOR LOAD BYTE REVERSED ELEMENT (32) VLEBRF VRX
|
|
v2 x 01 E604 VECTOR LOAD BYTE REVERSED ELEMENT AND ZERO VLLEBRZ VRX
|
|
v2 x 01 E605 VECTOR LOAD BYTE REVERSED ELEMENT AND REPLICATE VLBRREP VRX
|
|
v2 x 01 E606 VECTOR LOAD BYTE REVERSED ELEMENTS VLBR VRX
|
|
v2 x 01 E607 VECTOR LOAD ELEMENTS REVERSED VLER VRX
|
|
v2 x 02 E609 VECTOR STORE BYTE REVERSED ELEMENT (16) VSTEBRH VRX
|
|
v2 x 02 E60A VECTOR STORE BYTE REVERSED ELEMENT (64) VSTEBRG VRX
|
|
v2 x 02 E60B VECTOR STORE BYTE REVERSED ELEMENT (32) VSTEBRF VRX
|
|
v2 x 02 E60E VECTOR STORE BYTE REVERSED ELEMENTS VSTBR VRX
|
|
v2 x 02 E60F VECTOR STORE ELEMENTS REVERSED VSTER VRX
|
|
vd x 03 E634 VECTOR PACK ZONED VPKZ VSI
|
|
vd x 03 E635 VECTOR LOAD RIGHTMOST WITH LENGTH VLRL VSI
|
|
vd x 08 09 E637 VECTOR LOAD RIGHTMOST WITH LENGTH (reg) VLRLR VRS-d
|
|
vd x 04 E63C VECTOR UNPACK ZONED VUPKZ VSI
|
|
vd x 04 E63D VECTOR STORE RIGHTMOST WITH LENGTH VSTRL VSI
|
|
vd x 09 E63F VECTOR STORE RIGHTMOST WITH LENGTH (reg) VSTRLR VRS-d
|
|
vd x 10 E649 VECTOR LOAD IMMEDIATE DECIMAL VLIP VRI-h
|
|
vd3 x E64A VECTOR CONVERT TO DECIMAL (128) VCVDQ VRI-j
|
|
vd3 x E64E VECTOR CONVERT TO BINARY (128) VCVBQ VRR-k
|
|
vd x 11 E650 VECTOR CONVERT TO BINARY (32) VCVB VRR-i
|
|
vd2 x 12 E651 VECTOR COUNT LEADING ZERO DIGITS VCLZDP VRR-k
|
|
vd x 11 E652 VECTOR CONVERT TO BINARY (64) VCVBG VRR-i
|
|
vd2 x 12 E654 VECTOR UNPACK ZONED HIGH VUPKZH VRR-k
|
|
vd x 13 E658 VECTOR CONVERT TO DECIMAL (32) VCVD VRI-i
|
|
vd x 16 E659 VECTOR SHIFT AND ROUND DECIMAL VSRP VRI-g
|
|
vd x 13 E65A VECTOR CONVERT TO DECIMAL (64) VCVDG VRI-i
|
|
vd x 16 E65B VECTOR PERFORM SIGN OPERATION DECIMAL VPSOP VRI-g
|
|
vd2 x 12 E65C VECTOR UNPACK ZONED LOW VUPKZL VRR-k
|
|
vd x 14 E65F VECTOR TEST DECIMAL VTP VRR-g
|
|
vd2 x 06 E670 VECTOR PACK ZONED REGISTER VPKZR VRI-f
|
|
vd x 05 E671 VECTOR ADD DECIMAL VAP VRI-f
|
|
vd2 x 07 E672 VECTOR SHIFT AND ROUND DECIMAL REGISTER VSRPR VRI-f
|
|
vd x 05 E673 VECTOR SUBTRACT DECIMAL VSP VRI-f
|
|
vd2 x 17 E674 DECIMAL SCALE AND CONVERT TO HFP VSCHP VRR-b
|
|
vd x 15 E677 VECTOR COMPARE DECIMAL VCP VRR-h
|
|
vd x 05 E678 VECTOR MULTIPLY DECIMAL VMP VRI-f
|
|
vd x 05 E679 VECTOR MULTIPLY AND SHIFT DECIMAL VMSP VRI-f
|
|
vd x 05 E67A VECTOR DIVIDE DECIMAL VDP VRI-f
|
|
vd x 05 E67B VECTOR REMAINDER DECIMAL VRP VRI-f
|
|
vd2 x 18 E67C DECIMAL SCALE AND CONVERT AND SPLIT TO HFP VSCSHP VRR-b
|
|
vd2 x 19 E67D VECTOR CONVERT HFP TO SCALED DECIMAL VCSPH VRR-j
|
|
vd x 05 E67E VECTOR SHIFT AND DIVIDE DECIMAL VSDP VRI-f
|
|
vd3 E67F VECTOR TEST ZONED VTZ VRI-l
|
|
|
|
The following E6 z/arch vector instructions are implemented in nnpa.c:
|
|
nn E655 VECTOR FP CONVERT TO NNP VCNF VRR-a
|
|
nn E656 VECTOR FP CONVERT AND LENGTHEN FROM NNP HIGH VCLFNH VRR-a
|
|
nn E65D VECTOR FP CONVERT FROM NNP VCFN VRR-a
|
|
nn E65E VECTOR FP CONVERT AND LENGTHEN FROM NNP LOW VCLFNL VRR-a
|
|
nn E675 VECTOR FP CONVERT AND ROUND TO NNP VCRNF VRR-c
|
|
|
|
facility (bit):
|
|
nn - 165 - Neural-network-processing-assist facility
|
|
v2 - 148 - Vector-enhancements facility 2
|
|
vd - 134 - Vector packed-decimal facility
|
|
vd2 - 192 - Vector-packed-decimal-enhancement facility 2
|
|
vd3 - 199 - Vector-packed-decimal-enhancement facility 3
|
|
|
|
test#:
|
|
Instruction test are named 'zvector-e6-xx-hint' where 'xx' is the test# and 'hint' provides a hint of the
|
|
instructions tested. A test is limited to a single instruction format. Multiple instructions may be
|
|
tested within a single test. Multiple tests may be required to test all instructions for a given
|
|
instruction format, e.g. load type instructions in one test and store type instructions in a second test.
|
|
|
|
Implemented instruction are organized by ascending opcode.
|
|
-------------------------------------------------------------------------------------------------------------*/
|
|
|
|
#include "hstdinc.h"
|
|
|
|
#define _ZVECTOR2_C_
|
|
#define _HENGINE_DLL_
|
|
|
|
#include "hercules.h"
|
|
#include "opcode.h"
|
|
#include "inline.h"
|
|
|
|
#include "zvector.h"
|
|
|
|
#if defined(FEATURE_129_ZVECTOR_FACILITY)
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* decNumber required for Z/Vector Packed Decimal */
|
|
/*-------------------------------------------------------------------*/
|
|
#define DECNUMDIGITS 66
|
|
#include "decNumber.h"
|
|
#include "decPacked.h"
|
|
#endif
|
|
|
|
/* ====================================================================== */
|
|
/* ZVECTOR_END macro for debugging Vector instructions */
|
|
/* Note: block comments are used to avoid gcc */
|
|
/* warning: multi-line comment [-Wcomment] */
|
|
/*
|
|
#undef ZVECTOR_END
|
|
#define ZVECTOR_END(_regs) \
|
|
if (0 && inst[5] != (U8) 0x3E && inst[5] != (U8) 0x36) \
|
|
ARCH_DEP(display_inst) (_regs, inst);
|
|
*/
|
|
/* ====================================================================== */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Internal macro definitions */
|
|
/*-------------------------------------------------------------------*/
|
|
#define MAX_DECIMAL_LENGTH 16
|
|
#define MAX_DECIMAL_DIGITS (((MAX_DECIMAL_LENGTH)*2)-1)
|
|
#define MAX_ZONED_LENGTH 32
|
|
#define VR_PACKED_SIGN 15
|
|
|
|
|
|
/* Decimal handling helpers */
|
|
#define IS_VALID_SIGN(s) ( ((s) & 0x0F) > 9 )
|
|
#define IS_VALID_DECIMAL(s) ( ((s) & 0x0F) < 10 )
|
|
#define IS_PLUS_SIGN(s) ( (((s) & 0x0F) == 0x0A) || (((s) & 0x0F) == 0x0C) || (((s) & 0x0F) >= 0x0E) )
|
|
#define IS_MINUS_SIGN(s) ( (((s) & 0x0F) == 0x0B) || (((s) & 0x0F) == 0x0D) )
|
|
#define PREFERRED_PLUS 0x0C
|
|
#define PREFERRED_MINUS 0x0D
|
|
#define PREFERRED_ZONE 0x0F
|
|
#define PACKED_HIGH(p) ( ((p) & 0xF0) >> 4)
|
|
#define PACKED_LOW(p) ( ((p) & 0x0F) )
|
|
#define PACKED_SIGN(p) ( ((p) & 0x0F) )
|
|
#define ZONED_DECIMAL(p) ( ((p) & 0x0F) )
|
|
#define ZONED_SIGN(p) ( ((p) & 0xF0) >> 4)
|
|
|
|
|
|
/* Vector Register handling helpers */
|
|
#define SET_VR_ZERO(p) SetZero_128( &(regs->VR_Q( (p) )) )
|
|
#define GET_VR_SIGN(p) (PACKED_SIGN( regs->VR_B( (p), VR_PACKED_SIGN) ))
|
|
#define SET_VR_SIGN(p, sign) ( regs->VR_B( (p), VR_PACKED_SIGN) = (regs->VR_B( (p), VR_PACKED_SIGN) & 0xF0) | (sign & 0x0F) )
|
|
#define VR_HAS_PLUS_SIGN(p) (IS_PLUS_SIGN( GET_VR_SIGN(p) ) )
|
|
#define VR_HAS_MINUS_SIGN(p) (IS_MINUS_SIGN( GET_VR_SIGN(p) ) )
|
|
#define VR_HAS_VALID_SIGN(p) (IS_VALID_SIGN( GET_VR_SIGN(p) ) )
|
|
|
|
/* local Vector handling helpers */
|
|
#define SET_LV_ZERO(p) SetZero_128( &(lregs->VR_Q( (p) )) )
|
|
#define GET_LV_SIGN(p) (PACKED_SIGN( lregs->VR_B( (p), VR_PACKED_SIGN) ))
|
|
#define SET_LV_SIGN(p, sign) ( lregs->VR_B( (p), VR_PACKED_SIGN) = (lregs->VR_B( (p), VR_PACKED_SIGN) & 0xF0) | (sign & 0x0F) )
|
|
#define LV_HAS_PLUS_SIGN(p) (IS_PLUS_SIGN( GET_VR_SIGN(p) ) )
|
|
#define LV_HAS_MINUS_SIGN(p) (IS_MINUS_SIGN( GET_VR_SIGN(p) ) )
|
|
#define LV_HAS_VALID_SIGN(p) (IS_VALID_SIGN( GET_VR_SIGN(p) ) )
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Use Intrinsics */
|
|
/* - for MSVC */
|
|
/* - for Clang version less than 12 or GCC version less than 8 when */
|
|
/* when SSE 4.2 intrinsics are available */
|
|
/*-------------------------------------------------------------------*/
|
|
//Programmers note:
|
|
// intrinsics are defined for X64.
|
|
|
|
// future option for aarch64:
|
|
// sse2neon.h adds aarch64 Neon impelementations of X64 intrisics
|
|
// to allow a single intrinsic implementation to be used.
|
|
// https://github.com/DLTcollab/sse2neon
|
|
//
|
|
|
|
#undef __V128_SSE__
|
|
|
|
/* MSVC on X64: intrinsics are available and should be used for optimization */
|
|
#if ( defined (_MSC_VER ) || defined( _MSVC_ ) ) && defined( _M_X64 )
|
|
|
|
#define __V128_SSE__ 1
|
|
|
|
/*
|
|
GCC/Clang on X64: intrinsics are included if SSE2 is available
|
|
. Use intrinsics for optimization, if SSE 4.2 is available (all SSE intrinsics) and
|
|
Clang version less than 12 or
|
|
GCC version less than 8
|
|
otherwise use compiler -O3 optimization. -O3 optimization includes
|
|
"Vectorization of loops" https://gcc.gnu.org/onlinedocs/gnat_ugn/Vectorization-of-loops.html.
|
|
which uses native SIMD instructions, for example on ARM AArch64 processors, Intel X64 processors, ...
|
|
*/
|
|
|
|
#elif defined( __x86_64__ ) && defined( __SSE4_2__ ) && \
|
|
( (defined( __clang_major__ ) && __clang_major__ < 12 ) || \
|
|
(defined( __GNUC__ ) && __GNUC__ < 8 ) \
|
|
)
|
|
|
|
#define __V128_SSE__ 1
|
|
|
|
#endif
|
|
|
|
/* compile debug message: are we using intrinsics? */
|
|
#if 0
|
|
#if defined(__V128_SSE__)
|
|
#pragma message("__V128_SSE__ is defined. Using intrinsics." )
|
|
#else
|
|
#pragma message("No intrinsics are included for optimization; only compiler optimization")
|
|
#endif
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 128 bit types */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* are the compiler 128 bit types available? */
|
|
/*-------------------------------------------------------------------*/
|
|
#if defined( __SIZEOF_INT128__ )
|
|
#define _USE_128_
|
|
#endif
|
|
|
|
/*===================================================================*/
|
|
/* LOCAL Registers (saved vector registers) */
|
|
/* local vector registers ensure source input of a vector */
|
|
/* register which could also be an output vector register */
|
|
/* NOTE: the same vfp name to use VR_x macros */
|
|
/*===================================================================*/
|
|
|
|
/* local (saved) vector register */
|
|
typedef struct
|
|
{
|
|
QW vfp[3];
|
|
}
|
|
LOCAL_REGS;
|
|
|
|
#define LV1 0
|
|
#define LV2 1
|
|
#define LV3 2
|
|
|
|
#define VR_SAVE_LOCAL( _l, _r) memcpy( &( lregs->VR_Q(_l) ), &( regs->VR_Q(_r) ), sizeof(QW) )
|
|
|
|
#define LOCALS() \
|
|
LOCAL_REGS locals; \
|
|
LOCAL_REGS* lregs = &locals;
|
|
|
|
/*===================================================================*/
|
|
/* Achitecture Independent Routines */
|
|
/*===================================================================*/
|
|
|
|
#if !defined(_ZVECTOR2_ARCH_INDEPENDENT_)
|
|
#define _ZVECTOR2_ARCH_INDEPENDENT_
|
|
|
|
/*===================================================================*/
|
|
/* decNumbers Helpers */
|
|
/*===================================================================*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Debug helper for decNumbers */
|
|
/* */
|
|
/* Input: */
|
|
/* msg pointer to logmsg context string */
|
|
/* dn pointer to decNumber */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void dn_logmsg( const char * msg, decNumber* dn )
|
|
{
|
|
char string[DECNUMDIGITS+14]; // conversion buffer
|
|
|
|
decNumberToString(dn, string);
|
|
logmsg("%s: decNumber: digits=%d, bits=%hhx, exponent=%d, value=%s \n", msg, dn->digits, dn->bits, dn->exponent, string);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Debug helper for decNumber Context */
|
|
/* */
|
|
/* Input: */
|
|
/* msg pointer to logmsg context string */
|
|
/* context pointer to decContext */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void dc_logmsg( const char * msg, decContext* set )
|
|
{
|
|
int rounding;
|
|
|
|
rounding = decContextGetRounding( set );
|
|
logmsg("%s: decContext: rounding %d \n", msg, rounding);
|
|
}
|
|
|
|
/*===================================================================*/
|
|
/* Local Vector Register Helpers */
|
|
/*===================================================================*/
|
|
/* Programmer's note: */
|
|
/* */
|
|
/* There may be two helper routines (Local Vector and actual Vector) */
|
|
/* with similar names e.g. */
|
|
/* */
|
|
/* lv_packed_valid_digits ( LOCAL_REGS* regs, int v1 ) */
|
|
/* vr_packed_valid_digits ( REGS* regs, int v1 ) */
|
|
/* */
|
|
/* and function but with different register locations! */
|
|
/* */
|
|
/* The Local Vertor Register (copied VR) routines use 'lregs; as the */
|
|
/* context and LV1, LV2, or LV3 coresponding to the instruction */
|
|
/* v1, v2, or v3. */
|
|
/* */
|
|
/* The LOCALS() macro provides 3 local vector register saved areas */
|
|
/* for an instruction. */
|
|
/*===================================================================*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check a signed packed decimal local vector for valid digits */
|
|
/* */
|
|
/* Input: */
|
|
/* regs context for Local vector register access */
|
|
/* v1 Local vector register to check */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: all 31 packed digits are valid */
|
|
/* false: at least one invalid digit in the VR */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool lv_packed_valid_digits ( LOCAL_REGS* regs, int v1 )
|
|
{
|
|
int i, j; /* Array subscript */
|
|
bool valid = true; /* valid result */
|
|
|
|
for (i=0, j=0; i < MAX_DECIMAL_DIGITS && valid; i++)
|
|
{
|
|
if (i & 1)
|
|
valid = PACKED_LOW ( regs->VR_B( v1, j++ ) ) < 10;
|
|
else
|
|
valid = PACKED_HIGH ( regs->VR_B( v1, j ) ) < 10;
|
|
} /* end for */
|
|
|
|
return valid;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check a signed packed decimal local vector for a valid sign */
|
|
/* */
|
|
/* Input: */
|
|
/* regs context for Local vector register access */
|
|
/* v1 Local vector register to check */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: the VR sign is valid */
|
|
/* false: the VR sign is invalid */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool lv_packed_valid_sign ( LOCAL_REGS* regs, int v1 )
|
|
{
|
|
return PACKED_SIGN ( regs->VR_B( v1, VR_PACKED_SIGN ) ) > 9;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check a local Vector for a valid signed packed decimal */
|
|
/* */
|
|
/* Input: */
|
|
/* regs context for Local vector register access */
|
|
/* v1 Local vector register to check */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: the VR is a valid signed packed decimal */
|
|
/* false: the VR is invalid (sign or at least on digit) */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool lv_packed_valid ( LOCAL_REGS* regs, int v1 )
|
|
{
|
|
return lv_packed_valid_digits( regs, v1 ) &&
|
|
lv_packed_valid_sign ( regs, v1 );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Is a packed decimal Local vector register zero */
|
|
/* */
|
|
/* Input: */
|
|
/* regs context for Local vector register access */
|
|
/* v1 Local vector register to check */
|
|
/* Returns: */
|
|
/* true all vr decimal packed digits are zero */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool lv_is_zero( LOCAL_REGS* regs, int v1 )
|
|
{
|
|
int i; /* loop index */
|
|
|
|
/* first 30 digits, two at a time */
|
|
for ( i = 0; i < VR_PACKED_SIGN -1; i ++)
|
|
if ( regs->VR_B( v1, i) != 0 ) return false;
|
|
|
|
/* 31st digit */
|
|
if ( ( regs->VR_B( v1, VR_PACKED_SIGN ) & 0xF0) != 0 ) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* leading zeros of a packed decimal Local vector register */
|
|
/* */
|
|
/* Input: */
|
|
/* regs context for Local vector register access */
|
|
/* v1 Local vector register to check */
|
|
/* Returns: */
|
|
/* # of leading zeros */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int lv_leading_zero( LOCAL_REGS* regs, int v1 )
|
|
{
|
|
int i; /* loop index */
|
|
int packedix; /* packed index */
|
|
int count = 0; /* leading zero count */
|
|
|
|
packedix = 0;
|
|
for ( i = 0; i < MAX_DECIMAL_DIGITS; i++ )
|
|
{
|
|
if (i & 1)
|
|
{
|
|
if ( ( regs->VR_B( v1, packedix++) & 0xF0 ) != 0 ) return count;
|
|
}
|
|
else
|
|
{
|
|
if ( ( regs->VR_B( v1, packedix) & 0x0F ) != 0 ) return count;
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Copy count packed digits from a Local vector register */
|
|
/* to a vector register */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register - copied to */
|
|
/* lregs context for Local vector register access */
|
|
/* v2 vector register - copied from */
|
|
/* count number of digits to copy */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void lv_copy_to_vr(REGS* regs, int v1, LOCAL_REGS* lregs, int v2, int count)
|
|
{
|
|
int i; /* loop index */
|
|
int packedix; /* packed index */
|
|
|
|
SET_VR_ZERO( v1 );
|
|
|
|
/* copy Sign */
|
|
SET_VR_SIGN( v1, GET_LV_SIGN( v2 ) );
|
|
|
|
/* copy 'count' digits */
|
|
packedix = VR_PACKED_SIGN;
|
|
for ( i = MAX_DECIMAL_DIGITS; count > 0 && i >= 0; i--, count-- )
|
|
{
|
|
if (i & 1)
|
|
{
|
|
regs->VR_B( v1, packedix) |= lregs->VR_B( v2, packedix) & 0xF0;
|
|
packedix--;
|
|
}
|
|
else
|
|
regs->VR_B( v1, packedix) |= lregs->VR_B( v2, packedix) & 0x0F;
|
|
}
|
|
}
|
|
|
|
/*===================================================================*/
|
|
/* Vector Register Helpers */
|
|
/*===================================================================*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Is a vector register true zero */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register - copied to */
|
|
/* Returns: */
|
|
/* true all vr bytes are zero */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool vr_is_true_zero(REGS* regs, int v1)
|
|
{
|
|
if (regs->VR_D( v1, 0 ) != 0 ) return false;
|
|
if (regs->VR_D( v1, 1 ) != 0 ) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check a signed packed decimal VR for valid digits */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register to check */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: all 31 packed digits are valid */
|
|
/* false: at least one invalid digit in the VR */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool vr_packed_valid_digits ( REGS* regs, int v1 )
|
|
{
|
|
int i, j; /* Array subscript */
|
|
bool valid = true; /* valid result */
|
|
|
|
for (i=0, j=0; i < MAX_DECIMAL_DIGITS && valid; i++)
|
|
{
|
|
if (i & 1)
|
|
valid = PACKED_LOW ( regs->VR_B( v1, j++ ) ) < 10;
|
|
else
|
|
valid = PACKED_HIGH ( regs->VR_B( v1, j ) ) < 10;
|
|
} /* end for */
|
|
|
|
return valid;
|
|
}
|
|
|
|
static inline bool vr_packed_valid_digits_enhanced ( REGS* regs, int v1,
|
|
int et, /* Enhanced Testing (ET) (value FALSE or TRUE) */
|
|
int bpt, /* Byte-Padding Test (BPT) (value FALSE or TRUE) */
|
|
int dc ) /* Digits Count (DC) (value 0-31) */
|
|
{
|
|
int i, j; /* Array subscript */
|
|
bool valid = TRUE; /* valid result */
|
|
|
|
if (et == FALSE)
|
|
{
|
|
/* Enhanced Testing (ET) is not required. */
|
|
/* Codes 0-9 are considered valid in all digit positions. */
|
|
for (i=0, j=0; i < MAX_DECIMAL_DIGITS && valid; i++)
|
|
{
|
|
if (i & 1)
|
|
valid = PACKED_LOW ( regs->VR_B( v1, j++ ) ) < 10;
|
|
else
|
|
valid = PACKED_HIGH ( regs->VR_B( v1, j ) ) < 10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Enhanced Testing (ET) is required */
|
|
if (dc == 0)
|
|
{
|
|
/* N=0 */
|
|
/* Codes 0-F are considered valid in all digit positions */
|
|
/* (that is, none of the digit positions are tested for */
|
|
/* validity). */
|
|
}
|
|
else
|
|
{
|
|
/* N>0 */
|
|
i = MAX_DECIMAL_DIGITS - dc;
|
|
j = i / 2;
|
|
if (dc & 1)
|
|
{
|
|
/* N>0 and odd */
|
|
/* Codes 0-9 are considered valid in the rightmost N */
|
|
/* digit positions. Codes 0-F are considered valid */
|
|
/* in the remaining leftmost digit positions (that */
|
|
/* is, the remaining leftmost digit positions are */
|
|
/* not tested for validity). */
|
|
for ( ; i < MAX_DECIMAL_DIGITS && valid; i++)
|
|
{
|
|
if (i & 1)
|
|
valid = PACKED_LOW ( regs->VR_B( v1, j++ ) ) < 10;
|
|
else
|
|
valid = PACKED_HIGH ( regs->VR_B( v1, j ) ) < 10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* N>0 and even */
|
|
if (bpt == FALSE)
|
|
{
|
|
/* N>0 and even & BPT=0 */
|
|
/* Codes 0-9 are considered valid in the */
|
|
/* rightmost N digit positions. Codes 0-F are */
|
|
/* considered valid in the remaining leftmost */
|
|
/* digit positions (that is, the remaining */
|
|
/* leftmost digit positions are not tested for */
|
|
/* validity) */
|
|
for ( ; i < MAX_DECIMAL_DIGITS && valid; i++)
|
|
{
|
|
if (i & 1)
|
|
valid = PACKED_LOW ( regs->VR_B( v1, j++ ) ) < 10;
|
|
else
|
|
valid = PACKED_HIGH ( regs->VR_B( v1, j ) ) < 10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* N>0 and even & BPT=1 */
|
|
/* Codes 0-9 are considered valid in the */
|
|
/* rightmost N digit positions. Code 0 is */
|
|
/* considered valid in the digit position */
|
|
/* immediately to the left of the rightmost N */
|
|
/* digit positions. */
|
|
/* Codes 0-F are considered valid in the */
|
|
/* remaining leftmost digit positions (that is, */
|
|
/* the remaining leftmost digit positions are */
|
|
/* not tested for validity). */
|
|
valid = PACKED_HIGH ( regs->VR_B( v1, j ) ) == 0;
|
|
i++;
|
|
for ( ; i < MAX_DECIMAL_DIGITS && valid; i++)
|
|
{
|
|
if (i & 1)
|
|
valid = PACKED_LOW ( regs->VR_B( v1, j++ ) ) < 10;
|
|
else
|
|
valid = PACKED_HIGH ( regs->VR_B( v1, j ) ) < 10;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check a signed packed decimal VR for a valid sign */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register to check */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: the VR sign is valid */
|
|
/* false: the VR sign is invalid */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool vr_packed_valid_sign ( REGS* regs, int v1 )
|
|
{
|
|
return PACKED_SIGN ( regs->VR_B( v1, VR_PACKED_SIGN ) ) > 9;
|
|
}
|
|
|
|
static inline bool vr_packed_valid_sign_enhanced ( REGS* regs, int v1,
|
|
int et, /* Enhanced Testing (ET) (value FALSE or TRUE) */
|
|
int stc, /* Sign-Test Control (STC) (value 0-7) */
|
|
int dc ) /* Digits Count (DC) (value 0-31) */
|
|
{
|
|
int sign; /* Sign */
|
|
int i, j; /* Array subscript */
|
|
bool allzeros = TRUE; /* All N digits are zeros */
|
|
bool valid = TRUE; /* valid result */
|
|
|
|
sign = PACKED_SIGN (regs->VR_B( v1, VR_PACKED_SIGN ));
|
|
|
|
if (et == FALSE)
|
|
{
|
|
/* Enhanced Testing (ET) is not required. */
|
|
valid = sign >= 0xA;
|
|
}
|
|
else
|
|
{
|
|
/* Enhanced Testing (ET) is required */
|
|
|
|
switch (stc)
|
|
{
|
|
case 1: /* STC = 001 */
|
|
case 3: /* STC = 011 */
|
|
case 7: /* STC = 111 */
|
|
if (dc == 0)
|
|
{
|
|
/* N=0 */
|
|
allzeros = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* N>0 */
|
|
i = MAX_DECIMAL_DIGITS - dc;
|
|
j = i / 2;
|
|
if (!(dc & 1)) i++;
|
|
for ( ; i < MAX_DECIMAL_DIGITS && allzeros; i++)
|
|
{
|
|
if (i & 1)
|
|
allzeros = PACKED_LOW ( regs->VR_B( v1, j++ ) ) == 0;
|
|
else
|
|
allzeros = PACKED_HIGH ( regs->VR_B( v1, j ) ) == 0;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (stc)
|
|
{
|
|
case 0: /* STC = 000 */
|
|
valid = sign >= 0xA;
|
|
break;
|
|
case 1: /* STC = 001 */
|
|
if (!allzeros)
|
|
valid = sign >= 0xA;
|
|
else
|
|
valid = sign == 0xA || sign == 0xC || sign == 0xE || sign == 0xF;
|
|
break;
|
|
case 2: /* STC = 010 */
|
|
valid = sign == 0xC || sign == 0xD;
|
|
break;
|
|
case 3: /* STC = 011 */
|
|
if (!allzeros)
|
|
valid = sign == 0xC || sign == 0xD;
|
|
else
|
|
valid = sign == 0xC;
|
|
break;
|
|
case 4: /* STC = 100 */
|
|
case 5: /* STC = 101 */
|
|
valid = sign == 0xF;
|
|
break;
|
|
case 6: /* STC = 110 */
|
|
valid = sign == 0xC || sign == 0xD || sign == 0xF;
|
|
break;
|
|
case 7: /* STC = 111 */
|
|
if (!allzeros)
|
|
valid = sign == 0xC || sign == 0xD || sign == 0xF;
|
|
else
|
|
valid = sign == 0xC || sign == 0xF;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check a VR for a valid signed packed decimal */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register to check */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: the VR is a valid signed packed decimal */
|
|
/* false: the VR is invalid (sign or at least on digit) */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool vr_packed_valid ( REGS* regs, int v1 )
|
|
{
|
|
return vr_packed_valid_digits( regs, v1 ) &&
|
|
vr_packed_valid_sign ( regs, v1 );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Load a valid packed decimal from a vector register to a U128 */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register to check */
|
|
/* un pointer to U128 field */
|
|
/* forcePositive boolean to inicate whether the value should */
|
|
/* forced to a positive value */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
static inline U128 vr_to_U128( REGS* regs, int v1, bool forcePositive )
|
|
{
|
|
int i; /* Loop variable */
|
|
int packedix; /* packed byte index */
|
|
|
|
U8 digit; /* digit of packed byte */
|
|
U128 result; /* converted binary */
|
|
U128 scale; /* current digit scale */
|
|
U128 temp128; /* temp U128 */
|
|
U128 zero128; /* zero U128 */
|
|
|
|
packedix = VR_PACKED_SIGN;
|
|
|
|
scale.Q.D.H.D = 0; scale.Q.D.L.D = 1;
|
|
result.Q.D.H.D = 0; result.Q.D.L.D = 0;
|
|
|
|
for ( i=MAX_DECIMAL_DIGITS-1; packedix >= 0 ; i--)
|
|
{
|
|
if (i & 1)
|
|
digit = PACKED_LOW ( regs->VR_B( v1, packedix ) ) ;
|
|
else
|
|
digit = PACKED_HIGH ( regs->VR_B( v1, packedix-- ) ) ;
|
|
|
|
/* increment curent digit and adjust scale */
|
|
/* result += scale * digit; */
|
|
/* scale *= 10; */
|
|
|
|
if (digit != 0)
|
|
{
|
|
temp128 = U128_mul_32 (scale, digit);
|
|
result = U128_add ( result, temp128 );
|
|
}
|
|
scale = U128_mul_32 (scale, 10);
|
|
|
|
// debug
|
|
// logmsg("vr_to_u128: i=%d, digit=%d \n", i, digit);
|
|
// u128_logmsg("...temp128", temp128);
|
|
// u128_logmsg("...scale ", scale);
|
|
// u128_logmsg("...result ", result);
|
|
}
|
|
|
|
/* temp128 is positive */
|
|
if (!forcePositive && IS_MINUS_SIGN( GET_VR_SIGN( v1 ) ) )
|
|
{
|
|
/* negate **/
|
|
SetZero_128( &zero128 );
|
|
result = U128_sub( zero128, result);
|
|
}
|
|
|
|
// u128_logmsg("vr_to_U128 return...", result);
|
|
return result;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Copy count packed digits from a vector register */
|
|
/* to a vector register */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register - copied to */
|
|
/* v2 vector register - copied from */
|
|
/* count number of digits to copy */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void vr_copy_to_vr(REGS* regs, int v1, int v2, int count)
|
|
{
|
|
int i; /* loop index */
|
|
int packedix; /* packed index */
|
|
|
|
SET_VR_ZERO( v1 );
|
|
|
|
/* copy Sign */
|
|
SET_VR_SIGN( v1, GET_VR_SIGN( v2) );
|
|
|
|
/* copy 'count' digits */
|
|
packedix = VR_PACKED_SIGN;
|
|
for ( i = MAX_DECIMAL_DIGITS; count > 0 && i >= 0; i--, count-- )
|
|
{
|
|
if (i & 1)
|
|
{
|
|
regs->VR_B( v1, packedix) |= regs->VR_B( v2, packedix) & 0xF0;
|
|
packedix--;
|
|
}
|
|
else
|
|
regs->VR_B( v1, packedix) |= regs->VR_B( v2, packedix) & 0x0F;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Is a packed decimal vector register zero */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register - copied to */
|
|
/* Returns: */
|
|
/* true all vr decimal packed digits are zero */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool vr_is_zero(REGS* regs, int v1)
|
|
{
|
|
int i; /* loop index */
|
|
|
|
/* first 30 digits, two at a time */
|
|
for ( i = 0; i < VR_PACKED_SIGN; i ++)
|
|
if ( regs->VR_B( v1, i) != 0 ) return false;
|
|
|
|
/* 31st digit */
|
|
if ( ( regs->VR_B( v1, VR_PACKED_SIGN ) & 0xF0) != 0 ) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Is a packed decimal vector register minus zero */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register - copied to */
|
|
/* Returns: */
|
|
/* true all vr decimal packed digits are zero and sign */
|
|
/* is negative */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool vr_is_minus_zero(REGS* regs, int v1)
|
|
{
|
|
if ( VR_HAS_MINUS_SIGN( v1 ) && vr_is_zero( regs, v1 ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* leading zeros of a packed decimal vector register */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register - copied to */
|
|
/* Returns: */
|
|
/* # of leading zeros */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline int vr_leading_zero(REGS* regs, int v1)
|
|
{
|
|
int i; /* loop index */
|
|
int packedix; /* packed index */
|
|
int count; /* leading zero count */
|
|
|
|
count = 0;
|
|
packedix = 0;
|
|
for ( i = 0; i < MAX_DECIMAL_DIGITS; i++, count++ )
|
|
{
|
|
if (i & 1)
|
|
{
|
|
if ( ( regs->VR_B( v1, packedix++) & 0x0F ) != 0 ) return count;
|
|
}
|
|
else
|
|
{
|
|
if ( ( regs->VR_B( v1, packedix) & 0xF0 ) != 0 ) return count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Load a valid packed decimal from a vector register to a decNumber */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register to check */
|
|
/* dn pointer to decNumber to save vector packed value */
|
|
/* forcePositive boolean to inicate whether the value should */
|
|
/* forced to a positive value */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void vr_to_decNumber( REGS* regs, int v1, decNumber* pdn, bool forcePositive )
|
|
{
|
|
QW vr_bigEndian; /* vr as big endian */
|
|
int scale = 0; /* always 0 for zn's */
|
|
|
|
/* decPacked assumes big-endian packed decimal */
|
|
vr_bigEndian = CSWAP128( regs->VR_Q( v1 ) );
|
|
decPackedToNumber( (uint8_t *) &vr_bigEndian, sizeof( QW ), &scale, pdn );
|
|
|
|
if (forcePositive && decNumberIsNegative( pdn ) )
|
|
pdn->bits &= ~( DECNEG ); /* efficieny hack */
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Load a vector register from a decNumber */
|
|
/* */
|
|
/* */
|
|
/* Input: */
|
|
/* regs CPU register context for VR access */
|
|
/* v1 vector register to check */
|
|
/* dn pointer to decNumber to save vector packed value */
|
|
/* forcePositive boolean to inicate whether the value should */
|
|
/* forced to a positive value */
|
|
/* rdc result digit count: the number of rightmost digits */
|
|
/* to load */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: if an overflow was recognized */
|
|
/* - decNumber overflowed */
|
|
/* - number of digits is greater than result */
|
|
/* digit count */
|
|
/* false: no overflow */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool vr_from_decNumber( REGS* regs, int v1, decNumber* pdn, bool forcePositive, int rdc )
|
|
{
|
|
int overflow = false; /* overflow recognized */
|
|
U8 bcd_zn[DECNUMDIGITS]; /* decimal digits */
|
|
int toCopy; /* number of digits to pack */
|
|
int i, j, k; /* indexes */
|
|
BYTE ps; /* packed sign */
|
|
int startZn; /* Zn index */
|
|
int startVr; /* vector index */
|
|
|
|
/* rdc safety check */
|
|
if ( rdc <= 0 ) rdc = MAX_DECIMAL_DIGITS;
|
|
|
|
// dn_logmsg("vr_from_decNumber:", pdn);
|
|
|
|
/* get binary code decimal of number */
|
|
decNumberGetBCD(pdn, bcd_zn);
|
|
|
|
/* set vector to zero */
|
|
SET_VR_ZERO( v1 );
|
|
|
|
/* determine decimals to copy and where to pack them */
|
|
toCopy = (pdn->digits <= rdc) ? pdn->digits : rdc;
|
|
startZn = pdn->digits - toCopy;
|
|
startVr = (MAX_DECIMAL_DIGITS - toCopy) / 2;
|
|
|
|
//logmsg("packing: startVr=%d, startZn=%d, toCopy=%d, rdc=%d, digits=%d\n",startVr, startZn, toCopy, rdc, pdn->digits);
|
|
|
|
/* Pack digits into vector register */
|
|
for (i=startZn, j=startVr, k=0; k < toCopy; i++, k++)
|
|
{
|
|
//logmsg("packing: k=%d, j (startVr)=%d, i (startZn)=%d, bcd_zn=%d, odd=%d\n", k, j, i, bcd_zn[i], ( (MAX_DECIMAL_DIGITS - toCopy + k) & 1) );
|
|
|
|
if ( (MAX_DECIMAL_DIGITS - toCopy + k) & 1)
|
|
regs->VR_B( v1, j++) |= bcd_zn[i];
|
|
else
|
|
regs->VR_B( v1, j) |= bcd_zn[i] << 4;
|
|
}
|
|
|
|
/* Pack the sign into low-order digit */
|
|
ps = ( forcePositive ) ? PREFERRED_ZONE : ( ( decNumberIsNegative( pdn ) ) ? PREFERRED_MINUS : PREFERRED_PLUS);
|
|
regs->VR_B( v1, VR_PACKED_SIGN) |= ps;
|
|
|
|
/* overflowed? */
|
|
if ( pdn->digits > rdc ||
|
|
pdn->digits > MAX_DECIMAL_DIGITS ||
|
|
pdn->exponent != 0 )
|
|
overflow = true;
|
|
|
|
return overflow;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Set a decContext to the default for Z/vector numbers (fixed) */
|
|
/* - no traps */
|
|
/* - 66 digits (note: could be 62 (31 digits * 31 digits) */
|
|
/* but want to ensure that exponent is */
|
|
/* always zero */
|
|
/* */
|
|
/* Input: */
|
|
/* set pointer to decContext to set defaults */
|
|
/* */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void zn_ContextDefault( decContext* set )
|
|
{
|
|
decContextDefault( set, DEC_INIT_BASE); // initialize
|
|
set->traps = 0; // no traps, thank you
|
|
set->digits= DECNUMDIGITS;
|
|
}
|
|
|
|
/*===================================================================*/
|
|
/* hexFloat (from float.c) */
|
|
/*===================================================================*/
|
|
/*-------------------------------------------------------------------*/
|
|
/* 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;
|
|
|
|
/*===================================================================*/
|
|
/* copied from float.c TEMPORARY */
|
|
/*===================================================================*/
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Get extended float from registers */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted to */
|
|
/* fpr1 Pointer to first register to be converted from */
|
|
/* fpr2 Pointer to second register to be converted from */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void get_ef( EXTENDED_FLOAT *fl, U64 *fpr1, U64 *fpr2)
|
|
{
|
|
fl->sign = *fpr1 >> 63;
|
|
fl->expo = (*fpr1 >> 56) & 0x007F;
|
|
fl->ms_fract = (*fpr1 & 0x00FFFFFFFFFFFFFFULL) >> 8;
|
|
fl->ls_fract = (*fpr1 << 56)
|
|
| (*fpr2 & 0x00FFFFFFFFFFFFFFULL);
|
|
|
|
} /* end function get_ef */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 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 */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* 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, U64 *fpr )
|
|
{
|
|
*fpr = ((U64)fl->sign << 63)
|
|
| ((U64)fl->expo << 56)
|
|
| (fl->long_fract);
|
|
|
|
} /* end function store_lf */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Store extended float to register */
|
|
/* */
|
|
/* Input: */
|
|
/* fl Internal float format to be converted from */
|
|
/* fpr1 Pointer to first register to be converted to */
|
|
/* fpr2 Pointer to second register to be converted to */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void store_ef( EXTENDED_FLOAT *fl, U64 *fpr1, U64 *fpr2 )
|
|
{
|
|
*fpr1 = ((U64)fl->sign << 63)
|
|
| ((U64)fl->expo << 56)
|
|
| (fl->ms_fract << 8)
|
|
| (fl->ls_fract >> 56);
|
|
*fpr2 = ((U64)fl->sign << 63)
|
|
| (fl->ls_fract & 0x00FFFFFFFFFFFFFFULL);
|
|
|
|
if ( *fpr1 || *fpr2 ) {
|
|
*fpr2 |= ((((U64)fl->expo << 56) - 0x0E00000000000000ULL) & 0x7F00000000000000ULL);
|
|
}
|
|
|
|
} /* end function store_ef */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* HEX FLOATING-POINT HELPERS */
|
|
/*-------------------------------------------------------------------*/
|
|
#undef SHORT_FLOAT_NUM_DIGITS
|
|
#define SHORT_FLOAT_NUM_DIGITS 6
|
|
|
|
#undef LONG_FLOAT_NUM_DIGITS
|
|
#define LONG_FLOAT_NUM_DIGITS 14
|
|
|
|
#undef EXTENDED_FLOAT_NUM_DIGITS
|
|
#define EXTENDED_FLOAT_NUM_DIGITS 28
|
|
|
|
/*===================================================================*/
|
|
/* hexNumber */
|
|
/*===================================================================*/
|
|
/* hexNumber is similar to decNumber but with base 16 digits */
|
|
/*===================================================================*/
|
|
|
|
/* Bit settings for hexNumber.bits (same as decNumber) */
|
|
#define HEXNEG DECNEG /* Sign; 1=negative, 0=positive or zero */
|
|
#define HEXINF DECINF /* 1=Infinity */
|
|
#define HEXNAN DECNAN /* 1=NaN */
|
|
#define HEXSNAN DECSNAN /* 1=sNaN */
|
|
|
|
typedef struct {
|
|
int digits; /* Count of digits in the coefficient; >0 */
|
|
int exponent; /* Unadjusted exponent, unbiased, in */
|
|
/* range: -1999999997 through 999999999 */
|
|
uint8_t bits; /* Indicator bits (see decNumber) */
|
|
/* Coefficient, from least significant unit */
|
|
char hexDigit[DECNUMDIGITS];
|
|
} hexNumber;
|
|
|
|
/* hexNumnber prototypes */
|
|
static inline void hexNumberZero( hexNumber* hexN );
|
|
static inline bool hexNumberIsZero( hexNumber* hexN );
|
|
static inline void hexNumberCopy( hexNumber* hn, hexNumber* rhs);
|
|
static inline void hexNumberToString( hexNumber* hexN, char* s );
|
|
static inline void decNumberToHexNumber( decNumber * dn, hexNumber* hexN );
|
|
static inline void decNumberFromExtendedFloat( decNumber * dn, EXTENDED_FLOAT* ef );
|
|
static inline void hexNumberRound( hexNumber* hn, hexNumber* rhs, int numDigits );
|
|
static inline void hexNumberSplit( hexNumber* hn, SHORT_FLOAT* sf, LONG_FLOAT* lf );
|
|
static inline void hexNumberToShortFloat( hexNumber* hn, SHORT_FLOAT* sf );
|
|
static inline void hexNumberToLongFloat( hexNumber* hn, LONG_FLOAT* lf );
|
|
static inline void hexNumberToExtendedFloat( hexNumber* hn, EXTENDED_FLOAT* ef );
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberZero: set a hexNumber to zero */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void hexNumberZero( hexNumber* hexN )
|
|
{
|
|
hexN->bits = 0;
|
|
hexN->exponent = 0;
|
|
hexN->digits = 1;
|
|
hexN->hexDigit[0] = 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberIsZero: is hexNumber zero? */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool hexNumberIsZero( hexNumber* hexN )
|
|
{
|
|
if ( 1 &&
|
|
(hexN->bits & ~HEXNEG) == 0 &&
|
|
hexN->exponent == 0 &&
|
|
hexN->digits == 1 &&
|
|
hexN->hexDigit[0] == 0
|
|
)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberCopy: copy hexNumber */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void hexNumberCopy( hexNumber* hn, hexNumber* rhs)
|
|
{
|
|
memcpy( hn, rhs, sizeof(hexNumber) );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberToString: convert hexNumber to a string */
|
|
/* NOTE: currently only converts coefficient */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void hexNumberToString( hexNumber* hexN, char* s )
|
|
{
|
|
char hc[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
'A', 'B', 'C', 'D', 'E', 'F'
|
|
};
|
|
int i;
|
|
for ( i = 0; i < hexN->digits; i++ )
|
|
s[hexN->digits-1 - i] = hc[ (int) hexN->hexDigit[i] ];
|
|
|
|
s[ hexN->digits ] = 0; /* add \0 to end string */
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* decNumberToHexNumber: convert a decNumber to a hexNumber */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void decNumberToHexNumber( decNumber * dn, hexNumber* hexN )
|
|
{
|
|
int i; /* loop index */
|
|
int hexNumberDigits; /* count of hex digits */
|
|
decNumber dn16; /* decNumber constant 16 */
|
|
decNumber dnrem; /* remainder decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decContext set; /* zn default context */
|
|
|
|
zn_ContextDefault( &set );
|
|
decNumberFromInt32( &dn16, 16 );
|
|
|
|
decNumberCopy( &dntemp, dn);
|
|
dntemp.bits &= ~DECNEG; /* set positive */
|
|
|
|
for ( i = 0, hexNumberDigits = 0; !decNumberIsZero( &dntemp ) && i < DECNUMDIGITS; i++ )
|
|
{
|
|
decNumberRemainder( &dnrem, &dntemp, &dn16, &set );
|
|
decNumberDivideInteger( &dntemp, &dntemp, &dn16, &set );
|
|
hexN->hexDigit[ hexNumberDigits ] = (U8) decNumberToUInt32( &dnrem, &set );
|
|
|
|
//logmsg(" VSCHP - hexNumber digit: %x \n", hexN->hexDigit[ hexNumberDigits ] );
|
|
|
|
hexNumberDigits++;
|
|
}
|
|
|
|
hexN->bits = dn->bits; /* same sign */
|
|
hexN->digits = hexNumberDigits;
|
|
hexN->exponent = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* decNumberFromExtendedFloat: convert an Extended Float to decNumber*/
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void decNumberFromExtendedFloat( decNumber * dn, EXTENDED_FLOAT* ef)
|
|
{
|
|
|
|
unsigned int hexpart; /* part of ef fraction */
|
|
decNumber dn16; /* decNumber constant 16 */
|
|
decNumber dnpart; /* hxpart as decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decNumber dnraise; /* raise to decNumber */
|
|
decNumber dnpower; /* using in decNumberPower */
|
|
decContext set; /* zn default context */
|
|
|
|
zn_ContextDefault( &set );
|
|
decNumberFromInt32( &dn16, 16 );
|
|
decNumberZero( dn );
|
|
|
|
/* let decNumber do the heavy lifting */
|
|
/* process fraction in 32-bit chunks */
|
|
|
|
/* chunk 1: ls - low 32 bits */
|
|
hexpart = ef->ls_fract & 0x00000000FFFFFFFFULL;
|
|
if (hexpart != 0)
|
|
{
|
|
decNumberFromUInt32( &dnpart, hexpart );
|
|
decNumberFromInt32 ( &dnraise, ef->expo - 64 - (4+8+8+8) );
|
|
decNumberPower( &dnpower, &dn16, &dnraise, &set );
|
|
decNumberMultiply( dn, &dnpart, &dnpower, &set );
|
|
decNumberTrim( dn );
|
|
|
|
if (0) /* debug */
|
|
{
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 1 - dnpart: ", &dnpart);
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 1 - dn: ", dn);
|
|
}
|
|
}
|
|
|
|
/* chunk 2: ls - high 32 bits */
|
|
hexpart = ef->ls_fract >> 32;
|
|
if (hexpart != 0)
|
|
{
|
|
decNumberFromUInt32( &dnpart, hexpart );
|
|
decNumberFromInt32 ( &dnraise, ef->expo - 64 - (4+8+8) );
|
|
decNumberPower( &dnpower, &dn16, &dnraise, &set );
|
|
decNumberMultiply( &dntemp, &dnpart, &dnpower, &set );
|
|
decNumberAdd( dn, dn, &dntemp, &set );
|
|
decNumberTrim( dn );
|
|
|
|
if (0) /* debug */
|
|
{
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 2 - dntemp: ", &dntemp);
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 2 - dn: ", dn);
|
|
}
|
|
}
|
|
|
|
/* chunk 3: ms - low 32 bits */
|
|
hexpart = ef->ms_fract & 0x00000000FFFFFFFFULL;
|
|
if (hexpart != 0)
|
|
{
|
|
decNumberFromUInt32( &dnpart, hexpart );
|
|
decNumberFromInt32 ( &dnraise, ef->expo - 64 - (4+8) );
|
|
decNumberPower( &dnpower, &dn16, &dnraise, &set );
|
|
decNumberMultiply( &dntemp, &dnpart, &dnpower, &set );
|
|
decNumberAdd( dn, dn, &dntemp, &set );
|
|
decNumberTrim( dn );
|
|
|
|
if (0) /* debug */
|
|
{
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 3 - dntemp: ", &dntemp);
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 3 - dn: ", dn);
|
|
}
|
|
}
|
|
|
|
/* chunk 3: ms - high 32 bits */
|
|
hexpart = ef->ms_fract >> 32;
|
|
if (hexpart != 0)
|
|
{
|
|
decNumberFromUInt32( &dnpart, hexpart );
|
|
decNumberFromInt32 ( &dnraise, ef->expo - 64 - (4) );
|
|
decNumberPower( &dnpower, &dn16, &dnraise, &set );
|
|
decNumberMultiply( &dntemp, &dnpart, &dnpower, &set );
|
|
decNumberAdd( dn, dn, &dntemp, &set );
|
|
decNumberTrim( dn );
|
|
|
|
|
|
if (0) /* debug */
|
|
{
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 4 - dntemp: ", &dntemp);
|
|
dn_logmsg("decNumberFromExtendedFloat: chunk 4 - dn: ", dn);
|
|
}
|
|
}
|
|
|
|
/* set sign */
|
|
if (ef->sign)
|
|
{ /* negative */
|
|
decNumberMinus( dn, dn, &set );
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberRound: round a hexNumber for a # of significant digits */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void hexNumberRound( hexNumber* hn, hexNumber* rhs, int numDigits )
|
|
{
|
|
int i; /* loop index */
|
|
int carry; /* carry for rounding */
|
|
int idxGuard; /* index of guard digit */
|
|
int hexTemp; /* temp hex digit */
|
|
int hnIndex; /* index to hn digit */
|
|
|
|
if ( rhs->digits <= numDigits) /* is rounding requied */
|
|
{
|
|
hexNumberCopy( hn, rhs);
|
|
return;
|
|
}
|
|
|
|
hn->bits = rhs->bits;
|
|
hn->exponent = rhs->exponent + rhs->digits - numDigits;
|
|
hn-> digits = numDigits;
|
|
|
|
/* initial carry */
|
|
idxGuard = rhs->digits - numDigits -1;
|
|
carry = (rhs->hexDigit[ idxGuard ] + 8) >> 4;
|
|
|
|
/* copy digits with carry */
|
|
for( i = idxGuard+1, hnIndex = 0; i < rhs->digits; i++, hnIndex++ )
|
|
{
|
|
if (carry == 0)
|
|
{
|
|
hn->hexDigit[ hnIndex ] = rhs->hexDigit[ i ];
|
|
continue;
|
|
}
|
|
|
|
/* adjust with carry */
|
|
hexTemp = rhs->hexDigit[ i ] + carry;
|
|
carry = hexTemp >> 4;
|
|
hexTemp = hexTemp & 0x0F;
|
|
hn->hexDigit[ hnIndex ] = hexTemp;
|
|
}
|
|
|
|
/* carry -> additional digit */
|
|
if ( carry != 0 )
|
|
{
|
|
hn->hexDigit[ hn->digits ] = carry;
|
|
hn->digits++;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberSplit: split hexNumber to a Short_Float & a Long_Float */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void hexNumberSplit( hexNumber* hn, SHORT_FLOAT* sf, LONG_FLOAT* lf )
|
|
{
|
|
int i; /* loop index */
|
|
hexNumber shex; /* short hexNumber */
|
|
hexNumber lhex; /* long hexNumber */
|
|
|
|
/* long float is 0? */
|
|
if( hn->digits <= SHORT_FLOAT_NUM_DIGITS )
|
|
{
|
|
hexNumberToShortFloat( hn, sf);
|
|
hexNumberZero ( &lhex );
|
|
hexNumberToLongFloat( &lhex, lf);
|
|
return;
|
|
}
|
|
|
|
/* have to split hn */
|
|
/* high result - short_float */
|
|
hexNumberCopy(&shex, hn);
|
|
shex.exponent += hn->digits - SHORT_FLOAT_NUM_DIGITS;
|
|
shex.digits = SHORT_FLOAT_NUM_DIGITS;
|
|
for (i = 0; i < SHORT_FLOAT_NUM_DIGITS; i++)
|
|
shex.hexDigit[ i ] = shex.hexDigit[ hn->digits - SHORT_FLOAT_NUM_DIGITS + i];
|
|
hexNumberToShortFloat( &shex, sf);
|
|
|
|
/* low result - long_float */
|
|
hexNumberCopy(&lhex, hn);
|
|
lhex.exponent = hn->exponent;
|
|
lhex.digits = hn->digits - SHORT_FLOAT_NUM_DIGITS;
|
|
|
|
/* remove high order '0' digits */
|
|
for (i = lhex.digits -1; i > 0 ;i--)
|
|
{
|
|
if ( lhex.hexDigit[ i ] == 0 )
|
|
lhex.digits--;
|
|
else
|
|
break;
|
|
}
|
|
hexNumberToLongFloat( &lhex, lf);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberToShortFloat: convert hexNumber to Short_Float */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline void hexNumberToShortFloat( hexNumber* hn, SHORT_FLOAT* sf )
|
|
{
|
|
int i; /* loop index */
|
|
int hxdc; /* hex digit count */
|
|
U32 sfDigits[SHORT_FLOAT_NUM_DIGITS]; /* short float digits */
|
|
|
|
/* sign */
|
|
sf->sign = (hn->bits & HEXNEG) ? 1 : 0;
|
|
|
|
/* fraction digits */
|
|
sf->short_fract = 0;
|
|
memset( sfDigits, 0, sizeof(sfDigits) );
|
|
for ( i= hn->digits -1, hxdc = 0; i >= 0 && hxdc < SHORT_FLOAT_NUM_DIGITS; i--, hxdc++)
|
|
sfDigits[ hxdc ] = hn->hexDigit[ i ];
|
|
|
|
/* note: let compiler optimize */
|
|
sf->short_fract = (U32) ( sfDigits[0] << 20 ) |
|
|
(U32) ( sfDigits[1] << 16 ) |
|
|
(U32) ( sfDigits[2] << 12 ) |
|
|
(U32) ( sfDigits[3] << 8 ) |
|
|
(U32) ( sfDigits[4] << 4 ) |
|
|
(U32) ( sfDigits[5] );
|
|
|
|
/* exponent +64 */
|
|
sf->expo = hn->exponent + hn->digits +64;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberToLongFloat: convert hexNumber to Long_Float */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
static inline void hexNumberToLongFloat( hexNumber* hn, LONG_FLOAT* lf )
|
|
{
|
|
int i; /* loop index */
|
|
int hxdc; /* hex digit count */
|
|
U8 lfDigits[LONG_FLOAT_NUM_DIGITS]; /* long float digits */
|
|
int shift; /* shift left amount */
|
|
|
|
/* sign */
|
|
lf->sign = (hn->bits & HEXNEG) ? 1 : 0;
|
|
|
|
/* fraction digits */
|
|
lf->long_fract = 0;
|
|
memset( lfDigits, 0, sizeof(lfDigits) );
|
|
for ( i= hn->digits -1, hxdc = 0; i >= 0 && hxdc < LONG_FLOAT_NUM_DIGITS; i--, hxdc++)
|
|
lfDigits[ hxdc ] = hn->hexDigit[ i ];
|
|
|
|
|
|
for (i = 0, shift = 64-8-4; i < LONG_FLOAT_NUM_DIGITS; i++, shift-=4)
|
|
lf->long_fract |= (U64) ( ( (U64)lfDigits [ i ] ) << shift);
|
|
|
|
|
|
/* exponent +64 */
|
|
lf->expo = hn->exponent + hn->digits +64;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* hexNumberToExtendedFloat: convert hexNumber to Extended_Float */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
static inline void hexNumberToExtendedFloat( hexNumber* hn, EXTENDED_FLOAT* ef )
|
|
{
|
|
int i; /* loop index */
|
|
int hxdc; /* hex digit count */
|
|
U8 efDigits[EXTENDED_FLOAT_NUM_DIGITS]; /* extended float digits*/
|
|
int shift; /* shift left amount */
|
|
U64 ms_f = 0; /* ms fraction */
|
|
U64 ls_f = 0; /* ls fraction */
|
|
|
|
/* sign */
|
|
ef->sign = (hn->bits & HEXNEG) ? 1 : 0;
|
|
|
|
/* fraction digits */
|
|
ef->ms_fract = 0;
|
|
ef->ls_fract = 0;
|
|
memset( efDigits, 0, sizeof(efDigits) );
|
|
for ( i= hn->digits -1, hxdc = 0; i >= 0 && hxdc < EXTENDED_FLOAT_NUM_DIGITS; i--, hxdc++)
|
|
efDigits[ hxdc ] = hn->hexDigit[ i ];
|
|
|
|
/* ms_fraction - first half */
|
|
for (i = 0, shift = 64-8-4; i < EXTENDED_FLOAT_NUM_DIGITS / 2; i++, shift-=4)
|
|
ms_f |= (U64) ( ( (U64)efDigits [ i ] ) << shift);
|
|
|
|
/* ls_fraction - second half */
|
|
for (i = EXTENDED_FLOAT_NUM_DIGITS / 2, shift = 64-8-4; i < EXTENDED_FLOAT_NUM_DIGITS ; i++, shift-=4)
|
|
ls_f |= (U64) ( ( (U64)efDigits [ i ] ) << shift);
|
|
|
|
/* reformat fraction to float.c Extended */
|
|
ef->ms_fract = ms_f >> 8;
|
|
ef->ls_fract = ms_f << 56 | ls_f;
|
|
|
|
/* exponent +64 */
|
|
ef->expo = hn->exponent + hn->digits +64;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Extended Zone Format helpers */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/* zoned byte */
|
|
enum ZONED_BYTE_FORMAT
|
|
{
|
|
SD_BYTE =1, // SD-byte format (sign and digit)
|
|
ZD_BYTE, // ZD-byte format (zone and digit)
|
|
SP_BYTE, // SP-byte format (space)
|
|
SS_BYTE // SS-byte format (separate sign)
|
|
};
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Check a zoned source vector sign is valid */
|
|
/* */
|
|
/* Input: */
|
|
/* sign signed byte */
|
|
/* zsf zoned byte format of sign */
|
|
/* isZero is the zoned =number zero? */
|
|
/* stc Sign-Test Control (STC) (value 0-7) */
|
|
/* */
|
|
/* Returns: */
|
|
/* true: the sign is valid */
|
|
/* false: the sign is invalid */
|
|
/*-------------------------------------------------------------------*/
|
|
static inline bool zoned_valid_sign_enhanced (
|
|
BYTE sign, /* zoned byte containing the sign */
|
|
enum ZONED_BYTE_FORMAT zsf, /* sign format */
|
|
bool isZero, /* is the zone number zero? */
|
|
int stc) /* Sign-Test Control (STC) (value 0-7) */
|
|
{
|
|
bool valid = TRUE; /* valid result */
|
|
|
|
if (zsf == SS_BYTE)
|
|
{
|
|
/* SS formated sign */
|
|
switch (stc)
|
|
{
|
|
case 2: /* STC = 010 */
|
|
valid = sign == 0X4E || sign == 0X60;
|
|
break;
|
|
|
|
case 3: /* STC = 010 */
|
|
if (isZero)
|
|
{
|
|
valid = sign == 0X4E;
|
|
}
|
|
else
|
|
{
|
|
valid = sign == 0X4E || sign == 0X60;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
/* SD formated sign */
|
|
sign = ZONED_SIGN( sign ) ;
|
|
switch (stc)
|
|
{
|
|
case 0: /* STC = 000 */
|
|
valid = sign >= 0X0A;
|
|
break;
|
|
|
|
case 1: /* STC = 001 */
|
|
if (isZero)
|
|
{
|
|
valid = sign == 0x0A || sign == 0x0C || sign == 0x0E || sign == 0x0F;
|
|
}
|
|
else
|
|
{
|
|
valid = sign >= 0X0A;
|
|
}
|
|
break;
|
|
|
|
case 2: /* STC = 010 */
|
|
valid = sign == 0x0C || sign == 0x0D;
|
|
break;
|
|
|
|
case 3: /* STC = 011 */
|
|
if (isZero)
|
|
{
|
|
valid = sign == 0X0C;
|
|
}
|
|
else
|
|
{
|
|
valid = sign == 0x0C || sign == 0x0D;
|
|
}
|
|
break;
|
|
|
|
case 4: /* STC = 100 */
|
|
case 5: /* STC = 101 */
|
|
valid = sign == 0X0F;
|
|
break;
|
|
|
|
case 6: /* STC = 110 */
|
|
valid = sign == 0x0C || sign == 0x0D || sign == 0x0F;
|
|
break;
|
|
|
|
case 7: /* STC = 111 */
|
|
if (isZero)
|
|
{
|
|
valid = sign == 0x0C || sign == 0x0F;
|
|
}
|
|
else
|
|
{
|
|
valid = sign == 0x0C || sign == 0x0D || sign == 0x0F;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
#endif /*!defined(_ZVECTOR2_ARCH_INDEPENDENT_)*/
|
|
|
|
|
|
/*===================================================================*/
|
|
/* Achitecture Dependent Routines / Instructions */
|
|
/*===================================================================*/
|
|
|
|
#if defined( FEATURE_148_VECTOR_ENH_FACILITY_2 )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E601 VLEBRH - VECTOR LOAD BYTE REVERSED ELEMENT (16) [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_byte_reversed_element_16 )
|
|
{
|
|
int v1, m3, x2, b2;
|
|
VADR effective_addr2;
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK (regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
if (m3 > 7) /* M3 > 7 => Specficitcation excp */
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
regs->VR_H( v1, m3 ) = bswap_16( ARCH_DEP( vfetch2 )( effective_addr2, b2, regs ) );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E602 VLEBRG - VECTOR LOAD BYTE REVERSED ELEMENT (64) [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_byte_reversed_element_64 )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
if (m3 > 1) /* M3 > 1 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
regs->VR_D( v1, m3 ) = bswap_64( ARCH_DEP( vfetch8 )( effective_addr2, b2, regs ) );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E603 VLEBRF - VECTOR LOAD BYTE REVERSED ELEMENT (32) [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_byte_reversed_element_32 )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
if (m3 > 3) /* M3 > 3 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
regs->VR_F( v1, m3 ) = bswap_32( ARCH_DEP( vfetch4 )( effective_addr2, b2, regs ) );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E604 VLLEBRZ - VECTOR LOAD BYTE REVERSED ELEMENT AND ZERO [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_byte_reversed_element_and_zero )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
/* M3= 0, 4, 5, 7-15 => Specficitcation excp */
|
|
if (m3 == 0 || m3 == 4 || m3 == 5 || m3 >=7 )
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
SET_VR_ZERO( v1 );
|
|
|
|
switch (m3)
|
|
{
|
|
case 1: regs->VR_H( v1, 3 ) = bswap_16( ARCH_DEP( vfetch2 )( effective_addr2, b2, regs ) ); break;
|
|
case 2: regs->VR_F( v1, 1 ) = bswap_32( ARCH_DEP( vfetch4 )( effective_addr2, b2, regs ) ); break;
|
|
case 3: regs->VR_D( v1, 0 ) = bswap_64( ARCH_DEP( vfetch8 )( effective_addr2, b2, regs ) ); break;
|
|
case 6: regs->VR_F( v1, 0 ) = bswap_32( ARCH_DEP( vfetch4 )( effective_addr2, b2, regs ) ); break;
|
|
default:
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
break;
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* E605 VLBRREP - VECTOR LOAD BYTE REVERSED ELEMENT AND REPLICATE [VRX] */
|
|
/*----------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_byte_reversed_element_and_replicate )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int i; /* Loop variable */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
switch (m3)
|
|
{
|
|
case 1:
|
|
regs->VR_H( v1, 0 ) = bswap_16( ARCH_DEP( vfetch2 )( effective_addr2, b2, regs ) );
|
|
for (i=1; i < 8; i++)
|
|
regs->VR_H( v1, i ) = regs->VR_H( v1, 0 );
|
|
break;
|
|
|
|
case 2:
|
|
regs->VR_F( v1, 0 ) = bswap_32( ARCH_DEP( vfetch4 )( effective_addr2, b2, regs ) );
|
|
for (i=1; i < 4; i++)
|
|
regs->VR_F( v1, i ) = regs->VR_F( v1, 0 );
|
|
break;
|
|
|
|
case 3:
|
|
regs->VR_D( v1, 0 ) = bswap_64( ARCH_DEP( vfetch8 )( effective_addr2, b2, regs ) );
|
|
regs->VR_D( v1, 1 ) = regs->VR_D( v1, 0 );
|
|
break;
|
|
|
|
default:
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
break;
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E606 VLBR - VECTOR LOAD BYTE REVERSED ELEMENTS [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_byte_reversed_elements )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int i; /* Loop variable */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
switch (m3)
|
|
{
|
|
case 1: /* halfword */
|
|
for (i=0; i < 8; i++)
|
|
regs->VR_H( v1, i ) = bswap_16( ARCH_DEP( vfetch2 )( effective_addr2 + i*2, b2, regs ) );
|
|
break;
|
|
|
|
case 2: /* fullword */
|
|
for (i=0; i < 4; i++)
|
|
regs->VR_F( v1, i ) = bswap_32( ARCH_DEP( vfetch4 )( effective_addr2 + i *4, b2, regs ) );
|
|
break;
|
|
|
|
case 3: /* doubleword */
|
|
for (i=0; i < 2; i++)
|
|
regs->VR_D( v1, i ) = bswap_64( ARCH_DEP( vfetch8 )( effective_addr2 + i*8, b2, regs ) );
|
|
break;
|
|
|
|
case 4: /* quadword */
|
|
regs->VR_Q( v1 ) = bswap_128( ARCH_DEP( vfetch16 )( effective_addr2, b2, regs ) );
|
|
break;
|
|
|
|
default: /* M3= 0, 5-15 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
break;
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E607 VLER - VECTOR LOAD ELEMENTS REVERSED [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_elements_reversed )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int i; /* Loop variable */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
/* M3= 0, 5-15 => Specficitcation excp */
|
|
if (m3 == 0 || m3 >=5 )
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
switch (m3)
|
|
{
|
|
case 1: /* halfword */
|
|
for (i=0; i < 8; i++)
|
|
regs->VR_H( v1, (7 - i) ) = ARCH_DEP( vfetch2 )( effective_addr2 + i*2, b2, regs );
|
|
break;
|
|
|
|
case 2: /* fullword */
|
|
for (i=0; i < 4; i++)
|
|
regs->VR_F( v1, (3 - i) ) = ARCH_DEP( vfetch4 )( effective_addr2 + i *4, b2, regs );
|
|
break;
|
|
|
|
case 3: /* doubleword */
|
|
for (i=0; i < 2; i++)
|
|
regs->VR_D( v1, (1 - i) ) = ARCH_DEP( vfetch8 )( effective_addr2 + i*8, b2, regs );
|
|
break;
|
|
|
|
default: /* M3= 0, 4-15 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
break;
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E609 VSTEBRH - VECTOR STORE BYTE REVERSED ELEMENT (16) [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_store_byte_reversed_element_16 )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
VRX(inst, regs, v1, x2, b2, effective_addr2, m3);
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
if (m3 > 7) /* M3 > 7 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
ARCH_DEP( vstore2 )( bswap_16( regs->VR_H( v1, m3 ) ), effective_addr2, b2, regs );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E60A VSTEBRG - VECTOR STORE BYTE REVERSED ELEMENT (64) [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_store_byte_reversed_element_64 )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
if (m3 > 1) /* M3 > 1 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
ARCH_DEP( vstore8 )( bswap_64( regs->VR_D( v1, m3 ) ), effective_addr2, b2, regs );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E60B VSTEBRF - VECTOR STORE BYTE REVERSED ELEMENT (32) [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_store_byte_reversed_element_32 )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
if (m3 > 3) /* M3 > 3 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
ARCH_DEP( vstore4 )( bswap_32( regs->VR_F( v1, m3 ) ), effective_addr2, b2, regs );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E60E VSTBR - VECTOR STORE BYTE REVERSED ELEMENTS [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_store_byte_reversed_elements )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int i; /* Loop variable */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
switch (m3)
|
|
{
|
|
case 1: /* halfword */
|
|
for (i=0; i < 8; i++)
|
|
ARCH_DEP( vstore2 )( bswap_16( regs->VR_H( v1, i ) ), effective_addr2 + i*2, b2, regs );
|
|
break;
|
|
|
|
case 2: /* fullword */
|
|
for (i=0; i < 4; i++)
|
|
ARCH_DEP( vstore4 )( bswap_32( regs->VR_F( v1, i ) ), effective_addr2 + i*4, b2, regs );
|
|
break;
|
|
|
|
case 3: /* doubleword */
|
|
for (i=0; i < 2; i++)
|
|
ARCH_DEP( vstore8 )( bswap_64( regs->VR_D( v1, i ) ), effective_addr2 + i*8, b2, regs );
|
|
break;
|
|
|
|
case 4: /* quadword */
|
|
ARCH_DEP( vstore16 )( bswap_128( regs->VR_Q( v1 ) ), effective_addr2, b2, regs );
|
|
break;
|
|
|
|
default: /* M3= 0, 5-15 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
break;
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E60F VSTER - VECTOR STORE ELEMENTS REVERSED [VRX] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_store_elements_reversed )
|
|
{
|
|
int v1, m3, x2, b2; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int i; /* Loop variable */
|
|
|
|
VRX( inst, regs, v1, x2, b2, effective_addr2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK2( regs, x2, b2 );
|
|
|
|
switch (m3)
|
|
{
|
|
case 1: /* halfword */
|
|
for (i=0; i < 8; i++)
|
|
ARCH_DEP( vstore2 )( regs->VR_H( v1, i ) , effective_addr2 + (14 - i*2), b2, regs );
|
|
break;
|
|
|
|
case 2: /* fullword */
|
|
for (i=0; i < 4; i++)
|
|
ARCH_DEP( vstore4 )( regs->VR_F( v1, i ) , effective_addr2 + (12 - i*4), b2, regs );
|
|
break;
|
|
|
|
case 3: /* doubleword */
|
|
for (i=0; i < 2; i++)
|
|
ARCH_DEP( vstore8 )( regs->VR_D( v1, i ), effective_addr2 + (8 - i*8), b2, regs );
|
|
break;
|
|
|
|
default: /* M3= 0, 4-15 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
break;
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_148_VECTOR_ENH_FACILITY_2 ) */
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E634 VPKZ - VECTOR PACK ZONED [VSI] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_pack_zoned )
|
|
{
|
|
int v1, b2, i3; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int l2; /* length code (L2) control */
|
|
int i; /* Loop variable */
|
|
U8 zoned[MAX_ZONED_LENGTH]; /* local zoned decimal */
|
|
U8 digit_high; /* high digit of packed byte */
|
|
U8 digit_low; /* low digit of packed byte */
|
|
int packedix = 0; /* current packed byte index */
|
|
|
|
VSI( inst, regs, i3, b2, effective_addr2, v1 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
/* i3 reserved bits 0-2 must be zero */
|
|
if ( ( i3 & 0xE0 ) != 0 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
l2 = i3 & 0x1F; /* Operand 2 Length Code (L2): Bits 3-7 */
|
|
if ( l2 > 30 ) /* L2 > 30 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* get local copy; note: l2 is zoned length -1 */
|
|
ARCH_DEP( vfetchc )( zoned, l2, effective_addr2, b2, regs );
|
|
|
|
/* set v1 to zero */
|
|
SET_VR_ZERO( v1 );
|
|
|
|
/* handle last zoned field */
|
|
digit_low = ZONED_SIGN( zoned[ l2 ] ); /* sign */
|
|
digit_high = ZONED_DECIMAL( zoned[ l2 ] ); /* lowest digit */
|
|
regs->VR_B( v1, 15 ) = ( digit_high << 4 ) | digit_low;
|
|
//LOGMSG("VECTOR PACK ZONED: V1.B15=%hhX \n", regs->VR_B( v1, 15));
|
|
|
|
packedix = 14;
|
|
for ( i=l2 -1; i >=0; i -= 2, packedix--)
|
|
{
|
|
digit_low = ZONED_DECIMAL( zoned[ i ] );
|
|
digit_high = (i > 0 ) ? ZONED_DECIMAL( zoned[ i-1 ] ) << 4 : 0; /* have two digits? */
|
|
regs->VR_B( v1, packedix) = digit_high | digit_low;
|
|
//LOGMSG("VECTOR PACK ZONED: %d low:'%hhX' high: '%hhX' result: V%d.B%d=%hhX \n", i, zoned [i], zoned[i-1], v1, packedix, regs->VR_B( v1, packedix));
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E635 VLRL - VECTOR LOAD RIGHTMOST WITH LENGTH [VSI] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_rightmost_with_length )
|
|
{
|
|
int v1, b2, i3; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int l2; /* length code (L2) control */
|
|
int i; /* Loop variable */
|
|
U8 stor[16]; /* local stor */
|
|
|
|
VSI( inst, regs, i3, b2, effective_addr2, v1 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
l2 = i3 & 0xF0; /* i3 reserved bits 0-3 must be zero */
|
|
if ( l2 != 0 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
l2 = i3 & 0x0F; /* Operand 2 Length Code (L2): Bits 4-7 */
|
|
|
|
/* get local copy; note: l2 is length -1 */
|
|
ARCH_DEP( vfetchc )( stor, l2, effective_addr2, b2, regs );
|
|
|
|
/* set v1 to zero */
|
|
SET_VR_ZERO( v1 );
|
|
|
|
for ( i=0; i <= l2; i++ )
|
|
{
|
|
regs->VR_B( v1, (15 - l2) + i) = stor[i];
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E637 VLRLR - VECTOR LOAD RIGHTMOST WITH LENGTH (reg) [VRS-d] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_rightmost_with_length_reg )
|
|
{
|
|
int v1, b2, r3; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int l2; /* length code (L2) control */
|
|
int i; /* Loop variable */
|
|
U8 stor[16]; /* local stor */
|
|
U32 reg32; /* r3: bits 32-63 */
|
|
|
|
VRS_D( inst, regs, r3, b2, effective_addr2, v1 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
reg32 = regs->GR_L( r3 );
|
|
l2 = ( reg32 > 15 ) ? 15 : (int) reg32 ;
|
|
//LOGMSG("VECTOR LOAD RIGHTMOST WITH LENGTH (reg) : r3=%d, reg32=%d, l2=%d \n", r3, reg32, l2);
|
|
|
|
/* get local copy; note: l2 is length -1 */
|
|
ARCH_DEP( vfetchc )( stor, l2, effective_addr2, b2, regs );
|
|
|
|
/* set v1 to zero */
|
|
SET_VR_ZERO( v1 );
|
|
|
|
for ( i=0; i <= l2; i++ )
|
|
{
|
|
regs->VR_B( v1, (15 - l2) + i) = stor[i];
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E63C VUPKZ - VECTOR UNPACK ZONED [VSI] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_unpack_zoned )
|
|
{
|
|
int v1, b2, i3; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int l2; /* length code (L2) control */
|
|
int i; /* Loop variable */
|
|
U8 zoned[MAX_ZONED_LENGTH]; /* local zoned decimal */
|
|
U8 sign; /* sign of zoned decimal */
|
|
U8 digit_low; /* low digit of packed byte */
|
|
int packedix = 0; /* current packed byte index */
|
|
U8 zone = 0xF0; /* zone field '1111' */
|
|
|
|
VSI( inst, regs, i3, b2, effective_addr2, v1 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
l2 = i3 & 0xE0; /* i3 reserved bits 0-2 must be zero */
|
|
if ( l2 != 0 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
l2 = i3 & 0x1F; /* Operand 2 Length Code (L2): Bits 3-7 */
|
|
if ( l2 > 30 ) /* L2 > 30 => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* handle last zoned field - sign & digit */
|
|
sign = PACKED_SIGN( regs->VR_B( v1, VR_PACKED_SIGN) ); /* sign */
|
|
digit_low = PACKED_HIGH( regs->VR_B( v1, VR_PACKED_SIGN) ); /* lowest digit */
|
|
zoned[l2] = ( sign << 4 ) | digit_low;
|
|
//LOGMSG("VECTOR UNPACK ZONED: V1.B15=%hhX zoned:=%hhX \n", regs->VR_B( v1, 15), zoned[l2]);
|
|
|
|
packedix = 14;
|
|
for ( i=l2 -1; i >=0 ; i-=2, packedix-- )
|
|
{
|
|
zoned[i] = PACKED_LOW( regs->VR_B( v1, packedix) ) | zone;
|
|
//LOGMSG("VECTOR UNPACK ZONED low: %d '%hhX' source: V%d.B%d=%hhX \n", i, zoned [i], v1, packedix, regs->VR_B( v1, packedix));
|
|
if( i > 0 )
|
|
{
|
|
zoned[i-1] = PACKED_HIGH( regs->VR_B( v1, packedix) ) | zone;
|
|
//LOGMSG("VECTOR UNPACK ZONED high: %d '%hhX' source: V%d.B%d=%hhX \n", i, zoned [i-1], v1, packedix, regs->VR_B( v1, packedix));
|
|
}
|
|
}
|
|
|
|
/* save local copy; note: l2 is zoned length -1 */
|
|
ARCH_DEP( vstorec )( zoned, l2, effective_addr2, b2, regs );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E63D VSTRL - VECTOR STORE RIGHTMOST WITH LENGTH [VSI] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_store_rightmost_with_length )
|
|
{
|
|
int v1, b2, i3; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int l2; /* length code (L2) control */
|
|
int i; /* Loop variable */
|
|
U8 stor[16]; /* local stor */
|
|
|
|
VSI( inst, regs, i3, b2, effective_addr2, v1 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
l2 = i3 & 0xF0; /* i3 reserved bits 0-3 must be zero */
|
|
if ( l2 != 0 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
l2 = i3 & 0x0F; /* Operand 2 Length Code (L2): Bits 4-7 */
|
|
|
|
for ( i=0; i <= l2; i++ )
|
|
{
|
|
stor[i] = regs->VR_B( v1, (15 - l2) + i);
|
|
}
|
|
|
|
/* store local copy; note: l2 is length -1 */
|
|
ARCH_DEP( vstorec )( stor, l2, effective_addr2, b2, regs );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E63F VSTRLR - VECTOR STORE RIGHTMOST WITH LENGTH (reg) [VRS-d] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_store_rightmost_with_length_reg )
|
|
{
|
|
int v1, b2, r3; /* Instruction parts */
|
|
VADR effective_addr2; /* Effective address */
|
|
int l2; /* length code (L2) control */
|
|
int i; /* Loop variable */
|
|
U8 stor[16]; /* local stor */
|
|
U32 reg32; /* r3: bits 32-63 */
|
|
|
|
VRS_D( inst, regs, r3, b2, effective_addr2, v1 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
PER_ZEROADDR_XCHECK( regs, b2 );
|
|
|
|
reg32 = regs->GR_L( r3 );
|
|
l2 = ( reg32 > 15 ) ? 15 : (int) reg32 ;
|
|
//LOGMSG("VECTOR STORE RIGHTMOST WITH LENGTH (reg) : r3=%d, reg32=%d, l2=%d \n", r3, reg32, l2);
|
|
|
|
for ( i=0; i <= l2; i++ )
|
|
{
|
|
stor[i] = regs->VR_B( v1, (15 - l2) + i);
|
|
}
|
|
|
|
/* store local copy; note: l2 is length -1 */
|
|
ARCH_DEP( vstorec )( stor, l2, effective_addr2, b2, regs );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E649 VLIP - VECTOR LOAD IMMEDIATE DECIMAL [VRI-h] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_load_immediate_decimal )
|
|
{
|
|
int v1, i3; /* Instruction parts */
|
|
U16 i2; /* Instruction - Decimal Immediate */
|
|
int sc; /* Sign Control (SC): bit 0 */
|
|
int shift; /* Shift Amount (SHAMT): Bits 1-3 */
|
|
int i; /* Loop variable */
|
|
int idx; /* vector byte index to place digits*/
|
|
U16 temp; /* temporary */
|
|
union imm32
|
|
{
|
|
U32 digits; /* shifted digits for byte alignment */
|
|
U8 db[4];
|
|
} imm; /* immediate */
|
|
|
|
VRI_H( inst, regs, v1, i2, i3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* check i2 for valid decimal digits */
|
|
temp = i2;
|
|
for ( i = 0; i < 3; i++)
|
|
{
|
|
if ( (temp & 0x0F) > 9)
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
temp >>= 4;
|
|
}
|
|
|
|
/* get sign control and shift */
|
|
sc = ( i3 & 0x08 ) >> 3;
|
|
shift = ( i3 & 0x07 );
|
|
|
|
/* set v1 to zero */
|
|
SET_VR_ZERO( v1 );
|
|
|
|
/* set sign */
|
|
if (sc == 0)
|
|
regs->VR_B( v1, VR_PACKED_SIGN) = PREFERRED_PLUS; /* positive with a sign code of 1100 */
|
|
else
|
|
regs->VR_B( v1, VR_PACKED_SIGN) = PREFERRED_MINUS; /* negative with a sign code of 1101 */
|
|
|
|
//LOGMSG("VECTOR LOAD IMMEDIATE DECIMAL: i2 %X\n",i2 );
|
|
|
|
imm.digits = i2;
|
|
idx = VR_PACKED_SIGN - ( (shift / 2) + 2);
|
|
|
|
if ( shift & 0x01 ) /* is shift is odd */
|
|
{
|
|
/* odd shift; ignore sign */
|
|
imm.digits = (U32) CSWAP32( imm.digits );
|
|
regs->VR_B( v1, idx + 0 ) |= imm.db[2];
|
|
regs->VR_B( v1, idx + 1 ) |= imm.db[3];
|
|
//LOGMSG("VECTOR LOAD IMMEDIATE DECIMAL: Odd shift: %d digits %X, idx=%d, db[0]= %x, db[1]= %x, db[2]= %x, db[3]= %x\n",shift, imm.digits, idx, imm.db[0], imm.db[1], imm.db[2], imm.db[3] );
|
|
}
|
|
else
|
|
{
|
|
/* even shift; allow for sign */
|
|
imm.digits <<= 4;
|
|
imm.digits = (U32) CSWAP32( imm.digits );
|
|
regs->VR_B( v1, idx + 0 ) |= imm.db[1];
|
|
regs->VR_B( v1, idx + 1 ) |= imm.db[2];
|
|
regs->VR_B( v1, idx + 2 ) |= imm.db[3];
|
|
//LOGMSG("VECTOR LOAD IMMEDIATE DECIMAL: Even shift: %d digits %X, idx=%d, db[0]= %x, db[1]= %x, db[2]= %x, db[3]= %x\n",shift, imm.digits, idx, imm.db[0], imm.db[1], imm.db[2], imm.db[3] );
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#if defined( FEATURE_199_VECT_PACKDEC_ENH_FACILITY_3 )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E64A VCVDQ - VECTOR CONVERT TO DECIMAL (128) [VRI-j] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_convert_to_decimal_128 )
|
|
{
|
|
int v1, v2, i3, m4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
bool p1; /* Force Operand 1 Positive (P1) */
|
|
bool lb; /* Logical Binary (LB) */
|
|
bool cs; /* Condition Code Set (CS) */
|
|
|
|
bool possign; /* result has positive sign */
|
|
U128 convert128; /* value to convert */
|
|
U128 tempv2; /* copy of v2 copy to convert */
|
|
int i; /* Loop variable */
|
|
U8 digit; /* digit of packed byte */
|
|
U128 digit128; /* digit of packed byte */
|
|
U128 ten128; /* U128 number 10 */
|
|
int temp; /* temp */
|
|
bool overflow; /* did an overfor occur */
|
|
|
|
VRI_J( inst, regs, v1, v2, i3, m4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i3 reserved bits 1-2 must be zero */
|
|
if ( i3 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i3 parts */
|
|
iom = (i3 & 0x80) ? true : false;
|
|
rdc = (i3 & 0x1F);
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m4 parts */
|
|
lb = (m4 & 0x08) ? true : false;
|
|
p1 = (m4 & 0x02) ? true : false;
|
|
cs = (m4 & 0x01) ? true : false;
|
|
|
|
/* get sign and value to convert */
|
|
tempv2.Q = regs->VR_Q( v2 ); /* 128-bits to convert */
|
|
if (lb)
|
|
{
|
|
convert128 = tempv2; /* unsigned */
|
|
possign = true;
|
|
}
|
|
else
|
|
{ /* signed */
|
|
if (S128_isNeg( tempv2 ) )
|
|
{
|
|
possign = false;
|
|
convert128 = S128_neg( tempv2 );
|
|
}
|
|
else
|
|
{
|
|
possign = true;
|
|
convert128 = tempv2;
|
|
}
|
|
}
|
|
|
|
/* start with zero vector */
|
|
regs->VR_Q( v1 ) = U128_zero().Q;
|
|
|
|
// logmsg("VECTOR CONVERT TO DECIMAL (128): lb=%d, p1=%d, cs=%d \n", lb, p1, cs);
|
|
// U128_logmsg("VECTOR CONVERT TO DECIMAL (128): tempv2 ", tempv2);
|
|
// U128_logmsg("VECTOR CONVERT TO DECIMAL (128): convert128", convert128);
|
|
|
|
/* do convertion to decimal digits */
|
|
ten128 = U128_U64( 10 );
|
|
|
|
for (i = 30, temp = rdc; temp >0 && i >= 0 && !U128_isZero( convert128 ); i--, temp--)
|
|
{
|
|
// digit = convert % 10;
|
|
// convert = convert / 10;
|
|
convert128 = U128_divrem( convert128, ten128, &digit128 );
|
|
digit = digit128.Q.D.L.D;
|
|
|
|
regs->VR_B( v1, i / 2) |= ( i & 1) ? digit : digit << 4;
|
|
}
|
|
|
|
overflow = !U128_isZero( convert128 ); /* did not convert all (rdc limited result) */
|
|
|
|
/* set sign */
|
|
if (p1)
|
|
regs->VR_B( v1, VR_PACKED_SIGN) |= 0x0F; /* forces b'1111' positive sign */
|
|
else
|
|
regs->VR_B( v1, VR_PACKED_SIGN) |= (possign) ? PREFERRED_PLUS : PREFERRED_MINUS ;
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
regs->psw.cc = (overflow) ? 3 : 0;
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
// U128_logmsg("VECTOR CONVERT TO DECIMAL (128): V1", (U128) regs->VR_Q( v1) );
|
|
// U128_logmsg("VECTOR CONVERT TO DECIMAL (128): convert128", convert128);
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
#endif /* defined( FEATURE_199_VECT_PACKDEC_ENH_FACILITY_3 ) */
|
|
|
|
#if defined( FEATURE_199_VECT_PACKDEC_ENH_FACILITY_3 )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E64E VCVBQ - VECTOR CONVERT TO BINARY (128) [VRR-k] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_convert_to_binary_128 )
|
|
{
|
|
int v1, v2, m3; /* Instruction parts */
|
|
bool p2; /* Force Operand 2 Positive (P2) */
|
|
bool lb; /* Logical Binary (LB) */
|
|
U128 result; /* converted binary */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
|
|
VRR_K( inst, regs, v1, v2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m3 parts */
|
|
p2 = (m3 & 0x08) ? true : false;
|
|
lb = (m3 & 0x02) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
result = vr_to_U128( regs, v2, ( (lb) ? true : p2 ) );
|
|
|
|
regs->VR_Q(v1) = result.Q;
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
#endif /* defined( FEATURE_199_VECT_PACKDEC_ENH_FACILITY_3 ) */
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E650 VCVB - VECTOR CONVERT TO BINARY (32) [VRR-i] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_convert_to_binary_32 )
|
|
{
|
|
int r1, v2, m3, m4; /* Instruction parts */
|
|
bool p2; /* Force Operand 2 Positive (P2) */
|
|
bool lb; /* Logical Binary (LB) */
|
|
bool cs; /* Condition Code Set (CS) */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
bool orc; /* Overflow-Result Control (ORC) */
|
|
U128 result; /* converted binary */
|
|
bool overflow; /* did an overflow occur */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
|
|
VRR_I( inst, regs, r1, v2, m3, m4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m3 parts */
|
|
p2 = (m3 & 0x08) ? true : false;
|
|
lb = (m3 & 0x02) ? true : false;
|
|
cs = (m3 & 0x01) ? true : false;
|
|
|
|
/* m4 parts */
|
|
iom = (m4 & 0x08) ? true : false;
|
|
orc = (m4 & 0x04) ? true : false;
|
|
|
|
/* Note:
|
|
Z16: POP SA22-7832-13
|
|
Instruction-Overflow Mask (IOM): When the
|
|
vector-packed-decimal-enhancement facility 1 is
|
|
not installed, bit 0 is reserved and must contain zero; otherwise,
|
|
a specification exception is recognized.
|
|
|
|
Z17: POP SA22-7832-14
|
|
Instruction-Overflow Mask (IOM): When the
|
|
vector-packed-decimal-enhancement facility 1 is
|
|
not installed, bit 0 is reserved and should be
|
|
zero; otherwise the program may not operate
|
|
compatibly in the future.
|
|
|
|
Use SA22-7832-14 definition; just ignore IOM if
|
|
vector-packed-decimal-enhancement facility 1 is not installed.
|
|
*/
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
iom = false;
|
|
/* ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION ); */
|
|
|
|
if (orc && !FACILITY_ENABLED( 199_VECT_PACKDEC_ENH_3, regs ))
|
|
orc = false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
result = vr_to_U128( regs, v2, ( (lb) ? true : p2 ) );
|
|
|
|
/* did overflow happen? */
|
|
if (lb)
|
|
overflow = ( result.Q.D.L.D > (U64) UINT_MAX ) ? true : false;
|
|
else
|
|
{
|
|
if ( (p2) ? true : VR_HAS_PLUS_SIGN( v2 ) )
|
|
overflow = ( result.Q.D.L.D > (U64) INT_MAX ) ? true : false;
|
|
else
|
|
overflow = ( result.Q.D.L.D < (U64) INT_MIN ) ? true : false;
|
|
}
|
|
|
|
/* CC and 32 bit results */
|
|
//logmsg("... result=%16.16lX.%16.16lX \n", result.Q.D.H.D, result.Q.D.L.D);
|
|
if (orc && overflow)
|
|
regs->GR_L(r1) = 0;
|
|
else
|
|
regs->GR_L(r1) = (U32) (result.Q.D.L.D & 0xFFFFFFFF);
|
|
|
|
if (cs) regs->psw.cc = ( overflow ) ? 3 : 0;
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && FOMASK(®s->psw))
|
|
{
|
|
regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION);
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E651 VCLZDP - VECTOR COUNT LEADING ZERO DIGITS [VRR-k] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_count_leading_zero_digits )
|
|
{
|
|
int v1, v2, m3; /* Instruction parts */
|
|
bool nv; /* No Validation (NV): m3 bit 1 */
|
|
bool nz; /* Negative Zero (NZ): m3 bit 2 */
|
|
bool cs; /* Condition Code Set (CS) : m3 bit 3 */
|
|
|
|
bool isZero = false; /* is V2 zero */
|
|
U8 leading_zeros = 0; /* leading zero count */
|
|
bool isNeg; /* has negative sign */
|
|
bool valid = false; /* valid packed decimal */
|
|
BYTE cc; /* condition code */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
|
|
VRR_K( inst, regs, v1, v2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m3 parts */
|
|
nv = (m3 & 0x04) ? true : false;
|
|
nz = (m3 & 0x02) ? true : false;
|
|
cs = (m3 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = vr_packed_valid_sign( regs, v2 );
|
|
|
|
if ( !nv )
|
|
{
|
|
if ( !valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
}
|
|
|
|
/* count leading zeros */
|
|
leading_zeros = vr_leading_zero( regs, v2);
|
|
|
|
/* determine condition code */
|
|
if (cs)
|
|
{
|
|
isNeg = VR_HAS_MINUS_SIGN( v2 );
|
|
isZero = vr_is_zero( regs, v2 );
|
|
valid = valid_decimals2 && valid_sign2;
|
|
|
|
cc = 3; /* invalid */
|
|
if ( valid && isZero && !(nz && isNeg) ) cc = 0;
|
|
else if ( ( valid && isNeg ) || (nz && isNeg && isZero) ) cc = 1;
|
|
else if ( valid && !isZero && !isNeg ) cc = 2;
|
|
|
|
// logmsg( "VCLZDP: cc=%d : valid=%d, isZero=%d, isNeg=%d, nz=%d\n", cc, valid, isZero, isNeg, nz );
|
|
}
|
|
|
|
/* update V1 */
|
|
SET_VR_ZERO( v1 );
|
|
regs->VR_B( v1, 7) = leading_zeros;
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
regs->psw.cc = cc;
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E652 VCVBG - VECTOR CONVERT TO BINARY (64) [VRR-i] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_convert_to_binary_64 )
|
|
{
|
|
int r1, v2, m3, m4; /* Instruction parts */
|
|
bool p2; /* Force Operand 2 Positive (P2) */
|
|
bool lb; /* Logical Binary (LB) */
|
|
bool cs; /* Condition Code Set (CS) */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
bool orc; /* Overflow-Result Control (ORC) */
|
|
U128 result; /* converted binary */
|
|
bool overflow; /* did an overfor occur */
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
|
|
VRR_I( inst, regs, r1, v2, m3, m4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m3 parts */
|
|
p2 = (m3 & 0x08) ? true : false;
|
|
lb = (m3 & 0x02) ? true : false;
|
|
cs = (m3 & 0x01) ? true : false;
|
|
|
|
/* m4 parts */
|
|
iom = (m4 & 0x08) ? true : false;
|
|
orc = (m4 & 0x04) ? true : false;
|
|
|
|
/* Note:
|
|
Z16: POP SA22-7832-13
|
|
Instruction-Overflow Mask (IOM): When the
|
|
vector-packed-decimal-enhancement facility 1 is
|
|
not installed, bit 0 is reserved and must contain zero; otherwise,
|
|
a specification exception is recognized.
|
|
|
|
Z17: POP SA22-7832-14
|
|
Instruction-Overflow Mask (IOM): When the
|
|
vector-packed-decimal-enhancement facility 1 is
|
|
not installed, bit 0 is reserved and should be
|
|
zero; otherwise the program may not operate
|
|
compatibly in the future.
|
|
|
|
Use SA22-7832-14 definition; just ignore IOM if
|
|
vector-packed-decimal-enhancement facility 1 is not installed.
|
|
*/
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
iom = false;
|
|
/* ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION ); */
|
|
|
|
if (orc && !FACILITY_ENABLED( 199_VECT_PACKDEC_ENH_3, regs ))
|
|
orc = false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
result = vr_to_U128( regs, v2, ( (lb) ? true : p2 ) );
|
|
|
|
/* did overflow happen? */
|
|
if (lb)
|
|
overflow = ( result.Q.D.H.D != 0 );
|
|
else
|
|
{
|
|
if ( (p2) ? true : VR_HAS_PLUS_SIGN( v2 ) )
|
|
overflow = ( result.Q.D.H.D != 0 ) || ( (result.Q.D.L.D & 0x8000000000000000ULL) != 0 );
|
|
else
|
|
overflow = ( result.Q.D.H.D != (U64) -1 ) || ( (result.Q.D.L.D & 0x8000000000000000ULL) == 0 );
|
|
}
|
|
|
|
/* CC and 64 bit results */
|
|
//logmsg("... result=%16.16lX.%16.16lX \n", result.Q.D.H.D, result.Q.D.L.D);
|
|
if (orc && overflow)
|
|
regs->GR_G(r1) = 0;
|
|
else
|
|
regs->GR_G(r1) = result.Q.D.L.D;
|
|
|
|
if (cs) regs->psw.cc = ( overflow ) ? 3 : 0;
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && FOMASK(®s->psw))
|
|
{
|
|
regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION);
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E654 VUPKZH - VECTOR UNPACK ZONED HIGH [VRR-k] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_unpack_zoned_high )
|
|
{
|
|
int v1, v2, m3; /* Instruction parts */
|
|
bool nsv; /* No Sign Validation (NSV): bit 0 */
|
|
bool nv; /* No Validation (NV): bit 1 */
|
|
int i; /* loop variable */
|
|
int indx; /* index variable */
|
|
U8 temp; /* temp variable */
|
|
/* local vvector registers */
|
|
LOCALS()
|
|
|
|
VRR_K( inst, regs, v1, v2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m3 parts */
|
|
nsv = (m3 & 0x08) ? true : false;
|
|
nv = (m3 & 0x04) ? true : false;
|
|
|
|
/* any validation? */
|
|
if ( !nv )
|
|
{
|
|
/* validate sign? */
|
|
if ( !nsv && !vr_packed_valid_sign( regs, v2) )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* validate decimals */
|
|
if ( !vr_packed_valid_digits( regs, v2 ) )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
}
|
|
|
|
/* local v2 */
|
|
VR_SAVE_LOCAL( LV2, v2 );
|
|
|
|
/* set siggnificant zone digit to zero */
|
|
regs->VR_B( v1, 0 ) = 0xF0;
|
|
|
|
/* 14 decimals */
|
|
for (i = 1, indx = 0; i < 14; i += 2, indx++ )
|
|
{
|
|
temp = lregs->VR_B( LV2, indx );
|
|
regs->VR_B( v1, i ) = PACKED_HIGH (temp ) | 0xF0;
|
|
regs->VR_B( v1, i+1 ) = PACKED_LOW (temp ) | 0xF0;
|
|
}
|
|
|
|
/* 15th decimal */
|
|
temp = lregs->VR_B( LV2, 7 );
|
|
regs->VR_B( v1, 15 ) = PACKED_HIGH (temp ) | 0xF0;
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E658 VCVD - VECTOR CONVERT TO DECIMAL (32) [VRI-i] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_convert_to_decimal_32 )
|
|
{
|
|
int v1, r2, m4, i3; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
bool p1; /* Force Operand 1 Positive (P1) */
|
|
bool lb; /* Logical Binary (LB) */
|
|
bool cs; /* Condition Code Set (CS) */
|
|
bool possign; /* result has positive sign */
|
|
S32 tempS32; /* temp S32 */
|
|
U32 convert; /* value to convert */
|
|
U32 reg32; /* register to convert */
|
|
int i; /* Loop variable */
|
|
U8 digit; /* digit of packed byte */
|
|
int temp; /* temp */
|
|
bool overflow; /* did an overflow occur */
|
|
|
|
VRI_I( inst, regs, v1, r2, m4, i3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i3 reserved bits 1-2 must be zero */
|
|
if ( i3 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i3 parts */
|
|
iom = (i3 & 0x80) ? true : false;
|
|
rdc = (i3 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
|
|
/* m4 parts */
|
|
lb = (m4 & 0x08) ? true : false;
|
|
p1 = (m4 & 0x02) ? true : false;
|
|
cs = (m4 & 0x01) ? true : false;
|
|
|
|
/* get sign and value to convert */
|
|
reg32 = regs->GR_L( r2 ); /* 32-bits to convert */
|
|
|
|
if (lb)
|
|
{
|
|
/* unsigned */
|
|
convert = reg32;
|
|
possign = true;
|
|
}
|
|
else
|
|
{
|
|
/* signed */
|
|
tempS32 = (S32) reg32;
|
|
if ( tempS32 >= 0 )
|
|
{
|
|
possign = true;
|
|
convert = (U32) tempS32;
|
|
}
|
|
else
|
|
{
|
|
possign = false;
|
|
convert = (U32) -tempS32 ;
|
|
}
|
|
}
|
|
|
|
// logmsg("VECTOR CONVERT TO DECIMAL (32): lb=%d, reg32.ureg=%X, reg32.sreg=%d, possign=%d, convert=%ld, convert=%lx \n", lb, reg32.ureg, reg32.sreg, possign, convert, convert);
|
|
|
|
/* start with zero vector */
|
|
SET_VR_ZERO( v1 );
|
|
|
|
/* do convertion to decimal digits */
|
|
for (i = 30, temp = rdc; temp > 0 && i >= 0 && convert > 0; i--, temp--)
|
|
{
|
|
digit = convert % 10;
|
|
convert = convert / 10;
|
|
|
|
regs->VR_B( v1, i / 2) |= ( i & 1) ? digit : digit << 4;
|
|
}
|
|
|
|
overflow = convert > 0; /* did not convert all (rdc limited rersult) */
|
|
|
|
/* set sign */
|
|
if (p1)
|
|
regs->VR_B( v1, VR_PACKED_SIGN ) |= 0x0F; /* forces b'1111' positive sign */
|
|
else
|
|
regs->VR_B( v1, VR_PACKED_SIGN ) |= (possign) ? PREFERRED_PLUS : PREFERRED_MINUS ;
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
regs->psw.cc = (overflow) ? 3 : 0;
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E659 VSRP - VECTOR SHIFT AND ROUND DECIMAL [VRi-g] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_shift_and_round_decimal )
|
|
{
|
|
int v1, v2, i4, m5, i3; /* Instruction parts */
|
|
/* i3 bits */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count (RDC): Bits 3-7*/
|
|
/* i4 bits */
|
|
bool drd; /* Decimal Rounding Digit (DRD) bit 0 */
|
|
S8 shamt; /* Shift Amount (SHAMT): Bits 1-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decNumber dnshift; /* -shamt as decNumber (note:negative)*/
|
|
decContext set; /* zn default context */
|
|
|
|
VRI_G( inst, regs, v1, v2, i4, m5, i3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i3 reserved bits 1-2 must be zero */
|
|
if ( i3 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i3 parts */
|
|
iom = (i3 & 0x80) ? true : false;
|
|
rdc = (i3 & 0x1F);
|
|
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if (rdc == 0)
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
drd = (i4 & 0x80) ? true : false;
|
|
/* note: shamt is signed 7 bit field... */
|
|
shamt = (i4 & 0x7F);
|
|
shamt = (shamt > 0x4F ) ? (shamt | 0x80) : shamt;
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operand as decNumbers and set context */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
zn_ContextDefault( &set );
|
|
|
|
/* rounding by 5 and right shift */
|
|
if ( shamt < 0 && drd )
|
|
{
|
|
/* note: shift is negative so shift +1 to allow rounding */
|
|
decNumberFromInt32( &dnshift, shamt +1 );
|
|
decNumberShift( &dntemp, &dnv2, &dnshift, &set );
|
|
|
|
// dn_logmsg("dntemp: ", &dntemp);
|
|
|
|
/* rounding is on a positive value */
|
|
if (decNumberIsNegative( &dnv2) )
|
|
decNumberMinus( &dntemp, &dntemp, &set );
|
|
|
|
// dn_logmsg("dntemp: ", &dntemp);
|
|
|
|
decNumberFromInt32( &dnshift, 5 ); /*use shift as rounding digit */
|
|
decNumberAdd( &dntemp, &dntemp, &dnshift, &set);
|
|
|
|
// dn_logmsg("dntemp: ", &dntemp);
|
|
|
|
/* do last 1 position shift right */
|
|
decNumberFromInt32( &dnshift, -1 );
|
|
decNumberShift( &dnv1, &dntemp, &dnshift, &set );
|
|
|
|
/* rounding was on a positive value, switch back to negative */
|
|
if (decNumberIsNegative( &dnv2) )
|
|
decNumberMinus( &dnv1, &dnv1, &set );
|
|
}
|
|
else
|
|
{
|
|
/* get shift as decNumber and shift v2 */
|
|
decNumberFromInt32(&dnshift, shamt);
|
|
decNumberShift(&dnv1, &dnv2, &dnshift, &set);
|
|
}
|
|
|
|
// logmsg("... shamt=%d, rdc= %d, drd=%d, p1=%d, p2=%d \n",shamt, rdc, drd, p1, p2);
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnshift: ", &dnshift);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store shifted result in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, rdc);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E65A VCVDG - VECTOR CONVERT TO DECIMAL (64) [VRI-i] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_convert_to_decimal_64 )
|
|
{
|
|
int v1, r2, m4, i3; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
bool p1; /* Force Operand 1 Positive (P1) */
|
|
bool lb; /* Logical Binary (LB) */
|
|
bool cs; /* Condition Code Set (CS) */
|
|
|
|
bool possign; /* result has positive sign */
|
|
S64 tempS64; /* temp S64 */
|
|
U64 convert; /* value to convert */
|
|
U64 reg64; /* register to convert */
|
|
int i; /* Loop variable */
|
|
U8 digit; /* digit of packed byte */
|
|
int temp; /* temp */
|
|
bool overflow; /* did an overfor occur */
|
|
|
|
VRI_I( inst, regs, v1, r2, m4, i3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i3 reserved bits 1-2 must be zero */
|
|
if ( i3 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i3 parts */
|
|
iom = (i3 & 0x80) ? true : false;
|
|
rdc = (i3 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m4 parts */
|
|
lb = (m4 & 0x08) ? true : false;
|
|
p1 = (m4 & 0x02) ? true : false;
|
|
cs = (m4 & 0x01) ? true : false;
|
|
|
|
/* start with zero vector */
|
|
SET_VR_ZERO( v1 );
|
|
|
|
/* get sign and value to convert */
|
|
reg64 = regs->GR( r2 ); /* 64-bits to convert */
|
|
if (lb)
|
|
{
|
|
convert = reg64; /* unsigned */
|
|
possign = true;
|
|
}
|
|
else
|
|
{ /* signed */
|
|
tempS64 = (S64) reg64;
|
|
if (tempS64 >= 0 )
|
|
{
|
|
possign = true;
|
|
convert = (U64) tempS64;
|
|
}
|
|
else
|
|
{
|
|
possign = false;
|
|
convert = (U64) -tempS64;
|
|
}
|
|
}
|
|
|
|
//logmsg("VECTOR CONVERT TO DECIMAL (64): lb=%d, reg64=%lX, convert=%ld, convert=%lx \n", lb, reg64, convert, convert);
|
|
|
|
/* do convertion to decimal digits */
|
|
for (i = 30, temp = rdc; temp >0 && i >= 0 && convert > 0; i--, temp--)
|
|
{
|
|
digit = convert % 10;
|
|
convert = convert / 10;
|
|
|
|
regs->VR_B( v1, i / 2) |= ( i & 1) ? digit : digit << 4;
|
|
}
|
|
|
|
overflow = convert > 0; /* did not convert all (rdc limited rersult) */
|
|
|
|
/* set sign */
|
|
if (p1)
|
|
regs->VR_B( v1, VR_PACKED_SIGN) |= 0x0F; /* forces b'1111' positive sign */
|
|
else
|
|
regs->VR_B( v1, VR_PACKED_SIGN) |= (possign) ? PREFERRED_PLUS : PREFERRED_MINUS ;
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
regs->psw.cc = (overflow) ? 3 : 0;
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E65B VPSOP - VECTOR PERFORM SIGN OPERATION DECIMAL [VRI-g] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_perform_sign_operation_decimal )
|
|
{
|
|
int v1, v2, i4, m5, i3; /* Instruction parts */
|
|
|
|
/* i3 bits */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count (RDC): Bits 3-7*/
|
|
|
|
/* i4 bits */
|
|
bool nv; /* No Validation (NV): bit 0 */
|
|
bool nz; /* Negative Zero (NZ): bit 1 */
|
|
bool ps; /* Preserve sign (PS) control: bit 3 */
|
|
U8 so; /* Sign Operation (SO): Bits 4-5 */
|
|
bool pc; /* Positive Sign Code (PC): bit 6 */
|
|
bool sv; /* Op 2 Sign Validation (SV): bit 7 */
|
|
|
|
/* m5 bits */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
BYTE cc = 0; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
bool isZero = false; /* is result zero */
|
|
bool suppressingDX = false; /* suppressed data exception */
|
|
/* local vector registers */
|
|
LOCALS()
|
|
|
|
VRI_G( inst, regs, v1, v2, i4, m5, i3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i3 reserved bits 1-2 must be zero */
|
|
if ( i3 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i3 parts */
|
|
iom = (i3 & 0x80) ? true : false;
|
|
rdc = (i3 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
nv = (i4 & 0x80) ? true : false;
|
|
nz = (i4 & 0x40) ? true : false;
|
|
ps = (i4 & 0x10) ? true : false;
|
|
so = (i4 & 0x0C) >> 2;
|
|
pc = (i4 & 0x02) ? true : false;
|
|
sv = (i4 & 0x01) ? true : false;
|
|
|
|
if (!FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
{
|
|
nv = false; /* validate digits */
|
|
nz = false; /* no negative zero */
|
|
}
|
|
|
|
if ( !FACILITY_ENABLED( 199_VECT_PACKDEC_ENH_3, regs ) )
|
|
{
|
|
ps = false; /* preserve sign */
|
|
}
|
|
|
|
/* m5 parts */
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = ( nv ) ? true : vr_packed_valid_digits( regs, v2 );
|
|
if (
|
|
(so == 0x00 && !nv ) ||
|
|
(so == 0x01 ) ||
|
|
(so == 0x02 && sv ) ||
|
|
(so == 0x03 && sv )
|
|
)
|
|
valid_sign2 = vr_packed_valid_sign( regs, v2 );
|
|
else
|
|
valid_sign2 = true; /* ignored */
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* local v2 */
|
|
VR_SAVE_LOCAL( LV2, v2 );
|
|
|
|
/* initialize V1 */
|
|
lv_copy_to_vr( regs, v1, lregs, LV2, rdc );
|
|
overflow = lv_leading_zero(lregs , LV2) < (MAX_DECIMAL_DIGITS - rdc);
|
|
isZero = vr_is_zero(regs, v1);
|
|
|
|
/* programmer note: letting compiler optimize the following! */
|
|
switch (so)
|
|
{
|
|
case 0x00: /* 00 (maintain) */
|
|
{
|
|
if (ps)
|
|
{ /* PS==1; Perserve Sign*/
|
|
if (isZero)
|
|
{
|
|
{ cc = 0; break; }
|
|
}
|
|
else
|
|
{
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) )
|
|
{ cc = 2; break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) )
|
|
{ cc = 1; break; }
|
|
|
|
if ( !LV_HAS_VALID_SIGN( LV2 ) )
|
|
{ cc = 2; break; }
|
|
}
|
|
}
|
|
else
|
|
{ /* PS==0; Perserve Sign*/
|
|
if (isZero)
|
|
{
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) && pc )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) && !pc )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) && !pc && !nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) && pc && !nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) && nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_MINUS); break; }
|
|
|
|
if ( !LV_HAS_VALID_SIGN( LV2 ) )
|
|
{ cc = 0; break; }
|
|
}
|
|
else
|
|
{
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) && pc )
|
|
{ cc = 2; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) && !pc )
|
|
{ cc = 2; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) )
|
|
{ cc = 1; SET_VR_SIGN( v1, PREFERRED_MINUS); break; }
|
|
|
|
if ( !LV_HAS_VALID_SIGN( LV2 ) )
|
|
{ cc = 2; break; }
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x01: /* 01 (complement) */
|
|
{
|
|
if ( !LV_HAS_VALID_SIGN( LV2 ) ) { suppressingDX = true; break; }
|
|
|
|
if (isZero)
|
|
{
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) && !pc && !nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) && pc && !nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) && nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_MINUS); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) && pc )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) && !pc )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
}
|
|
else
|
|
{
|
|
if ( LV_HAS_PLUS_SIGN( LV2 ) )
|
|
{ cc = 1; SET_VR_SIGN( v1, PREFERRED_MINUS); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) && pc )
|
|
{ cc = 2; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
|
|
if ( LV_HAS_MINUS_SIGN( LV2 ) && !pc )
|
|
{ cc = 2; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x02: /* 10 (force positive) */
|
|
{
|
|
if (isZero)
|
|
{
|
|
if ( pc )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
else
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
}
|
|
else
|
|
{
|
|
if ( pc )
|
|
{ cc = 2; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
else
|
|
{ cc = 2; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x03: /* 11 (force negative) */
|
|
{
|
|
if (isZero)
|
|
{
|
|
if ( !pc && !nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_PLUS); break; }
|
|
|
|
if ( pc && !nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_ZONE); break; }
|
|
|
|
if ( nz )
|
|
{ cc = 0; SET_VR_SIGN( v1, PREFERRED_MINUS); break; }
|
|
|
|
}
|
|
else
|
|
{
|
|
{ cc = 1; SET_VR_SIGN( v1, PREFERRED_MINUS); break; }
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
/* invalid sign */
|
|
if ( suppressingDX )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
if ( isZero ) cc= 0; /* regardless on sign */
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E65C VUPKZL - VECTOR UNPACK ZONED LOW [VRR-k] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_unpack_zoned_low )
|
|
{
|
|
int v1, v2, m3; /* Instruction parts */
|
|
bool nsv; /* No Sign Validation (NSV): bit 0 */
|
|
bool nv; /* No Validation (NV): bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
int i; /* loop variable */
|
|
int indx; /* index variable */
|
|
U8 temp; /* temp variable */
|
|
U8 zoned_sign; /* sign for zoned digit */
|
|
/* local vector registers */
|
|
LOCALS()
|
|
|
|
VRR_K( inst, regs, v1, v2, m3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m3 parts */
|
|
nsv = (m3 & 0x08) ? true : false;
|
|
nv = (m3 & 0x04) ? true : false;
|
|
p1 = (m3 & 0x02) ? true : false;
|
|
|
|
/* any validation? */
|
|
if ( !nv )
|
|
{
|
|
/* validate sign? */
|
|
if ( !nsv && !vr_packed_valid_sign( regs, v2) )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* validate decimals */
|
|
if ( !vr_packed_valid_digits( regs, v2 ) )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
}
|
|
|
|
/* save v2 */
|
|
VR_SAVE_LOCAL( LV2, v2);
|
|
|
|
/* result sign */
|
|
zoned_sign = (p1) ? PREFERRED_ZONE : PACKED_SIGN ( lregs->VR_B( LV2, VR_PACKED_SIGN ) );
|
|
zoned_sign <<= 4;
|
|
|
|
/* 1st decimal */
|
|
temp = lregs->VR_B( LV2, 7 );
|
|
regs->VR_B( v1, 0 ) = PACKED_LOW (temp ) | 0xF0;
|
|
|
|
/* 2-15 decimals */
|
|
for (i = 1, indx = 8; i < 15; i += 2, indx++ )
|
|
{
|
|
temp = lregs->VR_B( LV2, indx );
|
|
regs->VR_B( v1, i ) = PACKED_HIGH (temp ) | 0xF0;
|
|
regs->VR_B( v1, i+1 ) = PACKED_LOW (temp ) | 0xF0;
|
|
}
|
|
|
|
/* 16th decimal */
|
|
temp = lregs->VR_B( LV2, 15 );
|
|
regs->VR_B( v1, 15 ) = PACKED_HIGH (temp ) | zoned_sign;
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E65F VTP - VECTOR TEST DECIMAL [VRR-g] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_test_decimal )
|
|
{
|
|
int v1, i2; /* Instruction parts */
|
|
int et; /* Enhanced Testing (ET) */
|
|
int bpt; /* Byte-Padding Test (BPT) */
|
|
int stc; /* Sign-Test Control (STC) */
|
|
int dc; /* Digits Count (DC) */
|
|
bool valid_decimal; /* decimal validation failed? */
|
|
bool valid_sign; /* sign validation failed? */
|
|
U8 cc; /* condition code */
|
|
|
|
VRR_G( inst, regs, v1, i2 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i2 parts */
|
|
et = FALSE;
|
|
bpt = FALSE;
|
|
stc = 0;
|
|
dc = 0;
|
|
if ( FACILITY_ENABLED( 199_VECT_PACKDEC_ENH_3, regs ) )
|
|
{
|
|
et = (i2 & 0x8000) ? TRUE : FALSE;
|
|
if ( et )
|
|
{
|
|
bpt = (i2 & 0x4000) ? TRUE : FALSE;
|
|
stc = (i2 & 0x00E0) >> 5;
|
|
dc = i2 & 0x001F;
|
|
}
|
|
}
|
|
|
|
/* validate decimals */
|
|
valid_decimal = vr_packed_valid_digits_enhanced( regs, v1, et, bpt, dc );
|
|
|
|
/* validate sign */
|
|
valid_sign = vr_packed_valid_sign_enhanced( regs, v1, et, stc, dc );
|
|
|
|
/* set condition code */
|
|
cc = (valid_decimal) ? ( (valid_sign) ? 0 : 1) :
|
|
( (valid_sign) ? 2 : 3) ;
|
|
regs->psw.cc = cc;
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E670 VPKZR - VECTOR PACK ZONED REGISTER [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_pack_zoned_register )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
bool nsv; /* No Sign Validation (NSV): bit 0 */
|
|
bool nv; /* No Validation (NV): bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool overflowed; /* overflow occurred */
|
|
bool isZero; /* is zoned decimal zero */
|
|
bool isPositive; /* is zoned decimal positive */
|
|
int i; /* loop variable */
|
|
int indx; /* index variable */
|
|
U8 temp; /* temp variable */
|
|
int temp_rdc; /* temp of rdc */
|
|
U8 zoned[32]; /* intermediate zoned decimal */
|
|
U8 packed_sign; /* sign for packed vector */
|
|
QW tempVR; /* temp vector regiter sized field */
|
|
bool valid_sign; /* is sign valid? */
|
|
bool valid_decimals; /* are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
rdc = (i4 & 0x1F);
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
nsv = (m5 & 0x08) ? true : false;
|
|
nv = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* create intermediate source */
|
|
tempVR = CSWAP128( regs->VR_Q ( v2 ) ); /* VR part 1 */
|
|
memcpy( &zoned[0], &tempVR, sizeof(QW) );
|
|
|
|
tempVR = CSWAP128( regs->VR_Q ( v3 ) ); /* VR part 2 */
|
|
memcpy( &zoned[16], &tempVR, sizeof(QW) );
|
|
|
|
/* zoned validation */
|
|
valid_sign = ZONED_SIGN( zoned[31] ) > 9;
|
|
valid_decimals = true;
|
|
for (i =0; i < 32 && valid_decimals; i++)
|
|
valid_decimals = IS_VALID_DECIMAL( zoned[i] );
|
|
|
|
/* general-operand data exception? */
|
|
/* validate sign: nsv=0 and nv=0 */
|
|
if ( !nsv && !nv && !valid_sign )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* validate decimals */
|
|
if ( !nv & !valid_decimals )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* build packed vector */
|
|
SET_VR_ZERO( v1 );
|
|
packed_sign = (p1) ? PREFERRED_ZONE : ZONED_SIGN( zoned[31] );
|
|
regs->VR_B( v1, VR_PACKED_SIGN) = (ZONED_DECIMAL( zoned[31] ) << 4) | packed_sign;
|
|
|
|
indx = 14;
|
|
for (i = 30, temp_rdc = rdc-1; i >=0 && temp_rdc > 0 && indx >=0 ; i--, temp_rdc--)
|
|
{
|
|
temp = ZONED_DECIMAL( zoned[ i ] );
|
|
regs->VR_B( v1, indx) |= (i & 1) ? temp << 4 : temp;
|
|
if ( i & 1) indx--;
|
|
}
|
|
|
|
/* check for overflow */
|
|
overflowed = false;
|
|
for (i = 0; i < (32 - rdc) && !overflowed; i++)
|
|
overflowed = ( ZONED_DECIMAL( zoned[ i ]) == 0 ) ? false : true;
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
/* is the zone decimal 0 */
|
|
isZero = true;
|
|
for (i = 0; i < 32 && isZero; i++)
|
|
isZero = ( ZONED_DECIMAL( zoned[ i ]) == 0 ) ? true : false;
|
|
|
|
/* is the zone decimal positive */
|
|
isPositive = IS_PLUS_SIGN( packed_sign );
|
|
|
|
if ( overflowed || !valid_decimals || !valid_sign) cc = 3;
|
|
else if (!overflowed && valid_decimals && valid_sign && !isZero && isPositive) cc = 2;
|
|
else if (!overflowed && valid_decimals && valid_sign && !isZero && !isPositive) cc = 1;
|
|
else if (!overflowed && valid_decimals && valid_sign && isZero ) cc = 0;
|
|
else cc = 0; /* should not get here */
|
|
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflowed && FOMASK(®s->psw))
|
|
{
|
|
regs->program_interrupt (regs, PGM_FIXED_POINT_OVERFLOW_EXCEPTION);
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E671 VAP - VECTOR ADD DECIMAL [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_add_decimal )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p3; /* Force Operand 3 Positive(P1) bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
bool valid_sign3; /* v3: is sign valid? */
|
|
bool valid_decimals3; /* v3: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dnv3; /* v3 as decNumber */
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
rdc = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p3 = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
valid_decimals3 = vr_packed_valid_digits( regs, v3 );
|
|
valid_sign3 = (p3) ? true : vr_packed_valid_sign( regs, v3 );
|
|
|
|
if (!valid_decimals2 || !valid_sign2 || !valid_decimals3 || !valid_sign3)
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
vr_to_decNumber( regs, v3, &dnv3, p3);
|
|
|
|
/* get product */
|
|
zn_ContextDefault( &set );
|
|
decNumberAdd( &dnv1, &dnv2, &dnv3, &set );
|
|
|
|
// DEBUG
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnv3: ", &dnv3);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store product in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, rdc);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E672 VSRPR - VECTOR SHIFT AND ROUND DECIMAL REGISTER [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_shift_and_round_decimal_register )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
/* i4 bits */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
bool drd; /* Decimal Rounding Digit (DRD) bit 1 */
|
|
int rdc; /* Result Digits Count (RDC): Bits 3-7*/
|
|
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
S8 shamt; /* Shift Amount (SHAMT): V3 byte 7 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decNumber dnshift; /* -shamt as decNumber (note:negative)*/
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i3 reserved bit 2 must be zero */
|
|
if ( i4 & 0x20 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
drd = (i4 & 0x40) ? true : false;
|
|
rdc = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if (rdc == 0)
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* get shamt from v3, byte 7. note: shamt is signed */
|
|
shamt = (S8) regs->VR_B( v3, 7);
|
|
if (shamt < -32 ) shamt = -32;
|
|
if (shamt > +31 ) shamt = +31;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operand as decNumbers and set context */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
zn_ContextDefault( &set );
|
|
|
|
/* rounding by 5 and right shift */
|
|
if ( shamt < 0 && drd )
|
|
{
|
|
/* note: shift is negative so shift +1 to allow rounding */
|
|
decNumberFromInt32( &dnshift, shamt +1 );
|
|
decNumberShift( &dntemp, &dnv2, &dnshift, &set );
|
|
|
|
// dn_logmsg("dntemp: ", &dntemp);
|
|
|
|
/* rounding is on a positive value */
|
|
if (decNumberIsNegative( &dnv2) )
|
|
decNumberMinus( &dntemp, &dntemp, &set );
|
|
|
|
// dn_logmsg("dntemp: ", &dntemp);
|
|
|
|
decNumberFromInt32( &dnshift, 5 ); /*use shift as rounding digit */
|
|
decNumberAdd( &dntemp, &dntemp, &dnshift, &set);
|
|
|
|
// dn_logmsg("dntemp: ", &dntemp);
|
|
|
|
/* do last 1 position shift right */
|
|
decNumberFromInt32( &dnshift, -1 );
|
|
decNumberShift( &dnv1, &dntemp, &dnshift, &set );
|
|
|
|
/* rounding was on a positive value, switch back to negative */
|
|
if (decNumberIsNegative( &dnv2) )
|
|
decNumberMinus( &dnv1, &dnv1, &set );
|
|
}
|
|
else
|
|
{
|
|
/* get shift as decNumber and shift v2 */
|
|
decNumberFromInt32(&dnshift, shamt);
|
|
decNumberShift(&dnv1, &dnv2, &dnshift, &set);
|
|
}
|
|
|
|
// logmsg("... shamt=%d, rdc= %d, drd=%d, p1=%d, p2=%d \n",shamt, rdc, drd, p1, p2);
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnshift: ", &dnshift);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store shifted result in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, rdc);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E673 VSP - VECTOR SUBTRACT DECIMAL [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_subtract_decimal )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p3; /* Force Operand 3 Positive(P1) bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
bool valid_sign3; /* v3: is sign valid? */
|
|
bool valid_decimals3; /* v3: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dnv3; /* v3 as decNumber */
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
rdc = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p3 = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
valid_decimals3 = vr_packed_valid_digits( regs, v3 );
|
|
valid_sign3 = (p3) ? true : vr_packed_valid_sign( regs, v3 );
|
|
|
|
if (!valid_decimals2 || !valid_sign2 || !valid_decimals3 || !valid_sign3)
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
vr_to_decNumber( regs, v3, &dnv3, p3);
|
|
|
|
/* get product */
|
|
zn_ContextDefault( &set );
|
|
decNumberSubtract( &dnv1, &dnv2, &dnv3, &set );
|
|
|
|
// DEBUG
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnv3: ", &dnv3);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store product in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, rdc);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E674 VSCHP - DECIMAL SCALE AND CONVERT TO HFP [VRR-b] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( decimal_scale_and_convert_to_hfp )
|
|
{
|
|
int v1, v2, v3, m4, m5;
|
|
|
|
bool rm; /* Rounding Mode (RM) */
|
|
U8 scale; /* scale factor: V3 byte 7 */
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decNumber dnscale; /* scale as decNumber */
|
|
decContext set; /* zn default context */
|
|
U8 hxNumber[DECNUMDIGITS]; /* hexNumber digits */
|
|
int roundDigits; /* number of significant digits */
|
|
hexNumber htemp; /* temp hexNumber */
|
|
hexNumber hNum; /* result hexNumber */
|
|
SHORT_FLOAT sf; /* hNum converted to short float */
|
|
LONG_FLOAT lf; /* hNum converted to long float */
|
|
EXTENDED_FLOAT ef; /* hNum converted to extended float */
|
|
|
|
VRR_B(inst, regs, v1, v2, v3, m4, m5);
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m4: HFP format */
|
|
switch (m4)
|
|
{
|
|
case 2: break; /* short HFP */
|
|
case 3: break; /* long HFP */
|
|
case 4: break; /* extended HFP */
|
|
default: /* reserved */
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
}
|
|
|
|
/* m5 parts */
|
|
rm = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = vr_packed_valid_sign( regs, v2 );
|
|
|
|
if (!valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* zero check */
|
|
if ( vr_is_zero( regs, v2) )
|
|
{
|
|
SET_VR_ZERO( v1 ); /* true zero; all formats */
|
|
|
|
ZVECTOR_END( regs );
|
|
return;
|
|
}
|
|
|
|
/* get scale factor from v3, byte 7. note: scale is unsigned */
|
|
scale = regs->VR_B( v3, 7);
|
|
|
|
/* scale factor: */
|
|
/* limited to values less than 8 otherwise results */
|
|
/* are unpredictable. */
|
|
scale &= 0x07;
|
|
|
|
/* operands as decNumber and context */
|
|
vr_to_decNumber( regs, v2, &dnv2, false );
|
|
zn_ContextDefault( &set );
|
|
decNumberFromInt32( &dnscale, (S32) scale );
|
|
|
|
/* scale/shift V2 */
|
|
decNumberShift( &dntemp, &dnv2, &dnscale, &set );
|
|
decNumberToHexNumber( &dntemp, &htemp );
|
|
|
|
/* debug */
|
|
if (0)
|
|
{
|
|
hexNumberToString(&htemp, hxNumber);
|
|
logmsg(" VSCHP - hexNumberToString: %s \n", hxNumber );
|
|
}
|
|
|
|
/* round? */
|
|
if ( rm )
|
|
{
|
|
switch (m4) /* m4: HFP format */
|
|
{
|
|
case 2: roundDigits = SHORT_FLOAT_NUM_DIGITS; break; /* short HFP */
|
|
case 3: roundDigits = LONG_FLOAT_NUM_DIGITS; break; /* long HFP */
|
|
case 4: roundDigits = EXTENDED_FLOAT_NUM_DIGITS; break; /* extended HFP */
|
|
/* avoid compiler warining */
|
|
default: roundDigits = DECNUMDIGITS; /* reserved */
|
|
}
|
|
hexNumberRound(&hNum, &htemp, roundDigits);
|
|
|
|
/* debug */
|
|
if (0)
|
|
{
|
|
hexNumberToString(&hNum, hxNumber);
|
|
logmsg(" VSCHP - rounded: %d, hn: %s \n", roundDigits, hxNumber );
|
|
}
|
|
}
|
|
else
|
|
hexNumberCopy(&hNum, &htemp);
|
|
|
|
/* convert hexNumber to HFP */
|
|
SET_VR_ZERO (v1);
|
|
|
|
switch (m4) /* m4: HFP format */
|
|
{
|
|
case 2: /* short HFP */
|
|
hexNumberToShortFloat( &hNum, &sf );
|
|
store_sf( &sf, ®s->VR_F(v1,0));
|
|
break;
|
|
|
|
case 3: /* long HFP */
|
|
hexNumberToLongFloat( &hNum, &lf );
|
|
store_lf( &lf, ®s->VR_D(v1,0));
|
|
break;
|
|
|
|
case 4: /* extended HFP */
|
|
hexNumberToExtendedFloat( &hNum, &ef );
|
|
store_ef( &ef, ®s->VR_D(v1,0), ®s->VR_D(v1,1));
|
|
break;
|
|
|
|
default: /* reserved */
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E677 VCP - VECTOR COMPARE DECIMAL [VRR-h] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_compare_decimal )
|
|
{
|
|
int v1, v2, m3; /* Instruction parts */
|
|
|
|
/* m3 bits */
|
|
bool p1; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p2; /* Force Operand 3 Positive(P1) bit 3 */
|
|
|
|
bool valid_sign1; /* v1: is sign valid? */
|
|
bool valid_decimals1; /* v1: are decimals valid? */
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dncompared; /* compared as decNumber */
|
|
decContext set; /* zn default contect */
|
|
|
|
VRR_H(inst, regs, v1, v2, m3);
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m5 parts */
|
|
p1 = (m3 & 0x08) ? true : false;
|
|
p2 = (m3 & 0x04) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals1 = vr_packed_valid_digits( regs, v1 );
|
|
valid_sign1 = (p1) ? true : vr_packed_valid_sign( regs, v1 );
|
|
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
if (!valid_decimals1 || !valid_sign1 || !valid_decimals2 || !valid_sign2)
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v1, &dnv1, p1);
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
|
|
/* get compare result*/
|
|
zn_ContextDefault( &set );
|
|
decNumberCompare( &dncompared, &dnv1, &dnv2, &set );
|
|
|
|
cc = ( decNumberIsZero( &dncompared ) ) ? 0 : ( decNumberIsNegative( &dncompared ) ) ? 1 : 2;
|
|
regs->psw.cc = cc;
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E678 VMP - VECTOR MULTIPLY DECIMAL [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_multiply_decimal )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p3; /* Force Operand 3 Positive(P1) bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
bool valid_sign3; /* v3: is sign valid? */
|
|
bool valid_decimals3; /* v3: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dnv3; /* v3 as decNumber */
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
rdc = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p3 = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
valid_decimals3 = vr_packed_valid_digits( regs, v3 );
|
|
valid_sign3 = (p3) ? true : vr_packed_valid_sign( regs, v3 );
|
|
|
|
if (!valid_decimals2 || !valid_sign2 || !valid_decimals3 || !valid_sign3)
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
vr_to_decNumber( regs, v3, &dnv3, p3);
|
|
|
|
/* get product */
|
|
zn_ContextDefault( &set );
|
|
decNumberMultiply( &dnv1, &dnv2, &dnv3, &set );
|
|
|
|
// DEBUG
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnv3: ", &dnv3);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store product in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, rdc);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E679 VMSP - VECTOR MULTIPLY AND SHIFT DECIMAL [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_multiply_and_shift_decimal )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
/* i4 bits */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int shamt; /* Shift Amount (SHAMT): Bits 3-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p3; /* Force Operand 3 Positive(P1) bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
bool valid_sign3; /* v3: is sign valid? */
|
|
bool valid_decimals3; /* v3: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dnv3; /* v3 as decNumber */
|
|
decNumber dnproduct; /* (v2 * v3) as decNumber */
|
|
decNumber dnshift; /* -shamt as decNumber (note:negative)*/
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
shamt = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p3 = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
valid_decimals3 = vr_packed_valid_digits( regs, v3 );
|
|
valid_sign3 = (p3) ? true : vr_packed_valid_sign( regs, v3 );
|
|
|
|
if (!valid_decimals2 || !valid_sign2 || !valid_decimals3 || !valid_sign3)
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
vr_to_decNumber( regs, v3, &dnv3, p3);
|
|
|
|
/* get product */
|
|
zn_ContextDefault( &set );
|
|
decNumberMultiply( &dnproduct, &dnv2, &dnv3, &set );
|
|
|
|
/* get shift as decNumber: right shift is negative */
|
|
decNumberFromInt32(&dnshift, -shamt);
|
|
decNumberShift(&dnv1, &dnproduct, &dnshift, &set);
|
|
|
|
// DEBUG
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnv3: ", &dnv3);
|
|
// dn_logmsg("dnvproduct: ", &dnproduct);
|
|
// dn_logmsg("dnshift: ", &dnshift);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store shifted result in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, MAX_DECIMAL_DIGITS);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E67A VDP - VECTOR DIVIDE DECIMAL [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_divide_decimal )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p3; /* Force Operand 3 Positive(P1) bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
bool valid_sign3; /* v3: is sign valid? */
|
|
bool valid_decimals3; /* v3: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dnv3; /* v3 as decNumber */
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
rdc = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p3 = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
valid_decimals3 = vr_packed_valid_digits( regs, v3 );
|
|
valid_sign3 = (p3) ? true : vr_packed_valid_sign( regs, v3 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 || !valid_decimals3 || !valid_sign3 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
vr_to_decNumber( regs, v3, &dnv3, p3);
|
|
|
|
/* Program check if divisor (v3) is zero */
|
|
if ( decNumberIsZero( &dnv3 ) )
|
|
ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_DIVIDE_EXCEPTION);
|
|
|
|
/* get integer quotient */
|
|
zn_ContextDefault( &set );
|
|
decNumberDivideInteger( &dnv1, &dnv2, &dnv3, &set );
|
|
|
|
// DEBUG
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnv3: ", &dnv3);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store product in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, rdc);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* E67B VRP - VECTOR REMAINDER DECIMAL [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_remainder_decimal )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int rdc; /* Result Digits Count(RDC) Bit 3-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p3; /* Force Operand 3 Positive(P1) bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
bool valid_sign3; /* v3: is sign valid? */
|
|
bool valid_decimals3; /* v3: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dnv3; /* v3 as decNumber */
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
rdc = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
if ( rdc == 0 ) /* zero rdc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p3 = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
valid_decimals3 = vr_packed_valid_digits( regs, v3 );
|
|
valid_sign3 = (p3) ? true : vr_packed_valid_sign( regs, v3 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 || !valid_decimals3 || !valid_sign3 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
vr_to_decNumber( regs, v3, &dnv3, p3);
|
|
|
|
/* Program check if divisor (v3) is zero */
|
|
if ( decNumberIsZero( &dnv3 ) )
|
|
ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_DIVIDE_EXCEPTION);
|
|
|
|
/* get remander */
|
|
zn_ContextDefault( &set );
|
|
decNumberRemainder( &dnv1, &dnv2, &dnv3, &set );
|
|
|
|
// DEBUG
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnv3: ", &dnv3);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store product in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, rdc);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E67C VSCSHP - DECIMAL SCALE AND CONVERT AND SPLIT TO HFP [VRR-b] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST(decimal_scale_and_convert_and_split_to_hfp )
|
|
{
|
|
int v1, v2, v3, m4, m5;
|
|
|
|
U8 scale; /* scale factor: V3 byte 7 */
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decNumber dnscale; /* scale as decNumber */
|
|
decContext set; /* zn default context */
|
|
U8 hxNumber[DECNUMDIGITS]; /* hexNumber digits */
|
|
hexNumber htemp; /* temp hexNumber */
|
|
SHORT_FLOAT sf; /* hNum converted to short float */
|
|
LONG_FLOAT lf; /* hNum converted to long float */
|
|
|
|
VRR_B(inst, regs, v1, v2, v3, m4, m5);
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m4 and m5 are not part of this instruction */
|
|
UNREFERENCED( m4 );
|
|
UNREFERENCED( m5 );
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = vr_packed_valid_sign( regs, v2 );
|
|
|
|
if (!valid_decimals2 || !valid_sign2 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* zero check */
|
|
if ( vr_is_zero( regs, v2) )
|
|
{
|
|
SET_VR_ZERO( v1 ); /* true zeros */
|
|
|
|
ZVECTOR_END( regs );
|
|
return;
|
|
}
|
|
|
|
/* get scale factor from v3, byte 7. note: scale is unsigned */
|
|
scale = regs->VR_B( v3, 7);
|
|
|
|
/* scale factor: */
|
|
/* limited to values less than 8 otherwise results */
|
|
/* are unpredictable. */
|
|
scale &= 0x07;
|
|
|
|
/* operands as decNumber and context */
|
|
vr_to_decNumber( regs, v2, &dnv2, false );
|
|
zn_ContextDefault( &set );
|
|
decNumberFromInt32( &dnscale, (S32) scale );
|
|
|
|
/* scale/shift V2 */
|
|
decNumberShift( &dntemp, &dnv2, &dnscale, &set );
|
|
decNumberToHexNumber( &dntemp, &htemp );
|
|
|
|
/* debug */
|
|
if (0)
|
|
{
|
|
hexNumberToString(&htemp, hxNumber);
|
|
logmsg(" VSCSHP - hexNumberToString: %s \n", hxNumber );
|
|
}
|
|
|
|
/* convert and split hexNumber */
|
|
SET_VR_ZERO (v1);
|
|
|
|
/* high and low results */
|
|
hexNumberSplit( &htemp, &sf, &lf );
|
|
store_sf( &sf, ®s->VR_F(v1,0));
|
|
|
|
/* not zero, save. (v1, already has true zero for low result) */
|
|
if ( lf.long_fract != 0 )
|
|
{
|
|
store_lf( &lf, ®s->VR_D(v1,1));
|
|
}
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E67D VCSPH - VECTOR CONVERT HFP TO SCALED DECIMAL [VRR-j] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_convert_hfp_to_scaled_decimal )
|
|
{
|
|
int v1, v2, v3, m4;
|
|
|
|
bool rm; /* Rounding Mode (RM) */
|
|
U8 scale; /* scale factor: V3 byte 7 */
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decNumber dntemp2; /* temp decNumber */
|
|
decNumber dnscale; /* scale as decNumber */
|
|
decContext set; /* zn default context */
|
|
EXTENDED_FLOAT ef; /* v2 as extended float */
|
|
|
|
VRR_J( inst, regs, v1, v2, v3, m4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* m4 parts */
|
|
rm = (m4 & 0x01) ? true : false;
|
|
|
|
/* get scale factor from v3, byte 7. note: scale is unsigned */
|
|
scale = regs->VR_B( v3, 7);
|
|
|
|
/* scale factor: */
|
|
/* must be less than 32 otherwise the result is */
|
|
/* unpredictable. */
|
|
scale &= 0x1F;
|
|
|
|
/* zero check */
|
|
if ( vr_is_true_zero( regs, v2) )
|
|
{
|
|
SET_VR_ZERO( v1 );
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
ZVECTOR_END( regs );
|
|
return;
|
|
}
|
|
|
|
/* get Extended Float form v2 */
|
|
get_ef( &ef, ®s->VR_D(v2,0), ®s->VR_D(v2,1) );
|
|
|
|
/* as decNumber */
|
|
decNumberFromExtendedFloat( &dntemp, &ef );
|
|
|
|
/* apply shift */
|
|
decNumberFromUInt32( &dnscale, scale );
|
|
zn_ContextDefault( &set );
|
|
decNumberShift( &dntemp2, &dntemp, &dnscale, &set );
|
|
|
|
/* convert to decimal integer */
|
|
if (rm)
|
|
{ /* rounded to nearest with ties away from zero */
|
|
decContextSetRounding( &set, DEC_ROUND_HALF_UP );
|
|
}
|
|
else
|
|
{
|
|
/* truncate */
|
|
decContextSetRounding( &set, DEC_ROUND_DOWN );
|
|
}
|
|
decNumberToIntegralValue( &dnv1, &dntemp2, &set );
|
|
|
|
if (0) /*debug */
|
|
{
|
|
dc_logmsg("VCSPH: ", &set);
|
|
dn_logmsg("VCSPH - v1: ", &dnv1);
|
|
}
|
|
|
|
/* load into vr */
|
|
vr_from_decNumber( regs, v1, &dnv1, false, 31);
|
|
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_192_VECT_PACKDEC_ENH_2_FACILITY ) */
|
|
|
|
|
|
#if defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E67E VSDP - VECTOR SHIFT AND DIVIDE DECIMAL [VRI-f] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_shift_and_divide_decimal )
|
|
{
|
|
int v1, v2, v3, m5, i4; /* Instruction parts */
|
|
bool iom; /* Instruction-Overflow Mask (IOM) */
|
|
int shamt; /* Shift Amount (SHAMT): Bits 3-7 */
|
|
/* m5 bits */
|
|
bool p2; /* Force Operand 2 Positive(P2) bit 0 */
|
|
bool p3; /* Force Operand 3 Positive(P1) bit 1 */
|
|
bool p1; /* Force Operand 1 Positive(P1) bit 2 */
|
|
bool cs; /* Condition Code Set (CS): bit 3 */
|
|
|
|
bool valid_sign2; /* v2: is sign valid? */
|
|
bool valid_decimals2; /* v2: are decimals valid? */
|
|
bool valid_sign3; /* v3: is sign valid? */
|
|
bool valid_decimals3; /* v3: are decimals valid? */
|
|
BYTE cc; /* condition code */
|
|
bool overflow = false; /* overflowed? */
|
|
|
|
decNumber dnv1; /* v1 as decNumber */
|
|
decNumber dnv2; /* v2 as decNumber */
|
|
decNumber dnv3; /* v3 as decNumber */
|
|
decNumber dnshift; /* shamt as decNumber */
|
|
decNumber dntemp; /* temp decNumber */
|
|
decContext set; /* zn default contect */
|
|
|
|
VRI_F( inst, regs, v1, v2, v3, m5, i4 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
/* i4 reserved bits 1-2 must be zero */
|
|
if ( i4 & 0x60 ) /* not zero => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* i4 parts */
|
|
iom = (i4 & 0x80) ? true : false;
|
|
shamt = (i4 & 0x1F);
|
|
|
|
if (iom && !FACILITY_ENABLED( 152_VECT_PACKDEC_ENH, regs ))
|
|
ARCH_DEP(program_interrupt)( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* m5 parts */
|
|
p2 = (m5 & 0x08) ? true : false;
|
|
p3 = (m5 & 0x04) ? true : false;
|
|
p1 = (m5 & 0x02) ? true : false;
|
|
cs = (m5 & 0x01) ? true : false;
|
|
|
|
/* valid checks */
|
|
valid_decimals2 = vr_packed_valid_digits( regs, v2 );
|
|
valid_sign2 = (p2) ? true : vr_packed_valid_sign( regs, v2 );
|
|
|
|
valid_decimals3 = vr_packed_valid_digits( regs, v3 );
|
|
valid_sign3 = (p3) ? true : vr_packed_valid_sign( regs, v3 );
|
|
|
|
if ( !valid_decimals2 || !valid_sign2 || !valid_decimals3 || !valid_sign3 )
|
|
{
|
|
regs->dxc = DXC_DECIMAL;
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DATA_EXCEPTION );
|
|
}
|
|
|
|
/* operands as decNumbers */
|
|
vr_to_decNumber( regs, v2, &dnv2, p2);
|
|
vr_to_decNumber( regs, v3, &dnv3, p3);
|
|
|
|
/* Program check if divisor (v3) is zero */
|
|
if ( decNumberIsZero( &dnv3 ) )
|
|
ARCH_DEP(program_interrupt) (regs, PGM_DECIMAL_DIVIDE_EXCEPTION);
|
|
|
|
/* shifted left the dividend (v2); get integer quotient */
|
|
zn_ContextDefault( &set );
|
|
decNumberFromInt32( &dnshift, shamt);
|
|
decNumberShift( &dntemp, &dnv2, &dnshift, &set);
|
|
decNumberDivideInteger( &dnv1, &dntemp, &dnv3, &set );
|
|
|
|
// DEBUG
|
|
// dn_logmsg("dnv2: ", &dnv2);
|
|
// dn_logmsg("dnv3: ", &dnv3);
|
|
// dn_logmsg("dnshift: ", &dnshift);
|
|
// dn_logmsg("dntemp: ", &dntemp);
|
|
// dn_logmsg("dnv1: ", &dnv1);
|
|
|
|
/* store product in vector register */
|
|
overflow = vr_from_decNumber( regs, v1, &dnv1, p1, MAX_DECIMAL_DIGITS);
|
|
|
|
/* if the result is 0 & the sign is negative; change to positive */
|
|
if ( vr_is_minus_zero( regs, v1 ) )
|
|
SET_VR_SIGN( v1, PREFERRED_PLUS );
|
|
|
|
/* set condition code */
|
|
if (cs)
|
|
{
|
|
cc = ( decNumberIsZero( &dnv1 ) ) ? 0 : ( VR_HAS_MINUS_SIGN( v1 ) ) ? 1 : 2;
|
|
if ( overflow ) cc = 3;
|
|
regs->psw.cc = cc;
|
|
}
|
|
|
|
/* note: operation is completed before any fixed-point overflow exception */
|
|
/* masked overflow? */
|
|
if ( !iom && overflow && DOMASK(®s->psw))
|
|
ARCH_DEP(program_interrupt) ( regs, PGM_DECIMAL_OVERFLOW_EXCEPTION );
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
|
|
#endif /* defined( FEATURE_134_ZVECTOR_PACK_DEC_FACILITY ) */
|
|
|
|
#if defined( FEATURE_199_VECT_PACKDEC_ENH_FACILITY_3 )
|
|
/*-------------------------------------------------------------------*/
|
|
/* E67F VTZ - Vector Test Zoned [VRI-l] */
|
|
/*-------------------------------------------------------------------*/
|
|
DEF_INST( vector_test_zoned )
|
|
{
|
|
int v1, v2, i3; /* Instruction parts */
|
|
|
|
/* i3 bits */
|
|
bool ssc; /* Separate-Sign Control (SSC): bit 1 */
|
|
bool ls; /* Leading Sign (LS): bit 2 */
|
|
U8 dsc; /* Disallowed-Spaces Count (DSC): bits 3-7 */
|
|
U8 stc; /* Sign-Test Control (STC): Bits 8-10 */
|
|
U8 dc; /* Digits Count (DC): Bits 11-15 */
|
|
|
|
SV temp; /* 32 byte source vector */
|
|
bool valid_decimal; /* decimal validation failed? */
|
|
bool valid_sign; /* sign validation failed? */
|
|
U8 cc; /* condition code */
|
|
|
|
int i; /* array index */
|
|
bool isZero; /* is the zoned value 0? */
|
|
BYTE sign; /* sign byte */
|
|
enum ZONED_BYTE_FORMAT zsf; /* zoned sign byte format */
|
|
|
|
VRI_L( inst, regs, v1, v2, i3 );
|
|
|
|
ZVECTOR_CHECK( regs );
|
|
|
|
valid_decimal = true;
|
|
valid_sign = true;
|
|
isZero = false;
|
|
|
|
SV_D( temp, 0 ) = regs->VR_D( v1, 0 );
|
|
SV_D( temp, 1 ) = regs->VR_D( v1, 1 );
|
|
SV_D( temp, 2 ) = regs->VR_D( v2, 0 );
|
|
SV_D( temp, 3 ) = regs->VR_D( v2, 1 );
|
|
|
|
/* i3 parts */
|
|
ssc = (i3 & 0x4000) ? true : false;
|
|
ls = (i3 & 0x2000) ? true : false;
|
|
dsc = (i3 & 0x1F00) >> 8;
|
|
stc = (i3 & 0x00E0) >> 5;
|
|
dc = (i3 & 0x001F);
|
|
|
|
// logmsg("VTZ: i3=%d, ssc: %d, ls: %d, dsc: %d, stc: %d, dc: %d\n", i3, ssc, ls, dsc, stc, dc);
|
|
|
|
if ( dc == 0 ) /* zero dc => Specficitcation excp */
|
|
ARCH_DEP( program_interrupt )( regs, PGM_SPECIFICATION_EXCEPTION );
|
|
|
|
/* validation depends on the type of zoned format */
|
|
/* Pop SA22-7832-14: Figure 25-7, page 25-34 */
|
|
|
|
if ( ssc == 0 && ls == 0 && dsc == dc )
|
|
{ /* ETS-type-zoned format */
|
|
zsf = SD_BYTE;
|
|
sign = SV_B( temp, 31);
|
|
|
|
/* validate digits & check isZero */
|
|
/* sign byte */
|
|
isZero = (sign & 0X0F) ? false : true;
|
|
valid_decimal = ( (sign & 0X0F) <= 9 ) ? true : false;
|
|
|
|
/* N-1 ZD bytes */
|
|
for (i=1; i < dc ; i++)
|
|
{
|
|
if ( SV_B( temp, 31-i) < 0xF0 || SV_B( temp, 31-i) > 0xF9 )
|
|
{
|
|
valid_decimal = false;
|
|
isZero = false;
|
|
}
|
|
else
|
|
if ( SV_B( temp, 31-i) != 0xF0 )
|
|
isZero = false;
|
|
}
|
|
|
|
/* validate sign */
|
|
valid_sign = zoned_valid_sign_enhanced( sign, zsf, isZero, stc);
|
|
|
|
// logmsg("VTZ: ETS-type: sign: %x, isZero: %d, valid_decimal: %d, valid_sign: %d\n", sign, isZero, valid_decimal, valid_sign);
|
|
}
|
|
|
|
else if ( ssc == 0 && ls == 0 && dsc < dc )
|
|
{ /* SETS-type-zoned format */
|
|
zsf = SD_BYTE;
|
|
sign = SV_B( temp, 31);
|
|
|
|
/* validate digits & check isZero */
|
|
/* sign byte */
|
|
isZero = (sign & 0X0F) ? false : true;
|
|
valid_decimal = ( (sign & 0X0F) <= 9 ) ? true : false;
|
|
|
|
/* dsc ZD bytes */
|
|
for (i=1; i < dsc ; i++)
|
|
{
|
|
if ( SV_B( temp, 31-i) < 0xF0 || SV_B( temp, 31-i) > 0xF9 )
|
|
{
|
|
valid_decimal = false;
|
|
isZero = false;
|
|
}
|
|
else
|
|
if ( SV_B( temp, 31-i) != 0xF0 )
|
|
isZero = false;
|
|
}
|
|
|
|
/* dc-dsc ZD bytes */
|
|
for (i=dsc; i < dc ; i++)
|
|
{
|
|
if ( SV_B( temp, 31-i) != 0x40 && ( SV_B( temp, 31-i) < 0xF0 || SV_B( temp, 31-i) > 0xF9 ) )
|
|
{
|
|
valid_decimal = false;
|
|
isZero = false;
|
|
}
|
|
else
|
|
if ( SV_B( temp, 31-i) != 0xF0 )
|
|
isZero = false;
|
|
}
|
|
|
|
/* validate sign */
|
|
valid_sign = zoned_valid_sign_enhanced( sign, zsf, isZero, stc);
|
|
|
|
// logmsg("VTZ: SETS-type: sign: %x, isZero: %d, valid_decimal: %d, valid_sign: %d\n", sign, isZero, valid_decimal, valid_sign);
|
|
}
|
|
|
|
else if ( ssc == 0 && ls == 1 )
|
|
{ /* ELS-type-zoned format */
|
|
zsf = SD_BYTE;
|
|
sign = SV_B( temp, 31 - dc ); //imbedded sign
|
|
|
|
/* validate digits & check isZero */
|
|
/* sign byte */
|
|
isZero = (sign & 0X0F) ? false : true;
|
|
valid_decimal = ( (sign & 0X0F) <= 9 ) ? true : false;
|
|
|
|
/* N-1 ZD bytes */
|
|
for (i=0; i < dc-1 ; i++)
|
|
{
|
|
if ( SV_B( temp, 31-i) < 0xF0 || SV_B( temp, 31-i) > 0xF9 )
|
|
{
|
|
valid_decimal = false;
|
|
isZero = false;
|
|
}
|
|
else
|
|
if ( SV_B( temp, 31-i) != 0xF0 )
|
|
isZero = false;
|
|
}
|
|
|
|
/* validate sign */
|
|
valid_sign = zoned_valid_sign_enhanced( sign, zsf, isZero, stc);
|
|
|
|
// logmsg("VTZ: ELS-type: sign: %x, isZero: %d, valid_decimal: %d, valid_sign: %d\n", sign, isZero, valid_decimal, valid_sign);
|
|
}
|
|
|
|
else if ( ssc == 1 && ls == 0 )
|
|
{ /* STS-type-zoned format */
|
|
zsf = SS_BYTE;
|
|
sign = SV_B( temp, 31);
|
|
|
|
/* validate digits & check isZero */
|
|
isZero = true;
|
|
valid_decimal = true;
|
|
|
|
/* N-1 ZD bytes */
|
|
for (i=1; i < dc ; i++)
|
|
{
|
|
if ( SV_B( temp, 31-i) < 0xF0 || SV_B( temp, 31-i) > 0xF9 )
|
|
{
|
|
valid_decimal = false;
|
|
isZero = false;
|
|
}
|
|
else
|
|
if ( SV_B( temp, 31-i) != 0xF0 )
|
|
isZero = false;
|
|
}
|
|
|
|
valid_sign = zoned_valid_sign_enhanced( sign, zsf, isZero, stc);
|
|
|
|
// logmsg("VTZ: STS-type: sign: %x, isZero: %d, valid_decimal: %d, valid_sign: %d\n", sign, isZero, valid_decimal, valid_sign);
|
|
}
|
|
|
|
else if ( ssc == 1 && ls == 1 )
|
|
{ /* SLS-type-zoned format */
|
|
zsf = SS_BYTE;
|
|
sign = SV_B( temp, 31 - dc ); //separate leading sign
|
|
|
|
/* validate digits & check isZero */
|
|
isZero = true;
|
|
valid_decimal = true;
|
|
|
|
/* N-1 ZD bytes */
|
|
for (i=0; i < dc ; i++)
|
|
{
|
|
if ( SV_B( temp, 31-i) < 0xF0 || SV_B( temp, 31-i) > 0xF9 )
|
|
{
|
|
valid_decimal = false;
|
|
isZero = false;
|
|
}
|
|
else
|
|
if ( SV_B( temp, 31-i) != 0xF0 )
|
|
isZero = false;
|
|
}
|
|
|
|
valid_sign = zoned_valid_sign_enhanced( sign, zsf, isZero, stc);
|
|
|
|
// logmsg("VTZ: SLS-type: sign: %x, isZero: %d, valid_decimal: %d, valid_sign: %d\n", sign, isZero, valid_decimal, valid_sign);
|
|
}
|
|
|
|
/* set condition code */
|
|
cc = (valid_decimal) ? ( (valid_sign) ? 0 : 1) :
|
|
( (valid_sign) ? 2 : 3) ;
|
|
|
|
// logmsg("VTZ: cc: %d\n", cc);
|
|
|
|
regs->psw.cc = cc;
|
|
|
|
ZVECTOR_END( regs );
|
|
}
|
|
#endif /* defined( FEATURE_199_VECT_PACKDEC_ENH_FACILITY_3 ) */
|
|
|
|
#endif /* defined(FEATURE_129_ZVECTOR_FACILITY) */
|
|
|
|
#if !defined( _GEN_ARCH )
|
|
|
|
#if defined( _ARCH_NUM_1 )
|
|
#define _GEN_ARCH _ARCH_NUM_1
|
|
#include "zvector2.c"
|
|
#endif
|
|
|
|
#if defined( _ARCH_NUM_2 )
|
|
#undef _GEN_ARCH
|
|
#define _GEN_ARCH _ARCH_NUM_2
|
|
#include "zvector2.c"
|
|
#endif
|
|
|
|
#endif /*!defined(_GEN_ARCH)*/
|