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_DATA *cgen_current_opcode_data;
39 /* Assembler instruction hash table. */
40 static CGEN_INSN_LIST **asm_hash_table;
42 /* Called once at startup and whenever machine/endian change. */
49 free (asm_hash_table);
50 asm_hash_table = NULL;
54 /* Called whenever starting to parse an insn. */
57 cgen_init_parse_operand ()
59 /* This tells the callback to re-initialize. */
60 (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0,
64 /* Build the assembler instruction hash table. */
67 build_asm_hash_table ()
70 int count = cgen_insn_count ();
71 CGEN_OPCODE_DATA *data = cgen_current_opcode_data;
72 CGEN_INSN_TABLE *insn_table = data->insn_table;
73 unsigned int entry_size = insn_table->entry_size;
74 unsigned int hash_size = insn_table->asm_hash_table_size;
75 const CGEN_INSN *insn;
76 CGEN_INSN_LIST *insn_lists,*new_insns;
78 /* The space allocated for the hash table consists of two parts:
79 the hash table and the hash lists. */
81 asm_hash_table = (CGEN_INSN_LIST **)
82 xmalloc (hash_size * sizeof (CGEN_INSN_LIST *)
83 + count * sizeof (CGEN_INSN_LIST));
84 memset (asm_hash_table, 0,
85 hash_size * sizeof (CGEN_INSN_LIST *)
86 + count * sizeof (CGEN_INSN_LIST));
87 insn_lists = (CGEN_INSN_LIST *) (asm_hash_table + hash_size);
89 /* Add compiled in insns.
90 The table is scanned backwards as later additions are inserted in
91 front of earlier ones and we want earlier ones to be prefered.
92 We stop at the first one as it is a reserved entry.
93 This is a bit tricky as the attribute member of CGEN_INSN is variable
94 among architectures. This code could be moved to cgen-asm.in, but
95 I prefer to keep it here for now. */
97 for (insn = (CGEN_INSN *)
98 ((char *) insn_table->init_entries
99 + entry_size * (insn_table->num_init_entries - 1));
100 insn > insn_table->init_entries;
101 insn = (CGEN_INSN *) ((char *) insn - entry_size), ++insn_lists)
103 hash = (*insn_table->asm_hash) CGEN_INSN_MNEMONIC (insn);
104 insn_lists->next = asm_hash_table[hash];
105 insn_lists->insn = insn;
106 asm_hash_table[hash] = insn_lists;
109 /* Add runtime added insns.
110 ??? Currently later added insns will be prefered over earlier ones.
111 Not sure this is a bug or not. */
112 for (new_insns = insn_table->new_entries;
114 new_insns = new_insns->next, ++insn_lists)
116 hash = (*insn_table->asm_hash) CGEN_INSN_MNEMONIC (new_insns->insn);
117 insn_lists->next = asm_hash_table[hash];
118 insn_lists->insn = new_insns->insn;
119 asm_hash_table[hash] = insn_lists;
123 /* Return the first entry in the hash list for INSN. */
126 cgen_asm_lookup_insn (insn)
131 if (asm_hash_table == NULL)
132 build_asm_hash_table ();
134 hash = (*cgen_current_opcode_data->insn_table->asm_hash) (insn);
135 return asm_hash_table[hash];
139 The result is NULL upon success or an error message.
140 If successful, *STRP is updated to point passed the keyword.
142 ??? At present we have a static notion of how to pick out a keyword.
143 Later we can allow a target to customize this if necessary [say by
144 recording something in the keyword table]. */
147 cgen_parse_keyword (strp, keyword_table, valuep)
149 CGEN_KEYWORD *keyword_table;
152 const CGEN_KEYWORD_ENTRY *ke;
154 const char *p,*start;
158 /* Allow any first character.
159 Note that this allows recognizing ",a" for the annul flag in sparc
160 even though "," is subsequently not a valid keyword char. */
164 /* Now allow letters, digits, and _. */
165 while (((p - start) < (int) sizeof (buf))
166 && (isalnum ((unsigned char) *p) || *p == '_'))
169 if (p - start >= (int) sizeof (buf))
170 return "unrecognized keyword/register name";
172 memcpy (buf, start, p - start);
175 ke = cgen_keyword_lookup_name (keyword_table, buf);
180 /* Don't advance pointer if we recognized the null keyword. */
181 if (ke->name[0] != 0)
186 return "unrecognized keyword/register name";
189 /* Signed integer parser. */
192 cgen_parse_signed_integer (strp, opindex, valuep)
198 enum cgen_parse_operand_result result;
201 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
202 opindex, BFD_RELOC_NONE,
204 /* FIXME: Examine `result'. */
210 /* Unsigned integer parser. */
213 cgen_parse_unsigned_integer (strp, opindex, valuep)
216 unsigned long *valuep;
219 enum cgen_parse_operand_result result;
222 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
223 opindex, BFD_RELOC_NONE,
225 /* FIXME: Examine `result'. */
231 /* Address parser. */
234 cgen_parse_address (strp, opindex, opinfo, resultp, valuep)
238 enum cgen_parse_operand_result *resultp;
242 enum cgen_parse_operand_result result_type;
245 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
247 &result_type, &value);
248 /* FIXME: Examine `result'. */
252 *resultp = result_type;
258 /* Signed integer validation routine. */
261 cgen_validate_signed_integer (value, min, max)
262 long value, min, max;
264 if (value < min || value > max)
267 "operand out of range (%ld not between %ld and %ld)";
268 static char buf[100];
270 sprintf (buf, err, value, min, max);
277 /* Unsigned integer validation routine.
278 Supplying `min' here may seem unnecessary, but we also want to handle
279 cases where min != 0 (and max > LONG_MAX). */
282 cgen_validate_unsigned_integer (value, min, max)
283 unsigned long value, min, max;
285 if (value < min || value > max)
288 "operand out of range (%lu not between %lu and %lu)";
289 static char buf[100];
291 sprintf (buf, err, value, min, max);