OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [opcodes/] [cgen-opc.c] - Blame information for rev 41

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.