static void disas_arm_insn(CPUARMState * env, DisasContext *s)

{

    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;

    TCGv_i32 tmp;

    TCGv_i32 tmp2;

    TCGv_i32 tmp3;

    TCGv_i32 addr;

    TCGv_i64 tmp64;

    insn = arm_ldl_code(env, s->pc, s->bswap_code);

    s->pc += 4;

    /* M variants do not implement ARM mode.  */

    if (IS_M(env))

        goto illegal_op;

    cond = insn >> 28;

    if (cond == 0xf){

        /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we

         * choose to UNDEF. In ARMv5 and above the space is used

         * for miscellaneous unconditional instructions.

         */

        ARCH(5);

        /* Unconditional instructions.  */

        if (((insn >> 25) & 7) == 1) {

            /* NEON Data processing.  */

            if (!arm_feature(env, ARM_FEATURE_NEON))

                goto illegal_op;

            if (disas_neon_data_insn(env, s, insn))

                goto illegal_op;

            return;

        }

        if ((insn & 0x0f100000) == 0x04000000) {

            /* NEON load/store.  */

            if (!arm_feature(env, ARM_FEATURE_NEON))

                goto illegal_op;

            if (disas_neon_ls_insn(env, s, insn))

                goto illegal_op;

            return;

        }

        if ((insn & 0x0f000e10) == 0x0e000a00) {

            /* VFP.  */

            if (disas_vfp_insn(env, s, insn)) {

                goto illegal_op;

            }

            return;

        }

        if (((insn & 0x0f30f000) == 0x0510f000) ||

            ((insn & 0x0f30f010) == 0x0710f000)) {

            if ((insn & (1 << 22)) == 0) {

                /* PLDW; v7MP */

                if (!arm_feature(env, ARM_FEATURE_V7MP)) {

                    goto illegal_op;

                }

            }

            /* Otherwise PLD; v5TE+ */

            ARCH(5TE);

            return;

        }

        if (((insn & 0x0f70f000) == 0x0450f000) ||

            ((insn & 0x0f70f010) == 0x0650f000)) {

            ARCH(7);

            return; /* PLI; V7 */

        }

        if (((insn & 0x0f700000) == 0x04100000) ||

            ((insn & 0x0f700010) == 0x06100000)) {

            if (!arm_feature(env, ARM_FEATURE_V7MP)) {

                goto illegal_op;

            }

            return; /* v7MP: Unallocated memory hint: must NOP */

        }

        if ((insn & 0x0ffffdff) == 0x01010000) {

            ARCH(6);

            /* setend */

            if (((insn >> 9) & 1) != s->bswap_code) {

                /* Dynamic endianness switching not implemented. */

                qemu_log_mask(LOG_UNIMP, "arm: unimplemented setend\n");

                goto illegal_op;

            }

            return;

        } else if ((insn & 0x0fffff00) == 0x057ff000) {

            switch ((insn >> 4) & 0xf) {

            case 1: /* clrex */

                ARCH(6K);

                gen_clrex(s);

                return;

            case 4: /* dsb */

            case 5: /* dmb */

            case 6: /* isb */

                ARCH(7);

                /* We don't emulate caches so these are a no-op.  */

                return;

            default:

                goto illegal_op;

            }

        } else if ((insn & 0x0e5fffe0) == 0x084d0500) {

            /* srs */

            if (IS_USER(s)) {

                goto illegal_op;

            }

            ARCH(6);

            gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));

            return;

        } else if ((insn & 0x0e50ffe0) == 0x08100a00) {

            /* rfe */

            int32_t offset;

            if (IS_USER(s))

                goto illegal_op;

            ARCH(6);

            rn = (insn >> 16) & 0xf;

            addr = load_reg(s, rn);

            i = (insn >> 23) & 3;

            switch (i) {

            case 0: offset = -4; break; /* DA */

            case 1: offset = 0; break; /* IA */

            case 2: offset = -8; break; /* DB */

            case 3: offset = 4; break; /* IB */

            default: abort();

            }

            if (offset)

                tcg_gen_addi_i32(addr, addr, offset);

            /* Load PC into tmp and CPSR into tmp2.  */

            tmp = tcg_temp_new_i32();

            gen_aa32_ld32u(tmp, addr, 0);

            tcg_gen_addi_i32(addr, addr, 4);

            tmp2 = tcg_temp_new_i32();

            gen_aa32_ld32u(tmp2, addr, 0);

            if (insn & (1 << 21)) {

                /* Base writeback.  */

                switch (i) {

                case 0: offset = -8; break;

                case 1: offset = 4; break;

                case 2: offset = -4; break;

                case 3: offset = 0; break;

                default: abort();

                }

                if (offset)

                    tcg_gen_addi_i32(addr, addr, offset);

                store_reg(s, rn, addr);

            } else {

                tcg_temp_free_i32(addr);

            }

            gen_rfe(s, tmp, tmp2);

            return;

        } else if ((insn & 0x0e000000) == 0x0a000000) {

            /* branch link and change to thumb (blx <offset>) */

            int32_t offset;

            val = (uint32_t)s->pc;

            tmp = tcg_temp_new_i32();

            tcg_gen_movi_i32(tmp, val);

            store_reg(s, 14, tmp);

            /* Sign-extend the 24-bit offset */

            offset = (((int32_t)insn) << 8) >> 8;

            /* offset * 4 + bit24 * 2 + (thumb bit) */

            val += (offset << 2) | ((insn >> 23) & 2) | 1;

            /* pipeline offset */

            val += 4;

            /* protected by ARCH(5); above, near the start of uncond block */

            gen_bx_im(s, val);

            return;

        } else if ((insn & 0x0e000f00) == 0x0c000100) {

            if (arm_feature(env, ARM_FEATURE_IWMMXT)) {

                /* iWMMXt register transfer.  */

                if (env->cp15.c15_cpar & (1 << 1))

                    if (!disas_iwmmxt_insn(env, s, insn))

                        return;

            }

        } else if ((insn & 0x0fe00000) == 0x0c400000) {

            /* Coprocessor double register transfer.  */

            ARCH(5TE);

        } else if ((insn & 0x0f000010) == 0x0e000010) {

            /* Additional coprocessor register transfer.  */

        } else if ((insn & 0x0ff10020) == 0x01000000) {

            uint32_t mask;

            uint32_t val;

            /* cps (privileged) */

            if (IS_USER(s))

                return;

            mask = val = 0;

            if (insn & (1 << 19)) {

                if (insn & (1 << 8))

                    mask |= CPSR_A;

                if (insn & (1 << 7))

                    mask |= CPSR_I;

                if (insn & (1 << 6))

                    mask |= CPSR_F;

                if (insn & (1 << 18))

                    val |= mask;

            }

            if (insn & (1 << 17)) {

                mask |= CPSR_M;

                val |= (insn & 0x1f);

            }

            if (mask) {

                gen_set_psr_im(s, mask, 0, val);

            }

            return;

        }

        goto illegal_op;

    }

    if (cond != 0xe) {

        /* if not always execute, we generate a conditional jump to

           next instruction */

        s->condlabel = gen_new_label();

        arm_gen_test_cc(cond ^ 1, s->condlabel);

        s->condjmp = 1;

    }

    if ((insn & 0x0f900000) == 0x03000000) {

        if ((insn & (1 << 21)) == 0) {

            ARCH(6T2);

            rd = (insn >> 12) & 0xf;

            val = ((insn >> 4) & 0xf000) | (insn & 0xfff);

            if ((insn & (1 << 22)) == 0) {

                /* MOVW */

                tmp = tcg_temp_new_i32();

                tcg_gen_movi_i32(tmp, val);

            } else {

                /* MOVT */

                tmp = load_reg(s, rd);

                tcg_gen_ext16u_i32(tmp, tmp);

                tcg_gen_ori_i32(tmp, tmp, val << 16);

            }

            store_reg(s, rd, tmp);

        } else {

            if (((insn >> 12) & 0xf) != 0xf)

                goto illegal_op;

            if (((insn >> 16) & 0xf) == 0) {

                gen_nop_hint(s, insn & 0xff);

            } else {

                /* CPSR = immediate */

                val = insn & 0xff;

                shift = ((insn >> 8) & 0xf) * 2;

                if (shift)

                    val = (val >> shift) | (val << (32 - shift));

                i = ((insn & (1 << 22)) != 0);

                if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val))

                    goto illegal_op;

            }

        }

    } else if ((insn & 0x0f900000) == 0x01000000

               && (insn & 0x00000090) != 0x00000090) {

        /* miscellaneous instructions */

        op1 = (insn >> 21) & 3;

        sh = (insn >> 4) & 0xf;

        rm = insn & 0xf;

        switch (sh) {

        case 0x0: /* move program status register */

            if (op1 & 1) {

                /* PSR = reg */

                tmp = load_reg(s, rm);

                i = ((op1 & 2) != 0);

                if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp))

                    goto illegal_op;

            } else {

                /* reg = PSR */

                rd = (insn >> 12) & 0xf;

                if (op1 & 2) {

                    if (IS_USER(s))

                        goto illegal_op;

                    tmp = load_cpu_field(spsr);

                } else {

                    tmp = tcg_temp_new_i32();

                    gen_helper_cpsr_read(tmp, cpu_env);

                }

                store_reg(s, rd, tmp);

            }

            break;

        case 0x1:

            if (op1 == 1) {

                /* branch/exchange thumb (bx).  */

                ARCH(4T);

                tmp = load_reg(s, rm);

                gen_bx(s, tmp);

            } else if (op1 == 3) {

                /* clz */

                ARCH(5);

                rd = (insn >> 12) & 0xf;

                tmp = load_reg(s, rm);

                gen_helper_clz(tmp, tmp);

                store_reg(s, rd, tmp);

            } else {

                goto illegal_op;

            }

            break;

        case 0x2:

            if (op1 == 1) {

                ARCH(5J); /* bxj */

                /* Trivial implementation equivalent to bx.  */

                tmp = load_reg(s, rm);

                gen_bx(s, tmp);

            } else {

                goto illegal_op;

            }

            break;

        case 0x3:

            if (op1 != 1)

              goto illegal_op;

            ARCH(5);

            /* branch link/exchange thumb (blx) */

            tmp = load_reg(s, rm);

            tmp2 = tcg_temp_new_i32();

            tcg_gen_movi_i32(tmp2, s->pc);

            store_reg(s, 14, tmp2);

            gen_bx(s, tmp);

            break;

        case 0x4:

        {

            /* crc32/crc32c */

            uint32_t c = extract32(insn, 8, 4);

            /* Check this CPU supports ARMv8 CRC instructions.

             * op1 == 3 is UNPREDICTABLE but handle as UNDEFINED.

             * Bits 8, 10 and 11 should be zero.

             */

            if (!arm_feature(env, ARM_FEATURE_CRC) || op1 == 0x3 ||

                (c & 0xd) != 0) {

                goto illegal_op;

            }

            rn = extract32(insn, 16, 4);

            rd = extract32(insn, 12, 4);

            tmp = load_reg(s, rn);

            tmp2 = load_reg(s, rm);

            tmp3 = tcg_const_i32(1 << op1);

            if (c & 0x2) {

                gen_helper_crc32c(tmp, tmp, tmp2, tmp3);

            } else {

                gen_helper_crc32(tmp, tmp, tmp2, tmp3);

            }

            tcg_temp_free_i32(tmp2);

            tcg_temp_free_i32(tmp3);

            store_reg(s, rd, tmp);

            break;

        }

        case 0x5: /* saturating add/subtract */

            ARCH(5TE);

            rd = (insn >> 12) & 0xf;

            rn = (insn >> 16) & 0xf;

            tmp = load_reg(s, rm);

            tmp2 = load_reg(s, rn);

            if (op1 & 2)

                gen_helper_double_saturate(tmp2, cpu_env, tmp2);

            if (op1 & 1)

                gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2);

            else

                gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);

            tcg_temp_free_i32(tmp2);

            store_reg(s, rd, tmp);

            break;

        case 7:

        {

            int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);

            /* SMC instruction (op1 == 3)

               and undefined instructions (op1 == 0 || op1 == 2)

               will trap */

            if (op1 != 1) {

                goto illegal_op;

            }

            /* bkpt */

            ARCH(5);

            gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false));

            break;

        }

        case 0x8: /* signed multiply */

        case 0xa:

        case 0xc:

        case 0xe:

            ARCH(5TE);

            rs = (insn >> 8) & 0xf;

            rn = (insn >> 12) & 0xf;

            rd = (insn >> 16) & 0xf;

            if (op1 == 1) {

                /* (32 * 16) >> 16 */

                tmp = load_reg(s, rm);

                tmp2 = load_reg(s, rs);

                if (sh & 4)

                    tcg_gen_sari_i32(tmp2, tmp2, 16);

                else

                    gen_sxth(tmp2);

                tmp64 = gen_muls_i64_i32(tmp, tmp2);

                tcg_gen_shri_i64(tmp64, tmp64, 16);

                tmp = tcg_temp_new_i32();

                tcg_gen_trunc_i64_i32(tmp, tmp64);

                tcg_temp_free_i64(tmp64);

                if ((sh & 2) == 0) {

                    tmp2 = load_reg(s, rn);

                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                }

                store_reg(s, rd, tmp);

            } else {

                /* 16 * 16 */

                tmp = load_reg(s, rm);

                tmp2 = load_reg(s, rs);

                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);

                tcg_temp_free_i32(tmp2);

                if (op1 == 2) {

                    tmp64 = tcg_temp_new_i64();

                    tcg_gen_ext_i32_i64(tmp64, tmp);

                    tcg_temp_free_i32(tmp);

                    gen_addq(s, tmp64, rn, rd);

                    gen_storeq_reg(s, rn, rd, tmp64);

                    tcg_temp_free_i64(tmp64);

                } else {

                    if (op1 == 0) {

                        tmp2 = load_reg(s, rn);

                        gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                    }

                    store_reg(s, rd, tmp);

                }

            }

            break;

        default:

            goto illegal_op;

        }

    } else if (((insn & 0x0e000000) == 0 &&

                (insn & 0x00000090) != 0x90) ||

               ((insn & 0x0e000000) == (1 << 25))) {

        int set_cc, logic_cc, shiftop;

        op1 = (insn >> 21) & 0xf;

        set_cc = (insn >> 20) & 1;

        logic_cc = table_logic_cc[op1] & set_cc;

        /* data processing instruction */

        if (insn & (1 << 25)) {

            /* immediate operand */

            val = insn & 0xff;

            shift = ((insn >> 8) & 0xf) * 2;

            if (shift) {

                val = (val >> shift) | (val << (32 - shift));

            }

            tmp2 = tcg_temp_new_i32();

            tcg_gen_movi_i32(tmp2, val);

            if (logic_cc && shift) {

                gen_set_CF_bit31(tmp2);

            }

        } else {

            /* register */

            rm = (insn) & 0xf;

            tmp2 = load_reg(s, rm);

            shiftop = (insn >> 5) & 3;

            if (!(insn & (1 << 4))) {

                shift = (insn >> 7) & 0x1f;

                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);

            } else {

                rs = (insn >> 8) & 0xf;

                tmp = load_reg(s, rs);

                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);

            }

        }

        if (op1 != 0x0f && op1 != 0x0d) {

            rn = (insn >> 16) & 0xf;

            tmp = load_reg(s, rn);

        } else {

            TCGV_UNUSED_I32(tmp);

        }

        rd = (insn >> 12) & 0xf;

        switch(op1) {

        case 0x00:

            tcg_gen_and_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x01:

            tcg_gen_xor_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x02:

            if (set_cc && rd == 15) {

                /* SUBS r15, ... is used for exception return.  */

                if (IS_USER(s)) {

                    goto illegal_op;

                }

                gen_sub_CC(tmp, tmp, tmp2);

                gen_exception_return(s, tmp);

            } else {

                if (set_cc) {

                    gen_sub_CC(tmp, tmp, tmp2);

                } else {

                    tcg_gen_sub_i32(tmp, tmp, tmp2);

                }

                store_reg_bx(env, s, rd, tmp);

            }

            break;

        case 0x03:

            if (set_cc) {

                gen_sub_CC(tmp, tmp2, tmp);

            } else {

                tcg_gen_sub_i32(tmp, tmp2, tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x04:

            if (set_cc) {

                gen_add_CC(tmp, tmp, tmp2);

            } else {

                tcg_gen_add_i32(tmp, tmp, tmp2);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x05:

            if (set_cc) {

                gen_adc_CC(tmp, tmp, tmp2);

            } else {

                gen_add_carry(tmp, tmp, tmp2);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x06:

            if (set_cc) {

                gen_sbc_CC(tmp, tmp, tmp2);

            } else {

                gen_sub_carry(tmp, tmp, tmp2);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x07:

            if (set_cc) {

                gen_sbc_CC(tmp, tmp2, tmp);

            } else {

                gen_sub_carry(tmp, tmp2, tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x08:

            if (set_cc) {

                tcg_gen_and_i32(tmp, tmp, tmp2);

                gen_logic_CC(tmp);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x09:

            if (set_cc) {

                tcg_gen_xor_i32(tmp, tmp, tmp2);

                gen_logic_CC(tmp);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x0a:

            if (set_cc) {

                gen_sub_CC(tmp, tmp, tmp2);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x0b:

            if (set_cc) {

                gen_add_CC(tmp, tmp, tmp2);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x0c:

            tcg_gen_or_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x0d:

            if (logic_cc && rd == 15) {

                /* MOVS r15, ... is used for exception return.  */

                if (IS_USER(s)) {

                    goto illegal_op;

                }

                gen_exception_return(s, tmp2);

            } else {

                if (logic_cc) {

                    gen_logic_CC(tmp2);

                }

                store_reg_bx(env, s, rd, tmp2);

            }

            break;

        case 0x0e:

            tcg_gen_andc_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        default:

        case 0x0f:

            tcg_gen_not_i32(tmp2, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp2);

            }

            store_reg_bx(env, s, rd, tmp2);

            break;

        }

        if (op1 != 0x0f && op1 != 0x0d) {

            tcg_temp_free_i32(tmp2);

        }

    } else {

        /* other instructions */

        op1 = (insn >> 24) & 0xf;

        switch(op1) {

        case 0x0:

        case 0x1:

            /* multiplies, extra load/stores */

            sh = (insn >> 5) & 3;

            if (sh == 0) {

                if (op1 == 0x0) {

                    rd = (insn >> 16) & 0xf;

                    rn = (insn >> 12) & 0xf;

                    rs = (insn >> 8) & 0xf;

                    rm = (insn) & 0xf;

                    op1 = (insn >> 20) & 0xf;

                    switch (op1) {

                    case 0: case 1: case 2: case 3: case 6:

                        /* 32 bit mul */

                        tmp = load_reg(s, rs);

                        tmp2 = load_reg(s, rm);

                        tcg_gen_mul_i32(tmp, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        if (insn & (1 << 22)) {

                            /* Subtract (mls) */

                            ARCH(6T2);

                            tmp2 = load_reg(s, rn);

                            tcg_gen_sub_i32(tmp, tmp2, tmp);

                            tcg_temp_free_i32(tmp2);

                        } else if (insn & (1 << 21)) {

                            /* Add */

                            tmp2 = load_reg(s, rn);

                            tcg_gen_add_i32(tmp, tmp, tmp2);

                            tcg_temp_free_i32(tmp2);

                        }

                        if (insn & (1 << 20))

                            gen_logic_CC(tmp);

                        store_reg(s, rd, tmp);

                        break;

                    case 4:

                        /* 64 bit mul double accumulate (UMAAL) */

                        ARCH(6);

                        tmp = load_reg(s, rs);

                        tmp2 = load_reg(s, rm);

                        tmp64 = gen_mulu_i64_i32(tmp, tmp2);

                        gen_addq_lo(s, tmp64, rn);

                        gen_addq_lo(s, tmp64, rd);

                        gen_storeq_reg(s, rn, rd, tmp64);

                        tcg_temp_free_i64(tmp64);

                        break;

                    case 8: case 9: case 10: case 11:

                    case 12: case 13: case 14: case 15:

                        /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */

                        tmp = load_reg(s, rs);

                        tmp2 = load_reg(s, rm);

                        if (insn & (1 << 22)) {

                            tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);

                        } else {

                            tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);

                        }

                        if (insn & (1 << 21)) { /* mult accumulate */

                            TCGv_i32 al = load_reg(s, rn);

                            TCGv_i32 ah = load_reg(s, rd);

                            tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah);

                            tcg_temp_free_i32(al);

                            tcg_temp_free_i32(ah);

                        }

                        if (insn & (1 << 20)) {

                            gen_logicq_cc(tmp, tmp2);

                        }

                        store_reg(s, rn, tmp);

                        store_reg(s, rd, tmp2);

                        break;

                    default:

                        goto illegal_op;

                    }

                } else {

                    rn = (insn >> 16) & 0xf;

                    rd = (insn >> 12) & 0xf;

                    if (insn & (1 << 23)) {

                        /* load/store exclusive */

                        int op2 = (insn >> 8) & 3;

                        op1 = (insn >> 21) & 0x3;

                        switch (op2) {

                        case 0: /* lda/stl */

                            if (op1 == 1) {

                                goto illegal_op;

                            }

                            ARCH(8);

                            break;

                        case 1: /* reserved */

                            goto illegal_op;

                        case 2: /* ldaex/stlex */

                            ARCH(8);

                            break;

                        case 3: /* ldrex/strex */

                            if (op1) {

                                ARCH(6K);

                            } else {

                                ARCH(6);

                            }

                            break;

                        }

                        addr = tcg_temp_local_new_i32();

                        load_reg_var(s, addr, rn);

                        /* Since the emulation does not have barriers,

                           the acquire/release semantics need no special

                           handling */

                        if (op2 == 0) {

                            if (insn & (1 << 20)) {

                                tmp = tcg_temp_new_i32();

                                switch (op1) {

                                case 0: /* lda */

                                    gen_aa32_ld32u(tmp, addr, IS_USER(s));

                                    break;

                                case 2: /* ldab */

                                    gen_aa32_ld8u(tmp, addr, IS_USER(s));

                                    break;

                                case 3: /* ldah */

                                    gen_aa32_ld16u(tmp, addr, IS_USER(s));

                                    break;

                                default:

                                    abort();

                                }

                                store_reg(s, rd, tmp);

                            } else {

                                rm = insn & 0xf;

                                tmp = load_reg(s, rm);

                                switch (op1) {

                                case 0: /* stl */

                                    gen_aa32_st32(tmp, addr, IS_USER(s));

                                    break;

                                case 2: /* stlb */

                                    gen_aa32_st8(tmp, addr, IS_USER(s));

                                    break;

                                case 3: /* stlh */

                                    gen_aa32_st16(tmp, addr, IS_USER(s));

                                    break;

                                default:

                                    abort();

                                }

                                tcg_temp_free_i32(tmp);

                            }

                        } else if (insn & (1 << 20)) {

                            switch (op1) {

                            case 0: /* ldrex */

                                gen_load_exclusive(s, rd, 15, addr, 2);

                                break;

                            case 1: /* ldrexd */

                                gen_load_exclusive(s, rd, rd + 1, addr, 3);

                                break;

                            case 2: /* ldrexb */

                                gen_load_exclusive(s, rd, 15, addr, 0);

                                break;

                            case 3: /* ldrexh */

                                gen_load_exclusive(s, rd, 15, addr, 1);

                                break;

                            default:

                                abort();

                            }

                        } else {

                            rm = insn & 0xf;

                            switch (op1) {

                            case 0:  /*  strex */

                                gen_store_exclusive(s, rd, rm, 15, addr, 2);

                                break;

                            case 1: /*  strexd */

                                gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);

                                break;

                            case 2: /*  strexb */

                                gen_store_exclusive(s, rd, rm, 15, addr, 0);

                                break;

                            case 3: /* strexh */

                                gen_store_exclusive(s, rd, rm, 15, addr, 1);

                                break;

                            default:

                                abort();

                            }

                        }

                        tcg_temp_free_i32(addr);

                    } else {

                        /* SWP instruction */

                        rm = (insn) & 0xf;

                        /* ??? This is not really atomic.  However we know

                           we never have multiple CPUs running in parallel,

                           so it is good enough.  */

                        addr = load_reg(s, rn);

                        tmp = load_reg(s, rm);

                        tmp2 = tcg_temp_new_i32();

                        if (insn & (1 << 22)) {

                            gen_aa32_ld8u(tmp2, addr, IS_USER(s));

                            gen_aa32_st8(tmp, addr, IS_USER(s));

                        } else {

                            gen_aa32_ld32u(tmp2, addr, IS_USER(s));

                            gen_aa32_st32(tmp, addr, IS_USER(s));

                        }

                        tcg_temp_free_i32(tmp);

                        tcg_temp_free_i32(addr);

                        store_reg(s, rd, tmp2);

                    }

                }

            } else {

                int address_offset;

                int load;

                /* Misc load/store */

                rn = (insn >> 16) & 0xf;

                rd = (insn >> 12) & 0xf;

                addr = load_reg(s, rn);

                if (insn & (1 << 24))

                    gen_add_datah_offset(s, insn, 0, addr);

                address_offset = 0;

                if (insn & (1 << 20)) {

                    /* load */

                    tmp = tcg_temp_new_i32();

                    switch(sh) {

                    case 1:

                        gen_aa32_ld16u(tmp, addr, IS_USER(s));

                        break;

                    case 2:

                        gen_aa32_ld8s(tmp, addr, IS_USER(s));

                        break;

                    default:

                    case 3:

                        gen_aa32_ld16s(tmp, addr, IS_USER(s));

                        break;

                    }

                    load = 1;

                } else if (sh & 2) {

                    ARCH(5TE);

                    /* doubleword */

                    if (sh & 1) {

                        /* store */

                        tmp = load_reg(s, rd);

                        gen_aa32_st32(tmp, addr, IS_USER(s));

                        tcg_temp_free_i32(tmp);

                        tcg_gen_addi_i32(addr, addr, 4);

                        tmp = load_reg(s, rd + 1);

                        gen_aa32_st32(tmp, addr, IS_USER(s));

                        tcg_temp_free_i32(tmp);

                        load = 0;

                    } else {

                        /* load */

                        tmp = tcg_temp_new_i32();

                        gen_aa32_ld32u(tmp, addr, IS_USER(s));

                        store_reg(s, rd, tmp);

                        tcg_gen_addi_i32(addr, addr, 4);

                        tmp = tcg_temp_new_i32();

                        gen_aa32_ld32u(tmp, addr, IS_USER(s));

                        rd++;

                        load = 1;

                    }

                    address_offset = -4;

                } else {

                    /* store */

                    tmp = load_reg(s, rd);

                    gen_aa32_st16(tmp, addr, IS_USER(s));

                    tcg_temp_free_i32(tmp);

                    load = 0;

                }

                /* Perform base writeback before the loaded value to

                   ensure correct behavior with overlapping index registers.

                   ldrd with base writeback is is undefined if the

                   destination and index registers overlap.  */

                if (!(insn & (1 << 24))) {

                    gen_add_datah_offset(s, insn, address_offset, addr);

                    store_reg(s, rn, addr);

                } else if (insn & (1 << 21)) {

                    if (address_offset)

                        tcg_gen_addi_i32(addr, addr, address_offset);

                    store_reg(s, rn, addr);

                } else {

                    tcg_temp_free_i32(addr);

                }

                if (load) {

                    /* Complete the load.  */

                    store_reg(s, rd, tmp);

                }

            }

            break;

        case 0x4:

        case 0x5:

            goto do_ldst;

        case 0x6:

        case 0x7:

            if (insn & (1 << 4)) {

                ARCH(6);

                /* Armv6 Media instructions.  */

                rm = insn & 0xf;

                rn = (insn >> 16) & 0xf;

                rd = (insn >> 12) & 0xf;

                rs = (insn >> 8) & 0xf;

                switch ((insn >> 23) & 3) {

                case 0: /* Parallel add/subtract.  */

                    op1 = (insn >> 20) & 7;

                    tmp = load_reg(s, rn);

                    tmp2 = load_reg(s, rm);

                    sh = (insn >> 5) & 7;

                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)

                        goto illegal_op;

                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                    store_reg(s, rd, tmp);

                    break;

                case 1:

                    if ((insn & 0x00700020) == 0) {

                        /* Halfword pack.  */

                        tmp = load_reg(s, rn);

                        tmp2 = load_reg(s, rm);

                        shift = (insn >> 7) & 0x1f;

                        if (insn & (1 << 6)) {

                            /* pkhtb */

                            if (shift == 0)

                                shift = 31;

                            tcg_gen_sari_i32(tmp2, tmp2, shift);

                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);

                            tcg_gen_ext16u_i32(tmp2, tmp2);

                        } else {

                            /* pkhbt */

                            if (shift)

                                tcg_gen_shli_i32(tmp2, tmp2, shift);

                            tcg_gen_ext16u_i32(tmp, tmp);

                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);

                        }

                        tcg_gen_or_i32(tmp, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

                    } else if ((insn & 0x00200020) == 0x00200000) {

                        /* [us]sat */

                        tmp = load_reg(s, rm);

                        shift = (insn >> 7) & 0x1f;

                        if (insn & (1 << 6)) {

                            if (shift == 0)

                                shift = 31;

                            tcg_gen_sari_i32(tmp, tmp, shift);

                        } else {

                            tcg_gen_shli_i32(tmp, tmp, shift);

                        }

                        sh = (insn >> 16) & 0x1f;

                        tmp2 = tcg_const_i32(sh);

                        if (insn & (1 << 22))

                          gen_helper_usat(tmp, cpu_env, tmp, tmp2);

                        else

                          gen_helper_ssat(tmp, cpu_env, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

                    } else if ((insn & 0x00300fe0) == 0x00200f20) {

                        /* [us]sat16 */

                        tmp = load_reg(s, rm);

                        sh = (insn >> 16) & 0x1f;

                        tmp2 = tcg_const_i32(sh);

                        if (insn & (1 << 22))

                          gen_helper_usat16(tmp, cpu_env, tmp, tmp2);

                        else

                          gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {

                        /* Select bytes.  */

                        tmp = load_reg(s, rn);

                        tmp2 = load_reg(s, rm);

                        tmp3 = tcg_temp_new_i32();

                        tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));

                        gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);

                        tcg_temp_free_i32(tmp3);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

                    } else if ((insn & 0x000003e0) == 0x00000060) {

                        tmp = load_reg(s, rm);

                        shift = (insn >> 10) & 3;

                        /* ??? In many cases it's not necessary to do a

                           rotate, a shift is sufficient.  */

                        if (shift != 0)

                            tcg_gen_rotri_i32(tmp, tmp, shift * 8);

                        op1 = (insn >> 20) & 7;

                        switch (op1) {

                        case 0: gen_sxtb16(tmp);  break;

                        case 2: gen_sxtb(tmp);    break;

                        case 3: gen_sxth(tmp);    break;

                        case 4: gen_uxtb16(tmp);  break;

                        case 6: gen_uxtb(tmp);    break;

                        case 7: gen_uxth(tmp);    break;

                        default: goto illegal_op;

                        }

                        if (rn != 15) {

                            tmp2 = load_reg(s, rn);

                            if ((op1 & 3) == 0) {

                                gen_add16(tmp, tmp2);

                            } else {

                                tcg_gen_add_i32(tmp, tmp, tmp2);

                                tcg_temp_free_i32(tmp2);

                            }

                        }

                        store_reg(s, rd, tmp);

                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {

                        /* rev */

                        tmp = load_reg(s, rm);

                        if (insn & (1 << 22)) {

                            if (insn & (1 << 7)) {

                                gen_revsh(tmp);

                            } else {

                                ARCH(6T2);

                                gen_helper_rbit(tmp, tmp);

                            }

                        } else {

                            if (insn & (1 << 7))

                                gen_rev16(tmp);

                            else

                                tcg_gen_bswap32_i32(tmp, tmp);

                        }

                        store_reg(s, rd, tmp);

                    } else {

                        goto illegal_op;

                    }

                    break;

                case 2: /* Multiplies (Type 3).  */

                    switch ((insn >> 20) & 0x7) {

                    case 5:

                        if (((insn >> 6) ^ (insn >> 7)) & 1) {

                            /* op2 not 00x or 11x : UNDEF */

                            goto illegal_op;

                        }

                        /* Signed multiply most significant [accumulate].

                           (SMMUL, SMMLA, SMMLS) */

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

                        tmp64 = gen_muls_i64_i32(tmp, tmp2);

                        if (rd != 15) {

                            tmp = load_reg(s, rd);

                            if (insn & (1 << 6)) {

                                tmp64 = gen_subq_msw(tmp64, tmp);

                            } else {

                                tmp64 = gen_addq_msw(tmp64, tmp);

                            }

                        }

                        if (insn & (1 << 5)) {

                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);

                        }

                        tcg_gen_shri_i64(tmp64, tmp64, 32);

                        tmp = tcg_temp_new_i32();

                        tcg_gen_trunc_i64_i32(tmp, tmp64);

                        tcg_temp_free_i64(tmp64);

                        store_reg(s, rn, tmp);

                        break;

                    case 0:

                    case 4:

                        /* SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD */

                        if (insn & (1 << 7)) {

                            goto illegal_op;

                        }

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

                        if (insn & (1 << 5))

                            gen_swap_half(tmp2);

                        gen_smul_dual(tmp, tmp2);

                        if (insn & (1 << 6)) {

                            /* This subtraction cannot overflow. */

                            tcg_gen_sub_i32(tmp, tmp, tmp2);

                        } else {

                            /* This addition cannot overflow 32 bits;

                             * however it may overflow considered as a signed

                             * operation, in which case we must set the Q flag.

                             */

                            gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                        }

                        tcg_temp_free_i32(tmp2);

                        if (insn & (1 << 22)) {

                            /* smlald, smlsld */

                            tmp64 = tcg_temp_new_i64();

                            tcg_gen_ext_i32_i64(tmp64, tmp);

                            tcg_temp_free_i32(tmp);

                            gen_addq(s, tmp64, rd, rn);

                            gen_storeq_reg(s, rd, rn, tmp64);

                            tcg_temp_free_i64(tmp64);

                        } else {

                            /* smuad, smusd, smlad, smlsd */

                            if (rd != 15)

                              {

                                tmp2 = load_reg(s, rd);

                                gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                                tcg_temp_free_i32(tmp2);

                              }

                            store_reg(s, rn, tmp);

                        }

                        break;

                    case 1:

                    case 3:

                        /* SDIV, UDIV */

                        if (!arm_feature(env, ARM_FEATURE_ARM_DIV)) {

                            goto illegal_op;

                        }

                        if (((insn >> 5) & 7) || (rd != 15)) {

                            goto illegal_op;

                        }

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

                        if (insn & (1 << 21)) {

                            gen_helper_udiv(tmp, tmp, tmp2);

                        } else {

                            gen_helper_sdiv(tmp, tmp, tmp2);

                        }

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rn, tmp);

                        break;

                    default:

                        goto illegal_op;

                    }

                    break;

                case 3:

                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);

                    switch (op1) {

                    case 0: /* Unsigned sum of absolute differences.  */

                        ARCH(6);

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

                        gen_helper_usad8(tmp, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        if (rd != 15) {

                            tmp2 = load_reg(s, rd);

                            tcg_gen_add_i32(tmp, tmp, tmp2);

                            tcg_temp_free_i32(tmp2);

                        }

                        store_reg(s, rn, tmp);

                        break;

                    case 0x20: case 0x24: case 0x28: case 0x2c:

                        /* Bitfield insert/clear.  */

                        ARCH(6T2);

                        shift = (insn >> 7) & 0x1f;

                        i = (insn >> 16) & 0x1f;

                        i = i + 1 - shift;

                        if (rm == 15) {

                            tmp = tcg_temp_new_i32();

                            tcg_gen_movi_i32(tmp, 0);

                        } else {

                            tmp = load_reg(s, rm);

                        }

                        if (i != 32) {

                            tmp2 = load_reg(s, rd);

                            tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i);

                            tcg_temp_free_i32(tmp2);

                        }

                        store_reg(s, rd, tmp);

                        break;

                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */

                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */

                        ARCH(6T2);

                        tmp = load_reg(s, rm);

                        shift = (insn >> 7) & 0x1f;

                        i = ((insn >> 16) & 0x1f) + 1;

                        if (shift + i > 32)

                            goto illegal_op;

                        if (i < 32) {

                            if (op1 & 0x20) {

                                gen_ubfx(tmp, shift, (1u << i) - 1);

                            } else {

                                gen_sbfx(tmp, shift, i);

                            }

                        }

                        store_reg(s, rd, tmp);

                        break;

                    default:

                        goto illegal_op;

                    }

                    break;

                }

                break;

            }

        do_ldst:

            /* Check for undefined extension instructions

             * per the ARM Bible IE:

             * xxxx 0111 1111 xxxx  xxxx xxxx 1111 xxxx

             */

            sh = (0xf << 20) | (0xf << 4);

            if (op1 == 0x7 && ((insn & sh) == sh))

            {

                goto illegal_op;

            }

            /* load/store byte/word */

            rn = (insn >> 16) & 0xf;

            rd = (insn >> 12) & 0xf;

            tmp2 = load_reg(s, rn);

            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);

            if (insn & (1 << 24))

                gen_add_data_offset(s, insn, tmp2);

            if (insn & (1 << 20)) {

                /* load */

                tmp = tcg_temp_new_i32();

                if (insn & (1 << 22)) {

                    gen_aa32_ld8u(tmp, tmp2, i);

                } else {

                    gen_aa32_ld32u(tmp, tmp2, i);

                }

            } else {

                /* store */

                tmp = load_reg(s, rd);

                if (insn & (1 << 22)) {

                    gen_aa32_st8(tmp, tmp2, i);

                } else {

                    gen_aa32_st32(tmp, tmp2, i);

                }

                tcg_temp_free_i32(tmp);

            }

            if (!(insn & (1 << 24))) {

                gen_add_data_offset(s, insn, tmp2);

                store_reg(s, rn, tmp2);

            } else if (insn & (1 << 21)) {

                store_reg(s, rn, tmp2);

            } else {

                tcg_temp_free_i32(tmp2);

            }

            if (insn & (1 << 20)) {

                /* Complete the load.  */

                store_reg_from_load(env, s, rd, tmp);

            }

            break;

        case 0x08:

        case 0x09:

            {

                int j, n, user, loaded_base;

                TCGv_i32 loaded_var;

                /* load/store multiple words */

                /* XXX: store correct base if write back */

                user = 0;

                if (insn & (1 << 22)) {

                    if (IS_USER(s))

                        goto illegal_op; /* only usable in supervisor mode */

                    if ((insn & (1 << 15)) == 0)

                        user = 1;

                }

                rn = (insn >> 16) & 0xf;

                addr = load_reg(s, rn);

                /* compute total size */

                loaded_base = 0;

                TCGV_UNUSED_I32(loaded_var);

                n = 0;

                for(i=0;i<16;i++) {

                    if (insn & (1 << i))

                        n++;

                }

                /* XXX: test invalid n == 0 case ? */

                if (insn & (1 << 23)) {

                    if (insn & (1 << 24)) {

                        /* pre increment */

                        tcg_gen_addi_i32(addr, addr, 4);

                    } else {

                        /* post increment */

                    }

                } else {

                    if (insn & (1 << 24)) {

                        /* pre decrement */

                        tcg_gen_addi_i32(addr, addr, -(n * 4));

                    } else {

                        /* post decrement */

                        if (n != 1)

                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));

                    }

                }

                j = 0;

                for(i=0;i<16;i++) {

                    if (insn & (1 << i)) {

                        if (insn & (1 << 20)) {

                            /* load */

                            tmp = tcg_temp_new_i32();

                            gen_aa32_ld32u(tmp, addr, IS_USER(s));

                            if (user) {

                                tmp2 = tcg_const_i32(i);

                                gen_helper_set_user_reg(cpu_env, tmp2, tmp);

                                tcg_temp_free_i32(tmp2);

                                tcg_temp_free_i32(tmp);

                            } else if (i == rn) {

                                loaded_var = tmp;

                                loaded_base = 1;

                            } else {

                                store_reg_from_load(env, s, i, tmp);

                            }

                        } else {

                            /* store */

                            if (i == 15) {

                                /* special case: r15 = PC + 8 */

                                val = (long)s->pc + 4;

                                tmp = tcg_temp_new_i32();

                                tcg_gen_movi_i32(tmp, val);

                            } else if (user) {

                                tmp = tcg_temp_new_i32();

                                tmp2 = tcg_const_i32(i);

                                gen_helper_get_user_reg(tmp, cpu_env, tmp2);

                                tcg_temp_free_i32(tmp2);

                            } else {

                                tmp = load_reg(s, i);

                            }

                            gen_aa32_st32(tmp, addr, IS_USER(s));

                            tcg_temp_free_i32(tmp);

                        }

                        j++;

                        /* no need to add after the last transfer */

                        if (j != n)

                            tcg_gen_addi_i32(addr, addr, 4);

                    }

                }

                if (insn & (1 << 21)) {

                    /* write back */

                    if (insn & (1 << 23)) {

                        if (insn & (1 << 24)) {

                            /* pre increment */

                        } else {

                            /* post increment */

                            tcg_gen_addi_i32(addr, addr, 4);

                        }

                    } else {

                        if (insn & (1 << 24)) {

                            /* pre decrement */

                            if (n != 1)

                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));

                        } else {

                            /* post decrement */

                            tcg_gen_addi_i32(addr, addr, -(n * 4));

                        }

                    }

                    store_reg(s, rn, addr);

                } else {

                    tcg_temp_free_i32(addr);

                }

                if (loaded_base) {

                    store_reg(s, rn, loaded_var);

                }

                if ((insn & (1 << 22)) && !user) {

                    /* Restore CPSR from SPSR.  */

                    tmp = load_cpu_field(spsr);

                    gen_set_cpsr(tmp, 0xffffffff);

                    tcg_temp_free_i32(tmp);

                    s->is_jmp = DISAS_UPDATE;

                }

            }

            break;

        case 0xa:

        case 0xb:

            {

                int32_t offset;

                /* branch (and link) */

                val = (int32_t)s->pc;

                if (insn & (1 << 24)) {

                    tmp = tcg_temp_new_i32();

                    tcg_gen_movi_i32(tmp, val);

                    store_reg(s, 14, tmp);

                }

                offset = sextract32(insn << 2, 0, 26);

                val += offset + 4;

                gen_jmp(s, val);

            }

            break;

        case 0xc:

        case 0xd:

        case 0xe:

            if (((insn >> 8) & 0xe) == 10) {

                /* VFP.  */

                if (disas_vfp_insn(env, s, insn)) {

                    goto illegal_op;

                }

            } else if (disas_coproc_insn(env, s, insn)) {

                /* Coprocessor.  */

                goto illegal_op;

            }

            break;

        case 0xf:

            /* swi */

            gen_set_pc_im(s, s->pc);

            s->svc_imm = extract32(insn, 0, 24);

            s->is_jmp = DISAS_SWI;

            break;

        default:

        illegal_op:

            gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());

            break;

        }

    }

}


