Back to index

cell-binutils  2.17cvs20070401
cgen-opc.c
Go to the documentation of this file.
00001 /* CGEN generic opcode support.
00002 
00003    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
00004    Free Software Foundation, Inc.
00005 
00006    This file is part of the GNU Binutils and GDB, the GNU debugger.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2, or (at your option)
00011    any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License along
00019    with this program; if not, write to the Free Software Foundation, Inc.,
00020    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00021 
00022 #include "sysdep.h"
00023 #include <stdio.h>
00024 #include "ansidecl.h"
00025 #include "libiberty.h"
00026 #include "safe-ctype.h"
00027 #include "bfd.h"
00028 #include "symcat.h"
00029 #include "opcode/cgen.h"
00030 
00031 #ifdef HAVE_ALLOCA_H
00032 #include <alloca.h>
00033 #endif
00034 
00035 static unsigned int hash_keyword_name
00036   (const CGEN_KEYWORD *, const char *, int);
00037 static unsigned int hash_keyword_value
00038   (const CGEN_KEYWORD *, unsigned int);
00039 static void build_keyword_hash_tables
00040   (CGEN_KEYWORD *);
00041 
00042 /* Return number of hash table entries to use for N elements.  */
00043 #define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
00044 
00045 /* Look up *NAMEP in the keyword table KT.
00046    The result is the keyword entry or NULL if not found.  */
00047 
00048 const CGEN_KEYWORD_ENTRY *
00049 cgen_keyword_lookup_name (CGEN_KEYWORD *kt, const char *name)
00050 {
00051   const CGEN_KEYWORD_ENTRY *ke;
00052   const char *p,*n;
00053 
00054   if (kt->name_hash_table == NULL)
00055     build_keyword_hash_tables (kt);
00056 
00057   ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)];
00058 
00059   /* We do case insensitive comparisons.
00060      If that ever becomes a problem, add an attribute that denotes
00061      "do case sensitive comparisons".  */
00062 
00063   while (ke != NULL)
00064     {
00065       n = name;
00066       p = ke->name;
00067 
00068       while (*p
00069             && (*p == *n
00070                || (ISALPHA (*p) && (TOLOWER (*p) == TOLOWER (*n)))))
00071        ++n, ++p;
00072 
00073       if (!*p && !*n)
00074        return ke;
00075 
00076       ke = ke->next_name;
00077     }
00078 
00079   if (kt->null_entry)
00080     return kt->null_entry;
00081   return NULL;
00082 }
00083 
00084 /* Look up VALUE in the keyword table KT.
00085    The result is the keyword entry or NULL if not found.  */
00086 
00087 const CGEN_KEYWORD_ENTRY *
00088 cgen_keyword_lookup_value (CGEN_KEYWORD *kt, int value)
00089 {
00090   const CGEN_KEYWORD_ENTRY *ke;
00091 
00092   if (kt->name_hash_table == NULL)
00093     build_keyword_hash_tables (kt);
00094 
00095   ke = kt->value_hash_table[hash_keyword_value (kt, value)];
00096 
00097   while (ke != NULL)
00098     {
00099       if (value == ke->value)
00100        return ke;
00101       ke = ke->next_value;
00102     }
00103 
00104   return NULL;
00105 }
00106 
00107 /* Add an entry to a keyword table.  */
00108 
00109 void
00110 cgen_keyword_add (CGEN_KEYWORD *kt, CGEN_KEYWORD_ENTRY *ke)
00111 {
00112   unsigned int hash;
00113   size_t i;
00114 
00115   if (kt->name_hash_table == NULL)
00116     build_keyword_hash_tables (kt);
00117 
00118   hash = hash_keyword_name (kt, ke->name, 0);
00119   ke->next_name = kt->name_hash_table[hash];
00120   kt->name_hash_table[hash] = ke;
00121 
00122   hash = hash_keyword_value (kt, ke->value);
00123   ke->next_value = kt->value_hash_table[hash];
00124   kt->value_hash_table[hash] = ke;
00125 
00126   if (ke->name[0] == 0)
00127     kt->null_entry = ke;
00128 
00129   for (i = 1; i < strlen (ke->name); i++)
00130     if (! ISALNUM (ke->name[i])
00131        && ! strchr (kt->nonalpha_chars, ke->name[i]))
00132       {
00133        size_t idx = strlen (kt->nonalpha_chars);
00134        
00135        /* If you hit this limit, please don't just
00136           increase the size of the field, instead
00137           look for a better algorithm.  */
00138        if (idx >= sizeof (kt->nonalpha_chars) - 1)
00139          abort ();
00140        kt->nonalpha_chars[idx] = ke->name[i];
00141        kt->nonalpha_chars[idx+1] = 0;
00142       }
00143 }
00144 
00145 /* FIXME: Need function to return count of keywords.  */
00146 
00147 /* Initialize a keyword table search.
00148    SPEC is a specification of what to search for.
00149    A value of NULL means to find every keyword.
00150    Currently NULL is the only acceptable value [further specification
00151    deferred].
00152    The result is an opaque data item used to record the search status.
00153    It is passed to each call to cgen_keyword_search_next.  */
00154 
00155 CGEN_KEYWORD_SEARCH
00156 cgen_keyword_search_init (CGEN_KEYWORD *kt, const char *spec)
00157 {
00158   CGEN_KEYWORD_SEARCH search;
00159 
00160   /* FIXME: Need to specify format of params.  */
00161   if (spec != NULL)
00162     abort ();
00163 
00164   if (kt->name_hash_table == NULL)
00165     build_keyword_hash_tables (kt);
00166 
00167   search.table = kt;
00168   search.spec = spec;
00169   search.current_hash = 0;
00170   search.current_entry = NULL;
00171   return search;
00172 }
00173 
00174 /* Return the next keyword specified by SEARCH.
00175    The result is the next entry or NULL if there are no more.  */
00176 
00177 const CGEN_KEYWORD_ENTRY *
00178 cgen_keyword_search_next (CGEN_KEYWORD_SEARCH *search)
00179 {
00180   /* Has search finished?  */
00181   if (search->current_hash == search->table->hash_table_size)
00182     return NULL;
00183 
00184   /* Search in progress?  */
00185   if (search->current_entry != NULL
00186       /* Anything left on this hash chain?  */
00187       && search->current_entry->next_name != NULL)
00188     {
00189       search->current_entry = search->current_entry->next_name;
00190       return search->current_entry;
00191     }
00192 
00193   /* Move to next hash chain [unless we haven't started yet].  */
00194   if (search->current_entry != NULL)
00195     ++search->current_hash;
00196 
00197   while (search->current_hash < search->table->hash_table_size)
00198     {
00199       search->current_entry = search->table->name_hash_table[search->current_hash];
00200       if (search->current_entry != NULL)
00201        return search->current_entry;
00202       ++search->current_hash;
00203     }
00204 
00205   return NULL;
00206 }
00207 
00208 /* Return first entry in hash chain for NAME.
00209    If CASE_SENSITIVE_P is non-zero, return a case sensitive hash.  */
00210 
00211 static unsigned int
00212 hash_keyword_name (const CGEN_KEYWORD *kt,
00213                  const char *name,
00214                  int case_sensitive_p)
00215 {
00216   unsigned int hash;
00217 
00218   if (case_sensitive_p)
00219     for (hash = 0; *name; ++name)
00220       hash = (hash * 97) + (unsigned char) *name;
00221   else
00222     for (hash = 0; *name; ++name)
00223       hash = (hash * 97) + (unsigned char) TOLOWER (*name);
00224   return hash % kt->hash_table_size;
00225 }
00226 
00227 /* Return first entry in hash chain for VALUE.  */
00228 
00229 static unsigned int
00230 hash_keyword_value (const CGEN_KEYWORD *kt, unsigned int value)
00231 {
00232   return value % kt->hash_table_size;
00233 }
00234 
00235 /* Build a keyword table's hash tables.
00236    We probably needn't build the value hash table for the assembler when
00237    we're using the disassembler, but we keep things simple.  */
00238 
00239 static void
00240 build_keyword_hash_tables (CGEN_KEYWORD *kt)
00241 {
00242   int i;
00243   /* Use the number of compiled in entries as an estimate for the
00244      typical sized table [not too many added at runtime].  */
00245   unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
00246 
00247   kt->hash_table_size = size;
00248   kt->name_hash_table = (CGEN_KEYWORD_ENTRY **)
00249     xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
00250   memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
00251   kt->value_hash_table = (CGEN_KEYWORD_ENTRY **)
00252     xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
00253   memset (kt->value_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
00254 
00255   /* The table is scanned backwards as we want keywords appearing earlier to
00256      be prefered over later ones.  */
00257   for (i = kt->num_init_entries - 1; i >= 0; --i)
00258     cgen_keyword_add (kt, &kt->init_entries[i]);
00259 }
00260 
00261 /* Hardware support.  */
00262 
00263 /* Lookup a hardware element by its name.
00264    Returns NULL if NAME is not supported by the currently selected
00265    mach/isa.  */
00266 
00267 const CGEN_HW_ENTRY *
00268 cgen_hw_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
00269 {
00270   unsigned int i;
00271   const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
00272 
00273   for (i = 0; i < cd->hw_table.num_entries; ++i)
00274     if (hw[i] && strcmp (name, hw[i]->name) == 0)
00275       return hw[i];
00276 
00277   return NULL;
00278 }
00279 
00280 /* Lookup a hardware element by its number.
00281    Hardware elements are enumerated, however it may be possible to add some
00282    at runtime, thus HWNUM is not an enum type but rather an int.
00283    Returns NULL if HWNUM is not supported by the currently selected mach.  */
00284 
00285 const CGEN_HW_ENTRY *
00286 cgen_hw_lookup_by_num (CGEN_CPU_DESC cd, unsigned int hwnum)
00287 {
00288   unsigned int i;
00289   const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
00290 
00291   /* ??? This can be speeded up.  */
00292   for (i = 0; i < cd->hw_table.num_entries; ++i)
00293     if (hw[i] && hwnum == hw[i]->type)
00294       return hw[i];
00295 
00296   return NULL;
00297 }
00298 
00299 /* Operand support.  */
00300 
00301 /* Lookup an operand by its name.
00302    Returns NULL if NAME is not supported by the currently selected
00303    mach/isa.  */
00304 
00305 const CGEN_OPERAND *
00306 cgen_operand_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
00307 {
00308   unsigned int i;
00309   const CGEN_OPERAND **op = cd->operand_table.entries;
00310 
00311   for (i = 0; i < cd->operand_table.num_entries; ++i)
00312     if (op[i] && strcmp (name, op[i]->name) == 0)
00313       return op[i];
00314 
00315   return NULL;
00316 }
00317 
00318 /* Lookup an operand by its number.
00319    Operands are enumerated, however it may be possible to add some
00320    at runtime, thus OPNUM is not an enum type but rather an int.
00321    Returns NULL if OPNUM is not supported by the currently selected
00322    mach/isa.  */
00323 
00324 const CGEN_OPERAND *
00325 cgen_operand_lookup_by_num (CGEN_CPU_DESC cd, int opnum)
00326 {
00327   return cd->operand_table.entries[opnum];
00328 }
00329 
00330 /* Instruction support.  */
00331 
00332 /* Return number of instructions.  This includes any added at runtime.  */
00333 
00334 int
00335 cgen_insn_count (CGEN_CPU_DESC cd)
00336 {
00337   int count = cd->insn_table.num_init_entries;
00338   CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
00339 
00340   for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
00341     ++count;
00342 
00343   return count;
00344 }
00345 
00346 /* Return number of macro-instructions.
00347    This includes any added at runtime.  */
00348 
00349 int
00350 cgen_macro_insn_count (CGEN_CPU_DESC cd)
00351 {
00352   int count = cd->macro_insn_table.num_init_entries;
00353   CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
00354 
00355   for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
00356     ++count;
00357 
00358   return count;
00359 }
00360 
00361 /* Cover function to read and properly byteswap an insn value.  */
00362 
00363 CGEN_INSN_INT
00364 cgen_get_insn_value (CGEN_CPU_DESC cd, unsigned char *buf, int length)
00365 {
00366   int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
00367   int insn_chunk_bitsize = cd->insn_chunk_bitsize;
00368   CGEN_INSN_INT value = 0;
00369 
00370   if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
00371     {
00372       /* We need to divide up the incoming value into insn_chunk_bitsize-length
00373         segments, and endian-convert them, one at a time. */
00374       int i;
00375 
00376       /* Enforce divisibility. */ 
00377       if ((length % insn_chunk_bitsize) != 0)
00378        abort ();
00379 
00380       for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
00381        {
00382          int index;
00383          bfd_vma this_value;
00384          index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
00385          this_value = bfd_get_bits (& buf[index / 8], insn_chunk_bitsize, big_p);
00386          value = (value << insn_chunk_bitsize) | this_value;
00387        }
00388     }
00389   else
00390     {
00391       value = bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG);
00392     }
00393 
00394   return value;
00395 }
00396 
00397 /* Cover function to store an insn value properly byteswapped.  */
00398 
00399 void
00400 cgen_put_insn_value (CGEN_CPU_DESC cd,
00401                    unsigned char *buf,
00402                    int length,
00403                    CGEN_INSN_INT value)
00404 {
00405   int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
00406   int insn_chunk_bitsize = cd->insn_chunk_bitsize;
00407 
00408   if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
00409     {
00410       /* We need to divide up the incoming value into insn_chunk_bitsize-length
00411         segments, and endian-convert them, one at a time. */
00412       int i;
00413 
00414       /* Enforce divisibility. */ 
00415       if ((length % insn_chunk_bitsize) != 0)
00416        abort ();
00417 
00418       for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
00419        {
00420          int index;
00421          index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */
00422          bfd_put_bits ((bfd_vma) value, & buf[index / 8], insn_chunk_bitsize, big_p);
00423          value >>= insn_chunk_bitsize;
00424        }
00425     }
00426   else
00427     {
00428       bfd_put_bits ((bfd_vma) value, buf, length, big_p);
00429     }
00430 }
00431 
00432 /* Look up instruction INSN_*_VALUE and extract its fields.
00433    INSN_INT_VALUE is used if CGEN_INT_INSN_P.
00434    Otherwise INSN_BYTES_VALUE is used.
00435    INSN, if non-null, is the insn table entry.
00436    Otherwise INSN_*_VALUE is examined to compute it.
00437    LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
00438    0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
00439    If INSN != NULL, LENGTH must be valid.
00440    ALIAS_P is non-zero if alias insns are to be included in the search.
00441 
00442    The result is a pointer to the insn table entry, or NULL if the instruction
00443    wasn't recognized.  */
00444 
00445 /* ??? Will need to be revisited for VLIW architectures.  */
00446 
00447 const CGEN_INSN *
00448 cgen_lookup_insn (CGEN_CPU_DESC cd,
00449                 const CGEN_INSN *insn,
00450                 CGEN_INSN_INT insn_int_value,
00451                 /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
00452                 unsigned char *insn_bytes_value,
00453                 int length,
00454                 CGEN_FIELDS *fields,
00455                 int alias_p)
00456 {
00457   unsigned char *buf;
00458   CGEN_INSN_INT base_insn;
00459   CGEN_EXTRACT_INFO ex_info;
00460   CGEN_EXTRACT_INFO *info;
00461 
00462   if (cd->int_insn_p)
00463     {
00464       info = NULL;
00465       buf = (unsigned char *) alloca (cd->max_insn_bitsize / 8);
00466       cgen_put_insn_value (cd, buf, length, insn_int_value);
00467       base_insn = insn_int_value;
00468     }
00469   else
00470     {
00471       info = &ex_info;
00472       ex_info.dis_info = NULL;
00473       ex_info.insn_bytes = insn_bytes_value;
00474       ex_info.valid = -1;
00475       buf = insn_bytes_value;
00476       base_insn = cgen_get_insn_value (cd, buf, length);
00477     }
00478 
00479   if (!insn)
00480     {
00481       const CGEN_INSN_LIST *insn_list;
00482 
00483       /* The instructions are stored in hash lists.
00484         Pick the first one and keep trying until we find the right one.  */
00485 
00486       insn_list = cgen_dis_lookup_insn (cd, (char *) buf, base_insn);
00487       while (insn_list != NULL)
00488        {
00489          insn = insn_list->insn;
00490 
00491          if (alias_p
00492              /* FIXME: Ensure ALIAS attribute always has same index.  */
00493              || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
00494            {
00495              /* Basic bit mask must be correct.  */
00496              /* ??? May wish to allow target to defer this check until the
00497                extract handler.  */
00498              if ((base_insn & CGEN_INSN_BASE_MASK (insn))
00499                 == CGEN_INSN_BASE_VALUE (insn))
00500               {
00501                 /* ??? 0 is passed for `pc' */
00502                 int elength = CGEN_EXTRACT_FN (cd, insn)
00503                   (cd, insn, info, base_insn, fields, (bfd_vma) 0);
00504                 if (elength > 0)
00505                   {
00506                     /* sanity check */
00507                     if (length != 0 && length != elength)
00508                      abort ();
00509                     return insn;
00510                   }
00511               }
00512            }
00513 
00514          insn_list = insn_list->next;
00515        }
00516     }
00517   else
00518     {
00519       /* Sanity check: can't pass an alias insn if ! alias_p.  */
00520       if (! alias_p
00521          && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
00522        abort ();
00523       /* Sanity check: length must be correct.  */
00524       if (length != CGEN_INSN_BITSIZE (insn))
00525        abort ();
00526 
00527       /* ??? 0 is passed for `pc' */
00528       length = CGEN_EXTRACT_FN (cd, insn)
00529        (cd, insn, info, base_insn, fields, (bfd_vma) 0);
00530       /* Sanity check: must succeed.
00531         Could relax this later if it ever proves useful.  */
00532       if (length == 0)
00533        abort ();
00534       return insn;
00535     }
00536 
00537   return NULL;
00538 }
00539 
00540 /* Fill in the operand instances used by INSN whose operands are FIELDS.
00541    INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
00542    in.  */
00543 
00544 void
00545 cgen_get_insn_operands (CGEN_CPU_DESC cd,
00546                      const CGEN_INSN *insn,
00547                      const CGEN_FIELDS *fields,
00548                      int *indices)
00549 {
00550   const CGEN_OPINST *opinst;
00551   int i;
00552 
00553   if (insn->opinst == NULL)
00554     abort ();
00555   for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
00556     {
00557       enum cgen_operand_type op_type = opinst->op_type;
00558       if (op_type == CGEN_OPERAND_NIL)
00559        indices[i] = opinst->index;
00560       else
00561        indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
00562     }
00563 }
00564 
00565 /* Cover function to cgen_get_insn_operands when either INSN or FIELDS
00566    isn't known.
00567    The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
00568    cgen_lookup_insn unchanged.
00569    INSN_INT_VALUE is used if CGEN_INT_INSN_P.
00570    Otherwise INSN_BYTES_VALUE is used.
00571 
00572    The result is the insn table entry or NULL if the instruction wasn't
00573    recognized.  */
00574 
00575 const CGEN_INSN *
00576 cgen_lookup_get_insn_operands (CGEN_CPU_DESC cd,
00577                             const CGEN_INSN *insn,
00578                             CGEN_INSN_INT insn_int_value,
00579                             /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
00580                             unsigned char *insn_bytes_value,
00581                             int length,
00582                             int *indices,
00583                             CGEN_FIELDS *fields)
00584 {
00585   /* Pass non-zero for ALIAS_P only if INSN != NULL.
00586      If INSN == NULL, we want a real insn.  */
00587   insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
00588                         length, fields, insn != NULL);
00589   if (! insn)
00590     return NULL;
00591 
00592   cgen_get_insn_operands (cd, insn, fields, indices);
00593   return insn;
00594 }
00595 
00596 /* Allow signed overflow of instruction fields.  */
00597 void
00598 cgen_set_signed_overflow_ok (CGEN_CPU_DESC cd)
00599 {
00600   cd->signed_overflow_ok_p = 1;
00601 }
00602 
00603 /* Generate an error message if a signed field in an instruction overflows.  */
00604 void
00605 cgen_clear_signed_overflow_ok (CGEN_CPU_DESC cd)
00606 {
00607   cd->signed_overflow_ok_p = 0;
00608 }
00609 
00610 /* Will an error message be generated if a signed field in an instruction overflows ? */
00611 unsigned int
00612 cgen_signed_overflow_ok_p (CGEN_CPU_DESC cd)
00613 {
00614   return cd->signed_overflow_ok_p;
00615 }