static void decode(Real288_internal *glob, float gain, int cb_coef)

{

    unsigned int x, y;

    float f;

    double sum, sumsum;

    float *p1, *p2;

    float buffer[5];

    for (x=36; x--; glob->sb[x+5] = glob->sb[x]);

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

        p1 = glob->sb+x;

        p2 = glob->pr1;

        for (sum=0, y=36; y--; sum -= (*(++p1))*(*(p2++)));

        glob->sb[x] = sum;

    }

    /* convert log and do rms */

    for (sum=32, x=10; x--; sum -= glob->pr2[x] * glob->lhist[x]);

    if (sum < 0)

        sum = 0;

    else if (sum > 60)

        sum = 60;

    sumsum = exp(sum * 0.1151292546497) * gain;    /* pow(10.0,sum/20)*f */

    for (sum=0, x=5; x--;) {

        buffer[x] = codetable[cb_coef][x] * sumsum;

        sum += buffer[x] * buffer[x];

    }

    if ((sum /= 5) < 1)

        sum = 1;

    /* shift and store */

    for (x=10; --x; glob->lhist[x] = glob->lhist[x-1]);

    *glob->lhist = glob->history[glob->phase] = 10 * log10(sum) - 32;

    for (x=1; x < 5; x++)

        for (y=x; y--; buffer[x] -= glob->pr1[x-y-1] * buffer[y]);

    /* output */

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

        f = glob->sb[4-x] + buffer[x];

        if (f > 4095)

            f = 4095;

        else if (f < -4095)

            f = -4095;

        glob->output[glob->phasep+x] = glob->sb[4-x] = f;

    }

}


int url_open_dyn_packet_buf(AVIOContext **s, int max_packet_size)

{

    if (max_packet_size <= 0)

        return -1;

    return url_open_dyn_buf_internal(s, max_packet_size);

}


static int ffmal_update_format(AVCodecContext *avctx)

{

    MMALDecodeContext *ctx = avctx->priv_data;

    MMAL_STATUS_T status;

    int ret = 0;

    MMAL_COMPONENT_T *decoder = ctx->decoder;

    MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format;

    ffmmal_poolref_unref(ctx->pool_out);

    if (!(ctx->pool_out = av_mallocz(sizeof(*ctx->pool_out)))) {

        ret = AVERROR(ENOMEM);

        goto fail;

    }

    atomic_store(&ctx->pool_out->refcount, 1);

    if (!format_out)

        goto fail;

    if ((status = mmal_port_parameter_set_uint32(decoder->output[0], MMAL_PARAMETER_EXTRA_BUFFERS, ctx->extra_buffers)))

        goto fail;

    if ((status = mmal_port_parameter_set_boolean(decoder->output[0], MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS, 0)))

        goto fail;

    if (avctx->pix_fmt == AV_PIX_FMT_MMAL) {

        format_out->encoding = MMAL_ENCODING_OPAQUE;

    } else {

        format_out->encoding_variant = format_out->encoding = MMAL_ENCODING_I420;

    }

    if ((status = mmal_port_format_commit(decoder->output[0])))

        goto fail;

    if ((ret = ff_set_dimensions(avctx, format_out->es->video.crop.x + format_out->es->video.crop.width,

                                        format_out->es->video.crop.y + format_out->es->video.crop.height)) < 0)

        goto fail;

    if (format_out->es->video.par.num && format_out->es->video.par.den) {

        avctx->sample_aspect_ratio.num = format_out->es->video.par.num;

        avctx->sample_aspect_ratio.den = format_out->es->video.par.den;

    }

    avctx->colorspace = ffmmal_csp_to_av_csp(format_out->es->video.color_space);

    decoder->output[0]->buffer_size =

        FFMAX(decoder->output[0]->buffer_size_min, decoder->output[0]->buffer_size_recommended);

    decoder->output[0]->buffer_num =

        FFMAX(decoder->output[0]->buffer_num_min, decoder->output[0]->buffer_num_recommended) + ctx->extra_buffers;

    ctx->pool_out->pool = mmal_pool_create(decoder->output[0]->buffer_num,

                                           decoder->output[0]->buffer_size);

    if (!ctx->pool_out->pool) {

        ret = AVERROR(ENOMEM);

        goto fail;

    }

    return 0;

fail:

    return ret < 0 ? ret : AVERROR_UNKNOWN;

}


static void gen_stswx(DisasContext *ctx)

{

    TCGv t0;

    TCGv_i32 t1, t2;

    gen_set_access_type(ctx, ACCESS_INT);

    /* NIP cannot be restored if the memory exception comes from an helper */

    gen_update_nip(ctx, ctx->nip - 4);

    t0 = tcg_temp_new();

    gen_addr_reg_index(ctx, t0);

    t1 = tcg_temp_new_i32();

    tcg_gen_trunc_tl_i32(t1, cpu_xer);

    tcg_gen_andi_i32(t1, t1, 0x7F);

    t2 = tcg_const_i32(rS(ctx->opcode));

    gen_helper_stsw(cpu_env, t0, t1, t2);

    tcg_temp_free(t0);

    tcg_temp_free_i32(t1);

    tcg_temp_free_i32(t2);

}


uint64_t HELPER(neon_abdl_s64)(uint32_t a, uint32_t b)

{

    uint64_t result;

    DO_ABD(result, a, b, int32_t);

    return result;

}


static int stdio_fclose(void *opaque)

{

    QEMUFileStdio *s = opaque;

    int ret = 0;

    if (qemu_file_is_writable(s->file)) {

        int fd = fileno(s->stdio_file);

        struct stat st;

        ret = fstat(fd, &st);

        if (ret == 0 && S_ISREG(st.st_mode)) {

            /*

             * If the file handle is a regular file make sure the

             * data is flushed to disk before signaling success.

             */

            ret = fsync(fd);

            if (ret != 0) {

                ret = -errno;

                return ret;

            }

        }

    }

    if (fclose(s->stdio_file) == EOF) {

        ret = -errno;

    }

    g_free(s);

    return ret;

}


static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,

                                     ppc_slb_t *slb, target_ulong eaddr,

                                     ppc_hash_pte64_t *pte)

{

    hwaddr pteg_off, pte_offset;

    hwaddr hash;

    uint64_t vsid, epnshift, epnmask, epn, ptem;

    /* Page size according to the SLB, which we use to generate the

     * EPN for hash table lookup..  When we implement more recent MMU

     * extensions this might be different from the actual page size

     * encoded in the PTE */

    epnshift = (slb->vsid & SLB_VSID_L)

        ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;

    epnmask = ~((1ULL << epnshift) - 1);

    if (slb->vsid & SLB_VSID_B) {

        /* 1TB segment */

        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;

        epn = (eaddr & ~SEGMENT_MASK_1T) & epnmask;

        hash = vsid ^ (vsid << 25) ^ (epn >> epnshift);

    } else {

        /* 256M segment */

        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;

        epn = (eaddr & ~SEGMENT_MASK_256M) & epnmask;

        hash = vsid ^ (epn >> epnshift);

    }

    ptem = (slb->vsid & SLB_VSID_PTEM) | ((epn >> 16) & HPTE64_V_AVPN);

    /* Page address translation */

    LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx

            " hash " TARGET_FMT_plx "\n",

            env->htab_base, env->htab_mask, hash);

    /* Primary PTEG lookup */

    LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx

            " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx

            " hash=" TARGET_FMT_plx "\n",

            env->htab_base, env->htab_mask, vsid, ptem,  hash);

    pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask;

    pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, pte);

    if (pte_offset == -1) {

        /* Secondary PTEG lookup */

        LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx

                " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx

                " hash=" TARGET_FMT_plx "\n", env->htab_base,

                env->htab_mask, vsid, ptem, ~hash);

        pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask;

        pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, pte);

    }

    return pte_offset;

}


static int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias)

{

    // init first elem to 1 to avoid div by 0 in convert_matrix

    uint16_t weight_matrix[64] = {1,}; // convert_matrix needs uint16_t*

    int qscale, i;

    CHECKED_ALLOCZ(ctx->qmatrix_l,   (ctx->m.avctx->qmax+1) * 64 * sizeof(int));

    CHECKED_ALLOCZ(ctx->qmatrix_c,   (ctx->m.avctx->qmax+1) * 64 * sizeof(int));

    CHECKED_ALLOCZ(ctx->qmatrix_l16, (ctx->m.avctx->qmax+1) * 64 * 2 * sizeof(uint16_t));

    CHECKED_ALLOCZ(ctx->qmatrix_c16, (ctx->m.avctx->qmax+1) * 64 * 2 * sizeof(uint16_t));

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

        int j = ctx->m.dsp.idct_permutation[ff_zigzag_direct[i]];

        weight_matrix[j] = ctx->cid_table->luma_weight[i];

    }

    ff_convert_matrix(&ctx->m.dsp, ctx->qmatrix_l, ctx->qmatrix_l16, weight_matrix,

                      ctx->m.intra_quant_bias, 1, ctx->m.avctx->qmax, 1);

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

        int j = ctx->m.dsp.idct_permutation[ff_zigzag_direct[i]];

        weight_matrix[j] = ctx->cid_table->chroma_weight[i];

    }

    ff_convert_matrix(&ctx->m.dsp, ctx->qmatrix_c, ctx->qmatrix_c16, weight_matrix,

                      ctx->m.intra_quant_bias, 1, ctx->m.avctx->qmax, 1);

    for (qscale = 1; qscale <= ctx->m.avctx->qmax; qscale++) {

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

            ctx->qmatrix_l  [qscale]   [i] <<= 2; ctx->qmatrix_c  [qscale]   [i] <<= 2;

            ctx->qmatrix_l16[qscale][0][i] <<= 2; ctx->qmatrix_l16[qscale][1][i] <<= 2;

            ctx->qmatrix_c16[qscale][0][i] <<= 2; ctx->qmatrix_c16[qscale][1][i] <<= 2;

        }

    }

    return 0;

 fail:

    return -1;

}


