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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [opcodes/] [cgen-opc.c] - Blame information for rev 1771

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

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

powered by: WebSVN 2.1.0

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