static void disas_arm_insn(DisasContext *s, unsigned int insn)

{

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

    TCGv_i32 tmp;

    TCGv_i32 tmp2;

    TCGv_i32 tmp3;

    TCGv_i32 addr;

    TCGv_i64 tmp64;

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

    if (arm_dc_feature(s, ARM_FEATURE_M)) {

        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_dc_feature(s, ARM_FEATURE_NEON)) {

                goto illegal_op;

            }

            if (disas_neon_data_insn(s, insn)) {

                goto illegal_op;

            }

            return;

        }

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

            /* NEON load/store.  */

            if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {

                goto illegal_op;

            }

            if (disas_neon_ls_insn(s, insn)) {

                goto illegal_op;

            }

            return;

        }

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

            /* VFP.  */

            if (disas_vfp_insn(s, insn)) {

                goto illegal_op;

            }

            return;

        }

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

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

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

                /* PLDW; v7MP */

                if (!arm_dc_feature(s, 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_dc_feature(s, 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 */

                ARCH(7);

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

                return;

            case 6: /* isb */

                /* We need to break the TB after this insn to execute

                 * self-modifying code correctly and also to take

                 * any pending interrupts immediately.

                 */

                gen_lookup_tb(s);

                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, get_mem_index(s));

            tcg_gen_addi_i32(addr, addr, 4);

            tmp2 = tcg_temp_new_i32();

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

            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_dc_feature(s, ARM_FEATURE_IWMMXT)) {

                /* iWMMXt register transfer.  */

                if (extract32(s->c15_cpar, 1, 1)) {

                    if (!disas_iwmmxt_insn(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(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(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_dc_feature(s, 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);

            if (op1 == 0) {

                tcg_gen_andi_i32(tmp2, tmp2, 0xff);

            } else if (op1 == 1) {

                tcg_gen_andi_i32(tmp2, tmp2, 0xffff);

            }

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

            switch (op1) {

            case 1:

                /* bkpt */

                ARCH(5);

                gen_exception_insn(s, 4, EXCP_BKPT,

                                   syn_aa32_bkpt(imm16, false),

                                   default_exception_el(s));

                break;

            case 2:

                /* Hypervisor call (v7) */

                ARCH(7);

                if (IS_USER(s)) {

                    goto illegal_op;

                }

                gen_hvc(s, imm16);

                break;

            case 3:

                /* Secure monitor call (v6+) */

                ARCH(6K);

                if (IS_USER(s)) {

                    goto illegal_op;

                }

                gen_smc(s);

                break;

            default:

                goto illegal_op;

            }

            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_extrl_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(s, rd, tmp);

            break;

        case 0x01:

            tcg_gen_xor_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(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(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(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(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(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(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(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(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(s, rd, tmp2);

            }

            break;

        case 0x0e:

            tcg_gen_andc_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(s, rd, tmp);

            break;

        default:

        case 0x0f:

            tcg_gen_not_i32(tmp2, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp2);

            }

            store_reg_bx(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, get_mem_index(s));

                                    break;

                                case 2: /* ldab */

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

                                    break;

                                case 3: /* ldah */

                                    gen_aa32_ld16u(tmp, addr, get_mem_index(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, get_mem_index(s));

                                    break;

                                case 2: /* stlb */

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

                                    break;

                                case 3: /* stlh */

                                    gen_aa32_st16(tmp, addr, get_mem_index(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, get_mem_index(s));

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

                        } else {

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

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

                        }

                        tcg_temp_free_i32(tmp);

                        tcg_temp_free_i32(addr);

                        store_reg(s, rd, tmp2);

                    }

                }

            } else {

                int address_offset;

                bool load = insn & (1 << 20);

                bool doubleword = false;

                /* Misc load/store */

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

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

                if (!load && (sh & 2)) {

                    /* doubleword */

                    ARCH(5TE);

                    if (rd & 1) {

                        /* UNPREDICTABLE; we choose to UNDEF */

                        goto illegal_op;

                    }

                    load = (sh & 1) == 0;

                    doubleword = true;

                }

                addr = load_reg(s, rn);

                if (insn & (1 << 24))

                    gen_add_datah_offset(s, insn, 0, addr);

                address_offset = 0;

                if (doubleword) {

                    if (!load) {

                        /* store */

                        tmp = load_reg(s, rd);

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

                        tcg_temp_free_i32(tmp);

                        tcg_gen_addi_i32(addr, addr, 4);

                        tmp = load_reg(s, rd + 1);

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

                        tcg_temp_free_i32(tmp);

                    } else {

                        /* load */

                        tmp = tcg_temp_new_i32();

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

                        store_reg(s, rd, tmp);

                        tcg_gen_addi_i32(addr, addr, 4);

                        tmp = tcg_temp_new_i32();

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

                        rd++;

                    }

                    address_offset = -4;

                } else if (load) {

                    /* load */

                    tmp = tcg_temp_new_i32();

                    switch (sh) {

                    case 1:

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

                        break;

                    case 2:

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

                        break;

                    default:

                    case 3:

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

                        break;

                    }

                } else {

                    /* store */

                    tmp = load_reg(s, rd);

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

                    tcg_temp_free_i32(tmp);

                }

                /* Perform base writeback before the loaded value to

                   ensure correct behavior with overlapping index registers.

                   ldrd with base writeback 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_extrl_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 << 22)) {

                            /* smlald, smlsld */

                            TCGv_i64 tmp64_2;

                            tmp64 = tcg_temp_new_i64();

                            tmp64_2 = tcg_temp_new_i64();

                            tcg_gen_ext_i32_i64(tmp64, tmp);

                            tcg_gen_ext_i32_i64(tmp64_2, tmp2);

                            tcg_temp_free_i32(tmp);

                            tcg_temp_free_i32(tmp2);

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

                                tcg_gen_sub_i64(tmp64, tmp64, tmp64_2);

                            } else {

                                tcg_gen_add_i64(tmp64, tmp64, tmp64_2);

                            }

                            tcg_temp_free_i64(tmp64_2);

                            gen_addq(s, tmp64, rd, rn);

                            gen_storeq_reg(s, rd, rn, tmp64);

                            tcg_temp_free_i64(tmp64);

                        } else {

                            /* smuad, smusd, smlad, smlsd */

                            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 (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_dc_feature(s, 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;

                        if (i < shift) {

                            /* UNPREDICTABLE; we choose to UNDEF */

                            goto illegal_op;

                        }

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

            if ((insn & 0x01200000) == 0x00200000) {

                /* ldrt/strt */

                i = get_a32_user_mem_index(s);

            } else {

                i = get_mem_index(s);

            }

            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(s, rd, tmp);

            }

            break;

        case 0x08:

        case 0x09:

            {

                int j, n, loaded_base;

                bool exc_return = false;

                bool is_load = extract32(insn, 20, 1);

                bool user = false;

                TCGv_i32 loaded_var;

                /* load/store multiple words */

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

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

                    /* LDM (user), LDM (exception return) and STM (user) */

                    if (IS_USER(s))

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

                    if (is_load && extract32(insn, 15, 1)) {

                        exc_return = true;

                    } else {

                        user = true;

                    }

                }

                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 (is_load) {

                            /* load */

                            tmp = tcg_temp_new_i32();

                            gen_aa32_ld32u(tmp, addr, get_mem_index(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(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, get_mem_index(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 (exc_return) {

                    /* Restore CPSR from SPSR.  */

                    tmp = load_cpu_field(spsr);

                    gen_set_cpsr(tmp, CPSR_ERET_MASK);

                    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(s, insn)) {

                    goto illegal_op;

                }

            } else if (disas_coproc_insn(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(),

                               default_exception_el(s));

            break;

        }

    }

}


static void pcie_pci_bridge_reset(DeviceState *qdev)

{

    PCIDevice *d = PCI_DEVICE(qdev);

    pci_bridge_reset(qdev);

    msi_reset(d);

    shpc_reset(d);

}


static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)

{

    uint32_t steplen = read_u32(data, 0);

    VNC_DEBUG("Got client step len %d\n", steplen);

    if (steplen > SASL_DATA_MAX_LEN) {

        VNC_DEBUG("Too much SASL data %d\n", steplen);

        vnc_client_error(vs);

        return -1;

    }

    if (steplen == 0)

        return protocol_client_auth_sasl_step(vs, NULL, 0);

    else

        vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);

    return 0;

}


int qemu_devtree_nop_node(void *fdt, const char *node_path)

{

    int offset;

    offset = fdt_path_offset(fdt, node_path);

    if (offset < 0)

        return offset;

    return fdt_nop_node(fdt, offset);

}


static int ogg_read_header(AVFormatContext *s)

{

    struct ogg *ogg = s->priv_data;

    int ret, i;

    ogg->curidx = -1;

    //linear headers seek from start

    do {

        ret = ogg_packet(s, NULL, NULL, NULL, NULL);

        if (ret < 0) {

            ogg_read_close(s);

            return ret;

        }

    } while (!ogg->headers);

    av_log(s, AV_LOG_TRACE, "found headers\n");

    for (i = 0; i < ogg->nstreams; i++) {

        struct ogg_stream *os = ogg->streams + i;

        if (ogg->streams[i].header < 0) {

            av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);

            ogg->streams[i].codec = NULL;

        } else if (os->codec && os->nb_header < os->codec->nb_header) {

            av_log(s, AV_LOG_WARNING,

                   "Headers mismatch for stream %d: "

                   "expected %d received %d.\n",

                   i, os->codec->nb_header, os->nb_header);

            if (s->error_recognition & AV_EF_EXPLODE)

                return AVERROR_INVALIDDATA;

        }

        if (os->start_granule != OGG_NOGRANULE_VALUE)

            os->lastpts = s->streams[i]->start_time =

                ogg_gptopts(s, i, os->start_granule, NULL);

    }

    //linear granulepos seek from end

    ret = ogg_get_length(s);

    if (ret < 0) {

        ogg_read_close(s);

        return ret;

    }

    return 0;

}


void qmp_drive_backup(DriveBackup *arg, Error **errp)

{

    return do_drive_backup(arg, NULL, errp);

}


static void vp56_decode_mb(VP56Context *s, int row, int col, int is_alpha)

{

    AVFrame *frame_current, *frame_ref;

    VP56mb mb_type;

    VP56Frame ref_frame;

    int b, ab, b_max, plane, off;

    if (s->framep[VP56_FRAME_CURRENT]->key_frame)

        mb_type = VP56_MB_INTRA;

    else

        mb_type = vp56_decode_mv(s, row, col);

    ref_frame = vp56_reference_frame[mb_type];

    s->dsp.clear_blocks(*s->block_coeff);

    s->parse_coeff(s);

    vp56_add_predictors_dc(s, ref_frame);

    frame_current = s->framep[VP56_FRAME_CURRENT];

    frame_ref = s->framep[ref_frame];

    if (mb_type != VP56_MB_INTRA && !frame_ref->data[0])

        return;

    ab = 6*is_alpha;

    b_max = 6 - 2*is_alpha;

    switch (mb_type) {

        case VP56_MB_INTRA:

            for (b=0; b<b_max; b++) {

                plane = ff_vp56_b2p[b+ab];

                s->dsp.idct_put(frame_current->data[plane] + s->block_offset[b],

                                s->stride[plane], s->block_coeff[b]);

            }

            break;

        case VP56_MB_INTER_NOVEC_PF:

        case VP56_MB_INTER_NOVEC_GF:

            for (b=0; b<b_max; b++) {

                plane = ff_vp56_b2p[b+ab];

                off = s->block_offset[b];

                s->dsp.put_pixels_tab[1][0](frame_current->data[plane] + off,

                                            frame_ref->data[plane] + off,

                                            s->stride[plane], 8);

                s->dsp.idct_add(frame_current->data[plane] + off,

                                s->stride[plane], s->block_coeff[b]);

            }

            break;

        case VP56_MB_INTER_DELTA_PF:

        case VP56_MB_INTER_V1_PF:

        case VP56_MB_INTER_V2_PF:

        case VP56_MB_INTER_DELTA_GF:

        case VP56_MB_INTER_4V:

        case VP56_MB_INTER_V1_GF:

        case VP56_MB_INTER_V2_GF:

            for (b=0; b<b_max; b++) {

                int x_off = b==1 || b==3 ? 8 : 0;

                int y_off = b==2 || b==3 ? 8 : 0;

                plane = ff_vp56_b2p[b+ab];

                vp56_mc(s, b, plane, frame_ref->data[plane], s->stride[plane],

                        16*col+x_off, 16*row+y_off);

                s->dsp.idct_add(frame_current->data[plane] + s->block_offset[b],

                                s->stride[plane], s->block_coeff[b]);

            }

            break;

    }

}


AVRational av_get_q(void *obj, const char *name, const AVOption **o_out)

{

    int64_t intnum=1;

    double num=1;

    int den=1;

    av_get_number(obj, name, o_out, &num, &den, &intnum);

    if (num == 1.0 && (int)intnum == intnum)

        return (AVRational){intnum, den};

    else

        return av_d2q(num*intnum/den, 1<<24);

}


static uint64_t megasas_queue_read(void *opaque, target_phys_addr_t addr,

                                   unsigned size)

{

    return 0;

}


int float32_is_nan( float32 a1 )

{

    float32u u;

    uint64_t a;

    u.f = a1;

    a = u.i;

    return ( 0xFF800000 < ( a<<1 ) );

}


static void bitband_writel(void *opaque, target_phys_addr_t offset,

                           uint32_t value)

{

    uint32_t addr;

    uint32_t mask;

    uint32_t v;

    addr = bitband_addr(opaque, offset) & ~3;

    mask = (1 << ((offset >> 2) & 31));

    mask = tswap32(mask);

    cpu_physical_memory_read(addr, (uint8_t *)&v, 4);

    if (value & 1)

        v |= mask;

    else

        v &= ~mask;

    cpu_physical_memory_write(addr, (uint8_t *)&v, 4);

}


static void vvfat_refresh_limits(BlockDriverState *bs, Error **errp)

{

    bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */

}


void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)

{

    SLAVIO_INTCTLState *s = opaque;

    s->cpu_envs[cpu] = env;

}


static void filter_mb_mbaff_edgev( H264Context *h, uint8_t *pix, int stride, int16_t bS[7], int bsi, int qp ) {

    int index_a = qp + h->slice_alpha_c0_offset;

    int alpha = alpha_table[index_a];

    int beta  = beta_table[qp + h->slice_beta_offset];

    if (alpha ==0 || beta == 0) return;

    if( bS[0] < 4 ) {

        int8_t tc[4];

        tc[0] = tc0_table[index_a][bS[0*bsi]];

        tc[1] = tc0_table[index_a][bS[1*bsi]];

        tc[2] = tc0_table[index_a][bS[2*bsi]];

        tc[3] = tc0_table[index_a][bS[3*bsi]];

        h->h264dsp.h264_h_loop_filter_luma_mbaff(pix, stride, alpha, beta, tc);

    } else {

        h->h264dsp.h264_h_loop_filter_luma_mbaff_intra(pix, stride, alpha, beta);

    }

}


static void kbd_write_command(void *opaque, hwaddr addr,

                              uint64_t val, unsigned size)

{

    KBDState *s = opaque;

    DPRINTF("kbd: write cmd=0x%02" PRIx64 "\n", val);

    /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed

     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE

     * command specify the output port bits to be pulsed.

     * 0: Bit should be pulsed. 1: Bit should not be modified.

     * The only useful version of this command is pulsing bit 0,

     * which does a CPU reset.

     */

    if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {

        if(!(val & 1))

            val = KBD_CCMD_RESET;

        else

            val = KBD_CCMD_NO_OP;

    }

    switch(val) {

    case KBD_CCMD_READ_MODE:

        kbd_queue(s, s->mode, 0);

        break;

    case KBD_CCMD_WRITE_MODE:

    case KBD_CCMD_WRITE_OBUF:

    case KBD_CCMD_WRITE_AUX_OBUF:

    case KBD_CCMD_WRITE_MOUSE:

    case KBD_CCMD_WRITE_OUTPORT:

        s->write_cmd = val;

        break;

    case KBD_CCMD_MOUSE_DISABLE:

        s->mode |= KBD_MODE_DISABLE_MOUSE;

        break;

    case KBD_CCMD_MOUSE_ENABLE:

        s->mode &= ~KBD_MODE_DISABLE_MOUSE;

        break;

    case KBD_CCMD_TEST_MOUSE:

        kbd_queue(s, 0x00, 0);

        break;

    case KBD_CCMD_SELF_TEST:

        s->status |= KBD_STAT_SELFTEST;

        kbd_queue(s, 0x55, 0);

        break;

    case KBD_CCMD_KBD_TEST:

        kbd_queue(s, 0x00, 0);

        break;

    case KBD_CCMD_KBD_DISABLE:

        s->mode |= KBD_MODE_DISABLE_KBD;

        kbd_update_irq(s);

        break;

    case KBD_CCMD_KBD_ENABLE:

        s->mode &= ~KBD_MODE_DISABLE_KBD;

        kbd_update_irq(s);

        break;

    case KBD_CCMD_READ_INPORT:

        kbd_queue(s, 0x80, 0);

        break;

    case KBD_CCMD_READ_OUTPORT:

        kbd_queue(s, s->outport, 0);

        break;

    case KBD_CCMD_ENABLE_A20:

        if (s->a20_out) {

            qemu_irq_raise(*s->a20_out);

        }

        s->outport |= KBD_OUT_A20;

        break;

    case KBD_CCMD_DISABLE_A20:

        if (s->a20_out) {

            qemu_irq_lower(*s->a20_out);

        }

        s->outport &= ~KBD_OUT_A20;

        break;

    case KBD_CCMD_RESET:

        qemu_system_reset_request();

        break;

    case KBD_CCMD_NO_OP:

        /* ignore that */

        break;

    default:

        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val);

        break;

    }

}


static int kvm_s390_supports_mem_limit(KVMState *s)

{

    struct kvm_device_attr attr = {

        .group = KVM_S390_VM_MEM_CTRL,

        .attr = KVM_S390_VM_MEM_LIMIT_SIZE,

    };

    return (kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr) == 0);

}


static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)

{

    uint64_t ret = 0;

    int ve;

    ve = fpscr_ve;

    switch (op) {

    case POWERPC_EXCP_FP_VXSNAN:

        env->fpscr |= 1 << FPSCR_VXSNAN;

        break;

    case POWERPC_EXCP_FP_VXSOFT:

        env->fpscr |= 1 << FPSCR_VXSOFT;

        break;

    case POWERPC_EXCP_FP_VXISI:

        /* Magnitude subtraction of infinities */

        env->fpscr |= 1 << FPSCR_VXISI;

        goto update_arith;

    case POWERPC_EXCP_FP_VXIDI:

        /* Division of infinity by infinity */

        env->fpscr |= 1 << FPSCR_VXIDI;

        goto update_arith;

    case POWERPC_EXCP_FP_VXZDZ:

        /* Division of zero by zero */

        env->fpscr |= 1 << FPSCR_VXZDZ;

        goto update_arith;

    case POWERPC_EXCP_FP_VXIMZ:

        /* Multiplication of zero by infinity */

        env->fpscr |= 1 << FPSCR_VXIMZ;

        goto update_arith;

    case POWERPC_EXCP_FP_VXVC:

        /* Ordered comparison of NaN */

        env->fpscr |= 1 << FPSCR_VXVC;

        env->fpscr &= ~(0xF << FPSCR_FPCC);

        env->fpscr |= 0x11 << FPSCR_FPCC;

        /* We must update the target FPR before raising the exception */

        if (ve != 0) {

            env->exception_index = POWERPC_EXCP_PROGRAM;

            env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;

            /* Update the floating-point enabled exception summary */

            env->fpscr |= 1 << FPSCR_FEX;

            /* Exception is differed */

            ve = 0;

        }

        break;

    case POWERPC_EXCP_FP_VXSQRT:

        /* Square root of a negative number */

        env->fpscr |= 1 << FPSCR_VXSQRT;

    update_arith:

        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));

        if (ve == 0) {

            /* Set the result to quiet NaN */

            ret = 0x7FF8000000000000ULL;

            env->fpscr &= ~(0xF << FPSCR_FPCC);

            env->fpscr |= 0x11 << FPSCR_FPCC;

        }

        break;

    case POWERPC_EXCP_FP_VXCVI:

        /* Invalid conversion */

        env->fpscr |= 1 << FPSCR_VXCVI;

        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));

        if (ve == 0) {

            /* Set the result to quiet NaN */

            ret = 0x7FF8000000000000ULL;

            env->fpscr &= ~(0xF << FPSCR_FPCC);

            env->fpscr |= 0x11 << FPSCR_FPCC;

        }

        break;

    }

    /* Update the floating-point invalid operation summary */

    env->fpscr |= 1 << FPSCR_VX;

    /* Update the floating-point exception summary */

    env->fpscr |= 1 << FPSCR_FX;

    if (ve != 0) {

        /* Update the floating-point enabled exception summary */

        env->fpscr |= 1 << FPSCR_FEX;

        if (msr_fe0 != 0 || msr_fe1 != 0) {

            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,

                                       POWERPC_EXCP_FP | op);

        }

    }

    return ret;

}


VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo)

{

    VirtIOBlock *s;

    int cylinders, heads, secs;

    static int virtio_blk_id;

    char *ps;

    s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,

                                          sizeof(struct virtio_blk_config),

                                          sizeof(VirtIOBlock));

    s->vdev.get_config = virtio_blk_update_config;

    s->vdev.get_features = virtio_blk_get_features;

    s->vdev.reset = virtio_blk_reset;

    s->bs = dinfo->bdrv;

    s->rq = NULL;

    if (strlen(ps = (char *)drive_get_serial(s->bs)))

        strncpy(s->serial_str, ps, sizeof(s->serial_str));

    else

        snprintf(s->serial_str, sizeof(s->serial_str), "0");

    s->bs->private = dev;

    bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);

    bdrv_set_geometry_hint(s->bs, cylinders, heads, secs);

    s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);

    qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);

    register_savevm("virtio-blk", virtio_blk_id++, 2,

                    virtio_blk_save, virtio_blk_load, s);

    return &s->vdev;

}


