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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [opcodes/] [openrisc-dis.c] - Blame information for rev 853

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

Line No. Rev Author Line
1 38 julius
/* Disassembler interface for targets using CGEN. -*- C -*-
2
   CGEN: Cpu tools GENerator
3
 
4
   THIS FILE IS MACHINE GENERATED WITH CGEN.
5
   - the resultant file is machine generated, cgen-dis.in isn't
6
 
7
   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007
8
   Free Software Foundation, Inc.
9
 
10
   This file is part of libopcodes.
11
 
12
   This library is free software; you can redistribute it and/or modify
13
   it under the terms of the GNU General Public License as published by
14
   the Free Software Foundation; either version 3, or (at your option)
15
   any later version.
16
 
17
   It is distributed in the hope that it will be useful, but WITHOUT
18
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20
   License for more details.
21
 
22
   You should have received a copy of the GNU General Public License
23
   along with this program; if not, write to the Free Software Foundation, Inc.,
24
   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25
 
26
/* ??? Eventually more and more of this stuff can go to cpu-independent files.
27
   Keep that in mind.  */
28
 
29
#include "sysdep.h"
30
#include <stdio.h>
31
#include "ansidecl.h"
32
#include "dis-asm.h"
33
#include "bfd.h"
34
#include "symcat.h"
35
#include "libiberty.h"
36
#include "openrisc-desc.h"
37
#include "openrisc-opc.h"
38
#include "opintl.h"
39
 
40
/* Default text to print if an instruction isn't recognized.  */
41
#define UNKNOWN_INSN_MSG _("*unknown*")
42
 
