static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)

{

    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);

    }



    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;

            }

            break;

        case OPC_MOVN:         /* Conditional move */

        case OPC_MOVZ:

            check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 |

                                 INSN_LOONGSON2E | INSN_LOONGSON2F);

            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;

            }

            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 ... OPC_DIVU:

            if (sa) {

                check_insn(ctx, INSN_VR54XX);

                op1 = MASK_MUL_VR54XX(ctx->opcode);

                gen_mul_vr54xx(ctx, op1, rd, rs, rt);

            } else

                gen_muldiv(ctx, op1, rs, rt);

            break;

        case OPC_JR ... OPC_JALR:

            gen_compute_branch(ctx, op1, 4, rs, rd, sa);

            *is_branch = 1;

            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:

            gen_HILO(ctx, op1, rd);

            break;

        case OPC_MTHI:

        case OPC_MTLO:          /* Move to HI/LO */

            gen_HILO(ctx, op1, rs);

            break;

        case OPC_PMON:          /* Pmon entry point, also R4010 selsl */

#ifdef MIPS_STRICT_STANDARD

            MIPS_INVAL("PMON / selsl");

            generate_exception(ctx, EXCP_RI);

#else

            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:

#ifdef MIPS_STRICT_STANDARD

            MIPS_INVAL("SPIM");

            generate_exception(ctx, EXCP_RI);

#else

           /* Implemented as RI exception for now. */

            MIPS_INVAL("spim (unofficial)");

            generate_exception(ctx, EXCP_RI);

#endif

            break;

        case OPC_SYNC:

            /* Treat as NOP. */

            break;



        case OPC_MOVCI:

            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;

            }

            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;

            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, rs, rt);

            break;

#endif

        default:            /* Invalid */

            MIPS_INVAL("special");

            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(ctx, ISA_MIPS32);

            gen_muldiv(ctx, op1, rs, rt);

            break;

        case OPC_MUL:

            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;

        }

        break;

    case OPC_SPECIAL3:

        op1 = MASK_SPECIAL3(ctx->opcode);

        switch (op1) {

        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;

                }

            } 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;



            }

            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;

            }

            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:

            check_dspr2(ctx);

            op2 = MASK_APPEND(ctx->opcode);

            gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1);

            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;

#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_DMOD_G_2E ... 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_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_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;

            }

            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;

            }

            break;

        case OPC_DAPPEND_DSP:

            check_dspr2(ctx);

            op2 = MASK_DAPPEND(ctx->opcode);

            gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1);

            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;

            }

            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;

            }

            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);



                    t0 = tcg_temp_new();

                    t1 = tcg_temp_new();



                    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);

            break;

#endif

        default:            /* Invalid */

            MIPS_INVAL("special3");

            generate_exception(ctx, EXCP_RI);

            break;

        }

        break;

    case OPC_REGIMM:

        op1 = MASK_REGIMM(ctx->opcode);

        switch (op1) {

        case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */

        case OPC_BLTZAL ... OPC_BGEZALL:

            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);

            *is_branch = 1;

            break;

        case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */

        case OPC_TNEI:

            gen_trap(ctx, op1, rs, -1, imm);

            break;

        case OPC_SYNCI:

            check_insn(ctx, ISA_MIPS32R2);

            /* Treat as NOP. */

            break;

        case OPC_BPOSGE32:    /* MIPS DSP branch */

#if defined(TARGET_MIPS64)

        case OPC_BPOSGE64:

#endif

            check_dsp(ctx);

            gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2);

            *is_branch = 1;

            break;

        default:            /* Invalid */

            MIPS_INVAL("regimm");

            generate_exception(ctx, EXCP_RI);

            break;

        }

        break;

    case OPC_CP0:

        check_cp0_enabled(ctx);

        op1 = MASK_CP0(ctx->opcode);

        switch (op1) {

        case OPC_MFC0:

        case OPC_MTC0:

        case OPC_MFTR:

        case OPC_MTTR:

#if defined(TARGET_MIPS64)

        case OPC_DMFC0:

        case OPC_DMTC0:

#endif

#ifndef CONFIG_USER_ONLY

            gen_cp0(env, ctx, op1, rt, rd);

#endif /* !CONFIG_USER_ONLY */

            break;

        case OPC_C0_FIRST ... OPC_C0_LAST:

#ifndef CONFIG_USER_ONLY

            gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd);

#endif /* !CONFIG_USER_ONLY */

            break;

        case OPC_MFMC0:

