static int disas_thumb2_insn(DisasContext *s, uint32_t insn)

{

    uint32_t imm, shift, offset;

    uint32_t rd, rn, rm, rs;

    TCGv_i32 tmp;

    TCGv_i32 tmp2;

    TCGv_i32 tmp3;

    TCGv_i32 addr;

    TCGv_i64 tmp64;

    int op;

    int shiftop;

    int conds;

    int logic_cc;

    /* The only 32 bit insn that's allowed for Thumb1 is the combined

     * BL/BLX prefix and suffix.

     */

    if ((insn & 0xf800e800) != 0xf000e800) {

        ARCH(6T2);

    }

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

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

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

    rm = insn & 0xf;

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

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

        /* 16-bit instructions.  Should never happen.  */

        abort();

    case 4:

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

            /* 0b1110_100x_x1xx_xxxx_xxxx_xxxx_xxxx_xxxx

             * - load/store doubleword, load/store exclusive, ldacq/strel,

             *   table branch.

             */

            if (insn == 0xe97fe97f && arm_dc_feature(s, ARM_FEATURE_M) &&

                arm_dc_feature(s, ARM_FEATURE_V8)) {

                /* 0b1110_1001_0111_1111_1110_1001_0111_111

                 *  - SG (v8M only)

                 * The bulk of the behaviour for this instruction is implemented

                 * in v7m_handle_execute_nsc(), which deals with the insn when

                 * it is executed by a CPU in non-secure state from memory

                 * which is Secure & NonSecure-Callable.

                 * Here we only need to handle the remaining cases:

                 *  * in NS memory (including the "security extension not

                 *    implemented" case) : NOP

                 *  * in S memory but CPU already secure (clear IT bits)

                 * We know that the attribute for the memory this insn is

                 * in must match the current CPU state, because otherwise

                 * get_phys_addr_pmsav8 would have generated an exception.

                 */

                if (s->v8m_secure) {

                    /* Like the IT insn, we don't need to generate any code */

                    s->condexec_cond = 0;

                    s->condexec_mask = 0;

                }

            } else if (insn & 0x01200000) {

                /* 0b1110_1000_x11x_xxxx_xxxx_xxxx_xxxx_xxxx

                 *  - load/store dual (post-indexed)

                 * 0b1111_1001_x10x_xxxx_xxxx_xxxx_xxxx_xxxx

                 *  - load/store dual (literal and immediate)

                 * 0b1111_1001_x11x_xxxx_xxxx_xxxx_xxxx_xxxx

                 *  - load/store dual (pre-indexed)

                 */

                if (rn == 15) {

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

                        /* UNPREDICTABLE */

                        goto illegal_op;

                    }

                    addr = tcg_temp_new_i32();

                    tcg_gen_movi_i32(addr, s->pc & ~3);

                } else {

                    addr = load_reg(s, rn);

                }

                offset = (insn & 0xff) * 4;

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

                    offset = -offset;

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

                    tcg_gen_addi_i32(addr, addr, offset);

                    offset = 0;

                }

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

                    /* ldrd */

                    tmp = tcg_temp_new_i32();

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

                    store_reg(s, rs, tmp);

                    tcg_gen_addi_i32(addr, addr, 4);

                    tmp = tcg_temp_new_i32();

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

                    store_reg(s, rd, tmp);

                } else {

                    /* strd */

                    tmp = load_reg(s, rs);

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

                    tcg_temp_free_i32(tmp);

                    tcg_gen_addi_i32(addr, addr, 4);

                    tmp = load_reg(s, rd);

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

                    tcg_temp_free_i32(tmp);

                }

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

                    /* Base writeback.  */

                    tcg_gen_addi_i32(addr, addr, offset - 4);

                    store_reg(s, rn, addr);

                } else {

                    tcg_temp_free_i32(addr);

                }

            } else if ((insn & (1 << 23)) == 0) {

                /* 0b1110_1000_010x_xxxx_xxxx_xxxx_xxxx_xxxx

                 * - load/store exclusive word

                 */

                if (rs == 15) {

                    goto illegal_op;

                }

                addr = tcg_temp_local_new_i32();

                load_reg_var(s, addr, rn);

                tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);

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

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

                } else {

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

                }

                tcg_temp_free_i32(addr);

            } else if ((insn & (7 << 5)) == 0) {

                /* Table Branch.  */

                if (rn == 15) {

                    addr = tcg_temp_new_i32();

                    tcg_gen_movi_i32(addr, s->pc);

                } else {

                    addr = load_reg(s, rn);

                }

                tmp = load_reg(s, rm);

                tcg_gen_add_i32(addr, addr, tmp);

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

                    /* tbh */

                    tcg_gen_add_i32(addr, addr, tmp);

                    tcg_temp_free_i32(tmp);

                    tmp = tcg_temp_new_i32();

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

                } else { /* tbb */

                    tcg_temp_free_i32(tmp);

                    tmp = tcg_temp_new_i32();

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

                }

                tcg_temp_free_i32(addr);

                tcg_gen_shli_i32(tmp, tmp, 1);

                tcg_gen_addi_i32(tmp, tmp, s->pc);

                store_reg(s, 15, tmp);

            } else {

                int op2 = (insn >> 6) & 0x3;

                op = (insn >> 4) & 0x3;

                switch (op2) {

                case 0:

                    goto illegal_op;

                case 1:

                    /* Load/store exclusive byte/halfword/doubleword */

                    if (op == 2) {

                        goto illegal_op;

                    }

                    ARCH(7);

                    break;

                case 2:

                    /* Load-acquire/store-release */

                    if (op == 3) {

                        goto illegal_op;

                    }

                    /* Fall through */

                case 3:

                    /* Load-acquire/store-release exclusive */

                    ARCH(8);

                    break;

                }

                addr = tcg_temp_local_new_i32();

                load_reg_var(s, addr, rn);

                if (!(op2 & 1)) {

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

                        tmp = tcg_temp_new_i32();

                        switch (op) {

                        case 0: /* ldab */

                            gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s),

                                              rs | ISSIsAcqRel);

                            break;

                        case 1: /* ldah */

                            gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),

                                               rs | ISSIsAcqRel);

                            break;

                        case 2: /* lda */

                            gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),

                                               rs | ISSIsAcqRel);

                            break;

                        default:

                            abort();

                        }

                        store_reg(s, rs, tmp);

                    } else {

                        tmp = load_reg(s, rs);

                        switch (op) {

                        case 0: /* stlb */

                            gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s),

                                             rs | ISSIsAcqRel);

                            break;

                        case 1: /* stlh */

                            gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s),

                                              rs | ISSIsAcqRel);

                            break;

                        case 2: /* stl */

                            gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s),

                                              rs | ISSIsAcqRel);

                            break;

                        default:

                            abort();

                        }

                        tcg_temp_free_i32(tmp);

                    }

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

                    gen_load_exclusive(s, rs, rd, addr, op);

                } else {

                    gen_store_exclusive(s, rm, rs, rd, addr, op);

                }

                tcg_temp_free_i32(addr);

            }

        } else {

            /* Load/store multiple, RFE, SRS.  */

            if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {

                /* RFE, SRS: not available in user mode or on M profile */

                if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {

                    goto illegal_op;

                }

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

                    /* rfe */

                    addr = load_reg(s, rn);

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

                        tcg_gen_addi_i32(addr, addr, -8);

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

                    tmp = tcg_temp_new_i32();

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

                    tcg_gen_addi_i32(addr, addr, 4);

                    tmp2 = tcg_temp_new_i32();

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

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

                        /* Base writeback.  */

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

                            tcg_gen_addi_i32(addr, addr, 4);

                        } else {

                            tcg_gen_addi_i32(addr, addr, -4);

                        }

                        store_reg(s, rn, addr);

                    } else {

                        tcg_temp_free_i32(addr);

                    }

                    gen_rfe(s, tmp, tmp2);

                } else {

                    /* srs */

                    gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2,

                            insn & (1 << 21));

                }

            } else {

                int i, loaded_base = 0;

                TCGv_i32 loaded_var;

                /* Load/store multiple.  */

                addr = load_reg(s, rn);

                offset = 0;

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

                    if (insn & (1 << i))

                        offset += 4;

                }

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

                    tcg_gen_addi_i32(addr, addr, -offset);

                }

                TCGV_UNUSED_I32(loaded_var);

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

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

                        continue;

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

                        /* Load.  */

                        tmp = tcg_temp_new_i32();

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

                        if (i == 15) {

                            gen_bx_excret(s, tmp);

                        } else if (i == rn) {

                            loaded_var = tmp;

                            loaded_base = 1;

                        } else {

                            store_reg(s, i, tmp);

                        }

                    } else {

                        /* Store.  */

                        tmp = load_reg(s, i);

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

                        tcg_temp_free_i32(tmp);

                    }

                    tcg_gen_addi_i32(addr, addr, 4);

                }

                if (loaded_base) {

                    store_reg(s, rn, loaded_var);

                }

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

                    /* Base register writeback.  */

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

                        tcg_gen_addi_i32(addr, addr, -offset);

                    }

                    /* Fault if writeback register is in register list.  */

                    if (insn & (1 << rn))

                        goto illegal_op;

                    store_reg(s, rn, addr);

                } else {

                    tcg_temp_free_i32(addr);

                }

            }

        }

        break;

    case 5:

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

        if (op == 6) {

            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                goto illegal_op;

            }

            /* Halfword pack.  */

            tmp = load_reg(s, rn);

            tmp2 = load_reg(s, rm);

            shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);

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

                /* 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 {

            /* Data processing register constant shift.  */

            if (rn == 15) {

                tmp = tcg_temp_new_i32();

                tcg_gen_movi_i32(tmp, 0);

            } else {

                tmp = load_reg(s, rn);

            }

            tmp2 = load_reg(s, rm);

            shiftop = (insn >> 4) & 3;

            shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);

            conds = (insn & (1 << 20)) != 0;

            logic_cc = (conds && thumb2_logic_op(op));

            gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);

            if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))

                goto illegal_op;

            tcg_temp_free_i32(tmp2);

            if (rd != 15) {

                store_reg(s, rd, tmp);

            } else {

                tcg_temp_free_i32(tmp);

            }

        }

        break;

    case 13: /* Misc data processing.  */

        op = ((insn >> 22) & 6) | ((insn >> 7) & 1);

        if (op < 4 && (insn & 0xf000) != 0xf000)

            goto illegal_op;

        switch (op) {

        case 0: /* Register controlled shift.  */

            tmp = load_reg(s, rn);

            tmp2 = load_reg(s, rm);

            if ((insn & 0x70) != 0)

                goto illegal_op;

            op = (insn >> 21) & 3;

            logic_cc = (insn & (1 << 20)) != 0;

            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);

            if (logic_cc)

                gen_logic_CC(tmp);

            store_reg(s, rd, tmp);

            break;

        case 1: /* Sign/zero extend.  */

            op = (insn >> 20) & 7;

            switch (op) {

            case 0: /* SXTAH, SXTH */

            case 1: /* UXTAH, UXTH */

            case 4: /* SXTAB, SXTB */

            case 5: /* UXTAB, UXTB */

                break;

            case 2: /* SXTAB16, SXTB16 */

            case 3: /* UXTAB16, UXTB16 */

                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                    goto illegal_op;

                }

                break;

            default:

                goto illegal_op;

            }

            if (rn != 15) {

                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                    goto illegal_op;

                }

            }

            tmp = load_reg(s, rm);

            shift = (insn >> 4) & 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);

            op = (insn >> 20) & 7;

            switch (op) {

            case 0: gen_sxth(tmp);   break;

            case 1: gen_uxth(tmp);   break;

            case 2: gen_sxtb16(tmp); break;

            case 3: gen_uxtb16(tmp); break;

            case 4: gen_sxtb(tmp);   break;

            case 5: gen_uxtb(tmp);   break;

            default:

                g_assert_not_reached();

            }

            if (rn != 15) {

                tmp2 = load_reg(s, rn);

                if ((op >> 1) == 1) {

                    gen_add16(tmp, tmp2);

                } else {

                    tcg_gen_add_i32(tmp, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                }

            }

            store_reg(s, rd, tmp);

            break;

        case 2: /* SIMD add/subtract.  */

            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                goto illegal_op;

            }

            op = (insn >> 20) & 7;

            shift = (insn >> 4) & 7;

            if ((op & 3) == 3 || (shift & 3) == 3)

                goto illegal_op;

            tmp = load_reg(s, rn);

            tmp2 = load_reg(s, rm);

            gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);

            tcg_temp_free_i32(tmp2);

            store_reg(s, rd, tmp);

            break;

        case 3: /* Other data processing.  */

            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);

            if (op < 4) {

                /* Saturating add/subtract.  */

                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                    goto illegal_op;

                }

                tmp = load_reg(s, rn);

                tmp2 = load_reg(s, rm);

                if (op & 1)

                    gen_helper_double_saturate(tmp, cpu_env, tmp);

                if (op & 2)

                    gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp);

                else

                    gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);

                tcg_temp_free_i32(tmp2);

            } else {

                switch (op) {

                case 0x0a: /* rbit */

                case 0x08: /* rev */

                case 0x09: /* rev16 */

                case 0x0b: /* revsh */

                case 0x18: /* clz */

                    break;

                case 0x10: /* sel */

                    if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                        goto illegal_op;

                    }

                    break;

                case 0x20: /* crc32/crc32c */

                case 0x21:

                case 0x22:

                case 0x28:

                case 0x29:

                case 0x2a:

                    if (!arm_dc_feature(s, ARM_FEATURE_CRC)) {

                        goto illegal_op;

                    }

                    break;

                default:

                    goto illegal_op;

                }

                tmp = load_reg(s, rn);

                switch (op) {

                case 0x0a: /* rbit */

                    gen_helper_rbit(tmp, tmp);

                    break;

                case 0x08: /* rev */

                    tcg_gen_bswap32_i32(tmp, tmp);

                    break;

                case 0x09: /* rev16 */

                    gen_rev16(tmp);

                    break;

                case 0x0b: /* revsh */

                    gen_revsh(tmp);

                    break;

                case 0x10: /* sel */

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

                    break;

                case 0x18: /* clz */

                    tcg_gen_clzi_i32(tmp, tmp, 32);

                    break;

                case 0x20:

                case 0x21:

                case 0x22:

                case 0x28:

                case 0x29:

                case 0x2a:

                {

                    /* crc32/crc32c */

                    uint32_t sz = op & 0x3;

                    uint32_t c = op & 0x8;

                    tmp2 = load_reg(s, rm);

                    if (sz == 0) {

                        tcg_gen_andi_i32(tmp2, tmp2, 0xff);

                    } else if (sz == 1) {

                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff);

                    }

                    tmp3 = tcg_const_i32(1 << sz);

                    if (c) {

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

                    break;

                }

                default:

                    g_assert_not_reached();

                }

            }

            store_reg(s, rd, tmp);

            break;

        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */

            switch ((insn >> 20) & 7) {

            case 0: /* 32 x 32 -> 32 */

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

                break;

            case 1: /* 16 x 16 -> 32 */

            case 2: /* Dual multiply add.  */

            case 3: /* 32 * 16 -> 32msb */

            case 4: /* Dual multiply subtract.  */

            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */

                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                    goto illegal_op;

                }

                break;

            }

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

            tmp = load_reg(s, rn);

            tmp2 = load_reg(s, rm);

            switch ((insn >> 20) & 7) {

            case 0: /* 32 x 32 -> 32 */

                tcg_gen_mul_i32(tmp, tmp, tmp2);

                tcg_temp_free_i32(tmp2);

                if (rs != 15) {

                    tmp2 = load_reg(s, rs);

                    if (op)

                        tcg_gen_sub_i32(tmp, tmp2, tmp);

                    else

                        tcg_gen_add_i32(tmp, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                }

                break;

            case 1: /* 16 x 16 -> 32 */

                gen_mulxy(tmp, tmp2, op & 2, op & 1);

                tcg_temp_free_i32(tmp2);

                if (rs != 15) {

                    tmp2 = load_reg(s, rs);

                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                }

                break;

            case 2: /* Dual multiply add.  */

            case 4: /* Dual multiply subtract.  */

                if (op)

                    gen_swap_half(tmp2);

                gen_smul_dual(tmp, tmp2);

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

                    /* 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 (rs != 15)

                  {

                    tmp2 = load_reg(s, rs);

                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                  }

                break;

            case 3: /* 32 * 16 -> 32msb */

                if (op)

                    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 (rs != 15)

                  {

                    tmp2 = load_reg(s, rs);

                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                  }

                break;

            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */

                tmp64 = gen_muls_i64_i32(tmp, tmp2);

                if (rs != 15) {

                    tmp = load_reg(s, rs);

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

                        tmp64 = gen_addq_msw(tmp64, tmp);

                    } else {

                        tmp64 = gen_subq_msw(tmp64, tmp);

                    }

                }

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

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

                break;

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

                gen_helper_usad8(tmp, tmp, tmp2);

                tcg_temp_free_i32(tmp2);

                if (rs != 15) {

                    tmp2 = load_reg(s, rs);

                    tcg_gen_add_i32(tmp, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                }

                break;

            }

            store_reg(s, rd, tmp);

            break;

        case 6: case 7: /* 64-bit multiply, Divide.  */

            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);

            tmp = load_reg(s, rn);

            tmp2 = load_reg(s, rm);

            if ((op & 0x50) == 0x10) {

                /* sdiv, udiv */

                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DIV)) {

                    goto illegal_op;

                }

                if (op & 0x20)

                    gen_helper_udiv(tmp, tmp, tmp2);

                else

                    gen_helper_sdiv(tmp, tmp, tmp2);

                tcg_temp_free_i32(tmp2);

                store_reg(s, rd, tmp);

            } else if ((op & 0xe) == 0xc) {

                /* Dual multiply accumulate long.  */

                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                    tcg_temp_free_i32(tmp);

                    tcg_temp_free_i32(tmp2);

                    goto illegal_op;

                }

                if (op & 1)

                    gen_swap_half(tmp2);

                gen_smul_dual(tmp, tmp2);

                if (op & 0x10) {

                    tcg_gen_sub_i32(tmp, tmp, tmp2);

                } else {

                    tcg_gen_add_i32(tmp, tmp, tmp2);

                }

                tcg_temp_free_i32(tmp2);

                /* BUGFIX */

                tmp64 = tcg_temp_new_i64();

                tcg_gen_ext_i32_i64(tmp64, tmp);

                tcg_temp_free_i32(tmp);

                gen_addq(s, tmp64, rs, rd);

                gen_storeq_reg(s, rs, rd, tmp64);

                tcg_temp_free_i64(tmp64);

            } else {

                if (op & 0x20) {

                    /* Unsigned 64-bit multiply  */

                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);

                } else {

                    if (op & 8) {

                        /* smlalxy */

                        if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                            tcg_temp_free_i32(tmp2);

                            tcg_temp_free_i32(tmp);

                            goto illegal_op;

                        }

                        gen_mulxy(tmp, tmp2, op & 2, op & 1);

                        tcg_temp_free_i32(tmp2);

                        tmp64 = tcg_temp_new_i64();

                        tcg_gen_ext_i32_i64(tmp64, tmp);

                        tcg_temp_free_i32(tmp);

                    } else {

                        /* Signed 64-bit multiply  */

                        tmp64 = gen_muls_i64_i32(tmp, tmp2);

                    }

                }

                if (op & 4) {

                    /* umaal */

                    if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                        tcg_temp_free_i64(tmp64);

                        goto illegal_op;

                    }

                    gen_addq_lo(s, tmp64, rs);

                    gen_addq_lo(s, tmp64, rd);

                } else if (op & 0x40) {

                    /* 64-bit accumulate.  */

                    gen_addq(s, tmp64, rs, rd);

                }

                gen_storeq_reg(s, rs, rd, tmp64);

                tcg_temp_free_i64(tmp64);

            }

            break;

        }

        break;

    case 6: case 7: case 14: case 15:

        /* Coprocessor.  */

        if (arm_dc_feature(s, ARM_FEATURE_M)) {

            /* We don't currently implement M profile FP support,

             * so this entire space should give a NOCP fault.

             */

            gen_exception_insn(s, 4, EXCP_NOCP, syn_uncategorized(),

                               default_exception_el(s));

            break;

        }

        if (((insn >> 24) & 3) == 3) {

            /* Translate into the equivalent ARM encoding.  */

            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);

            if (disas_neon_data_insn(s, insn)) {

                goto illegal_op;

            }

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

            if (disas_vfp_insn(s, insn)) {

                goto illegal_op;

            }

        } else {

            if (insn & (1 << 28))

                goto illegal_op;

            if (disas_coproc_insn(s, insn)) {

                goto illegal_op;

            }

        }

        break;

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

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

            /* Branches, misc control.  */

            if (insn & 0x5000) {

                /* Unconditional branch.  */

                /* signextend(hw1[10:0]) -> offset[:12].  */

                offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;

                /* hw1[10:0] -> offset[11:1].  */

                offset |= (insn & 0x7ff) << 1;

                /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]

                   offset[24:22] already have the same value because of the

                   sign extension above.  */

                offset ^= ((~insn) & (1 << 13)) << 10;

                offset ^= ((~insn) & (1 << 11)) << 11;

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

                    /* Branch and link.  */

                    tcg_gen_movi_i32(cpu_R[14], s->pc | 1);

                }

                offset += s->pc;

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

                    /* b/bl */

                    gen_jmp(s, offset);

                } else {

                    /* blx */

                    offset &= ~(uint32_t)2;

                    /* thumb2 bx, no need to check */

                    gen_bx_im(s, offset);

                }

            } else if (((insn >> 23) & 7) == 7) {

                /* Misc control */

                if (insn & (1 << 13))

                    goto illegal_op;

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

                    if (arm_dc_feature(s, ARM_FEATURE_M)) {

                        goto illegal_op;

                    }

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

                        /* Hypervisor call (v7) */

                        int imm16 = extract32(insn, 16, 4) << 12

                            | extract32(insn, 0, 12);

                        ARCH(7);

                        if (IS_USER(s)) {

                            goto illegal_op;

                        }

                        gen_hvc(s, imm16);

                    } else {

                        /* Secure monitor call (v6+) */

                        ARCH(6K);

                        if (IS_USER(s)) {

                            goto illegal_op;

                        }

                        gen_smc(s);

                    }

                } else {

                    op = (insn >> 20) & 7;

                    switch (op) {

                    case 0: /* msr cpsr.  */

                        if (arm_dc_feature(s, ARM_FEATURE_M)) {

                            tmp = load_reg(s, rn);

                            /* the constant is the mask and SYSm fields */

                            addr = tcg_const_i32(insn & 0xfff);

                            gen_helper_v7m_msr(cpu_env, addr, tmp);

                            tcg_temp_free_i32(addr);

                            tcg_temp_free_i32(tmp);

                            gen_lookup_tb(s);

                            break;

                        }

                        /* fall through */

                    case 1: /* msr spsr.  */

                        if (arm_dc_feature(s, ARM_FEATURE_M)) {

                            goto illegal_op;

                        }

                        if (extract32(insn, 5, 1)) {

                            /* MSR (banked) */

                            int sysm = extract32(insn, 8, 4) |

                                (extract32(insn, 4, 1) << 4);

                            int r = op & 1;

                            gen_msr_banked(s, r, sysm, rm);

                            break;

                        }

                        /* MSR (for PSRs) */

                        tmp = load_reg(s, rn);

                        if (gen_set_psr(s,

                              msr_mask(s, (insn >> 8) & 0xf, op == 1),

                              op == 1, tmp))

                            goto illegal_op;

                        break;

                    case 2: /* cps, nop-hint.  */

                        if (((insn >> 8) & 7) == 0) {

                            gen_nop_hint(s, insn & 0xff);

                        }

                        /* Implemented as NOP in user mode.  */

                        if (IS_USER(s))

                            break;

                        offset = 0;

                        imm = 0;

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

                            if (insn & (1 << 7))

                                offset |= CPSR_A;

                            if (insn & (1 << 6))

                                offset |= CPSR_I;

                            if (insn & (1 << 5))

                                offset |= CPSR_F;

                            if (insn & (1 << 9))

                                imm = CPSR_A | CPSR_I | CPSR_F;

                        }

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

                            offset |= 0x1f;

                            imm |= (insn & 0x1f);

                        }

                        if (offset) {

                            gen_set_psr_im(s, offset, 0, imm);

                        }

                        break;

                    case 3: /* Special control operations.  */

                        ARCH(7);

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

                        switch (op) {

                        case 2: /* clrex */

                            gen_clrex(s);

                            break;

                        case 4: /* dsb */

                        case 5: /* dmb */

                            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);

                            break;

                        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_goto_tb(s, 0, s->pc & ~1);

                            break;

                        default:

                            goto illegal_op;

                        }

                        break;

                    case 4: /* bxj */

                        /* Trivial implementation equivalent to bx.

                         * This instruction doesn't exist at all for M-profile.

                         */

                        if (arm_dc_feature(s, ARM_FEATURE_M)) {

                            goto illegal_op;

                        }

                        tmp = load_reg(s, rn);

                        gen_bx(s, tmp);

                        break;

                    case 5: /* Exception return.  */

                        if (IS_USER(s)) {

                            goto illegal_op;

                        }

                        if (rn != 14 || rd != 15) {

                            goto illegal_op;

                        }

                        tmp = load_reg(s, rn);

                        tcg_gen_subi_i32(tmp, tmp, insn & 0xff);

                        gen_exception_return(s, tmp);

                        break;

                    case 6: /* MRS */

                        if (extract32(insn, 5, 1) &&

                            !arm_dc_feature(s, ARM_FEATURE_M)) {

                            /* MRS (banked) */

                            int sysm = extract32(insn, 16, 4) |

                                (extract32(insn, 4, 1) << 4);

                            gen_mrs_banked(s, 0, sysm, rd);

                            break;

                        }

                        if (extract32(insn, 16, 4) != 0xf) {

                            goto illegal_op;

                        }

                        if (!arm_dc_feature(s, ARM_FEATURE_M) &&

                            extract32(insn, 0, 8) != 0) {

                            goto illegal_op;

                        }

                        /* mrs cpsr */

                        tmp = tcg_temp_new_i32();

                        if (arm_dc_feature(s, ARM_FEATURE_M)) {

                            addr = tcg_const_i32(insn & 0xff);

                            gen_helper_v7m_mrs(tmp, cpu_env, addr);

                            tcg_temp_free_i32(addr);

                        } else {

                            gen_helper_cpsr_read(tmp, cpu_env);

                        }

                        store_reg(s, rd, tmp);

                        break;

                    case 7: /* MRS */

                        if (extract32(insn, 5, 1) &&

                            !arm_dc_feature(s, ARM_FEATURE_M)) {

                            /* MRS (banked) */

                            int sysm = extract32(insn, 16, 4) |

                                (extract32(insn, 4, 1) << 4);

                            gen_mrs_banked(s, 1, sysm, rd);

                            break;

                        }

                        /* mrs spsr.  */

                        /* Not accessible in user mode.  */

                        if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {

                            goto illegal_op;

                        }

                        if (extract32(insn, 16, 4) != 0xf ||

                            extract32(insn, 0, 8) != 0) {

                            goto illegal_op;

                        }

                        tmp = load_cpu_field(spsr);

                        store_reg(s, rd, tmp);

                        break;

                    }

                }

            } else {

                /* Conditional branch.  */

                op = (insn >> 22) & 0xf;

                /* Generate a conditional jump to next instruction.  */

                s->condlabel = gen_new_label();

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

                s->condjmp = 1;

                /* offset[11:1] = insn[10:0] */

                offset = (insn & 0x7ff) << 1;

                /* offset[17:12] = insn[21:16].  */

                offset |= (insn & 0x003f0000) >> 4;

                /* offset[31:20] = insn[26].  */

                offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;

                /* offset[18] = insn[13].  */

                offset |= (insn & (1 << 13)) << 5;

                /* offset[19] = insn[11].  */

                offset |= (insn & (1 << 11)) << 8;

                /* jump to the offset */

                gen_jmp(s, s->pc + offset);

            }

        } else {

            /* Data processing immediate.  */

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

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

                    if (insn & (1 << 20))

                        goto illegal_op;

                    /* Bitfield/Saturate.  */

                    op = (insn >> 21) & 7;

                    imm = insn & 0x1f;

                    shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);

                    if (rn == 15) {

                        tmp = tcg_temp_new_i32();

                        tcg_gen_movi_i32(tmp, 0);

                    } else {

                        tmp = load_reg(s, rn);

                    }

                    switch (op) {

                    case 2: /* Signed bitfield extract.  */

                        imm++;

                        if (shift + imm > 32)

                            goto illegal_op;

                        if (imm < 32) {

                            tcg_gen_sextract_i32(tmp, tmp, shift, imm);

                        }

                        break;

                    case 6: /* Unsigned bitfield extract.  */

                        imm++;

                        if (shift + imm > 32)

                            goto illegal_op;

                        if (imm < 32) {

                            tcg_gen_extract_i32(tmp, tmp, shift, imm);

                        }

                        break;

                    case 3: /* Bitfield insert/clear.  */

                        if (imm < shift)

                            goto illegal_op;

                        imm = imm + 1 - shift;

                        if (imm != 32) {

                            tmp2 = load_reg(s, rd);

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

                            tcg_temp_free_i32(tmp2);

                        }

                        break;

                    case 7:

                        goto illegal_op;

                    default: /* Saturate.  */

                        if (shift) {

                            if (op & 1)

                                tcg_gen_sari_i32(tmp, tmp, shift);

                            else

                                tcg_gen_shli_i32(tmp, tmp, shift);

                        }

                        tmp2 = tcg_const_i32(imm);

                        if (op & 4) {

                            /* Unsigned.  */

                            if ((op & 1) && shift == 0) {

                                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                                    tcg_temp_free_i32(tmp);

                                    tcg_temp_free_i32(tmp2);

                                    goto illegal_op;

                                }

                                gen_helper_usat16(tmp, cpu_env, tmp, tmp2);

                            } else {

                                gen_helper_usat(tmp, cpu_env, tmp, tmp2);

                            }

                        } else {

                            /* Signed.  */

                            if ((op & 1) && shift == 0) {

                                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {

                                    tcg_temp_free_i32(tmp);

                                    tcg_temp_free_i32(tmp2);

                                    goto illegal_op;

                                }

                                gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);

                            } else {

                                gen_helper_ssat(tmp, cpu_env, tmp, tmp2);

                            }

                        }

                        tcg_temp_free_i32(tmp2);

                        break;

                    }

                    store_reg(s, rd, tmp);

                } else {

                    imm = ((insn & 0x04000000) >> 15)

                          | ((insn & 0x7000) >> 4) | (insn & 0xff);

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

                        /* 16-bit immediate.  */

                        imm |= (insn >> 4) & 0xf000;

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

                            /* movt */

                            tmp = load_reg(s, rd);

                            tcg_gen_ext16u_i32(tmp, tmp);

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

                        } else {

                            /* movw */

                            tmp = tcg_temp_new_i32();

                            tcg_gen_movi_i32(tmp, imm);

                        }

                    } else {

                        /* Add/sub 12-bit immediate.  */

                        if (rn == 15) {

                            offset = s->pc & ~(uint32_t)3;

                            if (insn & (1 << 23))

                                offset -= imm;

                            else

                                offset += imm;

                            tmp = tcg_temp_new_i32();

                            tcg_gen_movi_i32(tmp, offset);

                        } else {

                            tmp = load_reg(s, rn);

                            if (insn & (1 << 23))

                                tcg_gen_subi_i32(tmp, tmp, imm);

                            else

                                tcg_gen_addi_i32(tmp, tmp, imm);

                        }

                    }

                    store_reg(s, rd, tmp);

                }

            } else {

                int shifter_out = 0;

                /* modified 12-bit immediate.  */

                shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);

                imm = (insn & 0xff);

                switch (shift) {

                case 0: /* XY */

                    /* Nothing to do.  */

                    break;

                case 1: /* 00XY00XY */

                    imm |= imm << 16;

                    break;

                case 2: /* XY00XY00 */

                    imm |= imm << 16;

                    imm <<= 8;

                    break;

                case 3: /* XYXYXYXY */

                    imm |= imm << 16;

                    imm |= imm << 8;

                    break;

                default: /* Rotated constant.  */

                    shift = (shift << 1) | (imm >> 7);

                    imm |= 0x80;

                    imm = imm << (32 - shift);

                    shifter_out = 1;

                    break;

                }

                tmp2 = tcg_temp_new_i32();

                tcg_gen_movi_i32(tmp2, imm);

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

                if (rn == 15) {

                    tmp = tcg_temp_new_i32();

                    tcg_gen_movi_i32(tmp, 0);

                } else {

                    tmp = load_reg(s, rn);

                }

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

                if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,

                                       shifter_out, tmp, tmp2))

                    goto illegal_op;

                tcg_temp_free_i32(tmp2);

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

                if (rd != 15) {

                    store_reg(s, rd, tmp);

                } else {

                    tcg_temp_free_i32(tmp);

                }

            }

        }

        break;

    case 12: /* Load/store single data item.  */

        {

        int postinc = 0;

        int writeback = 0;

        int memidx;

        ISSInfo issinfo;

        if ((insn & 0x01100000) == 0x01000000) {

            if (disas_neon_ls_insn(s, insn)) {

                goto illegal_op;

            }

            break;

        }

        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);

        if (rs == 15) {

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

                goto illegal_op;

            }

            if (op != 2) {

                /* Byte or halfword load space with dest == r15 : memory hints.

                 * Catch them early so we don't emit pointless addressing code.

                 * This space is a mix of:

                 *  PLD/PLDW/PLI,  which we implement as NOPs (note that unlike

                 *     the ARM encodings, PLDW space doesn't UNDEF for non-v7MP

                 *     cores)

                 *  unallocated hints, which must be treated as NOPs

                 *  UNPREDICTABLE space, which we NOP or UNDEF depending on

                 *     which is easiest for the decoding logic

                 *  Some space which must UNDEF

                 */

                int op1 = (insn >> 23) & 3;

                int op2 = (insn >> 6) & 0x3f;

                if (op & 2) {

                    goto illegal_op;

                }

                if (rn == 15) {

                    /* UNPREDICTABLE, unallocated hint or

                     * PLD/PLDW/PLI (literal)

                     */

                    return 0;

                }

                if (op1 & 1) {

                    return 0; /* PLD/PLDW/PLI or unallocated hint */

                }

                if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {

                    return 0; /* PLD/PLDW/PLI or unallocated hint */

                }

                /* UNDEF space, or an UNPREDICTABLE */

                return 1;

            }

        }

        memidx = get_mem_index(s);

        if (rn == 15) {

            addr = tcg_temp_new_i32();

            /* PC relative.  */

            /* s->pc has already been incremented by 4.  */

            imm = s->pc & 0xfffffffc;

            if (insn & (1 << 23))

                imm += insn & 0xfff;

            else

                imm -= insn & 0xfff;

            tcg_gen_movi_i32(addr, imm);

        } else {

            addr = load_reg(s, rn);

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

                /* Positive offset.  */

                imm = insn & 0xfff;

                tcg_gen_addi_i32(addr, addr, imm);

            } else {

                imm = insn & 0xff;

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

                case 0x0: /* Shifted Register.  */

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

                    if (shift > 3) {

                        tcg_temp_free_i32(addr);

                        goto illegal_op;

                    }

                    tmp = load_reg(s, rm);

                    if (shift)

                        tcg_gen_shli_i32(tmp, tmp, shift);

                    tcg_gen_add_i32(addr, addr, tmp);

                    tcg_temp_free_i32(tmp);

                    break;

                case 0xc: /* Negative offset.  */

                    tcg_gen_addi_i32(addr, addr, -imm);

                    break;

                case 0xe: /* User privilege.  */

                    tcg_gen_addi_i32(addr, addr, imm);

                    memidx = get_a32_user_mem_index(s);

                    break;

                case 0x9: /* Post-decrement.  */

                    imm = -imm;

                    /* Fall through.  */

                case 0xb: /* Post-increment.  */

                    postinc = 1;

                    writeback = 1;

                    break;

                case 0xd: /* Pre-decrement.  */

                    imm = -imm;

                    /* Fall through.  */

                case 0xf: /* Pre-increment.  */

                    tcg_gen_addi_i32(addr, addr, imm);

                    writeback = 1;

                    break;

                default:

                    tcg_temp_free_i32(addr);

                    goto illegal_op;

                }

            }

        }

        issinfo = writeback ? ISSInvalid : rs;

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

            /* Load.  */

            tmp = tcg_temp_new_i32();

            switch (op) {

            case 0:

                gen_aa32_ld8u_iss(s, tmp, addr, memidx, issinfo);

                break;

            case 4:

                gen_aa32_ld8s_iss(s, tmp, addr, memidx, issinfo);

                break;

            case 1:

                gen_aa32_ld16u_iss(s, tmp, addr, memidx, issinfo);

                break;

            case 5:

                gen_aa32_ld16s_iss(s, tmp, addr, memidx, issinfo);

                break;

            case 2:

                gen_aa32_ld32u_iss(s, tmp, addr, memidx, issinfo);

                break;

            default:

                tcg_temp_free_i32(tmp);

                tcg_temp_free_i32(addr);

                goto illegal_op;

            }

            if (rs == 15) {

                gen_bx_excret(s, tmp);

            } else {

                store_reg(s, rs, tmp);

            }

        } else {

            /* Store.  */

            tmp = load_reg(s, rs);

            switch (op) {

            case 0:

                gen_aa32_st8_iss(s, tmp, addr, memidx, issinfo);

                break;

            case 1:

                gen_aa32_st16_iss(s, tmp, addr, memidx, issinfo);

                break;

            case 2:

                gen_aa32_st32_iss(s, tmp, addr, memidx, issinfo);

                break;

            default:

                tcg_temp_free_i32(tmp);

                tcg_temp_free_i32(addr);

                goto illegal_op;

            }

            tcg_temp_free_i32(tmp);

        }

        if (postinc)

            tcg_gen_addi_i32(addr, addr, imm);

        if (writeback) {

            store_reg(s, rn, addr);

        } else {

            tcg_temp_free_i32(addr);

        }

        }

        break;

    default:

        goto illegal_op;

    }

    return 0;

