long disas_insn(DisasContext *s, uint8_t *pc_start)

{

    int b, prefixes, aflag, dflag;

    int shift, ot;

    int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;

    unsigned int next_eip;

    s->pc = pc_start;

    prefixes = 0;

    aflag = s->code32;

    dflag = s->code32;

    s->override = -1;

 next_byte:

    b = ldub(s->pc);

    s->pc++;

    /* check prefixes */

    switch (b) {

    case 0xf3:

        prefixes |= PREFIX_REPZ;

        goto next_byte;

    case 0xf2:

        prefixes |= PREFIX_REPNZ;

        goto next_byte;

    case 0xf0:

        prefixes |= PREFIX_LOCK;

        goto next_byte;

    case 0x2e:

        s->override = R_CS;

        goto next_byte;

    case 0x36:

        s->override = R_SS;

        goto next_byte;

    case 0x3e:

        s->override = R_DS;

        goto next_byte;

    case 0x26:

        s->override = R_ES;

        goto next_byte;

    case 0x64:

        s->override = R_FS;

        goto next_byte;

    case 0x65:

        s->override = R_GS;

        goto next_byte;

    case 0x66:

        prefixes |= PREFIX_DATA;

        goto next_byte;

    case 0x67:

        prefixes |= PREFIX_ADR;

        goto next_byte;

    case 0x9b:

        prefixes |= PREFIX_FWAIT;

        goto next_byte;

    }

    if (prefixes & PREFIX_DATA)

        dflag ^= 1;

    if (prefixes & PREFIX_ADR)

        aflag ^= 1;

    s->prefix = prefixes;

    s->aflag = aflag;

    s->dflag = dflag;

    /* lock generation */

    if (prefixes & PREFIX_LOCK)

        gen_op_lock();

    /* now check op code */

 reswitch:

    switch(b) {

    case 0x0f:

        /**************************/

        /* extended op code */

        b = ldub(s->pc++) | 0x100;

        goto reswitch;

        /**************************/

        /* arith & logic */

    case 0x00 ... 0x05:

    case 0x08 ... 0x0d:

    case 0x10 ... 0x15:

    case 0x18 ... 0x1d:

    case 0x20 ... 0x25:

    case 0x28 ... 0x2d:

    case 0x30 ... 0x35:

    case 0x38 ... 0x3d:

        {

            int op, f, val;

            op = (b >> 3) & 7;

            f = (b >> 1) & 3;

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            switch(f) {

            case 0: /* OP Ev, Gv */

                modrm = ldub(s->pc++);

                reg = ((modrm >> 3) & 7) + OR_EAX;

                mod = (modrm >> 6) & 3;

                rm = modrm & 7;

                if (mod != 3) {

                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

                    gen_op_ld_T0_A0[ot]();

                    opreg = OR_TMP0;

                } else {

                    opreg = OR_EAX + rm;

                }

                gen_op(s, op, ot, opreg, reg);

                if (mod != 3 && op != 7) {

                    gen_op_st_T0_A0[ot]();

                }

                break;

            case 1: /* OP Gv, Ev */

                modrm = ldub(s->pc++);

                mod = (modrm >> 6) & 3;

                reg = ((modrm >> 3) & 7) + OR_EAX;

                rm = modrm & 7;

                if (mod != 3) {

                    gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

                    gen_op_ld_T1_A0[ot]();

                    opreg = OR_TMP1;

                } else {

                    opreg = OR_EAX + rm;

                }

                gen_op(s, op, ot, reg, opreg);

                break;

            case 2: /* OP A, Iv */

                val = insn_get(s, ot);

                gen_opi(s, op, ot, OR_EAX, val);

                break;

            }

        }

        break;

    case 0x80: /* GRP1 */

    case 0x81:

    case 0x83:

        {

            int val;

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            modrm = ldub(s->pc++);

            mod = (modrm >> 6) & 3;

            rm = modrm & 7;

            op = (modrm >> 3) & 7;

            if (mod != 3) {

                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

                gen_op_ld_T0_A0[ot]();

                opreg = OR_TMP0;

            } else {

                opreg = rm + OR_EAX;

            }

            switch(b) {

            default:

            case 0x80:

            case 0x81:

                val = insn_get(s, ot);

                break;

            case 0x83:

                val = (int8_t)insn_get(s, OT_BYTE);

                break;

            }

            gen_opi(s, op, ot, opreg, val);

            if (op != 7 && mod != 3) {

                gen_op_st_T0_A0[ot]();

            }

        }

        break;

        /**************************/

        /* inc, dec, and other misc arith */

    case 0x40 ... 0x47: /* inc Gv */

        ot = dflag ? OT_LONG : OT_WORD;

        gen_inc(s, ot, OR_EAX + (b & 7), 1);

        break;

    case 0x48 ... 0x4f: /* dec Gv */

        ot = dflag ? OT_LONG : OT_WORD;

        gen_inc(s, ot, OR_EAX + (b & 7), -1);

        break;

    case 0xf6: /* GRP3 */

    case 0xf7:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        mod = (modrm >> 6) & 3;

        rm = modrm & 7;

        op = (modrm >> 3) & 7;

        if (mod != 3) {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            gen_op_ld_T0_A0[ot]();

        } else {

            gen_op_mov_TN_reg[ot][0][rm]();

        }

        switch(op) {

        case 0: /* test */

            val = insn_get(s, ot);

            gen_op_movl_T1_im(val);

            gen_op_testl_T0_T1_cc();

            s->cc_op = CC_OP_LOGICB + ot;

            break;

        case 2: /* not */

            gen_op_notl_T0();

            if (mod != 3) {

                gen_op_st_T0_A0[ot]();

            } else {

                gen_op_mov_reg_T0[ot][rm]();

            }

            break;

        case 3: /* neg */

            gen_op_negl_T0_cc();

            if (mod != 3) {

                gen_op_st_T0_A0[ot]();

            } else {

                gen_op_mov_reg_T0[ot][rm]();

            }

            s->cc_op = CC_OP_SUBB + ot;

            break;

        case 4: /* mul */

            switch(ot) {

            case OT_BYTE:

                gen_op_mulb_AL_T0();

                break;

            case OT_WORD:

                gen_op_mulw_AX_T0();

                break;

            default:

            case OT_LONG:

                gen_op_mull_EAX_T0();

                break;

            }

            s->cc_op = CC_OP_MUL;

            break;

        case 5: /* imul */

            switch(ot) {

            case OT_BYTE:

                gen_op_imulb_AL_T0();

                break;

            case OT_WORD:

                gen_op_imulw_AX_T0();

                break;

            default:

            case OT_LONG:

                gen_op_imull_EAX_T0();

                break;

            }

            s->cc_op = CC_OP_MUL;

            break;

        case 6: /* div */

            switch(ot) {

            case OT_BYTE:

                gen_op_divb_AL_T0();

                break;

            case OT_WORD:

                gen_op_divw_AX_T0();

                break;

            default:

            case OT_LONG:

                gen_op_divl_EAX_T0();

                break;

            }

            break;

        case 7: /* idiv */

            switch(ot) {

            case OT_BYTE:

                gen_op_idivb_AL_T0();

                break;

            case OT_WORD:

                gen_op_idivw_AX_T0();

                break;

            default:

            case OT_LONG:

                gen_op_idivl_EAX_T0();

                break;

            }

            break;

        default:

            goto illegal_op;

        }

        break;

    case 0xfe: /* GRP4 */

    case 0xff: /* GRP5 */

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        mod = (modrm >> 6) & 3;

        rm = modrm & 7;

        op = (modrm >> 3) & 7;

        if (op >= 2 && b == 0xfe) {

            goto illegal_op;

        }

        if (mod != 3) {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            if (op != 3 && op != 5)

                gen_op_ld_T0_A0[ot]();

        } else {

            gen_op_mov_TN_reg[ot][0][rm]();

        }

        switch(op) {

        case 0: /* inc Ev */

            gen_inc(s, ot, OR_TMP0, 1);

            if (mod != 3)

                gen_op_st_T0_A0[ot]();

            else

                gen_op_mov_reg_T0[ot][rm]();

            break;

        case 1: /* dec Ev */

            gen_inc(s, ot, OR_TMP0, -1);

            if (mod != 3)

                gen_op_st_T0_A0[ot]();

            else

                gen_op_mov_reg_T0[ot][rm]();

            break;

        case 2: /* call Ev */

            /* XXX: optimize if memory (no and is necessary) */

            if (s->dflag == 0)

                gen_op_andl_T0_ffff();

            gen_op_jmp_T0();

            next_eip = s->pc - s->cs_base;

            gen_op_movl_T0_im(next_eip);

            gen_push_T0(s);

            s->is_jmp = 1;

            break;

        case 3: /* lcall Ev */

            /* push return segment + offset */

            gen_op_movl_T0_seg(R_CS);

            gen_push_T0(s);

            next_eip = s->pc - s->cs_base;

            gen_op_movl_T0_im(next_eip);

            gen_push_T0(s);

            gen_op_ld_T1_A0[ot]();

            gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));

            gen_op_lduw_T0_A0();

            gen_movl_seg_T0(s, R_CS);

            gen_op_movl_T0_T1();

            gen_op_jmp_T0();

            s->is_jmp = 1;

            break;

        case 4: /* jmp Ev */

            if (s->dflag == 0)

                gen_op_andl_T0_ffff();

            gen_op_jmp_T0();

            s->is_jmp = 1;

            break;

        case 5: /* ljmp Ev */

            gen_op_ld_T1_A0[ot]();

            gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));

            gen_op_lduw_T0_A0();

            gen_movl_seg_T0(s, R_CS);

            gen_op_movl_T0_T1();

            gen_op_jmp_T0();

            s->is_jmp = 1;

            break;

        case 6: /* push Ev */

            gen_push_T0(s);

            break;

        default:

            goto illegal_op;

        }

        break;

    case 0x84: /* test Ev, Gv */

    case 0x85:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        mod = (modrm >> 6) & 3;

        rm = modrm & 7;

        reg = (modrm >> 3) & 7;

        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);

        gen_op_mov_TN_reg[ot][1][reg + OR_EAX]();

        gen_op_testl_T0_T1_cc();

        s->cc_op = CC_OP_LOGICB + ot;

        break;

    case 0xa8: /* test eAX, Iv */

    case 0xa9:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        val = insn_get(s, ot);

        gen_op_mov_TN_reg[ot][0][OR_EAX]();

        gen_op_movl_T1_im(val);

        gen_op_testl_T0_T1_cc();

        s->cc_op = CC_OP_LOGICB + ot;

        break;

    case 0x98: /* CWDE/CBW */

        if (dflag)

            gen_op_movswl_EAX_AX();

        else

            gen_op_movsbw_AX_AL();

        break;

    case 0x99: /* CDQ/CWD */

        if (dflag)

            gen_op_movslq_EDX_EAX();

        else

            gen_op_movswl_DX_AX();

        break;

    case 0x1af: /* imul Gv, Ev */

    case 0x69: /* imul Gv, Ev, I */

    case 0x6b:

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = ((modrm >> 3) & 7) + OR_EAX;

        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);

        if (b == 0x69) {

            val = insn_get(s, ot);

            gen_op_movl_T1_im(val);

        } else if (b == 0x6b) {

            val = insn_get(s, OT_BYTE);

            gen_op_movl_T1_im(val);

        } else {

            gen_op_mov_TN_reg[ot][1][reg]();

        }

        if (ot == OT_LONG) {

            gen_op_imull_T0_T1();

        } else {

            gen_op_imulw_T0_T1();

        }

        gen_op_mov_reg_T0[ot][reg]();

        s->cc_op = CC_OP_MUL;

        break;

    case 0x1c0:

    case 0x1c1: /* xadd Ev, Gv */

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        if (mod == 3) {

            rm = modrm & 7;

            gen_op_mov_TN_reg[ot][0][reg]();

            gen_op_mov_TN_reg[ot][1][rm]();

            gen_op_addl_T0_T1_cc();

            gen_op_mov_reg_T0[ot][rm]();

            gen_op_mov_reg_T1[ot][reg]();

        } else {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            gen_op_mov_TN_reg[ot][0][reg]();

            gen_op_ld_T1_A0[ot]();

            gen_op_addl_T0_T1_cc();

            gen_op_st_T0_A0[ot]();

            gen_op_mov_reg_T1[ot][reg]();

        }

        s->cc_op = CC_OP_ADDB + ot;

        break;

    case 0x1b0:

    case 0x1b1: /* cmpxchg Ev, Gv */

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        gen_op_mov_TN_reg[ot][1][reg]();

        if (mod == 3) {

            rm = modrm & 7;

            gen_op_mov_TN_reg[ot][0][rm]();

            gen_op_cmpxchg_T0_T1_EAX_cc[ot]();

            gen_op_mov_reg_T0[ot][rm]();

        } else {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            gen_op_ld_T0_A0[ot]();

            gen_op_cmpxchg_T0_T1_EAX_cc[ot]();

            gen_op_st_T0_A0[ot]();

        }

        s->cc_op = CC_OP_SUBB + ot;

        break;

    case 0x1c7: /* cmpxchg8b */

        modrm = ldub(s->pc++);

        mod = (modrm >> 6) & 3;

        if (mod == 3)

            goto illegal_op;

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

        gen_op_cmpxchg8b();

        s->cc_op = CC_OP_EFLAGS;

        break;

        /**************************/

        /* push/pop */

    case 0x50 ... 0x57: /* push */

        gen_op_mov_TN_reg[OT_LONG][0][b & 7]();

        gen_push_T0(s);

        break;

    case 0x58 ... 0x5f: /* pop */

        ot = dflag ? OT_LONG : OT_WORD;

        gen_pop_T0(s);

        gen_op_mov_reg_T0[ot][b & 7]();

        gen_pop_update(s);

        break;

    case 0x60: /* pusha */

        gen_pusha(s);

        break;

    case 0x61: /* popa */

        gen_popa(s);

        break;

    case 0x68: /* push Iv */

    case 0x6a:

        ot = dflag ? OT_LONG : OT_WORD;

        if (b == 0x68)

            val = insn_get(s, ot);

        else

            val = (int8_t)insn_get(s, OT_BYTE);

        gen_op_movl_T0_im(val);

        gen_push_T0(s);

        break;

    case 0x8f: /* pop Ev */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        gen_pop_T0(s);

        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);

        gen_pop_update(s);

        break;

    case 0xc8: /* enter */

        {

            int level;

            val = lduw(s->pc);

            s->pc += 2;

            level = ldub(s->pc++);

            gen_enter(s, val, level);

        }

        break;

    case 0xc9: /* leave */

        /* XXX: exception not precise (ESP is update before potential exception) */

        if (s->ss32) {

            gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();

            gen_op_mov_reg_T0[OT_LONG][R_ESP]();

        } else {

            gen_op_mov_TN_reg[OT_WORD][0][R_EBP]();

            gen_op_mov_reg_T0[OT_WORD][R_ESP]();

        }

        gen_pop_T0(s);

        ot = dflag ? OT_LONG : OT_WORD;

        gen_op_mov_reg_T0[ot][R_EBP]();

        gen_pop_update(s);

        break;

    case 0x06: /* push es */

    case 0x0e: /* push cs */

    case 0x16: /* push ss */

    case 0x1e: /* push ds */

        gen_op_movl_T0_seg(b >> 3);

        gen_push_T0(s);

        break;

    case 0x1a0: /* push fs */

    case 0x1a8: /* push gs */

        gen_op_movl_T0_seg((b >> 3) & 7);

        gen_push_T0(s);

        break;

    case 0x07: /* pop es */

    case 0x17: /* pop ss */

    case 0x1f: /* pop ds */

        gen_pop_T0(s);

        gen_movl_seg_T0(s, b >> 3);

        gen_pop_update(s);

        break;

    case 0x1a1: /* pop fs */

    case 0x1a9: /* pop gs */

        gen_pop_T0(s);

        gen_movl_seg_T0(s, (b >> 3) & 7);

        gen_pop_update(s);

        break;

        /**************************/

        /* mov */

    case 0x88:

    case 0x89: /* mov Gv, Ev */

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        /* generate a generic store */

        gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1);

        break;

    case 0xc6:

    case 0xc7: /* mov Ev, Iv */

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        mod = (modrm >> 6) & 3;

        if (mod != 3)

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

        val = insn_get(s, ot);

        gen_op_movl_T0_im(val);

        if (mod != 3)

            gen_op_st_T0_A0[ot]();

        else

            gen_op_mov_reg_T0[ot][modrm & 7]();

        break;

    case 0x8a:

    case 0x8b: /* mov Ev, Gv */

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);

        gen_op_mov_reg_T0[ot][reg]();

        break;

    case 0x8e: /* mov seg, Gv */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);

        if (reg >= 6 || reg == R_CS)

            goto illegal_op;

        gen_movl_seg_T0(s, reg);

        break;

    case 0x8c: /* mov Gv, seg */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        if (reg >= 6)

            goto illegal_op;

        gen_op_movl_T0_seg(reg);

        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);

        break;

    case 0x1b6: /* movzbS Gv, Eb */

    case 0x1b7: /* movzwS Gv, Eb */

    case 0x1be: /* movsbS Gv, Eb */

    case 0x1bf: /* movswS Gv, Eb */

        {

            int d_ot;

            /* d_ot is the size of destination */

            d_ot = dflag + OT_WORD;

            /* ot is the size of source */

            ot = (b & 1) + OT_BYTE;

            modrm = ldub(s->pc++);

            reg = ((modrm >> 3) & 7) + OR_EAX;

            mod = (modrm >> 6) & 3;

            rm = modrm & 7;

            if (mod == 3) {

                gen_op_mov_TN_reg[ot][0][rm]();

                switch(ot | (b & 8)) {

                case OT_BYTE:

                    gen_op_movzbl_T0_T0();

                    break;

                case OT_BYTE | 8:

                    gen_op_movsbl_T0_T0();

                    break;

                case OT_WORD:

                    gen_op_movzwl_T0_T0();

                    break;

                default:

                case OT_WORD | 8:

                    gen_op_movswl_T0_T0();

                    break;

                }

                gen_op_mov_reg_T0[d_ot][reg]();

            } else {

                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

                if (b & 8) {

                    gen_op_lds_T0_A0[ot]();

                } else {

                    gen_op_ldu_T0_A0[ot]();

                }

                gen_op_mov_reg_T0[d_ot][reg]();

            }

        }

        break;

    case 0x8d: /* lea */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        /* we must ensure that no segment is added */

        s->override = -1;

        val = s->addseg;

        s->addseg = 0;

        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

        s->addseg = val;

        gen_op_mov_reg_A0[ot - OT_WORD][reg]();

        break;

    case 0xa0: /* mov EAX, Ov */

    case 0xa1:

    case 0xa2: /* mov Ov, EAX */

    case 0xa3:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        if (s->aflag)

            offset_addr = insn_get(s, OT_LONG);

        else

            offset_addr = insn_get(s, OT_WORD);

        gen_op_movl_A0_im(offset_addr);

        /* handle override */

        {

            int override, must_add_seg;

            must_add_seg = s->addseg;

            if (s->override >= 0) {

                override = s->override;

                must_add_seg = 1;

            } else {

                override = R_DS;

            }

            if (must_add_seg) {

                gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));

            }

        }

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

            gen_op_ld_T0_A0[ot]();

            gen_op_mov_reg_T0[ot][R_EAX]();

        } else {

            gen_op_mov_TN_reg[ot][0][R_EAX]();

            gen_op_st_T0_A0[ot]();

        }

        break;

    case 0xd7: /* xlat */

        gen_op_movl_A0_reg[R_EBX]();

        gen_op_addl_A0_AL();

        if (s->aflag == 0)

            gen_op_andl_A0_ffff();

        /* handle override */

        {

            int override, must_add_seg;

            must_add_seg = s->addseg;

            override = R_DS;

            if (s->override >= 0) {

                override = s->override;

                must_add_seg = 1;

            } else {

                override = R_DS;

            }

            if (must_add_seg) {

                gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));

            }

        }

        gen_op_ldub_T0_A0();

        gen_op_mov_reg_T0[OT_BYTE][R_EAX]();

        break;

    case 0xb0 ... 0xb7: /* mov R, Ib */

        val = insn_get(s, OT_BYTE);

        gen_op_movl_T0_im(val);

        gen_op_mov_reg_T0[OT_BYTE][b & 7]();

        break;

    case 0xb8 ... 0xbf: /* mov R, Iv */

        ot = dflag ? OT_LONG : OT_WORD;

        val = insn_get(s, ot);

        reg = OR_EAX + (b & 7);

        gen_op_movl_T0_im(val);

        gen_op_mov_reg_T0[ot][reg]();

        break;

    case 0x91 ... 0x97: /* xchg R, EAX */

        ot = dflag ? OT_LONG : OT_WORD;

        reg = b & 7;

        rm = R_EAX;

        goto do_xchg_reg;

    case 0x86:

    case 0x87: /* xchg Ev, Gv */

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        if (mod == 3) {

            rm = modrm & 7;

        do_xchg_reg:

            gen_op_mov_TN_reg[ot][0][reg]();

            gen_op_mov_TN_reg[ot][1][rm]();

            gen_op_mov_reg_T0[ot][rm]();

            gen_op_mov_reg_T1[ot][reg]();

        } else {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            gen_op_mov_TN_reg[ot][0][reg]();

            /* for xchg, lock is implicit */

            if (!(prefixes & PREFIX_LOCK))

                gen_op_lock();

            gen_op_ld_T1_A0[ot]();

            gen_op_st_T0_A0[ot]();

            if (!(prefixes & PREFIX_LOCK))

                gen_op_unlock();

            gen_op_mov_reg_T1[ot][reg]();

        }

        break;

    case 0xc4: /* les Gv */

        op = R_ES;

        goto do_lxx;

    case 0xc5: /* lds Gv */

        op = R_DS;

        goto do_lxx;

    case 0x1b2: /* lss Gv */

        op = R_SS;

        goto do_lxx;

    case 0x1b4: /* lfs Gv */

        op = R_FS;

        goto do_lxx;

    case 0x1b5: /* lgs Gv */

        op = R_GS;

    do_lxx:

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        if (mod == 3)

            goto illegal_op;

        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

        gen_op_ld_T1_A0[ot]();

        gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));

        /* load the segment first to handle exceptions properly */

        gen_op_lduw_T0_A0();

        gen_movl_seg_T0(s, op);

        /* then put the data */

        gen_op_mov_reg_T1[ot][reg]();

        break;

        /************************/

        /* shifts */

    case 0xc0:

    case 0xc1:

        /* shift Ev,Ib */

        shift = 2;

    grp2:

        {

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            modrm = ldub(s->pc++);

            mod = (modrm >> 6) & 3;

            rm = modrm & 7;

            op = (modrm >> 3) & 7;

            if (mod != 3) {

                gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

                gen_op_ld_T0_A0[ot]();

                opreg = OR_TMP0;

            } else {

                opreg = rm + OR_EAX;

            }

            /* simpler op */

            if (shift == 0) {

                gen_shift(s, op, ot, opreg, OR_ECX);

            } else {

                if (shift == 2) {

                    shift = ldub(s->pc++);

                }

                gen_shifti(s, op, ot, opreg, shift);

            }

            if (mod != 3) {

                gen_op_st_T0_A0[ot]();

            }

        }

        break;

    case 0xd0:

    case 0xd1:

        /* shift Ev,1 */

        shift = 1;

        goto grp2;

    case 0xd2:

    case 0xd3:

        /* shift Ev,cl */

        shift = 0;

        goto grp2;

    case 0x1a4: /* shld imm */

        op = 0;

        shift = 1;

        goto do_shiftd;

    case 0x1a5: /* shld cl */

        op = 0;

        shift = 0;

        goto do_shiftd;

    case 0x1ac: /* shrd imm */

        op = 1;

        shift = 1;

        goto do_shiftd;

    case 0x1ad: /* shrd cl */

        op = 1;

        shift = 0;

    do_shiftd:

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        mod = (modrm >> 6) & 3;

        rm = modrm & 7;

        reg = (modrm >> 3) & 7;

        if (mod != 3) {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            gen_op_ld_T0_A0[ot]();

        } else {

            gen_op_mov_TN_reg[ot][0][rm]();

        }

        gen_op_mov_TN_reg[ot][1][reg]();

        if (shift) {

            val = ldub(s->pc++);

            val &= 0x1f;

            if (val) {

                gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);

                if (op == 0 && ot != OT_WORD)

                    s->cc_op = CC_OP_SHLB + ot;

                else

                    s->cc_op = CC_OP_SARB + ot;

            }

        } else {

            if (s->cc_op != CC_OP_DYNAMIC)

                gen_op_set_cc_op(s->cc_op);

            gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();

            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */

        }

        if (mod != 3) {

            gen_op_st_T0_A0[ot]();

        } else {

            gen_op_mov_reg_T0[ot][rm]();

        }

        break;

        /************************/

        /* floats */

    case 0xd8 ... 0xdf:

        modrm = ldub(s->pc++);

        mod = (modrm >> 6) & 3;

        rm = modrm & 7;

        op = ((b & 7) << 3) | ((modrm >> 3) & 7);

        if (mod != 3) {

            /* memory op */

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            switch(op) {

            case 0x00 ... 0x07: /* fxxxs */

            case 0x10 ... 0x17: /* fixxxl */

            case 0x20 ... 0x27: /* fxxxl */

            case 0x30 ... 0x37: /* fixxx */

                {

                    int op1;

                    op1 = op & 7;

                    switch(op >> 4) {

                    case 0:

                        gen_op_flds_FT0_A0();

                        break;

                    case 1:

                        gen_op_fildl_FT0_A0();

                        break;

                    case 2:

                        gen_op_fldl_FT0_A0();

                        break;

                    case 3:

                    default:

                        gen_op_fild_FT0_A0();

                        break;

                    }

                    gen_op_fp_arith_ST0_FT0[op1]();

                    if (op1 == 3) {

                        /* fcomp needs pop */

                        gen_op_fpop();

                    }

                }

                break;

            case 0x08: /* flds */

            case 0x0a: /* fsts */

            case 0x0b: /* fstps */

            case 0x18: /* fildl */

            case 0x1a: /* fistl */

            case 0x1b: /* fistpl */

            case 0x28: /* fldl */

            case 0x2a: /* fstl */

            case 0x2b: /* fstpl */

            case 0x38: /* filds */

            case 0x3a: /* fists */

            case 0x3b: /* fistps */

                switch(op & 7) {

                case 0:

                    gen_op_fpush();

                    switch(op >> 4) {

                    case 0:

                        gen_op_flds_ST0_A0();

                        break;

                    case 1:

                        gen_op_fildl_ST0_A0();

                        break;

                    case 2:

                        gen_op_fldl_ST0_A0();

                        break;

                    case 3:

                    default:

                        gen_op_fild_ST0_A0();

                        break;

                    }

                    break;

                default:

                    switch(op >> 4) {

                    case 0:

                        gen_op_fsts_ST0_A0();

                        break;

                    case 1:

                        gen_op_fistl_ST0_A0();

                        break;

                    case 2:

                        gen_op_fstl_ST0_A0();

                        break;

                    case 3:

                    default:

                        gen_op_fist_ST0_A0();

                        break;

                    }

                    if ((op & 7) == 3)

                        gen_op_fpop();

                    break;

                }

                break;

            case 0x0d: /* fldcw mem */

                gen_op_fldcw_A0();

                break;

            case 0x0f: /* fnstcw mem */

                gen_op_fnstcw_A0();

                break;

            case 0x1d: /* fldt mem */

                gen_op_fpush();

                gen_op_fldt_ST0_A0();

                break;

            case 0x1f: /* fstpt mem */

                gen_op_fstt_ST0_A0();

                gen_op_fpop();

                break;

            case 0x2f: /* fnstsw mem */

                gen_op_fnstsw_A0();

                break;

            case 0x3c: /* fbld */

                gen_op_fpush();

                gen_op_fbld_ST0_A0();

                break;

            case 0x3e: /* fbstp */

                gen_op_fbst_ST0_A0();

                gen_op_fpop();

                break;

            case 0x3d: /* fildll */

                gen_op_fpush();

                gen_op_fildll_ST0_A0();

                break;

            case 0x3f: /* fistpll */

                gen_op_fistll_ST0_A0();

                gen_op_fpop();

                break;

            default:

                goto illegal_op;

            }

        } else {

            /* register float ops */

            opreg = rm;

            switch(op) {

            case 0x08: /* fld sti */

                gen_op_fpush();

                gen_op_fmov_ST0_STN((opreg + 1) & 7);

                break;

            case 0x09: /* fxchg sti */

                gen_op_fxchg_ST0_STN(opreg);

                break;

            case 0x0a: /* grp d9/2 */

                switch(rm) {

                case 0: /* fnop */

                    break;

                default:

                    goto illegal_op;

                }

                break;

            case 0x0c: /* grp d9/4 */

                switch(rm) {

                case 0: /* fchs */

                    gen_op_fchs_ST0();

                    break;

                case 1: /* fabs */

                    gen_op_fabs_ST0();

                    break;

                case 4: /* ftst */

                    gen_op_fldz_FT0();

                    gen_op_fcom_ST0_FT0();

                    break;

                case 5: /* fxam */

                    gen_op_fxam_ST0();

                    break;

                default:

                    goto illegal_op;

                }

                break;

            case 0x0d: /* grp d9/5 */

                {

                    switch(rm) {

                    case 0:

                        gen_op_fpush();

                        gen_op_fld1_ST0();

                        break;

                    case 1:

                        gen_op_fpush();

                        gen_op_fldl2t_ST0();

                        break;

                    case 2:

                        gen_op_fpush();

                        gen_op_fldl2e_ST0();

                        break;

                    case 3:

                        gen_op_fpush();

                        gen_op_fldpi_ST0();

                        break;

                    case 4:

                        gen_op_fpush();

                        gen_op_fldlg2_ST0();

                        break;

                    case 5:

                        gen_op_fpush();

                        gen_op_fldln2_ST0();

                        break;

                    case 6:

                        gen_op_fpush();

                        gen_op_fldz_ST0();

                        break;

                    default:

                        goto illegal_op;

                    }

                }

                break;

            case 0x0e: /* grp d9/6 */

                switch(rm) {

                case 0: /* f2xm1 */

                    gen_op_f2xm1();

                    break;

                case 1: /* fyl2x */

                    gen_op_fyl2x();

                    break;

                case 2: /* fptan */

                    gen_op_fptan();

                    break;

                case 3: /* fpatan */

                    gen_op_fpatan();

                    break;

                case 4: /* fxtract */

                    gen_op_fxtract();

                    break;

                case 5: /* fprem1 */

                    gen_op_fprem1();

                    break;

                case 6: /* fdecstp */

                    gen_op_fdecstp();

                    break;

                default:

                case 7: /* fincstp */

                    gen_op_fincstp();

                    break;

                }

                break;

            case 0x0f: /* grp d9/7 */

                switch(rm) {

                case 0: /* fprem */

                    gen_op_fprem();

                    break;

                case 1: /* fyl2xp1 */

                    gen_op_fyl2xp1();

                    break;

                case 2: /* fsqrt */

                    gen_op_fsqrt();

                    break;

                case 3: /* fsincos */

                    gen_op_fsincos();

                    break;

                case 5: /* fscale */

                    gen_op_fscale();

                    break;

                case 4: /* frndint */

                    gen_op_frndint();

                    break;

                case 6: /* fsin */

                    gen_op_fsin();

                    break;

                default:

                case 7: /* fcos */

                    gen_op_fcos();

                    break;

                }

                break;

            case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */

            case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */

            case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */

                {

                    int op1;

                    op1 = op & 7;

                    if (op >= 0x20) {

                        gen_op_fp_arith_STN_ST0[op1](opreg);

                        if (op >= 0x30)

                            gen_op_fpop();

                    } else {

                        gen_op_fmov_FT0_STN(opreg);

                        gen_op_fp_arith_ST0_FT0[op1]();

                    }

                }

                break;

            case 0x02: /* fcom */

                gen_op_fmov_FT0_STN(opreg);

                gen_op_fcom_ST0_FT0();

                break;

            case 0x03: /* fcomp */

                gen_op_fmov_FT0_STN(opreg);

                gen_op_fcom_ST0_FT0();

                gen_op_fpop();

                break;

            case 0x15: /* da/5 */

                switch(rm) {

                case 1: /* fucompp */

                    gen_op_fmov_FT0_STN(1);

                    gen_op_fucom_ST0_FT0();

                    gen_op_fpop();

                    gen_op_fpop();

                    break;

                default:

                    goto illegal_op;

                }

                break;

            case 0x1c:

                switch(rm) {

                case 2: /* fclex */

                    gen_op_fclex();

                    break;

                case 3: /* fninit */

                    gen_op_fninit();

                    break;

                default:

                    goto illegal_op;

                }

                break;

            case 0x2a: /* fst sti */

                gen_op_fmov_STN_ST0(opreg);

                break;

            case 0x2b: /* fstp sti */

                gen_op_fmov_STN_ST0(opreg);

                gen_op_fpop();

                break;

            case 0x2c: /* fucom st(i) */

                gen_op_fmov_FT0_STN(opreg);

                gen_op_fucom_ST0_FT0();

                break;

            case 0x2d: /* fucomp st(i) */

                gen_op_fmov_FT0_STN(opreg);

                gen_op_fucom_ST0_FT0();

                gen_op_fpop();

                break;

            case 0x33: /* de/3 */

                switch(rm) {

                case 1: /* fcompp */

                    gen_op_fmov_FT0_STN(1);

                    gen_op_fcom_ST0_FT0();

                    gen_op_fpop();

                    gen_op_fpop();

                    break;

                default:

                    goto illegal_op;

                }

                break;

            case 0x3c: /* df/4 */

                switch(rm) {

                case 0:

                    gen_op_fnstsw_EAX();

                    break;

                default:

                    goto illegal_op;

                }

                break;

            default:

                goto illegal_op;

            }

        }

        break;

        /************************/

        /* string ops */

    case 0xa4: /* movsS */

    case 0xa5:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        if (prefixes & PREFIX_REPZ) {

            gen_string_ds(s, ot, gen_op_movs + 9);

        } else {

            gen_string_ds(s, ot, gen_op_movs);

        }

        break;

    case 0xaa: /* stosS */

    case 0xab:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        if (prefixes & PREFIX_REPZ) {

            gen_string_es(s, ot, gen_op_stos + 9);

        } else {

            gen_string_es(s, ot, gen_op_stos);

        }

        break;

    case 0xac: /* lodsS */

    case 0xad:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        if (prefixes & PREFIX_REPZ) {

            gen_string_ds(s, ot, gen_op_lods + 9);

        } else {

            gen_string_ds(s, ot, gen_op_lods);

        }

        break;

    case 0xae: /* scasS */

    case 0xaf:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

                ot = dflag ? OT_LONG : OT_WORD;

        if (prefixes & PREFIX_REPNZ) {

            if (s->cc_op != CC_OP_DYNAMIC)

                gen_op_set_cc_op(s->cc_op);

            gen_string_es(s, ot, gen_op_scas + 9 * 2);

            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */

        } else if (prefixes & PREFIX_REPZ) {

            if (s->cc_op != CC_OP_DYNAMIC)

                gen_op_set_cc_op(s->cc_op);

            gen_string_es(s, ot, gen_op_scas + 9);

            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */

        } else {

            gen_string_es(s, ot, gen_op_scas);

            s->cc_op = CC_OP_SUBB + ot;

        }

        break;

    case 0xa6: /* cmpsS */

    case 0xa7:

        if ((b & 1) == 0)

            ot = OT_BYTE;

        else

            ot = dflag ? OT_LONG : OT_WORD;

        if (prefixes & PREFIX_REPNZ) {

            if (s->cc_op != CC_OP_DYNAMIC)

                gen_op_set_cc_op(s->cc_op);

            gen_string_ds(s, ot, gen_op_cmps + 9 * 2);

            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */

        } else if (prefixes & PREFIX_REPZ) {

            if (s->cc_op != CC_OP_DYNAMIC)

                gen_op_set_cc_op(s->cc_op);

            gen_string_ds(s, ot, gen_op_cmps + 9);

            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */

        } else {

            gen_string_ds(s, ot, gen_op_cmps);

            s->cc_op = CC_OP_SUBB + ot;

        }

        break;

    case 0x6c: /* insS */

    case 0x6d:

        if (s->cpl > s->iopl || s->vm86) {

            /* NOTE: even for (E)CX = 0 the exception is raised */

            gen_op_gpf(pc_start - s->cs_base);

        } else {

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            if (prefixes & PREFIX_REPZ) {

                gen_string_es(s, ot, gen_op_ins + 9);

            } else {

                gen_string_es(s, ot, gen_op_ins);

            }

        }

        break;

    case 0x6e: /* outsS */

    case 0x6f:

        if (s->cpl > s->iopl || s->vm86) {

            /* NOTE: even for (E)CX = 0 the exception is raised */

            gen_op_gpf(pc_start - s->cs_base);

        } else {

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            if (prefixes & PREFIX_REPZ) {

                gen_string_ds(s, ot, gen_op_outs + 9);

            } else {

                gen_string_ds(s, ot, gen_op_outs);

            }

        }

        break;

        /************************/

        /* port I/O */

    case 0xe4:

    case 0xe5:

        if (s->cpl > s->iopl || s->vm86) {

            gen_op_gpf(pc_start - s->cs_base);

        } else {

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            val = ldub(s->pc++);

            gen_op_movl_T0_im(val);

            gen_op_in[ot]();

            gen_op_mov_reg_T1[ot][R_EAX]();

        }

        break;

    case 0xe6:

    case 0xe7:

        if (s->cpl > s->iopl || s->vm86) {

            gen_op_gpf(pc_start - s->cs_base);

        } else {

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            val = ldub(s->pc++);

            gen_op_movl_T0_im(val);

            gen_op_mov_TN_reg[ot][1][R_EAX]();

            gen_op_out[ot]();

        }

        break;

    case 0xec:

    case 0xed:

        if (s->cpl > s->iopl || s->vm86) {

            gen_op_gpf(pc_start - s->cs_base);

        } else {

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();

            gen_op_in[ot]();

            gen_op_mov_reg_T1[ot][R_EAX]();

        }

        break;

    case 0xee:

    case 0xef:

        if (s->cpl > s->iopl || s->vm86) {

            gen_op_gpf(pc_start - s->cs_base);

        } else {

            if ((b & 1) == 0)

                ot = OT_BYTE;

            else

                ot = dflag ? OT_LONG : OT_WORD;

            gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();

            gen_op_mov_TN_reg[ot][1][R_EAX]();

            gen_op_out[ot]();

        }

        break;

        /************************/

        /* control */

    case 0xc2: /* ret im */

        val = ldsw(s->pc);

        s->pc += 2;

        gen_pop_T0(s);

        if (s->ss32)

            gen_op_addl_ESP_im(val + (2 << s->dflag));

        else

            gen_op_addw_ESP_im(val + (2 << s->dflag));

        if (s->dflag == 0)

            gen_op_andl_T0_ffff();

        gen_op_jmp_T0();

        s->is_jmp = 1;

        break;

    case 0xc3: /* ret */

        gen_pop_T0(s);

        gen_pop_update(s);

        if (s->dflag == 0)

            gen_op_andl_T0_ffff();

        gen_op_jmp_T0();

        s->is_jmp = 1;

        break;

    case 0xca: /* lret im */

        /* XXX: not restartable */

        val = ldsw(s->pc);

        s->pc += 2;

        /* pop offset */

        gen_pop_T0(s);

        if (s->dflag == 0)

            gen_op_andl_T0_ffff();

        gen_op_jmp_T0();

        gen_pop_update(s);

        /* pop selector */

        gen_pop_T0(s);

        gen_movl_seg_T0(s, R_CS);

        gen_pop_update(s);

        /* add stack offset */

        if (s->ss32)

            gen_op_addl_ESP_im(val + (2 << s->dflag));

        else

            gen_op_addw_ESP_im(val + (2 << s->dflag));

        s->is_jmp = 1;

        break;

    case 0xcb: /* lret */

        /* XXX: not restartable */

        /* pop offset */

        gen_pop_T0(s);

        if (s->dflag == 0)

            gen_op_andl_T0_ffff();

        gen_op_jmp_T0();

        gen_pop_update(s);

        /* pop selector */

        gen_pop_T0(s);

        gen_movl_seg_T0(s, R_CS);

        gen_pop_update(s);

        s->is_jmp = 1;

        break;

    case 0xcf: /* iret */

        /* XXX: not restartable */

        /* pop offset */

        gen_pop_T0(s);

        if (s->dflag == 0)

            gen_op_andl_T0_ffff();

        gen_op_jmp_T0();

        gen_pop_update(s);

        /* pop selector */

        gen_pop_T0(s);

        gen_movl_seg_T0(s, R_CS);

        gen_pop_update(s);

        /* pop eflags */

        gen_pop_T0(s);

        if (s->dflag) {

            if (s->vm86)

                gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);

            else

                gen_op_movl_eflags_T0();

        } else {

            if (s->vm86)

                gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);

            else

                gen_op_movw_eflags_T0();

        }

        gen_pop_update(s);

        s->cc_op = CC_OP_EFLAGS;

        s->is_jmp = 1;

        break;

    case 0xe8: /* call im */

        {

            unsigned int next_eip;

            ot = dflag ? OT_LONG : OT_WORD;

            val = insn_get(s, ot);

            next_eip = s->pc - s->cs_base;

            val += next_eip;

            if (s->dflag == 0)

                val &= 0xffff;

            gen_op_movl_T0_im(next_eip);

            gen_push_T0(s);

            gen_op_jmp_im(val);

            s->is_jmp = 1;

        }

        break;

    case 0x9a: /* lcall im */

        {

            unsigned int selector, offset;

            ot = dflag ? OT_LONG : OT_WORD;

            offset = insn_get(s, ot);

            selector = insn_get(s, OT_WORD);

            /* push return segment + offset */

            gen_op_movl_T0_seg(R_CS);

            gen_push_T0(s);

            next_eip = s->pc - s->cs_base;

            gen_op_movl_T0_im(next_eip);

            gen_push_T0(s);

            /* change cs and pc */

            gen_op_movl_T0_im(selector);

            gen_movl_seg_T0(s, R_CS);

            gen_op_jmp_im((unsigned long)offset);

            s->is_jmp = 1;

        }

        break;

    case 0xe9: /* jmp */

        ot = dflag ? OT_LONG : OT_WORD;

        val = insn_get(s, ot);

        val += s->pc - s->cs_base;

        if (s->dflag == 0)

            val = val & 0xffff;

        gen_op_jmp_im(val);

        s->is_jmp = 1;

        break;

    case 0xea: /* ljmp im */

        {

            unsigned int selector, offset;

            ot = dflag ? OT_LONG : OT_WORD;

            offset = insn_get(s, ot);

            selector = insn_get(s, OT_WORD);

            /* change cs and pc */

            gen_op_movl_T0_im(selector);

            gen_movl_seg_T0(s, R_CS);

            gen_op_jmp_im((unsigned long)offset);

            s->is_jmp = 1;

        }

        break;

    case 0xeb: /* jmp Jb */

        val = (int8_t)insn_get(s, OT_BYTE);

        val += s->pc - s->cs_base;

        if (s->dflag == 0)

            val = val & 0xffff;

        gen_op_jmp_im(val);

        s->is_jmp = 1;

        break;

    case 0x70 ... 0x7f: /* jcc Jb */

        val = (int8_t)insn_get(s, OT_BYTE);

        goto do_jcc;

    case 0x180 ... 0x18f: /* jcc Jv */

        if (dflag) {

            val = insn_get(s, OT_LONG);

        } else {

            val = (int16_t)insn_get(s, OT_WORD);

        }

    do_jcc:

        next_eip = s->pc - s->cs_base;

        val += next_eip;

        if (s->dflag == 0)

            val &= 0xffff;

        gen_jcc(s, b, val, next_eip);

        s->is_jmp = 1;

        break;

    case 0x190 ... 0x19f: /* setcc Gv */

        modrm = ldub(s->pc++);

        gen_setcc(s, b);

        gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);

        break;

    case 0x140 ... 0x14f: /* cmov Gv, Ev */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        gen_setcc(s, b);

        if (mod != 3) {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            gen_op_ld_T1_A0[ot]();

        } else {

            rm = modrm & 7;

            gen_op_mov_TN_reg[ot][1][rm]();

        }

        gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg]();

        break;

        /************************/

        /* flags */

    case 0x9c: /* pushf */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        if (s->vm86)

            gen_op_movl_T0_eflags_vm();

        else

            gen_op_movl_T0_eflags();

        gen_push_T0(s);

        break;

    case 0x9d: /* popf */

        gen_pop_T0(s);

        if (s->dflag) {

            if (s->vm86)

                gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);

            else

                gen_op_movl_eflags_T0();

        } else {

            if (s->vm86)

                gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);

            else

                gen_op_movw_eflags_T0();

        }

        gen_pop_update(s);

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0x9e: /* sahf */

        gen_op_mov_TN_reg[OT_BYTE][0][R_AH]();

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_movb_eflags_T0();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0x9f: /* lahf */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_movl_T0_eflags();

        gen_op_mov_reg_T0[OT_BYTE][R_AH]();

        break;

    case 0xf5: /* cmc */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_cmc();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0xf8: /* clc */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_clc();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0xf9: /* stc */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_stc();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0xfc: /* cld */

        gen_op_cld();

        break;

    case 0xfd: /* std */

        gen_op_std();

        break;

        /************************/

        /* bit operations */

    case 0x1ba: /* bt/bts/btr/btc Gv, im */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        op = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        rm = modrm & 7;

        if (mod != 3) {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            gen_op_ld_T0_A0[ot]();

        } else {

            gen_op_mov_TN_reg[ot][0][rm]();

        }

        /* load shift */

        val = ldub(s->pc++);

        gen_op_movl_T1_im(val);

        if (op < 4)

            goto illegal_op;

        op -= 4;

        gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();

        s->cc_op = CC_OP_SARB + ot;

        if (op != 0) {

            if (mod != 3)

                gen_op_st_T0_A0[ot]();

            else

                gen_op_mov_reg_T0[ot][rm]();

        }

        break;

    case 0x1a3: /* bt Gv, Ev */

        op = 0;

        goto do_btx;

    case 0x1ab: /* bts */

        op = 1;

        goto do_btx;

    case 0x1b3: /* btr */

        op = 2;

        goto do_btx;

    case 0x1bb: /* btc */

        op = 3;

    do_btx:

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        rm = modrm & 7;

        gen_op_mov_TN_reg[OT_LONG][1][reg]();

        if (mod != 3) {

            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

            /* specific case: we need to add a displacement */

            if (ot == OT_WORD)

                gen_op_add_bitw_A0_T1();

            else

                gen_op_add_bitl_A0_T1();

            gen_op_ld_T0_A0[ot]();

        } else {

            gen_op_mov_TN_reg[ot][0][rm]();

        }

        gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();

        s->cc_op = CC_OP_SARB + ot;

        if (op != 0) {

            if (mod != 3)

                gen_op_st_T0_A0[ot]();

            else

                gen_op_mov_reg_T0[ot][rm]();

        }

        break;

    case 0x1bc: /* bsf */

    case 0x1bd: /* bsr */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);

        gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();

        /* NOTE: we always write back the result. Intel doc says it is

           undefined if T0 == 0 */

        gen_op_mov_reg_T0[ot][reg]();

        s->cc_op = CC_OP_LOGICB + ot;

        break;

        /************************/

        /* bcd */

    case 0x27: /* daa */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_daa();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0x2f: /* das */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_das();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0x37: /* aaa */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_aaa();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0x3f: /* aas */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_aas();

        s->cc_op = CC_OP_EFLAGS;

        break;

    case 0xd4: /* aam */

        val = ldub(s->pc++);

        gen_op_aam(val);

        s->cc_op = CC_OP_LOGICB;

        break;

    case 0xd5: /* aad */

        val = ldub(s->pc++);

        gen_op_aad(val);

        s->cc_op = CC_OP_LOGICB;

        break;

        /************************/

        /* misc */

    case 0x90: /* nop */

        break;

    case 0xcc: /* int3 */

        gen_op_int3((long)pc_start);

        s->is_jmp = 1;

        break;

    case 0xcd: /* int N */

        val = ldub(s->pc++);

        gen_op_int_im(val, pc_start - s->cs_base);

        s->is_jmp = 1;

        break;

    case 0xce: /* into */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_into();

        break;

    case 0xfa: /* cli */

        if (!s->vm86) {

            if (s->cpl <= s->iopl)

                gen_op_cli();

            else

                gen_op_gpf(pc_start - s->cs_base);

        } else {

            if (s->iopl == 3)

                gen_op_cli();

            else

                gen_op_cli_vm();

        }

        break;

    case 0xfb: /* sti */

        if (!s->vm86) {

            if (s->cpl <= s->iopl)

                gen_op_sti();

            else

                gen_op_gpf(pc_start - s->cs_base);

        } else {

            if (s->iopl == 3)

                gen_op_sti();

            else

                gen_op_sti_vm(pc_start - s->cs_base);

        }

        break;

    case 0x62: /* bound */

        ot = dflag ? OT_LONG : OT_WORD;

        modrm = ldub(s->pc++);

        reg = (modrm >> 3) & 7;

        mod = (modrm >> 6) & 3;

        if (mod == 3)

            goto illegal_op;

        gen_op_mov_reg_T0[ot][reg]();

        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);

        if (ot == OT_WORD)

            gen_op_boundw();

        else

            gen_op_boundl();

        break;

    case 0x1c8 ... 0x1cf: /* bswap reg */

        reg = b & 7;

        gen_op_mov_TN_reg[OT_LONG][0][reg]();

        gen_op_bswapl_T0();

        gen_op_mov_reg_T0[OT_LONG][reg]();

        break;

    case 0xd6: /* salc */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        gen_op_salc();

        break;

    case 0xe0: /* loopnz */

    case 0xe1: /* loopz */

        if (s->cc_op != CC_OP_DYNAMIC)

            gen_op_set_cc_op(s->cc_op);

        /* FALL THRU */

    case 0xe2: /* loop */

    case 0xe3: /* jecxz */

        val = (int8_t)insn_get(s, OT_BYTE);

        next_eip = s->pc - s->cs_base;

        val += next_eip;

        if (s->dflag == 0)

            val &= 0xffff;

        gen_op_loop[s->aflag][b & 3](val, next_eip);

        s->is_jmp = 1;

        break;

    case 0x131: /* rdtsc */

        gen_op_rdtsc();

        break;

    case 0x1a2: /* cpuid */

        gen_op_cpuid();

        break;

    case 0xf4: /* hlt */

        if (s->cpl == 0) {

            /* ignored */

        } else {

            gen_op_gpf(pc_start - s->cs_base);

        }

        break;

    default:

        goto illegal_op;

    }

    /* lock generation */

    if (s->prefix & PREFIX_LOCK)

        gen_op_unlock();

    return (long)s->pc;

 illegal_op:

    /* XXX: ensure that no lock was generated */

    return -1;

}