int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,

                  target_ulong *raddr, int *flags, bool exc)

{

    int r = -1;

    uint8_t *sk;

    *flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;

    vaddr &= TARGET_PAGE_MASK;

    if (!(env->psw.mask & PSW_MASK_DAT)) {

        *raddr = vaddr;

        r = 0;

        goto out;

    }

    switch (asc) {

    case PSW_ASC_PRIMARY:

        PTE_DPRINTF("%s: asc=primary\n", __func__);

        r = mmu_translate_asce(env, vaddr, asc, env->cregs[1], raddr, flags,

                               rw, exc);

        break;

    case PSW_ASC_HOME:

        PTE_DPRINTF("%s: asc=home\n", __func__);

        r = mmu_translate_asce(env, vaddr, asc, env->cregs[13], raddr, flags,

                               rw, exc);

        break;

    case PSW_ASC_SECONDARY:

        PTE_DPRINTF("%s: asc=secondary\n", __func__);

        /*

         * Instruction: Primary

         * Data: Secondary

         */

        if (rw == MMU_INST_FETCH) {

            r = mmu_translate_asce(env, vaddr, PSW_ASC_PRIMARY, env->cregs[1],

                                   raddr, flags, rw, exc);

            *flags &= ~(PAGE_READ | PAGE_WRITE);

        } else {

            r = mmu_translate_asce(env, vaddr, PSW_ASC_SECONDARY, env->cregs[7],

                                   raddr, flags, rw, exc);

            *flags &= ~(PAGE_EXEC);

        }

        break;

    case PSW_ASC_ACCREG:

    default:

        hw_error("guest switched to unknown asc mode\n");

        break;

    }

 out:

    /* Convert real address -> absolute address */

    *raddr = mmu_real2abs(env, *raddr);

    if (*raddr <= ram_size) {

        sk = &env->storage_keys[*raddr / TARGET_PAGE_SIZE];

        if (*flags & PAGE_READ) {

            *sk |= SK_R;

        }

        if (*flags & PAGE_WRITE) {

            *sk |= SK_C;

        }

    }

    return r;

}


