static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, long src_size)

{

    const uint16_t *end;

#if COMPILE_TEMPLATE_MMX

    const uint16_t *mm_end;

#endif

    uint8_t *d = dst;

    const uint16_t *s = (const uint16_t*)src;

    end = s + src_size/2;

#if COMPILE_TEMPLATE_MMX

    __asm__ volatile(PREFETCH"    %0"::"m"(*s):"memory");

    mm_end = end - 7;

    while (s < mm_end) {

        __asm__ volatile(

            PREFETCH"    32%1           \n\t"

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

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

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

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

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

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

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

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

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

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

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

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

            "punpcklwd     %5, %%mm0    \n\t"

            "punpcklwd     %5, %%mm1    \n\t"

            "punpcklwd     %5, %%mm2    \n\t"

            "punpckhwd     %5, %%mm3    \n\t"

            "punpckhwd     %5, %%mm4    \n\t"

            "punpckhwd     %5, %%mm5    \n\t"

            "psllq         $8, %%mm1    \n\t"

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

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

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

            "psllq         $8, %%mm4    \n\t"

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

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

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

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

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

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

            "movq         8%1, %%mm1    \n\t"

            "movq         8%1, %%mm2    \n\t"

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

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

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

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

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

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

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

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

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

            "punpcklwd     %5, %%mm0    \n\t"

            "punpcklwd     %5, %%mm1    \n\t"

            "punpcklwd     %5, %%mm2    \n\t"

            "punpckhwd     %5, %%mm3    \n\t"

            "punpckhwd     %5, %%mm4    \n\t"

            "punpckhwd     %5, %%mm5    \n\t"

            "psllq         $8, %%mm1    \n\t"

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

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

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

            "psllq         $8, %%mm4    \n\t"

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

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

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

            :"=m"(*d)

            :"m"(*s),"m"(mask15b),"m"(mask15g),"m"(mask15r), "m"(mmx_null)

            :"memory");

        /* borrowed 32 to 24 */

        __asm__ volatile(

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

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

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

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

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

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

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

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

            STORE_BGR24_MMX

            :"=m"(*d)

            :"m"(*s)

            :"memory");

        d += 24;

        s += 8;

    }

    __asm__ volatile(SFENCE:::"memory");

    __asm__ volatile(EMMS:::"memory");

#endif

    while (s < end) {

        register uint16_t bgr;

        bgr = *s++;

        *d++ = (bgr&0x1F)<<3;

        *d++ = (bgr&0x3E0)>>2;

        *d++ = (bgr&0x7C00)>>7;

    }

}


static void tcg_out_movi(TCGContext *s, TCGType type,

                         TCGReg ret, tcg_target_long sval)

{

    static const S390Opcode lli_insns[4] = {

        RI_LLILL, RI_LLILH, RI_LLIHL, RI_LLIHH

    };

    tcg_target_ulong uval = sval;

    int i;

    if (type == TCG_TYPE_I32) {

        uval = (uint32_t)sval;

        sval = (int32_t)sval;

    }

    /* Try all 32-bit insns that can load it in one go.  */

    if (sval >= -0x8000 && sval < 0x8000) {

        tcg_out_insn(s, RI, LGHI, ret, sval);

        return;

    }

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

        tcg_target_long mask = 0xffffull << i*16;

        if ((uval & mask) == uval) {

            tcg_out_insn_RI(s, lli_insns[i], ret, uval >> i*16);

            return;

        }

    }

    /* Try all 48-bit insns that can load it in one go.  */

    if (facilities & FACILITY_EXT_IMM) {

        if (sval == (int32_t)sval) {

            tcg_out_insn(s, RIL, LGFI, ret, sval);

            return;

        }

        if (uval <= 0xffffffff) {

            tcg_out_insn(s, RIL, LLILF, ret, uval);

            return;

        }

        if ((uval & 0xffffffff) == 0) {

            tcg_out_insn(s, RIL, LLIHF, ret, uval >> 31 >> 1);

            return;

        }

    }

    /* Try for PC-relative address load.  */

    if ((sval & 1) == 0) {

        ptrdiff_t off = tcg_pcrel_diff(s, (void *)sval) >> 1;

        if (off == (int32_t)off) {

            tcg_out_insn(s, RIL, LARL, ret, off);

            return;

        }

    }

    /* If extended immediates are not present, then we may have to issue

       several instructions to load the low 32 bits.  */

    if (!(facilities & FACILITY_EXT_IMM)) {

        /* A 32-bit unsigned value can be loaded in 2 insns.  And given

           that the lli_insns loop above did not succeed, we know that

           both insns are required.  */

        if (uval <= 0xffffffff) {

            tcg_out_insn(s, RI, LLILL, ret, uval);

            tcg_out_insn(s, RI, IILH, ret, uval >> 16);

            return;

        }

        /* If all high bits are set, the value can be loaded in 2 or 3 insns.

           We first want to make sure that all the high bits get set.  With

           luck the low 16-bits can be considered negative to perform that for

           free, otherwise we load an explicit -1.  */

        if (sval >> 31 >> 1 == -1) {

            if (uval & 0x8000) {

                tcg_out_insn(s, RI, LGHI, ret, uval);

            } else {

                tcg_out_insn(s, RI, LGHI, ret, -1);

                tcg_out_insn(s, RI, IILL, ret, uval);

            }

            tcg_out_insn(s, RI, IILH, ret, uval >> 16);

            return;

        }

    }

    /* If we get here, both the high and low parts have non-zero bits.  */

    /* Recurse to load the lower 32-bits.  */

    tcg_out_movi(s, TCG_TYPE_I64, ret, uval & 0xffffffff);

    /* Insert data into the high 32-bits.  */

    uval = uval >> 31 >> 1;

    if (facilities & FACILITY_EXT_IMM) {

        if (uval < 0x10000) {

            tcg_out_insn(s, RI, IIHL, ret, uval);

        } else if ((uval & 0xffff) == 0) {

            tcg_out_insn(s, RI, IIHH, ret, uval >> 16);

        } else {

            tcg_out_insn(s, RIL, IIHF, ret, uval);

        }

    } else {

        if (uval & 0xffff) {

            tcg_out_insn(s, RI, IIHL, ret, uval);

        }

        if (uval & 0xffff0000) {

            tcg_out_insn(s, RI, IIHH, ret, uval >> 16);

        }

    }

}


milkymist_init(MachineState *machine)

{

    const char *cpu_model = machine->cpu_model;

    const char *kernel_filename = machine->kernel_filename;

    const char *kernel_cmdline = machine->kernel_cmdline;

    const char *initrd_filename = machine->initrd_filename;

    LM32CPU *cpu;

    CPULM32State *env;

    int kernel_size;

    DriveInfo *dinfo;

    MemoryRegion *address_space_mem = get_system_memory();

    MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);

    qemu_irq irq[32];

    int i;

    char *bios_filename;

    ResetInfo *reset_info;

    /* memory map */

    hwaddr flash_base   = 0x00000000;

    size_t flash_sector_size        = 128 * 1024;

    size_t flash_size               = 32 * 1024 * 1024;

    hwaddr sdram_base   = 0x40000000;

    size_t sdram_size               = 128 * 1024 * 1024;

    hwaddr initrd_base  = sdram_base + 0x1002000;

    hwaddr cmdline_base = sdram_base + 0x1000000;

    size_t initrd_max = sdram_size - 0x1002000;

    reset_info = g_malloc0(sizeof(ResetInfo));

    if (cpu_model == NULL) {

        cpu_model = "lm32-full";

    }

    cpu = cpu_lm32_init(cpu_model);

    if (cpu == NULL) {

        fprintf(stderr, "qemu: unable to find CPU '%s'\n", cpu_model);

        exit(1);

    }

    env = &cpu->env;

    reset_info->cpu = cpu;

    cpu_lm32_set_phys_msb_ignore(env, 1);

    memory_region_allocate_system_memory(phys_sdram, NULL, "milkymist.sdram",

                                         sdram_size);

    memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram);

    dinfo = drive_get(IF_PFLASH, 0, 0);

    /* Numonyx JS28F256J3F105 */

    pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size,

                          dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,

                          flash_sector_size, flash_size / flash_sector_size,

                          2, 0x00, 0x89, 0x00, 0x1d, 1);

    /* create irq lines */

    env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));

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

        irq[i] = qdev_get_gpio_in(env->pic_state, i);

    }

    /* load bios rom */

    if (bios_name == NULL) {

        bios_name = BIOS_FILENAME;

    }

    bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);

    if (bios_filename) {

        load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE);

    }

    reset_info->bootstrap_pc = BIOS_OFFSET;

    /* if no kernel is given no valid bios rom is a fatal error */

    if (!kernel_filename && !dinfo && !bios_filename && !qtest_enabled()) {

        fprintf(stderr, "qemu: could not load Milkymist One bios '%s'\n",

                bios_name);

        exit(1);

    }

    g_free(bios_filename);

    milkymist_uart_create(0x60000000, irq[0]);

    milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],

            80000000, 0x10014d31, 0x0000041f, 0x00000001);

    milkymist_hpdmc_create(0x60002000);

    milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);

    milkymist_memcard_create(0x60004000);

    milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);

    milkymist_pfpu_create(0x60006000, irq[8]);

    milkymist_tmu2_create(0x60007000, irq[9]);

    milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);

    milkymist_softusb_create(0x6000f000, irq[15],

            0x20000000, 0x1000, 0x20020000, 0x2000);

    /* make sure juart isn't the first chardev */

    env->juart_state = lm32_juart_init();

    if (kernel_filename) {

        uint64_t entry;

        /* Boots a kernel elf binary.  */

        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,

                               1, EM_LATTICEMICO32, 0, 0);

        reset_info->bootstrap_pc = entry;

        if (kernel_size < 0) {

            kernel_size = load_image_targphys(kernel_filename, sdram_base,

                                              sdram_size);

            reset_info->bootstrap_pc = sdram_base;

        }

        if (kernel_size < 0) {

            fprintf(stderr, "qemu: could not load kernel '%s'\n",

                    kernel_filename);

            exit(1);

        }

    }

    if (kernel_cmdline && strlen(kernel_cmdline)) {

        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,

                kernel_cmdline);

        reset_info->cmdline_base = (uint32_t)cmdline_base;

    }

    if (initrd_filename) {

        size_t initrd_size;

        initrd_size = load_image_targphys(initrd_filename, initrd_base,

                initrd_max);

        reset_info->initrd_base = (uint32_t)initrd_base;

        reset_info->initrd_size = (uint32_t)initrd_size;

    }

    qemu_register_reset(main_cpu_reset, reset_info);

}


static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,

                            int64_t offset_in_cluster, QEMUIOVector *qiov,

                            uint64_t qiov_offset, uint64_t n_bytes,

                            uint64_t offset)

{

    int ret;

    VmdkGrainMarker *data = NULL;

    uLongf buf_len;

    QEMUIOVector local_qiov;

    struct iovec iov;

    int64_t write_offset;

    int64_t write_end_sector;

    if (extent->compressed) {

        void *compressed_data;

        if (!extent->has_marker) {

            ret = -EINVAL;

            goto out;

        }

        buf_len = (extent->cluster_sectors << 9) * 2;

        data = g_malloc(buf_len + sizeof(VmdkGrainMarker));

        compressed_data = g_malloc(n_bytes);

        qemu_iovec_to_buf(qiov, qiov_offset, compressed_data, n_bytes);

        ret = compress(data->data, &buf_len, compressed_data, n_bytes);

        g_free(compressed_data);

        if (ret != Z_OK || buf_len == 0) {

            ret = -EINVAL;

            goto out;

        }

        data->lba = offset >> BDRV_SECTOR_BITS;

        data->size = buf_len;

        n_bytes = buf_len + sizeof(VmdkGrainMarker);

        iov = (struct iovec) {

            .iov_base   = data,

            .iov_len    = n_bytes,

        };

        qemu_iovec_init_external(&local_qiov, &iov, 1);

    } else {

        qemu_iovec_init(&local_qiov, qiov->niov);

        qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes);

    }

    write_offset = cluster_offset + offset_in_cluster,

    ret = bdrv_co_pwritev(extent->file->bs, write_offset, n_bytes,

                          &local_qiov, 0);

    write_end_sector = DIV_ROUND_UP(write_offset + n_bytes, BDRV_SECTOR_SIZE);

    if (extent->compressed) {

        extent->next_cluster_sector = write_end_sector;

    } else {

        extent->next_cluster_sector = MAX(extent->next_cluster_sector,

                                          write_end_sector);

    }

    if (ret < 0) {

        goto out;

    }

    ret = 0;

 out:

    g_free(data);

    if (!extent->compressed) {

        qemu_iovec_destroy(&local_qiov);

    }

    return ret;

}


