xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/cgen-opc.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1fddef416Sniklas /* CGEN generic opcode support.
2fddef416Sniklas 
35f210c2aSfgsch    Copyright 1996, 1997, 1998, 1999, 2000, 2001
45f210c2aSfgsch    Free Software Foundation, Inc.
5fddef416Sniklas 
6fddef416Sniklas    This file is part of the GNU Binutils and GDB, the GNU debugger.
7fddef416Sniklas 
8fddef416Sniklas    This program is free software; you can redistribute it and/or modify
9fddef416Sniklas    it under the terms of the GNU General Public License as published by
10fddef416Sniklas    the Free Software Foundation; either version 2, or (at your option)
11fddef416Sniklas    any later version.
12fddef416Sniklas 
13fddef416Sniklas    This program is distributed in the hope that it will be useful,
14fddef416Sniklas    but WITHOUT ANY WARRANTY; without even the implied warranty of
15fddef416Sniklas    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16fddef416Sniklas    GNU General Public License for more details.
17fddef416Sniklas 
18fddef416Sniklas    You should have received a copy of the GNU General Public License along
19fddef416Sniklas    with this program; if not, write to the Free Software Foundation, Inc.,
20fddef416Sniklas    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21fddef416Sniklas 
22fddef416Sniklas #include "sysdep.h"
23fddef416Sniklas #include <stdio.h>
24fddef416Sniklas #include "ansidecl.h"
25fddef416Sniklas #include "libiberty.h"
26d2201f2fSdrahn #include "safe-ctype.h"
27fddef416Sniklas #include "bfd.h"
28f7cc78ecSespie #include "symcat.h"
29fddef416Sniklas #include "opcode/cgen.h"
30fddef416Sniklas 
315f210c2aSfgsch #ifdef HAVE_ALLOCA_H
325f210c2aSfgsch #include <alloca.h>
335f210c2aSfgsch #endif
345f210c2aSfgsch 
35fddef416Sniklas static unsigned int hash_keyword_name
36*cf2f2c56Smiod   (const CGEN_KEYWORD *, const char *, int);
37fddef416Sniklas static unsigned int hash_keyword_value
38*cf2f2c56Smiod   (const CGEN_KEYWORD *, unsigned int);
39fddef416Sniklas static void build_keyword_hash_tables
40*cf2f2c56Smiod   (CGEN_KEYWORD *);
41fddef416Sniklas 
42fddef416Sniklas /* Return number of hash table entries to use for N elements.  */
43fddef416Sniklas #define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31)
44fddef416Sniklas 
45fddef416Sniklas /* Look up *NAMEP in the keyword table KT.
46fddef416Sniklas    The result is the keyword entry or NULL if not found.  */
47fddef416Sniklas 
48f7cc78ecSespie const CGEN_KEYWORD_ENTRY *
cgen_keyword_lookup_name(CGEN_KEYWORD * kt,const char * name)49*cf2f2c56Smiod cgen_keyword_lookup_name (CGEN_KEYWORD *kt, const char *name)
50fddef416Sniklas {
51f7cc78ecSespie   const CGEN_KEYWORD_ENTRY *ke;
52fddef416Sniklas   const char *p,*n;
53fddef416Sniklas 
54fddef416Sniklas   if (kt->name_hash_table == NULL)
55fddef416Sniklas     build_keyword_hash_tables (kt);
56fddef416Sniklas 
57f7cc78ecSespie   ke = kt->name_hash_table[hash_keyword_name (kt, name, 0)];
58fddef416Sniklas 
59fddef416Sniklas   /* We do case insensitive comparisons.
60fddef416Sniklas      If that ever becomes a problem, add an attribute that denotes
61fddef416Sniklas      "do case sensitive comparisons".  */
62fddef416Sniklas 
63fddef416Sniklas   while (ke != NULL)
64fddef416Sniklas     {
65fddef416Sniklas       n = name;
66fddef416Sniklas       p = ke->name;
67fddef416Sniklas 
68fddef416Sniklas       while (*p
69fddef416Sniklas 	     && (*p == *n
70d2201f2fSdrahn 		 || (ISALPHA (*p) && (TOLOWER (*p) == TOLOWER (*n)))))
71fddef416Sniklas 	++n, ++p;
72fddef416Sniklas 
73fddef416Sniklas       if (!*p && !*n)
74fddef416Sniklas 	return ke;
75fddef416Sniklas 
76fddef416Sniklas       ke = ke->next_name;
77fddef416Sniklas     }
78fddef416Sniklas 
79f7cc78ecSespie   if (kt->null_entry)
80f7cc78ecSespie     return kt->null_entry;
81fddef416Sniklas   return NULL;
82fddef416Sniklas }
83fddef416Sniklas 
84fddef416Sniklas /* Look up VALUE in the keyword table KT.
85fddef416Sniklas    The result is the keyword entry or NULL if not found.  */
86fddef416Sniklas 
87f7cc78ecSespie const CGEN_KEYWORD_ENTRY *
cgen_keyword_lookup_value(CGEN_KEYWORD * kt,int value)88*cf2f2c56Smiod cgen_keyword_lookup_value (CGEN_KEYWORD *kt, int value)
89fddef416Sniklas {
90f7cc78ecSespie   const CGEN_KEYWORD_ENTRY *ke;
91fddef416Sniklas 
92fddef416Sniklas   if (kt->name_hash_table == NULL)
93fddef416Sniklas     build_keyword_hash_tables (kt);
94fddef416Sniklas 
95fddef416Sniklas   ke = kt->value_hash_table[hash_keyword_value (kt, value)];
96fddef416Sniklas 
97fddef416Sniklas   while (ke != NULL)
98fddef416Sniklas     {
99fddef416Sniklas       if (value == ke->value)
100fddef416Sniklas 	return ke;
101fddef416Sniklas       ke = ke->next_value;
102fddef416Sniklas     }
103fddef416Sniklas 
104fddef416Sniklas   return NULL;
105fddef416Sniklas }
106fddef416Sniklas 
107fddef416Sniklas /* Add an entry to a keyword table.  */
108fddef416Sniklas 
109fddef416Sniklas void
cgen_keyword_add(CGEN_KEYWORD * kt,CGEN_KEYWORD_ENTRY * ke)110*cf2f2c56Smiod cgen_keyword_add (CGEN_KEYWORD *kt, CGEN_KEYWORD_ENTRY *ke)
111fddef416Sniklas {
112fddef416Sniklas   unsigned int hash;
113d2201f2fSdrahn   size_t i;
114fddef416Sniklas 
115fddef416Sniklas   if (kt->name_hash_table == NULL)
116fddef416Sniklas     build_keyword_hash_tables (kt);
117fddef416Sniklas 
118f7cc78ecSespie   hash = hash_keyword_name (kt, ke->name, 0);
119fddef416Sniklas   ke->next_name = kt->name_hash_table[hash];
120fddef416Sniklas   kt->name_hash_table[hash] = ke;
121fddef416Sniklas 
122fddef416Sniklas   hash = hash_keyword_value (kt, ke->value);
123fddef416Sniklas   ke->next_value = kt->value_hash_table[hash];
124fddef416Sniklas   kt->value_hash_table[hash] = ke;
125f7cc78ecSespie 
126f7cc78ecSespie   if (ke->name[0] == 0)
127f7cc78ecSespie     kt->null_entry = ke;
128d2201f2fSdrahn 
129d2201f2fSdrahn   for (i = 1; i < strlen (ke->name); i++)
130d2201f2fSdrahn     if (! ISALNUM (ke->name[i])
131d2201f2fSdrahn 	&& ! strchr (kt->nonalpha_chars, ke->name[i]))
132d2201f2fSdrahn       {
133d2201f2fSdrahn 	size_t idx = strlen (kt->nonalpha_chars);
134d2201f2fSdrahn 
135d2201f2fSdrahn 	/* If you hit this limit, please don't just
136d2201f2fSdrahn 	   increase the size of the field, instead
137d2201f2fSdrahn 	   look for a better algorithm.  */
138d2201f2fSdrahn 	if (idx >= sizeof (kt->nonalpha_chars) - 1)
139d2201f2fSdrahn 	  abort ();
140d2201f2fSdrahn 	kt->nonalpha_chars[idx] = ke->name[i];
141d2201f2fSdrahn 	kt->nonalpha_chars[idx+1] = 0;
142d2201f2fSdrahn       }
143fddef416Sniklas }
144fddef416Sniklas 
145fddef416Sniklas /* FIXME: Need function to return count of keywords.  */
146fddef416Sniklas 
147fddef416Sniklas /* Initialize a keyword table search.
148fddef416Sniklas    SPEC is a specification of what to search for.
149fddef416Sniklas    A value of NULL means to find every keyword.
150fddef416Sniklas    Currently NULL is the only acceptable value [further specification
151fddef416Sniklas    deferred].
152fddef416Sniklas    The result is an opaque data item used to record the search status.
153fddef416Sniklas    It is passed to each call to cgen_keyword_search_next.  */
154fddef416Sniklas 
155f7cc78ecSespie CGEN_KEYWORD_SEARCH
cgen_keyword_search_init(CGEN_KEYWORD * kt,const char * spec)156*cf2f2c56Smiod cgen_keyword_search_init (CGEN_KEYWORD *kt, const char *spec)
157fddef416Sniklas {
158f7cc78ecSespie   CGEN_KEYWORD_SEARCH search;
159fddef416Sniklas 
160fddef416Sniklas   /* FIXME: Need to specify format of PARAMS.  */
161fddef416Sniklas   if (spec != NULL)
162fddef416Sniklas     abort ();
163fddef416Sniklas 
164fddef416Sniklas   if (kt->name_hash_table == NULL)
165fddef416Sniklas     build_keyword_hash_tables (kt);
166fddef416Sniklas 
167fddef416Sniklas   search.table = kt;
168fddef416Sniklas   search.spec = spec;
169fddef416Sniklas   search.current_hash = 0;
170fddef416Sniklas   search.current_entry = NULL;
171fddef416Sniklas   return search;
172fddef416Sniklas }
173fddef416Sniklas 
174fddef416Sniklas /* Return the next keyword specified by SEARCH.
175fddef416Sniklas    The result is the next entry or NULL if there are no more.  */
176fddef416Sniklas 
177f7cc78ecSespie const CGEN_KEYWORD_ENTRY *
cgen_keyword_search_next(CGEN_KEYWORD_SEARCH * search)178*cf2f2c56Smiod cgen_keyword_search_next (CGEN_KEYWORD_SEARCH *search)
179fddef416Sniklas {
180fddef416Sniklas   /* Has search finished?  */
181fddef416Sniklas   if (search->current_hash == search->table->hash_table_size)
182fddef416Sniklas     return NULL;
183fddef416Sniklas 
184fddef416Sniklas   /* Search in progress?  */
185fddef416Sniklas   if (search->current_entry != NULL
186fddef416Sniklas       /* Anything left on this hash chain?  */
187fddef416Sniklas       && search->current_entry->next_name != NULL)
188fddef416Sniklas     {
189fddef416Sniklas       search->current_entry = search->current_entry->next_name;
190fddef416Sniklas       return search->current_entry;
191fddef416Sniklas     }
192fddef416Sniklas 
193fddef416Sniklas   /* Move to next hash chain [unless we haven't started yet].  */
194fddef416Sniklas   if (search->current_entry != NULL)
195fddef416Sniklas     ++search->current_hash;
196fddef416Sniklas 
197fddef416Sniklas   while (search->current_hash < search->table->hash_table_size)
198fddef416Sniklas     {
199fddef416Sniklas       search->current_entry = search->table->name_hash_table[search->current_hash];
200fddef416Sniklas       if (search->current_entry != NULL)
201fddef416Sniklas 	return search->current_entry;
202fddef416Sniklas       ++search->current_hash;
203fddef416Sniklas     }
204fddef416Sniklas 
205fddef416Sniklas   return NULL;
206fddef416Sniklas }
207fddef416Sniklas 
208f7cc78ecSespie /* Return first entry in hash chain for NAME.
209f7cc78ecSespie    If CASE_SENSITIVE_P is non-zero, return a case sensitive hash.  */
210fddef416Sniklas 
211fddef416Sniklas static unsigned int
hash_keyword_name(const CGEN_KEYWORD * kt,const char * name,int case_sensitive_p)212*cf2f2c56Smiod hash_keyword_name (const CGEN_KEYWORD *kt,
213*cf2f2c56Smiod 		   const char *name,
214*cf2f2c56Smiod 		   int case_sensitive_p)
215fddef416Sniklas {
216fddef416Sniklas   unsigned int hash;
217fddef416Sniklas 
218f7cc78ecSespie   if (case_sensitive_p)
219fddef416Sniklas     for (hash = 0; *name; ++name)
220fddef416Sniklas       hash = (hash * 97) + (unsigned char) *name;
221f7cc78ecSespie   else
222f7cc78ecSespie     for (hash = 0; *name; ++name)
223d2201f2fSdrahn       hash = (hash * 97) + (unsigned char) TOLOWER (*name);
224fddef416Sniklas   return hash % kt->hash_table_size;
225fddef416Sniklas }
226fddef416Sniklas 
227fddef416Sniklas /* Return first entry in hash chain for VALUE.  */
228fddef416Sniklas 
229fddef416Sniklas static unsigned int
hash_keyword_value(const CGEN_KEYWORD * kt,unsigned int value)230*cf2f2c56Smiod hash_keyword_value (const CGEN_KEYWORD *kt, unsigned int value)
231fddef416Sniklas {
232fddef416Sniklas   return value % kt->hash_table_size;
233fddef416Sniklas }
234fddef416Sniklas 
235fddef416Sniklas /* Build a keyword table's hash tables.
236fddef416Sniklas    We probably needn't build the value hash table for the assembler when
237fddef416Sniklas    we're using the disassembler, but we keep things simple.  */
238fddef416Sniklas 
239fddef416Sniklas static void
build_keyword_hash_tables(CGEN_KEYWORD * kt)240*cf2f2c56Smiod build_keyword_hash_tables (CGEN_KEYWORD *kt)
241fddef416Sniklas {
242fddef416Sniklas   int i;
243fddef416Sniklas   /* Use the number of compiled in entries as an estimate for the
244fddef416Sniklas      typical sized table [not too many added at runtime].  */
245fddef416Sniklas   unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries);
246fddef416Sniklas 
247fddef416Sniklas   kt->hash_table_size = size;
248f7cc78ecSespie   kt->name_hash_table = (CGEN_KEYWORD_ENTRY **)
249f7cc78ecSespie     xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
250f7cc78ecSespie   memset (kt->name_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
251f7cc78ecSespie   kt->value_hash_table = (CGEN_KEYWORD_ENTRY **)
252f7cc78ecSespie     xmalloc (size * sizeof (CGEN_KEYWORD_ENTRY *));
253f7cc78ecSespie   memset (kt->value_hash_table, 0, size * sizeof (CGEN_KEYWORD_ENTRY *));
254fddef416Sniklas 
255fddef416Sniklas   /* The table is scanned backwards as we want keywords appearing earlier to
256fddef416Sniklas      be prefered over later ones.  */
257fddef416Sniklas   for (i = kt->num_init_entries - 1; i >= 0; --i)
258fddef416Sniklas     cgen_keyword_add (kt, &kt->init_entries[i]);
259fddef416Sniklas }
260fddef416Sniklas 
261fddef416Sniklas /* Hardware support.  */
262fddef416Sniklas 
263f7cc78ecSespie /* Lookup a hardware element by its name.
264f7cc78ecSespie    Returns NULL if NAME is not supported by the currently selected
265f7cc78ecSespie    mach/isa.  */
266f7cc78ecSespie 
267f7cc78ecSespie const CGEN_HW_ENTRY *
cgen_hw_lookup_by_name(CGEN_CPU_DESC cd,const char * name)268*cf2f2c56Smiod cgen_hw_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
269fddef416Sniklas {
2705f210c2aSfgsch   unsigned int i;
271f7cc78ecSespie   const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
272fddef416Sniklas 
273f7cc78ecSespie   for (i = 0; i < cd->hw_table.num_entries; ++i)
274f7cc78ecSespie     if (hw[i] && strcmp (name, hw[i]->name) == 0)
275f7cc78ecSespie       return hw[i];
276fddef416Sniklas 
277fddef416Sniklas   return NULL;
278fddef416Sniklas }
279f7cc78ecSespie 
280f7cc78ecSespie /* Lookup a hardware element by its number.
281f7cc78ecSespie    Hardware elements are enumerated, however it may be possible to add some
282f7cc78ecSespie    at runtime, thus HWNUM is not an enum type but rather an int.
283f7cc78ecSespie    Returns NULL if HWNUM is not supported by the currently selected mach.  */
284f7cc78ecSespie 
285f7cc78ecSespie const CGEN_HW_ENTRY *
cgen_hw_lookup_by_num(CGEN_CPU_DESC cd,unsigned int hwnum)286*cf2f2c56Smiod cgen_hw_lookup_by_num (CGEN_CPU_DESC cd, unsigned int hwnum)
287f7cc78ecSespie {
2885f210c2aSfgsch   unsigned int i;
289f7cc78ecSespie   const CGEN_HW_ENTRY **hw = cd->hw_table.entries;
290f7cc78ecSespie 
291f7cc78ecSespie   /* ??? This can be speeded up.  */
292f7cc78ecSespie   for (i = 0; i < cd->hw_table.num_entries; ++i)
293f7cc78ecSespie     if (hw[i] && hwnum == hw[i]->type)
294f7cc78ecSespie       return hw[i];
295f7cc78ecSespie 
296f7cc78ecSespie   return NULL;
297f7cc78ecSespie }
298f7cc78ecSespie 
299f7cc78ecSespie /* Operand support.  */
300f7cc78ecSespie 
301f7cc78ecSespie /* Lookup an operand by its name.
302f7cc78ecSespie    Returns NULL if NAME is not supported by the currently selected
303f7cc78ecSespie    mach/isa.  */
304f7cc78ecSespie 
305f7cc78ecSespie const CGEN_OPERAND *
cgen_operand_lookup_by_name(CGEN_CPU_DESC cd,const char * name)306*cf2f2c56Smiod cgen_operand_lookup_by_name (CGEN_CPU_DESC cd, const char *name)
307f7cc78ecSespie {
3085f210c2aSfgsch   unsigned int i;
309f7cc78ecSespie   const CGEN_OPERAND **op = cd->operand_table.entries;
310f7cc78ecSespie 
311f7cc78ecSespie   for (i = 0; i < cd->operand_table.num_entries; ++i)
312f7cc78ecSespie     if (op[i] && strcmp (name, op[i]->name) == 0)
313f7cc78ecSespie       return op[i];
314f7cc78ecSespie 
315f7cc78ecSespie   return NULL;
316f7cc78ecSespie }
317f7cc78ecSespie 
318f7cc78ecSespie /* Lookup an operand by its number.
319f7cc78ecSespie    Operands are enumerated, however it may be possible to add some
320f7cc78ecSespie    at runtime, thus OPNUM is not an enum type but rather an int.
321f7cc78ecSespie    Returns NULL if OPNUM is not supported by the currently selected
322f7cc78ecSespie    mach/isa.  */
323f7cc78ecSespie 
324f7cc78ecSespie const CGEN_OPERAND *
cgen_operand_lookup_by_num(CGEN_CPU_DESC cd,int opnum)325*cf2f2c56Smiod cgen_operand_lookup_by_num (CGEN_CPU_DESC cd, int opnum)
326f7cc78ecSespie {
327f7cc78ecSespie   return cd->operand_table.entries[opnum];
328f7cc78ecSespie }
329fddef416Sniklas 
330fddef416Sniklas /* Instruction support.  */
331fddef416Sniklas 
332fddef416Sniklas /* Return number of instructions.  This includes any added at runtime.  */
333fddef416Sniklas 
334fddef416Sniklas int
cgen_insn_count(CGEN_CPU_DESC cd)335*cf2f2c56Smiod cgen_insn_count (CGEN_CPU_DESC cd)
336fddef416Sniklas {
337f7cc78ecSespie   int count = cd->insn_table.num_init_entries;
338f7cc78ecSespie   CGEN_INSN_LIST *rt_insns = cd->insn_table.new_entries;
339fddef416Sniklas 
340f7cc78ecSespie   for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
341fddef416Sniklas     ++count;
342fddef416Sniklas 
343fddef416Sniklas   return count;
344fddef416Sniklas }
345f7cc78ecSespie 
346f7cc78ecSespie /* Return number of macro-instructions.
347f7cc78ecSespie    This includes any added at runtime.  */
348f7cc78ecSespie 
349f7cc78ecSespie int
cgen_macro_insn_count(CGEN_CPU_DESC cd)350*cf2f2c56Smiod cgen_macro_insn_count (CGEN_CPU_DESC cd)
351f7cc78ecSespie {
352f7cc78ecSespie   int count = cd->macro_insn_table.num_init_entries;
353f7cc78ecSespie   CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
354f7cc78ecSespie 
355f7cc78ecSespie   for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
356f7cc78ecSespie     ++count;
357f7cc78ecSespie 
358f7cc78ecSespie   return count;
359f7cc78ecSespie }
360f7cc78ecSespie 
361f7cc78ecSespie /* Cover function to read and properly byteswap an insn value.  */
362f7cc78ecSespie 
363f7cc78ecSespie CGEN_INSN_INT
cgen_get_insn_value(CGEN_CPU_DESC cd,unsigned char * buf,int length)364*cf2f2c56Smiod cgen_get_insn_value (CGEN_CPU_DESC cd, unsigned char *buf, int length)
365f7cc78ecSespie {
366d2201f2fSdrahn   int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
367d2201f2fSdrahn   int insn_chunk_bitsize = cd->insn_chunk_bitsize;
368d2201f2fSdrahn   CGEN_INSN_INT value = 0;
369d2201f2fSdrahn 
370d2201f2fSdrahn   if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
371d2201f2fSdrahn     {
372d2201f2fSdrahn       /* We need to divide up the incoming value into insn_chunk_bitsize-length
373d2201f2fSdrahn 	 segments, and endian-convert them, one at a time. */
374d2201f2fSdrahn       int i;
375d2201f2fSdrahn 
376d2201f2fSdrahn       /* Enforce divisibility. */
377d2201f2fSdrahn       if ((length % insn_chunk_bitsize) != 0)
378d2201f2fSdrahn 	abort ();
379d2201f2fSdrahn 
380d2201f2fSdrahn       for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
381d2201f2fSdrahn 	{
382d2201f2fSdrahn 	  int index;
383d2201f2fSdrahn 	  bfd_vma this_value;
384d2201f2fSdrahn 	  index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
385d2201f2fSdrahn 	  this_value = bfd_get_bits (& buf[index / 8], insn_chunk_bitsize, big_p);
386d2201f2fSdrahn 	  value = (value << insn_chunk_bitsize) | this_value;
387d2201f2fSdrahn 	}
388d2201f2fSdrahn     }
389d2201f2fSdrahn   else
390d2201f2fSdrahn     {
391d2201f2fSdrahn       value = bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG);
392d2201f2fSdrahn     }
393d2201f2fSdrahn 
394d2201f2fSdrahn   return value;
395f7cc78ecSespie }
396f7cc78ecSespie 
397f7cc78ecSespie /* Cover function to store an insn value properly byteswapped.  */
398f7cc78ecSespie 
399f7cc78ecSespie void
cgen_put_insn_value(CGEN_CPU_DESC cd,unsigned char * buf,int length,CGEN_INSN_INT value)400*cf2f2c56Smiod cgen_put_insn_value (CGEN_CPU_DESC cd,
401*cf2f2c56Smiod 		     unsigned char *buf,
402*cf2f2c56Smiod 		     int length,
403*cf2f2c56Smiod 		     CGEN_INSN_INT value)
404f7cc78ecSespie {
405d2201f2fSdrahn   int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
406d2201f2fSdrahn   int insn_chunk_bitsize = cd->insn_chunk_bitsize;
407d2201f2fSdrahn 
408d2201f2fSdrahn   if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
409d2201f2fSdrahn     {
410d2201f2fSdrahn       /* We need to divide up the incoming value into insn_chunk_bitsize-length
411d2201f2fSdrahn 	 segments, and endian-convert them, one at a time. */
412d2201f2fSdrahn       int i;
413d2201f2fSdrahn 
414d2201f2fSdrahn       /* Enforce divisibility. */
415d2201f2fSdrahn       if ((length % insn_chunk_bitsize) != 0)
416d2201f2fSdrahn 	abort ();
417d2201f2fSdrahn 
418d2201f2fSdrahn       for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
419d2201f2fSdrahn 	{
420d2201f2fSdrahn 	  int index;
421d2201f2fSdrahn 	  index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */
422d2201f2fSdrahn 	  bfd_put_bits ((bfd_vma) value, & buf[index / 8], insn_chunk_bitsize, big_p);
423d2201f2fSdrahn 	  value >>= insn_chunk_bitsize;
424d2201f2fSdrahn 	}
425d2201f2fSdrahn     }
426d2201f2fSdrahn   else
427d2201f2fSdrahn     {
428d2201f2fSdrahn       bfd_put_bits ((bfd_vma) value, buf, length, big_p);
429d2201f2fSdrahn     }
430f7cc78ecSespie }
431f7cc78ecSespie 
432f7cc78ecSespie /* Look up instruction INSN_*_VALUE and extract its fields.
433f7cc78ecSespie    INSN_INT_VALUE is used if CGEN_INT_INSN_P.
434f7cc78ecSespie    Otherwise INSN_BYTES_VALUE is used.
435f7cc78ecSespie    INSN, if non-null, is the insn table entry.
436f7cc78ecSespie    Otherwise INSN_*_VALUE is examined to compute it.
437f7cc78ecSespie    LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
438f7cc78ecSespie    0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
439f7cc78ecSespie    If INSN != NULL, LENGTH must be valid.
440f7cc78ecSespie    ALIAS_P is non-zero if alias insns are to be included in the search.
441f7cc78ecSespie 
442f7cc78ecSespie    The result is a pointer to the insn table entry, or NULL if the instruction
443f7cc78ecSespie    wasn't recognized.  */
444f7cc78ecSespie 
445f7cc78ecSespie /* ??? Will need to be revisited for VLIW architectures.  */
446f7cc78ecSespie 
447f7cc78ecSespie const CGEN_INSN *
cgen_lookup_insn(CGEN_CPU_DESC cd,const CGEN_INSN * insn,CGEN_INSN_INT insn_int_value,unsigned char * insn_bytes_value,int length,CGEN_FIELDS * fields,int alias_p)448*cf2f2c56Smiod cgen_lookup_insn (CGEN_CPU_DESC cd,
449*cf2f2c56Smiod 		  const CGEN_INSN *insn,
450*cf2f2c56Smiod 		  CGEN_INSN_INT insn_int_value,
451f7cc78ecSespie 		  /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
452*cf2f2c56Smiod 		  unsigned char *insn_bytes_value,
453*cf2f2c56Smiod 		  int length,
454*cf2f2c56Smiod 		  CGEN_FIELDS *fields,
455*cf2f2c56Smiod 		  int alias_p)
456f7cc78ecSespie {
457f7cc78ecSespie   unsigned char *buf;
458f7cc78ecSespie   CGEN_INSN_INT base_insn;
459f7cc78ecSespie   CGEN_EXTRACT_INFO ex_info;
460f7cc78ecSespie   CGEN_EXTRACT_INFO *info;
461f7cc78ecSespie 
462f7cc78ecSespie   if (cd->int_insn_p)
463f7cc78ecSespie     {
464f7cc78ecSespie       info = NULL;
465f7cc78ecSespie       buf = (unsigned char *) alloca (cd->max_insn_bitsize / 8);
466f7cc78ecSespie       cgen_put_insn_value (cd, buf, length, insn_int_value);
467f7cc78ecSespie       base_insn = insn_int_value;
468f7cc78ecSespie     }
469f7cc78ecSespie   else
470f7cc78ecSespie     {
471f7cc78ecSespie       info = &ex_info;
472f7cc78ecSespie       ex_info.dis_info = NULL;
473f7cc78ecSespie       ex_info.insn_bytes = insn_bytes_value;
474f7cc78ecSespie       ex_info.valid = -1;
475f7cc78ecSespie       buf = insn_bytes_value;
476f7cc78ecSespie       base_insn = cgen_get_insn_value (cd, buf, length);
477f7cc78ecSespie     }
478f7cc78ecSespie 
479f7cc78ecSespie   if (!insn)
480f7cc78ecSespie     {
481f7cc78ecSespie       const CGEN_INSN_LIST *insn_list;
482f7cc78ecSespie 
483f7cc78ecSespie       /* The instructions are stored in hash lists.
484f7cc78ecSespie 	 Pick the first one and keep trying until we find the right one.  */
485f7cc78ecSespie 
486f7cc78ecSespie       insn_list = cgen_dis_lookup_insn (cd, buf, base_insn);
487f7cc78ecSespie       while (insn_list != NULL)
488f7cc78ecSespie 	{
489f7cc78ecSespie 	  insn = insn_list->insn;
490f7cc78ecSespie 
491f7cc78ecSespie 	  if (alias_p
492f7cc78ecSespie 	      /* FIXME: Ensure ALIAS attribute always has same index.  */
493f7cc78ecSespie 	      || ! CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
494f7cc78ecSespie 	    {
495f7cc78ecSespie 	      /* Basic bit mask must be correct.  */
496f7cc78ecSespie 	      /* ??? May wish to allow target to defer this check until the
497f7cc78ecSespie 		 extract handler.  */
498f7cc78ecSespie 	      if ((base_insn & CGEN_INSN_BASE_MASK (insn))
499f7cc78ecSespie 		  == CGEN_INSN_BASE_VALUE (insn))
500f7cc78ecSespie 		{
501f7cc78ecSespie 		  /* ??? 0 is passed for `pc' */
502f7cc78ecSespie 		  int elength = CGEN_EXTRACT_FN (cd, insn)
503f7cc78ecSespie 		    (cd, insn, info, base_insn, fields, (bfd_vma) 0);
504f7cc78ecSespie 		  if (elength > 0)
505f7cc78ecSespie 		    {
506f7cc78ecSespie 		      /* sanity check */
507f7cc78ecSespie 		      if (length != 0 && length != elength)
508f7cc78ecSespie 			abort ();
509f7cc78ecSespie 		      return insn;
510f7cc78ecSespie 		    }
511f7cc78ecSespie 		}
512f7cc78ecSespie 	    }
513f7cc78ecSespie 
514f7cc78ecSespie 	  insn_list = insn_list->next;
515f7cc78ecSespie 	}
516f7cc78ecSespie     }
517f7cc78ecSespie   else
518f7cc78ecSespie     {
519f7cc78ecSespie       /* Sanity check: can't pass an alias insn if ! alias_p.  */
520f7cc78ecSespie       if (! alias_p
521f7cc78ecSespie 	  && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_ALIAS))
522f7cc78ecSespie 	abort ();
523f7cc78ecSespie       /* Sanity check: length must be correct.  */
524f7cc78ecSespie       if (length != CGEN_INSN_BITSIZE (insn))
525f7cc78ecSespie 	abort ();
526f7cc78ecSespie 
527f7cc78ecSespie       /* ??? 0 is passed for `pc' */
528f7cc78ecSespie       length = CGEN_EXTRACT_FN (cd, insn)
529f7cc78ecSespie 	(cd, insn, info, base_insn, fields, (bfd_vma) 0);
530f7cc78ecSespie       /* Sanity check: must succeed.
531f7cc78ecSespie 	 Could relax this later if it ever proves useful.  */
532f7cc78ecSespie       if (length == 0)
533f7cc78ecSespie 	abort ();
534f7cc78ecSespie       return insn;
535f7cc78ecSespie     }
536f7cc78ecSespie 
537f7cc78ecSespie   return NULL;
538f7cc78ecSespie }
539f7cc78ecSespie 
540f7cc78ecSespie /* Fill in the operand instances used by INSN whose operands are FIELDS.
541f7cc78ecSespie    INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
542f7cc78ecSespie    in.  */
543f7cc78ecSespie 
544f7cc78ecSespie void
cgen_get_insn_operands(CGEN_CPU_DESC cd,const CGEN_INSN * insn,const CGEN_FIELDS * fields,int * indices)545*cf2f2c56Smiod cgen_get_insn_operands (CGEN_CPU_DESC cd,
546*cf2f2c56Smiod 			const CGEN_INSN *insn,
547*cf2f2c56Smiod 			const CGEN_FIELDS *fields,
548*cf2f2c56Smiod 			int *indices)
549f7cc78ecSespie {
550f7cc78ecSespie   const CGEN_OPINST *opinst;
551f7cc78ecSespie   int i;
552f7cc78ecSespie 
553f7cc78ecSespie   if (insn->opinst == NULL)
554f7cc78ecSespie     abort ();
555f7cc78ecSespie   for (i = 0, opinst = insn->opinst; opinst->type != CGEN_OPINST_END; ++i, ++opinst)
556f7cc78ecSespie     {
557f7cc78ecSespie       enum cgen_operand_type op_type = opinst->op_type;
558f7cc78ecSespie       if (op_type == CGEN_OPERAND_NIL)
559f7cc78ecSespie 	indices[i] = opinst->index;
560f7cc78ecSespie       else
561f7cc78ecSespie 	indices[i] = (*cd->get_int_operand) (cd, op_type, fields);
562f7cc78ecSespie     }
563f7cc78ecSespie }
564f7cc78ecSespie 
565f7cc78ecSespie /* Cover function to cgen_get_insn_operands when either INSN or FIELDS
566f7cc78ecSespie    isn't known.
567f7cc78ecSespie    The INSN, INSN_*_VALUE, and LENGTH arguments are passed to
568f7cc78ecSespie    cgen_lookup_insn unchanged.
569f7cc78ecSespie    INSN_INT_VALUE is used if CGEN_INT_INSN_P.
570f7cc78ecSespie    Otherwise INSN_BYTES_VALUE is used.
571f7cc78ecSespie 
572f7cc78ecSespie    The result is the insn table entry or NULL if the instruction wasn't
573f7cc78ecSespie    recognized.  */
574f7cc78ecSespie 
575f7cc78ecSespie const CGEN_INSN *
cgen_lookup_get_insn_operands(CGEN_CPU_DESC cd,const CGEN_INSN * insn,CGEN_INSN_INT insn_int_value,unsigned char * insn_bytes_value,int length,int * indices,CGEN_FIELDS * fields)576*cf2f2c56Smiod cgen_lookup_get_insn_operands (CGEN_CPU_DESC cd,
577*cf2f2c56Smiod 			       const CGEN_INSN *insn,
578*cf2f2c56Smiod 			       CGEN_INSN_INT insn_int_value,
579f7cc78ecSespie 			       /* ??? CGEN_INSN_BYTES would be a nice type name to use here.  */
580*cf2f2c56Smiod 			       unsigned char *insn_bytes_value,
581*cf2f2c56Smiod 			       int length,
582*cf2f2c56Smiod 			       int *indices,
583*cf2f2c56Smiod 			       CGEN_FIELDS *fields)
584f7cc78ecSespie {
585f7cc78ecSespie   /* Pass non-zero for ALIAS_P only if INSN != NULL.
586f7cc78ecSespie      If INSN == NULL, we want a real insn.  */
587f7cc78ecSespie   insn = cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value,
588f7cc78ecSespie 			   length, fields, insn != NULL);
589f7cc78ecSespie   if (! insn)
590f7cc78ecSespie     return NULL;
591f7cc78ecSespie 
592f7cc78ecSespie   cgen_get_insn_operands (cd, insn, fields, indices);
593f7cc78ecSespie   return insn;
594f7cc78ecSespie }
595f7cc78ecSespie 
596f7cc78ecSespie /* Allow signed overflow of instruction fields.  */
597f7cc78ecSespie void
cgen_set_signed_overflow_ok(CGEN_CPU_DESC cd)598*cf2f2c56Smiod cgen_set_signed_overflow_ok (CGEN_CPU_DESC cd)
599f7cc78ecSespie {
600f7cc78ecSespie   cd->signed_overflow_ok_p = 1;
601f7cc78ecSespie }
602f7cc78ecSespie 
603f7cc78ecSespie /* Generate an error message if a signed field in an instruction overflows.  */
604f7cc78ecSespie void
cgen_clear_signed_overflow_ok(CGEN_CPU_DESC cd)605*cf2f2c56Smiod cgen_clear_signed_overflow_ok (CGEN_CPU_DESC cd)
606f7cc78ecSespie {
607f7cc78ecSespie   cd->signed_overflow_ok_p = 0;
608f7cc78ecSespie }
609f7cc78ecSespie 
610f7cc78ecSespie /* Will an error message be generated if a signed field in an instruction overflows ? */
611f7cc78ecSespie unsigned int
cgen_signed_overflow_ok_p(CGEN_CPU_DESC cd)612*cf2f2c56Smiod cgen_signed_overflow_ok_p (CGEN_CPU_DESC cd)
613f7cc78ecSespie {
614f7cc78ecSespie   return cd->signed_overflow_ok_p;
615f7cc78ecSespie }
616