43
static void print_normal
44
  (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45
static void print_address
46
  (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
47
static void print_keyword
48
  (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
49
static void print_insn_normal
50
  (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51
static int print_insn
52
  (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
53
static int default_print_insn
54
  (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
55
static int read_insn
56
  (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
57
   unsigned long *);
58
 
59
/* -- disassembler routines inserted here.  */
60
 
61
 
62
void openrisc_cgen_print_operand
63
  (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
64
 
65
/* Main entry point for printing operands.
66
   XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
67
   of dis-asm.h on cgen.h.
68
 
69
   This function is basically just a big switch statement.  Earlier versions
70
   used tables to look up the function to use, but
71
   - if the table contains both assembler and disassembler functions then
72
     the disassembler contains much of the assembler and vice-versa,
73
   - there's a lot of inlining possibilities as things grow,
74
   - using a switch statement avoids the function call overhead.
75
 
76
   This function could be moved into `print_insn_normal', but keeping it
77
   separate makes clear the interface between `print_insn_normal' and each of
78
   the handlers.  */
79
 
80
void
81
openrisc_cgen_print_operand (CGEN_CPU_DESC cd,
82
                           int opindex,
83
                           void * xinfo,
84
                           CGEN_FIELDS *fields,
85
                           void const *attrs ATTRIBUTE_UNUSED,
86
                           bfd_vma pc,
87
                           int length)
88
{
89
  disassemble_info *info = (disassemble_info *) xinfo;
90
 
91
  switch (opindex)
92
    {
93
    case OPENRISC_OPERAND_ABS_26 :
94
      print_address (cd, info, fields->f_abs26, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
95
      break;
96
    case OPENRISC_OPERAND_DISP_26 :
97
      print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
98
      break;
99
    case OPENRISC_OPERAND_HI16 :
100
      print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
101
      break;
102
    case OPENRISC_OPERAND_LO16 :
103
      print_normal (cd, info, fields->f_lo16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
104
      break;
105
    case OPENRISC_OPERAND_OP_F_23 :
106
      print_normal (cd, info, fields->f_op4, 0, pc, length);
107
      break;
108
    case OPENRISC_OPERAND_OP_F_3 :
109
      print_normal (cd, info, fields->f_op5, 0, pc, length);
110
      break;
111
    case OPENRISC_OPERAND_RA :
112
      print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r2, 0);
113
      break;
114
    case OPENRISC_OPERAND_RB :
115
      print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r3, 0);
116
      break;
117
    case OPENRISC_OPERAND_RD :
118
      print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r1, 0);
119
      break;
120
    case OPENRISC_OPERAND_SIMM_16 :
121
      print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
122
      break;
123
    case OPENRISC_OPERAND_UI16NC :
124
      print_normal (cd, info, fields->f_i16nc, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
125
      break;
126
    case OPENRISC_OPERAND_UIMM_16 :
127
      print_normal (cd, info, fields->f_uimm16, 0, pc, length);
128
      break;
129
    case OPENRISC_OPERAND_UIMM_5 :
130
      print_normal (cd, info, fields->f_uimm5, 0, pc, length);
131
      break;
132
 
133
    default :
134
      /* xgettext:c-format */
135
      fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
136
               opindex);
137
    abort ();
138
  }
139
}
140
 
141
cgen_print_fn * const openrisc_cgen_print_handlers[] =
142
{
143
  print_insn_normal,
144
};
145
 
146
 
147
void
148
openrisc_cgen_init_dis (CGEN_CPU_DESC cd)
149
{
150
  openrisc_cgen_init_opcode_table (cd);
151
  openrisc_cgen_init_ibld_table (cd);
152
  cd->print_handlers = & openrisc_cgen_print_handlers[0];
153
  cd->print_operand = openrisc_cgen_print_operand;
154
}
155
 
156
 
157
/* Default print handler.  */
158
 
159
static void
160
print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
161
              void *dis_info,
162
              long value,
163
              unsigned int attrs,
164
              bfd_vma pc ATTRIBUTE_UNUSED,
165
              int length ATTRIBUTE_UNUSED)
166
{
167
  disassemble_info *info = (disassemble_info *) dis_info;
168
 
169
#ifdef CGEN_PRINT_NORMAL
170
  CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
171
#endif
172
 
173
  /* Print the operand as directed by the attributes.  */
174
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
175
    ; /* nothing to do */
176
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
177
    (*info->fprintf_func) (info->stream, "%ld", value);
178
  else
179
    (*info->fprintf_func) (info->stream, "0x%lx", value);
180
}
181
 
182
/* Default address handler.  */
183
 
184
static void
185
print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
186
               void *dis_info,
187
               bfd_vma value,
188
               unsigned int attrs,
189
               bfd_vma pc ATTRIBUTE_UNUSED,
190
               int length ATTRIBUTE_UNUSED)
191
{
192
  disassemble_info *info = (disassemble_info *) dis_info;
193
 
194
#ifdef CGEN_PRINT_ADDRESS
195
  CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
196
#endif
197
 
198
  /* Print the operand as directed by the attributes.  */
199
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
200
    ; /* Nothing to do.  */
201
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
202
    (*info->print_address_func) (value, info);
203
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
204
    (*info->print_address_func) (value, info);
205
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
206
    (*info->fprintf_func) (info->stream, "%ld", (long) value);
207
  else
208
    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
209
}
210
 
211
/* Keyword print handler.  */
212
 
213
static void
214
print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
215
               void *dis_info,
216
               CGEN_KEYWORD *keyword_table,
217
               long value,
218
               unsigned int attrs ATTRIBUTE_UNUSED)
219
{
220
  disassemble_info *info = (disassemble_info *) dis_info;
221
  const CGEN_KEYWORD_ENTRY *ke;
222
 
223
  ke = cgen_keyword_lookup_value (keyword_table, value);
224
  if (ke != NULL)
225
    (*info->fprintf_func) (info->stream, "%s", ke->name);
226
  else
227
    (*info->fprintf_func) (info->stream, "???");
228
}
229
 
230
/* Default insn printer.
231
 
232
   DIS_INFO is defined as `void *' so the disassembler needn't know anything
233
   about disassemble_info.  */
234
 
235
static void
236
print_insn_normal (CGEN_CPU_DESC cd,
237
                   void *dis_info,
238
                   const CGEN_INSN *insn,
239
                   CGEN_FIELDS *fields,
240
                   bfd_vma pc,
241
                   int length)
242
{
243
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
244
  disassemble_info *info = (disassemble_info *) dis_info;
245
  const CGEN_SYNTAX_CHAR_TYPE *syn;
246
 
247
  CGEN_INIT_PRINT (cd);
248
 
249
  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
250
    {
251
      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
252
        {
253
          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
254
          continue;
255
        }
256
      if (CGEN_SYNTAX_CHAR_P (*syn))
257
        {
258
          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
259
          continue;
260
        }
261
 
262
      /* We have an operand.  */
263
      openrisc_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
264
                                 fields, CGEN_INSN_ATTRS (insn), pc, length);
265
    }
266
}
267
 
268
/* Subroutine of print_insn. Reads an insn into the given buffers and updates
269
   the extract info.
270
   Returns 0 if all is well, non-zero otherwise.  */
271
 
272
static int
273
read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
274
           bfd_vma pc,
275
           disassemble_info *info,
276
           bfd_byte *buf,
277
           int buflen,
278
           CGEN_EXTRACT_INFO *ex_info,
279
           unsigned long *insn_value)
280
{
281
  int status = (*info->read_memory_func) (pc, buf, buflen, info);
282
 
283
  if (status != 0)
284
    {
285
      (*info->memory_error_func) (status, pc, info);
286
      return -1;
287
    }
288
 
289
  ex_info->dis_info = info;
290
  ex_info->valid = (1 << buflen) - 1;
291
  ex_info->insn_bytes = buf;
292
 
293
  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
294
  return 0;
295
}
296
 
297
/* Utility to print an insn.
298
   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
299
   The result is the size of the insn in bytes or zero for an unknown insn
300
   or -1 if an error occurs fetching data (memory_error_func will have
301
   been called).  */
302
 
303
static int
304
print_insn (CGEN_CPU_DESC cd,
305
            bfd_vma pc,
306
            disassemble_info *info,
307
            bfd_byte *buf,
308
            unsigned int buflen)
309
{
310
  CGEN_INSN_INT insn_value;
311
  const CGEN_INSN_LIST *insn_list;
312
  CGEN_EXTRACT_INFO ex_info;
313
  int basesize;
314
 
315
  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
316
  basesize = cd->base_insn_bitsize < buflen * 8 ?
317
                                     cd->base_insn_bitsize : buflen * 8;
318
  insn_value = cgen_get_insn_value (cd, buf, basesize);
319
 
320
 
321
  /* Fill in ex_info fields like read_insn would.  Don't actually call
322
     read_insn, since the incoming buffer is already read (and possibly
323
     modified a la m32r).  */
324
  ex_info.valid = (1 << buflen) - 1;
325
  ex_info.dis_info = info;
326
  ex_info.insn_bytes = buf;
327
 
328
  /* The instructions are stored in hash lists.
329
     Pick the first one and keep trying until we find the right one.  */
330
 
331
  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
332
  while (insn_list != NULL)
333
    {
334
      const CGEN_INSN *insn = insn_list->insn;
335
      CGEN_FIELDS fields;
336
      int length;
337
      unsigned long insn_value_cropped;
338
 
339
#ifdef CGEN_VALIDATE_INSN_SUPPORTED 
340
      /* Not needed as insn shouldn't be in hash lists if not supported.  */
341
      /* Supported by this cpu?  */
342
      if (! openrisc_cgen_insn_supported (cd, insn))
343
        {
344
          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
345
          continue;
346
        }
347
#endif
348
 
349
      /* Basic bit mask must be correct.  */
350
      /* ??? May wish to allow target to defer this check until the extract
351
         handler.  */
352
 
353
      /* Base size may exceed this instruction's size.  Extract the
354
         relevant part from the buffer. */
355
      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
356
          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
357
        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
358
                                           info->endian == BFD_ENDIAN_BIG);
359
      else
360
        insn_value_cropped = insn_value;
361
 
362
      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
363
          == CGEN_INSN_BASE_VALUE (insn))
364
        {
365
          /* Printing is handled in two passes.  The first pass parses the
366
             machine insn and extracts the fields.  The second pass prints
367
             them.  */
368
 
369
          /* Make sure the entire insn is loaded into insn_value, if it
370
             can fit.  */
371
          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
372
              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
373
            {
374
              unsigned long full_insn_value;
375
              int rc = read_insn (cd, pc, info, buf,
376
                                  CGEN_INSN_BITSIZE (insn) / 8,
377
                                  & ex_info, & full_insn_value);
378
              if (rc != 0)
379
                return rc;
380
              length = CGEN_EXTRACT_FN (cd, insn)
381
                (cd, insn, &ex_info, full_insn_value, &fields, pc);
382
            }
383
          else
384
            length = CGEN_EXTRACT_FN (cd, insn)
385
              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
386
 
387
          /* Length < 0 -> error.  */
388
          if (length < 0)
389
            return length;
390
          if (length > 0)
391
            {
392
              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
393
              /* Length is in bits, result is in bytes.  */
394
              return length / 8;
395
            }
396
        }
397
 
398
      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
399
    }
