Lose doc directory until we DOS-ize it; Add doc/.Sanitize
[binutils-gdb.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 }