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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [opcodes/] [openrisc-dis.c] - Blame information for rev 78

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

Line No. Rev Author Line
1 18 khays
/* 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
   2008, 2010  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
  /* Print the operand as directed by the attributes.  */
170
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
171
    ; /* nothing to do */
172
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
173
    (*info->fprintf_func) (info->stream, "%ld", value);
174
  else
175
    (*info->fprintf_func) (info->stream, "0x%lx", value);
176
}
177
 
178
/* Default address handler.  */
179
 
180
static void
181
print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
182
               void *dis_info,
183
               bfd_vma value,
184
               unsigned int attrs,
185
               bfd_vma pc ATTRIBUTE_UNUSED,
186
               int length ATTRIBUTE_UNUSED)
187
{
188
  disassemble_info *info = (disassemble_info *) dis_info;
189
 
190
  /* Print the operand as directed by the attributes.  */
191
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
192
    ; /* Nothing to do.  */
193
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
194
    (*info->print_address_func) (value, info);
195
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
196
    (*info->print_address_func) (value, info);
197
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
198
    (*info->fprintf_func) (info->stream, "%ld", (long) value);
199
  else
200
    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
201
}
202
 
203
/* Keyword print handler.  */
204
 
205
static void
206
print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
207
               void *dis_info,
208
               CGEN_KEYWORD *keyword_table,
209
               long value,
210
               unsigned int attrs ATTRIBUTE_UNUSED)
211
{
212
  disassemble_info *info = (disassemble_info *) dis_info;
213
  const CGEN_KEYWORD_ENTRY *ke;
214
 
215
  ke = cgen_keyword_lookup_value (keyword_table, value);
216
  if (ke != NULL)
217
    (*info->fprintf_func) (info->stream, "%s", ke->name);
218
  else
219
    (*info->fprintf_func) (info->stream, "???");
220
}
221
 
222
/* Default insn printer.
223
 
224
   DIS_INFO is defined as `void *' so the disassembler needn't know anything
225
   about disassemble_info.  */
226
 
227
static void
228
print_insn_normal (CGEN_CPU_DESC cd,
229
                   void *dis_info,
230
                   const CGEN_INSN *insn,
231
                   CGEN_FIELDS *fields,
232
                   bfd_vma pc,
233
                   int length)
234
{
235
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
236
  disassemble_info *info = (disassemble_info *) dis_info;
237
  const CGEN_SYNTAX_CHAR_TYPE *syn;
238
 
239
  CGEN_INIT_PRINT (cd);
240
 
241
  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
242
    {
243
      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
244
        {
245
          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
246
          continue;
247
        }
248
      if (CGEN_SYNTAX_CHAR_P (*syn))
249
        {
250
          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
251
          continue;
252
        }
253
 
254
      /* We have an operand.  */
255
      openrisc_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
256
                                 fields, CGEN_INSN_ATTRS (insn), pc, length);
257
    }
258
}
259
 
260
/* Subroutine of print_insn. Reads an insn into the given buffers and updates
261
   the extract info.
262
   Returns 0 if all is well, non-zero otherwise.  */
263
 
264
static int
265
read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
266
           bfd_vma pc,
267
           disassemble_info *info,
268
           bfd_byte *buf,
269
           int buflen,
270
           CGEN_EXTRACT_INFO *ex_info,
271
           unsigned long *insn_value)
272
{
273
  int status = (*info->read_memory_func) (pc, buf, buflen, info);
274
 
275
  if (status != 0)
276
    {
277
      (*info->memory_error_func) (status, pc, info);
278
      return -1;
279
    }
280
 
281
  ex_info->dis_info = info;
282
  ex_info->valid = (1 << buflen) - 1;
283
  ex_info->insn_bytes = buf;
284
 
285
  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
286
  return 0;
287
}
288
 
289
/* Utility to print an insn.
290
   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
291
   The result is the size of the insn in bytes or zero for an unknown insn
292
   or -1 if an error occurs fetching data (memory_error_func will have
293
   been called).  */
294
 
295
static int
296
print_insn (CGEN_CPU_DESC cd,
297
            bfd_vma pc,
298
            disassemble_info *info,
299
            bfd_byte *buf,
300
            unsigned int buflen)
