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"
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
*));
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
;
40 /* Assembler instruction hash table. */
41 static CGEN_INSN_LIST
**asm_hash_table
;
42 static CGEN_INSN_LIST
*asm_hash_table_entries
;
44 /* Called once at startup and whenever machine/endian change. */
51 free (asm_hash_table
);
52 free (asm_hash_table_entries
);
53 asm_hash_table
= NULL
;
54 asm_hash_table_entries
= NULL
;
58 /* Called whenever starting to parse an insn. */
61 cgen_init_parse_operand ()
63 /* This tells the callback to re-initialize. */
64 (void) (*cgen_parse_operand_fn
) (CGEN_PARSE_OPERAND_INIT
, NULL
, 0, 0,
68 /* Subroutine of build_asm_hash_table to add INSNS to the hash table.
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.
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. */
83 static CGEN_INSN_LIST
*
84 hash_insn_array (insns
, count
, entsize
, otable
, htable
, hentbuf
)
85 const CGEN_INSN
* insns
;
88 const CGEN_OPCODE_TABLE
* otable
;
89 CGEN_INSN_LIST
** htable
;
90 CGEN_INSN_LIST
* hentbuf
;
92 const CGEN_INSN
* insn
;
94 for (insn
= (CGEN_INSN
*) ((char *) insns
+ entsize
* (count
- 1));
96 insn
= (CGEN_INSN
*) ((char *) insn
- entsize
), ++ hentbuf
)
100 if (! (*otable
->asm_hash_p
) (insn
))
102 hash
= (*otable
->asm_hash
) (CGEN_INSN_MNEMONIC (insn
));
103 hentbuf
->next
= htable
[hash
];
104 hentbuf
->insn
= insn
;
105 htable
[hash
] = hentbuf
;
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
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
;
122 const CGEN_INSN_LIST
* ilist
;
124 for (ilist
= insns
; ilist
!= NULL
; ilist
= ilist
->next
, ++ hentbuf
)
128 if (! (*otable
->asm_hash_p
) (ilist
->insn
))
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
;
139 /* Build the assembler instruction hash table. */
142 build_asm_hash_table ()
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
;
151 /* The space allocated for the hash table consists of two parts:
152 the hash table and the hash lists. */
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
));
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. */
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
);
171 /* Add compiled in macro-insns. */
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
);
178 /* Add runtime added insns.
179 Later added insns will be prefered over earlier ones. */
181 hash_entry_buf
= hash_insn_list (insn_table
->new_entries
, opcode_table
,
182 asm_hash_table
, hash_entry_buf
);
184 /* Add runtime added macro-insns. */
186 hash_insn_list (macro_insn_table
->new_entries
,
187 opcode_table
, asm_hash_table
, hash_entry_buf
);
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. */
195 cgen_asm_lookup_insn (insn
)
200 if (asm_hash_table
== NULL
)
201 build_asm_hash_table ();
203 hash
= (*cgen_current_opcode_table
->asm_hash
) (insn
);
204 return asm_hash_table
[hash
];
208 The result is NULL upon success or an error message.
209 If successful, *STRP is updated to point passed the keyword.
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]. */
216 cgen_parse_keyword (strp
, keyword_table
, valuep
)
218 CGEN_KEYWORD
*keyword_table
;
221 const CGEN_KEYWORD_ENTRY
*ke
;
223 const char *p
,*start
;
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. */
233 /* Now allow letters, digits, and _. */
234 while (((p
- start
) < (int) sizeof (buf
))
235 && (isalnum ((unsigned char) *p
) || *p
== '_'))
238 if (p
- start
>= (int) sizeof (buf
))
239 return _("unrecognized keyword/register name");
241 memcpy (buf
, start
, p
- start
);
244 ke
= cgen_keyword_lookup_name (keyword_table
, buf
);
249 /* Don't advance pointer if we recognized the null keyword. */
250 if (ke
->name
[0] != 0)
255 return "unrecognized keyword/register name";
258 /* Signed integer parser. */
261 cgen_parse_signed_integer (strp
, opindex
, valuep
)
267 enum cgen_parse_operand_result result
;
270 errmsg
= (*cgen_parse_operand_fn
) (CGEN_PARSE_OPERAND_INTEGER
, strp
,
271 opindex
, BFD_RELOC_NONE
,
273 /* FIXME: Examine `result'. */
279 /* Unsigned integer parser. */
282 cgen_parse_unsigned_integer (strp
, opindex
, valuep
)
285 unsigned long *valuep
;
288 enum cgen_parse_operand_result result
;
291 errmsg
= (*cgen_parse_operand_fn
) (CGEN_PARSE_OPERAND_INTEGER
, strp
,
292 opindex
, BFD_RELOC_NONE
,
294 /* FIXME: Examine `result'. */
300 /* Address parser. */
303 cgen_parse_address (strp
, opindex
, opinfo
, resultp
, valuep
)
307 enum cgen_parse_operand_result
*resultp
;
311 enum cgen_parse_operand_result result_type
;
314 errmsg
= (*cgen_parse_operand_fn
) (CGEN_PARSE_OPERAND_ADDRESS
, strp
,
316 &result_type
, &value
);
317 /* FIXME: Examine `result'. */
321 *resultp
= result_type
;
327 /* Signed integer validation routine. */
330 cgen_validate_signed_integer (value
, min
, max
)
331 long value
, min
, max
;
333 if (value
< min
|| value
> max
)
335 static char buf
[100];
337 /* xgettext:c-format */
338 sprintf (buf
, _("operand out of range (%ld not between %ld and %ld)"),
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). */
351 cgen_validate_unsigned_integer (value
, min
, max
)
352 unsigned long value
, min
, max
;
354 if (value
< min
|| value
> max
)
356 static char buf
[100];
358 sprintf (buf
, _("operand out of range (%lu not between %lu and %lu)"),