Message ID | 1401461279-59617-6-git-send-email-leon.alrae@imgtec.com |
---|---|
State | New |
Headers | show |
On Fri, May 30, 2014 at 03:47:43PM +0100, Leon Alrae wrote: > 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> > --- > target-mips/translate.c | 1676 ++++++++++++++++++++++++----------------------- > 1 files changed, 858 insertions(+), 818 deletions(-) > > diff --git a/target-mips/translate.c b/target-mips/translate.c > index 5d6be30..eedfde3 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -14431,909 +14431,948 @@ 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(); > - > - 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); > - } > + uint32_t op1; > > - 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 (env->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 (env->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: > - 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; > - } > - 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; > + /* 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; > } > - 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: > - check_insn(ctx, ISA_MIPS3); > - check_mips_64(ctx); > - gen_shift(ctx, op1, rd, rs, rt); > + default: > + generate_exception(ctx, EXCP_RI); > 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; > - 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_DMULT ... OPC_DDIVU: > + /* Fallthrough */ > + case 0: > check_insn(ctx, ISA_MIPS3); > check_mips_64(ctx); > - gen_muldiv(ctx, op1, 0, rs, rt); > + gen_shift_imm(ctx, op1, rd, rt, sa); > break; > -#endif > - default: /* Invalid */ > - MIPS_INVAL("special"); > + default: > 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); > - 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); > + 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; > } > - /* 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); > + /* Fallthrough */ > + case 0: > + check_insn(ctx, ISA_MIPS3); > 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); > + gen_shift(ctx, op1, rd, rs, rt); > break; > -#endif > - default: /* Invalid */ > - MIPS_INVAL("special2"); > + default: > 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); > - 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(); > + 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; > + } > +} > > - 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(); > +static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) > +{ > + int rs, rt, rd; > + uint32_t op1; > > - 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; > - } > - } 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) { > + 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_LDX: > + 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 > - 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; > - } > - break; > - case OPC_ABSQ_S_PH_DSP: > - op2 = MASK_ABSQ_S_PH(ctx->opcode); > + 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_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: > + 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_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); > + 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 ABSQ_S.PH"); > + 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); > + } > + 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; > + } > + 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; > + } > + 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; > - 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 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_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_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_SHLL_QB_DSP: > - gen_mipsdsp_shift(ctx, op1, rd, rs, rt); > + 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_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); > + 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; > + } > + 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, 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; > + } > + 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_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 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_opc_removed(ctx, ISA_MIPS32R6); > + 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_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_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_opc_removed(ctx, ISA_MIPS32R6); > - 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); > - 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); > + gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0); > 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) { > @@ -15394,6 +15433,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); Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
diff --git a/target-mips/translate.c b/target-mips/translate.c index 5d6be30..eedfde3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -14431,909 +14431,948 @@ 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(); - - 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); - } + uint32_t op1; - 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 (env->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 (env->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: - 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; - } - 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; + /* 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; } - 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: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift(ctx, op1, rd, rs, rt); + default: + generate_exception(ctx, EXCP_RI); 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; - 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_DMULT ... OPC_DDIVU: + /* Fallthrough */ + case 0: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_muldiv(ctx, op1, 0, rs, rt); + gen_shift_imm(ctx, op1, rd, rt, sa); break; -#endif - default: /* Invalid */ - MIPS_INVAL("special"); + default: 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); - 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); + 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; } - /* 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); + /* Fallthrough */ + case 0: + check_insn(ctx, ISA_MIPS3); 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); + gen_shift(ctx, op1, rd, rs, rt); break; -#endif - default: /* Invalid */ - MIPS_INVAL("special2"); + default: 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); - 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(); + 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; + } +} - 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(); +static void decode_opc_special2(CPUMIPSState *env, DisasContext *ctx) +{ + int rs, rt, rd; + uint32_t op1; - 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; - } - } 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) { + 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_LDX: + 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 - 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; - } - break; - case OPC_ABSQ_S_PH_DSP: - op2 = MASK_ABSQ_S_PH(ctx->opcode); + 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_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: + 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_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); + 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 ABSQ_S.PH"); + 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); + } + 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; + } + 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; + } + 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; - 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 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_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_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_SHLL_QB_DSP: - gen_mipsdsp_shift(ctx, op1, rd, rs, rt); + 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_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); + 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; + } + 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, 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; + } + 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_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 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_opc_removed(ctx, ISA_MIPS32R6); + 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_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_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_opc_removed(ctx, ISA_MIPS32R6); - 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); - 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); + gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0); 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) { @@ -15394,6 +15433,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);
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> --- target-mips/translate.c | 1676 ++++++++++++++++++++++++----------------------- 1 files changed, 858 insertions(+), 818 deletions(-)