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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [opcodes/] [v850-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 V850 instructions.
2
   Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 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
 
23
#include <stdio.h>
24
 
25
#include "sysdep.h"
26
#include "opcode/v850.h"
27
#include "dis-asm.h"
28
#include "opintl.h"
29
 
30
static const char *const v850_reg_names[] =
31
{ "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
32
  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
33
  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
34
  "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
35
 
36
static const char *const v850_sreg_names[] =
37
{ "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7",
38
  "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
39
  "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23",
40
  "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31",
41
  "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
42
  "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
43
 
44
static const char *const v850_cc_names[] =
45
{ "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
46
  "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
47
 
48
static int
49
disassemble (bfd_vma memaddr,
50
             struct disassemble_info * info,
51
             unsigned long insn)
52
{
53
  struct v850_opcode * op = (struct v850_opcode *) v850_opcodes;
54
  const struct v850_operand * operand;
55
  int match = 0;
56
  int short_op = ((insn & 0x0600) != 0x0600);
57
  int bytes_read;
58
  int target_processor;
59
 
60
  /* Special case: 32 bit MOV.  */
61
  if ((insn & 0xffe0) == 0x0620)
62
    short_op = 1;
63
 
64
  bytes_read = short_op ? 2 : 4;
65
 
66
  /* If this is a two byte insn, then mask off the high bits.  */
67
  if (short_op)
68
    insn &= 0xffff;
69
 
70
  switch (info->mach)
71
    {
72
    case 0:
73
    default:
74
      target_processor = PROCESSOR_V850;
75
      break;
76
 
77
    case bfd_mach_v850e:
78
      target_processor = PROCESSOR_V850E;
79
      break;
80
 
81
    case bfd_mach_v850e1:
82
      target_processor = PROCESSOR_V850E1;
83
      break;
84
    }
85
 
86
  /* Find the opcode.  */
87
  while (op->name)
88
    {
89
      if ((op->mask & insn) == op->opcode
90
          && (op->processors & target_processor))
91
        {
92
          const unsigned char *opindex_ptr;
93
          unsigned int opnum;
94
          unsigned int memop;
95
 
96
          match = 1;
97
          (*info->fprintf_func) (info->stream, "%s\t", op->name);
98
 
99
          memop = op->memop;
100
          /* Now print the operands.
101
 
102
             MEMOP is the operand number at which a memory
103
             address specification starts, or zero if this
104
             instruction has no memory addresses.
105
 
106
             A memory address is always two arguments.
107
 
108
             This information allows us to determine when to
109
             insert commas into the output stream as well as
110
             when to insert disp[reg] expressions onto the
111
             output stream.  */
112
 
113
          for (opindex_ptr = op->operands, opnum = 1;
114
               *opindex_ptr != 0;
115
               opindex_ptr++, opnum++)
116
            {
117
              long value;
118
              int flag;
119
              int status;
120
              bfd_byte buffer[4];
121
 
122
              operand = &v850_operands[*opindex_ptr];
123
 
124
              if (operand->extract)
125
                value = (operand->extract) (insn, 0);
126
              else
127
                {
128
                  if (operand->bits == -1)
129
                    value = (insn & operand->shift);
130
                  else
131
                    value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
132
 
133
                  if (operand->flags & V850_OPERAND_SIGNED)
134
                    value = ((long)(value << (32 - operand->bits))
135
                             >> (32 - operand->bits));
136
                }
137
 
138
              /* The first operand is always output without any
139
                 special handling.
140
 
141
                 For the following arguments:
142
 
143
                   If memop && opnum == memop + 1, then we need '[' since
144
                   we're about to output the register used in a memory
145
                   reference.
146
 
147
                   If memop && opnum == memop + 2, then we need ']' since
148
                   we just finished the register in a memory reference.  We
149
                   also need a ',' before this operand.
150
 
151
                   Else we just need a comma.
152
 
153
                   We may need to output a trailing ']' if the last operand
154
                   in an instruction is the register for a memory address.
155
 
156
                   The exception (and there's always an exception) is the
157
                   "jmp" insn which needs square brackets around it's only
158
                   register argument.  */
159
 
160
                   if (memop && opnum == memop + 1)
161
                     info->fprintf_func (info->stream, "[");
162
                   else if (memop && opnum == memop + 2)
163
                     info->fprintf_func (info->stream, "],");
164
                   else if (memop == 1 && opnum == 1
165
                            && (operand->flags & V850_OPERAND_REG))
166
                     info->fprintf_func (info->stream, "[");
167
                   else if (opnum > 1)
168
                     info->fprintf_func (info->stream, ", ");
169
 
170
              /* Extract the flags, ignorng ones which
171
                 do not effect disassembly output. */
172
              flag = operand->flags;
173
              flag &= ~ V850_OPERAND_SIGNED;
174
              flag &= ~ V850_OPERAND_RELAX;
175
              flag &= - flag;
176
 
177
              switch (flag)
178
                {
179
                case V850_OPERAND_REG:
180
                  info->fprintf_func (info->stream, "%s", v850_reg_names[value]);
181
                  break;
182
                case V850_OPERAND_SRG:
183
                  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]);
184
                  break;
185
                case V850_OPERAND_CC:
186
                  info->fprintf_func (info->stream, "%s", v850_cc_names[value]);
187
                  break;
188
                case V850_OPERAND_EP:
189
                  info->fprintf_func (info->stream, "ep");
190
                  break;
191
                default:
192
                  info->fprintf_func (info->stream, "%ld", value);
193
                  break;
194
                case V850_OPERAND_DISP:
195
                  {
196
                    bfd_vma addr = value + memaddr;
197
 
198
                    /* On the v850 the top 8 bits of an address are used by an
199
                       overlay manager.  Thus it may happen that when we are
200
                       looking for a symbol to match against an address with
201
                       some of its top bits set, the search fails to turn up an
202
                       exact match.  In this case we try to find an exact match
203
                       against a symbol in the lower address space, and if we
204
                       find one, we use that address.   We only do this for
205
                       JARL instructions however, as we do not want to
206
                       misinterpret branch instructions.  */
207
                    if (operand->bits == 22)
208
                      {
209
                        if ( ! info->symbol_at_address_func (addr, info)
210
                            && ((addr & 0xFF000000) != 0)
211
                            && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
212
                          addr &= 0x00FFFFFF;
213
                      }
214
                    info->print_address_func (addr, info);
215
                    break;
216
                  }
217
 
218
                case V850E_PUSH_POP:
219
                  {
220
                    static int list12_regs[32]   = { 30,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
221
                    static int list18_h_regs[32] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
222
                    static int list18_l_regs[32] = {  3,  2,  1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 14, 15, 13, 12,  7,  6,  5,  4, 11, 10,  9,  8 };
223
                    int *regs;
224
                    int i;
225
                    unsigned long int mask = 0;
226
                    int pc = 0;
227
                    int sr = 0;
228
 
229
                    switch (operand->shift)
230
                      {
231
                      case 0xffe00001: regs = list12_regs; break;
232
                      case 0xfff8000f: regs = list18_h_regs; break;
233
                      case 0xfff8001f:
234
                        regs = list18_l_regs;
235
                        value &= ~0x10;  /* Do not include magic bit.  */
236
                          break;
237
                      default:
238
                        /* xgettext:c-format */
239
                        fprintf (stderr, _("unknown operand shift: %x\n"),
240
                                 operand->shift);
241
                        abort ();
242
                      }
243
 
244
                    for (i = 0; i < 32; i++)
245
                      {
246
                        if (value & (1 << i))
247
                          {
248
                            switch (regs[ i ])
249
                              {
250
                              default: mask |= (1 << regs[ i ]); break;
251
                                /* xgettext:c-format */
252
                              case 0:
253
                                fprintf (stderr, _("unknown pop reg: %d\n"), i );
254
                                abort ();
255
                              case -1: pc = 1; break;
256
                              case -2: sr = 1; break;
257
                              }
258
                          }
259
                      }
260
 
261
                    info->fprintf_func (info->stream, "{");
262
 
263
                    if (mask || pc || sr)
264
                      {
265
                        if (mask)
266
                          {
267
                            unsigned int bit;
268
                            int shown_one = 0;
269
 
270
                            for (bit = 0; bit < 32; bit++)
271
                              if (mask & (1 << bit))
272
                                {
273
                                  unsigned long int first = bit;
274
                                  unsigned long int last;
275
 
276
                                  if (shown_one)
277
                                    info->fprintf_func (info->stream, ", ");
278
                                  else
279
                                    shown_one = 1;
280
 
281
                                  info->fprintf_func (info->stream,
282
                                                      v850_reg_names[first]);
283
 
284
                                  for (bit++; bit < 32; bit++)
285
                                    if ((mask & (1 << bit)) == 0)
286
                                      break;
287
 
288
                                  last = bit;
289
 
290
                                  if (last > first + 1)
291
                                    info->fprintf_func (info->stream, " - %s",
292
                                                        v850_reg_names[last - 1]);
293
                                }
294
                          }
295
 
296
                        if (pc)
297
                          info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
298
                        if (sr)
299
                          info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
300
                      }
301
 
302
                    info->fprintf_func (info->stream, "}");
303
                  }
304
                break;
305
 
306
                case V850E_IMMEDIATE16:
307
                  status = info->read_memory_func (memaddr + bytes_read,
308
                                                   buffer, 2, info);
309
                  if (status == 0)
310
                    {
311
                      bytes_read += 2;
312
                      value = bfd_getl16 (buffer);
313
 
314
                      /* If this is a DISPOSE instruction with ff
315
                         set to 0x10, then shift value up by 16.  */
316
                      if ((insn & 0x001fffc0) == 0x00130780)
317
                        value <<= 16;
318
 
319
                      info->fprintf_func (info->stream, "0x%lx", value);
320
                    }
321
                  else
322
                    info->memory_error_func (status, memaddr + bytes_read,
323
                                             info);
324
                  break;
325
 
326
                case V850E_IMMEDIATE32:
327
                  status = info->read_memory_func (memaddr + bytes_read,
328
                                                   buffer, 4, info);
329
                  if (status == 0)
330
                    {
331
                      bytes_read += 4;
332
                      value = bfd_getl32 (buffer);
333
                      info->fprintf_func (info->stream, "0x%lx", value);
334
                    }
335
                  else
336
                    info->memory_error_func (status, memaddr + bytes_read,
337
                                             info);
338
                  break;
339
                }
340
 
341
              /* Handle jmp correctly.  */
342
              if (memop == 1 && opnum == 1
343
                  && ((operand->flags & V850_OPERAND_REG) != 0))
344
                (*info->fprintf_func) (info->stream, "]");
345
            }
346
 
347
          /* Close any square bracket we left open.  */
348
          if (memop && opnum == memop + 2)
349
            (*info->fprintf_func) (info->stream, "]");
350
 
351
          /* All done. */
352
          break;
353
        }
354
      op++;
355
    }
356
 
357
  if (!match)
358
    {
359
      if (short_op)
360
        info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
361
      else
362
        info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
363
    }
364
 
365
  return bytes_read;
366
}
367
 
368
int
369
print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
370
{
371
  int status;
372
  bfd_byte buffer[4];
373
  unsigned long insn = 0;
374
 
375
  /* First figure out how big the opcode is.  */
376
  status = info->read_memory_func (memaddr, buffer, 2, info);
377
  if (status == 0)
378
    {
379
      insn = bfd_getl16 (buffer);
380
 
381
      if (   (insn & 0x0600) == 0x0600
382
          && (insn & 0xffe0) != 0x0620)
383
        {
384
          /* If this is a 4 byte insn, read 4 bytes of stuff.  */
385
          status = info->read_memory_func (memaddr, buffer, 4, info);
386
 
387
          if (status == 0)
388
            insn = bfd_getl32 (buffer);
389
        }
390
    }
391
 
392
  if (status != 0)
393
    {
394
      info->memory_error_func (status, memaddr, info);
395
      return -1;
396
    }
397
 
398
  /* Make sure we tell our caller how many bytes we consumed.  */
399
  return disassemble (memaddr, info, insn);
400
}

powered by: WebSVN 2.1.0

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