static BlockAIOCB *raw_aio_writev(BlockDriverState *bs,

        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,

        BlockCompletionFunc *cb, void *opaque)

{

    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,

                          cb, opaque, QEMU_AIO_WRITE);

}


static void text_console_update(void *opaque, console_ch_t *chardata)

{

    QemuConsole *s = (QemuConsole *) opaque;

    int i, j, src;

    if (s->text_x[0] <= s->text_x[1]) {

        src = (s->y_base + s->text_y[0]) * s->width;

        chardata += s->text_y[0] * s->width;

        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)

            for (j = 0; j < s->width; j ++, src ++)

                console_write_ch(chardata ++, s->cells[src].ch |

                                (s->cells[src].t_attrib.fgcol << 12) |

                                (s->cells[src].t_attrib.bgcol << 8) |

                                (s->cells[src].t_attrib.bold << 21));

        dpy_text_update(s, s->text_x[0], s->text_y[0],

                        s->text_x[1] - s->text_x[0], i - s->text_y[0]);

        s->text_x[0] = s->width;

        s->text_y[0] = s->height;

        s->text_x[1] = 0;

        s->text_y[1] = 0;

    }

    if (s->cursor_invalidate) {

        dpy_text_cursor(s, s->x, s->y);

        s->cursor_invalidate = 0;

    }

}