illegal_op:

    return 1;

}


static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)

{

    uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),

                                cpu_to_be32(0x0), cpu_to_be32(0x0),

                                cpu_to_be32(0x0)};

    char mem_name[32];

    hwaddr node0_size, mem_start;

    uint64_t mem_reg_property[2];

    int i, off;

    /* memory node(s) */

    node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;

    /* RMA */

    mem_reg_property[0] = 0;

    mem_reg_property[1] = cpu_to_be64(spapr->rma_size);

    off = fdt_add_subnode(fdt, 0, "memory@0");

    _FDT(off);

    _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));

    _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,

                      sizeof(mem_reg_property))));

    _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,

                      sizeof(associativity))));

    /* RAM: Node 0 */

    if (node0_size > spapr->rma_size) {

        mem_reg_property[0] = cpu_to_be64(spapr->rma_size);

        mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size);

        sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size);

        off = fdt_add_subnode(fdt, 0, mem_name);

        _FDT(off);

        _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));

        _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,

                          sizeof(mem_reg_property))));

        _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,

                          sizeof(associativity))));

    }

    /* RAM: Node 1 and beyond */

    mem_start = node0_size;

    for (i = 1; i < nb_numa_nodes; i++) {

        mem_reg_property[0] = cpu_to_be64(mem_start);

        mem_reg_property[1] = cpu_to_be64(node_mem[i]);

        associativity[3] = associativity[4] = cpu_to_be32(i);

        sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);

        off = fdt_add_subnode(fdt, 0, mem_name);

        _FDT(off);

        _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));

        _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,

                          sizeof(mem_reg_property))));

        _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,

                          sizeof(associativity))));

        mem_start += node_mem[i];

    }

    return 0;

}


