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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [opcodes/] [mmix-dis.c] - Blame information for rev 853

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

Line No. Rev Author Line
1 38 julius
/* mmix-dis.c -- Disassemble MMIX instructions.
2
   Copyright 2000, 2001, 2002, 2007 Free Software Foundation, Inc.
3
   Written by Hans-Peter Nilsson (hp@bitrange.com)
4
 
5
   This file is part of the GNU opcodes library.
6
 
7
   This library is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3, or (at your option)
10
   any later version.
11
 
12
   It is distributed in the hope that it will be useful, but WITHOUT
13
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15
   License for more details.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with this file; see the file COPYING.  If not, write to the Free
19
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
 
22
#include <stdio.h>
23
#include <string.h>
24
#include <stdlib.h>
25
#include "opcode/mmix.h"
26
#include "dis-asm.h"
27
#include "libiberty.h"
28
#include "bfd.h"
29
#include "opintl.h"
30
 
31
#define BAD_CASE(x)                             \
32
 do                                             \
33
   {                                            \
34
     fprintf (stderr,                           \
35
              _("Bad case %d (%s) in %s:%d\n"), \
36
              x, #x, __FILE__, __LINE__);       \
37
     abort ();                                  \
38
   }                                            \
39
 while (0)
40
 
41
#define FATAL_DEBUG                                                     \
42
 do                                                                     \
43
   {                                                                    \
44
     fprintf (stderr,                                                   \
45
              _("Internal: Non-debugged code (test-case missing): %s:%d"),\
46
              __FILE__, __LINE__);                                      \
47
     abort ();                                                          \
48
   }                                                                    \
49
 while (0)
50
 
51
#define ROUND_MODE(n)                                   \
52
 ((n) == 1 ? "ROUND_OFF" : (n) == 2 ? "ROUND_UP" :      \
53
  (n) == 3 ? "ROUND_DOWN" : (n) == 4 ? "ROUND_NEAR" :   \
54
  _("(unknown)"))
55
 
56
#define INSN_IMMEDIATE_BIT (IMM_OFFSET_BIT << 24)
57
#define INSN_BACKWARD_OFFSET_BIT (1 << 24)
58
 
59
struct mmix_dis_info
60
 {
61
   const char *reg_name[256];
62
   const char *spec_reg_name[32];
63
 
64
   /* Waste a little memory so we don't have to allocate each separately.
65
      We could have an array with static contents for these, but on the
66
      other hand, we don't have to.  */
67
   char basic_reg_name[256][sizeof ("$255")];
68
 };
69
 
70
/* Initialize a target-specific array in INFO.  */
71
 
72
static bfd_boolean
73
initialize_mmix_dis_info (struct disassemble_info *info)
74
{
75
  struct mmix_dis_info *minfop = malloc (sizeof (struct mmix_dis_info));
76
  int i;
77
 
78
  if (minfop == NULL)
79
    return FALSE;
80
 
81
  memset (minfop, 0, sizeof (*minfop));
82
 
83
  /* Initialize register names from register symbols.  If there's no
84
     register section, then there are no register symbols.  */
85
  if ((info->section != NULL && info->section->owner != NULL)
86
      || (info->symbols != NULL
87
          && info->symbols[0] != NULL
88
          && bfd_asymbol_bfd (info->symbols[0]) != NULL))
89
    {
90
      bfd *abfd = info->section && info->section->owner != NULL
91
        ? info->section->owner
92
        : bfd_asymbol_bfd (info->symbols[0]);
93
      asection *reg_section = bfd_get_section_by_name (abfd, "*REG*");
94
 
95
      if (reg_section != NULL)
96
        {
97
          /* The returned symcount *does* include the ending NULL.  */
98
          long symsize = bfd_get_symtab_upper_bound (abfd);
99
          asymbol **syms = malloc (symsize);
100
          long nsyms;
101
          long i;
102
 
103
          if (syms == NULL)
104
            {
105
              FATAL_DEBUG;
106
              free (minfop);
107
              return FALSE;
108
            }
109
          nsyms = bfd_canonicalize_symtab (abfd, syms);
110
 
111
          /* We use the first name for a register.  If this is MMO, then
112
             it's the name with the first sequence number, presumably the
113
             first in the source.  */
114
          for (i = 0; i < nsyms && syms[i] != NULL; i++)
115
            {
116
              if (syms[i]->section == reg_section
117
                  && syms[i]->value < 256
118
                  && minfop->reg_name[syms[i]->value] == NULL)
119
                minfop->reg_name[syms[i]->value] = syms[i]->name;
120
            }
121
        }
122
    }
123
 
124
  /* Fill in the rest with the canonical names.  */
125
  for (i = 0; i < 256; i++)
126
    if (minfop->reg_name[i] == NULL)
127
      {
128
        sprintf (minfop->basic_reg_name[i], "$%d", i);
129
        minfop->reg_name[i] = minfop->basic_reg_name[i];
130
      }
131
 
132
  /* We assume it's actually a one-to-one mapping of number-to-name.  */
133
  for (i = 0; mmix_spec_regs[i].name != NULL; i++)
134
    minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
135
 
136
  info->private_data = (void *) minfop;
137
  return TRUE;
138
}
139
 
140
/* A table indexed by the first byte is constructed as we disassemble each
141
   tetrabyte.  The contents is a pointer into mmix_insns reflecting the
142
   first found entry with matching match-bits and lose-bits.  Further
143
   entries are considered one after one until the operand constraints
144
   match or the match-bits and lose-bits do not match.  Normally a
145
   "further entry" will just show that there was no other match.  */
146
 
147
static const struct mmix_opcode *
148
get_opcode (unsigned long insn)
149
{
150
  static const struct mmix_opcode **opcodes = NULL;
151
  const struct mmix_opcode *opcodep = mmix_opcodes;
152
  unsigned int opcode_part = (insn >> 24) & 255;
153
 
154
  if (opcodes == NULL)
155
    opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
156
 
157
  opcodep = opcodes[opcode_part];
158
  if (opcodep == NULL
159
      || (opcodep->match & insn) != opcodep->match
160
      || (opcodep->lose & insn) != 0)
161
    {
162
      /* Search through the table.  */
163
      for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
164
        {
165
          /* FIXME: Break out this into an initialization function.  */
166
          if ((opcodep->match & (opcode_part << 24)) == opcode_part
167
              && (opcodep->lose & (opcode_part << 24)) == 0)
168
            opcodes[opcode_part] = opcodep;
169
 
170
          if ((opcodep->match & insn) == opcodep->match
171
              && (opcodep->lose & insn) == 0)
172
            break;
173
        }
174
    }
175
 
176
  if (opcodep->name == NULL)
177
    return NULL;
178
 
179
  /* Check constraints.  If they don't match, loop through the next opcode
180
     entries.  */
181
  do
182
    {
183
      switch (opcodep->operands)
184
        {
185
          /* These have no restraint on what can be in the lower three
186
             bytes.  */
187
        case mmix_operands_regs:
188
        case mmix_operands_reg_yz:
189
        case mmix_operands_regs_z_opt:
190
        case mmix_operands_regs_z:
191
        case mmix_operands_jmp:
192
        case mmix_operands_pushgo:
193
        case mmix_operands_pop:
194
        case mmix_operands_sync:
195
        case mmix_operands_x_regs_z:
196
        case mmix_operands_neg:
197
        case mmix_operands_pushj:
198
        case mmix_operands_regaddr:
199
        case mmix_operands_get:
200
        case mmix_operands_set:
201
        case mmix_operands_save:
202
        case mmix_operands_unsave:
203
        case mmix_operands_xyz_opt:
204
          return opcodep;
205
 
206
          /* For a ROUND_MODE, the middle byte must be 0..4.  */
207
        case mmix_operands_roundregs_z:
208
        case mmix_operands_roundregs:
209
          {
210
            int midbyte = (insn >> 8) & 255;
211
 
212
            if (midbyte <= 4)
213
              return opcodep;
214
          }
215
        break;
216
 
217
        case mmix_operands_put:
218
          /* A "PUT".  If it is "immediate", then no restrictions,
219
             otherwise we have to make sure the register number is < 32.  */
220
          if ((insn & INSN_IMMEDIATE_BIT)
221
              || ((insn >> 16) & 255) < 32)
222
            return opcodep;
223
          break;
224
 
225
        case mmix_operands_resume:
226
          /* Middle bytes must be zero.  */
227
          if ((insn & 0x00ffff00) == 0)
228
            return opcodep;
229
          break;
230
 
231
        default:
232
          BAD_CASE (opcodep->operands);
233
        }
234
 
235
      opcodep++;
236
    }
237
  while ((opcodep->match & insn) == opcodep->match
238
         && (opcodep->lose & insn) == 0);
239
 
240
  /* If we got here, we had no match.  */
241
  return NULL;
242
}
243
 
244
/* The main disassembly function.  */
245
 
