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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [opcodes/] [openrisc-dis.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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