static int vnc_continue_handshake(struct VncState *vs) {

    int ret;

    if ((ret = gnutls_handshake(vs->tls_session)) < 0) {

       if (!gnutls_error_is_fatal(ret)) {

           VNC_DEBUG("Handshake interrupted (blocking)\n");

           if (!gnutls_record_get_direction(vs->tls_session))

               qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);

           else

               qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);

           return 0;

       }

       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));

       vnc_client_error(vs);

       return -1;

    }

    if (vs->vd->x509verify) {

	if (vnc_validate_certificate(vs) < 0) {

	    VNC_DEBUG("Client verification failed\n");

	    vnc_client_error(vs);

	    return -1;

	} else {

	    VNC_DEBUG("Client verification passed\n");

	}

    }

    VNC_DEBUG("Handshake done, switching to TLS data mode\n");

    vs->wiremode = VNC_WIREMODE_TLS;

    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);

    return start_auth_vencrypt_subauth(vs);

}


void cpu_reset (CPUMIPSState *env)
{
    memset(env, 0, offsetof(CPUMIPSState, breakpoints));
    tlb_flush(env, 1);
    /* Minimal init */
#if defined(CONFIG_USER_ONLY)
    env->hflags = MIPS_HFLAG_UM;
#else
    if (env->hflags & MIPS_HFLAG_BMASK) {
        /* If the exception was raised from a delay slot,
           come back to the jump.  */
        env->CP0_ErrorEPC = env->active_tc.PC - 4;
    } else {
        env->CP0_ErrorEPC = env->active_tc.PC;
    env->active_tc.PC = (int32_t)0xBFC00000;
    env->CP0_Wired = 0;
    /* SMP not implemented */
    env->CP0_EBase = 0x80000000;
    env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
    /* vectored interrupts not implemented, timer on int 7,
       no performance counters. */
    env->CP0_IntCtl = 0xe0000000;
    {
        int i;
        for (i = 0; i < 7; i++) {
            env->CP0_WatchLo[i] = 0;
            env->CP0_WatchHi[i] = 0x80000000;
        env->CP0_WatchLo[7] = 0;
        env->CP0_WatchHi[7] = 0;
    /* Count register increments in debug mode, EJTAG version 1 */
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
    env->hflags = MIPS_HFLAG_CP0;
#endif
    env->exception_index = EXCP_NONE;
    cpu_mips_register(env, env->cpu_model);


static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,

                     Error **errp)

{

    char *buf;

    int ret;

    BDRVVmdkState *s = bs->opaque;

    uint32_t magic;

    Error *local_err = NULL;

    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,

                               false, errp);

    if (!bs->file) {

        return -EINVAL;

    }

    buf = vmdk_read_desc(bs->file, 0, errp);

    if (!buf) {

        return -EINVAL;

    }

    magic = ldl_be_p(buf);

    switch (magic) {

        case VMDK3_MAGIC:

        case VMDK4_MAGIC:

            ret = vmdk_open_sparse(bs, bs->file, flags, buf, options,

                                   errp);

            s->desc_offset = 0x200;

            break;

        default:

            ret = vmdk_open_desc_file(bs, flags, buf, options, errp);

            break;

    }

    if (ret) {

        goto fail;

    }

    /* try to open parent images, if exist */

    ret = vmdk_parent_open(bs);

    if (ret) {

        goto fail;

    }

    s->cid = vmdk_read_cid(bs, 0);

    s->parent_cid = vmdk_read_cid(bs, 1);

    qemu_co_mutex_init(&s->lock);

    /* Disable migration when VMDK images are used */

    error_setg(&s->migration_blocker, "The vmdk format used by node '%s' "

               "does not support live migration",

               bdrv_get_device_or_node_name(bs));

    ret = migrate_add_blocker(s->migration_blocker, &local_err);

    if (local_err) {

        error_propagate(errp, local_err);

        error_free(s->migration_blocker);

        goto fail;

    }

    g_free(buf);

    return 0;

fail:

    g_free(buf);

    g_free(s->create_type);

    s->create_type = NULL;

    vmdk_free_extents(bs);

    return ret;

}


static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)

{

    if (u) {

        switch (size) {

        case 0: gen_helper_neon_widen_u8(dest, src); break;

        case 1: gen_helper_neon_widen_u16(dest, src); break;

        case 2: tcg_gen_extu_i32_i64(dest, src); break;

        default: abort();

        }

    } else {

        switch (size) {

        case 0: gen_helper_neon_widen_s8(dest, src); break;

        case 1: gen_helper_neon_widen_s16(dest, src); break;

        case 2: tcg_gen_ext_i32_i64(dest, src); break;

        default: abort();

        }

    }

    dead_tmp(src);

}


static int rv10_decode_frame(AVCodecContext *avctx,

                             void *data, int *data_size,

                             AVPacket *avpkt)

{

    const uint8_t *buf = avpkt->data;

    int buf_size = avpkt->size;

    MpegEncContext *s = avctx->priv_data;

    int i;

    AVFrame *pict = data;

    int slice_count;

    const uint8_t *slices_hdr = NULL;

    av_dlog(avctx, "*****frame %d size=%d\n", avctx->frame_number, buf_size);

    /* no supplementary picture */

    if (buf_size == 0) {

        return 0;

    }

    if(!avctx->slice_count){

        slice_count = (*buf++) + 1;

        slices_hdr = buf + 4;

        buf += 8 * slice_count;

    }else

        slice_count = avctx->slice_count;

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

        int offset= get_slice_offset(avctx, slices_hdr, i);

        int size, size2;

        if(i+1 == slice_count)

            size= buf_size - offset;

        else

            size= get_slice_offset(avctx, slices_hdr, i+1) - offset;

        if(i+2 >= slice_count)

            size2= buf_size - offset;

        else

            size2= get_slice_offset(avctx, slices_hdr, i+2) - offset;

        if(rv10_decode_packet(avctx, buf+offset, size, size2) > 8*size)

            i++;

    }

    if(s->current_picture_ptr != NULL && s->mb_y>=s->mb_height){

        ff_er_frame_end(s);

        MPV_frame_end(s);

        if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {

            *pict= *(AVFrame*)s->current_picture_ptr;

        } else if (s->last_picture_ptr != NULL) {

            *pict= *(AVFrame*)s->last_picture_ptr;

        }

        if(s->last_picture_ptr || s->low_delay){

            *data_size = sizeof(AVFrame);

            ff_print_debug_info(s, pict);

        }

        s->current_picture_ptr= NULL; //so we can detect if frame_end wasnt called (find some nicer solution...)

    }

    return buf_size;

}


static void output_client_manifest(struct VideoFiles *files,

                                   const char *basename, int split)

{

    char filename[1000];

    FILE *out;

    int i, j;

    if (split)

        snprintf(filename, sizeof(filename), "Manifest");

    else

        snprintf(filename, sizeof(filename), "%s.ismc", basename);

    out = fopen(filename, "w");

    if (!out) {

        perror(filename);

        return;

    }

    fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");

    fprintf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" "

                 "Duration=\"%"PRId64 "\">\n", files->duration * 10);

    if (files->video_file >= 0) {

        struct VideoFile *vf = files->files[files->video_file];

        int index = 0;

        fprintf(out,

                "\t<StreamIndex Type=\"video\" QualityLevels=\"%d\" "

                "Chunks=\"%d\" "

                "Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n",

                files->nb_video_files, vf->chunks);

        for (i = 0; i < files->nb_files; i++) {

            vf = files->files[i];

            if (!vf->is_video)

                continue;

            fprintf(out,

                    "\t\t<QualityLevel Index=\"%d\" Bitrate=\"%d\" "

                    "FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" "

                    "CodecPrivateData=\"",

                    index, vf->bitrate, vf->fourcc, vf->width, vf->height);

            for (j = 0; j < vf->codec_private_size; j++)

                fprintf(out, "%02X", vf->codec_private[j]);

            fprintf(out, "\" />\n");

            index++;

        }

        vf = files->files[files->video_file];

        for (i = 0; i < vf->chunks; i++)

            fprintf(out, "\t\t<c n=\"%d\" d=\"%d\" />\n", i,

                    vf->offsets[i].duration);

        fprintf(out, "\t</StreamIndex>\n");

    }

    if (files->audio_file >= 0) {

        struct VideoFile *vf = files->files[files->audio_file];

        int index = 0;

        fprintf(out,

                "\t<StreamIndex Type=\"audio\" QualityLevels=\"%d\" "

                "Chunks=\"%d\" "

                "Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n",

                files->nb_audio_files, vf->chunks);

        for (i = 0; i < files->nb_files; i++) {

            vf = files->files[i];

            if (!vf->is_audio)

                continue;

            fprintf(out,

                    "\t\t<QualityLevel Index=\"%d\" Bitrate=\"%d\" "

                    "FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" "

                    "BitsPerSample=\"16\" PacketSize=\"%d\" "

                    "AudioTag=\"%d\" CodecPrivateData=\"",

                    index, vf->bitrate, vf->fourcc, vf->sample_rate,

                    vf->channels, vf->blocksize, vf->tag);

            for (j = 0; j < vf->codec_private_size; j++)

                fprintf(out, "%02X", vf->codec_private[j]);

            fprintf(out, "\" />\n");

            index++;

        }

        vf = files->files[files->audio_file];

        for (i = 0; i < vf->chunks; i++)

            fprintf(out, "\t\t<c n=\"%d\" d=\"%d\" />\n",

                    i, vf->offsets[i].duration);

        fprintf(out, "\t</StreamIndex>\n");

    }

    fprintf(out, "</SmoothStreamingMedia>\n");

    fclose(out);

}


int qdev_unplug(DeviceState *dev)
{
    if (!dev->parent_bus->allow_hotplug) {
        qemu_error("Bus %s does not support hotplugging\n",
                   dev->parent_bus->name);
        return -1;
    }
    return dev->info->unplug(dev);
}


static int aa_read_header(AVFormatContext *s)

