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

Subversion Repositories open8_urisc

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

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

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

powered by: WebSVN 2.1.0

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