OSDN Git Service

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