* cpu.c,model.c,sem-switch.c,sem.c: Regenerated. Mostly comment
[deliverable/binutils-gdb.git] / opcodes / cgen-asm.c
CommitLineData
9c03036a
DE
1/* CGEN generic assembler support code.
2
2613b5e6 3 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
9c03036a 4
2613b5e6 5 This file is part of the GNU Binutils and GDB, the GNU debugger.
9c03036a 6
2613b5e6
DE
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.
9c03036a 11
2613b5e6
DE
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.
9c03036a 16
2613b5e6
DE
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. */
9c03036a 20
2613b5e6 21#include "sysdep.h"
9c03036a 22#include <stdio.h>
2613b5e6 23#include <ctype.h>
9c03036a
DE
24#include "ansidecl.h"
25#include "libiberty.h"
26#include "bfd.h"
2613b5e6 27#include "symcat.h"
9c03036a
DE
28#include "opcode/cgen.h"
29
5b3b8cb0 30/* Operand parsing callback. */
a394e326
DE
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 *));
5b3b8cb0 34
9c03036a
DE
35/* This is not published as part of the public interface so we don't
36 declare this in cgen.h. */
2613b5e6 37extern CGEN_OPCODE_TABLE *cgen_current_opcode_table;
9c03036a
DE
38
39/* Assembler instruction hash table. */
40static CGEN_INSN_LIST **asm_hash_table;
2613b5e6 41static CGEN_INSN_LIST *asm_hash_table_entries;
9c03036a 42
a394e326
DE
43/* Called once at startup and whenever machine/endian change. */
44
9c03036a
DE
45void
46cgen_asm_init ()
47{
48 if (asm_hash_table)
49 {
50 free (asm_hash_table);
2613b5e6 51 free (asm_hash_table_entries);
9c03036a 52 asm_hash_table = NULL;
2613b5e6 53 asm_hash_table_entries = NULL;
9c03036a
DE
54 }
55}
56
a394e326
DE
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
2613b5e6
DE
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
9c03036a
DE
138/* Build the assembler instruction hash table. */
139
140static void
141build_asm_hash_table ()
142{
2613b5e6
DE
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;
9c03036a
DE
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 **)
2613b5e6
DE
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));
9c03036a
DE
158
159 /* Add compiled in insns.
2613b5e6
DE
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. */
9c03036a 163
2613b5e6
DE
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);
9c03036a
DE
176
177 /* Add runtime added insns.
2613b5e6
DE
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);
9c03036a
DE
187}
188
2613b5e6
DE
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. */
9c03036a
DE
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
2613b5e6 202 hash = (*cgen_current_opcode_table->asm_hash) (insn);
9c03036a
DE
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;
2613b5e6 217 CGEN_KEYWORD *keyword_table;
9c03036a
DE
218 long *valuep;
219{
2613b5e6 220 const CGEN_KEYWORD_ENTRY *ke;
9c03036a 221 char buf[256];
2613b5e6 222 const char *p,*start;
9c03036a 223
2613b5e6 224 p = start = *strp;
9c03036a 225
2613b5e6
DE
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. */
9c03036a
DE
229 if (*p)
230 ++p;
231
232 /* Now allow letters, digits, and _. */
2613b5e6
DE
233 while (((p - start) < (int) sizeof (buf))
234 && (isalnum ((unsigned char) *p) || *p == '_'))
9c03036a
DE
235 ++p;
236
2613b5e6 237 if (p - start >= (int) sizeof (buf))
9c03036a
DE
238 return "unrecognized keyword/register name";
239
2613b5e6
DE
240 memcpy (buf, start, p - start);
241 buf[p - start] = 0;
9c03036a
DE
242
243 ke = cgen_keyword_lookup_name (keyword_table, buf);
244
245 if (ke != NULL)
246 {
247 *valuep = ke->value;
2613b5e6
DE
248 /* Don't advance pointer if we recognized the null keyword. */
249 if (ke->name[0] != 0)
250 *strp = p;
9c03036a
DE
251 return NULL;
252 }
253
254 return "unrecognized keyword/register name";
255}
256
257/* Signed integer parser. */
258
259const char *
2613b5e6 260cgen_parse_signed_integer (strp, opindex, valuep)
9c03036a
DE
261 const char **strp;
262 int opindex;
9c03036a
DE
263 long *valuep;
264{
2613b5e6 265 bfd_vma value;
a394e326 266 enum cgen_parse_operand_result result;
9c03036a
DE
267 const char *errmsg;
268
a394e326
DE
269 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
270 opindex, BFD_RELOC_NONE,
271 &result, &value);
9c03036a
DE
272 /* FIXME: Examine `result'. */
273 if (!errmsg)
2613b5e6 274 *valuep = value;
9c03036a
DE
275 return errmsg;
276}
277
278/* Unsigned integer parser. */
279
280const char *
2613b5e6 281cgen_parse_unsigned_integer (strp, opindex, valuep)
9c03036a
DE
282 const char **strp;
283 int opindex;
9c03036a
DE
284 unsigned long *valuep;
285{
2613b5e6 286 bfd_vma value;
a394e326 287 enum cgen_parse_operand_result result;
9c03036a
DE
288 const char *errmsg;
289
a394e326
DE
290 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
291 opindex, BFD_RELOC_NONE,
292 &result, &value);
9c03036a
DE
293 /* FIXME: Examine `result'. */
294 if (!errmsg)
2613b5e6 295 *valuep = value;
9c03036a
DE
296 return errmsg;
297}
298
299/* Address parser. */
300
301const char *
2613b5e6 302cgen_parse_address (strp, opindex, opinfo, resultp, valuep)
9c03036a
DE
303 const char **strp;
304 int opindex;
305 int opinfo;
2613b5e6 306 enum cgen_parse_operand_result *resultp;
9c03036a
DE
307 long *valuep;
308{
2613b5e6
DE
309 bfd_vma value;
310 enum cgen_parse_operand_result result_type;
9c03036a
DE
311 const char *errmsg;
312
a394e326
DE
313 errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
314 opindex, opinfo,
2613b5e6 315 &result_type, &value);
9c03036a
DE
316 /* FIXME: Examine `result'. */
317 if (!errmsg)
318 {
2613b5e6
DE
319 if (resultp != NULL)
320 *resultp = result_type;
9c03036a
DE
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.068275 seconds and 4 git commands to generate.