133965Sjdp/* CGEN generic opcode support. 233965Sjdp 3218822Sdim Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 485815Sobrien Free Software Foundation, Inc. 533965Sjdp 638889Sjdp This file is part of the GNU Binutils and GDB, the GNU debugger. 733965Sjdp 838889Sjdp This program is free software; you can redistribute it and/or modify 938889Sjdp it under the terms of the GNU General Public License as published by 1038889Sjdp the Free Software Foundation; either version 2, or (at your option) 1138889Sjdp any later version. 1233965Sjdp 1338889Sjdp This program is distributed in the hope that it will be useful, 1438889Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1538889Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1638889Sjdp GNU General Public License for more details. 1733965Sjdp 1838889Sjdp You should have received a copy of the GNU General Public License along 1938889Sjdp with this program; if not, write to the Free Software Foundation, Inc., 20218822Sdim 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2133965Sjdp 2233965Sjdp#include "sysdep.h" 2333965Sjdp#include <stdio.h> 2433965Sjdp#include "ansidecl.h" 2533965Sjdp#include "libiberty.h" 2689857Sobrien#include "safe-ctype.h" 2733965Sjdp#include "bfd.h" 2838889Sjdp#include "symcat.h" 2933965Sjdp#include "opcode/cgen.h" 3033965Sjdp 3185815Sobrien#ifdef HAVE_ALLOCA_H 3285815Sobrien#include <alloca.h> 3385815Sobrien#endif 3485815Sobrien 3533965Sjdpstatic unsigned int hash_keyword_name 36130561Sobrien (const CGEN_KEYWORD *, const char *, int); 3733965Sjdpstatic unsigned int hash_keyword_value 38130561Sobrien (const CGEN_KEYWORD *, unsigned int); 3933965Sjdpstatic void build_keyword_hash_tables 40130561Sobrien (CGEN_KEYWORD *); 4133965Sjdp 4233965Sjdp/* Return number of hash table entries to use for N elements. */ 4333965Sjdp#define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31) 4433965Sjdp 4533965Sjdp/* Look up *NAMEP in the keyword table KT. 4633965Sjdp The result is the keyword entry or NULL if not found. */ 4733965Sjdp 4838889Sjdpconst CGEN_KEYWORD_ENTRY * 49130561Sobriencgen_keyword_lookup_name (CGEN_KEYWORD *kt, const char *name) 5033965Sjdp{ 5138889Sjdp const CGEN_KEYWORD_ENTRY *ke; 5233965Sjdp const char *p,*n; 5333965Sjdp 5433965Sjdp if (kt->name_hash_table == NULL) 5533965Sjdp build_keyword_hash_tables (kt); 5633965Sjdp 5738889Sjdp ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)]; 5833965Sjdp 5933965Sjdp /* We do case insensitive comparisons. 6033965Sjdp If that ever becomes a problem, add an attribute that denotes 6133965Sjdp "do case sensitive comparisons". */ 6233965Sjdp 6333965Sjdp while (ke != NULL) 6433965Sjdp { 6533965Sjdp n = name; 6633965Sjdp p = ke->name; 6733965Sjdp 6833965Sjdp while (*p 6933965Sjdp && (*p == *n 7089857Sobrien || (ISALPHA (*p) && (TOLOWER (*p) == TOLOWER (*n))))) 7133965Sjdp ++n, ++p; 7233965Sjdp 7333965Sjdp if (!*p && !*n) 7433965Sjdp return ke; 7533965Sjdp 7633965Sjdp ke = ke->next_name; 7733965Sjdp } 7833965Sjdp 7938889Sjdp if (kt->null_entry) 8038889Sjdp return kt->null_entry; 8133965Sjdp return NULL; 8233965Sjdp} 8333965Sjdp 8433965Sjdp/* Look up VALUE in the keyword table KT. 8533965Sjdp The result is the keyword entry or NULL if not found. */ 8633965Sjdp 8738889Sjdpconst CGEN_KEYWORD_ENTRY * 88130561Sobriencgen_keyword_lookup_value (CGEN_KEYWORD *kt, int value) 8933965Sjdp{ 9038889Sjdp const CGEN_KEYWORD_ENTRY *ke; 9133965Sjdp 9233965Sjdp if (kt->name_hash_table == NULL) 9333965Sjdp build_keyword_hash_tables (kt); 9433965Sjdp 9533965Sjdp ke = kt->value_hash_table[hash_keyword_value (kt, value)]; 9633965Sjdp 9733965Sjdp while (ke != NULL) 9833965Sjdp { 9933965Sjdp if (value == ke->value) 10033965Sjdp return ke; 10133965Sjdp ke = ke->next_value; 10233965Sjdp } 10333965Sjdp 10433965Sjdp return NULL; 10533965Sjdp} 10633965Sjdp 10733965Sjdp/* Add an entry to a keyword table. */ 10833965Sjdp 10933965Sjdpvoid 110130561Sobriencgen_keyword_add (CGEN_KEYWORD *kt, CGEN_KEYWORD_ENTRY *ke) 11133965Sjdp{ 11233965Sjdp unsigned int hash; 11389857Sobrien size_t i; 11433965Sjdp 11533965Sjdp if (kt->name_hash_table == NULL) 11633965Sjdp build_keyword_hash_tables (kt); 11733965Sjdp 11838889Sjdp hash = hash_keyword_name (kt, ke->name, 0); 11933965Sjdp ke->next_name = kt->name_hash_table[hash]; 12033965Sjdp kt->name_hash_table[hash] = ke; 12133965Sjdp 12233965Sjdp hash = hash_keyword_value (kt, ke->value); 12333965Sjdp ke->next_value = kt->value_hash_table[hash]; 12433965Sjdp kt->value_hash_table[hash] = ke; 12538889Sjdp 12638889Sjdp if (ke->name[0] == 0) 12738889Sjdp kt->null_entry = ke; 12889857Sobrien 12989857Sobrien for (i = 1; i < strlen (ke->name); i++) 13089857Sobrien if (! ISALNUM (ke->name[i]) 13189857Sobrien && ! strchr (kt->nonalpha_chars, ke->name[i])) 13289857Sobrien { 13389857Sobrien size_t idx = strlen (kt->nonalpha_chars); 13489857Sobrien 13589857Sobrien /* If you hit this limit, please don't just 13689857Sobrien increase the size of the field, instead 13789857Sobrien look for a better algorithm. */ 13889857Sobrien if (idx >= sizeof (kt->nonalpha_chars) - 1) 13989857Sobrien abort (); 14089857Sobrien kt->nonalpha_chars[idx] = ke->name[i]; 14189857Sobrien kt->nonalpha_chars[idx+1] = 0; 14289857Sobrien } 14333965Sjdp} 14433965Sjdp 14533965Sjdp/* FIXME: Need function to return count of keywords. */ 14633965Sjdp 14733965Sjdp/* Initialize a keyword table search. 14833965Sjdp SPEC is a specification of what to search for. 14933965Sjdp A value of NULL means to find every keyword. 15033965Sjdp Currently NULL is the only acceptable value [further specification 15133965Sjdp deferred]. 15233965Sjdp The result is an opaque data item used to record the search status. 15333965Sjdp It is passed to each call to cgen_keyword_search_next. */ 15433965Sjdp 15538889SjdpCGEN_KEYWORD_SEARCH 156130561Sobriencgen_keyword_search_init (CGEN_KEYWORD *kt, const char *spec) 15733965Sjdp{ 15838889Sjdp CGEN_KEYWORD_SEARCH search; 15933965Sjdp 160218822Sdim /* FIXME: Need to specify format of params. */ 16133965Sjdp if (spec != NULL) 16233965Sjdp abort (); 16333965Sjdp 16433965Sjdp if (kt->name_hash_table == NULL) 16533965Sjdp build_keyword_hash_tables (kt); 16633965Sjdp 16733965Sjdp search.table = kt; 16833965Sjdp search.spec = spec; 16933965Sjdp search.current_hash = 0; 17033965Sjdp search.current_entry = NULL; 17133965Sjdp return search; 17233965Sjdp} 17333965Sjdp 17433965Sjdp/* Return the next keyword specified by SEARCH. 17533965Sjdp The result is the next entry or NULL if there are no more. */ 17633965Sjdp 17738889Sjdpconst CGEN_KEYWORD_ENTRY * 178130561Sobriencgen_keyword_search_next (CGEN_KEYWORD_SEARCH *search) 17933965Sjdp{ 18033965Sjdp /* Has search finished? */ 18133965Sjdp if (search->current_hash == search->table->hash_table_size) 18233965Sjdp return NULL; 18333965Sjdp 18433965Sjdp /* Search in progress? */ 18533965Sjdp if (search->current_entry != NULL 18633965Sjdp /* Anything left on this hash chain? */ 18733965Sjdp && search->current_entry->next_name != NULL) 18833965Sjdp { 18933965Sjdp search->current_entry = search->current_entry->next_name; 19033965Sjdp return search->current_entry; 19133965Sjdp } 19233965Sjdp 19333965Sjdp /* Move to next hash chain [unless we haven't started yet]. */ 19433965Sjdp if (search->current_entry != NULL) 19533965Sjdp ++search->current_hash; 19633965Sjdp 19733965Sjdp while (search->current_hash < search->table->hash_table_size) 19833965Sjdp { 19933965Sjdp search->current_entry = search->table->name_hash_table[search->current_hash]; 20033965Sjdp if (search->current_entry != NULL) 20133965Sjdp return search->current_entry; 20233965Sjdp ++search->current_hash; 20333965Sjdp } 20433965Sjdp 20533965Sjdp return NULL; 20633965Sjdp} 20733965Sjdp 20838889Sjdp/* Return first entry in hash chain for NAME. 20938889Sjdp If CASE_SENSITIVE_P is non-zero, return a case sensitive hash. */ 21033965Sjdp 21133965Sjdpstatic unsigned int 212130561Sobrienhash_keyword_name (const CGEN_KEYWORD *kt, 213130561Sobrien const char *name, 214130561Sobrien int case_sensitive_p) 21533965Sjdp{ 21633965Sjdp unsigned int hash; 21733965Sjdp 21838889Sjdp if (case_sensitive_p) 21938889Sjdp for (hash = 0; *name; ++name) 22038889Sjdp hash = (hash * 97) + (unsigned char) *name; 22138889Sjdp else 22238889Sjdp for (hash = 0; *name; ++name) 22389857Sobrien hash = (hash * 97) + (unsigned char) TOLOWER (*name); 22433965Sjdp return hash % kt->hash_table_size; 22533965Sjdp} 22633965Sjdp 22733965Sjdp/* Return first entry in hash chain for VALUE. */ 22833965Sjdp 22933965Sjdpstatic unsigned int 230130561Sobrienhash_keyword_value (const CGEN_KEYWORD *kt, unsigned int value) 23133965Sjdp{ 23233965Sjdp return value % kt->hash_table_size; 23333965Sjdp} 23433965Sjdp 23533965Sjdp/* Build a keyword table's hash tables. 23633965Sjdp We probably needn't build the value hash table for the assembler when 23733965Sjdp we're using the disassembler, but we keep things simple. */ 23833965Sjdp 23933965Sjdpstatic void 240130561Sobrienbuild_keyword_hash_tables (CGEN_KEYWORD *kt) 24133965Sjdp{ 24233965Sjdp int i; 24333965Sjdp /* Use the number of compiled in entries as an estimate for the 24433965Sjdp typical sized table [not too many added at runtime]. */ 24533965Sjdp unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries); 24633965Sjdp 24733965Sjdp kt->hash_table_size = size; 24838889Sjdp kt->name_hash_table = (CGEN_KEYWORD_ENTRY **) 24938889Sjdp xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *)); 25038889Sjdp memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *)); 25138889Sjdp kt->value_hash_table = (CGEN_KEYWORD_ENTRY **) 25238889Sjdp xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *)); 25338889Sjdp memset (kt->value_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *)); 25433965Sjdp 25533965Sjdp /* The table is scanned backwards as we want keywords appearing earlier to 25633965Sjdp be prefered over later ones. */ 25733965Sjdp for (i = kt->num_init_entries - 1; i >= 0; --i) 25833965Sjdp cgen_keyword_add (kt, &kt->init_entries[i]); 25933965Sjdp} 26033965Sjdp 26133965Sjdp/* Hardware support. */ 26233965Sjdp 26360484Sobrien/* Lookup a hardware element by its name. 26460484Sobrien Returns NULL if NAME is not supported by the currently selected 26560484Sobrien mach/isa. */ 26660484Sobrien 26738889Sjdpconst CGEN_HW_ENTRY * 268130561Sobriencgen_hw_lookup_by_name (CGEN_CPU_DESC cd, const char *name) 26933965Sjdp{ 27085815Sobrien unsigned int i; 27160484Sobrien const CGEN_HW_ENTRY **hw = cd->hw_table.entries; 27233965Sjdp 27360484Sobrien for (i = 0; i < cd->hw_table.num_entries; ++i) 27460484Sobrien if (hw[i] && strcmp (name, hw[i]->name) == 0) 27560484Sobrien return hw[i]; 27633965Sjdp 27733965Sjdp return NULL; 27833965Sjdp} 27960484Sobrien 28060484Sobrien/* Lookup a hardware element by its number. 28160484Sobrien Hardware elements are enumerated, however it may be possible to add some 28260484Sobrien at runtime, thus HWNUM is not an enum type but rather an int. 28360484Sobrien Returns NULL if HWNUM is not supported by the currently selected mach. */ 28460484Sobrien 28560484Sobrienconst CGEN_HW_ENTRY * 286130561Sobriencgen_hw_lookup_by_num (CGEN_CPU_DESC cd, unsigned int hwnum) 28760484Sobrien{ 28885815Sobrien unsigned int i; 28960484Sobrien const CGEN_HW_ENTRY **hw = cd->hw_table.entries; 29060484Sobrien 29160484Sobrien /* ??? This can be speeded up. */ 29260484Sobrien for (i = 0; i < cd->hw_table.num_entries; ++i) 29360484Sobrien if (hw[i] && hwnum == hw[i]->type) 29460484Sobrien return hw[i]; 29560484Sobrien 29660484Sobrien return NULL; 29760484Sobrien} 29833965Sjdp 29960484Sobrien/* Operand support. */ 30060484Sobrien 30160484Sobrien/* Lookup an operand by its name. 30260484Sobrien Returns NULL if NAME is not supported by the currently selected 30360484Sobrien mach/isa. */ 30460484Sobrien 30560484Sobrienconst CGEN_OPERAND * 306130561Sobriencgen_operand_lookup_by_name (CGEN_CPU_DESC cd, const char *name) 30760484Sobrien{ 30885815Sobrien unsigned int i; 30960484Sobrien const CGEN_OPERAND **op = cd->operand_table.entries; 31060484Sobrien 31160484Sobrien for (i = 0; i < cd->operand_table.num_entries; ++i) 31260484Sobrien if (op[i] && strcmp (name, op[i]->name) == 0) 31360484Sobrien return op[i]; 31460484Sobrien 31560484Sobrien return NULL; 31660484Sobrien} 31760484Sobrien 31860484Sobrien/* Lookup an operand by its number. 31960484Sobrien Operands are enumerated, however it may be possible to add some 32060484Sobrien at runtime, thus OPNUM is not an enum type but rather an int. 32160484Sobrien Returns NULL if OPNUM is not supported by the currently selected 32260484Sobrien mach/isa. */ 32360484Sobrien 32460484Sobrienconst CGEN_OPERAND * 325130561Sobriencgen_operand_lookup_by_num (CGEN_CPU_DESC cd, int opnum) 32660484Sobrien{ 32760484Sobrien return cd->operand_table.entries[opnum]; 32860484Sobrien} 32960484Sobrien 33033965Sjdp/* Instruction support. */ 33133965Sjdp 33233965Sjdp/* Return number of instructions. This includes any added at runtime. */ 33333965Sjdp 33433965Sjdpint 335130561Sobriencgen_insn_count (CGEN_CPU_DESC cd) 33633965Sjdp{ 33760484Sobrien int count = cd->insn_table.num_init_entries; 33860484Sobrien CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries; 33933965Sjdp 34060484Sobrien for ( ; rt_insns != NULL; rt_insns = rt_insns->next) 34133965Sjdp ++count; 34233965Sjdp 34333965Sjdp return count; 34433965Sjdp} 34560484Sobrien 34660484Sobrien/* Return number of macro-instructions. 34760484Sobrien This includes any added at runtime. */ 34860484Sobrien 34960484Sobrienint 350130561Sobriencgen_macro_insn_count (CGEN_CPU_DESC cd) 35160484Sobrien{ 35260484Sobrien int count = cd->macro_insn_table.num_init_entries; 35360484Sobrien CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries; 35460484Sobrien 35560484Sobrien for ( ; rt_insns != NULL; rt_insns = rt_insns->next) 35660484Sobrien ++count; 35760484Sobrien 35860484Sobrien return count; 35960484Sobrien} 36060484Sobrien 36160484Sobrien/* Cover function to read and properly byteswap an insn value. */ 36260484Sobrien 36360484SobrienCGEN_INSN_INT 364130561Sobriencgen_get_insn_value (CGEN_CPU_DESC cd, unsigned char *buf, int length) 36560484Sobrien{ 36689857Sobrien int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG); 36789857Sobrien int insn_chunk_bitsize = cd->insn_chunk_bitsize; 36889857Sobrien CGEN_INSN_INT value = 0; 36989857Sobrien 37089857Sobrien if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length) 37189857Sobrien { 37289857Sobrien /* We need to divide up the incoming value into insn_chunk_bitsize-length 37389857Sobrien segments, and endian-convert them, one at a time. */ 37489857Sobrien int i; 37589857Sobrien 37689857Sobrien /* Enforce divisibility. */ 37789857Sobrien if ((length % insn_chunk_bitsize) != 0) 37889857Sobrien abort (); 37989857Sobrien 38089857Sobrien for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */ 38189857Sobrien { 38289857Sobrien int index; 38389857Sobrien bfd_vma this_value; 38489857Sobrien index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */ 38589857Sobrien this_value = bfd_get_bits (& buf[index / 8], insn_chunk_bitsize, big_p); 38689857Sobrien value = (value << insn_chunk_bitsize) | this_value; 38789857Sobrien } 38889857Sobrien } 38989857Sobrien else 39089857Sobrien { 39189857Sobrien value = bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG); 39289857Sobrien } 39389857Sobrien 39489857Sobrien return value; 39560484Sobrien} 39660484Sobrien 39760484Sobrien/* Cover function to store an insn value properly byteswapped. */ 39860484Sobrien 39960484Sobrienvoid 400130561Sobriencgen_put_insn_value (CGEN_CPU_DESC cd, 401130561Sobrien unsigned char *buf, 402130561Sobrien int length, 403130561Sobrien CGEN_INSN_INT value) 40460484Sobrien{ 40589857Sobrien int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG); 40689857Sobrien int insn_chunk_bitsize = cd->insn_chunk_bitsize; 40789857Sobrien 40889857Sobrien if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length) 40989857Sobrien { 41089857Sobrien /* We need to divide up the incoming value into insn_chunk_bitsize-length 41189857Sobrien segments, and endian-convert them, one at a time. */ 41289857Sobrien int i; 41389857Sobrien 41489857Sobrien /* Enforce divisibility. */ 41589857Sobrien if ((length % insn_chunk_bitsize) != 0) 41689857Sobrien abort (); 41789857Sobrien 41889857Sobrien for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */ 41989857Sobrien { 42089857Sobrien int index; 42189857Sobrien index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */ 42289857Sobrien bfd_put_bits ((bfd_vma) value, & buf[index / 8], insn_chunk_bitsize, big_p); 42389857Sobrien value >>= insn_chunk_bitsize; 42489857Sobrien } 42589857Sobrien } 42689857Sobrien else 42789857Sobrien { 42889857Sobrien bfd_put_bits ((bfd_vma) value, buf, length, big_p); 42989857Sobrien } 43060484Sobrien} 43160484Sobrien 43260484Sobrien/* Look up instruction INSN_*_VALUE and extract its fields. 43360484Sobrien INSN_INT_VALUE is used if CGEN_INT_INSN_P. 43460484Sobrien Otherwise INSN_BYTES_VALUE is used. 43560484Sobrien INSN, if non-null, is the insn table entry. 43660484Sobrien Otherwise INSN_*_VALUE is examined to compute it. 43760484Sobrien LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0. 43860484Sobrien 0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'. 43960484Sobrien If INSN != NULL, LENGTH must be valid. 44060484Sobrien ALIAS_P is non-zero if alias insns are to be included in the search. 44160484Sobrien 44260484Sobrien The result is a pointer to the insn table entry, or NULL if the instruction 44360484Sobrien wasn't recognized. */ 44460484Sobrien 44560484Sobrien/* ??? Will need to be revisited for VLIW architectures. */ 44660484Sobrien 44760484Sobrienconst CGEN_INSN * 448130561Sobriencgen_lookup_insn (CGEN_CPU_DESC cd, 449130561Sobrien const CGEN_INSN *insn, 450130561Sobrien CGEN_INSN_INT insn_int_value, 451130561Sobrien /* ??? CGEN_INSN_BYTES would be a nice type name to use here. */ 452130561Sobrien unsigned char *insn_bytes_value, 453130561Sobrien int length, 454130561Sobrien CGEN_FIELDS *fields, 455130561Sobrien int alias_p) 45660484Sobrien{ 45760484Sobrien unsigned char *buf; 45860484Sobrien CGEN_INSN_INT base_insn; 45960484Sobrien CGEN_EXTRACT_INFO ex_info; 46060484Sobrien CGEN_EXTRACT_INFO *info; 46160484Sobrien 46260484Sobrien if (cd->int_insn_p) 46360484Sobrien { 46460484Sobrien info = NULL; 46560484Sobrien buf = (unsigned char *) alloca (cd->max_insn_bitsize / 8); 46660484Sobrien cgen_put_insn_value (cd, buf, length, insn_int_value); 46760484Sobrien base_insn = insn_int_value; 46860484Sobrien } 46960484Sobrien else 47060484Sobrien { 47160484Sobrien info = &ex_info; 47260484Sobrien ex_info.dis_info = NULL; 47360484Sobrien ex_info.insn_bytes = insn_bytes_value; 47460484Sobrien ex_info.valid = -1; 47560484Sobrien buf = insn_bytes_value; 47660484Sobrien base_insn = cgen_get_insn_value (cd, buf, length); 47760484Sobrien } 47860484Sobrien 47960484Sobrien if (!insn) 48060484Sobrien { 48160484Sobrien const CGEN_INSN_LIST *insn_list; 48260484Sobrien 48360484Sobrien /* The instructions are stored in hash lists. 48460484Sobrien Pick the first one and keep trying until we find the right one. */ 48560484Sobrien 486218822Sdim insn_list = cgen_dis_lookup_insn (cd, (char *) buf, base_insn); 48760484Sobrien while (insn_list != NULL) 48860484Sobrien { 48960484Sobrien insn = insn_list->insn; 49060484Sobrien 49160484Sobrien if (alias_p 49260484Sobrien /* FIXME: Ensure ALIAS attribute always has same index. */ 49360484Sobrien || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS)) 49460484Sobrien { 49560484Sobrien /* Basic bit mask must be correct. */ 49660484Sobrien /* ??? May wish to allow target to defer this check until the 49760484Sobrien extract handler. */ 49860484Sobrien if ((base_insn & CGEN_INSN_BASE_MASK (insn)) 49960484Sobrien == CGEN_INSN_BASE_VALUE (insn)) 50060484Sobrien { 50160484Sobrien /* ??? 0 is passed for `pc' */ 50260484Sobrien int elength = CGEN_EXTRACT_FN (cd, insn) 50360484Sobrien (cd, insn, info, base_insn, fields, (bfd_vma) 0); 50460484Sobrien if (elength > 0) 50560484Sobrien { 50660484Sobrien /* sanity check */ 50760484Sobrien if (length != 0 && length != elength) 50860484Sobrien abort (); 50960484Sobrien return insn; 51060484Sobrien } 51160484Sobrien } 51260484Sobrien } 51360484Sobrien 51460484Sobrien insn_list = insn_list->next; 51560484Sobrien } 51660484Sobrien } 51760484Sobrien else 51860484Sobrien { 51960484Sobrien /* Sanity check: can't pass an alias insn if ! alias_p. */ 52060484Sobrien if (! alias_p 52160484Sobrien && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS)) 52260484Sobrien abort (); 52360484Sobrien /* Sanity check: length must be correct. */ 52460484Sobrien if (length != CGEN_INSN_BITSIZE (insn)) 52560484Sobrien abort (); 52660484Sobrien 52760484Sobrien /* ??? 0 is passed for `pc' */ 52860484Sobrien length = CGEN_EXTRACT_FN (cd, insn) 52960484Sobrien (cd, insn, info, base_insn, fields, (bfd_vma) 0); 53060484Sobrien /* Sanity check: must succeed. 53160484Sobrien Could relax this later if it ever proves useful. */ 53260484Sobrien if (length == 0) 53360484Sobrien abort (); 53460484Sobrien return insn; 53560484Sobrien } 53660484Sobrien 53760484Sobrien return NULL; 53860484Sobrien} 53960484Sobrien 54060484Sobrien/* Fill in the operand instances used by INSN whose operands are FIELDS. 54160484Sobrien INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled 54260484Sobrien in. */ 54360484Sobrien 54460484Sobrienvoid 545130561Sobriencgen_get_insn_operands (CGEN_CPU_DESC cd, 546130561Sobrien const CGEN_INSN *insn, 547130561Sobrien const CGEN_FIELDS *fields, 548130561Sobrien int *indices) 54960484Sobrien{ 55060484Sobrien const CGEN_OPINST *opinst; 55160484Sobrien int i; 55260484Sobrien 55360484Sobrien if (insn->opinst == NULL) 55460484Sobrien abort (); 55560484Sobrien for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst) 55660484Sobrien { 55760484Sobrien enum cgen_operand_type op_type = opinst->op_type; 55860484Sobrien if (op_type == CGEN_OPERAND_NIL) 55960484Sobrien indices[i] = opinst->index; 56060484Sobrien else 56160484Sobrien indices[i] = (*cd->get_int_operand) (cd, op_type, fields); 56260484Sobrien } 56360484Sobrien} 56460484Sobrien 56560484Sobrien/* Cover function to cgen_get_insn_operands when either INSN or FIELDS 56660484Sobrien isn't known. 56760484Sobrien The INSN, INSN_*_VALUE, and LENGTH arguments are passed to 56860484Sobrien cgen_lookup_insn unchanged. 56960484Sobrien INSN_INT_VALUE is used if CGEN_INT_INSN_P. 57060484Sobrien Otherwise INSN_BYTES_VALUE is used. 57160484Sobrien 57260484Sobrien The result is the insn table entry or NULL if the instruction wasn't 57360484Sobrien recognized. */ 57460484Sobrien 57560484Sobrienconst CGEN_INSN * 576130561Sobriencgen_lookup_get_insn_operands (CGEN_CPU_DESC cd, 577130561Sobrien const CGEN_INSN *insn, 578130561Sobrien CGEN_INSN_INT insn_int_value, 579130561Sobrien /* ??? CGEN_INSN_BYTES would be a nice type name to use here. */ 580130561Sobrien unsigned char *insn_bytes_value, 581130561Sobrien int length, 582130561Sobrien int *indices, 583130561Sobrien CGEN_FIELDS *fields) 58460484Sobrien{ 58560484Sobrien /* Pass non-zero for ALIAS_P only if INSN != NULL. 58660484Sobrien If INSN == NULL, we want a real insn. */ 58760484Sobrien insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value, 58860484Sobrien length, fields, insn != NULL); 58960484Sobrien if (! insn) 59060484Sobrien return NULL; 59160484Sobrien 59260484Sobrien cgen_get_insn_operands (cd, insn, fields, indices); 59360484Sobrien return insn; 59460484Sobrien} 59560484Sobrien 59660484Sobrien/* Allow signed overflow of instruction fields. */ 59760484Sobrienvoid 598130561Sobriencgen_set_signed_overflow_ok (CGEN_CPU_DESC cd) 59960484Sobrien{ 60060484Sobrien cd->signed_overflow_ok_p = 1; 60160484Sobrien} 60260484Sobrien 60360484Sobrien/* Generate an error message if a signed field in an instruction overflows. */ 60460484Sobrienvoid 605130561Sobriencgen_clear_signed_overflow_ok (CGEN_CPU_DESC cd) 60660484Sobrien{ 60760484Sobrien cd->signed_overflow_ok_p = 0; 60860484Sobrien} 60960484Sobrien 61060484Sobrien/* Will an error message be generated if a signed field in an instruction overflows ? */ 61160484Sobrienunsigned int 612130561Sobriencgen_signed_overflow_ok_p (CGEN_CPU_DESC cd) 61360484Sobrien{ 61460484Sobrien return cd->signed_overflow_ok_p; 61560484Sobrien} 616