301
{
302
  CGEN_INSN_INT insn_value;
303
  const CGEN_INSN_LIST *insn_list;
304
  CGEN_EXTRACT_INFO ex_info;
305
  int basesize;
306
 
307
  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
308
  basesize = cd->base_insn_bitsize < buflen * 8 ?
309
                                     cd->base_insn_bitsize : buflen * 8;
310
  insn_value = cgen_get_insn_value (cd, buf, basesize);
311
 
312
 
313
  /* Fill in ex_info fields like read_insn would.  Don't actually call
314
     read_insn, since the incoming buffer is already read (and possibly
315
     modified a la m32r).  */
316
  ex_info.valid = (1 << buflen) - 1;
317
  ex_info.dis_info = info;
318
  ex_info.insn_bytes = buf;
319
 
320
  /* The instructions are stored in hash lists.
321
     Pick the first one and keep trying until we find the right one.  */
322
 
323
  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
324
  while (insn_list != NULL)
325
    {
326
      const CGEN_INSN *insn = insn_list->insn;
327
      CGEN_FIELDS fields;
328
      int length;
329
      unsigned long insn_value_cropped;
330
 
331
#ifdef CGEN_VALIDATE_INSN_SUPPORTED 
332
      /* Not needed as insn shouldn't be in hash lists if not supported.  */
333
      /* Supported by this cpu?  */
334
      if (! openrisc_cgen_insn_supported (cd, insn))
335
        {
336
          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
337
          continue;
338
        }
339
#endif
340
 
341
      /* Basic bit mask must be correct.  */
342
      /* ??? May wish to allow target to defer this check until the extract
343
         handler.  */
344
 
345
      /* Base size may exceed this instruction's size.  Extract the
346
         relevant part from the buffer. */
347
      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
348
          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
349
        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
350
                                           info->endian == BFD_ENDIAN_BIG);
351
      else
352
        insn_value_cropped = insn_value;
353
 
354
      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
355
          == CGEN_INSN_BASE_VALUE (insn))
356
        {
357
          /* Printing is handled in two passes.  The first pass parses the
358
             machine insn and extracts the fields.  The second pass prints
359
             them.  */
360
 
361
          /* Make sure the entire insn is loaded into insn_value, if it
362
             can fit.  */
363
          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
364
              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
365
            {
366
              unsigned long full_insn_value;
367
              int rc = read_insn (cd, pc, info, buf,
368
                                  CGEN_INSN_BITSIZE (insn) / 8,
369
                                  & ex_info, & full_insn_value);
370
              if (rc != 0)
371
                return rc;
372
              length = CGEN_EXTRACT_FN (cd, insn)
373
                (cd, insn, &ex_info, full_insn_value, &fields, pc);
374
            }
375
          else
376
            length = CGEN_EXTRACT_FN (cd, insn)
377
              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
378
 
379
          /* Length < 0 -> error.  */
380
          if (length < 0)
381
            return length;
382
          if (length > 0)
383
            {
384
              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
385
              /* Length is in bits, result is in bytes.  */
386
              return length / 8;
387
            }
388
        }
389
 
390
      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
391
    }
392
 
393
  return 0;
394
}
395
 
396
/* Default value for CGEN_PRINT_INSN.
397
   The result is the size of the insn in bytes or zero for an unknown insn
398
   or -1 if an error occured fetching bytes.  */
399
 
400
#ifndef CGEN_PRINT_INSN
401
#define CGEN_PRINT_INSN default_print_insn
402
#endif
403
 
404
static int
405
default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
406
{
407
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
408
  int buflen;
409
  int status;
410
 
411
  /* Attempt to read the base part of the insn.  */
412
  buflen = cd->base_insn_bitsize / 8;
413
  status = (*info->read_memory_func) (pc, buf, buflen, info);
414
 
415
  /* Try again with the minimum part, if min < base.  */
416
  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
417
    {
418
      buflen = cd->min_insn_bitsize / 8;
419
      status = (*info->read_memory_func) (pc, buf, buflen, info);
420
    }
421
 
422
  if (status != 0)
423
    {
424
      (*info->memory_error_func) (status, pc, info);
425
      return -1;
426
    }
427
 
428
  return print_insn (cd, pc, info, buf, buflen);
429
}
430
 
431
/* Main entry point.
432
   Print one instruction from PC on INFO->STREAM.
433
   Return the size of the instruction (in bytes).  */