static void adb_mouse_initfn(Object *obj)

{

    ADBDevice *d = ADB_DEVICE(obj);

    d->devaddr = ADB_DEVID_MOUSE;

}


int ff_raw_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
    AVStream *st;
    enum CodecID id;
    st = avformat_new_stream(s, NULL);
    if (!st)
        return AVERROR(ENOMEM);
        id = s->iformat->value;
        if (id == CODEC_ID_RAWVIDEO) {
            st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
        } else {
            st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
        st->codec->codec_id = id;
        switch(st->codec->codec_type) {
        case AVMEDIA_TYPE_AUDIO: {
            RawAudioDemuxerContext *s1 = s->priv_data;
            st->codec->channels = 1;
            if (id == CODEC_ID_ADPCM_G722)
                st->codec->sample_rate = 16000;
            if (s1 && s1->sample_rate)
                st->codec->sample_rate = s1->sample_rate;
            if (s1 && s1->channels)
                st->codec->channels    = s1->channels;
            st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
            assert(st->codec->bits_per_coded_sample > 0);
            st->codec->block_align = st->codec->bits_per_coded_sample*st->codec->channels/8;
            av_set_pts_info(st, 64, 1, st->codec->sample_rate);
            break;
        case AVMEDIA_TYPE_VIDEO: {
            FFRawVideoDemuxerContext *s1 = s->priv_data;
            int width = 0, height = 0, ret = 0;
            enum PixelFormat pix_fmt;
            AVRational framerate;
            if (s1->video_size && (ret = av_parse_video_size(&width, &height, s1->video_size)) < 0) {
                av_log(s, AV_LOG_ERROR, "Couldn't parse video size.\n");
                goto fail;
            if ((pix_fmt = av_get_pix_fmt(s1->pixel_format)) == PIX_FMT_NONE) {
                av_log(s, AV_LOG_ERROR, "No such pixel format: %s.\n", s1->pixel_format);
                ret = AVERROR(EINVAL);
                goto fail;
            if ((ret = av_parse_video_rate(&framerate, s1->framerate)) < 0) {
                av_log(s, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s1->framerate);
                goto fail;
            av_set_pts_info(st, 64, framerate.den, framerate.num);
            st->codec->width  = width;
            st->codec->height = height;
            st->codec->pix_fmt = pix_fmt;
fail:
            return ret;
        default:
            return -1;
    return 0;


e1000_mmio_map(PCIDevice *pci_dev, int region_num,
                uint32_t addr, uint32_t size, int type)
{
    E1000State *d = (E1000State *)pci_dev;
    DBGOUT(MMIO, "e1000_mmio_map addr=0x%08x 0x%08x\n", addr, size);
    cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
}


static av_cold int decode_init(AVCodecContext *avctx)

{

    WMAProDecodeCtx *s = avctx->priv_data;

    uint8_t *edata_ptr = avctx->extradata;

    unsigned int channel_mask;

    int i, bits;

    int log2_max_num_subframes;

    int num_possible_block_sizes;

    if (avctx->codec_id == AV_CODEC_ID_XMA1 || avctx->codec_id == AV_CODEC_ID_XMA2)

        avctx->block_align = 2048;

    if (!avctx->block_align) {

        av_log(avctx, AV_LOG_ERROR, "block_align is not set\n");

        return AVERROR(EINVAL);

    }

    s->avctx = avctx;

    s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT);

    if (!s->fdsp)

        return AVERROR(ENOMEM);

    init_put_bits(&s->pb, s->frame_data, MAX_FRAMESIZE);

    avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;

    if (avctx->codec_id == AV_CODEC_ID_XMA2 && avctx->extradata_size >= 34) {

        s->decode_flags    = 0x10d6;

        channel_mask       = AV_RL32(edata_ptr+2);

        s->bits_per_sample = 16;

        /** dump the extradata */

        for (i = 0; i < avctx->extradata_size; i++)

            ff_dlog(avctx, "[%x] ", avctx->extradata[i]);

        ff_dlog(avctx, "\n");

     } else if (avctx->codec_id == AV_CODEC_ID_XMA1 && avctx->extradata_size >= 28) {

        s->decode_flags    = 0x10d6;

        s->bits_per_sample = 16;

        channel_mask       = 0;

        /** dump the extradata */

        for (i = 0; i < avctx->extradata_size; i++)

            ff_dlog(avctx, "[%x] ", avctx->extradata[i]);

        ff_dlog(avctx, "\n");

     } else if (avctx->extradata_size >= 18) {

        s->decode_flags    = AV_RL16(edata_ptr+14);

        channel_mask       = AV_RL32(edata_ptr+2);

        s->bits_per_sample = AV_RL16(edata_ptr);

        /** dump the extradata */

        for (i = 0; i < avctx->extradata_size; i++)

            ff_dlog(avctx, "[%x] ", avctx->extradata[i]);

        ff_dlog(avctx, "\n");

    } else {

        avpriv_request_sample(avctx, "Unknown extradata size");

        return AVERROR_PATCHWELCOME;

    }

    if (avctx->codec_id != AV_CODEC_ID_WMAPRO && avctx->channels > 2) {

        avpriv_report_missing_feature(avctx, ">2 channels support");

        return AVERROR_PATCHWELCOME;

    }

    /** generic init */

    s->log2_frame_size = av_log2(avctx->block_align) + 4;

    if (s->log2_frame_size > 25) {

        avpriv_request_sample(avctx, "Large block align");

        return AVERROR_PATCHWELCOME;

    }

    /** frame info */

    if (avctx->codec_id != AV_CODEC_ID_WMAPRO)

        s->skip_frame = 0;

    else

        s->skip_frame = 1; /* skip first frame */

    s->packet_loss = 1;

    s->len_prefix  = (s->decode_flags & 0x40);

    /** get frame len */

    if (avctx->codec_id == AV_CODEC_ID_WMAPRO) {

        bits = ff_wma_get_frame_len_bits(avctx->sample_rate, 3, s->decode_flags);

        if (bits > WMAPRO_BLOCK_MAX_BITS) {

            avpriv_request_sample(avctx, "14-bit block sizes");

            return AVERROR_PATCHWELCOME;

        }

        s->samples_per_frame = 1 << bits;

    } else {

        s->samples_per_frame = 512;

    }

    /** subframe info */

    log2_max_num_subframes       = ((s->decode_flags & 0x38) >> 3);

    s->max_num_subframes         = 1 << log2_max_num_subframes;

    if (s->max_num_subframes == 16 || s->max_num_subframes == 4)

        s->max_subframe_len_bit = 1;

    s->subframe_len_bits = av_log2(log2_max_num_subframes) + 1;

    num_possible_block_sizes     = log2_max_num_subframes + 1;

    s->min_samples_per_subframe  = s->samples_per_frame / s->max_num_subframes;

    s->dynamic_range_compression = (s->decode_flags & 0x80);

    if (s->max_num_subframes > MAX_SUBFRAMES) {

        av_log(avctx, AV_LOG_ERROR, "invalid number of subframes %"PRId8"\n",

               s->max_num_subframes);

        return AVERROR_INVALIDDATA;

    }

    if (s->min_samples_per_subframe < WMAPRO_BLOCK_MIN_SIZE) {

        av_log(avctx, AV_LOG_ERROR, "min_samples_per_subframe of %d too small\n",

               s->min_samples_per_subframe);

        return AVERROR_INVALIDDATA;

    }

    if (s->avctx->sample_rate <= 0) {

        av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n");

        return AVERROR_INVALIDDATA;

    }

    if (avctx->channels < 0) {

        av_log(avctx, AV_LOG_ERROR, "invalid number of channels %d\n",

               avctx->channels);

        return AVERROR_INVALIDDATA;

    } else if (avctx->channels > WMAPRO_MAX_CHANNELS) {

        avpriv_request_sample(avctx,

                              "More than %d channels", WMAPRO_MAX_CHANNELS);

        return AVERROR_PATCHWELCOME;

    }

    /** init previous block len */

    for (i = 0; i < avctx->channels; i++)

        s->channel[i].prev_block_len = s->samples_per_frame;

    /** extract lfe channel position */

    s->lfe_channel = -1;

    if (channel_mask & 8) {

        unsigned int mask;

        for (mask = 1; mask < 16; mask <<= 1) {

            if (channel_mask & mask)

                ++s->lfe_channel;

        }

    }

    INIT_VLC_STATIC(&sf_vlc, SCALEVLCBITS, HUFF_SCALE_SIZE,

                    scale_huffbits, 1, 1,

                    scale_huffcodes, 2, 2, 616);

    INIT_VLC_STATIC(&sf_rl_vlc, VLCBITS, HUFF_SCALE_RL_SIZE,

                    scale_rl_huffbits, 1, 1,

                    scale_rl_huffcodes, 4, 4, 1406);

    INIT_VLC_STATIC(&coef_vlc[0], VLCBITS, HUFF_COEF0_SIZE,

                    coef0_huffbits, 1, 1,

                    coef0_huffcodes, 4, 4, 2108);

    INIT_VLC_STATIC(&coef_vlc[1], VLCBITS, HUFF_COEF1_SIZE,

                    coef1_huffbits, 1, 1,

                    coef1_huffcodes, 4, 4, 3912);

    INIT_VLC_STATIC(&vec4_vlc, VLCBITS, HUFF_VEC4_SIZE,

                    vec4_huffbits, 1, 1,

                    vec4_huffcodes, 2, 2, 604);

    INIT_VLC_STATIC(&vec2_vlc, VLCBITS, HUFF_VEC2_SIZE,

                    vec2_huffbits, 1, 1,

                    vec2_huffcodes, 2, 2, 562);

    INIT_VLC_STATIC(&vec1_vlc, VLCBITS, HUFF_VEC1_SIZE,

                    vec1_huffbits, 1, 1,

                    vec1_huffcodes, 2, 2, 562);

    /** calculate number of scale factor bands and their offsets

        for every possible block size */

    for (i = 0; i < num_possible_block_sizes; i++) {

        int subframe_len = s->samples_per_frame >> i;

        int x;

        int band = 1;

        int rate = get_rate(avctx);

        s->sfb_offsets[i][0] = 0;

        for (x = 0; x < MAX_BANDS-1 && s->sfb_offsets[i][band - 1] < subframe_len; x++) {

            int offset = (subframe_len * 2 * critical_freq[x]) / rate + 2;

            offset &= ~3;

            if (offset > s->sfb_offsets[i][band - 1])

                s->sfb_offsets[i][band++] = offset;

            if (offset >= subframe_len)

                break;

        }

        s->sfb_offsets[i][band - 1] = subframe_len;

        s->num_sfb[i]               = band - 1;

        if (s->num_sfb[i] <= 0) {

            av_log(avctx, AV_LOG_ERROR, "num_sfb invalid\n");

            return AVERROR_INVALIDDATA;

        }

    }

    /** Scale factors can be shared between blocks of different size

        as every block has a different scale factor band layout.

        The matrix sf_offsets is needed to find the correct scale factor.

     */

    for (i = 0; i < num_possible_block_sizes; i++) {

        int b;

        for (b = 0; b < s->num_sfb[i]; b++) {

            int x;

            int offset = ((s->sfb_offsets[i][b]

                           + s->sfb_offsets[i][b + 1] - 1) << i) >> 1;

            for (x = 0; x < num_possible_block_sizes; x++) {

                int v = 0;

                while (s->sfb_offsets[x][v + 1] << x < offset) {

                    v++;

                    av_assert0(v < MAX_BANDS);

                }

                s->sf_offsets[i][x][b] = v;

            }

        }

    }

    /** init MDCT, FIXME: only init needed sizes */

    for (i = 0; i < WMAPRO_BLOCK_SIZES; i++)

        ff_mdct_init(&s->mdct_ctx[i], WMAPRO_BLOCK_MIN_BITS+1+i, 1,

                     1.0 / (1 << (WMAPRO_BLOCK_MIN_BITS + i - 1))

                     / (1 << (s->bits_per_sample - 1)));

    /** init MDCT windows: simple sine window */

    for (i = 0; i < WMAPRO_BLOCK_SIZES; i++) {

        const int win_idx = WMAPRO_BLOCK_MAX_BITS - i;

        ff_init_ff_sine_windows(win_idx);

        s->windows[WMAPRO_BLOCK_SIZES - i - 1] = ff_sine_windows[win_idx];

    }

    /** calculate subwoofer cutoff values */

    for (i = 0; i < num_possible_block_sizes; i++) {

        int block_size = s->samples_per_frame >> i;

        int cutoff = (440*block_size + 3 * (s->avctx->sample_rate >> 1) - 1)

                     / s->avctx->sample_rate;

        s->subwoofer_cutoffs[i] = av_clip(cutoff, 4, block_size);

    }

    /** calculate sine values for the decorrelation matrix */

    for (i = 0; i < 33; i++)

        sin64[i] = sin(i*M_PI / 64.0);

    if (avctx->debug & FF_DEBUG_BITSTREAM)

        dump_context(s);

    avctx->channel_layout = channel_mask;

    return 0;

}


static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,

                                    uint64_t *new_offset)

{

    *new_offset = bdrv_getlength(bs->file->bs);

    /* per the spec, the address for a block is in units of 1MB */

    *new_offset = ROUND_UP(*new_offset, 1024 * 1024);

    return bdrv_truncate(bs->file, *new_offset + s->block_size,

                         PREALLOC_MODE_OFF, NULL);

}


POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)

{

    DeviceClass *dc = DEVICE_CLASS(oc);

    PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);

    dc->fw_name = "PowerPC,POWER7";

    dc->desc = "POWER7";

    pcc->pvr = CPU_POWERPC_POWER7_BASE;

    pcc->pvr_mask = CPU_POWERPC_POWER7_MASK;

    pcc->init_proc = init_proc_POWER7;

    pcc->check_pow = check_pow_nocheck;

    pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |

                       PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |

                       PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |

                       PPC_FLOAT_FRSQRTES |

                       PPC_FLOAT_STFIWX |

                       PPC_FLOAT_EXT |

                       PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |

                       PPC_MEM_SYNC | PPC_MEM_EIEIO |

                       PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |

                       PPC_64B | PPC_ALTIVEC |

                       PPC_SEGMENT_64B | PPC_SLBI |

                       PPC_POPCNTB | PPC_POPCNTWD;

    pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |

                        PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |

                        PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |

                        PPC2_FP_TST_ISA206;

    pcc->msr_mask = (1ull << MSR_SF) |

                    (1ull << MSR_VR) |

                    (1ull << MSR_VSX) |

                    (1ull << MSR_EE) |

                    (1ull << MSR_PR) |

                    (1ull << MSR_FP) |

                    (1ull << MSR_ME) |

                    (1ull << MSR_FE0) |

                    (1ull << MSR_SE) |

                    (1ull << MSR_DE) |

                    (1ull << MSR_FE1) |

                    (1ull << MSR_IR) |

                    (1ull << MSR_DR) |

                    (1ull << MSR_PMM) |

                    (1ull << MSR_RI) |

                    (1ull << MSR_LE);

    pcc->mmu_model = POWERPC_MMU_2_06;

#if defined(CONFIG_SOFTMMU)

    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;

#endif

    pcc->excp_model = POWERPC_EXCP_POWER7;

    pcc->bus_model = PPC_FLAGS_INPUT_POWER7;

    pcc->bfd_mach = bfd_mach_ppc64;

    pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |

                 POWERPC_FLAG_BE | POWERPC_FLAG_PMM |

                 POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |

                 POWERPC_FLAG_VSX;

    pcc->l1_dcache_size = 0x8000;

    pcc->l1_icache_size = 0x8000;

    pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;

}


static int parse_metadata_ext(DBEContext *s)

{

    if (s->mtd_ext_size)

        skip_input(s, s->key_present + s->mtd_ext_size + 1);

    return 0;

}


static void test_validate_fail_union_flat(TestInputVisitorData *data,

                                          const void *unused)

{

    UserDefFlatUnion *tmp = NULL;

    Error *err = NULL;

    Visitor *v;

    v = validate_test_init(data, "{ 'string': 'c', 'integer': 41, 'boolean': true }");

    visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);

    g_assert(err);

    qapi_free_UserDefFlatUnion(tmp);

}


static int net_slirp_init(VLANState *vlan, const char *model, const char *name)

{

    if (!slirp_inited) {

        slirp_inited = 1;

        slirp_init(slirp_restrict, slirp_ip);

    }

    slirp_vc = qemu_new_vlan_client(vlan, model, name,

                                    slirp_receive, NULL, NULL);

    slirp_vc->info_str[0] = '\0';

    return 0;

}


static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)

{

    MouseState *s = ADB_MOUSE(d);

    int dx, dy;

    if (s->last_buttons_state == s->buttons_state &&

        s->dx == 0 && s->dy == 0)

        return 0;

    dx = s->dx;

    if (dx < -63)

        dx = -63;

    else if (dx > 63)

        dx = 63;

    dy = s->dy;

    if (dy < -63)

        dy = -63;

    else if (dy > 63)

        dy = 63;

    s->dx -= dx;

    s->dy -= dy;

    s->last_buttons_state = s->buttons_state;

    dx &= 0x7f;

    dy &= 0x7f;

    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))

        dy |= 0x80;

    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))

        dx |= 0x80;

    obuf[0] = dy;

    obuf[1] = dx;

    return 2;

}


hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)

{

    PowerPCCPU *cpu = POWERPC_CPU(cs);

    CPUPPCState *env = &cpu->env;

    mmu_ctx_t ctx;

    switch (env->mmu_model) {

#if defined(TARGET_PPC64)

    case POWERPC_MMU_64B:

    case POWERPC_MMU_2_03:

    case POWERPC_MMU_2_06:

    case POWERPC_MMU_2_07:

        return ppc_hash64_get_phys_page_debug(env, addr);

#endif

    case POWERPC_MMU_32B:

    case POWERPC_MMU_601:

        return ppc_hash32_get_phys_page_debug(env, addr);

    default:

        ;

    }

    if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {

        /* Some MMUs have separate TLBs for code and data. If we only try an

         * ACCESS_INT, we may not be able to read instructions mapped by code

         * TLBs, so we also try a ACCESS_CODE.

         */

        if (unlikely(get_physical_address(env, &ctx, addr, 0,

                                          ACCESS_CODE) != 0)) {

            return -1;

        }

    }

    return ctx.raddr & TARGET_PAGE_MASK;

}


static int get_physical_address_data(CPUState *env,

                                     target_phys_addr_t *physical, int *prot,

                                     target_ulong address, int rw, int mmu_idx)

{

    unsigned int i;

    uint64_t context;

    int is_user = (mmu_idx == MMU_USER_IDX ||

                   mmu_idx == MMU_USER_SECONDARY_IDX);

    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */

        *physical = ultrasparc_truncate_physical(address);

        *prot = PAGE_READ | PAGE_WRITE;

        return 0;

    }

    switch(mmu_idx) {

    case MMU_USER_IDX:

    case MMU_KERNEL_IDX:

        context = env->dmmu.mmu_primary_context & 0x1fff;

        break;

    case MMU_USER_SECONDARY_IDX:

    case MMU_KERNEL_SECONDARY_IDX:

        context = env->dmmu.mmu_secondary_context & 0x1fff;

        break;

    case MMU_NUCLEUS_IDX:

        context = 0;

        break;

    }

    for (i = 0; i < 64; i++) {

        // ctx match, vaddr match, valid?

        if (ultrasparc_tag_match(&env->dtlb[i],

                                 address, context, physical)) {

            // access ok?

            if (((env->dtlb[i].tte & 0x4) && is_user) ||

                (!(env->dtlb[i].tte & 0x2) && (rw == 1))) {

                uint8_t fault_type = 0;

                if ((env->dtlb[i].tte & 0x4) && is_user) {

                    fault_type |= 1; /* privilege violation */

                }

                if (env->dmmu.sfsr & 1) /* Fault status register */

                    env->dmmu.sfsr = 2; /* overflow (not read before

                                             another fault) */

                env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;

                env->dmmu.sfsr |= (fault_type << 7);

                env->dmmu.sfar = address; /* Fault address register */

                env->exception_index = TT_DFAULT;

#ifdef DEBUG_MMU

                printf("DFAULT at 0x%" PRIx64 "\n", address);

#endif

                return 1;

            }

            *prot = PAGE_READ;

            if (env->dtlb[i].tte & 0x2)

                *prot |= PAGE_WRITE;

            TTE_SET_USED(env->dtlb[i].tte);

            return 0;

        }

    }

