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