Back to index

cell-binutils  2.17cvs20070401
cgen-asm.c
Go to the documentation of this file.
00001 /* CGEN generic assembler support code.
00002 
00003    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
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 #include "opintl.h"
00031 
00032 static CGEN_INSN_LIST *  hash_insn_array      (CGEN_CPU_DESC, const CGEN_INSN *, int, int, CGEN_INSN_LIST **, CGEN_INSN_LIST *);
00033 static CGEN_INSN_LIST *  hash_insn_list       (CGEN_CPU_DESC, const CGEN_INSN_LIST *, CGEN_INSN_LIST **, CGEN_INSN_LIST *);
00034 static void              build_asm_hash_table (CGEN_CPU_DESC);
00035 
00036 /* Set the cgen_parse_operand_fn callback.  */
00037 
00038 void
00039 cgen_set_parse_operand_fn (CGEN_CPU_DESC cd, cgen_parse_operand_fn fn)
00040 {
00041   cd->parse_operand_fn = fn;
00042 }
00043 
00044 /* Called whenever starting to parse an insn.  */
00045 
00046 void
00047 cgen_init_parse_operand (CGEN_CPU_DESC cd)
00048 {
00049   /* This tells the callback to re-initialize.  */
00050   (void) (* cd->parse_operand_fn)
00051     (cd, CGEN_PARSE_OPERAND_INIT, NULL, 0, 0, NULL, NULL);
00052 }
00053 
00054 /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
00055 
00056    COUNT is the number of elements in INSNS.
00057    ENTSIZE is sizeof (CGEN_IBASE) for the target.
00058    ??? No longer used but leave in for now.
00059    HTABLE points to the hash table.
00060    HENTBUF is a pointer to sufficiently large buffer of hash entries.
00061    The result is a pointer to the next entry to use.
00062 
00063    The table is scanned backwards as additions are made to the front of the
00064    list and we want earlier ones to be prefered.  */
00065 
00066 static CGEN_INSN_LIST *
00067 hash_insn_array (CGEN_CPU_DESC cd,
00068                const CGEN_INSN *insns,
00069                int count,
00070                int entsize ATTRIBUTE_UNUSED,
00071                CGEN_INSN_LIST **htable,
00072                CGEN_INSN_LIST *hentbuf)
00073 {
00074   int i;
00075 
00076   for (i = count - 1; i >= 0; --i, ++hentbuf)
00077     {
00078       unsigned int hash;
00079       const CGEN_INSN *insn = &insns[i];
00080 
00081       if (! (* cd->asm_hash_p) (insn))
00082        continue;
00083       hash = (* cd->asm_hash) (CGEN_INSN_MNEMONIC (insn));
00084       hentbuf->next = htable[hash];
00085       hentbuf->insn = insn;
00086       htable[hash] = hentbuf;
00087     }
00088 
00089   return hentbuf;
00090 }
00091 
00092 /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
00093    This function is identical to hash_insn_array except the insns are
00094    in a list.  */
00095 
00096 static CGEN_INSN_LIST *
00097 hash_insn_list (CGEN_CPU_DESC cd,
00098               const CGEN_INSN_LIST *insns,
00099               CGEN_INSN_LIST **htable,
00100               CGEN_INSN_LIST *hentbuf)
00101 {
00102   const CGEN_INSN_LIST *ilist;
00103 
00104   for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
00105     {
00106       unsigned int hash;
00107 
00108       if (! (* cd->asm_hash_p) (ilist->insn))
00109        continue;
00110       hash = (* cd->asm_hash) (CGEN_INSN_MNEMONIC (ilist->insn));
00111       hentbuf->next = htable[hash];
00112       hentbuf->insn = ilist->insn;
00113       htable[hash] = hentbuf;
00114     }
00115 
00116   return hentbuf;
00117 }
00118 
00119 /* Build the assembler instruction hash table.  */
00120 
00121 static void
00122 build_asm_hash_table (CGEN_CPU_DESC cd)
00123 {
00124   int count = cgen_insn_count (cd) + cgen_macro_insn_count (cd);
00125   CGEN_INSN_TABLE *insn_table = &cd->insn_table;
00126   CGEN_INSN_TABLE *macro_insn_table = &cd->macro_insn_table;
00127   unsigned int hash_size = cd->asm_hash_size;
00128   CGEN_INSN_LIST *hash_entry_buf;
00129   CGEN_INSN_LIST **asm_hash_table;
00130   CGEN_INSN_LIST *asm_hash_table_entries;
00131 
00132   /* The space allocated for the hash table consists of two parts:
00133      the hash table and the hash lists.  */
00134 
00135   asm_hash_table = (CGEN_INSN_LIST **)
00136     xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
00137   memset (asm_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
00138   asm_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
00139     xmalloc (count * sizeof (CGEN_INSN_LIST));
00140 
00141   /* Add compiled in insns.
00142      Don't include the first one as it is a reserved entry.  */
00143   /* ??? It was the end of all hash chains, and also the special
00144      "invalid insn" marker.  May be able to do it differently now.  */
00145 
00146   hash_entry_buf = hash_insn_array (cd,
00147                                 insn_table->init_entries + 1,
00148                                 insn_table->num_init_entries - 1,
00149                                 insn_table->entry_size,
00150                                 asm_hash_table, hash_entry_buf);
00151 
00152   /* Add compiled in macro-insns.  */
00153 
00154   hash_entry_buf = hash_insn_array (cd, macro_insn_table->init_entries,
00155                                 macro_insn_table->num_init_entries,
00156                                 macro_insn_table->entry_size,
00157                                 asm_hash_table, hash_entry_buf);
00158 
00159   /* Add runtime added insns.
00160      Later added insns will be prefered over earlier ones.  */
00161 
00162   hash_entry_buf = hash_insn_list (cd, insn_table->new_entries,
00163                                asm_hash_table, hash_entry_buf);
00164 
00165   /* Add runtime added macro-insns.  */
00166 
00167   hash_insn_list (cd, macro_insn_table->new_entries,
00168                 asm_hash_table, hash_entry_buf);
00169 
00170   cd->asm_hash_table = asm_hash_table;
00171   cd->asm_hash_table_entries = asm_hash_table_entries;
00172 }
00173 
00174 /* Return the first entry in the hash list for INSN.  */
00175 
00176 CGEN_INSN_LIST *
00177 cgen_asm_lookup_insn (CGEN_CPU_DESC cd, const char *insn)
00178 {
00179   unsigned int hash;
00180 
00181   if (cd->asm_hash_table == NULL)
00182     build_asm_hash_table (cd);
00183 
00184   hash = (* cd->asm_hash) (insn);
00185   return cd->asm_hash_table[hash];
00186 }
00187 
00188 /* Keyword parser.
00189    The result is NULL upon success or an error message.
00190    If successful, *STRP is updated to point passed the keyword.
00191 
00192    ??? At present we have a static notion of how to pick out a keyword.
00193    Later we can allow a target to customize this if necessary [say by
00194    recording something in the keyword table].  */
00195 
00196 const char *
00197 cgen_parse_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
00198                   const char **strp,
00199                   CGEN_KEYWORD *keyword_table,
00200                   long *valuep)
00201 {
00202   const CGEN_KEYWORD_ENTRY *ke;
00203   char buf[256];
00204   const char *p,*start;
00205 
00206   if (keyword_table->name_hash_table == NULL)
00207     (void) cgen_keyword_search_init (keyword_table, NULL);
00208 
00209   p = start = *strp;
00210 
00211   /* Allow any first character.  This is to make life easier for
00212      the fairly common case of suffixes, eg. 'ld.b.w', where the first
00213      character of the suffix ('.') is special.  */
00214   if (*p)
00215     ++p;
00216   
00217   /* Allow letters, digits, and any special characters.  */
00218   while (((p - start) < (int) sizeof (buf))
00219         && *p
00220         && (ISALNUM (*p)
00221             || *p == '_'
00222             || strchr (keyword_table->nonalpha_chars, *p)))
00223     ++p;
00224 
00225   if (p - start >= (int) sizeof (buf))
00226     {
00227       /* All non-empty CGEN keywords can fit into BUF.  The only thing
00228         we can match here is the empty keyword.  */
00229       buf[0] = 0;
00230     }
00231   else
00232     {
00233       memcpy (buf, start, p - start);
00234       buf[p - start] = 0;
00235     }
00236 
00237   ke = cgen_keyword_lookup_name (keyword_table, buf);
00238 
00239   if (ke != NULL)
00240     {
00241       *valuep = ke->value;
00242       /* Don't advance pointer if we recognized the null keyword.  */
00243       if (ke->name[0] != 0)
00244        *strp = p;
00245       return NULL;
00246     }
00247 
00248   return "unrecognized keyword/register name";
00249 }
00250 
00251 /* Parse a small signed integer parser.
00252    ??? VALUEP is not a bfd_vma * on purpose, though this is confusing.
00253    Note that if the caller expects a bfd_vma result, it should call
00254    cgen_parse_address.  */
00255 
00256 const char *
00257 cgen_parse_signed_integer (CGEN_CPU_DESC cd,
00258                         const char **strp,
00259                         int opindex,
00260                         long *valuep)
00261 {
00262   bfd_vma value;
00263   enum cgen_parse_operand_result result;
00264   const char *errmsg;
00265 
00266   errmsg = (* cd->parse_operand_fn)
00267     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
00268      &result, &value);
00269   /* FIXME: Examine `result'.  */
00270   if (!errmsg)
00271     *valuep = value;
00272   return errmsg;
00273 }
00274 
00275 /* Parse a small unsigned integer parser.
00276    ??? VALUEP is not a bfd_vma * on purpose, though this is confusing.
00277    Note that if the caller expects a bfd_vma result, it should call
00278    cgen_parse_address.  */
00279 
00280 const char *
00281 cgen_parse_unsigned_integer (CGEN_CPU_DESC cd,
00282                           const char **strp,
00283                           int opindex,
00284                           unsigned long *valuep)
00285 {
00286   bfd_vma value;
00287   enum cgen_parse_operand_result result;
00288   const char *errmsg;
00289 
00290   errmsg = (* cd->parse_operand_fn)
00291     (cd, CGEN_PARSE_OPERAND_INTEGER, strp, opindex, BFD_RELOC_NONE,
00292      &result, &value);
00293   /* FIXME: Examine `result'.  */
00294   if (!errmsg)
00295     *valuep = value;
00296   return errmsg;
00297 }
00298 
00299 /* Address parser.  */
00300 
00301 const char *
00302 cgen_parse_address (CGEN_CPU_DESC cd,
00303                   const char **strp,
00304                   int opindex,
00305                   int opinfo,
00306                   enum cgen_parse_operand_result *resultp,
00307                   bfd_vma *valuep)
00308 {
00309   bfd_vma value;
00310   enum cgen_parse_operand_result result_type;
00311   const char *errmsg;
00312 
00313   errmsg = (* cd->parse_operand_fn)
00314     (cd, CGEN_PARSE_OPERAND_ADDRESS, strp, opindex, opinfo,
00315      &result_type, &value);
00316   /* FIXME: Examine `result'.  */
00317   if (!errmsg)
00318     {
00319       if (resultp != NULL)
00320        *resultp = result_type;
00321       *valuep = value;
00322     }
00323   return errmsg;
00324 }
00325 
00326 /* Signed integer validation routine.  */
00327 
00328 const char *
00329 cgen_validate_signed_integer (long value, long min, long max)
00330 {
00331   if (value < min || value > max)
00332     {
00333       static char buf[100];
00334 
00335       /* xgettext:c-format */
00336       sprintf (buf, _("operand out of range (%ld not between %ld and %ld)"),
00337                     value, min, max);
00338       return buf;
00339     }
00340 
00341   return NULL;
00342 }
00343 
00344 /* Unsigned integer validation routine.
00345    Supplying `min' here may seem unnecessary, but we also want to handle
00346    cases where min != 0 (and max > LONG_MAX).  */
00347 
00348 const char *
00349 cgen_validate_unsigned_integer (unsigned long value,
00350                             unsigned long min,
00351                             unsigned long max)
00352 {
00353   if (value < min || value > max)
00354     {
00355       static char buf[100];
00356 
00357       /* xgettext:c-format */
00358       sprintf (buf, _("operand out of range (%lu not between %lu and %lu)"),
00359               value, min, max);
00360       return buf;
00361     }
00362 
00363   return NULL;
00364 }