static av_cold int a64multi_close_encoder(AVCodecContext *avctx)

{

    A64Context *c = avctx->priv_data;

    av_frame_free(&avctx->coded_frame);

    av_free(c->mc_meta_charset);

    av_free(c->mc_best_cb);

    av_free(c->mc_charset);

    av_free(c->mc_charmap);

    av_free(c->mc_colram);

    return 0;

}


void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
{
    unsigned int i;
    target_ulong val = 0;
    helper_check_align(addr, 3);
    addr = asi_address_mask(env, asi, addr);
    switch (asi) {
    case 0xe0: // UA2007 Block commit store primary (cache flush)
    case 0xe1: // UA2007 Block commit store secondary (cache flush)
    case 0xf0: // Block store primary
    case 0xf1: // Block store secondary
    case 0xf8: // Block store primary LE
    case 0xf9: // Block store secondary LE
            helper_st_asi(addr, val, asi & 0x8f, 4);
    default:
        break;
    switch(size) {
    default:
    case 4:
        val = *((uint32_t *)&env->fpr[rd]);
        break;
    case 8:
        val = *((int64_t *)&DT0);
        break;
    case 16:
        // XXX
        break;
    helper_st_asi(addr, val, asi, size);


static int drive_add(const char *file, const char *fmt, ...)

{

    va_list ap;

    int index = drive_opt_get_free_idx();

    if (nb_drives_opt >= MAX_DRIVES || index == -1) {

        fprintf(stderr, "qemu: too many drives\n");

        exit(1);

    }

    drives_opt[index].file = file;

    va_start(ap, fmt);

    vsnprintf(drives_opt[index].opt,

              sizeof(drives_opt[0].opt), fmt, ap);

    va_end(ap);

    nb_drives_opt++;

    return index;

}


int avcodec_close(AVCodecContext *avctx)

{

    entangled_thread_counter++;

    if(entangled_thread_counter != 1){

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

        entangled_thread_counter--;

        return -1;

    }

    if (ENABLE_THREADS && avctx->thread_opaque)

        avcodec_thread_free(avctx);

    if (avctx->codec->close)

        avctx->codec->close(avctx);

    avcodec_default_free_buffers(avctx);

    av_freep(&avctx->priv_data);

    avctx->codec = NULL;

    entangled_thread_counter--;

    return 0;

}


void av_dump_format(AVFormatContext *ic, int index,

                    const char *url, int is_output)

{

    int i;

    uint8_t *printed = ic->nb_streams ? av_mallocz(ic->nb_streams) : NULL;

    if (ic->nb_streams && !printed)

        return;

    av_log(NULL, AV_LOG_INFO, "%s #%d, %s, %s '%s':\n",

           is_output ? "Output" : "Input",

           index,

           is_output ? ic->oformat->name : ic->iformat->name,

           is_output ? "to" : "from", url);

    dump_metadata(NULL, ic->metadata, "  ");

    if (!is_output) {

        av_log(NULL, AV_LOG_INFO, "  Duration: ");

        if (ic->duration != AV_NOPTS_VALUE) {

            int hours, mins, secs, us;

            int64_t duration = ic->duration + (ic->duration <= INT64_MAX - 5000 ? 5000 : 0);

            secs  = duration / AV_TIME_BASE;

            us    = duration % AV_TIME_BASE;

            mins  = secs / 60;

            secs %= 60;

            hours = mins / 60;

            mins %= 60;

            av_log(NULL, AV_LOG_INFO, "%02d:%02d:%02d.%02d", hours, mins, secs,

                   (100 * us) / AV_TIME_BASE);

        } else {

            av_log(NULL, AV_LOG_INFO, "N/A");

        }

        if (ic->start_time != AV_NOPTS_VALUE) {

            int secs, us;

            av_log(NULL, AV_LOG_INFO, ", start: ");

            secs = ic->start_time / AV_TIME_BASE;

            us   = llabs(ic->start_time % AV_TIME_BASE);

            av_log(NULL, AV_LOG_INFO, "%d.%06d",

                   secs, (int) av_rescale(us, 1000000, AV_TIME_BASE));

        }

        av_log(NULL, AV_LOG_INFO, ", bitrate: ");

        if (ic->bit_rate)

            av_log(NULL, AV_LOG_INFO, "%"PRId64" kb/s", (int64_t)ic->bit_rate / 1000);

        else

            av_log(NULL, AV_LOG_INFO, "N/A");

        av_log(NULL, AV_LOG_INFO, "\n");

    }

    for (i = 0; i < ic->nb_chapters; i++) {

        AVChapter *ch = ic->chapters[i];

        av_log(NULL, AV_LOG_INFO, "    Chapter #%d:%d: ", index, i);

        av_log(NULL, AV_LOG_INFO,

               "start %f, ", ch->start * av_q2d(ch->time_base));

        av_log(NULL, AV_LOG_INFO,

               "end %f\n", ch->end * av_q2d(ch->time_base));

        dump_metadata(NULL, ch->metadata, "    ");

    }

    if (ic->nb_programs) {

        int j, k, total = 0;

        for (j = 0; j < ic->nb_programs; j++) {

            AVDictionaryEntry *name = av_dict_get(ic->programs[j]->metadata,

                                                  "name", NULL, 0);

            av_log(NULL, AV_LOG_INFO, "  Program %d %s\n", ic->programs[j]->id,

                   name ? name->value : "");

            dump_metadata(NULL, ic->programs[j]->metadata, "    ");

            for (k = 0; k < ic->programs[j]->nb_stream_indexes; k++) {

                dump_stream_format(ic, ic->programs[j]->stream_index[k],

                                   index, is_output);

                printed[ic->programs[j]->stream_index[k]] = 1;

            }

            total += ic->programs[j]->nb_stream_indexes;

        }

        if (total < ic->nb_streams)

            av_log(NULL, AV_LOG_INFO, "  No Program\n");

    }

    for (i = 0; i < ic->nb_streams; i++)

        if (!printed[i])

            dump_stream_format(ic, i, index, is_output);

    av_free(printed);

}


static int get_next_block(DumpState *s, RAMBlock *block)

{

    while (1) {

        block = QTAILQ_NEXT(block, next);

        if (!block) {

            /* no more block */

            return 1;

        }

        s->start = 0;

        s->block = block;

        if (s->has_filter) {

            if (block->offset >= s->begin + s->length ||

                block->offset + block->length <= s->begin) {

                /* This block is out of the range */

                continue;

            }

            if (s->begin > block->offset) {

                s->start = s->begin - block->offset;

            }

        }

        return 0;

    }

}


static void scsi_req_xfer_mode(SCSIRequest *req)

{

    switch (req->cmd.buf[0]) {

    case WRITE_6:

    case WRITE_10:

    case WRITE_VERIFY:

    case WRITE_12:

    case WRITE_VERIFY_12:

    case WRITE_16:

    case WRITE_VERIFY_16:

    case COPY:

    case COPY_VERIFY:

    case COMPARE:

    case CHANGE_DEFINITION:

    case LOG_SELECT:

    case MODE_SELECT:

    case MODE_SELECT_10:

    case SEND_DIAGNOSTIC:

    case WRITE_BUFFER:

    case FORMAT_UNIT:

    case REASSIGN_BLOCKS:

    case SEARCH_EQUAL:

    case SEARCH_HIGH:

    case SEARCH_LOW:

    case UPDATE_BLOCK:

    case WRITE_LONG:

    case WRITE_SAME:

    case SEARCH_HIGH_12:

    case SEARCH_EQUAL_12:

    case SEARCH_LOW_12:

    case MEDIUM_SCAN:

    case SEND_VOLUME_TAG:

    case WRITE_LONG_2:

    case PERSISTENT_RESERVE_OUT:

    case MAINTENANCE_OUT:

        req->cmd.mode = SCSI_XFER_TO_DEV;

        break;

    default:

        if (req->cmd.xfer)

            req->cmd.mode = SCSI_XFER_FROM_DEV;

        else {

            req->cmd.mode = SCSI_XFER_NONE;

        }

        break;

    }

}


static int decode_hextile(VmncContext *c, uint8_t *dst, const uint8_t *src,

                          int ssize, int w, int h, int stride)

{

    int i, j, k;

    int bg = 0, fg = 0, rects, color, flags, xy, wh;

    const int bpp = c->bpp2;

    uint8_t *dst2;

    int bw = 16, bh = 16;

    const uint8_t *ssrc = src;

    for (j = 0; j < h; j += 16) {

        dst2 = dst;

        bw   = 16;

        if (j + 16 > h)

            bh = h - j;

        for (i = 0; i < w; i += 16, dst2 += 16 * bpp) {

            if (src - ssrc >= ssize) {

                av_log(c->avctx, AV_LOG_ERROR, "Premature end of data!\n");

                return -1;

            }

            if (i + 16 > w)

                bw = w - i;

            flags = *src++;

            if (flags & HT_RAW) {

                if (src - ssrc > ssize - bw * bh * bpp) {

                    av_log(c->avctx, AV_LOG_ERROR, "Premature end of data!\n");

                    return -1;

                }

                paint_raw(dst2, bw, bh, src, bpp, c->bigendian, stride);

                src += bw * bh * bpp;

            } else {

                if (flags & HT_BKG) {

                    bg = vmnc_get_pixel(src, bpp, c->bigendian);

                    src += bpp;

                }

                if (flags & HT_FG) {

                    fg = vmnc_get_pixel(src, bpp, c->bigendian);

                    src += bpp;

                }

                rects = 0;

                if (flags & HT_SUB)

                    rects = *src++;

                color = !!(flags & HT_CLR);

                paint_rect(dst2, 0, 0, bw, bh, bg, bpp, stride);

                if (src - ssrc > ssize - rects * (color * bpp + 2)) {

                    av_log(c->avctx, AV_LOG_ERROR, "Premature end of data!\n");

                    return -1;

                }

                for (k = 0; k < rects; k++) {

                    if (color) {

                        fg = vmnc_get_pixel(src, bpp, c->bigendian);

                        src += bpp;

                    }

                    xy = *src++;

                    wh = *src++;

                    paint_rect(dst2, xy >> 4, xy & 0xF, (wh >> 4) + 1,

                               (wh & 0xF) + 1, fg, bpp, stride);

                }

            }

        }

        dst += stride * 16;

    }

    return src - ssrc;

}


void do_interrupt(CPUState *env)

{

    int intno = env->exception_index;

#ifdef DEBUG_PCALL

    if (qemu_loglevel_mask(CPU_LOG_INT)) {

        static int count;

        const char *name;

        if (intno < 0 || intno >= 0x180)

            name = "Unknown";

        else if (intno >= 0x100)

            name = "Trap Instruction";

        else if (intno >= 0xc0)

            name = "Window Fill";

        else if (intno >= 0x80)

            name = "Window Spill";

        else {

            name = excp_names[intno];

            if (!name)

                name = "Unknown";

        }

        qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64

                " SP=%016" PRIx64 "\n",

                count, name, intno,

                env->pc,

                env->npc, env->regwptr[6]);

        log_cpu_state(env, 0);

#if 0

        {

            int i;

            uint8_t *ptr;

            qemu_log("       code=");

            ptr = (uint8_t *)env->pc;

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

                qemu_log(" %02x", ldub(ptr + i));

            }

            qemu_log("\n");

        }

#endif

        count++;

    }

#endif

#if !defined(CONFIG_USER_ONLY)

    if (env->tl >= env->maxtl) {

        cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"

                  " Error state", env->exception_index, env->tl, env->maxtl);

        return;

    }

#endif

    if (env->tl < env->maxtl - 1) {

        env->tl++;

    } else {

        env->pstate |= PS_RED;

        if (env->tl < env->maxtl)

            env->tl++;

    }

    env->tsptr = &env->ts[env->tl & MAXTL_MASK];

    env->tsptr->tstate = ((uint64_t)GET_CCR(env) << 32) |

        ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |

        GET_CWP64(env);

    env->tsptr->tpc = env->pc;

    env->tsptr->tnpc = env->npc;

    env->tsptr->tt = intno;

    if (!(env->def->features & CPU_FEATURE_GL)) {

        switch (intno) {

        case TT_IVEC:

            change_pstate(PS_PEF | PS_PRIV | PS_IG);

            break;

        case TT_TFAULT:

        case TT_TMISS:

        case TT_DFAULT:

        case TT_DMISS:

        case TT_DPROT:

            change_pstate(PS_PEF | PS_PRIV | PS_MG);

            break;

        default:

            change_pstate(PS_PEF | PS_PRIV | PS_AG);

            break;

        }

    }

    if (intno == TT_CLRWIN)

        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));

    else if ((intno & 0x1c0) == TT_SPILL)

        cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));

    else if ((intno & 0x1c0) == TT_FILL)

        cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));

    env->tbr &= ~0x7fffULL;

    env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);

    env->pc = env->tbr;

    env->npc = env->pc + 4;

    env->exception_index = 0;

}


