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 <rdsandiford@googlemail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 26135ead80)
Conflicts:
target-mips/translate.c
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
This commit is contained in:
1 parent
d89f9ba43b
commit
6d0b135a98
3 files changed
+72
-90
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+64
-84
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user