diff options
author | Tom Musta <tommusta@gmail.com> | 2014-04-21 15:55:01 -0500 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2014-06-16 13:24:30 +0200 |
commit | a9d7ba03b0fa8c7b6d660c6aafa736d16921728f (patch) | |
tree | fffa6fed766005033e1d0fd4180b87eaffcb5b6e /target-ppc | |
parent | 27722744e9fc81e437a5e55db8ec31ec99b31714 (diff) | |
download | hqemu-a9d7ba03b0fa8c7b6d660c6aafa736d16921728f.zip hqemu-a9d7ba03b0fa8c7b6d660c6aafa736d16921728f.tar.gz |
target-ppc: Introduce DFP Add
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 <tommusta@gmail.com>
[agraf: move brace in function definition]
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/dfp_helper.c | 129 | ||||
-rw-r--r-- | target-ppc/helper.h | 3 | ||||
-rw-r--r-- | target-ppc/translate.c | 7 |
3 files changed, 134 insertions, 5 deletions
diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c index 9e9bc57..9f4cd33 100644 --- a/target-ppc/dfp_helper.c +++ b/target-ppc/dfp_helper.c @@ -79,7 +79,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) { @@ -104,7 +103,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) { @@ -152,7 +150,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) { @@ -161,3 +158,129 @@ static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, dfp->env->fpscr |= FP_FEX; } } + +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); +} + +#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); \ + postprocs(&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]; \ + } \ +} + +static void ADD_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_OX(dfp); + dfp_check_for_UX(dfp); + dfp_check_for_XX(dfp); + dfp_check_for_VXSNAN(dfp); + dfp_check_for_VXISI_add(dfp); +} + +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 22d5466..99e6198 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -615,3 +615,6 @@ DEF_HELPER_3(store_601_batu, void, env, i32, tl) #define dh_alias_fprp ptr #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) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 724cb7f..9397a6b 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) |