{

    int i, j, idx, largest_idx = -1;

    uint32_t nkey, nval, toc_size, npairs, header_seed, start;

    char key[128], val[128], codec_name[64] = {0};

    uint8_t output[24], dst[8], src[8];

    int64_t largest_size = -1, current_size = -1;

    struct toc_entry {

        uint32_t offset;

        uint32_t size;

    } TOC[MAX_TOC_ENTRIES];

    uint32_t header_key_part[4];

    uint8_t header_key[16];

    AADemuxContext *c = s->priv_data;

    AVIOContext *pb = s->pb;

    AVStream *st;

    /* parse .aa header */

    avio_skip(pb, 4); // file size

    avio_skip(pb, 4); // magic string

    toc_size = avio_rb32(pb); // TOC size

    avio_skip(pb, 4); // unidentified integer

    if (toc_size > MAX_TOC_ENTRIES)

        return AVERROR_INVALIDDATA;

    for (i = 0; i < toc_size; i++) { // read TOC

        avio_skip(pb, 4); // TOC entry index

        TOC[i].offset = avio_rb32(pb); // block offset

        TOC[i].size = avio_rb32(pb); // block size

    }

    avio_skip(pb, 24); // header termination block (ignored)

    npairs = avio_rb32(pb); // read dictionary entries

    if (npairs > MAX_DICTIONARY_ENTRIES)

        return AVERROR_INVALIDDATA;

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

        memset(val, 0, sizeof(val));

        memset(key, 0, sizeof(key));

        avio_skip(pb, 1); // unidentified integer

        nkey = avio_rb32(pb); // key string length

        nval = avio_rb32(pb); // value string length

        if (nkey > sizeof(key)) {

            avio_skip(pb, nkey);

        } else {

            avio_read(pb, key, nkey); // key string

        }

        if (nval > sizeof(val)) {

            avio_skip(pb, nval);

        } else {

            avio_read(pb, val, nval); // value string

        }

        if (!strcmp(key, "codec")) {

            av_log(s, AV_LOG_DEBUG, "Codec is <%s>\n", val);

            strncpy(codec_name, val, sizeof(codec_name) - 1);

        }

        if (!strcmp(key, "HeaderSeed")) {

            av_log(s, AV_LOG_DEBUG, "HeaderSeed is <%s>\n", val);

            header_seed = atoi(val);

        }

        if (!strcmp(key, "HeaderKey")) { // this looks like "1234567890 1234567890 1234567890 1234567890"

            av_log(s, AV_LOG_DEBUG, "HeaderKey is <%s>\n", val);

            sscanf(val, "%u%u%u%u", &header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]);

            for (idx = 0; idx < 4; idx++) {

                AV_WB32(&header_key[idx * 4], header_key_part[idx]); // convert each part to BE!

            }

            av_log(s, AV_LOG_DEBUG, "Processed HeaderKey is ");

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

                av_log(s, AV_LOG_DEBUG, "%02x", header_key[i]);

            av_log(s, AV_LOG_DEBUG, "\n");

        }

    }

    /* verify fixed key */

    if (c->aa_fixed_key_len != 16) {

        av_log(s, AV_LOG_ERROR, "aa_fixed_key value needs to be 16 bytes!\n");

        return AVERROR(EINVAL);

    }

    /* verify codec */

    if ((c->codec_second_size = get_second_size(codec_name)) == -1) {

        av_log(s, AV_LOG_ERROR, "unknown codec <%s>!\n", codec_name);

        return AVERROR(EINVAL);

    }

    /* decryption key derivation */

    c->tea_ctx = av_tea_alloc();

    if (!c->tea_ctx)

        return AVERROR(ENOMEM);

    av_tea_init(c->tea_ctx, c->aa_fixed_key, 16);

    output[0] = output[1] = 0; // purely for padding purposes

    memcpy(output + 2, header_key, 16);

    idx = 0;

    for (i = 0; i < 3; i++) { // TEA CBC with weird mixed endianness

        AV_WB32(src, header_seed);

        AV_WB32(src + 4, header_seed + 1);

        header_seed += 2;

        av_tea_crypt(c->tea_ctx, dst, src, 1, NULL, 0); // TEA ECB encrypt

        for (j = 0; j < TEA_BLOCK_SIZE && idx < 18; j+=1, idx+=1) {

            output[idx] = output[idx] ^ dst[j];

        }

    }

    memcpy(c->file_key, output + 2, 16); // skip first 2 bytes of output

    av_log(s, AV_LOG_DEBUG, "File key is ");

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

        av_log(s, AV_LOG_DEBUG, "%02x", c->file_key[i]);

    av_log(s, AV_LOG_DEBUG, "\n");

    /* decoder setup */

    st = avformat_new_stream(s, NULL);

    if (!st) {

        av_freep(&c->tea_ctx);

        return AVERROR(ENOMEM);

    }

    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;

    if (!strcmp(codec_name, "mp332")) {

        st->codec->codec_id = AV_CODEC_ID_MP3;

        st->codec->sample_rate = 22050;

        st->need_parsing = AVSTREAM_PARSE_FULL_RAW;

        st->start_time = 0;

    } else if (!strcmp(codec_name, "acelp85")) {

        st->codec->codec_id = AV_CODEC_ID_SIPR;

        st->codec->block_align = 19;

        st->codec->channels = 1;

        st->codec->sample_rate = 8500;

    } else if (!strcmp(codec_name, "acelp16")) {

        st->codec->codec_id = AV_CODEC_ID_SIPR;

        st->codec->block_align = 20;

        st->codec->channels = 1;

        st->codec->sample_rate = 16000;

    }

    /* determine, and jump to audio start offset */

    for (i = 1; i < toc_size; i++) { // skip the first entry!

        current_size = TOC[i].size;

        if (current_size > largest_size) {

            largest_idx = i;

            largest_size = current_size;

        }

    }

    start = TOC[largest_idx].offset;

    avio_seek(pb, start, SEEK_SET);

    c->current_chapter_size = 0;

    return 0;

}


vorbis_comment(AVFormatContext * as, uint8_t *buf, int size)

{

    const uint8_t *p = buf;

    const uint8_t *end = buf + size;

    unsigned s, n, j;

    if (size < 8) /* must have vendor_length and user_comment_list_length */

        return -1;

    s = bytestream_get_le32(&p);

    if (end - p < s)

        return -1;

    p += s;

    n = bytestream_get_le32(&p);

    while (p < end && n > 0) {

        const char *t, *v;

        int tl, vl;

        s = bytestream_get_le32(&p);

        if (end - p < s)

            break;

        t = p;

        p += s;

        n--;

        v = memchr(t, '=', s);

        if (!v)

            continue;

        tl = v - t;

        vl = s - tl - 1;

        v++;

        if (tl && vl) {

            char *tt, *ct;

            tt = av_malloc(tl + 1);

            ct = av_malloc(vl + 1);

            if (!tt || !ct) {

                av_freep(&tt);

                av_freep(&ct);

                av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");

                continue;

            }

            for (j = 0; j < tl; j++)

                tt[j] = toupper(t[j]);

            tt[tl] = 0;

            memcpy(ct, v, vl);

            ct[vl] = 0;

            av_metadata_set(&as->metadata, tt, ct);

            av_freep(&tt);

            av_freep(&ct);

        }

    }

    if (p != end)

        av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p);

    if (n > 0)

        av_log(as, AV_LOG_INFO,

               "truncated comment header, %i comments not found\n", n);

    return 0;

}


static float get_band_cost_ESC_mips(struct AACEncContext *s,

                                    PutBitContext *pb, const float *in,

                                    const float *scaled, int size, int scale_idx,

                                    int cb, const float lambda, const float uplim,

                                    int *bits)

{

    const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];

    const float IQ  = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512];

    const float CLIPPED_ESCAPE = 165140.0f * IQ;

    int i;

    float cost = 0;

    int qc1, qc2, qc3, qc4;

    int curbits = 0;

    uint8_t *p_bits  = (uint8_t*)ff_aac_spectral_bits[cb-1];

    float   *p_codes = (float*  )ff_aac_codebook_vectors[cb-1];

    for (i = 0; i < size; i += 4) {

        const float *vec, *vec2;

        int curidx, curidx2;

        float t1, t2, t3, t4;

        float di1, di2, di3, di4;

        int cond0, cond1, cond2, cond3;

        int c1, c2, c3, c4;

        int t6, t7;

        qc1 = scaled[i  ] * Q34 + ROUND_STANDARD;

        qc2 = scaled[i+1] * Q34 + ROUND_STANDARD;

        qc3 = scaled[i+2] * Q34 + ROUND_STANDARD;

        qc4 = scaled[i+3] * Q34 + ROUND_STANDARD;

        __asm__ volatile (

            ".set push                                  \n\t"

            ".set noreorder                             \n\t"

            "ori        %[t6],      $zero,  15          \n\t"

            "ori        %[t7],      $zero,  16          \n\t"

            "shll_s.w   %[c1],      %[qc1], 18          \n\t"

            "shll_s.w   %[c2],      %[qc2], 18          \n\t"

            "shll_s.w   %[c3],      %[qc3], 18          \n\t"

            "shll_s.w   %[c4],      %[qc4], 18          \n\t"

            "srl        %[c1],      %[c1],  18          \n\t"

            "srl        %[c2],      %[c2],  18          \n\t"

            "srl        %[c3],      %[c3],  18          \n\t"

            "srl        %[c4],      %[c4],  18          \n\t"

            "slt        %[cond0],   %[t6],  %[qc1]      \n\t"

            "slt        %[cond1],   %[t6],  %[qc2]      \n\t"

            "slt        %[cond2],   %[t6],  %[qc3]      \n\t"

            "slt        %[cond3],   %[t6],  %[qc4]      \n\t"

            "movn       %[qc1],     %[t7],  %[cond0]    \n\t"

            "movn       %[qc2],     %[t7],  %[cond1]    \n\t"

            "movn       %[qc3],     %[t7],  %[cond2]    \n\t"

            "movn       %[qc4],     %[t7],  %[cond3]    \n\t"

            ".set pop                                   \n\t"

            : [qc1]"+r"(qc1), [qc2]"+r"(qc2),

              [qc3]"+r"(qc3), [qc4]"+r"(qc4),

              [cond0]"=&r"(cond0), [cond1]"=&r"(cond1),

              [cond2]"=&r"(cond2), [cond3]"=&r"(cond3),

              [c1]"=&r"(c1), [c2]"=&r"(c2),

              [c3]"=&r"(c3), [c4]"=&r"(c4),

              [t6]"=&r"(t6), [t7]"=&r"(t7)

        );

        curidx = 17 * qc1;

        curidx += qc2;

        curidx2 = 17 * qc3;

        curidx2 += qc4;

        curbits += p_bits[curidx];

        curbits += esc_sign_bits[curidx];

        vec     = &p_codes[curidx*2];

        curbits += p_bits[curidx2];

        curbits += esc_sign_bits[curidx2];

        vec2     = &p_codes[curidx2*2];

        curbits += (av_log2(c1) * 2 - 3) & (-cond0);

        curbits += (av_log2(c2) * 2 - 3) & (-cond1);

        curbits += (av_log2(c3) * 2 - 3) & (-cond2);

        curbits += (av_log2(c4) * 2 - 3) & (-cond3);

        t1 = fabsf(in[i  ]);

        t2 = fabsf(in[i+1]);

        t3 = fabsf(in[i+2]);

        t4 = fabsf(in[i+3]);

        if (cond0) {

            if (t1 >= CLIPPED_ESCAPE) {

                di1 = t1 - CLIPPED_ESCAPE;

            } else {

                di1 = t1 - c1 * cbrtf(c1) * IQ;

            }

        } else

            di1 = t1 - vec[0] * IQ;

        if (cond1) {

            if (t2 >= CLIPPED_ESCAPE) {

                di2 = t2 - CLIPPED_ESCAPE;

            } else {

                di2 = t2 - c2 * cbrtf(c2) * IQ;

            }

        } else

            di2 = t2 - vec[1] * IQ;

        if (cond2) {

            if (t3 >= CLIPPED_ESCAPE) {

                di3 = t3 - CLIPPED_ESCAPE;

            } else {

                di3 = t3 - c3 * cbrtf(c3) * IQ;

            }

        } else

            di3 = t3 - vec2[0] * IQ;

        if (cond3) {

            if (t4 >= CLIPPED_ESCAPE) {

                di4 = t4 - CLIPPED_ESCAPE;

            } else {

                di4 = t4 - c4 * cbrtf(c4) * IQ;

            }

        } else

            di4 = t4 - vec2[1]*IQ;

        cost += di1 * di1 + di2 * di2

                + di3 * di3 + di4 * di4;

    }

    if (bits)

        *bits = curbits;

    return cost * lambda + curbits;

}


static PayloadContext *h264_new_context(void)

{

    PayloadContext *data =

        av_mallocz(sizeof(PayloadContext) +

                   FF_INPUT_BUFFER_PADDING_SIZE);

    if (data) {

        data->cookie = MAGIC_COOKIE;

    }

    return data;

}


int qemu_pipe(int pipefd[2])

{

    int ret;

#ifdef CONFIG_PIPE2

    ret = pipe2(pipefd, O_CLOEXEC);

#else

    ret = pipe(pipefd);

    if (ret == 0) {

        qemu_set_cloexec(pipefd[0]);

        qemu_set_cloexec(pipefd[1]);

    }

#endif

    return ret;

}


