static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,

                                    uint16_t insn_hw1)

{

    int32_t offset;

    uint16_t insn;

    int rt, rs, rd, rr;

    int16_t imm;

    uint32_t op, minor, mips32_op;

    uint32_t cond, fmt, cc;



    insn = cpu_lduw_code(env, ctx->pc + 2);

    ctx->opcode = (ctx->opcode << 16) | insn;



    rt = (ctx->opcode >> 21) & 0x1f;

    rs = (ctx->opcode >> 16) & 0x1f;

    rd = (ctx->opcode >> 11) & 0x1f;

    rr = (ctx->opcode >> 6) & 0x1f;

    imm = (int16_t) ctx->opcode;



    op = (ctx->opcode >> 26) & 0x3f;

    switch (op) {

    case POOL32A:

        minor = ctx->opcode & 0x3f;

        switch (minor) {

        case 0x00:

            minor = (ctx->opcode >> 6) & 0xf;

            switch (minor) {

            case SLL32:

                mips32_op = OPC_SLL;

                goto do_shifti;

            case SRA:

                mips32_op = OPC_SRA;

                goto do_shifti;

            case SRL32:

                mips32_op = OPC_SRL;

                goto do_shifti;

            case ROTR:

                mips32_op = OPC_ROTR;

            do_shifti:

                gen_shift_imm(ctx, mips32_op, rt, rs, rd);

                break;

            default:

                goto pool32a_invalid;

            }

            break;

        case 0x10:

            minor = (ctx->opcode >> 6) & 0xf;

            switch (minor) {

                /* Arithmetic */

            case ADD:

                mips32_op = OPC_ADD;

                goto do_arith;

            case ADDU32:

                mips32_op = OPC_ADDU;

                goto do_arith;

            case SUB:

                mips32_op = OPC_SUB;

                goto do_arith;

            case SUBU32:

                mips32_op = OPC_SUBU;

                goto do_arith;

            case MUL:

                mips32_op = OPC_MUL;

            do_arith:

                gen_arith(ctx, mips32_op, rd, rs, rt);

                break;

                /* Shifts */

            case SLLV:

                mips32_op = OPC_SLLV;

                goto do_shift;

            case SRLV:

                mips32_op = OPC_SRLV;

                goto do_shift;

            case SRAV:

                mips32_op = OPC_SRAV;

                goto do_shift;

            case ROTRV:

                mips32_op = OPC_ROTRV;

            do_shift:

                gen_shift(ctx, mips32_op, rd, rs, rt);

                break;

                /* Logical operations */

            case AND:

                mips32_op = OPC_AND;

                goto do_logic;

            case OR32:

                mips32_op = OPC_OR;

                goto do_logic;

            case NOR:

                mips32_op = OPC_NOR;

                goto do_logic;

            case XOR32:

                mips32_op = OPC_XOR;

            do_logic:

                gen_logic(ctx, mips32_op, rd, rs, rt);

                break;

                /* Set less than */

            case SLT:

                mips32_op = OPC_SLT;

                goto do_slt;

            case SLTU:

                mips32_op = OPC_SLTU;

            do_slt:

                gen_slt(ctx, mips32_op, rd, rs, rt);

                break;

            default:

                goto pool32a_invalid;

            }

            break;

        case 0x18:

            minor = (ctx->opcode >> 6) & 0xf;

            switch (minor) {

                /* Conditional moves */

            case MOVN:

                mips32_op = OPC_MOVN;

                goto do_cmov;

            case MOVZ:

                mips32_op = OPC_MOVZ;

            do_cmov:

                gen_cond_move(ctx, mips32_op, rd, rs, rt);

                break;

            case LWXS:

                gen_ldxs(ctx, rs, rt, rd);

                break;

            default:

                goto pool32a_invalid;

            }

            break;

        case INS:

            gen_bitops(ctx, OPC_INS, rt, rs, rr, rd);

            return;

        case EXT:

            gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd);

            return;

        case POOL32AXF:

            gen_pool32axf(env, ctx, rt, rs);

            break;

        case 0x07:

            generate_exception(ctx, EXCP_BREAK);

            break;

        default:

        pool32a_invalid:

                MIPS_INVAL("pool32a");

                generate_exception(ctx, EXCP_RI);

                break;

        }

        break;

    case POOL32B:

        minor = (ctx->opcode >> 12) & 0xf;

        switch (minor) {

        case CACHE:

            check_cp0_enabled(ctx);

            /* Treat as no-op. */

            break;

        case LWC2:

        case SWC2:

            /* COP2: Not implemented. */

            generate_exception_err(ctx, EXCP_CpU, 2);

            break;

        case LWP:

        case SWP:

#ifdef TARGET_MIPS64

        case LDP:

        case SDP:

#endif

            gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));

            break;

        case LWM32:

        case SWM32:

