cgen-opc.c revision 33965
1/* CGEN generic opcode support.
2
3Copyright (C) 1996, 1997 Free Software Foundation, Inc.
4
5This file is part of the GNU Binutils and GDB, the GNU debugger.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License along
18with this program; if not, write to the Free Software Foundation, Inc.,
1959 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21#include "sysdep.h"
22#include <stdio.h>
23#include "ansidecl.h"
24#include "libiberty.h"
25#include "bfd.h"
26#include "opcode/cgen.h"
27
28/* State variables.
29   These record the state of the currently selected cpu, machine, endian, etc.
30   They are set by cgen_set_cpu.  */
31
32/* Current opcode data.  */
33CGEN_OPCODE_DATA *cgen_current_opcode_data;
34
35/* Current machine (a la BFD machine number).  */
36int cgen_current_mach;
37
38/* Current endian.  */
39enum cgen_endian cgen_current_endian = CGEN_ENDIAN_UNKNOWN;
40
41void
42cgen_set_cpu (data, mach, endian)
43     CGEN_OPCODE_DATA *data;
44     int mach;
45     enum cgen_endian endian;
46{
47  cgen_current_opcode_data = data;
48  cgen_current_mach = mach;
49  cgen_current_endian = endian;
50
51#if 0 /* This isn't done here because it would put assembler support in the
52	 disassembler, etc.  The caller is required to call these after calling
53	 us.  */
54  /* Reset the hash tables.  */
55  cgen_asm_init ();
56  cgen_dis_init ();
57#endif
58}
59
60static unsigned int hash_keyword_name
61  PARAMS ((const struct cgen_keyword *, const char *));
62static unsigned int hash_keyword_value
63  PARAMS ((const struct cgen_keyword *, int));
64static void build_keyword_hash_tables
65  PARAMS ((struct cgen_keyword *));
66
67/* Return number of hash table entries to use for N elements.  */
68#define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
69
70/* Look up *NAMEP in the keyword table KT.
71   The result is the keyword entry or NULL if not found.  */
72
73const struct cgen_keyword_entry *
74cgen_keyword_lookup_name (kt, name)
75     struct cgen_keyword *kt;
76     const char *name;
77{
78  const struct cgen_keyword_entry *ke;
79  const char *p,*n;
80
81  if (kt->name_hash_table == NULL)
82    build_keyword_hash_tables (kt);
83
84  ke = kt->name_hash_table[hash_keyword_name (kt, name)];
85
86  /* We do case insensitive comparisons.
87     If that ever becomes a problem, add an attribute that denotes
88     "do case sensitive comparisons".  */
89
90  while (ke != NULL)
91    {
92      n = name;
93      p = ke->name;
94
95      while (*p
96	     && (*p == *n
97		 || (isalpha (*p) && tolower (*p) == tolower (*n))))
98	++n, ++p;
99
100      if (!*p && !*n)
101	return ke;
102
103      ke = ke->next_name;
104    }
105
106  return NULL;
107}
108
109/* Look up VALUE in the keyword table KT.
110   The result is the keyword entry or NULL if not found.  */
111
112const struct cgen_keyword_entry *
113cgen_keyword_lookup_value (kt, value)
114     struct cgen_keyword *kt;
115     int value;
116{
117  const struct cgen_keyword_entry *ke;
118
119  if (kt->name_hash_table == NULL)
120    build_keyword_hash_tables (kt);
121
122  ke = kt->value_hash_table[hash_keyword_value (kt, value)];
123
124  while (ke != NULL)
125    {
126      if (value == ke->value)
127	return ke;
128      ke = ke->next_value;
129    }
130
131  return NULL;
132}
133
134/* Add an entry to a keyword table.  */
135
136void
137cgen_keyword_add (kt, ke)
138     struct cgen_keyword *kt;
139     struct cgen_keyword_entry *ke;
140{
141  unsigned int hash;
142
143  if (kt->name_hash_table == NULL)
144    build_keyword_hash_tables (kt);
145
146  hash = hash_keyword_name (kt, ke->name);
147  ke->next_name = kt->name_hash_table[hash];
148  kt->name_hash_table[hash] = ke;
149
150  hash = hash_keyword_value (kt, ke->value);
151  ke->next_value = kt->value_hash_table[hash];
152  kt->value_hash_table[hash] = ke;
153}
154
155/* FIXME: Need function to return count of keywords.  */
156
157/* Initialize a keyword table search.
158   SPEC is a specification of what to search for.
159   A value of NULL means to find every keyword.
160   Currently NULL is the only acceptable value [further specification
161   deferred].
162   The result is an opaque data item used to record the search status.
163   It is passed to each call to cgen_keyword_search_next.  */
164
165struct cgen_keyword_search
166cgen_keyword_search_init (kt, spec)
167     struct cgen_keyword *kt;
168     const char *spec;
169{
170  struct cgen_keyword_search search;
171
172  /* FIXME: Need to specify format of PARAMS.  */
173  if (spec != NULL)
174    abort ();
175
176  if (kt->name_hash_table == NULL)
177    build_keyword_hash_tables (kt);
178
179  search.table = kt;
180  search.spec = spec;
181  search.current_hash = 0;
182  search.current_entry = NULL;
183  return search;
184}
185
186/* Return the next keyword specified by SEARCH.
187   The result is the next entry or NULL if there are no more.  */
188
189const struct cgen_keyword_entry *
190cgen_keyword_search_next (search)
191     struct cgen_keyword_search *search;
192{
193  const struct cgen_keyword_entry *ke;
194
195  /* Has search finished?  */
196  if (search->current_hash == search->table->hash_table_size)
197    return NULL;
198
199  /* Search in progress?  */
200  if (search->current_entry != NULL
201      /* Anything left on this hash chain?  */
202      && search->current_entry->next_name != NULL)
203    {
204      search->current_entry = search->current_entry->next_name;
205      return search->current_entry;
206    }
207
208  /* Move to next hash chain [unless we haven't started yet].  */
209  if (search->current_entry != NULL)
210    ++search->current_hash;
211
212  while (search->current_hash < search->table->hash_table_size)
213    {
214      search->current_entry = search->table->name_hash_table[search->current_hash];
215      if (search->current_entry != NULL)
216	return search->current_entry;
217      ++search->current_hash;
218    }
219
220  return NULL;
221}
222
223/* Return first entry in hash chain for NAME.  */
224
225static unsigned int
226hash_keyword_name (kt, name)
227     const struct cgen_keyword *kt;
228     const char *name;
229{
230  unsigned int hash;
231
232  for (hash = 0; *name; ++name)
233    hash = (hash * 97) + (unsigned char) *name;
234  return hash % kt->hash_table_size;
235}
236
237/* Return first entry in hash chain for VALUE.  */
238
239static unsigned int
240hash_keyword_value (kt, value)
241     const struct cgen_keyword *kt;
242     int value;
243{
244  return value % kt->hash_table_size;
245}
246
247/* Build a keyword table's hash tables.
248   We probably needn't build the value hash table for the assembler when
249   we're using the disassembler, but we keep things simple.  */
250
251static void
252build_keyword_hash_tables (kt)
253     struct cgen_keyword *kt;
254{
255  int i;
256  /* Use the number of compiled in entries as an estimate for the
257     typical sized table [not too many added at runtime].  */
258  unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
259
260  kt->hash_table_size = size;
261  kt->name_hash_table = (struct cgen_keyword_entry **)
262    xmalloc (size * sizeof (struct cgen_keyword_entry *));
263  memset (kt->name_hash_table, 0, size * sizeof (struct cgen_keyword_entry *));
264  kt->value_hash_table = (struct cgen_keyword_entry **)
265    xmalloc (size * sizeof (struct cgen_keyword_entry *));
266  memset (kt->value_hash_table, 0, size * sizeof (struct cgen_keyword_entry *));
267
268  /* The table is scanned backwards as we want keywords appearing earlier to
269     be prefered over later ones.  */
270  for (i = kt->num_init_entries - 1; i >= 0; --i)
271    cgen_keyword_add (kt, &kt->init_entries[i]);
272}
273
274/* Hardware support.  */
275
276CGEN_HW_ENTRY *
277cgen_hw_lookup (name)
278     const char *name;
279{
280  CGEN_HW_ENTRY *hw = cgen_current_opcode_data->hw_list;
281
282  while (hw != NULL)
283    {
284      if (strcmp (name, hw->name) == 0)
285	return hw;
286      hw = hw->next;
287    }
288
289  return NULL;
290}
291
292/* Instruction support.  */
293
294/* Return number of instructions.  This includes any added at runtime.  */
295
296int
297cgen_insn_count ()
298{
299  int count = cgen_current_opcode_data->insn_table->num_init_entries;
300  CGEN_INSN_LIST *insn = cgen_current_opcode_data->insn_table->new_entries;
301
302  for ( ; insn != NULL; insn = insn->next)
303    ++count;
304
305  return count;
306}
307