static inline int parse_nal_units(AVCodecParserContext *s,

                                  AVCodecContext *avctx,

                                  const uint8_t *buf, int buf_size)

{

    H264Context *h = s->priv_data;

    const uint8_t *buf_end = buf + buf_size;

    unsigned int pps_id;

    unsigned int slice_type;

    int state;

    const uint8_t *ptr;

    /* set some sane default values */

    s->pict_type = FF_I_TYPE;

    s->key_frame = 0;

    h->s.avctx= avctx;

    h->sei_recovery_frame_cnt = -1;

    h->sei_dpb_output_delay         =  0;

    h->sei_cpb_removal_delay        = -1;

    h->sei_buffering_period_present =  0;

    for(;;) {

        int src_length, dst_length, consumed;

        buf = ff_find_start_code(buf, buf_end, &state);

        if(buf >= buf_end)

            break;

        --buf;

        src_length = buf_end - buf;

        switch (state & 0x1f) {

        case NAL_SLICE:

        case NAL_IDR_SLICE:

            // Do not walk the whole buffer just to decode slice header

            if (src_length > 20)

                src_length = 20;

            break;

        }

        ptr= ff_h264_decode_nal(h, buf, &dst_length, &consumed, src_length);

        if (ptr==NULL || dst_length < 0)

            break;

        init_get_bits(&h->s.gb, ptr, 8*dst_length);

        switch(h->nal_unit_type) {

        case NAL_SPS:

            ff_h264_decode_seq_parameter_set(h);

            break;

        case NAL_PPS:

            ff_h264_decode_picture_parameter_set(h, h->s.gb.size_in_bits);

            break;

        case NAL_SEI:

            ff_h264_decode_sei(h);

            break;

        case NAL_IDR_SLICE:

            s->key_frame = 1;

            /* fall through */

        case NAL_SLICE:

            get_ue_golomb(&h->s.gb);  // skip first_mb_in_slice

            slice_type = get_ue_golomb_31(&h->s.gb);

            s->pict_type = golomb_to_pict_type[slice_type % 5];

            if (h->sei_recovery_frame_cnt >= 0) {

                /* key frame, since recovery_frame_cnt is set */

                s->key_frame = 1;

            }

            pps_id= get_ue_golomb(&h->s.gb);

            if(pps_id>=MAX_PPS_COUNT) {

                av_log(h->s.avctx, AV_LOG_ERROR, "pps_id out of range\n");

                return -1;

            }

            if(!h->pps_buffers[pps_id]) {

                av_log(h->s.avctx, AV_LOG_ERROR, "non-existing PPS referenced\n");

                return -1;

            }

            h->pps= *h->pps_buffers[pps_id];

            if(!h->sps_buffers[h->pps.sps_id]) {

                av_log(h->s.avctx, AV_LOG_ERROR, "non-existing SPS referenced\n");

                return -1;

            }

            h->sps = *h->sps_buffers[h->pps.sps_id];

            h->frame_num = get_bits(&h->s.gb, h->sps.log2_max_frame_num);

            if(h->sps.frame_mbs_only_flag){

                h->s.picture_structure= PICT_FRAME;

            }else{

                if(get_bits1(&h->s.gb)) { //field_pic_flag

                    h->s.picture_structure= PICT_TOP_FIELD + get_bits1(&h->s.gb); //bottom_field_flag

                } else {

                    h->s.picture_structure= PICT_FRAME;

                }

            }

            if(h->sps.pic_struct_present_flag) {

                switch (h->sei_pic_struct) {

                    case SEI_PIC_STRUCT_TOP_FIELD:

                    case SEI_PIC_STRUCT_BOTTOM_FIELD:

                        s->repeat_pict = 0;

                        break;

                    case SEI_PIC_STRUCT_FRAME:

                    case SEI_PIC_STRUCT_TOP_BOTTOM:

                    case SEI_PIC_STRUCT_BOTTOM_TOP:

                        s->repeat_pict = 1;

                        break;

                    case SEI_PIC_STRUCT_TOP_BOTTOM_TOP:

                    case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:

                        s->repeat_pict = 2;

                        break;

                    case SEI_PIC_STRUCT_FRAME_DOUBLING:

                        s->repeat_pict = 3;

                        break;

                    case SEI_PIC_STRUCT_FRAME_TRIPLING:

                        s->repeat_pict = 5;

                        break;

                    default:

                        s->repeat_pict = h->s.picture_structure == PICT_FRAME ? 1 : 0;

                        break;

                }

            } else {

                s->repeat_pict = h->s.picture_structure == PICT_FRAME ? 1 : 0;

            }

            return 0; /* no need to evaluate the rest */

        }

        buf += consumed;

    }

    /* didn't find a picture! */

    av_log(h->s.avctx, AV_LOG_ERROR, "missing picture in access unit\n");

    return -1;

}


static inline void write_IRQreg (openpic_t *opp, int n_IRQ,

                                 uint32_t reg, uint32_t val)

{

    uint32_t tmp;

    switch (reg) {

    case IRQ_IPVP:

        /* NOTE: not fully accurate for special IRQs, but simple and

           sufficient */

        /* ACTIVITY bit is read-only */

        opp->src[n_IRQ].ipvp =

            (opp->src[n_IRQ].ipvp & 0x40000000) |

            (val & 0x800F00FF);

        openpic_update_irq(opp, n_IRQ);

        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",

                n_IRQ, val, opp->src[n_IRQ].ipvp);

        break;

    case IRQ_IDE:

        tmp = val & 0xC0000000;

        tmp |= val & ((1 << MAX_CPU) - 1);

        opp->src[n_IRQ].ide = tmp;

        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);

        break;

    }

}


static void ff_h264_idct_add16_sse2(uint8_t *dst, const int *block_offset, DCTELEM *block, int stride, const uint8_t nnzc[6*8]){

    int i;

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

        if(nnzc[ scan8[i+0] ]|nnzc[ scan8[i+1] ])

            ff_x264_add8x4_idct_sse2 (dst + block_offset[i], block + i*16, stride);

}


static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,

                             target_ulong v)

{

    uint32_t status;

    uint32_t tcu, tmx, tasid, tksu;

    uint32_t mask = ((1 << CP0St_CU3)

                       | (1 << CP0St_CU2)

                       | (1 << CP0St_CU1)

                       | (1 << CP0St_CU0)

                       | (1 << CP0St_MX)

                       | (3 << CP0St_KSU));

    tcu = (v >> CP0TCSt_TCU0) & 0xf;

    tmx = (v >> CP0TCSt_TMX) & 0x1;

    tasid = v & 0xff;

    tksu = (v >> CP0TCSt_TKSU) & 0x3;

    status = tcu << CP0St_CU0;

    status |= tmx << CP0St_MX;

    status |= tksu << CP0St_KSU;

    cpu->CP0_Status &= ~mask;

    cpu->CP0_Status |= status;

    /* Sync the TASID with EntryHi.  */

    cpu->CP0_EntryHi &= ~0xff;

    cpu->CP0_EntryHi = tasid;

    compute_hflags(cpu);

}


