IA-64 ELF support.
[deliverable/binutils-gdb.git] / opcodes / ia64-dis.c
1 /* ia64-dis.c -- Disassemble ia64 instructions
2 Copyright (C) 1998, 1999 Free Software Foundation, Inc.
3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5 This file is part of GDB, GAS, and the GNU binutils.
6
7 GDB, GAS, and the GNU binutils are free software; you can redistribute
8 them and/or modify them under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either version
10 2, or (at your option) any later version.
11
12 GDB, GAS, and the GNU binutils are distributed in the hope that they
13 will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21
22 #include <assert.h>
23 #include <string.h>
24
25 #include "dis-asm.h"
26 #include "opcode/ia64.h"
27
28 #define NELEMS(a) ((int) (sizeof (a) / sizeof (a[0])))
29
30 /* Disassemble ia64 instruction. */
31
32 /* Return the instruction type for OPCODE found in unit UNIT. */
33
34 static enum ia64_insn_type
35 unit_to_type (ia64_insn opcode, enum ia64_unit unit)
36 {
37 enum ia64_insn_type type;
38 int op;
39
40 op = IA64_OP (opcode);
41
42 if (op >= 8 && (unit == IA64_UNIT_I || unit == IA64_UNIT_M))
43 {
44 type = IA64_TYPE_A;
45 }
46 else
47 {
48 switch (unit)
49 {
50 case IA64_UNIT_I:
51 type = IA64_TYPE_I; break;
52 case IA64_UNIT_M:
53 type = IA64_TYPE_M; break;
54 case IA64_UNIT_B:
55 type = IA64_TYPE_B; break;
56 case IA64_UNIT_F:
57 type = IA64_TYPE_F; break;
58 case IA64_UNIT_L:
59 case IA64_UNIT_X:
60 type = IA64_TYPE_X; break;
61 default:
62 type = -1;
63 }
64 }
65 return type;
66 }
67
68 int
69 print_insn_ia64 (bfd_vma memaddr, struct disassemble_info *info)
70 {
71 ia64_insn t0, t1, slot[3], template, s_bit, insn;
72 int slotnum, j, status, need_comma, retval, slot_multiplier;
73 const struct ia64_operand *odesc;
74 const struct ia64_opcode *idesc;
75 const char *err, *str, *tname;
76 BFD_HOST_U_64_BIT value;
77 bfd_byte bundle[16];
78 enum ia64_unit unit;
79 char regname[16];
80
81 if (info->bytes_per_line == 0)
82 info->bytes_per_line = 6;
83 info->display_endian = info->endian;
84
85 slot_multiplier = info->bytes_per_line;
86 retval = slot_multiplier;
87
88 slotnum = (((long) memaddr) & 0xf) / slot_multiplier;
89 if (slotnum > 2)
90 return -1;
91
92 memaddr -= (memaddr & 0xf);
93 status = (*info->read_memory_func) (memaddr, bundle, sizeof (bundle), info);
94 if (status != 0)
95 {
96 (*info->memory_error_func) (status, memaddr, info);
97 return -1;
98 }
99 /* bundles are always in little-endian byte order */
100 t0 = bfd_getl64 (bundle);
101 t1 = bfd_getl64 (bundle + 8);
102 s_bit = t0 & 1;
103 template = (t0 >> 1) & 0xf;
104 slot[0] = (t0 >> 5) & 0x1ffffffffffLL;
105 slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
106 slot[2] = (t1 >> 23) & 0x1ffffffffffLL;
107
108 tname = ia64_templ_desc[template].name;
109 if (slotnum == 0)
110 (*info->fprintf_func) (info->stream, "[%s] ", tname);
111 else
112 (*info->fprintf_func) (info->stream, " ", tname);
113
114 unit = ia64_templ_desc[template].exec_unit[slotnum];
115
116 if (template == 2 && slotnum == 1)
117 {
118 /* skip L slot in MLI template: */
119 slotnum = 2;
120 retval += slot_multiplier;
121 }
122
123 insn = slot[slotnum];
124
125 if (unit == IA64_UNIT_NIL)
126 goto decoding_failed;
127
128 idesc = ia64_dis_opcode (insn, unit_to_type (insn, unit));
129 if (idesc == NULL)
130 goto decoding_failed;
131
132 /* print predicate, if any: */
133
134 if ((idesc->flags & IA64_OPCODE_NO_PRED)
135 || (insn & 0x3f) == 0)
136 (*info->fprintf_func) (info->stream, " ");
137 else
138 (*info->fprintf_func) (info->stream, "(p%02d) ", (int)(insn & 0x3f));
139
140 /* now the actual instruction: */
141
142 (*info->fprintf_func) (info->stream, "%s", idesc->name);
143 if (idesc->operands[0])
144 (*info->fprintf_func) (info->stream, " ");
145
146 need_comma = 0;
147 for (j = 0; j < NELEMS (idesc->operands) && idesc->operands[j]; ++j)
148 {
149 odesc = elf64_ia64_operands + idesc->operands[j];
150
151 if (need_comma)
152 (*info->fprintf_func) (info->stream, ",");
153
154 if (odesc - elf64_ia64_operands == IA64_OPND_IMMU64)
155 {
156 /* special case of 64 bit immediate load: */
157 value = ((insn >> 13) & 0x7f) | (((insn >> 27) & 0x1ff) << 7)
158 | (((insn >> 22) & 0x1f) << 16) | (((insn >> 21) & 0x1) << 21)
159 | (slot[1] << 22) | (((insn >> 36) & 0x1) << 63);
160 }
161 else if (odesc - elf64_ia64_operands == IA64_OPND_IMMU62)
162 {
163 /* 62-bit immediate for nop.x/break.x */
164 value = ((slot[1] & 0x1ffffffffffLL) << 21)
165 | (((insn >> 36) & 0x1) << 20)
166 | ((insn >> 6) & 0xfffff);
167 }
168 else
169 {
170 err = (*odesc->extract) (odesc, insn, &value);
171 if (err)
172 {
173 (*info->fprintf_func) (info->stream, "%s", err);
174 goto done;
175 }
176 }
177
178 switch (odesc->class)
179 {
180 case IA64_OPND_CLASS_CST:
181 (*info->fprintf_func) (info->stream, "%s", odesc->str);
182 break;
183
184 case IA64_OPND_CLASS_REG:
185 if (odesc->str[0] == 'a' && odesc->str[1] == 'r')
186 {
187 switch (value)
188 {
189 case 0: case 1: case 2: case 3:
190 case 4: case 5: case 6: case 7:
191 sprintf (regname, "ar.k%u", (unsigned int) value);
192 break;
193 case 16: strcpy (regname, "ar.rsc"); break;
194 case 17: strcpy (regname, "ar.bsp"); break;
195 case 18: strcpy (regname, "ar.bspstore"); break;
196 case 19: strcpy (regname, "ar.rnat"); break;
197 case 32: strcpy (regname, "ar.ccv"); break;
198 case 36: strcpy (regname, "ar.unat"); break;
199 case 40: strcpy (regname, "ar.fpsr"); break;
200 case 44: strcpy (regname, "ar.itc"); break;
201 case 64: strcpy (regname, "ar.pfs"); break;
202 case 65: strcpy (regname, "ar.lc"); break;
203 case 66: strcpy (regname, "ar.ec"); break;
204 default:
205 sprintf (regname, "ar%u", (unsigned int) value);
206 break;
207 }
208 (*info->fprintf_func) (info->stream, "%s", regname);
209 }
210 else
211 (*info->fprintf_func) (info->stream, "%s%d", odesc->str, (int)value);
212 break;
213
214 case IA64_OPND_CLASS_IND:
215 (*info->fprintf_func) (info->stream, "%s[r%d]", odesc->str, (int)value);
216 break;
217
218 case IA64_OPND_CLASS_ABS:
219 str = 0;
220 if (odesc - elf64_ia64_operands == IA64_OPND_MBTYPE4)
221 switch (value)
222 {
223 case 0x0: str = "@brcst"; break;
224 case 0x8: str = "@mix"; break;
225 case 0x9: str = "@shuf"; break;
226 case 0xa: str = "@alt"; break;
227 case 0xb: str = "@rev"; break;
228 }
229
230 if (str)
231 (*info->fprintf_func) (info->stream, "%s", str);
232 else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_SIGNED)
233 (*info->fprintf_func) (info->stream, "%lld", value);
234 else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED)
235 (*info->fprintf_func) (info->stream, "%llu", value);
236 else
237 (*info->fprintf_func) (info->stream, "0x%llx", value);
238 break;
239
240 case IA64_OPND_CLASS_REL:
241 (*info->print_address_func) (memaddr + value, info);
242 break;
243 }
244
245 need_comma = 1;
246 if (j + 1 == idesc->num_outputs)
247 {
248 (*info->fprintf_func) (info->stream, "=");
249 need_comma = 0;
250 }
251 }
252 if (slotnum + 1 == ia64_templ_desc[template].group_boundary
253 || ((slotnum == 2) && s_bit))
254 (*info->fprintf_func) (info->stream, ";;");
255
256 done:
257 if (slotnum == 2)
258 retval += 16 - 3*slot_multiplier;
259 return retval;
260
261 decoding_failed:
262 (*info->fprintf_func) (info->stream, " data8 %#011llx", insn);
263 goto done;
264 }
This page took 0.036805 seconds and 4 git commands to generate.