qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 05/21] target-mips: extract decode_opc_special*


From: Aurelien Jarno
Subject: Re: [Qemu-devel] [PATCH 05/21] target-mips: extract decode_opc_special* from decode_opc
Date: Fri, 30 May 2014 22:09:03 +0200
User-agent: Mutt/1.5.21 (2010-09-15)

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 <address@hidden>
> ---
>  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 <address@hidden>


-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
address@hidden                 http://www.aurel32.net



reply via email to

[Prev in Thread] Current Thread [Next in Thread]