Separated out opcode aliases from m68k opcode table, to reduce table size and
[deliverable/binutils-gdb.git] / opcodes / arc-dis.c
CommitLineData
edb35c13 1/* Instruction printing code for the ARC.
98d42df9 2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
edb35c13
DE
3 Contributed by Doug Evans (dje@cygnus.com).
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation; either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18
19#include "dis-asm.h"
20#include "opcode/arc.h"
98d42df9
DE
21#include "libelf.h"
22#include "elf/arc.h"
23
24static int print_insn_arc_base PARAMS ((bfd_vma, disassemble_info *));
25static int print_insn_arc_host PARAMS ((bfd_vma, disassemble_info *));
26static int print_insn_arc_graphics PARAMS ((bfd_vma, disassemble_info *));
27static int print_insn_arc_audio PARAMS ((bfd_vma, disassemble_info *));
edb35c13
DE
28
29/* Print one instruction from PC on INFO->STREAM.
30 Return the size of the instruction (4 or 8 for the ARC). */
31
98d42df9
DE
32static int
33print_insn (pc, info, cpu)
edb35c13 34 bfd_vma pc;
98d42df9
DE
35 disassemble_info *info;
36 int cpu;
edb35c13
DE
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;
98d42df9
DE
47 static int current_cpu = 0;
48 /* Not used yet. Here to record byte order dependencies. */
49 int bigendian_p = 0;
edb35c13 50
98d42df9 51 if (!initialized || cpu != current_cpu)
edb35c13 52 {
98d42df9 53 arc_opcode_init_tables (cpu);
edb35c13 54 initialized = 1;
98d42df9 55 current_cpu = cpu;
edb35c13
DE
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 }
98d42df9
DE
64 if (bigendian_p)
65 insn[0] = bfd_getb32 (buffer);
66 else
67 insn[0] = bfd_getl32 (buffer);
edb35c13
DE
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
98d42df9 80 /* Basic bit mask must be correct. */
edb35c13
DE
81 if ((insn[0] & opcode->mask) != opcode->value)
82 continue;
83
98d42df9
DE
84 /* Supported by this cpu? */
85 if (! arc_opcode_supported (opcode))
86 continue;
87
edb35c13
DE
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
98d42df9 100 anyways, it's actually quite easy. */
edb35c13
DE
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 }
98d42df9
DE
133 if (bigendian_p)
134 insn[1] = bfd_getb32 (buffer);
135 else
136 insn[1] = bfd_getl32 (buffer);
edb35c13
DE
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)
98d42df9 203 (*info->print_address_func) (pc + 4 + value, info);
edb35c13
DE
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}
98d42df9
DE
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
227disassembler_ftype
c81a2ce3 228arc_get_disassembler (bfd *abfd)
98d42df9
DE
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
246static int
247print_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
256static int
257print_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
266static int
267print_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
276static int
277print_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.038145 seconds and 4 git commands to generate.