static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *gb)
{
    MpegEncContext *s = &ctx->m;
    int a     = 2 << s->sprite_warping_accuracy;
    int rho   = 3  - s->sprite_warping_accuracy;
    int r     = 16 / a;
    int alpha = 0;
    int beta  = 0;
    int w     = s->width;
    int h     = s->height;
    int min_ab, i, w2, h2, w3, h3;
    int sprite_ref[4][2];
    int virtual_ref[2][2];
    // only true for rectangle shapes
    const int vop_ref[4][2] = { { 0, 0 },         { s->width, 0 },
                                { 0, s->height }, { s->width, s->height } };
    int d[4][2]             = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
    if (w <= 0 || h <= 0)
        return AVERROR_INVALIDDATA;
    for (i = 0; i < ctx->num_sprite_warping_points; i++) {
        int length;
        int x = 0, y = 0;
        length = get_vlc2(gb, sprite_trajectory.table, SPRITE_TRAJ_VLC_BITS, 3);
        if (length > 0)
            x = get_xbits(gb, length);
        if (!(ctx->divx_version == 500 && ctx->divx_build == 413))
            check_marker(s->avctx, gb, "before sprite_trajectory");
        length = get_vlc2(gb, sprite_trajectory.table, SPRITE_TRAJ_VLC_BITS, 3);
        if (length > 0)
            y = get_xbits(gb, length);
        check_marker(s->avctx, gb, "after sprite_trajectory");
        ctx->sprite_traj[i][0] = d[i][0] = x;
        ctx->sprite_traj[i][1] = d[i][1] = y;
    for (; i < 4; i++)
        ctx->sprite_traj[i][0] = ctx->sprite_traj[i][1] = 0;
    while ((1 << alpha) < w)
        alpha++;
    while ((1 << beta) < h)
        beta++;  /* typo in the MPEG-4 std for the definition of w' and h' */
    w2 = 1 << alpha;
    h2 = 1 << beta;
    // Note, the 4th point isn't used for GMC
    if (ctx->divx_version == 500 && ctx->divx_build == 413) {
        sprite_ref[0][0] = a * vop_ref[0][0] + d[0][0];
        sprite_ref[0][1] = a * vop_ref[0][1] + d[0][1];
        sprite_ref[1][0] = a * vop_ref[1][0] + d[0][0] + d[1][0];
        sprite_ref[1][1] = a * vop_ref[1][1] + d[0][1] + d[1][1];
        sprite_ref[2][0] = a * vop_ref[2][0] + d[0][0] + d[2][0];
        sprite_ref[2][1] = a * vop_ref[2][1] + d[0][1] + d[2][1];
    } else {
        sprite_ref[0][0] = (a >> 1) * (2 * vop_ref[0][0] + d[0][0]);
        sprite_ref[0][1] = (a >> 1) * (2 * vop_ref[0][1] + d[0][1]);
        sprite_ref[1][0] = (a >> 1) * (2 * vop_ref[1][0] + d[0][0] + d[1][0]);
        sprite_ref[1][1] = (a >> 1) * (2 * vop_ref[1][1] + d[0][1] + d[1][1]);
        sprite_ref[2][0] = (a >> 1) * (2 * vop_ref[2][0] + d[0][0] + d[2][0]);
        sprite_ref[2][1] = (a >> 1) * (2 * vop_ref[2][1] + d[0][1] + d[2][1]);
    /* sprite_ref[3][0] = (a >> 1) * (2 * vop_ref[3][0] + d[0][0] + d[1][0] + d[2][0] + d[3][0]);
     * sprite_ref[3][1] = (a >> 1) * (2 * vop_ref[3][1] + d[0][1] + d[1][1] + d[2][1] + d[3][1]); */
    /* This is mostly identical to the MPEG-4 std (and is totally unreadable
     * because of that...). Perhaps it should be reordered to be more readable.
     * The idea behind this virtual_ref mess is to be able to use shifts later
     * per pixel instead of divides so the distance between points is converted
     * from w&h based to w2&h2 based which are of the 2^x form. */
    virtual_ref[0][0] = 16 * (vop_ref[0][0] + w2) +
                         ROUNDED_DIV(((w - w2) *
                                      (r * sprite_ref[0][0] - 16 * vop_ref[0][0]) +
                                      w2 * (r * sprite_ref[1][0] - 16 * vop_ref[1][0])), w);
    virtual_ref[0][1] = 16 * vop_ref[0][1] +
                        ROUNDED_DIV(((w - w2) *
                                     (r * sprite_ref[0][1] - 16 * vop_ref[0][1]) +
                                     w2 * (r * sprite_ref[1][1] - 16 * vop_ref[1][1])), w);
    virtual_ref[1][0] = 16 * vop_ref[0][0] +
                        ROUNDED_DIV(((h - h2) * (r * sprite_ref[0][0] - 16 * vop_ref[0][0]) +
                                     h2 * (r * sprite_ref[2][0] - 16 * vop_ref[2][0])), h);
    virtual_ref[1][1] = 16 * (vop_ref[0][1] + h2) +
                        ROUNDED_DIV(((h - h2) * (r * sprite_ref[0][1] - 16 * vop_ref[0][1]) +
                                     h2 * (r * sprite_ref[2][1] - 16 * vop_ref[2][1])), h);
    switch (ctx->num_sprite_warping_points) {
    case 0:
        s->sprite_offset[0][0] =
        s->sprite_offset[0][1] =
        s->sprite_offset[1][0] =
        s->sprite_offset[1][1] = 0;
        s->sprite_delta[0][0]  = a;
        s->sprite_delta[0][1]  =
        s->sprite_delta[1][0]  = 0;
        s->sprite_delta[1][1]  = a;
        ctx->sprite_shift[0]   =
        ctx->sprite_shift[1]   = 0;
        break;
    case 1:     // GMC only
        s->sprite_offset[0][0] = sprite_ref[0][0] - a * vop_ref[0][0];
        s->sprite_offset[0][1] = sprite_ref[0][1] - a * vop_ref[0][1];
        s->sprite_offset[1][0] = ((sprite_ref[0][0] >> 1) | (sprite_ref[0][0] & 1)) -
                                 a * (vop_ref[0][0] / 2);
        s->sprite_offset[1][1] = ((sprite_ref[0][1] >> 1) | (sprite_ref[0][1] & 1)) -
                                 a * (vop_ref[0][1] / 2);
        s->sprite_delta[0][0]  = a;
        s->sprite_delta[0][1]  =
        s->sprite_delta[1][0]  = 0;
        s->sprite_delta[1][1]  = a;
        ctx->sprite_shift[0]   =
        ctx->sprite_shift[1]   = 0;
        break;
    case 2:
        s->sprite_offset[0][0] = (sprite_ref[0][0] << (alpha + rho)) +
                                 (-r * sprite_ref[0][0] + virtual_ref[0][0]) *
                                 (-vop_ref[0][0]) +
                                 (r * sprite_ref[0][1] - virtual_ref[0][1]) *
                                 (-vop_ref[0][1]) + (1 << (alpha + rho - 1));
        s->sprite_offset[0][1] = (sprite_ref[0][1] << (alpha + rho)) +
                                 (-r * sprite_ref[0][1] + virtual_ref[0][1]) *
                                 (-vop_ref[0][0]) +
                                 (-r * sprite_ref[0][0] + virtual_ref[0][0]) *
                                 (-vop_ref[0][1]) + (1 << (alpha + rho - 1));
        s->sprite_offset[1][0] = ((-r * sprite_ref[0][0] + virtual_ref[0][0]) *
                                  (-2 * vop_ref[0][0] + 1) +
                                  (r * sprite_ref[0][1] - virtual_ref[0][1]) *
                                  (-2 * vop_ref[0][1] + 1) + 2 * w2 * r *
                                  sprite_ref[0][0] - 16 * w2 + (1 << (alpha + rho + 1)));
        s->sprite_offset[1][1] = ((-r * sprite_ref[0][1] + virtual_ref[0][1]) *
                                  (-2 * vop_ref[0][0] + 1) +
                                  (-r * sprite_ref[0][0] + virtual_ref[0][0]) *
                                  (-2 * vop_ref[0][1] + 1) + 2 * w2 * r *
                                  sprite_ref[0][1] - 16 * w2 + (1 << (alpha + rho + 1)));
        s->sprite_delta[0][0] = (-r * sprite_ref[0][0] + virtual_ref[0][0]);
        s->sprite_delta[0][1] = (+r * sprite_ref[0][1] - virtual_ref[0][1]);
        s->sprite_delta[1][0] = (-r * sprite_ref[0][1] + virtual_ref[0][1]);
        s->sprite_delta[1][1] = (-r * sprite_ref[0][0] + virtual_ref[0][0]);
        ctx->sprite_shift[0]  = alpha + rho;
        ctx->sprite_shift[1]  = alpha + rho + 2;
        break;
    case 3:
        min_ab = FFMIN(alpha, beta);
        w3     = w2 >> min_ab;
        h3     = h2 >> min_ab;
        s->sprite_offset[0][0] = (sprite_ref[0][0] * (1<<(alpha + beta + rho - min_ab))) +
                                 (-r * sprite_ref[0][0] + virtual_ref[0][0]) *
                                 h3 * (-vop_ref[0][0]) +
                                 (-r * sprite_ref[0][0] + virtual_ref[1][0]) *
                                 w3 * (-vop_ref[0][1]) +
                                 (1 << (alpha + beta + rho - min_ab - 1));
        s->sprite_offset[0][1] = (sprite_ref[0][1] * (1 << (alpha + beta + rho - min_ab))) +
                                 (-r * sprite_ref[0][1] + virtual_ref[0][1]) *
                                 h3 * (-vop_ref[0][0]) +
                                 (-r * sprite_ref[0][1] + virtual_ref[1][1]) *
                                 w3 * (-vop_ref[0][1]) +
                                 (1 << (alpha + beta + rho - min_ab - 1));
        s->sprite_offset[1][0] = (-r * sprite_ref[0][0] + virtual_ref[0][0]) *
                                 h3 * (-2 * vop_ref[0][0] + 1) +
                                 (-r * sprite_ref[0][0] + virtual_ref[1][0]) *
                                 w3 * (-2 * vop_ref[0][1] + 1) + 2 * w2 * h3 *
                                 r * sprite_ref[0][0] - 16 * w2 * h3 +
                                 (1 << (alpha + beta + rho - min_ab + 1));
        s->sprite_offset[1][1] = (-r * sprite_ref[0][1] + virtual_ref[0][1]) *
                                 h3 * (-2 * vop_ref[0][0] + 1) +
                                 (-r * sprite_ref[0][1] + virtual_ref[1][1]) *
                                 w3 * (-2 * vop_ref[0][1] + 1) + 2 * w2 * h3 *
                                 r * sprite_ref[0][1] - 16 * w2 * h3 +
                                 (1 << (alpha + beta + rho - min_ab + 1));
        s->sprite_delta[0][0] = (-r * sprite_ref[0][0] + virtual_ref[0][0]) * h3;
        s->sprite_delta[0][1] = (-r * sprite_ref[0][0] + virtual_ref[1][0]) * w3;
        s->sprite_delta[1][0] = (-r * sprite_ref[0][1] + virtual_ref[0][1]) * h3;
        s->sprite_delta[1][1] = (-r * sprite_ref[0][1] + virtual_ref[1][1]) * w3;
        ctx->sprite_shift[0]  = alpha + beta + rho - min_ab;
        ctx->sprite_shift[1]  = alpha + beta + rho - min_ab + 2;
        break;
    /* try to simplify the situation */
    if (s->sprite_delta[0][0] == a << ctx->sprite_shift[0] &&
        s->sprite_delta[0][1] == 0 &&
        s->sprite_delta[1][0] == 0 &&
        s->sprite_delta[1][1] == a << ctx->sprite_shift[0]) {
        s->sprite_offset[0][0] >>= ctx->sprite_shift[0];
        s->sprite_offset[0][1] >>= ctx->sprite_shift[0];
        s->sprite_offset[1][0] >>= ctx->sprite_shift[1];
        s->sprite_offset[1][1] >>= ctx->sprite_shift[1];
        s->sprite_delta[0][0] = a;
        s->sprite_delta[0][1] = 0;
        s->sprite_delta[1][0] = 0;
        s->sprite_delta[1][1] = a;
        ctx->sprite_shift[0] = 0;
        ctx->sprite_shift[1] = 0;
        s->real_sprite_warping_points = 1;
    } else {
        int shift_y = 16 - ctx->sprite_shift[0];
        int shift_c = 16 - ctx->sprite_shift[1];
        if (shift_c < 0 || shift_y < 0 ||
            FFABS(s->sprite_offset[0][0]) >= INT_MAX >> shift_y  ||
            FFABS(s->sprite_offset[1][0]) >= INT_MAX >> shift_c  ||
            FFABS(s->sprite_offset[0][1]) >= INT_MAX >> shift_y  ||
            FFABS(s->sprite_offset[1][1]) >= INT_MAX >> shift_c
        ) {
            avpriv_request_sample(s->avctx, "Too large sprite shift or offset");
        for (i = 0; i < 2; i++) {
            s->sprite_offset[0][i] *= 1 << shift_y;
            s->sprite_offset[1][i] *= 1 << shift_c;
            s->sprite_delta[0][i]  *= 1 << shift_y;
            s->sprite_delta[1][i]  *= 1 << shift_y;
            ctx->sprite_shift[i]     = 16;
        s->real_sprite_warping_points = ctx->num_sprite_warping_points;
    return 0;


static void gen_add16(TCGv t0, TCGv t1)

{

    TCGv tmp = new_tmp();

    tcg_gen_xor_i32(tmp, t0, t1);

    tcg_gen_andi_i32(tmp, tmp, 0x8000);

    tcg_gen_andi_i32(t0, t0, ~0x8000);

    tcg_gen_andi_i32(t1, t1, ~0x8000);

    tcg_gen_add_i32(t0, t0, t1);

    tcg_gen_xor_i32(t0, t0, tmp);

    dead_tmp(tmp);

    dead_tmp(t1);

}


static void do_v7m_exception_exit(ARMCPU *cpu)

{

    CPUARMState *env = &cpu->env;

    CPUState *cs = CPU(cpu);

    uint32_t excret;

    uint32_t xpsr;

    bool ufault = false;

    bool sfault = false;

    bool return_to_sp_process;

    bool return_to_handler;

    bool rettobase = false;

    bool exc_secure = false;

    bool return_to_secure;

    /* We can only get here from an EXCP_EXCEPTION_EXIT, and

     * gen_bx_excret() enforces the architectural rule

     * that jumps to magic addresses don't have magic behaviour unless

     * we're in Handler mode (compare pseudocode BXWritePC()).

     */

    assert(arm_v7m_is_handler_mode(env));

    /* In the spec pseudocode ExceptionReturn() is called directly

     * from BXWritePC() and gets the full target PC value including

     * bit zero. In QEMU's implementation we treat it as a normal

     * jump-to-register (which is then caught later on), and so split

     * the target value up between env->regs[15] and env->thumb in

     * gen_bx(). Reconstitute it.

     */

    excret = env->regs[15];

    if (env->thumb) {

        excret |= 1;

    }

    qemu_log_mask(CPU_LOG_INT, "Exception return: magic PC %" PRIx32

                  " previous exception %d\n",

                  excret, env->v7m.exception);

    if ((excret & R_V7M_EXCRET_RES1_MASK) != R_V7M_EXCRET_RES1_MASK) {

        qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "

                      "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",

                      excret);

    }

    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {

        /* EXC_RETURN.ES validation check (R_SMFL). We must do this before

         * we pick which FAULTMASK to clear.

         */

        if (!env->v7m.secure &&

            ((excret & R_V7M_EXCRET_ES_MASK) ||

             !(excret & R_V7M_EXCRET_DCRS_MASK))) {

            sfault = 1;

            /* For all other purposes, treat ES as 0 (R_HXSR) */

            excret &= ~R_V7M_EXCRET_ES_MASK;

        }

    }

    if (env->v7m.exception != ARMV7M_EXCP_NMI) {

        /* Auto-clear FAULTMASK on return from other than NMI.

         * If the security extension is implemented then this only

         * happens if the raw execution priority is >= 0; the

         * value of the ES bit in the exception return value indicates

         * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)

         */

        if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {

            exc_secure = excret & R_V7M_EXCRET_ES_MASK;

            if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {

                env->v7m.faultmask[exc_secure] = 0;

            }

        } else {

            env->v7m.faultmask[M_REG_NS] = 0;

        }

    }

    switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception,

                                     exc_secure)) {

    case -1:

        /* attempt to exit an exception that isn't active */

        ufault = true;

        break;

    case 0:

        /* still an irq active now */

        break;

    case 1:

        /* we returned to base exception level, no nesting.

         * (In the pseudocode this is written using "NestedActivation != 1"

         * where we have 'rettobase == false'.)

         */

        rettobase = true;

        break;

    default:

        g_assert_not_reached();

    }

    return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);

    return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;

    return_to_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&

        (excret & R_V7M_EXCRET_S_MASK);

    if (arm_feature(env, ARM_FEATURE_V8)) {

        if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {

            /* UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);

             * we choose to take the UsageFault.

             */

            if ((excret & R_V7M_EXCRET_S_MASK) ||

                (excret & R_V7M_EXCRET_ES_MASK) ||

                !(excret & R_V7M_EXCRET_DCRS_MASK)) {

                ufault = true;

            }

        }

        if (excret & R_V7M_EXCRET_RES0_MASK) {

            ufault = true;

        }

    } else {

        /* For v7M we only recognize certain combinations of the low bits */

        switch (excret & 0xf) {

        case 1: /* Return to Handler */

            break;

        case 13: /* Return to Thread using Process stack */

        case 9: /* Return to Thread using Main stack */

            /* We only need to check NONBASETHRDENA for v7M, because in

             * v8M this bit does not exist (it is RES1).

             */

            if (!rettobase &&

                !(env->v7m.ccr[env->v7m.secure] &

                  R_V7M_CCR_NONBASETHRDENA_MASK)) {

                ufault = true;

            }

            break;

        default:

            ufault = true;

        }

    }

    if (sfault) {

        env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;

        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);

        v7m_exception_taken(cpu, excret);

        qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "

                      "stackframe: failed EXC_RETURN.ES validity check\n");

        return;

    }

    if (ufault) {

        /* Bad exception return: instead of popping the exception

         * stack, directly take a usage fault on the current stack.

         */

        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;

        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);

        v7m_exception_taken(cpu, excret);

        qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "

                      "stackframe: failed exception return integrity check\n");

        return;

    }

    /* Set CONTROL.SPSEL from excret.SPSEL. Since we're still in

     * Handler mode (and will be until we write the new XPSR.Interrupt

     * field) this does not switch around the current stack pointer.

     */

    write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);

    switch_v7m_security_state(env, return_to_secure);

    {

        /* The stack pointer we should be reading the exception frame from

         * depends on bits in the magic exception return type value (and

         * for v8M isn't necessarily the stack pointer we will eventually

         * end up resuming execution with). Get a pointer to the location

         * in the CPU state struct where the SP we need is currently being

         * stored; we will use and modify it in place.

         * We use this limited C variable scope so we don't accidentally

         * use 'frame_sp_p' after we do something that makes it invalid.

         */

        uint32_t *frame_sp_p = get_v7m_sp_ptr(env,

                                              return_to_secure,

                                              !return_to_handler,

                                              return_to_sp_process);

        uint32_t frameptr = *frame_sp_p;

        if (!QEMU_IS_ALIGNED(frameptr, 8) &&

            arm_feature(env, ARM_FEATURE_V8)) {

            qemu_log_mask(LOG_GUEST_ERROR,

                          "M profile exception return with non-8-aligned SP "

                          "for destination state is UNPREDICTABLE\n");

        }

        /* Do we need to pop callee-saved registers? */

        if (return_to_secure &&

            ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||

             (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {

            uint32_t expected_sig = 0xfefa125b;

            uint32_t actual_sig = ldl_phys(cs->as, frameptr);

            if (expected_sig != actual_sig) {

                /* Take a SecureFault on the current stack */

                env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;

                armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);

                v7m_exception_taken(cpu, excret);

                qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "

                              "stackframe: failed exception return integrity "

                              "signature check\n");

                return;

            }

            env->regs[4] = ldl_phys(cs->as, frameptr + 0x8);

            env->regs[5] = ldl_phys(cs->as, frameptr + 0xc);

            env->regs[6] = ldl_phys(cs->as, frameptr + 0x10);

            env->regs[7] = ldl_phys(cs->as, frameptr + 0x14);

            env->regs[8] = ldl_phys(cs->as, frameptr + 0x18);

            env->regs[9] = ldl_phys(cs->as, frameptr + 0x1c);

            env->regs[10] = ldl_phys(cs->as, frameptr + 0x20);

            env->regs[11] = ldl_phys(cs->as, frameptr + 0x24);

            frameptr += 0x28;

        }

        /* Pop registers. TODO: make these accesses use the correct

         * attributes and address space (S/NS, priv/unpriv) and handle

         * memory transaction failures.

         */

        env->regs[0] = ldl_phys(cs->as, frameptr);

        env->regs[1] = ldl_phys(cs->as, frameptr + 0x4);

        env->regs[2] = ldl_phys(cs->as, frameptr + 0x8);

        env->regs[3] = ldl_phys(cs->as, frameptr + 0xc);

        env->regs[12] = ldl_phys(cs->as, frameptr + 0x10);

        env->regs[14] = ldl_phys(cs->as, frameptr + 0x14);

        env->regs[15] = ldl_phys(cs->as, frameptr + 0x18);

        /* Returning from an exception with a PC with bit 0 set is defined

         * behaviour on v8M (bit 0 is ignored), but for v7M it was specified

         * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore

         * the lsbit, and there are several RTOSes out there which incorrectly

         * assume the r15 in the stack frame should be a Thumb-style "lsbit

         * indicates ARM/Thumb" value, so ignore the bit on v7M as well, but

         * complain about the badly behaved guest.

         */

        if (env->regs[15] & 1) {

            env->regs[15] &= ~1U;

            if (!arm_feature(env, ARM_FEATURE_V8)) {

                qemu_log_mask(LOG_GUEST_ERROR,

                              "M profile return from interrupt with misaligned "

                              "PC is UNPREDICTABLE on v7M\n");

            }

        }

        xpsr = ldl_phys(cs->as, frameptr + 0x1c);

        if (arm_feature(env, ARM_FEATURE_V8)) {

            /* For v8M we have to check whether the xPSR exception field

             * matches the EXCRET value for return to handler/thread

             * before we commit to changing the SP and xPSR.

             */

            bool will_be_handler = (xpsr & XPSR_EXCP) != 0;

            if (return_to_handler != will_be_handler) {

                /* Take an INVPC UsageFault on the current stack.

                 * By this point we will have switched to the security state

                 * for the background state, so this UsageFault will target

                 * that state.

                 */

                armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,

                                        env->v7m.secure);

                env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;

                v7m_exception_taken(cpu, excret);

                qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "

                              "stackframe: failed exception return integrity "

                              "check\n");

                return;

            }

        }

        /* Commit to consuming the stack frame */

        frameptr += 0x20;

        /* Undo stack alignment (the SPREALIGN bit indicates that the original

         * pre-exception SP was not 8-aligned and we added a padding word to

         * align it, so we undo this by ORing in the bit that increases it

         * from the current 8-aligned value to the 8-unaligned value. (Adding 4

         * would work too but a logical OR is how the pseudocode specifies it.)

         */

        if (xpsr & XPSR_SPREALIGN) {

            frameptr |= 4;

        }

        *frame_sp_p = frameptr;

    }

    /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */

    xpsr_write(env, xpsr, ~XPSR_SPREALIGN);

    /* The restored xPSR exception field will be zero if we're

     * resuming in Thread mode. If that doesn't match what the

     * exception return excret specified then this is a UsageFault.

     * v7M requires we make this check here; v8M did it earlier.

     */

    if (return_to_handler != arm_v7m_is_handler_mode(env)) {

        /* Take an INVPC UsageFault by pushing the stack again;

         * we know we're v7M so this is never a Secure UsageFault.

         */

        assert(!arm_feature(env, ARM_FEATURE_V8));

        armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);

        env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;

        v7m_push_stack(cpu);

        v7m_exception_taken(cpu, excret);

        qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "

                      "failed exception return integrity check\n");

        return;

    }

    /* Otherwise, we have a successful exception exit. */

    arm_clear_exclusive(env);

    qemu_log_mask(CPU_LOG_INT, "...successful exception return\n");

}


