aboutsummaryrefslogtreecommitdiff
path: root/target-mips/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-mips/translate.c')
-rw-r--r--target-mips/translate.c221
1 files changed, 103 insertions, 118 deletions
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 3b77b53..0a53203 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);
}
@@ -2715,47 +2711,29 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc,
break;
case OPC_MULT:
{
- 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);
- tcg_temp_free_i64(t3);
- tcg_gen_trunc_i64_tl(t0, t2);
- tcg_gen_shri_i64(t2, t2, 32);
- tcg_gen_trunc_i64_tl(t1, t2);
- tcg_temp_free_i64(t2);
- tcg_gen_ext32s_tl(cpu_LO[acc], t0);
- tcg_gen_ext32s_tl(cpu_HI[acc], t1);
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t2, t0);
+ tcg_gen_trunc_tl_i32(t3, t1);
+ tcg_gen_muls2_i32(t2, t3, t2, t3);
+ tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+ tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
}
opn = "mult";
break;
case OPC_MULTU:
{
- 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);
- tcg_gen_extu_tl_i64(t3, t1);
- tcg_gen_mul_i64(t2, t2, t3);
- tcg_temp_free_i64(t3);
- tcg_gen_trunc_i64_tl(t0, t2);
- tcg_gen_shri_i64(t2, t2, 32);
- tcg_gen_trunc_i64_tl(t1, t2);
- tcg_temp_free_i64(t2);
- tcg_gen_ext32s_tl(cpu_LO[acc], t0);
- tcg_gen_ext32s_tl(cpu_HI[acc], t1);
+ TCGv_i32 t2 = tcg_temp_new_i32();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t2, t0);
+ tcg_gen_trunc_tl_i32(t3, t1);
+ tcg_gen_mulu2_i32(t2, t3, t2, t3);
+ tcg_gen_ext_i32_tl(cpu_LO[acc], t2);
+ tcg_gen_ext_i32_tl(cpu_HI[acc], t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t3);
}
opn = "multu";
break;
@@ -2771,8 +2749,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 +2761,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);
+ tcg_gen_muls2_i64(cpu_LO[acc], cpu_HI[acc], t0, t1);
opn = "dmult";
break;
case OPC_DMULTU:
- gen_helper_dmultu(cpu_env, t0, t1);
+ tcg_gen_mulu2_i64(cpu_LO[acc], cpu_HI[acc], t0, t1);
opn = "dmultu";
break;
#endif
@@ -2803,10 +2781,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 +2801,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 +2823,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 +2843,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 +10105,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 +10137,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 +10158,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 +10893,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 +11095,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 +11259,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;
@@ -13434,6 +13400,7 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2,
/* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
* the same mask and op1. */
case OPC_MULT_G_2E:
+ check_dspr2(ctx);
switch (op2) {
case OPC_MUL_PH:
gen_helper_mul_ph(cpu_gpr[ret], v1_t, v2_t, cpu_env);
@@ -14477,13 +14444,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 +14468,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 +14592,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 +14607,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);
@@ -15604,7 +15577,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb,
if (max_insns == 0)
max_insns = CF_COUNT_MASK;
LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags);
- gen_icount_start();
+ gen_tb_start();
while (ctx.bstate == BS_NONE) {
if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
@@ -15702,7 +15675,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb,
}
}
done_generating:
- gen_icount_end(tb, num_insns);
+ gen_tb_end(tb, num_insns);
*tcg_ctx.gen_opc_ptr = INDEX_op_end;
if (search_pc) {
j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
@@ -15836,7 +15809,7 @@ void cpu_dump_state (CPUMIPSState *env, FILE *f, fprintf_function cpu_fprintf,
#endif
}
-static void mips_tcg_init(void)
+void mips_tcg_init(void)
{
int i;
static int inited;
@@ -15915,9 +15888,9 @@ MIPSCPU *cpu_mips_init(const char *cpu_model)
#endif
fpu_init(env, def);
mvp_init(env, def);
- mips_tcg_init();
- cpu_reset(CPU(cpu));
- qemu_init_vcpu(env);
+
+ object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
+
return cpu;
}
@@ -15972,6 +15945,14 @@ void cpu_state_reset(CPUMIPSState *env)
#if defined(CONFIG_USER_ONLY)
env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
+# ifdef TARGET_MIPS64
+ /* Enable 64-bit register mode. */
+ env->CP0_Status |= (1 << CP0St_PX);
+# endif
+# ifdef TARGET_ABI_MIPSN64
+ /* Enable 64-bit address mode. */
+ env->CP0_Status |= (1 << CP0St_UX);
+# endif
/* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
hardware registers. */
env->CP0_HWREna |= 0x0000000F;
@@ -15981,6 +15962,10 @@ void cpu_state_reset(CPUMIPSState *env)
if (env->CP0_Config3 & (1 << CP0C3_DSPP)) {
env->CP0_Status |= (1 << CP0St_MX);
}
+ /* Enable 64-bit FPU if the target cpu supports it. */
+ if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
+ env->CP0_Status |= (1 << CP0St_FR);
+ }
#else
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
@@ -16020,7 +16005,7 @@ void cpu_state_reset(CPUMIPSState *env)
env->tcs[i].CP0_TCHalt = 1;
}
env->active_tc.CP0_TCHalt = 1;
- env->halted = 1;
+ cs->halted = 1;
if (cs->cpu_index == 0) {
/* VPE0 starts up enabled. */
@@ -16028,7 +16013,7 @@ void cpu_state_reset(CPUMIPSState *env)
env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
/* TC0 starts up unhalted. */
- env->halted = 0;
+ cs->halted = 0;
env->active_tc.CP0_TCHalt = 0;
env->tcs[0].CP0_TCHalt = 0;
/* With thread 0 active. */