int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,

               BlockDriver *drv)

{

    int ret, open_flags;

    char tmp_filename[PATH_MAX];

    char backing_filename[PATH_MAX];

    bs->read_only = 0;

    bs->is_temporary = 0;

    bs->encrypted = 0;

    bs->autogrow = 0;

    if (flags & BDRV_O_AUTOGROW)

        bs->autogrow = 1;

    if (flags & BDRV_O_SNAPSHOT) {

        BlockDriverState *bs1;

        int64_t total_size;

        /* if snapshot, we create a temporary backing file and open it

           instead of opening 'filename' directly */

        /* if there is a backing file, use it */

        bs1 = bdrv_new("");

        if (!bs1) {

            return -ENOMEM;

        }

        if (bdrv_open(bs1, filename, 0) < 0) {

            bdrv_delete(bs1);

            return -1;

        }

        total_size = bdrv_getlength(bs1) >> SECTOR_BITS;

        bdrv_delete(bs1);

        get_tmp_filename(tmp_filename, sizeof(tmp_filename));

        realpath(filename, backing_filename);

        if (bdrv_create(&bdrv_qcow2, tmp_filename,

                        total_size, backing_filename, 0) < 0) {

            return -1;

        }

        filename = tmp_filename;

        bs->is_temporary = 1;

    }

    pstrcpy(bs->filename, sizeof(bs->filename), filename);

    if (flags & BDRV_O_FILE) {

        drv = find_protocol(filename);

        if (!drv)

            return -ENOENT;

    } else {

        if (!drv) {

            drv = find_image_format(filename);

            if (!drv)

                return -1;

        }

    }

    bs->drv = drv;

    bs->opaque = qemu_mallocz(drv->instance_size);

    bs->total_sectors = 0; /* driver will set if it does not do getlength */

    if (bs->opaque == NULL && drv->instance_size > 0)

        return -1;

    /* Note: for compatibility, we open disk image files as RDWR, and

       RDONLY as fallback */

    if (!(flags & BDRV_O_FILE))

        open_flags = BDRV_O_RDWR | (flags & BDRV_O_DIRECT);

    else

        open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);

    ret = drv->bdrv_open(bs, filename, open_flags);

    if (ret == -EACCES && !(flags & BDRV_O_FILE)) {

        ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);

        bs->read_only = 1;

    }

    if (ret < 0) {

        qemu_free(bs->opaque);

        bs->opaque = NULL;

        bs->drv = NULL;

        return ret;

    }

    if (drv->bdrv_getlength) {

        bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;

    }

#ifndef _WIN32

    if (bs->is_temporary) {

        unlink(filename);

    }

#endif

    if (bs->backing_file[0] != '\0') {

        /* if there is a backing file, use it */

        bs->backing_hd = bdrv_new("");

        if (!bs->backing_hd) {

        fail:

            bdrv_close(bs);

            return -ENOMEM;

        }

        path_combine(backing_filename, sizeof(backing_filename),

                     filename, bs->backing_file);

        if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)

            goto fail;

    }

    /* call the change callback */

    bs->media_changed = 1;

    if (bs->change_cb)

        bs->change_cb(bs->change_opaque);

    return 0;

}


int ff_pre_estimate_p_frame_motion(MpegEncContext * s,

                                    int mb_x, int mb_y)

{

    MotionEstContext * const c= &s->me;

    int mx, my, dmin;

    int P[10][2];

    const int shift= 1+s->quarter_sample;

    const int xy= mb_x + mb_y*s->mb_stride;

    init_ref(c, s->new_picture.f.data, s->last_picture.f.data, NULL, 16*mb_x, 16*mb_y, 0);

    assert(s->quarter_sample==0 || s->quarter_sample==1);

    c->pre_penalty_factor    = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_pre_cmp);

    c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_MV;

    get_limits(s, 16*mb_x, 16*mb_y);

    c->skip=0;

    P_LEFT[0]       = s->p_mv_table[xy + 1][0];

    P_LEFT[1]       = s->p_mv_table[xy + 1][1];

    if(P_LEFT[0]       < (c->xmin<<shift)) P_LEFT[0]       = (c->xmin<<shift);

    /* special case for first line */

    if (s->first_slice_line) {

        c->pred_x= P_LEFT[0];

        c->pred_y= P_LEFT[1];

        P_TOP[0]= P_TOPRIGHT[0]= P_MEDIAN[0]=

        P_TOP[1]= P_TOPRIGHT[1]= P_MEDIAN[1]= 0; //FIXME

    } else {

        P_TOP[0]      = s->p_mv_table[xy + s->mb_stride    ][0];

        P_TOP[1]      = s->p_mv_table[xy + s->mb_stride    ][1];

        P_TOPRIGHT[0] = s->p_mv_table[xy + s->mb_stride - 1][0];

        P_TOPRIGHT[1] = s->p_mv_table[xy + s->mb_stride - 1][1];

        if(P_TOP[1]      < (c->ymin<<shift)) P_TOP[1]     = (c->ymin<<shift);

        if(P_TOPRIGHT[0] > (c->xmax<<shift)) P_TOPRIGHT[0]= (c->xmax<<shift);

        if(P_TOPRIGHT[1] < (c->ymin<<shift)) P_TOPRIGHT[1]= (c->ymin<<shift);

        P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);

        P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);

        c->pred_x = P_MEDIAN[0];

        c->pred_y = P_MEDIAN[1];

    }

    dmin = ff_epzs_motion_search(s, &mx, &my, P, 0, 0, s->p_mv_table, (1<<16)>>shift, 0, 16);

    s->p_mv_table[xy][0] = mx<<shift;

    s->p_mv_table[xy][1] = my<<shift;

    return dmin;

}


static inline int gsm_mult(int a, int b)

{

    return (a * b + (1 << 14)) >> 15;

}