static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)

{

    int (*filter_frame)(AVFilterLink *, AVFrame *);

    AVFilterContext *dstctx = link->dst;

    AVFilterPad *dst = link->dstpad;

    AVFrame *out;

    int ret;

    AVFilterCommand *cmd= link->dst->command_queue;

    int64_t pts;

    if (link->closed) {

        av_frame_free(&frame);

        return AVERROR_EOF;

    }

    if (!(filter_frame = dst->filter_frame))

        filter_frame = default_filter_frame;

    /* copy the frame if needed */

    if (dst->needs_writable && !av_frame_is_writable(frame)) {

        av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n");

        /* Maybe use ff_copy_buffer_ref instead? */

        switch (link->type) {

        case AVMEDIA_TYPE_VIDEO:

            out = ff_get_video_buffer(link, link->w, link->h);

            break;

        case AVMEDIA_TYPE_AUDIO:

            out = ff_get_audio_buffer(link, frame->nb_samples);

            break;

        default:

            ret = AVERROR(EINVAL);

            goto fail;

        }

        if (!out) {

            ret = AVERROR(ENOMEM);

            goto fail;

        }

        ret = av_frame_copy_props(out, frame);

        if (ret < 0)

            goto fail;

        switch (link->type) {

        case AVMEDIA_TYPE_VIDEO:

            av_image_copy(out->data, out->linesize, (const uint8_t **)frame->data, frame->linesize,

                          frame->format, frame->width, frame->height);

            break;

        case AVMEDIA_TYPE_AUDIO:

            av_samples_copy(out->extended_data, frame->extended_data,

                            0, 0, frame->nb_samples,

                            av_get_channel_layout_nb_channels(frame->channel_layout),

                            frame->format);

            break;

        default:

            ret = AVERROR(EINVAL);

            goto fail;

        }

        av_frame_free(&frame);

    } else

        out = frame;

    while(cmd && cmd->time <= out->pts * av_q2d(link->time_base)){

        av_log(link->dst, AV_LOG_DEBUG,

               "Processing command time:%f command:%s arg:%s\n",

               cmd->time, cmd->command, cmd->arg);

        avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags);

        ff_command_queue_pop(link->dst);

        cmd= link->dst->command_queue;

    }

    pts = out->pts;

    if (dstctx->enable_str) {

        int64_t pos = av_frame_get_pkt_pos(out);

        dstctx->var_values[VAR_N] = link->frame_count;

        dstctx->var_values[VAR_T] = pts == AV_NOPTS_VALUE ? NAN : pts * av_q2d(link->time_base);

        dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos;

        dstctx->is_disabled = fabs(av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) < 0.5;

        if (dstctx->is_disabled &&

            (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC))

            filter_frame = default_filter_frame;

    }

    ret = filter_frame(link, out);

    link->frame_count++;

    link->frame_requested = 0;

    ff_update_link_current_pts(link, pts);

    return ret;

fail:

    av_frame_free(&out);

    av_frame_free(&frame);

    return ret;

}


static inline void FUNC(idctRowCondDC)(int16_t *row, int extra_shift)

