diff options
-rw-r--r-- | target-ppc/op.c | 95 | ||||
-rw-r--r-- | target-ppc/op_helper.c | 12 | ||||
-rw-r--r-- | target-ppc/op_helper.h | 1 | ||||
-rw-r--r-- | target-ppc/translate.c | 104 |
4 files changed, 72 insertions, 140 deletions
diff --git a/target-ppc/op.c b/target-ppc/op.c index 2453300e3a..5a8fe0a600 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -326,34 +326,6 @@ void OPPROTO op_store_fpscr (void) RETURN(); } -/*** Integer arithmetic ***/ -/* add */ -void OPPROTO op_check_addo (void) -{ - int ov = (((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) & - ((uint32_t)T2 ^ (uint32_t)T0)) >> 31; - if (ov) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - } else { - env->xer &= ~(1 << XER_OV); - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_check_addo_64 (void) -{ - int ov = (((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) & - ((uint64_t)T2 ^ (uint64_t)T0)) >> 63; - if (ov) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - } else { - env->xer &= ~(1 << XER_OV); - } - RETURN(); -} -#endif - /*** Integer shift ***/ void OPPROTO op_srli_T1 (void) { @@ -1062,73 +1034,6 @@ void OPPROTO op_602_mfrom (void) #endif /* PowerPC 4xx specific micro-ops */ -void OPPROTO op_405_add_T0_T2 (void) -{ - T0 = (int32_t)T0 + (int32_t)T2; - RETURN(); -} - -void OPPROTO op_405_mulchw (void) -{ - T0 = ((int16_t)T0) * ((int16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mulchwu (void) -{ - T0 = ((uint16_t)T0) * ((uint16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mulhhw (void) -{ - T0 = ((int16_t)(T0 >> 16)) * ((int16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mulhhwu (void) -{ - T0 = ((uint16_t)(T0 >> 16)) * ((uint16_t)(T1 >> 16)); - RETURN(); -} - -void OPPROTO op_405_mullhw (void) -{ - T0 = ((int16_t)T0) * ((int16_t)T1); - RETURN(); -} - -void OPPROTO op_405_mullhwu (void) -{ - T0 = ((uint16_t)T0) * ((uint16_t)T1); - RETURN(); -} - -void OPPROTO op_405_check_sat (void) -{ - do_405_check_sat(); - RETURN(); -} - -void OPPROTO op_405_check_ovu (void) -{ - if (likely(T0 >= T2)) { - env->xer &= ~(1 << XER_OV); - } else { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - } - RETURN(); -} - -void OPPROTO op_405_check_satu (void) -{ - if (unlikely(T0 < T2)) { - /* Saturate result */ - T0 = UINT32_MAX; - } - RETURN(); -} - void OPPROTO op_load_dcr (void) { do_load_dcr(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 99aa0a01b9..ef1035fc56 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1510,18 +1510,6 @@ void do_op_602_mfrom (void) /*****************************************************************************/ /* Embedded PowerPC specific helpers */ -void do_405_check_sat (void) -{ - if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) || - !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) { - /* Saturate result */ - if (T2 >> 31) { - T0 = INT32_MIN; - } else { - T0 = INT32_MAX; - } - } -} /* XXX: to be improved to check access rights when in user-mode */ void do_load_dcr (void) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index b90e0c0f0e..7280cf40c5 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -144,7 +144,6 @@ void do_440_tlbwe (int word); #endif /* PowerPC 4xx specific helpers */ -void do_405_check_sat (void); void do_load_dcr (void); void do_store_dcr (void); #if !defined(CONFIG_USER_ONLY) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 73bfbc1bef..e003761d6a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5214,8 +5214,11 @@ static always_inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3, int ra, int rb, int rt, int Rc) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[ra]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rb]); + TCGv t0, t1; + + t0 = tcg_temp_local_new(TCG_TYPE_TL); + t1 = tcg_temp_local_new(TCG_TYPE_TL); + switch (opc3 & 0x0D) { case 0x05: /* macchw - macchw. - macchwo - macchwo. */ @@ -5223,13 +5226,17 @@ static always_inline void gen_405_mulladd_insn (DisasContext *ctx, /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */ /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */ /* mulchw - mulchw. */ - gen_op_405_mulchw(); + tcg_gen_ext16s_tl(t0, cpu_gpr[ra]); + tcg_gen_sari_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16s_tl(t1, t1); break; case 0x04: /* macchwu - macchwu. - macchwuo - macchwuo. */ /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */ /* mulchwu - mulchwu. */ - gen_op_405_mulchwu(); + tcg_gen_ext16u_tl(t0, cpu_gpr[ra]); + tcg_gen_shri_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16u_tl(t1, t1); break; case 0x01: /* machhw - machhw. - machhwo - machhwo. */ @@ -5237,13 +5244,19 @@ static always_inline void gen_405_mulladd_insn (DisasContext *ctx, /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */ /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */ /* mulhhw - mulhhw. */ - gen_op_405_mulhhw(); + tcg_gen_sari_tl(t0, cpu_gpr[ra], 16); + tcg_gen_ext16s_tl(t0, t0); + tcg_gen_sari_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16s_tl(t1, t1); break; case 0x00: /* machhwu - machhwu. - machhwuo - machhwuo. */ /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */ /* mulhhwu - mulhhwu. */ - gen_op_405_mulhhwu(); + tcg_gen_shri_tl(t0, cpu_gpr[ra], 16); + tcg_gen_ext16u_tl(t0, t0); + tcg_gen_shri_tl(t1, cpu_gpr[rb], 16); + tcg_gen_ext16u_tl(t1, t1); break; case 0x0D: /* maclhw - maclhw. - maclhwo - maclhwo. */ @@ -5251,43 +5264,70 @@ static always_inline void gen_405_mulladd_insn (DisasContext *ctx, /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */ /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */ /* mullhw - mullhw. */ - gen_op_405_mullhw(); + tcg_gen_ext16s_tl(t0, cpu_gpr[ra]); + tcg_gen_ext16s_tl(t1, cpu_gpr[rb]); break; case 0x0C: /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */ /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */ /* mullhwu - mullhwu. */ - gen_op_405_mullhwu(); + tcg_gen_ext16u_tl(t0, cpu_gpr[ra]); + tcg_gen_ext16u_tl(t1, cpu_gpr[rb]); break; } - if (opc2 & 0x02) { - /* nmultiply-and-accumulate (0x0E) */ - tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); - } if (opc2 & 0x04) { - /* (n)multiply-and-accumulate (0x0C - 0x0E) */ - tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rt]); - tcg_gen_mov_tl(cpu_T[1], cpu_T[0]); - gen_op_405_add_T0_T2(); - } - if (opc3 & 0x10) { - /* Check overflow */ - if (opc3 & 0x01) - gen_op_check_addo(); - else - gen_op_405_check_ovu(); - } - if (opc3 & 0x02) { - /* Saturate */ - if (opc3 & 0x01) - gen_op_405_check_sat(); - else - gen_op_405_check_satu(); + /* (n)multiply-and-accumulate (0x0C / 0x0E) */ + tcg_gen_mul_tl(t1, t0, t1); + if (opc2 & 0x02) { + /* nmultiply-and-accumulate (0x0E) */ + tcg_gen_sub_tl(t0, cpu_gpr[rt], t1); + } else { + /* multiply-and-accumulate (0x0C) */ + tcg_gen_add_tl(t0, cpu_gpr[rt], t1); + } + + if (opc3 & 0x12) { + /* Check overflow and/or saturate */ + int l1 = gen_new_label(); + + if (opc3 & 0x10) { + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + } + if (opc3 & 0x01) { + /* Signed */ + tcg_gen_xor_tl(t1, cpu_gpr[rt], t1); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_gen_xor_tl(t1, cpu_gpr[rt], t0); + tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1); + if (opc3 & 0x02) { + /* Saturate */ + tcg_gen_sari_tl(t0, cpu_gpr[rt], 31); + tcg_gen_xori_tl(t0, t0, 0x7fffffff); + } + } else { + /* Unsigned */ + tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); + if (opc3 & 0x02) { + /* Saturate */ + tcg_gen_movi_tl(t0, UINT32_MAX); + } + } + if (opc3 & 0x10) { + /* Check overflow */ + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + } + gen_set_label(l1); + tcg_gen_mov_tl(cpu_gpr[rt], t0); + } + } else { + tcg_gen_mul_tl(cpu_gpr[rt], t0, t1); } - tcg_gen_mov_tl(cpu_gpr[rt], cpu_T[0]); + tcg_temp_free(t0); + tcg_temp_free(t1); if (unlikely(Rc) != 0) { /* Update Rc0 */ - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rt]); } } |