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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [opcodes/] [mmix-dis.c] - Blame information for rev 1777

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

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

powered by: WebSVN 2.1.0

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