public static uint get_instruction(out INSTRUCTION inst, byte[] dat, uint idx, Mode mode)
        {
            INST ptr   = null;
            uint index = 0;
            uint flags = 0;

            inst = new INSTRUCTION();


            get_real_instruction(dat, idx, ref index, ref flags);



            if (Macros.MASK_EXT(flags) == 0)
            {
                inst.opcode = dat[idx + index];
                ptr         = opcode_tables.inst_table1[inst.opcode];
            }
            else if (Macros.MASK_EXT(flags) == Consts.EXT_CP)
            {
                if (dat[idx + index] < 0xc0)
                {
                    index--;
                    inst.fpuindex = dat[idx + index] - 0xd8;
                    inst.opcode   = dat[idx + index + 1];
                    ptr           = opcode_tables.inst_table4[inst.fpuindex][Macros.MASK_MODRM_REG(inst.opcode)];
                }
                else
                {
                    inst.fpuindex = dat[idx + index - 1] - 0xd8;
                    inst.opcode   = dat[idx + index];
                    ptr           = opcode_tables.inst_table4[inst.fpuindex][inst.opcode - 0xb8];
                }
            }
            else if (Macros.MASK_EXT(flags) == Consts.EXT_T2)
            {
                inst.opcode = dat[idx + index];


                get_real_instruction2(dat[idx + index], ref flags);


                ptr = opcode_tables.inst_table2[inst.opcode];


                if (Macros.MASK_TYPE_FLAGS((uint)ptr.type) == Consts.TYPE_3)
                {
                    if (Macros.MASK_PREFIX_OPERAND(flags) == 1)
                    {
                        ptr = opcode_tables.inst_table3_66[inst.opcode];
                    }
                    else if (Macros.MASK_PREFIX_G1(flags) == 2)
                    {
                        ptr = opcode_tables.inst_table3_f2[inst.opcode];
                    }
                    else if (Macros.MASK_PREFIX_G1(flags) == 3)
                    {
                        ptr = opcode_tables.inst_table3_f3[inst.opcode];
                    }
                }
            }

            if (Macros.MASK_EXT(flags) != 0 && (Macros.MASK_EXT(flags) < Consts.EXT_T2))
            {
                inst.opcode   = dat[idx + index];
                inst.extindex = Macros.MASK_MODRM_REG(dat[idx + index + 1]);

                switch (Macros.MASK_EXT(flags))
                {
                case Consts.EXT_GC:

                    if (Macros.MASK_PREFIX_OPERAND(flags) == 1)
                    {
                        ptr = opcode_tables.inst_table_ext12_66[inst.extindex];
                    }
                    else
                    {
                        ptr = opcode_tables.inst_table_ext12[inst.extindex];
                    }
                    break;

                case Consts.EXT_GD:

                    if (Macros.MASK_PREFIX_OPERAND(flags) == 1)
                    {
                        ptr = opcode_tables.inst_table_ext13_66[inst.extindex];
                    }
                    else
                    {
                        ptr = opcode_tables.inst_table_ext13[inst.extindex];
                    }
                    break;

                case Consts.EXT_GE:

                    if (Macros.MASK_PREFIX_OPERAND(flags) == 1)
                    {
                        ptr = opcode_tables.inst_table_ext14_66[inst.extindex];
                    }
                    else
                    {
                        ptr = opcode_tables.inst_table_ext14[inst.extindex];
                    }
                    break;


                case Consts.EXT_G7:
                    if (Macros.MASK_MODRM_MOD(dat[idx + index + 1]) == 3)
                    {
                        if (inst.extindex != 1)
                        {
                            return(0);
                        }
                        if (Macros.MASK_MODRM_RM(dat[idx + index + 1]) == 0)
                        {
                            ptr = opcode_tables.inst_monitor;


                            index++;
                        }
                        else if (Macros.MASK_MODRM_RM(dat[idx + index + 1]) == 1)
                        {
                            ptr = opcode_tables.inst_mwait;
                            index++;
                        }
                        else
                        {
                            return(0);
                        }
                    }
                    else
                    {
                        ptr = opcode_tables.inst_table_ext7[inst.extindex];
                    }
                    break;

                default:
                    ptr = opcode_tables.inst_table_ext[(Macros.MASK_EXT(flags)) - 1][inst.extindex];
                    break;
                }
            }

            index++;


            if (ptr == null)
            {
                return(0);
            }
            if (ptr.mnemonic == null)
            {
                return(0);
            }


            if (ptr.modrm)
            {
                inst.modrm_offset = index;
            }


            inst.type = (InstructionType)Macros.MASK_TYPE_VALUE((uint)ptr.type);


            inst.eflags_affected = ptr.eflags_affected;
            inst.eflags_used     = ptr.eflags_used;


            inst.ptr = ptr;



            if (!get_operand(ptr, ptr.flags1, inst, out inst.op1, dat, index + idx, mode, flags))
            {
                return(0);
            }
            if (!get_operand(ptr, ptr.flags2, inst, out inst.op2, dat, index + idx, mode, flags))
            {
                return(0);
            }
            if (!get_operand(ptr, ptr.flags3, inst, out inst.op3, dat, index + idx, mode, flags))
            {
                return(0);
            }


            inst.iop_read    = ptr.iop_read;
            inst.iop_written = ptr.iop_written;


            inst.length += index + inst.immbytes + inst.dispbytes;


            inst.mode = mode;


            inst.flags = flags;

            return(inst.length);
        }
        private static bool get_operand(INST inst, uint oflags, INSTRUCTION instruction, out OPERAND op, byte[] data, uint idx, Mode mode, uint iflags)
        {
            uint index     = 0;
            bool sib       = false;
            uint scale     = 0;
            uint reg       = Consts.REG_NOP;
            uint basereg   = Consts.REG_NOP;
            uint indexreg  = Consts.REG_NOP;
            uint dispbytes = 0;
            Mode pmode;

            op = new OPERAND();

            if (oflags == Consts.FLAGS_NONE)
            {
                op.type = OperandType.OPERAND_TYPE_NONE;
                return(true);
            }

            op.flags = oflags;


            op.reg      = Consts.REG_NOP;
            op.basereg  = Consts.REG_NOP;
            op.indexreg = Consts.REG_NOP;


            op.dispoffset = 0;
            op.immoffset  = 0;


            if (inst.modrm)
            {
                pmode = MODE_CHECK_ADDR(mode, iflags);


                if (instruction.length == 0)
                {
                    instruction.modrm   = (byte)idx;
                    instruction.length += 1;
                }

                reg = Macros.MASK_MODRM_REG(data[idx]);



                if (Macros.MASK_MODRM_MOD(data[idx]) == 0)
                {
                    if ((pmode == Mode.MODE_32) && (Macros.MASK_MODRM_RM(data[idx]) == Consts.REG_EBP))
                    {
                        dispbytes = 4;
                    }
                    if ((pmode == Mode.MODE_16) && (Macros.MASK_MODRM_RM(data[idx]) == Consts.REG_ESI))
                    {
                        dispbytes = 2;
                    }
                }
                else if (Macros.MASK_MODRM_MOD(data[idx]) == 1)
                {
                    dispbytes = 1;
                }
                else if (Macros.MASK_MODRM_MOD(data[idx]) == 2)
                {
                    dispbytes = (pmode == Mode.MODE_32) ? 4U : 2U;
                }



                if (pmode == Mode.MODE_32)
                {
                    if ((Macros.MASK_MODRM_RM(data[idx]) == Consts.REG_ESP) && (Macros.MASK_MODRM_MOD(data[idx]) != 3))
                    {
                        sib             = true;
                        instruction.sib = data[idx + 1];


                        if (instruction.length == 1)
                        {
                            instruction.sib     = data[idx + 1];
                            instruction.length += 1;
                        }
                        basereg  = Macros.MASK_SIB_BASE(data[idx + 1]);
                        indexreg = Macros.MASK_SIB_INDEX(data[idx + 1]);
                        scale    = Macros.MASK_SIB_SCALE(data[idx + 1]) * 2;

                        if (scale == 6)
                        {
                            scale += 2;
                        }


                        if ((basereg == Consts.REG_EBP) && Macros.MASK_MODRM_MOD(data[idx]) == 0)
                        {
                            basereg   = Consts.REG_NOP;
                            dispbytes = 4;
                        }
                        if (indexreg == Consts.REG_ESP)
                        {
                            indexreg = Consts.REG_NOP;
                        }
                    }
                    else
                    {
                        if (Macros.MASK_MODRM_MOD(data[idx]) == 0 && (Macros.MASK_MODRM_RM(data[idx]) == Consts.REG_EBP))
                        {
                            basereg = Consts.REG_NOP;
                        }
                        else
                        {
                            basereg = Macros.MASK_MODRM_RM(data[idx]);
                        }
                    }
                }
                else
                {
                    switch (Macros.MASK_MODRM_RM(data[idx]))
                    {
                    case 0:
                        basereg  = Consts.REG_EBX;
                        indexreg = Consts.REG_ESI;
                        break;

                    case 1:
                        basereg  = Consts.REG_EBX;
                        indexreg = Consts.REG_EDI;
                        break;

                    case 2:
                        basereg  = Consts.REG_EBP;
                        indexreg = Consts.REG_ESI;
                        break;

                    case 3:
                        basereg  = Consts.REG_EBP;
                        indexreg = Consts.REG_EDI;
                        break;

                    case 4:
                        basereg  = Consts.REG_ESI;
                        indexreg = Consts.REG_NOP;
                        break;

                    case 5:
                        basereg  = Consts.REG_EDI;
                        indexreg = Consts.REG_NOP;
                        break;

                    case 6:
                        if (Macros.MASK_MODRM_MOD(data[idx]) == 0)
                        {
                            basereg = Consts.REG_NOP;
                        }
                        else
                        {
                            basereg = Consts.REG_EBP;
                        }
                        indexreg = Consts.REG_NOP;
                        break;

                    case 7:
                        basereg  = Consts.REG_EBX;
                        indexreg = Consts.REG_NOP;
                        break;
                    }
                    if (Macros.MASK_MODRM_MOD(data[idx]) == 3)
                    {
                        basereg  = Macros.MASK_MODRM_RM(data[idx]);
                        indexreg = Consts.REG_NOP;
                    }
                }
            }


            switch (Macros.MASK_AM(oflags))
            {
            case Consts.AM_REG:
                op.type = OperandType.OPERAND_TYPE_REGISTER;
                op.reg  = Macros.MASK_REG(oflags);
                break;


            case Consts.AM_IND:
                op.type    = OperandType.OPERAND_TYPE_MEMORY;
                op.basereg = Macros.MASK_REG(oflags);
                break;


            case Consts.AM_M:
                if (Macros.MASK_MODRM_MOD(data[idx]) == 3)
                {
                    return(false);
                }
                goto skip_rest;

            case Consts.AM_R:
                if (Macros.MASK_MODRM_MOD(data[idx]) != 3)
                {
                    return(false);
                }
                goto skip_rest;

            case Consts.AM_Q:
            case Consts.AM_W:
            case Consts.AM_E:
skip_rest:
                op.type               = OperandType.OPERAND_TYPE_MEMORY;
                op.dispbytes          = dispbytes;
                instruction.dispbytes = dispbytes;
                op.basereg            = basereg;
                op.indexreg           = indexreg;
                op.scale              = scale;

                index = (sib) ? 1U : 0U;
                if (dispbytes != 0)
                {
                    op.dispoffset = index + 1 + idx;
                }
                switch (dispbytes)
                {
                case 0:
                    break;

                case 1:
                    op.displacement = Macros.FETCH8(data, idx + 1 + index);

                    if (op.displacement >= 0x80)
                    {
                        op.displacement |= 0xffffff00;
                    }
                    break;

                case 2:
                    op.displacement = Macros.FETCH16(data, idx + 1 + index);
                    break;

                case 4:
                    op.displacement = Macros.FETCH32(data, idx + 1 + index);
                    break;
                }


                if ((basereg != Consts.REG_NOP) && (Macros.MASK_MODRM_MOD(data[idx]) == 3))
                {
                    op.type = OperandType.OPERAND_TYPE_REGISTER;
                    op.reg  = basereg;
                }
                break;


            case Consts.AM_I1:
                op.type      = OperandType.OPERAND_TYPE_IMMEDIATE;
                op.immbytes  = 1;
                op.immediate = 1;
                break;

            case Consts.AM_J:
                op.type = OperandType.OPERAND_TYPE_IMMEDIATE;

                oflags |= Consts.F_s;
                goto am_i;

            case Consts.AM_I:
am_i:
                op.type      = OperandType.OPERAND_TYPE_IMMEDIATE;
                index        = (inst.modrm) ? 1U : 0U;
                index       += (sib) ? 1U : 0U;
                index       += instruction.immbytes;
                index       += instruction.dispbytes;
                op.immoffset = index + idx;


                mode = MODE_CHECK_OPERAND(mode, iflags);

                switch (Macros.MASK_OT(oflags))
                {
                case Consts.OT_b:
                    op.immbytes  = 1;
                    op.immediate = Macros.FETCH8(data, idx + index);
                    if ((op.immediate >= 0x80) && (Macros.MASK_FLAGS(oflags) == Consts.F_s))
                    {
                        op.immediate |= 0xffffff00;
                    }
                    break;

                case Consts.OT_v:
                    op.immbytes  = (mode == Mode.MODE_32) ? 4U : 2U;
                    op.immediate = (mode == Mode.MODE_32) ? Macros.FETCH32(data, idx + index) : Macros.FETCH16(data, idx + index);
                    break;

                case Consts.OT_w:
                    op.immbytes  = 2;
                    op.immediate = Macros.FETCH16(data, idx + index);
                    break;
                }
                instruction.immbytes += op.immbytes;
                break;


            case Consts.AM_A:
                op.type = OperandType.OPERAND_TYPE_IMMEDIATE;

                mode = MODE_CHECK_OPERAND(mode, iflags);

                op.dispbytes    = (mode == Mode.MODE_32) ? 6U : 4U;
                op.displacement = (mode == Mode.MODE_32) ? Macros.FETCH32(data, idx) : Macros.FETCH16(data, idx);
                op.section      = Macros.FETCH16(data, idx + op.dispbytes - 2);

                instruction.dispbytes    = op.dispbytes;
                instruction.sectionbytes = 2;
                break;


            case Consts.AM_O:
                op.type = OperandType.OPERAND_TYPE_MEMORY;
                switch (Macros.MASK_OT(oflags))
                {
                case Consts.OT_b:
                    op.dispbytes    = 1;
                    op.displacement = Macros.FETCH8(data, idx);
                    break;

                case Consts.OT_v:
                    op.dispbytes    = (mode == Mode.MODE_32) ? 4U : 2U;
                    op.displacement = (mode == Mode.MODE_32) ? Macros.FETCH32(data, idx) : Macros.FETCH16(data, idx);
                    break;
                }
                instruction.dispbytes = op.dispbytes;
                op.dispoffset         = idx;
                break;


            case Consts.AM_G:
                op.type = OperandType.OPERAND_TYPE_REGISTER;
                op.reg  = reg;
                break;


            case Consts.AM_C:

            case Consts.AM_D:

            case Consts.AM_S:

            case Consts.AM_T:

            case Consts.AM_P:

            case Consts.AM_V:
                op.type = OperandType.OPERAND_TYPE_REGISTER;
                op.reg  = Macros.MASK_MODRM_REG(instruction.modrm);
                break;
            }
            return(true);
        }