* cgen-opc.c (cgen_hw_lookup_by_name): Renamed from cgen_hw_lookup.
[binutils-gdb.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 }