ia64-dis.c revision 130561
184865Sobrien/* ia64-dis.c -- Disassemble ia64 instructions 284865Sobrien Copyright 1998, 1999, 2000 Free Software Foundation, Inc. 384865Sobrien Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 484865Sobrien 584865Sobrien This file is part of GDB, GAS, and the GNU binutils. 684865Sobrien 784865Sobrien GDB, GAS, and the GNU binutils are free software; you can redistribute 884865Sobrien them and/or modify them under the terms of the GNU General Public 984865Sobrien License as published by the Free Software Foundation; either version 1084865Sobrien 2, or (at your option) any later version. 1184865Sobrien 1284865Sobrien GDB, GAS, and the GNU binutils are distributed in the hope that they 1384865Sobrien will be useful, but WITHOUT ANY WARRANTY; without even the implied 1484865Sobrien warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 1584865Sobrien the GNU General Public License for more details. 1684865Sobrien 1784865Sobrien You should have received a copy of the GNU General Public License 1884865Sobrien along with this file; see the file COPYING. If not, write to the 1984865Sobrien Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2084865Sobrien 02111-1307, USA. */ 2184865Sobrien 2284865Sobrien#include <assert.h> 2384865Sobrien#include <string.h> 2484865Sobrien 2584865Sobrien#include "dis-asm.h" 2684865Sobrien#include "opcode/ia64.h" 2784865Sobrien 2884865Sobrien#define NELEMS(a) ((int) (sizeof (a) / sizeof (a[0]))) 2984865Sobrien 3084865Sobrien/* Disassemble ia64 instruction. */ 3184865Sobrien 3284865Sobrien/* Return the instruction type for OPCODE found in unit UNIT. */ 3384865Sobrien 3484865Sobrienstatic enum ia64_insn_type 3584865Sobrienunit_to_type (ia64_insn opcode, enum ia64_unit unit) 3684865Sobrien{ 3784865Sobrien enum ia64_insn_type type; 3884865Sobrien int op; 3984865Sobrien 4084865Sobrien op = IA64_OP (opcode); 4184865Sobrien 4284865Sobrien if (op >= 8 && (unit == IA64_UNIT_I || unit == IA64_UNIT_M)) 4384865Sobrien { 4484865Sobrien type = IA64_TYPE_A; 4584865Sobrien } 4684865Sobrien else 4784865Sobrien { 4884865Sobrien switch (unit) 4984865Sobrien { 5084865Sobrien case IA64_UNIT_I: 5184865Sobrien type = IA64_TYPE_I; break; 5284865Sobrien case IA64_UNIT_M: 5384865Sobrien type = IA64_TYPE_M; break; 5484865Sobrien case IA64_UNIT_B: 5584865Sobrien type = IA64_TYPE_B; break; 5684865Sobrien case IA64_UNIT_F: 5784865Sobrien type = IA64_TYPE_F; break; 5884865Sobrien case IA64_UNIT_L: 5984865Sobrien case IA64_UNIT_X: 6084865Sobrien type = IA64_TYPE_X; break; 6184865Sobrien default: 6284865Sobrien type = -1; 6384865Sobrien } 6484865Sobrien } 6584865Sobrien return type; 6684865Sobrien} 6784865Sobrien 6884865Sobrienint 6984865Sobrienprint_insn_ia64 (bfd_vma memaddr, struct disassemble_info *info) 7084865Sobrien{ 7184865Sobrien ia64_insn t0, t1, slot[3], template, s_bit, insn; 7284865Sobrien int slotnum, j, status, need_comma, retval, slot_multiplier; 7384865Sobrien const struct ia64_operand *odesc; 7484865Sobrien const struct ia64_opcode *idesc; 7584865Sobrien const char *err, *str, *tname; 7684865Sobrien BFD_HOST_U_64_BIT value; 7784865Sobrien bfd_byte bundle[16]; 7884865Sobrien enum ia64_unit unit; 7984865Sobrien char regname[16]; 8084865Sobrien 8184865Sobrien if (info->bytes_per_line == 0) 8284865Sobrien info->bytes_per_line = 6; 8384865Sobrien info->display_endian = info->endian; 8484865Sobrien 8584865Sobrien slot_multiplier = info->bytes_per_line; 8684865Sobrien retval = slot_multiplier; 8784865Sobrien 8884865Sobrien slotnum = (((long) memaddr) & 0xf) / slot_multiplier; 8984865Sobrien if (slotnum > 2) 9084865Sobrien return -1; 9184865Sobrien 9284865Sobrien memaddr -= (memaddr & 0xf); 9384865Sobrien status = (*info->read_memory_func) (memaddr, bundle, sizeof (bundle), info); 9484865Sobrien if (status != 0) 9584865Sobrien { 9684865Sobrien (*info->memory_error_func) (status, memaddr, info); 9784865Sobrien return -1; 9884865Sobrien } 9984865Sobrien /* bundles are always in little-endian byte order */ 10084865Sobrien t0 = bfd_getl64 (bundle); 10184865Sobrien t1 = bfd_getl64 (bundle + 8); 10284865Sobrien s_bit = t0 & 1; 10384865Sobrien template = (t0 >> 1) & 0xf; 10484865Sobrien slot[0] = (t0 >> 5) & 0x1ffffffffffLL; 10584865Sobrien slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18); 10684865Sobrien slot[2] = (t1 >> 23) & 0x1ffffffffffLL; 10784865Sobrien 10884865Sobrien tname = ia64_templ_desc[template].name; 10984865Sobrien if (slotnum == 0) 11084865Sobrien (*info->fprintf_func) (info->stream, "[%s] ", tname); 11184865Sobrien else 11284865Sobrien (*info->fprintf_func) (info->stream, " ", tname); 11384865Sobrien 11484865Sobrien unit = ia64_templ_desc[template].exec_unit[slotnum]; 11584865Sobrien 11684865Sobrien if (template == 2 && slotnum == 1) 11784865Sobrien { 11884865Sobrien /* skip L slot in MLI template: */ 11984865Sobrien slotnum = 2; 12084865Sobrien retval += slot_multiplier; 12184865Sobrien } 12284865Sobrien 12384865Sobrien insn = slot[slotnum]; 12484865Sobrien 12584865Sobrien if (unit == IA64_UNIT_NIL) 12684865Sobrien goto decoding_failed; 12784865Sobrien 12884865Sobrien idesc = ia64_dis_opcode (insn, unit_to_type (insn, unit)); 12984865Sobrien if (idesc == NULL) 13084865Sobrien goto decoding_failed; 13184865Sobrien 13284865Sobrien /* print predicate, if any: */ 13384865Sobrien 13484865Sobrien if ((idesc->flags & IA64_OPCODE_NO_PRED) 13584865Sobrien || (insn & 0x3f) == 0) 13684865Sobrien (*info->fprintf_func) (info->stream, " "); 13784865Sobrien else 13884865Sobrien (*info->fprintf_func) (info->stream, "(p%02d) ", (int)(insn & 0x3f)); 13984865Sobrien 14084865Sobrien /* now the actual instruction: */ 14184865Sobrien 14284865Sobrien (*info->fprintf_func) (info->stream, "%s", idesc->name); 14384865Sobrien if (idesc->operands[0]) 14484865Sobrien (*info->fprintf_func) (info->stream, " "); 14584865Sobrien 14684865Sobrien need_comma = 0; 14784865Sobrien for (j = 0; j < NELEMS (idesc->operands) && idesc->operands[j]; ++j) 14884865Sobrien { 14984865Sobrien odesc = elf64_ia64_operands + idesc->operands[j]; 15084865Sobrien 15184865Sobrien if (need_comma) 15284865Sobrien (*info->fprintf_func) (info->stream, ","); 15384865Sobrien 15484865Sobrien if (odesc - elf64_ia64_operands == IA64_OPND_IMMU64) 15584865Sobrien { 15684865Sobrien /* special case of 64 bit immediate load: */ 15784865Sobrien value = ((insn >> 13) & 0x7f) | (((insn >> 27) & 0x1ff) << 7) 15884865Sobrien | (((insn >> 22) & 0x1f) << 16) | (((insn >> 21) & 0x1) << 21) 15984865Sobrien | (slot[1] << 22) | (((insn >> 36) & 0x1) << 63); 16084865Sobrien } 16184865Sobrien else if (odesc - elf64_ia64_operands == IA64_OPND_IMMU62) 16284865Sobrien { 16384865Sobrien /* 62-bit immediate for nop.x/break.x */ 16484865Sobrien value = ((slot[1] & 0x1ffffffffffLL) << 21) 16584865Sobrien | (((insn >> 36) & 0x1) << 20) 16684865Sobrien | ((insn >> 6) & 0xfffff); 16784865Sobrien } 16884865Sobrien else if (odesc - elf64_ia64_operands == IA64_OPND_TGT64) 16984865Sobrien { 170130561Sobrien /* 60-bit immediate for long branches. */ 17184865Sobrien value = (((insn >> 13) & 0xfffff) 17284865Sobrien | (((insn >> 36) & 1) << 59) 173130561Sobrien | (((slot[1] >> 2) & 0x7fffffffffLL) << 20)) << 4; 17484865Sobrien } 17584865Sobrien else 17684865Sobrien { 17784865Sobrien err = (*odesc->extract) (odesc, insn, &value); 17884865Sobrien if (err) 17984865Sobrien { 18084865Sobrien (*info->fprintf_func) (info->stream, "%s", err); 18184865Sobrien goto done; 18284865Sobrien } 18384865Sobrien } 18484865Sobrien 18584865Sobrien switch (odesc->class) 18684865Sobrien { 18784865Sobrien case IA64_OPND_CLASS_CST: 18884865Sobrien (*info->fprintf_func) (info->stream, "%s", odesc->str); 18984865Sobrien break; 19084865Sobrien 19184865Sobrien case IA64_OPND_CLASS_REG: 19284865Sobrien if (odesc->str[0] == 'a' && odesc->str[1] == 'r') 19384865Sobrien { 19484865Sobrien switch (value) 19584865Sobrien { 19684865Sobrien case 0: case 1: case 2: case 3: 19784865Sobrien case 4: case 5: case 6: case 7: 19884865Sobrien sprintf (regname, "ar.k%u", (unsigned int) value); 19984865Sobrien break; 20084865Sobrien case 16: strcpy (regname, "ar.rsc"); break; 20184865Sobrien case 17: strcpy (regname, "ar.bsp"); break; 20284865Sobrien case 18: strcpy (regname, "ar.bspstore"); break; 20384865Sobrien case 19: strcpy (regname, "ar.rnat"); break; 20484865Sobrien case 32: strcpy (regname, "ar.ccv"); break; 20584865Sobrien case 36: strcpy (regname, "ar.unat"); break; 20684865Sobrien case 40: strcpy (regname, "ar.fpsr"); break; 20784865Sobrien case 44: strcpy (regname, "ar.itc"); break; 20884865Sobrien case 64: strcpy (regname, "ar.pfs"); break; 20984865Sobrien case 65: strcpy (regname, "ar.lc"); break; 21084865Sobrien case 66: strcpy (regname, "ar.ec"); break; 21184865Sobrien default: 21284865Sobrien sprintf (regname, "ar%u", (unsigned int) value); 21384865Sobrien break; 21484865Sobrien } 21584865Sobrien (*info->fprintf_func) (info->stream, "%s", regname); 21684865Sobrien } 21784865Sobrien else 21884865Sobrien (*info->fprintf_func) (info->stream, "%s%d", odesc->str, (int)value); 21984865Sobrien break; 22084865Sobrien 22184865Sobrien case IA64_OPND_CLASS_IND: 22284865Sobrien (*info->fprintf_func) (info->stream, "%s[r%d]", odesc->str, (int)value); 22384865Sobrien break; 22484865Sobrien 22584865Sobrien case IA64_OPND_CLASS_ABS: 22684865Sobrien str = 0; 22784865Sobrien if (odesc - elf64_ia64_operands == IA64_OPND_MBTYPE4) 22884865Sobrien switch (value) 22984865Sobrien { 23084865Sobrien case 0x0: str = "@brcst"; break; 23184865Sobrien case 0x8: str = "@mix"; break; 23284865Sobrien case 0x9: str = "@shuf"; break; 23384865Sobrien case 0xa: str = "@alt"; break; 23484865Sobrien case 0xb: str = "@rev"; break; 23584865Sobrien } 23684865Sobrien 23784865Sobrien if (str) 23884865Sobrien (*info->fprintf_func) (info->stream, "%s", str); 23984865Sobrien else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_SIGNED) 24084865Sobrien (*info->fprintf_func) (info->stream, "%lld", value); 24184865Sobrien else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED) 24284865Sobrien (*info->fprintf_func) (info->stream, "%llu", value); 24384865Sobrien else 24484865Sobrien (*info->fprintf_func) (info->stream, "0x%llx", value); 24584865Sobrien break; 24684865Sobrien 24784865Sobrien case IA64_OPND_CLASS_REL: 24884865Sobrien (*info->print_address_func) (memaddr + value, info); 24984865Sobrien break; 25084865Sobrien } 25184865Sobrien 25284865Sobrien need_comma = 1; 25384865Sobrien if (j + 1 == idesc->num_outputs) 25484865Sobrien { 25584865Sobrien (*info->fprintf_func) (info->stream, "="); 25684865Sobrien need_comma = 0; 25784865Sobrien } 25884865Sobrien } 25984865Sobrien if (slotnum + 1 == ia64_templ_desc[template].group_boundary 26084865Sobrien || ((slotnum == 2) && s_bit)) 26184865Sobrien (*info->fprintf_func) (info->stream, ";;"); 26284865Sobrien 26384865Sobrien done: 26484865Sobrien ia64_free_opcode ((struct ia64_opcode *)idesc); 26584865Sobrien failed: 26684865Sobrien if (slotnum == 2) 26784865Sobrien retval += 16 - 3*slot_multiplier; 26884865Sobrien return retval; 26984865Sobrien 27084865Sobrien decoding_failed: 27184865Sobrien (*info->fprintf_func) (info->stream, " data8 %#011llx", insn); 27284865Sobrien goto failed; 27384865Sobrien} 274