2003-09-03 Dave Brolley <brolley@redhat.com>
[external/binutils.git] / opcodes / ia64-dis.c
1 /* ia64-dis.c -- Disassemble ia64 instructions
2    Copyright 1998, 1999, 2000 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 if (odesc - elf64_ia64_operands == IA64_OPND_TGT64)
169         {
170           /* 60-bit immediate for long branches. */
171           value = (((insn >> 13) & 0xfffff)
172                    | (((insn >> 36) & 1) << 59)
173                    | (((slot[1] >> 2) & 0x7fffffffffLL) << 20)) << 4;
174         }
175       else
176         {
177           err = (*odesc->extract) (odesc, insn, &value);
178           if (err)
179             {
180               (*info->fprintf_func) (info->stream, "%s", err);
181               goto done;
182             }
183         }
184
185         switch (odesc->class)
186           {
187           case IA64_OPND_CLASS_CST:
188             (*info->fprintf_func) (info->stream, "%s", odesc->str);
189             break;
190
191           case IA64_OPND_CLASS_REG:
192             if (odesc->str[0] == 'a' && odesc->str[1] == 'r')
193               {
194                 switch (value)
195                   {
196                   case 0: case 1: case 2: case 3:
197                   case 4: case 5: case 6: case 7:
198                     sprintf (regname, "ar.k%u", (unsigned int) value);
199                     break;
200                   case 16:      strcpy (regname, "ar.rsc"); break;
201                   case 17:      strcpy (regname, "ar.bsp"); break;
202                   case 18:      strcpy (regname, "ar.bspstore"); break;
203                   case 19:      strcpy (regname, "ar.rnat"); break;
204                   case 32:      strcpy (regname, "ar.ccv"); break;
205                   case 36:      strcpy (regname, "ar.unat"); break;
206                   case 40:      strcpy (regname, "ar.fpsr"); break;
207                   case 44:      strcpy (regname, "ar.itc"); break;
208                   case 64:      strcpy (regname, "ar.pfs"); break;
209                   case 65:      strcpy (regname, "ar.lc"); break;
210                   case 66:      strcpy (regname, "ar.ec"); break;
211                   default:
212                     sprintf (regname, "ar%u", (unsigned int) value);
213                     break;
214                   }
215                 (*info->fprintf_func) (info->stream, "%s", regname);
216               }
217             else
218               (*info->fprintf_func) (info->stream, "%s%d", odesc->str, (int)value);
219             break;
220
221           case IA64_OPND_CLASS_IND:
222             (*info->fprintf_func) (info->stream, "%s[r%d]", odesc->str, (int)value);
223             break;
224
225           case IA64_OPND_CLASS_ABS:
226             str = 0;
227             if (odesc - elf64_ia64_operands == IA64_OPND_MBTYPE4)
228               switch (value)
229                 {
230                 case 0x0: str = "@brcst"; break;
231                 case 0x8: str = "@mix"; break;
232                 case 0x9: str = "@shuf"; break;
233                 case 0xa: str = "@alt"; break;
234                 case 0xb: str = "@rev"; break;
235                 }
236
237             if (str)
238               (*info->fprintf_func) (info->stream, "%s", str);
239             else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_SIGNED)
240               (*info->fprintf_func) (info->stream, "%lld", value);
241             else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED)
242               (*info->fprintf_func) (info->stream, "%llu", value);
243             else
244               (*info->fprintf_func) (info->stream, "0x%llx", value);
245             break;
246
247           case IA64_OPND_CLASS_REL:
248             (*info->print_address_func) (memaddr + value, info);
249             break;
250           }
251
252       need_comma = 1;
253       if (j + 1 == idesc->num_outputs)
254         {
255           (*info->fprintf_func) (info->stream, "=");
256           need_comma = 0;
257         }
258     }
259   if (slotnum + 1 == ia64_templ_desc[template].group_boundary 
260       || ((slotnum == 2) && s_bit))
261     (*info->fprintf_func) (info->stream, ";;");
262
263  done:
264   ia64_free_opcode ((struct ia64_opcode *)idesc);
265  failed:
266   if (slotnum == 2)
267     retval += 16 - 3*slot_multiplier;
268   return retval;
269
270  decoding_failed:
271   (*info->fprintf_func) (info->stream, "      data8 %#011llx", insn);
272   goto failed;
273 }