static void migrate_fd_put_notify(void *opaque)

{

    MigrationState *s = opaque;

    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);

    qemu_file_put_notify(s->file);

    if (qemu_file_get_error(s->file)) {

        migrate_fd_error(s);

    }

}


ParallelState *parallel_init(int index, CharDriverState *chr)

{

    ISADevice *dev;

    dev = isa_create("isa-parallel");

    qdev_prop_set_uint32(&dev->qdev, "index", index);

    qdev_prop_set_chr(&dev->qdev, "chardev", chr);

    if (qdev_init(&dev->qdev) < 0)

        return NULL;

    return &DO_UPCAST(ISAParallelState, dev, dev)->state;

}


static void main_loop(void)

{

    int r;

#ifdef CONFIG_IOTHREAD

    qemu_system_ready = 1;

    qemu_cond_broadcast(&qemu_system_cond);

#endif

    for (;;) {

        do {

#ifdef CONFIG_PROFILER

            int64_t ti;

#endif

#ifndef CONFIG_IOTHREAD

            tcg_cpu_exec();

#endif

#ifdef CONFIG_PROFILER

            ti = profile_getclock();

#endif

            main_loop_wait(qemu_calculate_timeout());

#ifdef CONFIG_PROFILER

            dev_time += profile_getclock() - ti;

#endif

        } while (vm_can_run());

        if (qemu_debug_requested()) {

            monitor_protocol_event(QEVENT_DEBUG, NULL);

            vm_stop(EXCP_DEBUG);

        }

        if (qemu_shutdown_requested()) {

            monitor_protocol_event(QEVENT_SHUTDOWN, NULL);

            if (no_shutdown) {

                vm_stop(0);

                no_shutdown = 0;

            } else

                break;

        }

        if (qemu_reset_requested()) {

            monitor_protocol_event(QEVENT_RESET, NULL);

            pause_all_vcpus();

            qemu_system_reset();

            resume_all_vcpus();

        }

        if (qemu_powerdown_requested()) {

            monitor_protocol_event(QEVENT_POWERDOWN, NULL);

            qemu_irq_raise(qemu_system_powerdown);

        }

        if ((r = qemu_vmstop_requested())) {

            vm_stop(r);

        }

    }

    pause_all_vcpus();

}


