1 1.1 christos /* This file is part of the program psim. 2 1.1 christos 3 1.1 christos Copyright 1994, 1995, 1996, 2003 Andrew Cagney 4 1.1 christos 5 1.1 christos This program is free software; you can redistribute it and/or modify 6 1.1 christos it under the terms of the GNU General Public License as published by 7 1.1 christos the Free Software Foundation; either version 3 of the License, or 8 1.1 christos (at your option) any later version. 9 1.1 christos 10 1.1 christos This program is distributed in the hope that it will be useful, 11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 christos GNU General Public License for more details. 14 1.1 christos 15 1.1 christos You should have received a copy of the GNU General Public License 16 1.1 christos along with this program; if not, see <http://www.gnu.org/licenses/>. 17 1.1 christos 18 1.1 christos */ 19 1.1 christos 20 1.1 christos 21 1.1 christos #include "misc.h" 22 1.1 christos #include "lf.h" 23 1.1 christos #include "table.h" 24 1.1 christos #include "filter.h" 25 1.8 christos #include "filter-ppc.h" 26 1.1 christos #include "ld-decode.h" 27 1.1 christos #include "ld-cache.h" 28 1.1 christos #include "ld-insn.h" 29 1.8 christos #include "dumpf.h" 30 1.1 christos 31 1.1 christos #include "igen.h" 32 1.1 christos 33 1.6 christos static model *last_model; 34 1.6 christos 35 1.6 christos static insn *last_model_macro; 36 1.6 christos static insn *last_model_function; 37 1.6 christos static insn *last_model_internal; 38 1.6 christos static insn *last_model_static; 39 1.6 christos static insn *last_model_data; 40 1.6 christos 41 1.6 christos model *models; 42 1.6 christos 43 1.6 christos insn *model_macros; 44 1.6 christos insn *model_functions; 45 1.6 christos insn *model_internal; 46 1.6 christos insn *model_static; 47 1.6 christos insn *model_data; 48 1.6 christos 49 1.6 christos int max_model_fields_len; 50 1.6 christos 51 1.1 christos static void 52 1.1 christos update_depth(insn_table *entry, 53 1.1 christos lf *file, 54 1.1 christos void *data, 55 1.1 christos insn *instruction, 56 1.1 christos int depth) 57 1.1 christos { 58 1.1 christos int *max_depth = (int*)data; 59 1.1 christos if (*max_depth < depth) 60 1.1 christos *max_depth = depth; 61 1.1 christos } 62 1.1 christos 63 1.1 christos 64 1.1 christos int 65 1.1 christos insn_table_depth(insn_table *table) 66 1.1 christos { 67 1.1 christos int depth = 0; 68 1.1 christos insn_table_traverse_tree(table, 69 1.1 christos NULL, 70 1.1 christos &depth, 71 1.1 christos 1, 72 1.1 christos NULL, /*start*/ 73 1.1 christos update_depth, 74 1.1 christos NULL, /*end*/ 75 1.1 christos NULL); /*padding*/ 76 1.1 christos return depth; 77 1.1 christos } 78 1.1 christos 79 1.1 christos 80 1.1 christos static insn_fields * 81 1.1 christos parse_insn_format(table_entry *entry, 82 1.7 christos const char *format) 83 1.1 christos { 84 1.7 christos const char *chp; 85 1.1 christos insn_fields *fields = ZALLOC(insn_fields); 86 1.1 christos 87 1.1 christos /* create a leading sentinal */ 88 1.1 christos fields->first = ZALLOC(insn_field); 89 1.1 christos fields->first->first = -1; 90 1.1 christos fields->first->last = -1; 91 1.1 christos fields->first->width = 0; 92 1.1 christos 93 1.1 christos /* and a trailing sentinal */ 94 1.1 christos fields->last = ZALLOC(insn_field); 95 1.1 christos fields->last->first = insn_bit_size; 96 1.1 christos fields->last->last = insn_bit_size; 97 1.1 christos fields->last->width = 0; 98 1.1 christos 99 1.1 christos /* link them together */ 100 1.1 christos fields->first->next = fields->last; 101 1.1 christos fields->last->prev = fields->first; 102 1.1 christos 103 1.1 christos /* now work through the formats */ 104 1.1 christos chp = format; 105 1.1 christos 106 1.1 christos while (*chp != '\0') { 107 1.7 christos const char *start_pos; 108 1.7 christos const char *start_val; 109 1.1 christos int strlen_val; 110 1.1 christos int strlen_pos; 111 1.1 christos insn_field *new_field; 112 1.1 christos 113 1.1 christos /* sanity check */ 114 1.1 christos if (!isdigit(*chp)) { 115 1.8 christos ERROR("%s:%d: missing position field at `%s'\n", 116 1.1 christos entry->file_name, entry->line_nr, chp); 117 1.1 christos } 118 1.1 christos 119 1.1 christos /* break out the bit position */ 120 1.1 christos start_pos = chp; 121 1.1 christos while (isdigit(*chp)) 122 1.1 christos chp++; 123 1.1 christos strlen_pos = chp - start_pos; 124 1.1 christos if (*chp == '.' && strlen_pos > 0) 125 1.1 christos chp++; 126 1.1 christos else { 127 1.8 christos ERROR("%s:%d: missing field value at %s\n", 128 1.1 christos entry->file_name, entry->line_nr, chp); 129 1.1 christos break; 130 1.1 christos } 131 1.1 christos 132 1.1 christos /* break out the value */ 133 1.1 christos start_val = chp; 134 1.1 christos while ((*start_val == '/' && *chp == '/') 135 1.1 christos || (isdigit(*start_val) && isdigit(*chp)) 136 1.1 christos || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))) 137 1.1 christos chp++; 138 1.1 christos strlen_val = chp - start_val; 139 1.1 christos if (*chp == ',') 140 1.1 christos chp++; 141 1.1 christos else if (*chp != '\0' || strlen_val == 0) { 142 1.8 christos ERROR("%s:%d: missing field terminator at %s\n", 143 1.1 christos entry->file_name, entry->line_nr, chp); 144 1.1 christos break; 145 1.1 christos } 146 1.1 christos 147 1.1 christos /* create a new field and insert it */ 148 1.1 christos new_field = ZALLOC(insn_field); 149 1.1 christos new_field->next = fields->last; 150 1.1 christos new_field->prev = fields->last->prev; 151 1.1 christos new_field->next->prev = new_field; 152 1.1 christos new_field->prev->next = new_field; 153 1.1 christos 154 1.1 christos /* the value */ 155 1.1 christos new_field->val_string = (char*)zalloc(strlen_val+1); 156 1.1 christos strncpy(new_field->val_string, start_val, strlen_val); 157 1.1 christos if (isdigit(*new_field->val_string)) { 158 1.1 christos new_field->val_int = a2i(new_field->val_string); 159 1.1 christos new_field->is_int = 1; 160 1.1 christos } 161 1.1 christos else if (new_field->val_string[0] == '/') { 162 1.1 christos new_field->is_slash = 1; 163 1.1 christos } 164 1.1 christos else { 165 1.1 christos new_field->is_string = 1; 166 1.1 christos } 167 1.1 christos 168 1.1 christos /* the pos */ 169 1.1 christos new_field->pos_string = (char*)zalloc(strlen_pos+1); 170 1.1 christos strncpy(new_field->pos_string, start_pos, strlen_pos); 171 1.1 christos new_field->first = target_a2i(hi_bit_nr, new_field->pos_string); 172 1.1 christos new_field->last = new_field->next->first - 1; /* guess */ 173 1.1 christos new_field->width = new_field->last - new_field->first + 1; /* guess */ 174 1.1 christos new_field->prev->last = new_field->first-1; /*fix*/ 175 1.1 christos new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/ 176 1.1 christos } 177 1.1 christos 178 1.1 christos /* fiddle first/last so that the sentinals `disapear' */ 179 1.1 christos ASSERT(fields->first->last < 0); 180 1.1 christos ASSERT(fields->last->first >= insn_bit_size); 181 1.1 christos fields->first = fields->first->next; 182 1.1 christos fields->last = fields->last->prev; 183 1.1 christos 184 1.1 christos /* now go over this again, pointing each bit position at a field 185 1.1 christos record */ 186 1.1 christos { 187 1.1 christos int i; 188 1.1 christos insn_field *field; 189 1.1 christos field = fields->first; 190 1.1 christos for (i = 0; i < insn_bit_size; i++) { 191 1.1 christos while (field->last < i) 192 1.1 christos field = field->next; 193 1.1 christos fields->bits[i] = field; 194 1.1 christos } 195 1.1 christos } 196 1.1 christos 197 1.1 christos /* go over each of the fields, and compute a `value' for the insn */ 198 1.1 christos { 199 1.1 christos insn_field *field; 200 1.1 christos fields->value = 0; 201 1.1 christos for (field = fields->first; 202 1.1 christos field->last < insn_bit_size; 203 1.1 christos field = field->next) { 204 1.1 christos fields->value <<= field->width; 205 1.1 christos if (field->is_int) 206 1.1 christos fields->value |= field->val_int; 207 1.1 christos } 208 1.1 christos } 209 1.1 christos return fields; 210 1.1 christos } 211 1.1 christos 212 1.1 christos 213 1.7 christos static void 214 1.1 christos parse_include_entry (table *file, 215 1.1 christos table_entry *file_entry, 216 1.1 christos filter *filters, 217 1.1 christos table_include *includes) 218 1.1 christos { 219 1.1 christos /* parse the include file_entry */ 220 1.1 christos if (file_entry->nr_fields < 4) 221 1.8 christos ERROR ("Incorrect nr fields for include record\n"); 222 1.1 christos /* process it */ 223 1.8 christos if (!is_filtered_out(filters, file_entry->fields[include_flags])) 224 1.1 christos { 225 1.1 christos table_push (file, includes, 226 1.1 christos file_entry->fields[include_path], 227 1.1 christos file_entry->nr_fields, file_entry->nr_fields); 228 1.1 christos } 229 1.1 christos } 230 1.1 christos 231 1.1 christos static void 232 1.1 christos model_table_insert(insn_table *table, 233 1.1 christos table_entry *file_entry) 234 1.1 christos { 235 1.1 christos int len; 236 1.1 christos 237 1.1 christos /* create a new model */ 238 1.1 christos model *new_model = ZALLOC(model); 239 1.1 christos 240 1.1 christos new_model->name = file_entry->fields[model_identifer]; 241 1.1 christos new_model->printable_name = file_entry->fields[model_name]; 242 1.1 christos new_model->insn_default = file_entry->fields[model_default]; 243 1.1 christos 244 1.1 christos while (*new_model->insn_default && isspace(*new_model->insn_default)) 245 1.1 christos new_model->insn_default++; 246 1.1 christos 247 1.1 christos len = strlen(new_model->insn_default); 248 1.1 christos if (max_model_fields_len < len) 249 1.1 christos max_model_fields_len = len; 250 1.1 christos 251 1.1 christos /* append it to the end of the model list */ 252 1.1 christos if (last_model) 253 1.1 christos last_model->next = new_model; 254 1.1 christos else 255 1.1 christos models = new_model; 256 1.1 christos last_model = new_model; 257 1.1 christos } 258 1.1 christos 259 1.1 christos static void 260 1.1 christos model_table_insert_specific(insn_table *table, 261 1.1 christos table_entry *file_entry, 262 1.1 christos insn **start_ptr, 263 1.1 christos insn **end_ptr) 264 1.1 christos { 265 1.1 christos insn *ptr = ZALLOC(insn); 266 1.1 christos ptr->file_entry = file_entry; 267 1.1 christos if (*end_ptr) 268 1.1 christos (*end_ptr)->next = ptr; 269 1.1 christos else 270 1.1 christos (*start_ptr) = ptr; 271 1.1 christos (*end_ptr) = ptr; 272 1.1 christos } 273 1.1 christos 274 1.1 christos 275 1.1 christos static void 276 1.1 christos insn_table_insert_function(insn_table *table, 277 1.1 christos table_entry *file_entry) 278 1.1 christos { 279 1.1 christos /* create a new function */ 280 1.1 christos insn *new_function = ZALLOC(insn); 281 1.1 christos new_function->file_entry = file_entry; 282 1.1 christos 283 1.1 christos /* append it to the end of the function list */ 284 1.1 christos if (table->last_function) 285 1.1 christos table->last_function->next = new_function; 286 1.1 christos else 287 1.1 christos table->functions = new_function; 288 1.1 christos table->last_function = new_function; 289 1.1 christos } 290 1.1 christos 291 1.1 christos extern void 292 1.1 christos insn_table_insert_insn(insn_table *table, 293 1.1 christos table_entry *file_entry, 294 1.1 christos insn_fields *fields) 295 1.1 christos { 296 1.1 christos insn **ptr_to_cur_insn = &table->insns; 297 1.1 christos insn *cur_insn = *ptr_to_cur_insn; 298 1.1 christos table_model_entry *insn_model_ptr; 299 1.1 christos model *model_ptr; 300 1.1 christos 301 1.1 christos /* create a new instruction */ 302 1.1 christos insn *new_insn = ZALLOC(insn); 303 1.1 christos new_insn->file_entry = file_entry; 304 1.1 christos new_insn->fields = fields; 305 1.1 christos 306 1.1 christos /* Check out any model information returned to make sure the model 307 1.1 christos is correct. */ 308 1.1 christos for(insn_model_ptr = file_entry->model_first; insn_model_ptr; insn_model_ptr = insn_model_ptr->next) { 309 1.7 christos const char *name = insn_model_ptr->fields[insn_model_name]; 310 1.1 christos int len = strlen (insn_model_ptr->fields[insn_model_fields]); 311 1.1 christos 312 1.1 christos while (len > 0 && isspace(*insn_model_ptr->fields[insn_model_fields])) { 313 1.1 christos len--; 314 1.1 christos insn_model_ptr->fields[insn_model_fields]++; 315 1.1 christos } 316 1.1 christos 317 1.1 christos if (max_model_fields_len < len) 318 1.1 christos max_model_fields_len = len; 319 1.1 christos 320 1.1 christos for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { 321 1.1 christos if (strcmp(name, model_ptr->printable_name) == 0) { 322 1.1 christos 323 1.1 christos /* Replace the name field with that of the global model, so that when we 324 1.1 christos want to print it out, we can just compare pointers. */ 325 1.1 christos insn_model_ptr->fields[insn_model_name] = model_ptr->printable_name; 326 1.1 christos break; 327 1.1 christos } 328 1.1 christos } 329 1.1 christos 330 1.1 christos if (!model_ptr) 331 1.8 christos ERROR("%s:%d: machine model `%s' was not known about\n", 332 1.1 christos file_entry->file_name, file_entry->line_nr, name); 333 1.1 christos } 334 1.1 christos 335 1.1 christos /* insert it according to the order of the fields */ 336 1.1 christos while (cur_insn != NULL 337 1.1 christos && new_insn->fields->value >= cur_insn->fields->value) { 338 1.1 christos ptr_to_cur_insn = &cur_insn->next; 339 1.1 christos cur_insn = *ptr_to_cur_insn; 340 1.1 christos } 341 1.1 christos 342 1.1 christos new_insn->next = cur_insn; 343 1.1 christos *ptr_to_cur_insn = new_insn; 344 1.1 christos 345 1.1 christos table->nr_insn++; 346 1.1 christos } 347 1.1 christos 348 1.1 christos 349 1.1 christos 350 1.1 christos insn_table * 351 1.1 christos load_insn_table(const char *file_name, 352 1.1 christos decode_table *decode_rules, 353 1.1 christos filter *filters, 354 1.1 christos table_include *includes, 355 1.1 christos cache_table **cache_rules) 356 1.1 christos { 357 1.1 christos table *file = table_open(file_name, nr_insn_table_fields, nr_insn_model_table_fields); 358 1.1 christos insn_table *table = ZALLOC(insn_table); 359 1.1 christos table_entry *file_entry; 360 1.1 christos table->opcode_rule = decode_rules; 361 1.1 christos 362 1.1 christos while ((file_entry = table_entry_read(file)) != NULL) { 363 1.1 christos if (it_is("function", file_entry->fields[insn_flags]) 364 1.1 christos || it_is("internal", file_entry->fields[insn_flags])) { 365 1.1 christos insn_table_insert_function(table, file_entry); 366 1.1 christos } 367 1.1 christos else if ((it_is("function", file_entry->fields[insn_form]) 368 1.1 christos || it_is("internal", file_entry->fields[insn_form])) 369 1.8 christos && !is_filtered_out(filters, file_entry->fields[insn_flags])) { 370 1.1 christos /* Ok, this is evil. Need to convert a new style function into 371 1.1 christos an old style function. Construct an old style table and then 372 1.1 christos copy it back. */ 373 1.1 christos char *fields[nr_insn_table_fields]; 374 1.1 christos memset (fields, 0, sizeof fields); 375 1.1 christos fields[insn_flags] = file_entry->fields[insn_form]; 376 1.1 christos fields[function_type] = file_entry->fields[insn_name]; 377 1.1 christos fields[function_name] = file_entry->fields[insn_comment]; 378 1.1 christos fields[function_param] = file_entry->fields[insn_field_6]; 379 1.1 christos memcpy (file_entry->fields, fields, 380 1.1 christos sizeof (fields[0]) * file_entry->nr_fields); 381 1.1 christos insn_table_insert_function(table, file_entry); 382 1.1 christos #if 0 383 1.1 christos ":" "..." 384 1.1 christos ":" <filter-flags> 385 1.1 christos ":" <filter-models> 386 1.1 christos ":" <typedef> 387 1.1 christos ":" <name> 388 1.1 christos [ ":" <parameter-list> ] 389 1.1 christos <nl> 390 1.1 christos [ <function-model> ] 391 1.1 christos <code-block> 392 1.1 christos #endif 393 1.1 christos } 394 1.1 christos else if (it_is("model", file_entry->fields[insn_flags])) { 395 1.1 christos model_table_insert(table, file_entry); 396 1.1 christos } 397 1.1 christos else if (it_is("model-macro", file_entry->fields[insn_flags])) { 398 1.1 christos model_table_insert_specific(table, file_entry, &model_macros, &last_model_macro); 399 1.1 christos } 400 1.1 christos else if (it_is("model-function", file_entry->fields[insn_flags])) { 401 1.1 christos model_table_insert_specific(table, file_entry, &model_functions, &last_model_function); 402 1.1 christos } 403 1.1 christos else if (it_is("model-internal", file_entry->fields[insn_flags])) { 404 1.1 christos model_table_insert_specific(table, file_entry, &model_internal, &last_model_internal); 405 1.1 christos } 406 1.1 christos else if (it_is("model-static", file_entry->fields[insn_flags])) { 407 1.1 christos model_table_insert_specific(table, file_entry, &model_static, &last_model_static); 408 1.1 christos } 409 1.1 christos else if (it_is("model-data", file_entry->fields[insn_flags])) { 410 1.1 christos model_table_insert_specific(table, file_entry, &model_data, &last_model_data); 411 1.1 christos } 412 1.1 christos else if (it_is("include", file_entry->fields[insn_form]) 413 1.8 christos && !is_filtered_out(filters, file_entry->fields[insn_flags])) { 414 1.1 christos parse_include_entry (file, file_entry, filters, includes); 415 1.1 christos } 416 1.1 christos else if ((it_is("cache", file_entry->fields[insn_form]) 417 1.1 christos || it_is("compute", file_entry->fields[insn_form]) 418 1.1 christos || it_is("scratch", file_entry->fields[insn_form])) 419 1.8 christos && !is_filtered_out(filters, file_entry->fields[insn_flags])) { 420 1.1 christos append_cache_rule (cache_rules, 421 1.1 christos file_entry->fields[insn_form], /* type */ 422 1.1 christos file_entry->fields[cache_name], 423 1.1 christos file_entry->fields[cache_derived_name], 424 1.1 christos file_entry->fields[cache_type_def], 425 1.1 christos file_entry->fields[cache_expression], 426 1.1 christos file_entry); 427 1.1 christos } 428 1.1 christos else { 429 1.1 christos insn_fields *fields; 430 1.1 christos /* skip instructions that aren't relevant to the mode */ 431 1.8 christos if (is_filtered_out(filters, file_entry->fields[insn_flags])) { 432 1.1 christos fprintf(stderr, "Dropping %s - %s\n", 433 1.1 christos file_entry->fields[insn_name], 434 1.1 christos file_entry->fields[insn_flags]); 435 1.1 christos } 436 1.1 christos else { 437 1.1 christos /* create/insert the new instruction */ 438 1.1 christos fields = parse_insn_format(file_entry, 439 1.1 christos file_entry->fields[insn_format]); 440 1.1 christos insn_table_insert_insn(table, file_entry, fields); 441 1.1 christos } 442 1.1 christos } 443 1.1 christos } 444 1.1 christos return table; 445 1.1 christos } 446 1.1 christos 447 1.1 christos 448 1.1 christos extern void 449 1.1 christos insn_table_traverse_tree(insn_table *table, 450 1.1 christos lf *file, 451 1.1 christos void *data, 452 1.1 christos int depth, 453 1.1 christos leaf_handler *start, 454 1.1 christos insn_handler *leaf, 455 1.1 christos leaf_handler *end, 456 1.1 christos padding_handler *padding) 457 1.1 christos { 458 1.1 christos insn_table *entry; 459 1.1 christos int entry_nr; 460 1.1 christos 461 1.1 christos ASSERT(table != NULL 462 1.1 christos && table->opcode != NULL 463 1.1 christos && table->nr_entries > 0 464 1.1 christos && table->entries != 0); 465 1.1 christos 466 1.1 christos if (start != NULL && depth >= 0) 467 1.1 christos start(table, file, data, depth); 468 1.1 christos 469 1.1 christos for (entry_nr = 0, entry = table->entries; 470 1.1 christos entry_nr < (table->opcode->is_boolean 471 1.1 christos ? 2 472 1.1 christos : (1 << (table->opcode->last - table->opcode->first + 1))); 473 1.1 christos entry_nr ++) { 474 1.1 christos if (entry == NULL 475 1.1 christos || (!table->opcode->is_boolean 476 1.1 christos && entry_nr < entry->opcode_nr)) { 477 1.1 christos if (padding != NULL && depth >= 0) 478 1.1 christos padding(table, file, data, depth, entry_nr); 479 1.1 christos } 480 1.1 christos else { 481 1.1 christos ASSERT(entry != NULL && (entry->opcode_nr == entry_nr 482 1.1 christos || table->opcode->is_boolean)); 483 1.1 christos if (entry->opcode != NULL && depth != 0) { 484 1.1 christos insn_table_traverse_tree(entry, file, data, depth+1, 485 1.1 christos start, leaf, end, padding); 486 1.1 christos } 487 1.1 christos else if (depth >= 0) { 488 1.1 christos if (leaf != NULL) 489 1.1 christos leaf(entry, file, data, entry->insns, depth); 490 1.1 christos } 491 1.1 christos entry = entry->sibling; 492 1.1 christos } 493 1.1 christos } 494 1.1 christos if (end != NULL && depth >= 0) 495 1.1 christos end(table, file, data, depth); 496 1.1 christos } 497 1.1 christos 498 1.1 christos 499 1.1 christos extern void 500 1.1 christos insn_table_traverse_function(insn_table *table, 501 1.1 christos lf *file, 502 1.1 christos void *data, 503 1.1 christos function_handler *leaf) 504 1.1 christos { 505 1.1 christos insn *function; 506 1.1 christos for (function = table->functions; 507 1.1 christos function != NULL; 508 1.1 christos function = function->next) { 509 1.1 christos leaf(table, file, data, function->file_entry); 510 1.1 christos } 511 1.1 christos } 512 1.1 christos 513 1.1 christos extern void 514 1.1 christos insn_table_traverse_insn(insn_table *table, 515 1.1 christos lf *file, 516 1.1 christos void *data, 517 1.1 christos insn_handler *handler) 518 1.1 christos { 519 1.1 christos insn *instruction; 520 1.1 christos for (instruction = table->insns; 521 1.1 christos instruction != NULL; 522 1.1 christos instruction = instruction->next) { 523 1.1 christos handler(table, file, data, instruction, 0); 524 1.1 christos } 525 1.1 christos } 526 1.1 christos 527 1.1 christos 528 1.1 christos /****************************************************************/ 529 1.1 christos 530 1.1 christos typedef enum { 531 1.1 christos field_constant_int = 1, 532 1.1 christos field_constant_slash = 2, 533 1.1 christos field_constant_string = 3 534 1.1 christos } constant_field_types; 535 1.1 christos 536 1.1 christos 537 1.1 christos static int 538 1.1 christos insn_field_is_constant(insn_field *field, 539 1.1 christos decode_table *rule) 540 1.1 christos { 541 1.1 christos /* field is an integer */ 542 1.1 christos if (field->is_int) 543 1.1 christos return field_constant_int; 544 1.1 christos /* field is `/' and treating that as a constant */ 545 1.1 christos if (field->is_slash && rule->force_slash) 546 1.1 christos return field_constant_slash; 547 1.1 christos /* field, though variable is on the list */ 548 1.1 christos if (field->is_string && rule->force_expansion != NULL) { 549 1.7 christos const char *forced_fields = rule->force_expansion; 550 1.1 christos while (*forced_fields != '\0') { 551 1.1 christos int field_len; 552 1.7 christos const char *end = strchr(forced_fields, ','); 553 1.1 christos if (end == NULL) 554 1.1 christos field_len = strlen(forced_fields); 555 1.1 christos else 556 1.1 christos field_len = end-forced_fields; 557 1.1 christos if (strncmp(forced_fields, field->val_string, field_len) == 0 558 1.1 christos && field->val_string[field_len] == '\0') 559 1.1 christos return field_constant_string; 560 1.1 christos forced_fields += field_len; 561 1.1 christos if (*forced_fields == ',') 562 1.1 christos forced_fields++; 563 1.1 christos } 564 1.1 christos } 565 1.1 christos return 0; 566 1.1 christos } 567 1.1 christos 568 1.1 christos 569 1.1 christos static opcode_field * 570 1.1 christos insn_table_find_opcode_field(insn *insns, 571 1.1 christos decode_table *rule, 572 1.1 christos int string_only) 573 1.1 christos { 574 1.1 christos opcode_field *curr_opcode = ZALLOC(opcode_field); 575 1.1 christos insn *entry; 576 1.1 christos ASSERT(rule); 577 1.1 christos 578 1.1 christos curr_opcode->first = insn_bit_size; 579 1.1 christos curr_opcode->last = -1; 580 1.1 christos for (entry = insns; entry != NULL; entry = entry->next) { 581 1.1 christos insn_fields *fields = entry->fields; 582 1.1 christos opcode_field new_opcode; 583 1.1 christos 584 1.1 christos /* find a start point for the opcode field */ 585 1.1 christos new_opcode.first = rule->first; 586 1.1 christos while (new_opcode.first <= rule->last 587 1.1 christos && (!string_only 588 1.1 christos || insn_field_is_constant(fields->bits[new_opcode.first], 589 1.1 christos rule) != field_constant_string) 590 1.1 christos && (string_only 591 1.1 christos || !insn_field_is_constant(fields->bits[new_opcode.first], 592 1.1 christos rule))) 593 1.1 christos new_opcode.first = fields->bits[new_opcode.first]->last + 1; 594 1.1 christos ASSERT(new_opcode.first > rule->last 595 1.1 christos || (string_only 596 1.1 christos && insn_field_is_constant(fields->bits[new_opcode.first], 597 1.1 christos rule) == field_constant_string) 598 1.1 christos || (!string_only 599 1.1 christos && insn_field_is_constant(fields->bits[new_opcode.first], 600 1.1 christos rule))); 601 1.1 christos 602 1.1 christos /* find the end point for the opcode field */ 603 1.1 christos new_opcode.last = rule->last; 604 1.1 christos while (new_opcode.last >= rule->first 605 1.1 christos && (!string_only 606 1.1 christos || insn_field_is_constant(fields->bits[new_opcode.last], 607 1.1 christos rule) != field_constant_string) 608 1.1 christos && (string_only 609 1.1 christos || !insn_field_is_constant(fields->bits[new_opcode.last], 610 1.1 christos rule))) 611 1.1 christos new_opcode.last = fields->bits[new_opcode.last]->first - 1; 612 1.1 christos ASSERT(new_opcode.last < rule->first 613 1.1 christos || (string_only 614 1.1 christos && insn_field_is_constant(fields->bits[new_opcode.last], 615 1.1 christos rule) == field_constant_string) 616 1.1 christos || (!string_only 617 1.1 christos && insn_field_is_constant(fields->bits[new_opcode.last], 618 1.1 christos rule))); 619 1.1 christos 620 1.1 christos /* now see if our current opcode needs expanding */ 621 1.1 christos if (new_opcode.first <= rule->last 622 1.1 christos && curr_opcode->first > new_opcode.first) 623 1.1 christos curr_opcode->first = new_opcode.first; 624 1.1 christos if (new_opcode.last >= rule->first 625 1.1 christos && curr_opcode->last < new_opcode.last) 626 1.1 christos curr_opcode->last = new_opcode.last; 627 1.1 christos 628 1.1 christos } 629 1.1 christos 630 1.1 christos /* was any thing interesting found? */ 631 1.1 christos if (curr_opcode->first > rule->last) { 632 1.1 christos ASSERT(curr_opcode->last < rule->first); 633 1.1 christos return NULL; 634 1.1 christos } 635 1.1 christos ASSERT(curr_opcode->last >= rule->first); 636 1.1 christos ASSERT(curr_opcode->first <= rule->last); 637 1.1 christos 638 1.1 christos /* if something was found, check it includes the forced field range */ 639 1.1 christos if (!string_only 640 1.1 christos && curr_opcode->first > rule->force_first) { 641 1.1 christos curr_opcode->first = rule->force_first; 642 1.1 christos } 643 1.1 christos if (!string_only 644 1.1 christos && curr_opcode->last < rule->force_last) { 645 1.1 christos curr_opcode->last = rule->force_last; 646 1.1 christos } 647 1.1 christos /* handle special case elminating any need to do shift after mask */ 648 1.1 christos if (string_only 649 1.1 christos && rule->force_last == insn_bit_size-1) { 650 1.1 christos curr_opcode->last = insn_bit_size-1; 651 1.1 christos } 652 1.1 christos 653 1.1 christos /* handle any special cases */ 654 1.1 christos switch (rule->type) { 655 1.1 christos case normal_decode_rule: 656 1.1 christos /* let the above apply */ 657 1.1 christos break; 658 1.1 christos case expand_forced_rule: 659 1.1 christos /* expand a limited nr of bits, ignoring the rest */ 660 1.1 christos curr_opcode->first = rule->force_first; 661 1.1 christos curr_opcode->last = rule->force_last; 662 1.1 christos break; 663 1.1 christos case boolean_rule: 664 1.1 christos curr_opcode->is_boolean = 1; 665 1.1 christos curr_opcode->boolean_constant = rule->special_constant; 666 1.1 christos break; 667 1.1 christos default: 668 1.8 christos ERROR("Something is going wrong\n"); 669 1.1 christos } 670 1.1 christos 671 1.1 christos return curr_opcode; 672 1.1 christos } 673 1.1 christos 674 1.1 christos 675 1.1 christos static void 676 1.1 christos insn_table_insert_expanded(insn_table *table, 677 1.1 christos insn *old_insn, 678 1.1 christos int new_opcode_nr, 679 1.1 christos insn_bits *new_bits) 680 1.1 christos { 681 1.1 christos insn_table **ptr_to_cur_entry = &table->entries; 682 1.1 christos insn_table *cur_entry = *ptr_to_cur_entry; 683 1.1 christos 684 1.1 christos /* find the new table for this entry */ 685 1.1 christos while (cur_entry != NULL 686 1.1 christos && cur_entry->opcode_nr < new_opcode_nr) { 687 1.1 christos ptr_to_cur_entry = &cur_entry->sibling; 688 1.1 christos cur_entry = *ptr_to_cur_entry; 689 1.1 christos } 690 1.1 christos 691 1.1 christos if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) { 692 1.1 christos insn_table *new_entry = ZALLOC(insn_table); 693 1.1 christos new_entry->opcode_nr = new_opcode_nr; 694 1.1 christos new_entry->expanded_bits = new_bits; 695 1.1 christos new_entry->opcode_rule = table->opcode_rule->next; 696 1.1 christos new_entry->sibling = cur_entry; 697 1.1 christos new_entry->parent = table; 698 1.1 christos *ptr_to_cur_entry = new_entry; 699 1.1 christos cur_entry = new_entry; 700 1.1 christos table->nr_entries++; 701 1.1 christos } 702 1.1 christos /* ASSERT new_bits == cur_entry bits */ 703 1.1 christos ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr); 704 1.1 christos insn_table_insert_insn(cur_entry, 705 1.1 christos old_insn->file_entry, 706 1.1 christos old_insn->fields); 707 1.1 christos } 708 1.1 christos 709 1.1 christos static void 710 1.1 christos insn_table_expand_opcode(insn_table *table, 711 1.1 christos insn *instruction, 712 1.1 christos int field_nr, 713 1.1 christos int opcode_nr, 714 1.1 christos insn_bits *bits) 715 1.1 christos { 716 1.1 christos 717 1.1 christos if (field_nr > table->opcode->last) { 718 1.1 christos insn_table_insert_expanded(table, instruction, opcode_nr, bits); 719 1.1 christos } 720 1.1 christos else { 721 1.1 christos insn_field *field = instruction->fields->bits[field_nr]; 722 1.1 christos if (field->is_int || field->is_slash) { 723 1.1 christos ASSERT(field->first >= table->opcode->first 724 1.1 christos && field->last <= table->opcode->last); 725 1.1 christos insn_table_expand_opcode(table, instruction, field->last+1, 726 1.1 christos ((opcode_nr << field->width) + field->val_int), 727 1.1 christos bits); 728 1.1 christos } 729 1.1 christos else { 730 1.1 christos int val; 731 1.1 christos int last_pos = ((field->last < table->opcode->last) 732 1.1 christos ? field->last : table->opcode->last); 733 1.1 christos int first_pos = ((field->first > table->opcode->first) 734 1.1 christos ? field->first : table->opcode->first); 735 1.1 christos int width = last_pos - first_pos + 1; 736 1.1 christos int last_val = (table->opcode->is_boolean 737 1.1 christos ? 2 : (1 << width)); 738 1.1 christos for (val = 0; val < last_val; val++) { 739 1.1 christos insn_bits *new_bits = ZALLOC(insn_bits); 740 1.1 christos new_bits->field = field; 741 1.1 christos new_bits->value = val; 742 1.1 christos new_bits->last = bits; 743 1.1 christos new_bits->opcode = table->opcode; 744 1.1 christos insn_table_expand_opcode(table, instruction, last_pos+1, 745 1.1 christos ((opcode_nr << width) | val), 746 1.1 christos new_bits); 747 1.1 christos } 748 1.1 christos } 749 1.1 christos } 750 1.1 christos } 751 1.1 christos 752 1.1 christos static void 753 1.1 christos insn_table_insert_expanding(insn_table *table, 754 1.1 christos insn *entry) 755 1.1 christos { 756 1.1 christos insn_table_expand_opcode(table, 757 1.1 christos entry, 758 1.1 christos table->opcode->first, 759 1.1 christos 0, 760 1.1 christos table->expanded_bits); 761 1.1 christos } 762 1.1 christos 763 1.1 christos 764 1.1 christos extern void 765 1.1 christos insn_table_expand_insns(insn_table *table) 766 1.1 christos { 767 1.1 christos 768 1.1 christos ASSERT(table->nr_insn >= 1); 769 1.1 christos 770 1.1 christos /* determine a valid opcode */ 771 1.1 christos while (table->opcode_rule) { 772 1.1 christos /* specials only for single instructions */ 773 1.1 christos if ((table->nr_insn > 1 774 1.1 christos && table->opcode_rule->special_mask == 0 775 1.1 christos && table->opcode_rule->type == normal_decode_rule) 776 1.1 christos || (table->nr_insn == 1 777 1.1 christos && table->opcode_rule->special_mask != 0 778 1.1 christos && ((table->insns->fields->value 779 1.1 christos & table->opcode_rule->special_mask) 780 1.1 christos == table->opcode_rule->special_value)) 781 1.1 christos || (generate_expanded_instructions 782 1.1 christos && table->opcode_rule->special_mask == 0 783 1.1 christos && table->opcode_rule->type == normal_decode_rule)) 784 1.1 christos table->opcode = 785 1.1 christos insn_table_find_opcode_field(table->insns, 786 1.1 christos table->opcode_rule, 787 1.1 christos table->nr_insn == 1/*string*/ 788 1.1 christos ); 789 1.1 christos if (table->opcode != NULL) 790 1.1 christos break; 791 1.1 christos table->opcode_rule = table->opcode_rule->next; 792 1.1 christos } 793 1.1 christos 794 1.1 christos /* did we find anything */ 795 1.1 christos if (table->opcode == NULL) { 796 1.1 christos return; 797 1.1 christos } 798 1.1 christos ASSERT(table->opcode != NULL); 799 1.1 christos 800 1.1 christos /* back link what we found to its parent */ 801 1.1 christos if (table->parent != NULL) { 802 1.1 christos ASSERT(table->parent->opcode != NULL); 803 1.1 christos table->opcode->parent = table->parent->opcode; 804 1.1 christos } 805 1.1 christos 806 1.1 christos /* expand the raw instructions according to the opcode */ 807 1.1 christos { 808 1.1 christos insn *entry; 809 1.1 christos for (entry = table->insns; entry != NULL; entry = entry->next) { 810 1.1 christos insn_table_insert_expanding(table, entry); 811 1.1 christos } 812 1.1 christos } 813 1.1 christos 814 1.1 christos /* and do the same for the sub entries */ 815 1.1 christos { 816 1.1 christos insn_table *entry; 817 1.1 christos for (entry = table->entries; entry != NULL; entry = entry->sibling) { 818 1.1 christos insn_table_expand_insns(entry); 819 1.1 christos } 820 1.1 christos } 821 1.1 christos } 822 1.1 christos 823 1.1 christos 824 1.1 christos 825 1.1 christos 826 1.1 christos #ifdef MAIN 827 1.1 christos 828 1.1 christos static void 829 1.1 christos dump_insn_field(insn_field *field, 830 1.1 christos int indent) 831 1.1 christos { 832 1.7 christos printf ("(insn_field*)%p\n", field); 833 1.7 christos dumpf (indent, "(first %d)\n", field->first); 834 1.7 christos dumpf (indent, "(last %d)\n", field->last); 835 1.7 christos dumpf (indent, "(width %d)\n", field->width); 836 1.1 christos if (field->is_int) 837 1.7 christos dumpf (indent, "(is_int %d)\n", field->val_int); 838 1.1 christos if (field->is_slash) 839 1.7 christos dumpf (indent, "(is_slash)\n"); 840 1.1 christos if (field->is_string) 841 1.7 christos dumpf (indent, "(is_string `%s')\n", field->val_string); 842 1.7 christos dumpf (indent, "(next %p)\n", field->next); 843 1.7 christos dumpf (indent, "(prev %p)\n", field->prev); 844 1.1 christos } 845 1.1 christos 846 1.1 christos static void 847 1.1 christos dump_insn_fields(insn_fields *fields, 848 1.1 christos int indent) 849 1.1 christos { 850 1.1 christos int i; 851 1.1 christos 852 1.1 christos printf("(insn_fields*)%p\n", fields); 853 1.1 christos 854 1.7 christos dumpf(indent, "(first %p)\n", fields->first); 855 1.7 christos dumpf(indent, "(last %p)\n", fields->last); 856 1.1 christos 857 1.1 christos dumpf(indent, "(value 0x%x)\n", fields->value); 858 1.1 christos 859 1.1 christos for (i = 0; i < insn_bit_size; i++) { 860 1.7 christos dumpf(indent, "(bits[%d]", i); 861 1.1 christos dump_insn_field(fields->bits[i], indent+1); 862 1.1 christos dumpf(indent, " )\n"); 863 1.1 christos } 864 1.1 christos 865 1.1 christos } 866 1.1 christos 867 1.1 christos 868 1.1 christos static void 869 1.1 christos dump_opcode_field(opcode_field *field, int indent, int levels) 870 1.1 christos { 871 1.1 christos printf("(opcode_field*)%p\n", field); 872 1.1 christos if (levels && field != NULL) { 873 1.1 christos dumpf(indent, "(first %d)\n", field->first); 874 1.1 christos dumpf(indent, "(last %d)\n", field->last); 875 1.1 christos dumpf(indent, "(is_boolean %d)\n", field->is_boolean); 876 1.1 christos dumpf(indent, "(parent "); 877 1.1 christos dump_opcode_field(field->parent, indent, levels-1); 878 1.1 christos } 879 1.1 christos } 880 1.1 christos 881 1.1 christos 882 1.1 christos static void 883 1.1 christos dump_insn_bits(insn_bits *bits, int indent, int levels) 884 1.1 christos { 885 1.1 christos printf("(insn_bits*)%p\n", bits); 886 1.1 christos 887 1.1 christos if (levels && bits != NULL) { 888 1.1 christos dumpf(indent, "(value %d)\n", bits->value); 889 1.1 christos dumpf(indent, "(opcode "); 890 1.1 christos dump_opcode_field(bits->opcode, indent+1, 0); 891 1.1 christos dumpf(indent, " )\n"); 892 1.1 christos dumpf(indent, "(field "); 893 1.1 christos dump_insn_field(bits->field, indent+1); 894 1.1 christos dumpf(indent, " )\n"); 895 1.1 christos dumpf(indent, "(last "); 896 1.1 christos dump_insn_bits(bits->last, indent+1, levels-1); 897 1.1 christos } 898 1.1 christos } 899 1.1 christos 900 1.1 christos 901 1.1 christos 902 1.1 christos static void 903 1.1 christos dump_insn(insn *entry, int indent, int levels) 904 1.1 christos { 905 1.1 christos printf("(insn*)%p\n", entry); 906 1.1 christos 907 1.1 christos if (levels && entry != NULL) { 908 1.1 christos 909 1.1 christos dumpf(indent, "(file_entry "); 910 1.1 christos dump_table_entry(entry->file_entry, indent+1); 911 1.1 christos dumpf(indent, " )\n"); 912 1.1 christos 913 1.1 christos dumpf(indent, "(fields "); 914 1.1 christos dump_insn_fields(entry->fields, indent+1); 915 1.1 christos dumpf(indent, " )\n"); 916 1.1 christos 917 1.1 christos dumpf(indent, "(next "); 918 1.1 christos dump_insn(entry->next, indent+1, levels-1); 919 1.1 christos dumpf(indent, " )\n"); 920 1.1 christos 921 1.1 christos } 922 1.1 christos 923 1.1 christos } 924 1.1 christos 925 1.1 christos 926 1.1 christos static void 927 1.1 christos dump_insn_table(insn_table *table, 928 1.1 christos int indent, int levels) 929 1.1 christos { 930 1.1 christos 931 1.1 christos printf("(insn_table*)%p\n", table); 932 1.1 christos 933 1.1 christos if (levels && table != NULL) { 934 1.1 christos 935 1.1 christos dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr); 936 1.1 christos 937 1.1 christos dumpf(indent, "(expanded_bits "); 938 1.1 christos dump_insn_bits(table->expanded_bits, indent+1, -1); 939 1.1 christos dumpf(indent, " )\n"); 940 1.1 christos 941 1.1 christos dumpf(indent, "(int nr_insn %d)\n", table->nr_insn); 942 1.1 christos 943 1.1 christos dumpf(indent, "(insns "); 944 1.1 christos dump_insn(table->insns, indent+1, table->nr_insn); 945 1.1 christos dumpf(indent, " )\n"); 946 1.1 christos 947 1.1 christos dumpf(indent, "(opcode_rule "); 948 1.1 christos dump_decode_rule(table->opcode_rule, indent+1); 949 1.1 christos dumpf(indent, " )\n"); 950 1.1 christos 951 1.1 christos dumpf(indent, "(opcode "); 952 1.1 christos dump_opcode_field(table->opcode, indent+1, 1); 953 1.1 christos dumpf(indent, " )\n"); 954 1.1 christos 955 1.7 christos dumpf(indent, "(nr_entries %d)\n", table->nr_entries); 956 1.1 christos dumpf(indent, "(entries "); 957 1.1 christos dump_insn_table(table->entries, indent+1, table->nr_entries); 958 1.1 christos dumpf(indent, " )\n"); 959 1.1 christos 960 1.7 christos dumpf(indent, "(sibling "); 961 1.1 christos dump_insn_table(table->sibling, indent+1, levels-1); 962 1.1 christos dumpf(indent, " )\n"); 963 1.1 christos 964 1.7 christos dumpf(indent, "(parent "); 965 1.1 christos dump_insn_table(table->parent, indent+1, 0); 966 1.1 christos dumpf(indent, " )\n"); 967 1.1 christos 968 1.1 christos } 969 1.1 christos } 970 1.1 christos 971 1.8 christos int insn_bit_size = ppc_max_insn_bit_size; 972 1.1 christos int hi_bit_nr; 973 1.1 christos int generate_expanded_instructions; 974 1.1 christos 975 1.1 christos int 976 1.1 christos main(int argc, char **argv) 977 1.1 christos { 978 1.1 christos filter *filters = NULL; 979 1.1 christos decode_table *decode_rules = NULL; 980 1.1 christos insn_table *instructions = NULL; 981 1.1 christos cache_table *cache_rules = NULL; 982 1.1 christos 983 1.1 christos if (argc != 5) 984 1.8 christos ERROR("Usage: insn <filter> <hi-bit-nr> <decode-table> <insn-table>\n"); 985 1.1 christos 986 1.8 christos filter_parse(&filters, argv[1]); 987 1.1 christos hi_bit_nr = a2i(argv[2]); 988 1.1 christos ASSERT(hi_bit_nr < insn_bit_size); 989 1.1 christos decode_rules = load_decode_table(argv[3], hi_bit_nr); 990 1.1 christos instructions = load_insn_table(argv[4], decode_rules, filters, NULL, 991 1.1 christos &cache_rules); 992 1.1 christos insn_table_expand_insns(instructions); 993 1.1 christos 994 1.1 christos dump_insn_table(instructions, 0, -1); 995 1.1 christos return 0; 996 1.1 christos } 997 1.1 christos 998 1.1 christos #endif 999