#ifndef CONFIG_USER_ONLY

            {

                TCGv t0 = tcg_temp_new();



                op2 = MASK_MFMC0(ctx->opcode);

                switch (op2) {

                case OPC_DMT:

                    check_insn(ctx, ASE_MT);

                    gen_helper_dmt(t0);

                    gen_store_gpr(t0, rt);

                    break;

                case OPC_EMT:

                    check_insn(ctx, ASE_MT);

                    gen_helper_emt(t0);

                    gen_store_gpr(t0, rt);

                    break;

                case OPC_DVPE:

                    check_insn(ctx, ASE_MT);

                    gen_helper_dvpe(t0, cpu_env);

                    gen_store_gpr(t0, rt);

                    break;

                case OPC_EVPE:

                    check_insn(ctx, ASE_MT);

                    gen_helper_evpe(t0, cpu_env);

                    gen_store_gpr(t0, rt);

                    break;

                case OPC_DI:

                    check_insn(ctx, ISA_MIPS32R2);

                    save_cpu_state(ctx, 1);

                    gen_helper_di(t0, cpu_env);

                    gen_store_gpr(t0, rt);

                    /* Stop translation as we may have switched the execution mode */

                    ctx->bstate = BS_STOP;

                    break;

                case OPC_EI:

                    check_insn(ctx, ISA_MIPS32R2);

                    save_cpu_state(ctx, 1);

                    gen_helper_ei(t0, cpu_env);

                    gen_store_gpr(t0, rt);

                    /* Stop translation as we may have switched the execution mode */

                    ctx->bstate = BS_STOP;

                    break;

                default:            /* Invalid */

                    MIPS_INVAL("mfmc0");

                    generate_exception(ctx, EXCP_RI);

                    break;

                }

                tcg_temp_free(t0);

            }

