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

Subversion Repositories or1k

[/] [or1k/] [branches/] [oc/] [gdb-5.0/] [opcodes/] [arc-dis.c] - Blame information for rev 106

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

Line No. Rev Author Line
1 106 markom
/* Instruction printing code for the ARC.
2
   Copyright (C) 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
3
   Contributed by Doug Evans (dje@cygnus.com).
4
 
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
9
 
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
 
19
#include "dis-asm.h"
20
#include "opcode/arc.h"
21
#include "elf-bfd.h"
22
#include "elf/arc.h"
23
#include "opintl.h"
24
 
25
static int print_insn_arc_base_little PARAMS ((bfd_vma, disassemble_info *));
26
static int print_insn_arc_base_big PARAMS ((bfd_vma, disassemble_info *));
27
 
28
static int print_insn PARAMS ((bfd_vma, disassemble_info *, int, int));
29
 
30
/* Print one instruction from PC on INFO->STREAM.
31
   Return the size of the instruction (4 or 8 for the ARC). */
32
 
33
static int
34
print_insn (pc, info, mach, big_p)
35
     bfd_vma pc;
36
     disassemble_info *info;
37
     int mach;
38
     int big_p;
39
{
40
  const struct arc_opcode *opcode;
41
  bfd_byte buffer[4];
42
  void *stream = info->stream;
43
  fprintf_ftype func = info->fprintf_func;
44
  int status;
45
  /* First element is insn, second element is limm (if present).  */
46
  arc_insn insn[2];
47
  int got_limm_p = 0;
48
  static int initialized = 0;
49
  static int current_mach = 0;
50
 
51
  if (!initialized || mach != current_mach)
52
    {
53
      initialized = 1;
54
      current_mach = arc_get_opcode_mach (mach, big_p);
55
      arc_opcode_init_tables (current_mach);
56
    }
57
 
58
  status = (*info->read_memory_func) (pc, buffer, 4, info);
59
  if (status != 0)
60
    {
61
      (*info->memory_error_func) (status, pc, info);
62
      return -1;
63
    }
64
  if (big_p)
65
    insn[0] = bfd_getb32 (buffer);
66
  else
67
    insn[0] = bfd_getl32 (buffer);
68
 
69
  (*func) (stream, "%08lx\t", insn[0]);
70
 
71
  /* The instructions are stored in lists hashed by the insn code
72
     (though we needn't care how they're hashed).  */
73
 
74
  opcode = arc_opcode_lookup_dis (insn[0]);
75
  for ( ; opcode != NULL; opcode = ARC_OPCODE_NEXT_DIS (opcode))
76
    {
77
      char *syn;
78
      int mods,invalid;
79
      long value;
80
      const struct arc_operand *operand;
81
      const struct arc_operand_value *opval;
82
 
83
      /* Basic bit mask must be correct.  */
84
      if ((insn[0] & opcode->mask) != opcode->value)
85
        continue;
86
 
87
      /* Supported by this cpu?  */
88
      if (! arc_opcode_supported (opcode))
89
        continue;
90
 
91
      /* Make two passes over the operands.  First see if any of them
92
         have extraction functions, and, if they do, make sure the
93
         instruction is valid.  */
94
 
95
      arc_opcode_init_extract ();
96
      invalid = 0;
97
 
98
      /* ??? Granted, this is slower than the `ppc' way.  Maybe when this is
99
         done it'll be clear what the right way to do this is.  */
100
      /* Instructions like "add.f r0,r1,1" are tricky because the ".f" gets
101
         printed first, but we don't know how to print it until we've processed
102
         the regs.  Since we're scanning all the args before printing the insn
103
         anyways, it's actually quite easy.  */
104
 
105
      for (syn = opcode->syntax; *syn; ++syn)
106
        {
107
          int c;
108
 
109
          if (*syn != '%' || *++syn == '%')
110
            continue;
111
          mods = 0;
112
          c = *syn;
113
          while (ARC_MOD_P (arc_operands[arc_operand_map[c]].flags))
114
            {
115
              mods |= arc_operands[arc_operand_map[c]].flags & ARC_MOD_BITS;
116
              ++syn;
117
              c = *syn;
118
            }
119
          operand = arc_operands + arc_operand_map[c];
120
          if (operand->extract)
121
            (*operand->extract) (insn, operand, mods,
122
                                 (const struct arc_operand_value **) NULL,
123
                                 &invalid);
124
        }
125
      if (invalid)
126
        continue;
127
 
128
      /* The instruction is valid.  */
129
 
130
      /* If we have an insn with a limm, fetch it now.  Scanning the insns
131
         twice lets us do this.  */
132
      if (arc_opcode_limm_p (NULL))
133
        {
134
          status = (*info->read_memory_func) (pc + 4, buffer, 4, info);
135
          if (status != 0)
136
            {
137
              (*info->memory_error_func) (status, pc, info);
138
              return -1;
139
            }
140
          if (big_p)
141
            insn[1] = bfd_getb32 (buffer);
142
          else
143
            insn[1] = bfd_getl32 (buffer);
144
          got_limm_p = 1;
145
        }
146
 
147
      for (syn = opcode->syntax; *syn; ++syn)
148
        {
149
          int c;
150
 
151
          if (*syn != '%' || *++syn == '%')
152
            {
153
              (*func) (stream, "%c", *syn);
154
              continue;
155
            }
156
 
157
          /* We have an operand.  Fetch any special modifiers.  */
158
          mods = 0;
159
          c = *syn;
160
          while (ARC_MOD_P (arc_operands[arc_operand_map[c]].flags))
161
            {
162
              mods |= arc_operands[arc_operand_map[c]].flags & ARC_MOD_BITS;
163
              ++syn;
164
              c = *syn;
165
            }
166
          operand = arc_operands + arc_operand_map[c];
167
 
168
          /* Extract the value from the instruction.  */
169
          opval = NULL;
170
          if (operand->extract)
171
            {
172
              value = (*operand->extract) (insn, operand, mods,
173
                                           &opval, (int *) NULL);
174
            }
175
          else
176
            {
177
              value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
178
              if ((operand->flags & ARC_OPERAND_SIGNED)
179
                  && (value & (1 << (operand->bits - 1))))
180
                value -= 1 << operand->bits;
181
 
182
              /* If this is a suffix operand, set `opval'.  */
183
              if (operand->flags & ARC_OPERAND_SUFFIX)
184
                opval = arc_opcode_lookup_suffix (operand, value);
185
            }
186
 
187
          /* Print the operand as directed by the flags.  */
188
          if (operand->flags & ARC_OPERAND_FAKE)
189
            ; /* nothing to do (??? at least not yet) */
190
          else if (operand->flags & ARC_OPERAND_SUFFIX)
191
            {
192
              /* Default suffixes aren't printed.  Fortunately, they all have
193
                 zero values.  Also, zero values for boolean suffixes are
194
                 represented by the absence of text.  */
195
 
196
              if (value != 0)
197
                {
198
                  /* ??? OPVAL should have a value.  If it doesn't just cope
199
                     as we want disassembly to be reasonably robust.
200
                     Also remember that several condition code values (16-31)
201
                     aren't defined yet.  For these cases just print the
202
                     number suitably decorated.  */
203
                  if (opval)
204
                    (*func) (stream, "%s%s",
205
                             mods & ARC_MOD_DOT ? "." : "",
206
                             opval->name);
207
                  else
208
                    (*func) (stream, "%s%c%d",
209
                             mods & ARC_MOD_DOT ? "." : "",
210
                             operand->fmt, value);
211
                }
212
            }
213
          else if (operand->flags & ARC_OPERAND_RELATIVE_BRANCH)
214
            (*info->print_address_func) (pc + 4 + value, info);
215
          /* ??? Not all cases of this are currently caught.  */
216
          else if (operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH)
217
            (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
218
          else if (operand->flags & ARC_OPERAND_ADDRESS)
219
            (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
220
          else if (opval)
221
            /* Note that this case catches both normal and auxiliary regs.  */
222
            (*func) (stream, "%s", opval->name);
223
          else
224
            (*func) (stream, "%ld", value);
225
        }
226
 
227
      /* We have found and printed an instruction; return.  */
228
      return got_limm_p ? 8 : 4;
229
    }
230
 
231
  (*func) (stream, _("*unknown*"));
232
  return 4;
233
}
234
 
235
/* Given MACH, one of bfd_mach_arc_xxx, return the print_insn function to use.
236
   This does things a non-standard way (the "standard" way would be to copy
237
   this code into disassemble.c).  Since there are more than a couple of
238
   variants, hiding all this crud here seems cleaner.  */
239
 
240
disassembler_ftype
241
arc_get_disassembler (mach, big_p)
242
     int mach;
243
     int big_p;
244
{
245
  switch (mach)
246
    {
247
    case bfd_mach_arc_base:
248
      return big_p ? print_insn_arc_base_big : print_insn_arc_base_little;
249
    }
250
  return print_insn_arc_base_little;
251
}
252
 
253
static int
254
print_insn_arc_base_little (pc, info)
255
     bfd_vma pc;
256
     disassemble_info *info;
257
{
258
  return print_insn (pc, info, bfd_mach_arc_base, 0);
259
}
260
 
261
static int
262
print_insn_arc_base_big (pc, info)
263
     bfd_vma pc;
264
     disassemble_info *info;
265
{
266
  return print_insn (pc, info, bfd_mach_arc_base, 1);
267
}

powered by: WebSVN 2.1.0

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