184865Sobrien/* ia64-opc.c -- Functions to access the compacted opcode table
2218822Sdim   Copyright 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
384865Sobrien   Written by Bob Manson of Cygnus Solutions, <manson@cygnus.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
19218822Sdim   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20218822Sdim   02110-1301, USA.  */
2184865Sobrien
2284865Sobrien#include "ansidecl.h"
23218822Sdim#include "sysdep.h"
2484865Sobrien#include "libiberty.h"
2584865Sobrien#include "ia64-asmtab.h"
2684865Sobrien#include "ia64-asmtab.c"
2784865Sobrien
28130561Sobrienstatic void get_opc_prefix (const char **, char *);
29130561Sobrienstatic short int find_string_ent (const char *);
30130561Sobrienstatic short int find_main_ent (short int);
31130561Sobrienstatic short int find_completer (short int, short int, const char *);
32130561Sobrienstatic ia64_insn apply_completer (ia64_insn, int);
33130561Sobrienstatic int extract_op_bits (int, int, int);
34130561Sobrienstatic int extract_op (int, int *, unsigned int *);
35130561Sobrienstatic int opcode_verify (ia64_insn, int, enum ia64_insn_type);
36130561Sobrienstatic int locate_opcode_ent (ia64_insn, enum ia64_insn_type);
3789857Sobrienstatic struct ia64_opcode *make_ia64_opcode
38130561Sobrien  (ia64_insn, const char *, int, int);
3989857Sobrienstatic struct ia64_opcode *ia64_find_matching_opcode
40130561Sobrien  (const char *, short int);
4189857Sobrien
4284865Sobrienconst struct ia64_templ_desc ia64_templ_desc[16] =
4384865Sobrien  {
4484865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },	/* 0 */
4584865Sobrien    { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },
4684865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" },
4784865Sobrien    { 0, { 0, },				    "-3-" },
4884865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },	/* 4 */
4984865Sobrien    { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },
5084865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" },
5184865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" },
5284865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" },	/* 8 */
5384865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" },
5484865Sobrien    { 0, { 0, },				    "-a-" },
5584865Sobrien    { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" },
5684865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" },	/* c */
5784865Sobrien    { 0, { 0, },				    "-d-" },
5884865Sobrien    { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" },
5984865Sobrien    { 0, { 0, },				    "-f-" },
6084865Sobrien  };
6184865Sobrien
6284865Sobrien
6384865Sobrien/* Copy the prefix contained in *PTR (up to a '.' or a NUL) to DEST.
6484865Sobrien   PTR will be adjusted to point to the start of the next portion
6584865Sobrien   of the opcode, or at the NUL character. */
6684865Sobrien
6784865Sobrienstatic void
68130561Sobrienget_opc_prefix (const char **ptr, char *dest)
6984865Sobrien{
7084865Sobrien  char *c = strchr (*ptr, '.');
7184865Sobrien  if (c != NULL)
7284865Sobrien    {
7384865Sobrien      memcpy (dest, *ptr, c - *ptr);
7484865Sobrien      dest[c - *ptr] = '\0';
7584865Sobrien      *ptr = c + 1;
7684865Sobrien    }
7784865Sobrien  else
7884865Sobrien    {
7984865Sobrien      int l = strlen (*ptr);
8084865Sobrien      memcpy (dest, *ptr, l);
8184865Sobrien      dest[l] = '\0';
8284865Sobrien      *ptr += l;
8384865Sobrien    }
8484865Sobrien}
8584865Sobrien
8684865Sobrien/* Find the index of the entry in the string table corresponding to
8784865Sobrien   STR; return -1 if one does not exist. */
8884865Sobrien
8984865Sobrienstatic short
90130561Sobrienfind_string_ent (const char *str)
9184865Sobrien{
9284865Sobrien  short start = 0;
9384865Sobrien  short end = sizeof (ia64_strings) / sizeof (const char *);
9484865Sobrien  short i = (start + end) / 2;
9584865Sobrien
9684865Sobrien  if (strcmp (str, ia64_strings[end - 1]) > 0)
9784865Sobrien    {
9884865Sobrien      return -1;
9984865Sobrien    }
10084865Sobrien  while (start <= end)
10184865Sobrien    {
10284865Sobrien      int c = strcmp (str, ia64_strings[i]);
10384865Sobrien      if (c < 0)
10484865Sobrien	{
10584865Sobrien	  end = i - 1;
10684865Sobrien	}
10784865Sobrien      else if (c == 0)
10884865Sobrien	{
10984865Sobrien	  return i;
11084865Sobrien	}
11184865Sobrien      else
11284865Sobrien	{
11384865Sobrien	  start = i + 1;
11484865Sobrien	}
11584865Sobrien      i = (start + end) / 2;
11684865Sobrien    }
11784865Sobrien  return -1;
11884865Sobrien}
11984865Sobrien
12084865Sobrien/* Find the opcode in the main opcode table whose name is STRINGINDEX, or
12184865Sobrien   return -1 if one does not exist. */
12284865Sobrien
12384865Sobrienstatic short
124130561Sobrienfind_main_ent (short nameindex)
12584865Sobrien{
12684865Sobrien  short start = 0;
12784865Sobrien  short end = sizeof (main_table) / sizeof (struct ia64_main_table);
12884865Sobrien  short i = (start + end) / 2;
12984865Sobrien
13084865Sobrien  if (nameindex < main_table[0].name_index
13184865Sobrien      || nameindex > main_table[end - 1].name_index)
13284865Sobrien    {
13384865Sobrien      return -1;
13484865Sobrien    }
13584865Sobrien  while (start <= end)
13684865Sobrien    {
13784865Sobrien      if (nameindex < main_table[i].name_index)
13884865Sobrien	{
13984865Sobrien	  end = i - 1;
14084865Sobrien	}
14184865Sobrien      else if (nameindex == main_table[i].name_index)
14284865Sobrien	{
14384865Sobrien	  while (i > 0 && main_table[i - 1].name_index == nameindex)
14484865Sobrien	    {
14584865Sobrien	      i--;
14684865Sobrien	    }
14784865Sobrien	  return i;
14884865Sobrien	}
14984865Sobrien      else
15084865Sobrien	{
15184865Sobrien	  start = i + 1;
15284865Sobrien	}
15384865Sobrien      i = (start + end) / 2;
15484865Sobrien    }
15584865Sobrien  return -1;
15684865Sobrien}
15784865Sobrien
15884865Sobrien/* Find the index of the entry in the completer table that is part of
15984865Sobrien   MAIN_ENT (starting from PREV_COMPLETER) that matches NAME, or
16084865Sobrien   return -1 if one does not exist. */
16184865Sobrien
16289857Sobrienstatic short
163130561Sobrienfind_completer (short main_ent, short prev_completer, const char *name)
16484865Sobrien{
16584865Sobrien  short name_index = find_string_ent (name);
16684865Sobrien
16784865Sobrien  if (name_index < 0)
16884865Sobrien    {
16984865Sobrien      return -1;
17084865Sobrien    }
17184865Sobrien
17284865Sobrien  if (prev_completer == -1)
17384865Sobrien    {
17484865Sobrien      prev_completer = main_table[main_ent].completers;
17584865Sobrien    }
17684865Sobrien  else
17784865Sobrien    {
17884865Sobrien      prev_completer = completer_table[prev_completer].subentries;
17984865Sobrien    }
18084865Sobrien
18184865Sobrien  while (prev_completer != -1)
18284865Sobrien    {
18384865Sobrien      if (completer_table[prev_completer].name_index == name_index)
18484865Sobrien	{
18584865Sobrien	  return prev_completer;
18684865Sobrien	}
18784865Sobrien      prev_completer = completer_table[prev_completer].alternative;
18884865Sobrien    }
18984865Sobrien  return -1;
19084865Sobrien}
19184865Sobrien
19284865Sobrien/* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and
19384865Sobrien   return the result. */
19484865Sobrien
19584865Sobrienstatic ia64_insn
196130561Sobrienapply_completer (ia64_insn opcode, int completer_index)
19784865Sobrien{
19884865Sobrien  ia64_insn mask = completer_table[completer_index].mask;
19984865Sobrien  ia64_insn bits = completer_table[completer_index].bits;
20084865Sobrien  int shiftamt = (completer_table[completer_index].offset & 63);
20184865Sobrien
20284865Sobrien  mask = mask << shiftamt;
20384865Sobrien  bits = bits << shiftamt;
20484865Sobrien  opcode = (opcode & ~mask) | bits;
20584865Sobrien  return opcode;
20684865Sobrien}
20784865Sobrien
20884865Sobrien/* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in
20984865Sobrien   the dis_table array, and return its value.  (BITOFFSET is numbered
21084865Sobrien   starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the
21184865Sobrien   first byte in OP_POINTER.) */
21284865Sobrien
21384865Sobrienstatic int
214130561Sobrienextract_op_bits (int op_pointer, int bitoffset, int bits)
21584865Sobrien{
21684865Sobrien  int res = 0;
21784865Sobrien
21884865Sobrien  op_pointer += (bitoffset / 8);
21984865Sobrien
22084865Sobrien  if (bitoffset % 8)
22184865Sobrien    {
22284865Sobrien      unsigned int op = dis_table[op_pointer++];
22384865Sobrien      int numb = 8 - (bitoffset % 8);
22484865Sobrien      int mask = (1 << numb) - 1;
22584865Sobrien      int bata = (bits < numb) ? bits : numb;
22684865Sobrien      int delta = numb - bata;
22784865Sobrien
22884865Sobrien      res = (res << bata) | ((op & mask) >> delta);
22984865Sobrien      bitoffset += bata;
23084865Sobrien      bits -= bata;
23184865Sobrien    }
23284865Sobrien  while (bits >= 8)
23384865Sobrien    {
23484865Sobrien      res = (res << 8) | (dis_table[op_pointer++] & 255);
23584865Sobrien      bits -= 8;
23684865Sobrien    }
23784865Sobrien  if (bits > 0)
23884865Sobrien    {
23984865Sobrien      unsigned int op = (dis_table[op_pointer++] & 255);
24084865Sobrien      res = (res << bits) | (op >> (8 - bits));
24184865Sobrien    }
24284865Sobrien  return res;
24384865Sobrien}
24484865Sobrien
24584865Sobrien/* Examine the state machine entry at OP_POINTER in the dis_table
24684865Sobrien   array, and extract its values into OPVAL and OP.  The length of the
24784865Sobrien   state entry in bits is returned. */
24884865Sobrien
24984865Sobrienstatic int
250130561Sobrienextract_op (int op_pointer, int *opval, unsigned int *op)
25184865Sobrien{
25284865Sobrien  int oplen = 5;
25384865Sobrien
25484865Sobrien  *op = dis_table[op_pointer];
25584865Sobrien
25684865Sobrien  if ((*op) & 0x40)
25784865Sobrien    {
25884865Sobrien      opval[0] = extract_op_bits (op_pointer, oplen, 5);
25984865Sobrien      oplen += 5;
26084865Sobrien    }
26184865Sobrien  switch ((*op) & 0x30)
26284865Sobrien    {
26384865Sobrien    case 0x10:
26484865Sobrien      {
26584865Sobrien	opval[1] = extract_op_bits (op_pointer, oplen, 8);
26684865Sobrien	oplen += 8;
26784865Sobrien	opval[1] += op_pointer;
26884865Sobrien	break;
26984865Sobrien      }
27084865Sobrien    case 0x20:
27184865Sobrien      {
27284865Sobrien	opval[1] = extract_op_bits (op_pointer, oplen, 16);
27384865Sobrien	if (! (opval[1] & 32768))
27484865Sobrien	  {
27584865Sobrien	    opval[1] += op_pointer;
27684865Sobrien	  }
27784865Sobrien	oplen += 16;
27884865Sobrien	break;
27984865Sobrien      }
28084865Sobrien    case 0x30:
28184865Sobrien      {
28284865Sobrien	oplen--;
28384865Sobrien	opval[2] = extract_op_bits (op_pointer, oplen, 12);
28484865Sobrien	oplen += 12;
28584865Sobrien	opval[2] |= 32768;
28684865Sobrien	break;
28784865Sobrien      }
28884865Sobrien    }
28984865Sobrien  if (((*op) & 0x08) && (((*op) & 0x30) != 0x30))
29084865Sobrien    {
29184865Sobrien      opval[2] = extract_op_bits (op_pointer, oplen, 16);
29284865Sobrien      oplen += 16;
29384865Sobrien      if (! (opval[2] & 32768))
29484865Sobrien	{
29584865Sobrien	  opval[2] += op_pointer;
29684865Sobrien	}
29784865Sobrien    }
29884865Sobrien  return oplen;
29984865Sobrien}
30084865Sobrien
30184865Sobrien/* Returns a non-zero value if the opcode in the main_table list at
30284865Sobrien   PLACE matches OPCODE and is of type TYPE. */
30384865Sobrien
30484865Sobrienstatic int
305130561Sobrienopcode_verify (ia64_insn opcode, int place, enum ia64_insn_type type)
30684865Sobrien{
30784865Sobrien  if (main_table[place].opcode_type != type)
30884865Sobrien    {
30984865Sobrien      return 0;
31084865Sobrien    }
31189857Sobrien  if (main_table[place].flags
31284865Sobrien      & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT))
31384865Sobrien    {
31484865Sobrien      const struct ia64_operand *o1, *o2;
31584865Sobrien      ia64_insn f2, f3;
31684865Sobrien
31784865Sobrien      if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3)
31884865Sobrien	{
31984865Sobrien	  o1 = elf64_ia64_operands + IA64_OPND_F2;
32084865Sobrien	  o2 = elf64_ia64_operands + IA64_OPND_F3;
32184865Sobrien	  (*o1->extract) (o1, opcode, &f2);
32284865Sobrien	  (*o2->extract) (o2, opcode, &f3);
32384865Sobrien	  if (f2 != f3)
32484865Sobrien	    return 0;
32584865Sobrien	}
32684865Sobrien      else
32784865Sobrien	{
32884865Sobrien	  ia64_insn len, count;
32984865Sobrien
33084865Sobrien	  /* length must equal 64-count: */
33184865Sobrien	  o1 = elf64_ia64_operands + IA64_OPND_LEN6;
33284865Sobrien	  o2 = elf64_ia64_operands + main_table[place].operands[2];
33384865Sobrien	  (*o1->extract) (o1, opcode, &len);
33484865Sobrien	  (*o2->extract) (o2, opcode, &count);
33584865Sobrien	  if (len != 64 - count)
33684865Sobrien	    return 0;
33784865Sobrien	}
33884865Sobrien    }
33984865Sobrien  return 1;
34084865Sobrien}
34184865Sobrien
34284865Sobrien/* Find an instruction entry in the ia64_dis_names array that matches
34384865Sobrien   opcode OPCODE and is of type TYPE.  Returns either a positive index
34484865Sobrien   into the array, or a negative value if an entry for OPCODE could
34584865Sobrien   not be found.  Checks all matches and returns the one with the highest
34684865Sobrien   priority. */
34784865Sobrien
34884865Sobrienstatic int
349130561Sobrienlocate_opcode_ent (ia64_insn opcode, enum ia64_insn_type type)
35084865Sobrien{
35184865Sobrien  int currtest[41];
35284865Sobrien  int bitpos[41];
35384865Sobrien  int op_ptr[41];
35484865Sobrien  int currstatenum = 0;
35584865Sobrien  short found_disent = -1;
35684865Sobrien  short found_priority = -1;
35784865Sobrien
35884865Sobrien  currtest[currstatenum] = 0;
35984865Sobrien  op_ptr[currstatenum] = 0;
36084865Sobrien  bitpos[currstatenum] = 40;
36184865Sobrien
36284865Sobrien  while (1)
36384865Sobrien    {
36484865Sobrien      int op_pointer = op_ptr[currstatenum];
36584865Sobrien      unsigned int op;
36684865Sobrien      int currbitnum = bitpos[currstatenum];
36784865Sobrien      int oplen;
368218822Sdim      int opval[3] = {0};
36984865Sobrien      int next_op;
37084865Sobrien      int currbit;
37184865Sobrien
37284865Sobrien      oplen = extract_op (op_pointer, opval, &op);
37384865Sobrien
37484865Sobrien      bitpos[currstatenum] = currbitnum;
37584865Sobrien
37684865Sobrien      /* Skip opval[0] bits in the instruction. */
37784865Sobrien      if (op & 0x40)
37884865Sobrien	{
37984865Sobrien	  currbitnum -= opval[0];
38084865Sobrien	}
38184865Sobrien
38284865Sobrien      /* The value of the current bit being tested. */
38384865Sobrien      currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0;
38484865Sobrien      next_op = -1;
38584865Sobrien
38684865Sobrien      /* We always perform the tests specified in the current state in
38784865Sobrien	 a particular order, falling through to the next test if the
38884865Sobrien	 previous one failed. */
38984865Sobrien      switch (currtest[currstatenum])
39084865Sobrien	{
39184865Sobrien	case 0:
39284865Sobrien	  currtest[currstatenum]++;
39384865Sobrien	  if (currbit == 0 && (op & 0x80))
39484865Sobrien	    {
39584865Sobrien	      /* Check for a zero bit.  If this test solely checks for
39684865Sobrien		 a zero bit, we can check for up to 8 consecutive zero
39784865Sobrien		 bits (the number to check is specified by the lower 3
39884865Sobrien		 bits in the state code.)
39984865Sobrien
40084865Sobrien		 If the state instruction matches, we go to the very
40184865Sobrien		 next state instruction; otherwise, try the next test. */
40284865Sobrien
40384865Sobrien	      if ((op & 0xf8) == 0x80)
40484865Sobrien		{
40584865Sobrien		  int count = op & 0x7;
40684865Sobrien		  int x;
40784865Sobrien
40884865Sobrien		  for (x = 0; x <= count; x++)
40984865Sobrien		    {
41084865Sobrien		      int i =
41184865Sobrien			opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0;
41284865Sobrien		      if (i)
41384865Sobrien			{
41484865Sobrien			  break;
41584865Sobrien			}
41684865Sobrien		    }
41784865Sobrien		  if (x > count)
41884865Sobrien		    {
41984865Sobrien		      next_op = op_pointer + ((oplen + 7) / 8);
42084865Sobrien		      currbitnum -= count;
42184865Sobrien		      break;
42284865Sobrien		    }
42384865Sobrien		}
42484865Sobrien	      else if (! currbit)
42584865Sobrien		{
42684865Sobrien		  next_op = op_pointer + ((oplen + 7) / 8);
42784865Sobrien		  break;
42884865Sobrien		}
42984865Sobrien	    }
43084865Sobrien	  /* FALLTHROUGH */
43184865Sobrien	case 1:
43284865Sobrien	  /* If the bit in the instruction is one, go to the state
43384865Sobrien	     instruction specified by opval[1]. */
43484865Sobrien	  currtest[currstatenum]++;
43584865Sobrien	  if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30))
43684865Sobrien	    {
43784865Sobrien	      next_op = opval[1];
43884865Sobrien	      break;
43984865Sobrien	    }
44084865Sobrien	  /* FALLTHROUGH */
44184865Sobrien	case 2:
44284865Sobrien	  /* Don't care.  Skip the current bit and go to the state
44384865Sobrien	     instruction specified by opval[2].
44484865Sobrien
44584865Sobrien	     An encoding of 0x30 is special; this means that a 12-bit
44684865Sobrien	     offset into the ia64_dis_names[] array is specified.  */
44784865Sobrien	  currtest[currstatenum]++;
44884865Sobrien	  if ((op & 0x08) || ((op & 0x30) == 0x30))
44984865Sobrien	    {
45084865Sobrien	      next_op = opval[2];
45184865Sobrien	      break;
45284865Sobrien	    }
45384865Sobrien	}
45484865Sobrien
45584865Sobrien      /* If bit 15 is set in the address of the next state, an offset
45684865Sobrien	 in the ia64_dis_names array was specified instead.  We then
45784865Sobrien	 check to see if an entry in the list of opcodes matches the
45884865Sobrien	 opcode we were given; if so, we have succeeded.  */
45984865Sobrien
46084865Sobrien      if ((next_op >= 0) && (next_op & 32768))
46184865Sobrien	{
46284865Sobrien	  short disent = next_op & 32767;
46384865Sobrien          short priority = -1;
46484865Sobrien
46584865Sobrien	  if (next_op > 65535)
46684865Sobrien	    {
46784865Sobrien	      abort ();
46884865Sobrien	    }
46984865Sobrien
47084865Sobrien	  /* Run through the list of opcodes to check, trying to find
47184865Sobrien	     one that matches.  */
47284865Sobrien	  while (disent >= 0)
47384865Sobrien	    {
47484865Sobrien	      int place = ia64_dis_names[disent].insn_index;
47584865Sobrien
47684865Sobrien              priority = ia64_dis_names[disent].priority;
47784865Sobrien
47889857Sobrien	      if (opcode_verify (opcode, place, type)
47984865Sobrien                  && priority > found_priority)
48084865Sobrien		{
48184865Sobrien		  break;
48284865Sobrien		}
48384865Sobrien	      if (ia64_dis_names[disent].next_flag)
48484865Sobrien		{
48584865Sobrien		  disent++;
48684865Sobrien		}
48784865Sobrien	      else
48884865Sobrien		{
48984865Sobrien		  disent = -1;
49084865Sobrien		}
49184865Sobrien	    }
49284865Sobrien
49384865Sobrien	  if (disent >= 0)
49484865Sobrien	    {
49584865Sobrien              found_disent = disent;
49684865Sobrien              found_priority = priority;
49784865Sobrien	    }
49884865Sobrien          /* Try the next test in this state, regardless of whether a match
49984865Sobrien             was found. */
50084865Sobrien          next_op = -2;
50184865Sobrien	}
50284865Sobrien
50384865Sobrien      /* next_op == -1 is "back up to the previous state".
50484865Sobrien	 next_op == -2 is "stay in this state and try the next test".
50584865Sobrien	 Otherwise, transition to the state indicated by next_op. */
50684865Sobrien
50784865Sobrien      if (next_op == -1)
50884865Sobrien	{
50984865Sobrien	  currstatenum--;
51084865Sobrien	  if (currstatenum < 0)
51184865Sobrien	    {
51284865Sobrien              return found_disent;
51384865Sobrien	    }
51484865Sobrien	}
51584865Sobrien      else if (next_op >= 0)
51684865Sobrien	{
51784865Sobrien	  currstatenum++;
51884865Sobrien	  bitpos[currstatenum] = currbitnum - 1;
51984865Sobrien	  op_ptr[currstatenum] = next_op;
52084865Sobrien	  currtest[currstatenum] = 0;
52184865Sobrien	}
52284865Sobrien    }
52384865Sobrien}
52484865Sobrien
52584865Sobrien/* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */
52684865Sobrien
52784865Sobrienstatic struct ia64_opcode *
528130561Sobrienmake_ia64_opcode (ia64_insn opcode, const char *name, int place, int depind)
52984865Sobrien{
53084865Sobrien  struct ia64_opcode *res =
53184865Sobrien    (struct ia64_opcode *) xmalloc (sizeof (struct ia64_opcode));
53284865Sobrien  res->name = xstrdup (name);
53384865Sobrien  res->type = main_table[place].opcode_type;
53484865Sobrien  res->num_outputs = main_table[place].num_outputs;
53584865Sobrien  res->opcode = opcode;
53684865Sobrien  res->mask = main_table[place].mask;
53784865Sobrien  res->operands[0] = main_table[place].operands[0];
53884865Sobrien  res->operands[1] = main_table[place].operands[1];
53984865Sobrien  res->operands[2] = main_table[place].operands[2];
54084865Sobrien  res->operands[3] = main_table[place].operands[3];
54184865Sobrien  res->operands[4] = main_table[place].operands[4];
54284865Sobrien  res->flags = main_table[place].flags;
54384865Sobrien  res->ent_index = place;
54484865Sobrien  res->dependencies = &op_dependencies[depind];
54584865Sobrien  return res;
54684865Sobrien}
54784865Sobrien
54884865Sobrien/* Determine the ia64_opcode entry for the opcode specified by INSN
54984865Sobrien   and TYPE.  If a valid entry is not found, return NULL. */
55084865Sobrienstruct ia64_opcode *
551130561Sobrienia64_dis_opcode (ia64_insn insn, enum ia64_insn_type type)
55284865Sobrien{
55384865Sobrien  int disent = locate_opcode_ent (insn, type);
55484865Sobrien
55584865Sobrien  if (disent < 0)
55684865Sobrien    {
55784865Sobrien      return NULL;
55884865Sobrien    }
55984865Sobrien  else
56084865Sobrien    {
56184865Sobrien      unsigned int cb = ia64_dis_names[disent].completer_index;
56284865Sobrien      static char name[128];
56384865Sobrien      int place = ia64_dis_names[disent].insn_index;
56484865Sobrien      int ci = main_table[place].completers;
56584865Sobrien      ia64_insn tinsn = main_table[place].opcode;
56684865Sobrien
56784865Sobrien      strcpy (name, ia64_strings [main_table[place].name_index]);
56884865Sobrien
56984865Sobrien      while (cb)
57084865Sobrien	{
57184865Sobrien	  if (cb & 1)
57284865Sobrien	    {
57384865Sobrien	      int cname = completer_table[ci].name_index;
57484865Sobrien
57584865Sobrien	      tinsn = apply_completer (tinsn, ci);
57684865Sobrien
57784865Sobrien	      if (ia64_strings[cname][0] != '\0')
57884865Sobrien		{
57984865Sobrien		  strcat (name, ".");
58084865Sobrien		  strcat (name, ia64_strings[cname]);
58184865Sobrien		}
58284865Sobrien	      if (cb != 1)
58384865Sobrien		{
58484865Sobrien		  ci = completer_table[ci].subentries;
58584865Sobrien		}
58684865Sobrien	    }
58784865Sobrien	  else
58884865Sobrien	    {
58984865Sobrien	      ci = completer_table[ci].alternative;
59084865Sobrien	    }
59184865Sobrien	  if (ci < 0)
59284865Sobrien	    {
59384865Sobrien	      abort ();
59484865Sobrien	    }
59584865Sobrien	  cb = cb >> 1;
59684865Sobrien	}
59784865Sobrien      if (tinsn != (insn & main_table[place].mask))
59884865Sobrien	{
59984865Sobrien	  abort ();
60084865Sobrien	}
60189857Sobrien      return make_ia64_opcode (insn, name, place,
60284865Sobrien                               completer_table[ci].dependencies);
60384865Sobrien    }
60484865Sobrien}
60584865Sobrien
60684865Sobrien/* Search the main_opcode table starting from PLACE for an opcode that
60784865Sobrien   matches NAME.  Return NULL if one is not found. */
60884865Sobrien
60984865Sobrienstatic struct ia64_opcode *
610130561Sobrienia64_find_matching_opcode (const char *name, short place)
61184865Sobrien{
61284865Sobrien  char op[129];
61384865Sobrien  const char *suffix;
61484865Sobrien  short name_index;
61584865Sobrien
61684865Sobrien  if (strlen (name) > 128)
61784865Sobrien    {
61884865Sobrien      return NULL;
61984865Sobrien    }
62084865Sobrien  suffix = name;
62184865Sobrien  get_opc_prefix (&suffix, op);
62284865Sobrien  name_index = find_string_ent (op);
62384865Sobrien  if (name_index < 0)
62484865Sobrien    {
62584865Sobrien      return NULL;
62684865Sobrien    }
62784865Sobrien
62884865Sobrien  while (main_table[place].name_index == name_index)
62984865Sobrien    {
63084865Sobrien      const char *curr_suffix = suffix;
63184865Sobrien      ia64_insn curr_insn = main_table[place].opcode;
63284865Sobrien      short completer = -1;
63384865Sobrien
63484865Sobrien      do {
63589857Sobrien	if (suffix[0] == '\0')
63684865Sobrien	  {
63784865Sobrien	    completer = find_completer (place, completer, suffix);
63884865Sobrien	  }
63984865Sobrien	else
64084865Sobrien	  {
64184865Sobrien	    get_opc_prefix (&curr_suffix, op);
64284865Sobrien	    completer = find_completer (place, completer, op);
64384865Sobrien	  }
64484865Sobrien	if (completer != -1)
64584865Sobrien	  {
64684865Sobrien	    curr_insn = apply_completer (curr_insn, completer);
64784865Sobrien	  }
64884865Sobrien      } while (completer != -1 && curr_suffix[0] != '\0');
64984865Sobrien
65084865Sobrien      if (completer != -1 && curr_suffix[0] == '\0'
65184865Sobrien	  && completer_table[completer].terminal_completer)
65284865Sobrien	{
65384865Sobrien          int depind = completer_table[completer].dependencies;
65484865Sobrien	  return make_ia64_opcode (curr_insn, name, place, depind);
65584865Sobrien	}
65684865Sobrien      else
65784865Sobrien	{
65884865Sobrien	  place++;
65984865Sobrien	}
66084865Sobrien    }
66184865Sobrien  return NULL;
66284865Sobrien}
66384865Sobrien
66484865Sobrien/* Find the next opcode after PREV_ENT that matches PREV_ENT, or return NULL
66584865Sobrien   if one does not exist.
66684865Sobrien
66784865Sobrien   It is the caller's responsibility to invoke ia64_free_opcode () to
66884865Sobrien   release any resources used by the returned entry. */
66984865Sobrien
67084865Sobrienstruct ia64_opcode *
671130561Sobrienia64_find_next_opcode (struct ia64_opcode *prev_ent)
67284865Sobrien{
67384865Sobrien  return ia64_find_matching_opcode (prev_ent->name,
67484865Sobrien				    prev_ent->ent_index + 1);
67584865Sobrien}
67684865Sobrien
67784865Sobrien/* Find the first opcode that matches NAME, or return NULL if it does
67884865Sobrien   not exist.
67984865Sobrien
68084865Sobrien   It is the caller's responsibility to invoke ia64_free_opcode () to
68184865Sobrien   release any resources used by the returned entry. */
68284865Sobrien
68384865Sobrienstruct ia64_opcode *
684130561Sobrienia64_find_opcode (const char *name)
68584865Sobrien{
68684865Sobrien  char op[129];
68784865Sobrien  const char *suffix;
68884865Sobrien  short place;
68984865Sobrien  short name_index;
69084865Sobrien
69184865Sobrien  if (strlen (name) > 128)
69284865Sobrien    {
69384865Sobrien      return NULL;
69484865Sobrien    }
69584865Sobrien  suffix = name;
69684865Sobrien  get_opc_prefix (&suffix, op);
69784865Sobrien  name_index = find_string_ent (op);
69884865Sobrien  if (name_index < 0)
69984865Sobrien    {
70084865Sobrien      return NULL;
70184865Sobrien    }
70284865Sobrien
70384865Sobrien  place = find_main_ent (name_index);
70484865Sobrien
70584865Sobrien  if (place < 0)
70684865Sobrien    {
70784865Sobrien      return NULL;
70884865Sobrien    }
70984865Sobrien  return ia64_find_matching_opcode (name, place);
71084865Sobrien}
71184865Sobrien
71284865Sobrien/* Free any resources used by ENT. */
71384865Sobrienvoid
714130561Sobrienia64_free_opcode (struct ia64_opcode *ent)
71584865Sobrien{
71684865Sobrien  free ((void *)ent->name);
71784865Sobrien  free (ent);
71884865Sobrien}
71984865Sobrien
72084865Sobrienconst struct ia64_dependency *
721130561Sobrienia64_find_dependency (int index)
72284865Sobrien{
72384865Sobrien  index = DEP(index);
72484865Sobrien
72584865Sobrien  if (index < 0
72684865Sobrien      || index >= (int)(sizeof(dependencies) / sizeof(dependencies[0])))
72784865Sobrien    return NULL;
72884865Sobrien
72984865Sobrien  return &dependencies[index];
73084865Sobrien}
731