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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [opcodes/] [microblaze-dis.c] - Blame information for rev 853

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

Line No. Rev Author Line
1 205 julius
/* Disassemble Xilinx microblaze instructions.
2
 
3
   Copyright 2009 Free Software Foundation, Inc.
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
19
   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
 
22
 
23
#include "sysdep.h"
24
#define STATIC_TABLE
25
#define DEFINE_TABLE
26
 
27
#include "microblaze-opc.h"
28
#include "dis-asm.h"
29
#include <strings.h>
30
 
31
#define get_field_rd(instr)        get_field (instr, RD_MASK, RD_LOW)
32
#define get_field_r1(instr)        get_field (instr, RA_MASK, RA_LOW)
33
#define get_field_r2(instr)        get_field (instr, RB_MASK, RB_LOW)
34
#define get_int_field_imm(instr)   ((instr & IMM_MASK) >> IMM_LOW)
35
#define get_int_field_r1(instr)    ((instr & RA_MASK) >> RA_LOW)
36
 
37
static char *
38
get_field (long instr, long mask, unsigned short low)
39
{
40
  char tmpstr[25];
41
 
42
  sprintf (tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
43
  return (strdup (tmpstr));
44
}
45
 
46
static char *
47
get_field_imm (long instr)
48
{
49
  char tmpstr[25];
50
 
51
  sprintf (tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
52
  return (strdup (tmpstr));
53
}
54
 
55
static char *
56
get_field_imm5 (long instr)
57
{
58
  char tmpstr[25];
59
 
60
  sprintf (tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
61
  return (strdup (tmpstr));
62
}
63
 
64
static char *
65
get_field_rfsl (long instr)
66
{
67
  char tmpstr[25];
68
 
69
  sprintf (tmpstr, "%s%d", fsl_register_prefix,
70
           (short)((instr & RFSL_MASK) >> IMM_LOW));
71
  return (strdup (tmpstr));
72
}
73
 
74
static char *
75
get_field_imm15 (long instr)
76
{
77
  char tmpstr[25];
78
 
79
  sprintf (tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
80
  return (strdup (tmpstr));
81
}
82
 
83
static char *
84
get_field_special (long instr, struct op_code_struct * op)
85
{
86
  char tmpstr[25];
87
  char spr[6];
88
 
89
  switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask))
90
    {
91
    case REG_MSR_MASK :
92
      strcpy (spr, "msr");
93
      break;
94
    case REG_PC_MASK :
95
      strcpy (spr, "pc");
96
      break;
97
    case REG_EAR_MASK :
98
      strcpy (spr, "ear");
99
      break;
100
    case REG_ESR_MASK :
101
      strcpy (spr, "esr");
102
      break;
103
    case REG_FSR_MASK :
104
      strcpy (spr, "fsr");
105
      break;
106
    case REG_BTR_MASK :
107
      strcpy (spr, "btr");
108
      break;
109
    case REG_EDR_MASK :
110
      strcpy (spr, "edr");
111
      break;
112
    case REG_PID_MASK :
113
      strcpy (spr, "pid");
114
      break;
115
    case REG_ZPR_MASK :
116
      strcpy (spr, "zpr");
117
      break;
118
    case REG_TLBX_MASK :
119
      strcpy (spr, "tlbx");
120
      break;
121
    case REG_TLBLO_MASK :
122
      strcpy (spr, "tlblo");
123
      break;
124
    case REG_TLBHI_MASK :
125
      strcpy (spr, "tlbhi");
126
      break;
127
    case REG_TLBSX_MASK :
128
      strcpy (spr, "tlbsx");
129
      break;
130
    default :
131
      if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000)
132
          == REG_PVR_MASK)
133
        {
134
          sprintf (tmpstr, "%spvr%d", register_prefix,
135
                   (unsigned short)(((instr & IMM_MASK) >> IMM_LOW)
136
                                    ^ op->immval_mask) ^ REG_PVR_MASK);
137
          return (strdup (tmpstr));
138
        }
139
      else
140
        strcpy (spr, "pc");
141
      break;
142
    }
143
 
144
   sprintf (tmpstr, "%s%s", register_prefix, spr);
145
   return (strdup (tmpstr));
146
}
147
 
148
static unsigned long
149
read_insn_microblaze (bfd_vma memaddr,
150
                      struct disassemble_info *info,
151
                      struct op_code_struct **opr)
152
{
153
  unsigned char       ibytes[4];
154
  int                 status;
155
  struct op_code_struct * op;
156
  unsigned long inst;
157
 
158
  status = info->read_memory_func (memaddr, ibytes, 4, info);
159
 
160
  if (status != 0)
161
    {
162
      info->memory_error_func (status, memaddr, info);
163
      return 0;
164
    }
165
 
166
  if (info->endian == BFD_ENDIAN_BIG)
167
    inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
168
  else if (info->endian == BFD_ENDIAN_LITTLE)
169
    inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
170
  else
171
    abort ();
172
 
173
  /* Just a linear search of the table.  */
