diff options
Diffstat (limited to 'include/opcode/cgen.h')
-rwxr-xr-x | include/opcode/cgen.h | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/include/opcode/cgen.h b/include/opcode/cgen.h new file mode 100755 index 0000000..039926b --- /dev/null +++ b/include/opcode/cgen.h @@ -0,0 +1,1202 @@ +/* Header file for targets using CGEN: Cpu tools GENerator. + +Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GDB, the GNU debugger, and the GNU Binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 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. */ + +#ifndef CGEN_H +#define CGEN_H + +/* Enums must be defined before they can be used. + Allow them to be used in struct definitions, even though the enum must + be defined elsewhere. + if CGEN_ARCH isn't defined, this file is being included by something other + than <arch>-opc.h. */ + +/* Prepend the arch name, defined in <arch>-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 <arch>-opc.h. + It can be included independently of <arch>-opc.h, in which case the arch + dependent portions will be declared as "unknown_cgen_foo". */ + +#ifndef CGEN_SYM +#define CGEN_SYM(s) CONCAT3 (unknown,_cgen_,s) +#endif + +/* This file contains the static (unchanging) pieces and as much other stuff + as we can reasonably put here. It's generally cleaner to put stuff here + rather than having it machine generated if possible. */ + +/* The assembler syntax is made up of expressions (duh...). + At the lowest level the values are mnemonics, register names, numbers, etc. + Above that are subexpressions, if any (an example might be the + "effective address" in m68k cpus). At the second highest level are the + insns themselves. Above that are pseudo-insns, synthetic insns, and macros, + if any. +*/ + +/* Lots of cpu's have a fixed insn size, or one which rarely changes, + and it's generally easier to handle these by treating the insn as an + integer type, rather than an array of characters. So we allow targets + to control this. When an integer type the value is in host byte order, + when an array of characters the value is in target byte order. */ + +typedef unsigned int CGEN_INSN_INT; +#if CGEN_INT_INSN_P +typedef CGEN_INSN_INT CGEN_INSN_BYTES; +typedef CGEN_INSN_INT *CGEN_INSN_BYTES_PTR; +#else +typedef unsigned char *CGEN_INSN_BYTES; +typedef unsigned char *CGEN_INSN_BYTES_PTR; +#endif + +#ifdef __GNUC__ +#define CGEN_INLINE inline +#else +#define CGEN_INLINE +#endif + +enum cgen_endian +{ + CGEN_ENDIAN_UNKNOWN, + CGEN_ENDIAN_LITTLE, + CGEN_ENDIAN_BIG +}; + +/* Forward decl. */ + +typedef struct cgen_insn CGEN_INSN; + +/* Opaque pointer version for use by external world. */ + +typedef struct cgen_opcode_table * CGEN_OPCODE_DESC; + +/* Attributes. + Attributes are used to describe various random things associated with + an object (ifield, hardware, operand, insn, whatever) and are specified + as name/value pairs. + Integer attributes computed at compile time are currently all that's + supported, though adding string attributes and run-time computation is + straightforward. Integer attribute values are always host int's + (signed or unsigned). For portability, this means 32 bits. + Integer attributes are further categorized as boolean, bitset, integer, + and enum types. Boolean attributes appear frequently enough that they're + recorded in one host int. This limits the maximum number of boolean + attributes to 32, though that's a *lot* of attributes. */ + +/* Type of attribute values. */ + +typedef int CGEN_ATTR_VALUE_TYPE; + +/* Struct to record attribute information. */ + +typedef struct +{ + /* Number of non-boolean attributes. */ + unsigned char num_nonbools; + /* Boolean attributes have indices >= num_nonbools. */ + unsigned int bool; + /* Non-boolean integer attributes. */ + CGEN_ATTR_VALUE_TYPE nonbool[1]; +} CGEN_ATTR; + +/* Define a structure member for attributes with N non-boolean entries. + The attributes are sorted so that the non-boolean ones come first. + There is a maximum of 32 attributes total. + ??? Though this is just to simplify the implementation. The actual limit + is 32 booleans). */ + +#define CGEN_ATTR_TYPE(n) \ +struct { int num_nonbools; \ + unsigned int bool; \ + CGEN_ATTR_VALUE_TYPE nonbool[(n) ? (n) : 1]; } + +/* Return the boolean attributes. */ + +#define CGEN_ATTR_BOOLS(a) ((a)->bool) + +/* 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 (not used at present + but is reserved for future purposes). */ + +#define CGEN_ATTR_VALUE(obj, attr_table, attr) \ +((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; + CGEN_ATTR_VALUE_TYPE value; +} CGEN_ATTR_ENTRY; + +/* For each domain (ifld,hw,operand,insn), list of attributes. */ + +typedef struct +{ + const char * name; + const CGEN_ATTR_ENTRY * dfault; + const CGEN_ATTR_ENTRY * vals; +} CGEN_ATTR_TABLE; + +/* Parse result (also extraction result). + + The result of parsing an insn is stored here. + To generate the actual insn, this is passed to the insert handler. + When printing an insn, the result of extraction is stored here. + To print the insn, this is passed to the print handler. + + It is machine generated so we don't define it here, + but we do need a forward decl for the handler fns. + + There is one member for each possible field in the insn. + The type depends on the field. + Also recorded here is the computed length of the insn for architectures + where it varies. +*/ + +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 + if it ever gets inlined. On architectures where insns all have the same + size, may wish to detect that and make this macro a constant - to allow + further optimizations. */ + +#define CGEN_FIELDS_BITSIZE(fields) ((fields)->length) + +/* Extraction support for variable length insn sets. */ + +/* When disassembling we don't know the number of bytes to read at the start. + So the first CGEN_BASE_INSN_SIZE bytes are read at the start and the rest + are read when needed. This struct controls this. It is basically the + disassemble_info stuff, except that we provide a cache for values already + read (since bytes can typically be read several times to fetch multiple + operands that may be in them), and that extraction of fields is needed + in contexts other than disassembly. */ + +typedef struct { + /* A pointer to the disassemble_info struct. + We don't require dis-asm.h so we use PTR for the type here. + If NULL, BYTES is full of valid data (VALID == -1). */ + PTR dis_info; + /* Points to a working buffer of sufficient size. */ + unsigned char *insn_bytes; + /* Mask of bytes that are valid in INSN_BYTES. */ + unsigned int valid; +} CGEN_EXTRACT_INFO; + +/* Associated with each insn or expression is a set of "handlers" for + performing operations like parsing, printing, etc. These require a bfd_vma + value to be passed around but we don't want all applications to need bfd.h. + So this stuff is only provided if bfd.h has been included. */ + +#ifdef BFD_VERSION + +/* Parse handler. + OD is an opcode table descriptor. + INSN is a pointer to a struct describing the insn being parsed. + STRP is a pointer to a pointer to the text being parsed. + FIELDS is a pointer to a cgen_fields struct in which the results are placed. + If the expression is successfully parsed, *STRP is updated. + If not it is left alone. + The result is NULL if success or an error message. */ +typedef const char * (cgen_parse_fn) + PARAMS ((CGEN_OPCODE_DESC /*od*/, const CGEN_INSN * /*insn*/, + const char ** /*strp*/, CGEN_FIELDS * /*fields*/)); + +/* Insert handler. + OD is an opcode table descriptor. + INSN is a pointer to a struct describing the insn being parsed. + FIELDS is a pointer to a cgen_fields struct from which the values + are fetched. + INSNP is a pointer to a buffer in which to place the insn. + PC is the pc value of the insn. + The result is an error message or NULL if success. */ + +typedef const char * (cgen_insert_fn) + PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN * /*insn*/, + CGEN_FIELDS * /*fields*/, CGEN_INSN_BYTES_PTR /*insnp*/, + bfd_vma /*pc*/)); + +/* Extract handler. + OD is an opcode table descriptor. + INSN is a pointer to a struct describing the insn being parsed. + The second argument is a pointer to a struct controlling extraction + (only used for variable length insns). + EX_INFO is a pointer to a struct for controlling reading of further + bytes for the insn. + BASE_INSN is the first CGEN_BASE_INSN_SIZE bytes (host order). + FIELDS is a pointer to a cgen_fields struct in which the results are placed. + PC is the pc value of the insn. + The result is the length of the insn in bits or zero if not recognized. */ + +typedef int (cgen_extract_fn) + PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN * /*insn*/, + CGEN_EXTRACT_INFO * /*ex_info*/, CGEN_INSN_INT /*base_insn*/, + CGEN_FIELDS * /*fields*/, bfd_vma /*pc*/)); + +/* Print handler. + OD is an opcode table descriptor. + INFO is a pointer to the disassembly info. + Eg: disassemble_info. It's defined as `PTR' so this file can be included + without dis-asm.h. + INSN is a pointer to a struct describing the insn being printed. + FIELDS is a pointer to a cgen_fields struct. + PC is the pc value of the insn. + LEN is the length of the insn, in bits. */ + +typedef void (cgen_print_fn) + PARAMS ((CGEN_OPCODE_DESC /*od*/, PTR /*info*/, + const CGEN_INSN * /*insn*/, + CGEN_FIELDS * /*fields*/, bfd_vma /*pc*/, int /*len*/)); + +/* The `parse' and `insert' fields are indices into these tables. + The elements are pointer to specialized handler functions. + Element 0 is special, it means use the default handler. */ + +extern cgen_parse_fn * const CGEN_SYM (parse_handlers) []; +#define CGEN_PARSE_FN(x) (CGEN_SYM (parse_handlers)[(x)->base.parse]) +extern cgen_insert_fn * const CGEN_SYM (insert_handlers) []; +#define CGEN_INSERT_FN(x) (CGEN_SYM (insert_handlers)[(x)->base.insert]) + +/* Likewise for the `extract' and `print' fields. */ + +extern cgen_extract_fn * const CGEN_SYM (extract_handlers) []; +#define CGEN_EXTRACT_FN(x) (CGEN_SYM (extract_handlers)[(x)->base.extract]) +extern cgen_print_fn * const CGEN_SYM (print_handlers) []; +#define CGEN_PRINT_FN(x) (CGEN_SYM (print_handlers)[(x)->base.print]) + +/* Default insn parser, printer. */ + +extern cgen_parse_fn CGEN_SYM (parse_insn); +extern cgen_insert_fn CGEN_SYM (insert_insn); +extern cgen_extract_fn CGEN_SYM (extract_insn); +extern cgen_print_fn CGEN_SYM (print_insn); + +#endif /* BFD_VERSION */ + +/* Base class of parser/printer. + (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, insert, extract, + and print each of them. + This is an underutilized facility, and exists as a potential escape hatch + for handling more complicated assembler syntaxes. */ + +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). + Using indices also keeps assembler code out of the disassembler and + vice versa. */ + unsigned char parse, insert, extract, print; +}; + +/* 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. + ??? Note that one possible use of the assembler besides GAS is GDB. + + 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. */ + +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 +}; + +#ifdef BFD_VERSION /* Don't require bfd.h unnecessarily. */ +typedef const char * (cgen_parse_operand_fn) + PARAMS ((CGEN_OPCODE_DESC, + enum cgen_parse_operand_type, const char **, int, int, + enum cgen_parse_operand_result *, bfd_vma *)); +#else +typedef const char * (cgen_parse_operand_fn) (); +#endif + +/* Set the cgen_parse_operand_fn callback. */ + +extern void cgen_set_parse_operand_fn + PARAMS ((CGEN_OPCODE_DESC, cgen_parse_operand_fn)); + +/* Called before trying to match a table entry with the insn. */ + +extern void cgen_init_parse_operand PARAMS ((CGEN_OPCODE_DESC)); + +/* Operand values (keywords, integers, symbols, etc.) */ + +/* Types of assembler elements. */ + +enum cgen_asm_type +{ + CGEN_ASM_KEYWORD, CGEN_ASM_MAX +}; + +/* List of hardware elements. */ + +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; +#ifndef CGEN_HW_NBOOL_ATTRS +#define CGEN_HW_NBOOL_ATTRS 1 +#endif + CGEN_ATTR_TYPE (CGEN_HW_NBOOL_ATTRS) attrs; +#define CGEN_HW_ATTRS(hw) (&(hw)->attrs) +} CGEN_HW_ENTRY; + +/* Return value of attribute ATTR in HW. */ + +#define CGEN_HW_ATTR(hw, attr) \ +CGEN_ATTR_VALUE ((hw), CGEN_HW_ATTRS (hw), (attr)) + +extern const CGEN_HW_ENTRY * cgen_hw_lookup_by_name + PARAMS ((CGEN_OPCODE_DESC, const char *)); +extern const CGEN_HW_ENTRY * cgen_hw_lookup_by_num + PARAMS ((CGEN_OPCODE_DESC, int)); + +/* This struct is used to describe things like register names, etc. */ + +typedef struct cgen_keyword_entry +{ + /* Name (as in register 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. + 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. The goal is to eventually record + attributes in their raw form, evaluate them at runtime, and cache the + values, so this worry will go away anyway. */ + /* ??? 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. */ +#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; + /* Next value hash table entry. */ + struct cgen_keyword_entry *next_value; +} CGEN_KEYWORD_ENTRY; + +/* Top level struct for describing a set of related keywords + (e.g. register names). + + This struct supports runtime entry of new values, and hashed lookups. */ + +typedef struct cgen_keyword +{ + /* Pointer to initial [compiled in] values. */ + CGEN_KEYWORD_ENTRY * init_entries; + + /* Number of entries in `init_entries'. */ + unsigned int num_init_entries; + + /* Hash table used for name lookup. */ + CGEN_KEYWORD_ENTRY ** name_hash_table; + + /* Hash table used for value lookup. */ + 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 +{ + /* Table being searched. */ + const CGEN_KEYWORD * table; + + /* Specification of what is being searched for. */ + const char * spec; + + /* Current index in hash table. */ + unsigned int current_hash; + + /* Current element in current hash chain. */ + CGEN_KEYWORD_ENTRY * current_entry; +} CGEN_KEYWORD_SEARCH; + +/* Lookup a keyword from its name. */ + +const CGEN_KEYWORD_ENTRY * cgen_keyword_lookup_name + PARAMS ((CGEN_KEYWORD *, const char *)); + +/* Lookup a keyword from its value. */ + +const CGEN_KEYWORD_ENTRY * cgen_keyword_lookup_value + PARAMS ((CGEN_KEYWORD *, int)); + +/* Add a keyword. */ + +void cgen_keyword_add PARAMS ((CGEN_KEYWORD *, CGEN_KEYWORD_ENTRY *)); + +/* Keyword searching. + This can be used to retrieve every keyword, or a subset. */ + +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. */ + +extern const char * cgen_parse_keyword + PARAMS ((CGEN_OPCODE_DESC, const char **, CGEN_KEYWORD *, long *)); +#ifdef BFD_VERSION /* Don't require bfd.h unnecessarily. */ +extern const char * cgen_parse_signed_integer + PARAMS ((CGEN_OPCODE_DESC, const char **, int, long *)); +extern const char * cgen_parse_unsigned_integer + PARAMS ((CGEN_OPCODE_DESC, const char **, int, unsigned long *)); +extern const char * cgen_parse_address + PARAMS ((CGEN_OPCODE_DESC, const char **, int, int, + enum cgen_parse_operand_result *, bfd_vma *)); +extern const char * cgen_validate_signed_integer + PARAMS ((long, long, long)); +extern const char * cgen_validate_unsigned_integer + PARAMS ((unsigned long, unsigned long, unsigned long)); +#endif + +/* 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, /* ??? 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_TARGET_MAX, + CGEN_MODE_INT, CGEN_MODE_UINT, + CGEN_MODE_MAX +}; + +/* FIXME: Until simulator is updated. */ + +#define CGEN_MODE_VM CGEN_MODE_VOID + +/* This struct defines each entry in the operand table. */ + +typedef struct cgen_operand +{ + /* Name as it appears in the syntax string. */ + 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. + 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; + +#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. The goal is to eventually record + attributes in their raw form, evaluate them at runtime, and cache the + values, so this worry will go away anyway. */ +#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. */ + +#define CGEN_OPERAND_ATTR(operand, attr) \ +CGEN_ATTR_VALUE ((operand), CGEN_OPERAND_ATTRS (operand), (attr)) + +/* The operand table is currently a very static entity. */ + +extern const CGEN_OPERAND CGEN_SYM (operand_table)[]; + +enum cgen_operand_type; + +#define CGEN_OPERAND_INDEX(operand) ((int) ((operand) - CGEN_SYM (operand_table))) +/* 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]) + +/* 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) + + /* Name of operand. */ + const char *name; +#define CGEN_OPERAND_INSTANCE_NAME(opinst) ((opinst)->name) + + /* 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) + + /* Attributes. + ??? This perhaps should be a real attribute struct but there's + no current need, so we save a bit of space and just have a set of + flags. The interface is such that this can easily be made attributes + should it prove useful. */ + unsigned int attrs; +#define CGEN_OPERAND_INSTANCE_ATTRS(opinst) ((opinst)->attrs) +/* Return value of attribute ATTR in OPINST. */ +#define CGEN_OPERAND_INSTANCE_ATTR(opinst, attr) \ +((CGEN_OPERAND_INSTANCE_ATTRS (opinst) & (attr)) != 0) +/* Operand is conditionally referenced (read/written). */ +#define CGEN_OPERAND_INSTANCE_COND_REF 1 +} 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 fields. + + ??? We currently don't allow adding fields at runtime. + Easy to fix when needed. */ + +typedef struct { + /* Enum of ifield. */ + int num; +#define CGEN_IFLD_NUM(f) ((f)->num) + + /* Name of the field, distinguishes it from all other fields. */ + const char *name; +#define CGEN_IFLD_NAME(f) ((f)->name) + + /* Default offset, in bits, from the start of the insn to the word + containing the field. */ + int word_offset; +#define CGEN_IFLD_WORD_OFFSET(f) ((f)->word_offset) + + /* Default length of the word containing the field. */ + int word_size; +#define CGEN_IFLD_WORD_SIZE(f) ((f)->word_size) + + /* Default starting bit number. + Whether lsb=0 or msb=0 is determined by CGEN_INSN_LSB0_P. */ + int start; +#define CGEN_IFLD_START(f) ((f)->start) + + /* Length of the field, in bits. */ + int length; +#define CGEN_IFLD_LENGTH(f) ((f)->length) + +#ifndef CGEN_IFLD_NBOOL_ATTRS +#define CGEN_IFLD_NBOOL_ATTRS 1 +#endif + CGEN_ATTR_TYPE (CGEN_IFLD_NBOOL_ATTRS) attrs; +#define CGEN_IFLD_ATTRS(f) (&(f)->attrs) +} CGEN_IFLD; + +/* Return value of attribute ATTR in IFLD. */ +#define CGEN_IFLD_ATTR(ifld, attr) \ +CGEN_ATTR_VALUE ((ifld), CGEN_IFLD_ATTRS (ifld), (attr)) + +/* Instruction formats. + + Instructions are grouped by format. Associated with an instruction is its + format. Each insn's 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. */ + +/* Accompanying each iformat description is a list of its fields. */ + +typedef struct { + const CGEN_IFLD *ifld; +#define CGEN_IFMT_IFLD_IFLD(ii) ((ii)->ifld) +} CGEN_IFMT_IFLD; + +#ifndef CGEN_MAX_IFMT_OPERANDS +#define CGEN_MAX_IFMT_OPERANDS 1 +#endif + +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; +#define CGEN_IFMT_MASK_LENGTH(ifmt) ((ifmt)->mask_length) + + /* Total length of instruction, in bits. */ + unsigned char length; +#define CGEN_IFMT_LENGTH(ifmt) ((ifmt)->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. */ + CGEN_INSN_INT mask; +#define CGEN_IFMT_MASK(ifmt) ((ifmt)->mask) + + /* Instruction fields. + +1 for trailing NULL. */ + CGEN_IFMT_IFLD iflds[CGEN_MAX_IFMT_OPERANDS + 1]; +#define CGEN_IFMT_IFLDS(ifmt) ((ifmt)->iflds) +} CGEN_IFMT; + +/* Instruction values. */ + +typedef struct +{ + /* The opcode portion of the base insn. */ + CGEN_INSN_INT base_value; + +#ifdef CGEN_MAX_EXTRA_OPCODE_OPERANDS + /* Extra opcode values beyond base_value. */ + unsigned long ifield_values[CGEN_MAX_EXTRA_OPCODE_OPERANDS]; +#endif +} CGEN_IVALUE; + +/* This struct defines each entry in the instruction table. */ + +struct cgen_insn +{ + /* This field is an array of functions that operand on this entry. */ + struct cgen_base base; +#define CGEN_INSN_BASE(insn) (&(insn)->base) + + /* Each real instruction is enumerated. + ??? The simulator use to use this value but currently no longer does. + This may go away in time. */ + int num; +#define CGEN_INSN_NUM(insn) ((insn)->num) + + /* 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. */ + CGEN_SYNTAX syntax; +#define CGEN_INSN_SYNTAX(insn) (& (insn)->syntax) + + /* Format entry. */ + const CGEN_IFMT *format; +#define CGEN_INSN_FORMAT(insn) ((insn)->format) +#define CGEN_INSN_MASK_BITSIZE(insn) CGEN_IFMT_MASK_LENGTH (CGEN_INSN_FORMAT (insn)) +#define CGEN_INSN_BITSIZE(insn) CGEN_IFMT_LENGTH (CGEN_INSN_FORMAT (insn)) +#define CGEN_INSN_IFLDS(insn) CGEN_IFMT_IFLDS (CGEN_INSN_FORMAT (insn)) + + /* Instruction opcode value. */ + CGEN_IVALUE value; +#define CGEN_INSN_VALUE(insn) (& (insn)->value) +#define CGEN_INSN_BASE_VALUE(insn) (CGEN_INSN_VALUE (insn)->base_value) +#define CGEN_INSN_BASE_MASK(insn) CGEN_IFMT_MASK (CGEN_INSN_FORMAT (insn)) + +#if 0 /* ??? Disabled for now as there is a problem with embedded newlines + and the table is already pretty big. Should perhaps be moved + to a file of its own. */ + /* Semantics, as RTL. */ + /* ??? Note that the operand instance table could be computed at runtime + if we parse this and cache the results. Something to eventually do. */ + const char *rtx; +#define CGEN_INSN_RTX(insn) ((insn)->rtx) +#endif + + /* Opaque pointer to "subclass" specific data. + In the case of real insns this points to a NULL entry terminated + table of operands used, or NULL if none. + In the case of macro insns this points to data to control the expansion. + ??? I'd rather not get carried away and lay things out with pedantic + purity right now. Sure, other fields might better be tucked away in + `data'. Not now. */ + PTR data; +#define CGEN_INSN_DATA(insn) ((insn)->data) +#define CGEN_INSN_OPERANDS(insn) ((CGEN_OPERAND_INSTANCE *) (insn)->data) + + /* 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. The goal is to eventually record attributes in their raw form, + evaluate them at runtime, and cache the values, so this worry will go + away anyway. */ +#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)) +}; + +/* Return non-zero if INSN is the "invalid" insn marker. */ + +#define CGEN_INSN_INVALID_P(insn) (CGEN_INSN_MNEMONIC (insn) == 0) + +/* 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 CGEN_INSN * insn; +} CGEN_INSN_LIST; + +/* The table of instructions. */ + +typedef struct +{ + /* Pointer to initial [compiled in] 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. */ + CGEN_INSN_LIST * new_entries; +} CGEN_INSN_TABLE; + +/* ??? This is currently used by the simulator. */ +extern const CGEN_INSN CGEN_SYM (insn_table_entries)[]; + +/* Return number of instructions. This includes any added at runtime. */ + +extern int cgen_insn_count PARAMS ((CGEN_OPCODE_DESC)); +extern int cgen_macro_insn_count PARAMS ((CGEN_OPCODE_DESC)); + +/* Macro instructions. + Macro insns aren't real insns, they map to one or more real insns. + E.g. An architecture's "nop" insn may actually be an "mv r0,r0" or + some such. + + Macro insns can expand to nothing (e.g. a nop that is optimized away). + This is useful in multi-insn macros that build a constant in a register. + Of course this isn't the default behaviour and must be explicitly enabled. + + Assembly of macro-insns is relatively straightforward. Disassembly isn't. + However, disassembly of at least some kinds of macro insns is important + in order that the disassembled code preserve the readability of the original + insn. What is attempted here is to disassemble all "simple" macro-insns, + where "simple" is currently defined to mean "expands to one real insn". + + Simple macro-insns are handled specially. They are emitted as ALIAS's + of real insns. This simplifies their handling since there's usually more + of them than any other kind of macro-insn, and proper disassembly of them + falls out for free. */ + +/* For each macro-insn there may be multiple expansion possibilities, + depending on the arguments. This structure is accessed via the `data' + member of CGEN_INSN. */ + +typedef struct cgen_minsn_expansion { + /* Function to do the expansion. + If the expansion fails (e.g. "no match") NULL is returned. + Space for the expansion is obtained with malloc. + It is up to the caller to free it. */ + const char * (* fn) PARAMS ((const struct cgen_minsn_expansion *, + const char *, const char **, int *, CGEN_OPERAND **)); +#define CGEN_MIEXPN_FN(ex) ((ex)->fn) + + /* Instruction(s) the macro expands to. + The format of STR is defined by FN. + It is typically the assembly code of the real insn, but it could also be + the original Scheme expression or a tokenized form of it (with FN being + an appropriate interpreter). */ + const char * str; +#define CGEN_MIEXPN_STR(ex) ((ex)->str) +} CGEN_MINSN_EXPANSION; + +/* Normal expander. + When supported, this function will convert the input string to another + string and the parser will be invoked recursively. The output string + may contain further macro invocations. */ + +extern const char * cgen_expand_macro_insn + PARAMS ((CGEN_OPCODE_DESC, const struct cgen_minsn_expansion *, + const char *, const char **, int *, CGEN_OPERAND **)); + +/* 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 + examples like the first letter or a function of the entire mnemonic). */ + +#ifndef CGEN_ASM_HASH_P +#define CGEN_ASM_HASH_P(insn) 1 +#endif + +/* INSN is the CGEN_INSN entry when building the hash table and NULL + when looking up the insn during assembly. */ + +#ifndef CGEN_ASM_HASH +#define CGEN_ASM_HASH_SIZE 127 +#ifdef CGEN_MNEMONIC_OPERANDS +#define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE) +#else +#define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE) /*FIXME*/ +#endif +#endif + +extern CGEN_INSN_LIST * cgen_asm_lookup_insn + PARAMS ((CGEN_OPCODE_DESC, const char *)); +#define CGEN_ASM_LOOKUP_INSN(od, string) cgen_asm_lookup_insn ((od), (string)) +#define CGEN_ASM_NEXT_INSN(insn) ((insn)->next) + +/* The disassembler insn table is hashed based on some function of machine + instruction (the actually hashing done is up to the target). */ + +#ifndef CGEN_DIS_HASH_P +#define CGEN_DIS_HASH_P(insn) 1 +#endif + +/* It doesn't make much sense to provide a default here, + but while this is under development we do. + BUFFER is a pointer to the bytes of the insn. + VALUE is the first CGEN_BASE_INSN_SIZE bytes as an int in host order. */ + +#ifndef CGEN_DIS_HASH +#define CGEN_DIS_HASH_SIZE 256 +#define CGEN_DIS_HASH(buffer, value) (*(unsigned char *) (buffer)) +#endif + +extern CGEN_INSN_LIST * cgen_dis_lookup_insn + PARAMS ((CGEN_OPCODE_DESC, const char *, CGEN_INSN_INT)); +#define CGEN_DIS_LOOKUP_INSN(od, buf, value) cgen_dis_lookup_insn ((od), (buf), (value)) +#define CGEN_DIS_NEXT_INSN(insn) ((insn)->next) + +/* The opcode table. + A copy of this is created when the opcode table is "opened". + All global state information is recorded here. */ + +typedef struct cgen_opcode_table +{ + const CGEN_HW_ENTRY * hw_list; +#define CGEN_OPCODE_HW_LIST(od) ((od)->hw_list) + + const CGEN_IFLD * ifld_table; +#define CGEN_OPCODE_IFLD_TABLE(od) ((od)->ifld_table) + + const CGEN_OPERAND * operand_table; +#define CGEN_OPCODE_OPERAND_TABLE(od) ((od)->operand_table) + + CGEN_INSN_TABLE insn_table; +#define CGEN_OPCODE_INSN_TABLE(od) (& (od)->insn_table) + + /* Macro instructions are defined separately and are combined with real + insns during hash table computation. */ + CGEN_INSN_TABLE macro_insn_table; +#define CGEN_OPCODE_MACRO_INSN_TABLE(od) (& (od)->macro_insn_table) + + /* Return non-zero if insn should be added to hash table. */ + int (* asm_hash_p) PARAMS ((const CGEN_INSN *)); +#define CGEN_OPCODE_ASM_HASH_P(od) ((od)->asm_hash_p) + + /* Assembler hash function. */ + unsigned int (* asm_hash) PARAMS ((const char *)); +#define CGEN_OPCODE_ASM_HASH(od) ((od)->asm_hash) + + /* Number of entries in assembler hash table. */ + unsigned int asm_hash_size; +#define CGEN_OPCODE_ASM_HASH_SIZE(od) ((od)->asm_hash_size) + + /* Return non-zero if insn should be added to hash table. */ + int (* dis_hash_p) PARAMS ((const CGEN_INSN *)); +#define CGEN_OPCODE_DIS_HASH_P(od) ((od)->dis_hash_p) + + /* Disassembler hash function. */ + unsigned int (* dis_hash) PARAMS ((const char *, CGEN_INSN_INT)); +#define CGEN_OPCODE_DIS_HASH(od) ((od)->dis_hash) + + /* Number of entries in disassembler hash table. */ + unsigned int dis_hash_size; +#define CGEN_OPCODE_DIS_HASH_SIZE(od) ((od)->dis_hash_size) + + /* Operand parser callback. */ + cgen_parse_operand_fn * parse_operand_fn; +#define CGEN_OPCODE_PARSE_OPERAND_FN(od) ((od)->parse_operand_fn) + + /* Current machine (a la BFD machine number). */ + int mach; +#define CGEN_OPCODE_MACH(od) ((od)->mach) + + /* Current endian. */ + enum cgen_endian endian; +#define CGEN_OPCODE_ENDIAN(od) ((od)->endian) + + /* Current insn endian. */ + enum cgen_endian insn_endian; +#define CGEN_OPCODE_INSN_ENDIAN(od) ((od)->insn_endian) + + /* Assembler instruction hash table. */ + CGEN_INSN_LIST **asm_hash_table; +#define CGEN_OPCODE_ASM_HASH_TABLE(od) ((od)->asm_hash_table) + CGEN_INSN_LIST *asm_hash_table_entries; +#define CGEN_OPCODE_ASM_HASH_TABLE_ENTRIES(od) ((od)->asm_hash_table_entries) + + /* Disassembler instruction hash table. */ + CGEN_INSN_LIST ** dis_hash_table; +#define CGEN_OPCODE_DIS_HASH_TABLE(od) ((od)->dis_hash_table) + CGEN_INSN_LIST * dis_hash_table_entries; +#define CGEN_OPCODE_DIS_HASH_TABLE_ENTRIES(od) ((od)->dis_hash_table_entries) + +} CGEN_OPCODE_TABLE; + +/* wip */ +#ifndef CGEN_WORD_ENDIAN +#define CGEN_WORD_ENDIAN(od) CGEN_OPCODE_ENDIAN (od) +#endif +#ifndef CGEN_INSN_WORD_ENDIAN +#define CGEN_INSN_WORD_ENDIAN(od) CGEN_OPCODE_INSN_ENDIAN (od) +#endif + +/* Prototypes of major functions. */ +/* FIXME: Move all CGEN_SYM-defined functions into CGEN_OPCODE_DESC. */ + +/* Open an opcode table for use. */ + +extern CGEN_OPCODE_DESC CGEN_SYM (opcode_open) + PARAMS ((int, enum cgen_endian)); + +/* Close it. */ + +extern void CGEN_SYM (opcode_close) PARAMS ((CGEN_OPCODE_DESC)); + +/* `init_tables' must be called before `xxx_supported'. */ + +extern void CGEN_SYM (init_tables) PARAMS ((int)); + +/* Initialize an opcode table for assembler or disassembler use. + These must be called immediately after opcode_open. */ + +extern void CGEN_SYM (init_asm) PARAMS ((CGEN_OPCODE_DESC)); +extern void CGEN_SYM (init_dis) PARAMS ((CGEN_OPCODE_DESC)); + +/* Change the mach and/or endianness. */ + +extern void cgen_set_cpu PARAMS ((CGEN_OPCODE_DESC, int, enum cgen_endian)); + +extern const CGEN_INSN * CGEN_SYM (assemble_insn) + PARAMS ((CGEN_OPCODE_DESC, const char *, CGEN_FIELDS *, + CGEN_INSN_BYTES_PTR, char **)); + +extern const CGEN_KEYWORD CGEN_SYM (operand_mach); +extern int CGEN_SYM (get_mach) PARAMS ((const char *)); + +extern const CGEN_INSN * CGEN_SYM (lookup_insn) + PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, + CGEN_INSN_BYTES, int, CGEN_FIELDS *, int)); +extern void CGEN_SYM (get_insn_operands) + PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, + const CGEN_FIELDS *, int *)); +extern const CGEN_INSN * CGEN_SYM (lookup_get_insn_operands) + PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, + CGEN_INSN_BYTES, int, int *)); + +/* Get/set fields in the CGEN_FIELDS struct. */ + +int CGEN_SYM (get_int_operand) + PARAMS ((int, const CGEN_FIELDS *)); +void CGEN_SYM (set_int_operand) + PARAMS ((int, CGEN_FIELDS *, int)); +#ifdef BFD_VERSION /* Don't require bfd.h unnecessarily. */ +bfd_vma CGEN_SYM (get_vma_operand) + PARAMS ((int, const CGEN_FIELDS *)); +void CGEN_SYM (set_vma_operand) + PARAMS ((int, CGEN_FIELDS *, bfd_vma)); +#endif + +extern const char * CGEN_SYM (parse_operand) + PARAMS ((CGEN_OPCODE_DESC, int, const char **, CGEN_FIELDS *)); + +#ifdef BFD_VERSION /* Don't require bfd.h unnecessarily. */ +extern const char * CGEN_SYM (insert_operand) + PARAMS ((CGEN_OPCODE_DESC, int, CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, + bfd_vma)); +extern int CGEN_SYM (extract_operand) + PARAMS ((CGEN_OPCODE_DESC, int, CGEN_EXTRACT_INFO *, CGEN_INSN_INT, + CGEN_FIELDS *, bfd_vma)); +#endif + +/* Cover fns to bfd_get/set. */ + +extern CGEN_INSN_INT cgen_get_insn_value + PARAMS ((CGEN_OPCODE_DESC, unsigned char *, int)); +extern void cgen_put_insn_value + PARAMS ((CGEN_OPCODE_DESC, unsigned char *, int, CGEN_INSN_INT)); + +/* Read in a cpu description file. */ + +extern const char * cgen_read_cpu_file + PARAMS ((CGEN_OPCODE_DESC, const char * filename_)); + +#endif /* CGEN_H */ |