static void qpi_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)

{

}


uint64_t cpu_get_tsc(CPUX86State *env)

{

    /* Note: when using kqemu, it is more logical to return the host TSC

       because kqemu does not trap the RDTSC instruction for

       performance reasons */

#ifdef CONFIG_KQEMU

    if (env->kqemu_enabled) {

        return cpu_get_real_ticks();

    } else

#endif

    {

        return cpu_get_ticks();

    }

}


void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)

{

    uint64_t r;

    switch (num) {

    case 0x500:

        /* KVM hypercall */

        qemu_mutex_lock_iothread();

        r = s390_virtio_hypercall(env);

        qemu_mutex_unlock_iothread();

        break;

    case 0x44:

        /* yield */

        r = 0;

        break;

    case 0x308:

        /* ipl */

        handle_diag_308(env, r1, r3);

        r = 0;

        break;

    default:

        r = -1;

        break;

    }

    if (r) {

        program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);

    }

}


static void piix3_write_config(PCIDevice *dev,

                               uint32_t address, uint32_t val, int len)

{

    pci_default_write_config(dev, address, val, len);

    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {

        PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);

        int pic_irq;

        pci_bus_fire_intx_routing_notifier(piix3->dev.bus);

        piix3_update_irq_levels(piix3);

        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {

            piix3_set_irq_pic(piix3, pic_irq);

        }

    }

}