174
  for (op = opcodes; op->name != 0; op ++)
175
    if (op->bit_sequence == (inst & op->opcode_mask))
176
      break;
177
 
178
  *opr = op;
179
  return inst;
180
}
181
 
182
 
183
int
184
print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
185
{
186
  fprintf_ftype       fprintf = info->fprintf_func;
187
  void *              stream = info->stream;
188
  unsigned long       inst, prev_inst;
189
  struct op_code_struct * op, *pop;
190
  int                 immval = 0;
191
  bfd_boolean         immfound = FALSE;
192
  static bfd_vma      prev_insn_addr = -1; /* Init the prev insn addr.  */
193
  static int          prev_insn_vma = -1;  /* Init the prev insn vma.  */
194
  int                 curr_insn_vma = info->buffer_vma;
195
 
196
  info->bytes_per_chunk = 4;
197
 
198
  inst = read_insn_microblaze (memaddr, info, &op);
199
  if (inst == 0)
200
    return -1;
201
 
202
  if (prev_insn_vma == curr_insn_vma)
203
    {
204
      if (memaddr-(info->bytes_per_chunk) == prev_insn_addr)
205
        {
206
          prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
207
          if (prev_inst == 0)
208
            return -1;
209
          if (pop->instr == imm)
210
            {
211
              immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000;
212
              immfound = TRUE;
213
            }
214
          else
215
            {
216
              immval = 0;
217
              immfound = FALSE;
218
            }
219
        }
220
    }
221
 
222
  /* Make curr insn as prev insn.  */
223
  prev_insn_addr = memaddr;
224
  prev_insn_vma = curr_insn_vma;
225
 
226
  if (op->name == NULL)
227
    fprintf (stream, ".short 0x%04x", inst);
228
  else
229
    {
230
      fprintf (stream, "%s", op->name);
231
 
232
      switch (op->inst_type)
233
        {
234
        case INST_TYPE_RD_R1_R2:
235
          fprintf (stream, "\t%s, %s, %s", get_field_rd (inst),
236
                   get_field_r1(inst), get_field_r2 (inst));
237
          break;
238
        case INST_TYPE_RD_R1_IMM:
239
          fprintf (stream, "\t%s, %s, %s", get_field_rd (inst),
240
                   get_field_r1(inst), get_field_imm (inst));
241
          if (info->print_address_func && get_int_field_r1 (inst) == 0
242
              && info->symbol_at_address_func)
243
            {
244
              if (immfound)
245
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
246
              else
247
                {
248
                  immval = get_int_field_imm (inst);
249
                  if (immval & 0x8000)
250
                    immval |= 0xFFFF0000;
251
                }
252
              if (immval > 0 && info->symbol_at_address_func (immval, info))
253
                {
254
                  fprintf (stream, "\t// ");
255
                  info->print_address_func (immval, info);
256
                }
257
            }
258
          break;
259
        case INST_TYPE_RD_R1_IMM5:
260
          fprintf (stream, "\t%s, %s, %s", get_field_rd (inst),
261
                   get_field_r1(inst), get_field_imm5 (inst));
262
          break;
263
        case INST_TYPE_RD_RFSL:
264
          fprintf (stream, "\t%s, %s", get_field_rd (inst), get_field_rfsl (inst));
265
          break;
266
        case INST_TYPE_R1_RFSL:
267
          fprintf (stream, "\t%s, %s", get_field_r1 (inst), get_field_rfsl (inst));
268
          break;
269
        case INST_TYPE_RD_SPECIAL:
270
          fprintf (stream, "\t%s, %s", get_field_rd (inst),
271
                   get_field_special (inst, op));
272
          break;
273
        case INST_TYPE_SPECIAL_R1:
274
          fprintf (stream, "\t%s, %s", get_field_special (inst, op),
275
                   get_field_r1(inst));
276
          break;
277
        case INST_TYPE_RD_R1:
278
          fprintf (stream, "\t%s, %s", get_field_rd (inst), get_field_r1 (inst));
279
          break;
280
        case INST_TYPE_R1_R2:
281
          fprintf (stream, "\t%s, %s", get_field_r1 (inst), get_field_r2 (inst));
282
          break;
283
        case INST_TYPE_R1_IMM:
284
          fprintf (stream, "\t%s, %s", get_field_r1 (inst), get_field_imm (inst));
285
          /* The non-pc relative instructions are returns, which shouldn't
286
             have a label printed.  */
287
          if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET
288
              && info->symbol_at_address_func)
289
            {
290
              if (immfound)
291
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
292
              else
293
                {
294
                  immval = get_int_field_imm (inst);
295
                  if (immval & 0x8000)
296
                    immval |= 0xFFFF0000;
297
                }
298
              immval += memaddr;
299
              if (immval > 0 && info->symbol_at_address_func (immval, info))
300
                {
301
                  fprintf (stream, "\t// ");
302
                  info->print_address_func (immval, info);
303
                }
304
              else
305
                {
306
                  fprintf (stream, "\t\t// ");
307
                  fprintf (stream, "%x", immval);
308
                }
309
            }
310
          break;
311
        case INST_TYPE_RD_IMM:
312
          fprintf (stream, "\t%s, %s", get_field_rd (inst), get_field_imm (inst));
313
          if (info->print_address_func && info->symbol_at_address_func)
314
            {
315
            if (immfound)
316
              immval |= (get_int_field_imm (inst) & 0x0000ffff);
317
            else
318
              {
319
                immval = get_int_field_imm (inst);
320
                if (immval & 0x8000)
321
                  immval |= 0xFFFF0000;
322
              }
323
            if (op->inst_offset_type == INST_PC_OFFSET)
324
              immval += (int) memaddr;
325
            if (info->symbol_at_address_func (immval, info))
326
              {
327
                fprintf (stream, "\t// ");
328
                info->print_address_func (immval, info);
329
              }
330
            }
331
          break;
332
        case INST_TYPE_IMM:
333
          fprintf (stream, "\t%s", get_field_imm (inst));
334
          if (info->print_address_func && info->symbol_at_address_func
335
              && op->instr != imm)
336
            {
337
              if (immfound)
338
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
339
              else
340
                {
341
                  immval = get_int_field_imm (inst);
342
                  if (immval & 0x8000)
343
                    immval |= 0xFFFF0000;
344
                }
345
              if (op->inst_offset_type == INST_PC_OFFSET)
346
                immval += (int) memaddr;
347
              if (immval > 0 && info->symbol_at_address_func (immval, info))
348
                {
349
                  fprintf (stream, "\t// ");
350
                  info->print_address_func (immval, info);
351
                }
352
              else if (op->inst_offset_type == INST_PC_OFFSET)
353
                {
354
                  fprintf (stream, "\t\t// ");
355
                  fprintf (stream, "%x", immval);
356
                }
357
            }
358
          break;
359
        case INST_TYPE_RD_R2:
360
          fprintf (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
361
          break;
362
        case INST_TYPE_R2:
363
          fprintf (stream, "\t%s", get_field_r2 (inst));
364
          break;
365
        case INST_TYPE_R1:
366
          fprintf (stream, "\t%s", get_field_r1 (inst));
367
          break;
368
        case INST_TYPE_RD_R1_SPECIAL:
369
          fprintf (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
370
          break;
371
        case INST_TYPE_RD_IMM15:
372
          fprintf (stream, "\t%s, %s", get_field_rd (inst), get_field_imm15 (inst));
373
          break;
374
        /* For tuqula instruction */
375
        case INST_TYPE_RD:
376
          fprintf (stream, "\t%s", get_field_rd (inst));
377
          break;
378
        case INST_TYPE_RFSL:
379
          fprintf (stream, "\t%s", get_field_rfsl (inst));
380
          break;
381
        default:
382
          /* If the disassembler lags the instruction set.  */
383
          fprintf (stream, "\tundecoded operands, inst is 0x%04x", inst);
384
          break;
385
        }
386
    }
387
 
388
  /* Say how many bytes we consumed.  */
389
  return 4;
390
}
391
#if 0
392
static enum microblaze_instr
393
get_insn_microblaze (long inst,
394
                     bfd_boolean *isunsignedimm,
395
                     enum microblaze_instr_type *insn_type,
396
                     short *delay_slots)
397
{
398
  struct op_code_struct * op;
399
  *isunsignedimm = FALSE;
400
 
401
  /* Just a linear search of the table.  */
402
  for (op = opcodes; op->name != 0; op ++)
403
    if (op->bit_sequence == (inst & op->opcode_mask))
404
      break;
405
 
406
  if (op->name == 0)
407
    return invalid_inst;
408
  else
409
    {
410
      *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
411
      *insn_type = op->instr_type;
412
      *delay_slots = op->delay_slots;
413
      return op->instr;
414
    }
415
}
416
 
417
short
418
get_delay_slots_microblaze (long inst)
419
{
420
  bfd_boolean isunsignedimm;
421
  enum microblaze_instr_type insn_type;
422
  enum microblaze_instr op;
423
  short delay_slots;
424
 
425
  op = get_insn_microblaze (inst, &isunsignedimm, &insn_type, &delay_slots);
426
  if (op == invalid_inst)
427
    return 0;
428
  else
429
    return delay_slots;
430
}
431
 
432
enum microblaze_instr
433
microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *imm)
434
{
435
  enum microblaze_instr op;
436
  bfd_boolean t1;
437
  enum microblaze_instr_type t2;
438
  short t3;
439
 
440
  op = get_insn_microblaze (insn, &t1, &t2, &t3);
441
  *rd = (insn & RD_MASK) >> RD_LOW;
442
  *ra = (insn & RA_MASK) >> RA_LOW;
443
  *rb = (insn & RB_MASK) >> RB_LOW;
444
  t3 = (insn & IMM_MASK) >> IMM_LOW;
445
  *imm = (int) t3;
446
  return (op);
447
}
448
 
