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

Subversion Repositories open8_urisc

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

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

Line No. Rev Author Line
1 18 khays
/* Disassemble D30V instructions.
2
   Copyright 1997, 1998, 2000, 2001, 2005, 2007
3
   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 program; if not, write to the Free Software
19
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
 
22
#include <stdio.h>
23
#include "sysdep.h"
24
#include "opcode/d30v.h"
25
#include "dis-asm.h"
26
#include "opintl.h"
27
 
28
#define PC_MASK 0xFFFFFFFF
29
 
30
/* Return 0 if lookup fails,
31
   1 if found and only one form,
32
   2 if found and there are short and long forms.  */
33
 
34
static int
35
lookup_opcode (struct d30v_insn *insn, long num, int is_long)
36
{
37
  int i = 0, op_index;
38
  struct d30v_format *f;
39
  struct d30v_opcode *op = (struct d30v_opcode *) d30v_opcode_table;
40
  int op1 = (num >> 25) & 0x7;
41
  int op2 = (num >> 20) & 0x1f;
42
  int mod = (num >> 18) & 0x3;
43
 
44
  /* Find the opcode.  */
45
  do
46
    {
47
      if ((op->op1 == op1) && (op->op2 == op2))
48
        break;
49
      op++;
50
    }
51
  while (op->name);
52
 
53
  if (!op || !op->name)
54
    return 0;
55
 
56
  while (op->op1 == op1 && op->op2 == op2)
57
    {
58
      /* Scan through all the formats for the opcode.  */
59
      op_index = op->format[i++];
60
      do
61
        {
62
          f = (struct d30v_format *) &d30v_format_table[op_index];
63
          while (f->form == op_index)
64
            {
65
              if ((!is_long || f->form >= LONG) && (f->modifier == mod))
66
                {
67
                  insn->form = f;
68
                  break;
69
                }
70
              f++;
71
            }
72
          if (insn->form)
73
            break;
74
        }
75
      while ((op_index = op->format[i++]) != 0);
76
      if (insn->form)
77
        break;
78
      op++;
79
      i = 0;
80
    }
81
  if (insn->form == NULL)
82
    return 0;
83
 
84
  insn->op = op;
85
  insn->ecc = (num >> 28) & 0x7;
86
  if (op->format[1])
87
    return 2;
88
  else
89
    return 1;
90
}
91
 
92
static int
93
extract_value (long long num, struct d30v_operand *oper, int is_long)
94
{
95
  int val;
96
  int shift = 12 - oper->position;
97
  int mask = (0xFFFFFFFF >> (32 - oper->bits));
98
 
99
  if (is_long)
100
    {
101
      if (oper->bits == 32)
102
        /* Piece together 32-bit constant.  */
103
        val = ((num & 0x3FFFF)
104
               | ((num & 0xFF00000) >> 2)
105
               | ((num & 0x3F00000000LL) >> 6));
106
      else
107
        val = (num >> (32 + shift)) & mask;
108
    }
109
  else
110
    val = (num >> shift) & mask;
111
 
112
  if (oper->flags & OPERAND_SHIFT)
113
    val <<= 3;
114
 
115
  return val;
116
}
117
 
118
static void
119
print_insn (struct disassemble_info *info,
120
            bfd_vma memaddr,
121
            long long num,
122
            struct d30v_insn *insn,
123
            int is_long,
124
            int show_ext)
125
{
126
  int val, opnum, need_comma = 0;
127
  struct d30v_operand *oper;
128
  int i, match, opind = 0, need_paren = 0, found_control = 0;
129
 
130
  (*info->fprintf_func) (info->stream, "%s", insn->op->name);
131
 
132
  /* Check for CMP or CMPU.  */
133
  if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME)
134
    {
135
      opind++;
136
      val =
137
        extract_value (num,
138
                       (struct d30v_operand *) &d30v_operand_table[insn->form->operands[0]],
139
                       is_long);
140
      (*info->fprintf_func) (info->stream, "%s", d30v_cc_names[val]);
141
    }
142
 
143
  /* Add in ".s" or ".l".  */
144
  if (show_ext == 2)
145
    {
146
      if (is_long)
147
        (*info->fprintf_func) (info->stream, ".l");
148
      else
149
        (*info->fprintf_func) (info->stream, ".s");
150
    }
151
 