static void xhci_process_commands(XHCIState *xhci)

{

    XHCITRB trb;

    TRBType type;

    XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};

    dma_addr_t addr;

    unsigned int i, slotid = 0;

    DPRINTF("xhci_process_commands()\n");

    if (!xhci_running(xhci)) {

        DPRINTF("xhci_process_commands() called while xHC stopped or paused\n");

        return;

    }

    xhci->crcr_low |= CRCR_CRR;

    while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) {

        event.ptr = addr;

        switch (type) {

        case CR_ENABLE_SLOT:

            for (i = 0; i < xhci->numslots; i++) {

                if (!xhci->slots[i].enabled) {

                    break;

                }

            }

            if (i >= xhci->numslots) {

                DPRINTF("xhci: no device slots available\n");

                event.ccode = CC_NO_SLOTS_ERROR;

            } else {

                slotid = i+1;

                event.ccode = xhci_enable_slot(xhci, slotid);

            }

            break;

        case CR_DISABLE_SLOT:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                event.ccode = xhci_disable_slot(xhci, slotid);

            }

            break;

        case CR_ADDRESS_DEVICE:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                event.ccode = xhci_address_slot(xhci, slotid, trb.parameter,

                                                trb.control & TRB_CR_BSR);

            }

            break;

        case CR_CONFIGURE_ENDPOINT:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter,

                                                  trb.control & TRB_CR_DC);

            }

            break;

        case CR_EVALUATE_CONTEXT:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter);

            }

            break;

        case CR_STOP_ENDPOINT:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)

                    & TRB_CR_EPID_MASK;

                event.ccode = xhci_stop_ep(xhci, slotid, epid);

            }

            break;

        case CR_RESET_ENDPOINT:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)

                    & TRB_CR_EPID_MASK;

                event.ccode = xhci_reset_ep(xhci, slotid, epid);

            }

            break;

        case CR_SET_TR_DEQUEUE:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)

                    & TRB_CR_EPID_MASK;

                unsigned int streamid = (trb.status >> 16) & 0xffff;

                event.ccode = xhci_set_ep_dequeue(xhci, slotid,

                                                  epid, streamid,

                                                  trb.parameter);

            }

            break;

        case CR_RESET_DEVICE:

            slotid = xhci_get_slot(xhci, &event, &trb);

            if (slotid) {

                event.ccode = xhci_reset_slot(xhci, slotid);

            }

            break;

        case CR_GET_PORT_BANDWIDTH:

            event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);

            break;

        case CR_VENDOR_VIA_CHALLENGE_RESPONSE:

            xhci_via_challenge(xhci, trb.parameter);

            break;

        case CR_VENDOR_NEC_FIRMWARE_REVISION:

            event.type = 48; /* NEC reply */

            event.length = 0x3025;

            break;

        case CR_VENDOR_NEC_CHALLENGE_RESPONSE:

        {

            uint32_t chi = trb.parameter >> 32;

            uint32_t clo = trb.parameter;

            uint32_t val = xhci_nec_challenge(chi, clo);

            event.length = val & 0xFFFF;

            event.epid = val >> 16;

            slotid = val >> 24;

            event.type = 48; /* NEC reply */

        }

        break;

        default:

            trace_usb_xhci_unimplemented("command", type);

            event.ccode = CC_TRB_ERROR;

            break;

        }

        event.slotid = slotid;

        xhci_event(xhci, &event, 0);

    }

}


void cpu_loop(CPUTLGState *env)

{

    CPUState *cs = CPU(tilegx_env_get_cpu(env));

    int trapnr;

    while (1) {

        cpu_exec_start(cs);

        trapnr = cpu_tilegx_exec(cs);

        cpu_exec_end(cs);

        switch (trapnr) {

        case TILEGX_EXCP_SYSCALL:

            env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR],

                                                env->regs[0], env->regs[1],

                                                env->regs[2], env->regs[3],

                                                env->regs[4], env->regs[5],

                                                env->regs[6], env->regs[7]);

            env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE])

                                                      ? - env->regs[TILEGX_R_RE]

                                                      : 0;

            break;

        case TILEGX_EXCP_OPCODE_EXCH:

            do_exch(env, true, false);

            break;

        case TILEGX_EXCP_OPCODE_EXCH4:

            do_exch(env, false, false);

            break;

        case TILEGX_EXCP_OPCODE_CMPEXCH:

            do_exch(env, true, true);

            break;

        case TILEGX_EXCP_OPCODE_CMPEXCH4:

            do_exch(env, false, true);

            break;

        case TILEGX_EXCP_OPCODE_FETCHADD:

        case TILEGX_EXCP_OPCODE_FETCHADDGEZ:

        case TILEGX_EXCP_OPCODE_FETCHAND:

        case TILEGX_EXCP_OPCODE_FETCHOR:

            do_fetch(env, trapnr, true);

            break;

        case TILEGX_EXCP_OPCODE_FETCHADD4:

        case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:

        case TILEGX_EXCP_OPCODE_FETCHAND4:

        case TILEGX_EXCP_OPCODE_FETCHOR4:

            do_fetch(env, trapnr, false);

            break;

        case TILEGX_EXCP_SIGNAL:

            do_signal(env, env->signo, env->sigcode);

            break;

        case TILEGX_EXCP_REG_IDN_ACCESS:

        case TILEGX_EXCP_REG_UDN_ACCESS:

            gen_sigill_reg(env);

            break;

        default:

            fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);

            g_assert_not_reached();

        }

        process_pending_signals(env);

    }

}


sofree(struct socket *so)

{

  Slirp *slirp = so->slirp;

  struct mbuf *ifm;

  for (ifm = (struct mbuf *) slirp->if_fastq.qh_link;

       (struct quehead *) ifm != &slirp->if_fastq;

       ifm = ifm->ifq_next) {

    if (ifm->ifq_so == so) {

      ifm->ifq_so = NULL;

  for (ifm = (struct mbuf *) slirp->if_batchq.qh_link;

       (struct quehead *) ifm != &slirp->if_batchq;

       ifm = ifm->ifq_next) {

    if (ifm->ifq_so == so) {

      ifm->ifq_so = NULL;

  if (so->so_emu==EMU_RSH && so->extra) {

	sofree(so->extra);

	so->extra=NULL;

  if (so == slirp->tcp_last_so) {

      slirp->tcp_last_so = &slirp->tcb;

  } else if (so == slirp->udp_last_so) {

      slirp->udp_last_so = &slirp->udb;

  } else if (so == slirp->icmp_last_so) {

      slirp->icmp_last_so = &slirp->icmp;

  m_free(so->so_m);

  if(so->so_next && so->so_prev)

    remque(so);  /* crashes if so is not in a queue */

  free(so);


static void close_slave(TeeSlave *tee_slave)

{

    AVFormatContext *avf;

    unsigned i;

    avf = tee_slave->avf;

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

        AVBitStreamFilterContext *bsf_next, *bsf = tee_slave->bsfs[i];

        while (bsf) {

            bsf_next = bsf->next;

            av_bitstream_filter_close(bsf);

            bsf = bsf_next;

        }

    }

    av_freep(&tee_slave->stream_map);

    av_freep(&tee_slave->bsfs);

    ff_format_io_close(avf, &avf->pb);

    avformat_free_context(avf);

    tee_slave->avf = NULL;

}


static int ac3_decode_frame(AVCodecContext * avctx, void *data,

                            int *got_frame_ptr, AVPacket *avpkt)

{

    const uint8_t *buf = avpkt->data;

    int buf_size = avpkt->size;

    AC3DecodeContext *s = avctx->priv_data;

    int blk, ch, err, ret;

    const uint8_t *channel_map;

    const float *output[AC3_MAX_CHANNELS];

    /* copy input buffer to decoder context to avoid reading past the end

       of the buffer, which can be caused by a damaged input stream. */

    if (buf_size >= 2 && AV_RB16(buf) == 0x770B) {

        // seems to be byte-swapped AC-3

        int cnt = FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE) >> 1;

        s->dsp.bswap16_buf((uint16_t *)s->input_buffer, (const uint16_t *)buf, cnt);

    } else

        memcpy(s->input_buffer, buf, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE));

    buf = s->input_buffer;

    /* initialize the GetBitContext with the start of valid AC-3 Frame */

    init_get_bits(&s->gbc, buf, buf_size * 8);

    /* parse the syncinfo */

    err = parse_frame_header(s);

    if (err) {

        switch (err) {

        case AAC_AC3_PARSE_ERROR_SYNC:

            av_log(avctx, AV_LOG_ERROR, "frame sync error\n");

            return -1;

        case AAC_AC3_PARSE_ERROR_BSID:

            av_log(avctx, AV_LOG_ERROR, "invalid bitstream id\n");

            break;

        case AAC_AC3_PARSE_ERROR_SAMPLE_RATE:

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

            break;

        case AAC_AC3_PARSE_ERROR_FRAME_SIZE:

            av_log(avctx, AV_LOG_ERROR, "invalid frame size\n");

            break;

        case AAC_AC3_PARSE_ERROR_FRAME_TYPE:

            /* skip frame if CRC is ok. otherwise use error concealment. */

            /* TODO: add support for substreams and dependent frames */

            if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT || s->substreamid) {

                av_log(avctx, AV_LOG_ERROR, "unsupported frame type : "

                       "skipping frame\n");

                *got_frame_ptr = 0;

                return s->frame_size;

            } else {

                av_log(avctx, AV_LOG_ERROR, "invalid frame type\n");

            }

            break;

        default:

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

            break;

        }

    } else {

        /* check that reported frame size fits in input buffer */

        if (s->frame_size > buf_size) {

            av_log(avctx, AV_LOG_ERROR, "incomplete frame\n");

            err = AAC_AC3_PARSE_ERROR_FRAME_SIZE;

        } else if (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL)) {

            /* check for crc mismatch */

            if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, &buf[2],

                       s->frame_size - 2)) {

                av_log(avctx, AV_LOG_ERROR, "frame CRC mismatch\n");

                err = AAC_AC3_PARSE_ERROR_CRC;

            }

        }

    }

    /* if frame is ok, set audio parameters */

    if (!err) {

        avctx->sample_rate = s->sample_rate;

        avctx->bit_rate    = s->bit_rate;

        /* channel config */

        s->out_channels = s->channels;

        s->output_mode  = s->channel_mode;

        if (s->lfe_on)

            s->output_mode |= AC3_OUTPUT_LFEON;

        if (avctx->request_channels > 0 && avctx->request_channels <= 2 &&

                avctx->request_channels < s->channels) {

            s->out_channels = avctx->request_channels;

            s->output_mode  = avctx->request_channels == 1 ? AC3_CHMODE_MONO : AC3_CHMODE_STEREO;

            s->channel_layout = avpriv_ac3_channel_layout_tab[s->output_mode];

        }

        avctx->channels       = s->out_channels;

        avctx->channel_layout = s->channel_layout;

        s->loro_center_mix_level   = gain_levels[s->  center_mix_level];

        s->loro_surround_mix_level = gain_levels[s->surround_mix_level];

        s->ltrt_center_mix_level   = LEVEL_MINUS_3DB;

        s->ltrt_surround_mix_level = LEVEL_MINUS_3DB;

        /* set downmixing coefficients if needed */

        if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) &&

                s->fbw_channels == s->out_channels)) {

            set_downmix_coeffs(s);

        }

    } else if (!s->out_channels) {

        s->out_channels = avctx->channels;

        if (s->out_channels < s->channels)

            s->output_mode  = s->out_channels == 1 ? AC3_CHMODE_MONO : AC3_CHMODE_STEREO;

    }

    if (avctx->channels != s->out_channels) {

        av_log(avctx, AV_LOG_ERROR, "channel number mismatching on damaged frame\n");

        return AVERROR_INVALIDDATA;

    }

    /* set audio service type based on bitstream mode for AC-3 */

    avctx->audio_service_type = s->bitstream_mode;

    if (s->bitstream_mode == 0x7 && s->channels > 1)

        avctx->audio_service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE;

    /* get output buffer */

    avctx->channels = s->out_channels;

    s->frame.nb_samples = s->num_blocks * 256;

    if ((ret = ff_get_buffer(avctx, &s->frame)) < 0) {

        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");

        return ret;

    }

    /* decode the audio blocks */

    channel_map = ff_ac3_dec_channel_map[s->output_mode & ~AC3_OUTPUT_LFEON][s->lfe_on];

    for (ch = 0; ch < s->channels; ch++) {

        if (ch < s->out_channels)

            s->outptr[channel_map[ch]] = (float *)s->frame.data[ch];

        else

            s->outptr[ch] = s->output[ch];

        output[ch] = s->output[ch];

    }

    for (blk = 0; blk < s->num_blocks; blk++) {

        if (!err && decode_audio_block(s, blk)) {

            av_log(avctx, AV_LOG_ERROR, "error decoding the audio block\n");

            err = 1;

        }

        if (err)

            for (ch = 0; ch < s->out_channels; ch++)

                memcpy(s->outptr[channel_map[ch]], output[ch], 1024);

        for (ch = 0; ch < s->out_channels; ch++) {

            output[ch] = s->outptr[channel_map[ch]];

            s->outptr[channel_map[ch]] += AC3_BLOCK_SIZE;

        }

    }

    s->frame.decode_error_flags = err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0;

    /* keep last block for error concealment in next frame */

    for (ch = 0; ch < s->out_channels; ch++)

        memcpy(s->output[ch], output[ch], 1024);

    *got_frame_ptr   = 1;

    *(AVFrame *)data = s->frame;

    return FFMIN(buf_size, s->frame_size);

}


static int ffserver_parse_config_global(FFServerConfig *config, const char *cmd,

                                        const char **p, int line_num)

{

    int val;

    char arg[1024];

    if (!av_strcasecmp(cmd, "Port") || !av_strcasecmp(cmd, "HTTPPort")) {

        if (!av_strcasecmp(cmd, "Port"))

            WARNING("Port option is deprecated, use HTTPPort instead\n");

        ffserver_get_arg(arg, sizeof(arg), p);

        val = atoi(arg);

        if (val < 1 || val > 65536)

            ERROR("Invalid port: %s\n", arg);

        if (val < 1024)

            WARNING("Trying to use IETF assigned system port: %d\n", val);

        config->http_addr.sin_port = htons(val);

    } else if (!av_strcasecmp(cmd, "HTTPBindAddress") || !av_strcasecmp(cmd, "BindAddress")) {

        if (!av_strcasecmp(cmd, "BindAddress"))

            WARNING("BindAddress option is deprecated, use HTTPBindAddress instead\n");

        ffserver_get_arg(arg, sizeof(arg), p);

        if (resolve_host(&config->http_addr.sin_addr, arg) != 0)

            ERROR("%s:%d: Invalid host/IP address: %s\n", arg);

    } else if (!av_strcasecmp(cmd, "NoDaemon")) {

        WARNING("NoDaemon option has no effect, you should remove it\n");

    } else if (!av_strcasecmp(cmd, "RTSPPort")) {

        ffserver_get_arg(arg, sizeof(arg), p);

        val = atoi(arg);

        if (val < 1 || val > 65536)

            ERROR("%s:%d: Invalid port: %s\n", arg);

        config->rtsp_addr.sin_port = htons(atoi(arg));

    } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {

        ffserver_get_arg(arg, sizeof(arg), p);

        if (resolve_host(&config->rtsp_addr.sin_addr, arg) != 0)

            ERROR("Invalid host/IP address: %s\n", arg);

    } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {

        ffserver_get_arg(arg, sizeof(arg), p);

        val = atoi(arg);

        if (val < 1 || val > 65536)

            ERROR("Invalid MaxHTTPConnections: %s\n", arg);

        config->nb_max_http_connections = val;

    } else if (!av_strcasecmp(cmd, "MaxClients")) {

        ffserver_get_arg(arg, sizeof(arg), p);

        val = atoi(arg);

        if (val < 1 || val > config->nb_max_http_connections)

            ERROR("Invalid MaxClients: %s\n", arg);

        else

            config->nb_max_connections = val;

    } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {

        int64_t llval;

        ffserver_get_arg(arg, sizeof(arg), p);

        llval = strtoll(arg, NULL, 10);

        if (llval < 10 || llval > 10000000)

            ERROR("Invalid MaxBandwidth: %s\n", arg);

        else

            config->max_bandwidth = llval;

    } else if (!av_strcasecmp(cmd, "CustomLog")) {

        if (!config->debug)

            ffserver_get_arg(config->logfilename, sizeof(config->logfilename), p);

    } else if (!av_strcasecmp(cmd, "LoadModule")) {

        ERROR("Loadable modules no longer supported\n");

    } else

        ERROR("Incorrect keyword: '%s'\n", cmd);

    return 0;

}


int ff_h264_fill_default_ref_list(H264Context *h)

{

    int i, len;

    if (h->slice_type_nos == AV_PICTURE_TYPE_B) {

        Picture *sorted[32];

        int cur_poc, list;

        int lens[2];

        if (FIELD_PICTURE(h))

            cur_poc = h->cur_pic_ptr->field_poc[h->picture_structure == PICT_BOTTOM_FIELD];

        else

            cur_poc = h->cur_pic_ptr->poc;

        for (list = 0; list < 2; list++) {

            len  = add_sorted(sorted,       h->short_ref, h->short_ref_count, cur_poc, 1 ^ list);

            len += add_sorted(sorted + len, h->short_ref, h->short_ref_count, cur_poc, 0 ^ list);

            assert(len <= 32);

            len  = build_def_list(h->default_ref_list[list],       sorted,      len, 0, h->picture_structure);

            len += build_def_list(h->default_ref_list[list] + len, h->long_ref, 16,  1, h->picture_structure);

            assert(len <= 32);

            if (len < h->ref_count[list])

                memset(&h->default_ref_list[list][len], 0, sizeof(Picture) * (h->ref_count[list] - len));

            lens[list] = len;

        }

        if (lens[0] == lens[1] && lens[1] > 1) {

            for (i = 0; h->default_ref_list[0][i].f.data[0] == h->default_ref_list[1][i].f.data[0] && i < lens[0]; i++);

            if (i == lens[0]) {

                Picture tmp;

                COPY_PICTURE(&tmp, &h->default_ref_list[1][0]);

                COPY_PICTURE(&h->default_ref_list[1][0], &h->default_ref_list[1][1]);

                COPY_PICTURE(&h->default_ref_list[1][1], &tmp);

            }

        }

    } else {

        len  = build_def_list(h->default_ref_list[0],       h->short_ref, h->short_ref_count, 0, h->picture_structure);

        len += build_def_list(h->default_ref_list[0] + len, h-> long_ref, 16,                 1, h->picture_structure);

        assert(len <= 32);

        if (len < h->ref_count[0])

            memset(&h->default_ref_list[0][len], 0, sizeof(Picture) * (h->ref_count[0] - len));

    }

#ifdef TRACE

    for (i = 0; i < h->ref_count[0]; i++) {

        tprintf(h->avctx, "List0: %s fn:%d 0x%p\n",

                (h->default_ref_list[0][i].long_ref ? "LT" : "ST"),

                h->default_ref_list[0][i].pic_id,

                h->default_ref_list[0][i].f.data[0]);

    }

    if (h->slice_type_nos == AV_PICTURE_TYPE_B) {

        for (i = 0; i < h->ref_count[1]; i++) {

            tprintf(h->avctx, "List1: %s fn:%d 0x%p\n",

                    (h->default_ref_list[1][i].long_ref ? "LT" : "ST"),

                    h->default_ref_list[1][i].pic_id,

                    h->default_ref_list[1][i].f.data[0]);

        }

    }

#endif

    return 0;

}


static int check_strtox_error(const char *p, char *endptr, const char **next,

                              int err)

{

    /* If no conversion was performed, prefer BSD behavior over glibc

     * behavior.

     */

    if (err == 0 && endptr == p) {

        err = EINVAL;

    }

    if (!next && *endptr) {

        return -EINVAL;

    }

    if (next) {

        *next = endptr;

    }

    return -err;

}


static void ram_decompress_close(RamDecompressState *s)

{

    inflateEnd(&s->zstream);

}


static void ahci_hba_enable(AHCIQState *ahci)

{

    /* Bits of interest in this section:

     * GHC.AE     Global Host Control / AHCI Enable

     * PxCMD.ST   Port Command: Start

     * PxCMD.SUD  "Spin Up Device"

     * PxCMD.POD  "Power On Device"

     * PxCMD.FRE  "FIS Receive Enable"

     * PxCMD.FR   "FIS Receive Running"

     * PxCMD.CR   "Command List Running"

     */

    uint32_t reg, ports_impl;

    uint16_t i;

    uint8_t num_cmd_slots;

    g_assert(ahci != NULL);

    /* Set GHC.AE to 1 */

    ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE);

    reg = ahci_rreg(ahci, AHCI_GHC);

    ASSERT_BIT_SET(reg, AHCI_GHC_AE);

    /* Cache CAP and CAP2. */

    ahci->cap = ahci_rreg(ahci, AHCI_CAP);

    ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2);

    /* Read CAP.NCS, how many command slots do we have? */

    num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1;

    g_test_message("Number of Command Slots: %u", num_cmd_slots);

    /* Determine which ports are implemented. */

    ports_impl = ahci_rreg(ahci, AHCI_PI);

    for (i = 0; ports_impl; ports_impl >>= 1, ++i) {

        if (!(ports_impl & 0x01)) {

            continue;

        }

        g_test_message("Initializing port %u", i);

        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);

        if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR |

                   AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) {

            g_test_message("port is idle");

        } else {

            g_test_message("port needs to be idled");

            ahci_px_clr(ahci, i, AHCI_PX_CMD,

                        (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE));

            /* The port has 500ms to disengage. */

            usleep(500000);

            reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);

            ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR);

            ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR);

            g_test_message("port is now idle");

            /* The spec does allow for possibly needing a PORT RESET

             * or HBA reset if we fail to idle the port. */

        }

        /* Allocate Memory for the Command List Buffer & FIS Buffer */

        /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */

        ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20);

        qmemset(ahci->port[i].clb, 0x00, 0x100);

        g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb);

        ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb);

        g_assert_cmphex(ahci->port[i].clb, ==,

                        ahci_px_rreg(ahci, i, AHCI_PX_CLB));

        /* PxFB space ... 0x100, as in 4.2.1 p 35 */

        ahci->port[i].fb = ahci_alloc(ahci, 0x100);

        qmemset(ahci->port[i].fb, 0x00, 0x100);

        g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb);

        ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb);

        g_assert_cmphex(ahci->port[i].fb, ==,

                        ahci_px_rreg(ahci, i, AHCI_PX_FB));

        /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */

        ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF);

        ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF);

        ahci_wreg(ahci, AHCI_IS, (1 << i));

        /* Verify Interrupts Cleared */

        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);

        g_assert_cmphex(reg, ==, 0);

        reg = ahci_px_rreg(ahci, i, AHCI_PX_IS);

        g_assert_cmphex(reg, ==, 0);

        reg = ahci_rreg(ahci, AHCI_IS);

        ASSERT_BIT_CLEAR(reg, (1 << i));

        /* Enable All Interrupts: */

        ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF);

        reg = ahci_px_rreg(ahci, i, AHCI_PX_IE);

        g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED));

        /* Enable the FIS Receive Engine. */

        ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE);

        reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD);

        ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR);

        /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates

         * physical presence, a device is present and may be started. However,

         * PxSERR.DIAG.X /may/ need to be cleared a priori. */

        reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR);

        if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) {

            ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X);

        }

        reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD);

        if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) {

            reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS);

            if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) {

                /* Device Found: set PxCMD.ST := 1 */

                ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST);

                ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD),

                               AHCI_PX_CMD_CR);

                g_test_message("Started Device %u", i);

            } else if ((reg & AHCI_PX_SSTS_DET)) {

                /* Device present, but in some unknown state. */

                g_assert_not_reached();

            }

        }

    }

    /* Enable GHC.IE */

    ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE);

    reg = ahci_rreg(ahci, AHCI_GHC);

    ASSERT_BIT_SET(reg, AHCI_GHC_IE);

    /* TODO: The device should now be idling and waiting for commands.

     * In the future, a small test-case to inspect the Register D2H FIS

     * and clear the initial interrupts might be good. */

}


