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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [opcodes/] [cgen-opc.c] - Blame information for rev 307

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

Line No. Rev Author Line
1 24 jeremybenn
/* CGEN generic opcode support.
2
 
3 225 jeremybenn
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005, 2007, 2009
4 24 jeremybenn
   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 225 jeremybenn
#include "alloca-conf.h"
23 24 jeremybenn
#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 index;
380
          bfd_vma this_value;
381
          index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
382
          this_value = bfd_get_bits (& buf[index / 8], insn_chunk_bitsize, big_p);
383
          value = (value << insn_chunk_bitsize) | this_value;
384
        }
385
    }
386
  else
387
    {
388
      value = bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG);
389
    }
390
 
391
  return value;
392
}
393
 
394
/* Cover function to store an insn value properly byteswapped.  */
395
 
396
void
397
cgen_put_insn_value (CGEN_CPU_DESC cd,
398
                     unsigned char *buf,
399
                     int length,
400
                     CGEN_INSN_INT value)
401
{
402
  int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
403
  int insn_chunk_bitsize = cd->insn_chunk_bitsize;
404
 
405
  if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
406
    {
407
      /* We need to divide up the incoming value into insn_chunk_bitsize-length
408
         segments, and endian-convert them, one at a time. */
409
      int i;
410
 
411
      /* Enforce divisibility. */
412
      if ((length % insn_chunk_bitsize) != 0)
413
        abort ();
414
 
415
      for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
416
        {
417
          int index;
418
          index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */
419
          bfd_put_bits ((bfd_vma) value, & buf[index / 8], insn_chunk_bitsize, big_p);
420
          value >>= insn_chunk_bitsize;
421
        }
422
    }
423
  else
424
    {
425
      bfd_put_bits ((bfd_vma) value, buf, length, big_p);
426
    }
427
}
428
 
429
/* Look up instruction INSN_*_VALUE and extract its fields.
430
   INSN_INT_VALUE is used if CGEN_INT_INSN_P.
431
   Otherwise INSN_BYTES_VALUE is used.
432
   INSN, if non-null, is the insn table entry.
433
   Otherwise INSN_*_VALUE is examined to compute it.
434
   LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
435
 
436
   If INSN != NULL, LENGTH must be valid.
437
   ALIAS_P is non-zero if alias insns are to be included in the search.
438
 
439
   The result is a pointer to the insn table entry, or NULL if the instruction
440
   wasn't recognized.  */
441
 
442
/* ??? Will need to be revisited for VLIW architectures.  */
443
 
444
const CGEN_INSN *
445
cgen_lookup_insn (CGEN_CPU_DESC cd,
446
                  const CGEN_INSN *insn,
447
                  CGEN_INSN_INT insn_int_value,
448
                  /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
449
                  unsigned char *insn_bytes_value,
450
                  int length,
451
                  CGEN_FIELDS *fields,
452
                  int alias_p)
