target-ppc: Introduce DFP Shift Significand

Add emulation of the PowerPC Decimal Floating Point Shift Significand
Left Immediate (dscli[q][.]) and DFP Shift Significant Right Immediate
(dscri[q][.]) instructions.

Signed-off-by: Tom Musta <tommusta@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Tom Musta 2014-04-21 15:55:21 -05:00 committed by Alexander Graf
parent 297666eba0
commit 804e654a56
3 changed files with 109 additions and 0 deletions

View File

@ -1220,3 +1220,98 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
DFP_HELPER_IEX(diex, 64)
DFP_HELPER_IEX(diexq, 128)
static void dfp_clear_lmd_from_g5msb(uint64_t *t)
{
/* The most significant 5 bits of the PowerPC DFP format combine bits */
/* from the left-most decimal digit (LMD) and the biased exponent. */
/* This routine clears the LMD bits while preserving the exponent */
/* bits. See "Figure 80: Encoding of bits 0:4 of the G field for */
/* Finite Numbers" in the Power ISA for additional details. */
uint64_t g5msb = (*t >> 58) & 0x1F;
if ((g5msb >> 3) < 3) { /* LMD in [0-7] ? */
*t &= ~(7ULL << 58);
} else {
switch (g5msb & 7) {
case 0:
case 1:
g5msb = 0;
break;
case 2:
case 3:
g5msb = 0x8;
break;
case 4:
case 5:
g5msb = 0x10;
break;
case 6:
g5msb = 0x1E;
break;
case 7:
g5msb = 0x1F;
break;
}
*t &= ~(0x1fULL << 58);
*t |= (g5msb << 58);
}
}
#define DFP_HELPER_SHIFT(op, size, shift_left) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \
uint32_t sh) \
{ \
struct PPC_DFP dfp; \
unsigned max_digits = ((size) == 64) ? 16 : 34; \
\
dfp_prepare_decimal##size(&dfp, a, 0, env); \
\
if (sh <= max_digits) { \
\
decNumber shd; \
unsigned special = dfp.a.bits & DECSPECIAL; \
\
if (shift_left) { \
decNumberFromUInt32(&shd, sh); \
} else { \
decNumberFromInt32(&shd, -((int32_t)sh)); \
} \
\
dfp.a.bits &= ~DECSPECIAL; \
decNumberShift(&dfp.t, &dfp.a, &shd, &dfp.context); \
\
dfp.t.bits |= special; \
if (special && (dfp.t.digits >= max_digits)) { \
dfp.t.digits = max_digits - 1; \
} \
\
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
&dfp.context); \
} else { \
if ((size) == 64) { \
dfp.t64[0] = dfp.a64[0] & 0xFFFC000000000000ULL; \
dfp_clear_lmd_from_g5msb(dfp.t64); \
} else { \
dfp.t64[HI_IDX] = dfp.a64[HI_IDX] & \
0xFFFFC00000000000ULL; \
dfp_clear_lmd_from_g5msb(dfp.t64 + HI_IDX); \
dfp.t64[LO_IDX] = 0; \
} \
} \
\
if ((size) == 64) { \
t[0] = dfp.t64[0]; \
} else { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
}
DFP_HELPER_SHIFT(dscli, 64, 1)
DFP_HELPER_SHIFT(dscliq, 128, 1)
DFP_HELPER_SHIFT(dscri, 64, 0)
DFP_HELPER_SHIFT(dscriq, 128, 0)

View File

@ -662,3 +662,7 @@ DEF_HELPER_3(dxex, void, env, fprp, fprp)
DEF_HELPER_3(dxexq, void, env, fprp, fprp)
DEF_HELPER_4(diex, void, env, fprp, fprp, fprp)
DEF_HELPER_4(diexq, void, env, fprp, fprp, fprp)
DEF_HELPER_4(dscri, void, env, fprp, fprp, i32)
DEF_HELPER_4(dscriq, void, env, fprp, fprp, i32)
DEF_HELPER_4(dscli, void, env, fprp, fprp, i32)
DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32)

View File

@ -8402,6 +8402,11 @@ GEN_DFP_T_B_Rc(dxex)
GEN_DFP_T_B_Rc(dxexq)
GEN_DFP_T_A_B_Rc(diex)
GEN_DFP_T_A_B_Rc(diexq)
GEN_DFP_T_FPR_I32_Rc(dscli, rA, DCM)
GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM)
GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM)
GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM)
/*** SPE extension ***/
/* Register moves */
@ -11375,6 +11380,11 @@ GEN_DFP_T_B_Rc(dxex, 0x02, 0x0b),
GEN_DFP_T_Bp_Rc(dxexq, 0x02, 0x0b),
GEN_DFP_T_A_B_Rc(diex, 0x02, 0x1b),
GEN_DFP_Tp_A_Bp_Rc(diexq, 0x02, 0x1b),
GEN_DFP_T_A_SH_Rc(dscli, 0x02, 0x02),
GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02),
GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03),
GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03),
#undef GEN_SPE
#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \
GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE)