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

Subversion Repositories open8_urisc

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

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

powered by: WebSVN 2.1.0

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