int ff_xvid_rate_control_init(MpegEncContext *s){

    char *tmp_name;

    int fd, i;

    xvid_plg_create_t xvid_plg_create;

    xvid_plugin_2pass2_t xvid_2pass2;

//xvid_debug=-1;

    fd=av_tempfile("xvidrc.", &tmp_name, 0, s->avctx);

    if (fd == -1) {

        av_log(NULL, AV_LOG_ERROR, "Can't create temporary pass2 file.\n");

        return -1;

    }

    for(i=0; i<s->rc_context.num_entries; i++){

        static const char *frame_types = " ipbs";

        char tmp[256];

        RateControlEntry *rce;

        rce= &s->rc_context.entry[i];

        snprintf(tmp, sizeof(tmp), "%c %d %d %d %d %d %d\n",

            frame_types[rce->pict_type], (int)lrintf(rce->qscale / FF_QP2LAMBDA), rce->i_count, s->mb_num - rce->i_count - rce->skip_count,

            rce->skip_count, (rce->i_tex_bits + rce->p_tex_bits + rce->misc_bits+7)/8, (rce->header_bits+rce->mv_bits+7)/8);

//av_log(NULL, AV_LOG_ERROR, "%s\n", tmp);

        write(fd, tmp, strlen(tmp));

    }

    close(fd);

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

    xvid_2pass2.version= XVID_MAKE_VERSION(1,1,0);

    xvid_2pass2.filename= tmp_name;

    xvid_2pass2.bitrate= s->avctx->bit_rate;

    xvid_2pass2.vbv_size= s->avctx->rc_buffer_size;

    xvid_2pass2.vbv_maxrate= s->avctx->rc_max_rate;

    xvid_2pass2.vbv_initial= s->avctx->rc_initial_buffer_occupancy;

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

    xvid_plg_create.version= XVID_MAKE_VERSION(1,1,0);

    xvid_plg_create.fbase= s->avctx->time_base.den;

    xvid_plg_create.fincr= s->avctx->time_base.num;

    xvid_plg_create.param= &xvid_2pass2;

    if(xvid_plugin_2pass2(NULL, XVID_PLG_CREATE, &xvid_plg_create, &s->rc_context.non_lavc_opaque)<0){

        av_log(NULL, AV_LOG_ERROR, "xvid_plugin_2pass2 failed\n");

        return -1;

    }

    return 0;

}


static int dct_quantize_c(MpegEncContext *s,

                        DCTELEM *block, int n,

                        int qscale)

{

    int i, j, level, last_non_zero, q;

    const int *qmat;

    int minLevel, maxLevel;

    if(s->avctx!=NULL && s->avctx->codec->id==CODEC_ID_MPEG4){

	/* mpeg4 */

        minLevel= -2048;

	maxLevel= 2047;

    }else if(s->out_format==FMT_MPEG1){

	/* mpeg1 */

        minLevel= -255;

	maxLevel= 255;

    }else if(s->out_format==FMT_MJPEG){

	/* (m)jpeg */

        minLevel= -1023;

	maxLevel= 1023;

    }else{

	/* h263 / msmpeg4 */

        minLevel= -128;

	maxLevel= 127;

    }

    av_fdct (block);

    /* we need this permutation so that we correct the IDCT

       permutation. will be moved into DCT code */

    block_permute(block);

    if (s->mb_intra) {

        if (n < 4)

            q = s->y_dc_scale;

        else

            q = s->c_dc_scale;

        q = q << 3;

        /* note: block[0] is assumed to be positive */

        block[0] = (block[0] + (q >> 1)) / q;

        i = 1;

        last_non_zero = 0;

        if (s->out_format == FMT_H263) {

            qmat = s->q_non_intra_matrix;

        } else {

            qmat = s->q_intra_matrix;

        }

    } else {

        i = 0;

        last_non_zero = -1;

        qmat = s->q_non_intra_matrix;

    }

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

        j = zigzag_direct[i];

        level = block[j];

        level = level * qmat[j];

#ifdef PARANOID

        {

            static int count = 0;

            int level1, level2, qmat1;

            double val;

            if (qmat == s->q_non_intra_matrix) {

                qmat1 = default_non_intra_matrix[j] * s->qscale;

            } else {

                qmat1 = default_intra_matrix[j] * s->qscale;

            }

            if (av_fdct != jpeg_fdct_ifast)

                val = ((double)block[j] * 8.0) / (double)qmat1;

            else

                val = ((double)block[j] * 8.0 * 2048.0) /

                    ((double)qmat1 * aanscales[j]);

            level1 = (int)val;

            level2 = level / (1 << (QMAT_SHIFT - 3));

            if (level1 != level2) {

                fprintf(stderr, "%d: quant error qlevel=%d wanted=%d level=%d qmat1=%d qmat=%d wantedf=%0.6f\n",

                        count, level2, level1, block[j], qmat1, qmat[j],

                        val);

                count++;

            }

        }

#endif

        /* XXX: slight error for the low range. Test should be equivalent to

           (level <= -(1 << (QMAT_SHIFT - 3)) || level >= (1 <<

           (QMAT_SHIFT - 3)))

        */

        if (((level << (31 - (QMAT_SHIFT - 3))) >> (31 - (QMAT_SHIFT - 3))) !=

            level) {

            level = level / (1 << (QMAT_SHIFT - 3));

            /* XXX: currently, this code is not optimal. the range should be:

               mpeg1: -255..255

               mpeg2: -2048..2047

               h263:  -128..127

               mpeg4: -2048..2047

            */

            if (level > maxLevel)

                level = maxLevel;

            else if (level < minLevel)

                level = minLevel;

            block[j] = level;

            last_non_zero = i;

        } else {

            block[j] = 0;

        }

    }

    return last_non_zero;

}


static void drive_backup_abort(BlkActionState *common)

{

    DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);

    BlockDriverState *bs = state->bs;

    /* Only cancel if it's the job we started */

    if (bs && bs->job && bs->job == state->job) {

        block_job_cancel_sync(bs->job);

    }

}


static void ivshmem_check_version(void *opaque, const uint8_t * buf, int size)

{

    IVShmemState *s = opaque;

    int tmp;

    int64_t version;

    if (!fifo_update_and_get_i64(s, buf, size, &version)) {

        return;

    }

    tmp = qemu_chr_fe_get_msgfd(s->server_chr);

    if (tmp != -1 || version != IVSHMEM_PROTOCOL_VERSION) {

        fprintf(stderr, "incompatible version, you are connecting to a ivshmem-"

                "server using a different protocol please check your setup\n");

        qemu_chr_add_handlers(s->server_chr, NULL, NULL, NULL, s);

        return;

    }

    IVSHMEM_DPRINTF("version check ok, switch to real chardev handler\n");

    qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,

                          NULL, s);

}


static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof)

{

    AVIOContext *pb = s->pb;

    char abss[24];

    int hour, min, sec, i, ret, config;

    int dsd_layout[6];

    ID3v2ExtraMeta *id3v2_extra_meta;

    while (avio_tell(pb) + 12 <= eof) {

        uint32_t tag      = avio_rl32(pb);

        uint64_t size     = avio_rb64(pb);

        uint64_t orig_pos = avio_tell(pb);

        switch(tag) {

        case MKTAG('A','B','S','S'):

            if (size < 8)

                return AVERROR_INVALIDDATA;

            hour = avio_rb16(pb);

            min  = avio_r8(pb);

            sec  = avio_r8(pb);

            snprintf(abss, sizeof(abss), "%02dh:%02dm:%02ds:%d", hour, min, sec, avio_rb32(pb));

            av_dict_set(&st->metadata, "absolute_start_time", abss, 0);

            break;

        case MKTAG('C','H','N','L'):

            if (size < 2)

                return AVERROR_INVALIDDATA;

            st->codecpar->channels       = avio_rb16(pb);

            if (size < 2 + st->codecpar->channels * 4)

                return AVERROR_INVALIDDATA;

            st->codecpar->channel_layout = 0;

            if (st->codecpar->channels > FF_ARRAY_ELEMS(dsd_layout)) {

                avpriv_request_sample(s, "channel layout");

                break;

            }

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

                dsd_layout[i] = avio_rl32(pb);

            for (i = 0; i < FF_ARRAY_ELEMS(dsd_channel_layout); i++) {

                const DSDLayoutDesc * d = &dsd_channel_layout[i];

                if (av_get_channel_layout_nb_channels(d->layout) == st->codecpar->channels &&

                    !memcmp(d->dsd_layout, dsd_layout, st->codecpar->channels * sizeof(uint32_t))) {

                    st->codecpar->channel_layout = d->layout;

                    break;

                }

            }

            break;

        case MKTAG('C','M','P','R'):

            if (size < 4)

                return AVERROR_INVALIDDATA;

            tag = avio_rl32(pb);

            st->codecpar->codec_id = ff_codec_get_id(dsd_codec_tags, tag);

            if (!st->codecpar->codec_id) {

                av_log(s, AV_LOG_ERROR, "'%c%c%c%c' compression is not supported\n",

                    tag&0xFF, (tag>>8)&0xFF, (tag>>16)&0xFF, (tag>>24)&0xFF);

                return AVERROR_PATCHWELCOME;

            }

            break;

        case MKTAG('F','S',' ',' '):

            if (size < 4)

                return AVERROR_INVALIDDATA;

            st->codecpar->sample_rate = avio_rb32(pb) / 8;

            break;

        case MKTAG('I','D','3',' '):

            id3v2_extra_meta = NULL;

            ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size);

            if (id3v2_extra_meta) {

                if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) {

                    ff_id3v2_free_extra_meta(&id3v2_extra_meta);

                    return ret;

                }

                ff_id3v2_free_extra_meta(&id3v2_extra_meta);

            }

            if (size < avio_tell(pb) - orig_pos) {

                av_log(s, AV_LOG_ERROR, "id3 exceeds chunk size\n");

                return AVERROR_INVALIDDATA;

            }

            break;

        case MKTAG('L','S','C','O'):

            if (size < 2)

                return AVERROR_INVALIDDATA;

            config = avio_rb16(pb);

            if (config != 0xFFFF) {

                if (config < FF_ARRAY_ELEMS(dsd_loudspeaker_config))

                    st->codecpar->channel_layout = dsd_loudspeaker_config[config];

                if (!st->codecpar->channel_layout)

                    avpriv_request_sample(s, "loudspeaker configuration %d", config);

            }

            break;

        }

        avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1));

    }

    return 0;

}


static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,

                           uint8_t *buf, int buf_size)

