/*BEGIN_LEGAL Intel Open Source License Copyright (c) 2002-2005 Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. END_LEGAL */ /// @file xed-gheaders.H /// @author Mark Charney //////////////////////////////////////////////////////////////////////////// #ifndef _XED_GHEADERS_H_ # define _XED_GHEADERS_H_ #include "xed-types.H" #include "xed-reg-class.H" #include "rexr.H" #include "rexb.H" #include "rexx.H" #include "rexw.H" #include "m64width.H" #include "modrm-mod.H" #include "x87-opcode-enum.H" #include "operand-code.H" #include "memop.H" #include "operand-width.H" #include "operand-width-index.H" #include "address-width.H" #include "xed-operand.H" #include "opvis.H" #include "xed-opnd-action.H" #include "xed-prefix-enum.H" #include "prefix-index.H" #include "xed-iclass.H" #include "displacement.H" #include "xed-group-opcode-maps.H" #include "xed-x87-cond-code-enum.H" #include "regs.H" #include "xed-modes.H" #include "xed-machine-modes.H" #include "xed-flags.H" //rflags #include "xed-tcode.H" #include "xed-resource.H" #include "xed-pseudo-res.H" #include "xed-encoder-subtable.H" #include "xed-category.H" #include "xed-extension.H" #include "xed-opnd-class.H" #include "xed-opcode-match.H" #include "xed-common-defs.H" namespace XED { using namespace std; #define MAX_GPRS 16 #define MODRM_MOD_MAX 4 #define MODRM_REG_MAX 8 #define MODRM_RM_MAX 8 #define SIB_SCALE_MAX 4 #define SIB_INDEX_MAX 8 #define SIB_BASE_MAX 8 #define SIB_BASE_MAX 8 #define MAX_ONE_BYTE_VALUES 0x100 /// These are the internal operands template tables. class xed_operand_template_t { public: xed_operand_enum_t opnd; xed_opvis_enum_t opvis; xed_opnd_action_t rw; xed_operand_template_t() // CONS : opnd(XED_OPERAND_NA), opvis(XED_OPVIS_INVALID), rw(XED_OPND_ACTION_INVALID) { } inline xed_operand_enum_t get_opnd() const { return opnd; } inline bool reads() const { ///< reads or read+writes return rw == XED_OPND_ACTION_R || rw == XED_OPND_ACTION_RW; } inline bool writes() const { ///< writes or reads+writes return rw == XED_OPND_ACTION_W || rw == XED_OPND_ACTION_RW; } inline bool reads_and_writes() const { ///< reads-and-writes return rw == XED_OPND_ACTION_RW; } inline void set( xed_operand_enum_t arg_opnd, xed_opvis_enum_t arg_opvis, xed_opnd_action_t arg_rw ) { opnd = arg_opnd; opvis = arg_opvis; // AGEN's do not allow for r/w action // if (opnd == XED_OPERAND_AGEN) { // rw = XED_OPND_ACTION_INVALID; // } // else { rw = arg_rw; } } inline void zero() { opnd = XED_OPERAND_NA; opvis = XED_OPVIS_INVALID; rw = XED_OPND_ACTION_INVALID; } inline bool invalid() const { return (opnd == XED_OPERAND_NA); } #if XED_PRINT==1 void print(ostream& o) const { o << opnd << "/" << opvis << "/" << rw; } #endif xed_opvis_enum_t get_opvis() const { return opvis; } bool is_implicit() const { // implicit-expressed return opvis == XED_OPVIS_IMPLICIT; } bool is_suppressed() const { // implicit-suppressed return opvis == XED_OPVIS_SUPPRESSED; } bool is_explicit() const { // explicit (normal case) return opvis == XED_OPVIS_EXPLICIT; } bool expressed() const { // expressed -- explicit ops or implicit-expressed ops return is_explicit() || is_implicit(); } }; #if XED_PRINT==1 XED_DLL_EXPORT ostream& operator<<(ostream& o, const xed_operand_template_t& x); #endif /// The first half of the "split codes" used to describe operand type. (Eb, Gv, etc.) class xed_operand_code_first_t { public: bool modrm; xed_reg_class_t reg_class; xed_memop_enum_t memop; xed_operand_code_first_t() // CONS : modrm(false), reg_class(XED_REG_CLASS_INVALID), memop(XED_MEMOP_INVALID) { } }; /// The valid widths for each operand code class xed_operand_code_width_t { public: opnd_width_t width1; opnd_width_t width2; opnd_width_t width3; xed_operand_code_width_t() //CONS : width1(OPND_WIDTH_INVALID), width2(OPND_WIDTH_INVALID), width3(OPND_WIDTH_INVALID) { } }; /// This is the base opcode class. All the other opcode classes are /// derived from xed_opcode_base_t. It provides the common variables /// present in all the derived opcodes. The derived opcodes often /// add other fields like refining prefixes. These opcodes come from /// big tables in XED. class xed_opcode_base_t { public: xed_tcode_t tcode :6 ; ///< type code for decoding m64_width_t m64_width :2 ; ///< Default width in 64b mode xed_iclass_t cls :16 ; ///< The instruction class (ADD, SUB, etc.) xed_operand_template_t op[XED_MAX_OPERANDS]; ///< operand templates. Before decoding. xedmode_enum_t mode :6 ; ///< mode restrictions for decoding bool modrm :1 ; ///< Uses modrm byte bool _valid_opcode :1 ; ///< is this a non-instruction opcode (prefix, etc.) or part of a valid instruction xed_category_t category :8 ; ///< Like an ALU class xed_extension_t extension :8 ; ///< ISA extension (MMX,SSE,SSE2, SSE3, VTx...) opnd_width_t width :8 ; ///< Operation width used to override default widths /// could be used for 1st opcode byte, 2nd opcode byte or 3DNow /// immed opcode. UINT8 opcode1; public: /// Constructor xed_opcode_base_t(UINT8 arg_opcode1=0) // CONS : tcode(XEDTCODE_N), m64_width(M64_WIDTH_NRMW), cls(XEDICLASS_INVALID), mode(XEDMODE_ALL_MODES), modrm(false), _valid_opcode(false), category(XED_CATEGORY_INVALID), extension(XED_EXTENSION_INVALID), width(OPND_WIDTH_DEFAULT), opcode1(arg_opcode1) { } virtual ~xed_opcode_base_t() { } virtual xed_prefix_enum_t get_refining_prefix() const { return XED_PREFIX_INVALID; } /// @name Internal routines for XED -- ignore //@{ /// Identifies which modes this opcode is valid for. Restricts the /// decoding to specific modes. inline xedmode_enum_t get_mode() const { return mode; } inline bool two_byte_modrm_opcode() const { return (tcode == XEDTCODE_T); } inline bool prefetch() const { return (tcode == XEDTCODE_P); } inline bool lockable_if_accesses_memory() const { return (tcode == XEDTCODE_M) || (tcode == XEDTCODE_MW); } inline bool rexw_required() const { return (tcode == XEDTCODE_W) || (tcode == XEDTCODE_MW); } inline bool rep_able_opcode() const { // able to have a rep-prefix return (tcode == XEDTCODE_Q); } inline bool x87_escape() const { // These require a modrm return (tcode == XEDTCODE_F); } inline bool external_decoder_escape() const { return (tcode == XEDTCODE_C); } inline bool escape() const { // Two byte opcodes return (cls == XEDICLASS_ESCAPE); } inline bool escape_3B() const { // three byte opcodes return (tcode == XEDTCODE_3); } inline bool three_byte_opcode() const { // three byte opcodes return (tcode == XEDTCODE_Z); } inline bool valid_opcode() const { return _valid_opcode; } inline bool invalid() const { return (cls == XEDICLASS_INVALID); } inline bool group_opcode() const { return (tcode == XEDTCODE_G); } inline bool amd_3dnow_opcode() const { return (tcode == XEDTCODE_U); } /// Set the instruction ALU category inline void set_category(xed_category_t arg_category) { category = arg_category; } /// Set the instruction ISA extension inline void set_extension(xed_extension_t arg_extension) { extension = arg_extension; } // Set the first opcode, category, and extension inline void set_opc_cls_cat_ext(xed_iclass_t arg_cls, UINT8 arg_opcode, xed_category_t arg_cat, xed_extension_t arg_ext, xed_tcode_t arg_tcode) { opcode1 = arg_opcode; cls = arg_cls; category = arg_cat; extension = arg_ext; set_tcode(arg_tcode); } void set_valid_opcode() { switch(tcode) { case XEDTCODE_X: case XEDTCODE_S: case XEDTCODE_O: case XEDTCODE_A: case XEDTCODE_L: case XEDTCODE_R: break; default: _valid_opcode = true; break; } } inline void set_tcode(xed_tcode_t t) { tcode = t; set_valid_opcode(); } /// set the instruction class and the string name. void set( xed_iclass_t arg_cls ) { cls = arg_cls; } /// Get the number of template operands -- slow -- this counts them inline unsigned int get_noperands() const { /// VERY SLOW - returns the number of /// operands in the op[] array. int nopnd = 0; for( ; !op[nopnd].invalid() && nopnd < XED_MAX_OPERANDS ; nopnd++ ) { } return nopnd; } /// get a specific operand template inline const xed_operand_template_t& get_operand_template(int indx) const { assert(indx < XED_MAX_OPERANDS); return op[indx]; } void set_operand(int indx, const xed_operand_enum_t opnd, const xed_opvis_enum_t opvis = XED_OPVIS_EXPLICIT, const xed_opnd_action_t rw = XED_OPND_ACTION_RW) { assert(indx < XED_MAX_OPERANDS); //FIXME: check if the opnd's OC1_ is an OC1_I if (opnd != XED_OPERAND_NA) { op[indx].set(opnd,opvis,rw); } } //@} /// @name Accessors for instruction information //@{ inline bool default_width() const { return (width == OPND_WIDTH_DEFAULT); } inline bool byte_width() const { return (width == OPND_WIDTH_8b); } /// True if the instruction defaults to 64b width. No REX prefix /// required (unless register names need it). inline bool default_64b_width() const { return m64_width == M64_WIDTH_DF64; } /// The instruction name inline xed_iclass_t get_iclass() const { return cls; } /// The instruction category or type, roughly based on function units used to execute the instruction inline xed_category_t get_category() const { return category; } /// The ISA extension that added this instruction. inline xed_extension_t get_extension() const { return extension; } /// Get the opcode associated with this instruction inline UINT8 get_opcode() const { return opcode1; } //@} #if XED_PRINT==1 /// @name Printing & Debugging //@{ /// print the opcode information void print(ostream& o) const { ostream::fmtflags oflags = o.flags(); o << cls << " "; sub_print_prefix(o); o << hex << std::setfill('0') << "0x" << std::setw(2); o << (int)opcode1 << dec << std::setfill(' ') <<" "; sub_print(o); o << " " << mode << " " << tcode << " " << m64_width << " " << opnd_print(); o.flags(oflags); } /// Print the actual operands inline string opnd_print() const { ostringstream s; for(int i=0;i