#ifdef TARGET_MIPS64

        case LDM:

        case SDM:

#endif

            gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));

            break;

        default:

            MIPS_INVAL("pool32b");

            generate_exception(ctx, EXCP_RI);

            break;

        }

        break;

    case POOL32F:

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

            minor = ctx->opcode & 0x3f;

            check_cp1_enabled(ctx);

            switch (minor) {

            case ALNV_PS:

                mips32_op = OPC_ALNV_PS;

                goto do_madd;

            case MADD_S:

                mips32_op = OPC_MADD_S;

                goto do_madd;

            case MADD_D:

                mips32_op = OPC_MADD_D;

                goto do_madd;

            case MADD_PS:

                mips32_op = OPC_MADD_PS;

                goto do_madd;

            case MSUB_S:

                mips32_op = OPC_MSUB_S;

                goto do_madd;

            case MSUB_D:

                mips32_op = OPC_MSUB_D;

                goto do_madd;

            case MSUB_PS:

                mips32_op = OPC_MSUB_PS;

                goto do_madd;

            case NMADD_S:

                mips32_op = OPC_NMADD_S;

                goto do_madd;

            case NMADD_D:

                mips32_op = OPC_NMADD_D;

                goto do_madd;

            case NMADD_PS:

                mips32_op = OPC_NMADD_PS;

                goto do_madd;

            case NMSUB_S:

                mips32_op = OPC_NMSUB_S;

                goto do_madd;

            case NMSUB_D:

                mips32_op = OPC_NMSUB_D;

                goto do_madd;

            case NMSUB_PS:

                mips32_op = OPC_NMSUB_PS;

            do_madd:

                gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt);

                break;

            case CABS_COND_FMT:

                cond = (ctx->opcode >> 6) & 0xf;

                cc = (ctx->opcode >> 13) & 0x7;

                fmt = (ctx->opcode >> 10) & 0x3;

                switch (fmt) {

                case 0x0:

                    gen_cmpabs_s(ctx, cond, rt, rs, cc);

                    break;

                case 0x1:

                    gen_cmpabs_d(ctx, cond, rt, rs, cc);

                    break;

                case 0x2:

                    gen_cmpabs_ps(ctx, cond, rt, rs, cc);

                    break;

                default:

                    goto pool32f_invalid;

                }

                break;

            case C_COND_FMT:

                cond = (ctx->opcode >> 6) & 0xf;

                cc = (ctx->opcode >> 13) & 0x7;

                fmt = (ctx->opcode >> 10) & 0x3;

                switch (fmt) {

                case 0x0:

                    gen_cmp_s(ctx, cond, rt, rs, cc);

                    break;

                case 0x1:

                    gen_cmp_d(ctx, cond, rt, rs, cc);

                    break;

                case 0x2:

                    gen_cmp_ps(ctx, cond, rt, rs, cc);

                    break;

                default:

                    goto pool32f_invalid;

                }

                break;

            case POOL32FXF:

                gen_pool32fxf(ctx, rt, rs);

                break;

            case 0x00:

                /* PLL foo */

                switch ((ctx->opcode >> 6) & 0x7) {

                case PLL_PS:

                    mips32_op = OPC_PLL_PS;

                    goto do_ps;

                case PLU_PS:

                    mips32_op = OPC_PLU_PS;

                    goto do_ps;

                case PUL_PS:

                    mips32_op = OPC_PUL_PS;

                    goto do_ps;

                case PUU_PS:

                    mips32_op = OPC_PUU_PS;

                    goto do_ps;

                case CVT_PS_S:

                    mips32_op = OPC_CVT_PS_S;

                do_ps:

                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);

                    break;

                default:

                    goto pool32f_invalid;

                }

                break;

            case 0x08:

                /* [LS][WDU]XC1 */

                switch ((ctx->opcode >> 6) & 0x7) {

                case LWXC1:

                    mips32_op = OPC_LWXC1;

                    goto do_ldst_cp1;

                case SWXC1:

                    mips32_op = OPC_SWXC1;

                    goto do_ldst_cp1;

                case LDXC1:

                    mips32_op = OPC_LDXC1;

                    goto do_ldst_cp1;

                case SDXC1:

                    mips32_op = OPC_SDXC1;

                    goto do_ldst_cp1;

                case LUXC1:

                    mips32_op = OPC_LUXC1;

                    goto do_ldst_cp1;

                case SUXC1:

                    mips32_op = OPC_SUXC1;

                do_ldst_cp1:

                    gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs);

                    break;

                default:

                    goto pool32f_invalid;

                }

                break;

            case 0x18:

                /* 3D insns */

                fmt = (ctx->opcode >> 9) & 0x3;

                switch ((ctx->opcode >> 6) & 0x7) {

                case RSQRT2_FMT:

                    switch (fmt) {

                    case FMT_SDPS_S:

                        mips32_op = OPC_RSQRT2_S;

                        goto do_3d;

                    case FMT_SDPS_D:

                        mips32_op = OPC_RSQRT2_D;

                        goto do_3d;

                    case FMT_SDPS_PS:

                        mips32_op = OPC_RSQRT2_PS;

                        goto do_3d;

                    default:

                        goto pool32f_invalid;

                    }

                    break;

                case RECIP2_FMT:

                    switch (fmt) {

                    case FMT_SDPS_S:

                        mips32_op = OPC_RECIP2_S;

                        goto do_3d;

                    case FMT_SDPS_D:

                        mips32_op = OPC_RECIP2_D;

                        goto do_3d;

                    case FMT_SDPS_PS:

                        mips32_op = OPC_RECIP2_PS;

                        goto do_3d;

                    default:

                        goto pool32f_invalid;

                    }

                    break;

                case ADDR_PS:

                    mips32_op = OPC_ADDR_PS;

                    goto do_3d;

                case MULR_PS:

                    mips32_op = OPC_MULR_PS;

                do_3d:

                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);

                    break;

                default:

                    goto pool32f_invalid;

                }

                break;

            case 0x20:

                /* MOV[FT].fmt and PREFX */

                cc = (ctx->opcode >> 13) & 0x7;

                fmt = (ctx->opcode >> 9) & 0x3;

                switch ((ctx->opcode >> 6) & 0x7) {

                case MOVF_FMT:

                    switch (fmt) {

                    case FMT_SDPS_S:

                        gen_movcf_s(rs, rt, cc, 0);

                        break;

                    case FMT_SDPS_D:

                        gen_movcf_d(ctx, rs, rt, cc, 0);

                        break;

                    case FMT_SDPS_PS:

                        gen_movcf_ps(rs, rt, cc, 0);

                        break;

                    default:

                        goto pool32f_invalid;

                    }

                    break;

                case MOVT_FMT:

                    switch (fmt) {

                    case FMT_SDPS_S:

                        gen_movcf_s(rs, rt, cc, 1);

                        break;

                    case FMT_SDPS_D:

                        gen_movcf_d(ctx, rs, rt, cc, 1);

                        break;

                    case FMT_SDPS_PS:

                        gen_movcf_ps(rs, rt, cc, 1);

                        break;

                    default:

                        goto pool32f_invalid;

                    }

                    break;

                case PREFX:

                    break;

                default:

                    goto pool32f_invalid;

                }

                break;