246
int
247
print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
248
{
249
  unsigned char buffer[4];
250
  unsigned long insn;
251
  unsigned int x, y, z;
252
  const struct mmix_opcode *opcodep;
253
  int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
254
  struct mmix_dis_info *minfop;
255
 
256
  if (status != 0)
257
    {
258
      (*info->memory_error_func) (status, memaddr, info);
259
      return -1;
260
    }
261
 
262
  /* FIXME: Is -1 suitable?  */
263
  if (info->private_data == NULL
264
      && ! initialize_mmix_dis_info (info))
265
    return -1;
266
 
267
  minfop = (struct mmix_dis_info *) info->private_data;
268
  x = buffer[1];
269
  y = buffer[2];
270
  z = buffer[3];
271
 
272
  insn = bfd_getb32 (buffer);
273
 
274
  opcodep = get_opcode (insn);
275
 
276
  if (opcodep == NULL)
277
    {
278
      (*info->fprintf_func) (info->stream, _("*unknown*"));
279
      return 4;
280
    }
281
 
282
  (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
283
 
284
  /* Present bytes in the order they are laid out in memory.  */
285
  info->display_endian = BFD_ENDIAN_BIG;
286
 
287
  info->insn_info_valid = 1;
288
  info->bytes_per_chunk = 4;
289
  info->branch_delay_insns = 0;
290
  info->target = 0;
291
  switch (opcodep->type)
292
    {
293
    case mmix_type_normal:
294
    case mmix_type_memaccess_block:
295
      info->insn_type = dis_nonbranch;
296
      break;
297
 
298
    case mmix_type_branch:
299
      info->insn_type = dis_branch;
300
      break;
301
 
302
    case mmix_type_condbranch:
303
      info->insn_type = dis_condbranch;
304
      break;
305
 
306
    case mmix_type_memaccess_octa:
307
      info->insn_type = dis_dref;
308
      info->data_size = 8;
309
      break;
310
 
311
    case mmix_type_memaccess_tetra:
312
      info->insn_type = dis_dref;
313
      info->data_size = 4;
314
      break;
315
 
316
    case mmix_type_memaccess_wyde:
317
      info->insn_type = dis_dref;
318
      info->data_size = 2;
319
      break;
320
 
321
    case mmix_type_memaccess_byte:
322
      info->insn_type = dis_dref;
323
      info->data_size = 1;
324
      break;
325
 
326
    case mmix_type_jsr:
327
      info->insn_type = dis_jsr;
328
      break;
329
 
330
    default:
331
      BAD_CASE(opcodep->type);
332
    }
333
 
334
  switch (opcodep->operands)
335
    {
336
    case mmix_operands_regs:
337
      /*  All registers: "$X,$Y,$Z".  */
338
      (*info->fprintf_func) (info->stream, "%s,%s,%s",
339
                             minfop->reg_name[x],
340
                             minfop->reg_name[y],
341
                             minfop->reg_name[z]);
342
      break;
343
 
344
    case mmix_operands_reg_yz:
345
      /* Like SETH - "$X,YZ".  */
346
      (*info->fprintf_func) (info->stream, "%s,0x%x",
347
                             minfop->reg_name[x], y * 256 + z);
348
      break;
349
 
350
    case mmix_operands_regs_z_opt:
351
    case mmix_operands_regs_z:
352
    case mmix_operands_pushgo:
353
      /* The regular "$X,$Y,$Z|Z".  */
354
      if (insn & INSN_IMMEDIATE_BIT)
355
        (*info->fprintf_func) (info->stream, "%s,%s,%d",
356
                               minfop->reg_name[x], minfop->reg_name[y], z);
357
      else
358
        (*info->fprintf_func) (info->stream, "%s,%s,%s",
359
                               minfop->reg_name[x],
360
                               minfop->reg_name[y],
361
                               minfop->reg_name[z]);
362
      break;
363
 
364
    case mmix_operands_jmp:
365
      /* Address; only JMP.  */
366
      {
367
        bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
368
 
369
        if (insn & INSN_BACKWARD_OFFSET_BIT)
370
          offset -= (256 * 65536) * 4;
371
 
372
        info->target = memaddr + offset;
373
        (*info->print_address_func) (memaddr + offset, info);
374
      }
375
      break;
376
 
377
    case mmix_operands_roundregs_z:
378
      /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
379
         "$X,ROUND_MODE,$Z|Z".  */
380
      if (y != 0)
381
        {
382
          if (insn & INSN_IMMEDIATE_BIT)
383
            (*info->fprintf_func) (info->stream, "%s,%s,%d",
384
                                   minfop->reg_name[x],
385
                                   ROUND_MODE (y), z);
386
          else
387
            (*info->fprintf_func) (info->stream, "%s,%s,%s",
388
                                   minfop->reg_name[x],
389
                                   ROUND_MODE (y),
390
                                   minfop->reg_name[z]);
391
        }
392
      else
393
        {
394
          if (insn & INSN_IMMEDIATE_BIT)
395
            (*info->fprintf_func) (info->stream, "%s,%d",
396
                                   minfop->reg_name[x], z);
397
          else
398
            (*info->fprintf_func) (info->stream, "%s,%s",
399
                                   minfop->reg_name[x],
400
                                   minfop->reg_name[z]);
401
        }
402
      break;
403
 
404
    case mmix_operands_pop:
405
      /* Like POP - "X,YZ".  */
406
      (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
407
      break;
408
 
409
    case mmix_operands_roundregs:
410
      /* Two registers, possibly with rounding: "$X,$Z" or
411
         "$X,ROUND_MODE,$Z".  */
412
      if (y != 0)
413
        (*info->fprintf_func) (info->stream, "%s,%s,%s",
414
                               minfop->reg_name[x],
415
                               ROUND_MODE (y),
416
                               minfop->reg_name[z]);
417
      else
418
        (*info->fprintf_func) (info->stream, "%s,%s",
419
                               minfop->reg_name[x],
420
                               minfop->reg_name[z]);
421
      break;
422
 
423
    case mmix_operands_sync:
424
        /* Like SYNC - "XYZ".  */
425
      (*info->fprintf_func) (info->stream, "%u",
426
                             x * 65536 + y * 256 + z);
427
      break;
428
 
429
    case mmix_operands_x_regs_z:
430
      /* Like SYNCD - "X,$Y,$Z|Z".  */
431
      if (insn & INSN_IMMEDIATE_BIT)
432
        (*info->fprintf_func) (info->stream, "%d,%s,%d",
433
                               x, minfop->reg_name[y], z);
434
      else
435
        (*info->fprintf_func) (info->stream, "%d,%s,%s",
436
                               x, minfop->reg_name[y],
437
                               minfop->reg_name[z]);
438
      break;
439
 
440
    case mmix_operands_neg:
441
      /* Like NEG and NEGU - "$X,Y,$Z|Z".  */
442
      if (insn & INSN_IMMEDIATE_BIT)
443
        (*info->fprintf_func) (info->stream, "%s,%d,%d",
444
                               minfop->reg_name[x], y, z);
445
      else
446
        (*info->fprintf_func) (info->stream, "%s,%d,%s",
447
                               minfop->reg_name[x], y,
448
                               minfop->reg_name[z]);
449
      break;
450
 
451
    case mmix_operands_pushj:
452
    case mmix_operands_regaddr:
453
      /* Like GETA or branches - "$X,Address".  */
454
      {
455
        bfd_signed_vma offset = (y * 256 + z) * 4;
456
 
457
        if (insn & INSN_BACKWARD_OFFSET_BIT)
458
          offset -= 65536 * 4;
459
 
460
        info->target = memaddr + offset;
461
 
462
        (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
463
        (*info->print_address_func) (memaddr + offset, info);
464
      }
465
      break;
466
 
467
    case mmix_operands_get:
468
      /* GET - "X,spec_reg".  */
469
      (*info->fprintf_func) (info->stream, "%s,%s",
470
                             minfop->reg_name[x],
471
                             minfop->spec_reg_name[z]);
472
      break;
473
 
474
    case mmix_operands_put:
475
      /* PUT - "spec_reg,$Z|Z".  */
476
      if (insn & INSN_IMMEDIATE_BIT)
477
        (*info->fprintf_func) (info->stream, "%s,%d",
478
                               minfop->spec_reg_name[x], z);
479
      else
480
        (*info->fprintf_func) (info->stream, "%s,%s",
481
                               minfop->spec_reg_name[x],
482
                               minfop->reg_name[z]);
483
      break;
484
 
485
    case mmix_operands_set:
486
      /*  Two registers, "$X,$Y".  */
487
      (*info->fprintf_func) (info->stream, "%s,%s",
488
                             minfop->reg_name[x],
489
                             minfop->reg_name[y]);
490
      break;
491
 
492
    case mmix_operands_save:
493
      /* SAVE - "$X,0".  */
494
      (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
495
      break;
496
 
497
    case mmix_operands_unsave:
498
      /* UNSAVE - "0,$Z".  */
499
      (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
500
      break;
501
 
502
    case mmix_operands_xyz_opt:
503
      /* Like SWYM or TRAP - "X,Y,Z".  */
504
      (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
505
      break;
506
 
507
    case mmix_operands_resume:
508
      /* Just "Z", like RESUME.  */
509
      (*info->fprintf_func) (info->stream, "%d", z);
510
      break;
511
 
512
    default:
513
      (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
514
                             opcodep->operands);
515
      break;
516
    }
517
 
518
  return 4;
519
}

powered by: WebSVN 2.1.0

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