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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [opcodes/] [cgen-dis.in] - Blame information for rev 89

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 
31
#include "ansidecl.h"
32
#include "dis-asm.h"
33
#include "bfd.h"
34
#include "symcat.h"
35
#include "libiberty.h"
36
#include "@prefix@-desc.h"
37
#include "@prefix@-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
/* Default print handler.  */
62
 
63
static void
64
print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
65
              void *dis_info,
66
              long value,
67
              unsigned int attrs,
68
              bfd_vma pc ATTRIBUTE_UNUSED,
69
              int length ATTRIBUTE_UNUSED)
70
{
71
  disassemble_info *info = (disassemble_info *) dis_info;
72
 
73
  /* Print the operand as directed by the attributes.  */
74
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
75
    ; /* nothing to do */
76
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
77
    (*info->fprintf_func) (info->stream, "%ld", value);
78
  else
79
    (*info->fprintf_func) (info->stream, "0x%lx", value);
80
}
81
 
82
/* Default address handler.  */
83
 
84
static void
85
print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
86
               void *dis_info,
87
               bfd_vma value,
88
               unsigned int attrs,
89
               bfd_vma pc ATTRIBUTE_UNUSED,
90
               int length ATTRIBUTE_UNUSED)
91
{
92
  disassemble_info *info = (disassemble_info *) dis_info;
93
 
94
  /* Print the operand as directed by the attributes.  */
95
  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
96
    ; /* Nothing to do.  */
97
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
98
    (*info->print_address_func) (value, info);
99
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
100
    (*info->print_address_func) (value, info);
101
  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
102
    (*info->fprintf_func) (info->stream, "%ld", (long) value);
103
  else
104
    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
105
}
106
 
107
/* Keyword print handler.  */
108
 
109
static void
110
print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
111
               void *dis_info,
112
               CGEN_KEYWORD *keyword_table,
113
               long value,
114
               unsigned int attrs ATTRIBUTE_UNUSED)
115
{
116
  disassemble_info *info = (disassemble_info *) dis_info;
117
  const CGEN_KEYWORD_ENTRY *ke;
118
 
119
  ke = cgen_keyword_lookup_value (keyword_table, value);
120
  if (ke != NULL)
121
    (*info->fprintf_func) (info->stream, "%s", ke->name);
122
  else
123
    (*info->fprintf_func) (info->stream, "???");
124
}
125
 
126
/* Default insn printer.
127
 
128
   DIS_INFO is defined as `void *' so the disassembler needn't know anything
129
   about disassemble_info.  */
130
 
131
static void
132
print_insn_normal (CGEN_CPU_DESC cd,
133
                   void *dis_info,
134
                   const CGEN_INSN *insn,
135
                   CGEN_FIELDS *fields,
136
                   bfd_vma pc,
137
                   int length)
138
{
139
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
140
  disassemble_info *info = (disassemble_info *) dis_info;
141
  const CGEN_SYNTAX_CHAR_TYPE *syn;
142
 
143
  CGEN_INIT_PRINT (cd);
144
 
145
  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
146
    {
147
      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
148
        {
149
          (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
150
          continue;
151
        }
152
      if (CGEN_SYNTAX_CHAR_P (*syn))
153
        {
154
          (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
155
          continue;
156
        }
157
 
158
      /* We have an operand.  */
159
      @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
160
                                 fields, CGEN_INSN_ATTRS (insn), pc, length);
161
    }
162
}
163
 
164
/* Subroutine of print_insn. Reads an insn into the given buffers and updates
165
   the extract info.
166
   Returns 0 if all is well, non-zero otherwise.  */
167
 
168
static int
169
read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
170
           bfd_vma pc,
171
           disassemble_info *info,
172
           bfd_byte *buf,
173
           int buflen,
174
           CGEN_EXTRACT_INFO *ex_info,
175
           unsigned long *insn_value)
176
{
177
  int status = (*info->read_memory_func) (pc, buf, buflen, info);
178
 
179
  if (status != 0)
180
    {
181
      (*info->memory_error_func) (status, pc, info);
182
      return -1;
183
    }
184
 
185
  ex_info->dis_info = info;
186
  ex_info->valid = (1 << buflen) - 1;
187
  ex_info->insn_bytes = buf;
188
 
189
  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
190
  return 0;
191
}
192
 
193
/* Utility to print an insn.
194
   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
195
   The result is the size of the insn in bytes or zero for an unknown insn
196
   or -1 if an error occurs fetching data (memory_error_func will have
197
   been called).  */
