Home | History | Annotate | Line # | Download | only in ppc
gen-icache.c revision 1.1.1.1.2.1
      1 /*  This file is part of the program psim.
      2 
      3     Copyright (C) 1994-1997, Andrew Cagney <cagney (at) highland.com.au>
      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 #include "misc.h"
     22 #include "lf.h"
     23 #include "table.h"
     24 
     25 #include "filter.h"
     26 
     27 #include "ld-decode.h"
     28 #include "ld-cache.h"
     29 #include "ld-insn.h"
     30 
     31 #include "igen.h"
     32 
     33 #include "gen-semantics.h"
     34 #include "gen-idecode.h"
     35 #include "gen-icache.h"
     36 
     37 
     38 
     39 static void
     40 print_icache_function_header(lf *file,
     41 			     const char *basename,
     42 			     insn_bits *expanded_bits,
     43 			     int is_function_definition)
     44 {
     45   lf_printf(file, "\n");
     46   lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", " ");
     47   print_function_name(file,
     48 		      basename,
     49 		      expanded_bits,
     50 		      function_name_prefix_icache);
     51   lf_printf(file, "\n(%s)", ICACHE_FUNCTION_FORMAL);
     52   if (!is_function_definition)
     53     lf_printf(file, ";");
     54   lf_printf(file, "\n");
     55 }
     56 
     57 
     58 void
     59 print_icache_declaration(insn_table *entry,
     60 			 lf *file,
     61 			 void *data,
     62 			 insn *instruction,
     63 			 int depth)
     64 {
     65   if (generate_expanded_instructions) {
     66     ASSERT(entry->nr_insn == 1);
     67     print_icache_function_header(file,
     68 				 entry->insns->file_entry->fields[insn_name],
     69 				 entry->expanded_bits,
     70 				 0/* is not function definition */);
     71   }
     72   else {
     73     print_icache_function_header(file,
     74 				 instruction->file_entry->fields[insn_name],
     75 				 NULL,
     76 				 0/* is not function definition */);
     77   }
     78 }
     79 
     80 
     81 
     82 static void
     83 print_icache_extraction(lf *file,
     84 			insn *instruction,
     85 			const char *entry_name,
     86 			const char *entry_type,
     87 			const char *entry_expression,
     88 			const char *original_name,
     89 			const char *file_name,
     90 			int line_nr,
     91 			insn_field *cur_field,
     92 			insn_bits *bits,
     93 			icache_decl_type what_to_declare,
     94 			icache_body_type what_to_do,
     95 			const char *reason)
     96 {
     97   const char *expression;
     98   ASSERT(entry_name != NULL);
     99 
    100   /* Define a storage area for the cache element */
    101   if (what_to_declare == undef_variables) {
    102     /* We've finished with the value - destory it */
    103     lf_indent_suppress(file);
    104     lf_printf(file, "#undef %s\n", entry_name);
    105     return;
    106   }
    107   else if (what_to_declare == define_variables) {
    108     lf_indent_suppress(file);
    109     lf_printf(file, "#define %s ", entry_name);
    110   }
    111   else {
    112     if (file_name != NULL)
    113       lf_print__external_reference(file, line_nr, file_name);
    114     lf_printf(file, "%s const %s UNUSED = ",
    115 	      entry_type == NULL ? "unsigned" : entry_type,
    116 	      entry_name);
    117   }
    118 
    119   /* define a value for that storage area as determined by what is in
    120      the cache */
    121   if (bits != NULL
    122       && strcmp(entry_name, cur_field->val_string) == 0
    123       && ((bits->opcode->is_boolean && bits->value == 0)
    124 	  || (!bits->opcode->is_boolean))) {
    125     /* The simple field has been made constant (as a result of
    126        expanding instructions or similar).  Remember that for a
    127        boolean field, value is either 0 (implying the required
    128        boolean_constant) or nonzero (implying some other value and
    129        handled later below) - Define the variable accordingly */
    130     expression = "constant field";
    131     ASSERT(bits->field == cur_field);
    132     ASSERT(entry_type == NULL);
    133     if (bits->opcode->is_boolean)
    134       lf_printf(file, "%d", bits->opcode->boolean_constant);
    135     else if (bits->opcode->last < bits->field->last)
    136       lf_printf(file, "%d",
    137 		bits->value << (bits->field->last - bits->opcode->last));
    138     else
    139       lf_printf(file, "%d", bits->value);
    140   }
    141   else if (bits != NULL
    142 	   && original_name != NULL
    143 	   && strncmp(entry_name,
    144 		      original_name, strlen(original_name)) == 0
    145 	   && strncmp(entry_name + strlen(original_name),
    146 		      "_is_", strlen("_is_")) == 0
    147 	   && ((bits->opcode->is_boolean
    148 		&& (atol(entry_name + strlen(original_name) + strlen("_is_"))
    149 		    == bits->opcode->boolean_constant))
    150 	       || (!bits->opcode->is_boolean))) {
    151     expression = "constant compare";
    152     /* An entry, derived from ORIGINAL_NAME, is testing to see of the
    153        ORIGINAL_NAME has a specific constant value.  That value
    154        matching a boolean or constant field */
    155     if (bits->opcode->is_boolean)
    156       lf_printf(file, "%d /* %s == %d */",
    157 		bits->value == 0,
    158 		original_name,
    159 		bits->opcode->boolean_constant);
    160     else if (bits->opcode->last < bits->field->last)
    161       lf_printf(file, "%d /* %s == %d */",
    162 		(atol(entry_name + strlen(original_name) + strlen("_is_"))
    163 		 == (bits->value << (bits->field->last - bits->opcode->last))),
    164 		original_name,
    165 		(bits->value << (bits->field->last - bits->opcode->last)));
    166     else
    167       lf_printf(file, "%d /* %s == %d */",
    168 		(atol(entry_name + strlen(original_name) + strlen("_is_"))
    169 		 == bits->value),
    170 		original_name,
    171 		bits->value);
    172   }
    173   else {
    174     /* put the field in the local variable, possibly also enter it
    175        into the cache */
    176     expression = "extraction";
    177     /* handle the cache */
    178     if ((what_to_do & get_values_from_icache)
    179 	|| (what_to_do & put_values_in_icache)) {
    180       lf_printf(file, "cache_entry->crack.%s.%s",
    181 		instruction->file_entry->fields[insn_form],
    182 		entry_name);
    183       if (what_to_do & put_values_in_icache) /* also put it in the cache? */
    184 	lf_printf(file, " = ");
    185     }
    186     if ((what_to_do & put_values_in_icache)
    187 	|| what_to_do == do_not_use_icache) {
    188       if (cur_field != NULL && strcmp(entry_name, cur_field->val_string) == 0)
    189 	lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
    190 		  i2target(hi_bit_nr, cur_field->first),
    191 		  i2target(hi_bit_nr, cur_field->last));
    192       else if (entry_expression != NULL)
    193 	lf_printf(file, "%s", entry_expression);
    194       else
    195 	lf_printf(file, "eval_%s", entry_name);
    196     }
    197   }
    198 
    199   if (!((what_to_declare == define_variables)
    200 	|| (what_to_declare == undef_variables)))
    201     lf_printf(file, ";");
    202   if (reason != NULL)
    203     lf_printf(file, " /* %s - %s */", reason, expression);
    204   lf_printf(file, "\n");
    205 }
    206 
    207 
    208 void
    209 print_icache_body(lf *file,
    210 		  insn *instruction,
    211 		  insn_bits *expanded_bits,
    212 		  cache_table *cache_rules,
    213 		  icache_decl_type what_to_declare,
    214 		  icache_body_type what_to_do)
    215 {
    216   insn_field *cur_field;
    217 
    218   /* extract instruction fields */
    219   lf_printf(file, "/* extraction: %s ",
    220 	    instruction->file_entry->fields[insn_format]);
    221   switch (what_to_declare) {
    222   case define_variables:
    223     lf_printf(file, "#define");
    224     break;
    225   case declare_variables:
    226     lf_printf(file, "declare");
    227     break;
    228   case undef_variables:
    229     lf_printf(file, "#undef");
    230     break;
    231   }
    232   lf_printf(file, " ");
    233   switch (what_to_do) {
    234   case get_values_from_icache:
    235     lf_printf(file, "get-values-from-icache");
    236     break;
    237   case put_values_in_icache:
    238     lf_printf(file, "put-values-in-icache");
    239     break;
    240   case both_values_and_icache:
    241     lf_printf(file, "get-values-from-icache|put-values-in-icache");
    242     break;
    243   case do_not_use_icache:
    244     lf_printf(file, "do-not-use-icache");
    245     break;
    246   }
    247   lf_printf(file, " */\n");
    248 
    249   for (cur_field = instruction->fields->first;
    250        cur_field->first < insn_bit_size;
    251        cur_field = cur_field->next) {
    252     if (cur_field->is_string) {
    253       insn_bits *bits;
    254       int found_rule = 0;
    255       /* find any corresponding value */
    256       for (bits = expanded_bits;
    257 	   bits != NULL;
    258 	   bits = bits->last) {
    259 	if (bits->field == cur_field)
    260 	  break;
    261       }
    262       /* try the cache rule table for what to do */
    263       {
    264 	cache_table *cache_rule;
    265 	for (cache_rule = cache_rules;
    266 	     cache_rule != NULL;
    267 	     cache_rule = cache_rule->next) {
    268 	  if (strcmp(cur_field->val_string, cache_rule->field_name) == 0) {
    269 	    found_rule = 1;
    270 	    if (cache_rule->type == scratch_value
    271 		&& ((what_to_do & put_values_in_icache)
    272 		    || what_to_do == do_not_use_icache))
    273 	      print_icache_extraction(file,
    274 				      instruction,
    275 				      cache_rule->derived_name,
    276 				      cache_rule->type_def,
    277 				      cache_rule->expression,
    278 				      cache_rule->field_name,
    279 				      cache_rule->file_entry->file_name,
    280 				      cache_rule->file_entry->line_nr,
    281 				      cur_field,
    282 				      bits,
    283 				      what_to_declare,
    284 				      do_not_use_icache,
    285 				      "icache scratch");
    286 	    else if (cache_rule->type == compute_value
    287 		     && ((what_to_do & get_values_from_icache)
    288 			 || what_to_do == do_not_use_icache))
    289 	      print_icache_extraction(file,
    290 				      instruction,
    291 				      cache_rule->derived_name,
    292 				      cache_rule->type_def,
    293 				      cache_rule->expression,
    294 				      cache_rule->field_name,
    295 				      cache_rule->file_entry->file_name,
    296 				      cache_rule->file_entry->line_nr,
    297 				      cur_field,
    298 				      bits,
    299 				      what_to_declare,
    300 				      do_not_use_icache,
    301 				      "semantic compute");
    302 	    else if (cache_rule->type == cache_value
    303 		     && ((what_to_declare != undef_variables)
    304 			 || !(what_to_do & put_values_in_icache)))
    305 	      print_icache_extraction(file,
    306 				      instruction,
    307 				      cache_rule->derived_name,
    308 				      cache_rule->type_def,
    309 				      cache_rule->expression,
    310 				      cache_rule->field_name,
    311 				      cache_rule->file_entry->file_name,
    312 				      cache_rule->file_entry->line_nr,
    313 				      cur_field,
    314 				      bits,
    315 				      ((what_to_do & put_values_in_icache)
    316 				       ? declare_variables
    317 				       : what_to_declare),
    318 				      what_to_do,
    319 				      "in icache");
    320 	  }
    321 	}
    322       }
    323       /* No rule at all, assume that this is needed in the semantic
    324          function (when values are extracted from the icache) and
    325          hence must be put into the cache */
    326       if (found_rule == 0
    327 	  && ((what_to_declare != undef_variables)
    328 	      || !(what_to_do & put_values_in_icache)))
    329 	print_icache_extraction(file,
    330 				instruction,
    331 				cur_field->val_string,
    332 				NULL, NULL, NULL, /* type, exp, orig */
    333 				instruction->file_entry->file_name,
    334 				instruction->file_entry->line_nr,
    335 				cur_field,
    336 				bits,
    337 				((what_to_do & put_values_in_icache)
    338 				 ? declare_variables
    339 				 : what_to_declare),
    340 				what_to_do,
    341 				"default in icache");
    342       /* any thing else ... */
    343     }
    344   }
    345 
    346   lf_print__internal_reference(file);
    347 
    348   if ((code & generate_with_insn_in_icache)) {
    349     lf_printf(file, "\n");
    350     print_icache_extraction(file,
    351 			    instruction,
    352 			    "insn",
    353 			    "instruction_word",
    354 			    "instruction",
    355 			    NULL, /* origin */
    356 			    NULL, 0, /* file_name & line_nr */
    357 			    NULL, NULL,
    358 			    what_to_declare,
    359 			    what_to_do,
    360 			    NULL);
    361   }
    362 }
    363 
    364 
    365 
    366 typedef struct _icache_tree icache_tree;
    367 struct _icache_tree {
    368   char *name;
    369   icache_tree *next;
    370   icache_tree *children;
    371 };
    372 
    373 static icache_tree *
    374 icache_tree_insert(icache_tree *tree,
    375 		   char *name)
    376 {
    377   icache_tree *new_tree;
    378   /* find it */
    379   icache_tree **ptr_to_cur_tree = &tree->children;
    380   icache_tree *cur_tree = *ptr_to_cur_tree;
    381   while (cur_tree != NULL
    382 	 && strcmp(cur_tree->name, name) < 0) {
    383     ptr_to_cur_tree = &cur_tree->next;
    384     cur_tree = *ptr_to_cur_tree;
    385   }
    386   ASSERT(cur_tree == NULL
    387 	 || strcmp(cur_tree->name, name) >= 0);
    388   /* already in the tree */
    389   if (cur_tree != NULL
    390       && strcmp(cur_tree->name, name) == 0)
    391     return cur_tree;
    392   /* missing, insert it */
    393   ASSERT(cur_tree == NULL
    394 	 || strcmp(cur_tree->name, name) > 0);
    395   new_tree = ZALLOC(icache_tree);
    396   new_tree->name = name;
    397   new_tree->next = cur_tree;
    398   *ptr_to_cur_tree = new_tree;
    399   return new_tree;
    400 }
    401 
    402 
    403 static icache_tree *
    404 insn_table_cache_fields(insn_table *table)
    405 {
    406   icache_tree *tree = ZALLOC(icache_tree);
    407   insn *instruction;
    408   for (instruction = table->insns;
    409        instruction != NULL;
    410        instruction = instruction->next) {
    411     insn_field *field;
    412     icache_tree *form =
    413       icache_tree_insert(tree,
    414 			 instruction->file_entry->fields[insn_form]);
    415     for (field = instruction->fields->first;
    416 	 field != NULL;
    417 	 field = field->next) {
    418       if (field->is_string)
    419 	icache_tree_insert(form, field->val_string);
    420     }
    421   }
    422   return tree;
    423 }
    424 
    425 
    426 
    427 extern void
    428 print_icache_struct(insn_table *instructions,
    429 		    cache_table *cache_rules,
    430 		    lf *file)
    431 {
    432   icache_tree *tree = insn_table_cache_fields(instructions);
    433 
    434   lf_printf(file, "\n");
    435   lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n",
    436 	    (code & generate_with_icache) ? icache_size : 0);
    437   lf_printf(file, "\n");
    438 
    439   /* create an instruction cache if being used */
    440   if ((code & generate_with_icache)) {
    441     icache_tree *form;
    442     lf_printf(file, "typedef struct _idecode_cache {\n");
    443     lf_printf(file, "  unsigned_word address;\n");
    444     lf_printf(file, "  void *semantic;\n");
    445     lf_printf(file, "  union {\n");
    446     for (form = tree->children;
    447 	 form != NULL;
    448 	 form = form->next) {
    449       icache_tree *field;
    450       lf_printf(file, "    struct {\n");
    451       if (code & generate_with_insn_in_icache)
    452 	lf_printf(file, "      instruction_word insn;\n");
    453       for (field = form->children;
    454 	   field != NULL;
    455 	   field = field->next) {
    456 	cache_table *cache_rule;
    457 	int found_rule = 0;
    458 	for (cache_rule = cache_rules;
    459 	     cache_rule != NULL;
    460 	     cache_rule = cache_rule->next) {
    461 	  if (strcmp(field->name, cache_rule->field_name) == 0) {
    462 	    found_rule = 1;
    463 	    if (cache_rule->derived_name != NULL)
    464 	      lf_printf(file, "      %s %s; /* %s */\n",
    465 			(cache_rule->type_def == NULL
    466 			 ? "unsigned"
    467 			 : cache_rule->type_def),
    468 			cache_rule->derived_name,
    469 			cache_rule->field_name);
    470 	  }
    471 	}
    472 	if (!found_rule)
    473 	  lf_printf(file, "      unsigned %s;\n", field->name);
    474       }
    475       lf_printf(file, "    } %s;\n", form->name);
    476     }
    477     lf_printf(file, "  } crack;\n");
    478     lf_printf(file, "} idecode_cache;\n");
    479   }
    480   else {
    481     /* alernativly, since no cache, emit a dummy definition for
    482        idecode_cache so that code refering to the type can still compile */
    483     lf_printf(file, "typedef void idecode_cache;\n");
    484   }
    485   lf_printf(file, "\n");
    486 }
    487 
    488 
    489 
    490 static void
    491 print_icache_function(lf *file,
    492 		      insn *instruction,
    493 		      insn_bits *expanded_bits,
    494 		      opcode_field *opcodes,
    495 		      cache_table *cache_rules)
    496 {
    497   int indent;
    498 
    499   /* generate code to enter decoded instruction into the icache */
    500   lf_printf(file, "\n");
    501   lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", "\n");
    502   indent = print_function_name(file,
    503 			       instruction->file_entry->fields[insn_name],
    504 			       expanded_bits,
    505 			       function_name_prefix_icache);
    506   lf_indent(file, +indent);
    507   lf_printf(file, "(%s)\n", ICACHE_FUNCTION_FORMAL);
    508   lf_indent(file, -indent);
    509 
    510   /* function header */
    511   lf_printf(file, "{\n");
    512   lf_indent(file, +2);
    513 
    514   print_my_defines(file, expanded_bits, instruction->file_entry);
    515   print_itrace(file, instruction->file_entry, 1/*putting-value-in-cache*/);
    516 
    517   print_idecode_validate(file, instruction, opcodes);
    518 
    519   lf_printf(file, "\n");
    520   lf_printf(file, "{\n");
    521   lf_indent(file, +2);
    522   if ((code & generate_with_semantic_icache))
    523     lf_printf(file, "unsigned_word nia;\n");
    524   print_icache_body(file,
    525 		    instruction,
    526 		    expanded_bits,
    527 		    cache_rules,
    528 		    ((code & generate_with_direct_access)
    529 		     ? define_variables
    530 		     : declare_variables),
    531 		    ((code & generate_with_semantic_icache)
    532 		     ? both_values_and_icache
    533 		     : put_values_in_icache));
    534 
    535   lf_printf(file, "\n");
    536   lf_printf(file, "cache_entry->address = cia;\n");
    537   lf_printf(file, "cache_entry->semantic = ");
    538   print_function_name(file,
    539 		      instruction->file_entry->fields[insn_name],
    540 		      expanded_bits,
    541 		      function_name_prefix_semantics);
    542   lf_printf(file, ";\n");
    543   lf_printf(file, "\n");
    544 
    545   if ((code & generate_with_semantic_icache)) {
    546     lf_printf(file, "/* semantic routine */\n");
    547     print_semantic_body(file,
    548 			instruction,
    549 			expanded_bits,
    550 			opcodes);
    551     lf_printf(file, "return nia;\n");
    552   }
    553 
    554   if (!(code & generate_with_semantic_icache)) {
    555     lf_printf(file, "/* return the function proper */\n");
    556     lf_printf(file, "return ");
    557     print_function_name(file,
    558 			instruction->file_entry->fields[insn_name],
    559 			expanded_bits,
    560 			function_name_prefix_semantics);
    561     lf_printf(file, ";\n");
    562   }
    563 
    564   if ((code & generate_with_direct_access))
    565     print_icache_body(file,
    566 		      instruction,
    567 		      expanded_bits,
    568 		      cache_rules,
    569 		      undef_variables,
    570 		      ((code & generate_with_semantic_icache)
    571 		       ? both_values_and_icache
    572 		       : put_values_in_icache));
    573 
    574   lf_indent(file, -2);
    575   lf_printf(file, "}\n");
    576   lf_indent(file, -2);
    577   lf_printf(file, "}\n");
    578 }
    579 
    580 
    581 void
    582 print_icache_definition(insn_table *entry,
    583 			lf *file,
    584 			void *data,
    585 			insn *instruction,
    586 			int depth)
    587 {
    588   cache_table *cache_rules = (cache_table*)data;
    589   if (generate_expanded_instructions) {
    590     ASSERT(entry->nr_insn == 1
    591 	   && entry->opcode == NULL
    592 	   && entry->parent != NULL
    593 	   && entry->parent->opcode != NULL);
    594     ASSERT(entry->nr_insn == 1
    595 	   && entry->opcode == NULL
    596 	   && entry->parent != NULL
    597 	   && entry->parent->opcode != NULL
    598 	   && entry->parent->opcode_rule != NULL);
    599     print_icache_function(file,
    600 			  entry->insns,
    601 			  entry->expanded_bits,
    602 			  entry->opcode,
    603 			  cache_rules);
    604   }
    605   else {
    606     print_icache_function(file,
    607 			  instruction,
    608 			  NULL,
    609 			  NULL,
    610 			  cache_rules);
    611   }
    612 }
    613 
    614 
    615 
    616 void
    617 print_icache_internal_function_declaration(insn_table *table,
    618 					   lf *file,
    619 					   void *data,
    620 					   table_entry *function)
    621 {
    622   ASSERT((code & generate_with_icache) != 0);
    623   if (it_is("internal", function->fields[insn_flags])) {
    624     lf_printf(file, "\n");
    625     lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "PSIM_INLINE_ICACHE",
    626 			   "\n");
    627     print_function_name(file,
    628 			function->fields[insn_name],
    629 			NULL,
    630 			function_name_prefix_icache);
    631     lf_printf(file, "\n(%s);\n", ICACHE_FUNCTION_FORMAL);
    632   }
    633 }
    634 
    635 
    636 void
    637 print_icache_internal_function_definition(insn_table *table,
    638 					  lf *file,
    639 					  void *data,
    640 					  table_entry *function)
    641 {
    642   ASSERT((code & generate_with_icache) != 0);
    643   if (it_is("internal", function->fields[insn_flags])) {
    644     lf_printf(file, "\n");
    645     lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "PSIM_INLINE_ICACHE",
    646 			   "\n");
    647     print_function_name(file,
    648 			function->fields[insn_name],
    649 			NULL,
    650 			function_name_prefix_icache);
    651     lf_printf(file, "\n(%s)\n", ICACHE_FUNCTION_FORMAL);
    652     lf_printf(file, "{\n");
    653     lf_indent(file, +2);
    654     lf_printf(file, "/* semantic routine */\n");
    655     table_entry_print_cpp_line_nr(file, function);
    656     if ((code & generate_with_semantic_icache)) {
    657       lf_print__c_code(file, function->annex);
    658       lf_printf(file, "error(\"Internal function must longjump\\n\");\n");
    659       lf_printf(file, "return 0;\n");
    660     }
    661     else {
    662       lf_printf(file, "return ");
    663       print_function_name(file,
    664 			  function->fields[insn_name],
    665 			  NULL,
    666 			  function_name_prefix_semantics);
    667       lf_printf(file, ";\n");
    668     }
    669 
    670     lf_print__internal_reference(file);
    671     lf_indent(file, -2);
    672     lf_printf(file, "}\n");
    673   }
    674 }
    675