449
unsigned long
450
microblaze_get_target_address (long inst, bfd_boolean immfound, int immval,
451
                               long pcval, long r1val, long r2val,
452
                               bfd_boolean *targetvalid,
453
                               bfd_boolean *unconditionalbranch)
454
{
455
  struct op_code_struct * op;
456
  long targetaddr = 0;
457
 
458
  *unconditionalbranch = FALSE;
459
  /* Just a linear search of the table.  */
460
  for (op = opcodes; op->name != 0; op ++)
461
    if (op->bit_sequence == (inst & op->opcode_mask))
462
      break;
463
 
464
  if (op->name == 0)
465
    {
466
      *targetvalid = FALSE;
467
    }
468
  else if (op->instr_type == branch_inst)
469
    {
470
      switch (op->inst_type)
471
        {
472
        case INST_TYPE_R2:
473
          *unconditionalbranch = TRUE;
474
        /* Fall through.  */
475
        case INST_TYPE_RD_R2:
476
        case INST_TYPE_R1_R2:
477
          targetaddr = r2val;
478
          *targetvalid = TRUE;
479
          if (op->inst_offset_type == INST_PC_OFFSET)
480
            targetaddr += pcval;
481
          break;
482
        case INST_TYPE_IMM:
483
          *unconditionalbranch = TRUE;
484
        /* Fall through.  */
485
        case INST_TYPE_RD_IMM:
486
        case INST_TYPE_R1_IMM:
487
          if (immfound)
488
            {
489
              targetaddr = (immval << 16) & 0xffff0000;
490
              targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
491
            }
492
          else
493
            {
494
              targetaddr = get_int_field_imm (inst);
495
              if (targetaddr & 0x8000)
496
                targetaddr |= 0xFFFF0000;
497
            }
498
          if (op->inst_offset_type == INST_PC_OFFSET)
499
            targetaddr += pcval;
500
          *targetvalid = TRUE;
501
          break;
502
        default:
503
          *targetvalid = FALSE;
504
          break;
505
        }
506
    }
507
  else if (op->instr_type == return_inst)
508
    {
509
      if (immfound)
510
        {
511
          targetaddr = (immval << 16) & 0xffff0000;
512
          targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
513
        }
514
      else
515
        {
516
          targetaddr = get_int_field_imm (inst);
517
          if (targetaddr & 0x8000)
518
            targetaddr |= 0xFFFF0000;
519
        }
520
      targetaddr += r1val;
521
      *targetvalid = TRUE;
522
    }
523
  else
524
    *targetvalid = FALSE;
525
  return targetaddr;
526
}
527
#endif

powered by: WebSVN 2.1.0

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