#define FINSN_3ARG_SDPS(prfx)                           \

                switch ((ctx->opcode >> 8) & 0x3) {     \

                case FMT_SDPS_S:                        \

                    mips32_op = OPC_##prfx##_S;         \

                    goto do_fpop;                       \

                case FMT_SDPS_D:                        \

                    mips32_op = OPC_##prfx##_D;         \

                    goto do_fpop;                       \

                case FMT_SDPS_PS:                       \

                    mips32_op = OPC_##prfx##_PS;        \

                    goto do_fpop;                       \

                default:                                \

                    goto pool32f_invalid;               \

                }

            case 0x30:

                /* regular FP ops */

                switch ((ctx->opcode >> 6) & 0x3) {

                case ADD_FMT:

                    FINSN_3ARG_SDPS(ADD);

                    break;

                case SUB_FMT:

                    FINSN_3ARG_SDPS(SUB);

                    break;

                case MUL_FMT:

                    FINSN_3ARG_SDPS(MUL);

                    break;

                case DIV_FMT:

                    fmt = (ctx->opcode >> 8) & 0x3;

                    if (fmt == 1) {

                        mips32_op = OPC_DIV_D;

                    } else if (fmt == 0) {

                        mips32_op = OPC_DIV_S;

                    } else {

                        goto pool32f_invalid;

                    }

                    goto do_fpop;

                default:

                    goto pool32f_invalid;

                }

                break;

            case 0x38:

                /* cmovs */

                switch ((ctx->opcode >> 6) & 0x3) {

                case MOVN_FMT:

                    FINSN_3ARG_SDPS(MOVN);

                    break;

                case MOVZ_FMT:

                    FINSN_3ARG_SDPS(MOVZ);

                    break;

                default:

                    goto pool32f_invalid;

                }

                break;

            do_fpop:

                gen_farith(ctx, mips32_op, rt, rs, rd, 0);

                break;

            default:

            pool32f_invalid:

                MIPS_INVAL("pool32f");

                generate_exception(ctx, EXCP_RI);

                break;

            }

        } else {

            generate_exception_err(ctx, EXCP_CpU, 1);

        }

        break;

    case POOL32I:

        minor = (ctx->opcode >> 21) & 0x1f;

        switch (minor) {

        case BLTZ:

            mips32_op = OPC_BLTZ;

            goto do_branch;

        case BLTZAL:

            mips32_op = OPC_BLTZAL;

            goto do_branch;

        case BLTZALS:

            mips32_op = OPC_BLTZALS;

            goto do_branch;

        case BGEZ:

            mips32_op = OPC_BGEZ;

            goto do_branch;

        case BGEZAL:

            mips32_op = OPC_BGEZAL;

            goto do_branch;

        case BGEZALS:

            mips32_op = OPC_BGEZALS;

            goto do_branch;

        case BLEZ:

            mips32_op = OPC_BLEZ;

            goto do_branch;

        case BGTZ:

            mips32_op = OPC_BGTZ;

        do_branch:

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

            break;



            /* Traps */

        case TLTI:

            mips32_op = OPC_TLTI;

            goto do_trapi;

        case TGEI:

            mips32_op = OPC_TGEI;

            goto do_trapi;

        case TLTIU:

            mips32_op = OPC_TLTIU;

            goto do_trapi;

        case TGEIU:

            mips32_op = OPC_TGEIU;

            goto do_trapi;

        case TNEI:

            mips32_op = OPC_TNEI;

            goto do_trapi;

        case TEQI:

            mips32_op = OPC_TEQI;

        do_trapi:

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

            break;



        case BNEZC:

        case BEQZC:

            gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ,

                               4, rs, 0, imm << 1);

            /* Compact branches don't have a delay slot, so just let

               the normal delay slot handling take us to the branch

               target. */

            break;

        case LUI:

            gen_logic_imm(ctx, OPC_LUI, rs, -1, imm);

            break;

        case SYNCI:

            break;

        case BC2F:

        case BC2T:

            /* COP2: Not implemented. */

            generate_exception_err(ctx, EXCP_CpU, 2);

            break;

        case BC1F:

            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F;

            goto do_cp1branch;

        case BC1T:

            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T;

            goto do_cp1branch;

        case BC1ANY4F:

            mips32_op = OPC_BC1FANY4;

            goto do_cp1mips3d;

        case BC1ANY4T:

            mips32_op = OPC_BC1TANY4;

        do_cp1mips3d:

            check_cop1x(ctx);

            check_insn(ctx, ASE_MIPS3D);

            /* Fall through */

        do_cp1branch:

            gen_compute_branch1(ctx, mips32_op,

                                (ctx->opcode >> 18) & 0x7, imm << 1);

            break;

        case BPOSGE64:

        case BPOSGE32:

            /* MIPS DSP: not implemented */

            /* Fall through */

        default:

            MIPS_INVAL("pool32i");

            generate_exception(ctx, EXCP_RI);

            break;

        }

        break;

    case POOL32C:

        minor = (ctx->opcode >> 12) & 0xf;

        switch (minor) {

        case LWL:

            mips32_op = OPC_LWL;

            goto do_ld_lr;

        case SWL:

            mips32_op = OPC_SWL;

            goto do_st_lr;

        case LWR:

            mips32_op = OPC_LWR;

            goto do_ld_lr;

        case SWR:

            mips32_op = OPC_SWR;

            goto do_st_lr;

#if defined(TARGET_MIPS64)

        case LDL:

            mips32_op = OPC_LDL;

            goto do_ld_lr;

        case SDL:

            mips32_op = OPC_SDL;

            goto do_st_lr;

        case LDR:

            mips32_op = OPC_LDR;

            goto do_ld_lr;

        case SDR:

            mips32_op = OPC_SDR;

            goto do_st_lr;

        case LWU:

            mips32_op = OPC_LWU;

            goto do_ld_lr;

        case LLD:

            mips32_op = OPC_LLD;

            goto do_ld_lr;

#endif

        case LL:

            mips32_op = OPC_LL;

            goto do_ld_lr;

        do_ld_lr:

            gen_ld(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));

            break;

        do_st_lr:

            gen_st(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));

            break;

        case SC:

            gen_st_cond(ctx, OPC_SC, rt, rs, SIMM(ctx->opcode, 0, 12));

            break;

