diff options
-rw-r--r-- | target-ppc/dfp_helper.c | 72 | ||||
-rw-r--r-- | target-ppc/helper.h | 2 | ||||
-rw-r--r-- | target-ppc/translate.c | 4 |
3 files changed, 78 insertions, 0 deletions
diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c index df40da7ca9..c6c104b739 100644 --- a/target-ppc/dfp_helper.c +++ b/target-ppc/dfp_helper.c @@ -1049,3 +1049,75 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ DFP_HELPER_DEDPD(ddedpd, 64) DFP_HELPER_DEDPD(ddedpdq, 128) + +static inline uint8_t dfp_get_bcd_digit_64(uint64_t *t, unsigned n) +{ + return *t >> ((n << 2) & 63) & 15; +} + +static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n) +{ + return t[(n & 0x10) ? HI_IDX : LO_IDX] >> ((n << 2) & 63) & 15; +} + +#define DFP_HELPER_ENBCD(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ +{ \ + struct PPC_DFP dfp; \ + uint8_t digits[32]; \ + int n = 0, offset = 0, sgn = 0, nonzero = 0; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + decNumberZero(&dfp.t); \ + \ + if (s) { \ + uint8_t sgnNibble = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + switch (sgnNibble) { \ + case 0xD: \ + case 0xB: \ + sgn = 1; \ + break; \ + case 0xC: \ + case 0xF: \ + case 0xA: \ + case 0xE: \ + sgn = 0; \ + break; \ + default: \ + dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ + return; \ + } \ + } \ + \ + while (offset < (size)/4) { \ + n++; \ + digits[(size)/4-n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + if (digits[(size)/4-n] > 10) { \ + dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ + return; \ + } else { \ + nonzero |= (digits[(size)/4-n] > 0); \ + } \ + } \ + \ + if (nonzero) { \ + decNumberSetBCD(&dfp.t, digits+((size)/4)-n, n); \ + } \ + \ + if (s && sgn) { \ + dfp.t.bits |= DECNEG; \ + } \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ + &dfp.context); \ + dfp_set_FPRF_from_FRT(&dfp); \ + if ((size) == 64) { \ + t[0] = dfp.t64[0]; \ + } else if ((size) == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_ENBCD(denbcd, 64) +DFP_HELPER_ENBCD(denbcdq, 128) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index d4e73f26cb..1b40ce5e43 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -656,3 +656,5 @@ DEF_HELPER_3(dctfix, void, env, fprp, fprp) DEF_HELPER_3(dctfixq, void, env, fprp, fprp) DEF_HELPER_4(ddedpd, void, env, fprp, fprp, i32) DEF_HELPER_4(ddedpdq, void, env, fprp, fprp, i32) +DEF_HELPER_4(denbcd, void, env, fprp, fprp, i32) +DEF_HELPER_4(denbcdq, void, env, fprp, fprp, i32) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2588ddb548..ea5df2f77f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -8396,6 +8396,8 @@ GEN_DFP_T_B_Rc(dctfix) GEN_DFP_T_B_Rc(dctfixq) GEN_DFP_T_FPR_I32_Rc(ddedpd, rB, SP) GEN_DFP_T_FPR_I32_Rc(ddedpdq, rB, SP) +GEN_DFP_T_FPR_I32_Rc(denbcd, rB, SP) +GEN_DFP_T_FPR_I32_Rc(denbcdq, rB, SP) /*** SPE extension ***/ /* Register moves */ @@ -11363,6 +11365,8 @@ GEN_DFP_T_B_Rc(dctfix, 0x02, 0x09), GEN_DFP_T_Bp_Rc(dctfixq, 0x02, 0x09), GEN_DFP_SP_T_B_Rc(ddedpd, 0x02, 0x0a), GEN_DFP_SP_Tp_Bp_Rc(ddedpdq, 0x02, 0x0a), +GEN_DFP_S_T_B_Rc(denbcd, 0x02, 0x1a), +GEN_DFP_S_Tp_Bp_Rc(denbcdq, 0x02, 0x1a), #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) |