cgen-opc.c revision 33965
1/* CGEN generic opcode support. 2 3Copyright (C) 1996, 1997 Free Software Foundation, Inc. 4 5This file is part of the GNU Binutils and GDB, the GNU debugger. 6 7This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12This program is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License along 18with this program; if not, write to the Free Software Foundation, Inc., 1959 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 21#include "sysdep.h" 22#include <stdio.h> 23#include "ansidecl.h" 24#include "libiberty.h" 25#include "bfd.h" 26#include "opcode/cgen.h" 27 28/* State variables. 29 These record the state of the currently selected cpu, machine, endian, etc. 30 They are set by cgen_set_cpu. */ 31 32/* Current opcode data. */ 33CGEN_OPCODE_DATA *cgen_current_opcode_data; 34 35/* Current machine (a la BFD machine number). */ 36int cgen_current_mach; 37 38/* Current endian. */ 39enum cgen_endian cgen_current_endian = CGEN_ENDIAN_UNKNOWN; 40 41void 42cgen_set_cpu (data, mach, endian) 43 CGEN_OPCODE_DATA *data; 44 int mach; 45 enum cgen_endian endian; 46{ 47 cgen_current_opcode_data = data; 48 cgen_current_mach = mach; 49 cgen_current_endian = endian; 50 51#if 0 /* This isn't done here because it would put assembler support in the 52 disassembler, etc. The caller is required to call these after calling 53 us. */ 54 /* Reset the hash tables. */ 55 cgen_asm_init (); 56 cgen_dis_init (); 57#endif 58} 59 60static unsigned int hash_keyword_name 61 PARAMS ((const struct cgen_keyword *, const char *)); 62static unsigned int hash_keyword_value 63 PARAMS ((const struct cgen_keyword *, int)); 64static void build_keyword_hash_tables 65 PARAMS ((struct cgen_keyword *)); 66 67/* Return number of hash table entries to use for N elements. */ 68#define KEYWORD_HASH_SIZE(n) ((n) <= 31 ? 17 : 31) 69 70/* Look up *NAMEP in the keyword table KT. 71 The result is the keyword entry or NULL if not found. */ 72 73const struct cgen_keyword_entry * 74cgen_keyword_lookup_name (kt, name) 75 struct cgen_keyword *kt; 76 const char *name; 77{ 78 const struct cgen_keyword_entry *ke; 79 const char *p,*n; 80 81 if (kt->name_hash_table == NULL) 82 build_keyword_hash_tables (kt); 83 84 ke = kt->name_hash_table[hash_keyword_name (kt, name)]; 85 86 /* We do case insensitive comparisons. 87 If that ever becomes a problem, add an attribute that denotes 88 "do case sensitive comparisons". */ 89 90 while (ke != NULL) 91 { 92 n = name; 93 p = ke->name; 94 95 while (*p 96 && (*p == *n 97 || (isalpha (*p) && tolower (*p) == tolower (*n)))) 98 ++n, ++p; 99 100 if (!*p && !*n) 101 return ke; 102 103 ke = ke->next_name; 104 } 105 106 return NULL; 107} 108 109/* Look up VALUE in the keyword table KT. 110 The result is the keyword entry or NULL if not found. */ 111 112const struct cgen_keyword_entry * 113cgen_keyword_lookup_value (kt, value) 114 struct cgen_keyword *kt; 115 int value; 116{ 117 const struct cgen_keyword_entry *ke; 118 119 if (kt->name_hash_table == NULL) 120 build_keyword_hash_tables (kt); 121 122 ke = kt->value_hash_table[hash_keyword_value (kt, value)]; 123 124 while (ke != NULL) 125 { 126 if (value == ke->value) 127 return ke; 128 ke = ke->next_value; 129 } 130 131 return NULL; 132} 133 134/* Add an entry to a keyword table. */ 135 136void 137cgen_keyword_add (kt, ke) 138 struct cgen_keyword *kt; 139 struct cgen_keyword_entry *ke; 140{ 141 unsigned int hash; 142 143 if (kt->name_hash_table == NULL) 144 build_keyword_hash_tables (kt); 145 146 hash = hash_keyword_name (kt, ke->name); 147 ke->next_name = kt->name_hash_table[hash]; 148 kt->name_hash_table[hash] = ke; 149 150 hash = hash_keyword_value (kt, ke->value); 151 ke->next_value = kt->value_hash_table[hash]; 152 kt->value_hash_table[hash] = ke; 153} 154 155/* FIXME: Need function to return count of keywords. */ 156 157/* Initialize a keyword table search. 158 SPEC is a specification of what to search for. 159 A value of NULL means to find every keyword. 160 Currently NULL is the only acceptable value [further specification 161 deferred]. 162 The result is an opaque data item used to record the search status. 163 It is passed to each call to cgen_keyword_search_next. */ 164 165struct cgen_keyword_search 166cgen_keyword_search_init (kt, spec) 167 struct cgen_keyword *kt; 168 const char *spec; 169{ 170 struct cgen_keyword_search search; 171 172 /* FIXME: Need to specify format of PARAMS. */ 173 if (spec != NULL) 174 abort (); 175 176 if (kt->name_hash_table == NULL) 177 build_keyword_hash_tables (kt); 178 179 search.table = kt; 180 search.spec = spec; 181 search.current_hash = 0; 182 search.current_entry = NULL; 183 return search; 184} 185 186/* Return the next keyword specified by SEARCH. 187 The result is the next entry or NULL if there are no more. */ 188 189const struct cgen_keyword_entry * 190cgen_keyword_search_next (search) 191 struct cgen_keyword_search *search; 192{ 193 const struct cgen_keyword_entry *ke; 194 195 /* Has search finished? */ 196 if (search->current_hash == search->table->hash_table_size) 197 return NULL; 198 199 /* Search in progress? */ 200 if (search->current_entry != NULL 201 /* Anything left on this hash chain? */ 202 && search->current_entry->next_name != NULL) 203 { 204 search->current_entry = search->current_entry->next_name; 205 return search->current_entry; 206 } 207 208 /* Move to next hash chain [unless we haven't started yet]. */ 209 if (search->current_entry != NULL) 210 ++search->current_hash; 211 212 while (search->current_hash < search->table->hash_table_size) 213 { 214 search->current_entry = search->table->name_hash_table[search->current_hash]; 215 if (search->current_entry != NULL) 216 return search->current_entry; 217 ++search->current_hash; 218 } 219 220 return NULL; 221} 222 223/* Return first entry in hash chain for NAME. */ 224 225static unsigned int 226hash_keyword_name (kt, name) 227 const struct cgen_keyword *kt; 228 const char *name; 229{ 230 unsigned int hash; 231 232 for (hash = 0; *name; ++name) 233 hash = (hash * 97) + (unsigned char) *name; 234 return hash % kt->hash_table_size; 235} 236 237/* Return first entry in hash chain for VALUE. */ 238 239static unsigned int 240hash_keyword_value (kt, value) 241 const struct cgen_keyword *kt; 242 int value; 243{ 244 return value % kt->hash_table_size; 245} 246 247/* Build a keyword table's hash tables. 248 We probably needn't build the value hash table for the assembler when 249 we're using the disassembler, but we keep things simple. */ 250 251static void 252build_keyword_hash_tables (kt) 253 struct cgen_keyword *kt; 254{ 255 int i; 256 /* Use the number of compiled in entries as an estimate for the 257 typical sized table [not too many added at runtime]. */ 258 unsigned int size = KEYWORD_HASH_SIZE (kt->num_init_entries); 259 260 kt->hash_table_size = size; 261 kt->name_hash_table = (struct cgen_keyword_entry **) 262 xmalloc (size * sizeof (struct cgen_keyword_entry *)); 263 memset (kt->name_hash_table, 0, size * sizeof (struct cgen_keyword_entry *)); 264 kt->value_hash_table = (struct cgen_keyword_entry **) 265 xmalloc (size * sizeof (struct cgen_keyword_entry *)); 266 memset (kt->value_hash_table, 0, size * sizeof (struct cgen_keyword_entry *)); 267 268 /* The table is scanned backwards as we want keywords appearing earlier to 269 be prefered over later ones. */ 270 for (i = kt->num_init_entries - 1; i >= 0; --i) 271 cgen_keyword_add (kt, &kt->init_entries[i]); 272} 273 274/* Hardware support. */ 275 276CGEN_HW_ENTRY * 277cgen_hw_lookup (name) 278 const char *name; 279{ 280 CGEN_HW_ENTRY *hw = cgen_current_opcode_data->hw_list; 281 282 while (hw != NULL) 283 { 284 if (strcmp (name, hw->name) == 0) 285 return hw; 286 hw = hw->next; 287 } 288 289 return NULL; 290} 291 292/* Instruction support. */ 293 294/* Return number of instructions. This includes any added at runtime. */ 295 296int 297cgen_insn_count () 298{ 299 int count = cgen_current_opcode_data->insn_table->num_init_entries; 300 CGEN_INSN_LIST *insn = cgen_current_opcode_data->insn_table->new_entries; 301 302 for ( ; insn != NULL; insn = insn->next) 303 ++count; 304 305 return count; 306} 307