* cpu.c,model.c,sem-switch.c,sem.c: Regenerated. Mostly comment
[deliverable/binutils-gdb.git] / opcodes / cgen-asm.c
... / ...
CommitLineData
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
30/* Operand parsing callback. */
31const char * (*cgen_parse_operand_fn)
32 PARAMS ((enum cgen_parse_operand_type, const char **, int, int,
33 enum cgen_parse_operand_result *, bfd_vma *));
34
35/* This is not published as part of the public interface so we don't
36 declare this in cgen.h. */
37extern CGEN_OPCODE_TABLE *cgen_current_opcode_table;
38
39/* Assembler instruction hash table. */
40static CGEN_INSN_LIST **asm_hash_table;
41static CGEN_INSN_LIST *asm_hash_table_entries;
42
43/* Called once at startup and whenever machine/endian change. */
44
45void
46cgen_asm_init ()
47{
48 if (asm_hash_table)
49 {
50 free (asm_hash_table);
51 free (asm_hash_table_entries);
52 asm_hash_table = NULL;
53 asm_hash_table_entries = NULL;
54 }
55}
56
57/* Called whenever starting to parse an insn. */
58
59void
60cgen_init_parse_operand ()
61{
62 /* This tells the callback to re-initialize. */
63 (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0,
64 NULL, NULL);
65}
66
67/* Subroutine of build_asm_hash_table to add INSNS to the hash table.
68
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.
78
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. */
81
82static CGEN_INSN_LIST *
83hash_insn_array (insns, count, entsize, otable, htable, hentbuf)
84 const CGEN_INSN * insns;
85 int count;
86 int entsize;
87 const CGEN_OPCODE_TABLE * otable;
88 CGEN_INSN_LIST ** htable;
89 CGEN_INSN_LIST * hentbuf;
90{
91 const CGEN_INSN * insn;
92
93 for (insn = (CGEN_INSN *) ((char *) insns + entsize * (count - 1));
94 insn >= insns;
95 insn = (CGEN_INSN *) ((char *) insn - entsize), ++ hentbuf)
96 {
97 unsigned int hash;
98
99 if (! (*otable->asm_hash_p) (insn))
100 continue;
101 hash = (*otable->asm_hash) (CGEN_INSN_MNEMONIC (insn));
102 hentbuf->next = htable[hash];
103 hentbuf->insn = insn;
104 htable[hash] = hentbuf;
105 }
106
107 return hentbuf;
108}
109
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
112 in a list. */
113
114static CGEN_INSN_LIST *
115hash_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;
120{
121 const CGEN_INSN_LIST * ilist;
122
123 for (ilist = insns; ilist != NULL; ilist = ilist->next, ++ hentbuf)
124 {
125 unsigned int hash;
126
127 if (! (*otable->asm_hash_p) (ilist->insn))
128 continue;
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;
133 }
134
135 return hentbuf;
136}
137
138/* Build the assembler instruction hash table. */
139
140static void
141build_asm_hash_table ()
142{
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;
149
150 /* The space allocated for the hash table consists of two parts:
151 the hash table and the hash lists. */
152
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));
158
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. */
163
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);
169
170 /* Add compiled in macro-insns. */
171
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);
176
177 /* Add runtime added insns.
178 Later added insns will be prefered over earlier ones. */
179
180 hash_entry_buf = hash_insn_list (insn_table->new_entries, opcode_table,
181 asm_hash_table, hash_entry_buf);
182
183 /* Add runtime added macro-insns. */
184
185 hash_insn_list (macro_insn_table->new_entries,
186 opcode_table, asm_hash_table, hash_entry_buf);
187}
188
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. */
192
193CGEN_INSN_LIST *
194cgen_asm_lookup_insn (insn)
195 const char *insn;
196{
197 unsigned int hash;
198
199 if (asm_hash_table == NULL)
200 build_asm_hash_table ();
201
202 hash = (*cgen_current_opcode_table->asm_hash) (insn);
203 return asm_hash_table[hash];
204}
205\f
206/* Keyword parser.
207 The result is NULL upon success or an error message.
208 If successful, *STRP is updated to point passed the keyword.
209
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]. */
213
214const char *
215cgen_parse_keyword (strp, keyword_table, valuep)
216 const char **strp;
217 CGEN_KEYWORD *keyword_table;
218 long *valuep;
219{
220 const CGEN_KEYWORD_ENTRY *ke;
221 char buf[256];
222 const char *p,*start;
223
224 p = start = *strp;
225
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. */
229 if (*p)
230 ++p;
231
232 /* Now allow letters, digits, and _. */
233 while (((p - start) < (int) sizeof (buf))
234 && (isalnum ((unsigned char) *p) || *p == '_'))
235 ++p;
236
237 if (p - start >= (int) sizeof (buf))
238 return "unrecognized keyword/register name";
239
240 memcpy (buf, start, p - start);
241 buf[p - start] = 0;
242
243 ke = cgen_keyword_lookup_name (keyword_table, buf);
244
245 if (ke != NULL)
246 {
247 *valuep = ke->value;
248 /* Don't advance pointer if we recognized the null keyword. */
249 if (ke->name[0] != 0)
250 *strp = p;
251 return NULL;
252 }
253
254 return "unrecognized keyword/register name";
255}
256
257/* Signed integer parser. */
258
259const char *
260cgen_parse_signed_integer (strp, opindex, valuep)
261 const char **strp;
262 int opindex;
263 long *valuep;
264{
265 bfd_vma value;
266 enum cgen_parse_operand_result result;
267 const char *errmsg;
268
269 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
270 opindex, BFD_RELOC_NONE,
271 &result, &value);
272 /* FIXME: Examine `result'. */
273 if (!errmsg)
274 *valuep = value;
275 return errmsg;
276}
277
278/* Unsigned integer parser. */
279
280const char *
281cgen_parse_unsigned_integer (strp, opindex, valuep)
282 const char **strp;
283 int opindex;
284 unsigned long *valuep;
285{
286 bfd_vma value;
287 enum cgen_parse_operand_result result;
288 const char *errmsg;
289
290 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
291 opindex, BFD_RELOC_NONE,
292 &result, &value);
293 /* FIXME: Examine `result'. */
294 if (!errmsg)
295 *valuep = value;
296 return errmsg;
297}
298
299/* Address parser. */
300
301const char *
302cgen_parse_address (strp, opindex, opinfo, resultp, valuep)
303 const char **strp;
304 int opindex;
305 int opinfo;
306 enum cgen_parse_operand_result *resultp;
307 long *valuep;
308{
309 bfd_vma value;
310 enum cgen_parse_operand_result result_type;
311 const char *errmsg;
312
313 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
314 opindex, opinfo,
315 &result_type, &value);
316 /* FIXME: Examine `result'. */
317 if (!errmsg)
318 {
319 if (resultp != NULL)
320 *resultp = result_type;
321 *valuep = value;
322 }
323 return errmsg;
324}
325\f
326/* Signed integer validation routine. */
327
328const char *
329cgen_validate_signed_integer (value, min, max)
330 long value, min, max;
331{
332 if (value < min || value > max)
333 {
334 const char *err =
335 "operand out of range (%ld not between %ld and %ld)";
336 static char buf[100];
337
338 sprintf (buf, err, value, min, max);
339 return buf;
340 }
341
342 return NULL;
343}
344
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). */
348
349const char *
350cgen_validate_unsigned_integer (value, min, max)
351 unsigned long value, min, max;
352{
353 if (value < min || value > max)
354 {
355 const char *err =
356 "operand out of range (%lu not between %lu and %lu)";
357 static char buf[100];
358
359 sprintf (buf, err, value, min, max);
360 return buf;
361 }
362
363 return NULL;
364}
This page took 0.023804 seconds and 4 git commands to generate.