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