Add emulation of the PowerPC Decimal Floating Point Add instructions dadd[q][.]
Various GCC unused annotations are removed since it is now safe to remove them. Signed-off-by: Tom Musta <tommu...@gmail.com> --- target-ppc/dfp_helper.c | 129 +++++++++++++++++++++++++++++++++++++++++++++-- target-ppc/helper.h | 2 + target-ppc/translate.c | 7 ++- 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c index 0c11696..100b0d7 100644 --- a/target-ppc/dfp_helper.c +++ b/target-ppc/dfp_helper.c @@ -77,7 +77,6 @@ static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr) decContextSetRounding(context, rnd); } -__attribute__ ((unused)) static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, uint64_t *b, CPUPPCState *env) { @@ -102,7 +101,6 @@ static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, } } -__attribute__ ((unused)) static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, uint64_t *b, CPUPPCState *env) { @@ -150,7 +148,6 @@ static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, #define FP_VE (1ull << FPSCR_VE) #define FP_FI (1ull << FPSCR_FI) -__attribute__ ((unused)) static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, uint64_t enabled) { @@ -162,7 +159,103 @@ static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, typedef void (*PPC_DFP_PostProc)(struct PPC_DFP *); -__attribute__ ((unused)) +static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp, + decContext *context) +{ + uint64_t fprf = 0; + + /* construct FPRF */ + switch (decNumberClass(&dfp->t, context)) { + case DEC_CLASS_SNAN: + fprf = 0x01; + break; + case DEC_CLASS_QNAN: + fprf = 0x11; + break; + case DEC_CLASS_NEG_INF: + fprf = 0x09; + break; + case DEC_CLASS_NEG_NORMAL: + fprf = 0x08; + break; + case DEC_CLASS_NEG_SUBNORMAL: + fprf = 0x18; + break; + case DEC_CLASS_NEG_ZERO: + fprf = 0x12; + break; + case DEC_CLASS_POS_ZERO: + fprf = 0x02; + break; + case DEC_CLASS_POS_SUBNORMAL: + fprf = 0x14; + break; + case DEC_CLASS_POS_NORMAL: + fprf = 0x04; + break; + case DEC_CLASS_POS_INF: + fprf = 0x05; + break; + default: + assert(0); /* should never get here */ + } + dfp->env->fpscr &= ~(0x1F << 12); + dfp->env->fpscr |= (fprf << 12); +} + +static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT_with_context(dfp, &dfp->context); +} + +static void dfp_check_for_OX(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Overflow) { + dfp_set_FPSCR_flag(dfp, FP_OX, FP_OE); + } +} + +static void dfp_check_for_UX(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Underflow) { + dfp_set_FPSCR_flag(dfp, FP_UX, FP_UE); + } +} + +static void dfp_check_for_XX(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Inexact) { + dfp_set_FPSCR_flag(dfp, FP_XX | FP_FI, FP_XE); + } +} + +static void dfp_check_for_VXSNAN(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Invalid_operation) { + if (decNumberIsSNaN(&dfp->a) || decNumberIsSNaN(&dfp->b)) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FP_VE); + } + } +} + +static void dfp_check_for_VXISI(struct PPC_DFP *dfp, int testForSameSign) +{ + if (dfp->context.status & DEC_Invalid_operation) { + if (decNumberIsInfinite(&dfp->a) && decNumberIsInfinite(&dfp->b)) { + int same = decNumberClass(&dfp->a, &dfp->context) == + decNumberClass(&dfp->b, &dfp->context); + if ((same && testForSameSign) || (!same && !testForSameSign)) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXISI, FP_VE); + } + } + } +} + +static void dfp_check_for_VXISI_add(struct PPC_DFP *dfp) +{ + dfp_check_for_VXISI(dfp, 0); +} + static void dfp_run_post_processors(struct PPC_DFP *dfp, PPC_DFP_PostProc post_processors[], const size_t n) { @@ -172,3 +265,31 @@ static void dfp_run_post_processors(struct PPC_DFP *dfp, post_processors[i](dfp); } } + +#define DFP_HELPER_TAB(op, dnop, postprocs, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + dfp_prepare_decimal##size(&dfp, a, b, env); \ + dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_run_post_processors(&dfp, postprocs, ARRAY_SIZE(postprocs)); \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +PPC_DFP_PostProc ADD_PPs[] = { + dfp_set_FPRF_from_FRT, + dfp_check_for_OX, + dfp_check_for_UX, + dfp_check_for_XX, + dfp_check_for_VXSNAN, + dfp_check_for_VXISI_add, +}; + +DFP_HELPER_TAB(dadd, decNumberAdd, ADD_PPs, 64) +DFP_HELPER_TAB(daddq, decNumberAdd, ADD_PPs, 128) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 1bebc8e..337c005 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -618,4 +618,6 @@ DEF_HELPER_3(store_601_batu, void, env, i32, tl) #define dh_ctype_fprp uint64_t * #define dh_is_signed_fprp dh_is_signed_ptr +DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp) +DEF_HELPER_4(daddq, void, env, fprp, fprp, fprp) #include "exec/def-helper.h" diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 12aee63..4550667 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -8197,7 +8197,6 @@ static inline TCGv_ptr gen_fprp_ptr(int reg) } #if defined(TARGET_PPC64) -__attribute__ ((unused)) static void gen_set_cr6_from_fpscr(DisasContext *ctx) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -8206,7 +8205,6 @@ static void gen_set_cr6_from_fpscr(DisasContext *ctx) tcg_temp_free_i32(tmp); } #else -__attribute__ ((unused)) static void gen_set_cr6_from_fpscr(DisasContext *ctx) { tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); @@ -8358,6 +8356,9 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free_i32(i32); \ } +GEN_DFP_T_A_B_Rc(dadd) +GEN_DFP_T_A_B_Rc(daddq) + /*** SPE extension ***/ /* Register moves */ @@ -11285,6 +11286,8 @@ _GEN_DFP_LONGx2(name, op1, op2, 0x00000000) #define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \ _GEN_DFP_QUADx2(name, op1, op2, 0x00210000) +GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00), +GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00), #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) -- 1.7.1