133965Sjdp/* CGEN generic opcode support.
233965Sjdp
3218822Sdim   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
485815Sobrien   Free Software Foundation, Inc.
533965Sjdp
638889Sjdp   This file is part of the GNU Binutils and GDB, the GNU debugger.
733965Sjdp
838889Sjdp   This program is free software; you can redistribute it and/or modify
938889Sjdp   it under the terms of the GNU General Public License as published by
1038889Sjdp   the Free Software Foundation; either version 2, or (at your option)
1138889Sjdp   any later version.
1233965Sjdp
1338889Sjdp   This program is distributed in the hope that it will be useful,
1438889Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1538889Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1638889Sjdp   GNU General Public License for more details.
1733965Sjdp
1838889Sjdp   You should have received a copy of the GNU General Public License along
1938889Sjdp   with this program; if not, write to the Free Software Foundation, Inc.,
20218822Sdim   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2133965Sjdp
2233965Sjdp#include "sysdep.h"
2333965Sjdp#include <stdio.h>
2433965Sjdp#include "ansidecl.h"
2533965Sjdp#include "libiberty.h"
2689857Sobrien#include "safe-ctype.h"
2733965Sjdp#include "bfd.h"
2838889Sjdp#include "symcat.h"
2933965Sjdp#include "opcode/cgen.h"
3033965Sjdp
3185815Sobrien#ifdef HAVE_ALLOCA_H
3285815Sobrien#include <alloca.h>
3385815Sobrien#endif
3485815Sobrien
3533965Sjdpstatic unsigned int hash_keyword_name
36130561Sobrien  (const CGEN_KEYWORD *, const char *, int);
3733965Sjdpstatic unsigned int hash_keyword_value
38130561Sobrien  (const CGEN_KEYWORD *, unsigned int);
3933965Sjdpstatic void build_keyword_hash_tables
40130561Sobrien  (CGEN_KEYWORD *);
4133965Sjdp
4233965Sjdp/* Return number of hash table entries to use for N elements.  */
4333965Sjdp#define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
4433965Sjdp
4533965Sjdp/* Look up *NAMEP in the keyword table KT.
4633965Sjdp   The result is the keyword entry or NULL if not found.  */
4733965Sjdp
4838889Sjdpconst CGEN_KEYWORD_ENTRY *
49130561Sobriencgen_keyword_lookup_name (CGEN_KEYWORD *kt, const char *name)
5033965Sjdp{
5138889Sjdp  const CGEN_KEYWORD_ENTRY *ke;
5233965Sjdp  const char *p,*n;
5333965Sjdp
5433965Sjdp  if (kt->name_hash_table == NULL)
5533965Sjdp    build_keyword_hash_tables (kt);
5633965Sjdp
5738889Sjdp  ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)];
5833965Sjdp
5933965Sjdp  /* We do case insensitive comparisons.
6033965Sjdp     If that ever becomes a problem, add an attribute that denotes
6133965Sjdp     "do case sensitive comparisons".  */
6233965Sjdp
6333965Sjdp  while (ke != NULL)
6433965Sjdp    {
6533965Sjdp      n = name;
6633965Sjdp      p = ke->name;
6733965Sjdp
6833965Sjdp      while (*p
6933965Sjdp	     && (*p == *n
7089857Sobrien		 || (ISALPHA (*p) && (TOLOWER (*p) == TOLOWER (*n)))))
7133965Sjdp	++n, ++p;
7233965Sjdp
7333965Sjdp      if (!*p && !*n)
7433965Sjdp	return ke;
7533965Sjdp
7633965Sjdp      ke = ke->next_name;
7733965Sjdp    }
7833965Sjdp
7938889Sjdp  if (kt->null_entry)
8038889Sjdp    return kt->null_entry;
8133965Sjdp  return NULL;
8233965Sjdp}
8333965Sjdp
8433965Sjdp/* Look up VALUE in the keyword table KT.
8533965Sjdp   The result is the keyword entry or NULL if not found.  */
8633965Sjdp
8738889Sjdpconst CGEN_KEYWORD_ENTRY *
88130561Sobriencgen_keyword_lookup_value (CGEN_KEYWORD *kt, int value)
8933965Sjdp{
9038889Sjdp  const CGEN_KEYWORD_ENTRY *ke;
9133965Sjdp
9233965Sjdp  if (kt->name_hash_table == NULL)
9333965Sjdp    build_keyword_hash_tables (kt);
9433965Sjdp
9533965Sjdp  ke = kt->value_hash_table[hash_keyword_value (kt, value)];
9633965Sjdp
9733965Sjdp  while (ke != NULL)
9833965Sjdp    {
9933965Sjdp      if (value == ke->value)
10033965Sjdp	return ke;
10133965Sjdp      ke = ke->next_value;
10233965Sjdp    }
10333965Sjdp
10433965Sjdp  return NULL;
10533965Sjdp}
10633965Sjdp
10733965Sjdp/* Add an entry to a keyword table.  */
10833965Sjdp
10933965Sjdpvoid
110130561Sobriencgen_keyword_add (CGEN_KEYWORD *kt, CGEN_KEYWORD_ENTRY *ke)
11133965Sjdp{
11233965Sjdp  unsigned int hash;
11389857Sobrien  size_t i;
11433965Sjdp
11533965Sjdp  if (kt->name_hash_table == NULL)
11633965Sjdp    build_keyword_hash_tables (kt);
11733965Sjdp
11838889Sjdp  hash = hash_keyword_name (kt, ke->name, 0);
11933965Sjdp  ke->next_name = kt->name_hash_table[hash];
12033965Sjdp  kt->name_hash_table[hash] = ke;
12133965Sjdp
12233965Sjdp  hash = hash_keyword_value (kt, ke->value);
12333965Sjdp  ke->next_value = kt->value_hash_table[hash];
12433965Sjdp  kt->value_hash_table[hash] = ke;
12538889Sjdp
12638889Sjdp  if (ke->name[0] == 0)
12738889Sjdp    kt->null_entry = ke;
12889857Sobrien
12989857Sobrien  for (i = 1; i < strlen (ke->name); i++)
13089857Sobrien    if (! ISALNUM (ke->name[i])
13189857Sobrien	&& ! strchr (kt->nonalpha_chars, ke->name[i]))
13289857Sobrien      {
13389857Sobrien	size_t idx = strlen (kt->nonalpha_chars);
13489857Sobrien
13589857Sobrien	/* If you hit this limit, please don't just
13689857Sobrien	   increase the size of the field, instead
13789857Sobrien	   look for a better algorithm.  */
13889857Sobrien	if (idx >= sizeof (kt->nonalpha_chars) - 1)
13989857Sobrien	  abort ();
14089857Sobrien	kt->nonalpha_chars[idx] = ke->name[i];
14189857Sobrien	kt->nonalpha_chars[idx+1] = 0;
14289857Sobrien      }
14333965Sjdp}
14433965Sjdp
14533965Sjdp/* FIXME: Need function to return count of keywords.  */
14633965Sjdp
14733965Sjdp/* Initialize a keyword table search.
14833965Sjdp   SPEC is a specification of what to search for.
14933965Sjdp   A value of NULL means to find every keyword.
15033965Sjdp   Currently NULL is the only acceptable value [further specification
15133965Sjdp   deferred].
15233965Sjdp   The result is an opaque data item used to record the search status.
15333965Sjdp   It is passed to each call to cgen_keyword_search_next.  */
15433965Sjdp
15538889SjdpCGEN_KEYWORD_SEARCH
156130561Sobriencgen_keyword_search_init (CGEN_KEYWORD *kt, const char *spec)
15733965Sjdp{
15838889Sjdp  CGEN_KEYWORD_SEARCH search;
15933965Sjdp
160218822Sdim  /* FIXME: Need to specify format of params.  */
16133965Sjdp  if (spec != NULL)
16233965Sjdp    abort ();
16333965Sjdp
16433965Sjdp  if (kt->name_hash_table == NULL)
16533965Sjdp    build_keyword_hash_tables (kt);
16633965Sjdp
16733965Sjdp  search.table = kt;
16833965Sjdp  search.spec = spec;
16933965Sjdp  search.current_hash = 0;
17033965Sjdp  search.current_entry = NULL;
17133965Sjdp  return search;
17233965Sjdp}
17333965Sjdp
17433965Sjdp/* Return the next keyword specified by SEARCH.
17533965Sjdp   The result is the next entry or NULL if there are no more.  */
17633965Sjdp
17738889Sjdpconst CGEN_KEYWORD_ENTRY *
178130561Sobriencgen_keyword_search_next (CGEN_KEYWORD_SEARCH *search)
17933965Sjdp{
18033965Sjdp  /* Has search finished?  */
18133965Sjdp  if (search->current_hash == search->table->hash_table_size)
18233965Sjdp    return NULL;
18333965Sjdp
18433965Sjdp  /* Search in progress?  */
18533965Sjdp  if (search->current_entry != NULL
18633965Sjdp      /* Anything left on this hash chain?  */
18733965Sjdp      && search->current_entry->next_name != NULL)
18833965Sjdp    {
18933965Sjdp      search->current_entry = search->current_entry->next_name;
19033965Sjdp      return search->current_entry;
19133965Sjdp    }
19233965Sjdp
19333965Sjdp  /* Move to next hash chain [unless we haven't started yet].  */
19433965Sjdp  if (search->current_entry != NULL)
19533965Sjdp    ++search->current_hash;
19633965Sjdp
19733965Sjdp  while (search->current_hash < search->table->hash_table_size)
19833965Sjdp    {
19933965Sjdp      search->current_entry = search->table->name_hash_table[search->current_hash];
20033965Sjdp      if (search->current_entry != NULL)
20133965Sjdp	return search->current_entry;
20233965Sjdp      ++search->current_hash;
20333965Sjdp    }
20433965Sjdp
20533965Sjdp  return NULL;
20633965Sjdp}
20733965Sjdp
20838889Sjdp/* Return first entry in hash chain for NAME.
20938889Sjdp   If CASE_SENSITIVE_P is non-zero, return a case sensitive hash.  */
21033965Sjdp
21133965Sjdpstatic unsigned int
212130561Sobrienhash_keyword_name (const CGEN_KEYWORD *kt,
213130561Sobrien		   const char *name,
214130561Sobrien		   int case_sensitive_p)
21533965Sjdp{
21633965Sjdp  unsigned int hash;
21733965Sjdp
21838889Sjdp  if (case_sensitive_p)
21938889Sjdp    for (hash = 0; *name; ++name)
22038889Sjdp      hash = (hash * 97) + (unsigned char) *name;
22138889Sjdp  else
22238889Sjdp    for (hash = 0; *name; ++name)
22389857Sobrien      hash = (hash * 97) + (unsigned char) TOLOWER (*name);
22433965Sjdp  return hash % kt->hash_table_size;
22533965Sjdp}
22633965Sjdp
22733965Sjdp/* Return first entry in hash chain for VALUE.  */
22833965Sjdp
22933965Sjdpstatic unsigned int
230130561Sobrienhash_keyword_value (const CGEN_KEYWORD *kt, unsigned int value)
23133965Sjdp{
23233965Sjdp  return value % kt->hash_table_size;
23333965Sjdp}
23433965Sjdp
23533965Sjdp/* Build a keyword table's hash tables.
23633965Sjdp   We probably needn't build the value hash table for the assembler when
23733965Sjdp   we're using the disassembler, but we keep things simple.  */
23833965Sjdp
23933965Sjdpstatic void
240130561Sobrienbuild_keyword_hash_tables (CGEN_KEYWORD *kt)
24133965Sjdp{
24233965Sjdp  int i;
24333965Sjdp  /* Use the number of compiled in entries as an estimate for the
24433965Sjdp     typical sized table [not too many added at runtime].  */
24533965Sjdp  unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
24633965Sjdp
24733965Sjdp  kt->hash_table_size = size;
24838889Sjdp  kt->name_hash_table = (CGEN_KEYWORD_ENTRY **)
24938889Sjdp    xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
25038889Sjdp  memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
25138889Sjdp  kt->value_hash_table = (CGEN_KEYWORD_ENTRY **)
25238889Sjdp    xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
25338889Sjdp  memset (kt->value_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
25433965Sjdp
25533965Sjdp  /* The table is scanned backwards as we want keywords appearing earlier to
25633965Sjdp     be prefered over later ones.  */
25733965Sjdp  for (i = kt->num_init_entries - 1; i >= 0; --i)
25833965Sjdp    cgen_keyword_add (kt, &kt->init_entries[i]);
25933965Sjdp}
26033965Sjdp
26133965Sjdp/* Hardware support.  */
26233965Sjdp
26360484Sobrien/* Lookup a hardware element by its name.
26460484Sobrien   Returns NULL if NAME is not supported by the currently selected
26560484Sobrien   mach/isa.  */
26660484Sobrien
26738889Sjdpconst CGEN_HW_ENTRY *
268130561Sobriencgen_hw_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
26933965Sjdp{
27085815Sobrien  unsigned int i;
27160484Sobrien  const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
27233965Sjdp
27360484Sobrien  for (i = 0; i < cd->hw_table.num_entries; ++i)
27460484Sobrien    if (hw[i] && strcmp (name, hw[i]->name) == 0)
27560484Sobrien      return hw[i];
27633965Sjdp
27733965Sjdp  return NULL;
27833965Sjdp}
27960484Sobrien
28060484Sobrien/* Lookup a hardware element by its number.
28160484Sobrien   Hardware elements are enumerated, however it may be possible to add some
28260484Sobrien   at runtime, thus HWNUM is not an enum type but rather an int.
28360484Sobrien   Returns NULL if HWNUM is not supported by the currently selected mach.  */
28460484Sobrien
28560484Sobrienconst CGEN_HW_ENTRY *
286130561Sobriencgen_hw_lookup_by_num (CGEN_CPU_DESC cd, unsigned int hwnum)
28760484Sobrien{
28885815Sobrien  unsigned int i;
28960484Sobrien  const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
29060484Sobrien
29160484Sobrien  /* ??? This can be speeded up.  */
29260484Sobrien  for (i = 0; i < cd->hw_table.num_entries; ++i)
29360484Sobrien    if (hw[i] && hwnum == hw[i]->type)
29460484Sobrien      return hw[i];
29560484Sobrien
29660484Sobrien  return NULL;
29760484Sobrien}
29833965Sjdp
29960484Sobrien/* Operand support.  */
30060484Sobrien
30160484Sobrien/* Lookup an operand by its name.
30260484Sobrien   Returns NULL if NAME is not supported by the currently selected
30360484Sobrien   mach/isa.  */
30460484Sobrien
30560484Sobrienconst CGEN_OPERAND *
306130561Sobriencgen_operand_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
30760484Sobrien{
30885815Sobrien  unsigned int i;
30960484Sobrien  const CGEN_OPERAND **op = cd->operand_table.entries;
31060484Sobrien
31160484Sobrien  for (i = 0; i < cd->operand_table.num_entries; ++i)
31260484Sobrien    if (op[i] && strcmp (name, op[i]->name) == 0)
31360484Sobrien      return op[i];
31460484Sobrien
31560484Sobrien  return NULL;
31660484Sobrien}
31760484Sobrien
31860484Sobrien/* Lookup an operand by its number.
31960484Sobrien   Operands are enumerated, however it may be possible to add some
32060484Sobrien   at runtime, thus OPNUM is not an enum type but rather an int.
32160484Sobrien   Returns NULL if OPNUM is not supported by the currently selected
32260484Sobrien   mach/isa.  */
32360484Sobrien
32460484Sobrienconst CGEN_OPERAND *
325130561Sobriencgen_operand_lookup_by_num (CGEN_CPU_DESC cd, int opnum)
32660484Sobrien{
32760484Sobrien  return cd->operand_table.entries[opnum];
32860484Sobrien}
32960484Sobrien
33033965Sjdp/* Instruction support.  */
33133965Sjdp
33233965Sjdp/* Return number of instructions.  This includes any added at runtime.  */
33333965Sjdp
33433965Sjdpint
335130561Sobriencgen_insn_count (CGEN_CPU_DESC cd)
33633965Sjdp{
33760484Sobrien  int count = cd->insn_table.num_init_entries;
33860484Sobrien  CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
33933965Sjdp
34060484Sobrien  for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
34133965Sjdp    ++count;
34233965Sjdp
34333965Sjdp  return count;
34433965Sjdp}
34560484Sobrien
34660484Sobrien/* Return number of macro-instructions.
34760484Sobrien   This includes any added at runtime.  */
34860484Sobrien
34960484Sobrienint
350130561Sobriencgen_macro_insn_count (CGEN_CPU_DESC cd)
35160484Sobrien{
35260484Sobrien  int count = cd->macro_insn_table.num_init_entries;
35360484Sobrien  CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
35460484Sobrien
35560484Sobrien  for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
35660484Sobrien    ++count;
35760484Sobrien
35860484Sobrien  return count;
35960484Sobrien}
36060484Sobrien
36160484Sobrien/* Cover function to read and properly byteswap an insn value.  */
36260484Sobrien
36360484SobrienCGEN_INSN_INT
364130561Sobriencgen_get_insn_value (CGEN_CPU_DESC cd, unsigned char *buf, int length)
36560484Sobrien{
36689857Sobrien  int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
36789857Sobrien  int insn_chunk_bitsize = cd->insn_chunk_bitsize;
36889857Sobrien  CGEN_INSN_INT value = 0;
36989857Sobrien
37089857Sobrien  if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
37189857Sobrien    {
37289857Sobrien      /* We need to divide up the incoming value into insn_chunk_bitsize-length
37389857Sobrien	 segments, and endian-convert them, one at a time. */
37489857Sobrien      int i;
37589857Sobrien
37689857Sobrien      /* Enforce divisibility. */
37789857Sobrien      if ((length % insn_chunk_bitsize) != 0)
37889857Sobrien	abort ();
37989857Sobrien
38089857Sobrien      for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
38189857Sobrien	{
38289857Sobrien	  int index;
38389857Sobrien	  bfd_vma this_value;
38489857Sobrien	  index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
38589857Sobrien	  this_value = bfd_get_bits (& buf[index / 8], insn_chunk_bitsize, big_p);
38689857Sobrien	  value = (value << insn_chunk_bitsize) | this_value;
38789857Sobrien	}
38889857Sobrien    }
38989857Sobrien  else
39089857Sobrien    {
39189857Sobrien      value = bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG);
39289857Sobrien    }
39389857Sobrien
39489857Sobrien  return value;
39560484Sobrien}
39660484Sobrien
39760484Sobrien/* Cover function to store an insn value properly byteswapped.  */
39860484Sobrien
39960484Sobrienvoid
400130561Sobriencgen_put_insn_value (CGEN_CPU_DESC cd,
401130561Sobrien		     unsigned char *buf,
402130561Sobrien		     int length,
403130561Sobrien		     CGEN_INSN_INT value)
40460484Sobrien{
40589857Sobrien  int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
40689857Sobrien  int insn_chunk_bitsize = cd->insn_chunk_bitsize;
40789857Sobrien
40889857Sobrien  if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
40989857Sobrien    {
41089857Sobrien      /* We need to divide up the incoming value into insn_chunk_bitsize-length
41189857Sobrien	 segments, and endian-convert them, one at a time. */
41289857Sobrien      int i;
41389857Sobrien
41489857Sobrien      /* Enforce divisibility. */
41589857Sobrien      if ((length % insn_chunk_bitsize) != 0)
41689857Sobrien	abort ();
41789857Sobrien
41889857Sobrien      for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
41989857Sobrien	{
42089857Sobrien	  int index;
42189857Sobrien	  index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */
42289857Sobrien	  bfd_put_bits ((bfd_vma) value, & buf[index / 8], insn_chunk_bitsize, big_p);
42389857Sobrien	  value >>= insn_chunk_bitsize;
42489857Sobrien	}
42589857Sobrien    }
42689857Sobrien  else
42789857Sobrien    {
42889857Sobrien      bfd_put_bits ((bfd_vma) value, buf, length, big_p);
42989857Sobrien    }
43060484Sobrien}
43160484Sobrien
43260484Sobrien/* Look up instruction INSN_*_VALUE and extract its fields.
43360484Sobrien   INSN_INT_VALUE is used if CGEN_INT_INSN_P.
43460484Sobrien   Otherwise INSN_BYTES_VALUE is used.
43560484Sobrien   INSN, if non-null, is the insn table entry.
43660484Sobrien   Otherwise INSN_*_VALUE is examined to compute it.
43760484Sobrien   LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
43860484Sobrien   0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
43960484Sobrien   If INSN != NULL, LENGTH must be valid.
44060484Sobrien   ALIAS_P is non-zero if alias insns are to be included in the search.
44160484Sobrien
44260484Sobrien   The result is a pointer to the insn table entry, or NULL if the instruction
44360484Sobrien   wasn't recognized.  */
44460484Sobrien
44560484Sobrien/* ??? Will need to be revisited for VLIW architectures.  */
44660484Sobrien
44760484Sobrienconst CGEN_INSN *
448130561Sobriencgen_lookup_insn (CGEN_CPU_DESC cd,
449130561Sobrien		  const CGEN_INSN *insn,
450130561Sobrien		  CGEN_INSN_INT insn_int_value,
451130561Sobrien		  /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
452130561Sobrien		  unsigned char *insn_bytes_value,
453130561Sobrien		  int length,
454130561Sobrien		  CGEN_FIELDS *fields,
455130561Sobrien		  int alias_p)
45660484Sobrien{
45760484Sobrien  unsigned char *buf;
45860484Sobrien  CGEN_INSN_INT base_insn;
45960484Sobrien  CGEN_EXTRACT_INFO ex_info;
46060484Sobrien  CGEN_EXTRACT_INFO *info;
46160484Sobrien
46260484Sobrien  if (cd->int_insn_p)
46360484Sobrien    {
46460484Sobrien      info = NULL;
46560484Sobrien      buf = (unsigned char *) alloca (cd->max_insn_bitsize / 8);
46660484Sobrien      cgen_put_insn_value (cd, buf, length, insn_int_value);
46760484Sobrien      base_insn = insn_int_value;
46860484Sobrien    }
46960484Sobrien  else
47060484Sobrien    {
47160484Sobrien      info = &ex_info;
47260484Sobrien      ex_info.dis_info = NULL;
47360484Sobrien      ex_info.insn_bytes = insn_bytes_value;
47460484Sobrien      ex_info.valid = -1;
47560484Sobrien      buf = insn_bytes_value;
47660484Sobrien      base_insn = cgen_get_insn_value (cd, buf, length);
47760484Sobrien    }
47860484Sobrien
47960484Sobrien  if (!insn)
48060484Sobrien    {
48160484Sobrien      const CGEN_INSN_LIST *insn_list;
48260484Sobrien
48360484Sobrien      /* The instructions are stored in hash lists.
48460484Sobrien	 Pick the first one and keep trying until we find the right one.  */
48560484Sobrien
486218822Sdim      insn_list = cgen_dis_lookup_insn (cd, (char *) buf, base_insn);
48760484Sobrien      while (insn_list != NULL)
48860484Sobrien	{
48960484Sobrien	  insn = insn_list->insn;
49060484Sobrien
49160484Sobrien	  if (alias_p
49260484Sobrien	      /* FIXME: Ensure ALIAS attribute always has same index.  */
49360484Sobrien	      || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
49460484Sobrien	    {
49560484Sobrien	      /* Basic bit mask must be correct.  */
49660484Sobrien	      /* ??? May wish to allow target to defer this check until the
49760484Sobrien		 extract handler.  */
49860484Sobrien	      if ((base_insn & CGEN_INSN_BASE_MASK (insn))
49960484Sobrien		  == CGEN_INSN_BASE_VALUE (insn))
50060484Sobrien		{
50160484Sobrien		  /* ??? 0 is passed for `pc' */
50260484Sobrien		  int elength = CGEN_EXTRACT_FN (cd, insn)
50360484Sobrien		    (cd, insn, info, base_insn, fields, (bfd_vma) 0);
50460484Sobrien		  if (elength > 0)
50560484Sobrien		    {
50660484Sobrien		      /* sanity check */
50760484Sobrien		      if (length != 0 && length != elength)
50860484Sobrien			abort ();
50960484Sobrien		      return insn;
51060484Sobrien		    }
51160484Sobrien		}
51260484Sobrien	    }
51360484Sobrien
51460484Sobrien	  insn_list = insn_list->next;
51560484Sobrien	}
51660484Sobrien    }
51760484Sobrien  else
51860484Sobrien    {
51960484Sobrien      /* Sanity check: can't pass an alias insn if ! alias_p.  */
52060484Sobrien      if (! alias_p
52160484Sobrien	  && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
52260484Sobrien	abort ();
52360484Sobrien      /* Sanity check: length must be correct.  */
52460484Sobrien      if (length != CGEN_INSN_BITSIZE (insn))
52560484Sobrien	abort ();
52660484Sobrien
52760484Sobrien      /* ??? 0 is passed for `pc' */
52860484Sobrien      length = CGEN_EXTRACT_FN (cd, insn)
52960484Sobrien	(cd, insn, info, base_insn, fields, (bfd_vma) 0);
53060484Sobrien      /* Sanity check: must succeed.
53160484Sobrien	 Could relax this later if it ever proves useful.  */
53260484Sobrien      if (length == 0)
53360484Sobrien	abort ();
53460484Sobrien      return insn;
53560484Sobrien    }
53660484Sobrien
53760484Sobrien  return NULL;
53860484Sobrien}
53960484Sobrien
54060484Sobrien/* Fill in the operand instances used by INSN whose operands are FIELDS.
54160484Sobrien   INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
54260484Sobrien   in.  */
54360484Sobrien
54460484Sobrienvoid
545130561Sobriencgen_get_insn_operands (CGEN_CPU_DESC cd,
546130561Sobrien			const CGEN_INSN *insn,
547130561Sobrien			const CGEN_FIELDS *fields,
548130561Sobrien			int *indices)
54960484Sobrien{
55060484Sobrien  const CGEN_OPINST *opinst;
55160484Sobrien  int i;
55260484Sobrien
55360484Sobrien  if (insn->opinst == NULL)
55460484Sobrien    abort ();
55560484Sobrien  for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
55660484Sobrien    {
55760484Sobrien      enum cgen_operand_type op_type = opinst->op_type;
55860484Sobrien      if (op_type == CGEN_OPERAND_NIL)
55960484Sobrien	indices[i] = opinst->index;
56060484Sobrien      else
56160484Sobrien	indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
56260484Sobrien    }
56360484Sobrien}
56460484Sobrien
56560484Sobrien/* Cover function to cgen_get_insn_operands when either INSN or FIELDS
56660484Sobrien   isn't known.
56760484Sobrien   The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
56860484Sobrien   cgen_lookup_insn unchanged.
56960484Sobrien   INSN_INT_VALUE is used if CGEN_INT_INSN_P.
57060484Sobrien   Otherwise INSN_BYTES_VALUE is used.
57160484Sobrien
57260484Sobrien   The result is the insn table entry or NULL if the instruction wasn't
57360484Sobrien   recognized.  */
57460484Sobrien
57560484Sobrienconst CGEN_INSN *
576130561Sobriencgen_lookup_get_insn_operands (CGEN_CPU_DESC cd,
577130561Sobrien			       const CGEN_INSN *insn,
578130561Sobrien			       CGEN_INSN_INT insn_int_value,
579130561Sobrien			       /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
580130561Sobrien			       unsigned char *insn_bytes_value,
581130561Sobrien			       int length,
582130561Sobrien			       int *indices,
583130561Sobrien			       CGEN_FIELDS *fields)
58460484Sobrien{
58560484Sobrien  /* Pass non-zero for ALIAS_P only if INSN != NULL.
58660484Sobrien     If INSN == NULL, we want a real insn.  */
58760484Sobrien  insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
58860484Sobrien			   length, fields, insn != NULL);
58960484Sobrien  if (! insn)
59060484Sobrien    return NULL;
59160484Sobrien
59260484Sobrien  cgen_get_insn_operands (cd, insn, fields, indices);
59360484Sobrien  return insn;
59460484Sobrien}
59560484Sobrien
59660484Sobrien/* Allow signed overflow of instruction fields.  */
59760484Sobrienvoid
598130561Sobriencgen_set_signed_overflow_ok (CGEN_CPU_DESC cd)
59960484Sobrien{
60060484Sobrien  cd->signed_overflow_ok_p = 1;
60160484Sobrien}
60260484Sobrien
60360484Sobrien/* Generate an error message if a signed field in an instruction overflows.  */
60460484Sobrienvoid
605130561Sobriencgen_clear_signed_overflow_ok (CGEN_CPU_DESC cd)
60660484Sobrien{
60760484Sobrien  cd->signed_overflow_ok_p = 0;
60860484Sobrien}
60960484Sobrien
61060484Sobrien/* Will an error message be generated if a signed field in an instruction overflows ? */
61160484Sobrienunsigned int
612130561Sobriencgen_signed_overflow_ok_p (CGEN_CPU_DESC cd)
61360484Sobrien{
61460484Sobrien  return cd->signed_overflow_ok_p;
61560484Sobrien}
616