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