400
 
401
  return 0;
402
}
403
 
404
/* Default value for CGEN_PRINT_INSN.
405
   The result is the size of the insn in bytes or zero for an unknown insn
406
   or -1 if an error occured fetching bytes.  */
407
 
408
#ifndef CGEN_PRINT_INSN
409
#define CGEN_PRINT_INSN default_print_insn
410
#endif
411
 
412
static int
413
default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
414
{
415
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
416
  int buflen;
417
  int status;
418
 
419
  /* Attempt to read the base part of the insn.  */
420
  buflen = cd->base_insn_bitsize / 8;
421
  status = (*info->read_memory_func) (pc, buf, buflen, info);
422
 
423
  /* Try again with the minimum part, if min < base.  */
424
  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
425
    {
426
      buflen = cd->min_insn_bitsize / 8;
427
      status = (*info->read_memory_func) (pc, buf, buflen, info);
428
    }
429
 
430
  if (status != 0)
431
    {
432
      (*info->memory_error_func) (status, pc, info);
433
      return -1;
434
    }
435
 
436
  return print_insn (cd, pc, info, buf, buflen);
437
}
438
 
439
/* Main entry point.
440
   Print one instruction from PC on INFO->STREAM.
441
   Return the size of the instruction (in bytes).  */
442
 
