diff options
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/dfp_helper.c | 95 | ||||
-rw-r--r-- | target-ppc/helper.h | 4 | ||||
-rw-r--r-- | target-ppc/translate.c | 10 |
3 files changed, 109 insertions, 0 deletions
diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c index adb9763192..773803a285 100644 --- a/target-ppc/dfp_helper.c +++ b/target-ppc/dfp_helper.c @@ -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) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 435a1c0924..7e00a76d75 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -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) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index da71e925ec..0d5a9a57c9 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -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) |