bool qemu_peer_has_ufo(NetClientState *nc)

{

    if (!nc->peer || !nc->peer->info->has_ufo) {

        return false;

    }

    return nc->peer->info->has_ufo(nc->peer);

}


void kbd_put_keycode(int keycode)

{

    if (!runstate_is_running()) {

        return;

    }

    if (qemu_put_kbd_event) {

        qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);

    }

}


ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)

{

    uint8_t buf[NBD_REPLY_SIZE];

    uint32_t magic;

    ssize_t ret;

    ret = read_sync_eof(ioc, buf, sizeof(buf), errp);

    if (ret <= 0) {

        return ret;

    }

    if (ret != sizeof(buf)) {

        error_setg(errp, "read failed");

        return -EINVAL;

    }

    /* Reply

       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)

       [ 4 ..  7]    error   (0 == no error)

       [ 7 .. 15]    handle

     */

    magic = ldl_be_p(buf);

    reply->error  = ldl_be_p(buf + 4);

    reply->handle = ldq_be_p(buf + 8);

    reply->error = nbd_errno_to_system_errno(reply->error);

    if (reply->error == ESHUTDOWN) {

        /* This works even on mingw which lacks a native ESHUTDOWN */

        error_setg(errp, "server shutting down");

        return -EINVAL;

    }

    TRACE("Got reply: { magic = 0x%" PRIx32 ", .error = % " PRId32

          ", handle = %" PRIu64" }",

          magic, reply->error, reply->handle);

    if (magic != NBD_REPLY_MAGIC) {

        error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic);

        return -EINVAL;

    }

    return sizeof(buf);

}


