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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [gdb-5.0/] [opcodes/] [cgen-opc.c] - Blame information for rev 1778

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

Line No. Rev Author Line
1 106 markom
/* CGEN generic opcode support.
2
 
3
   Copyright (C) 1996, 1997, 1998, 1999, 2000 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
 
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
 
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
 
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
 
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
 
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
}
598
 
599
/* Allow signed overflow of instruction fields.  */
600
void
601
cgen_set_signed_overflow_ok (cd)
602
     CGEN_CPU_DESC cd;
603
{
604
  cd->signed_overflow_ok_p = 1;
605
}
606
 
607
/* Generate an error message if a signed field in an instruction overflows.  */
608
void
609
cgen_clear_signed_overflow_ok (cd)
610
     CGEN_CPU_DESC cd;
611
{
612
  cd->signed_overflow_ok_p = 0;
613
}
614
 
615
/* Will an error message be generated if a signed field in an instruction overflows ? */
616
unsigned int
617
cgen_signed_overflow_ok_p (cd)
618
     CGEN_CPU_DESC cd;
619
{
620
  return cd->signed_overflow_ok_p;
621
}

powered by: WebSVN 2.1.0

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