{

    int a0, a1, a2, a3, b0, b1, b2, b3;

#if HAVE_FAST_64BIT

#define ROW0_MASK (0xffffLL << 48 * HAVE_BIGENDIAN)

    if (((((uint64_t *)row)[0] & ~ROW0_MASK) | ((uint64_t *)row)[1]) == 0) {

        uint64_t temp;

        if (DC_SHIFT - extra_shift > 0) {

            temp = (row[0] << (DC_SHIFT - extra_shift)) & 0xffff;

        } else {

            temp = (row[0] >> (extra_shift - DC_SHIFT)) & 0xffff;

        }

        temp += temp << 16;

        temp += temp << 32;

        ((uint64_t *)row)[0] = temp;

        ((uint64_t *)row)[1] = temp;

        return;

    }

#else

    if (!(((uint32_t*)row)[1] |

          ((uint32_t*)row)[2] |

          ((uint32_t*)row)[3] |

          row[1])) {

        uint32_t temp;

        if (DC_SHIFT - extra_shift > 0) {

            temp = (row[0] << (DC_SHIFT - extra_shift)) & 0xffff;

        } else {

            temp = (row[0] >> (extra_shift - DC_SHIFT)) & 0xffff;

        }

        temp += temp << 16;

        ((uint32_t*)row)[0]=((uint32_t*)row)[1] =

            ((uint32_t*)row)[2]=((uint32_t*)row)[3] = temp;

        return;

    }

#endif

    a0 = (W4 * row[0]) + (1 << (ROW_SHIFT - 1));

    a1 = a0;

    a2 = a0;

    a3 = a0;

    a0 += W2 * row[2];

    a1 += W6 * row[2];

    a2 -= W6 * row[2];

    a3 -= W2 * row[2];

    b0 = MUL(W1, row[1]);

    MAC(b0, W3, row[3]);

    b1 = MUL(W3, row[1]);

    MAC(b1, -W7, row[3]);

    b2 = MUL(W5, row[1]);

    MAC(b2, -W1, row[3]);

    b3 = MUL(W7, row[1]);

    MAC(b3, -W5, row[3]);

    if (AV_RN64A(row + 4)) {

        a0 +=   W4*row[4] + W6*row[6];

        a1 += - W4*row[4] - W2*row[6];

        a2 += - W4*row[4] + W2*row[6];

        a3 +=   W4*row[4] - W6*row[6];

        MAC(b0,  W5, row[5]);

        MAC(b0,  W7, row[7]);

        MAC(b1, -W1, row[5]);

        MAC(b1, -W5, row[7]);

        MAC(b2,  W7, row[5]);

        MAC(b2,  W3, row[7]);

        MAC(b3,  W3, row[5]);

        MAC(b3, -W1, row[7]);

    }

    row[0] = (a0 + b0) >> (ROW_SHIFT + extra_shift);

    row[7] = (a0 - b0) >> (ROW_SHIFT + extra_shift);

    row[1] = (a1 + b1) >> (ROW_SHIFT + extra_shift);

    row[6] = (a1 - b1) >> (ROW_SHIFT + extra_shift);

    row[2] = (a2 + b2) >> (ROW_SHIFT + extra_shift);

    row[5] = (a2 - b2) >> (ROW_SHIFT + extra_shift);

    row[3] = (a3 + b3) >> (ROW_SHIFT + extra_shift);

    row[4] = (a3 - b3) >> (ROW_SHIFT + extra_shift);

}


static int io_write_data_type(void *opaque, uint8_t *buf, int size,

                              enum AVIODataMarkerType type, int64_t time)

{

    char timebuf[30], content[5] = { 0 };

    const char *str;

    switch (type) {

    case AVIO_DATA_MARKER_HEADER:         str = "header";   break;

    case AVIO_DATA_MARKER_SYNC_POINT:     str = "sync";     break;

    case AVIO_DATA_MARKER_BOUNDARY_POINT: str = "boundary"; break;

    case AVIO_DATA_MARKER_UNKNOWN:        str = "unknown";  break;

    case AVIO_DATA_MARKER_TRAILER:        str = "trailer";  break;

    }

    if (time == AV_NOPTS_VALUE)

        snprintf(timebuf, sizeof(timebuf), "nopts");

    else

        snprintf(timebuf, sizeof(timebuf), "%"PRId64, time);

    // There can be multiple header/trailer callbacks, only log the box type

    // for header at out_size == 0

    if (type != AVIO_DATA_MARKER_UNKNOWN &&

        type != AVIO_DATA_MARKER_TRAILER &&

        (type != AVIO_DATA_MARKER_HEADER || out_size == 0) &&

        size >= 8)

        memcpy(content, &buf[4], 4);

    else

        snprintf(content, sizeof(content), "-");

    printf("write_data len %d, time %s, type %s atom %s\n", size, timebuf, str, content);

    return io_write(opaque, buf, size);

}


static void release_buffer(AVCodecContext *avctx, AVFrame *pic)

{

    int i;

    CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];

    CVPixelBufferUnlockBaseAddress(cv_buffer, 0);

    CVPixelBufferRelease(cv_buffer);

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

        pic->data[i] = NULL;

}


AVOption *av_set_string(void *obj, const char *name, const char *val){

    AVOption *o= find_opt(obj, name);

    if(!o || !val || o->offset<=0)

        return NULL;

    if(o->type != FF_OPT_TYPE_STRING){

        double d=0, tmp_d;

        for(;;){

            int i;

            char buf[256], *tail;

            for(i=0; i<sizeof(buf)-1 && val[i] && val[i]!='+'; i++)

                buf[i]= val[i];

            buf[i]=0;

            val+= i;

            tmp_d= av_parse_num(buf, &tail);

            if(tail > buf)

                d+= tmp_d;

            else{

                AVOption *o_named= find_opt(obj, buf);

                if(o_named && o_named->type == FF_OPT_TYPE_CONST)

                    d+= o_named->default_val;

                else if(!strcmp(buf, "default")) d+= o->default_val;

                else if(!strcmp(buf, "max"    )) d+= o->max;

                else if(!strcmp(buf, "min"    )) d+= o->min;

                else return NULL;

            }

            if(*val == '+') val++;

            if(!*val)

                return av_set_number(obj, name, d, 1, 1);

        }

        return NULL;

    }

    memcpy(((uint8_t*)obj) + o->offset, val, sizeof(val));

    return o;

}


static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)

{

    BDRVQEDState *s = acb_to_s(acb);

    /* Freeze this request if another allocating write is in progress */

    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {

        QSIMPLEQ_INSERT_TAIL(&s->allocating_write_reqs, acb, next);

    }

    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {

        return; /* wait for existing request to finish */

    }

    acb->cur_nclusters = qed_bytes_to_clusters(s,

            qed_offset_into_cluster(s, acb->cur_pos) + len);

    acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);

    qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);

    if (qed_should_set_need_check(s)) {

        s->header.features |= QED_F_NEED_CHECK;

        qed_write_header(s, qed_aio_write_prefill, acb);

    } else {

        qed_aio_write_prefill(acb, 0);

    }

}


static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)

{

    NumaOptions *object = NULL;

    Error *err = NULL;

    {

        Visitor *v = opts_visitor_new(opts);

        visit_type_NumaOptions(v, NULL, &object, &err);

        visit_free(v);

    }

    if (err) {

        goto error;

    }

    switch (object->type) {

    case NUMA_OPTIONS_KIND_NODE:

        numa_node_parse(object->u.node.data, opts, &err);

        if (err) {

            goto error;

        }

        nb_numa_nodes++;

        break;

    default:

        abort();

    }

    return 0;

error:

    error_report_err(err);

    qapi_free_NumaOptions(object);

    return -1;

}


static uint8_t send_read_command(void)

{

    uint8_t drive = 0;

    uint8_t head = 0;

    uint8_t cyl = 0;

    uint8_t sect_addr = 1;

    uint8_t sect_size = 2;

    uint8_t eot = 1;

    uint8_t gap = 0x1b;

    uint8_t gpl = 0xff;

    uint8_t msr = 0;

    uint8_t st0;

    uint8_t ret = 0;

    floppy_send(CMD_READ);

    floppy_send(head << 2 | drive);

    g_assert(!get_irq(FLOPPY_IRQ));

    floppy_send(cyl);

    floppy_send(head);

    floppy_send(sect_addr);

    floppy_send(sect_size);

    floppy_send(eot);

    floppy_send(gap);

    floppy_send(gpl);

    uint8_t i = 0;

    uint8_t n = 2;

    for (; i < n; i++) {

        msr = inb(FLOPPY_BASE + reg_msr);

        if (msr == 0xd0) {

            break;

        }

        sleep(1);

    }

    if (i >= n) {

        return 1;

    }

    st0 = floppy_recv();

    if (st0 != 0x40) {

        ret = 1;

    }

    floppy_recv();

    floppy_recv();

    floppy_recv();

    floppy_recv();

    floppy_recv();

    floppy_recv();

    return ret;

}


static void trigger_ascii_console_data(void *opaque, int n, int level)

{

    sclp_service_interrupt(0);

}


static uint64_t bonito_readl(void *opaque, hwaddr addr,

                             unsigned size)

{

    PCIBonitoState *s = opaque;

    uint32_t saddr;

    saddr = (addr - BONITO_REGBASE) >> 2;

    DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr);

    switch (saddr) {

    case BONITO_INTISR:

        return s->regs[saddr];

    default:

        return s->regs[saddr];

    }

}


static int virtio_net_can_receive(void *opaque)

{

    VirtIONet *n = opaque;

    return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE);

}


static void bt_hci_inquiry_result(struct bt_hci_s *hci,

                struct bt_device_s *slave)

{

    if (!slave->inquiry_scan || !hci->lm.responses_left)

        return;

    hci->lm.responses_left --;

    hci->lm.responses ++;

    switch (hci->lm.inquiry_mode) {

    case 0x00:

        bt_hci_inquiry_result_standard(hci, slave);

        return;

    case 0x01:

        bt_hci_inquiry_result_with_rssi(hci, slave);

        return;

    default:

        fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__,

                        hci->lm.inquiry_mode);

        exit(-1);

    }

}


static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr)

{

    printf("qemu: hpet_read w at %" PRIx64 "\n", addr);

    return 0;

}


gen_intermediate_code_internal(MicroBlazeCPU *cpu, TranslationBlock *tb,

                               bool search_pc)

{

    CPUState *cs = CPU(cpu);

    CPUMBState *env = &cpu->env;

    uint32_t pc_start;

    int j, lj;

    struct DisasContext ctx;

    struct DisasContext *dc = &ctx;

    uint32_t next_page_start, org_flags;

    target_ulong npc;

    int num_insns;

    int max_insns;

    pc_start = tb->pc;

    dc->cpu = cpu;

    dc->tb = tb;

    org_flags = dc->synced_flags = dc->tb_flags = tb->flags;

    dc->is_jmp = DISAS_NEXT;

    dc->jmp = 0;

    dc->delayed_branch = !!(dc->tb_flags & D_FLAG);

    if (dc->delayed_branch) {

        dc->jmp = JMP_INDIRECT;

    }

    dc->pc = pc_start;

    dc->singlestep_enabled = cs->singlestep_enabled;

    dc->cpustate_changed = 0;

    dc->abort_at_next_insn = 0;

    dc->nr_nops = 0;

    if (pc_start & 3) {

        cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);

    }

    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {

#if !SIM_COMPAT

        qemu_log("--------------\n");

        log_cpu_state(CPU(cpu), 0);

#endif

    }

    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;

    lj = -1;

    num_insns = 0;

    max_insns = tb->cflags & CF_COUNT_MASK;

    if (max_insns == 0)

        max_insns = CF_COUNT_MASK;

    gen_tb_start(tb);

    do

    {

#if SIM_COMPAT

        if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {

            tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);

            gen_helper_debug();

        }

