/*
 * Copyright (c) 1996-2011 Barton P. Miller
 * 
 * We provide the Paradyn Parallel Performance Tools (below
 * described as "Paradyn") on an AS IS basis, and do not warrant its
 * validity or performance.  We reserve the right to update, modify,
 * or discontinue this software at any time.  We shall have no
 * obligation to supply such updates or modifications or any other
 * form of support to you.
 * 
 * By your use of Paradyn, you understand and agree that we (or any
 * other person or entity with proprietary rights in Paradyn) are
 * under no obligation to provide either maintenance services,
 * update services, notices of latent defects, or correction of
 * defects for Paradyn.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

// $Id: arch-x86.C,v 1.5 2008/09/04 21:06:48 bill Exp $

// Official documentation used:    - IA-32 Intel Architecture Software Developer Manual (2001 ed.)
//                                 - AMD x86-64 Architecture Programmer's Manual (rev 3.00, 1/2002)
// Unofficial documentation used:  - www.sandpile.org/ia32
//                                 - NASM documentation

// Note: Unless specified "book" refers to Intel's manual

// This include *must* come first in the file.
#include "common/h/Types.h"

#include <assert.h>
#include <stdio.h>
#include <map>
#include <string>
#include <iostream>

#include "boost/assign/list_of.hpp"
#include "boost/assign/std/vector.hpp"
#include "boost/assign/std/set.hpp"

#include "common/h/arch-x86.h"
#include "dyn_regs.h"

#if defined(os_vxworks)
#include "common/h/wtxKludges.h"
#endif

using namespace std;
using namespace boost::assign;

namespace NS_x86 {

unsigned int swapBytesIfNeeded(unsigned int i)
{
    return i;
}

// groups
enum {
  Grp1a=0, Grp1b, Grp1c, Grp1d, Grp2, Grp3a, Grp3b, Grp4, Grp5, Grp6, Grp7,
  Grp8, Grp9, Grp11, Grp12, Grp13, Grp14, Grp15, Grp16, Grp17, GrpAMD
};

// SSE
enum {
  SSE10=0, SSE11, SSE12, SSE13, SSE14, SSE15, SSE16, SSE17,
  SSE28, SSE29, SSE2A, SSE2B, SSE2C, SSE2D, SSE2E, SSE2F,
  SSE50, SSE51, SSE52, SSE53, SSE54, SSE55, SSE56, SSE57,
  SSE58, SSE59, SSE5A, SSE5B, SSE5C, SSE5D, SSE5E, SSE5F,
  SSE60, SSE61, SSE62, SSE63, SSE64, SSE65, SSE66, SSE67,
  SSE68, SSE69, SSE6A, SSE6B, SSE6C, SSE6D, SSE6E, SSE6F,
  SSE70, SSE74, SSE75, SSE76,
  SSE78, SSE79, SSE7C, SSE7D, SSE7E, SSE7F,
  SSEB8,
  SSEC2, SSEC4, SSEC5, SSEC6,
  SSED0, SSED1, SSED2, SSED3, SSED4, SSED5, SSED6, SSED7,
  SSED8, SSED9, SSEDA, SSEDB, SSEDC, SSEDD, SSEDE, SSEDF,
  SSEE0, SSEE1, SSEE2, SSEE3, SSEE4, SSEE5, SSEE6, SSEE7,
  SSEE8, SSEE9, SSEEA, SSEEB, SSEEC, SSEED, SSEEE, SSEEF,
  SSEF0, SSEF1, SSEF2, SSEF3, SSEF4, SSEF5, SSEF6, SSEF7,
  SSEF8, SSEF9, SSEFA, SSEFB, SSEFC, SSEFD, SSEFE, SSEFF
};


// SSE groups
enum {
  G12SSE010B=0, G12SSE100B, G12SSE110B,
  G13SSE010B, G13SSE100B, G13SSE110B,
  G14SSE010B, G14SSE011B, G14SSE110B, G14SSE111B,
};

enum {
    GrpD8=0, GrpD9, GrpDA, GrpDB, GrpDC, GrpDD, GrpDE, GrpDF
};

#define Zz   { 0, 0 }
#define ImplImm { am_ImplImm, op_b }
#define Ap   { am_A, op_p }
#define Cd   { am_C, op_d }
#define Dd   { am_D, op_d }
#define Eb   { am_E, op_b }
#define Ed   { am_E, op_d }
#define Ef   { am_E, op_f }
#define Efd  { am_E, op_dbl }
#define Ep   { am_E, op_p }
#define Ev   { am_E, op_v }
#define Ew   { am_E, op_w }
#define Fv   { am_F, op_v }
#define Gb   { am_G, op_b }
#define Gd   { am_G, op_d }
#define Gv   { am_G, op_v }
#define Gw   { am_G, op_w }
#define Gf   { am_G, op_f }
#define Gfd  { am_G, op_dbl }
#define Ib   { am_I, op_b }
#define Iv   { am_I, op_v }
#define Iw   { am_I, op_w }
#define Iz   { am_I, op_z }
#define Jb   { am_J, op_b }
#define Jv   { am_J, op_v }
#define Jz   { am_J, op_z }
#define Ma   { am_M, op_a }
#define Mb   { am_M, op_b }
#define Mlea { am_M, op_lea }
#define Mp   { am_M, op_p }
#define Ms   { am_M, op_s }
#define Md   { am_M, op_d }
#define Mq   { am_M, op_q }
#define Mdq   { am_M, op_dq }
#define M512 { am_M, op_512 }
#define Mf   { am_M, op_f }
#define Mfd  { am_M, op_dbl }
#define M14  { am_M, op_14 }
#define Ob   { am_O, op_b }
#define Ov   { am_O, op_v }
#define Pd   { am_P, op_d }
#define Pdq  { am_P, op_dq }
#define Ppi  { am_P, op_pi }
#define Pq   { am_P, op_q }
#define Qdq  { am_Q, op_dq }
#define Qd   { am_Q, op_d }
#define Qpi  { am_Q, op_pi }
#define Qq   { am_Q, op_q }
#define Rd   { am_R, op_d }
#define Td   { am_T, op_d }
#define Sw   { am_S, op_w }
#define Vd   { am_V, op_d }
#define Vdq  { am_V, op_dq }
#define Vpd  { am_V, op_pd }
#define Vps  { am_V, op_ps }
#define Vq   { am_V, op_q }
#define VRq  { am_VR, op_q }
#define VRdq { am_VR, op_dq }
#define Vss  { am_V, op_ss }
#define Vsd  { am_V, op_sd }
#define Wdq  { am_W, op_dq }
#define Wpd  { am_W, op_pd }
#define Wps  { am_W, op_ps }
#define Wq   { am_W, op_q }
#define Ws   { am_W, op_s }
#define Wsd  { am_W, op_sd }
#define Wss  { am_W, op_ss }
#define Xb   { am_X, op_b }
#define Xv   { am_X, op_v }
#define Yb   { am_Y, op_b }
#define Yv   { am_Y, op_v }
#define STHb { am_stackH, op_b }
#define STPb { am_stackP, op_b }
#define STHv { am_stackH, op_v }
#define STPv { am_stackP, op_v }
#define STHw { am_stackH, op_w }
#define STPw { am_stackP, op_w }
#define STHd { am_stackH, op_d }
#define STPd { am_stackP, op_d }
#define STHa { am_stackH, op_allgprs }
#define STPa { am_stackP, op_allgprs }

#define STKb { am_stack, op_b }
#define STKv { am_stack, op_v }
#define STKw { am_stack, op_w }
#define STKd { am_stack, op_d }
#define STKa { am_stack, op_allgprs }


#define GPRS { am_allgprs, op_allgprs }

#define AH  { am_reg, x86::iah }
#define AX  { am_reg, x86::iax }
#define BH  { am_reg, x86::ibh }
#define CH  { am_reg, x86::ich }
#define DH  { am_reg, x86::idh }
#define AL  { am_reg, x86::ial }
#define BL  { am_reg, x86::ibl }
#define CL  { am_reg, x86::icl }
#define CS  { am_reg, x86::ics }
#define DL  { am_reg, x86::idl }
#define DX  { am_reg, x86::idx }
#define eAX { am_reg, x86::ieax }
#define eBX { am_reg, x86::iebx }
#define eCX { am_reg, x86::iecx }
#define eDX { am_reg, x86::iedx }
#define EAX { am_reg, x86::ieax }
#define EBX { am_reg, x86::iebx }
#define ECX { am_reg, x86::iecx }
#define EDX { am_reg, x86::iedx }
#define DS  { am_reg, x86::ids }
#define ES  { am_reg, x86::ies }
#define FS  { am_reg, x86::ifs }
#define GS  { am_reg, x86::igs }
#define SS  { am_reg, x86::iss }
#define eSP { am_reg, x86::iesp }
#define eBP { am_reg, x86::iebp }
#define eSI { am_reg, x86::iesi }
#define eDI { am_reg, x86::iedi }
#define ESP { am_reg, x86::iesp }
#define EBP { am_reg, x86::iebp }
#define ESI { am_reg, x86::iesi }
#define EDI { am_reg, x86::iedi }
#define ECXEBX { am_tworeghack, op_ecxebx }
#define EDXEAX { am_tworeghack, op_edxeax }
#define rAX { am_reg, x86_64::irax }
#define rBX { am_reg, x86_64::irbx }
#define rCX { am_reg, x86_64::ircx }
#define rDX { am_reg, x86_64::irdx }
#define rSP { am_reg, x86_64::irsp }
#define rBP { am_reg, x86_64::irbp }
#define rSI { am_reg, x86_64::irsi }
#define rDI { am_reg, x86_64::irdi }
#define ST0 { am_reg, x86::ist0 }
#define ST1 { am_reg, x86::ist1 }
#define ST2 { am_reg, x86::ist2 }
#define ST3 { am_reg, x86::ist3 }
#define ST4 { am_reg, x86::ist4 }
#define ST5 { am_reg, x86::ist5 }
#define ST6 { am_reg, x86::ist6 }
#define ST7 { am_reg, x86::ist7 }
#define FPOS 16

enum {
  fNT=1,   // non-temporal
  fPREFETCHNT,
  fPREFETCHT0,
  fPREFETCHT1,
  fPREFETCHT2,
  fPREFETCHAMDE,
  fPREFETCHAMDW,
  fCALL,
  fNEARRET,
  fFARRET,
  fIRET,
  fENTER,
  fLEAVE,
  fXLAT,
  fIO,
  fSEGDESC,
  fCOND,
  fCMPXCH,
  fCMPXCH8,
  fINDIRCALL,
  fINDIRJUMP,
  fFXSAVE,
  fFXRSTOR,
  fCLFLUSH,
  fREP,   // only rep prefix allowed: ins, movs, outs, lods, stos
  fSCAS,
  fCMPS
};

COMMON_EXPORT dyn_hash_map<entryID, std::string> entryNames_IAPI = map_list_of
  (e_aaa, "aaa")
  (e_aad, "aad")
  (e_aam, "aam")
  (e_aas, "aas")
  (e_adc, "adc")
  (e_add, "add")
  (e_addpd, "addpd")
  (e_addps, "addps")
  (e_addsd, "addsd")
  (e_addss, "addss")
  (e_addsubpd, "addsubpd")
  (e_addsubps, "addsubps")
  (e_and, "and")
  (e_andnpd, "andnpd")
  (e_andnps, "andnps")
  (e_andpd, "andpd")
  (e_andps, "andps")
  (e_arpl, "arpl")
  (e_bound, "bound")
  (e_bsf, "bsf")
  (e_bsr, "bsr")
  (e_bswap, "bswap")
  (e_bt, "bt")
  (e_btc, "btc")
  (e_btr, "btr")
  (e_bts, "bts")
  (e_call, "call")
  (e_cbw, "cbw")
  (e_cdq, "cdq")
  (e_clc, "clc")
  (e_cld, "cld")
  (e_clflush, "clflush")
  (e_cli, "cli")
  (e_clts, "clts")
  (e_cmc, "cmc")
  (e_cmovbe, "cmovbe")
  (e_cmove, "cmove")
  (e_cmovnae, "cmovnae")
  (e_cmovnb, "cmovnb")
  (e_cmovnbe, "cmovnbe")
  (e_cmovne, "cmovne")
  (e_cmovng, "cmovng")
  (e_cmovnge, "cmovnge")
  (e_cmovnl, "cmovnl")
  (e_cmovno, "cmovno")
  (e_cmovns, "cmovns")
  (e_cmovo, "cmovo")
  (e_cmovpe, "cmovpe")
  (e_cmovpo, "cmovpo")
  (e_cmovs, "cmovs")
  (e_cmp, "cmp")
  (e_cmppd, "cmppd")
  (e_cmpps, "cmpps")
  (e_cmpsb, "cmpsb")
  (e_cmpsd, "cmpsd")
  (e_cmpss, "cmpss")
  (e_cmpsw, "cmpsw")
  (e_cmpxch, "cmpxch")
  (e_cmpxch8b, "cmpxch8b")
  (e_comisd, "comisd")
  (e_comiss, "comiss")
  (e_cpuid, "cpuid")
  (e_cvtdq2pd, "cvtdq2pd")
  (e_cvtdq2ps, "cvtdq2ps")
  (e_cvtpd2dq, "cvtpd2dq")
  (e_cvtpd2pi, "cvtpd2pi")
  (e_cvtpd2ps, "cvtpd2ps")
  (e_cvtpi2pd, "cvtpi2pd")
  (e_cvtpi2ps, "cvtpi2ps")
  (e_cvtps2dq, "cvtps2dq")
  (e_cvtps2pd, "cvtps2pd")
  (e_cvtps2pi, "cvtps2pi")
  (e_cvtsd2si, "cvtsd2si")
  (e_cvtsd2ss, "cvtsd2ss")
  (e_cvtsi2sd, "cvtsi2sd")
  (e_cvtsi2ss, "cvtsi2ss")
  (e_cvtss2sd, "cvtss2sd")
  (e_cvtss2si, "cvtss2si")
  (e_cvttpd2dq, "cvttpd2dq")
  (e_cvttpd2pi, "cvttpd2pi")
  (e_cvttps2dq, "cvttps2dq")
  (e_cvttps2pi, "cvttps2pi")
  (e_cvttsd2si, "cvttsd2si")
  (e_cvttss2si, "cvttss2si")
  (e_cwd, "cwd")
  (e_cwde, "cwde")
  (e_daa, "daa")
  (e_das, "das")
  (e_dec, "dec")
  (e_div, "div")
  (e_divpd, "divpd")
  (e_divps, "divps")
  (e_divsd, "divsd")
  (e_divss, "divss")
  (e_emms, "emms")
  (e_enter, "enter")
  (e_extrq, "extrq")
  (e_fadd, "fadd")
  (e_faddp, "faddp")
  (e_f2xm1, "f2xm1")
  (e_fbld, "fbld")
  (e_fbstp, "fbstp")
  (e_fchs, "fchs")
  (e_fcmovb, "fcmovb")
  (e_fcmovbe, "fcmovbe")
  (e_fcmove, "fcmove")
  (e_fcmovne, "fcmovne")
  (e_fcmovu, "fcmovu")
  (e_fcmovnu, "fcmovnu")
  (e_fcmovnb, "fcmovnb")
  (e_fcmovnbe, "fcmovnbe")
  (e_fcom, "fcom")
  (e_fcomi, "fcomi")
  (e_fcomip, "fcomip")
  (e_fcomp, "fcomp")
  (e_fcompp, "fcompp")
  (e_fdiv, "fdiv")
  (e_fdivp, "fdivp")
  (e_fdivr, "fdivr")
  (e_fdivrp, "fdivrp")
  (e_femms, "femms")
  (e_ffree, "ffree")
  (e_fiadd, "fiadd")
  (e_ficom, "ficom")
  (e_ficomp, "ficomp")
  (e_fidiv, "fidiv")
  (e_fidivr, "fidivr")
  (e_fild, "fild")
  (e_fimul, "fimul")
  (e_fist, "fist")
  (e_fistp, "fistp")
  (e_fisttp, "fisttp")
  (e_fisub, "fisub")
  (e_fisubr, "fisubr")
  (e_fld, "fld")
  (e_fld1, "fld1")
  (e_fldcw, "fldcw")
  (e_fldenv, "fldenv")
  (e_fmul, "fmul")
  (e_fmulp, "fmulp")
  (e_fnop, "fnop")
  (e_fprem, "fprem")
  (e_frstor, "frstor")
  (e_fsave, "fsave")
  (e_fst, "fst")
  (e_fstcw, "fstcw")
  (e_fstenv, "fstenv")
  (e_fstp, "fstp")
  (e_fstsw, "fstsw")
  (e_fsub, "fsub")
  (e_fsubp, "fsubp")
  (e_fsubr, "fsubr")
  (e_fsubrp, "fsubrp")
  (e_fucom, "fucom")
  (e_fucomp, "fucomp")
  (e_fucomi, "fucomi")
  (e_fucomip, "fucomip")
  (e_fucompp, "fucompp")
  (e_fxch, "fxch")
  (e_fxrstor, "fxrstor")
  (e_fxsave, "fxsave")
  (e_haddpd, "haddpd")
  (e_haddps, "haddps")
  (e_hlt, "hlt")
  (e_hsubpd, "hsubpd")
  (e_hsubps, "hsubps")
  (e_idiv, "idiv")
  (e_imul, "imul")
  (e_in, "in")
  (e_inc, "inc")
  (e_insb, "insb")
  (e_insd, "insd")
  (e_insertq, "insertq")
  (e_insw, "insw")
  (e_int, "int")
  (e_int3, "int 3")
  (e_int1, "int1")
  (e_int80, "int 80")
  (e_into, "into")
  (e_invd, "invd")
  (e_invlpg, "invlpg")
  (e_iret, "iret")
  (e_jb, "jb")
  (e_jb_jnaej_j, "jb/jnaej/j")
  (e_jbe, "jbe")
  (e_jcxz_jec, "jcxz/jec")
  (e_jl, "jl")
  (e_jle, "jle")
  (e_jmp, "jmp")
  (e_jmpe, "jmpe")
  (e_jnb, "jnb")
  (e_jnb_jae_j, "jnb/jae/j")
  (e_jnbe, "jnbe")
  (e_jnl, "jnl")
  (e_jnle, "jnle")
  (e_jno, "jno")
  (e_jnp, "jnp")
  (e_jns, "jns")
  (e_jnz, "jnz")
  (e_jo, "jo")
  (e_jp, "jp")
  (e_js, "js")
  (e_jz, "jz")
  (e_lahf, "lahf")
  (e_lar, "lar")
  (e_lddqu, "lddqu")
  (e_ldmxcsr, "ldmxcsr")
  (e_lds, "lds")
  (e_lea, "lea")
  (e_leave, "leave")
  (e_les, "les")
  (e_lfence, "lfence")
  (e_lfs, "lfs")
  (e_lgdt, "lgdt")
  (e_lgs, "lgs")
  (e_lidt, "lidt")
  (e_lldt, "lldt")
  (e_lmsw, "lmsw")
  (e_lodsb, "lodsb")
  (e_lodsd, "lodsd")
  (e_lodsw, "lodsw")
  (e_loop, "loop")
  (e_loope, "loope")
  (e_loopn, "loopn")
  (e_lsl, "lsl")
  (e_lss, "lss")
  (e_ltr, "ltr")
  (e_maskmovdqu, "maskmovdqu")
  (e_maskmovq, "maskmovq")
  (e_maxpd, "maxpd")
  (e_maxps, "maxps")
  (e_maxsd, "maxsd")
  (e_maxss, "maxss")
  (e_mfence, "mfence")
  (e_minpd, "minpd")
  (e_minps, "minps")
  (e_minsd, "minsd")
  (e_minss, "minss")
  (e_mmxud, "mmxud")
  (e_mov, "mov")
  (e_movapd, "movapd")
  (e_movaps, "movaps")
  (e_movd, "movd")
  (e_movddup, "movddup")
  (e_movdq2q, "movdq2q")
  (e_movdqa, "movdqa")
  (e_movdqu, "movdqu")
  (e_movhpd, "movhpd")
  (e_movhps, "movhps")
  (e_movhps_movlhps, "movhps/movlhps")
  (e_movlpd, "movlpd")
  (e_movlps, "movlps")
  (e_movlps_movhlps, "movlps/movhlps")
  (e_movmskpd, "movmskpd")
  (e_movmskps, "movmskps")
  (e_movntdq, "movntdq")
  (e_movnti, "movnti")
  (e_movntpd, "movntpd")
  (e_movntps, "movntps")
  (e_movntq, "movntq")
  (e_movntsd, "movntsd")
  (e_movntss, "movntss")
  (e_movq, "movq")
  (e_movq2dq, "movq2dq")
  (e_movsb, "movsb")
  (e_movsd, "movsd")
  (e_movshdup, "movshdup")
  (e_movsldup, "movsldup")
  (e_movss, "movss")
  (e_movsw, "movsw")
  (e_movsx, "movsx")
  (e_movsxd, "movsxd")
  (e_movupd, "movupd")
  (e_movups, "movups")
  (e_movzx, "movzx")
  (e_mul, "mul")
  (e_mulpd, "mulpd")
  (e_mulps, "mulps")
  (e_mulsd, "mulsd")
  (e_mulss, "mulss")
  (e_neg, "neg")
  (e_nop, "nop")
  (e_not, "not")
  (e_or, "or")
  (e_orpd, "orpd")
  (e_orps, "orps")
  (e_out, "out")
  (e_outsb, "outsb")
  (e_outsd, "outsd")
  (e_outsw, "outsw")
  (e_packssdw, "packssdw")
  (e_packsswb, "packsswb")
  (e_packuswb, "packuswb")
  (e_paddb, "paddb")
  (e_paddd, "paddd")
  (e_paddq, "paddq")
  (e_paddsb, "paddsb")
  (e_paddsw, "paddsw")
  (e_paddusb, "paddusb")
  (e_paddusw, "paddusw")
  (e_paddw, "paddw")
  (e_pand, "pand")
  (e_pandn, "pandn")
  (e_pavgb, "pavgb")
  (e_pavgw, "pavgw")
  (e_pcmpeqb, "pcmpeqb")
  (e_pcmpeqd, "pcmpeqd")
  (e_pcmpeqw, "pcmpeqw")
  (e_pcmpgdt, "pcmpgdt")
  (e_pcmpgtb, "pcmpgtb")
  (e_pcmpgtw, "pcmpgtw")
  (e_pextrw, "pextrw")
  (e_pinsrw, "pinsrw")
  (e_pmaddwd, "pmaddwd")
  (e_pmaxsw, "pmaxsw")
  (e_pmaxub, "pmaxub")
  (e_pminsw, "pminsw")
  (e_pminub, "pminub")
  (e_pmovmskb, "pmovmskb")
  (e_pmulhuw, "pmulhuw")
  (e_pmulhw, "pmulhw")
  (e_pmullw, "pmullw")
  (e_pmuludq, "pmuludq")
  (e_pop, "pop")
  (e_popa, "popa")
  (e_popad, "popad")
  (e_popf, "popf")
  (e_popfd, "popfd")
  (e_popcnt, "popcnt")
  (e_por, "por")
  (e_prefetch, "prefetch")
  (e_prefetchNTA, "prefetchNTA")
  (e_prefetchT0, "prefetchT0")
  (e_prefetchT1, "prefetchT1")
  (e_prefetchT2, "prefetchT2")
  (e_prefetch_w, "prefetch(w)")
  (e_prefetchw, "prefetchw")
  (e_psadbw, "psadbw")
  (e_pshufd, "pshufd")
  (e_pshufhw, "pshufhw")
  (e_pshuflw, "pshuflw")
  (e_pshufw, "pshufw")
  (e_pslld, "pslld")
  (e_pslldq, "pslldq")
  (e_psllq, "psllq")
  (e_psllw, "psllw")
  (e_psrad, "psrad")
  (e_psraw, "psraw")
  (e_psrld, "psrld")
  (e_psrldq, "psrldq")
  (e_psrlq, "psrlq")
  (e_psrlw, "psrlw")
  (e_psubb, "psubb")
  (e_psubd, "psubd")
  (e_psubsb, "psubsb")
  (e_psubsw, "psubsw")
  (e_psubusb, "psubusb")
  (e_psubusw, "psubusw")
  (e_psubw, "psubw")
  (e_punpckhbw, "punpckhbw")
  (e_punpckhdq, "punpckhdq")
  (e_punpckhqd, "punpckhqd")
  (e_punpckhwd, "punpckhwd")
  (e_punpcklbw, "punpcklbw")
  (e_punpcklqd, "punpcklqd")
  (e_punpcklqld, "punpcklqld")
  (e_punpcklwd, "punpcklwd")
  (e_push, "push")
  (e_pusha, "pusha")
  (e_pushad, "pushad")
  (e_pushf, "pushf")
  (e_pushfd, "pushfd")
  (e_pxor, "pxor")
  (e_rcl, "rcl")
  (e_rcpps, "rcpps")
  (e_rcpss, "rcpss")
  (e_rcr, "rcr")
  (e_rdmsr, "rdmsr")
  (e_rdpmc, "rdpmc")
  (e_rdtsc, "rdtsc")
  (e_ret_far, "ret far")
  (e_ret_near, "ret near")
  (e_rol, "rol")
  (e_ror, "ror")
  (e_rsm, "rsm")
  (e_rsqrtps, "rsqrtps")
  (e_rsqrtss, "rsqrtss")
  (e_sahf, "sahf")
  (e_salc, "salc")
  (e_sar, "sar")
  (e_sbb, "sbb")
  (e_scasb, "scasb")
  (e_scasd, "scasd")
  (e_scasw, "scasw")
  (e_setb, "setb")
  (e_setbe, "setbe")
  (e_setl, "setl")
  (e_setle, "setle")
  (e_setnb, "setnb")
  (e_setnbe, "setnbe")
  (e_setnl, "setnl")
  (e_setnle, "setnle")
  (e_setno, "setno")
  (e_setnp, "setnp")
  (e_setns, "setns")
  (e_setnz, "setnz")
  (e_seto, "seto")
  (e_setp, "setp")
  (e_sets, "sets")
  (e_setz, "setz")
  (e_sfence, "sfence")
  (e_sgdt, "sgdt")
  (e_shl_sal, "shl/sal")
  (e_shld, "shld")
  (e_shr, "shr")
  (e_shrd, "shrd")
  (e_shufpd, "shufpd")
  (e_shufps, "shufps")
  (e_sidt, "sidt")
  (e_sldt, "sldt")
  (e_smsw, "smsw")
  (e_sqrtpd, "sqrtpd")
  (e_sqrtps, "sqrtps")
  (e_sqrtsd, "sqrtsd")
  (e_sqrtss, "sqrtss")
  (e_stc, "stc")
  (e_std, "std")
  (e_sti, "sti")
  (e_stmxcsr, "stmxcsr")
  (e_stosb, "stosb")
  (e_stosd, "stosd")
  (e_stosw, "stosw")
  (e_str, "str")
  (e_sub, "sub")
  (e_subpd, "subpd")
  (e_subps, "subps")
  (e_subsd, "subsd")
  (e_subss, "subss")
  (e_syscall, "syscall")
  (e_sysenter, "sysenter")
  (e_sysexit, "sysexit")
  (e_sysret, "sysret")
  (e_test, "test")
  (e_ucomisd, "ucomisd")
  (e_ucomiss, "ucomiss")
  (e_ud, "ud")
  (e_ud2, "ud2")
  (e_ud2grp10, "ud2grp10")
  (e_unpckhpd, "unpckhpd")
  (e_unpckhps, "unpckhps")
  (e_unpcklpd, "unpcklpd")
  (e_unpcklps, "unpcklps")
  (e_verr, "verr")
  (e_verw, "verw")
  (e_vmread, "vmread")
  (e_vmwrite, "vmwrite")
  (e_vsyscall, "vsyscall")
  (e_wait, "wait")
  (e_wbinvd, "wbinvd")
  (e_wrmsr, "wrmsr")
  (e_xadd, "xadd")
  (e_xchg, "xchg")
  (e_xlat, "xlat")
  (e_xor, "xor")
  (e_xorpd, "xorpd")
  (e_xorps, "xorps")
  (e_fp_generic, "[FIXME: GENERIC FPU INSN]")
  (e_3dnow_generic, "[FIXME: GENERIC 3DNow INSN]")
        ;

dyn_hash_map<prefixEntryID, std::string> prefixEntryNames_IAPI = map_list_of
  (prefix_rep, "REP")
  (prefix_repnz, "REPNZ")
        ;

COMMON_EXPORT dyn_hash_map<entryID, flagInfo> const& ia32_instruction::getFlagTable()
{
  static dyn_hash_map<entryID, flagInfo> flagTable;
  if(flagTable.empty()) 
  {
    ia32_instruction::initFlagTable(flagTable);
  }
  return flagTable;
}
  
void ia32_instruction::initFlagTable(dyn_hash_map<entryID, flagInfo>& flagTable)
{
  static const vector<Dyninst::MachRegister> standardFlags = list_of(x86::of)(x86::sf)(x86::zf)(x86::af)(x86::pf)(x86::cf);

  flagTable[e_aaa] = flagInfo(list_of(x86::af), standardFlags);
  flagTable[e_aad] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_aam] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_aas] = flagInfo(list_of(x86::af), standardFlags);
  flagTable[e_adc] = flagInfo(list_of(x86::cf), standardFlags);
  flagTable[e_add] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_and] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_arpl] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::zf));
  flagTable[e_bsf] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_bsr] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_bt] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_bts] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_btr] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_btc] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_clc] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::cf));
  flagTable[e_cld] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::df));
  flagTable[e_cli] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::if_));
  flagTable[e_cmc] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::cf));
  flagTable[e_cmovbe] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmove] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovnae] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovnb] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovnbe] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovne] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovng] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovnge] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovnl] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovno] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovns] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovo] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovpe] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovpo] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmovs] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_cmp] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_cmpsb] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_cmpsd] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_cmpss] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_cmpsw] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_cmpxch] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_cmpxch8b] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::zf));
  flagTable[e_comisd] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_comiss] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_daa] = flagInfo(list_of(x86::af)(x86::cf), standardFlags);
  flagTable[e_das] = flagInfo(list_of(x86::af)(x86::cf), standardFlags);
  flagTable[e_dec] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::of)(x86::sf)(x86::zf)(x86::af)(x86::pf));
  flagTable[e_div] = flagInfo(list_of(x86::af)(x86::cf), standardFlags);
  // TODO: FCMOVcc (not in our entry table) (reads zf/pf/cf)
  // TODO: FCOMI/FCOMIP/FUCOMI/FUCOMIP (writes/zf/pf/cf)
  flagTable[e_idiv] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_imul] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_inc] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::of)(x86::sf)(x86::zf)(x86::af)(x86::pf));
  flagTable[e_insb] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_insw] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_insd] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_int] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::tf)(x86::nt_));
  flagTable[e_int3] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::tf)(x86::nt_));
  flagTable[e_int80] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::tf)(x86::nt_));
  flagTable[e_into] = flagInfo(list_of(x86::of), list_of(x86::tf)(x86::nt_));
  flagTable[e_ucomisd] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_ucomiss] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_iret] = flagInfo(list_of(x86::nt_),
list_of(x86::of)(x86::sf)(x86::zf)(x86::af)(x86::pf)(x86::cf)(x86::tf)(x86::if_)(x86::df));
  flagTable[e_jb] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jb_jnaej_j] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jbe] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jl] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jle] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jnb] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jnb_jae_j] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jnbe] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jnl] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jnle] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jno] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jnp] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jns] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jnz] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jo] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jp] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_js] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_jz] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_lar] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::zf));
  flagTable[e_lodsb] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_lodsd] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_lodsw] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_loope] = flagInfo(list_of(x86::zf), vector<Dyninst::MachRegister>());
  flagTable[e_loopn] = flagInfo(list_of(x86::zf), vector<Dyninst::MachRegister>());
  flagTable[e_lsl] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::zf));
  // I'd expect that mov control/debug/test gets handled when we do operand analysis
  // If it doesn't, fix later
  flagTable[e_mul] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_neg] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_or] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_outsb] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_outsw] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_outsd] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_popf] = flagInfo(vector<Dyninst::MachRegister>(),
list_of(x86::of)(x86::sf)(x86::zf)(x86::af)(x86::pf)(x86::cf)(x86::tf)(x86::if_)(x86::df)(x86::nt_));
  flagTable[e_popfd] = flagInfo(vector<Dyninst::MachRegister>(),
list_of(x86::of)(x86::sf)(x86::zf)(x86::af)(x86::pf)(x86::cf)(x86::tf)(x86::if_)(x86::df)(x86::nt_));
  flagTable[e_rcl] = flagInfo(list_of(x86::cf), list_of(x86::of)(x86::cf));
  flagTable[e_rcr] = flagInfo(list_of(x86::cf), list_of(x86::of)(x86::cf));
  flagTable[e_rol] = flagInfo(list_of(x86::cf), list_of(x86::of)(x86::cf));
  flagTable[e_ror] = flagInfo(list_of(x86::cf), list_of(x86::of)(x86::cf));
  flagTable[e_rsm] = flagInfo(vector<Dyninst::MachRegister>(),
list_of(x86::of)(x86::sf)(x86::zf)(x86::af)(x86::pf)(x86::cf)(x86::tf)(x86::if_)(x86::df)(x86::nt_)(x86::rf));
  flagTable[e_sahf] = flagInfo(list_of(x86::sf)(x86::zf)(x86::af)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_sar] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_shr] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_salc] = flagInfo(list_of(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_sbb] = flagInfo(list_of(x86::cf), standardFlags);
  flagTable[e_setb] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setbe] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setl] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setle] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setnb] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setnbe] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setnl] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setnle] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setno] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setnp] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setns] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setnz] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_seto] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setp] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_sets] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_setz] = flagInfo(list_of(x86::of)(x86::sf)(x86::zf)(x86::pf)(x86::cf), vector<Dyninst::MachRegister>());
  flagTable[e_shld] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_shrd] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_shl_sal] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_stc] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::cf));
  flagTable[e_std] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::df));
  flagTable[e_sti] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::if_));
  flagTable[e_stosb] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_stosd] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_stosw] = flagInfo(list_of(x86::df), vector<Dyninst::MachRegister>());
  flagTable[e_sub] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_test] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_verr] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::zf));
  flagTable[e_verw] = flagInfo(vector<Dyninst::MachRegister>(), list_of(x86::zf));
  flagTable[e_xadd] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_xor] = flagInfo(vector<Dyninst::MachRegister>(), standardFlags);
  flagTable[e_scasb] = flagInfo(list_of(x86::df), standardFlags);
  flagTable[e_scasw] = flagInfo(list_of(x86::df), standardFlags);
  flagTable[e_scasd] = flagInfo(list_of(x86::df), standardFlags);
}

bool ia32_entry::flagsUsed(std::set<MachRegister>& flagsRead, std::set<MachRegister>& flagsWritten, ia32_locations* locs)
{
  dyn_hash_map<entryID, flagInfo>::const_iterator found = ia32_instruction::getFlagTable().find(getID(locs));
  if(found == ia32_instruction::getFlagTable().end())
  {
    return false;
  }
  // No entries for something that touches no flags, so always return true if we had an entry

  copy((found->second).readFlags.begin(), (found->second).readFlags.end(), inserter(flagsRead, flagsRead.begin()));
  copy((found->second).writtenFlags.begin(), (found->second).writtenFlags.end(), inserter(flagsWritten,flagsWritten.begin()));
  return true;
}



// Modded table entry for push/pop, daa, das, aaa, aas, insb/w/d, outsb/w/d, xchg, cbw
// les, lds, aam, aad, loop(z/nz), cmpxch, lss, mul, imul, div, idiv, cmpxch8, [ld/st]mxcsr
// clflush, prefetch*


// oneByteMap: one byte opcode map
static ia32_entry oneByteMap[256] = {
  /* 00 */
  { e_add,  t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
  { e_add,  t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_add,  t_done, 0, true, { Gb, Eb, Zz }, 0, s1RW2R },
  { e_add,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  { e_add,  t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
  { e_add,  t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
  { e_push, t_done, 0, false, { ES, eSP, Zz }, 0, s1R2RW }, // Semantics rewritten to ignore stack "operand"
  { e_pop,  t_done, 0, false, { ES, eSP, Zz }, 0, s1W2RW },
  /* 08 */
  { e_or,   t_done, 0, 
true, { Eb, Gb, Zz }, 0, s1RW2R },
  { e_or,   t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_or,   t_done, 0, true, { Gb, Eb, Zz }, 0, s1RW2R },
  { e_or,   t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  { e_or,   t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
  { e_or,   t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
  { e_push, t_done, 0, false, { CS, eSP, Zz }, 0, s1R2RW },
  { e_No_Entry,      t_twoB, 0, false, { Zz, Zz, Zz }, 0, 0 },
  /* 10 */
  { e_adc,  t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
  { e_adc,  t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_adc,  t_done, 0, true, { Gb, Eb, Zz }, 0, s1RW2R },
  { e_adc,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  { e_adc,  t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
  { e_adc,  t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
  { e_push, t_done, 0, false, { SS, eSP, Zz }, 0, s1R2RW },
  { e_pop,  t_done, 0, false, { SS, eSP, Zz }, 0, s1W2RW },
  /* 18 */
  { e_sbb,  t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
  { e_sbb,  t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_sbb,  t_done, 0, true, { Gb, Eb, Zz }, 0, s1RW2R },
  { e_sbb,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  { e_sbb,  t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
  { e_sbb,  t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
  { e_push, t_done, 0, false, { DS, eSP, Zz }, 0, s1R2RW },
  { e_pop , t_done, 0, false, { DS, eSP, Zz }, 0, s1W2RW },
  /* 20 */
  { e_and, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
  { e_and, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_and, t_done, 0, true, { Gb, Eb, Zz }, 0, s1RW2R },
  { e_and, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  { e_and, t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
  { e_and, t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
  { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 }, // PREFIX_SEG_OVR
  { e_daa, t_done, 0, false, { AL, Zz, Zz }, 0, s1RW },
  /* 28 */
  { e_sub, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
  { e_sub, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_sub, t_done, 0, true, { Gb, Eb, Zz }, 0, s1RW2R },
  { e_sub, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  { e_sub, t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
  { e_sub, t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
  { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 }, // PREFIX_SEG_OVR
  { e_das , t_done, 0, false, { AL, Zz, Zz }, 0, s1RW },
  /* 30 */
  { e_xor, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2R },
  { e_xor, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_xor, t_done, 0, true, { Gb, Eb, Zz }, 0, s1RW2R },
  { e_xor, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  { e_xor, t_done, 0, false, { AL, Ib, Zz }, 0, s1RW2R },
  { e_xor, t_done, 0, false, { eAX, Iz, Zz }, 0, s1RW2R },
  { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 }, // PREFIX_SEG_OVR
  { e_aaa, t_done, 0, false, { AX, Zz, Zz }, 0, s1RW },
  /* 38 */
  { e_cmp, t_done, 0, true, { Eb, Gb, Zz }, 0, s1R2R },
  { e_cmp, t_done, 0, true, { Ev, Gv, Zz }, 0, s1R2R },
  { e_cmp, t_done, 0, true, { Gb, Eb, Zz }, 0, s1R2R },
  { e_cmp, t_done, 0, true, { Gv, Ev, Zz }, 0, s1R2R },
  { e_cmp, t_done, 0, false, { AL, Ib, Zz }, 0, s1R2R },
  { e_cmp, t_done, 0, false, { eAX, Iz, Zz }, 0, s1R2R },
  { e_No_Entry,     t_ill,  0, false, { Zz, Zz, Zz }, 0, 0 }, // PREFIX_SEG_OVR
  { e_aas, t_done, 0, false, { AX, Zz, Zz }, 0, s1RW },
  /* 40 */
  { e_inc, t_done, 0, false, { eAX, Zz, Zz }, 0, s1RW },
  { e_inc, t_done, 0, false, { eCX, Zz, Zz }, 0, s1RW },
  { e_inc, t_done, 0, false, { eDX, Zz, Zz }, 0, s1RW },
  { e_inc, t_done, 0, false, { eBX, Zz, Zz }, 0, s1RW },
  { e_inc, t_done, 0, false, { eSP, Zz, Zz }, 0, s1RW },
  { e_inc, t_done, 0, false, { eBP, Zz, Zz }, 0, s1RW },
  { e_inc, t_done, 0, false, { eSI, Zz, Zz }, 0, s1RW },
  { e_inc, t_done, 0, false, { eDI, Zz, Zz }, 0, s1RW },
  /* 48 */
  { e_dec, t_done, 0, false, { eAX, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, false, { eCX, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, false, { eDX, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, false, { eBX, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, false, { eSP, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, false, { eBP, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, false, { eSI, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, false, { eDI, Zz, Zz }, 0, s1RW },
  /* 50 */
  { e_push, t_done, 0, false, { rAX, eSP, Zz }, 0, s1R2RW },
  { e_push, t_done, 0, false, { rCX, eSP, Zz }, 0, s1R2RW },
  { e_push, t_done, 0, false, { rDX, eSP, Zz }, 0, s1R2RW },
  { e_push, t_done, 0, false, { rBX, eSP, Zz }, 0, s1R2RW },
  { e_push, t_done, 0, false, { rSP, eSP, Zz }, 0, s1R2RW },
  { e_push, t_done, 0, false, { rBP, eSP, Zz }, 0, s1R2RW },
  { e_push, t_done, 0, false, { rSI, eSP, Zz }, 0, s1R2RW },
  { e_push, t_done, 0, false, { rDI, eSP, Zz }, 0, s1R2RW },
  /* 58 */
  { e_pop, t_done, 0, false, { rAX, eSP, Zz }, 0, s1W2RW },
  { e_pop, t_done, 0, false, { rCX, eSP, Zz }, 0, s1W2RW },
  { e_pop, t_done, 0, false, { rDX, eSP, Zz }, 0, s1W2RW },
  { e_pop, t_done, 0, false, { rBX, eSP, Zz }, 0, s1W2RW },
  { e_pop, t_done, 0, false, { rSP, eSP, Zz }, 0, s1W2RW },
  { e_pop, t_done, 0, false, { rBP, eSP, Zz }, 0, s1W2RW },
  { e_pop, t_done, 0, false, { rSI, eSP, Zz }, 0, s1W2RW },
  { e_pop, t_done, 0, false, { rDI, eSP, Zz }, 0, s1W2RW },
  /* 60 */
  { e_pushad, t_done, 0, false, { GPRS, eSP, Zz }, 0, s1R2RW },
  { e_popad,  t_done, 0, false, { GPRS, eSP, Zz }, 0, s1W2RW },
  { e_bound,    t_done, 0, true, { Gv, Ma, Zz }, 0, s1R2R },
  { e_arpl,     t_done, 0, true, { Ew, Gw, Zz }, 0, s1R2R },
  { e_No_Entry,          t_ill,  0, false, { Zz, Zz, Zz }, 0, 0 }, // PREFIX_SEG_OVR
  { e_No_Entry,          t_ill,  0, false, { Zz, Zz, Zz }, 0, 0 }, // PREFIX_SEG_OVR
  { e_No_Entry,   t_prefixedSSE, 2, false, { Zz, Zz, Zz }, 0, 0 }, /* operand size prefix (PREFIX_OPR_SZ)*/
  { e_No_Entry,          t_ill,  0, false, { Zz, Zz, Zz }, 0, 0 }, /* address size prefix (PREFIX_ADDR_SZ)*/
  /* 68 */
  { e_push,    t_done, 0, false, { Iz, eSP, Zz }, 0, s1R2RW },
  { e_imul,    t_done, 0, true, { Gv, Ev, Iz }, 0, s1W2R3R },
  { e_push,    t_done, 0, false, { Ib, eSP, Zz }, 0, s1R2RW },
  { e_imul,    t_done, 0, true, { Gv, Ev, Ib }, 0, s1W2R3R },
  { e_insb,    t_done, 0, false, { Yb, DX, Zz }, 0, s1W2R | (fREP << FPOS) }, // (e)SI/DI changed
  { e_insd,  t_done, 0, false, { Yv, DX, Zz }, 0, s1W2R | (fREP << FPOS) },
  { e_outsb,   t_done, 0, false, { DX, Xb, Zz }, 0, s1W2R | (fREP << FPOS) },
  { e_outsd, t_done, 0, false, { DX, Xv, Zz }, 0, s1W2R | (fREP << FPOS) },
  /* 70 */
  { e_jo,         t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jno,        t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jb_jnaej_j, t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jnb_jae_j,  t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jz,         t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jnz,        t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jbe,        t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jnbe,       t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  /* 78 */
  { e_js,   t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jns,  t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jp,   t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jnp,  t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jl,   t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jnl,  t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jle,  t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  { e_jnle, t_done, 0, false, { Jb, Zz, Zz }, (IS_JCC | REL_B), s1R },
  /* 80 */
  { e_No_Entry, t_grp, Grp1a, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_grp, Grp1b, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_grp, Grp1c, true, { Zz, Zz, Zz }, 0, 0 }, // book says Grp1 however;sandpile.org agrees.
  { e_No_Entry, t_grp, Grp1d, true, { Zz, Zz, Zz }, 0, 0 },
  { e_test, t_done, 0, true, { Eb, Gb, Zz }, 0, s1R2R },
  { e_test, t_done, 0, true, { Ev, Gv, Zz }, 0, s1R2R },
  { e_xchg, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2RW },
  { e_xchg, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2RW },
  /* 88 */
  { e_mov, t_done, 0, true, { Eb, Gb, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Ev, Gv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Gb, Eb, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Gv, Ev, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Ew, Sw, Zz }, 0, s1W2R },
  { e_lea, t_done, 0, true, { Gv, Mlea, Zz }, IS_NOP, s1W2R }, // this is just M in the book
                                                        // AFAICT the 2nd operand is not accessed
  { e_mov, t_done, 0, true, { Sw, Ew, Zz }, 0, s1W2R },
  { e_pop, t_done, 0, true, { Ev, eSP, Zz }, 0, s1W2RW },
  /* 90 */
  { e_nop,  t_done, 0, false, { Zz, Zz, Zz }, IS_NOP, sNONE }, // actually xchg eax,eax
  { e_xchg, t_done, 0, false, { eCX, eAX, Zz }, 0, s1RW2RW },
  { e_xchg, t_done, 0, false, { eDX, eAX, Zz }, 0, s1RW2RW },
  { e_xchg, t_done, 0, false, { eBX, eAX, Zz }, 0, s1RW2RW },
  { e_xchg, t_done, 0, false, { eSP, eAX, Zz }, 0, s1RW2RW },
  { e_xchg, t_done, 0, false, { eBP, eAX, Zz }, 0, s1RW2RW },
  { e_xchg, t_done, 0, false, { eSI, eAX, Zz }, 0, s1RW2RW },
  { e_xchg, t_done, 0, false, { eDI, eAX, Zz }, 0, s1RW2RW },
  /* 98 */
  { e_cwde, t_done, 0, false, { eAX, Zz, Zz }, 0, s1RW },
  { e_cdq,  t_done, 0, false, { eDX, eAX, Zz }, 0, s1W2R },
  { e_call,     t_done, 0, false, { Ap, Zz, Zz }, IS_CALL | PTR_WX, s1R },
  { e_wait,     t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_pushfd, t_done, 0, false, { Fv, eSP, Zz }, 0, s1R2RW },
  { e_popfd,  t_done, 0, false, { Fv, eSP, Zz }, 0, s1W2RW },
  { e_sahf,     t_done, 0, false, { Zz, Zz, Zz }, 0, 0 }, // FIXME Intel
  { e_lahf,     t_done, 0, false, { Zz, Zz, Zz }, 0, 0 }, // FIXME Intel
  /* A0 */
  { e_mov,   t_done, 0, false, { AL, Ob, Zz },  0, s1W2R },
  { e_mov,   t_done, 0, false, { eAX, Ov, Zz }, 0, s1W2R },
  { e_mov,   t_done, 0, false, { Ob, AL, Zz },  0, s1W2R },
  { e_mov,   t_done, 0, false, { Ov, eAX, Zz }, 0, s1W2R },
  // XXX: Xv is source, Yv is destination for movs, so they're swapped!
  { e_movsb, t_done, 0, false, { Yb, Xb, Zz },  0, s1W2R | (fREP << FPOS) }, // (e)SI/DI changed
  { e_movsd, t_done, 0, false, { Yv, Xv, Zz }, 0, s1W2R | (fREP << FPOS) },
  { e_cmpsb, t_done, 0, false, { Xb, Yb, Zz },  0, s1R2R | (fCMPS << FPOS) },
  { e_cmpsw, t_done, 0, false, { Xv, Yv, Zz },  0, s1R2R | (fCMPS << FPOS) },
  /* A8 */
  { e_test,     t_done, 0, false, { AL, Ib, Zz },  0, s1R2R },
  { e_test,     t_done, 0, false, { eAX, Iz, Zz }, 0, s1R2R },
  { e_stosb,    t_done, 0, false, { Yb, AL, Zz },  0, s1W2R | (fREP << FPOS) },
  { e_stosd,  t_done, 0, false, { Yv, eAX, Zz }, 0, s1W2R | (fREP << FPOS) },
  { e_lodsb,    t_done, 0, false, { AL, Xb, Zz },  0, s1W2R | (fREP << FPOS) },
  { e_lodsd,    t_done, 0, false, { eAX, Xv, Zz }, 0, s1W2R | (fREP << FPOS) },
  { e_scasb,    t_done, 0, false, { AL, Yb, Zz },  0, s1R2R | (fSCAS << FPOS) },
  { e_scasd,  t_done, 0, false, { eAX, Yv, Zz }, 0, s1R2R | (fSCAS << FPOS) },
  /* B0 */
  { e_mov, t_done, 0, false, { AL, Ib, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { CL, Ib, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { DL, Ib, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { BL, Ib, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { AH, Ib, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { CH, Ib, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { DH, Ib, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { BH, Ib, Zz }, 0, s1W2R },
  /* B8 */
  { e_mov, t_done, 0, false, { eAX, Iv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { eCX, Iv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { eDX, Iv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { eBX, Iv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { eSP, Iv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { eBP, Iv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { eSI, Iv, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, false, { eDI, Iv, Zz }, 0, s1W2R },
  /* C0 */
  { e_No_Entry, t_grp, Grp2, true, { Eb, Ib, Zz }, 0, s1RW2R },
  { e_No_Entry, t_grp, Grp2, true, { Ev, Ib, Zz }, 0, s1RW2R },
  { e_ret_near, t_done, 0, false, { Iw, Zz, Zz }, (IS_RET | IS_RETC), s1R | (fNEARRET << FPOS) },
  { e_ret_near, t_done, 0, false, { Zz, Zz, Zz }, (IS_RET), fNEARRET << FPOS },
  { e_les,      t_done, 0, true, { ES, Gv, Mp }, 0, s1W2W3R },
  { e_lds,      t_done, 0, true, { DS, Gv, Mp }, 0, s1W2W3R },
  { e_No_Entry, t_grp, Grp11, true, { Eb, Ib, Zz }, 0, s1W2R },
  { e_No_Entry, t_grp, Grp11, true, { Ev, Iz, Zz }, 0, s1W2R },
  /* C8 */
  { e_enter,   t_done, 0, false, { Iw, Ib, Zz }, 0, s1R2R | (fENTER << FPOS) },
  { e_leave,   t_done, 0, false, { Zz, Zz, Zz }, 0, fLEAVE << FPOS },
  { e_ret_far, t_done, 0, false, { Iw, Zz, Zz }, (IS_RETF | IS_RETC), s1R | (fFARRET << FPOS) },
  { e_ret_far, t_done, 0, false, { Zz, Zz, Zz }, (IS_RETF), fFARRET << FPOS },
  { e_int3,   t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_int,     t_done, 0, false, { Ib, Zz, Zz }, 0, s1R },
  { e_into,    t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_iret,    t_done, 0, false, { Zz, Zz, Zz }, (IS_RET), fIRET << FPOS},
  /* D0 */
  { e_No_Entry, t_grp, Grp2, true, { Eb, ImplImm, Zz }, 0, s1RW2R }, // const1
  { e_No_Entry, t_grp, Grp2, true, { Ev, ImplImm, Zz }, 0, s1RW2R }, // --"--
  { e_No_Entry, t_grp, Grp2, true, { Eb, CL, Zz }, 0, s1RW2R },
  { e_No_Entry, t_grp, Grp2, true, { Ev, CL, Zz }, 0, s1RW2R },
  { e_aam,  t_done, 0, false, { AX, Ib, Zz }, 0, s1RW2R },
  { e_aad,  t_done, 0, false, { AX, Ib, Zz }, 0, s1RW2R },
  { e_salc, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE }, // undocumeted
  { e_xlat, t_done, 0, false, { Zz, Zz, Zz }, 0, fXLAT << FPOS }, // scream
  /* D8 */
  { e_No_Entry, t_coprocEsc, GrpD8, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_coprocEsc, GrpD9, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_coprocEsc, GrpDA, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_coprocEsc, GrpDB, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_coprocEsc, GrpDC, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_coprocEsc, GrpDD, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_coprocEsc, GrpDE, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_coprocEsc, GrpDF, true, { Zz, Zz, Zz }, 0, 0 },
  /* E0 */
  { e_loopn,    t_done, 0, false, { Jb, eCX, Zz }, (IS_JCC | REL_B), s1R2R }, 
  { e_loope,    t_done, 0, false, { Jb, eCX, Zz }, (IS_JCC | REL_B), s1R2R },
  { e_loop,     t_done, 0, false, { Jb, eCX, Zz }, (IS_JCC | REL_B), s1R2R },
  { e_jcxz_jec, t_done, 0, false, { Jb, eCX, Zz }, (IS_JCC | REL_B), s1R2R },
  { e_in,       t_done, 0, false, { AL, Ib, Zz }, 0, s1W2R | (fIO << FPOS) },
  { e_in,       t_done, 0, false, { eAX, Ib, Zz }, 0, s1W2R | (fIO << FPOS) },
  { e_out,      t_done, 0, false, { Ib, AL, Zz }, 0, s1W2R | (fIO << FPOS) },
  { e_out,      t_done, 0, false, { Ib, eAX, Zz }, 0, s1W2R | (fIO << FPOS) },
  /* E8 */
  { e_call, t_done, 0, false, { Jz, Zz, Zz }, (IS_CALL | REL_X), s1R | (fCALL << FPOS) },
  { e_jmp,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JUMP | REL_X), s1R },
  { e_jmp,  t_done, 0, false, { Ap, Zz, Zz }, (IS_JUMP | PTR_WX), s1R },
  { e_jmp,  t_done, 0, false, { Jb, Zz, Zz }, (IS_JUMP | REL_B), s1R },
  { e_in,   t_done, 0, false, { AL, DX, Zz }, 0, s1W2R | (fIO << FPOS) },
  { e_in,   t_done, 0, false, { eAX, DX, Zz }, 0, s1W2R | (fIO << FPOS) },
  { e_out,  t_done, 0, false, { DX, AL, Zz }, 0, s1W2R | (fIO << FPOS) },
  { e_out,  t_done, 0, false, { DX, eAX, Zz }, 0, s1W2R | (fIO << FPOS) },
  /* F0 */
  { e_No_Entry,      t_ill,  0, false, { Zz, Zz, Zz }, 0, 0 }, // PREFIX_INSTR
  { e_int1, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE }, // undocumented
  { e_No_Entry, t_prefixedSSE, 3, false, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_prefixedSSE, 1, false, { Zz, Zz, Zz }, 0, 0 },
  { e_hlt,  t_done, 0, false, { Zz, Zz, Zz }, PRVLGD, sNONE },
  { e_cmc,  t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_No_Entry, t_grp, Grp3a, true, { Zz, Zz, Zz }, 0, sNONE },
  { e_No_Entry, t_grp, Grp3b, true, { Zz, Zz, Zz }, 0, sNONE },
  /* F8 */
  { e_clc, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_stc, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_cli, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_sti, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_cld, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_std, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_No_Entry, t_grp, Grp4, true, { Zz, Zz, Zz }, 0, sNONE },
  { e_No_Entry, t_grp, Grp5, true, { Zz, Zz, Zz }, 0, sNONE }
};


// twoByteMap: two byte opcode instructions (first byte is 0x0F)
static ia32_entry twoByteMap[256] = {
  /* 00 */
  // Syscall/sysret are somewhat hacked
  // Syscall on amd64 will also read CS/SS for where to call in 32-bit mode
  { e_No_Entry, t_grp, Grp6, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_grp, Grp7, false, { Zz, Zz, Zz }, 0, 0 },
  { e_lar,        t_done, 0, true, { Gv, Ew, Zz }, 0, s1W2R | (fSEGDESC << FPOS) },
  { e_lsl,        t_done, 0, true, { Gv, Ew, Zz }, 0, s1W2R | (fSEGDESC << FPOS) },
  { e_No_Entry,    t_ill, 0, false, { Zz, Zz, Zz }, 0, 0},
  { e_syscall,    t_done, 0, false, { eCX, Zz, Zz }, 0, s1W }, // AMD: writes return address to eCX; for liveness, treat as hammering all
  { e_clts,       t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_sysret,     t_done, 0, false, { eCX, Zz, Zz }, 0, s1R }, // AMD; reads return address from eCX; unlikely to occur in Dyninst use cases but we'll be paranoid
  /* 08 */
  { e_invd,   t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE }, // only in priviledge 0, so ignored
  { e_wbinvd, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE }, // idem
  { e_No_Entry,        t_ill,  0, false, { Zz, Zz, Zz }, 0, 0 },
  { e_ud2,    t_ill,  0, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry,        t_ill,  0, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_prefetch_w, t_grp, GrpAMD, true, { Zz, Zz, Zz }, 0, 0 },    // AMD prefetch group
  { e_femms,       t_done,  0, false, { Zz, Zz, Zz }, 0, sNONE },  // AMD specific
  // semantic is bogus for the 1st operand - but correct for the 2nd,
  // which is the only one that can be a memory operand :)
  // fixing the 1st operand requires an extra table for the 3dnow instructions...
  { e_No_Entry,             t_3dnow, 0, true,  { Pq, Qq, Zz }, 0, s1RW2R }, // AMD 3DNow! suffixes
  /* 10 */
  { e_No_Entry, t_sse, SSE10, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE11, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE12, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE13, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE14, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE15, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE16, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE17, true, { Zz, Zz, Zz }, 0, 0 },
  /* 18 */
  { e_No_Entry, t_grp, Grp16, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_nop, t_done, 0, true, { Ev, Zz, Zz }, IS_NOP, 0 }, // 19-1F according to sandpile and AMD are NOPs with an Ev operand
  { e_nop, t_done, 0, true, { Ev, Zz, Zz }, IS_NOP, 0 }, // Can we go out on a limb that the 'operand' of a NOP is never read?
  { e_nop, t_done, 0, true, { Ev, Zz, Zz }, IS_NOP, 0 }, // I think we can...so nullary operand semantics, but consume the
  { e_nop, t_done, 0, true, { Ev, Zz, Zz }, IS_NOP, 0 }, // mod/rm byte operand.
  { e_nop, t_done, 0, true, { Ev, Zz, Zz }, IS_NOP, 0 }, // -- BW 1/08
  { e_nop, t_done, 0, true, { Ev, Zz, Zz }, IS_NOP, 0 },
  { e_nop, t_done, 0, true, { Ev, Zz, Zz }, IS_NOP, 0 },
  /* 20 */
  { e_mov, t_done, 0, true, { Rd, Cd, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Rd, Dd, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Cd, Rd, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Dd, Rd, Zz }, 0, s1W2R },
  { e_mov, t_done, 0, true, { Rd, Td, Zz }, 0, s1W2R }, // actually a SSE5A
  { e_No_Entry,     t_ill,  0, 0, { Zz, Zz, Zz }, 0, 0 }, // SSE5A
  { e_mov, t_done, 0, true, { Td, Rd, Zz }, 0, s1W2R },
  { e_No_Entry,     t_ill,  0, 0, { Zz, Zz, Zz }, 0, 0 },
  /* 28 */
  { e_No_Entry, t_sse, SSE28, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE29, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE2A, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE2B, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE2C, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE2D, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE2E, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE2F, true, { Zz, Zz, Zz }, 0, 0 },
  /* 30 */
  { e_wrmsr, t_done, 0, false, { rAX, rDX, rCX }, 0, s1R2R3R },
  { e_rdtsc, t_done, 0, false, { rAX, rDX, Zz }, 0, s1W2W3R },
  { e_rdmsr, t_done, 0, false, { rAX, rDX, rCX }, 0, s1W2W3R },
  { e_rdpmc, t_done, 0, false, { rAX, rDX, rCX }, 0, s1W2W3R },
  { e_sysenter, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE }, // XXX: fixme for kernel work
  { e_sysexit,  t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE }, // XXX: fixme for kernel work
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0, 0 }, 
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  /* 38 */
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0 ,0 },
  /* 40 */
  { e_cmovo,   t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovno,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovnae, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovnb,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmove,   t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovne,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovbe,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovnbe, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  /* 48 */
  { e_cmovs,   t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovns,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovpe,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovpo,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovnge, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovnl,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovng,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  { e_cmovnl,  t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R | (fCOND << FPOS) },
  /* 50 */
  { e_No_Entry, t_sse, SSE50, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE51, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE52, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE53, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE54, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE55, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE56, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE57, true, { Zz, Zz, Zz }, 0, 0 },
  /* 58 */
  { e_No_Entry, t_sse, SSE58, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE59, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE5A, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE5B, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE5C, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE5D, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE5E, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE5F, true, { Zz, Zz, Zz }, 0, 0 },
  /* 60 */
  { e_No_Entry, t_sse, SSE60, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE61, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE62, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE63, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE64, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE65, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE66, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE67, true, { Zz, Zz, Zz }, 0, 0 },
  /* 68 */
  { e_No_Entry, t_sse, SSE68, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE69, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE6A, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE6B, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE6C, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE6D, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE6E, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE6F, true, { Zz, Zz, Zz }, 0, 0 },
  /* 70 */
  { e_No_Entry, t_sse, SSE70, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_grp, Grp12, false, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_grp, Grp13, false, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_grp, Grp14, false, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE74, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE75, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE76, true, { Zz, Zz, Zz }, 0, 0 },
  { e_emms, t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  /* 78 */
  { e_No_Entry, t_sse, SSE78, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE79, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0, 0 }, // SSE5A will go in 7A and 7B when it comes out
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE7C, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE7D, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE7E, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSE7F, 0, { Zz, Zz, Zz }, 0, 0 },
  /* 80 */
  { e_jo,   t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jno,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jb,   t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jnb,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jz,   t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jnz,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jbe,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jnbe, t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  /* 88 */
  { e_js,   t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jns,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jp,   t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jnp,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jl,   t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jnl,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jle,  t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  { e_jnle, t_done, 0, false, { Jz, Zz, Zz }, (IS_JCC | REL_X), s1R | (fCOND << FPOS) },
  /* 90 */
  { e_seto,   t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setno,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setb,   t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setnb,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setz,   t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setnz,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setbe,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setnbe, t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  /* 98 */
  { e_sets,   t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setns,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setp,   t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setnp,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setl,   t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setnl,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setle,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  { e_setnle, t_done, 0, true, { Eb, Zz, Zz }, 0, s1W | (fCOND << FPOS) },
  /* A0 */
  { e_push,   t_done, 0, false, { FS, eSP, Zz }, 0, s1R2RW },
  { e_pop,    t_done, 0, false, { FS, eSP, Zz }, 0, s1W2RW },
  { e_cpuid,  t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_bt,     t_done, 0, true, { Ev, Gv, Zz }, 0, s1R2R },
  { e_shld,   t_done, 0, true, { Ev, Gv, Ib }, 0, s1RW2R3R },
  { e_shld,   t_done, 0, true, { Ev, Gv, CL }, 0, s1RW2R3R },
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0, 0 }, 
  { e_No_Entry, t_ill, 0, 0, { Zz, Zz, Zz }, 0, 0 },
  /* A8 */
  { e_push, t_done, 0, false, { GS, eSP, Zz }, 0, s1R2RW },
  { e_pop,  t_done, 0, false, { GS, eSP, Zz }, 0, s1W2RW },
  { e_rsm,  t_done, 0, false, { Zz, Zz, Zz }, 0, sNONE },
  { e_bts,  t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_shrd, t_done, 0, true, { Ev, Gv, Ib }, 0, s1RW2R3R },
  { e_shrd, t_done, 0, true, { Ev, Gv, CL }, 0, s1RW2R3R },
  { e_No_Entry, t_grp, Grp15, 0, { Zz, Zz, Zz }, 0, 0 }, 
  { e_imul, t_done, 0, true, { Gv, Ev, Zz }, 0, s1RW2R },
  /* B0 */
  // Assuming this is used with LOCK prefix, the destination gets a write anyway
  // This is not the case without lock prefix, but I ignore that case
  // Also, given that the 3rd operand is a register I ignore that it may be written
  { e_cmpxch, t_done, 0, true, { Eb, Gb, AL }, 0, s1RW2R3R | (fCMPXCH << FPOS) },
  { e_cmpxch, t_done, 0, true, { Ev, Gv, eAX }, 0, s1RW2R3R | (fCMPXCH << FPOS) },
  { e_lss, t_done, 0, true, { SS, Gv, Mp }, 0, s1W2W3R },
  { e_btr, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_lfs, t_done, 0, true, { FS, Gv, Mp }, 0, s1W2W3R },
  { e_lgs, t_done, 0, true, { GS, Gv, Mp }, 0, s1W2W3R },
  { e_movzx, t_done, 0, true, { Gv, Eb, Zz }, 0, s1W2R },
  { e_movzx, t_done, 0, true, { Gv, Ew, Zz }, 0, s1W2R },
  /* B8 */
  { e_No_Entry, t_sse, SSEB8, 0, { Zz, Zz, Zz }, 0, 0 },
  { e_ud2grp10, t_ill, 0, 0, { Zz, Zz, Zz }, 0, sNONE },
  { e_No_Entry, t_grp, Grp8, true, { Zz, Zz, Zz }, 0, 0 },
  { e_btc, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2R },
  { e_bsf, t_done, 0, true, { Gv, Ev, Zz }, 0, s1W2R },
  { e_bsr, t_done, 0, true, { Gv, Ev, Zz }, 0, s1W2R },
  { e_movsx, t_done, 0, true, { Gv, Eb, Zz }, 0, s1W2R },
  { e_movsx, t_done, 0, true, { Gv, Ew, Zz }, 0, s1W2R },
  /* C0 */
  { e_xadd, t_done, 0, true, { Eb, Gb, Zz }, 0, s1RW2RW },
  { e_xadd, t_done, 0, true, { Ev, Gv, Zz }, 0, s1RW2RW },
  { e_No_Entry, t_sse, SSEC2, true, { Zz, Zz, Zz }, 0, 0 },
  { e_movnti , t_done, 0, true, { Ev, Gv, Zz }, 0, s1W2R | (fNT << FPOS) },
  { e_No_Entry, t_sse, SSEC4, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEC5, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEC6, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_grp, Grp9,  true, { Zz, Zz, Zz }, 0, 0 },
  /* C8 */
  { e_bswap, t_done, 0, false, { EAX, Zz, Zz }, 0, s1RW }, 
  { e_bswap, t_done, 0, false, { ECX, Zz, Zz }, 0, s1RW },
  { e_bswap, t_done, 0, false, { EDX, Zz, Zz }, 0, s1RW }, 
  { e_bswap, t_done, 0, false, { EBX, Zz, Zz }, 0, s1RW }, 
  { e_bswap, t_done, 0, false, { ESP, Zz, Zz }, 0, s1RW },
  { e_bswap, t_done, 0, false, { EBP, Zz, Zz }, 0, s1RW }, 
  { e_bswap, t_done, 0, false, { ESI, Zz, Zz }, 0, s1RW }, 
  { e_bswap, t_done, 0, false, { EDI, Zz, Zz }, 0, s1RW }, 
  /* D0 */
  { e_No_Entry, t_sse, SSED0, false, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED1, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED2, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED3, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED4, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED5, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED6, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED7, true, { Zz, Zz, Zz }, 0, 0 },
  /* D8 */
  { e_No_Entry, t_sse, SSED8, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSED9, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEDA, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEDB, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEDC, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEDD, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEDE, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEDF, true, { Zz, Zz, Zz }, 0, 0 },
  /* E0 */
  { e_No_Entry, t_sse, SSEE0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE1, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE2, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE3, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE4, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE5, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE6, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE7, true, { Zz, Zz, Zz }, 0, 0 },
  /* E8 */
  { e_No_Entry, t_sse, SSEE8, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEE9, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEEA, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEEB, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEEC, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEED, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEEE, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEEF, true, { Zz, Zz, Zz }, 0, 0 },
  /* F0 */
  { e_No_Entry, t_sse, SSEF0, false, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF1, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF2, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF3, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF4, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF5, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF6, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF7, true, { Zz, Zz, Zz }, 0, 0 },
  /* F8 */
  { e_No_Entry, t_sse, SSEF8, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEF9, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEFA, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEFB, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEFC, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEFD, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEFE, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_sse, SSEFF, false, { Zz, Zz, Zz }, 0, 0 }
};

static ia32_entry fpuMap[][2][8] = {
{
    { // D8
        { e_fadd,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fmul,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcom,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcomp, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }, // stack pop
        { e_fsub,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fsubr, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fdiv,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fdivr, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }
    },
    { // D8 -- IMPORTANT NOTE: the C0-FF tables in the book are interleaved from how they
        // need to appear here (and for all FPU insns).  i.e. book rows 0, 4, 1, 5, 2, 6, 3, 7 are table rows
        // 0, 1, 2, 3, 4, 5, 6, 7.
        { e_fadd,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fmul,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcom,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcomp, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }, // stack pop
        { e_fsub,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fsubr, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fdiv,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fdivr, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }
    },
},
{
    { // D9 
        { e_fld,    t_done, 0, true, { ST0, Ef, Zz }, 0, s1W2R }, // stack push
        { e_fnop,   t_done, 0, true, { Zz,  Zz, Zz }, 0, sNONE },
        { e_fst,    t_done, 0, true, { Ef, ST0, Zz }, 0, s1W2R },
        { e_fstp,   t_done, 0, true, { Ef, ST0, Zz }, 0, s1W2R }, // stack pop
        { e_fldenv, t_done, 0, true, { M14, Zz, Zz }, 0, s1R },
        { e_fldcw,  t_done, 0, true, { Ew,  Zz, Zz }, 0, s1R },
        { e_fstenv, t_done, 0, true, { M14, Zz, Zz }, 0, s1W },
        { e_fstcw,  t_done, 0, true, { Ew,  Zz, Zz }, 0, s1W }
    },
    { // D9 
        { e_fld,    t_done, 0, true, { ST0, Ef, Zz }, 0, s1W2R }, // stack push
        { e_fxch, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2RW },
        { e_fnop,   t_done, 0, true, { Zz,  Zz, Zz }, 0, sNONE },
        { e_No_Entry,  t_done, 0, true, { Zz,  Zz, Zz }, 0, sNONE },
        { e_fchs,    t_done, 0, true, { ST0, Zz, Zz }, 0, s1RW }, // FIXME: using first of group as placeholder
        { e_fld1, t_done, 0, true, { ST0, Zz, Zz }, 0, s1RW }, // FIXME: using first of group
        { e_f2xm1,   t_done, 0, true, { ST0, ST1, Zz }, 0, s1RW2R }, // FIXME: using first of group as placeholder
        { e_fprem,  t_done, 0, true, { ST0, ST1, Zz }, 0, s1RW2R } // FIXME: using first of group
    },
},
{
    { // DA 
        { e_fiadd,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fimul,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_ficom,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_ficomp, t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R }, // stack pop
        { e_fisub,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fisubr, t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fidiv,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fidivr, t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R }
    },
    { // DA
        { e_fcmovb,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcmove,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcmovbe, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcmovu, t_done, 0, true,  { ST0, Ef, Zz }, 0, s1RW2R },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_fucompp,  t_done, 0, true, { ST0, ST1, Zz }, 0, s1RW2RW }, // double pop
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
    },
},
{
    { // DB 
      { e_fild,   t_done, 0, true, { ST0, Ev, Zz }, 0, s1W2R },
      { e_fisttp, t_done, 0, true, { Ev, ST0, Zz }, 0, s1W2R }, //stack pop
      { e_fist,   t_done, 0, true, { Ev, ST0, Zz }, 0, s1W2R },
      { e_fistp,  t_done, 0, true, { Ev, ST0, Zz }, 0, s1W2R }, // stack pop
      { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
      { e_fld,    t_done, 0, true, { ST0, Ef, Zz }, 0, s1W2R },
      { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
      { e_fstp,   t_done, 0, true, { Ef, ST0, Zz }, 0, s1W2R }
    },
    { // DB
        { e_fcmovnb,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcmovne,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcmovnbe, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcmovnu,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE }, // FIXME: needs FCLEX and FINIT in group
        { e_fucomi,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fcomi,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
    },
},
{
    { // DC
        { e_fadd,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fmul,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fcom,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fcomp, t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R }, // stack pop
        { e_fsub,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fsubr, t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fdiv,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fdivr, t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R }
    },
    { // DC
        { e_fadd,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fmul,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_fsubr,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fsub,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fdivr,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_fdiv,  t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
    },
},
{
    { // DD TODO semantics check
        { e_fld,    t_done, 0, true, { ST0, Efd, Zz }, 0, s1W2R },
        { e_fisttp, t_done, 0, true, { Mq, ST0, Zz }, 0, s1W2R },
        { e_fst,    t_done, 0, true, { Efd, ST0, Zz }, 0, s1W2R },
        { e_fstp,   t_done, 0, true, { Efd, ST0, Zz }, 0, s1W2R }, // stack pop
        { e_frstor, t_done, 0, true, { M512, Zz, Zz }, 0, s1R },
        { e_fucomp, t_done, 0, true, { ST0, Efd, Zz }, 0, s1R2R }, // stack pop
        { e_fsave,  t_done, 0, true, { M512, Zz, Zz }, 0, s1W },
        { e_fstsw,  t_done, 0, true, { Ew, Zz, Zz }, 0, s1W }
    },
    { // DD TODO semantics check
        { e_ffree,    t_done, 0, true, { Efd, Zz, Zz }, 0, s1W },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_fst, t_done, 0, true, { Efd, ST0, Zz }, 0, s1W2R },
        { e_fstp, t_done, 0, true, { Efd, ST0, Zz }, 0, s1W2RW },
        { e_fucom,    t_done, 0, true, { ST0, Efd, Zz }, 0, s1R2R },
        { e_fucomp,    t_done, 0, true, { ST0, Efd, Zz }, 0, s1RW2R },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
    },
},
{    
    { // DE 
        { e_fiadd,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fimul,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_ficom,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_ficomp, t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R }, // stack pop
        { e_fisub,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fisubr, t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fidiv,  t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R },
        { e_fidivr, t_done, 0, true, { ST0, Ev, Zz }, 0, s1RW2R }
    },
    { // DE
        { e_faddp,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fmulp,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_fcompp, t_done, 0, true, { ST0, ST1, Zz }, 0, s1RW2R },
        { e_fsubrp,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fsubp,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R },
        { e_fdivrp, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }, // stack pop
        { e_fdivp, t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }
    },
},
{
    { // DF TODO semantics/operand sizes
        { e_fild,   t_done, 0, true, { ST0, Ew, Zz }, 0, s1W2R },
        { e_fisttp, t_done, 0, true, { Ew, ST0, Zz }, 0, s1W2R },
        { e_fist,   t_done, 0, true, { Ew, ST0, Zz }, 0, s1W2R },
        { e_fistp,  t_done, 0, true, { Ew, ST0, Zz }, 0, s1W2R }, // stack pop
        { e_fbld,   t_done, 0, true, { ST0, Mq, Zz }, 0, s1W2R }, // BCD 80 bit
        { e_fild,   t_done, 0, true, { ST0, Ev, Zz }, 0, s1W2R },
        { e_fbstp,  t_done, 0, true, { Mq, ST0, Zz }, 0, s1RW2R },// BCD 80 bit
        { e_fistp,  t_done, 0, true, { Ev, ST0, Zz }, 0, s1W2R }
    },
    { // DF TODO semantics/operand sizes
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
        { e_fstsw,   t_done, 0, true, { AX, Zz, Zz }, 0, s1W },
        { e_fucomip,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }, // stack pop
        { e_fcomip,  t_done, 0, true, { ST0, Ef, Zz }, 0, s1RW2R }, // stack pop
        { e_No_Entry,  t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
    }
}
};

static ia32_entry groupMap[][8] = {
  { /* group 1a */
    { e_add, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_or,  t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_adc, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_sbb, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_and, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_sub, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_xor, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_cmp, t_done, 0, true, { Eb, Ib, Zz }, 0, s1R2R },
  },
  { /* group 1b */
    { e_add, t_done, 0, true, { Ev, Iz, Zz }, 0, s1RW2R },
    { e_or,  t_done, 0, true, { Ev, Iz, Zz }, 0, s1RW2R },
    { e_adc, t_done, 0, true, { Ev, Iz, Zz }, 0, s1RW2R },
    { e_sbb, t_done, 0, true, { Ev, Iz, Zz }, 0, s1RW2R },
    { e_and, t_done, 0, true, { Ev, Iz, Zz }, 0, s1RW2R },
    { e_sub, t_done, 0, true, { Ev, Iz, Zz }, 0, s1RW2R },
    { e_xor, t_done, 0, true, { Ev, Iz, Zz }, 0, s1RW2R },
    { e_cmp, t_done, 0, true, { Ev, Iz, Zz }, 0, s1R2R },
  },
  { /* group 1c */
    { e_add, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_or,  t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_adc, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_sbb, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_and, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_sub, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_xor, t_done, 0, true, { Eb, Ib, Zz }, 0, s1RW2R },
    { e_cmp, t_done, 0, true, { Eb, Ib, Zz }, 0, s1R2R },
  },
  { /* group 1d */
    { e_add, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
    { e_or,  t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
    { e_adc, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
    { e_sbb, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
    { e_and, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
    { e_sub, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
    { e_xor, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
    { e_cmp, t_done, 0, true, { Ev, Ib, Zz }, 0, s1R2R },
  },


 {  /* group 2 - only opcode is defined here, 
       operands are defined in the one or two byte maps above */
  { e_rol, t_done, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_ror, t_done, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_rcl, t_done, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_rcr, t_done, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_shl_sal, t_done, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_shr, t_done, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_sar, t_done, 0, true, { Zz, Zz, Zz }, 0, 0 }
 },

 { /* group 3a - operands are defined here */
  { e_test, t_done, 0, true, { Eb, Ib, Zz }, 0, s1R2R },
  { e_test, t_done, 0, true, { Eb, Ib, Zz }, 0, s1R2R }, // book swears this is illegal, sandpile claims it's an aliased TEST
  { e_not,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1RW },
  { e_neg,  t_done, 0, true, { Eb, Zz, Zz }, 0, s1RW },
  { e_mul,  t_done, 0, true, { AX, AL, Eb }, 0, s1W2RW3R },
  { e_imul, t_done, 0, true, { AX, AL, Eb }, 0, s1W2R3R },
  { e_div,  t_done, 0, true, { AX, AL, Eb }, 0, s1RW2R3R },
  { e_idiv, t_done, 0, true, { AX, AL, Eb }, 0, s1W2R3R }
 },

 { /* group 3b - operands are defined here */
  { e_test, t_done, 0, true, { Ev, Iz, Zz }, 0, s1R2R },
  { e_test, t_done, 0, true, { Ev, Iz, Zz }, 0, s1R2R }, // book swears this is illegal, sandpile claims it's an aliased TEST
  { e_not,  t_done, 0, true, { Ev, Zz, Zz }, 0, s1RW },
  { e_neg,  t_done, 0, true, { Ev, Zz, Zz }, 0, s1RW },
  { e_mul,  t_done, 0, true, { eDX, eAX, Ev }, 0, s1W2RW3R },
  { e_imul, t_done, 0, true, { eDX, eAX, Ev }, 0, s1W2RW3R },
  { e_div,  t_done, 0, true, { eDX, eAX, Ev }, 0, s1RW2RW3R },
  { e_idiv, t_done, 0, true, { eDX, eAX, Ev }, 0, s1RW2RW3R }
 },

 { /* group 4 - operands are defined here */
  { e_inc, t_done, 0, true, { Eb, Zz, Zz }, 0, s1RW },
  { e_dec, t_done, 0, true, { Eb, Zz, Zz }, 0, s1RW },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
 },

 { /* group 5 - operands are defined here */
  { e_inc,  t_done, 0, true, { Ev, Zz, Zz }, 0, s1RW },
  { e_dec,  t_done, 0, true, { Ev, Zz, Zz }, 0, s1RW },
  { e_call, t_done, 0, true, { Ev, Zz, Zz }, (IS_CALL | INDIR), s1R | (fINDIRCALL << FPOS) },
  { e_call, t_done, 0, true, { Ep, Zz, Zz }, (IS_CALL | INDIR), s1R | (fINDIRCALL << FPOS) },
  { e_jmp,  t_done, 0, true, { Ev, Zz, Zz }, (IS_JUMP | INDIR), s1R | (fINDIRJUMP << FPOS) },
  { e_jmp,  t_done, 0, true, { Ep, Zz, Zz }, (IS_JUMP | INDIR), s1R | (fINDIRJUMP << FPOS) },
  { e_push, t_done, 0, true, { Ev, eSP, Zz }, 0, s1R2RW },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
 },

 { /* group 6 - operands are defined here */
   // these need to be fixed for kernel mode accesses
  { e_sldt, t_done, 0, true, { Ew, Zz, Zz }, 0, s1W },
  { e_str,  t_done, 0, true, { Ew, Zz, Zz }, 0, s1W },
  { e_lldt, t_done, 0, true, { Ew, Zz, Zz }, 0, s1R },
  { e_ltr,  t_done, 0, true, { Ew, Zz, Zz }, 0, s1R },
  { e_verr, t_done, 0, true, { Ew, Zz, Zz }, 0, s1R },
  { e_verw, t_done, 0, true, { Ew, Zz, Zz }, 0, s1R },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
 },

 { /* group 7 - operands are defined here */
   // idem
  { e_sgdt, t_done, 0, true, { Ms, Zz, Zz }, 0, s1W },
  { e_sidt, t_done, 0, true, { Ms, Zz, Zz }, 0, s1W },
  { e_lgdt, t_done, 0, true, { Ms, Zz, Zz }, 0, s1R },
  { e_lidt, t_done, 0, true, { Ms, Zz, Zz }, 0, s1R },
  { e_smsw, t_done, 0, true, { Ew, Zz, Zz }, 0, s1W },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_lmsw, t_done, 0, true, { Ew, Zz, Zz }, 0, s1R },
  { e_invlpg, t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE }, // 64-bit: swapgs also uses this encoding (w/ mod=11)
 },

 { /* group 8 - only opcode is defined here, 
     operands are defined in the one or two byte maps below */
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_bt,  t_done, 0, true, { Ev, Ib, Zz }, 0, s1R2R },
  { e_bts, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
  { e_btr, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
  { e_btc, t_done, 0, true, { Ev, Ib, Zz }, 0, s1RW2R },
 },

 { /* group 9 - operands are defined here */
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  // see comments for cmpxch
  { e_cmpxch8b, t_done, 0, true, { EDXEAX, Mq, ECXEBX }, 0, s1RW2RW3R | (fCMPXCH8 << FPOS) },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
  { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 }
 },

 /* group 10 is all illegal */

 { /* group 11, opcodes defined in one byte map */
   { e_mov, t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
   { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
   { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
   { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
   { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
   { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
   { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
   { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
 }

};


// Groups 12-16 are split by mod={mem,11}. Some spill over into SSE groups!
// Notation: G12SSE010B = group 12, SSE, reg=010; B means mod=11
// Use A if Intel decides to put SSE instructions for mod=mem
static ia32_entry groupMap2[][2][8] = {
  { /* group 12 */
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    },
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G12SSE010B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G12SSE100B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G12SSE110B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    }
  },
  { /* group 13 */
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    },
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G13SSE010B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G13SSE100B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G13SSE110B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    }
  },
  { /* group 14 */
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    },
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G14SSE010B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G14SSE011B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G14SSE110B, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_grpsse, G14SSE111B, true, { Zz, Zz, Zz }, 0, 0 },
    }
  },
  { /* group 15 */
    {
      { e_fxsave,  t_done, 0, true, { M512, Zz, Zz }, 0, s1W | (fFXSAVE << FPOS) },
      { e_fxrstor, t_done, 0, true, { M512, Zz, Zz }, 0, s1R | (fFXRSTOR << FPOS) },
      { e_ldmxcsr, t_done, 0, true, { Md, Zz, Zz }, 0, s1R },
      { e_stmxcsr, t_done, 0, true, { Md, Zz, Zz }, 0, s1W },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_clflush, t_done, 0, true, { Mb, Zz, Zz }, 0, s1W | (fCLFLUSH << FPOS) },
    },
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_lfence, t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
      { e_mfence, t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
      { e_sfence, t_done, 0, true, { Zz, Zz, Zz }, 0, sNONE },
    }
  },
  { /* group 16 */
    {
      { e_prefetchNTA, t_done, 0, true, { Mb, Zz, Zz }, 0, s1R | (fPREFETCHNT << FPOS) },
      { e_prefetchT0,  t_done, 0, true, { Mb, Zz, Zz }, 0, s1R | (fPREFETCHT0 << FPOS) },
      { e_prefetchT1,  t_done, 0, true, { Mb, Zz, Zz }, 0, s1R | (fPREFETCHT1 << FPOS) },
      { e_prefetchT2,  t_done, 0, true, { Mb, Zz, Zz }, 0, s1R | (fPREFETCHT1 << FPOS) },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    },
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    }
  },
  { /* group 17 */
    {
      { e_extrq, t_done, 0, true, { Vdq, Ib, Ib }, 0, s1RW2R3R },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    },
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    }
  },
  { /* AMD prefetch group */
    {
      { e_prefetch,   t_done, 0, true, { Mb, Zz, Zz }, 0, s1R | (fPREFETCHAMDE << FPOS) },
      { e_prefetchw,  t_done, 0, true, { Mb, Zz, Zz }, 0, s1R | (fPREFETCHAMDW << FPOS) },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 }, // this is reserved, not illegal, ugh...
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 }, // this is reserved, not illegal, ugh...
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 }, // this is reserved, not illegal, ugh...
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 }, // this is reserved, not illegal, ugh...
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 }, // this is reserved, not illegal, ugh...
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 }, // this is reserved, not illegal, ugh...
    },
    {
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
      { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    }
  }


};

/* rows are not, F3, 66, F2 prefixed in this order (see book) */
static ia32_entry sseMap[][4] = {
  { /* SSE10 */
    { e_movups, t_done, 0, true, { Vps, Wps, Zz }, 0, s1W2R },
    { e_movss,  t_done, 0, true, { Vss, Wss, Zz }, 0, s1W2R },
    { e_movupd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1W2R },
    { e_movsd,  t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1W2R },
  },
  { /* SSE11 */
    { e_movups, t_done, 0, true, { Wps, Vps, Zz }, 0, s1W2R },
    { e_movss,  t_done, 0, true, { Wss, Vss, Zz }, 0, s1W2R },
    { e_movupd, t_done, 0, true, { Wpd, Vpd, Zz }, 0, s1W2R },
    { e_movsd,  t_done, 0, true, { Wsd, Vsd, Zz }, 0, s1W2R }, // Book is wrong, this is a W/V
  },
  { /* SSE12 */
    { e_movlps_movhlps, t_done, 0, true, { Wq, Vq, Zz }, 0, s1W2R }, // FIXME: wierd 1st op
    { e_movsldup, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1W2R },
    { e_movlpd, t_done, 0, true, { Vq, Ws, Zz }, 0, s1W2R },
    { e_movddup, t_done, 0, true, { Vdq, Wq, Zz }, 0, s1W2R },
  },
  { /* SSE13 */
    { e_movlps, t_done, 0, true, { Vq, Wq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movlpd, t_done, 0, true, { Vq, Wq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE14 */
    { e_unpcklps, t_done, 0, true, { Vps, Wq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_unpcklpd, t_done, 0, true, { Vpd, Wq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE15 */
    { e_unpckhps, t_done, 0, true, { Vps, Wq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_unpckhpd, t_done, 0, true, { Vpd, Wq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE16 */
    { e_movhps_movlhps, t_done, 0, true, { Vq, Wq, Zz }, 0, s1W2R }, // FIXME: wierd 2nd op
    { e_movshdup, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1W2R },
    { e_movhpd, t_done, 0, true, { Vq, Wq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE17 */
    { e_movhps, t_done, 0, true, { Wq, Vq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movhpd, t_done, 0, true, { Wq, Vq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE28 */
    { e_movaps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movapd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE29 */
    { e_movaps, t_done, 0, true, { Wps, Vps, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movapd, t_done, 0, true, { Wpd, Vpd, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE2A */
    { e_cvtpi2ps, t_done, 0, true, { Vps, Qq, Zz }, 0, s1W2R },
    { e_cvtsi2ss, t_done, 0, true, { Vss, Ev, Zz }, 0, s1W2R },
    { e_cvtpi2pd, t_done, 0, true, { Vpd, Qdq, Zz }, 0, s1W2R },
    { e_cvtsi2sd, t_done, 0, true, { Vsd, Ev, Zz }, 0, s1W2R },
  },
  { /* SSE2B */
    { e_movntps, t_done, 0, true, { Wps, Vps, Zz }, 0, s1W2R | (fNT << FPOS) },
    { e_movntss, t_done, 0, true, { Md, Vd, Zz }, 0, s1W2R | (fNT << FPOS) },
    { e_movntpd, t_done, 0, true, { Wpd, Vpd, Zz }, 0, s1W2R | (fNT << FPOS) }, // bug in book
    { e_movntsd, t_done, 0, true, { Wq, Vq, Zz }, 0, s1W2R | (fNT << FPOS) },
  },
  { /* SSE2C */
    { e_cvttps2pi, t_done, 0, true, { Qq, Wps, Zz }, 0, s1W2R },
    { e_cvttss2si, t_done, 0, true, { Gv, Wss, Zz }, 0, s1W2R },
    { e_cvttpd2pi, t_done, 0, true, { Qdq, Wpd, Zz }, 0, s1W2R },
    { e_cvttsd2si, t_done, 0, true, { Gv, Wsd, Zz }, 0, s1W2R },
  },
  { /* SSE2D */
    { e_cvtps2pi, t_done, 0, true, { Qq, Wps, Zz }, 0, s1W2R },
    { e_cvtss2si, t_done, 0, true, { Gv, Wss, Zz }, 0, s1W2R },
    { e_cvtpd2pi, t_done, 0, true, { Qdq, Wpd, Zz }, 0, s1W2R },
    { e_cvtsd2si, t_done, 0, true, { Gv, Wsd, Zz }, 0, s1W2R },
  },
  { /* SSE2E */
    { e_ucomiss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_ucomisd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE2F */
    { e_comiss, t_done, 0, true, { Vps, Wps, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_comisd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE50 */
    { e_movmskps, t_done, 0, true, { Ed, Vps, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movmskpd, t_done, 0, true, { Ed, Vpd, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE51 */
    { e_sqrtps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1W2R },
    { e_sqrtss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1W2R },
    { e_sqrtpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1W2R },
    { e_sqrtsd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1W2R },
  },
  { /* SSE52 */
    { e_rsqrtps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1W2R },
    { e_rsqrtss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE53 */
    { e_rcpps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1W2R },
    { e_rcpss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE54 */
    { e_andps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_andpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE55 */
    { e_andnps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_andnpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE56 */
    { e_orps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_orpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE57 */
    { e_xorps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_xorpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE58 */
    { e_addps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_addss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1RW2R },
    { e_addpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_addsd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1RW2R },
  },
  { /* SSE59 */
    { e_mulps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_mulss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1RW2R },
    { e_mulpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_mulsd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1RW2R },
  },
  { /* SSE5A */
    { e_cvtps2pd, t_done, 0, true, { Vpd, Wps, Zz }, 0, s1W2R },
    { e_cvtss2sd, t_done, 0, true, { Vss, Wss, Zz }, 0, s1W2R },
    { e_cvtpd2ps, t_done, 0, true, { Vps, Wpd, Zz }, 0, s1W2R }, // FIXME: book bug ???
    { e_cvtsd2ss, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1W2R },
  },
  { /* SSE5B */
    { e_cvtdq2ps, t_done, 0, true, { Vps, Wdq, Zz }, 0, s1W2R },
    { e_cvttps2dq, t_done, 0, true, { Vdq, Wps, Zz }, 0, s1W2R }, // book has this/next swapped!!! 
    { e_cvtps2dq, t_done, 0, true, { Vdq, Wps, Zz }, 0, s1W2R },  // FIXME: book bug ???
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE5C */
    { e_subps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_subss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1RW2R },
    { e_subpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_subsd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1RW2R },
  },
  { /* SSE5D */
    { e_minps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_minss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1RW2R },
    { e_minpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_minsd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1RW2R },
  },
  { /* SSE5E */
    { e_divps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_divss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1RW2R },
    { e_divpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_divsd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1RW2R },
  },
  { /* SSE5F */
    { e_maxps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
    { e_maxss, t_done, 0, true, { Vss, Wss, Zz }, 0, s1RW2R },
    { e_maxpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_maxsd, t_done, 0, true, { Vsd, Wsd, Zz }, 0, s1RW2R },
  },
  { /* SSE60 */
    { e_punpcklbw, t_done, 0, true, { Pq, Qd, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpcklbw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE61 */
    { e_punpcklwd, t_done, 0, true, { Pq, Qd, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpcklwd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE62 */
    { e_punpcklqd, t_done, 0, true, { Pq, Qd, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpcklqd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE63 */
    { e_packsswb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_packsswb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE64 */
    { e_pcmpgtb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pcmpgtb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE65 */
    { e_pcmpgtw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pcmpgtw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE66 */
    { e_pcmpgdt, t_done, 0, true, { Pq, Qq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pcmpgdt, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE67 */
    { e_packuswb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_packuswb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE68 */
    { e_punpckhbw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpckhbw, t_done, 0, true, { Pdq, Qdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE69 */
    { e_punpckhwd, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpckhwd, t_done, 0, true, { Pdq, Qdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE6A */
    { e_punpckhdq, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpckhdq, t_done, 0, true, { Pdq, Qdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE6B */
    { e_packssdw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_packssdw, t_done, 0, true, { Pdq, Qdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE6C */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpcklqld, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE6D */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_punpckhqd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE6E */
    { e_movd, t_done, 0, true, { Pd, Ev, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movd, t_done, 0, true, { Vdq, Ev, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE6F */
    { e_movq, t_done, 0, true, { Pq, Qq, Zz }, 0, s1W2R },
    { e_movdqu, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1W2R }, // book has this/next swapped!!!
    { e_movdqa, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE70 */
    { e_pshufw, t_done, 0, true, { Pq, Qq, Ib }, 0, s1W2R3R },
    { e_pshufhw, t_done, 0, true, { Vdq, Wdq, Ib }, 0, s1W2R3R }, // book has this/next swapped!!!
    { e_pshufd, t_done, 0, true, { Vdq, Wdq, Ib }, 0, s1W2R3R },
    { e_pshuflw, t_done, 0, true, { Vdq, Wdq, Ib }, 0, s1W2R3R },
  },
  { /* SSE74 */
    { e_pcmpeqb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pcmpeqb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE75 */
    { e_pcmpeqw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pcmpeqw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE76 */
    { e_pcmpeqd, t_done, 0, true, { Pq, Qq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pcmpeqd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1R2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE78 */
    { e_vmread, t_done, 0, true, { Ed, Gd, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_grp, Grp17, false, { Zz, Zz, Zz }, 0, 0 },
    { e_insertq, t_done, 0, true, {Vdq, VRq, Iw}, 0, s1RW2R3R}, // This is actually 2 8-bit immediates, treat as 1 16-bit for decode
  },
  { /* SSE79 */
    { e_vmwrite, t_done, 0, true, { Ed, Gd, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_extrq, t_done, 0, true, {Vdq, VRq, Zz}, 0, s1RW2R},
    { e_insertq, t_done, 0, true, {Vdq, VRdq, Zz}, 0, s1RW2R},
  },
  { /* SSE7C */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_haddpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_haddps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
  },
  { /* SSE7D */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_hsubpd, t_done, 0, true, { Vpd, Wpd, Zz }, 0, s1RW2R },
    { e_hsubps, t_done, 0, true, { Vps, Wps, Zz }, 0, s1RW2R },
  },
  { /* SSE7E */
    { e_movd, t_done, 0, true, { Ev, Pd, Zz }, 0, s1W2R },
    { e_movq, t_done, 0, true, { Vq, Wq, Zz }, 0, s1W2R }, // book has this and next swapped!!!
    { e_movd, t_done, 0, true, { Ev, Vdq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSE7F */
    { e_movq, t_done, 0, true, { Qq, Pq, Zz }, 0, s1W2R },
    { e_movdqu, t_done, 0, true, { Wdq, Vdq, Zz }, 0, s1W2R }, // book has this and next swapped!!!
    { e_movdqa, t_done, 0, true, { Wdq, Vdq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEB8 */
    { e_jmpe, t_done, 0, false, { Jz, Zz, Zz }, 0, s1R },
    { e_popcnt, t_done, 0, true, { Gv, Ev, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEC2 */
    { e_cmpps, t_done, 0, true, { Vps, Wps, Ib }, 0, s1RW2R3R }, // comparison writes to dest!
    { e_cmpss, t_done, 0, true, { Vss, Wss, Ib }, 0, s1RW2R3R },
    { e_cmppd, t_done, 0, true, { Vpd, Wpd, Ib }, 0, s1RW2R3R },
    { e_cmpsd, t_done, 0, true, { Vsd, Wsd, Ib }, 0, s1RW2R3R },
  },
  { /* SSEC4 */
    { e_pinsrw, t_done, 0, true, { Pq, Ed, Ib }, 0, s1RW2R3R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pinsrw, t_done, 0, true, { Vdq, Ed, Ib }, 0, s1RW2R3R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEC5 */
    { e_pextrw, t_done, 0, true, { Gd, Pq, Ib }, 0, s1W2R3R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pextrw, t_done, 0, true, { Gd, Vdq, Ib }, 0, s1W2R3R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEC6 */
    { e_shufps, t_done, 0, true, { Vps, Wps, Ib }, 0, s1RW2R3R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_shufpd, t_done, 0, true, { Vpd, Wpd, Ib }, 0, s1RW2R3R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED0 */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_addsubpd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_addsubps, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
  },
  { /* SSED1 */
    { e_psrlw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psrlw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED2 */
    { e_psrld, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psrld, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED3 */
    { e_psrlq, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psrlq, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED4 */
    { e_paddq, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddq, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED5 */
    { e_pmullw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmullw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED6 */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movq2dq, t_done, 0, true, { Vdq, Qq, Zz }, 0, s1W2R }, // lines jumbled in book
    { e_movq, t_done, 0, true, { Wq, Vq, Zz }, 0, s1W2R },
    { e_movdq2q, t_done, 0, true, { Pq, Wq, Zz }, 0, s1W2R },
  },
  { /* SSED7 */
    { e_pmovmskb, t_done, 0, true, { Gd, Pq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmovmskb, t_done, 0, true, { Gd, Vdq, Zz }, 0, s1W2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED8 */
    { e_psubusb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubusb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSED9 */
    { e_psubusw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubusw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEDA */
    { e_pminub, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pminub, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEDB */
    { e_pand, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pand, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEDC */
    { e_paddusb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddusb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEDD */
    { e_paddusw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddusw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEDE */
    { e_pmaxub, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmaxub, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEDF */
    { e_pandn, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pandn, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE0 */
    { e_pavgb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pavgb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE1 */
    { e_psraw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psraw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE2 */
    { e_psrad, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psrad, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE3 */
    { e_pavgw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pavgw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE4 */
    { e_pmulhuw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmulhuw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE5 */
    { e_pmulhw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmulhw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE6 */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_cvtdq2pd, t_done, 0, true, { Vpd, Wdq, Zz }, 0, s1W2R }, // lines jumbled in book
    { e_cvttpd2dq, t_done, 0, true, { Vdq, Wpd, Zz }, 0, s1W2R },
    { e_cvtpd2dq, t_done, 0, true, { Vdq, Wpd, Zz }, 0, s1W2R },
  },
  { /* SSEE7 */
    { e_movntq, t_done, 0, true, { Wq, Vq, Zz }, 0, s1W2R | (fNT << FPOS) },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_movntdq, t_done, 0, true, { Wdq, Vdq, Zz }, 0, s1W2R | (fNT << FPOS) },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE8 */
    { e_psubsb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubsb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEE9 */
    { e_psubsw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubsw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEEA */
    { e_pminsw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pminsw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEEB */
    { e_por, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_por, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEEC */
    { e_paddsb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddsb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEED */
    { e_paddsw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddsw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEEE */
    { e_pmaxsw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmaxsw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEEF */
    { e_pxor, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pxor, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF0 */
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_lddqu, t_done, 0, true, { Vdq, Mdq, Zz }, 0, s1W2R },
  },
  { /* SSEF1 */
    { e_psllw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psllw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF2 */
    { e_pslld, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pslld, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF3 */
    { e_psllq, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psllq, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF4 */
    { e_pmuludq, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmuludq, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF5 */
    { e_pmaddwd, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_pmaddwd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF6 */
    { e_psadbw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psadbw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF7 */
    { e_maskmovq, t_done, 0, true, { Ppi, Qpi, Zz }, 0, s1W2R | (fNT << FPOS) },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_maskmovdqu, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1W2R | (fNT << FPOS) }, // bug in book
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF8 */
    { e_psubb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEF9 */
    { e_psubw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEFA */
    { e_psubd, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEFB */ // FIXME: Same????
    { e_psubd, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_psubd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEFC */
    { e_paddb, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddb, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEFD */
    { e_paddw, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddw, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEFE */
    { e_paddd, t_done, 0, true, { Pq, Qq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_paddd, t_done, 0, true, { Vdq, Wdq, Zz }, 0, s1RW2R },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  },
  { /* SSEFF */
    { e_ud, t_done, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_ud, t_done, 0, false, { Zz, Zz, Zz }, 0, 0 },
    { e_No_Entry, t_ill, 0, false, { Zz, Zz, Zz }, 0, 0 },
  }
};

/* rows are none or 66 prefixed in this order (see book) */
static ia32_entry ssegrpMap[][2] = {
  /* G12SSE010B */
  {
    { e_psrlw, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_psrlw, t_done, 0, true, { Pdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G12SSE100B */
  {
    { e_psraw, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_psraw, t_done, 0, true, { Pdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G12SSE110B */
  {
    { e_psllw, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_psllw, t_done, 0, true, { Pdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G13SSE010B */
  {
    { e_psrld, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_psrld, t_done, 0, true, { Wdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G13SSE100B */
  {
    { e_psrad, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_psrad, t_done, 0, true, { Wdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G13SSE110B */
  {
    { e_pslld, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_pslld, t_done, 0, true, { Wdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G14SSE010B */
  {
    { e_psrlq, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_psrlq, t_done, 0, true, { Wdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G14SSE011B */
  {
    { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    { e_psrldq, t_done, 0, true, { Wdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G14SSE110B */
  {
    { e_psllq, t_done, 0, true, { Pq, Ib, Zz }, 0, s1RW2R },
    { e_psllq, t_done, 0, true, { Wdq, Ib, Zz }, 0, s1RW2R }
  },
  /* G14SSE111B */
  {
    { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 },
    { e_pslldq, t_done, 0, true, { Wdq, Ib, Zz }, 0, s1RW2R }
  }
};

static bool mode_64 = false;

void ia32_set_mode_64(bool mode) {
  mode_64 = mode;
}

bool ia32_is_mode_64() {
  return mode_64;
}

ia32_entry movsxd = { e_movsxd, t_done, 0, true, { Gv, Ed, Zz }, 0, s1W2R };
ia32_entry invalid = { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0 };
		       
static void ia32_translate_for_64(ia32_entry** gotit_ptr)
{
    if (*gotit_ptr == &oneByteMap[0x63]) // APRL redefined to MOVSXD
	*gotit_ptr = &movsxd;
    if (*gotit_ptr == &oneByteMap[0x06] || // Invalid instructions in 64-bit mode: push es
	*gotit_ptr == &oneByteMap[0x07] || // pop es
	*gotit_ptr == &oneByteMap[0x0E] || // push cs
	*gotit_ptr == &oneByteMap[0x16] || // push ss
	*gotit_ptr == &oneByteMap[0x17] || // pop ss
	*gotit_ptr == &oneByteMap[0x1E] || // push ds
	*gotit_ptr == &oneByteMap[0x1F] || // pop ds
	*gotit_ptr == &oneByteMap[0x27] || // daa
	*gotit_ptr == &oneByteMap[0x2F] || // das
	*gotit_ptr == &oneByteMap[0x37] || // aaa
	*gotit_ptr == &oneByteMap[0x3F] || // aas
	*gotit_ptr == &oneByteMap[0x60] || // pusha
	*gotit_ptr == &oneByteMap[0x61] || // popa
	*gotit_ptr == &oneByteMap[0x62] || // bound gv, ma
	*gotit_ptr == &oneByteMap[0x82] || // group 1 eb/ib
	*gotit_ptr == &oneByteMap[0x9A] || // call ap
	*gotit_ptr == &oneByteMap[0x9E] || // sahf
	*gotit_ptr == &oneByteMap[0x9F] || // lahf
	*gotit_ptr == &oneByteMap[0xC4] || // les gz, mp
	*gotit_ptr == &oneByteMap[0xC5] || // lds gz, mp
	*gotit_ptr == &oneByteMap[0xCE] || // into
	*gotit_ptr == &oneByteMap[0xD4] || // aam ib
	*gotit_ptr == &oneByteMap[0xD5] || // aad ib
	*gotit_ptr == &oneByteMap[0xD6] || // salc
	*gotit_ptr == &oneByteMap[0xEA]) { // jump ap
      *gotit_ptr = &invalid;
    }
    
}

/* full decoding version: supports memory access information */
static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr,
                                      const unsigned char* addr,
                                      ia32_memacc* macadr,
                                      const ia32_prefixes* pref,
                                      ia32_locations *pos);


void ia32_memacc::print()
{
    fprintf(stderr, "base: %d, index: %d, scale:%d, disp: %ld (%lx), size: %d, addr_size: %d\n",
	    regs[0], regs[1], scale, imm, imm, size, addr_size);
}

int getOperSz(const ia32_prefixes &pref) 
{
   if (pref.rexW()) return 4;
   else if (pref.getPrefix(2) == PREFIX_SZOPER) return 1;
   else return 2;
}

ia32_instruction& ia32_decode(unsigned int capa, const unsigned char* addr, ia32_instruction& instruct)
{
  ia32_prefixes& pref = instruct.prf;
  unsigned int table, nxtab;
  unsigned int idx = 0, sseidx = 0;
  ia32_entry *gotit = NULL;
  int condbits = 0;

  if(capa & IA32_DECODE_MEMACCESS)
    assert(instruct.mac != NULL);

  if (!ia32_decode_prefixes(addr, pref, instruct.loc)) {
    instruct.size = 1;
    instruct.legacy_type = ILLEGAL;
    return instruct;
  }

  if((pref.getOpcodePrefix()) && pref.getCount())
  {
    idx = pref.getOpcodePrefix();
  }

  if (instruct.loc) instruct.loc->num_prefixes = pref.getCount();
  instruct.size = pref.getCount();
  addr += instruct.size;

  table = t_oneB;
  if(idx == 0) {
    // consume opcode
    idx = addr[0];
    instruct.size += 1;
    addr += 1;
  } else {
    // opcode already consumed (prefix opcode)
  }

  gotit = &oneByteMap[idx];
  nxtab = gotit->otable;

  if(capa & IA32_DECODE_CONDITION) {
    assert(instruct.cond != NULL);
    condbits = idx & 0x0F;
  }

  while(nxtab != t_done) {
    table = nxtab;
    switch(table) {
    case t_twoB:
      idx = addr[0];
      gotit = &twoByteMap[idx];
      nxtab = gotit->otable;
      instruct.size += 1;
      addr += 1;
      if(capa & IA32_DECODE_CONDITION)
        condbits = idx & 0x0F;
      break;
    case t_prefixedSSE:
      sseidx = gotit->tabidx;
      if(addr[0] != 0x0F)
      {
          // all valid SSE insns will have 0x0F as their first byte after prefix
          instruct.size += 1;
          addr += 1;
          instruct.entry = &invalid;
          return instruct;
      }
      idx = addr[1];
      gotit = &twoByteMap[idx];
      nxtab = gotit->otable;
      instruct.size += 2;
      addr += 2;
      break;
    case t_sse:
      idx = gotit->tabidx;
      gotit = &sseMap[idx][sseidx];
      nxtab = gotit->otable;
      break;
    case t_grp: {
      idx = gotit->tabidx;
      unsigned int reg  = (addr[0] >> 3) & 7;
      if(idx < Grp12)
        switch(idx) {
        case Grp2:
        case Grp11:
          /* leave table unchanged because operands are in not 
             defined in group map, unless this is an invalid index
             into the group, in which case we need the instruction
             to reflect its illegal status */
          if(groupMap[idx][reg].id == e_No_Entry)
            gotit = &groupMap[idx][reg];
          nxtab = groupMap[idx][reg].otable;
          assert(nxtab==t_done || nxtab==t_ill);
          break;
        default:
          gotit = &groupMap[idx][reg];
          nxtab = gotit->otable;
        }
      else {
        unsigned int mod = addr[0] >> 6;
        gotit = &groupMap2[idx-Grp12][mod==3][reg];
        nxtab = gotit->otable;
      }
      break;
    }
    case t_grpsse:
      sseidx >>= 1;
      idx = gotit->tabidx;
      gotit = &ssegrpMap[idx][sseidx];
      nxtab = gotit->otable;
      break;
    case t_coprocEsc:
      {
        instruct.legacy_type = 0;
        unsigned int reg  = (addr[0] >> 3) & 7;
        unsigned int mod = addr[0] >> 6;
        gotit = &fpuMap[gotit->tabidx][mod==3][reg];
        ia32_decode_FP(idx, pref, addr, instruct, gotit, instruct.mac);
        return instruct;
      }
    case t_3dnow:
      // 3D now opcodes are given as suffix: ModRM [SIB] [displacement] opcode
      // Right now we don't care what the actual opcode is, so there's no table
      instruct.size += 1;
      nxtab = t_done;
      break;
    case t_ill:
      instruct.legacy_type = ILLEGAL;
      instruct.entry = gotit;
      return instruct;
    default:
      assert(!"wrong table");
    }
  }

  assert(gotit != NULL);
  instruct.legacy_type = gotit->legacyType;

  // addr points after the opcode, and the size has been adjusted accordingly
  if (instruct.loc) instruct.loc->opcode_size = instruct.size - pref.getCount();
  if (instruct.loc) instruct.loc->opcode_position = pref.getCount();

  // make adjustments for instruction redefined in 64-bit mode
  if (mode_64)
    ia32_translate_for_64(&gotit);

  ia32_decode_operands(pref, *gotit, addr, instruct, instruct.mac); // all but FP

  if(capa & IA32_DECODE_MEMACCESS) {
    int sema = gotit->opsema & ((1<<FPOS)-1);
    int hack = gotit->opsema >> FPOS;
    switch(sema) {
    case sNONE:
      break;
    case s1R:
      switch(hack) {
      case fPREFETCHNT:
        instruct.mac[0].prefetch = true;
        instruct.mac[0].prefetchlvl = 0;
        break;
      case fPREFETCHT0:
        instruct.mac[0].prefetch = true;
        instruct.mac[0].prefetchlvl = 1;
        break;
      case fPREFETCHT1:
        instruct.mac[0].prefetch = true;
        instruct.mac[0].prefetchlvl = 2;
        break;
      case fPREFETCHT2:
        instruct.mac[0].prefetch = true;
        instruct.mac[0].prefetchlvl = 3;
        break;
      case fPREFETCHAMDE:
        instruct.mac[0].prefetch = true;
        instruct.mac[0].prefetchstt = 0;
        break;
      case fPREFETCHAMDW:
        instruct.mac[0].prefetch = true;
        instruct.mac[0].prefetchstt = 1;
        break;
      default:
        instruct.mac[0].read = true;
      }
      break;
    case s1W:
      instruct.mac[0].write = true;
      break;
    case s1RW:
      instruct.mac[0].read = true;
      instruct.mac[0].write = true;
      instruct.mac[0].nt = hack == fNT;
      break;
    case s1R2R:
      instruct.mac[0].read = true;
      instruct.mac[1].read = true;
      break;
    case s1W2R:
      instruct.mac[0].write = true;
      instruct.mac[0].nt = hack == fNT; // all NTs are s1W2R
      instruct.mac[1].read = true;
      break;
    case s1RW2R:
      instruct.mac[0].read = true;
      instruct.mac[0].write = true;
      instruct.mac[1].read = true;
      break;
    case s1RW2RW:
      instruct.mac[0].read = true;
      instruct.mac[0].write = true;
      instruct.mac[1].read = true;
      instruct.mac[1].write = true;
      break;
    case s1W2R3R:
      instruct.mac[0].write = true;
      instruct.mac[1].read = true;
      instruct.mac[2].read = true;
      break;
    case s1W2W3R:
      instruct.mac[0].write = true;
      instruct.mac[1].write = true;
      instruct.mac[2].read = true;
      break;
    case s1W2RW3R:
      instruct.mac[0].write = true;
      instruct.mac[1].read = true;
      instruct.mac[1].write = true;
      instruct.mac[2].read = true;
      break;
    case s1W2R3RW:
      instruct.mac[0].write = true;
      instruct.mac[1].read = true;
      instruct.mac[2].read = true;
      instruct.mac[2].write = true;
      break;
    case s1RW2R3R:
      instruct.mac[0].read = true;
      instruct.mac[0].write = true;
      instruct.mac[1].read = true;
      instruct.mac[2].read = true;
      break;
    case s1RW2RW3R:
      instruct.mac[0].write = true;
      instruct.mac[0].read = true;
      instruct.mac[1].read = true;
      instruct.mac[1].write = true;
      instruct.mac[2].read = true;
      break;
    }

    switch(pref.getPrefix(0)) {
    case PREFIX_REPNZ:
      switch(hack) {
      case fSCAS:
        instruct.mac[1].sizehack = shREPNESCAS;
        break;
      case fCMPS:
        instruct.mac[0].sizehack = shREPNECMPS;
        instruct.mac[1].sizehack = shREPNECMPS;
        break;
      default:
	  break;
      }
      break;
    case PREFIX_REP:
      switch(hack) {
      case fSCAS:
        instruct.mac[1].sizehack = shREPESCAS;
        break;
      case fCMPS:
        instruct.mac[0].sizehack = shREPECMPS;
        instruct.mac[1].sizehack = shREPECMPS;
        break;
      case fREP:
        instruct.mac[0].sizehack = shREP;
        instruct.mac[1].sizehack = shREP;
        break;
      default:
	break;
      }
      break;
    case 0:
    case PREFIX_LOCK:
      break;
    default:
      break;
    }

#if 0
    // debug output for memory access decoding
    for (int i = 0; i < 3; i++) {
	if (instruct.mac[i].is) {
	    fprintf(stderr, "%d)", i);
	    if (instruct.mac[i].read)
		fprintf(stderr, " read");
	    if (instruct.mac[i].write)
		fprintf(stderr, " write");
	    if (instruct.mac[i].nt)
		fprintf(stderr, " nt");
	    if (instruct.mac[i].sizehack)
		fprintf(stderr, " sizehack");
	    fprintf(stderr, "\n");
	    instruct.mac[i].print();
	}
    }
#endif

  }


  if(capa & IA32_DECODE_CONDITION) {
    int hack = gotit->opsema >> FPOS;
    if(hack == fCOND)
      instruct.cond->set(condbits);
  }

  // flip id of opcodes overloaded on operand size prefix
  int operSzAttr = getOperSz(pref);
  if (1 == operSzAttr) {
    entryID newID = gotit->id;
    switch (gotit->id) {
    case e_cwde: newID = e_cbw; break;
    case e_cdq: newID = e_cwd; break;
    case e_insd: newID = e_insw; break;
    case e_lodsd: newID = e_lodsw; break;
    case e_movsd: newID = e_movsw; break;
    case e_outsd: newID = e_outsw; break;
    case e_popad: newID = e_popa; break;
    case e_popfd: newID = e_popf; break;
    case e_pushad: newID = e_pusha; break;
    case e_pushfd: newID = e_pushf; break;
    case e_scasd: newID = e_scasw; break;
    case e_stosd: newID = e_stosw; break;
    default: break;
    }
    gotit->id = newID;
  }

  instruct.entry = gotit;
  return instruct;
}

ia32_instruction& ia32_decode_FP(unsigned int opcode, const ia32_prefixes& pref,
                                 const unsigned char* addr, ia32_instruction& instruct,
                                 ia32_entry * entry, ia32_memacc *mac)
{
  // addr points after the opcode, and the size has been adjusted accordingly
  if (instruct.loc) instruct.loc->opcode_size = instruct.size - pref.getCount();
  if (instruct.loc) instruct.loc->opcode_position = pref.getCount();

  unsigned int nib = byteSzB; // modRM
  unsigned int addrSzAttr = (pref.getPrefix(3) == PREFIX_SZADDR ? 1 : 2); // 32-bit mode implicit
  unsigned int operSzAttr = (pref.getPrefix(2) == PREFIX_SZOPER ? 1 : 2); // 32-bit mode implicit

  // There *will* be a mod r/m byte at least as far as locs are concerned, though the mod=3 case does not
  // consume extra bytes.  So pull this out of the conditional.
  if (instruct.loc) {
      instruct.loc->modrm_position = instruct.loc->opcode_position +
              instruct.loc->opcode_size;
      instruct.loc->modrm_operand = 0;
  }
  nib += ia32_decode_modrm(addrSzAttr, addr, mac, &pref, instruct.loc);
    // also need to check for AMD64 rip-relative data addressing
    // occurs when mod == 0 and r/m == 101
  if (mode_64)
      if ((addr[0] & 0xc7) == 0x05)
          instruct.rip_relative_data = true;
  if (addr[0] <= 0xBF) { // modrm
    // operand size has to be determined from opcode
    if(mac)
      {
	switch(opcode) {
	case 0xD8: // all single real
	  mac->size = 4;
	  mac->read = true;
	  break;
	case 0xD9: {
	  unsigned char modrm = addr[0];
	  unsigned char reg = (modrm >> 3) & 7;
	  switch(reg) {
	  case 0:
	    mac->size = 4;
	    mac->read = true;
	    break;
	  case 2:
	  case 3:
	    mac->size = 4;
	    mac->write = true;
	    break;
	  case 1:
	    instruct.legacy_type = ILLEGAL;
	    break;
	  case 4:
	    mac->size = 14 * operSzAttr;
	    mac->read = true;
	    break;
	  case 5:
	    mac->read = true;
	    mac->size = 2;
	    break;
	  case 6:
	    mac->size = 14 * operSzAttr;
	    mac->write = true;
	    break;
	  case 7:
	    mac->write = true;
	    mac->size = 2;
	    break;
	  }
	  break; }
	case 0xDA:  // all double real
	  mac->size = 8;
	  mac->read = true;
	  break;
	case 0xDB: {
	  unsigned char modrm = addr[0];
	  unsigned char reg = (modrm >> 3) & 7;
	  switch(reg) {
	  case 0:
	    mac->size = dwordSzB;
	    mac->read = true;
	    break;
	  case 2:
	  case 3:
	    mac->size = dwordSzB;
	    mac->write = true;
	    break;
	  case 1:
	  case 4:
	  case 6:
	    instruct.legacy_type = ILLEGAL;
	    break;
	  case 5:
	    mac->size = 10; // extended real
	    mac->read = true;
	    break;
	  case 7:
	    mac->size = 10; // extended real
	    mac->write = true;
	    break;
	  }
	  break; }
	case 0xDC:   // all double real
	  mac->size = 8;
	  mac->read = true;
	  break;
	case 0xDD: {
	  unsigned char modrm = addr[0];
	  unsigned char reg = (modrm >> 3) & 7;
	  switch(reg) {
	  case 0:
	    mac->size = 8;
	    mac->read = true;
	    break;
	  case 2:
	  case 3:
	    mac->size = 8;
	    mac->write = true;
	    break;
	  case 1:
	  case 5:
	    instruct.legacy_type = ILLEGAL;
	    break;
	  case 4:
	    mac->size = operSzAttr == 2 ? 108 : 98;
	    mac->read = true;
	    break;
	  case 6:
	    mac->size = operSzAttr == 2 ? 108 : 98;
	    mac->write = true;
	    break;
	  case 7:
	    mac->size = 2;
	    mac->write = true;
	    break;    
	  }
	  break; }
	case 0xDE: // all word integer
	  mac->size = wordSzB;
	  mac->write = true;
	  break;
	case 0xDF: {
	  unsigned char modrm = addr[0];
	  unsigned char reg = (modrm >> 3) & 7;
	  switch(reg) {
	  case 0:
	    mac->size = wordSzB;
	    mac->read = true;
	    break;
	  case 2:
	  case 3:
	    mac->size = wordSzB;
	    mac->write = true;
	    break;
	  case 1:
	    instruct.legacy_type = ILLEGAL;
	    break;
	  case 4:
	    mac->size = 10;
	    mac->read = true;
	    break;
	  case 5:
	    mac->size = 8;
	    mac->read = true;
	    break;
	  case 6:
	    mac->size = 10;
	    mac->write = true;
	    break;
	  case 7:
	    mac->size = 8;
	    mac->write = true;
	    break;
	  }
	  break; }
	} // switch(opcode) 
      } // if mac
  } // if modrm
  
  instruct.size += nib;
  instruct.entry = entry;
  
  return instruct;
}

#define MODRM_MOD(x) ((x) >> 6)
#define MODRM_RM(x) ((x) & 7)
#define MODRM_REG(x) (((x) & (7 << 3)) >> 3)
#define MODRM_SET_MOD(x, y) ((x) |= ((y) << 6))
#define MODRM_SET_RM(x, y) ((x) |= (y))
#define MODRM_SET_REG(x, y) ((x) |= ((y) << 3))

static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr,
                                      const unsigned char* addr,
                                      ia32_memacc* macadr,
                                      const ia32_prefixes* pref,
                                      ia32_locations *loc)
{
 
  unsigned char modrm = addr[0];
  unsigned char mod = MODRM_MOD(modrm);
  unsigned char rm  = MODRM_RM(modrm);
  unsigned char reg = MODRM_REG(modrm);
  if (loc) {
     loc->modrm_byte = modrm;
     loc->modrm_mod = mod;
     loc->modrm_rm = rm;
     loc->modrm_reg = reg;
     loc->address_size = addrSzAttr;
  }
  ++addr;

  if(addrSzAttr == 1) { // 16-bit, cannot have SIB
    //bperr( "16bit addr!\n");
    switch(mod) {
    case 0:
      //bperr( "16bit addr - case 0, rm = %d!\n", rm);
      if(macadr)
        switch (rm) {
        case 0: // [BX+SI]
          macadr->set16(mBX, mSI, 0);
          break;
        case 1:
          macadr->set16(mBX, mDI, 0);
          break;
        case 2:
          macadr->set16(mBP, mSI, 0);
          break;
        case 3:
          macadr->set16(mBP, mDI, 0);
          break;
        case 4:
          macadr->set16(mSI, -1, 0);
          break;
        case 5:
          macadr->set16(mDI, -1, 0);
          break;
        case 6: { 
           // disp16
           const short int *pdisp16 = (const short int*)addr;
           //bperr( "16bit addr - case6!\n");
           macadr->set16(-1, -1, *pdisp16);
           if (loc) { 
              loc->disp_position = loc->modrm_position + 1;
              loc->disp_size = 2;
           }
           break; 
        }
        case 7:
          macadr->set16(mBX, -1, 0);
          break;
        }
      return rm==6 ? wordSzB : 0;
    case 1:
      //bperr( "16bit addr - case1!\n");
      if(macadr) {
        const char *pdisp8 = (const char*)addr;
        if (loc) { 
           loc->disp_position = loc->modrm_position + 1;
           loc->disp_size = 1;
        }
        switch (rm) {
        case 0: 
          macadr->set16(mBX, mSI, *pdisp8);
          break;
        case 1:
          macadr->set16(mBX, mDI, *pdisp8);
          break;
        case 2:
          macadr->set16(mBP, mSI, *pdisp8);
          break;
        case 3:
          macadr->set16(mBP, mDI, *pdisp8);
          break;
        case 4:
          macadr->set16(mSI, -1, *pdisp8);
          break;
        case 5:
          macadr->set16(mDI, -1, *pdisp8);
          break;
        case 6:
          macadr->set16(mBP, -1, *pdisp8);
          break;
        case 7:
          macadr->set16(mBX, -1, *pdisp8);
          break;
        }
      }
      return byteSzB;
    case 2:
      //bperr( "16bit addr - case2!\n");
      if(macadr) {
        const short int *pdisp16 = (const short int*)addr;
        if (loc) { 
           loc->disp_position = loc->modrm_position + 1;
           loc->disp_size = 2;
        }
        switch (rm) {
        case 0: 
          macadr->set16(mBX, mSI, *pdisp16);
          break;
        case 1:
          macadr->set16(mBX, mDI, *pdisp16);
          break;
        case 2:
          macadr->set16(mBP, mSI, *pdisp16);
          break;
        case 3:
          macadr->set16(mBP, mDI, *pdisp16);
          break;
        case 4:
          macadr->set16(mSI, -1, *pdisp16);
          break;
        case 5:
          macadr->set16(mDI, -1, *pdisp16);
          break;
        case 6:
          macadr->set16(mBP, -1, *pdisp16);
          break;
        case 7:
          macadr->set16(mBX, -1, *pdisp16);
          break;
        }
      }

      return wordSzB;
    case 3:
      return 0; // register
    default:
      assert(0);
    }
  }
  else { // 32-bit or 64-bit, may have SIB
    if(mod == 3)
      return 0; // only registers, no SIB
    bool hassib = rm == 4;
    unsigned int nsib = 0;
    unsigned char sib;
    int base = 0, scale = -1, index = -1;  // prevent g++ from whining.
    if(hassib) {
      nsib = byteSzB;
      sib = addr[0];
      if (loc) { 
         loc->sib_position = loc->modrm_position + 1;
         loc->sib_byte = sib;
      }
      ++addr;
      base = sib & 7;
      if(macadr) {
        scale = sib >> 6;
        index = (sib >> 3) & 7;

	// stack pointer can't be used as an index - supports base-only addressing w/ SIB
        if(index == 4 && !pref->rexX())
          index = -1;
      }
    }
    switch(mod) {
    case 0: {
      /* this is tricky: there is a disp32 iff (1) rm == 5  or  (2) hassib && base == 5 */
      unsigned char check5 = hassib ? base : rm;
      if(macadr)
        switch (rm) {
        case 0:
          macadr->set(apply_rex_bit(mEAX, pref->rexB()), 0, addrSzAttr);
          break;
        case 1:
          macadr->set(apply_rex_bit(mECX, pref->rexB()), 0, addrSzAttr);
          break;
        case 2:
          macadr->set(apply_rex_bit(mEDX, pref->rexB()), 0, addrSzAttr);
          break;
        case 3:
          macadr->set(apply_rex_bit(mEBX, pref->rexB()), 0, addrSzAttr);
          break;
        case 4: // SIB
          if(base == 5) 
          { 
             // disp32[index<<scale]
             const int *pdisp32 = (const int*)addr;
             if (loc) { 
                loc->disp_position = loc->sib_position + 1;
                loc->disp_size = 4;
             }
             macadr->set_sib(-1, scale, apply_rex_bit(index, pref->rexX()), 
                             *pdisp32, addrSzAttr);
          }
          else
            macadr->set_sib(apply_rex_bit(base, pref->rexB()), scale, 
                            apply_rex_bit(index, pref->rexX()),
                            0, addrSzAttr);
          break;
        case 5: { 
           // disp32 (or [RIP + disp32] for 64-bit mode)
           if (loc) { 
              loc->disp_position = loc->modrm_position + 1;
              loc->disp_size = 4;
           }
           const int *pdisp32 = (const int*)addr;
           if (mode_64)
              macadr->set(mRIP, *pdisp32, addrSzAttr);
           else
              macadr->set(-1, *pdisp32, addrSzAttr);
           break; 
        }
        case 6:
           macadr->set(apply_rex_bit(mESI, pref->rexB()), 0, addrSzAttr);
           break;
        case 7:
           macadr->set(apply_rex_bit(mEDI, pref->rexB()), 0, addrSzAttr);
           break;
      }
      return nsib + ((check5 == 5) ? dwordSzB : 0);
    }
    case 1:
      if(macadr) {
         const char *pdisp8 = (const char*)addr;
         if (loc) { 
            loc->disp_position = loc->modrm_position + 1;
            loc->disp_size = 1;
         }
        switch (rm) {
        case 0:
           macadr->set(apply_rex_bit(mEAX, pref->rexB()), *pdisp8, addrSzAttr);
          break;
        case 1:
          macadr->set(apply_rex_bit(mECX, pref->rexB()), *pdisp8, addrSzAttr);
          break;
        case 2:
          macadr->set(apply_rex_bit(mEDX, pref->rexB()), *pdisp8, addrSzAttr);
          break;
        case 3:
          macadr->set(apply_rex_bit(mEBX, pref->rexB()), *pdisp8, addrSzAttr);
          break;
        case 4:
          // disp8[EBP + index<<scale] happens naturally here when base=5
           if (loc) { 
              loc->disp_position = loc->sib_position + 1;
              loc->disp_size = 1;
           }           
          macadr->set_sib(apply_rex_bit(base, pref->rexB()), scale, apply_rex_bit(index, pref->rexX()),
			  *pdisp8, addrSzAttr);
          break;
        case 5:
          macadr->set(apply_rex_bit(mEBP, pref->rexB()), *pdisp8, addrSzAttr);
          break;
        case 6:
          macadr->set(apply_rex_bit(mESI, pref->rexB()), *pdisp8, addrSzAttr);
          break;
        case 7:
          macadr->set(apply_rex_bit(mEDI, pref->rexB()), *pdisp8, addrSzAttr);
          break;
        }
      }
      return nsib + byteSzB;
    case 2:
      if(macadr) {
        const int *pdisp32 = (const int*)addr;
        if (loc) { 
           loc->disp_position = loc->modrm_position + 1;
           loc->disp_size = 4;
        }
        switch (rm) {
        case 0:
          macadr->set(apply_rex_bit(mEAX, pref->rexB()), *pdisp32, addrSzAttr);
          break;
        case 1:
          macadr->set(apply_rex_bit(mECX, pref->rexB()), *pdisp32, addrSzAttr);
          break;
        case 2:
          macadr->set(apply_rex_bit(mEDX, pref->rexB()), *pdisp32, addrSzAttr);
          break;
        case 3:
          macadr->set(apply_rex_bit(mEBX, pref->rexB()), *pdisp32, addrSzAttr);
          break;
        case 4:
          // disp32[EBP + index<<scale] happens naturally here when base=5
           if (loc) { 
              loc->disp_position = loc->sib_position + 1;
              loc->disp_size = 4;
           }
          macadr->set_sib(apply_rex_bit(base, pref->rexB()), scale, apply_rex_bit(index, pref->rexX()),
			  *pdisp32, addrSzAttr);
          break;
        case 5:
          macadr->set(apply_rex_bit(mEBP, pref->rexB()), *pdisp32, addrSzAttr);
          break;
        case 6:
          macadr->set(apply_rex_bit(mESI, pref->rexB()), *pdisp32, addrSzAttr);
          break;
        case 7:
          macadr->set(apply_rex_bit(mEDI, pref->rexB()), *pdisp32, addrSzAttr);
          break;
        }
      }
      return nsib + dwordSzB;
    default:
      assert(0);
    }
  }
  return 0; // MS compiler from VS 6.0 wants this
}


static inline int type2size(unsigned int optype, unsigned int operSzAttr)
{
  switch(optype) {
  case op_a:
    return 2 * wordSzB * operSzAttr;
  case op_b:
    return byteSzB;
  case op_c:
    assert(!"Where is this used, Intel?");
    return byteSzB * operSzAttr;
  case op_d:
    return dwordSzB;
  case op_dq:
    return dqwordSzB;
  case op_p:
    return wordSzB + wordSzB * operSzAttr; // XXX book says operand size...
  case op_pd:  // Intel "forgot" to define this in book, but uses it
    return dqwordSzB;
  case op_pi:
    return qwordSzB;
  case op_ps:
    return dqwordSzB;
  case op_q:
    return qwordSzB;
  case op_s:
    return 6;
  case op_sd:  // another Intel amnesia case
    return qwordSzB;
  case op_ss:
    return dwordSzB;
  case op_si:
    assert(!"Where is this used, Intel?");
    return dwordSzB;
  case op_v:
    return wordSzB * operSzAttr;
  case op_w:
    return wordSzB;
  case op_z:
      return operSzAttr == 1 ? wordSzB : dwordSzB;
  case op_lea:
    //    assert(!"Should not be evaluated");
    // We might be called, if we don't know this is an lea ahead of time
    // It's okay to return 0 here, because we really don't load/store
    return 0;
  case op_allgprs:
    return 8 * wordSzB * operSzAttr;
  case op_512:
    return 512;
  default:
      assert(0);
      return 0;
//    RegisterAST reg(optype);
//    return reg.eval().size();
  }
}

unsigned int ia32_decode_operands (const ia32_prefixes& pref, 
                                   const ia32_entry& gotit, 
                                   const unsigned char* addr, 
                                   ia32_instruction& instruct,
                                   ia32_memacc *mac)
{
  ia32_locations *loc = instruct.loc;
  if (loc) loc->imm_cnt = 0;
  unsigned int nib = 0 /* # of bytes in instruction */;

  int addrSzAttr = (pref.getPrefix(3) == PREFIX_SZADDR ? 1 : 2);

  if (mode_64)
    addrSzAttr *= 2;

  int operSzAttr = getOperSz(pref);

  if(gotit.hasModRM)
    nib += byteSzB;

  for(unsigned int i=0; i<3; ++i) {
    const ia32_operand& op = gotit.operands[i];
    if(op.admet) {
      // At most two operands can be memory, the third is register or immediate
      //assert(i<2 || op.admet == am_reg || op.admet == am_I);
      switch(op.admet) {
      case am_A: /* address = segment + offset (word or dword or qword) */
        nib += wordSzB * addrSzAttr;
	nib += dwordSzB;
	break;
      case am_O: /* operand offset */
        nib += wordSzB * addrSzAttr;
        if(mac) {
          int offset;
          switch(addrSzAttr) {
          case 1: // 16-bit offset
              offset = *((const short int*)addr);
              break;
          case 2: // 32-bit offset
              offset = *((const int*)addr);
              break;
          case 4: // 64-bit
	      offset = *((const long*)addr);
              break;
          default:
              assert(0);
              break;
          }
          mac[i].set(-1, offset, addrSzAttr);
          mac[i].size = type2size(op.optype, operSzAttr);
        }
        break;
      case am_C:   /* control register */
      case am_D:   /* debug register */
      case am_F:   /* flags register */
      case am_G:   /* general purpose register, selecteb by reg field */
      case am_P:   /* MMX register */
      case am_R:   /* general purpose register, selected by r/m field */
      case am_S:   /* segment register */
      case am_T:   /* test register */
      case am_V:   /* XMM register */
      case am_reg: /* register implicitely encoded in opcode */
      case am_allgprs:
        break;
      case am_E: /* register or memory location, so decoding needed */
      case am_M: /* memory operand, decoding needed; size includes modRM byte */
      case am_Q: /* MMX register or memory location */
      case am_W: /* XMM register or memory location */
         if (loc) {
            loc->modrm_position = loc->opcode_size + loc->opcode_position;
            loc->modrm_operand = i;
         }
         if(mac) {
            nib += ia32_decode_modrm(addrSzAttr, addr, &mac[i], &pref, loc);
            mac[i].size = type2size(op.optype, operSzAttr);
            if (loc) loc->address_size = mac[i].size;
         }
         else
            nib += ia32_decode_modrm(addrSzAttr, addr, NULL, &pref, loc);
         
         // also need to check for AMD64 rip-relative data addressing
         // occurs when mod == 0 and r/m == 101
         if (mode_64)
            if ((addr[0] & 0xc7) == 0x05)
               instruct.rip_relative_data = true;
         
         break;
      case am_I: /* immediate data */
      case am_J: { /* instruction pointer offset */
         int imm_size = type2size(op.optype, operSzAttr);
         if (loc) {
            // sanity
            if(loc->imm_cnt > 1) {
                fprintf(stderr,"Oops, more than two immediate operands\n");
            } else {
                loc->imm_position[loc->imm_cnt] = 
                    nib + loc->opcode_position + loc->opcode_size;
                loc->imm_size[loc->imm_cnt] = imm_size;
                ++loc->imm_cnt;
            }
         }
         nib += imm_size;
         break;
      }
      /* TODO: rep prefixes, deal with them here? */
      case am_X: /* memory at DS:(E)SI*/
        if(mac)
          mac[i].setXY(mESI, type2size(op.optype, operSzAttr), addrSzAttr);
        break;
      case am_Y: /* memory at ES:(E)DI*/
        if(mac)
          mac[i].setXY(mEDI, type2size(op.optype, operSzAttr), addrSzAttr);
        break;
      case am_stackH: /* stack push */
      case am_stackP: /* stack pop */
	assert(0 && "Wrong table!");
        break;
      case am_tworeghack:
      case am_ImplImm:
	// Don't do nuthin'
	break;
      default:
        assert(0 && "Bad addressing mode!");
      }
    }
    else
      break;
  }
  if((gotit.id == e_push) && mac)
  {
    // assuming 32-bit (64-bit for AMD64) stack segment
    // AMD64: push defaults to 64-bit operand size
    if (mode_64 && operSzAttr == 2)
      operSzAttr = 4;
    mac[1].set(mESP, -2 * operSzAttr, addrSzAttr);
    if(gotit.operands[0].admet == am_reg)
    {
        mac[1].size = type2size(op_v, operSzAttr);
    }
    else
    {
        mac[1].size = type2size(gotit.operands[0].optype, operSzAttr);
    }
    mac[1].write = true;
  }
  if((gotit.id == e_pop) && mac)
  {
    // assuming 32-bit (64-bit for AMD64) stack segment
    // AMD64: pop defaults to 64-bit operand size
    if (mode_64 && operSzAttr == 2)
      operSzAttr = 4;
    mac[1].set(mESP, 0, addrSzAttr);
    if(gotit.operands[0].admet == am_reg)
    {
        mac[1].size = type2size(op_v, operSzAttr);
    }
    else
    {
        mac[1].size = type2size(gotit.operands[0].optype, operSzAttr);
    }
    mac[1].read = true;
  }
  if((gotit.id == e_leave) && mac)
  {
    // assuming 32-bit (64-bit for AMD64) stack segment
    // AMD64: push defaults to 64-bit operand size
    if (mode_64 && operSzAttr == 2)
      operSzAttr = 4;
    mac[0].set(mESP, 0, addrSzAttr);
    mac[0].size = type2size(op_v, operSzAttr);
    mac[0].read = true;
  }
  if((gotit.id == e_ret_near || gotit.id == e_ret_far) && mac)
  {
    mac[0].set(mESP, 0, addrSzAttr);
    mac[0].size = type2size(op_v, addrSzAttr);
    mac[0].read = true;
  }
  if((gotit.id == e_call) && mac)
  {
      mac[0].set(mESP, -2 * addrSzAttr, addrSzAttr);
      mac[0].size = type2size(op_v, addrSzAttr);
      mac[0].write = true;
            
  }
  
  instruct.size += nib;
  return nib;
}


static const unsigned char sse_prefix[256] = {
  /*       0 1 2 3 4 5 6 7 8 9 A B C D E F  */
  /* 0x */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  /* 1x */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
  /* 2x */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
  /* 3x */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  /* 4x */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  /* 5x */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  /* 6x */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  /* 7x */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, // Grp12-14 are SSE groups
  /* 8x */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  /* 9x */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  /* Ax */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  /* Bx */ 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
  /* Cx */ 0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,
  /* Dx */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  /* Ex */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  /* Fx */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
};

#define REX_ISREX(x) (((x) >> 4) == 4)


// FIXME: lookahead might blow up...
bool ia32_decode_prefixes(const unsigned char* addr, ia32_prefixes& pref,
                          ia32_locations *loc)
{
  pref.count = 0;
  pref.prfx[0] = pref.prfx[1] = pref.prfx[2] = pref.prfx[3] = pref.prfx[4] = 0;
  pref.opcode_prefix = 0;
  bool in_prefix = true;

  while(in_prefix) {
    switch(addr[0]) {
    case PREFIX_REPNZ:
    case PREFIX_REP:
       if(mode_64 && REX_ISREX(addr[1]) &&
	  addr[2]==0x0F && sse_prefix[addr[3]]) 
       {
	 ++pref.count;
          pref.opcode_prefix = addr[0];
          break;
       }
       else if(addr[1]==0x0F && sse_prefix[addr[2]]) {
          ++pref.count;
          pref.opcode_prefix = addr[0];
          break;
       }
       
    case PREFIX_LOCK:
       ++pref.count;
       pref.prfx[0] = addr[0];
       break;
    case PREFIX_SEGCS:
    case PREFIX_SEGSS:
    case PREFIX_SEGDS:
    case PREFIX_SEGES:
    case PREFIX_SEGFS:
    case PREFIX_SEGGS:
       ++pref.count;
       pref.prfx[1] = addr[0];
       break;
    case PREFIX_SZOPER:
       if(addr[1]==0x0F && sse_prefix[addr[2]]) {
          pref.opcode_prefix = addr[0];
          break;
       }
       if(mode_64 && REX_ISREX(addr[1]) &&
	  addr[2]==0x0F && sse_prefix[addr[3]]) 
       {
	 ++pref.count;
          pref.opcode_prefix = addr[0];
          break;
       }
       ++pref.count;
       pref.prfx[2] = addr[0];
       break;
    case PREFIX_SZADDR:
       ++pref.count;
       pref.prfx[3] = addr[0];
       break;
    default:
       in_prefix=false;
    }
    
    ++addr;
  }

  bool result = true;
  if (mode_64)
     result = ia32_decode_rex(addr - 1, pref, loc);
  if (loc) loc->num_prefixes = pref.count;

  return result;
}

#define REX_W(x) ((x) & 0x8)
#define REX_R(x) ((x) & 0x4)
#define REX_X(x) ((x) & 0x2)
#define REX_B(x) ((x) & 0x1)

#define REX_INIT(x) ((x) = 0x40)
#define REX_SET_W(x, v) ((x) |= ((v) ? 0x8 : 0))
#define REX_SET_R(x, v) ((x) |= ((v) ? 0x4 : 0))
#define REX_SET_X(x, v) ((x) |= ((v) ? 0x2 : 0))
#define REX_SET_B(x, v) ((x) |= ((v) ? 0x1 : 0))

bool ia32_decode_rex(const unsigned char* addr, ia32_prefixes& pref,
                     ia32_locations *loc)
{
   if (REX_ISREX(addr[0])) {
     
      ++pref.count;
      pref.prfx[4] = addr[0];

      if (loc) {
         loc->rex_byte = addr[0];
         loc->rex_w = REX_W(addr[0]);
         loc->rex_r = REX_R(addr[0]);
         loc->rex_x = REX_X(addr[0]);
         loc->rex_b = REX_B(addr[0]);
         loc->rex_position = pref.count - 1;
      }
      
      // it is an error to have legacy prefixes after a REX prefix
      // in particular, ia32_decode will get confused if a prefix
      // that could be used as an SSE opcode extension follows our
      // REX
      if (addr[1] == PREFIX_SZOPER || addr[1] == PREFIX_REPNZ || addr[1] == PREFIX_REP)
      {
         return false;
      }
   }

   return true;
}

unsigned int ia32_emulate_old_type(ia32_instruction& instruct)
{
  const ia32_prefixes& pref = instruct.prf;
  unsigned int& insnType = instruct.legacy_type;

  unsigned int operSzAttr = getOperSz(pref);

  if (pref.getPrefix(0)) // no distinction between these
    insnType |= PREFIX_INST;
  if (pref.getPrefix(3) == PREFIX_SZADDR)
    insnType |= PREFIX_ADDR;
  if (pref.getPrefix(2) == PREFIX_SZOPER)
    insnType |= PREFIX_OPR;
  if (pref.getPrefix(1))
    insnType |= PREFIX_SEG; // no distinction between segments
  if (mode_64 && pref.getPrefix(4))
    insnType |= PREFIX_REX;
  if (pref.getOpcodePrefix())
      insnType |= PREFIX_OPCODE;

  // this still works for AMD64, since there is no "REL_Q"
  // actually, it will break if there is both a REX.W and operand
  // size prefix, since REX.W takes precedence (FIXME)
  if (insnType & REL_X) {
    if (operSzAttr == 1)
      insnType |= REL_W;
    else
      insnType |= REL_D;
  }
  else if (insnType & PTR_WX) {
    if (operSzAttr == 1)
      insnType |= PTR_WW;
    else
      insnType |= PTR_WD;
  }

  // AMD64 rip-relative data
  if (instruct.hasRipRelativeData())
      insnType |= REL_D_DATA;

  return insnType;
}

/* decode instruction at address addr, return size of instruction */
unsigned get_instruction(const unsigned char* addr, unsigned &insnType,
			 const unsigned char** op_ptr)
{
  int r1;

  ia32_instruction i;
  ia32_decode(0, addr, i);

  r1 = i.getSize();
  insnType = ia32_emulate_old_type(i);
  if (op_ptr)
      *op_ptr = addr + i.getPrefixCount();

  return r1;
}

// find the target of a jump or call
Address get_target(const unsigned char *instr, unsigned type, unsigned size,
		   Address addr) {
#if defined(os_vxworks)
    Address ret;
    // FIXME requires vxworks in Dyninst
    if (relocationTarget(addr+1, &ret))
        return ret;
#endif
  int disp = displacement(instr, type);
  return (Address)(addr + size + disp);
}

// get the displacement of a jump or call
int displacement(const unsigned char *instr, unsigned type) {

  int disp = 0;
  //skip prefix
  instr = skip_headers( instr );

  if (type & REL_D_DATA) {
    // Some SIMD instructions have a mandatory 0xf2 prefix; the call to skip_headers
    // doesn't skip it and I don't feel confident in changing that - bernat, 22MAY06
      // 0xf3 as well...
      // Some 3-byte opcodes start with 0x66... skip
      if (*instr == 0x66) instr++;
      if (*instr == 0xf2) instr++;
      else if (*instr == 0xf3) instr++;
    // And the "0x0f is a 2-byte opcode" skip
    if (*instr == 0x0F) instr++;
    // Skip the instr opcode and the MOD/RM byte
    disp = *(const int *)(instr+2);
  } else if (type & IS_JUMP) {
    if (type & REL_B) {
      disp = *(const char *)(instr+1);
    } else if (type & REL_W) {
      disp = *(const short *)(instr+1); // skip opcode
    } else if (type & REL_D) {
      disp = *(const int *)(instr+1);
    }
  } else if (type & IS_JCC) {
    if (type & REL_B) {
      disp = *(const char *)(instr+1);
    } else if (type & REL_W) {
      disp = *(const short *)(instr+2); // skip two byte opcode
    } else if (type & REL_D) {
      disp = *(const int *)(instr+2);   // skip two byte opcode
    }
  } else if (type & IS_CALL) {
    if (type & REL_W) {
      disp = *(const short *)(instr+1); // skip opcode
    } else if (type & REL_D) {
      disp = *(const int *)(instr+1);
    }
  }  

  return disp;
}

int count_prefixes(unsigned insnType) {
  unsigned nPrefixes = 0;
  if (insnType & PREFIX_OPR)
    nPrefixes++;
  if (insnType & PREFIX_SEG)
    nPrefixes++;
  if (insnType & PREFIX_OPCODE)
    nPrefixes++;
  if (insnType & PREFIX_REX)
    nPrefixes++;
  if (insnType & PREFIX_INST)
    nPrefixes++;
  if (insnType & PREFIX_ADDR)
    nPrefixes++;
  return nPrefixes;
}

unsigned copy_prefixes(const unsigned char *&origInsn, unsigned char *&newInsn, unsigned insnType) {
  unsigned nPrefixes = count_prefixes(insnType);

  for (unsigned u = 0; u < nPrefixes; u++)
     *newInsn++ = *origInsn++;
  return nPrefixes;
}

//Copy all prefixes but the Operand-Size and Address-Size prefixes (0x66 and 0x67)
unsigned copy_prefixes_nosize(const unsigned char *&origInsn, unsigned char *&newInsn, 
                              unsigned insnType) 
{
  unsigned nPrefixes = count_prefixes(insnType);

  for (unsigned u = 0; u < nPrefixes; u++) {
     if (*origInsn == 0x66 || *origInsn == 0x67)
     {
        origInsn++;
        continue;
     }
     *newInsn++ = *origInsn++;
  }
  return nPrefixes;
}

bool convert_to_rel8(const unsigned char*&origInsn, unsigned char *&newInsn) {
  if (*origInsn == 0x0f)
    origInsn++;

  // We think that an opcode in the 0x8? range can be mapped to an equivalent
  // opcode in the 0x7? range...

  if ((*origInsn >= 0x70) &&
      (*origInsn < 0x80)) {
    *newInsn++ = *origInsn++;
    return true;
  }

  if ((*origInsn >= 0x80) &&
      (*origInsn < 0x90)) {
    *newInsn++ = *origInsn++ - 0x10;
    return true;
  }

  if (*origInsn == 0xE3) {
    *newInsn++ = *origInsn++;
    return true;
  }

  // Oops...
  fprintf(stderr, "Unhandled jump conversion case: opcode is 0x%x\n", *origInsn);
  assert(0 && "Unhandled jump conversion case!");
  return false;
}

bool convert_to_rel32(const unsigned char*&origInsn, unsigned char *&newInsn) {
  if (*origInsn == 0x0f)
    origInsn++;
  *newInsn++ = 0x0f;

  // We think that an opcode in the 0x7? range can be mapped to an equivalent
  // opcode in the 0x8? range...

  if ((*origInsn >= 0x70) &&
      (*origInsn < 0x80)) {
    *newInsn++ = *origInsn++ + 0x10;
    return true;
  }

  if ((*origInsn >= 0x80) &&
      (*origInsn < 0x90)) {
    *newInsn++ = *origInsn++;
    return true;
  }

  // Oops...
  fprintf(stderr, "Unhandled jump conversion case: opcode is 0x%x\n", *origInsn);
  assert(0 && "Unhandled jump conversion case!");
  return false;
}
  


//Determine appropriate scale, index, and base given SIB byte.
void decode_SIB(unsigned sib, unsigned& scale, Register& index_reg, Register& base_reg){
  scale = sib >> 6;
  
  //scale = 2^scale
  if(scale == 0)
    scale = 1;
  else if(scale == 1)
    scale = 2;
  else if(scale == 2)
    scale = 4;
  else if(scale == 3)
    scale = 8;

  index_reg = (sib >> 3) & 0x07;
  base_reg = sib & 0x07;
}

const unsigned char*
skip_headers(const unsigned char* addr, ia32_prefixes* prefs)
{
  ia32_prefixes default_prefs;
  if (prefs == NULL)
      prefs = &default_prefs;
  ia32_decode_prefixes(addr, *prefs);
  return addr + prefs->getCount();
}

bool insn_hasSIB(unsigned ModRMbyte,unsigned& Mod,unsigned& Reg,unsigned& RM){
    Mod = (ModRMbyte >> 6) & 0x03;
    Reg = (ModRMbyte >> 3) & 0x07;
    RM = ModRMbyte & 0x07;
    return ((Mod != 3) && (RM == 4));
}

bool insn_hasDisp8(unsigned ModRMbyte){
    unsigned Mod = (ModRMbyte >> 6) & 0x03;
    return (Mod == 1);
}

bool insn_hasDisp32(unsigned ModRMbyte){
    unsigned Mod = (ModRMbyte >> 6) & 0x03;
    /* unsigned Reg = (ModRMbyte >> 3) & 0x07; */
    unsigned RM = ModRMbyte & 0x07;
    return (Mod == 0 && RM == 5) || (Mod == 2);
}

// We keep an array-let that represents various fixed
// insns
unsigned char illegalRep[2] = {0x0f, 0x0b};
unsigned char trapRep[1] = {0xCC};
 

const char* ia32_entry::name(ia32_locations* loc)
{
  dyn_hash_map<entryID, string>::const_iterator found = entryNames_IAPI.find(id);
  if(found != entryNames_IAPI.end())
  {
    return found->second.c_str();
  }
  if(loc)
  {
    if(otable == t_grp && (tabidx == Grp2 || tabidx == Grp11))
    {
      int reg = loc->modrm_reg;
      found = entryNames_IAPI.find(groupMap[tabidx][reg].id);
      if(found != entryNames_IAPI.end())
      {
	return found->second.c_str();
      }
    }
  }
  return NULL;
}

entryID ia32_entry::getID(ia32_locations* l) const
{
  if((id != e_No_Entry) || (tabidx == t_done) || (l == NULL))
  {
    return id;
  }
  int reg = l->modrm_reg;
  switch(otable)
  {
  case t_grp:
    switch(tabidx)
    {
    case Grp2:
    case Grp11:
      return groupMap[tabidx][reg].id;
      break;
    default:
      break;
    }
  case t_coprocEsc:
      return e_fp_generic;
      case t_3dnow:
          return e_3dnow_generic;
      default:
    break;
  }
  return id;
}

Address get_immediate_operand(instruction *instr)
{
    ia32_memacc mac[3];
    ia32_condition cond;
    ia32_locations loc;
    ia32_instruction detail(mac,&cond,&loc);

    ia32_decode(IA32_FULL_DECODER,(const unsigned char *)(instr->ptr()),detail);

    // now find the immediate value in the locations
    Address immediate = 0;

    switch(loc.imm_size[0]) {
        case 8:
            immediate = *(const unsigned long*)(instr->ptr()+loc.imm_position[0]);
            break;
        case 4:
            immediate = *(const unsigned int*)(instr->ptr()+loc.imm_position[0]);
            break;
        case 2:
            immediate = *(const unsigned short*)(instr->ptr()+loc.imm_position[0]);
            break;
        case 1:
            immediate = *(const unsigned char*)(instr->ptr()+loc.imm_position[0]);
            break;
        default:
            fprintf(stderr,"%s[%u]:  invalid immediate size %d in insn\n",
                FILE__,__LINE__,loc.imm_size[0]);
            break;
    }

    return immediate;
}

// get the displacement of a relative jump or call

int get_disp(instruction *insn) {
  return displacement(insn->ptr(), insn->type());
}

bool isStackFramePrecheck_gcc( const unsigned char *buffer )
{
   //Currently enabled entry bytes for gaps:
   //  0x55 - push %ebp
   static char gap_initial_bytes[] =
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   return (gap_initial_bytes[*buffer] != 0);
}  

bool isStackFramePrecheck_msvs( const unsigned char *buffer )
{
   //Currently enabled entry bytes for gaps:
   //  0x55 - push %ebp
   static char gap_initial_bytes[] =
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   return (gap_initial_bytes[*buffer] != 0);
}  

/*
bool isStackFramePreamble( instruction& insn1 )
{       
    instruction insn2, insn3;
    insn2.setInstruction( insn1.ptr() + insn1.size() );       
    insn3.setInstruction( insn2.ptr() + insn2.size() );

    const unsigned char* p = insn1.op_ptr();
    const unsigned char* q = insn2.op_ptr();
    const unsigned char* r = insn3.op_ptr();
    
    unsigned Mod1_1 =  ( q[ 1 ] >> 3 ) & 0x07;
    unsigned Mod1_2 =  q[ 1 ] & 0x07;
    unsigned Mod2_1 =  ( r[ 1 ] >> 3 ) & 0x07;
    unsigned Mod2_2 =  r[ 1 ] & 0x07;

    if( insn1.size() != 1 )
    {
        return false;  //shouldn't need this, but you never know
    }
    
    if( p[ 0 ] == PUSHEBP  )
    {   
        // Looking for mov %esp -> %ebp in one of the two
        // following instructions.  There are two ways to encode 
        // mov %esp -> %ebp: as '0x8b 0xec' or as '0x89 0xe5'.  
        if( insn2.isMoveRegMemToRegMem() && 
            ((Mod1_1 == 0x05 && Mod1_2 == 0x04) ||
             (Mod1_1 == 0x04 && Mod1_2 == 0x05)))
            return true;

        if( insn3.isMoveRegMemToRegMem() && 
            ((Mod2_1 == 0x05 && Mod2_2 == 0x04) ||
             (Mod2_1 == 0x04 && Mod2_2 == 0x05)))
            return true;
    }
    
    return false;
}
*/

instruction *instruction::copy() const {
    // Or should we copy? I guess it depends on who allocated
    // the memory...
    return new instruction(*this);
}

unsigned instruction::spaceToRelocate() const {
    // List of instructions that might be painful:
    // jumps (displacement will change)
    // call (displacement will change)
    // PC-relative ops

    // TODO: pc-relative ops

    // longJumpSize == size of code needed to get
    // anywhere in memory space.
#if defined(arch_x86_64)
    const int longJumpSize = JUMP_ABS64_SZ;
#else
    const int longJumpSize = JUMP_ABS32_SZ;
#endif


    // Assumption: rewriting calls into immediates will
    // not be larger than rewriting a call into a call...

    if (!((type() & REL_B) ||
	  (type() & REL_W) ||
	  (type() & REL_D) ||
	  (type() & REL_D_DATA))) {
      return size();
    }
    
    // Now that the easy case is out of the way...
    
    if (type() & IS_JUMP) {
      // Worst-case: prefixes + max-displacement branch
      return count_prefixes(type()) + longJumpSize;
    }
    if (type() & IS_JCC) {
      // Jump conditional; jump past jump; long jump
      return count_prefixes(type()) + 2 + 2 + longJumpSize;
    }
    if (type() & IS_CALL) {
      // Worst case is approximated by two long jumps (AMD64) or a REL32 (x86)
      unsigned size;
#if defined(arch_x86_64)
      size = 2*JUMP_ABS64_SZ+count_prefixes(type());
#else
      size = JUMP_SZ+count_prefixes(type());
#endif
      size = (size > CALL_RELOC_THUNK) ? size : CALL_RELOC_THUNK;
      return size;
    }
#if defined(arch_x86_64)
    if (type() & REL_D_DATA) {
      // Worst-case: replace RIP with push of IP, use, and cleanup
      // 8: unknown; previous constant
      return count_prefixes(type()) + size() + 8;
    }
#endif

    assert(0);
    return 0;
}

#if defined(arch_x86_64)
unsigned instruction::jumpSize(long disp, unsigned addr_width) 
{
   if (addr_width == 8 && !is_disp32(disp))
      return JUMP_ABS64_SZ;
   return JUMP_SZ;
}
#else
unsigned instruction::jumpSize(long /*disp*/, unsigned /*addr_width*/) 
{
   return JUMP_SZ;
}
#endif

unsigned instruction::jumpSize(Address from, Address to, unsigned addr_width) 
{
    long disp = to - (from + JUMP_SZ);
    return jumpSize(disp, addr_width);
}

#if defined(arch_x86_64)
unsigned instruction::maxJumpSize(unsigned addr_width) 
{
   if (addr_width == 8)
      return JUMP_ABS64_SZ;
   return JUMP_SZ;
}
#else
unsigned instruction::maxJumpSize(unsigned /*addr_width*/) 
{
   return JUMP_SZ;
}
#endif

bool instruction::isCmp() const {
    if(*op_ptr_ == CMP_EB_GB || *op_ptr_ == CMP_EV_GV ||
       *op_ptr_ == CMP_GB_EB || *op_ptr_ == CMP_GV_EV ||
       *op_ptr_ == CMP_AL_LB || *op_ptr_ == CMP_RAX_LZ)
    {
        return true;
    }

    if(*op_ptr_ == 0x80 || *op_ptr_ == 0x81 || *op_ptr_ == 0x83) 
    {
        // group 1 opcodes -- operation depends on reg (bits 3-5) of
        // modr/m byte
        const unsigned char *p = op_ptr_+1;
        if( (*p & (7<<3)) == (7<<3))
            return true;
    }

    return false;
}

#define SIB_SET_REG(x, y) ((x) |= ((y) & 7))
#define SIB_SET_INDEX(x, y) ((x) |= (((y) & 7) << 3))
#define SIB_SET_SS(x, y) ((x) | (((y) & 3) << 6))

bool instruction::getUsedRegs(pdvector<int> &regs) {
   const unsigned char *insn_ptr = ptr();

   struct ia32_memacc memacc[3];
   struct ia32_condition cond;
   class ia32_locations loc;
   ia32_entry *entry;
   ia32_instruction orig_instr(memacc, &cond, &loc);
   ia32_decode(IA32_DECODE_MEMACCESS | IA32_DECODE_CONDITION,
               insn_ptr, orig_instr);
   entry = orig_instr.getEntry();

   if (orig_instr.getPrefix()->getPrefix(1) != 0)
      //The instruction accesses memory via segment registers.  Disallow.
      return false;
   
   if (loc.modrm_position == -1)
      //Only supporting MOD/RM instructions now
      return false; 

   if (loc.address_size == 1)
      //Don't support 16-bit instructions yet
      return false;

   if (loc.modrm_reg == 4 && !loc.rex_r)
      //The non-memory access register is %rsp/%esp, we can't work with
      // this register due to our register saving techniques.
      return false;

   if (loc.modrm_mod == 3)
      //This instruction doesn't use the MOD/RM to access memory
      return false;

   for (unsigned i=0; i<3; i++) {
      const ia32_operand& op = entry->operands[i];
      if (op.admet == am_O) {
         //The MOD/RM specifies a register that's used
         int regused = loc.modrm_reg;
         if (loc.address_size == 4) {
            regused |= loc.rex_r << 4;
         }
         regs.push_back(regused);
      }
      else if (op.admet == am_reg) {
	//using namespace Dyninst::InstructionAPI;
         //The instruction implicitely references a memory instruction
         switch (op.optype) {
             case x86::iah:   
             case x86::ial:
             case x86::iax:   
             case x86::ieax:
               regs.push_back(REGNUM_RAX);
               if (loc.rex_byte) regs.push_back(REGNUM_R8);
               break;
             case x86::ibh:
             case x86::ibl:
             case x86::ibx:
             case x86::iebx:
               regs.push_back(REGNUM_RBX);
               if (loc.rex_byte) regs.push_back(REGNUM_R11);
               break;
             case x86::ich:
             case x86::icl:
             case x86::icx:
             case x86::iecx:
                 regs.push_back(REGNUM_RCX);
               if (loc.rex_byte) regs.push_back(REGNUM_R9);
               break;
             case x86::idh:
             case x86::idl:
             case x86::idx:
             case x86::iedx:
                 regs.push_back(REGNUM_RDX);
               if (loc.rex_byte) regs.push_back(REGNUM_R10);
               break;
             case x86::isp:
             case x86::iesp:
                regs.push_back(REGNUM_RSP);
               if (loc.rex_byte) regs.push_back(REGNUM_R12);
               break;
             case x86::ibp:
             case x86::iebp:
               regs.push_back(REGNUM_RBP);
               if (loc.rex_byte) regs.push_back(REGNUM_R13);
               break;
             case x86::isi:
             case x86::iesi:
               regs.push_back(REGNUM_RSI);
               if (loc.rex_byte) regs.push_back(REGNUM_R14);
               break;
             case x86::idi:
             case x86::iedi:
               regs.push_back(REGNUM_RDI);
               if (loc.rex_byte) regs.push_back(REGNUM_R15);
               break;
            case op_edxeax:
               regs.push_back(REGNUM_RAX);
               regs.push_back(REGNUM_RDX);
               break;
            case op_ecxebx:
               regs.push_back(REGNUM_RBX);
               regs.push_back(REGNUM_RCX);
               break;
         }
      }
   }
   return true;
}

int instruction::getStackDelta()
{
   ia32_instruction instruc;
   const unsigned char *p = ptr();
   ia32_decode(0, ptr(), instruc);

   if (instruc.getEntry()->id == e_push)
      return -4;
   if (instruc.getEntry()->id == e_pop)
      return 4;
   if (instruc.getEntry()->id == e_pusha)
      return (-2 * 9);
   if (instruc.getEntry()->id == e_pushad)
      return (-4 * 9);
   if (instruc.getEntry()->id == e_popa)
      return (2 * 9);
   if (instruc.getEntry()->id == e_popad)
      return (4 * 9);

   if (p[0] == 0x83 && p[1] == 0xec) {
      //Subtract byte
      return -1 * (signed char) p[2];
   }

   if (p[0] == 0x83 && p[1] == 0xc4) {
      //Add byte
      return (signed char) p[2];
   }
   
   return 0;
}

bool instruction::isNop() const
{ 

   int displacement_location = 0;
   int displacement_size = 0;
   if (!(type_ & IS_NOP)) //NOP or LEA
      return false;

   if (*op_ptr_ == NOP) {
      return true;
   }

   ia32_memacc mac[3];
   ia32_condition cnd;
   ia32_locations loc;

   ia32_instruction instruc(mac, &cnd, &loc);

   ia32_decode(IA32_FULL_DECODER, ptr(), instruc);


   if (instruc.getEntry()->id == e_nop) {
      return true;
   }

   if (loc.modrm_mod == 3) {
      return false;
   }
   if (loc.modrm_mod == 0 && loc.modrm_rm == 5) {
      return false;
   }

   if (loc.rex_x) {
      return false;
   }
   if (loc.rex_r != loc.rex_b) {
      return false;
   }

   if (loc.disp_position != -1) {
      for (unsigned i=0; i<loc.disp_size; i++) {
         if (ptr_[i + loc.disp_position] != 0) {
            return false;
         }
      }
      displacement_location = loc.disp_position;
      displacement_size = loc.disp_size;
   }
   
   if (loc.modrm_rm == 4) {
      unsigned scale;
      Register index, base;
      decode_SIB(loc.sib_byte, scale, index, base);
      
      if (index != 4) {
         return false;
      }

      if (base != loc.modrm_reg) {
         return false;
      }
   }
   else if (loc.modrm_reg != loc.modrm_rm) {
      return false;
   }


   return true;
}

} // namespace arch_x86
