xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/gen-icache.c (revision 4b004442778f1201b2161e87fd65ba87aae6601a)
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 "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 ATTRIBUTE_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   const char *name;
370   icache_tree *next;
371   icache_tree *children;
372 };
373 
374 static icache_tree *
375 icache_tree_insert(icache_tree *tree,
376 		   const 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