1/* This file is part of the program psim. 2 3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 18 */ 19 20 21 22#include <getopt.h> 23 24#include "misc.h" 25#include "lf.h" 26#include "table.h" 27#include "build-config.h" 28 29#include "filter.h" 30 31#include "ld-cache.h" 32#include "ld-decode.h" 33#include "ld-insn.h" 34 35#include "igen.h" 36 37#include "gen-model.h" 38#include "gen-icache.h" 39#include "gen-itable.h" 40#include "gen-idecode.h" 41#include "gen-semantics.h" 42#include "gen-support.h" 43 44int hi_bit_nr; 45int insn_bit_size = max_insn_bit_size; 46 47igen_code code = generate_calls; 48 49int generate_expanded_instructions; 50int icache_size = 1024; 51int generate_smp; 52 53/****************************************************************/ 54 55static int 56print_insn_bits(lf *file, insn_bits *bits) 57{ 58 int nr = 0; 59 if (bits == NULL) 60 return nr; 61 nr += print_insn_bits(file, bits->last); 62 nr += lf_putchr(file, '_'); 63 nr += lf_putstr(file, bits->field->val_string); 64 if (bits->opcode->is_boolean && bits->value == 0) 65 nr += lf_putint(file, bits->opcode->boolean_constant); 66 else if (!bits->opcode->is_boolean) { 67 if (bits->opcode->last < bits->field->last) 68 nr += lf_putint(file, bits->value << (bits->field->last - bits->opcode->last)); 69 else 70 nr += lf_putint(file, bits->value); 71 } 72 return nr; 73} 74 75extern int 76print_function_name(lf *file, 77 const char *basename, 78 insn_bits *expanded_bits, 79 lf_function_name_prefixes prefix) 80{ 81 int nr = 0; 82 /* the prefix */ 83 switch (prefix) { 84 case function_name_prefix_semantics: 85 nr += lf_putstr(file, "semantic_"); 86 break; 87 case function_name_prefix_idecode: 88 nr += lf_printf(file, "idecode_"); 89 break; 90 case function_name_prefix_itable: 91 nr += lf_putstr(file, "itable_"); 92 break; 93 case function_name_prefix_icache: 94 nr += lf_putstr(file, "icache_"); 95 break; 96 default: 97 break; 98 } 99 100 /* the function name */ 101 { 102 const char *pos; 103 for (pos = basename; 104 *pos != '\0'; 105 pos++) { 106 switch (*pos) { 107 case '/': 108 case '-': 109 case '(': 110 case ')': 111 break; 112 case ' ': 113 nr += lf_putchr(file, '_'); 114 break; 115 default: 116 nr += lf_putchr(file, *pos); 117 break; 118 } 119 } 120 } 121 122 /* the suffix */ 123 if (generate_expanded_instructions) 124 nr += print_insn_bits(file, expanded_bits); 125 126 return nr; 127} 128 129 130void 131print_my_defines(lf *file, 132 insn_bits *expanded_bits, 133 table_entry *file_entry) 134{ 135 /* #define MY_INDEX xxxxx */ 136 lf_indent_suppress(file); 137 lf_printf(file, "#undef MY_INDEX\n"); 138 lf_indent_suppress(file); 139 lf_printf(file, "#define MY_INDEX "); 140 print_function_name(file, 141 file_entry->fields[insn_name], 142 NULL, 143 function_name_prefix_itable); 144 lf_printf(file, "\n"); 145 /* #define MY_PREFIX xxxxxx */ 146 lf_indent_suppress(file); 147 lf_printf(file, "#undef MY_PREFIX\n"); 148 lf_indent_suppress(file); 149 lf_printf(file, "#define MY_PREFIX "); 150 print_function_name(file, 151 file_entry->fields[insn_name], 152 expanded_bits, 153 function_name_prefix_none); 154 lf_printf(file, "\n"); 155} 156 157 158void 159print_itrace(lf *file, 160 table_entry *file_entry, 161 int idecode) 162{ 163 lf_print__external_reference(file, file_entry->line_nr, file_entry->file_name); 164 lf_printf(file, "ITRACE(trace_%s, (\"%s %s\\n\"));\n", 165 (idecode ? "idecode" : "semantics"), 166 (idecode ? "idecode" : "semantics"), 167 file_entry->fields[insn_name]); 168 lf_print__internal_reference(file); 169} 170 171 172/****************************************************************/ 173 174 175static void 176gen_semantics_h(insn_table *table, 177 lf *file, 178 igen_code generate) 179{ 180 lf_printf(file, "typedef %s idecode_semantic\n(%s);\n", 181 SEMANTIC_FUNCTION_TYPE, 182 SEMANTIC_FUNCTION_FORMAL); 183 lf_printf(file, "\n"); 184 if ((code & generate_calls)) { 185 lf_printf(file, "extern int option_mpc860c0;\n"); 186 lf_printf(file, "#define PAGE_SIZE 0x1000\n"); 187 lf_printf(file, "\n"); 188 lf_printf(file, "PSIM_EXTERN_SEMANTICS(void)\n"); 189 lf_printf(file, "semantic_init(device* root);\n"); 190 lf_printf(file, "\n"); 191 if (generate_expanded_instructions) 192 insn_table_traverse_tree(table, 193 file, NULL, 194 1, 195 NULL, /* start */ 196 print_semantic_declaration, /* leaf */ 197 NULL, /* end */ 198 NULL); /* padding */ 199 else 200 insn_table_traverse_insn(table, 201 file, NULL, 202 print_semantic_declaration); 203 204 } 205 else { 206 lf_print__this_file_is_empty(file); 207 } 208} 209 210 211static void 212gen_semantics_c(insn_table *table, 213 cache_table *cache_rules, 214 lf *file, 215 igen_code generate) 216{ 217 if ((code & generate_calls)) { 218 lf_printf(file, "\n"); 219 lf_printf(file, "#include \"cpu.h\"\n"); 220 lf_printf(file, "#include \"idecode.h\"\n"); 221 lf_printf(file, "#include \"semantics.h\"\n"); 222 lf_printf(file, "#ifdef HAVE_COMMON_FPU\n"); 223 lf_printf(file, "#include \"sim-inline.h\"\n"); 224 lf_printf(file, "#include \"sim-fpu.h\"\n"); 225 lf_printf(file, "#endif\n"); 226 lf_printf(file, "#include \"support.h\"\n"); 227 lf_printf(file, "\n"); 228 lf_printf(file, "int option_mpc860c0 = 0;\n"); 229 lf_printf(file, "\n"); 230 lf_printf(file, "PSIM_EXTERN_SEMANTICS(void)\n"); 231 lf_printf(file, "semantic_init(device* root)\n"); 232 lf_printf(file, "{\n"); 233 lf_printf(file, " option_mpc860c0 = 0;\n"); 234 lf_printf(file, " if (tree_find_property(root, \"/options/mpc860c0\"))\n"); 235 lf_printf(file, " option_mpc860c0 = tree_find_integer_property(root, \"/options/mpc860c0\");\n"); 236 lf_printf(file, " option_mpc860c0 *= 4; /* convert word count to byte count */\n"); 237 lf_printf(file, "}\n"); 238 lf_printf(file, "\n"); 239 if (generate_expanded_instructions) 240 insn_table_traverse_tree(table, 241 file, cache_rules, 242 1, 243 NULL, /* start */ 244 print_semantic_definition, /* leaf */ 245 NULL, /* end */ 246 NULL); /* padding */ 247 else 248 insn_table_traverse_insn(table, 249 file, cache_rules, 250 print_semantic_definition); 251 252 } 253 else { 254 lf_print__this_file_is_empty(file); 255 } 256} 257 258 259/****************************************************************/ 260 261 262static void 263gen_icache_h(insn_table *table, 264 lf *file, 265 igen_code generate) 266{ 267 lf_printf(file, "typedef %s idecode_icache\n(%s);\n", 268 ICACHE_FUNCTION_TYPE, 269 ICACHE_FUNCTION_FORMAL); 270 lf_printf(file, "\n"); 271 if ((code & generate_calls) 272 && (code & generate_with_icache)) { 273 insn_table_traverse_function(table, 274 file, NULL, 275 print_icache_internal_function_declaration); 276 if (generate_expanded_instructions) 277 insn_table_traverse_tree(table, 278 file, NULL, 279 1, 280 NULL, /* start */ 281 print_icache_declaration, /* leaf */ 282 NULL, /* end */ 283 NULL); /* padding */ 284 else 285 insn_table_traverse_insn(table, 286 file, NULL, 287 print_icache_declaration); 288 289 } 290 else { 291 lf_print__this_file_is_empty(file); 292 } 293} 294 295static void 296gen_icache_c(insn_table *table, 297 cache_table *cache_rules, 298 lf *file, 299 igen_code generate) 300{ 301 /* output `internal' invalid/floating-point unavailable functions 302 where needed */ 303 if ((code & generate_calls) 304 && (code & generate_with_icache)) { 305 lf_printf(file, "\n"); 306 lf_printf(file, "#include \"cpu.h\"\n"); 307 lf_printf(file, "#include \"idecode.h\"\n"); 308 lf_printf(file, "#include \"semantics.h\"\n"); 309 lf_printf(file, "#include \"icache.h\"\n"); 310 lf_printf(file, "#ifdef HAVE_COMMON_FPU\n"); 311 lf_printf(file, "#include \"sim-inline.h\"\n"); 312 lf_printf(file, "#include \"sim-fpu.h\"\n"); 313 lf_printf(file, "#endif\n"); 314 lf_printf(file, "#include \"support.h\"\n"); 315 lf_printf(file, "\n"); 316 insn_table_traverse_function(table, 317 file, NULL, 318 print_icache_internal_function_definition); 319 lf_printf(file, "\n"); 320 if (generate_expanded_instructions) 321 insn_table_traverse_tree(table, 322 file, cache_rules, 323 1, 324 NULL, /* start */ 325 print_icache_definition, /* leaf */ 326 NULL, /* end */ 327 NULL); /* padding */ 328 else 329 insn_table_traverse_insn(table, 330 file, cache_rules, 331 print_icache_definition); 332 333 } 334 else { 335 lf_print__this_file_is_empty(file); 336 } 337} 338 339 340/****************************************************************/ 341 342 343int 344main(int argc, 345 char **argv, 346 char **envp) 347{ 348 cache_table *cache_rules = NULL; 349 lf_file_references file_references = lf_include_references; 350 decode_table *decode_rules = NULL; 351 filter *filters = NULL; 352 insn_table *instructions = NULL; 353 table_include *includes = NULL; 354 char *real_file_name = NULL; 355 int is_header = 0; 356 int ch; 357 358 if (argc == 1) { 359 printf("Usage:\n"); 360 printf(" igen <config-opts> ... <input-opts>... <output-opts>...\n"); 361 printf("Config options:\n"); 362 printf(" -F <filter-out-flag> eg -F 64 to skip 64bit instructions\n"); 363 printf(" -E Expand (duplicate) semantic functions\n"); 364 printf(" -I <icache-size> Generate cracking cache version\n"); 365 printf(" -C Include semantics in cache functions\n"); 366 printf(" -S Include insn (instruction) in icache\n"); 367 printf(" -R Use defines to reference cache vars\n"); 368 printf(" -L Supress line numbering in output files\n"); 369 printf(" -B <bit-size> Set the number of bits in an instruction\n"); 370 printf(" -H <high-bit> Set the nr of the high (msb bit)\n"); 371 printf(" -N <nr-cpus> Specify the max number of cpus the simulation will support\n"); 372 printf(" -J Use jumps instead of function calls\n"); 373 printf(" -T <mechanism> Override the mechanism used to decode an instruction\n"); 374 printf(" using <mechanism> instead of what was specified in the\n"); 375 printf(" decode-rules input file\n"); 376 printf("\n"); 377 printf("Input options (ucase version also dumps loaded table):\n"); 378 printf(" -o <decode-rules>\n"); 379 printf(" -k <cache-rules>\n"); 380 printf(" -i <instruction-table>\n"); 381 printf("\n"); 382 printf("Output options:\n"); 383 printf(" -n <real-name> Specify the real name of for the next output file\n"); 384 printf(" -h Generate header file\n"); 385 printf(" -c <output-file> output icache\n"); 386 printf(" -d <output-file> output idecode\n"); 387 printf(" -m <output-file> output model\n"); 388 printf(" -s <output-file> output schematic\n"); 389 printf(" -t <output-file> output itable\n"); 390 printf(" -f <output-file> output support functions\n"); 391 } 392 393 while ((ch = getopt(argc, argv, 394 "F:EI:RSLJT:CB:H:N:o:k:i:n:hc:d:m:s:t:f:")) 395 != -1) { 396 fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : "")); 397 switch(ch) { 398 case 'C': 399 code |= generate_with_icache; 400 code |= generate_with_semantic_icache; 401 break; 402 case 'S': 403 code |= generate_with_icache; 404 code |= generate_with_insn_in_icache; 405 break; 406 case 'L': 407 file_references = lf_omit_references; 408 break; 409 case 'E': 410 generate_expanded_instructions = 1; 411 break; 412 case 'G': 413 { 414 int enable_p; 415 char *argp; 416 if (strncmp (optarg, "no-", strlen ("no-")) == 0) 417 { 418 argp = optarg + strlen ("no-"); 419 enable_p = 0; 420 } 421 else if (strncmp (optarg, "!", strlen ("!")) == 0) 422 { 423 argp = optarg + strlen ("no-"); 424 enable_p = 0; 425 } 426 else 427 { 428 argp = optarg; 429 enable_p = 1; 430 } 431 if (strncmp (argp, "gen-icache", strlen ("gen-icache")) == 0) 432 { 433 switch (argp[strlen ("gen-icache")]) 434 { 435 case '=': 436 icache_size = atoi (argp + strlen ("gen-icache") + 1); 437 code |= generate_with_icache; 438 break; 439 case '\0': 440 code |= generate_with_icache; 441 break; 442 default: 443 error (NULL, "Expecting -Ggen-icache or -Ggen-icache=<N>\n"); 444 } 445 } 446 } 447 case 'I': 448 { 449 table_include **dir = &includes; 450 while ((*dir) != NULL) 451 dir = &(*dir)->next; 452 (*dir) = ZALLOC (table_include); 453 (*dir)->dir = strdup (optarg); 454 } 455 break; 456 case 'N': 457 generate_smp = a2i(optarg); 458 break; 459 case 'R': 460 code |= generate_with_direct_access; 461 break; 462 case 'B': 463 insn_bit_size = a2i(optarg); 464 ASSERT(insn_bit_size > 0 && insn_bit_size <= max_insn_bit_size 465 && (hi_bit_nr == insn_bit_size-1 || hi_bit_nr == 0)); 466 break; 467 case 'H': 468 hi_bit_nr = a2i(optarg); 469 ASSERT(hi_bit_nr == insn_bit_size-1 || hi_bit_nr == 0); 470 break; 471 case 'F': 472 filters = new_filter(optarg, filters); 473 break; 474 case 'J': 475 code &= ~generate_calls; 476 code |= generate_jumps; 477 break; 478 case 'T': 479 force_decode_gen_type(optarg); 480 break; 481 case 'i': 482 if (decode_rules == NULL) { 483 fprintf(stderr, "Must specify decode tables\n"); 484 exit (1); 485 } 486 instructions = load_insn_table(optarg, decode_rules, filters, includes, 487 &cache_rules); 488 fprintf(stderr, "\texpanding ...\n"); 489 insn_table_expand_insns(instructions); 490 break; 491 case 'o': 492 decode_rules = load_decode_table(optarg, hi_bit_nr); 493 break; 494 case 'k': 495 cache_rules = load_cache_table(optarg, hi_bit_nr); 496 break; 497 case 'n': 498 real_file_name = strdup(optarg); 499 break; 500 case 'h': 501 is_header = 1; 502 break; 503 case 's': 504 case 'd': 505 case 'm': 506 case 't': 507 case 'f': 508 case 'c': 509 { 510 lf *file = lf_open(optarg, real_file_name, file_references, 511 (is_header ? lf_is_h : lf_is_c), 512 argv[0]); 513 lf_print__file_start(file); 514 ASSERT(instructions != NULL); 515 switch (ch) { 516 case 's': 517 if(is_header) 518 gen_semantics_h(instructions, file, code); 519 else 520 gen_semantics_c(instructions, cache_rules, file, code); 521 break; 522 case 'd': 523 if (is_header) 524 gen_idecode_h(file, instructions, cache_rules); 525 else 526 gen_idecode_c(file, instructions, cache_rules); 527 break; 528 case 'm': 529 if (is_header) 530 gen_model_h(instructions, file); 531 else 532 gen_model_c(instructions, file); 533 break; 534 case 't': 535 if (is_header) 536 gen_itable_h(instructions, file); 537 else 538 gen_itable_c(instructions, file); 539 break; 540 case 'f': 541 if (is_header) 542 gen_support_h(instructions, file); 543 else 544 gen_support_c(instructions, file); 545 break; 546 case 'c': 547 if (is_header) 548 gen_icache_h(instructions, file, code); 549 else 550 gen_icache_c(instructions, cache_rules, file, code); 551 break; 552 } 553 lf_print__file_finish(file); 554 lf_close(file); 555 is_header = 0; 556 } 557 real_file_name = NULL; 558 break; 559 default: 560 error("unknown option\n"); 561 } 562 } 563 return 0; 564} 565