{

    RTSPState *rt = s->priv_data;

    int id, len, i, ret;

    RTSPStream *rtsp_st;

#ifdef DEBUG_RTP_TCP

    dprintf(s, "tcp_read_packet:\n");

#endif

 redo:

    for(;;) {

        RTSPMessageHeader reply;

        ret = rtsp_read_reply(s, &reply, NULL, 1);

        if (ret == -1)

            return -1;

        if (ret == 1) /* received '$' */

            break;

        /* XXX: parse message */

        if (rt->state != RTSP_STATE_PLAYING)

            return 0;

    }

    ret = url_read_complete(rt->rtsp_hd, buf, 3);

    if (ret != 3)

        return -1;

    id = buf[0];

    len = AV_RB16(buf + 1);

#ifdef DEBUG_RTP_TCP

    dprintf(s, "id=%d len=%d\n", id, len);

#endif

    if (len > buf_size || len < 12)

        goto redo;

    /* get the data */

    ret = url_read_complete(rt->rtsp_hd, buf, len);

    if (ret != len)

        return -1;

    if (rt->transport == RTSP_TRANSPORT_RDT &&

        ff_rdt_parse_header(buf, len, &id, NULL, NULL, NULL, NULL) < 0)

        return -1;

    /* find the matching stream */

    for(i = 0; i < rt->nb_rtsp_streams; i++) {

        rtsp_st = rt->rtsp_streams[i];

        if (id >= rtsp_st->interleaved_min &&

            id <= rtsp_st->interleaved_max)

            goto found;

    }

    goto redo;

 found:

    *prtsp_st = rtsp_st;

    return len;

}


static int read_ts(const char *s, int64_t *start, int *duration)

{

    int64_t end;

    int hh1, mm1, ss1, ms1;

    int hh2, mm2, ss2, ms2;

    if (sscanf(s, "%u:%u:%u.%u,%u:%u:%u.%u",

               &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2) == 8) {

        end    = (hh2*3600 + mm2*60 + ss2) * 100 + ms2;

        *start = (hh1*3600 + mm1*60 + ss1) * 100 + ms1;

        *duration = end - *start;

        return 0;

    }

    return -1;

}


static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap)

{

    RMContext *rm = s->priv_data;

    AVStream *st;

    rm->old_format = 1;

    st = av_new_stream(s, 0);

    if (!st)

        goto fail;

    rm_read_audio_stream_info(s, st, 1);

    return 0;

 fail:

    return -1;

}


static void alloc_aio_bitmap(BlkMigDevState *bmds)

{

    BlockDriverState *bs = bmds->bs;

    int64_t bitmap_size;

    bitmap_size = bdrv_nb_sectors(bs) + BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;

    bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;

    bmds->aio_bitmap = g_malloc0(bitmap_size);

}


static uint8_t *xen_map_cache_unlocked(hwaddr phys_addr, hwaddr size,

                                       uint8_t lock, bool dma)

{

    MapCacheEntry *entry, *pentry = NULL;

    hwaddr address_index;

    hwaddr address_offset;

    hwaddr cache_size = size;

    hwaddr test_bit_size;

    bool translated G_GNUC_UNUSED = false;

    bool dummy = false;

tryagain:

    address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;

    address_offset = phys_addr & (MCACHE_BUCKET_SIZE - 1);

    trace_xen_map_cache(phys_addr);

    /* test_bit_size is always a multiple of XC_PAGE_SIZE */

    if (size) {

        test_bit_size = size + (phys_addr & (XC_PAGE_SIZE - 1));

        if (test_bit_size % XC_PAGE_SIZE) {

            test_bit_size += XC_PAGE_SIZE - (test_bit_size % XC_PAGE_SIZE);

        }

    } else {

        test_bit_size = XC_PAGE_SIZE;

    }

    if (mapcache->last_entry != NULL &&

        mapcache->last_entry->paddr_index == address_index &&

        !lock && !size &&

        test_bits(address_offset >> XC_PAGE_SHIFT,

                  test_bit_size >> XC_PAGE_SHIFT,

                  mapcache->last_entry->valid_mapping)) {

        trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);

        return mapcache->last_entry->vaddr_base + address_offset;

    }

    /* size is always a multiple of MCACHE_BUCKET_SIZE */

    if (size) {

        cache_size = size + address_offset;

        if (cache_size % MCACHE_BUCKET_SIZE) {

            cache_size += MCACHE_BUCKET_SIZE - (cache_size % MCACHE_BUCKET_SIZE);

        }

    } else {

        cache_size = MCACHE_BUCKET_SIZE;

    }

    entry = &mapcache->entry[address_index % mapcache->nr_buckets];

    while (entry && entry->lock && entry->vaddr_base &&

            (entry->paddr_index != address_index || entry->size != cache_size ||

             !test_bits(address_offset >> XC_PAGE_SHIFT,

                 test_bit_size >> XC_PAGE_SHIFT,

                 entry->valid_mapping))) {

        pentry = entry;

        entry = entry->next;

    }

    if (!entry) {

        entry = g_malloc0(sizeof (MapCacheEntry));

        pentry->next = entry;

        xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);

    } else if (!entry->lock) {

        if (!entry->vaddr_base || entry->paddr_index != address_index ||

                entry->size != cache_size ||

                !test_bits(address_offset >> XC_PAGE_SHIFT,

                    test_bit_size >> XC_PAGE_SHIFT,

                    entry->valid_mapping)) {

            xen_remap_bucket(entry, NULL, cache_size, address_index, dummy);

        }

    }

    if(!test_bits(address_offset >> XC_PAGE_SHIFT,

                test_bit_size >> XC_PAGE_SHIFT,

                entry->valid_mapping)) {

        mapcache->last_entry = NULL;

#ifdef XEN_COMPAT_PHYSMAP

        if (!translated && mapcache->phys_offset_to_gaddr) {

            phys_addr = mapcache->phys_offset_to_gaddr(phys_addr, size, mapcache->opaque);

            translated = true;

            goto tryagain;

        }

#endif

        if (!dummy && runstate_check(RUN_STATE_INMIGRATE)) {

            dummy = true;

            goto tryagain;

        }

        trace_xen_map_cache_return(NULL);

        return NULL;

    }

    mapcache->last_entry = entry;

    if (lock) {

        MapCacheRev *reventry = g_malloc0(sizeof(MapCacheRev));

        entry->lock++;

        reventry->dma = dma;

        reventry->vaddr_req = mapcache->last_entry->vaddr_base + address_offset;

        reventry->paddr_index = mapcache->last_entry->paddr_index;

        reventry->size = entry->size;

        QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);

    }

    trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset);

    return mapcache->last_entry->vaddr_base + address_offset;

}


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

