1 /* CGEN generic assembler support code.
3 Copyright (C) 1996, 1997 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. */
30 #include "libiberty.h"
32 #include "opcode/cgen.h"
34 /* Operand parsing callback. */
35 const char * (*cgen_parse_operand_fn
)
36 PARAMS ((enum cgen_parse_operand_type
, const char **, int, int,
37 enum cgen_parse_operand_result
*, bfd_vma
*));
39 /* This is not published as part of the public interface so we don't
40 declare this in cgen.h. */
41 extern CGEN_OPCODE_DATA
*cgen_current_opcode_data
;
43 /* Assembler instruction hash table. */
44 static CGEN_INSN_LIST
**asm_hash_table
;
46 /* Called once at startup and whenever machine/endian change. */
53 free (asm_hash_table
);
54 asm_hash_table
= 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 /* Build the assembler instruction hash table. */
71 build_asm_hash_table ()
75 int count
= cgen_insn_count ();
76 CGEN_OPCODE_DATA
*data
= cgen_current_opcode_data
;
77 CGEN_INSN_TABLE
*insn_table
= data
->insn_table
;
78 unsigned int hash_size
= insn_table
->asm_hash_table_size
;
79 const CGEN_INSN
*insn
;
80 CGEN_INSN_LIST
*insn_lists
,*new_insns
;
82 /* The space allocated for the hash table consists of two parts:
83 the hash table and the hash lists. */
85 asm_hash_table
= (CGEN_INSN_LIST
**)
86 xmalloc (hash_size
* sizeof (CGEN_INSN_LIST
*)
87 + count
* sizeof (CGEN_INSN_LIST
));
88 memset (asm_hash_table
, 0,
89 hash_size
* sizeof (CGEN_INSN_LIST
*)
90 + count
* sizeof (CGEN_INSN_LIST
));
91 insn_lists
= (CGEN_INSN_LIST
*) (asm_hash_table
+ hash_size
);
93 /* Add compiled in insns.
94 The table is scanned backwards as later additions are inserted in
95 front of earlier ones and we want earlier ones to be prefered.
96 We stop at the first one as it is a reserved entry. */
98 for (insn
= insn_table
->init_entries
+ insn_table
->num_init_entries
- 1;
99 insn
> insn_table
->init_entries
;
100 --insn
, ++insn_lists
)
102 hash
= (*insn_table
->asm_hash
) (insn
->syntax
.mnemonic
);
103 insn_lists
->next
= asm_hash_table
[hash
];
104 insn_lists
->insn
= insn
;
105 asm_hash_table
[hash
] = insn_lists
;
108 /* Add runtime added insns.
109 ??? Currently later added insns will be prefered over earlier ones.
110 Not sure this is a bug or not. */
111 for (new_insns
= insn_table
->new_entries
;
113 new_insns
= new_insns
->next
, ++insn_lists
)
115 hash
= (*insn_table
->asm_hash
) (new_insns
->insn
->syntax
.mnemonic
);
116 insn_lists
->next
= asm_hash_table
[hash
];
117 insn_lists
->insn
= new_insns
->insn
;
118 asm_hash_table
[hash
] = insn_lists
;
122 /* Return the first entry in the hash list for INSN. */
125 cgen_asm_lookup_insn (insn
)
130 if (asm_hash_table
== NULL
)
131 build_asm_hash_table ();
133 hash
= (*cgen_current_opcode_data
->insn_table
->asm_hash
) (insn
);
134 return asm_hash_table
[hash
];
138 The result is NULL upon success or an error message.
139 If successful, *STRP is updated to point passed the keyword.
141 ??? At present we have a static notion of how to pick out a keyword.
142 Later we can allow a target to customize this if necessary [say by
143 recording something in the keyword table]. */
146 cgen_parse_keyword (strp
, keyword_table
, valuep
)
148 struct cgen_keyword
*keyword_table
;
151 const struct cgen_keyword_entry
*ke
;
157 /* Allow any first character. */
161 /* Now allow letters, digits, and _. */
162 while (isalnum (*p
) || *p
== '_')
166 return "unrecognized keyword/register name";
168 memcpy (buf
, *strp
, p
- *strp
);
171 ke
= cgen_keyword_lookup_name (keyword_table
, buf
);
180 return "unrecognized keyword/register name";
183 /* Signed integer parser. */
186 cgen_parse_signed_integer (strp
, opindex
, min
, max
, valuep
)
193 enum cgen_parse_operand_result result
;
196 errmsg
= (*cgen_parse_operand_fn
) (CGEN_PARSE_OPERAND_INTEGER
, strp
,
197 opindex
, BFD_RELOC_NONE
,
199 /* FIXME: Examine `result'. */
202 if (value
< min
|| value
> max
)
203 return "integer operand out of range";
209 /* Unsigned integer parser. */
212 cgen_parse_unsigned_integer (strp
, opindex
, min
, max
, valuep
)
215 unsigned long min
, max
;
216 unsigned long *valuep
;
219 enum cgen_parse_operand_result result
;
222 errmsg
= (*cgen_parse_operand_fn
) (CGEN_PARSE_OPERAND_INTEGER
, strp
,
223 opindex
, BFD_RELOC_NONE
,
225 /* FIXME: Examine `result'. */
228 if (value
< min
|| value
> max
)
229 return "integer operand out of range";
235 /* Address parser. */
238 cgen_parse_address (strp
, opindex
, opinfo
, valuep
)
245 enum cgen_parse_operand_result result
;
248 errmsg
= (*cgen_parse_operand_fn
) (CGEN_PARSE_OPERAND_ADDRESS
, strp
,
251 /* FIXME: Examine `result'. */
259 /* Signed integer validation routine. */
262 cgen_validate_signed_integer (value
, min
, max
)
263 long value
, min
, max
;
265 if (value
< min
|| value
> max
)
268 "operand out of range (%ld not between %ld and %ld)";
269 static char buf
[100];
271 sprintf (buf
, err
, value
, min
, max
);
278 /* Unsigned integer validation routine.
279 Supplying `min' here may seem unnecessary, but we also want to handle
280 cases where min != 0 (and max > LONG_MAX). */
283 cgen_validate_unsigned_integer (value
, min
, max
)
284 unsigned long value
, min
, max
;
286 if (value
< min
|| value
> max
)
289 "operand out of range (%lu not between %lu and %lu)";
290 static char buf
[100];
292 sprintf (buf
, err
, value
, min
, max
);