#ifdef DEBUG_MMU

    printf("DMISS at 0x%" PRIx64 "\n", address);

#endif

    env->dmmu.tag_access = (address & ~0x1fffULL) | context;

    env->exception_index = TT_DMISS;

    return 1;

}


static void virtio_pci_reset(DeviceState *qdev)

{

    VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);

    VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);

    int i;

    virtio_pci_stop_ioeventfd(proxy);

    virtio_bus_reset(bus);

    msix_unuse_all_vectors(&proxy->pci_dev);

    for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {

        proxy->vqs[i].enabled = 0;

    }

}


static int decode_residual(const H264Context *h, H264SliceContext *sl,

                           GetBitContext *gb, int16_t *block, int n,

                           const uint8_t *scantable, const uint32_t *qmul,

                           int max_coeff)

{

    static const int coeff_token_table_index[17]= {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3};

    int level[16];

    int zeros_left, coeff_token, total_coeff, i, trailing_ones, run_before;

    //FIXME put trailing_onex into the context

    if(max_coeff <= 8){

        if (max_coeff == 4)

            coeff_token = get_vlc2(gb, chroma_dc_coeff_token_vlc.table, CHROMA_DC_COEFF_TOKEN_VLC_BITS, 1);

        else

            coeff_token = get_vlc2(gb, chroma422_dc_coeff_token_vlc.table, CHROMA422_DC_COEFF_TOKEN_VLC_BITS, 1);

        total_coeff= coeff_token>>2;

    }else{

        if(n >= LUMA_DC_BLOCK_INDEX){

            total_coeff= pred_non_zero_count(h, sl, (n - LUMA_DC_BLOCK_INDEX)*16);

            coeff_token= get_vlc2(gb, coeff_token_vlc[ coeff_token_table_index[total_coeff] ].table, COEFF_TOKEN_VLC_BITS, 2);

            total_coeff= coeff_token>>2;

        }else{

            total_coeff= pred_non_zero_count(h, sl, n);

            coeff_token= get_vlc2(gb, coeff_token_vlc[ coeff_token_table_index[total_coeff] ].table, COEFF_TOKEN_VLC_BITS, 2);

            total_coeff= coeff_token>>2;

        }

    }

    sl->non_zero_count_cache[scan8[n]] = total_coeff;

    //FIXME set last_non_zero?

    if(total_coeff==0)

        return 0;

    if(total_coeff > (unsigned)max_coeff) {

        av_log(h->avctx, AV_LOG_ERROR, "corrupted macroblock %d %d (total_coeff=%d)\n", sl->mb_x, sl->mb_y, total_coeff);

        return -1;

    }

    trailing_ones= coeff_token&3;

    ff_tlog(h->avctx, "trailing:%d, total:%d\n", trailing_ones, total_coeff);

    assert(total_coeff<=16);

    i = show_bits(gb, 3);

    skip_bits(gb, trailing_ones);

    level[0] = 1-((i&4)>>1);

    level[1] = 1-((i&2)   );

    level[2] = 1-((i&1)<<1);

    if(trailing_ones<total_coeff) {

        int mask, prefix;

        int suffix_length = total_coeff > 10 & trailing_ones < 3;

        int bitsi= show_bits(gb, LEVEL_TAB_BITS);

        int level_code= cavlc_level_tab[suffix_length][bitsi][0];

        skip_bits(gb, cavlc_level_tab[suffix_length][bitsi][1]);

        if(level_code >= 100){

            prefix= level_code - 100;

            if(prefix == LEVEL_TAB_BITS)

                prefix += get_level_prefix(gb);

            //first coefficient has suffix_length equal to 0 or 1

            if(prefix<14){ //FIXME try to build a large unified VLC table for all this

                if(suffix_length)

                    level_code= (prefix<<1) + get_bits1(gb); //part

                else

                    level_code= prefix; //part

            }else if(prefix==14){

                if(suffix_length)

                    level_code= (prefix<<1) + get_bits1(gb); //part

                else

                    level_code= prefix + get_bits(gb, 4); //part

            }else{

                level_code= 30 + get_bits(gb, prefix-3); //part

                if(prefix>=16){

                    if(prefix > 25+3){

                        av_log(h->avctx, AV_LOG_ERROR, "Invalid level prefix\n");

                        return -1;

                    }

                    level_code += (1<<(prefix-3))-4096;

                }

            }

            if(trailing_ones < 3) level_code += 2;

            suffix_length = 2;

            mask= -(level_code&1);

            level[trailing_ones]= (((2+level_code)>>1) ^ mask) - mask;

        }else{

            level_code += ((level_code>>31)|1) & -(trailing_ones < 3);

            suffix_length = 1 + (level_code + 3U > 6U);

            level[trailing_ones]= level_code;

        }

        //remaining coefficients have suffix_length > 0

        for(i=trailing_ones+1;i<total_coeff;i++) {

            static const unsigned int suffix_limit[7] = {0,3,6,12,24,48,INT_MAX };

            int bitsi= show_bits(gb, LEVEL_TAB_BITS);

            level_code= cavlc_level_tab[suffix_length][bitsi][0];

            skip_bits(gb, cavlc_level_tab[suffix_length][bitsi][1]);

            if(level_code >= 100){

                prefix= level_code - 100;

                if(prefix == LEVEL_TAB_BITS){

                    prefix += get_level_prefix(gb);

                }

                if(prefix<15){

                    level_code = (prefix<<suffix_length) + get_bits(gb, suffix_length);

                }else{

                    level_code = (15<<suffix_length) + get_bits(gb, prefix-3);

                    if(prefix>=16)

                        level_code += (1<<(prefix-3))-4096;

                }

                mask= -(level_code&1);

                level_code= (((2+level_code)>>1) ^ mask) - mask;

            }

            level[i]= level_code;

            suffix_length+= suffix_limit[suffix_length] + level_code > 2U*suffix_limit[suffix_length];

        }

    }

    if(total_coeff == max_coeff)

        zeros_left=0;

    else{

        if (max_coeff <= 8) {

            if (max_coeff == 4)

                zeros_left = get_vlc2(gb, chroma_dc_total_zeros_vlc[total_coeff - 1].table,

                                      CHROMA_DC_TOTAL_ZEROS_VLC_BITS, 1);

            else

                zeros_left = get_vlc2(gb, chroma422_dc_total_zeros_vlc[total_coeff - 1].table,

                                      CHROMA422_DC_TOTAL_ZEROS_VLC_BITS, 1);

        } else {

            zeros_left= get_vlc2(gb, total_zeros_vlc[total_coeff - 1].table, TOTAL_ZEROS_VLC_BITS, 1);

        }

    }

#define STORE_BLOCK(type) \

    scantable += zeros_left + total_coeff - 1; \

    if(n >= LUMA_DC_BLOCK_INDEX){ \

        ((type*)block)[*scantable] = level[0]; \

        for(i=1;i<total_coeff && zeros_left > 0;i++) { \

            if(zeros_left < 7) \

                run_before= get_vlc2(gb, run_vlc[zeros_left - 1].table, RUN_VLC_BITS, 1); \

            else \

                run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \

            zeros_left -= run_before; \

            scantable -= 1 + run_before; \

            ((type*)block)[*scantable]= level[i]; \

        } \

        for(;i<total_coeff;i++) { \

            scantable--; \

            ((type*)block)[*scantable]= level[i]; \

        } \

    }else{ \

        ((type*)block)[*scantable] = ((int)(level[0] * qmul[*scantable] + 32))>>6; \

        for(i=1;i<total_coeff && zeros_left > 0;i++) { \

            if(zeros_left < 7) \

                run_before= get_vlc2(gb, run_vlc[zeros_left - 1].table, RUN_VLC_BITS, 1); \

            else \

                run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \

            zeros_left -= run_before; \

            scantable -= 1 + run_before; \

            ((type*)block)[*scantable]= ((int)(level[i] * qmul[*scantable] + 32))>>6; \

        } \

        for(;i<total_coeff;i++) { \

            scantable--; \

            ((type*)block)[*scantable]= ((int)(level[i] * qmul[*scantable] + 32))>>6; \

        } \

    }

    if (zeros_left < 0) {

        av_log(h->avctx, AV_LOG_ERROR,

               "negative number of zero coeffs at %d %d\n", sl->mb_x, sl->mb_y);

        return AVERROR_INVALIDDATA;

    }

    if (h->pixel_shift) {

        STORE_BLOCK(int32_t)

    } else {

        STORE_BLOCK(int16_t)

    }

    return 0;

}