{

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

    TCGv tmp;

    TCGv tmp2;

    TCGv tmp3;

    TCGv addr;

    TCGv_i64 tmp64;

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

    s->pc += 4;

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

    if (IS_M(env))

        goto illegal_op;

    cond = insn >> 28;

    if (cond == 0xf){

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

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

         * for miscellaneous unconditional instructions.

         */

        ARCH(5);

        /* Unconditional instructions.  */

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

            /* NEON Data processing.  */

            if (!arm_feature(env, ARM_FEATURE_NEON))

                goto illegal_op;

            if (disas_neon_data_insn(env, s, insn))

                goto illegal_op;

        }

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

            /* NEON load/store.  */

            if (!arm_feature(env, ARM_FEATURE_NEON))

                goto illegal_op;

            if (disas_neon_ls_insn(env, s, insn))

                goto illegal_op;

        }

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

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

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

                /* PLDW; v7MP */

                if (!arm_feature(env, ARM_FEATURE_V7MP)) {

                    goto illegal_op;

                }

            }

            /* Otherwise PLD; v5TE+ */

            ARCH(5TE);

        }

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

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

            ARCH(7);

            return; /* PLI; V7 */

        }

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

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

            if (!arm_feature(env, ARM_FEATURE_V7MP)) {

                goto illegal_op;

            }

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

        }

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

            ARCH(6);

            /* setend */

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

                /* Dynamic endianness switching not implemented. */

                goto illegal_op;

            }

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

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

            case 1: /* clrex */

                ARCH(6K);

                gen_clrex(s);

            case 4: /* dsb */

            case 5: /* dmb */

            case 6: /* isb */

                ARCH(7);

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

            default:

                goto illegal_op;

            }

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

            /* srs */

            if (IS_USER(s)) {

                goto illegal_op;

            }

            ARCH(6);

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

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

            /* rfe */

            int32_t offset;

            if (IS_USER(s))

                goto illegal_op;

            ARCH(6);

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

            addr = load_reg(s, rn);

            i = (insn >> 23) & 3;

            switch (i) {

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

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

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

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

            default: abort();

            }

            if (offset)

                tcg_gen_addi_i32(addr, addr, offset);

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

            tmp = gen_ld32(addr, 0);

            tcg_gen_addi_i32(addr, addr, 4);

            tmp2 = gen_ld32(addr, 0);

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

                /* Base writeback.  */

                switch (i) {

                case 0: offset = -8; break;

                case 1: offset = 4; break;

                case 2: offset = -4; break;

                case 3: offset = 0; break;

                default: abort();

                }

                if (offset)

                    tcg_gen_addi_i32(addr, addr, offset);

                store_reg(s, rn, addr);

            } else {

                tcg_temp_free_i32(addr);

            }

            gen_rfe(s, tmp, tmp2);

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

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

            int32_t offset;

            val = (uint32_t)s->pc;

            tmp = tcg_temp_new_i32();

            tcg_gen_movi_i32(tmp, val);

            store_reg(s, 14, tmp);

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

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

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

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

            /* pipeline offset */

            val += 4;

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

            gen_bx_im(s, val);

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

            if (arm_feature(env, ARM_FEATURE_IWMMXT)) {

                /* iWMMXt register transfer.  */

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

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

            }

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

            /* Coprocessor double register transfer.  */

            ARCH(5TE);

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

            /* Additional coprocessor register transfer.  */

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

            uint32_t mask;

            uint32_t val;

            /* cps (privileged) */

            if (IS_USER(s))

            mask = val = 0;

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

                if (insn & (1 << 8))

                    mask |= CPSR_A;

                if (insn & (1 << 7))

                    mask |= CPSR_I;

                if (insn & (1 << 6))

                    mask |= CPSR_F;

                if (insn & (1 << 18))

                    val |= mask;

            }

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

                mask |= CPSR_M;

                val |= (insn & 0x1f);

            }

            if (mask) {

                gen_set_psr_im(s, mask, 0, val);

            }

        }

        goto illegal_op;

    }

    if (cond != 0xe) {

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

           next instruction */

        s->condlabel = gen_new_label();

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

        s->condjmp = 1;

    }

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

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

            ARCH(6T2);

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

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

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

                /* MOVW */

                tmp = tcg_temp_new_i32();

                tcg_gen_movi_i32(tmp, val);

            } else {

                /* MOVT */

                tmp = load_reg(s, rd);

                tcg_gen_ext16u_i32(tmp, tmp);

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

            }

            store_reg(s, rd, tmp);

        } else {

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

                goto illegal_op;

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

                gen_nop_hint(s, insn & 0xff);

            } else {

                /* CPSR = immediate */

                val = insn & 0xff;

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

                if (shift)

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

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

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

                    goto illegal_op;

            }

        }

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

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

        /* miscellaneous instructions */

        op1 = (insn >> 21) & 3;

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

        rm = insn & 0xf;

        switch (sh) {

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

            if (op1 & 1) {

                /* PSR = reg */

                tmp = load_reg(s, rm);

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

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

                    goto illegal_op;

            } else {

                /* reg = PSR */

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

                if (op1 & 2) {

                    if (IS_USER(s))

                        goto illegal_op;

                    tmp = load_cpu_field(spsr);

                } else {

                    tmp = tcg_temp_new_i32();

                    gen_helper_cpsr_read(tmp, cpu_env);

                }

                store_reg(s, rd, tmp);

            }

            break;

        case 0x1:

            if (op1 == 1) {

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

                ARCH(4T);

                tmp = load_reg(s, rm);

                gen_bx(s, tmp);

            } else if (op1 == 3) {

                /* clz */

                ARCH(5);

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

                tmp = load_reg(s, rm);

                gen_helper_clz(tmp, tmp);

                store_reg(s, rd, tmp);

            } else {

                goto illegal_op;

            }

            break;

        case 0x2:

            if (op1 == 1) {

                ARCH(5J); /* bxj */

                /* Trivial implementation equivalent to bx.  */

                tmp = load_reg(s, rm);

                gen_bx(s, tmp);

            } else {

                goto illegal_op;

            }

            break;

        case 0x3:

            if (op1 != 1)

              goto illegal_op;

            ARCH(5);

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

            tmp = load_reg(s, rm);

            tmp2 = tcg_temp_new_i32();

            tcg_gen_movi_i32(tmp2, s->pc);

            store_reg(s, 14, tmp2);

            gen_bx(s, tmp);

            break;

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

            ARCH(5TE);

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

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

            tmp = load_reg(s, rm);

            tmp2 = load_reg(s, rn);

            if (op1 & 2)

                gen_helper_double_saturate(tmp2, cpu_env, tmp2);

            if (op1 & 1)

                gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2);

            else

                gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);

            tcg_temp_free_i32(tmp2);

            store_reg(s, rd, tmp);

            break;

        case 7:

            /* SMC instruction (op1 == 3)

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

               will trap */

            if (op1 != 1) {

                goto illegal_op;

            }

            /* bkpt */

            ARCH(5);

            gen_exception_insn(s, 4, EXCP_BKPT);

            break;

        case 0x8: /* signed multiply */

        case 0xa:

        case 0xc:

        case 0xe:

            ARCH(5TE);

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

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

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

            if (op1 == 1) {

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

                tmp = load_reg(s, rm);

                tmp2 = load_reg(s, rs);

                if (sh & 4)

                    tcg_gen_sari_i32(tmp2, tmp2, 16);

                else

                    gen_sxth(tmp2);

                tmp64 = gen_muls_i64_i32(tmp, tmp2);

                tcg_gen_shri_i64(tmp64, tmp64, 16);

                tmp = tcg_temp_new_i32();

                tcg_gen_trunc_i64_i32(tmp, tmp64);

                tcg_temp_free_i64(tmp64);

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

                    tmp2 = load_reg(s, rn);

                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                }

                store_reg(s, rd, tmp);

            } else {

                /* 16 * 16 */

                tmp = load_reg(s, rm);

                tmp2 = load_reg(s, rs);

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

                tcg_temp_free_i32(tmp2);

                if (op1 == 2) {

                    tmp64 = tcg_temp_new_i64();

                    tcg_gen_ext_i32_i64(tmp64, tmp);

                    tcg_temp_free_i32(tmp);

                    gen_addq(s, tmp64, rn, rd);

                    gen_storeq_reg(s, rn, rd, tmp64);

                    tcg_temp_free_i64(tmp64);

                } else {

                    if (op1 == 0) {

                        tmp2 = load_reg(s, rn);

                        gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                    }

                    store_reg(s, rd, tmp);

                }

            }

            break;

        default:

            goto illegal_op;

        }

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

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

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

        int set_cc, logic_cc, shiftop;

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

        set_cc = (insn >> 20) & 1;

        logic_cc = table_logic_cc[op1] & set_cc;

        /* data processing instruction */

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

            /* immediate operand */

            val = insn & 0xff;

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

            if (shift) {

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

            }

            tmp2 = tcg_temp_new_i32();

            tcg_gen_movi_i32(tmp2, val);

            if (logic_cc && shift) {

                gen_set_CF_bit31(tmp2);

            }

        } else {

            /* register */

            rm = (insn) & 0xf;

            tmp2 = load_reg(s, rm);

            shiftop = (insn >> 5) & 3;

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

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

                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);

            } else {

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

                tmp = load_reg(s, rs);

                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);

            }

        }

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

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

            tmp = load_reg(s, rn);

        } else {

            TCGV_UNUSED(tmp);

        }

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

        switch(op1) {

        case 0x00:

            tcg_gen_and_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x01:

            tcg_gen_xor_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x02:

            if (set_cc && rd == 15) {

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

                if (IS_USER(s)) {

                    goto illegal_op;

                }

                gen_sub_CC(tmp, tmp, tmp2);

                gen_exception_return(s, tmp);

            } else {

                if (set_cc) {

                    gen_sub_CC(tmp, tmp, tmp2);

                } else {

                    tcg_gen_sub_i32(tmp, tmp, tmp2);

                }

                store_reg_bx(env, s, rd, tmp);

            }

            break;

        case 0x03:

            if (set_cc) {

                gen_sub_CC(tmp, tmp2, tmp);

            } else {

                tcg_gen_sub_i32(tmp, tmp2, tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x04:

            if (set_cc) {

                gen_add_CC(tmp, tmp, tmp2);

            } else {

                tcg_gen_add_i32(tmp, tmp, tmp2);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x05:

            if (set_cc) {

                gen_adc_CC(tmp, tmp, tmp2);

            } else {

                gen_add_carry(tmp, tmp, tmp2);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x06:

            if (set_cc) {

                gen_sbc_CC(tmp, tmp, tmp2);

            } else {

                gen_sub_carry(tmp, tmp, tmp2);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x07:

            if (set_cc) {

                gen_sbc_CC(tmp, tmp2, tmp);

            } else {

                gen_sub_carry(tmp, tmp2, tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x08:

            if (set_cc) {

                tcg_gen_and_i32(tmp, tmp, tmp2);

                gen_logic_CC(tmp);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x09:

            if (set_cc) {

                tcg_gen_xor_i32(tmp, tmp, tmp2);

                gen_logic_CC(tmp);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x0a:

            if (set_cc) {

                gen_sub_CC(tmp, tmp, tmp2);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x0b:

            if (set_cc) {

                gen_add_CC(tmp, tmp, tmp2);

            }

            tcg_temp_free_i32(tmp);

            break;

        case 0x0c:

            tcg_gen_or_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        case 0x0d:

            if (logic_cc && rd == 15) {

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

                if (IS_USER(s)) {

                    goto illegal_op;

                }

                gen_exception_return(s, tmp2);

            } else {

                if (logic_cc) {

                    gen_logic_CC(tmp2);

                }

                store_reg_bx(env, s, rd, tmp2);

            }

            break;

        case 0x0e:

            tcg_gen_andc_i32(tmp, tmp, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp);

            }

            store_reg_bx(env, s, rd, tmp);

            break;

        default:

        case 0x0f:

            tcg_gen_not_i32(tmp2, tmp2);

            if (logic_cc) {

                gen_logic_CC(tmp2);

            }

            store_reg_bx(env, s, rd, tmp2);

            break;

        }

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

            tcg_temp_free_i32(tmp2);

        }

    } else {

        /* other instructions */

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

        switch(op1) {

        case 0x0:

        case 0x1:

            /* multiplies, extra load/stores */

            sh = (insn >> 5) & 3;

            if (sh == 0) {

                if (op1 == 0x0) {

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

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

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

                    rm = (insn) & 0xf;

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

                    switch (op1) {

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

                        /* 32 bit mul */

                        tmp = load_reg(s, rs);

                        tmp2 = load_reg(s, rm);

                        tcg_gen_mul_i32(tmp, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

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

                            /* Subtract (mls) */

                            ARCH(6T2);

                            tmp2 = load_reg(s, rn);

                            tcg_gen_sub_i32(tmp, tmp2, tmp);

                            tcg_temp_free_i32(tmp2);

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

                            /* Add */

                            tmp2 = load_reg(s, rn);

                            tcg_gen_add_i32(tmp, tmp, tmp2);

                            tcg_temp_free_i32(tmp2);

                        }

                        if (insn & (1 << 20))

                            gen_logic_CC(tmp);

                        store_reg(s, rd, tmp);

                        break;

                    case 4:

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

                        ARCH(6);

                        tmp = load_reg(s, rs);

                        tmp2 = load_reg(s, rm);

                        tmp64 = gen_mulu_i64_i32(tmp, tmp2);

                        gen_addq_lo(s, tmp64, rn);

                        gen_addq_lo(s, tmp64, rd);

                        gen_storeq_reg(s, rn, rd, tmp64);

                        tcg_temp_free_i64(tmp64);

                        break;

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

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

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

                        tmp = load_reg(s, rs);

                        tmp2 = load_reg(s, rm);

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

                            tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);

                        } else {

                            tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);

                        }

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

                            TCGv al = load_reg(s, rn);

                            TCGv ah = load_reg(s, rd);

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

                            tcg_temp_free(al);

                            tcg_temp_free(ah);

                        }

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

                            gen_logicq_cc(tmp, tmp2);

                        }

                        store_reg(s, rn, tmp);

                        store_reg(s, rd, tmp2);

                        break;

                    default:

                        goto illegal_op;

                    }

                } else {

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

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

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

                        /* load/store exclusive */

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

                        if (op1)

                            ARCH(6K);

                        else

                            ARCH(6);

                        addr = tcg_temp_local_new_i32();

                        load_reg_var(s, addr, rn);

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

                            switch (op1) {

                            case 0: /* ldrex */

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

                                break;

                            case 1: /* ldrexd */

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

                                break;

                            case 2: /* ldrexb */

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

                                break;

                            case 3: /* ldrexh */

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

                                break;

                            default:

                                abort();

                            }

                        } else {

                            rm = insn & 0xf;

                            switch (op1) {

                            case 0:  /*  strex */

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

                                break;

                            case 1: /*  strexd */

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

                                break;

                            case 2: /*  strexb */

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

                                break;

                            case 3: /* strexh */

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

                                break;

                            default:

                                abort();

                            }

                        }

                        tcg_temp_free(addr);

                    } else {

                        /* SWP instruction */

                        rm = (insn) & 0xf;

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

                           we never have multiple CPUs running in parallel,

                           so it is good enough.  */

                        addr = load_reg(s, rn);

                        tmp = load_reg(s, rm);

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

                            tmp2 = gen_ld8u(addr, IS_USER(s));

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

                        } else {

                            tmp2 = gen_ld32(addr, IS_USER(s));

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

                        }

                        tcg_temp_free_i32(addr);

                        store_reg(s, rd, tmp2);

                    }

                }

            } else {

                int address_offset;

                int load;

                /* Misc load/store */

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

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

                addr = load_reg(s, rn);

                if (insn & (1 << 24))

                    gen_add_datah_offset(s, insn, 0, addr);

                address_offset = 0;

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

                    /* load */

                    switch(sh) {

                    case 1:

                        tmp = gen_ld16u(addr, IS_USER(s));

                        break;

                    case 2:

                        tmp = gen_ld8s(addr, IS_USER(s));

                        break;

                    default:

                    case 3:

                        tmp = gen_ld16s(addr, IS_USER(s));

                        break;

                    }

                    load = 1;

                } else if (sh & 2) {

                    ARCH(5TE);

                    /* doubleword */

                    if (sh & 1) {

                        /* store */

                        tmp = load_reg(s, rd);

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

                        tcg_gen_addi_i32(addr, addr, 4);

                        tmp = load_reg(s, rd + 1);

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

                        load = 0;

                    } else {

                        /* load */

                        tmp = gen_ld32(addr, IS_USER(s));

                        store_reg(s, rd, tmp);

                        tcg_gen_addi_i32(addr, addr, 4);

                        tmp = gen_ld32(addr, IS_USER(s));

                        rd++;

                        load = 1;

                    }

                    address_offset = -4;

                } else {

                    /* store */

                    tmp = load_reg(s, rd);

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

                    load = 0;

                }

                /* Perform base writeback before the loaded value to

                   ensure correct behavior with overlapping index registers.

                   ldrd with base writeback is is undefined if the

                   destination and index registers overlap.  */

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

                    gen_add_datah_offset(s, insn, address_offset, addr);

                    store_reg(s, rn, addr);

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

                    if (address_offset)

                        tcg_gen_addi_i32(addr, addr, address_offset);

                    store_reg(s, rn, addr);

                } else {

                    tcg_temp_free_i32(addr);

                }

                if (load) {

                    /* Complete the load.  */

                    store_reg(s, rd, tmp);

                }

            }

            break;

        case 0x4:

        case 0x5:

            goto do_ldst;

        case 0x6:

        case 0x7:

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

                ARCH(6);

                /* Armv6 Media instructions.  */

                rm = insn & 0xf;

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

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

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

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

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

                    op1 = (insn >> 20) & 7;

                    tmp = load_reg(s, rn);

                    tmp2 = load_reg(s, rm);

                    sh = (insn >> 5) & 7;

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

                        goto illegal_op;

                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);

                    tcg_temp_free_i32(tmp2);

                    store_reg(s, rd, tmp);

                    break;

                case 1:

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

                        /* Halfword pack.  */

                        tmp = load_reg(s, rn);

                        tmp2 = load_reg(s, rm);

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

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

                            /* pkhtb */

                            if (shift == 0)

                                shift = 31;

                            tcg_gen_sari_i32(tmp2, tmp2, shift);

                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);

                            tcg_gen_ext16u_i32(tmp2, tmp2);

                        } else {

                            /* pkhbt */

                            if (shift)

                                tcg_gen_shli_i32(tmp2, tmp2, shift);

                            tcg_gen_ext16u_i32(tmp, tmp);

                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);

                        }

                        tcg_gen_or_i32(tmp, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

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

                        /* [us]sat */

                        tmp = load_reg(s, rm);

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

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

                            if (shift == 0)

                                shift = 31;

                            tcg_gen_sari_i32(tmp, tmp, shift);

                        } else {

                            tcg_gen_shli_i32(tmp, tmp, shift);

                        }

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

                        tmp2 = tcg_const_i32(sh);

                        if (insn & (1 << 22))

                          gen_helper_usat(tmp, cpu_env, tmp, tmp2);

                        else

                          gen_helper_ssat(tmp, cpu_env, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

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

                        /* [us]sat16 */

                        tmp = load_reg(s, rm);

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

                        tmp2 = tcg_const_i32(sh);

                        if (insn & (1 << 22))

                          gen_helper_usat16(tmp, cpu_env, tmp, tmp2);

                        else

                          gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

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

                        /* Select bytes.  */

                        tmp = load_reg(s, rn);

                        tmp2 = load_reg(s, rm);

                        tmp3 = tcg_temp_new_i32();

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

                        gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);

                        tcg_temp_free_i32(tmp3);

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rd, tmp);

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

                        tmp = load_reg(s, rm);

                        shift = (insn >> 10) & 3;

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

                           rotate, a shift is sufficient.  */

                        if (shift != 0)

                            tcg_gen_rotri_i32(tmp, tmp, shift * 8);

                        op1 = (insn >> 20) & 7;

                        switch (op1) {

                        case 0: gen_sxtb16(tmp);  break;

                        case 2: gen_sxtb(tmp);    break;

                        case 3: gen_sxth(tmp);    break;

                        case 4: gen_uxtb16(tmp);  break;

                        case 6: gen_uxtb(tmp);    break;

                        case 7: gen_uxth(tmp);    break;

                        default: goto illegal_op;

                        }

                        if (rn != 15) {

                            tmp2 = load_reg(s, rn);

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

                                gen_add16(tmp, tmp2);

                            } else {

                                tcg_gen_add_i32(tmp, tmp, tmp2);

                                tcg_temp_free_i32(tmp2);

                            }

                        }

                        store_reg(s, rd, tmp);

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

                        /* rev */

                        tmp = load_reg(s, rm);

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

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

                                gen_revsh(tmp);

                            } else {

                                ARCH(6T2);

                                gen_helper_rbit(tmp, tmp);

                            }

                        } else {

                            if (insn & (1 << 7))

                                gen_rev16(tmp);

                            else

                                tcg_gen_bswap32_i32(tmp, tmp);

                        }

                        store_reg(s, rd, tmp);

                    } else {

                        goto illegal_op;

                    }

                    break;

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

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

                    case 5:

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

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

                            goto illegal_op;

                        }

                        /* Signed multiply most significant [accumulate].

                           (SMMUL, SMMLA, SMMLS) */

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

                        tmp64 = gen_muls_i64_i32(tmp, tmp2);

                        if (rd != 15) {

                            tmp = load_reg(s, rd);

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

                                tmp64 = gen_subq_msw(tmp64, tmp);

                            } else {

                                tmp64 = gen_addq_msw(tmp64, tmp);

                            }

                        }

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

                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);

                        }

                        tcg_gen_shri_i64(tmp64, tmp64, 32);

                        tmp = tcg_temp_new_i32();

                        tcg_gen_trunc_i64_i32(tmp, tmp64);

                        tcg_temp_free_i64(tmp64);

                        store_reg(s, rn, tmp);

                        break;

                    case 0:

                    case 4:

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

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

                            goto illegal_op;

                        }

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

                        if (insn & (1 << 5))

                            gen_swap_half(tmp2);

                        gen_smul_dual(tmp, tmp2);

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

                            /* This subtraction cannot overflow. */

                            tcg_gen_sub_i32(tmp, tmp, tmp2);

                        } else {

                            /* This addition cannot overflow 32 bits;

                             * however it may overflow considered as a signed

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

                             */

                            gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                        }

                        tcg_temp_free_i32(tmp2);

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

                            /* smlald, smlsld */

                            tmp64 = tcg_temp_new_i64();

                            tcg_gen_ext_i32_i64(tmp64, tmp);

                            tcg_temp_free_i32(tmp);

                            gen_addq(s, tmp64, rd, rn);

                            gen_storeq_reg(s, rd, rn, tmp64);

                            tcg_temp_free_i64(tmp64);

                        } else {

                            /* smuad, smusd, smlad, smlsd */

                            if (rd != 15)

                              {

                                tmp2 = load_reg(s, rd);

                                gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);

                                tcg_temp_free_i32(tmp2);

                              }

                            store_reg(s, rn, tmp);

                        }

                        break;

                    case 1:

                    case 3:

                        /* SDIV, UDIV */

                        if (!arm_feature(env, ARM_FEATURE_ARM_DIV)) {

                            goto illegal_op;

                        }

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

                            goto illegal_op;

                        }

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

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

                            gen_helper_udiv(tmp, tmp, tmp2);

                        } else {

                            gen_helper_sdiv(tmp, tmp, tmp2);

                        }

                        tcg_temp_free_i32(tmp2);

                        store_reg(s, rn, tmp);

                        break;

                    default:

                        goto illegal_op;

                    }

                    break;

                case 3:

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

                    switch (op1) {

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

                        ARCH(6);

                        tmp = load_reg(s, rm);

                        tmp2 = load_reg(s, rs);

                        gen_helper_usad8(tmp, tmp, tmp2);

                        tcg_temp_free_i32(tmp2);

                        if (rd != 15) {

                            tmp2 = load_reg(s, rd);

                            tcg_gen_add_i32(tmp, tmp, tmp2);

                            tcg_temp_free_i32(tmp2);

                        }

                        store_reg(s, rn, tmp);

                        break;

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

                        /* Bitfield insert/clear.  */

                        ARCH(6T2);

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

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

                        i = i + 1 - shift;

                        if (rm == 15) {

                            tmp = tcg_temp_new_i32();

                            tcg_gen_movi_i32(tmp, 0);

                        } else {

                            tmp = load_reg(s, rm);

                        }

                        if (i != 32) {

                            tmp2 = load_reg(s, rd);

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

                            tcg_temp_free_i32(tmp2);

                        }

                        store_reg(s, rd, tmp);

                        break;

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

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

                        ARCH(6T2);

                        tmp = load_reg(s, rm);

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

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

                        if (shift + i > 32)

                            goto illegal_op;

                        if (i < 32) {

                            if (op1 & 0x20) {

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

                            } else {

                                gen_sbfx(tmp, shift, i);

                            }

                        }

                        store_reg(s, rd, tmp);

                        break;

                    default:

                        goto illegal_op;

                    }

                    break;

                }

                break;

            }

        do_ldst:

            /* Check for undefined extension instructions

             * per the ARM Bible IE:

             * xxxx 0111 1111 xxxx  xxxx xxxx 1111 xxxx

             */

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

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

            {

                goto illegal_op;

            }

            /* load/store byte/word */

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

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

            tmp2 = load_reg(s, rn);

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

            if (insn & (1 << 24))

                gen_add_data_offset(s, insn, tmp2);

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

                /* load */

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

                    tmp = gen_ld8u(tmp2, i);

                } else {

                    tmp = gen_ld32(tmp2, i);

                }

            } else {

                /* store */

                tmp = load_reg(s, rd);

                if (insn & (1 << 22))

                    gen_st8(tmp, tmp2, i);

                else

                    gen_st32(tmp, tmp2, i);

            }

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

                gen_add_data_offset(s, insn, tmp2);

                store_reg(s, rn, tmp2);

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

                store_reg(s, rn, tmp2);

            } else {

                tcg_temp_free_i32(tmp2);

            }

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

                /* Complete the load.  */

                store_reg_from_load(env, s, rd, tmp);

            }

            break;

        case 0x08:

        case 0x09:

            {

                int j, n, user, loaded_base;

                TCGv loaded_var;

                /* load/store multiple words */

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

                user = 0;

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

                    if (IS_USER(s))

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

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

                        user = 1;

                }

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

                addr = load_reg(s, rn);

                /* compute total size */

                loaded_base = 0;

                TCGV_UNUSED(loaded_var);

                n = 0;

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

                    if (insn & (1 << i))

                        n++;

                }

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

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

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

                        /* pre increment */

                        tcg_gen_addi_i32(addr, addr, 4);

                    } else {

                        /* post increment */

                    }

                } else {

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

                        /* pre decrement */

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

                    } else {

                        /* post decrement */

                        if (n != 1)

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

                    }

                }

                j = 0;

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

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

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

                            /* load */

                            tmp = gen_ld32(addr, IS_USER(s));

                            if (user) {

                                tmp2 = tcg_const_i32(i);

                                gen_helper_set_user_reg(cpu_env, tmp2, tmp);

                                tcg_temp_free_i32(tmp2);

                                tcg_temp_free_i32(tmp);

                            } else if (i == rn) {

                                loaded_var = tmp;

                                loaded_base = 1;

                            } else {

                                store_reg_from_load(env, s, i, tmp);

                            }

                        } else {

                            /* store */

                            if (i == 15) {

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

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

                                tmp = tcg_temp_new_i32();

                                tcg_gen_movi_i32(tmp, val);

                            } else if (user) {

                                tmp = tcg_temp_new_i32();

                                tmp2 = tcg_const_i32(i);

                                gen_helper_get_user_reg(tmp, cpu_env, tmp2);

                                tcg_temp_free_i32(tmp2);

                            } else {

                                tmp = load_reg(s, i);

                            }

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

                        }

                        j++;

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

                        if (j != n)

                            tcg_gen_addi_i32(addr, addr, 4);

                    }

                }

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

                    /* write back */

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

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

                            /* pre increment */

                        } else {

                            /* post increment */

                            tcg_gen_addi_i32(addr, addr, 4);

                        }

                    } else {

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

                            /* pre decrement */

                            if (n != 1)

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

                        } else {

                            /* post decrement */

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

                        }

                    }

                    store_reg(s, rn, addr);

                } else {

                    tcg_temp_free_i32(addr);

                }

                if (loaded_base) {

                    store_reg(s, rn, loaded_var);

                }

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

                    /* Restore CPSR from SPSR.  */

                    tmp = load_cpu_field(spsr);

                    gen_set_cpsr(tmp, 0xffffffff);

                    tcg_temp_free_i32(tmp);

                    s->is_jmp = DISAS_UPDATE;

                }

            }

            break;

        case 0xa:

        case 0xb:

            {

                int32_t offset;

                /* branch (and link) */

                val = (int32_t)s->pc;

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

                    tmp = tcg_temp_new_i32();

                    tcg_gen_movi_i32(tmp, val);

                    store_reg(s, 14, tmp);

                }

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

                val += (offset << 2) + 4;

                gen_jmp(s, val);

            }

            break;

        case 0xc:

        case 0xd:

        case 0xe:

            /* Coprocessor.  */

            if (disas_coproc_insn(env, s, insn))

                goto illegal_op;

            break;

        case 0xf:

            /* swi */

            gen_set_pc_im(s->pc);

            s->is_jmp = DISAS_SWI;

            break;

        default:

        illegal_op:

            gen_exception_insn(s, 4, EXCP_UDEF);

            break;

        }

    }

}