434
 
435
typedef struct cpu_desc_list
436
{
437
  struct cpu_desc_list *next;
438
  CGEN_BITSET *isa;
439
  int mach;
440
  int endian;
441
  CGEN_CPU_DESC cd;
442
} cpu_desc_list;
443
 
444
int
445
print_insn_openrisc (bfd_vma pc, disassemble_info *info)
446
{
447
  static cpu_desc_list *cd_list = 0;
448
  cpu_desc_list *cl = 0;
449
  static CGEN_CPU_DESC cd = 0;
450
  static CGEN_BITSET *prev_isa;
451
  static int prev_mach;
452
  static int prev_endian;
453
  int length;
454
  CGEN_BITSET *isa;
455
  int mach;
456
  int endian = (info->endian == BFD_ENDIAN_BIG
457
                ? CGEN_ENDIAN_BIG
458
                : CGEN_ENDIAN_LITTLE);
459
  enum bfd_architecture arch;
460
 
461
  /* ??? gdb will set mach but leave the architecture as "unknown" */
462
#ifndef CGEN_BFD_ARCH
463
#define CGEN_BFD_ARCH bfd_arch_openrisc
464
#endif
465
  arch = info->arch;
466
  if (arch == bfd_arch_unknown)
467
    arch = CGEN_BFD_ARCH;
468
 
469
  /* There's no standard way to compute the machine or isa number
470
     so we leave it to the target.  */
471
#ifdef CGEN_COMPUTE_MACH
472
  mach = CGEN_COMPUTE_MACH (info);
473
#else
474
  mach = info->mach;
475
#endif
476
 
477
#ifdef CGEN_COMPUTE_ISA
478
  {
479
    static CGEN_BITSET *permanent_isa;
480
 
481
    if (!permanent_isa)
482
      permanent_isa = cgen_bitset_create (MAX_ISAS);
483
    isa = permanent_isa;
484
    cgen_bitset_clear (isa);
485
    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
486
  }
487
#else
488
  isa = info->insn_sets;
489
#endif
490
 
491
  /* If we've switched cpu's, try to find a handle we've used before */
492
  if (cd
493
      && (cgen_bitset_compare (isa, prev_isa) != 0
494
          || mach != prev_mach
495
          || endian != prev_endian))
496
    {
497
      cd = 0;
498
      for (cl = cd_list; cl; cl = cl->next)
499
        {
500
          if (cgen_bitset_compare (cl->isa, isa) == 0 &&
501
              cl->mach == mach &&
502
              cl->endian == endian)
503
            {
504
              cd = cl->cd;
505
              prev_isa = cd->isas;
506
              break;
507
            }
508
        }
509
    }
510
 
511
  /* If we haven't initialized yet, initialize the opcode table.  */
512
  if (! cd)
513
    {
514
      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
515
      const char *mach_name;
516
 
517
      if (!arch_type)
518
        abort ();
519
      mach_name = arch_type->printable_name;
520
 
521
      prev_isa = cgen_bitset_copy (isa);
522
      prev_mach = mach;
523
      prev_endian = endian;
524
      cd = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
525
                                 CGEN_CPU_OPEN_BFDMACH, mach_name,
526
                                 CGEN_CPU_OPEN_ENDIAN, prev_endian,
527
                                 CGEN_CPU_OPEN_END);
528
      if (!cd)
529
        abort ();
530
 
531
      /* Save this away for future reference.  */
532
      cl = xmalloc (sizeof (struct cpu_desc_list));
533
      cl->cd = cd;
534
      cl->isa = prev_isa;
535
      cl->mach = mach;
536
      cl->endian = endian;
537
      cl->next = cd_list;
538
      cd_list = cl;
539
 
540
      openrisc_cgen_init_dis (cd);
541
    }
542
 
543
  /* We try to have as much common code as possible.
544
     But at this point some targets need to take over.  */
545
  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
546
     but if not possible try to move this hook elsewhere rather than
547
     have two hooks.  */
548
  length = CGEN_PRINT_INSN (cd, pc, info);
549
  if (length > 0)
550
    return length;
551
  if (length < 0)
552
    return -1;
553
 
554
  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
555
  return cd->default_insn_bitsize / 8;
556
}

powered by: WebSVN 2.1.0

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