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