DISAS_INSN(fsave)

{

    /* TODO: Implement fsave.  */

    qemu_assert(0, "FSAVE not implemented");

}


static int tap_alloc(char *dev, size_t dev_size)

{

    int tap_fd, if_fd, ppa = -1;

    static int ip_fd = 0;

    char *ptr;

    static int arp_fd = 0;

    int ip_muxid, arp_muxid;

    struct strioctl  strioc_if, strioc_ppa;

    int link_type = I_PLINK;

    struct lifreq ifr;

    char actual_name[32] = "";

    memset(&ifr, 0x0, sizeof(ifr));

    if( *dev ){

       ptr = dev;

       while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;

       ppa = atoi(ptr);

    }

    /* Check if IP device was opened */

    if( ip_fd )

       close(ip_fd);

    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));

    if (ip_fd < 0) {

       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");

       return -1;

    }

    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));

    if (tap_fd < 0) {

       syslog(LOG_ERR, "Can't open /dev/tap");

       return -1;

    }

    /* Assign a new PPA and get its unit number. */

    strioc_ppa.ic_cmd = TUNNEWPPA;

    strioc_ppa.ic_timout = 0;

    strioc_ppa.ic_len = sizeof(ppa);

    strioc_ppa.ic_dp = (char *)&ppa;

    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)

       syslog (LOG_ERR, "Can't assign new interface");

    TFR(if_fd = open("/dev/tap", O_RDWR, 0));

    if (if_fd < 0) {

       syslog(LOG_ERR, "Can't open /dev/tap (2)");

       return -1;

    }

    if(ioctl(if_fd, I_PUSH, "ip") < 0){

       syslog(LOG_ERR, "Can't push IP module");

       return -1;

    }

    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)

	syslog(LOG_ERR, "Can't get flags\n");

    snprintf (actual_name, 32, "tap%d", ppa);

    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);

    ifr.lifr_ppa = ppa;

    /* Assign ppa according to the unit number returned by tun device */

    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)

        syslog (LOG_ERR, "Can't set PPA %d", ppa);

    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)

        syslog (LOG_ERR, "Can't get flags\n");

    /* Push arp module to if_fd */

    if (ioctl (if_fd, I_PUSH, "arp") < 0)

        syslog (LOG_ERR, "Can't push ARP module (2)");

    /* Push arp module to ip_fd */

    if (ioctl (ip_fd, I_POP, NULL) < 0)

        syslog (LOG_ERR, "I_POP failed\n");

    if (ioctl (ip_fd, I_PUSH, "arp") < 0)

        syslog (LOG_ERR, "Can't push ARP module (3)\n");

    /* Open arp_fd */

    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));

    if (arp_fd < 0)

       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");

    /* Set ifname to arp */

    strioc_if.ic_cmd = SIOCSLIFNAME;

    strioc_if.ic_timout = 0;

    strioc_if.ic_len = sizeof(ifr);

    strioc_if.ic_dp = (char *)𝔦

    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){

        syslog (LOG_ERR, "Can't set ifname to arp\n");

    }

    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){

       syslog(LOG_ERR, "Can't link TAP device to IP");

       return -1;

    }

    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)

        syslog (LOG_ERR, "Can't link TAP device to ARP");

    close (if_fd);

    memset(&ifr, 0x0, sizeof(ifr));

    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);

    ifr.lifr_ip_muxid  = ip_muxid;

    ifr.lifr_arp_muxid = arp_muxid;

    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)

    {

      ioctl (ip_fd, I_PUNLINK , arp_muxid);

      ioctl (ip_fd, I_PUNLINK, ip_muxid);

      syslog (LOG_ERR, "Can't set multiplexor id");

    }

    snprintf(dev, dev_size, "tap%d", ppa);

    return tap_fd;

}