static void idcin_decode_vlcs(IdcinContext *s)

{

    hnode_t *hnodes;

    long x, y;

    int prev;

    unsigned char v = 0;

    int bit_pos, node_num, dat_pos;

    prev = bit_pos = dat_pos = 0;

    for (y = 0; y < (s->frame.linesize[0] * s->avctx->height);

        y += s->frame.linesize[0]) {

        for (x = y; x < y + s->avctx->width; x++) {

            node_num = s->num_huff_nodes[prev];

            hnodes = s->huff_nodes[prev];

            while(node_num >= HUF_TOKENS) {

                if(!bit_pos) {

                    if(dat_pos > s->size) {

                        av_log(s->avctx, AV_LOG_ERROR, "Huffman decode error.\n");

                        return;

                    }

                    bit_pos = 8;

                    v = s->buf[dat_pos++];

                }

                node_num = hnodes[node_num].children[v & 0x01];

                v = v >> 1;

                bit_pos--;

            }

            s->frame.data[0][x] = node_num;

            prev = node_num;

        }

    }

}


static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,

                               AVFrame *p, AVPacket *avpkt)

{

    AVDictionary *metadata  = NULL;

    uint32_t tag, length;

    int decode_next_dat = 0;

    int ret;

    for (;;) {

        length = bytestream2_get_bytes_left(&s->gb);

        if (length <= 0) {

            if (CONFIG_APNG_DECODER && avctx->codec_id == AV_CODEC_ID_APNG && length == 0) {

                if (!(s->state & PNG_IDAT))

                    return 0;

                else

                    goto exit_loop;

            }

            av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", length);

            if (   s->state & PNG_ALLIMAGE

                && avctx->strict_std_compliance <= FF_COMPLIANCE_NORMAL)

                goto exit_loop;

            ret = AVERROR_INVALIDDATA;

            goto fail;

        }

        length = bytestream2_get_be32(&s->gb);

        if (length > 0x7fffffff || length > bytestream2_get_bytes_left(&s->gb)) {

            av_log(avctx, AV_LOG_ERROR, "chunk too big\n");

            ret = AVERROR_INVALIDDATA;

            goto fail;

        }

        tag = bytestream2_get_le32(&s->gb);

        if (avctx->debug & FF_DEBUG_STARTCODE)

            av_log(avctx, AV_LOG_DEBUG, "png: tag=%c%c%c%c length=%u\n",

                (tag & 0xff),

                ((tag >> 8) & 0xff),

                ((tag >> 16) & 0xff),

                ((tag >> 24) & 0xff), length);

        switch (tag) {

        case MKTAG('I', 'H', 'D', 'R'):

            if ((ret = decode_ihdr_chunk(avctx, s, length)) < 0)

                goto fail;

            break;

        case MKTAG('p', 'H', 'Y', 's'):

            if ((ret = decode_phys_chunk(avctx, s)) < 0)

                goto fail;

            break;

        case MKTAG('f', 'c', 'T', 'L'):

            if (!CONFIG_APNG_DECODER || avctx->codec_id != AV_CODEC_ID_APNG)

                goto skip_tag;

            if ((ret = decode_fctl_chunk(avctx, s, length)) < 0)

                goto fail;

            decode_next_dat = 1;

            break;

        case MKTAG('f', 'd', 'A', 'T'):

            if (!CONFIG_APNG_DECODER || avctx->codec_id != AV_CODEC_ID_APNG)

                goto skip_tag;

            if (!decode_next_dat) {

                ret = AVERROR_INVALIDDATA;

                goto fail;

            }

            bytestream2_get_be32(&s->gb);

            length -= 4;

            /* fallthrough */

        case MKTAG('I', 'D', 'A', 'T'):

            if (CONFIG_APNG_DECODER && avctx->codec_id == AV_CODEC_ID_APNG && !decode_next_dat)

                goto skip_tag;

            if ((ret = decode_idat_chunk(avctx, s, length, p)) < 0)

                goto fail;

            break;

        case MKTAG('P', 'L', 'T', 'E'):

            if (decode_plte_chunk(avctx, s, length) < 0)

                goto skip_tag;

            break;

        case MKTAG('t', 'R', 'N', 'S'):

            if (decode_trns_chunk(avctx, s, length) < 0)

                goto skip_tag;

            break;

        case MKTAG('t', 'E', 'X', 't'):

            if (decode_text_chunk(s, length, 0, &metadata) < 0)

                av_log(avctx, AV_LOG_WARNING, "Broken tEXt chunk\n");

            bytestream2_skip(&s->gb, length + 4);

            break;

        case MKTAG('z', 'T', 'X', 't'):

            if (decode_text_chunk(s, length, 1, &metadata) < 0)

                av_log(avctx, AV_LOG_WARNING, "Broken zTXt chunk\n");

            bytestream2_skip(&s->gb, length + 4);

            break;

        case MKTAG('I', 'E', 'N', 'D'):

            if (!(s->state & PNG_ALLIMAGE))

                av_log(avctx, AV_LOG_ERROR, "IEND without all image\n");

            if (!(s->state & (PNG_ALLIMAGE|PNG_IDAT))) {

                ret = AVERROR_INVALIDDATA;

                goto fail;

            }

            bytestream2_skip(&s->gb, 4); /* crc */

            goto exit_loop;

        default:

            /* skip tag */

skip_tag:

            bytestream2_skip(&s->gb, length + 4);

            break;

        }

    }

exit_loop:

    if (s->bits_per_pixel <= 4)

        handle_small_bpp(s, p);

    /* apply transparency if needed */

    if (s->has_trns && s->color_type != PNG_COLOR_TYPE_PALETTE) {

        size_t byte_depth = s->bit_depth > 8 ? 2 : 1;

        size_t raw_bpp = s->bpp - byte_depth;

        unsigned x, y;

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

            uint8_t *row = &s->image_buf[s->image_linesize * y];

            /* since we're updating in-place, we have to go from right to left */

            for (x = s->width; x > 0; --x) {

                uint8_t *pixel = &row[s->bpp * (x - 1)];

                memmove(pixel, &row[raw_bpp * (x - 1)], raw_bpp);

                if (!memcmp(pixel, s->transparent_color_be, raw_bpp)) {

                    memset(&pixel[raw_bpp], 0, byte_depth);

                } else {

                    memset(&pixel[raw_bpp], 0xff, byte_depth);

                }

            }

        }

    }

    /* handle p-frames only if a predecessor frame is available */

    if (s->last_picture.f->data[0]) {

        if (   !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")

            && s->last_picture.f->width == p->width

            && s->last_picture.f->height== p->height

            && s->last_picture.f->format== p->format

         ) {

            if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG)

                handle_p_frame_png(s, p);

            else if (CONFIG_APNG_DECODER &&

                     avctx->codec_id == AV_CODEC_ID_APNG &&

                     (ret = handle_p_frame_apng(avctx, s, p)) < 0)

                goto fail;

        }

    }

    ff_thread_report_progress(&s->picture, INT_MAX, 0);

    av_frame_set_metadata(p, metadata);

    metadata   = NULL;

    return 0;

fail:

    av_dict_free(&metadata);

    ff_thread_report_progress(&s->picture, INT_MAX, 0);

    return ret;

}


void helper_idivq_EAX_T0(void)

{

    uint64_t r0, r1;

    if (T0 == 0) {

        raise_exception(EXCP00_DIVZ);

    }

    r0 = EAX;

    r1 = EDX;

    idiv64(&r0, &r1, T0);

    EAX = r0;

    EDX = r1;

}


static void start_children(FFServerStream *feed)