198
 
199
static int
200
print_insn (CGEN_CPU_DESC cd,
201
            bfd_vma pc,
202
            disassemble_info *info,
203
            bfd_byte *buf,
204
            unsigned int buflen)
205
{
206
  CGEN_INSN_INT insn_value;
207
  const CGEN_INSN_LIST *insn_list;
208
  CGEN_EXTRACT_INFO ex_info;
209
  int basesize;
210
 
211
  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
212
  basesize = cd->base_insn_bitsize < buflen * 8 ?
213
                                     cd->base_insn_bitsize : buflen * 8;
214
  insn_value = cgen_get_insn_value (cd, buf, basesize);
215
 
216
 
217
  /* Fill in ex_info fields like read_insn would.  Don't actually call
218
     read_insn, since the incoming buffer is already read (and possibly
219
     modified a la m32r).  */
220
  ex_info.valid = (1 << buflen) - 1;
221
  ex_info.dis_info = info;
222
  ex_info.insn_bytes = buf;
223
 
224
  /* The instructions are stored in hash lists.
225
     Pick the first one and keep trying until we find the right one.  */
226
 
227
  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
228
  while (insn_list != NULL)
229
    {
230
      const CGEN_INSN *insn = insn_list->insn;
231
      CGEN_FIELDS fields;
232
      int length;
233
      unsigned long insn_value_cropped;
234
 
235
#ifdef CGEN_VALIDATE_INSN_SUPPORTED
236
      /* Not needed as insn shouldn't be in hash lists if not supported.  */
237
      /* Supported by this cpu?  */
238
      if (! @arch@_cgen_insn_supported (cd, insn))
239
        {
240
          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
241
          continue;
242
        }
243
#endif
244
 
245
      /* Basic bit mask must be correct.  */
246
      /* ??? May wish to allow target to defer this check until the extract
247
         handler.  */
248
 
249
      /* Base size may exceed this instruction's size.  Extract the
250
         relevant part from the buffer. */
251
      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
252
          (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
253
        insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
254
                                           info->endian == BFD_ENDIAN_BIG);
255
      else
256
        insn_value_cropped = insn_value;
257
 
258
      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
259
          == CGEN_INSN_BASE_VALUE (insn))
260
        {
261
          /* Printing is handled in two passes.  The first pass parses the
262
             machine insn and extracts the fields.  The second pass prints
263
             them.  */
264
 
265
          /* Make sure the entire insn is loaded into insn_value, if it
266
             can fit.  */
267
          if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
268
              (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
269
            {
270
              unsigned long full_insn_value;
271
              int rc = read_insn (cd, pc, info, buf,
272
                                  CGEN_INSN_BITSIZE (insn) / 8,
273
                                  & ex_info, & full_insn_value);
274
              if (rc != 0)
275
                return rc;
276
              length = CGEN_EXTRACT_FN (cd, insn)
277
                (cd, insn, &ex_info, full_insn_value, &fields, pc);
278
            }
279
          else
280
            length = CGEN_EXTRACT_FN (cd, insn)
281
              (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
282
 
283
          /* Length < 0 -> error.  */
284
          if (length < 0)
285
            return length;
286
          if (length > 0)
287
            {
288
              CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
289
              /* Length is in bits, result is in bytes.  */
290
              return length / 8;
291
            }
292
        }
293
 
294
      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
295
    }
296
 
297
  return 0;
298
}
299
 
300
/* Default value for CGEN_PRINT_INSN.
301
   The result is the size of the insn in bytes or zero for an unknown insn
302
   or -1 if an error occured fetching bytes.  */
303
 
304
#ifndef CGEN_PRINT_INSN
305
#define CGEN_PRINT_INSN default_print_insn
306
#endif
307
 
308
static int
309
default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
310
{
311
  bfd_byte buf[CGEN_MAX_INSN_SIZE];
312
  int buflen;
313
  int status;
314
 
315
  /* Attempt to read the base part of the insn.  */
316
  buflen = cd->base_insn_bitsize / 8;
317
  status = (*info->read_memory_func) (pc, buf, buflen, info);
318
 
319
  /* Try again with the minimum part, if min < base.  */
320
  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
321
    {
322
      buflen = cd->min_insn_bitsize / 8;
323
      status = (*info->read_memory_func) (pc, buf, buflen, info);
324
    }
325
 
326
  if (status != 0)
327
    {
328
      (*info->memory_error_func) (status, pc, info);
329
      return -1;
330
    }
331
 
332
  return print_insn (cd, pc, info, buf, buflen);
333
}
334
 
335
/* Main entry point.
336
   Print one instruction from PC on INFO->STREAM.
337
   Return the size of the instruction (in bytes).  */
338
 
339
typedef struct cpu_desc_list
340
{
341
  struct cpu_desc_list *next;
342
  CGEN_BITSET *isa;
343
  int mach;
344
  int endian;
345
  CGEN_CPU_DESC cd;
346
} cpu_desc_list;
347
 
348
int
349
print_insn_@arch@ (bfd_vma pc, disassemble_info *info)
350
{
351
  static cpu_desc_list *cd_list = 0;
352
  cpu_desc_list *cl = 0;
353
  static CGEN_CPU_DESC cd = 0;
354
  static CGEN_BITSET *prev_isa;
355
  static int prev_mach;
356
  static int prev_endian;
357
  int length;
358
  CGEN_BITSET *isa;
359
  int mach;
360
  int endian = (info->endian == BFD_ENDIAN_BIG
361
                ? CGEN_ENDIAN_BIG
362
                : CGEN_ENDIAN_LITTLE);
363
  enum bfd_architecture arch;
364
 
365
  /* ??? gdb will set mach but leave the architecture as "unknown" */
366
#ifndef CGEN_BFD_ARCH
367
#define CGEN_BFD_ARCH bfd_arch_@arch@
368
#endif
369
  arch = info->arch;
370
  if (arch == bfd_arch_unknown)
371
    arch = CGEN_BFD_ARCH;
372
 
373
  /* There's no standard way to compute the machine or isa number
374
     so we leave it to the target.  */
375
#ifdef CGEN_COMPUTE_MACH
376
  mach = CGEN_COMPUTE_MACH (info);
377
#else
378
  mach = info->mach;
379
#endif
380
 
381
#ifdef CGEN_COMPUTE_ISA
382
  {
383
    static CGEN_BITSET *permanent_isa;
384
 
385
    if (!permanent_isa)
386
      permanent_isa = cgen_bitset_create (MAX_ISAS);
387
    isa = permanent_isa;
388
    cgen_bitset_clear (isa);
389
    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
390
  }
391
#else
392
  isa = info->insn_sets;
393
#endif
394
 
395
  /* If we've switched cpu's, try to find a handle we've used before */
396
  if (cd
397
      && (cgen_bitset_compare (isa, prev_isa) != 0
398
          || mach != prev_mach
399
          || endian != prev_endian))
400
    {
401
      cd = 0;
402
      for (cl = cd_list; cl; cl = cl->next)
403
        {
404
          if (cgen_bitset_compare (cl->isa, isa) == 0 &&
405
              cl->mach == mach &&
406
              cl->endian == endian)
407
            {
408
              cd = cl->cd;
409
              prev_isa = cd->isas;
410
              break;
411
            }
412
        }
413
    }
414
 
415
  /* If we haven't initialized yet, initialize the opcode table.  */
416
  if (! cd)
417
    {
418
      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
419
      const char *mach_name;
420
 
421
      if (!arch_type)
422
        abort ();
423
      mach_name = arch_type->printable_name;
424
 
425
      prev_isa = cgen_bitset_copy (isa);
426
      prev_mach = mach;
427
      prev_endian = endian;
428
      cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
429
                                 CGEN_CPU_OPEN_BFDMACH, mach_name,
430
                                 CGEN_CPU_OPEN_ENDIAN, prev_endian,
431
                                 CGEN_CPU_OPEN_END);
432
      if (!cd)
433
        abort ();
434
 
435
      /* Save this away for future reference.  */
436
      cl = xmalloc (sizeof (struct cpu_desc_list));
437
      cl->cd = cd;
438
      cl->isa = prev_isa;
439
      cl->mach = mach;
440
      cl->endian = endian;
441
      cl->next = cd_list;
442
      cd_list = cl;
443
 
444
      @arch@_cgen_init_dis (cd);
445
    }
446
 
447
  /* We try to have as much common code as possible.
448
     But at this point some targets need to take over.  */
449
  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
450
     but if not possible try to move this hook elsewhere rather than
451
     have two hooks.  */
452
  length = CGEN_PRINT_INSN (cd, pc, info);
453
  if (length > 0)
454
    return length;
455
  if (length < 0)
456
    return -1;
457
 
458
  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
459
  return cd->default_insn_bitsize / 8;
460
}

powered by: WebSVN 2.1.0

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