* sun build fix for thinko (?)
[binutils-gdb.git] / opcodes / cgen-opc.c
blobaef9d6b3582aa0f70f3419abe03803c4ac50bbb8
1 /* CGEN generic opcode support.
3 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
5 This file is part of the GNU Binutils and GDB, the GNU debugger.
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.
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.
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. */
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"
30 /* State variables.
31 These record the state of the currently selected cpu, machine, endian, etc.
32 They are set by cgen_set_cpu. */
34 /* Current opcode data. */
35 const CGEN_OPCODE_TABLE *cgen_current_opcode_table;
37 /* Current machine (a la BFD machine number). */
38 int cgen_current_mach;
40 /* Current endian. */
41 enum cgen_endian cgen_current_endian = CGEN_ENDIAN_UNKNOWN;
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. */
47 void
48 cgen_set_cpu (table, mach, endian)
49 const CGEN_OPCODE_TABLE * table;
50 int mach;
51 enum cgen_endian endian;
53 static int init_once_p;
55 cgen_current_opcode_table = table;
56 cgen_current_mach = mach;
57 cgen_current_endian = endian;
59 /* Initialize those things that only need be done once. */
60 if (! init_once_p)
62 /* Nothing to do currently. */
63 init_once_p = 1;
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
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 *));
82 /* Return number of hash table entries to use for N elements. */
83 #define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
85 /* Look up *NAMEP in the keyword table KT.
86 The result is the keyword entry or NULL if not found. */
88 const CGEN_KEYWORD_ENTRY *
89 cgen_keyword_lookup_name (kt, name)
90 CGEN_KEYWORD *kt;
91 const char *name;
93 const CGEN_KEYWORD_ENTRY *ke;
94 const char *p,*n;
96 if (kt->name_hash_table == NULL)
97 build_keyword_hash_tables (kt);
99 ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)];
101 /* We do case insensitive comparisons.
102 If that ever becomes a problem, add an attribute that denotes
103 "do case sensitive comparisons". */
105 while (ke != NULL)
107 n = name;
108 p = ke->name;
110 while (*p
111 && (*p == *n
112 || (isalpha ((unsigned char) *p)
113 && (tolower ((unsigned char) *p)
114 == tolower ((unsigned char) *n)))))
115 ++n, ++p;
117 if (!*p && !*n)
118 return ke;
120 ke = ke->next_name;
123 if (kt->null_entry)
124 return kt->null_entry;
125 return NULL;
128 /* Look up VALUE in the keyword table KT.
129 The result is the keyword entry or NULL if not found. */
131 const CGEN_KEYWORD_ENTRY *
132 cgen_keyword_lookup_value (kt, value)
133 CGEN_KEYWORD *kt;
134 int value;
136 const CGEN_KEYWORD_ENTRY *ke;
138 if (kt->name_hash_table == NULL)
139 build_keyword_hash_tables (kt);
141 ke = kt->value_hash_table[hash_keyword_value (kt, value)];
143 while (ke != NULL)
145 if (value == ke->value)
146 return ke;
147 ke = ke->next_value;
150 return NULL;
153 /* Add an entry to a keyword table. */
155 void
156 cgen_keyword_add (kt, ke)
157 CGEN_KEYWORD *kt;
158 CGEN_KEYWORD_ENTRY *ke;
160 unsigned int hash;
162 if (kt->name_hash_table == NULL)
163 build_keyword_hash_tables (kt);
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;
169 hash = hash_keyword_value (kt, ke->value);
170 ke->next_value = kt->value_hash_table[hash];
171 kt->value_hash_table[hash] = ke;
173 if (ke->name[0] == 0)
174 kt->null_entry = ke;
177 /* FIXME: Need function to return count of keywords. */
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. */
187 CGEN_KEYWORD_SEARCH
188 cgen_keyword_search_init (kt, spec)
189 CGEN_KEYWORD *kt;
190 const char *spec;
192 CGEN_KEYWORD_SEARCH search;
194 /* FIXME: Need to specify format of PARAMS. */
195 if (spec != NULL)
196 abort ();
198 if (kt->name_hash_table == NULL)
199 build_keyword_hash_tables (kt);
201 search.table = kt;
202 search.spec = spec;
203 search.current_hash = 0;
204 search.current_entry = NULL;
205 return search;
208 /* Return the next keyword specified by SEARCH.
209 The result is the next entry or NULL if there are no more. */
211 const CGEN_KEYWORD_ENTRY *
212 cgen_keyword_search_next (search)
213 CGEN_KEYWORD_SEARCH *search;
215 /* Has search finished? */
216 if (search->current_hash == search->table->hash_table_size)
217 return NULL;
219 /* Search in progress? */
220 if (search->current_entry != NULL
221 /* Anything left on this hash chain? */
222 && search->current_entry->next_name != NULL)
224 search->current_entry = search->current_entry->next_name;
225 return search->current_entry;
228 /* Move to next hash chain [unless we haven't started yet]. */
229 if (search->current_entry != NULL)
230 ++search->current_hash;
232 while (search->current_hash < search->table->hash_table_size)
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;
240 return NULL;
243 /* Return first entry in hash chain for NAME.
244 If CASE_SENSITIVE_P is non-zero, return a case sensitive hash. */
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;
252 unsigned int hash;
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;
263 /* Return first entry in hash chain for VALUE. */
265 static unsigned int
266 hash_keyword_value (kt, value)
267 const CGEN_KEYWORD *kt;
268 unsigned int value;
270 return value % kt->hash_table_size;
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. */
277 static void
278 build_keyword_hash_tables (kt)
279 CGEN_KEYWORD *kt;
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);
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 *));
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]);
300 /* Hardware support. */
302 /* Lookup a hardware element by its name. */
304 const CGEN_HW_ENTRY *
305 cgen_hw_lookup_by_name (name)
306 const char *name;
308 const CGEN_HW_ENTRY * hw = cgen_current_opcode_table->hw_list;
310 while (hw != NULL)
312 if (strcmp (name, hw->name) == 0)
313 return hw;
314 hw = hw->next;
317 return NULL;
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. */
324 const CGEN_HW_ENTRY *
325 cgen_hw_lookup_by_enum (hwnum)
326 int hwnum;
328 const CGEN_HW_ENTRY * hw = cgen_current_opcode_table->hw_list;
330 /* ??? This can be speeded up if we first make a guess into
331 the compiled in table. */
332 while (hw != NULL)
334 if (hwnum == hw->type)
335 return hw;
337 return NULL;
340 /* Instruction support. */
342 /* Return number of instructions. This includes any added at runtime. */
345 cgen_insn_count ()
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;
350 for ( ; insn != NULL; insn = insn->next)
351 ++count;
353 return count;
356 /* Return number of macro-instructions. This includes any added at runtime. */
359 cgen_macro_insn_count ()
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;
364 for ( ; insn != NULL; insn = insn->next)
365 ++count;
367 return count;