1 /* CGEN generic assembler support code.
3 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
5 This file is part of the GNU Binutils and GDB, the GNU debugger.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 #include "libiberty.h"
28 #include "opcode/cgen.h"
30 /* Operand parsing callback. */
31 const char * (*cgen_parse_operand_fn)
32 PARAMS ((enum cgen_parse_operand_type, const char **, int, int,
33 enum cgen_parse_operand_result *, bfd_vma *));
35 /* This is not published as part of the public interface so we don't
36 declare this in cgen.h. */
37 extern CGEN_OPCODE_TABLE *cgen_current_opcode_table;
39 /* Assembler instruction hash table. */
40 static CGEN_INSN_LIST **asm_hash_table;
41 static CGEN_INSN_LIST *asm_hash_table_entries;
43 /* Called once at startup and whenever machine/endian change. */
50 free (asm_hash_table);
51 free (asm_hash_table_entries);
52 asm_hash_table = NULL;
53 asm_hash_table_entries = NULL;
57 /* Called whenever starting to parse an insn. */
60 cgen_init_parse_operand ()
62 /* This tells the callback to re-initialize. */
63 (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0,
67 /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
69 COUNT is the number of elements in INSNS.
70 ENTSIZE is sizeof (CGEN_INSN) for the target.
71 This is a bit tricky as the size of the attribute member of CGEN_INSN
72 is variable among architectures. This code could be moved to
73 cgen-asm.in, but I prefer to keep it here for now.
74 OTABLE is the opcode table.
75 HTABLE points to the hash table.
76 HENTBUF is a pointer to sufficiently large buffer of hash entries.
77 The result is a pointer to the next entry to use.
79 The table is scanned backwards as additions are made to the front of the
80 list and we want earlier ones to be prefered. */
82 static CGEN_INSN_LIST *
83 hash_insn_array (insns, count, entsize, otable, htable, hentbuf)
84 const CGEN_INSN * insns;
87 const CGEN_OPCODE_TABLE * otable;
88 CGEN_INSN_LIST ** htable;
89 CGEN_INSN_LIST * hentbuf;
91 const CGEN_INSN * insn;
93 for (insn = (CGEN_INSN *) ((char *) insns + entsize * (count - 1));
95 insn = (CGEN_INSN *) ((char *) insn - entsize), ++ hentbuf)
99 if (! (*otable->asm_hash_p) (insn))
101 hash = (*otable->asm_hash) (CGEN_INSN_MNEMONIC (insn));
102 hentbuf->next = htable[hash];
103 hentbuf->insn = insn;
104 htable[hash] = hentbuf;
110 /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
111 This function is identical to hash_insn_array except the insns are
114 static CGEN_INSN_LIST *
115 hash_insn_list (insns, otable, htable, hentbuf)
116 const CGEN_INSN_LIST * insns;
117 const CGEN_OPCODE_TABLE * otable;
118 CGEN_INSN_LIST ** htable;
119 CGEN_INSN_LIST * hentbuf;
121 const CGEN_INSN_LIST * ilist;
123 for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
127 if (! (*otable->asm_hash_p) (ilist->insn))
129 hash = (*otable->asm_hash) (CGEN_INSN_MNEMONIC (ilist->insn));
130 hentbuf->next = htable[hash];
131 hentbuf->insn = ilist->insn;
132 asm_hash_table[hash] = hentbuf;
138 /* Build the assembler instruction hash table. */
141 build_asm_hash_table ()
143 int count = cgen_insn_count () + cgen_macro_insn_count ();
144 CGEN_OPCODE_TABLE *opcode_table = cgen_current_opcode_table;
145 CGEN_INSN_TABLE *insn_table = opcode_table->insn_table;
146 CGEN_INSN_TABLE *macro_insn_table = opcode_table->macro_insn_table;
147 unsigned int hash_size = opcode_table->asm_hash_table_size;
148 CGEN_INSN_LIST *hash_entry_buf;
150 /* The space allocated for the hash table consists of two parts:
151 the hash table and the hash lists. */
153 asm_hash_table = (CGEN_INSN_LIST **)
154 xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
155 memset (asm_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
156 asm_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
157 xmalloc (count * sizeof (CGEN_INSN_LIST));
159 /* Add compiled in insns.
160 Don't include the first one as it is a reserved entry. */
161 /* ??? It was the end of all hash chains, and also the special
162 "illegal insn" marker. May be able to do it differently now. */
164 hash_entry_buf = hash_insn_array ((CGEN_INSN *) ((char *) insn_table->init_entries
165 + insn_table->entry_size),
166 insn_table->num_init_entries - 1,
167 insn_table->entry_size,
168 opcode_table, asm_hash_table, hash_entry_buf);
170 /* Add compiled in macro-insns. */
172 hash_entry_buf = hash_insn_array (macro_insn_table->init_entries,
173 macro_insn_table->num_init_entries,
174 macro_insn_table->entry_size,
175 opcode_table, asm_hash_table, hash_entry_buf);
177 /* Add runtime added insns.
178 Later added insns will be prefered over earlier ones. */
180 hash_entry_buf = hash_insn_list (insn_table->new_entries, opcode_table,
181 asm_hash_table, hash_entry_buf);
183 /* Add runtime added macro-insns. */
185 hash_insn_list (macro_insn_table->new_entries,
186 opcode_table, asm_hash_table, hash_entry_buf);
189 /* Return the first entry in the hash list for INSN.
190 ??? Of course it would be better to pass in a pointer to the
191 opcode data structure, rather than reference a global. Later. */
194 cgen_asm_lookup_insn (insn)
199 if (asm_hash_table == NULL)
200 build_asm_hash_table ();
202 hash = (*cgen_current_opcode_table->asm_hash) (insn);
203 return asm_hash_table[hash];
207 The result is NULL upon success or an error message.
208 If successful, *STRP is updated to point passed the keyword.
210 ??? At present we have a static notion of how to pick out a keyword.
211 Later we can allow a target to customize this if necessary [say by
212 recording something in the keyword table]. */
215 cgen_parse_keyword (strp, keyword_table, valuep)
217 CGEN_KEYWORD *keyword_table;
220 const CGEN_KEYWORD_ENTRY *ke;
222 const char *p,*start;
226 /* Allow any first character.
227 Note that this allows recognizing ",a" for the annul flag in sparc
228 even though "," is subsequently not a valid keyword char. */
232 /* Now allow letters, digits, and _. */
233 while (((p - start) < (int) sizeof (buf))
234 && (isalnum ((unsigned char) *p) || *p == '_'))
237 if (p - start >= (int) sizeof (buf))
238 return "unrecognized keyword/register name";
240 memcpy (buf, start, p - start);
243 ke = cgen_keyword_lookup_name (keyword_table, buf);
248 /* Don't advance pointer if we recognized the null keyword. */
249 if (ke->name[0] != 0)
254 return "unrecognized keyword/register name";
257 /* Signed integer parser. */
260 cgen_parse_signed_integer (strp, opindex, valuep)
266 enum cgen_parse_operand_result result;
269 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
270 opindex, BFD_RELOC_NONE,
272 /* FIXME: Examine `result'. */
278 /* Unsigned integer parser. */
281 cgen_parse_unsigned_integer (strp, opindex, valuep)
284 unsigned long *valuep;
287 enum cgen_parse_operand_result result;
290 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
291 opindex, BFD_RELOC_NONE,
293 /* FIXME: Examine `result'. */
299 /* Address parser. */
302 cgen_parse_address (strp, opindex, opinfo, resultp, valuep)
306 enum cgen_parse_operand_result *resultp;
310 enum cgen_parse_operand_result result_type;
313 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
315 &result_type, &value);
316 /* FIXME: Examine `result'. */
320 *resultp = result_type;
326 /* Signed integer validation routine. */
329 cgen_validate_signed_integer (value, min, max)
330 long value, min, max;
332 if (value < min || value > max)
335 "operand out of range (%ld not between %ld and %ld)";
336 static char buf[100];
338 sprintf (buf, err, value, min, max);
345 /* Unsigned integer validation routine.
346 Supplying `min' here may seem unnecessary, but we also want to handle
347 cases where min != 0 (and max > LONG_MAX). */
350 cgen_validate_unsigned_integer (value, min, max)
351 unsigned long value, min, max;
353 if (value < min || value > max)
356 "operand out of range (%lu not between %lu and %lu)";
357 static char buf[100];
359 sprintf (buf, err, value, min, max);