diff options
Diffstat (limited to 'contrib/binutils/include/opcode/cgen.h')
-rw-r--r-- | contrib/binutils/include/opcode/cgen.h | 671 |
1 files changed, 429 insertions, 242 deletions
diff --git a/contrib/binutils/include/opcode/cgen.h b/contrib/binutils/include/opcode/cgen.h index cda3373..ab59f24 100644 --- a/contrib/binutils/include/opcode/cgen.h +++ b/contrib/binutils/include/opcode/cgen.h @@ -1,6 +1,6 @@ /* Header file for targets using CGEN: Cpu tools GENerator. -Copyright (C) 1996, 1997 Free Software Foundation, Inc. +Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of GDB, the GNU debugger, and the GNU Binutils. @@ -14,22 +14,13 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef CGEN_H #define CGEN_H -#ifndef CGEN_CAT3 -#if defined(__STDC__) || defined(ALMOST_STDC) -#define CGEN_XCAT3(a,b,c) a ## b ## c -#define CGEN_CAT3(a,b,c) CGEN_XCAT3 (a, b, c) -#else -#define CGEN_CAT3(a,b,c) a/**/b/**/c -#endif -#endif - /* Prepend the cpu name, defined in cpu-opc.h, and _cgen_ to symbol S. The lack of spaces in the arg list is important for non-stdc systems. This file is included by <cpu>-opc.h. @@ -37,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ dependent portions will be declared as "unknown_cgen_foo". */ #ifndef CGEN_SYM -#define CGEN_SYM(s) CGEN_CAT3 (unknown,_cgen_,s) +#define CGEN_SYM(s) CONCAT3 (unknown,_cgen_,s) #endif /* This file contains the static (unchanging) pieces and as much other stuff @@ -60,7 +51,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef CGEN_INT_INSN typedef unsigned int cgen_insn_t; #else -typedef char *cgen_insn_t; +typedef char * cgen_insn_t; #endif #ifdef __GNUC__ @@ -71,7 +62,8 @@ typedef char *cgen_insn_t; /* Perhaps we should just use bfd.h, but it's not clear one would want to require that yet. */ -enum cgen_endian { +enum cgen_endian +{ CGEN_ENDIAN_UNKNOWN, CGEN_ENDIAN_LITTLE, CGEN_ENDIAN_BIG @@ -81,8 +73,9 @@ enum cgen_endian { Attributes are used to describe various random things. */ /* Struct to record attribute information. */ -typedef struct { - unsigned int num_nonbools; +typedef struct +{ + unsigned char num_nonbools; unsigned int bool; unsigned int nonbool[1]; } CGEN_ATTR; @@ -94,13 +87,17 @@ typedef struct { nonbool: values of non-boolean attributes There is a maximum of 32 attributes total. */ #define CGEN_ATTR_TYPE(n) \ -const struct { unsigned int num_nonbools; \ +const struct { unsigned char num_nonbools; \ unsigned int bool; \ unsigned int nonbool[(n) ? (n) : 1]; } /* Given an attribute number, return its mask. */ #define CGEN_ATTR_MASK(attr) (1 << (attr)) +/* Return the value of boolean attribute ATTR in ATTRS. */ +#define CGEN_BOOL_ATTR(attrs, attr) \ +((CGEN_ATTR_MASK (attr) & (attrs)) != 0) + /* Return value of attribute ATTR in ATTR_TABLE for OBJ. OBJ is a pointer to the entity that has the attributes. It's not used at present but is reserved for future purposes. */ @@ -108,6 +105,24 @@ const struct { unsigned int num_nonbools; \ ((unsigned int) (attr) < (attr_table)->num_nonbools \ ? ((attr_table)->nonbool[attr]) \ : (((attr_table)->bool & (1 << (attr))) != 0)) + +/* Attribute name/value tables. + These are used to assist parsing of descriptions at runtime. */ + +typedef struct +{ + const char * name; + int value; +} CGEN_ATTR_ENTRY; + +/* For each domain (fld,operand,insn), list of attributes. */ + +typedef struct +{ + const char * name; + /* NULL for boolean attributes. */ + const CGEN_ATTR_ENTRY * vals; +} CGEN_ATTR_TABLE; /* Parse result (also extraction result). @@ -125,7 +140,7 @@ const struct { unsigned int num_nonbools; \ where it varies. */ -struct cgen_fields; +typedef struct cgen_fields CGEN_FIELDS; /* Total length of the insn, as recorded in the `fields' struct. */ /* ??? The field insert handler has lots of opportunities for optimization @@ -151,7 +166,7 @@ typedef struct cgen_insn CGEN_INSN; The result is NULL if success or an error message. */ typedef const char * (cgen_parse_fn) PARAMS ((const struct cgen_insn *, const char **, - struct cgen_fields *)); + CGEN_FIELDS *)); /* Print handler. The first argument is a pointer to the disassembly info. @@ -165,7 +180,7 @@ typedef const char * (cgen_parse_fn) PARAMS ((const struct cgen_insn *, /* Don't require bfd.h unnecessarily. */ #ifdef BFD_VERSION typedef void (cgen_print_fn) PARAMS ((PTR, const struct cgen_insn *, - struct cgen_fields *, bfd_vma, int)); + CGEN_FIELDS *, bfd_vma, int)); #else typedef void (cgen_print_fn) (); #endif @@ -175,9 +190,10 @@ typedef void (cgen_print_fn) (); parsed. The second argument is a pointer to a cgen_fields struct from which the values are fetched. - The third argument is a pointer to a buffer in which to place the insn. */ -typedef void (cgen_insert_fn) PARAMS ((const struct cgen_insn *, - struct cgen_fields *, cgen_insn_t *)); + The third argument is a pointer to a buffer in which to place the insn. + The result is an error message or NULL if success. */ +typedef const char * (cgen_insert_fn) PARAMS ((const struct cgen_insn *, + CGEN_FIELDS *, cgen_insn_t *)); /* Extract handler. The first argument is a pointer to a struct describing the insn being @@ -190,7 +206,7 @@ typedef void (cgen_insert_fn) PARAMS ((const struct cgen_insn *, The result is the length of the insn or zero if not recognized. */ typedef int (cgen_extract_fn) PARAMS ((const struct cgen_insn *, void *, cgen_insn_t, - struct cgen_fields *)); + CGEN_FIELDS *)); /* The `parse' and `insert' fields are indices into these tables. The elements are pointer to specialized handler functions. @@ -207,127 +223,155 @@ extern cgen_print_fn * CGEN_SYM (print_handlers) []; #define CGEN_PRINT_FN(x) (CGEN_SYM (print_handlers)[(x)->base.print]) /* Base class of parser/printer. - (Don't read too much into the use of the phrase "base class"). + (Don't read too much into the use of the phrase "base class". + It's a name I'm using to organize my thoughts.) Instructions and expressions all share this data in common. - It's a collection of the common elements needed to parse and print - each of them. */ + It's a collection of the common elements needed to parse, insert, extract, + and print each of them. */ -#ifndef CGEN_MAX_INSN_ATTRS -#define CGEN_MAX_INSN_ATTRS 1 -#endif - -struct cgen_base { +struct cgen_base +{ /* Indices into the handler tables. We could use pointers here instead, but in the case of the insn table, 90% of them would be identical and that's a lot of redundant data. 0 means use the default (what the default is is up to the code). */ unsigned char parse, insert, extract, print; - - /* Attributes. */ - CGEN_ATTR_TYPE (CGEN_MAX_INSN_ATTRS) attrs; }; -/* Syntax table. +/* Assembler interface. - Each insn and subexpression has one of these. + The interface to the assembler is intended to be clean in the sense that + libopcodes.a is a standalone entity and could be used with any assembler. + Not that one would necessarily want to do that but rather that it helps + keep a clean interface. The interface will obviously be slanted towards + GAS, but at least it's a start. - The syntax "string" consists of characters (n > 0 && n < 128), and operand - values (n >= 128), and is terminated by 0. Operand values are 128 + index - into the operand table. The operand table doesn't exist in C, per se, as - the data is recorded in the parse/insert/extract/print switch statements. + Parsing is controlled by the assembler which calls + CGEN_SYM (assemble_insn). If it can parse and build the entire insn + it doesn't call back to the assembler. If it needs/wants to call back + to the assembler, (*cgen_parse_operand_fn) is called which can either - ??? Whether we want to use yacc instead is unclear, but we do make an - effort to not make doing that difficult. At least that's the intent. -*/ + - return a number to be inserted in the insn + - return a "register" value to be inserted + (the register might not be a register per pe) + - queue the argument and return a marker saying the expression has been + queued (eg: a fix-up) + - return an error message indicating the expression wasn't recognizable -struct cgen_syntax { - /* Original syntax string, for debugging purposes. */ - char *orig; + The result is an error message or NULL for success. + The parsed value is stored in the bfd_vma *. */ - /* Name of entry (that distinguishes it from all other entries). - This is used, for example, in simulator profiling results. */ - char *name; +/* Values for indicating what the caller wants. */ +enum cgen_parse_operand_type +{ + CGEN_PARSE_OPERAND_INIT, + CGEN_PARSE_OPERAND_INTEGER, + CGEN_PARSE_OPERAND_ADDRESS +}; + +/* Values for indicating what was parsed. + ??? Not too useful at present but in time. */ +enum cgen_parse_operand_result +{ + CGEN_PARSE_OPERAND_RESULT_NUMBER, + CGEN_PARSE_OPERAND_RESULT_REGISTER, + CGEN_PARSE_OPERAND_RESULT_QUEUED, + CGEN_PARSE_OPERAND_RESULT_ERROR +}; -#if 0 /* not needed yet */ - /* Format of this insn. - This doesn't closely follow the notion of instruction formats for more - complex instruction sets. This is the value computed at runtime. */ - enum cgen_fmt_type fmt; +/* Don't require bfd.h unnecessarily. */ +#ifdef BFD_VERSION +extern const char * (*cgen_parse_operand_fn) + PARAMS ((enum cgen_parse_operand_type, const char **, int, int, + enum cgen_parse_operand_result *, bfd_vma *)); #endif - /* Mnemonic (or name if expression). */ - char *mnemonic; +/* Called before trying to match a table entry with the insn. */ +void cgen_init_parse_operand PARAMS ((void)); - /* Syntax string. */ - /* FIXME: If each insn's mnemonic is constant, do we want to record just - the arguments here? */ -#ifndef CGEN_MAX_SYNTAX_BYTES -#define CGEN_MAX_SYNTAX_BYTES 16 -#endif - unsigned char syntax[CGEN_MAX_SYNTAX_BYTES]; +/* Called from <cpu>-asm.c to initialize operand parsing. */ -#define CGEN_SYNTAX_CHAR_P(c) ((c) < 128) -#define CGEN_SYNTAX_CHAR(c) (c) -#define CGEN_SYNTAX_FIELD(c) ((c) - 128) +/* These are GAS specific. They're not here as part of the interface, + but rather that we need to put them somewhere. */ - /* recognize insn if (op & mask) == value - For architectures with variable length insns, this is just a preliminary - test. */ - /* FIXME: Might want a selectable type (rather than always - unsigned long). */ - unsigned long mask, value; +/* Call this from md_assemble to initialize the assembler callback. */ +void cgen_asm_init_parse PARAMS ((void)); - /* length, in bits - This is the size that `mask' and `value' have been calculated to. - Normally it is CGEN_BASE_INSN_BITSIZE. On vliw architectures where - the base insn size may be larger than the size of an insn, this field is - less than CGEN_BASE_INSN_BITSIZE. - On architectures like the 386 and m68k the real size of the insn may - be computed while parsing. */ - /* FIXME: wip, of course */ - int length; -}; +/* Don't require bfd.h unnecessarily. */ +#ifdef BFD_VERSION +/* The result is an error message or NULL for success. + The parsed value is stored in the bfd_vma *. */ +const char * cgen_parse_operand PARAMS ((enum cgen_parse_operand_type, + const char **, int, int, + enum cgen_parse_operand_result *, + bfd_vma *)); +#endif + +void cgen_save_fixups PARAMS ((void)); +void cgen_restore_fixups PARAMS ((void)); +void cgen_swap_fixups PARAMS ((void)); + +/* Add a register to the assembler's hash table. + This makes lets GAS parse registers for us. + ??? This isn't currently used, but it could be in the future. */ +void cgen_asm_record_register PARAMS ((char *, int)); + +/* After CGEN_SYM (assemble_insn) is done, this is called to + output the insn and record any fixups. The address of the + assembled instruction is returned in case it is needed by + the caller. */ +char * cgen_asm_finish_insn PARAMS ((const struct cgen_insn *, cgen_insn_t *, + unsigned int)); /* Operand values (keywords, integers, symbols, etc.) */ /* Types of assembler elements. */ -enum cgen_asm_type { +enum cgen_asm_type +{ CGEN_ASM_KEYWORD, CGEN_ASM_MAX }; /* List of hardware elements. */ -typedef struct cgen_hw_entry { - struct cgen_hw_entry *next; - char *name; - enum cgen_asm_type asm_type; - PTR asm_data; +typedef struct cgen_hw_entry +{ + /* The type of this entry, one of `enum hw_type'. + This is an int and not the enum as the latter may not be declared yet. */ + int type; + const struct cgen_hw_entry * next; + char * name; + enum cgen_asm_type asm_type; + PTR asm_data; } CGEN_HW_ENTRY; -extern CGEN_HW_ENTRY *CGEN_SYM (hw_list); - -CGEN_HW_ENTRY *cgen_hw_lookup PARAMS ((const char *)); - -#ifndef CGEN_MAX_KEYWORD_ATTRS -#define CGEN_MAX_KEYWORD_ATTRS 1 -#endif +const CGEN_HW_ENTRY * cgen_hw_lookup PARAMS ((const char *)); /* This struct is used to describe things like register names, etc. */ -typedef struct cgen_keyword_entry { +typedef struct cgen_keyword_entry +{ /* Name (as in register name). */ - char *name; + char * name; /* Value (as in register number). The value cannot be -1 as that is used to indicate "not found". IDEA: Have "FUNCTION" attribute? [function is called to fetch value]. */ int value; - /* Attributes. */ + /* Attributes. + This should, but technically needn't, appear last. It is a variable sized + array in that one architecture may have 1 nonbool attribute and another + may have more. Having this last means the non-architecture specific code + needn't care. */ + /* ??? Moving this last should be done by treating keywords like insn lists + and moving the `next' fields into a CGEN_KEYWORD_LIST struct. */ /* FIXME: Not used yet. */ - CGEN_ATTR_TYPE (CGEN_MAX_KEYWORD_ATTRS) attrs; +#ifndef CGEN_KEYWORD_NBOOL_ATTRS +#define CGEN_KEYWORD_NBOOL_ATTRS 1 +#endif + CGEN_ATTR_TYPE (CGEN_KEYWORD_NBOOL_ATTRS) attrs; /* Next name hash table entry. */ struct cgen_keyword_entry *next_name; @@ -340,93 +384,138 @@ typedef struct cgen_keyword_entry { This struct supports runtime entry of new values, and hashed lookups. */ -typedef struct cgen_keyword { +typedef struct cgen_keyword +{ /* Pointer to initial [compiled in] values. */ - struct cgen_keyword_entry *init_entries; + CGEN_KEYWORD_ENTRY * init_entries; + /* Number of entries in `init_entries'. */ unsigned int num_init_entries; + /* Hash table used for name lookup. */ - struct cgen_keyword_entry **name_hash_table; + CGEN_KEYWORD_ENTRY ** name_hash_table; + /* Hash table used for value lookup. */ - struct cgen_keyword_entry **value_hash_table; + CGEN_KEYWORD_ENTRY ** value_hash_table; + /* Number of entries in the hash_tables. */ unsigned int hash_table_size; + + /* Pointer to null keyword "" entry if present. */ + const CGEN_KEYWORD_ENTRY * null_entry; } CGEN_KEYWORD; /* Structure used for searching. */ -typedef struct cgen_keyword_search { +typedef struct +{ /* Table being searched. */ - const struct cgen_keyword *table; + const CGEN_KEYWORD * table; + /* Specification of what is being searched for. */ - const char *spec; + const char * spec; + /* Current index in hash table. */ unsigned int current_hash; + /* Current element in current hash chain. */ - struct cgen_keyword_entry *current_entry; + CGEN_KEYWORD_ENTRY * current_entry; } CGEN_KEYWORD_SEARCH; /* Lookup a keyword from its name. */ -const struct cgen_keyword_entry * cgen_keyword_lookup_name - PARAMS ((struct cgen_keyword *, const char *)); +const CGEN_KEYWORD_ENTRY * cgen_keyword_lookup_name + PARAMS ((CGEN_KEYWORD *, const char *)); /* Lookup a keyword from its value. */ -const struct cgen_keyword_entry * cgen_keyword_lookup_value - PARAMS ((struct cgen_keyword *, int)); +const CGEN_KEYWORD_ENTRY * cgen_keyword_lookup_value + PARAMS ((CGEN_KEYWORD *, int)); /* Add a keyword. */ -void cgen_keyword_add PARAMS ((struct cgen_keyword *, - struct cgen_keyword_entry *)); +void cgen_keyword_add PARAMS ((CGEN_KEYWORD *, CGEN_KEYWORD_ENTRY *)); /* Keyword searching. This can be used to retrieve every keyword, or a subset. */ -struct cgen_keyword_search cgen_keyword_search_init - PARAMS ((struct cgen_keyword *, const char *)); -const struct cgen_keyword_entry *cgen_keyword_search_next - PARAMS ((struct cgen_keyword_search *)); +CGEN_KEYWORD_SEARCH cgen_keyword_search_init + PARAMS ((CGEN_KEYWORD *, const char *)); +const CGEN_KEYWORD_ENTRY *cgen_keyword_search_next + PARAMS ((CGEN_KEYWORD_SEARCH *)); /* Operand value support routines. */ /* FIXME: some of the long's here will need to be bfd_vma or some such. */ const char * cgen_parse_keyword PARAMS ((const char **, - struct cgen_keyword *, + CGEN_KEYWORD *, long *)); -const char * cgen_parse_signed_integer PARAMS ((const char **, int, - long, long, long *)); +const char * cgen_parse_signed_integer PARAMS ((const char **, int, long *)); const char * cgen_parse_unsigned_integer PARAMS ((const char **, int, - unsigned long, unsigned long, unsigned long *)); -const char * cgen_parse_address PARAMS ((const char **, int, - int, long *)); +const char * cgen_parse_address PARAMS ((const char **, int, int, + enum cgen_parse_operand_result *, + long *)); const char * cgen_validate_signed_integer PARAMS ((long, long, long)); const char * cgen_validate_unsigned_integer PARAMS ((unsigned long, unsigned long, unsigned long)); +/* Operand modes. */ + +/* ??? This duplicates the values in arch.h. Revisit. + These however need the CGEN_ prefix [as does everything in this file]. */ +/* ??? Targets may need to add their own modes so we may wish to move this + to <arch>-opc.h, or add a hook. */ + +enum cgen_mode { + CGEN_MODE_VOID, /* FIXME: rename simulator's VM to VOID */ + CGEN_MODE_BI, CGEN_MODE_QI, CGEN_MODE_HI, CGEN_MODE_SI, CGEN_MODE_DI, + CGEN_MODE_UBI, CGEN_MODE_UQI, CGEN_MODE_UHI, CGEN_MODE_USI, CGEN_MODE_UDI, + CGEN_MODE_SF, CGEN_MODE_DF, CGEN_MODE_XF, CGEN_MODE_TF, + CGEN_MODE_MAX +}; + +/* FIXME: Until simulator is updated. */ +#define CGEN_MODE_VM CGEN_MODE_VOID + /* This struct defines each entry in the operand table. */ -#ifndef CGEN_MAX_OPERAND_ATTRS -#define CGEN_MAX_OPERAND_ATTRS 1 -#endif +typedef struct cgen_operand +{ + /* Name as it appears in the syntax string. */ + char * name; -typedef struct cgen_operand { - /* For debugging. */ - char *name; + /* The hardware element associated with this operand. */ + const CGEN_HW_ENTRY *hw; + + /* FIXME: We don't yet record ifield definitions, which we should. + When we do it might make sense to delete start/length (since they will + be duplicated in the ifield's definition) and replace them with a + pointer to the ifield entry. Note that as more complicated situations + need to be handled, going more and more with an OOP paradigm will help + keep the complication under control. Of course, this was the goal from + the start, but getting there in one step was too much too soon. */ /* Bit position (msb of first byte = bit 0). + This is just a hint, and may be unused in more complex operands. May be unused for a modifier. */ unsigned char start; /* The number of bits in the operand. + This is just a hint, and may be unused in more complex operands. May be unused for a modifier. */ unsigned char length; - /* Attributes. */ - CGEN_ATTR_TYPE (CGEN_MAX_OPERAND_ATTRS) attrs; -#define CGEN_OPERAND_ATTRS(operand) (&(operand)->attrs) - -#if 0 /* ??? Interesting idea but relocs tend to get too complicated for - simple table lookups to work. */ +#if 0 /* ??? Interesting idea but relocs tend to get too complicated, + and ABI dependent, for simple table lookups to work. */ /* Ideally this would be the internal (external?) reloc type. */ int reloc_type; #endif + + /* Attributes. + This should, but technically needn't, appear last. It is a variable sized + array in that one architecture may have 1 nonbool attribute and another + may have more. Having this last means the non-architecture specific code + needn't care, now or tomorrow. */ +#ifndef CGEN_OPERAND_NBOOL_ATTRS +#define CGEN_OPERAND_NBOOL_ATTRS 1 +#endif + CGEN_ATTR_TYPE (CGEN_OPERAND_NBOOL_ATTRS) attrs; +#define CGEN_OPERAND_ATTRS(operand) (&(operand)->attrs) } CGEN_OPERAND; /* Return value of attribute ATTR in OPERAND. */ @@ -442,48 +531,207 @@ enum cgen_operand_type; /* FIXME: Rename, cpu-opc.h defines this as the typedef of the enum. */ #define CGEN_OPERAND_TYPE(operand) ((enum cgen_operand_type) CGEN_OPERAND_INDEX (operand)) #define CGEN_OPERAND_ENTRY(n) (& CGEN_SYM (operand_table) [n]) + +/* Types of parse/insert/extract/print cover-fn handlers. */ +/* FIXME: move opindex first to match caller. */ +/* FIXME: also need types of insert/extract/print fns. */ +/* FIXME: not currently used as type of 3rd arg varies. */ +typedef const char * (CGEN_PARSE_OPERAND_FN) PARAMS ((const char **, int, + long *)); + +/* Instruction operand instances. + + For each instruction, a list of the hardware elements that are read and + written are recorded. */ + +/* The type of the instance. */ +enum cgen_operand_instance_type { + /* End of table marker. */ + CGEN_OPERAND_INSTANCE_END = 0, + CGEN_OPERAND_INSTANCE_INPUT, CGEN_OPERAND_INSTANCE_OUTPUT +}; + +typedef struct +{ + /* The type of this operand. */ + enum cgen_operand_instance_type type; +#define CGEN_OPERAND_INSTANCE_TYPE(opinst) ((opinst)->type) + + /* The hardware element referenced. */ + const CGEN_HW_ENTRY *hw; +#define CGEN_OPERAND_INSTANCE_HW(opinst) ((opinst)->hw) + + /* The mode in which the operand is being used. */ + enum cgen_mode mode; +#define CGEN_OPERAND_INSTANCE_MODE(opinst) ((opinst)->mode) + + /* The operand table entry or NULL if there is none (i.e. an explicit + hardware reference). */ + const CGEN_OPERAND *operand; +#define CGEN_OPERAND_INSTANCE_OPERAND(opinst) ((opinst)->operand) + + /* If `operand' is NULL, the index (e.g. into array of registers). */ + int index; +#define CGEN_OPERAND_INSTANCE_INDEX(opinst) ((opinst)->index) +} CGEN_OPERAND_INSTANCE; + +/* Syntax string. + + Each insn format and subexpression has one of these. + + The syntax "string" consists of characters (n > 0 && n < 128), and operand + values (n >= 128), and is terminated by 0. Operand values are 128 + index + into the operand table. The operand table doesn't exist in C, per se, as + the data is recorded in the parse/insert/extract/print switch statements. */ + +#ifndef CGEN_MAX_SYNTAX_BYTES +#define CGEN_MAX_SYNTAX_BYTES 16 +#endif + +typedef struct +{ + unsigned char syntax[CGEN_MAX_SYNTAX_BYTES]; +} CGEN_SYNTAX; + +#define CGEN_SYNTAX_STRING(syn) (syn->syntax) +#define CGEN_SYNTAX_CHAR_P(c) ((c) < 128) +#define CGEN_SYNTAX_CHAR(c) (c) +#define CGEN_SYNTAX_FIELD(c) ((c) - 128) +#define CGEN_SYNTAX_MAKE_FIELD(c) ((c) + 128) + +/* ??? I can't currently think of any case where the mnemonic doesn't come + first [and if one ever doesn't building the hash tables will be tricky]. + However, we treat mnemonics as just another operand of the instruction. + A value of 1 means "this is where the mnemonic appears". 1 isn't + special other than it's a non-printable ASCII char. */ +#define CGEN_SYNTAX_MNEMONIC 1 +#define CGEN_SYNTAX_MNEMONIC_P(ch) ((ch) == CGEN_SYNTAX_MNEMONIC) + +/* Instruction formats. + + Instructions are grouped by format. Associated with an instruction is its + format. Each opcode table entry contains a format table entry. + ??? There is usually very few formats compared with the number of insns, + so one can reduce the size of the opcode table by recording the format table + as a separate entity. Given that we currently don't, format table entries + are also distinguished by their operands. This increases the size of the + table, but reduces the number of tables. It's all minutiae anyway so it + doesn't really matter [at this point in time]. + + ??? Support for variable length ISA's is wip. */ + +typedef struct +{ + /* Length that MASK and VALUE have been calculated to + [VALUE is recorded elsewhere]. + Normally it is CGEN_BASE_INSN_BITSIZE. On [V]LIW architectures where + the base insn size may be larger than the size of an insn, this field is + less than CGEN_BASE_INSN_BITSIZE. */ + unsigned char mask_length; + + /* Total length of instruction, in bits. */ + unsigned char length; + + /* Mask to apply to the first MASK_LENGTH bits. + Each insn's value is stored with the insn. + The first step in recognizing an insn for disassembly is + (opcode & mask) == value. */ + unsigned int mask; +} CGEN_FORMAT; /* This struct defines each entry in the instruction table. */ -struct cgen_insn { +struct cgen_insn +{ + /* ??? Further table size reductions can be had by moving this element + either to the format table or to a separate table of its own. Not + sure this is desirable yet. */ struct cgen_base base; + /* Given a pointer to a cgen_insn struct, return a pointer to `base'. */ #define CGEN_INSN_BASE(insn) (&(insn)->base) -#define CGEN_INSN_ATTRS(insn) (&(insn)->base.attrs) - struct cgen_syntax syntax; -#define CGEN_INSN_SYNTAX(insn) (&(insn)->syntax) -#define CGEN_INSN_FMT(insn) ((insn)->syntax.fmt) -#define CGEN_INSN_BITSIZE(insn) ((insn)->syntax.length) -}; + /* Name of entry (that distinguishes it from all other entries). + This is used, for example, in simulator profiling results. */ + /* ??? If mnemonics have operands, try to print full mnemonic. */ + const char * name; +#define CGEN_INSN_NAME(insn) ((insn)->name) + /* Mnemonic. This is used when parsing and printing the insn. + In the case of insns that have operands on the mnemonics, this is + only the constant part. E.g. for conditional execution of an `add' insn, + where the full mnemonic is addeq, addne, etc., this is only "add". */ + const char * mnemonic; +#define CGEN_INSN_MNEMONIC(insn) ((insn)->mnemonic) + + /* Syntax string. */ + const CGEN_SYNTAX syntax; +#define CGEN_INSN_SYNTAX(insn) (& (insn)->syntax) + + /* Format entry. */ + const CGEN_FORMAT format; +#define CGEN_INSN_MASK_BITSIZE(insn) ((insn)->format.mask_length) +#define CGEN_INSN_BITSIZE(insn) ((insn)->format.length) + + /* Instruction opcode value. */ + unsigned int value; +#define CGEN_INSN_VALUE(insn) ((insn)->value) +#define CGEN_INSN_MASK(insn) ((insn)->format.mask) + + /* Pointer to NULL entry terminated table of operands used, + or NULL if none. */ + const CGEN_OPERAND_INSTANCE *operands; +#define CGEN_INSN_OPERANDS(insn) ((insn)->operands) + + /* Attributes. + This must appear last. It is a variable sized array in that one + architecture may have 1 nonbool attribute and another may have more. + Having this last means the non-architecture specific code needn't + care. */ +#ifndef CGEN_INSN_NBOOL_ATTRS +#define CGEN_INSN_NBOOL_ATTRS 1 +#endif + CGEN_ATTR_TYPE (CGEN_INSN_NBOOL_ATTRS) attrs; +#define CGEN_INSN_ATTRS(insn) (&(insn)->attrs) /* Return value of attribute ATTR in INSN. */ #define CGEN_INSN_ATTR(insn, attr) \ CGEN_ATTR_VALUE (insn, CGEN_INSN_ATTRS (insn), attr) +}; /* Instruction lists. This is used for adding new entries and for creating the hash lists. */ -typedef struct cgen_insn_list { - struct cgen_insn_list *next; - const struct cgen_insn *insn; +typedef struct cgen_insn_list +{ + struct cgen_insn_list * next; + const CGEN_INSN * insn; } CGEN_INSN_LIST; /* The table of instructions. */ -typedef struct cgen_insn_table { +typedef struct +{ /* Pointer to initial [compiled in] entries. */ - const struct cgen_insn *init_entries; + const CGEN_INSN * init_entries; + + /* Size of an entry (since the attribute member is variable sized). */ + unsigned int entry_size; + /* Number of entries in `init_entries', including trailing NULL entry. */ unsigned int num_init_entries; + /* Values added at runtime. */ - struct cgen_insn_list *new_entries; + CGEN_INSN_LIST * new_entries; + /* Assembler hash function. */ - unsigned int (*asm_hash) PARAMS ((const char *)); + unsigned int (* asm_hash) PARAMS ((const char *)); + /* Number of entries in assembler hash table. */ unsigned int asm_hash_table_size; + /* Disassembler hash function. */ - unsigned int (*dis_hash) PARAMS ((const char *, unsigned long)); + unsigned int (* dis_hash) PARAMS ((const char *, unsigned long)); + /* Number of entries in disassembler hash table. */ unsigned int dis_hash_table_size; } CGEN_INSN_TABLE; @@ -498,7 +746,7 @@ extern const CGEN_INSN CGEN_SYM (insn_table_entries)[]; /* Return number of instructions. This includes any added at runtime. */ -int cgen_insn_count PARAMS (()); +int cgen_insn_count PARAMS ((void)); /* The assembler insn table is hashed based on some function of the mnemonic (the actually hashing done is up to the target, but we provide a few @@ -541,10 +789,11 @@ CGEN_INSN_LIST * cgen_dis_lookup_insn PARAMS ((const char *, unsigned long)); /* Top level structures and functions. */ -typedef struct cgen_opcode_data { - CGEN_HW_ENTRY *hw_list; - /*CGEN_OPERAND_TABLE *operand_table; - FIXME:wip */ - CGEN_INSN_TABLE *insn_table; +typedef struct +{ + const CGEN_HW_ENTRY * hw_list; + /*CGEN_OPERAND_TABLE * operand_table; - FIXME:wip */ + CGEN_INSN_TABLE * insn_table; } CGEN_OPCODE_DATA; /* Each CPU has one of these. */ @@ -562,7 +811,7 @@ extern enum cgen_endian cgen_current_endian; /* Prototypes of major functions. */ -/* Set the current cpu (+ mach number, endian, etc.). *? +/* Set the current cpu (+ mach number, endian, etc.). */ void cgen_set_cpu PARAMS ((CGEN_OPCODE_DATA *, int, enum cgen_endian)); /* Initialize the assembler, disassembler. */ @@ -577,28 +826,40 @@ void CGEN_SYM (init_parse) PARAMS ((void)); void CGEN_SYM (init_print) PARAMS ((void)); void CGEN_SYM (init_insert) PARAMS ((void)); void CGEN_SYM (init_extract) PARAMS ((void)); + +/* FIXME: This prototype is wrong ifndef CGEN_INT_INSN. + Furthermore, ifdef CGEN_INT_INSN, the insn is created in + target byte order (in which case why use int's at all). + Perhaps replace cgen_insn_t * with char *? */ const struct cgen_insn * -CGEN_SYM (assemble_insn) PARAMS ((const char *, struct cgen_fields *, +CGEN_SYM (assemble_insn) PARAMS ((const char *, CGEN_FIELDS *, cgen_insn_t *, char **)); -int CGEN_SYM (insn_supported) PARAMS ((const struct cgen_syntax *)); #if 0 /* old */ +int CGEN_SYM (insn_supported) PARAMS ((const struct cgen_insn *)); int CGEN_SYM (opval_supported) PARAMS ((const struct cgen_opval *)); #endif -extern const struct cgen_keyword CGEN_SYM (operand_mach); +extern const CGEN_KEYWORD CGEN_SYM (operand_mach); int CGEN_SYM (get_mach) PARAMS ((const char *)); +const CGEN_INSN * +CGEN_SYM (get_insn_operands) PARAMS ((const CGEN_INSN *, cgen_insn_t, + int, int *)); +const CGEN_INSN * +CGEN_SYM (lookup_insn) PARAMS ((const CGEN_INSN *, cgen_insn_t, + int, CGEN_FIELDS *, int)); + CGEN_INLINE void CGEN_SYM (put_operand) PARAMS ((int, const long *, - struct cgen_fields *)); + CGEN_FIELDS *)); CGEN_INLINE long -CGEN_SYM (get_operand) PARAMS ((int, const struct cgen_fields *)); +CGEN_SYM (get_operand) PARAMS ((int, const CGEN_FIELDS *)); -CGEN_INLINE const char * -CGEN_SYM (parse_operand) PARAMS ((int, const char **, struct cgen_fields *)); +const char * +CGEN_SYM (parse_operand) PARAMS ((int, const char **, CGEN_FIELDS *)); -CGEN_INLINE const char * -CGEN_SYM (validate_operand) PARAMS ((int, const struct cgen_fields *)); +const char * +CGEN_SYM (insert_operand) PARAMS ((int, CGEN_FIELDS *, char *)); /* Default insn parser, printer. */ extern cgen_parse_fn CGEN_SYM (parse_insn); @@ -608,79 +869,5 @@ extern cgen_print_fn CGEN_SYM (print_insn); /* Read in a cpu description file. */ const char * cgen_read_cpu_file PARAMS ((const char *)); - -/* Assembler interface. - - The interface to the assembler is intended to be clean in the sense that - libopcodes.a is a standalone entity and could be used with any assembler. - Not that one would necessarily want to do that but rather that it helps - keep a clean interface. The interface will obviously be slanted towards - GAS, but at least it's a start. - - Parsing is controlled by the assembler which calls - CGEN_SYM (assemble_insn). If it can parse and build the entire insn - it doesn't call back to the assembler. If it needs/wants to call back - to the assembler, (*cgen_parse_operand_fn) is called which can either - - - return a number to be inserted in the insn - - return a "register" value to be inserted - (the register might not be a register per pe) - - queue the argument and return a marker saying the expression has been - queued (eg: a fix-up) - - return an error message indicating the expression wasn't recognizable - - The result is an error message or NULL for success. - The parsed value is stored in the bfd_vma *. */ - -/* Values for indicating what the caller wants. */ -enum cgen_parse_operand_type { - CGEN_PARSE_OPERAND_INIT, CGEN_PARSE_OPERAND_INTEGER, - CGEN_PARSE_OPERAND_ADDRESS -}; - -/* Values for indicating what was parsed. - ??? Not too useful at present but in time. */ -enum cgen_parse_operand_result { - CGEN_PARSE_OPERAND_RESULT_NUMBER, CGEN_PARSE_OPERAND_RESULT_REGISTER, - CGEN_PARSE_OPERAND_RESULT_QUEUED, CGEN_PARSE_OPERAND_RESULT_ERROR -}; - -/* Don't require bfd.h unnecessarily. */ -#ifdef BFD_VERSION -extern const char * (*cgen_parse_operand_fn) - PARAMS ((enum cgen_parse_operand_type, const char **, int, int, - enum cgen_parse_operand_result *, bfd_vma *)); -#endif - -/* Called before trying to match a table entry with the insn. */ -void cgen_init_parse_operand PARAMS ((void)); - -/* Called from <cpu>-asm.c to initialize operand parsing. */ - -/* These are GAS specific. They're not here as part of the interface, - but rather that we need to put them somewhere. */ - -/* Call this from md_assemble to initialize the assembler callback. */ -void cgen_asm_init_parse PARAMS ((void)); - -/* Don't require bfd.h unnecessarily. */ -#ifdef BFD_VERSION -/* The result is an error message or NULL for success. - The parsed value is stored in the bfd_vma *. */ -const char *cgen_parse_operand PARAMS ((enum cgen_parse_operand_type, - const char **, int, int, - enum cgen_parse_operand_result *, - bfd_vma *)); -#endif - -/* Add a register to the assembler's hash table. - This makes lets GAS parse registers for us. - ??? This isn't currently used, but it could be in the future. */ -void cgen_asm_record_register PARAMS ((char *, int)); - -/* After CGEN_SYM (assemble_insn) is done, this is called to - output the insn and record any fixups. */ -void cgen_asm_finish_insn PARAMS ((const struct cgen_insn *, cgen_insn_t *, - unsigned int)); #endif /* CGEN_H */ |