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