New simulator changes from Andrew
[external/binutils.git] / sim / ppc / gen-icache.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1995, 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 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                         char *field_name,
87                         char *field_type,
88                         char *field_expression,
89                         const char *file_name,
90                         int line_nr,
91                         insn_field *cur_field,
92                         insn_bits *bits,
93                         int use_defines,
94                         int get_value_from_cache,
95                         int put_value_in_cache)
96 {
97   ASSERT(field_name != NULL);
98   if (use_defines && put_value_in_cache) {
99     /* We've finished with the value - destory it */
100     lf_indent_suppress(file);
101     lf_printf(file, "#undef %s\n", field_name);
102     return;
103   }
104   else if (use_defines && get_value_from_cache) {
105       lf_indent_suppress(file);
106       lf_printf(file, "#define %s ", field_name);
107   }
108   else {
109     lf_print__external_reference(file, line_nr, file_name);
110     lf_printf(file, "%s const %s __attribute__((__unused__)) = ",
111               field_type == NULL ? "unsigned" : field_type,
112               field_name);
113   }
114
115   if (bits != NULL
116       && ((bits->opcode->is_boolean
117            && bits->value == 0)
118           || !bits->opcode->is_boolean)
119       && strcmp(field_name, cur_field->val_string) == 0) {
120     /* The field has been made constant (as a result of expanding
121        instructions or similar) - define a constant variable with the
122        corresponding value. */
123     ASSERT(bits->field == cur_field);
124     ASSERT(field_type == NULL);
125     if (bits->opcode->is_boolean)
126       lf_printf(file, "%d", bits->opcode->boolean_constant);
127     else if (bits->opcode->last < bits->field->last)
128       lf_printf(file, "%d",
129                 bits->value << (bits->field->last - bits->opcode->last));
130     else
131       lf_printf(file, "%d", bits->value);
132   }
133   else {
134     /* put the field in the local variable, possibly also enter it
135        into the cache */
136     /* getting it from the cache */
137     if (get_value_from_cache || put_value_in_cache) {
138       lf_printf(file, "cache_entry->crack.%s.%s",
139                 instruction->file_entry->fields[insn_form],
140                 field_name);
141       if (put_value_in_cache) /* also put it in the cache? */
142         lf_printf(file, " = ");
143     }
144     if (!get_value_from_cache) {
145       if (strcmp(field_name, cur_field->val_string) == 0)
146         lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
147                   i2target(hi_bit_nr, cur_field->first),
148                   i2target(hi_bit_nr, cur_field->last));
149       else if (field_expression != NULL)
150         lf_printf(file, "%s", field_expression);
151       else
152         lf_printf(file, "eval_%s", field_name);
153     }
154   }
155
156   if (use_defines && get_value_from_cache)
157     lf_printf(file, "\n");
158   else
159     lf_printf(file, ";\n");
160 }
161
162
163 void
164 print_icache_body(lf *file,
165                   insn *instruction,
166                   insn_bits *expanded_bits,
167                   cache_table *cache_rules,
168                   int use_defines,
169                   int get_value_from_cache,
170                   int put_value_in_cache)
171 {
172   insn_field *cur_field;
173   
174   /* extract instruction fields */
175   lf_printf(file, "/* extraction: %s defines=%d get-value=%d put-value=%d */\n",
176             instruction->file_entry->fields[insn_format],
177             use_defines, get_value_from_cache, put_value_in_cache);
178   
179   for (cur_field = instruction->fields->first;
180        cur_field->first < insn_bit_size;
181        cur_field = cur_field->next) {
182     if (cur_field->is_string) {
183       insn_bits *bits;
184       int found_rule = 0;
185       /* find any corresponding value */
186       for (bits = expanded_bits;
187            bits != NULL;
188            bits = bits->last) {
189         if (bits->field == cur_field)
190           break;
191       }
192       /* try the cache rule table for what to do */
193       if (get_value_from_cache || put_value_in_cache) {      
194         cache_table *cache_rule;
195         for (cache_rule = cache_rules;
196              cache_rule != NULL;
197              cache_rule = cache_rule->next) {
198           if (strcmp(cur_field->val_string, cache_rule->old_name) == 0) {
199             found_rule = 1;
200             if (cache_rule->type == compute_value
201                 && put_value_in_cache
202                 && !use_defines)
203               print_icache_extraction(file,
204                                       instruction,
205                                       cache_rule->new_name,
206                                       cache_rule->type_def,
207                                       cache_rule->expression,
208                                       cache_rule->file_entry->file_name,
209                                       cache_rule->file_entry->line_nr,
210                                       cur_field,
211                                       bits,
212                                       0 /*use_defines*/,
213                                       0 /*get-value-from-cache*/,
214                                       0 /*put-value-in-cache*/);
215             else if (cache_rule->type == cache_value)
216               print_icache_extraction(file,
217                                       instruction,
218                                       cache_rule->new_name,
219                                       cache_rule->type_def,
220                                       cache_rule->expression,
221                                       cache_rule->file_entry->file_name,
222                                       cache_rule->file_entry->line_nr,
223                                       cur_field,
224                                       bits,
225                                       use_defines,
226                                       get_value_from_cache,
227                                       put_value_in_cache);
228           }
229         }
230       }
231       if (found_rule == 0)
232         print_icache_extraction(file,
233                                 instruction,
234                                 cur_field->val_string,
235                                 0,
236                                 0,
237                                 instruction->file_entry->file_name,
238                                 instruction->file_entry->line_nr,
239                                 cur_field,
240                                 bits,
241                                 use_defines,
242                                 get_value_from_cache,
243                                 put_value_in_cache);
244       /* if any (XXX == 0), output a corresponding test */
245       if (instruction->file_entry->annex != NULL) {
246         char *field_name = cur_field->val_string;
247         char *is_0_ptr = instruction->file_entry->annex;
248         int field_len = strlen(field_name);
249         if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) {
250           is_0_ptr += field_len;
251           while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) {
252             if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0
253                 && !isalpha(is_0_ptr[ - field_len - 1])) {
254               if (!use_defines || (use_defines && get_value_from_cache)) {
255                 if (use_defines) {
256                   lf_indent_suppress(file);
257                   lf_printf(file, "#define %s_is_0 ", field_name);
258                 }
259                 else {
260                   table_entry_print_cpp_line_nr(file, instruction->file_entry);
261                   lf_printf(file, "const unsigned %s_is_0 __attribute__((__unused__)) = ",
262                             field_name);
263                 }
264                 if (bits != NULL)
265                   lf_printf(file, "(%d == 0)", bits->value);
266                 else
267                   lf_printf(file, "(%s == 0)", field_name);
268                 if (use_defines)
269                   lf_printf(file, "\n");
270                 else
271                   lf_printf(file, ";\n");
272               }
273               else if (use_defines && put_value_in_cache) {
274                 lf_indent_suppress(file);
275                 lf_printf(file, "#undef %s_is_0\n", field_name);
276               }
277               break;
278             }
279             is_0_ptr += strlen("_is_0");
280           }
281         }
282       }
283       /* any thing else ... */
284     }
285   }
286   lf_print__internal_reference(file);
287 }
288
289
290
291 typedef struct _icache_tree icache_tree;
292 struct _icache_tree {
293   char *name;
294   icache_tree *next;
295   icache_tree *children;
296 };
297
298 static icache_tree *
299 icache_tree_insert(icache_tree *tree,
300                    char *name)
301 {
302   icache_tree *new_tree;
303   /* find it */
304   icache_tree **ptr_to_cur_tree = &tree->children;
305   icache_tree *cur_tree = *ptr_to_cur_tree;
306   while (cur_tree != NULL
307          && strcmp(cur_tree->name, name) < 0) {
308     ptr_to_cur_tree = &cur_tree->next;
309     cur_tree = *ptr_to_cur_tree;
310   }
311   ASSERT(cur_tree == NULL
312          || strcmp(cur_tree->name, name) >= 0);
313   /* already in the tree */
314   if (cur_tree != NULL
315       && strcmp(cur_tree->name, name) == 0)
316     return cur_tree;
317   /* missing, insert it */
318   ASSERT(cur_tree == NULL
319          || strcmp(cur_tree->name, name) > 0);
320   new_tree = ZALLOC(icache_tree);
321   new_tree->name = name;
322   new_tree->next = cur_tree;
323   *ptr_to_cur_tree = new_tree;
324   return new_tree;
325 }
326
327
328 static icache_tree *
329 insn_table_cache_fields(insn_table *table)
330 {
331   icache_tree *tree = ZALLOC(icache_tree);
332   insn *instruction;
333   for (instruction = table->insns;
334        instruction != NULL;
335        instruction = instruction->next) {
336     insn_field *field;
337     icache_tree *form =
338       icache_tree_insert(tree,
339                          instruction->file_entry->fields[insn_form]);
340     for (field = instruction->fields->first;
341          field != NULL;
342          field = field->next) {
343       if (field->is_string)
344         icache_tree_insert(form, field->val_string);
345     }
346   }
347   return tree;
348 }
349
350
351
352 extern void
353 print_icache_struct(insn_table *instructions,
354                     cache_table *cache_rules,
355                     lf *file)
356 {
357   icache_tree *tree = insn_table_cache_fields(instructions);
358   
359   lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n",
360             (code & generate_with_icache) ? icache_size : 0);
361   lf_printf(file, "\n");
362   
363   /* create an instruction cache if being used */
364   if ((code & generate_with_icache)) {
365     icache_tree *form;
366     lf_printf(file, "typedef struct _idecode_cache {\n");
367     lf_printf(file, "  unsigned_word address;\n");
368     lf_printf(file, "  void *semantic;\n");
369     lf_printf(file, "  union {\n");
370     for (form = tree->children;
371          form != NULL;
372          form = form->next) {
373       icache_tree *field;
374       lf_printf(file, "    struct {\n");
375       for (field = form->children;
376            field != NULL;
377            field = field->next) {
378         cache_table *cache_rule;
379         int found_rule = 0;
380         for (cache_rule = cache_rules;
381              cache_rule != NULL;
382              cache_rule = cache_rule->next) {
383           if (strcmp(field->name, cache_rule->old_name) == 0) {
384             found_rule = 1;
385             if (cache_rule->new_name != NULL)
386               lf_printf(file, "      %s %s; /* %s */\n",
387                         (cache_rule->type_def == NULL
388                          ? "unsigned" 
389                          : cache_rule->type_def),
390                         cache_rule->new_name,
391                         cache_rule->old_name);
392           }
393         }
394         if (!found_rule)
395           lf_printf(file, "      unsigned %s;\n", field->name);
396       }
397       lf_printf(file, "    } %s;\n", form->name);
398     }
399     lf_printf(file, "  } crack;\n");
400     lf_printf(file, "} idecode_cache;\n");
401   }
402   else {
403     /* alernativly, since no cache, #define the fields to be
404        extractions from the instruction variable.  Emit a dummy
405        definition for idecode_cache to allow model_issue to not
406        be #ifdefed at the call level */
407     cache_table *cache_rule;
408     lf_printf(file, "\n");
409     lf_printf(file, "typedef void idecode_cache;\n");
410     lf_printf(file, "\n");
411     for (cache_rule = cache_rules;
412          cache_rule != NULL;
413          cache_rule = cache_rule->next) {
414       if (cache_rule->expression != NULL
415           && strlen(cache_rule->expression) > 0)
416         lf_printf(file, "#define %s %s\n",
417                   cache_rule->new_name, cache_rule->expression);
418     }
419   }
420 }
421
422
423
424 static void
425 print_icache_function(lf *file,
426                       insn *instruction,
427                       insn_bits *expanded_bits,
428                       opcode_field *opcodes,
429                       cache_table *cache_rules)
430 {
431   int indent;
432
433   /* generate code to enter decoded instruction into the icache */
434   lf_printf(file, "\n");
435   lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "EXTERN_ICACHE", "\n");
436   indent = print_function_name(file,
437                                instruction->file_entry->fields[insn_name],
438                                expanded_bits,
439                                function_name_prefix_icache);
440   lf_indent(file, +indent);
441   lf_printf(file, "(%s)\n", ICACHE_FUNCTION_FORMAL);
442   lf_indent(file, -indent);
443   
444   /* function header */
445   lf_printf(file, "{\n");
446   lf_indent(file, +2);
447   
448   print_define_my_index(file, instruction->file_entry);
449   print_itrace(file, instruction->file_entry, 1/*putting-value-in-cache*/);
450   
451   print_idecode_validate(file, instruction, opcodes);
452   
453   lf_printf(file, "\n");
454   lf_printf(file, "{\n");
455   lf_indent(file, +2);
456   print_icache_body(file,
457                     instruction,
458                     expanded_bits,
459                     cache_rules,
460                     0/*use_defines*/,
461                     0/*get_value_from_cache*/,
462                     1/*put_value_in_cache*/);
463   
464   if ((code & generate_with_semantic_icache)) {
465     lf_printf(file, "unsigned_word nia;\n");
466     lf_printf(file, "cache_entry->address = cia;\n");
467     lf_printf(file, "cache_entry->semantic = ");
468     print_function_name(file,
469                         instruction->file_entry->fields[insn_name],
470                         expanded_bits,
471                         function_name_prefix_semantics);
472     lf_printf(file, ";\n");
473     print_semantic_body(file,
474                         instruction,
475                         expanded_bits,
476                         opcodes);
477     lf_printf(file, "\n");
478     lf_printf(file, "return nia;\n");
479   }
480   lf_indent(file, -2);
481   lf_printf(file, "}\n");
482   
483   if (!(code & generate_with_semantic_icache)) {
484     /* return the function propper (main sorts this one out) */
485     lf_printf(file, "\n");
486     lf_printf(file, "/* semantic routine */\n");
487     table_entry_print_cpp_line_nr(file, instruction->file_entry);
488     lf_printf(file, "return ");
489     print_function_name(file,
490                         instruction->file_entry->fields[insn_name],
491                         expanded_bits,
492                         function_name_prefix_semantics);
493     lf_printf(file, ";\n");
494     lf_print__internal_reference(file);
495   }
496   
497   lf_indent(file, -2);
498   lf_printf(file, "}\n");
499 }
500
501
502 void
503 print_icache_definition(insn_table *entry,
504                         lf *file,
505                         void *data,
506                         insn *instruction,
507                         int depth)
508 {
509   cache_table *cache_rules = (cache_table*)data;
510   if (generate_expanded_instructions) {
511     ASSERT(entry->nr_insn == 1
512            && entry->opcode == NULL
513            && entry->parent != NULL
514            && entry->parent->opcode != NULL);
515     ASSERT(entry->nr_insn == 1
516            && entry->opcode == NULL
517            && entry->parent != NULL
518            && entry->parent->opcode != NULL
519            && entry->parent->opcode_rule != NULL);
520     print_icache_function(file,
521                           entry->insns,
522                           entry->expanded_bits,
523                           entry->opcode,
524                           cache_rules);
525   }
526   else {
527     print_icache_function(file,
528                           instruction,
529                           NULL,
530                           NULL,
531                           cache_rules);
532   }
533 }
534
535
536
537 void
538 print_icache_internal_function_declaration(insn_table *table,
539                                            lf *file,
540                                            void *data,
541                                            table_entry *function)
542 {
543   ASSERT((code & generate_with_icache) != 0);
544   if (it_is("internal", function->fields[insn_flags])) {
545     lf_printf(file, "\n");
546     lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE",
547                            "\n");
548     print_function_name(file,
549                         function->fields[insn_name],
550                         NULL,
551                         function_name_prefix_icache);
552     lf_printf(file, "\n(%s);\n", ICACHE_FUNCTION_FORMAL);
553   }
554 }
555
556
557 void
558 print_icache_internal_function_definition(insn_table *table,
559                                           lf *file,
560                                           void *data,
561                                           table_entry *function)
562 {
563   ASSERT((code & generate_with_icache) != 0);
564   if (it_is("internal", function->fields[insn_flags])) {
565     lf_printf(file, "\n");
566     lf_print_function_type(file, ICACHE_FUNCTION_TYPE, "INLINE_ICACHE",
567                            "\n");
568     print_function_name(file,
569                         function->fields[insn_name],
570                         NULL,
571                         function_name_prefix_icache);
572     lf_printf(file, "\n(%s)\n", ICACHE_FUNCTION_FORMAL);
573     lf_printf(file, "{\n");
574     lf_indent(file, +2);
575     lf_printf(file, "/* semantic routine */\n");
576     table_entry_print_cpp_line_nr(file, function);
577     if ((code & generate_with_semantic_icache)) {
578       lf_print__c_code(file, function->annex);
579       lf_printf(file, "error(\"Internal function must longjump\\n\");\n");
580       lf_printf(file, "return 0;\n");
581     }
582     else {
583       lf_printf(file, "return ");
584       print_function_name(file,
585                           function->fields[insn_name],
586                           NULL,
587                           function_name_prefix_semantics);
588       lf_printf(file, ";\n");
589     }
590     
591     lf_print__internal_reference(file);
592     lf_indent(file, -2);
593     lf_printf(file, "}\n");
594   }
595 }