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 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
40static void
41print_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
59void
60print_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
83static void
84print_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
209void
210print_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
367typedef struct _icache_tree icache_tree;
368struct _icache_tree {
369  char *name;
370  icache_tree *next;
371  icache_tree *children;
372};
373
374static icache_tree *
375icache_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
404static icache_tree *
405insn_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
428extern void
429print_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
491static void
492print_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
582void
583print_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
617void
618print_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
637void
638print_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