{

    char *pathname;

    char *slash;

    int i;

    size_t cmd_length;

    if (no_launch)

        return;

    cmd_length = strlen(my_program_name);

   /**

    * FIXME: WIP Safeguard. Remove after clearing all harcoded

    * '1024' path lengths

    */

    if (cmd_length > PATH_LENGTH - 1) {

        http_log("Could not start children. Command line: '%s' exceeds "

                    "path length limit (%d)\n", my_program_name, PATH_LENGTH);

        return;

    }

    pathname = av_strdup (my_program_name);

    if (!pathname) {

        http_log("Could not allocate memory for children cmd line\n");

        return;

    }

   /* replace "ffserver" with "ffmpeg" in the path of current

    * program. Ignore user provided path */

    slash = strrchr(pathname, '/');

    if (!slash)

        slash = pathname;

    else

        slash++;

    strcpy(slash, "ffmpeg");

    for (; feed; feed = feed->next) {

        if (!feed->child_argv || feed->pid)

            continue;

        feed->pid_start = time(0);

        feed->pid = fork();

        if (feed->pid < 0) {

            http_log("Unable to create children: %s\n", strerror(errno));

            av_free (pathname);

            exit(EXIT_FAILURE);

        }

        if (feed->pid)

            continue;

        /* In child */

        http_log("Launch command line: ");

        http_log("%s ", pathname);

        for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)

            http_log("%s ", feed->child_argv[i]);

        http_log("\n");

        for (i = 3; i < 256; i++)

            close(i);

        if (!config.debug) {

            if (!freopen("/dev/null", "r", stdin))

                http_log("failed to redirect STDIN to /dev/null\n;");

            if (!freopen("/dev/null", "w", stdout))

                http_log("failed to redirect STDOUT to /dev/null\n;");

            if (!freopen("/dev/null", "w", stderr))

                http_log("failed to redirect STDERR to /dev/null\n;");

        }

        signal(SIGPIPE, SIG_DFL);

        execvp(pathname, feed->child_argv);

        av_free (pathname);

        _exit(1);

    }

    av_free (pathname);

}


static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)

{

    struct dshow_ctx *ctx = s->priv_data;

    AVPacketList *pktl = NULL;

    while (!ctx->eof && !pktl) {

        WaitForSingleObject(ctx->mutex, INFINITE);

        pktl = ctx->pktl;

        if (pktl) {

            *pkt = pktl->pkt;

            ctx->pktl = ctx->pktl->next;

            av_free(pktl);

            ctx->curbufsize -= pkt->size;

        }

        ResetEvent(ctx->event[1]);

        ReleaseMutex(ctx->mutex);

        if (!pktl) {

            if (dshow_check_event_queue(ctx->media_event) < 0) {

                ctx->eof = 1;

            } else if (s->flags & AVFMT_FLAG_NONBLOCK) {

                return AVERROR(EAGAIN);

            } else {

                WaitForMultipleObjects(2, ctx->event, 0, INFINITE);

            }

        }

    }

    return ctx->eof ? AVERROR(EIO) : pkt->size;

}


static void vmxnet3_update_pm_state(VMXNET3State *s)

{

    struct Vmxnet3_VariableLenConfDesc pm_descr;

    pm_descr.confLen =

        VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confLen);

    pm_descr.confVer =

        VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confVer);

    pm_descr.confPA =

        VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.pmConfDesc.confPA);

    vmxnet3_dump_conf_descr("PM State", &pm_descr);

}


static int adx_encode_frame(AVCodecContext *avctx,

			    unsigned char *frame, int buf_size, const void *data)

{

	ADXContext *c = avctx->priv_data;

	const short *samples = data;

	unsigned char *dst = frame;

	int rest = avctx->frame_size;

/*

	input data size =

	ffmpeg.c: do_audio_out()

	frame_bytes = enc->frame_size * 2 * enc->channels;

*/

//	printf("sz=%d ",buf_size); fflush(stdout);

	if (!c->header_parsed) {

		int hdrsize = adx_encode_header(avctx,dst,buf_size);

		dst+=hdrsize;

		c->header_parsed = 1;

	}

	if (avctx->channels==1) {

		while(rest>=32) {

			adx_encode(dst,samples,c->prev);

			dst+=18;

			samples+=32;

			rest-=32;

		}

	} else {

		while(rest>=32*2) {

			short tmpbuf[32*2];

			int i;

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

				tmpbuf[i] = samples[i*2];

				tmpbuf[i+32] = samples[i*2+1];

			}

			adx_encode(dst,tmpbuf,c->prev);

			adx_encode(dst+18,tmpbuf+32,c->prev+1);

			dst+=18*2;

			samples+=32*2;

			rest-=32*2;

		}

	}

	return dst-frame;

}


void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)

{

    int i;

    uint32_t changed;

    changed = env->vfp.xregs[ARM_VFP_FPSCR];

    env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff);

    env->vfp.vec_len = (val >> 16) & 7;

    env->vfp.vec_stride = (val >> 20) & 3;

    changed ^= val;

    if (changed & (3 << 22)) {

        i = (val >> 22) & 3;

        switch (i) {

        case 0:

            i = float_round_nearest_even;

            break;

        case 1:

            i = float_round_up;

            break;

        case 2:

            i = float_round_down;

            break;

        case 3:

            i = float_round_to_zero;

            break;

        }

        set_float_rounding_mode(i, &env->vfp.fp_status);

    }

    if (changed & (1 << 24))

        set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);

    if (changed & (1 << 25))

        set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);

    i = vfp_exceptbits_to_host(val);

    set_float_exception_flags(i, &env->vfp.fp_status);

}


static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)

{

    VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);

    DeviceState *vdev = DEVICE(&dev->vdev);

    virtio_blk_set_conf(vdev, &(dev->blk));

    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));

    if (qdev_init(vdev) < 0) {

        return -1;

    }

    return 0;

}


void ff_convert_matrix(DSPContext *dsp, int (*qmat)[64],

                       uint16_t (*qmat16)[2][64],

                       const uint16_t *quant_matrix,

                       int bias, int qmin, int qmax, int intra)

{

    int qscale;

    int shift = 0;

    for (qscale = qmin; qscale <= qmax; qscale++) {

        int i;

        if (dsp->fdct == ff_jpeg_fdct_islow_8 ||

            dsp->fdct == ff_jpeg_fdct_islow_10 ||

            dsp->fdct == ff_faandct) {

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

                const int j = dsp->idct_permutation[i];

                /* 16 <= qscale * quant_matrix[i] <= 7905

                 * Assume x = ff_aanscales[i] * qscale * quant_matrix[i]

                 *             19952 <=              x  <= 249205026

                 * (1 << 36) / 19952 >= (1 << 36) / (x) >= (1 << 36) / 249205026

                 *           3444240 >= (1 << 36) / (x) >= 275 */

                qmat[qscale][i] = (int)((UINT64_C(1) << QMAT_SHIFT) /

                                        (qscale * quant_matrix[j]));

            }

        } else if (dsp->fdct == ff_fdct_ifast) {

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

                const int j = dsp->idct_permutation[i];

                /* 16 <= qscale * quant_matrix[i] <= 7905

                 * Assume x = ff_aanscales[i] * qscale * quant_matrix[i]

                 *             19952 <=              x  <= 249205026

                 * (1 << 36) / 19952 >= (1 << 36) / (x) >= (1 << 36) / 249205026

                 *           3444240 >= (1 << 36) / (x) >= 275 */

                qmat[qscale][i] = (int)((UINT64_C(1) << (QMAT_SHIFT + 14)) /

                                        (ff_aanscales[i] * qscale * quant_matrix[j]));

            }

        } else {

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

                const int j = dsp->idct_permutation[i];

                /* We can safely suppose that 16 <= quant_matrix[i] <= 255

                 * Assume x = qscale * quant_matrix[i]

                 * So             16 <=              x  <= 7905

                 * so (1 << 19) / 16 >= (1 << 19) / (x) >= (1 << 19) / 7905

                 * so          32768 >= (1 << 19) / (x) >= 67 */

                qmat[qscale][i] = (int)((UINT64_C(1) << QMAT_SHIFT) /

                                        (qscale * quant_matrix[j]));

                //qmat  [qscale][i] = (1 << QMAT_SHIFT_MMX) /

                //                    (qscale * quant_matrix[i]);

                qmat16[qscale][0][i] = (1 << QMAT_SHIFT_MMX) /

                                       (qscale * quant_matrix[j]);

                if (qmat16[qscale][0][i] == 0 ||

                    qmat16[qscale][0][i] == 128 * 256)

                    qmat16[qscale][0][i] = 128 * 256 - 1;

                qmat16[qscale][1][i] =

                    ROUNDED_DIV(bias << (16 - QUANT_BIAS_SHIFT),

                                qmat16[qscale][0][i]);

            }

        }

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

            int64_t max = 8191;

            if (dsp->fdct == ff_fdct_ifast) {

                max = (8191LL * ff_aanscales[i]) >> 14;

            }

            while (((max * qmat[qscale][i]) >> shift) > INT_MAX) {

                shift++;

            }

        }

    }

    if (shift) {

        av_log(NULL, AV_LOG_INFO,

               "Warning, QMAT_SHIFT is larger than %d, overflows possible\n",

               QMAT_SHIFT - shift);

    }

}


static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)

