aboutsummaryrefslogtreecommitdiff
path: root/target-mips/translate.c
diff options
context:
space:
mode:
authorLeon Alrae <leon.alrae@imgtec.com>2014-06-27 08:49:01 +0100
committerLeon Alrae <leon.alrae@imgtec.com>2014-10-13 12:38:24 +0100
commit099e5b4d9fe99860b5533d09fac7ac8b64c12b53 (patch)
treefb2032947ed1f7839000a9bcff1cca1d4093318b /target-mips/translate.c
parent4368b29a26ebd13db95325b3511c0157ea9826f0 (diff)
target-mips: extract decode_opc_special* from decode_opc
Creating separate decode functions for special, special2 and special3 instructions to ease adding new R6 instructions and removing legacy instructions. Signed-off-by: Leon Alrae <leon.alrae@imgtec.com> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target-mips/translate.c')
-rw-r--r--target-mips/translate.c1650
1 files changed, 845 insertions, 805 deletions
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 8606f32499..5b8f762ec6 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -14482,911 +14482,950 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx, uint32_t op1, uint32_t op2,
/* End MIPSDSP functions. */
-static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
+static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
{
- int32_t offset;
int rs, rt, rd, sa;
- uint32_t op, op1, op2;
- int16_t imm;
-
- /* make sure instructions are on a word boundary */
- if (ctx->pc & 0x3) {
- env->CP0_BadVAddr = ctx->pc;
- generate_exception(ctx, EXCP_AdEL);
- return;
- }
-
- /* Handle blikely not taken case */
- if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) {
- int l1 = gen_new_label();
+ uint32_t op1;
- MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
- tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
- tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK);
- gen_goto_tb(ctx, 1, ctx->pc + 4);
- gen_set_label(l1);
- }
-
- if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
- tcg_gen_debug_insn_start(ctx->pc);
- }
-
- op = MASK_OP_MAJOR(ctx->opcode);
rs = (ctx->opcode >> 21) & 0x1f;
rt = (ctx->opcode >> 16) & 0x1f;
rd = (ctx->opcode >> 11) & 0x1f;
sa = (ctx->opcode >> 6) & 0x1f;
- imm = (int16_t)ctx->opcode;
- switch (op) {
- case OPC_SPECIAL:
- op1 = MASK_SPECIAL(ctx->opcode);
- switch (op1) {
- case OPC_SLL: /* Shift with immediate */
- case OPC_SRA:
- gen_shift_imm(ctx, op1, rd, rt, sa);
- break;
- case OPC_SRL:
- switch ((ctx->opcode >> 21) & 0x1f) {
- case 1:
- /* rotr is decoded as srl on non-R2 CPUs */
- if (ctx->insn_flags & ISA_MIPS32R2) {
- op1 = OPC_ROTR;
- }
- /* Fallthrough */
- case 0:
- gen_shift_imm(ctx, op1, rd, rt, sa);
- break;
- default:
- generate_exception(ctx, EXCP_RI);
- break;
+
+ op1 = MASK_SPECIAL(ctx->opcode);
+ switch (op1) {
+ case OPC_SLL: /* Shift with immediate */
+ case OPC_SRA:
+ gen_shift_imm(ctx, op1, rd, rt, sa);
+ break;
+ case OPC_SRL:
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 1:
+ /* rotr is decoded as srl on non-R2 CPUs */
+ if (ctx->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_ROTR;
}
+ /* Fallthrough */
+ case 0:
+ gen_shift_imm(ctx, op1, rd, rt, sa);
break;
- case OPC_MOVN: /* Conditional move */
- case OPC_MOVZ:
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
- INSN_LOONGSON2E | INSN_LOONGSON2F);
- gen_cond_move(ctx, op1, rd, rs, rt);
- break;
- case OPC_SELEQZ:
- case OPC_SELNEZ:
- check_insn(ctx, ISA_MIPS32R6);
- gen_cond_move(ctx, op1, rd, rs, rt);
- break;
- case OPC_ADD ... OPC_SUBU:
- gen_arith(ctx, op1, rd, rs, rt);
- break;
- case OPC_SLLV: /* Shifts */
- case OPC_SRAV:
- gen_shift(ctx, op1, rd, rs, rt);
- break;
- case OPC_SRLV:
- switch ((ctx->opcode >> 6) & 0x1f) {
- case 1:
- /* rotrv is decoded as srlv on non-R2 CPUs */
- if (ctx->insn_flags & ISA_MIPS32R2) {
- op1 = OPC_ROTRV;
- }
- /* Fallthrough */
- case 0:
- gen_shift(ctx, op1, rd, rs, rt);
- break;
- default:
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ default:
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_SLT: /* Set on less than */
- case OPC_SLTU:
- gen_slt(ctx, op1, rd, rs, rt);
- break;
- case OPC_AND: /* Logic*/
- case OPC_OR:
- case OPC_NOR:
- case OPC_XOR:
- gen_logic(ctx, op1, rd, rs, rt);
- break;
- 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, rd & 3, rs, rt);
+ }
+ break;
+ case OPC_MOVN: /* Conditional move */
+ case OPC_MOVZ:
+ check_insn_opc_removed(ctx, ISA_MIPS32R6);
+ check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |
+ INSN_LOONGSON2E | INSN_LOONGSON2F);
+ gen_cond_move(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_SELEQZ:
+ case OPC_SELNEZ:
+ check_insn(ctx, ISA_MIPS32R6);
+ gen_cond_move(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_ADD ... OPC_SUBU:
+ gen_arith(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_SLLV: /* Shifts */
+ case OPC_SRAV:
+ gen_shift(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_SRLV:
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 1:
+ /* rotrv is decoded as srlv on non-R2 CPUs */
+ if (ctx->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_ROTRV;
}
+ /* Fallthrough */
+ case 0:
+ gen_shift(ctx, op1, rd, 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);
- break;
- case OPC_TGE ... OPC_TEQ: /* Traps */
- case OPC_TNE:
- gen_trap(ctx, op1, rs, rt, -1);
- break;
- case OPC_MFHI: /* Move from HI/LO */
- case OPC_MFLO:
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- gen_HILO(ctx, op1, rs & 3, rd);
- break;
- case OPC_MTHI:
- case OPC_MTLO: /* Move to HI/LO */
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- gen_HILO(ctx, op1, rd & 3, rs);
+ default:
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_PMON: /* Pmon entry point, also R4010 selsl */
+ }
+ break;
+ case OPC_SLT: /* Set on less than */
+ case OPC_SLTU:
+ gen_slt(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_AND: /* Logic*/
+ case OPC_OR:
+ case OPC_NOR:
+ case OPC_XOR:
+ gen_logic(ctx, op1, rd, rs, rt);
+ break;
+ 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, 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);
+ break;
+ case OPC_TGE ... OPC_TEQ: /* Traps */
+ case OPC_TNE:
+ gen_trap(ctx, op1, rs, rt, -1);
+ break;
+ case OPC_MFHI: /* Move from HI/LO */
+ case OPC_MFLO:
+ check_insn_opc_removed(ctx, ISA_MIPS32R6);
+ gen_HILO(ctx, op1, rs & 3, rd);
+ break;
+ case OPC_MTHI:
+ case OPC_MTLO: /* Move to HI/LO */
+ check_insn_opc_removed(ctx, ISA_MIPS32R6);
+ gen_HILO(ctx, op1, rd & 3, rs);
+ break;
+ case OPC_PMON: /* Pmon entry point, also R4010 selsl */
#ifdef MIPS_STRICT_STANDARD
- MIPS_INVAL("PMON / selsl");
- generate_exception(ctx, EXCP_RI);
+ MIPS_INVAL("PMON / selsl");
+ generate_exception(ctx, EXCP_RI);
#else
- gen_helper_0e0i(pmon, sa);
+ gen_helper_0e0i(pmon, sa);
#endif
- break;
- case OPC_SYSCALL:
- generate_exception(ctx, EXCP_SYSCALL);
- ctx->bstate = BS_STOP;
- break;
- case OPC_BREAK:
- generate_exception(ctx, EXCP_BREAK);
- break;
- case OPC_SPIM:
+ break;
+ case OPC_SYSCALL:
+ generate_exception(ctx, EXCP_SYSCALL);
+ ctx->bstate = BS_STOP;
+ break;
+ case OPC_BREAK:
+ generate_exception(ctx, EXCP_BREAK);
+ break;
+ case OPC_SPIM:
#ifdef MIPS_STRICT_STANDARD
- MIPS_INVAL("SPIM");
- generate_exception(ctx, EXCP_RI);
+ MIPS_INVAL("SPIM");
+ generate_exception(ctx, EXCP_RI);
#else
- /* Implemented as RI exception for now. */
- MIPS_INVAL("spim (unofficial)");
- generate_exception(ctx, EXCP_RI);
+ /* Implemented as RI exception for now. */
+ MIPS_INVAL("spim (unofficial)");
+ generate_exception(ctx, EXCP_RI);
#endif
- break;
- case OPC_SYNC:
- /* Treat as NOP. */
- break;
+ break;
+ case OPC_SYNC:
+ /* Treat as NOP. */
+ break;
- case OPC_MOVCI:
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
- if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
- check_cp1_enabled(ctx);
- gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
- (ctx->opcode >> 16) & 1);
- } else {
- generate_exception_err(ctx, EXCP_CpU, 1);
- }
- break;
+ case OPC_MOVCI:
+ check_insn_opc_removed(ctx, ISA_MIPS32R6);
+ check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
+ if (ctx->CP0_Config1 & (1 << CP0C1_FP)) {
+ check_cp1_enabled(ctx);
+ gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+ (ctx->opcode >> 16) & 1);
+ } else {
+ generate_exception_err(ctx, EXCP_CpU, 1);
+ }
+ break;
#if defined(TARGET_MIPS64)
- /* MIPS64 specific opcodes */
- case OPC_DSLL:
- case OPC_DSRA:
- case OPC_DSLL32:
- case OPC_DSRA32:
+ /* MIPS64 specific opcodes */
+ case OPC_DSLL:
+ case OPC_DSRA:
+ case OPC_DSLL32:
+ case OPC_DSRA32:
+ check_insn(ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_shift_imm(ctx, op1, rd, rt, sa);
+ break;
+ case OPC_DSRL:
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 1:
+ /* drotr is decoded as dsrl on non-R2 CPUs */
+ if (ctx->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_DROTR;
+ }
+ /* Fallthrough */
+ case 0:
check_insn(ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift_imm(ctx, op1, rd, rt, sa);
break;
- case OPC_DSRL:
- switch ((ctx->opcode >> 21) & 0x1f) {
- case 1:
- /* drotr is decoded as dsrl on non-R2 CPUs */
- if (ctx->insn_flags & ISA_MIPS32R2) {
- op1 = OPC_DROTR;
- }
- /* Fallthrough */
- case 0:
- check_insn(ctx, ISA_MIPS3);
- check_mips_64(ctx);
- gen_shift_imm(ctx, op1, rd, rt, sa);
- break;
- default:
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ default:
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_DSRL32:
- switch ((ctx->opcode >> 21) & 0x1f) {
- case 1:
- /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
- if (ctx->insn_flags & ISA_MIPS32R2) {
- op1 = OPC_DROTR32;
- }
- /* Fallthrough */
- case 0:
- check_insn(ctx, ISA_MIPS3);
- check_mips_64(ctx);
- gen_shift_imm(ctx, op1, rd, rt, sa);
- break;
- default:
- generate_exception(ctx, EXCP_RI);
- break;
+ }
+ break;
+ case OPC_DSRL32:
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 1:
+ /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
+ if (ctx->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_DROTR32;
}
- break;
- case OPC_DADD ... OPC_DSUBU:
+ /* Fallthrough */
+ case 0:
check_insn(ctx, ISA_MIPS3);
check_mips_64(ctx);
- gen_arith(ctx, op1, rd, rs, rt);
+ gen_shift_imm(ctx, op1, rd, rt, sa);
break;
- case OPC_DSLLV:
- case OPC_DSRAV:
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case OPC_DADD ... OPC_DSUBU:
+ check_insn(ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_arith(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_DSLLV:
+ case OPC_DSRAV:
+ check_insn(ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_shift(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_DSRLV:
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 1:
+ /* drotrv is decoded as dsrlv on non-R2 CPUs */
+ if (ctx->insn_flags & ISA_MIPS32R2) {
+ op1 = OPC_DROTRV;
+ }
+ /* Fallthrough */
+ case 0:
check_insn(ctx, ISA_MIPS3);
check_mips_64(ctx);
gen_shift(ctx, op1, rd, rs, rt);
break;
- case OPC_DSRLV:
- switch ((ctx->opcode >> 6) & 0x1f) {
- case 1:
- /* drotrv is decoded as dsrlv on non-R2 CPUs */
- if (ctx->insn_flags & ISA_MIPS32R2) {
- op1 = OPC_DROTRV;
- }
- /* Fallthrough */
- case 0:
- check_insn(ctx, ISA_MIPS3);
- check_mips_64(ctx);
- gen_shift(ctx, op1, rd, rs, rt);
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case OPC_DMULT ... OPC_DDIVU:
+ check_insn(ctx, ISA_MIPS3);
+ check_mips_64(ctx);
+ gen_muldiv(ctx, op1, 0, rs, rt);
+ break;
+#endif
+ default: /* Invalid */
+ MIPS_INVAL("special");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+}
+
+static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx)
+{
+ int rs, rt, rd;
+ uint32_t op1;
+
+ rs = (ctx->opcode >> 21) & 0x1f;
+ rt = (ctx->opcode >> 16) & 0x1f;
+ rd = (ctx->opcode >> 11) & 0x1f;
+
+ op1 = MASK_SPECIAL2(ctx->opcode);
+ switch (op1) {
+ case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
+ case OPC_MSUB ... OPC_MSUBU:
+ check_insn_opc_removed(ctx, ISA_MIPS32R6);
+ check_insn(ctx, ISA_MIPS32);
+ gen_muldiv(ctx, op1, rd & 3, rs, rt);
+ break;
+ case OPC_MUL:
+ check_insn_opc_removed(ctx, ISA_MIPS32R6);
+ gen_arith(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_CLO:
+ case OPC_CLZ:
+ check_insn(ctx, ISA_MIPS32);
+ gen_cl(ctx, op1, rd, rs);
+ break;
+ case OPC_SDBBP:
+ /* XXX: not clear which exception should be raised
+ * when in debug mode...
+ */
+ check_insn(ctx, ISA_MIPS32);
+ if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+ generate_exception(ctx, EXCP_DBp);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
+ /* Treat as NOP. */
+ break;
+ case OPC_DIV_G_2F:
+ case OPC_DIVU_G_2F:
+ case OPC_MULT_G_2F:
+ case OPC_MULTU_G_2F:
+ case OPC_MOD_G_2F:
+ case OPC_MODU_G_2F:
+ check_insn(ctx, INSN_LOONGSON2F);
+ gen_loongson_integer(ctx, op1, rd, rs, rt);
+ break;
+#if defined(TARGET_MIPS64)
+ case OPC_DCLO:
+ case OPC_DCLZ:
+ check_insn(ctx, ISA_MIPS64);
+ check_mips_64(ctx);
+ gen_cl(ctx, op1, rd, rs);
+ break;
+ case OPC_DMULT_G_2F:
+ case OPC_DMULTU_G_2F:
+ case OPC_DDIV_G_2F:
+ case OPC_DDIVU_G_2F:
+ case OPC_DMOD_G_2F:
+ case OPC_DMODU_G_2F:
+ check_insn(ctx, INSN_LOONGSON2F);
+ gen_loongson_integer(ctx, op1, rd, rs, rt);
+ break;
+#endif
+ default: /* Invalid */
+ MIPS_INVAL("special2");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+}
+static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
+{
+ int rs, rt, rd, sa;
+ uint32_t op1, op2;
+ int16_t imm;
+
+ rs = (ctx->opcode >> 21) & 0x1f;
+ rt = (ctx->opcode >> 16) & 0x1f;
+ rd = (ctx->opcode >> 11) & 0x1f;
+ sa = (ctx->opcode >> 6) & 0x1f;
+ imm = (int16_t)ctx->opcode;
+
+ op1 = MASK_SPECIAL3(ctx->opcode);
+ switch (op1) {
+ case R6_OPC_LL:
+ check_insn(ctx, ISA_MIPS32R6);
+ gen_ld(ctx, op1, rt, rs, imm >> 7);
+ break;
+ case OPC_EXT:
+ case OPC_INS:
+ check_insn(ctx, ISA_MIPS32R2);
+ gen_bitops(ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_BSHFL:
+ check_insn(ctx, ISA_MIPS32R2);
+ op2 = MASK_BSHFL(ctx->opcode);
+ gen_bshfl(ctx, op2, rt, rd);
+ break;
+ case OPC_RDHWR:
+ gen_rdhwr(ctx, rt, rd);
+ break;
+ case OPC_FORK:
+ check_insn(ctx, ASE_MT);
+ {
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ gen_load_gpr(t0, rt);
+ gen_load_gpr(t1, rs);
+ gen_helper_fork(t0, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ }
+ break;
+ case OPC_YIELD:
+ check_insn(ctx, ASE_MT);
+ {
+ TCGv t0 = tcg_temp_new();
+
+ save_cpu_state(ctx, 1);
+ gen_load_gpr(t0, rs);
+ gen_helper_yield(t0, cpu_env, t0);
+ gen_store_gpr(t0, rd);
+ tcg_temp_free(t0);
+ }
+ break;
+ case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
+ case OPC_MOD_G_2E ... OPC_MODU_G_2E:
+ case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
+ /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
+ * the same mask and op1. */
+ if ((ctx->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) {
+ op2 = MASK_ADDUH_QB(ctx->opcode);
+ switch (op2) {
+ case OPC_ADDUH_QB:
+ case OPC_ADDUH_R_QB:
+ case OPC_ADDQH_PH:
+ case OPC_ADDQH_R_PH:
+ case OPC_ADDQH_W:
+ case OPC_ADDQH_R_W:
+ case OPC_SUBUH_QB:
+ case OPC_SUBUH_R_QB:
+ case OPC_SUBQH_PH:
+ case OPC_SUBQH_R_PH:
+ case OPC_SUBQH_W:
+ case OPC_SUBQH_R_W:
+ gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
+ break;
+ case OPC_MUL_PH:
+ case OPC_MUL_S_PH:
+ case OPC_MULQ_S_W:
+ case OPC_MULQ_RS_W:
+ gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
break;
default:
+ MIPS_INVAL("MASK ADDUH.QB");
generate_exception(ctx, EXCP_RI);
break;
}
- break;
- case OPC_DMULT ... OPC_DDIVU:
- check_insn(ctx, ISA_MIPS3);
- check_mips_64(ctx);
- gen_muldiv(ctx, op1, 0, rs, rt);
- break;
+ } else if (ctx->insn_flags & INSN_LOONGSON2E) {
+ gen_loongson_integer(ctx, op1, rd, rs, rt);
+ } else {
+ generate_exception(ctx, EXCP_RI);
+ }
+ break;
+ case OPC_LX_DSP:
+ op2 = MASK_LX(ctx->opcode);
+ switch (op2) {
+#if defined(TARGET_MIPS64)
+ case OPC_LDX:
#endif
+ case OPC_LBUX:
+ case OPC_LHX:
+ case OPC_LWX:
+ gen_mipsdsp_ld(ctx, op2, rd, rs, rt);
+ break;
default: /* Invalid */
- MIPS_INVAL("special");
+ MIPS_INVAL("MASK LX");
generate_exception(ctx, EXCP_RI);
break;
}
break;
- case OPC_SPECIAL2:
- op1 = MASK_SPECIAL2(ctx->opcode);
- switch (op1) {
- case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
- case OPC_MSUB ... OPC_MSUBU:
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- check_insn(ctx, ISA_MIPS32);
- gen_muldiv(ctx, op1, rd & 3, rs, rt);
- break;
- case OPC_MUL:
- check_insn_opc_removed(ctx, ISA_MIPS32R6);
- gen_arith(ctx, op1, rd, rs, rt);
+ case OPC_ABSQ_S_PH_DSP:
+ op2 = MASK_ABSQ_S_PH(ctx->opcode);
+ switch (op2) {
+ case OPC_ABSQ_S_QB:
+ case OPC_ABSQ_S_PH:
+ case OPC_ABSQ_S_W:
+ case OPC_PRECEQ_W_PHL:
+ case OPC_PRECEQ_W_PHR:
+ case OPC_PRECEQU_PH_QBL:
+ case OPC_PRECEQU_PH_QBR:
+ case OPC_PRECEQU_PH_QBLA:
+ case OPC_PRECEQU_PH_QBRA:
+ case OPC_PRECEU_PH_QBL:
+ case OPC_PRECEU_PH_QBR:
+ case OPC_PRECEU_PH_QBLA:
+ case OPC_PRECEU_PH_QBRA:
+ gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
break;
- case OPC_CLO:
- case OPC_CLZ:
- check_insn(ctx, ISA_MIPS32);
- gen_cl(ctx, op1, rd, rs);
+ case OPC_BITREV:
+ case OPC_REPL_QB:
+ case OPC_REPLV_QB:
+ case OPC_REPL_PH:
+ case OPC_REPLV_PH:
+ gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
break;
- case OPC_SDBBP:
- /* XXX: not clear which exception should be raised
- * when in debug mode...
- */
- check_insn(ctx, ISA_MIPS32);
- if (!(ctx->hflags & MIPS_HFLAG_DM)) {
- generate_exception(ctx, EXCP_DBp);
- } else {
- generate_exception(ctx, EXCP_DBp);
- }
- /* Treat as NOP. */
+ default:
+ MIPS_INVAL("MASK ABSQ_S.PH");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_DIV_G_2F:
- case OPC_DIVU_G_2F:
- case OPC_MULT_G_2F:
- case OPC_MULTU_G_2F:
- case OPC_MOD_G_2F:
- case OPC_MODU_G_2F:
- check_insn(ctx, INSN_LOONGSON2F);
- gen_loongson_integer(ctx, op1, rd, rs, rt);
+ }
+ break;
+ case OPC_ADDU_QB_DSP:
+ op2 = MASK_ADDU_QB(ctx->opcode);
+ switch (op2) {
+ case OPC_ADDQ_PH:
+ case OPC_ADDQ_S_PH:
+ case OPC_ADDQ_S_W:
+ case OPC_ADDU_QB:
+ case OPC_ADDU_S_QB:
+ case OPC_ADDU_PH:
+ case OPC_ADDU_S_PH:
+ case OPC_SUBQ_PH:
+ case OPC_SUBQ_S_PH:
+ case OPC_SUBQ_S_W:
+ case OPC_SUBU_QB:
+ case OPC_SUBU_S_QB:
+ case OPC_SUBU_PH:
+ case OPC_SUBU_S_PH:
+ case OPC_ADDSC:
+ case OPC_ADDWC:
+ case OPC_MODSUB:
+ case OPC_RADDU_W_QB:
+ gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
break;
-#if defined(TARGET_MIPS64)
- case OPC_DCLO:
- case OPC_DCLZ:
- check_insn(ctx, ISA_MIPS64);
- check_mips_64(ctx);
- gen_cl(ctx, op1, rd, rs);
- break;
- case OPC_DMULT_G_2F:
- case OPC_DMULTU_G_2F:
- case OPC_DDIV_G_2F:
- case OPC_DDIVU_G_2F:
- case OPC_DMOD_G_2F:
- case OPC_DMODU_G_2F:
- check_insn(ctx, INSN_LOONGSON2F);
- gen_loongson_integer(ctx, op1, rd, rs, rt);
+ case OPC_MULEU_S_PH_QBL:
+ case OPC_MULEU_S_PH_QBR:
+ case OPC_MULQ_RS_PH:
+ case OPC_MULEQ_S_W_PHL:
+ case OPC_MULEQ_S_W_PHR:
+ case OPC_MULQ_S_PH:
+ gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
break;
-#endif
default: /* Invalid */
- MIPS_INVAL("special2");
+ MIPS_INVAL("MASK ADDU.QB");
generate_exception(ctx, EXCP_RI);
break;
+
}
break;
- case OPC_SPECIAL3:
- op1 = MASK_SPECIAL3(ctx->opcode);
- switch (op1) {
- case R6_OPC_LL:
- check_insn(ctx, ISA_MIPS32R6);
- gen_ld(ctx, op1, rt, rs, imm >> 7);
+ case OPC_CMPU_EQ_QB_DSP:
+ op2 = MASK_CMPU_EQ_QB(ctx->opcode);
+ switch (op2) {
+ case OPC_PRECR_SRA_PH_W:
+ case OPC_PRECR_SRA_R_PH_W:
+ gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
break;
- case OPC_EXT:
- case OPC_INS:
- check_insn(ctx, ISA_MIPS32R2);
- gen_bitops(ctx, op1, rt, rs, sa, rd);
+ case OPC_PRECR_QB_PH:
+ case OPC_PRECRQ_QB_PH:
+ case OPC_PRECRQ_PH_W:
+ case OPC_PRECRQ_RS_PH_W:
+ case OPC_PRECRQU_S_QB_PH:
+ gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
break;
- case OPC_BSHFL:
- check_insn(ctx, ISA_MIPS32R2);
- op2 = MASK_BSHFL(ctx->opcode);
- gen_bshfl(ctx, op2, rt, rd);
+ case OPC_CMPU_EQ_QB:
+ case OPC_CMPU_LT_QB:
+ case OPC_CMPU_LE_QB:
+ case OPC_CMP_EQ_PH:
+ case OPC_CMP_LT_PH:
+ case OPC_CMP_LE_PH:
+ gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
break;
- case OPC_RDHWR:
- gen_rdhwr(ctx, rt, rd);
+ case OPC_CMPGU_EQ_QB:
+ case OPC_CMPGU_LT_QB:
+ case OPC_CMPGU_LE_QB:
+ case OPC_CMPGDU_EQ_QB:
+ case OPC_CMPGDU_LT_QB:
+ case OPC_CMPGDU_LE_QB:
+ case OPC_PICK_QB:
+ case OPC_PICK_PH:
+ case OPC_PACKRL_PH:
+ gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
break;
- case OPC_FORK:
- check_insn(ctx, ASE_MT);
+ default: /* Invalid */
+ MIPS_INVAL("MASK CMPU.EQ.QB");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case OPC_SHLL_QB_DSP:
+ gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_DPA_W_PH_DSP:
+ op2 = MASK_DPA_W_PH(ctx->opcode);
+ switch (op2) {
+ case OPC_DPAU_H_QBL:
+ case OPC_DPAU_H_QBR:
+ case OPC_DPSU_H_QBL:
+ case OPC_DPSU_H_QBR:
+ case OPC_DPA_W_PH:
+ case OPC_DPAX_W_PH:
+ case OPC_DPAQ_S_W_PH:
+ case OPC_DPAQX_S_W_PH:
+ case OPC_DPAQX_SA_W_PH:
+ case OPC_DPS_W_PH:
+ case OPC_DPSX_W_PH:
+ case OPC_DPSQ_S_W_PH:
+ case OPC_DPSQX_S_W_PH:
+ case OPC_DPSQX_SA_W_PH:
+ case OPC_MULSAQ_S_W_PH:
+ case OPC_DPAQ_SA_L_W:
+ case OPC_DPSQ_SA_L_W:
+ case OPC_MAQ_S_W_PHL:
+ case OPC_MAQ_S_W_PHR:
+ case OPC_MAQ_SA_W_PHL:
+ case OPC_MAQ_SA_W_PHR:
+ case OPC_MULSA_W_PH:
+ gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
+ break;
+ default: /* Invalid */
+ MIPS_INVAL("MASK DPAW.PH");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case OPC_INSV_DSP:
+ op2 = MASK_INSV(ctx->opcode);
+ switch (op2) {
+ case OPC_INSV:
+ check_dsp(ctx);
{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
+ TCGv t0, t1;
+
+ if (rt == 0) {
+ MIPS_DEBUG("NOP");
+ break;
+ }
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
gen_load_gpr(t0, rt);
gen_load_gpr(t1, rs);
- gen_helper_fork(t0, t1);
+
+ gen_helper_insv(cpu_gpr[rt], cpu_env, t1, t0);
+
tcg_temp_free(t0);
tcg_temp_free(t1);
+ break;
}
+ default: /* Invalid */
+ MIPS_INVAL("MASK INSV");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_YIELD:
- check_insn(ctx, ASE_MT);
- {
- TCGv t0 = tcg_temp_new();
-
- save_cpu_state(ctx, 1);
- gen_load_gpr(t0, rs);
- gen_helper_yield(t0, cpu_env, t0);
- gen_store_gpr(t0, rd);
- tcg_temp_free(t0);
- }
+ }
+ break;
+ case OPC_APPEND_DSP:
+ gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+ break;
+ case OPC_EXTR_W_DSP:
+ op2 = MASK_EXTR_W(ctx->opcode);
+ switch (op2) {
+ case OPC_EXTR_W:
+ case OPC_EXTR_R_W:
+ case OPC_EXTR_RS_W:
+ case OPC_EXTR_S_H:
+ case OPC_EXTRV_S_H:
+ case OPC_EXTRV_W:
+ case OPC_EXTRV_R_W:
+ case OPC_EXTRV_RS_W:
+ case OPC_EXTP:
+ case OPC_EXTPV:
+ case OPC_EXTPDP:
+ case OPC_EXTPDPV:
+ gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
break;
- case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
- case OPC_MOD_G_2E ... OPC_MODU_G_2E:
- case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
- /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have
- * the same mask and op1. */
- if ((ctx->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) {
- op2 = MASK_ADDUH_QB(ctx->opcode);
- switch (op2) {
- case OPC_ADDUH_QB:
- case OPC_ADDUH_R_QB:
- case OPC_ADDQH_PH:
- case OPC_ADDQH_R_PH:
- case OPC_ADDQH_W:
- case OPC_ADDQH_R_W:
- case OPC_SUBUH_QB:
- case OPC_SUBUH_R_QB:
- case OPC_SUBQH_PH:
- case OPC_SUBQH_R_PH:
- case OPC_SUBQH_W:
- case OPC_SUBQH_R_W:
- gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
- break;
- case OPC_MUL_PH:
- case OPC_MUL_S_PH:
- case OPC_MULQ_S_W:
- case OPC_MULQ_RS_W:
- gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
- break;
- default:
- MIPS_INVAL("MASK ADDUH.QB");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- } else if (ctx->insn_flags & INSN_LOONGSON2E) {
- gen_loongson_integer(ctx, op1, rd, rs, rt);
- } else {
- generate_exception(ctx, EXCP_RI);
- }
+ case OPC_RDDSP:
+ gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1);
break;
- case OPC_LX_DSP:
- op2 = MASK_LX(ctx->opcode);
- switch (op2) {
-#if defined(TARGET_MIPS64)
- case OPC_LDX:
-#endif
- case OPC_LBUX:
- case OPC_LHX:
- case OPC_LWX:
- gen_mipsdsp_ld(ctx, op2, rd, rs, rt);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK LX");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ case OPC_SHILO:
+ case OPC_SHILOV:
+ case OPC_MTHLIP:
+ case OPC_WRDSP:
+ gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
break;
- case OPC_ABSQ_S_PH_DSP:
- op2 = MASK_ABSQ_S_PH(ctx->opcode);
- switch (op2) {
- case OPC_ABSQ_S_QB:
- case OPC_ABSQ_S_PH:
- case OPC_ABSQ_S_W:
- case OPC_PRECEQ_W_PHL:
- case OPC_PRECEQ_W_PHR:
- case OPC_PRECEQU_PH_QBL:
- case OPC_PRECEQU_PH_QBR:
- case OPC_PRECEQU_PH_QBLA:
- case OPC_PRECEQU_PH_QBRA:
- case OPC_PRECEU_PH_QBL:
- case OPC_PRECEU_PH_QBR:
- case OPC_PRECEU_PH_QBLA:
- case OPC_PRECEU_PH_QBRA:
- gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
- break;
- case OPC_BITREV:
- case OPC_REPL_QB:
- case OPC_REPLV_QB:
- case OPC_REPL_PH:
- case OPC_REPLV_PH:
- gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
- break;
- default:
- MIPS_INVAL("MASK ABSQ_S.PH");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ default: /* Invalid */
+ MIPS_INVAL("MASK EXTR.W");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_ADDU_QB_DSP:
- op2 = MASK_ADDU_QB(ctx->opcode);
- switch (op2) {
- case OPC_ADDQ_PH:
- case OPC_ADDQ_S_PH:
- case OPC_ADDQ_S_W:
- case OPC_ADDU_QB:
- case OPC_ADDU_S_QB:
- case OPC_ADDU_PH:
- case OPC_ADDU_S_PH:
- case OPC_SUBQ_PH:
- case OPC_SUBQ_S_PH:
- case OPC_SUBQ_S_W:
- case OPC_SUBU_QB:
- case OPC_SUBU_S_QB:
- case OPC_SUBU_PH:
- case OPC_SUBU_S_PH:
- case OPC_ADDSC:
- case OPC_ADDWC:
- case OPC_MODSUB:
- case OPC_RADDU_W_QB:
- gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
- break;
- case OPC_MULEU_S_PH_QBL:
- case OPC_MULEU_S_PH_QBR:
- case OPC_MULQ_RS_PH:
- case OPC_MULEQ_S_W_PHL:
- case OPC_MULEQ_S_W_PHR:
- case OPC_MULQ_S_PH:
- gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK ADDU.QB");
- generate_exception(ctx, EXCP_RI);
- break;
-
- }
+ }
+ break;
+ case R6_OPC_SC: /* OPC_DMOD_G_2E */
+ if (ctx->insn_flags & ISA_MIPS32R6) {
+ gen_st_cond(ctx, op1, rt, rs, imm >> 7);
+ } else {
+#if defined(TARGET_MIPS64)
+ check_insn(ctx, INSN_LOONGSON2E);
+ gen_loongson_integer(ctx, op1, rd, rs, rt);
+#else
+ /* Invalid in MIPS32 */
+ generate_exception(ctx, EXCP_RI);
+#endif
+ }
+ break;
+#if defined(TARGET_MIPS64)
+ case OPC_DEXTM ... OPC_DEXT:
+ case OPC_DINSM ... OPC_DINS:
+ check_insn(ctx, ISA_MIPS64R2);
+ check_mips_64(ctx);
+ gen_bitops(ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_DBSHFL:
+ check_insn(ctx, ISA_MIPS64R2);
+ check_mips_64(ctx);
+ op2 = MASK_DBSHFL(ctx->opcode);
+ gen_bshfl(ctx, op2, rt, rd);
+ break;
+ case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
+ case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
+ case OPC_DMODU_G_2E:
+ check_insn(ctx, INSN_LOONGSON2E);
+ gen_loongson_integer(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_ABSQ_S_QH_DSP:
+ op2 = MASK_ABSQ_S_QH(ctx->opcode);
+ switch (op2) {
+ case OPC_PRECEQ_L_PWL:
+ case OPC_PRECEQ_L_PWR:
+ case OPC_PRECEQ_PW_QHL:
+ case OPC_PRECEQ_PW_QHR:
+ case OPC_PRECEQ_PW_QHLA:
+ case OPC_PRECEQ_PW_QHRA:
+ case OPC_PRECEQU_QH_OBL:
+ case OPC_PRECEQU_QH_OBR:
+ case OPC_PRECEQU_QH_OBLA:
+ case OPC_PRECEQU_QH_OBRA:
+ case OPC_PRECEU_QH_OBL:
+ case OPC_PRECEU_QH_OBR:
+ case OPC_PRECEU_QH_OBLA:
+ case OPC_PRECEU_QH_OBRA:
+ case OPC_ABSQ_S_OB:
+ case OPC_ABSQ_S_PW:
+ case OPC_ABSQ_S_QH:
+ gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
break;
- case OPC_CMPU_EQ_QB_DSP:
- op2 = MASK_CMPU_EQ_QB(ctx->opcode);
- switch (op2) {
- case OPC_PRECR_SRA_PH_W:
- case OPC_PRECR_SRA_R_PH_W:
- gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
- break;
- case OPC_PRECR_QB_PH:
- case OPC_PRECRQ_QB_PH:
- case OPC_PRECRQ_PH_W:
- case OPC_PRECRQ_RS_PH_W:
- case OPC_PRECRQU_S_QB_PH:
- gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
- break;
- case OPC_CMPU_EQ_QB:
- case OPC_CMPU_LT_QB:
- case OPC_CMPU_LE_QB:
- case OPC_CMP_EQ_PH:
- case OPC_CMP_LT_PH:
- case OPC_CMP_LE_PH:
- gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
- break;
- case OPC_CMPGU_EQ_QB:
- case OPC_CMPGU_LT_QB:
- case OPC_CMPGU_LE_QB:
- case OPC_CMPGDU_EQ_QB:
- case OPC_CMPGDU_LT_QB:
- case OPC_CMPGDU_LE_QB:
- case OPC_PICK_QB:
- case OPC_PICK_PH:
- case OPC_PACKRL_PH:
- gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK CMPU.EQ.QB");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ case OPC_REPL_OB:
+ case OPC_REPL_PW:
+ case OPC_REPL_QH:
+ case OPC_REPLV_OB:
+ case OPC_REPLV_PW:
+ case OPC_REPLV_QH:
+ gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
break;
- case OPC_SHLL_QB_DSP:
- gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+ default: /* Invalid */
+ MIPS_INVAL("MASK ABSQ_S.QH");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_DPA_W_PH_DSP:
- op2 = MASK_DPA_W_PH(ctx->opcode);
- switch (op2) {
- case OPC_DPAU_H_QBL:
- case OPC_DPAU_H_QBR:
- case OPC_DPSU_H_QBL:
- case OPC_DPSU_H_QBR:
- case OPC_DPA_W_PH:
- case OPC_DPAX_W_PH:
- case OPC_DPAQ_S_W_PH:
- case OPC_DPAQX_S_W_PH:
- case OPC_DPAQX_SA_W_PH:
- case OPC_DPS_W_PH:
- case OPC_DPSX_W_PH:
- case OPC_DPSQ_S_W_PH:
- case OPC_DPSQX_S_W_PH:
- case OPC_DPSQX_SA_W_PH:
- case OPC_MULSAQ_S_W_PH:
- case OPC_DPAQ_SA_L_W:
- case OPC_DPSQ_SA_L_W:
- case OPC_MAQ_S_W_PHL:
- case OPC_MAQ_S_W_PHR:
- case OPC_MAQ_SA_W_PHL:
- case OPC_MAQ_SA_W_PHR:
- case OPC_MULSA_W_PH:
- gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK DPAW.PH");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ }
+ break;
+ case OPC_ADDU_OB_DSP:
+ op2 = MASK_ADDU_OB(ctx->opcode);
+ switch (op2) {
+ case OPC_RADDU_L_OB:
+ case OPC_SUBQ_PW:
+ case OPC_SUBQ_S_PW:
+ case OPC_SUBQ_QH:
+ case OPC_SUBQ_S_QH:
+ case OPC_SUBU_OB:
+ case OPC_SUBU_S_OB:
+ case OPC_SUBU_QH:
+ case OPC_SUBU_S_QH:
+ case OPC_SUBUH_OB:
+ case OPC_SUBUH_R_OB:
+ case OPC_ADDQ_PW:
+ case OPC_ADDQ_S_PW:
+ case OPC_ADDQ_QH:
+ case OPC_ADDQ_S_QH:
+ case OPC_ADDU_OB:
+ case OPC_ADDU_S_OB:
+ case OPC_ADDU_QH:
+ case OPC_ADDU_S_QH:
+ case OPC_ADDUH_OB:
+ case OPC_ADDUH_R_OB:
+ gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
break;
- case OPC_INSV_DSP:
- op2 = MASK_INSV(ctx->opcode);
- switch (op2) {
- case OPC_INSV:
- check_dsp(ctx);
- {
- TCGv t0, t1;
-
- if (rt == 0) {
- MIPS_DEBUG("NOP");
- break;
- }
-
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
-
- gen_load_gpr(t0, rt);
- gen_load_gpr(t1, rs);
-
- gen_helper_insv(cpu_gpr[rt], cpu_env, t1, t0);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- break;
- }
- default: /* Invalid */
- MIPS_INVAL("MASK INSV");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ case OPC_MULEQ_S_PW_QHL:
+ case OPC_MULEQ_S_PW_QHR:
+ case OPC_MULEU_S_QH_OBL:
+ case OPC_MULEU_S_QH_OBR:
+ case OPC_MULQ_RS_QH:
+ gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
break;
- case OPC_APPEND_DSP:
- gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+ default: /* Invalid */
+ MIPS_INVAL("MASK ADDU.OB");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_EXTR_W_DSP:
- op2 = MASK_EXTR_W(ctx->opcode);
- switch (op2) {
- case OPC_EXTR_W:
- case OPC_EXTR_R_W:
- case OPC_EXTR_RS_W:
- case OPC_EXTR_S_H:
- case OPC_EXTRV_S_H:
- case OPC_EXTRV_W:
- case OPC_EXTRV_R_W:
- case OPC_EXTRV_RS_W:
- case OPC_EXTP:
- case OPC_EXTPV:
- case OPC_EXTPDP:
- case OPC_EXTPDPV:
- gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
- break;
- case OPC_RDDSP:
- gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 1);
- break;
- case OPC_SHILO:
- case OPC_SHILOV:
- case OPC_MTHLIP:
- case OPC_WRDSP:
- gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK EXTR.W");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ }
+ break;
+ case OPC_CMPU_EQ_OB_DSP:
+ op2 = MASK_CMPU_EQ_OB(ctx->opcode);
+ switch (op2) {
+ case OPC_PRECR_SRA_QH_PW:
+ case OPC_PRECR_SRA_R_QH_PW:
+ /* Return value is rt. */
+ gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
break;
- case R6_OPC_SC: /* OPC_DMOD_G_2E */
- if (ctx->insn_flags & ISA_MIPS32R6) {
- gen_st_cond(ctx, op1, rt, rs, imm >> 7);
- } else {
-#if defined(TARGET_MIPS64)
- check_insn(ctx, INSN_LOONGSON2E);
- gen_loongson_integer(ctx, op1, rd, rs, rt);
-#else
- /* Invalid in MIPS32 */
- generate_exception(ctx, EXCP_RI);
-#endif
- }
+ case OPC_PRECR_OB_QH:
+ case OPC_PRECRQ_OB_QH:
+ case OPC_PRECRQ_PW_L:
+ case OPC_PRECRQ_QH_PW:
+ case OPC_PRECRQ_RS_QH_PW:
+ case OPC_PRECRQU_S_OB_QH:
+ gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
break;
-#if defined(TARGET_MIPS64)
- case OPC_DEXTM ... OPC_DEXT:
- case OPC_DINSM ... OPC_DINS:
- check_insn(ctx, ISA_MIPS64R2);
- check_mips_64(ctx);
- gen_bitops(ctx, op1, rt, rs, sa, rd);
+ case OPC_CMPU_EQ_OB:
+ case OPC_CMPU_LT_OB:
+ case OPC_CMPU_LE_OB:
+ case OPC_CMP_EQ_QH:
+ case OPC_CMP_LT_QH:
+ case OPC_CMP_LE_QH:
+ case OPC_CMP_EQ_PW:
+ case OPC_CMP_LT_PW:
+ case OPC_CMP_LE_PW:
+ gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
break;
- case OPC_DBSHFL:
- check_insn(ctx, ISA_MIPS64R2);
- check_mips_64(ctx);
- op2 = MASK_DBSHFL(ctx->opcode);
- gen_bshfl(ctx, op2, rt, rd);
+ case OPC_CMPGDU_EQ_OB:
+ case OPC_CMPGDU_LT_OB:
+ case OPC_CMPGDU_LE_OB:
+ case OPC_CMPGU_EQ_OB:
+ case OPC_CMPGU_LT_OB:
+ case OPC_CMPGU_LE_OB:
+ case OPC_PACKRL_PW:
+ case OPC_PICK_OB:
+ case OPC_PICK_PW:
+ case OPC_PICK_QH:
+ gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
break;
- case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
- case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
- case OPC_DMODU_G_2E:
- check_insn(ctx, INSN_LOONGSON2E);
- gen_loongson_integer(ctx, op1, rd, rs, rt);
+ default: /* Invalid */
+ MIPS_INVAL("MASK CMPU_EQ.OB");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_ABSQ_S_QH_DSP:
- op2 = MASK_ABSQ_S_QH(ctx->opcode);
- switch (op2) {
- case OPC_PRECEQ_L_PWL:
- case OPC_PRECEQ_L_PWR:
- case OPC_PRECEQ_PW_QHL:
- case OPC_PRECEQ_PW_QHR:
- case OPC_PRECEQ_PW_QHLA:
- case OPC_PRECEQ_PW_QHRA:
- case OPC_PRECEQU_QH_OBL:
- case OPC_PRECEQU_QH_OBR:
- case OPC_PRECEQU_QH_OBLA:
- case OPC_PRECEQU_QH_OBRA:
- case OPC_PRECEU_QH_OBL:
- case OPC_PRECEU_QH_OBR:
- case OPC_PRECEU_QH_OBLA:
- case OPC_PRECEU_QH_OBRA:
- case OPC_ABSQ_S_OB:
- case OPC_ABSQ_S_PW:
- case OPC_ABSQ_S_QH:
- gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
- break;
- case OPC_REPL_OB:
- case OPC_REPL_PW:
- case OPC_REPL_QH:
- case OPC_REPLV_OB:
- case OPC_REPLV_PW:
- case OPC_REPLV_QH:
- gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK ABSQ_S.QH");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ }
+ break;
+ case OPC_DAPPEND_DSP:
+ gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+ break;
+ case OPC_DEXTR_W_DSP:
+ op2 = MASK_DEXTR_W(ctx->opcode);
+ switch (op2) {
+ case OPC_DEXTP:
+ case OPC_DEXTPDP:
+ case OPC_DEXTPDPV:
+ case OPC_DEXTPV:
+ case OPC_DEXTR_L:
+ case OPC_DEXTR_R_L:
+ case OPC_DEXTR_RS_L:
+ case OPC_DEXTR_W:
+ case OPC_DEXTR_R_W:
+ case OPC_DEXTR_RS_W:
+ case OPC_DEXTR_S_H:
+ case OPC_DEXTRV_L:
+ case OPC_DEXTRV_R_L:
+ case OPC_DEXTRV_RS_L:
+ case OPC_DEXTRV_S_H:
+ case OPC_DEXTRV_W:
+ case OPC_DEXTRV_R_W:
+ case OPC_DEXTRV_RS_W:
+ gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
break;
- case OPC_ADDU_OB_DSP:
- op2 = MASK_ADDU_OB(ctx->opcode);
- switch (op2) {
- case OPC_RADDU_L_OB:
- case OPC_SUBQ_PW:
- case OPC_SUBQ_S_PW:
- case OPC_SUBQ_QH:
- case OPC_SUBQ_S_QH:
- case OPC_SUBU_OB:
- case OPC_SUBU_S_OB:
- case OPC_SUBU_QH:
- case OPC_SUBU_S_QH:
- case OPC_SUBUH_OB:
- case OPC_SUBUH_R_OB:
- case OPC_ADDQ_PW:
- case OPC_ADDQ_S_PW:
- case OPC_ADDQ_QH:
- case OPC_ADDQ_S_QH:
- case OPC_ADDU_OB:
- case OPC_ADDU_S_OB:
- case OPC_ADDU_QH:
- case OPC_ADDU_S_QH:
- case OPC_ADDUH_OB:
- case OPC_ADDUH_R_OB:
- gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
- break;
- case OPC_MULEQ_S_PW_QHL:
- case OPC_MULEQ_S_PW_QHR:
- case OPC_MULEU_S_QH_OBL:
- case OPC_MULEU_S_QH_OBR:
- case OPC_MULQ_RS_QH:
- gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 1);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK ADDU.OB");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ case OPC_DMTHLIP:
+ case OPC_DSHILO:
+ case OPC_DSHILOV:
+ gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
break;
- case OPC_CMPU_EQ_OB_DSP:
- op2 = MASK_CMPU_EQ_OB(ctx->opcode);
- switch (op2) {
- case OPC_PRECR_SRA_QH_PW:
- case OPC_PRECR_SRA_R_QH_PW:
- /* Return value is rt. */
- gen_mipsdsp_arith(ctx, op1, op2, rt, rs, rd);
- break;
- case OPC_PRECR_OB_QH:
- case OPC_PRECRQ_OB_QH:
- case OPC_PRECRQ_PW_L:
- case OPC_PRECRQ_QH_PW:
- case OPC_PRECRQ_RS_QH_PW:
- case OPC_PRECRQU_S_OB_QH:
- gen_mipsdsp_arith(ctx, op1, op2, rd, rs, rt);
- break;
- case OPC_CMPU_EQ_OB:
- case OPC_CMPU_LT_OB:
- case OPC_CMPU_LE_OB:
- case OPC_CMP_EQ_QH:
- case OPC_CMP_LT_QH:
- case OPC_CMP_LE_QH:
- case OPC_CMP_EQ_PW:
- case OPC_CMP_LT_PW:
- case OPC_CMP_LE_PW:
- gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 0);
- break;
- case OPC_CMPGDU_EQ_OB:
- case OPC_CMPGDU_LT_OB:
- case OPC_CMPGDU_LE_OB:
- case OPC_CMPGU_EQ_OB:
- case OPC_CMPGU_LT_OB:
- case OPC_CMPGU_LE_OB:
- case OPC_PACKRL_PW:
- case OPC_PICK_OB:
- case OPC_PICK_PW:
- case OPC_PICK_QH:
- gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rd, rs, rt, 1);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK CMPU_EQ.OB");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ default: /* Invalid */
+ MIPS_INVAL("MASK EXTR.W");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_DAPPEND_DSP:
- gen_mipsdsp_append(env, ctx, op1, rt, rs, rd);
+ }
+ break;
+ case OPC_DPAQ_W_QH_DSP:
+ op2 = MASK_DPAQ_W_QH(ctx->opcode);
+ switch (op2) {
+ case OPC_DPAU_H_OBL:
+ case OPC_DPAU_H_OBR:
+ case OPC_DPSU_H_OBL:
+ case OPC_DPSU_H_OBR:
+ case OPC_DPA_W_QH:
+ case OPC_DPAQ_S_W_QH:
+ case OPC_DPS_W_QH:
+ case OPC_DPSQ_S_W_QH:
+ case OPC_MULSAQ_S_W_QH:
+ case OPC_DPAQ_SA_L_PW:
+ case OPC_DPSQ_SA_L_PW:
+ case OPC_MULSAQ_S_L_PW:
+ gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
+ break;
+ case OPC_MAQ_S_W_QHLL:
+ case OPC_MAQ_S_W_QHLR:
+ case OPC_MAQ_S_W_QHRL:
+ case OPC_MAQ_S_W_QHRR:
+ case OPC_MAQ_SA_W_QHLL:
+ case OPC_MAQ_SA_W_QHLR:
+ case OPC_MAQ_SA_W_QHRL:
+ case OPC_MAQ_SA_W_QHRR:
+ case OPC_MAQ_S_L_PWL:
+ case OPC_MAQ_S_L_PWR:
+ case OPC_DMADD:
+ case OPC_DMADDU:
+ case OPC_DMSUB:
+ case OPC_DMSUBU:
+ gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
break;
- case OPC_DEXTR_W_DSP:
- op2 = MASK_DEXTR_W(ctx->opcode);
- switch (op2) {
- case OPC_DEXTP:
- case OPC_DEXTPDP:
- case OPC_DEXTPDPV:
- case OPC_DEXTPV:
- case OPC_DEXTR_L:
- case OPC_DEXTR_R_L:
- case OPC_DEXTR_RS_L:
- case OPC_DEXTR_W:
- case OPC_DEXTR_R_W:
- case OPC_DEXTR_RS_W:
- case OPC_DEXTR_S_H:
- case OPC_DEXTRV_L:
- case OPC_DEXTRV_R_L:
- case OPC_DEXTRV_RS_L:
- case OPC_DEXTRV_S_H:
- case OPC_DEXTRV_W:
- case OPC_DEXTRV_R_W:
- case OPC_DEXTRV_RS_W:
- gen_mipsdsp_accinsn(ctx, op1, op2, rt, rs, rd, 1);
- break;
- case OPC_DMTHLIP:
- case OPC_DSHILO:
- case OPC_DSHILOV:
- gen_mipsdsp_accinsn(ctx, op1, op2, rd, rs, rt, 0);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK EXTR.W");
- generate_exception(ctx, EXCP_RI);
- break;
- }
+ default: /* Invalid */
+ MIPS_INVAL("MASK DPAQ.W.QH");
+ generate_exception(ctx, EXCP_RI);
break;
- case OPC_DPAQ_W_QH_DSP:
- op2 = MASK_DPAQ_W_QH(ctx->opcode);
- switch (op2) {
- case OPC_DPAU_H_OBL:
- case OPC_DPAU_H_OBR:
- case OPC_DPSU_H_OBL:
- case OPC_DPSU_H_OBR:
- case OPC_DPA_W_QH:
- case OPC_DPAQ_S_W_QH:
- case OPC_DPS_W_QH:
- case OPC_DPSQ_S_W_QH:
- case OPC_MULSAQ_S_W_QH:
- case OPC_DPAQ_SA_L_PW:
- case OPC_DPSQ_SA_L_PW:
- case OPC_MULSAQ_S_L_PW:
- gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
- break;
- case OPC_MAQ_S_W_QHLL:
- case OPC_MAQ_S_W_QHLR:
- case OPC_MAQ_S_W_QHRL:
- case OPC_MAQ_S_W_QHRR:
- case OPC_MAQ_SA_W_QHLL:
- case OPC_MAQ_SA_W_QHLR:
- case OPC_MAQ_SA_W_QHRL:
- case OPC_MAQ_SA_W_QHRR:
- case OPC_MAQ_S_L_PWL:
- case OPC_MAQ_S_L_PWR:
- case OPC_DMADD:
- case OPC_DMADDU:
- case OPC_DMSUB:
- case OPC_DMSUBU:
- gen_mipsdsp_multiply(ctx, op1, op2, rd, rs, rt, 0);
- break;
- default: /* Invalid */
- MIPS_INVAL("MASK DPAQ.W.QH");
- generate_exception(ctx, EXCP_RI);
+ }
+ break;
+ case OPC_DINSV_DSP:
+ op2 = MASK_INSV(ctx->opcode);
+ switch (op2) {
+ case OPC_DINSV:
+ {
+ TCGv t0, t1;
+
+ if (rt == 0) {
+ MIPS_DEBUG("NOP");
break;
}
- break;
- case OPC_DINSV_DSP:
- op2 = MASK_INSV(ctx->opcode);
- switch (op2) {
- case OPC_DINSV:
- {
- TCGv t0, t1;
-
- if (rt == 0) {
- MIPS_DEBUG("NOP");
- break;
- }
- check_dsp(ctx);
+ check_dsp(ctx);
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
- gen_load_gpr(t0, rt);
- gen_load_gpr(t1, rs);
+ gen_load_gpr(t0, rt);
+ gen_load_gpr(t1, rs);
- gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0);
+ gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- break;
- }
- default: /* Invalid */
- MIPS_INVAL("MASK DINSV");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- break;
- case OPC_SHLL_OB_DSP:
- gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
break;
-#endif
+ }
default: /* Invalid */
- MIPS_INVAL("special3");
+ MIPS_INVAL("MASK DINSV");
generate_exception(ctx, EXCP_RI);
break;
}
break;
+ case OPC_SHLL_OB_DSP:
+ gen_mipsdsp_shift(ctx, op1, rd, rs, rt);
+ break;
+#endif
+ default: /* Invalid */
+ MIPS_INVAL("special3");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+}
+
+static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
+{
+ int32_t offset;
+ int rs, rt, rd, sa;
+ uint32_t op, op1;
+ int16_t imm;
+
+ /* make sure instructions are on a word boundary */
+ if (ctx->pc & 0x3) {
+ env->CP0_BadVAddr = ctx->pc;
+ generate_exception(ctx, EXCP_AdEL);
+ return;
+ }
+
+ /* Handle blikely not taken case */
+ if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) {
+ int l1 = gen_new_label();
+
+ MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
+ tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
+ tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK);
+ gen_goto_tb(ctx, 1, ctx->pc + 4);
+ gen_set_label(l1);
+ }
+
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
+ tcg_gen_debug_insn_start(ctx->pc);
+ }
+
+ op = MASK_OP_MAJOR(ctx->opcode);
+ rs = (ctx->opcode >> 21) & 0x1f;
+ rt = (ctx->opcode >> 16) & 0x1f;
+ rd = (ctx->opcode >> 11) & 0x1f;
+ sa = (ctx->opcode >> 6) & 0x1f;
+ imm = (int16_t)ctx->opcode;
+ switch (op) {
+ case OPC_SPECIAL:
+ decode_opc_special(env, ctx);
+ break;
+ case OPC_SPECIAL2:
+ decode_opc_special2(env, ctx);
+ break;
+ case OPC_SPECIAL3:
+ decode_opc_special3(env, ctx);
+ break;
case OPC_REGIMM:
op1 = MASK_REGIMM(ctx->opcode);
switch (op1) {
@@ -15447,6 +15486,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
case OPC_MFMC0:
#ifndef CONFIG_USER_ONLY
{
+ uint32_t op2;
TCGv t0 = tcg_temp_new();
op2 = MASK_MFMC0(ctx->opcode);