static int file_open(URLContext *h, const char *filename, int flags)

{

    int access;

    int fd;

    av_strstart(filename, "file:", &filename);

    if (flags & URL_RDWR) {

        access = O_CREAT | O_TRUNC | O_RDWR;

    } else if (flags & URL_WRONLY) {

        access = O_CREAT | O_TRUNC | O_WRONLY;

    } else {

        access = O_RDONLY;

    }

#if defined(__MINGW32__) || defined(CONFIG_OS2) || defined(__CYGWIN__)

    access |= O_BINARY;

#endif

    fd = open(filename, access, 0666);

    if (fd < 0)

        return AVERROR(ENOENT);

    h->priv_data = (void *)(size_t)fd;

    return 0;

}


void *qemu_get_ram_ptr(ram_addr_t addr)

{

    RAMBlock *prev;

    RAMBlock **prevp;

    RAMBlock *block;

#ifdef CONFIG_KQEMU

    if (kqemu_phys_ram_base) {

        return kqemu_phys_ram_base + addr;

    }

#endif

    prev = NULL;

    prevp = &ram_blocks;

    block = ram_blocks;

    while (block && (block->offset > addr

                     || block->offset + block->length <= addr)) {

        if (prev)

          prevp = &prev->next;

        prev = block;

        block = block->next;

    }

    if (!block) {

        fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);

        abort();

    }

    /* Move this entry to to start of the list.  */

    if (prev) {

        prev->next = block->next;

        block->next = *prevp;

        *prevp = block;

    }

    return block->host + (addr - block->offset);

}