152
  if (insn->ecc)
153
    (*info->fprintf_func) (info->stream, "/%s", d30v_ecc_names[insn->ecc]);
154
 
155
  (*info->fprintf_func) (info->stream, "\t");
156
 
157
  while ((opnum = insn->form->operands[opind++]) != 0)
158
    {
159
      int bits;
160
 
161
      oper = (struct d30v_operand *) &d30v_operand_table[opnum];
162
      bits = oper->bits;
163
      if (oper->flags & OPERAND_SHIFT)
164
        bits += 3;
165
 
166
      if (need_comma
167
          && oper->flags != OPERAND_PLUS
168
          && oper->flags != OPERAND_MINUS)
169
        {
170
          need_comma = 0;
171
          (*info->fprintf_func) (info->stream, ", ");
172
        }
173
 
174
      if (oper->flags == OPERAND_ATMINUS)
175
        {
176
          (*info->fprintf_func) (info->stream, "@-");
177
          continue;
178
        }
179
      if (oper->flags == OPERAND_MINUS)
180
        {
181
          (*info->fprintf_func) (info->stream, "-");
182
          continue;
183
        }
184
      if (oper->flags == OPERAND_PLUS)
185
        {
186
          (*info->fprintf_func) (info->stream, "+");
187
          continue;
188
        }
189
      if (oper->flags == OPERAND_ATSIGN)
190
        {
191
          (*info->fprintf_func) (info->stream, "@");
192
          continue;
193
        }
194
      if (oper->flags == OPERAND_ATPAR)
195
        {
196
          (*info->fprintf_func) (info->stream, "@(");
197
          need_paren = 1;
198
          continue;
199
        }
200
 
201
      if (oper->flags == OPERAND_SPECIAL)
202
        continue;
203
 
204
      val = extract_value (num, oper, is_long);
205
 
206
      if (oper->flags & OPERAND_REG)
207
        {
208
          match = 0;
209
          if (oper->flags & OPERAND_CONTROL)
210
            {
211
              struct d30v_operand *oper3 =
212
                (struct d30v_operand *) &d30v_operand_table[insn->form->operands[2]];
213
              int id = extract_value (num, oper3, is_long);
214
 
215
              found_control = 1;
216
              switch (id)
217
                {
218
                case 0:
219
                  val |= OPERAND_CONTROL;
220
                  break;
221
                case 1:
222
                case 2:
223
                  val = OPERAND_CONTROL + MAX_CONTROL_REG + id;
224
                  break;
225
                case 3:
226
                  val |= OPERAND_FLAG;
227
                  break;
228
                default:
229
                  fprintf (stderr, "illegal id (%d)\n", id);
230
                }
231
            }
232
          else if (oper->flags & OPERAND_ACC)
233
            val |= OPERAND_ACC;
234
          else if (oper->flags & OPERAND_FLAG)
235
            val |= OPERAND_FLAG;
236
          for (i = 0; i < reg_name_cnt (); i++)
237
            {
238
              if (val == pre_defined_registers[i].value)
239
                {
240
                  if (pre_defined_registers[i].pname)
241
                    (*info->fprintf_func)
242
                      (info->stream, "%s", pre_defined_registers[i].pname);
243
                  else
244
                    (*info->fprintf_func)
245
                      (info->stream, "%s", pre_defined_registers[i].name);
246
                  match = 1;
247
                  break;
248
                }
249
            }
250
          if (match == 0)
251
            {
252
              /* This would only get executed if a register was not in
253
                 the register table.  */
254
              (*info->fprintf_func)
255
                (info->stream, _("<unknown register %d>"), val & 0x3F);
256
            }
257
        }
258
      /* repeati has a relocation, but its first argument is a plain
259
         immediate.  OTOH instructions like djsri have a pc-relative
260
         delay target, but an absolute jump target.  Therefore, a test
261
         of insn->op->reloc_flag is not specific enough; we must test
262
         if the actual operand we are handling now is pc-relative.  */
263
      else if (oper->flags & OPERAND_PCREL)
264
        {
265
          int neg = 0;
266
 
267
          /* IMM6S3 is unsigned.  */
268
          if (oper->flags & OPERAND_SIGNED || bits == 32)
269
            {
270
              long max;
271
              max = (1 << (bits - 1));
272
              if (val & max)
273
                {
274
                  if (bits == 32)
275
                    val = -val;
276
                  else
277
                    val = -val & ((1 << bits) - 1);
278
                  neg = 1;
279
                }
280
            }
281
          if (neg)
282
            {
283
              (*info->fprintf_func) (info->stream, "-%x\t(", val);
284
              (*info->print_address_func) ((memaddr - val) & PC_MASK, info);
285
              (*info->fprintf_func) (info->stream, ")");
286
            }
287
          else
288
            {
289
              (*info->fprintf_func) (info->stream, "%x\t(", val);
290
              (*info->print_address_func) ((memaddr + val) & PC_MASK, info);
291
              (*info->fprintf_func) (info->stream, ")");
292
            }
293
        }
294
      else if (insn->op->reloc_flag == RELOC_ABS)
295
        {
296
          (*info->print_address_func) (val, info);
297
        }
298
      else
299
        {
300
          if (oper->flags & OPERAND_SIGNED)
301
            {
302
              int max = (1 << (bits - 1));
303
 
304
              if (val & max)
305
                {
306
                  val = -val;
307
                  if (bits < 32)
308
                    val &= ((1 << bits) - 1);
309
                  (*info->fprintf_func) (info->stream, "-");
310
                }
311
            }
312
          (*info->fprintf_func) (info->stream, "0x%x", val);
313
        }
314
      /* If there is another operand, then write a comma and space.  */
315
      if (insn->form->operands[opind] && !(found_control && opind == 2))
316
        need_comma = 1;
317
    }