static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band,

                                  IVITile *tile, int32_t mv_scale)

{

    int             x, y, need_mc, mbn, blk, num_blocks, mv_x, mv_y, mc_type;

    int             offs, mb_offset, row_offset;

    IVIMbInfo       *mb, *ref_mb;

    const int16_t   *src;

    int16_t         *dst;

    void (*mc_no_delta_func)(int16_t *buf, const int16_t *ref_buf, uint32_t pitch,

                             int mc_type);

    if (tile->num_MBs != IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size)) {

        av_log(avctx, AV_LOG_ERROR, "Allocated tile size %d mismatches "

               "parameters %d in ivi_process_empty_tile()\n",

               tile->num_MBs, IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size));

        return AVERROR_INVALIDDATA;

    }

    offs       = tile->ypos * band->pitch + tile->xpos;

    mb         = tile->mbs;

    ref_mb     = tile->ref_mbs;

    row_offset = band->mb_size * band->pitch;

    need_mc    = 0; /* reset the mc tracking flag */

    for (y = tile->ypos; y < (tile->ypos + tile->height); y += band->mb_size) {

        mb_offset = offs;

        for (x = tile->xpos; x < (tile->xpos + tile->width); x += band->mb_size) {

            mb->xpos     = x;

            mb->ypos     = y;

            mb->buf_offs = mb_offset;

            mb->type = 1; /* set the macroblocks type = INTER */

            mb->cbp  = 0; /* all blocks are empty */

            if (!band->qdelta_present && !band->plane && !band->band_num) {

                mb->q_delta = band->glob_quant;

                mb->mv_x    = 0;

                mb->mv_y    = 0;

            }

            if (band->inherit_qdelta && ref_mb)

                mb->q_delta = ref_mb->q_delta;

            if (band->inherit_mv) {

                /* motion vector inheritance */

                if (mv_scale) {

                    mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale);

                    mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale);

                } else {

                    mb->mv_x = ref_mb->mv_x;

                    mb->mv_y = ref_mb->mv_y;

                }

                need_mc |= mb->mv_x || mb->mv_y; /* tracking non-zero motion vectors */

            }

            mb++;

            if (ref_mb)

                ref_mb++;

            mb_offset += band->mb_size;

        } // for x

        offs += row_offset;

    } // for y

    if (band->inherit_mv && need_mc) { /* apply motion compensation if there is at least one non-zero motion vector */

        num_blocks = (band->mb_size != band->blk_size) ? 4 : 1; /* number of blocks per mb */

        mc_no_delta_func = (band->blk_size == 8) ? ff_ivi_mc_8x8_no_delta

                                                 : ff_ivi_mc_4x4_no_delta;

        for (mbn = 0, mb = tile->mbs; mbn < tile->num_MBs; mb++, mbn++) {

            mv_x = mb->mv_x;

            mv_y = mb->mv_y;

            if (!band->is_halfpel) {

                mc_type = 0; /* we have only fullpel vectors */

            } else {

                mc_type = ((mv_y & 1) << 1) | (mv_x & 1);

                mv_x >>= 1;

                mv_y >>= 1; /* convert halfpel vectors into fullpel ones */

            }

            for (blk = 0; blk < num_blocks; blk++) {

                /* adjust block position in the buffer according with its number */

                offs = mb->buf_offs + band->blk_size * ((blk & 1) + !!(blk & 2) * band->pitch);

                mc_no_delta_func(band->buf + offs,

                                 band->ref_buf + offs + mv_y * band->pitch + mv_x,

                                 band->pitch, mc_type);

            }

        }

    } else {

        /* copy data from the reference tile into the current one */

        src = band->ref_buf + tile->ypos * band->pitch + tile->xpos;

        dst = band->buf     + tile->ypos * band->pitch + tile->xpos;

        for (y = 0; y < tile->height; y++) {

            memcpy(dst, src, tile->width*sizeof(band->buf[0]));

            src += band->pitch;

            dst += band->pitch;

        }

    }

    return 0;

}


