1 /* ia64-dis.c -- Disassemble ia64 instructions
2    Copyright 1998, 1999, 2000, 2002 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
unit_to_type(ia64_insn opcode,enum ia64_unit unit)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
print_insn_ia64(bfd_vma memaddr,struct disassemble_info * info)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 }
274