source: trunk/src/binutils/opcodes/cgen-opc.c@ 10

Last change on this file since 10 was 10, checked in by bird, 22 years ago

Initial revision

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