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