static inline void tcg_reg_sync(TCGContext *s, int reg)

{

    TCGTemp *ts;

    int temp;

    temp = s->reg_to_temp[reg];

    ts = &s->temps[temp];

    assert(ts->val_type == TEMP_VAL_REG);

    if (!ts->mem_coherent && !ts->fixed_reg) {

        if (!ts->mem_allocated) {

            temp_allocate_frame(s, temp);

        }

        tcg_out_st(s, ts->type, reg, ts->mem_reg, ts->mem_offset);

    }

    ts->mem_coherent = 1;

}


int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,

                                    SocketAddressLegacy *addr,

                                    Error **errp)

{

    int fd;

    trace_qio_channel_socket_connect_sync(ioc, addr);

    fd = socket_connect(addr, NULL, NULL, errp);

    if (fd < 0) {

        trace_qio_channel_socket_connect_fail(ioc);

        return -1;

    }

    trace_qio_channel_socket_connect_complete(ioc, fd);

    if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) {

        close(fd);

        return -1;

    }

    return 0;

}


static int transcode(OutputFile *output_files,

                     int nb_output_files,

                     InputFile *input_files,

                     int nb_input_files)

{

    int ret, i;

    AVFormatContext *is, *os;

    OutputStream *ost;

    InputStream *ist;

    uint8_t *no_packet;

    int no_packet_count=0;

    int64_t timer_start;

    int key;

    if (!(no_packet = av_mallocz(nb_input_files)))

        exit_program(1);

    ret = transcode_init(output_files, nb_output_files, input_files, nb_input_files);

    if (ret < 0)

        goto fail;

    if (!using_stdin) {

        if(verbose >= 0)

            fprintf(stderr, "Press [q] to stop, [?] for help\n");

        avio_set_interrupt_cb(decode_interrupt_cb);

    }

    term_init();

    timer_start = av_gettime();

    for(; received_sigterm == 0;) {

        int file_index, ist_index;

        AVPacket pkt;

        int64_t ipts_min;

        double opts_min;

    redo:

        ipts_min= INT64_MAX;

        opts_min= 1e100;

        /* if 'q' pressed, exits */

        if (!using_stdin) {

            if (q_pressed)

                break;

            /* read_key() returns 0 on EOF */

            key = read_key();

            if (key == 'q')

                break;

            if (key == '+') verbose++;

            if (key == '-') verbose--;

            if (key == 's') qp_hist     ^= 1;

            if (key == 'h'){

                if (do_hex_dump){

                    do_hex_dump = do_pkt_dump = 0;

                } else if(do_pkt_dump){

                    do_hex_dump = 1;

                } else

                    do_pkt_dump = 1;

                av_log_set_level(AV_LOG_DEBUG);

            }

            if (key == 'c' || key == 'C'){

                char ret[4096], target[64], cmd[256], arg[256]={0};

                double ts;

                fprintf(stderr, "\nEnter command: <target> <time> <command>[ <argument>]\n");

                if(scanf("%4095[^\n\r]%*c", ret) == 1 && sscanf(ret, "%63[^ ] %lf %255[^ ] %255[^\n]", target, &ts, cmd, arg) >= 3){

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

                        int r;

                        ost = &output_streams[i];

                        if(ost->graph){

                            if(ts<0){

                                r= avfilter_graph_send_command(ost->graph, target, cmd, arg, ret, sizeof(ret), key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);

                                fprintf(stderr, "Command reply for %d: %d, %s\n", i, r, ret);

                            }else{

                                r= avfilter_graph_queue_command(ost->graph, target, cmd, arg, 0, ts);

                            }

                        }

                    }

                }else{

                    fprintf(stderr, "Parse error\n");

                }

            }

            if (key == 'd' || key == 'D'){

                int debug=0;

                if(key == 'D') {

                    debug = input_streams[0].st->codec->debug<<1;

                    if(!debug) debug = 1;

                    while(debug & (FF_DEBUG_DCT_COEFF|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) //unsupported, would just crash

                        debug += debug;

                }else

                    scanf("%d", &debug);

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

                    input_streams[i].st->codec->debug = debug;

                }

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

                    ost = &output_streams[i];

                    ost->st->codec->debug = debug;

                }

                if(debug) av_log_set_level(AV_LOG_DEBUG);

                fprintf(stderr,"debug=%d\n", debug);

            }

            if (key == '?'){

                fprintf(stderr, "key    function\n"

                                "?      show this help\n"

                                "+      increase verbosity\n"

                                "-      decrease verbosity\n"

                                "c      Send command to filtergraph\n"

                                "D      cycle through available debug modes\n"

                                "h      dump packets/hex press to cycle through the 3 states\n"

                                "q      quit\n"

                                "s      Show QP histogram\n"

                );

            }

        }

        /* select the stream that we must read now by looking at the

           smallest output pts */

        file_index = -1;

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

            OutputFile *of;

            int64_t ipts;

            double  opts;

            ost = &output_streams[i];

            of = &output_files[ost->file_index];

            os = output_files[ost->file_index].ctx;

            ist = &input_streams[ost->source_index];

            if (ost->is_past_recording_time || no_packet[ist->file_index] ||

                (os->pb && avio_tell(os->pb) >= of->limit_filesize))

                continue;

            opts = ost->st->pts.val * av_q2d(ost->st->time_base);

            ipts = ist->pts;

            if (!input_files[ist->file_index].eof_reached){

                if(ipts < ipts_min) {

                    ipts_min = ipts;

                    if(input_sync ) file_index = ist->file_index;

                }

                if(opts < opts_min) {

                    opts_min = opts;

                    if(!input_sync) file_index = ist->file_index;

                }

            }

            if(ost->frame_number >= max_frames[ost->st->codec->codec_type]){

                file_index= -1;

                break;

            }

        }

        /* if none, if is finished */

        if (file_index < 0) {

            if(no_packet_count){

                no_packet_count=0;

                memset(no_packet, 0, nb_input_files);

                usleep(10000);

                continue;

            }

            break;

        }

        /* read a frame from it and output it in the fifo */

        is = input_files[file_index].ctx;

        ret= av_read_frame(is, &pkt);

        if(ret == AVERROR(EAGAIN)){

            no_packet[file_index]=1;

            no_packet_count++;

            continue;

        }

        if (ret < 0) {

            input_files[file_index].eof_reached = 1;

            if (opt_shortest)

                break;

            else

                continue;

        }

        no_packet_count=0;

        memset(no_packet, 0, nb_input_files);

        if (do_pkt_dump) {

            av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,

                             is->streams[pkt.stream_index]);

        }

        /* the following test is needed in case new streams appear

           dynamically in stream : we ignore them */

        if (pkt.stream_index >= input_files[file_index].nb_streams)

            goto discard_packet;

        ist_index = input_files[file_index].ist_index + pkt.stream_index;

        ist = &input_streams[ist_index];

        if (ist->discard)

            goto discard_packet;

        if (pkt.dts != AV_NOPTS_VALUE)

            pkt.dts += av_rescale_q(input_files[ist->file_index].ts_offset, AV_TIME_BASE_Q, ist->st->time_base);

        if (pkt.pts != AV_NOPTS_VALUE)

            pkt.pts += av_rescale_q(input_files[ist->file_index].ts_offset, AV_TIME_BASE_Q, ist->st->time_base);

        if (ist->ts_scale) {

            if(pkt.pts != AV_NOPTS_VALUE)

                pkt.pts *= ist->ts_scale;

            if(pkt.dts != AV_NOPTS_VALUE)

                pkt.dts *= ist->ts_scale;

        }

