Commit 182608d4 authored by Aurelien Jarno's avatar Aurelien Jarno
Browse files

target-ppc: convert 405 MAC instructions to TCG



Signed-off-by: default avatarAurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5591 c046a42c-6fe2-441c-8c8c-71466251a162
parent 74637406
Loading
Loading
Loading
Loading
+0 −95
Original line number Diff line number Diff line
@@ -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();
+0 −12
Original line number Diff line number Diff line
@@ -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)
+0 −1
Original line number Diff line number Diff line
@@ -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)
+72 −32
Original line number Diff line number Diff line
@@ -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 & 0x04) {
        /* (n)multiply-and-accumulate (0x0C / 0x0E) */
        tcg_gen_mul_tl(t1, t0, t1);
        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();
            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) {
        /* Check overflow */
        if (opc3 & 0x01)
            gen_op_check_addo();
        else
            gen_op_405_check_ovu();
                /* 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 */
        if (opc3 & 0x01)
            gen_op_405_check_sat();
        else
            gen_op_405_check_satu();
                    tcg_gen_sari_tl(t0, cpu_gpr[rt], 31);
                    tcg_gen_xori_tl(t0, t0, 0x7fffffff);
                }
    tcg_gen_mov_tl(cpu_gpr[rt], cpu_T[0]);
            } 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_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]);
    }
}