]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/gen-icache.c
sim: enable silent rules in common builds
[thirdparty/binutils-gdb.git] / sim / ppc / gen-icache.c
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 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 char *name;
370 icache_tree *next;
371 icache_tree *children;
372 };
373
374 static icache_tree *
375 icache_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
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 }