static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length)

{

    int x, y;

    const int width  = f->avctx->width;

    const int height = f->avctx->height;

    uint16_t *src    = (uint16_t *)f->last_picture.data[0];

    uint16_t *dst    = (uint16_t *)f->current_picture.data[0];

    const int stride =             f->current_picture.linesize[0] >> 1;

    unsigned int bitstream_size, bytestream_size, wordstream_size, extra,

                 bytestream_offset, wordstream_offset;

    if (f->version > 1) {

        extra           = 20;

        if (length < extra)

            return -1;

        bitstream_size  = AV_RL32(buf + 8);

        wordstream_size = AV_RL32(buf + 12);

        bytestream_size = AV_RL32(buf + 16);

    } else {

        extra           = 0;

        bitstream_size  = AV_RL16(buf - 4);

        wordstream_size = AV_RL16(buf - 2);

        bytestream_size = FFMAX(length - bitstream_size - wordstream_size, 0);

    }

    if (bitstream_size > length ||

        bytestream_size > length - bitstream_size ||

        wordstream_size > length - bytestream_size - bitstream_size ||

        extra > length - bytestream_size - bitstream_size - wordstream_size) {

        av_log(f->avctx, AV_LOG_ERROR, "lengths %d %d %d %d\n", bitstream_size, bytestream_size, wordstream_size,

        bitstream_size+ bytestream_size+ wordstream_size - length);

        return -1;

    }

    av_fast_malloc(&f->bitstream_buffer, &f->bitstream_buffer_size,

                   bitstream_size + FF_INPUT_BUFFER_PADDING_SIZE);

    if (!f->bitstream_buffer)

        return AVERROR(ENOMEM);

    f->dsp.bswap_buf(f->bitstream_buffer, (const uint32_t*)(buf + extra),

                     bitstream_size / 4);

    memset((uint8_t*)f->bitstream_buffer + bitstream_size,

           0, FF_INPUT_BUFFER_PADDING_SIZE);

    init_get_bits(&f->gb, f->bitstream_buffer, 8 * bitstream_size);

    wordstream_offset = extra + bitstream_size;

    bytestream_offset = extra + bitstream_size + wordstream_size;

    bytestream2_init(&f->g2, buf + wordstream_offset,

                     length - wordstream_offset);

    bytestream2_init(&f->g, buf + bytestream_offset,

                     length - bytestream_offset);

    init_mv(f);

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

        for (x = 0; x < width; x += 8)

            decode_p_block(f, dst + x, src + x, 3, 3, stride);

        src += 8 * stride;

        dst += 8 * stride;

    }

    return 0;

}


void *kqemu_vmalloc(size_t size)

{

    static int phys_ram_fd = -1;

    static int phys_ram_size = 0;

    const char *tmpdir;

    char phys_ram_file[1024];

    void *ptr;

    struct statfs stfs;

    if (phys_ram_fd < 0) {

        tmpdir = getenv("QEMU_TMPDIR");

        if (!tmpdir)

            tmpdir = "/dev/shm";

        if (statfs(tmpdir, &stfs) == 0) {

            int64_t free_space;

            int ram_mb;

            extern int ram_size;

            free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;

            if ((ram_size + 8192 * 1024) >= free_space) {

                ram_mb = (ram_size / (1024 * 1024));

                fprintf(stderr,

                        "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",

                        tmpdir, ram_mb);

                if (strcmp(tmpdir, "/dev/shm") == 0) {

                    fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n"

                            "umount /dev/shm\n"

                            "mount -t tmpfs -o size=%dm none /dev/shm\n",

                            ram_mb + 16);

                } else {

                    fprintf(stderr,

                            "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"

                            "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"

                            "temporary RAM file will be opened.\n");

                }

                fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");

                exit(1);

            }

        }

        snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",

                 tmpdir);

        if (mkstemp(phys_ram_file) < 0) {

            fprintf(stderr,

                    "warning: could not create temporary file in '%s'.\n"

                    "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"

                    "Using '/tmp' as fallback.\n",

                    tmpdir);

            snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",

                     "/tmp");

            if (mkstemp(phys_ram_file) < 0) {

                fprintf(stderr, "Could not create temporary memory file '%s'\n",

                        phys_ram_file);

                exit(1);

            }

        }

        phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);

        if (phys_ram_fd < 0) {

            fprintf(stderr, "Could not open temporary memory file '%s'\n",

                    phys_ram_file);

            exit(1);

        }

        unlink(phys_ram_file);

    }

    size = (size + 4095) & ~4095;

    ftruncate(phys_ram_fd, phys_ram_size + size);

    ptr = mmap(NULL,

               size,

               PROT_WRITE | PROT_READ, MAP_SHARED,

               phys_ram_fd, phys_ram_size);

    if (ptr == MAP_FAILED) {

        fprintf(stderr, "Could not map physical memory\n");

        exit(1);

    }

    phys_ram_size += size;

    return ptr;

}


static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t off)

{

    QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;

    uint64_t val;

    val = qpci_io_readq(dev->pdev, CONFIG_BASE(dev) + off);

    if (qvirtio_is_big_endian(d)) {

        val = bswap64(val);

    }

    return val;

}


void video_decode_example(const char *outfilename, const char *filename)

{

    AVCodec *codec;

    AVCodecContext *c= NULL;

    int frame, size, got_picture, len;

    FILE *f;

    AVFrame *picture;

    uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_ptr;

    char buf[1024];

    /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */

    memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);

    printf("Video decoding\n");

    /* find the mpeg1 video decoder */

    codec = avcodec_find_decoder(CODEC_ID_MPEG1VIDEO);

    if (!codec) {

        fprintf(stderr, "codec not found\n");

        exit(1);

    }

    c= avcodec_alloc_context();

    picture= avcodec_alloc_frame();

    if(codec->capabilities&CODEC_CAP_TRUNCATED)

        c->flags|= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */

    /* for some codecs, such as msmpeg4 and mpeg4, width and height

       MUST be initialized there because these info are not available

       in the bitstream */

    /* open it */

    if (avcodec_open(c, codec) < 0) {

        fprintf(stderr, "could not open codec\n");

        exit(1);

    }

    /* the codec gives us the frame size, in samples */

    f = fopen(filename, "r");

    if (!f) {

        fprintf(stderr, "could not open %s\n", filename);

        exit(1);

    }

    frame = 0;

    for(;;) {

        size = fread(inbuf, 1, INBUF_SIZE, f);

        if (size == 0)

            break;

        /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)

           and this is the only method to use them because you cannot

           know the compressed data size before analysing it.

           BUT some other codecs (msmpeg4, mpeg4) are inherently frame

           based, so you must call them with all the data for one

           frame exactly. You must also initialize 'width' and

           'height' before initializing them. */

        /* NOTE2: some codecs allow the raw parameters (frame size,

           sample rate) to be changed at any frame. We handle this, so

           you should also take care of it */

        /* here, we use a stream based decoder (mpeg1video), so we

           feed decoder and see if it could decode a frame */

        inbuf_ptr = inbuf;

        while (size > 0) {

            len = avcodec_decode_video(c, picture, &got_picture,

                                       inbuf_ptr, size);

            if (len < 0) {

                fprintf(stderr, "Error while decoding frame %d\n", frame);

                exit(1);

            }

            if (got_picture) {

                printf("saving frame %3d\n", frame);

                fflush(stdout);

                /* the picture is allocated by the decoder. no need to

                   free it */

                snprintf(buf, sizeof(buf), outfilename, frame);

                pgm_save(picture->data[0], picture->linesize[0],

                         c->width, c->height, buf);

                frame++;

            }

            size -= len;

            inbuf_ptr += len;

        }

    }

    /* some codecs, such as MPEG, transmit the I and P frame with a

       latency of one frame. You must do the following to have a

       chance to get the last frame of the video */

    len = avcodec_decode_video(c, picture, &got_picture,

                               NULL, 0);

    if (got_picture) {

        printf("saving last frame %3d\n", frame);

        fflush(stdout);

        /* the picture is allocated by the decoder. no need to

           free it */

        snprintf(buf, sizeof(buf), outfilename, frame);

        pgm_save(picture->data[0], picture->linesize[0],

                 c->width, c->height, buf);

        frame++;

    }

    fclose(f);

    avcodec_close(c);

    free(c);

    free(picture);

    printf("\n");

}