This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / opcodes / cgen-opc.c
1 /* CGEN generic opcode support.
2
3 Copyright (C) 1996, 1997, 1998, 1999 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 static unsigned int hash_keyword_name
31 PARAMS ((const CGEN_KEYWORD *, const char *, int));
32 static unsigned int hash_keyword_value
33 PARAMS ((const CGEN_KEYWORD *, unsigned int));
34 static void build_keyword_hash_tables
35 PARAMS ((CGEN_KEYWORD *));
36
37 /* Return number of hash table entries to use for N elements. */
38 #define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
39
40 /* Look up *NAMEP in the keyword table KT.
41 The result is the keyword entry or NULL if not found. */
42
43 const CGEN_KEYWORD_ENTRY *
44 cgen_keyword_lookup_name (kt, name)
45 CGEN_KEYWORD *kt;
46 const char *name;
47 {
48 const CGEN_KEYWORD_ENTRY *ke;
49 const char *p,*n;
50
51 if (kt->name_hash_table == NULL)
52 build_keyword_hash_tables (kt);
53
54 ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)];
55
56 /* We do case insensitive comparisons.
57 If that ever becomes a problem, add an attribute that denotes
58 "do case sensitive comparisons". */
59
60 while (ke != NULL)
61 {
62 n = name;
63 p = ke->name;
64
65 while (*p
66 && (*p == *n
67 || (isalpha ((unsigned char) *p)
68 && (tolower ((unsigned char) *p)
69 == tolower ((unsigned char) *n)))))
70 ++n, ++p;
71
72 if (!*p && !*n)
73 return ke;
74
75 ke = ke->next_name;
76 }
77
78 if (kt->null_entry)
79 return kt->null_entry;
80 return NULL;
81 }
82
83 /* Look up VALUE in the keyword table KT.
84 The result is the keyword entry or NULL if not found. */
85
86 const CGEN_KEYWORD_ENTRY *
87 cgen_keyword_lookup_value (kt, value)
88 CGEN_KEYWORD *kt;
89 int value;
90 {
91 const CGEN_KEYWORD_ENTRY *ke;
92
93 if (kt->name_hash_table == NULL)
94 build_keyword_hash_tables (kt);
95
96 ke = kt->value_hash_table[hash_keyword_value (kt, value)];
97
98 while (ke != NULL)
99 {
100 if (value == ke->value)
101 return ke;
102 ke = ke->next_value;
103 }
104
105 return NULL;
106 }
107
108 /* Add an entry to a keyword table. */
109
110 void
111 cgen_keyword_add (kt, ke)
112 CGEN_KEYWORD *kt;
113 CGEN_KEYWORD_ENTRY *ke;
114 {
115 unsigned int hash;
116
117 if (kt->name_hash_table == NULL)
118 build_keyword_hash_tables (kt);
119
120 hash = hash_keyword_name (kt, ke->name, 0);
121 ke->next_name = kt->name_hash_table[hash];
122 kt->name_hash_table[hash] = ke;
123
124 hash = hash_keyword_value (kt, ke->value);
125 ke->next_value = kt->value_hash_table[hash];
126 kt->value_hash_table[hash] = ke;
127
128 if (ke->name[0] == 0)
129 kt->null_entry = ke;
130 }
131
132 /* FIXME: Need function to return count of keywords. */
133
134 /* Initialize a keyword table search.
135 SPEC is a specification of what to search for.
136 A value of NULL means to find every keyword.
137 Currently NULL is the only acceptable value [further specification
138 deferred].
139 The result is an opaque data item used to record the search status.
140 It is passed to each call to cgen_keyword_search_next. */
141
142 CGEN_KEYWORD_SEARCH
143 cgen_keyword_search_init (kt, spec)
144 CGEN_KEYWORD *kt;
145 const char *spec;
146 {
147 CGEN_KEYWORD_SEARCH search;
148
149 /* FIXME: Need to specify format of PARAMS. */
150 if (spec != NULL)
151 abort ();
152
153 if (kt->name_hash_table == NULL)
154 build_keyword_hash_tables (kt);
155
156 search.table = kt;
157 search.spec = spec;
158 search.current_hash = 0;
159 search.current_entry = NULL;
160 return search;
161 }
162
163 /* Return the next keyword specified by SEARCH.
164 The result is the next entry or NULL if there are no more. */
165
166 const CGEN_KEYWORD_ENTRY *
167 cgen_keyword_search_next (search)
168 CGEN_KEYWORD_SEARCH *search;
169 {
170 /* Has search finished? */
171 if (search->current_hash == search->table->hash_table_size)
172 return NULL;
173
174 /* Search in progress? */
175 if (search->current_entry != NULL
176 /* Anything left on this hash chain? */
177 && search->current_entry->next_name != NULL)
178 {
179 search->current_entry = search->current_entry->next_name;
180 return search->current_entry;
181 }
182
183 /* Move to next hash chain [unless we haven't started yet]. */
184 if (search->current_entry != NULL)
185 ++search->current_hash;
186
187 while (search->current_hash < search->table->hash_table_size)
188 {
189 search->current_entry = search->table->name_hash_table[search->current_hash];
190 if (search->current_entry != NULL)
191 return search->current_entry;
192 ++search->current_hash;
193 }
194
195 return NULL;
196 }
197
198 /* Return first entry in hash chain for NAME.
199 If CASE_SENSITIVE_P is non-zero, return a case sensitive hash. */
200
201 static unsigned int
202 hash_keyword_name (kt, name, case_sensitive_p)
203 const CGEN_KEYWORD *kt;
204 const char *name;
205 int case_sensitive_p;
206 {
207 unsigned int hash;
208
209 if (case_sensitive_p)
210 for (hash = 0; *name; ++name)
211 hash = (hash * 97) + (unsigned char) *name;
212 else
213 for (hash = 0; *name; ++name)
214 hash = (hash * 97) + (unsigned char) tolower (*name);
215 return hash % kt->hash_table_size;
216 }
217
218 /* Return first entry in hash chain for VALUE. */
219
220 static unsigned int
221 hash_keyword_value (kt, value)
222 const CGEN_KEYWORD *kt;
223 unsigned int value;
224 {
225 return value % kt->hash_table_size;
226 }
227
228 /* Build a keyword table's hash tables.
229 We probably needn't build the value hash table for the assembler when
230 we're using the disassembler, but we keep things simple. */
231
232 static void
233 build_keyword_hash_tables (kt)
234 CGEN_KEYWORD *kt;
235 {
236 int i;
237 /* Use the number of compiled in entries as an estimate for the
238 typical sized table [not too many added at runtime]. */
239 unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
240
241 kt->hash_table_size = size;
242 kt->name_hash_table = (CGEN_KEYWORD_ENTRY **)
243 xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
244 memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
245 kt->value_hash_table = (CGEN_KEYWORD_ENTRY **)
246 xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
247 memset (kt->value_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
248
249 /* The table is scanned backwards as we want keywords appearing earlier to
250 be prefered over later ones. */
251 for (i = kt->num_init_entries - 1; i >= 0; --i)
252 cgen_keyword_add (kt, &kt->init_entries[i]);
253 }
254 \f
255 /* Hardware support. */
256
257 /* Lookup a hardware element by its name.
258 Returns NULL if NAME is not supported by the currently selected
259 mach/isa. */
260
261 const CGEN_HW_ENTRY *
262 cgen_hw_lookup_by_name (cd, name)
263 CGEN_CPU_DESC cd;
264 const char *name;
265 {
266 int i;
267 const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
268
269 for (i = 0; i < cd->hw_table.num_entries; ++i)
270 if (hw[i] && strcmp (name, hw[i]->name) == 0)
271 return hw[i];
272
273 return NULL;
274 }
275
276 /* Lookup a hardware element by its number.
277 Hardware elements are enumerated, however it may be possible to add some
278 at runtime, thus HWNUM is not an enum type but rather an int.
279 Returns NULL if HWNUM is not supported by the currently selected mach. */
280
281 const CGEN_HW_ENTRY *
282 cgen_hw_lookup_by_num (cd, hwnum)
283 CGEN_CPU_DESC cd;
284 int hwnum;
285 {
286 int i;
287 const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
288
289 /* ??? This can be speeded up. */
290 for (i = 0; i < cd->hw_table.num_entries; ++i)
291 if (hw[i] && hwnum == hw[i]->type)
292 return hw[i];
293
294 return NULL;
295 }
296 \f
297 /* Operand support. */
298
299 /* Lookup an operand by its name.
300 Returns NULL if NAME is not supported by the currently selected
301 mach/isa. */
302
303 const CGEN_OPERAND *
304 cgen_operand_lookup_by_name (cd, name)
305 CGEN_CPU_DESC cd;
306 const char *name;
307 {
308 int i;
309 const CGEN_OPERAND **op = cd->operand_table.entries;
310
311 for (i = 0; i < cd->operand_table.num_entries; ++i)
312 if (op[i] && strcmp (name, op[i]->name) == 0)
313 return op[i];
314
315 return NULL;
316 }
317
318 /* Lookup an operand by its number.
319 Operands are enumerated, however it may be possible to add some
320 at runtime, thus OPNUM is not an enum type but rather an int.
321 Returns NULL if OPNUM is not supported by the currently selected
322 mach/isa. */
323
324 const CGEN_OPERAND *
325 cgen_operand_lookup_by_num (cd, opnum)
326 CGEN_CPU_DESC cd;
327 int opnum;
328 {
329 return cd->operand_table.entries[opnum];
330 }
331 \f
332 /* Instruction support. */
333
334 /* Return number of instructions. This includes any added at runtime. */
335
336 int
337 cgen_insn_count (cd)
338 CGEN_CPU_DESC cd;
339 {
340 int count = cd->insn_table.num_init_entries;
341 CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
342
343 for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
344 ++count;
345
346 return count;
347 }
348
349 /* Return number of macro-instructions.
350 This includes any added at runtime. */
351
352 int
353 cgen_macro_insn_count (cd)
354 CGEN_CPU_DESC cd;
355 {
356 int count = cd->macro_insn_table.num_init_entries;
357 CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
358
359 for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
360 ++count;
361
362 return count;
363 }
364
365 /* Cover function to read and properly byteswap an insn value. */
366
367 CGEN_INSN_INT
368 cgen_get_insn_value (cd, buf, length)
369 CGEN_CPU_DESC cd;
370 unsigned char *buf;
371 int length;
372 {
373 CGEN_INSN_INT value;
374
375 switch (length)
376 {
377 case 8:
378 value = *buf;
379 break;
380 case 16:
381 if (cd->insn_endian == CGEN_ENDIAN_BIG)
382 value = bfd_getb16 (buf);
383 else
384 value = bfd_getl16 (buf);
385 break;
386 case 32:
387 if (cd->insn_endian == CGEN_ENDIAN_BIG)
388 value = bfd_getb32 (buf);
389 else
390 value = bfd_getl32 (buf);
391 break;
392 default:
393 abort ();
394 }
395
396 return value;
397 }
398
399 /* Cover function to store an insn value properly byteswapped. */
400
401 void
402 cgen_put_insn_value (cd, buf, length, value)
403 CGEN_CPU_DESC cd;
404 unsigned char *buf;
405 int length;
406 CGEN_INSN_INT value;
407 {
408 switch (length)
409 {
410 case 8:
411 buf[0] = value;
412 break;
413 case 16:
414 if (cd->insn_endian == CGEN_ENDIAN_BIG)
415 bfd_putb16 (value, buf);
416 else
417 bfd_putl16 (value, buf);
418 break;
419 case 32:
420 if (cd->insn_endian == CGEN_ENDIAN_BIG)
421 bfd_putb32 (value, buf);
422 else
423 bfd_putl32 (value, buf);
424 break;
425 default:
426 abort ();
427 }
428 }
429 \f
430 /* Look up instruction INSN_*_VALUE and extract its fields.
431 INSN_INT_VALUE is used if CGEN_INT_INSN_P.
432 Otherwise INSN_BYTES_VALUE is used.
433 INSN, if non-null, is the insn table entry.
434 Otherwise INSN_*_VALUE is examined to compute it.
435 LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
436 0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
437 If INSN != NULL, LENGTH must be valid.
438 ALIAS_P is non-zero if alias insns are to be included in the search.
439
440 The result is a pointer to the insn table entry, or NULL if the instruction
441 wasn't recognized. */
442
443 /* ??? Will need to be revisited for VLIW architectures. */
444
445 const CGEN_INSN *
446 cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value, length, fields,
447 alias_p)
448 CGEN_CPU_DESC cd;
449 const CGEN_INSN *insn;
450 CGEN_INSN_INT insn_int_value;
451 /* ??? CGEN_INSN_BYTES would be a nice type name to use here. */
452 unsigned char *insn_bytes_value;
453 int length;
454 CGEN_FIELDS *fields;
455 int alias_p;
456 {
457 unsigned char *buf;
458 CGEN_INSN_INT base_insn;
459 CGEN_EXTRACT_INFO ex_info;
460 CGEN_EXTRACT_INFO *info;
461
462 if (cd->int_insn_p)
463 {
464 info = NULL;
465 buf = (unsigned char *) alloca (cd->max_insn_bitsize / 8);
466 cgen_put_insn_value (cd, buf, length, insn_int_value);
467 base_insn = insn_int_value;
468 }
469 else
470 {
471 info = &ex_info;
472 ex_info.dis_info = NULL;
473 ex_info.insn_bytes = insn_bytes_value;
474 ex_info.valid = -1;
475 buf = insn_bytes_value;
476 base_insn = cgen_get_insn_value (cd, buf, length);
477 }
478
479 if (!insn)
480 {
481 const CGEN_INSN_LIST *insn_list;
482
483 /* The instructions are stored in hash lists.
484 Pick the first one and keep trying until we find the right one. */
485
486 insn_list = cgen_dis_lookup_insn (cd, buf, base_insn);
487 while (insn_list != NULL)
488 {
489 insn = insn_list->insn;
490
491 if (alias_p
492 /* FIXME: Ensure ALIAS attribute always has same index. */
493 || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
494 {
495 /* Basic bit mask must be correct. */
496 /* ??? May wish to allow target to defer this check until the
497 extract handler. */
498 if ((base_insn & CGEN_INSN_BASE_MASK (insn))
499 == CGEN_INSN_BASE_VALUE (insn))
500 {
501 /* ??? 0 is passed for `pc' */
502 int elength = CGEN_EXTRACT_FN (cd, insn)
503 (cd, insn, info, base_insn, fields, (bfd_vma) 0);
504 if (elength > 0)
505 {
506 /* sanity check */
507 if (length != 0 && length != elength)
508 abort ();
509 return insn;
510 }
511 }
512 }
513
514 insn_list = insn_list->next;
515 }
516 }
517 else
518 {
519 /* Sanity check: can't pass an alias insn if ! alias_p. */
520 if (! alias_p
521 && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
522 abort ();
523 /* Sanity check: length must be correct. */
524 if (length != CGEN_INSN_BITSIZE (insn))
525 abort ();
526
527 /* ??? 0 is passed for `pc' */
528 length = CGEN_EXTRACT_FN (cd, insn)
529 (cd, insn, info, base_insn, fields, (bfd_vma) 0);
530 /* Sanity check: must succeed.
531 Could relax this later if it ever proves useful. */
532 if (length == 0)
533 abort ();
534 return insn;
535 }
536
537 return NULL;
538 }
539
540 /* Fill in the operand instances used by INSN whose operands are FIELDS.
541 INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
542 in. */
543
544 void
545 cgen_get_insn_operands (cd, insn, fields, indices)
546 CGEN_CPU_DESC cd;
547 const CGEN_INSN *insn;
548 const CGEN_FIELDS *fields;
549 int *indices;
550 {
551 const CGEN_OPINST *opinst;
552 int i;
553
554 if (insn->opinst == NULL)
555 abort ();
556 for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
557 {
558 enum cgen_operand_type op_type = opinst->op_type;
559 if (op_type == CGEN_OPERAND_NIL)
560 indices[i] = opinst->index;
561 else
562 indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
563 }
564 }
565
566 /* Cover function to cgen_get_insn_operands when either INSN or FIELDS
567 isn't known.
568 The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
569 cgen_lookup_insn unchanged.
570 INSN_INT_VALUE is used if CGEN_INT_INSN_P.
571 Otherwise INSN_BYTES_VALUE is used.
572
573 The result is the insn table entry or NULL if the instruction wasn't
574 recognized. */
575
576 const CGEN_INSN *
577 cgen_lookup_get_insn_operands (cd, insn, insn_int_value, insn_bytes_value,
578 length, indices, fields)
579 CGEN_CPU_DESC cd;
580 const CGEN_INSN *insn;
581 CGEN_INSN_INT insn_int_value;
582 /* ??? CGEN_INSN_BYTES would be a nice type name to use here. */
583 unsigned char *insn_bytes_value;
584 int length;
585 int *indices;
586 CGEN_FIELDS *fields;
587 {
588 /* Pass non-zero for ALIAS_P only if INSN != NULL.
589 If INSN == NULL, we want a real insn. */
590 insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
591 length, fields, insn != NULL);
592 if (! insn)
593 return NULL;
594
595 cgen_get_insn_operands (cd, insn, fields, indices);
596 return insn;
597 }
This page took 0.041928 seconds and 5 git commands to generate.