OSDN Git Service

Fix typos in ChangeLogs; fix dates in copyright notices
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / cgen-opc.c
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
35 static unsigned int hash_keyword_name
36   PARAMS ((const CGEN_KEYWORD *, const char *, int));
37 static unsigned int hash_keyword_value
38   PARAMS ((const CGEN_KEYWORD *, unsigned int));
39 static 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
48 const CGEN_KEYWORD_ENTRY *
49 cgen_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
91 const CGEN_KEYWORD_ENTRY *
92 cgen_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
115 void
116 cgen_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
147 CGEN_KEYWORD_SEARCH
148 cgen_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
171 const CGEN_KEYWORD_ENTRY *
172 cgen_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
206 static unsigned int
207 hash_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
225 static unsigned int
226 hash_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
237 static void
238 build_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 \f
260 /* Hardware support.  */
261
262 /* Lookup a hardware element by its name.
263    Returns NULL if NAME is not supported by the currently selected
264    mach/isa.  */
265
266 const CGEN_HW_ENTRY *
267 cgen_hw_lookup_by_name (cd, name)
268      CGEN_CPU_DESC cd;
269      const char *name;
270 {
271   unsigned int i;
272   const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
273
274   for (i = 0; i < cd->hw_table.num_entries; ++i)
275     if (hw[i] && strcmp (name, hw[i]->name) == 0)
276       return hw[i];
277
278   return NULL;
279 }
280
281 /* Lookup a hardware element by its number.
282    Hardware elements are enumerated, however it may be possible to add some
283    at runtime, thus HWNUM is not an enum type but rather an int.
284    Returns NULL if HWNUM is not supported by the currently selected mach.  */
285
286 const CGEN_HW_ENTRY *
287 cgen_hw_lookup_by_num (cd, hwnum)
288      CGEN_CPU_DESC cd;
289      unsigned int hwnum;
290 {
291   unsigned int i;
292   const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
293
294   /* ??? This can be speeded up.  */
295   for (i = 0; i < cd->hw_table.num_entries; ++i)
296     if (hw[i] && hwnum == hw[i]->type)
297       return hw[i];
298
299   return NULL;
300 }
301 \f
302 /* Operand support.  */
303
304 /* Lookup an operand by its name.
305    Returns NULL if NAME is not supported by the currently selected
306    mach/isa.  */
307
308 const CGEN_OPERAND *
309 cgen_operand_lookup_by_name (cd, name)
310      CGEN_CPU_DESC cd;
311      const char *name;
312 {
313   unsigned int i;
314   const CGEN_OPERAND **op = cd->operand_table.entries;
315
316   for (i = 0; i < cd->operand_table.num_entries; ++i)
317     if (op[i] && strcmp (name, op[i]->name) == 0)
318       return op[i];
319
320   return NULL;
321 }
322
323 /* Lookup an operand by its number.
324    Operands are enumerated, however it may be possible to add some
325    at runtime, thus OPNUM is not an enum type but rather an int.
326    Returns NULL if OPNUM is not supported by the currently selected
327    mach/isa.  */
328
329 const CGEN_OPERAND *
330 cgen_operand_lookup_by_num (cd, opnum)
331      CGEN_CPU_DESC cd;
332      int opnum;
333 {
334   return cd->operand_table.entries[opnum];
335 }
336 \f
337 /* Instruction support.  */
338
339 /* Return number of instructions.  This includes any added at runtime.  */
340
341 int
342 cgen_insn_count (cd)
343      CGEN_CPU_DESC cd;
344 {
345   int count = cd->insn_table.num_init_entries;
346   CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
347
348   for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
349     ++count;
350
351   return count;
352 }
353
354 /* Return number of macro-instructions.
355    This includes any added at runtime.  */
356
357 int
358 cgen_macro_insn_count (cd)
359      CGEN_CPU_DESC cd;
360 {
361   int count = cd->macro_insn_table.num_init_entries;
362   CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
363
364   for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
365     ++count;
366
367   return count;
368 }
369
370 /* Cover function to read and properly byteswap an insn value.  */
371
372 CGEN_INSN_INT
373 cgen_get_insn_value (cd, buf, length)
374      CGEN_CPU_DESC cd;
375      unsigned char *buf;
376      int length;
377 {
378   return bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG);
379 }
380
381 /* Cover function to store an insn value properly byteswapped.  */
382
383 void
384 cgen_put_insn_value (cd, buf, length, value)
385      CGEN_CPU_DESC cd;
386      unsigned char *buf;
387      int length;
388      CGEN_INSN_INT value;
389 {
390   bfd_put_bits ((bfd_vma) value, buf, length,
391                 cd->insn_endian == CGEN_ENDIAN_BIG);
392 }
393 \f
394 /* Look up instruction INSN_*_VALUE and extract its fields.
395    INSN_INT_VALUE is used if CGEN_INT_INSN_P.
396    Otherwise INSN_BYTES_VALUE is used.
397    INSN, if non-null, is the insn table entry.
398    Otherwise INSN_*_VALUE is examined to compute it.
399    LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
400    0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
401    If INSN != NULL, LENGTH must be valid.
402    ALIAS_P is non-zero if alias insns are to be included in the search.
403
404    The result is a pointer to the insn table entry, or NULL if the instruction
405    wasn't recognized.  */
406
407 /* ??? Will need to be revisited for VLIW architectures.  */
408
409 const CGEN_INSN *
410 cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value, length, fields,
411                   alias_p)
412      CGEN_CPU_DESC cd;
413      const CGEN_INSN *insn;
414      CGEN_INSN_INT insn_int_value;
415      /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
416      unsigned char *insn_bytes_value;
417      int length;
418      CGEN_FIELDS *fields;
419      int alias_p;
420 {
421   unsigned char *buf;
422   CGEN_INSN_INT base_insn;
423   CGEN_EXTRACT_INFO ex_info;
424   CGEN_EXTRACT_INFO *info;
425
426   if (cd->int_insn_p)
427     {
428       info = NULL;
429       buf = (unsigned char *) alloca (cd->max_insn_bitsize / 8);
430       cgen_put_insn_value (cd, buf, length, insn_int_value);
431       base_insn = insn_int_value;
432     }
433   else
434     {
435       info = &ex_info;
436       ex_info.dis_info = NULL;
437       ex_info.insn_bytes = insn_bytes_value;
438       ex_info.valid = -1;
439       buf = insn_bytes_value;
440       base_insn = cgen_get_insn_value (cd, buf, length);
441     }
442
443   if (!insn)
444     {
445       const CGEN_INSN_LIST *insn_list;
446
447       /* The instructions are stored in hash lists.
448          Pick the first one and keep trying until we find the right one.  */
449
450       insn_list = cgen_dis_lookup_insn (cd, buf, base_insn);
451       while (insn_list != NULL)
452         {
453           insn = insn_list->insn;
454
455           if (alias_p
456               /* FIXME: Ensure ALIAS attribute always has same index.  */
457               || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
458             {
459               /* Basic bit mask must be correct.  */
460               /* ??? May wish to allow target to defer this check until the
461                  extract handler.  */
462               if ((base_insn & CGEN_INSN_BASE_MASK (insn))
463                   == CGEN_INSN_BASE_VALUE (insn))
464                 {
465                   /* ??? 0 is passed for `pc' */
466                   int elength = CGEN_EXTRACT_FN (cd, insn)
467                     (cd, insn, info, base_insn, fields, (bfd_vma) 0);
468                   if (elength > 0)
469                     {
470                       /* sanity check */
471                       if (length != 0 && length != elength)
472                         abort ();
473                       return insn;
474                     }
475                 }
476             }
477
478           insn_list = insn_list->next;
479         }
480     }
481   else
482     {
483       /* Sanity check: can't pass an alias insn if ! alias_p.  */
484       if (! alias_p
485           && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
486         abort ();
487       /* Sanity check: length must be correct.  */
488       if (length != CGEN_INSN_BITSIZE (insn))
489         abort ();
490
491       /* ??? 0 is passed for `pc' */
492       length = CGEN_EXTRACT_FN (cd, insn)
493         (cd, insn, info, base_insn, fields, (bfd_vma) 0);
494       /* Sanity check: must succeed.
495          Could relax this later if it ever proves useful.  */
496       if (length == 0)
497         abort ();
498       return insn;
499     }
500
501   return NULL;
502 }
503
504 /* Fill in the operand instances used by INSN whose operands are FIELDS.
505    INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
506    in.  */
507
508 void
509 cgen_get_insn_operands (cd, insn, fields, indices)
510      CGEN_CPU_DESC cd;
511      const CGEN_INSN *insn;
512      const CGEN_FIELDS *fields;
513      int *indices;
514 {
515   const CGEN_OPINST *opinst;
516   int i;
517
518   if (insn->opinst == NULL)
519     abort ();
520   for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
521     {
522       enum cgen_operand_type op_type = opinst->op_type;
523       if (op_type == CGEN_OPERAND_NIL)
524         indices[i] = opinst->index;
525       else
526         indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
527     }
528 }
529
530 /* Cover function to cgen_get_insn_operands when either INSN or FIELDS
531    isn't known.
532    The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
533    cgen_lookup_insn unchanged.
534    INSN_INT_VALUE is used if CGEN_INT_INSN_P.
535    Otherwise INSN_BYTES_VALUE is used.
536
537    The result is the insn table entry or NULL if the instruction wasn't
538    recognized.  */
539
540 const CGEN_INSN *
541 cgen_lookup_get_insn_operands (cd, insn, insn_int_value, insn_bytes_value,
542                                length, indices, fields)
543      CGEN_CPU_DESC cd;
544      const CGEN_INSN *insn;
545      CGEN_INSN_INT insn_int_value;
546      /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
547      unsigned char *insn_bytes_value;
548      int length;
549      int *indices;
550      CGEN_FIELDS *fields;
551 {
552   /* Pass non-zero for ALIAS_P only if INSN != NULL.
553      If INSN == NULL, we want a real insn.  */
554   insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
555                            length, fields, insn != NULL);
556   if (! insn)
557     return NULL;
558
559   cgen_get_insn_operands (cd, insn, fields, indices);
560   return insn;
561 }
562
563 /* Allow signed overflow of instruction fields.  */
564 void
565 cgen_set_signed_overflow_ok (cd)
566      CGEN_CPU_DESC cd;
567 {
568   cd->signed_overflow_ok_p = 1;
569 }
570
571 /* Generate an error message if a signed field in an instruction overflows.  */
572 void
573 cgen_clear_signed_overflow_ok (cd)
574      CGEN_CPU_DESC cd;
575 {
576   cd->signed_overflow_ok_p = 0;
577 }
578
579 /* Will an error message be generated if a signed field in an instruction overflows ? */
580 unsigned int
581 cgen_signed_overflow_ok_p (cd)
582      CGEN_CPU_DESC cd;
583 {
584   return cd->signed_overflow_ok_p;
585 }