//        fprintf(stderr, "next:%"PRId64" dts:%"PRId64" off:%"PRId64" %d\n", ist->next_pts, pkt.dts, input_files[ist->file_index].ts_offset, ist->st->codec->codec_type);

        if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE

            && (is->iformat->flags & AVFMT_TS_DISCONT)) {

            int64_t pkt_dts= av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);

            int64_t delta= pkt_dts - ist->next_pts;

            if((delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||

                (delta > 1LL*dts_delta_threshold*AV_TIME_BASE &&

                 ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||

                pkt_dts+1<ist->pts)&& !copy_ts){

                input_files[ist->file_index].ts_offset -= delta;

                if (verbose > 2)

                    fprintf(stderr, "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",

                            delta, input_files[ist->file_index].ts_offset);

                pkt.dts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);

                if(pkt.pts != AV_NOPTS_VALUE)

                    pkt.pts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);

            }

        }

        //fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);

        if (output_packet(ist, ist_index, output_streams, nb_output_streams, &pkt) < 0) {

            if (verbose >= 0)

                fprintf(stderr, "Error while decoding stream #%d.%d\n",

                        ist->file_index, ist->st->index);

            if (exit_on_error)

                exit_program(1);

            av_free_packet(&pkt);

            goto redo;

        }

    discard_packet:

        av_free_packet(&pkt);

        /* dump report by using the output first video and audio streams */

        print_report(output_files, output_streams, nb_output_streams, 0, timer_start);

    }

    /* at the end of stream, we must flush the decoder buffers */

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

        ist = &input_streams[i];

        if (ist->decoding_needed) {

            output_packet(ist, i, output_streams, nb_output_streams, NULL);

        }

    }

    flush_encoders(output_streams, nb_output_streams);

    term_exit();

    /* write the trailer if needed and close file */

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

        os = output_files[i].ctx;

        av_write_trailer(os);

    }

    /* dump report by using the first video and audio streams */

    print_report(output_files, output_streams, nb_output_streams, 1, timer_start);

    /* close each encoder */

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

        ost = &output_streams[i];

        if (ost->encoding_needed) {

            av_freep(&ost->st->codec->stats_in);

            avcodec_close(ost->st->codec);

        }