{

    /* no traces of 44100 and 32000Hz in any commercial software or player */

    static const uint32_t frequencies[4] = { 48000, 96000, 44100, 32000 };

    PCMDVDContext *s = avctx->priv_data;

    int header_int = (header[0] & 0xe0) | (header[1] << 8) | (header[2] << 16);

    /* early exit if the header didn't change apart from the frame number */

    if (s->last_header == header_int)

        return 0;

    if (avctx->debug & FF_DEBUG_PICT_INFO)

        av_dlog(avctx, "pcm_dvd_parse_header: header = %02x%02x%02x\n",

                header[0], header[1], header[2]);

    /*

     * header[0] emphasis (1), muse(1), reserved(1), frame number(5)

     * header[1] quant (2), freq(2), reserved(1), channels(3)

     * header[2] dynamic range control (0x80 = off)

     */

    /* Discard potentially existing leftover samples from old channel layout */

    s->extra_sample_count = 0;

    /* get the sample depth and derive the sample format from it */

    avctx->bits_per_coded_sample = 16 + (header[1] >> 6 & 3) * 4;

    if (avctx->bits_per_coded_sample == 28) {

        av_log(avctx, AV_LOG_ERROR,

               "PCM DVD unsupported sample depth %i\n",

               avctx->bits_per_coded_sample);

        return AVERROR_INVALIDDATA;

    }

    avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16

                                                           : AV_SAMPLE_FMT_S32;

    avctx->bits_per_raw_sample = avctx->bits_per_coded_sample;

    /* get the sample rate */

    avctx->sample_rate = frequencies[header[1] >> 4 & 3];

    /* get the number of channels */

    avctx->channels = 1 + (header[1] & 7);

    /* calculate the bitrate */

    avctx->bit_rate = avctx->channels *

                      avctx->sample_rate *

                      avctx->bits_per_coded_sample;

    /* 4 samples form a group in 20/24bit PCM on DVD Video.

     * A block is formed by the number of groups that are

     * needed to complete a set of samples for each channel. */

    if (avctx->bits_per_coded_sample == 16) {

        s->samples_per_block = 1;

        s->block_size        = avctx->channels * 2;

    } else {

        switch (avctx->channels) {

        case 1:

        case 2:

        case 4:

            /* one group has all the samples needed */

            s->block_size        = 4 * avctx->bits_per_coded_sample / 8;

            s->samples_per_block = 4 / avctx->channels;

            s->groups_per_block  = 1;

            break;

        case 8:

            /* two groups have all the samples needed */

            s->block_size        = 8 * avctx->bits_per_coded_sample / 8;

            s->samples_per_block = 1;

            s->groups_per_block  = 2;

            break;

        default:

            /* need avctx->channels groups */

            s->block_size        = 4 * avctx->channels *

                                   avctx->bits_per_coded_sample / 8;

            s->samples_per_block = 4;

            s->groups_per_block  = avctx->channels;

            break;

        }

    }

    if (avctx->debug & FF_DEBUG_PICT_INFO)

        av_dlog(avctx,

                "pcm_dvd_parse_header: %d channels, %d bits per sample, %d Hz, %d bit/s\n",

                avctx->channels, avctx->bits_per_coded_sample,

                avctx->sample_rate, avctx->bit_rate);

    s->last_header = header_int;

    return 0;

}


static int64_t nfs_client_open(NFSClient *client, QDict *options,

                               int flags, int open_flags, Error **errp)

{

    int ret = -EINVAL;

    QemuOpts *opts = NULL;

    Error *local_err = NULL;

    struct stat st;

    char *file = NULL, *strp = NULL;

    qemu_mutex_init(&client->mutex);

    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);

    qemu_opts_absorb_qdict(opts, options, &local_err);

    if (local_err) {

        error_propagate(errp, local_err);

        ret = -EINVAL;

        goto fail;

    }

    client->path = g_strdup(qemu_opt_get(opts, "path"));

    if (!client->path) {

        ret = -EINVAL;

        error_setg(errp, "No path was specified");

        goto fail;

    }

    strp = strrchr(client->path, '/');

    if (strp == NULL) {

        error_setg(errp, "Invalid URL specified");

        goto fail;

    }

    file = g_strdup(strp);

    *strp = 0;

    /* Pop the config into our state object, Exit if invalid */

    client->server = nfs_config(options, errp);

    if (!client->server) {

        ret = -EINVAL;

        goto fail;

    }

    client->context = nfs_init_context();

    if (client->context == NULL) {

        error_setg(errp, "Failed to init NFS context");

        goto fail;

    }

    if (qemu_opt_get(opts, "user")) {

        client->uid = qemu_opt_get_number(opts, "user", 0);

        nfs_set_uid(client->context, client->uid);

    }

    if (qemu_opt_get(opts, "group")) {

        client->gid = qemu_opt_get_number(opts, "group", 0);

        nfs_set_gid(client->context, client->gid);

    }

    if (qemu_opt_get(opts, "tcp-syn-count")) {

        client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);

        nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);

    }

#ifdef LIBNFS_FEATURE_READAHEAD

    if (qemu_opt_get(opts, "readahead-size")) {

        if (open_flags & BDRV_O_NOCACHE) {

            error_setg(errp, "Cannot enable NFS readahead "

                             "if cache.direct = on");

            goto fail;

        }

        client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);

        if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {

            warn_report("Truncating NFS readahead size to %d",

                        QEMU_NFS_MAX_READAHEAD_SIZE);

            client->readahead = QEMU_NFS_MAX_READAHEAD_SIZE;

        }

        nfs_set_readahead(client->context, client->readahead);

#ifdef LIBNFS_FEATURE_PAGECACHE

        nfs_set_pagecache_ttl(client->context, 0);

#endif

        client->cache_used = true;

    }

#endif

#ifdef LIBNFS_FEATURE_PAGECACHE

    if (qemu_opt_get(opts, "page-cache-size")) {

        if (open_flags & BDRV_O_NOCACHE) {

            error_setg(errp, "Cannot enable NFS pagecache "

                             "if cache.direct = on");

            goto fail;

        }

        client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);

        if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {

            warn_report("Truncating NFS pagecache size to %d pages",

                        QEMU_NFS_MAX_PAGECACHE_SIZE);

            client->pagecache = QEMU_NFS_MAX_PAGECACHE_SIZE;

        }

        nfs_set_pagecache(client->context, client->pagecache);

        nfs_set_pagecache_ttl(client->context, 0);

        client->cache_used = true;

    }

#endif

#ifdef LIBNFS_FEATURE_DEBUG

    if (qemu_opt_get(opts, "debug")) {

        client->debug = qemu_opt_get_number(opts, "debug", 0);

        /* limit the maximum debug level to avoid potential flooding

         * of our log files. */

        if (client->debug > QEMU_NFS_MAX_DEBUG_LEVEL) {

            warn_report("Limiting NFS debug level to %d",

                        QEMU_NFS_MAX_DEBUG_LEVEL);

            client->debug = QEMU_NFS_MAX_DEBUG_LEVEL;

        }

        nfs_set_debug(client->context, client->debug);

    }

#endif

    ret = nfs_mount(client->context, client->server->host, client->path);

    if (ret < 0) {

        error_setg(errp, "Failed to mount nfs share: %s",

                   nfs_get_error(client->context));

        goto fail;

    }

    if (flags & O_CREAT) {

        ret = nfs_creat(client->context, file, 0600, &client->fh);

        if (ret < 0) {

            error_setg(errp, "Failed to create file: %s",

                       nfs_get_error(client->context));

            goto fail;

        }

    } else {

        ret = nfs_open(client->context, file, flags, &client->fh);

        if (ret < 0) {

            error_setg(errp, "Failed to open file : %s",

                       nfs_get_error(client->context));

            goto fail;

        }

    }

    ret = nfs_fstat(client->context, client->fh, &st);

    if (ret < 0) {

        error_setg(errp, "Failed to fstat file: %s",

                   nfs_get_error(client->context));

        goto fail;

    }

    ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE);

    client->st_blocks = st.st_blocks;

    client->has_zero_init = S_ISREG(st.st_mode);

    *strp = '/';

    goto out;

fail:

    nfs_client_close(client);

out:

    qemu_opts_del(opts);

    g_free(file);

    return ret;

}


ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)

{

    if (so->s == -1 && so->extra) {

        qemu_chr_fe_write(so->extra, buf, len);

        return len;

    }

    return send(so->s, buf, len, flags);

}


static int diff_C(unsigned char *old, unsigned char *new, int os, int ns)

{

    int x, y, d=0;

    for (y = 8; y; y--) {

        for (x = 8; x; x--) {

            d += abs(new[x] - old[x]);

        }

        new += ns;

        old += os;

    }

    return d;

}


void do_icbi (void)

{

    uint32_t tmp;

    /* Invalidate one cache line :

     * PowerPC specification says this is to be treated like a load

     * (not a fetch) by the MMU. To be sure it will be so,

     * do the load "by hand".

     */

#if defined(TARGET_PPC64)

    if (!msr_sf)

        T0 &= 0xFFFFFFFFULL;

#endif

    tmp = ldl_kernel(T0);

    T0 &= ~(ICACHE_LINE_SIZE - 1);

    tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);

}


static int xen_pt_register_regions(XenPCIPassthroughState *s)

{

    int i = 0;

    XenHostPCIDevice *d = &s->real_device;

    /* Register PIO/MMIO BARs */

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

        XenHostPCIIORegion *r = &d->io_regions[i];

        uint8_t type;

        if (r->base_addr == 0 || r->size == 0) {

            continue;

        }

        s->bases[i].access.u = r->base_addr;

        if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {

            type = PCI_BASE_ADDRESS_SPACE_IO;

        } else {

            type = PCI_BASE_ADDRESS_SPACE_MEMORY;

            if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {

                type |= PCI_BASE_ADDRESS_MEM_PREFETCH;

            }

            if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {

                type |= PCI_BASE_ADDRESS_MEM_TYPE_64;

            }

        }

        memory_region_init_io(&s->bar[i], OBJECT(s), &ops, &s->dev,

                              "xen-pci-pt-bar", r->size);

        pci_register_bar(&s->dev, i, type, &s->bar[i]);

        XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64

                   " base_addr=0x%08"PRIx64" type: %#x)\n",

                   i, r->size, r->base_addr, type);

    }

    /* Register expansion ROM address */

    if (d->rom.base_addr && d->rom.size) {

        uint32_t bar_data = 0;

        /* Re-set BAR reported by OS, otherwise ROM can't be read. */

        if (xen_host_pci_get_long(d, PCI_ROM_ADDRESS, &bar_data)) {

            return 0;

        }

        if ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) {

            bar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK;

            xen_host_pci_set_long(d, PCI_ROM_ADDRESS, bar_data);

        }

        s->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr;

        memory_region_init_io(&s->rom, OBJECT(s), &ops, &s->dev,

                              "xen-pci-pt-rom", d->rom.size);

        pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_MEM_PREFETCH,

                         &s->rom);

        XEN_PT_LOG(&s->dev, "Expansion ROM registered (size=0x%08"PRIx64

                   " base_addr=0x%08"PRIx64")\n",

                   d->rom.size, d->rom.base_addr);

    }

    return 0;

}


void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,

                    int nr_sectors)

{

    BdrvDirtyBitmap *bitmap;

    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {

        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);

    }

}


av_cold void ff_vp8dsp_init_armv6(VP8DSPContext *dsp)