#if defined(TARGET_MIPS64)

        case SCD:

            gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12));

            break;

#endif

        case PREF:

            /* Treat as no-op */

            break;

        default:

            MIPS_INVAL("pool32c");

            generate_exception(ctx, EXCP_RI);

            break;

        }

        break;

    case ADDI32:

        mips32_op = OPC_ADDI;

        goto do_addi;

    case ADDIU32:

        mips32_op = OPC_ADDIU;

    do_addi:

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

        break;



        /* Logical operations */

    case ORI32:

        mips32_op = OPC_ORI;

        goto do_logici;

    case XORI32:

        mips32_op = OPC_XORI;

        goto do_logici;

    case ANDI32:

        mips32_op = OPC_ANDI;

    do_logici:

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

        break;



        /* Set less than immediate */

    case SLTI32:

        mips32_op = OPC_SLTI;

        goto do_slti;

    case SLTIU32:

        mips32_op = OPC_SLTIU;

    do_slti:

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

        break;

    case JALX32:

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

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

        break;

    case JALS32:

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

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

        break;

    case BEQ32:

        gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1);

        break;

    case BNE32:

        gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1);

        break;

    case J32:

        gen_compute_branch(ctx, OPC_J, 4, rt, rs,

                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);

        break;

    case JAL32:

        gen_compute_branch(ctx, OPC_JAL, 4, rt, rs,

                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);

        break;

        /* Floating point (COP1) */

    case LWC132:

        mips32_op = OPC_LWC1;

        goto do_cop1;

    case LDC132:

        mips32_op = OPC_LDC1;

        goto do_cop1;

    case SWC132:

        mips32_op = OPC_SWC1;

        goto do_cop1;

    case SDC132:

        mips32_op = OPC_SDC1;

    do_cop1:

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

        break;

    case ADDIUPC:

        {

            int reg = mmreg(ZIMM(ctx->opcode, 23, 3));

            int offset = SIMM(ctx->opcode, 0, 23) << 2;



            gen_addiupc(ctx, reg, offset, 0, 0);

        }

        break;

        /* Loads and stores */

    case LB32:

        mips32_op = OPC_LB;

        goto do_ld;

    case LBU32:

        mips32_op = OPC_LBU;

        goto do_ld;

    case LH32:

        mips32_op = OPC_LH;

        goto do_ld;

    case LHU32:

        mips32_op = OPC_LHU;

        goto do_ld;

    case LW32:

        mips32_op = OPC_LW;

        goto do_ld;

#ifdef TARGET_MIPS64

    case LD32:

        mips32_op = OPC_LD;

        goto do_ld;

    case SD32:

        mips32_op = OPC_SD;

        goto do_st;

#endif

    case SB32:

        mips32_op = OPC_SB;

        goto do_st;

    case SH32:

        mips32_op = OPC_SH;

        goto do_st;

    case SW32:

        mips32_op = OPC_SW;

        goto do_st;

    do_ld:

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

        break;

    do_st:

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

        break;

    default:

        generate_exception(ctx, EXCP_RI);

        break;

    }

}