#if CONFIG_AVFILTER

        avfilter_graph_free(&ost->graph);

#endif

    }

    /* close each decoder */

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

        ist = &input_streams[i];

        if (ist->decoding_needed) {

            avcodec_close(ist->st->codec);

        }

    }

    /* finished ! */

    ret = 0;

 fail:

    av_freep(&bit_buffer);

    av_freep(&no_packet);

    if (output_streams) {

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

            ost = &output_streams[i];

            if (ost) {

                if (ost->st->stream_copy)

                    av_freep(&ost->st->codec->extradata);

                if (ost->logfile) {

                    fclose(ost->logfile);

                    ost->logfile = NULL;

                }

                av_fifo_free(ost->fifo); /* works even if fifo is not

                                             initialized but set to zero */

                av_freep(&ost->st->codec->subtitle_header);

                av_free(ost->resample_frame.data[0]);

                av_free(ost->forced_kf_pts);

                if (ost->video_resample)

                    sws_freeContext(ost->img_resample_ctx);

                if (ost->resample)

                    audio_resample_close(ost->resample);

                if (ost->reformat_ctx)

                    av_audio_convert_free(ost->reformat_ctx);

                av_dict_free(&ost->opts);

            }

        }

    }

    return ret;

}


static void mirror_start_job(const char *job_id, BlockDriverState *bs,

                             int creation_flags, BlockDriverState *target,

                             const char *replaces, int64_t speed,

                             uint32_t granularity, int64_t buf_size,

                             BlockMirrorBackingMode backing_mode,

                             BlockdevOnError on_source_error,

                             BlockdevOnError on_target_error,

                             bool unmap,

                             BlockCompletionFunc *cb,

                             void *opaque, Error **errp,

                             const BlockJobDriver *driver,

                             bool is_none_mode, BlockDriverState *base,

                             bool auto_complete, const char *filter_node_name)