{

    dsp->vp8_luma_dc_wht    = ff_vp8_luma_dc_wht_armv6;

    dsp->vp8_luma_dc_wht_dc = ff_vp8_luma_dc_wht_dc_armv6;

    dsp->vp8_idct_add       = ff_vp8_idct_add_armv6;

    dsp->vp8_idct_dc_add    = ff_vp8_idct_dc_add_armv6;

    dsp->vp8_idct_dc_add4y  = ff_vp8_idct_dc_add4y_armv6;

    dsp->vp8_idct_dc_add4uv = ff_vp8_idct_dc_add4uv_armv6;

    dsp->vp8_v_loop_filter16y = ff_vp8_v_loop_filter16_armv6;

    dsp->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16_armv6;

    dsp->vp8_v_loop_filter8uv = ff_vp8_v_loop_filter8uv_armv6;

    dsp->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_armv6;

    dsp->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16_inner_armv6;

    dsp->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16_inner_armv6;

    dsp->vp8_v_loop_filter8uv_inner = ff_vp8_v_loop_filter8uv_inner_armv6;

    dsp->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_armv6;

    dsp->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter16_simple_armv6;

    dsp->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter16_simple_armv6;

    dsp->put_vp8_epel_pixels_tab[0][0][0] = ff_put_vp8_pixels16_armv6;

    dsp->put_vp8_epel_pixels_tab[0][0][2] = ff_put_vp8_epel16_h6_armv6;

    dsp->put_vp8_epel_pixels_tab[0][2][0] = ff_put_vp8_epel16_v6_armv6;

    dsp->put_vp8_epel_pixels_tab[0][2][2] = ff_put_vp8_epel16_h6v6_armv6;

    dsp->put_vp8_epel_pixels_tab[1][0][0] = ff_put_vp8_pixels8_armv6;

    dsp->put_vp8_epel_pixels_tab[1][0][1] = ff_put_vp8_epel8_h4_armv6;

    dsp->put_vp8_epel_pixels_tab[1][0][2] = ff_put_vp8_epel8_h6_armv6;

    dsp->put_vp8_epel_pixels_tab[1][1][0] = ff_put_vp8_epel8_v4_armv6;

    dsp->put_vp8_epel_pixels_tab[1][1][1] = ff_put_vp8_epel8_h4v4_armv6;

    dsp->put_vp8_epel_pixels_tab[1][1][2] = ff_put_vp8_epel8_h6v4_armv6;

    dsp->put_vp8_epel_pixels_tab[1][2][0] = ff_put_vp8_epel8_v6_armv6;

    dsp->put_vp8_epel_pixels_tab[1][2][1] = ff_put_vp8_epel8_h4v6_armv6;

    dsp->put_vp8_epel_pixels_tab[1][2][2] = ff_put_vp8_epel8_h6v6_armv6;

    dsp->put_vp8_epel_pixels_tab[2][0][0] = ff_put_vp8_pixels4_armv6;

    dsp->put_vp8_epel_pixels_tab[2][0][1] = ff_put_vp8_epel4_h4_armv6;

    dsp->put_vp8_epel_pixels_tab[2][0][2] = ff_put_vp8_epel4_h6_armv6;

    dsp->put_vp8_epel_pixels_tab[2][1][0] = ff_put_vp8_epel4_v4_armv6;

    dsp->put_vp8_epel_pixels_tab[2][1][1] = ff_put_vp8_epel4_h4v4_armv6;

    dsp->put_vp8_epel_pixels_tab[2][1][2] = ff_put_vp8_epel4_h6v4_armv6;

    dsp->put_vp8_epel_pixels_tab[2][2][0] = ff_put_vp8_epel4_v6_armv6;

    dsp->put_vp8_epel_pixels_tab[2][2][1] = ff_put_vp8_epel4_h4v6_armv6;

    dsp->put_vp8_epel_pixels_tab[2][2][2] = ff_put_vp8_epel4_h6v6_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][0][1] = ff_put_vp8_bilin16_h_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][0][2] = ff_put_vp8_bilin16_h_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][1][0] = ff_put_vp8_bilin16_v_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][1][1] = ff_put_vp8_bilin16_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][1][2] = ff_put_vp8_bilin16_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][2][0] = ff_put_vp8_bilin16_v_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][2][1] = ff_put_vp8_bilin16_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[0][2][2] = ff_put_vp8_bilin16_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][0][0] = ff_put_vp8_pixels8_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][0][1] = ff_put_vp8_bilin8_h_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][0][2] = ff_put_vp8_bilin8_h_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][1][0] = ff_put_vp8_bilin8_v_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][1][1] = ff_put_vp8_bilin8_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][1][2] = ff_put_vp8_bilin8_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][2][0] = ff_put_vp8_bilin8_v_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][2][1] = ff_put_vp8_bilin8_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[1][2][2] = ff_put_vp8_bilin8_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][0][0] = ff_put_vp8_pixels4_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][0][1] = ff_put_vp8_bilin4_h_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][0][2] = ff_put_vp8_bilin4_h_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][1][0] = ff_put_vp8_bilin4_v_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][1][1] = ff_put_vp8_bilin4_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][1][2] = ff_put_vp8_bilin4_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][2][0] = ff_put_vp8_bilin4_v_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][2][1] = ff_put_vp8_bilin4_hv_armv6;

    dsp->put_vp8_bilinear_pixels_tab[2][2][2] = ff_put_vp8_bilin4_hv_armv6;

}


static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)

{

#if defined(TARGET_I386)

    cpu_synchronize_state(s->c_cpu);

    s->c_cpu->eip = pc;

#elif defined (TARGET_PPC)

    s->c_cpu->nip = pc;

#elif defined (TARGET_SPARC)

    s->c_cpu->npc = pc + 4;

#elif defined (TARGET_ARM)

    s->c_cpu->regs[15] = pc;

#elif defined (TARGET_SH4)

#elif defined (TARGET_MIPS)

    s->c_cpu->active_tc.PC = pc & ~(target_ulong)1;

    if (pc & 1) {

        s->c_cpu->hflags |= MIPS_HFLAG_M16;

    } else {

        s->c_cpu->hflags &= ~(MIPS_HFLAG_M16);

    }

#elif defined (TARGET_MICROBLAZE)

    s->c_cpu->sregs[SR_PC] = pc;

#elif defined (TARGET_CRIS)

#elif defined (TARGET_ALPHA)

#elif defined (TARGET_S390X)

    cpu_synchronize_state(s->c_cpu);

    s->c_cpu->psw.addr = pc;

#elif defined (TARGET_LM32)

#endif

}


void hid_reset(HIDState *hs)

{

    switch (hs->kind) {

    case HID_KEYBOARD:

        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));

        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));

        hs->kbd.keys = 0;

        break;

    case HID_MOUSE:

    case HID_TABLET:

        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));

        break;

    }

    hs->head = 0;

    hs->n = 0;

    hs->protocol = 1;

    hs->idle = 0;

    hs->idle_pending = false;

    hid_del_idle_timer(hs);

}


av_cold int avcodec_close(AVCodecContext *avctx)

{

    /* If there is a user-supplied mutex locking routine, call it. */

    if (ff_lockmgr_cb) {

        if ((*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))

            return -1;

    }

    entangled_thread_counter++;

    if (entangled_thread_counter != 1) {

        av_log(avctx, AV_LOG_ERROR, "insufficient thread locking around avcodec_open/close()\n");

        entangled_thread_counter--;

        return -1;

    }

    if (avcodec_is_open(avctx)) {

        if (HAVE_THREADS && avctx->internal->frame_thread_encoder && avctx->thread_count > 1) {

            entangled_thread_counter --;

            ff_frame_thread_encoder_free(avctx);

            entangled_thread_counter ++;

        }

        if (HAVE_THREADS && avctx->thread_opaque)

            ff_thread_free(avctx);

        if (avctx->codec && avctx->codec->close)

            avctx->codec->close(avctx);

        avcodec_default_free_buffers(avctx);

        avctx->coded_frame = NULL;

        avctx->internal->byte_buffer_size = 0;

        av_freep(&avctx->internal->byte_buffer);

        av_freep(&avctx->internal);

    }

    if (avctx->priv_data && avctx->codec && avctx->codec->priv_class)

        av_opt_free(avctx->priv_data);

    av_opt_free(avctx);

    av_freep(&avctx->priv_data);

    if (av_codec_is_encoder(avctx->codec))

        av_freep(&avctx->extradata);

    avctx->codec = NULL;

    avctx->active_thread_type = 0;

    entangled_thread_counter--;

    /* Release any user-supplied mutex. */

    if (ff_lockmgr_cb) {

        (*ff_lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);

    }

    return 0;

}


static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag)

{

    return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));

}


static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,

                uint8_t *rsp, const uint8_t *req, ssize_t len)

{

    ssize_t seqlen;

    int i, count, start, end, max;

    int32_t handle;

    /* Perform the search */

    for (i = 0; i < sdp->services; i ++)

        sdp->service_list[i].match = 0;

    if (len < 1)

        return -SDP_INVALID_SYNTAX;

    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {

        seqlen = sdp_datalen(&req, &len);

        if (seqlen < 3 || len < seqlen)

            return -SDP_INVALID_SYNTAX;

        len -= seqlen;

        while (seqlen)

            if (sdp_svc_match(sdp, &req, &seqlen))

                return -SDP_INVALID_SYNTAX;

    } else if (sdp_svc_match(sdp, &req, &seqlen))

        return -SDP_INVALID_SYNTAX;

    if (len < 3)

        return -SDP_INVALID_SYNTAX;

    max = (req[0] << 8) | req[1];

    req += 2;

    len -= 2;

    if (*req) {

        if (len <= sizeof(int))

            return -SDP_INVALID_SYNTAX;

        len -= sizeof(int);

        memcpy(&start, req + 1, sizeof(int));

    } else

        start = 0;

    if (len > 1)

        return -SDP_INVALID_SYNTAX;

    /* Output the results */

    len = 4;

    count = 0;

    end = start;

    for (i = 0; i < sdp->services; i ++)

        if (sdp->service_list[i].match) {

            if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {

                handle = i;

                memcpy(rsp + len, &handle, 4);

                len += 4;

                end = count + 1;

            }

            count ++;

        }

    rsp[0] = count >> 8;

    rsp[1] = count & 0xff;

    rsp[2] = (end - start) >> 8;

    rsp[3] = (end - start) & 0xff;

    if (end < count) {

        rsp[len ++] = sizeof(int);

        memcpy(rsp + len, &end, sizeof(int));

        len += 4;

    } else

        rsp[len ++] = 0;

    return len;

}