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, 51 Franklin Street - Fifth Floor, Boston, MA
20   02110-1301, 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
34static enum ia64_insn_type
35unit_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
68int
69print_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, "      ");
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", (long long) value);
241	    else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED)
242	      (*info->fprintf_func) (info->stream, "%llu", (long long) value);
243	    else
244	      (*info->fprintf_func) (info->stream, "0x%llx", (long long) 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", (long long) insn);
272  goto failed;
273}
274