#endif

        check_breakpoint(env, dc);

        if (search_pc) {

            j = tcg_op_buf_count();

            if (lj < j) {

                lj++;

                while (lj < j)

                    tcg_ctx.gen_opc_instr_start[lj++] = 0;

            }

            tcg_ctx.gen_opc_pc[lj] = dc->pc;

            tcg_ctx.gen_opc_instr_start[lj] = 1;

                        tcg_ctx.gen_opc_icount[lj] = num_insns;

        }

        /* Pretty disas.  */

        LOG_DIS("%8.8x:\t", dc->pc);

        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))

            gen_io_start();

        dc->clear_imm = 1;

        decode(dc, cpu_ldl_code(env, dc->pc));

        if (dc->clear_imm)

            dc->tb_flags &= ~IMM_FLAG;

        dc->pc += 4;

        num_insns++;

        if (dc->delayed_branch) {

            dc->delayed_branch--;

            if (!dc->delayed_branch) {

                if (dc->tb_flags & DRTI_FLAG)

                    do_rti(dc);

                 if (dc->tb_flags & DRTB_FLAG)

                    do_rtb(dc);

                if (dc->tb_flags & DRTE_FLAG)

                    do_rte(dc);

                /* Clear the delay slot flag.  */

                dc->tb_flags &= ~D_FLAG;

                /* If it is a direct jump, try direct chaining.  */

                if (dc->jmp == JMP_INDIRECT) {

                    eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));

                    dc->is_jmp = DISAS_JUMP;

                } else if (dc->jmp == JMP_DIRECT) {

                    t_sync_flags(dc);

                    gen_goto_tb(dc, 0, dc->jmp_pc);

                    dc->is_jmp = DISAS_TB_JUMP;

                } else if (dc->jmp == JMP_DIRECT_CC) {

                    int l1;

                    t_sync_flags(dc);

                    l1 = gen_new_label();

                    /* Conditional jmp.  */

                    tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);

                    gen_goto_tb(dc, 1, dc->pc);

                    gen_set_label(l1);

                    gen_goto_tb(dc, 0, dc->jmp_pc);

                    dc->is_jmp = DISAS_TB_JUMP;

                }

                break;

            }

        }

        if (cs->singlestep_enabled) {

            break;

        }

    } while (!dc->is_jmp && !dc->cpustate_changed

             && !tcg_op_buf_full()

             && !singlestep

             && (dc->pc < next_page_start)

             && num_insns < max_insns);

    npc = dc->pc;

    if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {

        if (dc->tb_flags & D_FLAG) {

            dc->is_jmp = DISAS_UPDATE;

            tcg_gen_movi_tl(cpu_SR[SR_PC], npc);

            sync_jmpstate(dc);

        } else

            npc = dc->jmp_pc;

    }

    if (tb->cflags & CF_LAST_IO)

        gen_io_end();

    /* Force an update if the per-tb cpu state has changed.  */

    if (dc->is_jmp == DISAS_NEXT

        && (dc->cpustate_changed || org_flags != dc->tb_flags)) {

        dc->is_jmp = DISAS_UPDATE;

        tcg_gen_movi_tl(cpu_SR[SR_PC], npc);

    }

    t_sync_flags(dc);

    if (unlikely(cs->singlestep_enabled)) {

        TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);

        if (dc->is_jmp != DISAS_JUMP) {

            tcg_gen_movi_tl(cpu_SR[SR_PC], npc);

        }

        gen_helper_raise_exception(cpu_env, tmp);

        tcg_temp_free_i32(tmp);

    } else {

        switch(dc->is_jmp) {

            case DISAS_NEXT:

                gen_goto_tb(dc, 1, npc);

                break;

            default:

            case DISAS_JUMP:

            case DISAS_UPDATE:

                /* indicate that the hash table must be used

                   to find the next TB */

                tcg_gen_exit_tb(0);

                break;

            case DISAS_TB_JUMP:

                /* nothing more to generate */

                break;

        }

    }

    gen_tb_end(tb, num_insns);

    if (search_pc) {

        j = tcg_op_buf_count();

        lj++;

        while (lj <= j)

            tcg_ctx.gen_opc_instr_start[lj++] = 0;

    } else {

        tb->size = dc->pc - pc_start;

                tb->icount = num_insns;

    }

#ifdef DEBUG_DISAS

#if !SIM_COMPAT

    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {

        qemu_log("\n");

#if DISAS_GNU

        log_target_disas(env, pc_start, dc->pc - pc_start, 0);

#endif

        qemu_log("\nisize=%d osize=%d\n",

                 dc->pc - pc_start, tcg_op_buf_count());

    }

#endif

#endif

    assert(!dc->abort_at_next_insn);

}


static void test_bh_delete_from_cb_many(void)

{

    BHTestData data1 = { .n = 0, .max = 1 };

    BHTestData data2 = { .n = 0, .max = 3 };

    BHTestData data3 = { .n = 0, .max = 2 };

    BHTestData data4 = { .n = 0, .max = 4 };

    data1.bh = aio_bh_new(ctx, bh_delete_cb, &data1);

    data2.bh = aio_bh_new(ctx, bh_delete_cb, &data2);

    data3.bh = aio_bh_new(ctx, bh_delete_cb, &data3);

    data4.bh = aio_bh_new(ctx, bh_delete_cb, &data4);

    qemu_bh_schedule(data1.bh);

    qemu_bh_schedule(data2.bh);

    qemu_bh_schedule(data3.bh);

    qemu_bh_schedule(data4.bh);

    g_assert_cmpint(data1.n, ==, 0);

    g_assert_cmpint(data2.n, ==, 0);

    g_assert_cmpint(data3.n, ==, 0);

    g_assert_cmpint(data4.n, ==, 0);

    g_assert(aio_poll(ctx, false));

    g_assert_cmpint(data1.n, ==, 1);

    g_assert_cmpint(data2.n, ==, 1);

    g_assert_cmpint(data3.n, ==, 1);

    g_assert_cmpint(data4.n, ==, 1);

    g_assert(data1.bh == NULL);

    wait_for_aio();

    g_assert_cmpint(data1.n, ==, data1.max);

    g_assert_cmpint(data2.n, ==, data2.max);

    g_assert_cmpint(data3.n, ==, data3.max);

    g_assert_cmpint(data4.n, ==, data4.max);

    g_assert(data1.bh == NULL);

    g_assert(data2.bh == NULL);

    g_assert(data3.bh == NULL);

    g_assert(data4.bh == NULL);

}


static int raw_has_zero_init(BlockDriverState *bs)

{

    return bdrv_has_zero_init(bs->file->bs);

}


void bios_linker_loader_add_pointer(GArray *linker,

                                    const char *dest_file,

                                    const char *src_file,

                                    GArray *table, void *pointer,

                                    uint8_t pointer_size)

{

    BiosLinkerLoaderEntry entry;

    memset(&entry, 0, sizeof entry);

    strncpy(entry.pointer.dest_file, dest_file,

            sizeof entry.pointer.dest_file - 1);

    strncpy(entry.pointer.src_file, src_file,

            sizeof entry.pointer.src_file - 1);

    entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER);

    entry.pointer.offset = cpu_to_le32((gchar *)pointer - table->data);

    entry.pointer.size = pointer_size;

    assert(pointer_size == 1 || pointer_size == 2 ||

           pointer_size == 4 || pointer_size == 8);

    g_array_append_val(linker, entry);

}


static void vga_draw_graphic(VGACommonState *s, int full_update)

{

    int y1, y, update, linesize, y_start, double_scan, mask, depth;

    int width, height, shift_control, line_offset, bwidth, bits;

    ram_addr_t page0, page1, page_min, page_max;

    int disp_width, multi_scan, multi_run;

    uint8_t *d;

    uint32_t v, addr1, addr;

    vga_draw_line_func *vga_draw_line;

    full_update |= update_basic_params(s);

    if (!full_update)

        vga_sync_dirty_bitmap(s);

    s->get_resolution(s, &width, &height);

    disp_width = width;

    shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;

    double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);

    if (shift_control != 1) {

        multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)

            - 1;

    } else {

        /* in CGA modes, multi_scan is ignored */

        /* XXX: is it correct ? */

        multi_scan = double_scan;

    }

    multi_run = multi_scan;

    if (shift_control != s->shift_control ||

        double_scan != s->double_scan) {

        full_update = 1;

        s->shift_control = shift_control;

        s->double_scan = double_scan;

    }

    if (shift_control == 0) {

        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {

            disp_width <<= 1;

        }

    } else if (shift_control == 1) {

        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {

            disp_width <<= 1;

        }

    }

    depth = s->get_bpp(s);

    if (s->line_offset != s->last_line_offset ||

        disp_width != s->last_width ||

        height != s->last_height ||

        s->last_depth != depth) {

#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)

        if (depth == 16 || depth == 32) {

#else

        if (depth == 32) {

#endif

            qemu_free_displaysurface(s->ds);

            s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,

                    s->line_offset,

                    s->vram_ptr + (s->start_addr * 4));

#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)

            s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);

#endif

            dpy_gfx_resize(s->ds);

        } else {

            qemu_console_resize(s->ds, disp_width, height);

        }

        s->last_scr_width = disp_width;

        s->last_scr_height = height;

        s->last_width = disp_width;

        s->last_height = height;

        s->last_line_offset = s->line_offset;

        s->last_depth = depth;

        full_update = 1;

    } else if (is_buffer_shared(s->ds->surface) &&

               (full_update || ds_get_data(s->ds) != s->vram_ptr

                + (s->start_addr * 4))) {

        qemu_free_displaysurface(s->ds);

        s->ds->surface = qemu_create_displaysurface_from(disp_width,

                height, depth,

                s->line_offset,

                s->vram_ptr + (s->start_addr * 4));

        dpy_gfx_setdata(s->ds);

    }

    s->rgb_to_pixel =

        rgb_to_pixel_dup_table[get_depth_index(s->ds)];

    if (shift_control == 0) {

        full_update |= update_palette16(s);

        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {

            v = VGA_DRAW_LINE4D2;

        } else {

            v = VGA_DRAW_LINE4;

        }

        bits = 4;

    } else if (shift_control == 1) {

        full_update |= update_palette16(s);

        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {

            v = VGA_DRAW_LINE2D2;

        } else {

            v = VGA_DRAW_LINE2;

        }

        bits = 4;

    } else {

        switch(s->get_bpp(s)) {

        default:

        case 0:

            full_update |= update_palette256(s);

            v = VGA_DRAW_LINE8D2;

            bits = 4;

            break;

        case 8:

            full_update |= update_palette256(s);

            v = VGA_DRAW_LINE8;

            bits = 8;

            break;

        case 15:

            v = VGA_DRAW_LINE15;

            bits = 16;

            break;

        case 16:

            v = VGA_DRAW_LINE16;

            bits = 16;

            break;

        case 24:

            v = VGA_DRAW_LINE24;

            bits = 24;

            break;

        case 32:

            v = VGA_DRAW_LINE32;

            bits = 32;

            break;

        }

    }

    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];

    if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)

        s->cursor_invalidate(s);

    line_offset = s->line_offset;

#if 0

    printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",

           width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],

           s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);

#endif

    addr1 = (s->start_addr * 4);

    bwidth = (width * bits + 7) / 8;

    y_start = -1;

    page_min = -1;

    page_max = 0;

    d = ds_get_data(s->ds);

    linesize = ds_get_linesize(s->ds);

    y1 = 0;

    for(y = 0; y < height; y++) {

        addr = addr1;

        if (!(s->cr[VGA_CRTC_MODE] & 1)) {

            int shift;

            /* CGA compatibility handling */

            shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);

            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);

        }

        if (!(s->cr[VGA_CRTC_MODE] & 2)) {

            addr = (addr & ~0x8000) | ((y1 & 2) << 14);

        }

        update = full_update;

        page0 = addr;

        page1 = addr + bwidth - 1;

        update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,

                                          DIRTY_MEMORY_VGA);

        /* explicit invalidation for the hardware cursor */

        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;

        if (update) {

            if (y_start < 0)

                y_start = y;

            if (page0 < page_min)

                page_min = page0;

            if (page1 > page_max)

                page_max = page1;

            if (!(is_buffer_shared(s->ds->surface))) {

                vga_draw_line(s, d, s->vram_ptr + addr, width);

                if (s->cursor_draw_line)

                    s->cursor_draw_line(s, d, y);

            }

        } else {

            if (y_start >= 0) {

                /* flush to display */

                dpy_gfx_update(s->ds, 0, y_start,

                               disp_width, y - y_start);

                y_start = -1;

            }

        }

        if (!multi_run) {

            mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;

            if ((y1 & mask) == mask)

                addr1 += line_offset;

            y1++;

            multi_run = multi_scan;

        } else {

            multi_run--;

        }

        /* line compare acts on the displayed lines */

        if (y == s->line_compare)

            addr1 = 0;

        d += linesize;

    }

    if (y_start >= 0) {

        /* flush to display */

        dpy_gfx_update(s->ds, 0, y_start,

                       disp_width, y - y_start);

    }

    /* reset modified pages */

    if (page_max >= page_min) {

        memory_region_reset_dirty(&s->vram,

                                  page_min,

                                  page_max - page_min,

                                  DIRTY_MEMORY_VGA);

    }

    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);

}