453
{
454
  unsigned char *buf;
455
  CGEN_INSN_INT base_insn;
456
  CGEN_EXTRACT_INFO ex_info;
457
  CGEN_EXTRACT_INFO *info;
458
 
459
  if (cd->int_insn_p)
460
    {
461
      info = NULL;
462
      buf = (unsigned char *) alloca (cd->max_insn_bitsize / 8);
463
      cgen_put_insn_value (cd, buf, length, insn_int_value);
464
      base_insn = insn_int_value;
465
    }
466
  else
467
    {
468
      info = &ex_info;
469
      ex_info.dis_info = NULL;
470
      ex_info.insn_bytes = insn_bytes_value;
471
      ex_info.valid = -1;
472
      buf = insn_bytes_value;
473
      base_insn = cgen_get_insn_value (cd, buf, length);
474
    }
475
 
476
  if (!insn)
477
    {
478
      const CGEN_INSN_LIST *insn_list;
479
 
480
      /* The instructions are stored in hash lists.
481
         Pick the first one and keep trying until we find the right one.  */
482
 
483
      insn_list = cgen_dis_lookup_insn (cd, (char *) buf, base_insn);
484
      while (insn_list != NULL)
485
        {
486
          insn = insn_list->insn;
487
 
488
          if (alias_p
489
              /* FIXME: Ensure ALIAS attribute always has same index.  */
490
              || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
491
            {
492
              /* Basic bit mask must be correct.  */
493
              /* ??? May wish to allow target to defer this check until the
494
                 extract handler.  */
495
              if ((base_insn & CGEN_INSN_BASE_MASK (insn))
496
                  == CGEN_INSN_BASE_VALUE (insn))
497
                {
498
                  /* ??? 0 is passed for `pc' */
499
                  int elength = CGEN_EXTRACT_FN (cd, insn)
500
                    (cd, insn, info, base_insn, fields, (bfd_vma) 0);
501
                  if (elength > 0)
502
                    {
503
                      /* sanity check */
504
                      if (length != 0 && length != elength)
505
                        abort ();
506
                      return insn;
507
                    }
508
                }
509
            }
510
 
511
          insn_list = insn_list->next;
512
        }
513
    }
514
  else
515
    {
516
      /* Sanity check: can't pass an alias insn if ! alias_p.  */
517
      if (! alias_p
518
          && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
519
        abort ();
520
      /* Sanity check: length must be correct.  */
521
      if (length != CGEN_INSN_BITSIZE (insn))
522
        abort ();
523
 
524
      /* ??? 0 is passed for `pc' */
525
      length = CGEN_EXTRACT_FN (cd, insn)
526
        (cd, insn, info, base_insn, fields, (bfd_vma) 0);
527
      /* Sanity check: must succeed.
528
         Could relax this later if it ever proves useful.  */
529
      if (length == 0)
530
        abort ();
531
      return insn;
532
    }
533
 
534
  return NULL;
535
}
536
 
537
/* Fill in the operand instances used by INSN whose operands are FIELDS.
538
   INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
539
   in.  */
540
 
541
void
542
cgen_get_insn_operands (CGEN_CPU_DESC cd,
543
                        const CGEN_INSN *insn,
544
                        const CGEN_FIELDS *fields,
545
                        int *indices)
546
{
547
  const CGEN_OPINST *opinst;
548
  int i;
549
 
550
  if (insn->opinst == NULL)
551
    abort ();
552
  for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
553
    {
554
      enum cgen_operand_type op_type = opinst->op_type;
555
      if (op_type == CGEN_OPERAND_NIL)
556
        indices[i] = opinst->index;
557
      else
558
        indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
559
    }
560
}
561
 
562
/* Cover function to cgen_get_insn_operands when either INSN or FIELDS
563
   isn't known.
564
   The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
565
   cgen_lookup_insn unchanged.
566
   INSN_INT_VALUE is used if CGEN_INT_INSN_P.
567
   Otherwise INSN_BYTES_VALUE is used.
568
 
569
   The result is the insn table entry or NULL if the instruction wasn't
570
   recognized.  */
571
 
572
const CGEN_INSN *
573
cgen_lookup_get_insn_operands (CGEN_CPU_DESC cd,
574
                               const CGEN_INSN *insn,
575
                               CGEN_INSN_INT insn_int_value,
576
                               /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
577
                               unsigned char *insn_bytes_value,
578
                               int length,
579
                               int *indices,
580
                               CGEN_FIELDS *fields)
581
{
582
  /* Pass non-zero for ALIAS_P only if INSN != NULL.
583
     If INSN == NULL, we want a real insn.  */
584
  insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
585
                           length, fields, insn != NULL);
586
  if (! insn)
587
    return NULL;
588
 
589
  cgen_get_insn_operands (cd, insn, fields, indices);
590
  return insn;
591
}
592
 
593
/* Allow signed overflow of instruction fields.  */
594
void
595
cgen_set_signed_overflow_ok (CGEN_CPU_DESC cd)
596
{
597
  cd->signed_overflow_ok_p = 1;
598
}
599
 
600
/* Generate an error message if a signed field in an instruction overflows.  */
601
void
602
cgen_clear_signed_overflow_ok (CGEN_CPU_DESC cd)
603
{
604
  cd->signed_overflow_ok_p = 0;
605
}
606
 
607
/* Will an error message be generated if a signed field in an instruction overflows ? */
608
unsigned int
609
cgen_signed_overflow_ok_p (CGEN_CPU_DESC cd)
610
{
611
  return cd->signed_overflow_ok_p;
612
}

powered by: WebSVN 2.1.0

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