#endif /* !CONFIG_USER_ONLY */

            break;

        case OPC_RDPGPR:

            check_insn(ctx, ISA_MIPS32R2);

            gen_load_srsgpr(rt, rd);

            break;

        case OPC_WRPGPR:

            check_insn(ctx, ISA_MIPS32R2);

            gen_store_srsgpr(rt, rd);

            break;

        default:

            MIPS_INVAL("cp0");

            generate_exception(ctx, EXCP_RI);

            break;

        }

        break;

    case OPC_ADDI: /* Arithmetic with immediate opcode */

    case OPC_ADDIU:

         gen_arith_imm(ctx, op, rt, rs, imm);

         break;

    case OPC_SLTI: /* Set on less than with immediate opcode */

    case OPC_SLTIU:

         gen_slt_imm(ctx, op, rt, rs, imm);

         break;

    case OPC_ANDI: /* Arithmetic with immediate opcode */

    case OPC_LUI:

    case OPC_ORI:

    case OPC_XORI:

         gen_logic_imm(ctx, op, rt, rs, imm);

         break;

    case OPC_J ... OPC_JAL: /* Jump */

         offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;

         gen_compute_branch(ctx, op, 4, rs, rt, offset);

         *is_branch = 1;

         break;

    case OPC_BEQ ... OPC_BGTZ: /* Branch */

    case OPC_BEQL ... OPC_BGTZL:

         gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);

         *is_branch = 1;

         break;

    case OPC_LB ... OPC_LWR: /* Load and stores */

    case OPC_LL:

         gen_ld(ctx, op, rt, rs, imm);

         break;

    case OPC_SB ... OPC_SW:

    case OPC_SWR:

         gen_st(ctx, op, rt, rs, imm);

         break;

    case OPC_SC:

         gen_st_cond(ctx, op, rt, rs, imm);

         break;

    case OPC_CACHE:

        check_cp0_enabled(ctx);

        check_insn(ctx, ISA_MIPS3 | ISA_MIPS32);

        /* Treat as NOP. */

        break;

    case OPC_PREF:

        check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);

        /* Treat as NOP. */

        break;



    /* Floating point (COP1). */

    case OPC_LWC1:

    case OPC_LDC1:

    case OPC_SWC1:

    case OPC_SDC1:

        gen_cop1_ldst(env, ctx, op, rt, rs, imm);

        break;



    case OPC_CP1:

        if (env->CP0_Config1 & (1 << CP0C1_FP)) {

            check_cp1_enabled(ctx);

            op1 = MASK_CP1(ctx->opcode);

            switch (op1) {

            case OPC_MFHC1:

            case OPC_MTHC1:

                check_insn(ctx, ISA_MIPS32R2);

            case OPC_MFC1:

            case OPC_CFC1:

            case OPC_MTC1:

            case OPC_CTC1:

                gen_cp1(ctx, op1, rt, rd);

                break;

#if defined(TARGET_MIPS64)

            case OPC_DMFC1:

            case OPC_DMTC1:

                check_insn(ctx, ISA_MIPS3);

                gen_cp1(ctx, op1, rt, rd);

                break;

#endif

            case OPC_BC1ANY2:

            case OPC_BC1ANY4:

                check_cop1x(ctx);

                check_insn(ctx, ASE_MIPS3D);

                /* fall through */

            case OPC_BC1:

                gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),

                                    (rt >> 2) & 0x7, imm << 2);

                *is_branch = 1;

                break;

            case OPC_S_FMT:

            case OPC_D_FMT:

            case OPC_W_FMT:

            case OPC_L_FMT:

            case OPC_PS_FMT:

                gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,

                           (imm >> 8) & 0x7);

                break;

            default:

                MIPS_INVAL("cp1");

                generate_exception (ctx, EXCP_RI);

                break;

            }

        } else {

            generate_exception_err(ctx, EXCP_CpU, 1);

        }

        break;



    /* COP2.  */

    case OPC_LWC2:

    case OPC_LDC2:

    case OPC_SWC2:

    case OPC_SDC2:

        /* COP2: Not implemented. */

        generate_exception_err(ctx, EXCP_CpU, 2);

        break;

    case OPC_CP2:

        check_insn(ctx, INSN_LOONGSON2F);

        /* Note that these instructions use different fields.  */

        gen_loongson_multimedia(ctx, sa, rd, rt);

        break;



    case OPC_CP3:

        if (env->CP0_Config1 & (1 << CP0C1_FP)) {

            check_cp1_enabled(ctx);

            op1 = MASK_CP3(ctx->opcode);

            switch (op1) {

            case OPC_LWXC1:

            case OPC_LDXC1:

            case OPC_LUXC1:

            case OPC_SWXC1:

            case OPC_SDXC1:

            case OPC_SUXC1:

                gen_flt3_ldst(ctx, op1, sa, rd, rs, rt);

                break;

            case OPC_PREFX:

                /* Treat as NOP. */

                break;

            case OPC_ALNV_PS:

            case OPC_MADD_S:

            case OPC_MADD_D:

            case OPC_MADD_PS:

            case OPC_MSUB_S:

            case OPC_MSUB_D:

            case OPC_MSUB_PS:

            case OPC_NMADD_S:

            case OPC_NMADD_D:

            case OPC_NMADD_PS:

            case OPC_NMSUB_S:

            case OPC_NMSUB_D:

            case OPC_NMSUB_PS:

                gen_flt3_arith(ctx, op1, sa, rs, rd, rt);

                break;

            default:

                MIPS_INVAL("cp3");

                generate_exception (ctx, EXCP_RI);

                break;

            }

        } else {

            generate_exception_err(ctx, EXCP_CpU, 1);

        }

        break;



#if defined(TARGET_MIPS64)

    /* MIPS64 opcodes */

    case OPC_LWU:

    case OPC_LDL ... OPC_LDR:

    case OPC_LLD:

    case OPC_LD:

        check_insn(ctx, ISA_MIPS3);

        check_mips_64(ctx);

        gen_ld(ctx, op, rt, rs, imm);

        break;

    case OPC_SDL ... OPC_SDR:

    case OPC_SD:

        check_insn(ctx, ISA_MIPS3);

        check_mips_64(ctx);

        gen_st(ctx, op, rt, rs, imm);

        break;

    case OPC_SCD:

        check_insn(ctx, ISA_MIPS3);

        check_mips_64(ctx);

        gen_st_cond(ctx, op, rt, rs, imm);

        break;

    case OPC_DADDI:

    case OPC_DADDIU:

        check_insn(ctx, ISA_MIPS3);

        check_mips_64(ctx);

        gen_arith_imm(ctx, op, rt, rs, imm);

        break;

#endif

    case OPC_JALX:

        check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS);

        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;

        gen_compute_branch(ctx, op, 4, rs, rt, offset);

        *is_branch = 1;

        break;

    case OPC_MDMX:

        check_insn(ctx, ASE_MDMX);

        /* MDMX: Not implemented. */

    default:            /* Invalid */

        MIPS_INVAL("major opcode");

        generate_exception(ctx, EXCP_RI);

        break;

    }

}