{

    MirrorBlockJob *s;

    BlockDriverState *mirror_top_bs;

    bool target_graph_mod;

    bool target_is_backing;

    Error *local_err = NULL;

    int ret;

    if (granularity == 0) {

        granularity = bdrv_get_default_bitmap_granularity(target);

    }

    assert ((granularity & (granularity - 1)) == 0);

    if (buf_size < 0) {

        error_setg(errp, "Invalid parameter 'buf-size'");

        return;

    }

    if (buf_size == 0) {

        buf_size = DEFAULT_MIRROR_BUF_SIZE;

    }

    /* In the case of active commit, add dummy driver to provide consistent

     * reads on the top, while disabling it in the intermediate nodes, and make

     * the backing chain writable. */

    mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,

                                         BDRV_O_RDWR, errp);

    if (mirror_top_bs == NULL) {

        return;

    }

    mirror_top_bs->total_sectors = bs->total_sectors;

    /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep

     * it alive until block_job_create() even if bs has no parent. */

    bdrv_ref(mirror_top_bs);

    bdrv_drained_begin(bs);

    bdrv_append(mirror_top_bs, bs, &local_err);

    bdrv_drained_end(bs);

    if (local_err) {

        bdrv_unref(mirror_top_bs);

        error_propagate(errp, local_err);

        return;

    }

    /* Make sure that the source is not resized while the job is running */

    s = block_job_create(job_id, driver, mirror_top_bs,

                         BLK_PERM_CONSISTENT_READ,

                         BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |

                         BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,

                         creation_flags, cb, opaque, errp);

    bdrv_unref(mirror_top_bs);

    if (!s) {

        goto fail;

    }

    s->source = bs;

    s->mirror_top_bs = mirror_top_bs;

    /* No resize for the target either; while the mirror is still running, a

     * consistent read isn't necessarily possible. We could possibly allow

     * writes and graph modifications, though it would likely defeat the

     * purpose of a mirror, so leave them blocked for now.

     *

     * In the case of active commit, things look a bit different, though,

     * because the target is an already populated backing file in active use.

     * We can allow anything except resize there.*/

    target_is_backing = bdrv_chain_contains(bs, target);

    target_graph_mod = (backing_mode != MIRROR_LEAVE_BACKING_CHAIN);

    s->target = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |

                        (target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),

                        BLK_PERM_WRITE_UNCHANGED |

                        (target_is_backing ? BLK_PERM_CONSISTENT_READ |

                                             BLK_PERM_WRITE |

                                             BLK_PERM_GRAPH_MOD : 0));

    ret = blk_insert_bs(s->target, target, errp);

    if (ret < 0) {

        goto fail;

    }

    s->replaces = g_strdup(replaces);

    s->on_source_error = on_source_error;

    s->on_target_error = on_target_error;

    s->is_none_mode = is_none_mode;

    s->backing_mode = backing_mode;

    s->base = base;

    s->granularity = granularity;

    s->buf_size = ROUND_UP(buf_size, granularity);

    s->unmap = unmap;

    if (auto_complete) {

        s->should_complete = true;

    }

    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);

    if (!s->dirty_bitmap) {

        goto fail;

    }

    /* Required permissions are already taken with blk_new() */

    block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL,

                       &error_abort);

    /* In commit_active_start() all intermediate nodes disappear, so

     * any jobs in them must be blocked */

    if (target_is_backing) {

        BlockDriverState *iter;

        for (iter = backing_bs(bs); iter != target; iter = backing_bs(iter)) {

            /* XXX BLK_PERM_WRITE needs to be allowed so we don't block

             * ourselves at s->base (if writes are blocked for a node, they are

             * also blocked for its backing file). The other options would be a

             * second filter driver above s->base (== target). */

            ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,

                                     BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,

                                     errp);

            if (ret < 0) {

                goto fail;

            }

        }

    }

    trace_mirror_start(bs, s, opaque);

    block_job_start(&s->common);

    return;

fail:

    if (s) {

        g_free(s->replaces);

        blk_unref(s->target);

        block_job_unref(&s->common);

    }

    bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,

                            &error_abort);

    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);

}


static void perf_cost(void)

{

    const unsigned long maxcycles = 40000000;

    unsigned long i = 0;

    double duration;

    unsigned long ops;

    Coroutine *co;

    g_test_timer_start();

    while (i++ < maxcycles) {

        co = qemu_coroutine_create(perf_cost_func);

        qemu_coroutine_enter(co, &i);

        qemu_coroutine_enter(co, NULL);

    }

    duration = g_test_timer_elapsed();

    ops = (long)(maxcycles / (duration * 1000));

    g_test_message("Run operation %lu iterations %f s, %luK operations/s, "

                   "%luns per coroutine",

                   maxcycles,

                   duration, ops,

                   (unsigned long)(1000000000 * duration) / maxcycles);

}


int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,

                    int ts_start, int duration, int raw)

{

    AVBPrint buf;

    int ret, dlen;

    AVSubtitleRect **rects;

    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);

    if ((ret = ff_ass_bprint_dialog(&buf, dialog, ts_start, duration, raw)) < 0)

        goto err;

    dlen = ret;

    if (!av_bprint_is_complete(&buf))

    rects = av_realloc_array(sub->rects, (sub->num_rects+1), sizeof(*sub->rects));

    if (!rects)

    sub->rects = rects;

    sub->end_display_time = FFMAX(sub->end_display_time, 10 * duration);

    rects[sub->num_rects]       = av_mallocz(sizeof(*rects[0]));

    rects[sub->num_rects]->type = SUBTITLE_ASS;

    ret = av_bprint_finalize(&buf, &rects[sub->num_rects]->ass);

    if (ret < 0)

        goto err;

    sub->num_rects++;

    return dlen;

errnomem:

    ret = AVERROR(ENOMEM);

err:

    av_bprint_finalize(&buf, NULL);

    return ret;

}