xref: /netbsd-src/external/gpl3/gdb.old/dist/sim/ppc/gen-icache.c (revision 867d70fc718005c0918b8b8b2f9d7f2d52d0a0db)
1 /*  This file is part of the program psim.
2 
3     Copyright (C) 1994-1997, Andrew Cagney <cagney@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