318
  if (need_paren)
319
    (*info->fprintf_func) (info->stream, ")");
320
}
321
 
322
int
323
print_insn_d30v (bfd_vma memaddr, struct disassemble_info *info)
324
{
325
  int status, result;
326
  bfd_byte buffer[12];
327
  unsigned long in1, in2;
328
  struct d30v_insn insn;
329
  long long num;
330
 
331
  insn.form = NULL;
332
 
333
  info->bytes_per_line = 8;
334
  info->bytes_per_chunk = 4;
335
  info->display_endian = BFD_ENDIAN_BIG;
336
 
337
  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
338
  if (status != 0)
339
    {
340
      (*info->memory_error_func) (status, memaddr, info);
341
      return -1;
342
    }
343
  in1 = bfd_getb32 (buffer);
344
 
345
  status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
346
  if (status != 0)
347
    {
348
      info->bytes_per_line = 8;
349
      if (!(result = lookup_opcode (&insn, in1, 0)))
350
        (*info->fprintf_func) (info->stream, ".long\t0x%lx", in1);
351
      else
352
        print_insn (info, memaddr, (long long) in1, &insn, 0, result);
353
      return 4;
354
    }
355
  in2 = bfd_getb32 (buffer);
356
 
357
  if (in1 & in2 & FM01)
358
    {
359
      /* LONG instruction.  */
360
      if (!(result = lookup_opcode (&insn, in1, 1)))
361
        {
362
          (*info->fprintf_func) (info->stream, ".long\t0x%lx,0x%lx", in1, in2);
363
          return 8;
364
        }
365
      num = (long long) in1 << 32 | in2;
366
      print_insn (info, memaddr, num, &insn, 1, result);
367
    }
368
  else
369
    {
370
      num = in1;
371
      if (!(result = lookup_opcode (&insn, in1, 0)))
372
        (*info->fprintf_func) (info->stream, ".long\t0x%lx", in1);
373
      else
374
        print_insn (info, memaddr, num, &insn, 0, result);
375
 
376
      switch (((in1 >> 31) << 1) | (in2 >> 31))
377
        {
378
        case 0:
379
          (*info->fprintf_func) (info->stream, "\t||\t");
380
          break;
381
        case 1:
382
          (*info->fprintf_func) (info->stream, "\t->\t");
383
          break;
384
        case 2:
385
          (*info->fprintf_func) (info->stream, "\t<-\t");
386
        default:
387
          break;
388
        }
389
 
390
      insn.form = NULL;
391
      num = in2;
392
      if (!(result = lookup_opcode (&insn, in2, 0)))
393
        (*info->fprintf_func) (info->stream, ".long\t0x%lx", in2);
394
      else
395
        print_insn (info, memaddr, num, &insn, 0, result);
396
    }
397
  return 8;
398
}

powered by: WebSVN 2.1.0

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