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