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

Subversion Repositories open8_urisc

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

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

Line No. Rev Author Line
1 18 khays
/* Disassemble SH64 instructions.
2
   Copyright 2000, 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
3
 
4
   This file is part of the GNU opcodes library.
5
 
6
   This library is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3, or (at your option)
9
   any later version.
10
 
11
   It is distributed in the hope that it will be useful, but WITHOUT
12
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14
   License for more details.
15
 
16
   You should have received a copy of the GNU General Public License
17
   along with this file; see the file COPYING.  If not, write to the
18
   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
19
   MA 02110-1301, USA.  */
20
 
21
#include <stdio.h>
22
 
23
#include "dis-asm.h"
24
#include "sysdep.h"
25
#include "sh64-opc.h"
26
#include "libiberty.h"
27
/* We need to refer to the ELF header structure.  */
28
#include "elf-bfd.h"
29
#include "elf/sh.h"
30
#include "elf32-sh64.h"
31
 
32
#define ELF_MODE32_CODE_LABEL_P(SYM) \
33
 (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
34
 
35
#define SAVED_MOVI_R(INFO) \
36
 (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
37
 
38
#define SAVED_MOVI_IMM(INFO) \
39
 (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
40
 
41
struct sh64_disassemble_info
42
 {
43
   /* When we see a MOVI, we save the register and the value, and merge a
44
      subsequent SHORI and display the address, if there is one.  */
45
   unsigned int address_reg;
46
   bfd_signed_vma built_address;
47
 
48
   /* This is the range decriptor for the current address.  It is kept
49
      around for the next call.  */
50
   sh64_elf_crange crange;
51
 };
52
 
53
/* Each item in the table is a mask to indicate which bits to be set
54
   to determine an instruction's operator.
55
   The index is as same as the instruction in the opcode table.
56
   Note that some archs have this as a field in the opcode table.  */
57
static unsigned long *shmedia_opcode_mask_table;
58
 
59
/* Initialize the SH64 opcode mask table for each instruction in SHmedia
60
   mode.  */
61
 
62
static void
63
initialize_shmedia_opcode_mask_table (void)
64
{
65
  int n_opc;
66
  int n;
67
 
68
  /* Calculate number of opcodes.  */
69
  for (n_opc = 0; shmedia_table[n_opc].name != NULL; n_opc++)
70
    ;
71
 
72
  shmedia_opcode_mask_table
73
    = xmalloc (sizeof (shmedia_opcode_mask_table[0]) * n_opc);
74
 
75
  for (n = 0; n < n_opc; n++)
76
    {
77
      int i;
78
 
79
      unsigned long mask = 0;
80
 
81
      for (i = 0; shmedia_table[n].arg[i] != A_NONE; i++)
82
        {
83
          int offset = shmedia_table[n].nibbles[i];
84
          int length;
85
 
86
          switch (shmedia_table[n].arg[i])
87
            {
88
            case A_GREG_M:
89
            case A_GREG_N:
90
            case A_GREG_D:
91
            case A_CREG_K:
92
            case A_CREG_J:
93
            case A_FREG_G:
94
            case A_FREG_H:
95
            case A_FREG_F:
96
            case A_DREG_G:
97
            case A_DREG_H:
98
            case A_DREG_F:
99
            case A_FMREG_G:
100
            case A_FMREG_H:
101
            case A_FMREG_F:
102
            case A_FPREG_G:
103
            case A_FPREG_H:
104
            case A_FPREG_F:
105
            case A_FVREG_G:
106
            case A_FVREG_H:
107
            case A_FVREG_F:
108
            case A_REUSE_PREV:
109
              length = 6;
110
              break;
111
 
112
            case A_TREG_A:
113
            case A_TREG_B:
114
              length = 3;
115
              break;
116
 
117
            case A_IMMM:
118
              abort ();
119
              break;
120
 
121
            case A_IMMU5:
122
              length = 5;
123
              break;
124
 
125
            case A_IMMS6:
126
            case A_IMMU6:
127
            case A_IMMS6BY32:
128
              length = 6;
129
              break;
130
 
131
            case A_IMMS10:
132
            case A_IMMS10BY1:
133
            case A_IMMS10BY2:
134
            case A_IMMS10BY4:
135
            case A_IMMS10BY8:
136
              length = 10;
137
              break;
138
 
139
            case A_IMMU16:
140
            case A_IMMS16:
141
            case A_PCIMMS16BY4:
142
            case A_PCIMMS16BY4_PT:
143
              length = 16;
144
              break;
145
 
146
            default:
147
              abort ();
148
              length = 0;
149
              break;
150
            }
151
 
152
          if (length != 0)
153
            mask |= (0xffffffff >> (32 - length)) << offset;
154
        }
155
      shmedia_opcode_mask_table[n] = 0xffffffff & ~mask;
156
    }
157
}
158
 
159
/* Get a predefined control-register-name, or return NULL.  */
160
 
161
static const char *
162
creg_name (int cregno)
163
{
164
  const shmedia_creg_info *cregp;
165
 
166
  /* If control register usage is common enough, change this to search a
167
     hash-table.  */
168
  for (cregp = shmedia_creg_table; cregp->name != NULL; cregp++)
169
    if (cregp->cregno == cregno)
170
      return cregp->name;
171
 
172
  return NULL;
173
}
174
 
175
/* Main function to disassemble SHmedia instructions.  */
176
 
177
static int
178
print_insn_shmedia (bfd_vma memaddr, struct disassemble_info *info)
179
{
180
  fprintf_ftype fprintf_fn = info->fprintf_func;
181
  void *stream = info->stream;
182
  unsigned char insn[4];
183
  unsigned long instruction;
184
  int status;
185
  int n;
186
  const shmedia_opcode_info *op;
187
  int i;
188
  unsigned int r = 0;
189
  long imm = 0;
190
  bfd_vma disp_pc_addr;
191
 
192
  status = info->read_memory_func (memaddr, insn, 4, info);
193
 
194
  /* If we can't read four bytes, something is wrong.  Display any data we
195
     can get as .byte:s.  */
196
  if (status != 0)
197
    {
198
      for (i = 0; i < 3; i++)
199
        {
200
          status = info->read_memory_func (memaddr + i, insn, 1, info);
201
          if (status != 0)
202
            break;
203
          (*fprintf_fn) (stream, "%s0x%02x",
204
                         i == 0 ? ".byte " : ", ",
205
                         insn[0]);
206
        }
207
 
208
      return i ? i : -1;
209
    }
210
 
211
  /* Rearrange the bytes to make up an instruction.  */
212
  if (info->endian == BFD_ENDIAN_LITTLE)
213
    instruction = bfd_getl32 (insn);
214
  else
215
    instruction = bfd_getb32 (insn);
216
 
217
  /* FIXME: Searching could be implemented using a hash on relevant
218
     fields.  */
219
  for (n = 0, op = shmedia_table;
220
       op->name != NULL
221
       && ((instruction & shmedia_opcode_mask_table[n]) != op->opcode_base);
222
       n++, op++)
223
    ;
224
 
225
  /* FIXME: We should also check register number constraints.  */
226
  if (op->name == NULL)
227
    {
228
      fprintf_fn (stream, ".long 0x%08lx", instruction);
229
      return 4;
230
    }
231
 
232
  fprintf_fn (stream, "%s\t", op->name);
233
 
234
  for (i = 0; i < 3 && op->arg[i] != A_NONE; i++)
235
    {
236
      unsigned long temp = instruction >> op->nibbles[i];
237
      int by_number = 0;
238
 
239
      if (i > 0 && op->arg[i] != A_REUSE_PREV)
240
        fprintf_fn (stream, ",");
241
 
242
      switch (op->arg[i])
243
        {
244
        case A_REUSE_PREV:
245
          continue;
246
 
247
        case A_GREG_M:
248
        case A_GREG_N:
249
        case A_GREG_D:
250
          r = temp & 0x3f;
251
          fprintf_fn (stream, "r%d", r);
252
          break;
253
 
254
        case A_FVREG_F:
255
        case A_FVREG_G:
256
        case A_FVREG_H:
257
          r = temp & 0x3f;
258
          fprintf_fn (stream, "fv%d", r);
259
          break;
260
 
261
        case A_FPREG_F:
262
        case A_FPREG_G:
263
        case A_FPREG_H:
264
          r = temp & 0x3f;
265
          fprintf_fn (stream, "fp%d", r);
266
          break;
267
 
268
        case A_FMREG_F:
269
        case A_FMREG_G:
270
        case A_FMREG_H:
271
          r = temp & 0x3f;
272
          fprintf_fn (stream, "mtrx%d", r);
273
          break;
274
 
275
        case A_CREG_K:
276
        case A_CREG_J:
277
          {
278
            const char *name;
279
 
280
            r = temp & 0x3f;
281
 
282
            name = creg_name (r);
283
 
284
            if (name != NULL)
285
              fprintf_fn (stream, "%s", name);
286
            else
287
              fprintf_fn (stream, "cr%d", r);
288
          }
289
          break;
290
 
291
        case A_FREG_G:
292
        case A_FREG_H:
293
        case A_FREG_F:
294
          r = temp & 0x3f;
295
          fprintf_fn (stream, "fr%d", r);
296
          break;
297
 
298
        case A_DREG_G:
299
        case A_DREG_H:
300
        case A_DREG_F:
301
          r = temp & 0x3f;
302
          fprintf_fn (stream, "dr%d", r);
303
          break;
304
 
305
        case A_TREG_A:
306
        case A_TREG_B:
307
          r = temp & 0x7;
308
          fprintf_fn (stream, "tr%d", r);
309
          break;
310
 
311
          /* A signed 6-bit number.  */
312
        case A_IMMS6:
313
          imm = temp & 0x3f;
314
          if (imm & (unsigned long) 0x20)
315
            imm |= ~(unsigned long) 0x3f;
316
          fprintf_fn (stream, "%ld", imm);
317
          break;
318
 
319
          /* A signed 6-bit number, multiplied by 32 when used.  */
320
        case A_IMMS6BY32:
321
          imm = temp & 0x3f;
322
          if (imm & (unsigned long) 0x20)
323
            imm |= ~(unsigned long) 0x3f;
324
          fprintf_fn (stream, "%ld", imm * 32);
325
          break;
326
 
327
          /* A signed 10-bit number, multiplied by 8 when used.  */
328
        case A_IMMS10BY8:
329
          by_number++;
330
          /* Fall through.  */
331
 
332
          /* A signed 10-bit number, multiplied by 4 when used.  */
333
        case A_IMMS10BY4:
334
          by_number++;
335
          /* Fall through.  */
336
 
337
          /* A signed 10-bit number, multiplied by 2 when used.  */
338
        case A_IMMS10BY2:
339
          by_number++;
340
          /* Fall through.  */
341
 
342
          /* A signed 10-bit number.  */
343
        case A_IMMS10:
344
        case A_IMMS10BY1:
345
          imm = temp & 0x3ff;
346
          if (imm & (unsigned long) 0x200)
347
            imm |= ~(unsigned long) 0x3ff;
348
          imm <<= by_number;
349
          fprintf_fn (stream, "%ld", imm);
350
          break;
351
 
352
          /* A signed 16-bit number.  */
353
        case A_IMMS16:
354
          imm = temp & 0xffff;
355
          if (imm & (unsigned long) 0x8000)
356
            imm |= ~((unsigned long) 0xffff);
357
          fprintf_fn (stream, "%ld", imm);
358
          break;
359
 
360
          /* A PC-relative signed 16-bit number, multiplied by 4 when
361
             used.  */
362
        case A_PCIMMS16BY4:
363
          imm = temp & 0xffff;  /* 16 bits */
364
          if (imm & (unsigned long) 0x8000)
365
            imm |= ~(unsigned long) 0xffff;
366
          imm <<= 2;
367
          disp_pc_addr = (bfd_vma) imm + memaddr;
368
          (*info->print_address_func) (disp_pc_addr, info);
369
          break;
370
 
371
          /* An unsigned 5-bit number.  */
372
        case A_IMMU5:
373
          imm = temp & 0x1f;
374
          fprintf_fn (stream, "%ld", imm);
375
          break;
376
 
377
          /* An unsigned 6-bit number.  */
378
        case A_IMMU6:
379
          imm = temp & 0x3f;
380
          fprintf_fn (stream, "%ld", imm);
381
          break;
382
 
383
          /* An unsigned 16-bit number.  */
384
        case A_IMMU16:
385
          imm = temp & 0xffff;
386
          fprintf_fn (stream, "%ld", imm);
387
          break;
388
 
389
        default:
390
          abort ();
391
          break;
392
        }
393
    }
394
 
395
  /* FIXME: Looks like 32-bit values only are handled.
396
     FIXME: PC-relative numbers aren't handled correctly.  */
397
  if (op->opcode_base == (unsigned long) SHMEDIA_SHORI_OPC
398
      && SAVED_MOVI_R (info) == r)
399
    {
400
      asection *section = info->section;
401
 
402
      /* Most callers do not set the section field correctly yet.  Revert
403
         to getting the section from symbols, if any. */
404
      if (section == NULL
405
          && info->symbols != NULL
406
          && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
407
          && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
408
          && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
409
        section = bfd_get_section (info->symbols[0]);
410
 
411
      /* Only guess addresses when the contents of this section is fully
412
         relocated.  Otherwise, the value will be zero or perhaps even
413
         bogus.  */
414
      if (section == NULL
415
          || section->owner == NULL
416
          || elf_elfheader (section->owner)->e_type == ET_EXEC)
417
        {
418
          bfd_signed_vma shori_addr;
419
 
420
          shori_addr = SAVED_MOVI_IMM (info) << 16;
421
          shori_addr |= imm;
422
 
423
          fprintf_fn (stream, "\t! 0x");
424
          (*info->print_address_func) (shori_addr, info);
425
        }
426
    }
427
 
428
  if (op->opcode_base == SHMEDIA_MOVI_OPC)
429
    {
430
      SAVED_MOVI_IMM (info) = imm;
431
      SAVED_MOVI_R (info) = r;
432
    }
433
  else
434
    {
435
      SAVED_MOVI_IMM (info) = 0;
436
      SAVED_MOVI_R (info) = 255;
437
    }
438
 
439
  return 4;
440
}
441
 
442
/* Check the type of contents about to be disassembled.  This is like
443
   sh64_get_contents_type (which may be called from here), except that it
444
   takes the same arguments as print_insn_* and does what can be done if
445
   no section is available.  */
446
 
447
static enum sh64_elf_cr_type
448
sh64_get_contents_type_disasm (bfd_vma memaddr, struct disassemble_info *info)
449
{
450
  struct sh64_disassemble_info *sh64_infop = info->private_data;
451
 
452
  /* Perhaps we have a region from a previous probe and it still counts
453
     for this address?  */
454
  if (sh64_infop->crange.cr_type != CRT_NONE
455
      && memaddr >= sh64_infop->crange.cr_addr
456
      && memaddr < sh64_infop->crange.cr_addr + sh64_infop->crange.cr_size)
457
    return sh64_infop->crange.cr_type;
458
 
459
  /* If we have a section, try and use it.  */
460
  if (info->section
461
      && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour)
462
    {
463
      enum sh64_elf_cr_type cr_type
464
        = sh64_get_contents_type (info->section, memaddr,
465
                                  &sh64_infop->crange);
466
 
467
      if (cr_type != CRT_NONE)
468
        return cr_type;
469
    }
470
 
471
  /* If we have symbols, we can try and get at a section from *that*.  */
472
  if (info->symbols != NULL
473
      && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
474
      && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
475
      && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
476
    {
477
      enum sh64_elf_cr_type cr_type
478
        = sh64_get_contents_type (bfd_get_section (info->symbols[0]),
479
                                  memaddr, &sh64_infop->crange);
480
 
481
      if (cr_type != CRT_NONE)
482
        return cr_type;
483
    }
484
 
485
  /* We can make a reasonable guess based on the st_other field of a
486
     symbol; for a BranchTarget this is marked as STO_SH5_ISA32 and then
487
     it's most probably code there.  */
488
  if (info->symbols
489
      && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
490
      && elf_symbol_from (bfd_asymbol_bfd (info->symbols[0]),
491
                          info->symbols[0])->internal_elf_sym.st_other
492
      == STO_SH5_ISA32)
493
    return CRT_SH5_ISA32;
494
 
495
  /* If all else fails, guess this is code and guess on the low bit set.  */
496
  return (memaddr & 1) == 1 ? CRT_SH5_ISA32 : CRT_SH5_ISA16;
497
}
498
 
499
/* Initialize static and dynamic disassembly state.  */
500
 
501
static bfd_boolean
502
init_sh64_disasm_info (struct disassemble_info *info)
503
{
504
  struct sh64_disassemble_info *sh64_infop
505
    = calloc (sizeof (*sh64_infop), 1);
506
 
507
  if (sh64_infop == NULL)
508
    return FALSE;
509
 
510
  info->private_data = sh64_infop;
511
 
512
  SAVED_MOVI_IMM (info) = 0;
513
  SAVED_MOVI_R (info) = 255;
514
 
515
  if (shmedia_opcode_mask_table == NULL)
516
    initialize_shmedia_opcode_mask_table ();
517
 
518
  return TRUE;
519
}
520
 
521
/* Main entry to disassemble SHmedia instructions, given an endian set in
522
   INFO.  Note that the simulator uses this as the main entry and does not
523
   use any of the functions further below.  */
524
 
525
int
526
print_insn_sh64x_media (bfd_vma memaddr, struct disassemble_info *info)
527
{
528
  if (info->private_data == NULL && ! init_sh64_disasm_info (info))
529
    return -1;
530
 
531
  /* Make reasonable output.  */
532
  info->bytes_per_line = 4;
533
  info->bytes_per_chunk = 4;
534
 
535
  return print_insn_shmedia (memaddr, info);
536
}
537
 
538
/* Main entry to disassemble SHmedia insns.
539
   If we see an SHcompact instruction, return -2.  */
540
 
541
int
542
print_insn_sh64 (bfd_vma memaddr, struct disassemble_info *info)
543
{
544
  enum bfd_endian endian = info->endian;
545
  enum sh64_elf_cr_type cr_type;
546
 
547
  if (info->private_data == NULL && ! init_sh64_disasm_info (info))
548
    return -1;
549
 
550
  cr_type = sh64_get_contents_type_disasm (memaddr, info);
551
  if (cr_type != CRT_SH5_ISA16)
552
    {
553
      int length = 4 - (memaddr % 4);
554
      info->display_endian = endian;
555
 
556
      /* If we got an uneven address to indicate SHmedia, adjust it.  */
557
      if (cr_type == CRT_SH5_ISA32 && length == 3)
558
        memaddr--, length = 4;
559
 
560
      /* Only disassemble on four-byte boundaries.  Addresses that are not
561
         a multiple of four can happen after a data region.  */
562
      if (cr_type == CRT_SH5_ISA32 && length == 4)
563
        return print_insn_sh64x_media (memaddr, info);
564
 
565
      /* We get CRT_DATA *only* for data regions in a mixed-contents
566
         section.  For sections with data only, we get indication of one
567
         of the ISA:s.  You may think that we shouldn't disassemble
568
         section with only data if we can figure that out.  However, the
569
         disassembly function is by default not called for data-only
570
         sections, so if the user explicitly specified disassembly of a
571
         data section, that's what we should do.  */
572
      if (cr_type == CRT_DATA || length != 4)
573
        {
574
          int status;
575
          unsigned char data[4];
576
          struct sh64_disassemble_info *sh64_infop = info->private_data;
577
 
578
          if (length == 4
579
              && sh64_infop->crange.cr_type != CRT_NONE
580
              && memaddr >= sh64_infop->crange.cr_addr
581
              && memaddr < (sh64_infop->crange.cr_addr
582
                            + sh64_infop->crange.cr_size))
583
            length
584
              = (sh64_infop->crange.cr_addr
585
                 + sh64_infop->crange.cr_size - memaddr);
586
 
587
          status
588
            = (*info->read_memory_func) (memaddr, data,
589
                                         length >= 4 ? 4 : length, info);
590
 
591
          if (status == 0 && length >= 4)
592
            {
593
              (*info->fprintf_func) (info->stream, ".long 0x%08lx",
594
                                     endian == BFD_ENDIAN_BIG
595
                                     ? (long) (bfd_getb32 (data))
596
                                     : (long) (bfd_getl32 (data)));
597
              return 4;
598
            }
599
          else
600
            {
601
              int i;
602
 
603
              for (i = 0; i < length; i++)
604
                {
605
                  status = info->read_memory_func (memaddr + i, data, 1, info);
606
                  if (status != 0)
607
                    break;
608
                  (*info->fprintf_func) (info->stream, "%s0x%02x",
609
                                         i == 0 ? ".byte " : ", ",
610
                                         data[0]);
611
                }
612
 
613
              return i ? i : -1;
614
            }
615
        }
616
    }
617
 
618
  /* SH1 .. SH4 instruction, let caller handle it.  */
619
  return -2;
620
}

powered by: WebSVN 2.1.0

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