]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/binutils/opcodes/cgen-asm.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / contrib / binutils / 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
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 *));
34
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;
38
39 /* Assembler instruction hash table.  */
40 static CGEN_INSN_LIST **asm_hash_table;
41
42 /* Called once at startup and whenever machine/endian change.  */
43
44 void
45 cgen_asm_init ()
46 {
47   if (asm_hash_table)
48     {
49       free (asm_hash_table);
50       asm_hash_table = NULL;
51     }
52 }
53
54 /* Called whenever starting to parse an insn.  */
55
56 void
57 cgen_init_parse_operand ()
58 {
59   /* This tells the callback to re-initialize.  */
60   (void) (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INIT, NULL, 0, 0,
61                                    NULL, NULL);
62 }
63
64 /* Build the assembler instruction hash table.  */
65
66 static void
67 build_asm_hash_table ()
68 {
69   unsigned int hash;
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;
77
78   /* The space allocated for the hash table consists of two parts:
79      the hash table and the hash lists.  */
80
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);
88
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.  */
96
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)
102     {
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;
107     }
108
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;
113        new_insns != NULL;
114        new_insns = new_insns->next, ++insn_lists)
115     {
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;
120     }
121 }
122
123 /* Return the first entry in the hash list for INSN.  */
124
125 CGEN_INSN_LIST *
126 cgen_asm_lookup_insn (insn)
127      const char *insn;
128 {
129   unsigned int hash;
130
131   if (asm_hash_table == NULL)
132     build_asm_hash_table ();
133
134   hash = (*cgen_current_opcode_data->insn_table->asm_hash) (insn);
135   return asm_hash_table[hash];
136 }
137 \f
138 /* Keyword parser.
139    The result is NULL upon success or an error message.
140    If successful, *STRP is updated to point passed the keyword.
141
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].  */
145
146 const char *
147 cgen_parse_keyword (strp, keyword_table, valuep)
148      const char **strp;
149      CGEN_KEYWORD *keyword_table;
150      long *valuep;
151 {
152   const CGEN_KEYWORD_ENTRY *ke;
153   char buf[256];
154   const char *p,*start;
155
156   p = start = *strp;
157
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.  */
161   if (*p)
162     ++p;
163
164   /* Now allow letters, digits, and _.  */
165   while (((p - start) < (int) sizeof (buf))
166          && (isalnum ((unsigned char) *p) || *p == '_'))
167     ++p;
168
169   if (p - start >= (int) sizeof (buf))
170     return "unrecognized keyword/register name";
171
172   memcpy (buf, start, p - start);
173   buf[p - start] = 0;
174
175   ke = cgen_keyword_lookup_name (keyword_table, buf);
176
177   if (ke != NULL)
178     {
179       *valuep = ke->value;
180       /* Don't advance pointer if we recognized the null keyword.  */
181       if (ke->name[0] != 0)
182         *strp = p;
183       return NULL;
184     }
185
186   return "unrecognized keyword/register name";
187 }
188
189 /* Signed integer parser.  */
190
191 const char *
192 cgen_parse_signed_integer (strp, opindex, valuep)
193      const char **strp;
194      int opindex;
195      long *valuep;
196 {
197   bfd_vma value;
198   enum cgen_parse_operand_result result;
199   const char *errmsg;
200
201   errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
202                                      opindex, BFD_RELOC_NONE,
203                                      &result, &value);
204   /* FIXME: Examine `result'.  */
205   if (!errmsg)
206     *valuep = value;
207   return errmsg;
208 }
209
210 /* Unsigned integer parser.  */
211
212 const char *
213 cgen_parse_unsigned_integer (strp, opindex, valuep)
214      const char **strp;
215      int opindex;
216      unsigned long *valuep;
217 {
218   bfd_vma value;
219   enum cgen_parse_operand_result result;
220   const char *errmsg;
221
222   errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_INTEGER, strp,
223                                      opindex, BFD_RELOC_NONE,
224                                      &result, &value);
225   /* FIXME: Examine `result'.  */
226   if (!errmsg)
227     *valuep = value;
228   return errmsg;
229 }
230
231 /* Address parser.  */
232
233 const char *
234 cgen_parse_address (strp, opindex, opinfo, resultp, valuep)
235      const char **strp;
236      int opindex;
237      int opinfo;
238      enum cgen_parse_operand_result *resultp;
239      long *valuep;
240 {
241   bfd_vma value;
242   enum cgen_parse_operand_result result_type;
243   const char *errmsg;
244
245   errmsg = (*cgen_parse_operand_fn) (CGEN_PARSE_OPERAND_ADDRESS, strp,
246                                      opindex, opinfo,
247                                      &result_type, &value);
248   /* FIXME: Examine `result'.  */
249   if (!errmsg)
250     {
251       if (resultp != NULL)
252         *resultp = result_type;
253       *valuep = value;
254     }
255   return errmsg;
256 }
257 \f
258 /* Signed integer validation routine.  */
259
260 const char *
261 cgen_validate_signed_integer (value, min, max)
262      long value, min, max;
263 {
264   if (value < min || value > max)
265     {
266       const char *err =
267         "operand out of range (%ld not between %ld and %ld)";
268       static char buf[100];
269
270       sprintf (buf, err, value, min, max);
271       return buf;
272     }
273
274   return NULL;
275 }
276
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).  */
280
281 const char *
282 cgen_validate_unsigned_integer (value, min, max)
283      unsigned long value, min, max;
284 {
285   if (value < min || value > max)
286     {
287       const char *err =
288         "operand out of range (%lu not between %lu and %lu)";
289       static char buf[100];
290
291       sprintf (buf, err, value, min, max);
292       return buf;
293     }
294
295   return NULL;
296 }