s/sanitize-m32rx/sanitize-cygnus/
[deliverable/binutils-gdb.git] / opcodes / cgen-asm.c
1 /* CGEN generic assembler support code.
2
3 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
4
5 This file is part of the GNU Binutils and GDB, the GNU debugger.
6
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)
10 any later version.
11
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.
16
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. */
20
21 #include "sysdep.h"
22 #include <stdio.h>
23 #include <ctype.h>
24 #include "ansidecl.h"
25 #include "libiberty.h"
26 #include "bfd.h"
27 #include "symcat.h"
28 #include "opcode/cgen.h"
29 #include "opintl.h"
30
31 /* Operand parsing callback. */
32 const char * (*cgen_parse_operand_fn)
33 PARAMS ((enum cgen_parse_operand_type, const char **, int, int,
34 enum cgen_parse_operand_result *, bfd_vma *));
35
36 /* This is not published as part of the public interface so we don't
37 declare this in cgen.h. */
38 extern CGEN_OPCODE_TABLE *cgen_current_opcode_table;
39
40 /* Assembler instruction hash table. */
41 static CGEN_INSN_LIST **asm_hash_table;
42 static CGEN_INSN_LIST *asm_hash_table_entries;
43
44 /* Called once at startup and whenever machine/endian change. */
45
46 void
47 cgen_asm_init ()
48 {
49 if (asm_hash_table)
50 {
51 free (asm_hash_table);
52 free (asm_hash_table_entries);
53 asm_hash_table = NULL;
54 asm_hash_table_entries = NULL;
55 }
56 }
57
58 /* Called whenever starting to parse an insn. */
59
60 void
61 cgen_init_parse_operand ()
62 {
63 /* This tells the callback to re-initialize. */
64 (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0,
65 NULL, NULL);
66 }
67
68 /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
69
70 COUNT is the number of elements in INSNS.
71 ENTSIZE is sizeof (CGEN_INSN) for the target.
72 This is a bit tricky as the size of the attribute member of CGEN_INSN
73 is variable among architectures. This code could be moved to
74 cgen-asm.in, but I prefer to keep it here for now.
75 OTABLE is the opcode table.
76 HTABLE points to the hash table.
77 HENTBUF is a pointer to sufficiently large buffer of hash entries.
78 The result is a pointer to the next entry to use.
79
80 The table is scanned backwards as additions are made to the front of the
81 list and we want earlier ones to be prefered. */
82
83 static CGEN_INSN_LIST *
84 hash_insn_array (insns, count, entsize, otable, htable, hentbuf)
85 const CGEN_INSN * insns;
86 int count;
87 int entsize;
88 const CGEN_OPCODE_TABLE * otable;
89 CGEN_INSN_LIST ** htable;
90 CGEN_INSN_LIST * hentbuf;
91 {
92 const CGEN_INSN * insn;
93
94 for (insn = (CGEN_INSN *) ((char *) insns + entsize * (count - 1));
95 insn >= insns;
96 insn = (CGEN_INSN *) ((char *) insn - entsize), ++ hentbuf)
97 {
98 unsigned int hash;
99
100 if (! (*otable->asm_hash_p) (insn))
101 continue;
102 hash = (*otable->asm_hash) (CGEN_INSN_MNEMONIC (insn));
103 hentbuf->next = htable[hash];
104 hentbuf->insn = insn;
105 htable[hash] = hentbuf;
106 }
107
108 return hentbuf;
109 }
110
111 /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
112 This function is identical to hash_insn_array except the insns are
113 in a list. */
114
115 static CGEN_INSN_LIST *
116 hash_insn_list (insns, otable, htable, hentbuf)
117 const CGEN_INSN_LIST * insns;
118 const CGEN_OPCODE_TABLE * otable;
119 CGEN_INSN_LIST ** htable;
120 CGEN_INSN_LIST * hentbuf;
121 {
122 const CGEN_INSN_LIST * ilist;
123
124 for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
125 {
126 unsigned int hash;
127
128 if (! (*otable->asm_hash_p) (ilist->insn))
129 continue;
130 hash = (*otable->asm_hash) (CGEN_INSN_MNEMONIC (ilist->insn));
131 hentbuf->next = htable[hash];
132 hentbuf->insn = ilist->insn;
133 asm_hash_table[hash] = hentbuf;
134 }
135
136 return hentbuf;
137 }
138
139 /* Build the assembler instruction hash table. */
140
141 static void
142 build_asm_hash_table ()
143 {
144 int count = cgen_insn_count () + cgen_macro_insn_count ();
145 CGEN_OPCODE_TABLE *opcode_table = cgen_current_opcode_table;
146 CGEN_INSN_TABLE *insn_table = opcode_table->insn_table;
147 CGEN_INSN_TABLE *macro_insn_table = opcode_table->macro_insn_table;
148 unsigned int hash_size = opcode_table->asm_hash_table_size;
149 CGEN_INSN_LIST *hash_entry_buf;
150
151 /* The space allocated for the hash table consists of two parts:
152 the hash table and the hash lists. */
153
154 asm_hash_table = (CGEN_INSN_LIST **)
155 xmalloc (hash_size * sizeof (CGEN_INSN_LIST *));
156 memset (asm_hash_table, 0, hash_size * sizeof (CGEN_INSN_LIST *));
157 asm_hash_table_entries = hash_entry_buf = (CGEN_INSN_LIST *)
158 xmalloc (count * sizeof (CGEN_INSN_LIST));
159
160 /* Add compiled in insns.
161 Don't include the first one as it is a reserved entry. */
162 /* ??? It was the end of all hash chains, and also the special
163 "illegal insn" marker. May be able to do it differently now. */
164
165 hash_entry_buf = hash_insn_array ((CGEN_INSN *) ((char *) insn_table->init_entries
166 + insn_table->entry_size),
167 insn_table->num_init_entries - 1,
168 insn_table->entry_size,
169 opcode_table, asm_hash_table, hash_entry_buf);
170
171 /* Add compiled in macro-insns. */
172
173 hash_entry_buf = hash_insn_array (macro_insn_table->init_entries,
174 macro_insn_table->num_init_entries,
175 macro_insn_table->entry_size,
176 opcode_table, asm_hash_table, hash_entry_buf);
177
178 /* Add runtime added insns.
179 Later added insns will be prefered over earlier ones. */
180
181 hash_entry_buf = hash_insn_list (insn_table->new_entries, opcode_table,
182 asm_hash_table, hash_entry_buf);
183
184 /* Add runtime added macro-insns. */
185
186 hash_insn_list (macro_insn_table->new_entries,
187 opcode_table, asm_hash_table, hash_entry_buf);
188 }
189
190 /* Return the first entry in the hash list for INSN.
191 ??? Of course it would be better to pass in a pointer to the
192 opcode data structure, rather than reference a global. Later. */
193
194 CGEN_INSN_LIST *
195 cgen_asm_lookup_insn (insn)
196 const char *insn;
197 {
198 unsigned int hash;
199
200 if (asm_hash_table == NULL)
201 build_asm_hash_table ();
202
203 hash = (*cgen_current_opcode_table->asm_hash) (insn);
204 return asm_hash_table[hash];
205 }
206 \f
207 /* Keyword parser.
208 The result is NULL upon success or an error message.
209 If successful, *STRP is updated to point passed the keyword.
210
211 ??? At present we have a static notion of how to pick out a keyword.
212 Later we can allow a target to customize this if necessary [say by
213 recording something in the keyword table]. */
214
215 const char *
216 cgen_parse_keyword (strp, keyword_table, valuep)
217 const char **strp;
218 CGEN_KEYWORD *keyword_table;
219 long *valuep;
220 {
221 const CGEN_KEYWORD_ENTRY *ke;
222 char buf[256];
223 const char *p,*start;
224
225 p = start = *strp;
226
227 /* Allow any first character.
228 Note that this allows recognizing ",a" for the annul flag in sparc
229 even though "," is subsequently not a valid keyword char. */
230 if (*p)
231 ++p;
232
233 /* Now allow letters, digits, and _. */
234 while (((p - start) < (int) sizeof (buf))
235 && (isalnum ((unsigned char) *p) || *p == '_'))
236 ++p;
237
238 if (p - start >= (int) sizeof (buf))
239 return _("unrecognized keyword/register name");
240
241 memcpy (buf, start, p - start);
242 buf[p - start] = 0;
243
244 ke = cgen_keyword_lookup_name (keyword_table, buf);
245
246 if (ke != NULL)
247 {
248 *valuep = ke->value;
249 /* Don't advance pointer if we recognized the null keyword. */
250 if (ke->name[0] != 0)
251 *strp = p;
252 return NULL;
253 }
254
255 return "unrecognized keyword/register name";
256 }
257
258 /* Signed integer parser. */
259
260 const char *
261 cgen_parse_signed_integer (strp, opindex, valuep)
262 const char **strp;
263 int opindex;
264 long *valuep;
265 {
266 bfd_vma value;
267 enum cgen_parse_operand_result result;
268 const char *errmsg;
269
270 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
271 opindex, BFD_RELOC_NONE,
272 &result, &value);
273 /* FIXME: Examine `result'. */
274 if (!errmsg)
275 *valuep = value;
276 return errmsg;
277 }
278
279 /* Unsigned integer parser. */
280
281 const char *
282 cgen_parse_unsigned_integer (strp, opindex, valuep)
283 const char **strp;
284 int opindex;
285 unsigned long *valuep;
286 {
287 bfd_vma value;
288 enum cgen_parse_operand_result result;
289 const char *errmsg;
290
291 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
292 opindex, BFD_RELOC_NONE,
293 &result, &value);
294 /* FIXME: Examine `result'. */
295 if (!errmsg)
296 *valuep = value;
297 return errmsg;
298 }
299
300 /* Address parser. */
301
302 const char *
303 cgen_parse_address (strp, opindex, opinfo, resultp, valuep)
304 const char **strp;
305 int opindex;
306 int opinfo;
307 enum cgen_parse_operand_result *resultp;
308 long *valuep;
309 {
310 bfd_vma value;
311 enum cgen_parse_operand_result result_type;
312 const char *errmsg;
313
314 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
315 opindex, opinfo,
316 &result_type, &value);
317 /* FIXME: Examine `result'. */
318 if (!errmsg)
319 {
320 if (resultp != NULL)
321 *resultp = result_type;
322 *valuep = value;
323 }
324 return errmsg;
325 }
326 \f
327 /* Signed integer validation routine. */
328
329 const char *
330 cgen_validate_signed_integer (value, min, max)
331 long value, min, max;
332 {
333 if (value < min || value > max)
334 {
335 static char buf[100];
336
337 /* xgettext:c-format */
338 sprintf (buf, _("operand out of range (%ld not between %ld and %ld)"),
339 value, min, max);
340 return buf;
341 }
342
343 return NULL;
344 }
345
346 /* Unsigned integer validation routine.
347 Supplying `min' here may seem unnecessary, but we also want to handle
348 cases where min != 0 (and max > LONG_MAX). */
349
350 const char *
351 cgen_validate_unsigned_integer (value, min, max)
352 unsigned long value, min, max;
353 {
354 if (value < min || value > max)
355 {
356 static char buf[100];
357
358 sprintf (buf, _("operand out of range (%lu not between %lu and %lu)"),
359 value, min, max);
360 return buf;
361 }
362
363 return NULL;
364 }
This page took 0.037539 seconds and 4 git commands to generate.