static void set_palette(AVFrame * frame, const uint8_t * palette_buffer)

{

    uint32_t * palette = (uint32_t *)frame->data[1];

    int a;

    for(a = 0; a < 256; a++){

        palette[a] = AV_RB24(&palette_buffer[a * 3]) * 4;

    }

    frame->palette_has_changed = 1;

}


static inline void RENAME(rgb32to15)(const uint8_t *src, uint8_t *dst, unsigned src_size)

{

	const uint8_t *s = src;

	const uint8_t *end;

#ifdef HAVE_MMX

	const uint8_t *mm_end;

#endif

	uint16_t *d = (uint16_t *)dst;

	end = s + src_size;

#ifdef HAVE_MMX

	mm_end = end - 15;

#if 1 //is faster only if multiplies are reasonable fast (FIXME figure out on which cpus this is faster, on Athlon its slightly faster)

	asm volatile(

		"movq %3, %%mm5			\n\t"

		"movq %4, %%mm6			\n\t"

		"movq %5, %%mm7			\n\t"

		".balign 16			\n\t"

		"1:				\n\t"

		PREFETCH" 32(%1)		\n\t"

		"movd	(%1), %%mm0		\n\t"

		"movd	4(%1), %%mm3		\n\t"

		"punpckldq 8(%1), %%mm0		\n\t"

		"punpckldq 12(%1), %%mm3	\n\t"

		"movq %%mm0, %%mm1		\n\t"

		"movq %%mm3, %%mm4		\n\t"

		"pand %%mm6, %%mm0		\n\t"

		"pand %%mm6, %%mm3		\n\t"

		"pmaddwd %%mm7, %%mm0		\n\t"

		"pmaddwd %%mm7, %%mm3		\n\t"

		"pand %%mm5, %%mm1		\n\t"

		"pand %%mm5, %%mm4		\n\t"

		"por %%mm1, %%mm0		\n\t"

		"por %%mm4, %%mm3		\n\t"

		"psrld $6, %%mm0		\n\t"

		"pslld $10, %%mm3		\n\t"

		"por %%mm3, %%mm0		\n\t"

		MOVNTQ"	%%mm0, (%0)		\n\t"

		"addl $16, %1			\n\t"

		"addl $8, %0			\n\t"

		"cmpl %2, %1			\n\t"

		" jb 1b				\n\t"

		: "+r" (d), "+r"(s)

		: "r" (mm_end), "m" (mask3215g), "m" (mask3216br), "m" (mul3215)

	);

#else

	__asm __volatile(PREFETCH"	%0"::"m"(*src):"memory");

	__asm __volatile(

	    "movq	%0, %%mm7\n\t"

	    "movq	%1, %%mm6\n\t"

	    ::"m"(red_15mask),"m"(green_15mask));

	while(s < mm_end)

	{

	    __asm __volatile(

		PREFETCH" 32%1\n\t"

		"movd	%1, %%mm0\n\t"

		"movd	4%1, %%mm3\n\t"

		"punpckldq 8%1, %%mm0\n\t"

		"punpckldq 12%1, %%mm3\n\t"

		"movq	%%mm0, %%mm1\n\t"

		"movq	%%mm0, %%mm2\n\t"

		"movq	%%mm3, %%mm4\n\t"

		"movq	%%mm3, %%mm5\n\t"

		"psrlq	$3, %%mm0\n\t"

		"psrlq	$3, %%mm3\n\t"

		"pand	%2, %%mm0\n\t"

		"pand	%2, %%mm3\n\t"

		"psrlq	$6, %%mm1\n\t"

		"psrlq	$6, %%mm4\n\t"

		"pand	%%mm6, %%mm1\n\t"

		"pand	%%mm6, %%mm4\n\t"

		"psrlq	$9, %%mm2\n\t"

		"psrlq	$9, %%mm5\n\t"

		"pand	%%mm7, %%mm2\n\t"

		"pand	%%mm7, %%mm5\n\t"

		"por	%%mm1, %%mm0\n\t"

		"por	%%mm4, %%mm3\n\t"

		"por	%%mm2, %%mm0\n\t"

		"por	%%mm5, %%mm3\n\t"

		"psllq	$16, %%mm3\n\t"

		"por	%%mm3, %%mm0\n\t"

		MOVNTQ"	%%mm0, %0\n\t"

		:"=m"(*d):"m"(*s),"m"(blue_15mask):"memory");

		d += 4;

		s += 16;

	}

#endif

	__asm __volatile(SFENCE:::"memory");

	__asm __volatile(EMMS:::"memory");

#endif

	while(s < end)

	{

		const int src= *((uint32_t*)s)++;

		*d++ = ((src&0xFF)>>3) + ((src&0xF800)>>6) + ((src&0xF80000)>>9);

	}

}


void helper_do_semihosting(CPUMIPSState *env)

{

    target_ulong *gpr = env->active_tc.gpr;

    const UHIOp op = gpr[25];

    char *p, *p2;

    switch (op) {

    case UHI_exit:

        qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);

        exit(gpr[4]);

    case UHI_open:

        GET_TARGET_STRING(p, gpr[4]);

        if (!strcmp("/dev/stdin", p)) {

            gpr[2] = 0;

        } else if (!strcmp("/dev/stdout", p)) {

            gpr[2] = 1;

        } else if (!strcmp("/dev/stderr", p)) {

            gpr[2] = 2;

        } else {

            gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);

            gpr[3] = errno_mips(errno);

        }

        FREE_TARGET_STRING(p, gpr[4]);

        break;

    case UHI_close:

        if (gpr[4] < 3) {

            /* ignore closing stdin/stdout/stderr */

            gpr[2] = 0;

            goto uhi_done;

        }

        gpr[2] = close(gpr[4]);

        gpr[3] = errno_mips(errno);

        break;

    case UHI_read:

        gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0);

        gpr[3] = errno_mips(errno);

        break;

    case UHI_write:

        gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0);

        gpr[3] = errno_mips(errno);

        break;

    case UHI_lseek:

        gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);

        gpr[3] = errno_mips(errno);

        break;

    case UHI_unlink:

        GET_TARGET_STRING(p, gpr[4]);

        gpr[2] = remove(p);

        gpr[3] = errno_mips(errno);

        FREE_TARGET_STRING(p, gpr[4]);

        break;

    case UHI_fstat:

        {

            struct stat sbuf;

            memset(&sbuf, 0, sizeof(sbuf));

            gpr[2] = fstat(gpr[4], &sbuf);

            gpr[3] = errno_mips(errno);

            if (gpr[2]) {

                goto uhi_done;

            }

            gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);

            gpr[3] = errno_mips(errno);

        }

        break;

    case UHI_argc:

        gpr[2] = semihosting_get_argc();

        break;

    case UHI_argnlen:

        if (gpr[4] >= semihosting_get_argc()) {

            gpr[2] = -1;

            goto uhi_done;

        }

        gpr[2] = strlen(semihosting_get_arg(gpr[4]));

        break;

    case UHI_argn:

        if (gpr[4] >= semihosting_get_argc()) {

            gpr[2] = -1;

            goto uhi_done;

        }

        gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);

        break;

    case UHI_plog:

        GET_TARGET_STRING(p, gpr[4]);

        p2 = strstr(p, "%d");

        if (p2) {

            int char_num = p2 - p;

            char *buf = g_malloc(char_num + 1);

            strncpy(buf, p, char_num);

            buf[char_num] = '\0';

            gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2);

            g_free(buf);

        } else {

            gpr[2] = printf("%s", p);

        }

        FREE_TARGET_STRING(p, gpr[4]);

        break;

    case UHI_assert:

        GET_TARGET_STRING(p, gpr[4]);

        GET_TARGET_STRING(p2, gpr[5]);

        printf("assertion '");

        printf("\"%s\"", p);

        printf("': file \"%s\", line %d\n", p2, (int)gpr[6]);

        FREE_TARGET_STRING(p2, gpr[5]);

        FREE_TARGET_STRING(p, gpr[4]);

        abort();

        break;

    case UHI_pread:

        gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);

        gpr[3] = errno_mips(errno);

        break;

    case UHI_pwrite:

        gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);

        gpr[3] = errno_mips(errno);

        break;

#ifndef _WIN32

    case UHI_link:

        GET_TARGET_STRING(p, gpr[4]);

        GET_TARGET_STRING(p2, gpr[5]);

        gpr[2] = link(p, p2);

        gpr[3] = errno_mips(errno);

        FREE_TARGET_STRING(p2, gpr[5]);

        FREE_TARGET_STRING(p, gpr[4]);

        break;

#endif

    default:

        fprintf(stderr, "Unknown UHI operation %d\n", op);

        abort();

    }

uhi_done:

    return;

}