d4ea62b505dfff86bc4dbbd622ad957e6aa4e0e8
[external/binutils.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   ia64_free_opcode (idesc);
258   if (slotnum == 2)
259     retval += 16 - 3*slot_multiplier;
260   return retval;
261
262  decoding_failed:
263   (*info->fprintf_func) (info->stream, "      data8 %#011llx", insn);
264   goto done;
265 }