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