443
typedef struct cpu_desc_list
444
{
445
  struct cpu_desc_list *next;
446
  CGEN_BITSET *isa;
447
  int mach;
448
  int endian;
449
  CGEN_CPU_DESC cd;
450
} cpu_desc_list;
451
 
452
int
453
print_insn_openrisc (bfd_vma pc, disassemble_info *info)
454
{
455
  static cpu_desc_list *cd_list = 0;
456
  cpu_desc_list *cl = 0;
457
  static CGEN_CPU_DESC cd = 0;
458
  static CGEN_BITSET *prev_isa;
459
  static int prev_mach;
460
  static int prev_endian;
461
  int length;
462
  CGEN_BITSET *isa;
463
  int mach;
464
  int endian = (info->endian == BFD_ENDIAN_BIG
465
                ? CGEN_ENDIAN_BIG
466
                : CGEN_ENDIAN_LITTLE);
467
  enum bfd_architecture arch;
468
 
469
  /* ??? gdb will set mach but leave the architecture as "unknown" */
470
#ifndef CGEN_BFD_ARCH
471
#define CGEN_BFD_ARCH bfd_arch_openrisc
472
#endif
473
  arch = info->arch;
474
  if (arch == bfd_arch_unknown)
475
    arch = CGEN_BFD_ARCH;
476
 
477
  /* There's no standard way to compute the machine or isa number
478
     so we leave it to the target.  */
479
#ifdef CGEN_COMPUTE_MACH
480
  mach = CGEN_COMPUTE_MACH (info);
481
#else
482
  mach = info->mach;
483
#endif
484
 
485
#ifdef CGEN_COMPUTE_ISA
486
  {
487
    static CGEN_BITSET *permanent_isa;
488
 
489
    if (!permanent_isa)
490
      permanent_isa = cgen_bitset_create (MAX_ISAS);
491
    isa = permanent_isa;
492
    cgen_bitset_clear (isa);
493
    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
494
  }
495
#else
496
  isa = info->insn_sets;
497
#endif
498
 
499
  /* If we've switched cpu's, try to find a handle we've used before */
500
  if (cd
501
      && (cgen_bitset_compare (isa, prev_isa) != 0
502
          || mach != prev_mach
503
          || endian != prev_endian))
504
    {
505
      cd = 0;
506
      for (cl = cd_list; cl; cl = cl->next)
507
        {
508
          if (cgen_bitset_compare (cl->isa, isa) == 0 &&
509
              cl->mach == mach &&
510
              cl->endian == endian)
511
            {
512
              cd = cl->cd;
513
              prev_isa = cd->isas;
514
              break;
515
            }
516
        }
517
    }
518
 
519
  /* If we haven't initialized yet, initialize the opcode table.  */
520
  if (! cd)
521
    {
522
      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
523
      const char *mach_name;
524
 
525
      if (!arch_type)
526
        abort ();
527
      mach_name = arch_type->printable_name;
528
 
529
      prev_isa = cgen_bitset_copy (isa);
530
      prev_mach = mach;
531
      prev_endian = endian;
532
      cd = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
533
                                 CGEN_CPU_OPEN_BFDMACH, mach_name,
534
                                 CGEN_CPU_OPEN_ENDIAN, prev_endian,
535
                                 CGEN_CPU_OPEN_END);
536
      if (!cd)
537
        abort ();
538
 
539
      /* Save this away for future reference.  */
540
      cl = xmalloc (sizeof (struct cpu_desc_list));
541
      cl->cd = cd;
542
      cl->isa = prev_isa;
543
      cl->mach = mach;
544
      cl->endian = endian;
545
      cl->next = cd_list;
546
      cd_list = cl;
547
 
548
      openrisc_cgen_init_dis (cd);
549
    }
550
 
551
  /* We try to have as much common code as possible.
552
     But at this point some targets need to take over.  */
553
  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
554
     but if not possible try to move this hook elsewhere rather than
555
     have two hooks.  */
556
  length = CGEN_PRINT_INSN (cd, pc, info);
557
  if (length > 0)
558
    return length;
559
  if (length < 0)
560
    return -1;
561
 
562
  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
563
  return cd->default_insn_bitsize / 8;
564
}

powered by: WebSVN 2.1.0

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