* arc-dis.c (print_insn_arc): Rename to print_insn and make static.
[deliverable/binutils-gdb.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_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 }
This page took 0.051604 seconds and 5 git commands to generate.