static const uint8_t *pcx_rle_decode(const uint8_t *src, uint8_t *dst,

                            unsigned int bytes_per_scanline, int compressed) {

    unsigned int i = 0;

    unsigned char run, value;

    if (compressed) {

        while (i<bytes_per_scanline) {

            run = 1;

            value = *src++;

            if (value >= 0xc0) {

                run = value & 0x3f;

                value = *src++;

            }

            while (i<bytes_per_scanline && run--)

                dst[i++] = value;

        }

    } else {

        memcpy(dst, src, bytes_per_scanline);

        src += bytes_per_scanline;

    }

    return src;

}


static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)

{

    uint64_t reqid = request_id++;

    int ret = bdrv_co_flush(bs->file->bs);

    block_request_create(reqid, bs, qemu_coroutine_self());

    qemu_coroutine_yield();

    return ret;

}


USBDevice *usb_net_init(NICInfo *nd)

{

    USBNetState *s;

    s = qemu_mallocz(sizeof(USBNetState));

    s->dev.speed = USB_SPEED_FULL;

    s->dev.handle_packet = usb_generic_handle_packet;

    s->dev.handle_reset = usb_net_handle_reset;

    s->dev.handle_control = usb_net_handle_control;

    s->dev.handle_data = usb_net_handle_data;

    s->dev.handle_destroy = usb_net_handle_destroy;

    s->rndis = 1;

    s->rndis_state = RNDIS_UNINITIALIZED;

    s->medium = 0;	/* NDIS_MEDIUM_802_3 */

    s->speed = 1000000; /* 100MBps, in 100Bps units */

    s->media_state = 0;	/* NDIS_MEDIA_STATE_CONNECTED */;

    s->filter = 0;

    s->vendorid = 0x1234;

    memcpy(s->mac, nd->macaddr, 6);

    TAILQ_INIT(&s->rndis_resp);

    pstrcpy(s->dev.devname, sizeof(s->dev.devname),

                    "QEMU USB Network Interface");

    s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,

                    usbnet_receive, usbnet_can_receive, s);

    qemu_format_nic_info_str(s->vc, s->mac);

    snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),

                    "%02x%02x%02x%02x%02x%02x",

                    0x40, s->mac[1], s->mac[2],

                    s->mac[3], s->mac[4], s->mac[5]);

    fprintf(stderr, "usbnet: initialized mac %02x:%02x:%02x:%02x:%02x:%02x\n",

                    s->mac[0], s->mac[1], s->mac[2],

                    s->mac[3], s->mac[4], s->mac[5]);

    return (USBDevice *) s;

}