>From 30947b811973648636c8676f730f18a76bd9749a Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 21 Jan 2013 20:43:31 +0000 Subject: [PATCH] target-mips: Fix accumulator selection for MIPS16 and microMIPS Add accumulator arguments to gen_HILO and gen_muldiv, rather than extracting the accumulator directly from ctx->opcode. The extraction was only right for the standard encoding: MIPS16 doesn't have access to the DSP registers, while microMIPS encodes the accumulator register in a different field (bits 14 and 15). Passing the accumulator register is probably an over-generalisation for division and 64-bit multiplication, which never access anything other than HI and LO, and which always pass 0 as the new argument. Separating them felt a bit fussy though. Signed-off-by: Richard Sandiford Signed-off-by: Aurelien Jarno (cherry picked from commit 26135ead80fa1fd13e95c162dacfd06f2ba82981) Conflicts: target-mips/translate.c --- target-mips/helper.h | 4 +- target-mips/op_helper.c | 10 ++-- target-mips/translate.c | 148 ++++++++++++++++++++--------------------------- 3 files changed, 72 insertions(+), 90 deletions(-) diff --git a/target-mips/helper.h b/target-mips/helper.h index cd48738..cfe98f1 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -24,8 +24,8 @@ DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl) #ifdef TARGET_MIPS64 DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_3(dmult, void, env, tl, tl) -DEF_HELPER_3(dmultu, void, env, tl, tl) +DEF_HELPER_4(dmult, void, env, int, tl, tl) +DEF_HELPER_4(dmultu, void, env, int, tl, tl) #endif DEF_HELPER_3(muls, tl, env, tl, tl) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 526f84f..c054300 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -268,14 +268,16 @@ target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1, } #ifdef TARGET_MIPS64 -void helper_dmult(CPUMIPSState *env, target_ulong arg1, target_ulong arg2) +void helper_dmult(CPUMIPSState *env, int acc, target_ulong arg1, + target_ulong arg2) { - muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); + muls64(&(env->active_tc.LO[acc]), &(env->active_tc.HI[acc]), arg1, arg2); } -void helper_dmultu(CPUMIPSState *env, target_ulong arg1, target_ulong arg2) +void helper_dmultu(CPUMIPSState *env, int acc, target_ulong arg1, + target_ulong arg2) { - mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); + mulu64(&(env->active_tc.LO[acc]), &(env->active_tc.HI[acc]), arg1, arg2); } #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index 3b77b53..9ed6477 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2582,10 +2582,9 @@ static void gen_shift(DisasContext *ctx, uint32_t opc, } /* Arithmetic on HI/LO registers */ -static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) +static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) { const char *opn = "hilo"; - unsigned int acc; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { /* Treat as NOP. */ @@ -2593,12 +2592,6 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) return; } - if (opc == OPC_MFHI || opc == OPC_MFLO) { - acc = ((ctx->opcode) >> 21) & 0x03; - } else { - acc = ((ctx->opcode) >> 11) & 0x03; - } - if (acc != 0) { check_dsp(ctx); } @@ -2661,12 +2654,11 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) MIPS_DEBUG("%s %s", opn, regnames[reg]); } -static void gen_muldiv (DisasContext *ctx, uint32_t opc, - int rs, int rt) +static void gen_muldiv(DisasContext *ctx, uint32_t opc, + int acc, int rs, int rt) { const char *opn = "mul/div"; TCGv t0, t1; - unsigned int acc; t0 = tcg_temp_new(); t1 = tcg_temp_new(); @@ -2674,6 +2666,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, gen_load_gpr(t0, rs); gen_load_gpr(t1, rt); + if (acc != 0) { + check_dsp(ctx); + } + switch (opc) { case OPC_DIV: { @@ -2688,10 +2684,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, tcg_gen_or_tl(t2, t2, t3); tcg_gen_movi_tl(t3, 0); tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); - tcg_gen_div_tl(cpu_LO[0], t0, t1); - tcg_gen_rem_tl(cpu_HI[0], t0, t1); - tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]); - tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]); + tcg_gen_div_tl(cpu_LO[acc], t0, t1); + tcg_gen_rem_tl(cpu_HI[acc], t0, t1); + tcg_gen_ext32s_tl(cpu_LO[acc], cpu_LO[acc]); + tcg_gen_ext32s_tl(cpu_HI[acc], cpu_HI[acc]); tcg_temp_free(t3); tcg_temp_free(t2); } @@ -2704,10 +2700,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, tcg_gen_ext32u_tl(t0, t0); tcg_gen_ext32u_tl(t1, t1); tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); - tcg_gen_divu_tl(cpu_LO[0], t0, t1); - tcg_gen_remu_tl(cpu_HI[0], t0, t1); - tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]); - tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]); + tcg_gen_divu_tl(cpu_LO[acc], t0, t1); + tcg_gen_remu_tl(cpu_HI[acc], t0, t1); + tcg_gen_ext32s_tl(cpu_LO[acc], cpu_LO[acc]); + tcg_gen_ext32s_tl(cpu_HI[acc], cpu_HI[acc]); tcg_temp_free(t3); tcg_temp_free(t2); } @@ -2717,11 +2713,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } - tcg_gen_ext_tl_i64(t2, t0); tcg_gen_ext_tl_i64(t3, t1); tcg_gen_mul_i64(t2, t2, t3); @@ -2739,11 +2730,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } - tcg_gen_ext32u_tl(t0, t0); tcg_gen_ext32u_tl(t1, t1); tcg_gen_extu_tl_i64(t2, t0); @@ -2771,8 +2757,8 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, tcg_gen_or_tl(t2, t2, t3); tcg_gen_movi_tl(t3, 0); tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); - tcg_gen_div_tl(cpu_LO[0], t0, t1); - tcg_gen_rem_tl(cpu_HI[0], t0, t1); + tcg_gen_div_tl(cpu_LO[acc], t0, t1); + tcg_gen_rem_tl(cpu_HI[acc], t0, t1); tcg_temp_free(t3); tcg_temp_free(t2); } @@ -2783,19 +2769,19 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, TCGv t2 = tcg_const_tl(0); TCGv t3 = tcg_const_tl(1); tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); - tcg_gen_divu_i64(cpu_LO[0], t0, t1); - tcg_gen_remu_i64(cpu_HI[0], t0, t1); + tcg_gen_divu_i64(cpu_LO[acc], t0, t1); + tcg_gen_remu_i64(cpu_HI[acc], t0, t1); tcg_temp_free(t3); tcg_temp_free(t2); } opn = "ddivu"; break; case OPC_DMULT: - gen_helper_dmult(cpu_env, t0, t1); + gen_helper_dmult(cpu_env, acc, t0, t1); opn = "dmult"; break; case OPC_DMULTU: - gen_helper_dmultu(cpu_env, t0, t1); + gen_helper_dmultu(cpu_env, acc, t0, t1); opn = "dmultu"; break; #endif @@ -2803,10 +2789,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext_tl_i64(t2, t0); tcg_gen_ext_tl_i64(t3, t1); @@ -2827,10 +2809,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext32u_tl(t0, t0); tcg_gen_ext32u_tl(t1, t1); @@ -2853,10 +2831,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext_tl_i64(t2, t0); tcg_gen_ext_tl_i64(t3, t1); @@ -2877,10 +2851,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext32u_tl(t0, t0); tcg_gen_ext32u_tl(t1, t1); @@ -10143,7 +10113,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, gen_logic(ctx, OPC_NOR, rx, ry, 0); break; case RR_MFHI: - gen_HILO(ctx, OPC_MFHI, rx); + gen_HILO(ctx, OPC_MFHI, 0, rx); break; case RR_CNVT: switch (cnvt_op) { @@ -10175,7 +10145,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, } break; case RR_MFLO: - gen_HILO(ctx, OPC_MFLO, rx); + gen_HILO(ctx, OPC_MFLO, 0, rx); break; #if defined (TARGET_MIPS64) case RR_DSRA: @@ -10196,33 +10166,33 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, break; #endif case RR_MULT: - gen_muldiv(ctx, OPC_MULT, rx, ry); + gen_muldiv(ctx, OPC_MULT, 0, rx, ry); break; case RR_MULTU: - gen_muldiv(ctx, OPC_MULTU, rx, ry); + gen_muldiv(ctx, OPC_MULTU, 0, rx, ry); break; case RR_DIV: - gen_muldiv(ctx, OPC_DIV, rx, ry); + gen_muldiv(ctx, OPC_DIV, 0, rx, ry); break; case RR_DIVU: - gen_muldiv(ctx, OPC_DIVU, rx, ry); + gen_muldiv(ctx, OPC_DIVU, 0, rx, ry); break; #if defined (TARGET_MIPS64) case RR_DMULT: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DMULT, rx, ry); + gen_muldiv(ctx, OPC_DMULT, 0, rx, ry); break; case RR_DMULTU: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DMULTU, rx, ry); + gen_muldiv(ctx, OPC_DMULTU, 0, rx, ry); break; case RR_DDIV: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DDIV, rx, ry); + gen_muldiv(ctx, OPC_DDIV, 0, rx, ry); break; case RR_DDIVU: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DDIVU, rx, ry); + gen_muldiv(ctx, OPC_DDIVU, 0, rx, ry); break; #endif default: @@ -10931,11 +10901,11 @@ static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) break; case MFHI16 + 0: case MFHI16 + 1: - gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode)); + gen_HILO(ctx, OPC_MFHI, 0, uMIPS_RS5(ctx->opcode)); break; case MFLO16 + 0: case MFLO16 + 1: - gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode)); + gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode)); break; case BREAK16: generate_exception(ctx, EXCP_BREAK); @@ -11133,30 +11103,34 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, break; case MULT: mips32_op = OPC_MULT; - goto do_muldiv; + goto do_mul; case MULTU: mips32_op = OPC_MULTU; - goto do_muldiv; + goto do_mul; case DIV: mips32_op = OPC_DIV; - goto do_muldiv; + goto do_div; case DIVU: mips32_op = OPC_DIVU; - goto do_muldiv; + goto do_div; + do_div: + check_insn(ctx, ISA_MIPS32); + gen_muldiv(ctx, mips32_op, 0, rs, rt); + break; case MADD: mips32_op = OPC_MADD; - goto do_muldiv; + goto do_mul; case MADDU: mips32_op = OPC_MADDU; - goto do_muldiv; + goto do_mul; case MSUB: mips32_op = OPC_MSUB; - goto do_muldiv; + goto do_mul; case MSUBU: mips32_op = OPC_MSUBU; - do_muldiv: + do_mul: check_insn(ctx, ISA_MIPS32); - gen_muldiv(ctx, mips32_op, rs, rt); + gen_muldiv(ctx, mips32_op, (ctx->opcode >> 14) & 3, rs, rt); break; default: goto pool32axf_invalid; @@ -11293,18 +11267,18 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, } break; case 0x35: - switch (minor) { + switch (minor & 3) { case MFHI32: - gen_HILO(ctx, OPC_MFHI, rs); + gen_HILO(ctx, OPC_MFHI, minor >> 2, rs); break; case MFLO32: - gen_HILO(ctx, OPC_MFLO, rs); + gen_HILO(ctx, OPC_MFLO, minor >> 2, rs); break; case MTHI32: - gen_HILO(ctx, OPC_MTHI, rs); + gen_HILO(ctx, OPC_MTHI, minor >> 2, rs); break; case MTLO32: - gen_HILO(ctx, OPC_MTLO, rs); + gen_HILO(ctx, OPC_MTLO, minor >> 2, rs); break; default: goto pool32axf_invalid; @@ -14477,13 +14451,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_XOR: gen_logic(ctx, op1, rd, rs, rt); break; - case OPC_MULT ... OPC_DIVU: + case OPC_MULT: + case OPC_MULTU: if (sa) { check_insn(ctx, INSN_VR54XX); op1 = MASK_MUL_VR54XX(ctx->opcode); gen_mul_vr54xx(ctx, op1, rd, rs, rt); - } else - gen_muldiv(ctx, op1, rs, rt); + } else { + gen_muldiv(ctx, op1, rd & 3, rs, rt); + } + break; + case OPC_DIV: + case OPC_DIVU: + gen_muldiv(ctx, op1, 0, rs, rt); break; case OPC_JR ... OPC_JALR: gen_compute_branch(ctx, op1, 4, rs, rd, sa); @@ -14495,11 +14475,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_MFHI: /* Move from HI/LO */ case OPC_MFLO: - gen_HILO(ctx, op1, rd); + gen_HILO(ctx, op1, rs & 3, rd); break; case OPC_MTHI: case OPC_MTLO: /* Move to HI/LO */ - gen_HILO(ctx, op1, rs); + gen_HILO(ctx, op1, rd & 3, rs); break; case OPC_PMON: /* Pmon entry point, also R4010 selsl */ #ifdef MIPS_STRICT_STANDARD @@ -14619,7 +14599,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_DMULT ... OPC_DDIVU: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_muldiv(ctx, op1, rs, rt); + gen_muldiv(ctx, op1, 0, rs, rt); break; #endif default: /* Invalid */ @@ -14634,7 +14614,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ case OPC_MSUB ... OPC_MSUBU: check_insn(ctx, ISA_MIPS32); - gen_muldiv(ctx, op1, rs, rt); + gen_muldiv(ctx, op1, rd & 3, rs, rt); break; case OPC_MUL: gen_arith(ctx, op1, rd, rs, rt); -- 1.7.10.4