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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [opcodes/] [lm32-dis.c] - Blame information for rev 205

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

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

powered by: WebSVN 2.1.0

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