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

Subversion Repositories open8_urisc

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

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

Line No. Rev Author Line
1 18 khays
/* mmix-dis.c -- Disassemble MMIX instructions.
2
   Copyright 2000, 2001, 2002, 2005, 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
  long 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
 
102
          if (syms == NULL)
103
            {
104
              FATAL_DEBUG;
105
              free (minfop);
106
              return FALSE;
107
            }
108
          nsyms = bfd_canonicalize_symtab (abfd, syms);
109
 
110
          /* We use the first name for a register.  If this is MMO, then
111
             it's the name with the first sequence number, presumably the
112
             first in the source.  */
113
          for (i = 0; i < nsyms && syms[i] != NULL; i++)
114
            {
115
              if (syms[i]->section == reg_section
116
                  && syms[i]->value < 256
117
                  && minfop->reg_name[syms[i]->value] == NULL)
118
                minfop->reg_name[syms[i]->value] = syms[i]->name;
119
            }
120
        }
121
    }
122
 
123
  /* Fill in the rest with the canonical names.  */
124
  for (i = 0; i < 256; i++)
125
    if (minfop->reg_name[i] == NULL)
126
      {
127
        sprintf (minfop->basic_reg_name[i], "$%ld", i);
128
        minfop->reg_name[i] = minfop->basic_reg_name[i];
129
      }
130
 
131
  /* We assume it's actually a one-to-one mapping of number-to-name.  */
132
  for (i = 0; mmix_spec_regs[i].name != NULL; i++)
133
    minfop->spec_reg_name[mmix_spec_regs[i].number] = mmix_spec_regs[i].name;
134
 
135
  info->private_data = (void *) minfop;
136
  return TRUE;
137
}
138
 
139
/* A table indexed by the first byte is constructed as we disassemble each
140
   tetrabyte.  The contents is a pointer into mmix_insns reflecting the
141
   first found entry with matching match-bits and lose-bits.  Further
142
   entries are considered one after one until the operand constraints
143
   match or the match-bits and lose-bits do not match.  Normally a
144
   "further entry" will just show that there was no other match.  */
145
 
146
static const struct mmix_opcode *
147
get_opcode (unsigned long insn)
148
{
149
  static const struct mmix_opcode **opcodes = NULL;
150
  const struct mmix_opcode *opcodep = mmix_opcodes;
151
  unsigned int opcode_part = (insn >> 24) & 255;
152
 
153
  if (opcodes == NULL)
154
    opcodes = xcalloc (256, sizeof (struct mmix_opcode *));
155
 
156
  opcodep = opcodes[opcode_part];
157
  if (opcodep == NULL
158
      || (opcodep->match & insn) != opcodep->match
159
      || (opcodep->lose & insn) != 0)
160
    {
161
      /* Search through the table.  */
162
      for (opcodep = mmix_opcodes; opcodep->name != NULL; opcodep++)
163
        {
164
          /* FIXME: Break out this into an initialization function.  */
165
          if ((opcodep->match & (opcode_part << 24)) == opcode_part
166
              && (opcodep->lose & (opcode_part << 24)) == 0)
167
            opcodes[opcode_part] = opcodep;
168
 
169
          if ((opcodep->match & insn) == opcodep->match
170
              && (opcodep->lose & insn) == 0)
171
            break;
172
        }
173
    }
174
 
175
  if (opcodep->name == NULL)
176
    return NULL;
177
 
178
  /* Check constraints.  If they don't match, loop through the next opcode
179
     entries.  */
180
  do
181
    {
182
      switch (opcodep->operands)
183
        {
184
          /* These have no restraint on what can be in the lower three
185
             bytes.  */
186
        case mmix_operands_regs:
187
        case mmix_operands_reg_yz:
188
        case mmix_operands_regs_z_opt:
189
        case mmix_operands_regs_z:
190
        case mmix_operands_jmp:
191
        case mmix_operands_pushgo:
192
        case mmix_operands_pop:
193
        case mmix_operands_sync:
194
        case mmix_operands_x_regs_z:
195
        case mmix_operands_neg:
196
        case mmix_operands_pushj:
197
        case mmix_operands_regaddr:
198
        case mmix_operands_get:
199
        case mmix_operands_set:
200
        case mmix_operands_save:
201
        case mmix_operands_unsave:
202
        case mmix_operands_xyz_opt:
203
          return opcodep;
204
 
205
          /* For a ROUND_MODE, the middle byte must be 0..4.  */
206
        case mmix_operands_roundregs_z:
207
        case mmix_operands_roundregs:
208
          {
209
            int midbyte = (insn >> 8) & 255;
210
 
211
            if (midbyte <= 4)
212
              return opcodep;
213
          }
214
        break;
215
 
216
        case mmix_operands_put:
217
          /* A "PUT".  If it is "immediate", then no restrictions,
218
             otherwise we have to make sure the register number is < 32.  */
219
          if ((insn & INSN_IMMEDIATE_BIT)
220
              || ((insn >> 16) & 255) < 32)
221
            return opcodep;
222
          break;
223
 
224
        case mmix_operands_resume:
225
          /* Middle bytes must be zero.  */
226
          if ((insn & 0x00ffff00) == 0)
227
            return opcodep;
228
          break;
229
 
230
        default:
231
          BAD_CASE (opcodep->operands);
232
        }
233
 
234
      opcodep++;
235
    }
236
  while ((opcodep->match & insn) == opcodep->match
237
         && (opcodep->lose & insn) == 0);
238
 
239
  /* If we got here, we had no match.  */
240
  return NULL;
241
}
242
 
243
/* The main disassembly function.  */
244
 
245
int
246
print_insn_mmix (bfd_vma memaddr, struct disassemble_info *info)
247
{
248
  unsigned char buffer[4];
249
  unsigned long insn;
250
  unsigned int x, y, z;
251
  const struct mmix_opcode *opcodep;
252
  int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
253
  struct mmix_dis_info *minfop;
254
 
255
  if (status != 0)
256
    {
257
      (*info->memory_error_func) (status, memaddr, info);
258
      return -1;
259
    }
260
 
261
  /* FIXME: Is -1 suitable?  */
262
  if (info->private_data == NULL
263
      && ! initialize_mmix_dis_info (info))
264
    return -1;
265
 
266
  minfop = (struct mmix_dis_info *) info->private_data;
267
  x = buffer[1];
268
  y = buffer[2];
269
  z = buffer[3];
270
 
271
  insn = bfd_getb32 (buffer);
272
 
273
  opcodep = get_opcode (insn);
274
 
275
  if (opcodep == NULL)
276
    {
277
      (*info->fprintf_func) (info->stream, _("*unknown*"));
278
      return 4;
279
    }
280
 
281
  (*info->fprintf_func) (info->stream, "%s ", opcodep->name);
282
 
283
  /* Present bytes in the order they are laid out in memory.  */
284
  info->display_endian = BFD_ENDIAN_BIG;
285
 
286
  info->insn_info_valid = 1;
287
  info->bytes_per_chunk = 4;
288
  info->branch_delay_insns = 0;
289
  info->target = 0;
290
  switch (opcodep->type)
291
    {
292
    case mmix_type_normal:
293
    case mmix_type_memaccess_block:
294
      info->insn_type = dis_nonbranch;
295
      break;
296
 
297
    case mmix_type_branch:
298
      info->insn_type = dis_branch;
299
      break;
300
 
301
    case mmix_type_condbranch:
302
      info->insn_type = dis_condbranch;
303
      break;
304
 
305
    case mmix_type_memaccess_octa:
306
      info->insn_type = dis_dref;
307
      info->data_size = 8;
308
      break;
309
 
310
    case mmix_type_memaccess_tetra:
311
      info->insn_type = dis_dref;
312
      info->data_size = 4;
313
      break;
314
 
315
    case mmix_type_memaccess_wyde:
316
      info->insn_type = dis_dref;
317
      info->data_size = 2;
318
      break;
319
 
320
    case mmix_type_memaccess_byte:
321
      info->insn_type = dis_dref;
322
      info->data_size = 1;
323
      break;
324
 
325
    case mmix_type_jsr:
326
      info->insn_type = dis_jsr;
327
      break;
328
 
329
    default:
330
      BAD_CASE(opcodep->type);
331
    }
332
 
333
  switch (opcodep->operands)
334
    {
335
    case mmix_operands_regs:
336
      /*  All registers: "$X,$Y,$Z".  */
337
      (*info->fprintf_func) (info->stream, "%s,%s,%s",
338
                             minfop->reg_name[x],
339
                             minfop->reg_name[y],
340
                             minfop->reg_name[z]);
341
      break;
342
 
343
    case mmix_operands_reg_yz:
344
      /* Like SETH - "$X,YZ".  */
345
      (*info->fprintf_func) (info->stream, "%s,0x%x",
346
                             minfop->reg_name[x], y * 256 + z);
347
      break;
348
 
349
    case mmix_operands_regs_z_opt:
350
    case mmix_operands_regs_z:
351
    case mmix_operands_pushgo:
352
      /* The regular "$X,$Y,$Z|Z".  */
353
      if (insn & INSN_IMMEDIATE_BIT)
354
        (*info->fprintf_func) (info->stream, "%s,%s,%d",
355
                               minfop->reg_name[x], minfop->reg_name[y], z);
356
      else
357
        (*info->fprintf_func) (info->stream, "%s,%s,%s",
358
                               minfop->reg_name[x],
359
                               minfop->reg_name[y],
360
                               minfop->reg_name[z]);
361
      break;
362
 
363
    case mmix_operands_jmp:
364
      /* Address; only JMP.  */
365
      {
366
        bfd_signed_vma offset = (x * 65536 + y * 256 + z) * 4;
367
 
368
        if (insn & INSN_BACKWARD_OFFSET_BIT)
369
          offset -= (256 * 65536) * 4;
370
 
371
        info->target = memaddr + offset;
372
        (*info->print_address_func) (memaddr + offset, info);
373
      }
374
      break;
375
 
376
    case mmix_operands_roundregs_z:
377
      /* Two registers, like FLOT, possibly with rounding: "$X,$Z|Z"
378
         "$X,ROUND_MODE,$Z|Z".  */
379
      if (y != 0)
380
        {
381
          if (insn & INSN_IMMEDIATE_BIT)
382
            (*info->fprintf_func) (info->stream, "%s,%s,%d",
383
                                   minfop->reg_name[x],
384
                                   ROUND_MODE (y), z);
385
          else
386
            (*info->fprintf_func) (info->stream, "%s,%s,%s",
387
                                   minfop->reg_name[x],
388
                                   ROUND_MODE (y),
389
                                   minfop->reg_name[z]);
390
        }
391
      else
392
        {
393
          if (insn & INSN_IMMEDIATE_BIT)
394
            (*info->fprintf_func) (info->stream, "%s,%d",
395
                                   minfop->reg_name[x], z);
396
          else
397
            (*info->fprintf_func) (info->stream, "%s,%s",
398
                                   minfop->reg_name[x],
399
                                   minfop->reg_name[z]);
400
        }
401
      break;
402
 
403
    case mmix_operands_pop:
404
      /* Like POP - "X,YZ".  */
405
      (*info->fprintf_func) (info->stream, "%d,%d", x, y*256 + z);
406
      break;
407
 
408
    case mmix_operands_roundregs:
409
      /* Two registers, possibly with rounding: "$X,$Z" or
410
         "$X,ROUND_MODE,$Z".  */
411
      if (y != 0)
412
        (*info->fprintf_func) (info->stream, "%s,%s,%s",
413
                               minfop->reg_name[x],
414
                               ROUND_MODE (y),
415
                               minfop->reg_name[z]);
416
      else
417
        (*info->fprintf_func) (info->stream, "%s,%s",
418
                               minfop->reg_name[x],
419
                               minfop->reg_name[z]);
420
      break;
421
 
422
    case mmix_operands_sync:
423
        /* Like SYNC - "XYZ".  */
424
      (*info->fprintf_func) (info->stream, "%u",
425
                             x * 65536 + y * 256 + z);
426
      break;
427
 
428
    case mmix_operands_x_regs_z:
429
      /* Like SYNCD - "X,$Y,$Z|Z".  */
430
      if (insn & INSN_IMMEDIATE_BIT)
431
        (*info->fprintf_func) (info->stream, "%d,%s,%d",
432
                               x, minfop->reg_name[y], z);
433
      else
434
        (*info->fprintf_func) (info->stream, "%d,%s,%s",
435
                               x, minfop->reg_name[y],
436
                               minfop->reg_name[z]);
437
      break;
438
 
439
    case mmix_operands_neg:
440
      /* Like NEG and NEGU - "$X,Y,$Z|Z".  */
441
      if (insn & INSN_IMMEDIATE_BIT)
442
        (*info->fprintf_func) (info->stream, "%s,%d,%d",
443
                               minfop->reg_name[x], y, z);
444
      else
445
        (*info->fprintf_func) (info->stream, "%s,%d,%s",
446
                               minfop->reg_name[x], y,
447
                               minfop->reg_name[z]);
448
      break;
449
 
450
    case mmix_operands_pushj:
451
    case mmix_operands_regaddr:
452
      /* Like GETA or branches - "$X,Address".  */
453
      {
454
        bfd_signed_vma offset = (y * 256 + z) * 4;
455
 
456
        if (insn & INSN_BACKWARD_OFFSET_BIT)
457
          offset -= 65536 * 4;
458
 
459
        info->target = memaddr + offset;
460
 
461
        (*info->fprintf_func) (info->stream, "%s,", minfop->reg_name[x]);
462
        (*info->print_address_func) (memaddr + offset, info);
463
      }
464
      break;
465
 
466
    case mmix_operands_get:
467
      /* GET - "X,spec_reg".  */
468
      (*info->fprintf_func) (info->stream, "%s,%s",
469
                             minfop->reg_name[x],
470
                             minfop->spec_reg_name[z]);
471
      break;
472
 
473
    case mmix_operands_put:
474
      /* PUT - "spec_reg,$Z|Z".  */
475
      if (insn & INSN_IMMEDIATE_BIT)
476
        (*info->fprintf_func) (info->stream, "%s,%d",
477
                               minfop->spec_reg_name[x], z);
478
      else
479
        (*info->fprintf_func) (info->stream, "%s,%s",
480
                               minfop->spec_reg_name[x],
481
                               minfop->reg_name[z]);
482
      break;
483
 
484
    case mmix_operands_set:
485
      /*  Two registers, "$X,$Y".  */
486
      (*info->fprintf_func) (info->stream, "%s,%s",
487
                             minfop->reg_name[x],
488
                             minfop->reg_name[y]);
489
      break;
490
 
491
    case mmix_operands_save:
492
      /* SAVE - "$X,0".  */
493
      (*info->fprintf_func) (info->stream, "%s,0", minfop->reg_name[x]);
494
      break;
495
 
496
    case mmix_operands_unsave:
497
      /* UNSAVE - "0,$Z".  */
498
      (*info->fprintf_func) (info->stream, "0,%s", minfop->reg_name[z]);
499
      break;
500
 
501
    case mmix_operands_xyz_opt:
502
      /* Like SWYM or TRAP - "X,Y,Z".  */
503
      (*info->fprintf_func) (info->stream, "%d,%d,%d", x, y, z);
504
      break;
505
 
506
    case mmix_operands_resume:
507
      /* Just "Z", like RESUME.  */
508
      (*info->fprintf_func) (info->stream, "%d", z);
509
      break;
510
 
511
    default:
512
      (*info->fprintf_func) (info->stream, _("*unknown operands type: %d*"),
513
                             opcodep->operands);
514
      break;
515
    }
516
 
517
  return 4;
518
}

powered by: WebSVN 2.1.0

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