Add support to count the number of instructions issued.
[deliverable/binutils-gdb.git] / sim / ppc / gen.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 /* BUGS:
23
24 Instead of using/abusing macro's the semantic code should be parsed
25 and each `cachable' expression replaced with the corresponding
26 value.
27
28 If not expanding fields, invalid_insn has call to its self this is
29 a little fatal when semantic_invalid() is being called because an
30 instruction is invalid */
31
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <getopt.h>
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <stdarg.h>
42 #include <string.h>
43
44 #include "config.h"
45 #include "ppc-config.h"
46
47 #undef WITH_ASSERT
48 #define WITH_ASSERT 1
49
50 #include "debug.h"
51
52
53 /****************************************************************/
54
55 void
56 error (char *msg, ...)
57 {
58 va_list ap;
59 va_start(ap, msg);
60 vprintf(msg, ap);
61 va_end(ap);
62 exit (1);
63 }
64
65 void *
66 zmalloc(long size)
67 {
68 void *memory = malloc(size);
69 if (memory == NULL)
70 error("zmalloc failed\n");
71 bzero(memory, size);
72 return memory;
73 }
74
75 void
76 dumpf (int indent, char *msg, ...)
77 {
78 va_list ap;
79 for (; indent > 0; indent--)
80 printf(" ");
81 va_start(ap, msg);
82 vprintf(msg, ap);
83 va_end(ap);
84 }
85
86
87 /****************************************************************/
88
89 int idecode_expand_semantics = WITH_IDECODE_EXPAND_SEMANTICS;
90 int idecode_cache = WITH_IDECODE_CACHE;
91 int spreg_lookup_table = WITH_SPREG_LOOKUP_TABLE;
92
93 /****************************************************************/
94
95 typedef struct {
96 int valid;
97 char *old_name;
98 char *new_name;
99 char *type;
100 char *expression;
101 } extraction_rules;
102
103 extraction_rules cachable_values[] = WITH_IDECODE_CACHE_RULES;
104
105 /****************************************************************/
106
107 typedef struct _opcode_rules {
108 int valid;
109 int first;
110 int last;
111 int force_first;
112 int force_last;
113 int force_slash;
114 char *force_expansion;
115 int use_switch;
116 unsigned special_mask;
117 unsigned special_value;
118 unsigned special_rule;
119 } opcode_rules;
120
121 /* FIXME - this should be loaded from a file */
122 opcode_rules opcode_table[] = WITH_IDECODE_OPCODE_RULES;
123
124 dump_opcode_rule(opcode_rules *rule,
125 int indent)
126 {
127 printf("(opcode_rules*)0x%x\n", rule);
128 dumpf(indent, "(valid %d)\n", rule->valid);
129 ASSERT(rule != NULL);
130 if (rule->valid) {
131 dumpf(indent, "(first %d)\n", rule->first);
132 dumpf(indent, "(last %d)\n", rule->last);
133 dumpf(indent, "(force_first %d)\n", rule->force_first);
134 dumpf(indent, "(force_last %d)\n", rule->force_last);
135 dumpf(indent, "(force_slash %d)\n", rule->force_slash);
136 dumpf(indent, "(force_expansion %s)\n", rule->force_expansion);
137 }
138 }
139
140
141 /****************************************************************/
142
143 enum gen_constants {
144 insn_size = 32,
145 nr_of_sprs = 1024
146 };
147
148 char cache_idecode_formal[] = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia,\n idecode_cache *cache_entry";
149 char cache_idecode_actual[] = "processor, instruction, cia, cache_entry";
150 char cache_insn_formal[] = "cpu *processor,\n idecode_cache *cache_entry,\n unsigned_word cia";
151 char cache_insn_actual[] = "processor, entry, cia";
152
153 char insn_formal[] = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia";
154 char insn_actual[] = "processor, instruction, cia";
155
156 char insn_local[] = "unsigned_word nia = cia + 4;";
157
158
159 /****************************************************************/
160
161 int
162 bin2i(char *bin, int width)
163 {
164 int i = 0;
165 while (*bin != '\0' && width != 0) {
166 i = (i << 1) + (*bin - '0');
167 width--;
168 bin++;
169 }
170 return i;
171 }
172
173
174 int
175 it_is(char *flag,
176 char *flags)
177 {
178 int flag_len = strlen(flag);
179 while (*flags != '\0') {
180 if (!strncmp(flags, flag, flag_len)
181 && (flags[flag_len] == ',' || flags[flag_len] == '\0'))
182 return 1;
183 while (*flags != ',') {
184 if (*flags == '\0')
185 return 0;
186 flags++;
187 }
188 flags++;
189 }
190 return 0;
191 }
192
193
194 /****************************************************************/
195
196 typedef struct _lf lf;
197 struct _lf {
198 FILE *stream;
199 int line_nr; /* nr complete lines written, curr line is line_nr+1 */
200 int indent;
201 int line_blank;
202 char *file_name;
203 };
204
205
206 lf *
207 lf_open(char *name)
208 {
209 /* create a file object */
210 lf *new_lf = zmalloc(sizeof(lf));
211 ASSERT(new_lf != NULL);
212 new_lf->file_name = name;
213
214 /* attach to stdout if pipe */
215 if (!strcmp(name, "-")) {
216 new_lf->stream = stdout;
217 }
218 else {
219 /* create a new file */
220 new_lf->stream = fopen(name, "w");
221 ASSERT(new_lf->stream != NULL);
222 }
223 return new_lf;
224 }
225
226
227 void
228 lf_close(lf *file)
229 {
230 if (file->stream != stdout) {
231 if (fclose(file->stream)) {
232 perror("lf_close.fclose");
233 exit(1);
234 }
235 free(file);
236 }
237 }
238
239
240 void
241 lf_putchr(lf *file,
242 const char chr)
243 {
244 if (chr == '\n') {
245 file->line_nr += 1;
246 file->line_blank = 1;
247 }
248 else if (file->line_blank) {
249 int pad;
250 for (pad = file->indent; pad > 0; pad--)
251 putc(' ', file->stream);
252 file->line_blank = 0;
253 }
254 putc(chr, file->stream);
255 }
256
257 void
258 lf_indent_suppress(lf *file)
259 {
260 file->line_blank = 0;
261 }
262
263
264 void
265 lf_putstr(lf *file,
266 const char *string)
267 {
268 const char *chp;
269 if (string != NULL) {
270 for (chp = string; *chp != '\0'; chp++) {
271 lf_putchr(file, *chp);
272 }
273 }
274 }
275
276 void
277 do_lf_putunsigned(lf *file,
278 unsigned u)
279 {
280 if (u > 0) {
281 do_lf_putunsigned(file, u / 10);
282 lf_putchr(file, (u % 10) + '0');
283 }
284 }
285
286
287 void
288 lf_putint(lf *file,
289 int decimal)
290 {
291 if (decimal == 0)
292 lf_putchr(file, '0');
293 else if (decimal < 0) {
294 lf_putchr(file, '-');
295 do_lf_putunsigned(file, -decimal);
296 }
297 else if (decimal > 0) {
298 do_lf_putunsigned(file, decimal);
299 }
300 else
301 ASSERT(0);
302 }
303
304 void
305 lf_printf(lf *file,
306 const char *fmt,
307 ...)
308 {
309 char buf[1024];
310 va_list ap;
311 int nr_chars;
312
313 va_start(ap, fmt);
314 vsprintf(buf, fmt, ap);
315 /* FIXME - this is really stuffed but so is vsprintf() on a sun! */
316 ASSERT(strlen(buf) > 0 && strlen(buf) < sizeof(buf));
317 lf_putstr(file, buf);
318 va_end(ap);
319 }
320
321 void
322 lf_print_file_line_nr(lf *file)
323 {
324 #if WITH_LINE_NUMBERS
325 lf_indent_suppress(file);
326 lf_putstr(file, "#line ");
327 lf_putint(file, file->line_nr+2); /*line_nr == last_line, want next */
328 lf_putstr(file, " \"");
329 lf_putstr(file, file->file_name);
330 lf_putstr(file, "\"\n");
331 #endif
332 }
333
334 lf_indent(lf *file, int delta)
335 {
336 file->indent += delta;
337 }
338
339
340 /****************************************************************/
341
342 /* read entries from ppc.instructions */
343
344 enum {
345 file_table_max_fields = 6,
346 };
347
348 typedef struct _file_table file_table;
349 struct _file_table {
350 size_t size;
351 char *buffer;
352 char *pos;
353 int line_nr;
354 char *file_name;
355 };
356
357 typedef struct _file_table_entry file_table_entry;
358 struct _file_table_entry {
359 char *fields[file_table_max_fields];
360 int line_nr;
361 char *file_name;
362 char *annex;
363 };
364
365
366 file_table *
367 file_table_open(char *file_name)
368 {
369 int fd;
370 struct stat stat_buf;
371 file_table *file;
372
373 /* create a file descriptor */
374 file = (file_table*)zmalloc(sizeof(file_table));
375 ASSERT(file != NULL);
376
377 /* save the file name */
378 file->file_name = (char*)zmalloc(strlen(file_name) + 1);
379 ASSERT(file->file_name != NULL);
380 strcpy(file->file_name, file_name);
381
382 /* open the file */
383 fd = open(file->file_name, O_RDONLY, 0);
384 ASSERT(fd >= 0);
385
386 /* determine the size */
387 if (fstat(fd, &stat_buf) < 0) {
388 perror("file_table_open.fstat");
389 exit(1);
390 }
391 file->size = stat_buf.st_size;
392
393 /* allocate this much memory */
394 file->buffer = (char*)zmalloc(file->size+1);
395 if(file->buffer == NULL) {
396 perror("file_table_open.calloc.file->size+1");
397 exit(1);
398 }
399 file->pos = file->buffer;
400
401 /* read it in */
402 if (read(fd, file->buffer, file->size) < file->size) {
403 perror("file_table_open.read");
404 exit(1);
405 }
406 file->buffer[file->size] = '\0';
407
408 /* done */
409 close(fd);
410 return file;
411 }
412
413
414 file_table_entry *
415 file_table_read(file_table *file)
416 {
417 int field;
418 file_table_entry *entry;
419
420 /* skip comments/blanks */
421 while(1) {
422 /* leading white space */
423 while (*file->pos != '\0'
424 && *file->pos != '\n'
425 && isspace(*file->pos))
426 file->pos++;
427 /* comment */
428 if (*file->pos == '#') {
429 do {
430 file->pos++;
431 } while (*file->pos != '\0' && *file->pos != '\n');
432 }
433 /* end of line? */
434 if (*file->pos == '\n') {
435 file->pos++;
436 file->line_nr++;
437 }
438 else
439 break;
440 }
441 if (*file->pos == '\0')
442 return NULL;
443
444 /* create this new entry */
445 entry = (file_table_entry*)zmalloc(sizeof(file_table_entry));
446 ASSERT(entry != NULL);
447 entry->file_name = file->file_name;
448
449 /* break the line into its colon delimitered fields */
450 for (field = 0; field < file_table_max_fields-1; field++) {
451 entry->fields[field] = file->pos;
452 while(*file->pos && *file->pos != ':' && *file->pos != '\n')
453 file->pos++;
454 if (*file->pos == ':') {
455 *file->pos = '\0';
456 file->pos++;
457 }
458 }
459
460 /* any trailing stuff not the last field */
461 ASSERT(field == file_table_max_fields-1);
462 entry->fields[field] = file->pos;
463 while (*file->pos && *file->pos != '\n') {
464 file->pos++;
465 }
466 if (*file->pos == '\n') {
467 *file->pos = '\0';
468 file->pos++;
469 }
470 file->line_nr++;
471 entry->line_nr = file->line_nr;
472
473 /* if following lines tab indented, put in the annex */
474 if (*file->pos == '\t') {
475 entry->annex = file->pos;
476 do {
477 do {
478 file->pos++;
479 } while (*file->pos != '\0' && *file->pos != '\n');
480 if (*file->pos == '\n') {
481 file->pos++;
482 file->line_nr++;
483 }
484 } while (*file->pos != '\0' && *file->pos == '\t');
485 if (file->pos[-1] == '\n')
486 file->pos[-1] = '\0';
487 }
488 else
489 entry->annex = NULL;
490
491 /* return it */
492 return entry;
493
494 }
495
496
497 void
498 dump_file_table_entry(file_table_entry *entry,
499 int indent)
500 {
501 printf("(file_table_entry*)0x%x\n", entry);
502
503 if (entry != NULL) {
504 int field;
505 char sep;
506
507 sep = ' ';
508 dumpf(indent, "(fields");
509 for (field = 0; field < file_table_max_fields; field++) {
510 printf("%c%s", sep, entry->fields[field]);
511 sep = ':';
512 }
513 printf(")\n");
514
515 dumpf(indent, "(line_nr %d)\n", entry->line_nr);
516
517 dumpf(indent, "(file_name %s)\n", entry->file_name);
518
519 dumpf(indent, "(annex\n%s\n", entry->annex);
520 dumpf(indent, " )\n");
521
522 }
523 }
524
525
526 /****************************************************************/
527
528 typedef struct _insn_field insn_field;
529 struct _insn_field {
530 int first;
531 int last;
532 int width;
533 int is_int;
534 int is_slash;
535 int is_string;
536 int val_int;
537 char *pos_string;
538 char *val_string;
539 insn_field *next;
540 insn_field *prev;
541 };
542
543 typedef struct _insn_fields insn_fields;
544 struct _insn_fields {
545 insn_field *bits[insn_size];
546 insn_field *first;
547 insn_field *last;
548 unsigned value;
549 };
550
551 insn_field *
552 insn_field_new()
553 {
554 insn_field *new_field = (insn_field*)zmalloc(sizeof(insn_field));
555 ASSERT(new_field != NULL);
556 return new_field;
557 }
558
559 insn_fields *
560 insn_fields_new()
561 {
562 insn_fields *new_fields = (insn_fields*)zmalloc(sizeof(insn_fields));
563 ASSERT(new_fields != NULL);
564 return new_fields;
565 }
566
567
568 insn_fields *
569 parse_insn_format(file_table_entry *entry,
570 char *format)
571 {
572 char *chp;
573 insn_fields *fields = insn_fields_new();
574
575 /* create a leading sentinal */
576 fields->first = insn_field_new();
577 fields->first->first = -1;
578 fields->first->last = -1;
579 fields->first->width = 0;
580
581 /* and a trailing sentinal */
582 fields->last = insn_field_new();
583 fields->last->first = insn_size;
584 fields->last->last = insn_size;
585 fields->last->width = 0;
586
587 /* link them together */
588 fields->first->next = fields->last;
589 fields->last->prev = fields->first;
590
591 /* now work through the formats */
592 chp = format;
593
594 while (*chp != '\0') {
595 char *start_pos;
596 char *start_val;
597 int strlen_val;
598 int strlen_pos;
599 insn_field *new_field;
600
601 /* sanity check */
602 if (!isdigit(*chp)) {
603 fprintf(stderr, "%s:%d: missing position field at %s\n",
604 entry->file_name, entry->line_nr, chp);
605 break;
606 }
607
608 /* break out the bit position */
609 start_pos = chp;
610 while (isdigit(*chp))
611 chp++;
612 strlen_pos = chp - start_pos;
613 if (*chp == '.' && strlen_pos > 0)
614 chp++;
615 else {
616 fprintf(stderr, "%s:%d: missing field value at %s\n",
617 entry->file_name, entry->line_nr, chp);
618 break;
619 }
620
621 /* break out the value */
622 start_val = chp;
623 while (*start_val == '/' && *chp == '/'
624 || isdigit(*start_val) && isdigit(*chp)
625 || isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))
626 chp++;
627 strlen_val = chp - start_val;
628 if (*chp == ',')
629 chp++;
630 else if (*chp != '\0' || strlen_val == 0) {
631 fprintf(stderr, "%s:%d: missing field terminator at %s\n",
632 entry->file_name, entry->line_nr, chp);
633 break;
634 }
635
636 /* create a new field and insert it */
637 new_field = insn_field_new();
638 new_field->next = fields->last;
639 new_field->prev = fields->last->prev;
640 new_field->next->prev = new_field;
641 new_field->prev->next = new_field;
642
643 /* the value */
644 new_field->val_string = (char*)zmalloc(strlen_val+1);
645 strncpy(new_field->val_string, start_val, strlen_val);
646 if (isdigit(*new_field->val_string)) {
647 new_field->val_int = atoi(new_field->val_string);
648 new_field->is_int = 1;
649 }
650 else if (new_field->val_string[0] == '/') {
651 new_field->is_slash = 1;
652 }
653 else {
654 new_field->is_string = 1;
655 }
656
657 /* the pos */
658 new_field->pos_string = (char*)zmalloc(strlen_pos+1);
659 strncpy(new_field->pos_string, start_pos, strlen_pos);
660 new_field->first = atoi(new_field->pos_string);
661 new_field->last = new_field->next->first - 1; /* guess */
662 new_field->width = new_field->last - new_field->first + 1; /* guess */
663 new_field->prev->last = new_field->first-1; /*fix*/
664 new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/
665 }
666
667 /* fiddle first/last so that the sentinals `disapear' */
668 ASSERT(fields->first->last < 0);
669 ASSERT(fields->last->first >= insn_size);
670 fields->first = fields->first->next;
671 fields->last = fields->last->prev;
672
673 /* now go over this again, pointing each bit position at a field
674 record */
675 {
676 int i;
677 insn_field *field;
678 field = fields->first;
679 for (i = 0; i < insn_size; i++) {
680 while (field->last < i)
681 field = field->next;
682 fields->bits[i] = field;
683 }
684 }
685
686 /* go over each of the fields, and compute a `value' for the insn */
687 {
688 insn_field *field;
689 fields->value = 0;
690 for (field = fields->first;
691 field->last < insn_size;
692 field = field->next) {
693 fields->value <<= field->width;
694 if (field->is_int)
695 fields->value |= field->val_int;
696 }
697 }
698 return fields;
699 }
700
701
702 typedef enum {
703 field_constant_int = 1,
704 field_constant_slash = 2,
705 field_constant_string = 3
706 } constant_field_types;
707
708
709 int
710 insn_field_is_constant(insn_field *field,
711 opcode_rules *rule)
712 {
713 /* field is an integer */
714 if (field->is_int)
715 return field_constant_int;
716 /* field is `/' and treating that as a constant */
717 if (field->is_slash && rule->force_slash)
718 return field_constant_slash;
719 /* field, though variable is on the list */
720 if (field->is_string && rule->force_expansion != NULL) {
721 char *forced_fields = rule->force_expansion;
722 while (*forced_fields != '\0') {
723 int field_len;
724 char *end = strchr(forced_fields, ',');
725 if (end == NULL)
726 field_len = strlen(forced_fields);
727 else
728 field_len = end-forced_fields;
729 if (strncmp(forced_fields, field->val_string, field_len) == 0
730 && field->val_string[field_len] == '\0')
731 return field_constant_string;
732 forced_fields += field_len;
733 if (*forced_fields == ',')
734 forced_fields++;
735 }
736 }
737 return 0;
738 }
739
740
741 void
742 dump_insn_field(insn_field *field,
743 int indent)
744 {
745
746 printf("(insn_field*)0x%x\n", field);
747
748 dumpf(indent, "(first %d)\n", field->first);
749
750 dumpf(indent, "(last %d)\n", field->last);
751
752 dumpf(indent, "(width %d)\n", field->width);
753
754 if (field->is_int)
755 dumpf(indent, "(is_int %d)\n", field->val_int);
756
757 if (field->is_slash)
758 dumpf(indent, "(is_slash)\n");
759
760 if (field->is_string)
761 dumpf(indent, "(is_string `%s')\n", field->val_string);
762
763 dumpf(indent, "(next 0x%x)\n", field->next);
764
765 dumpf(indent, "(prev 0x%x)\n", field->prev);
766
767
768 }
769
770 void
771 dump_insn_fields(insn_fields *fields,
772 int indent)
773 {
774 insn_field *field;
775 int i;
776
777 printf("(insn_fields*)0x%x\n", fields);
778
779 dumpf(indent, "(first 0x%x)\n", fields->first);
780 dumpf(indent, "(last 0x%x)\n", fields->last);
781
782 dumpf(indent, "(value 0x%x)\n", fields->value);
783
784 for (i = 0; i < insn_size; i++) {
785 dumpf(indent, "(bits[%d] ", i, fields->bits[i]);
786 dump_insn_field(fields->bits[i], indent+1);
787 dumpf(indent, " )\n");
788 }
789
790 }
791
792
793 /****************************************************************/
794
795 typedef struct _opcode_field opcode_field;
796 struct _opcode_field {
797 int first;
798 int last;
799 int is_boolean;
800 opcode_field *parent;
801 };
802
803 opcode_field *
804 opcode_field_new()
805 {
806 opcode_field *new_field = (opcode_field*)zmalloc(sizeof(opcode_field));
807 ASSERT(new_field != NULL);
808 new_field->first = insn_size;
809 new_field->last = -1;
810 return new_field;
811 }
812
813 void
814 dump_opcode_field(opcode_field *field, int indent, int levels)
815 {
816 printf("(opcode_field*)0x%x\n", field);
817 if (levels && field != NULL) {
818 dumpf(indent, "(first %d)\n", field->first);
819 dumpf(indent, "(last %d)\n", field->last);
820 dumpf(indent, "(is_boolean %d)\n", field->is_boolean);
821 dumpf(indent, "(parent ");
822 dump_opcode_field(field->parent, indent, levels-1);
823 }
824 }
825
826
827 /****************************************************************/
828
829 typedef struct _insn_bits insn_bits;
830 struct _insn_bits {
831 int is_expanded;
832 int value;
833 insn_field *field;
834 opcode_field *opcode;
835 insn_bits *last;
836 };
837
838 insn_bits *
839 insn_bits_new()
840 {
841 insn_bits *new_bits = (insn_bits*)zmalloc(sizeof(insn_bits));
842 ASSERT(new_bits);
843 return new_bits;
844 }
845
846
847 void
848 dump_insn_bits(insn_bits *bits, int indent, int levels)
849 {
850 printf("(insn_bits*)0x%x\n", bits);
851
852 if (levels && bits != NULL) {
853 dumpf(indent, "(value %d)\n", bits->value);
854 dumpf(indent, "(opcode ");
855 dump_opcode_field(bits->opcode, indent+1, 0);
856 dumpf(indent, " )\n");
857 dumpf(indent, "(field ");
858 dump_insn_field(bits->field, indent+1);
859 dumpf(indent, " )\n");
860 dumpf(indent, "(last ");
861 dump_insn_bits(bits->last, indent+1, levels-1);
862 }
863 }
864
865
866 /****************************************************************/
867
868
869 typedef enum {
870 insn_format,
871 insn_form,
872 insn_flags,
873 insn_nmemonic,
874 insn_name,
875 insn_comment,
876 nr_insn_table_fields = file_table_max_fields
877 } insn_table_fields;
878 char *insn_field_name[] = {
879 "format", "form", "flags", "nmemonic", "name", "comments"
880 };
881
882 typedef struct _insn insn;
883 struct _insn {
884 file_table_entry *file_entry;
885 insn_fields *fields;
886 insn *next;
887 };
888
889 typedef struct _insn_table insn_table;
890 struct _insn_table {
891 int opcode_nr;
892 insn_bits *expanded_bits;
893 int nr_insn;
894 insn *insns;
895 opcode_rules *opcode_rule;
896 opcode_field *opcode;
897 int nr_entries;
898 insn_table *entries;
899 insn_table *sibling;
900 insn_table *parent;
901 };
902
903
904
905 insn *
906 insn_new()
907 {
908 insn *new_entry = ((insn*) zmalloc(sizeof(insn)));
909 ASSERT(new_entry != NULL);
910 return new_entry;
911 }
912
913 insn_table *
914 insn_table_new()
915 {
916 insn_table *new_table = (insn_table*)zmalloc(sizeof(insn_table));
917 ASSERT(new_table != NULL);
918 return new_table;
919 }
920
921
922 void
923 insn_table_insert_insn(insn_table *table,
924 file_table_entry *file_entry,
925 insn_fields *fields)
926 {
927 insn **ptr_to_cur_insn = &table->insns;
928 insn *cur_insn = *ptr_to_cur_insn;
929
930 /* create a new instruction */
931 insn *new_insn = insn_new();
932 new_insn->file_entry = file_entry;
933 new_insn->fields = fields;
934
935 /* insert it according to the order of the fields */
936 while (cur_insn != NULL
937 && new_insn->fields->value >= cur_insn->fields->value) {
938 ptr_to_cur_insn = &cur_insn->next;
939 cur_insn = *ptr_to_cur_insn;
940 }
941
942 new_insn->next = cur_insn;
943 *ptr_to_cur_insn = new_insn;
944
945 table->nr_insn++;
946 }
947
948
949 opcode_field *
950 insn_table_find_opcode_field(insn *insns,
951 opcode_rules *rule,
952 int string_only)
953 {
954 opcode_field *curr_opcode = opcode_field_new();
955 insn *entry;
956
957 ASSERT(rule->valid);
958
959 for (entry = insns; entry != NULL; entry = entry->next) {
960 insn_fields *fields = entry->fields;
961 opcode_field new_opcode;
962
963 /* find a start point for the opcode field */
964 new_opcode.first = rule->first;
965 while (new_opcode.first <= rule->last
966 && (!string_only
967 || insn_field_is_constant(fields->bits[new_opcode.first],
968 rule) != field_constant_string)
969 && (string_only
970 || !insn_field_is_constant(fields->bits[new_opcode.first],
971 rule)))
972 new_opcode.first = fields->bits[new_opcode.first]->last + 1;
973 ASSERT(new_opcode.first > rule->last
974 || (string_only
975 && insn_field_is_constant(fields->bits[new_opcode.first],
976 rule) == field_constant_string)
977 || (!string_only
978 && insn_field_is_constant(fields->bits[new_opcode.first],
979 rule)));
980
981 /* find the end point for the opcode field */
982 new_opcode.last = rule->last;
983 while (new_opcode.last >= rule->first
984 && (!string_only
985 || insn_field_is_constant(fields->bits[new_opcode.last],
986 rule) != field_constant_string)
987 && (string_only
988 || !insn_field_is_constant(fields->bits[new_opcode.last],
989 rule)))
990 new_opcode.last = fields->bits[new_opcode.last]->first - 1;
991 ASSERT(new_opcode.last < rule->first
992 || (string_only
993 && insn_field_is_constant(fields->bits[new_opcode.last],
994 rule) == field_constant_string)
995 || (!string_only
996 && insn_field_is_constant(fields->bits[new_opcode.last],
997 rule)));
998
999 /* now see if our current opcode needs expanding */
1000 if (new_opcode.first <= rule->last
1001 && curr_opcode->first > new_opcode.first)
1002 curr_opcode->first = new_opcode.first;
1003 if (new_opcode.last >= rule->first
1004 && curr_opcode->last < new_opcode.last)
1005 curr_opcode->last = new_opcode.last;
1006
1007 }
1008
1009 /* was any thing interesting found? */
1010 if (curr_opcode->first > rule->last) {
1011 ASSERT(curr_opcode->last < rule->first);
1012 free(curr_opcode);
1013 return NULL;
1014 }
1015 ASSERT(curr_opcode->last >= rule->first);
1016 ASSERT(curr_opcode->first <= rule->last);
1017
1018 /* if something was found, check it includes the forced field range */
1019 if (!string_only
1020 && curr_opcode->first > rule->force_first) {
1021 curr_opcode->first = rule->force_first;
1022 }
1023 if (!string_only
1024 && curr_opcode->last < rule->force_last) {
1025 curr_opcode->last = rule->force_last;
1026 }
1027 /* handle special case elminating any need to do shift after mask */
1028 if (string_only
1029 && rule->force_last == insn_size-1) {
1030 curr_opcode->last = insn_size-1;
1031 }
1032
1033 /* handle any special cases */
1034 switch (rule->special_rule) {
1035 case 0: /* let the above apply */
1036 break;
1037 case 1: /* expand a limited nr of bits, ignoring the rest */
1038 curr_opcode->first = rule->force_first;
1039 curr_opcode->last = rule->force_last;
1040 break;
1041 case 2: /* boolean field */
1042 curr_opcode->is_boolean = 1;
1043 break;
1044 }
1045
1046 return curr_opcode;
1047 }
1048
1049
1050 void
1051 insn_table_insert_expanded(insn_table *table,
1052 insn *old_insn,
1053 int new_opcode_nr,
1054 insn_bits *new_bits)
1055 {
1056 insn_table **ptr_to_cur_entry = &table->entries;
1057 insn_table *cur_entry = *ptr_to_cur_entry;
1058
1059 /* find the new table for this entry */
1060 while (cur_entry != NULL
1061 && cur_entry->opcode_nr < new_opcode_nr) {
1062 ptr_to_cur_entry = &cur_entry->sibling;
1063 cur_entry = *ptr_to_cur_entry;
1064 }
1065
1066 if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) {
1067 insn_table *new_entry = insn_table_new();
1068 new_entry->opcode_nr = new_opcode_nr;
1069 new_entry->expanded_bits = new_bits;
1070 new_entry->opcode_rule = table->opcode_rule+1;
1071 new_entry->sibling = cur_entry;
1072 new_entry->parent = table;
1073 *ptr_to_cur_entry = new_entry;
1074 cur_entry = new_entry;
1075 table->nr_entries++;
1076 }
1077 /* ASSERT new_bits == cur_entry bits */
1078 ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr);
1079 insn_table_insert_insn(cur_entry,
1080 old_insn->file_entry,
1081 old_insn->fields);
1082 }
1083
1084 void
1085 insn_table_expand_opcode(insn_table *table,
1086 insn *instruction,
1087 int field_nr,
1088 int opcode_nr,
1089 insn_bits *bits)
1090 {
1091
1092 if (field_nr > table->opcode->last) {
1093 insn_table_insert_expanded(table, instruction, opcode_nr, bits);
1094 }
1095 else {
1096 insn_field *field = instruction->fields->bits[field_nr];
1097 if (field->is_int || field->is_slash) {
1098 ASSERT(field->first >= table->opcode->first
1099 && field->last <= table->opcode->last);
1100 insn_table_expand_opcode(table, instruction, field->last+1,
1101 ((opcode_nr << field->width) + field->val_int),
1102 bits);
1103 }
1104 else {
1105 int val;
1106 int last_pos = ((field->last < table->opcode->last)
1107 ? field->last : table->opcode->last);
1108 int first_pos = ((field->first > table->opcode->first)
1109 ? field->first : table->opcode->first);
1110 int width = last_pos - first_pos + 1;
1111 int last_val = (table->opcode->is_boolean
1112 ? 2 : (1 << width));
1113 for (val = 0; val < last_val; val++) {
1114 insn_bits *new_bits = insn_bits_new();
1115 new_bits->field = field;
1116 new_bits->value = val;
1117 new_bits->last = bits;
1118 new_bits->opcode = table->opcode;
1119 insn_table_expand_opcode(table, instruction, last_pos+1,
1120 ((opcode_nr << width) | val),
1121 new_bits);
1122 }
1123 }
1124 }
1125 }
1126
1127 insn_table_insert_expanding(insn_table *table,
1128 insn *entry)
1129 {
1130 insn_table_expand_opcode(table,
1131 entry,
1132 table->opcode->first,
1133 0,
1134 table->expanded_bits);
1135 }
1136
1137
1138 void
1139 insn_table_expand_insns(insn_table *table)
1140 {
1141
1142 ASSERT(table->nr_insn >= 1);
1143
1144 /* determine a valid opcode */
1145 while (table->opcode_rule->valid) {
1146 /* specials only for single instructions */
1147 if ((table->nr_insn > 1
1148 && table->opcode_rule->special_mask == 0
1149 && table->opcode_rule->special_rule == 0)
1150 || (table->nr_insn == 1
1151 && table->opcode_rule->special_mask != 0
1152 && ((table->insns->fields->value
1153 & table->opcode_rule->special_mask)
1154 == table->opcode_rule->special_value))
1155 || (idecode_expand_semantics
1156 && table->opcode_rule->special_mask == 0
1157 && table->opcode_rule->special_rule == 0))
1158 table->opcode =
1159 insn_table_find_opcode_field(table->insns,
1160 table->opcode_rule,
1161 table->nr_insn == 1/*string*/
1162 );
1163 if (table->opcode != NULL)
1164 break;
1165 table->opcode_rule++;
1166 }
1167
1168 /* did we find anything */
1169 if (table->opcode == NULL) {
1170 return;
1171 }
1172 ASSERT(table->opcode != NULL);
1173
1174 /* back link what we found to its parent */
1175 if (table->parent != NULL) {
1176 ASSERT(table->parent->opcode != NULL);
1177 table->opcode->parent = table->parent->opcode;
1178 }
1179
1180 /* expand the raw instructions according to the opcode */
1181 {
1182 insn *entry;
1183 for (entry = table->insns; entry != NULL; entry = entry->next) {
1184 insn_table_insert_expanding(table, entry);
1185 }
1186 }
1187
1188 /* and do the same for the sub entries */
1189 {
1190 insn_table *entry;
1191 for (entry = table->entries; entry != NULL; entry = entry->sibling) {
1192 insn_table_expand_insns(entry);
1193 }
1194 }
1195 }
1196
1197
1198
1199 insn_table *
1200 insn_table_load_insns(char *file_name)
1201 {
1202 file_table *file = file_table_open(file_name);
1203 insn_table *table = insn_table_new();
1204 file_table_entry *file_entry;
1205 table->opcode_rule = opcode_table;
1206
1207 while (file_entry = file_table_read(file)) {
1208 insn_fields *fields;
1209 /* skip instructions that aren't relevant to the mode */
1210 if (it_is("64", file_entry->fields[insn_flags]) && !WITH_64BIT_TARGET
1211 || it_is("32", file_entry->fields[insn_flags]) && WITH_64BIT_TARGET)
1212 continue;
1213 /* create/insert the new instruction */
1214 fields = parse_insn_format(file_entry, file_entry->fields[insn_format]);
1215 insn_table_insert_insn(table, file_entry, fields);
1216 }
1217
1218 return table;
1219 }
1220
1221
1222 void
1223 dump_insn(insn *entry, int indent, int levels)
1224 {
1225 printf("(insn*)0x%x\n", entry);
1226
1227 if (levels && entry != NULL) {
1228
1229 dumpf(indent, "(file_entry ");
1230 dump_file_table_entry(entry->file_entry, indent+1);
1231 dumpf(indent, " )\n");
1232
1233 dumpf(indent, "(fields ");
1234 dump_insn_fields(entry->fields, indent+1);
1235 dumpf(indent, " )\n");
1236
1237 dumpf(indent, "(next ");
1238 dump_insn(entry->next, indent+1, levels-1);
1239 dumpf(indent, " )\n");
1240
1241 }
1242
1243 }
1244
1245
1246 void
1247 dump_insn_table(insn_table *table,
1248 int indent, int levels)
1249 {
1250
1251 printf("(insn_table*)0x%x\n", table);
1252
1253 if (levels && table != NULL) {
1254 insn *entry;
1255
1256 dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr);
1257
1258 dumpf(indent, "(expanded_bits ");
1259 dump_insn_bits(table->expanded_bits, indent+1, -1);
1260 dumpf(indent, " )\n");
1261
1262 dumpf(indent, "(int nr_insn %d)\n", table->nr_insn);
1263
1264 dumpf(indent, "(insns ");
1265 dump_insn(table->insns, indent+1, table->nr_insn);
1266 dumpf(indent, " )\n");
1267
1268 dumpf(indent, "(opcode_rule ");
1269 dump_opcode_rule(table->opcode_rule, indent+1);
1270 dumpf(indent, " )\n");
1271
1272 dumpf(indent, "(opcode ");
1273 dump_opcode_field(table->opcode, indent+1, 1);
1274 dumpf(indent, " )\n");
1275
1276 dumpf(indent, "(nr_entries %d)\n", table->entries);
1277 dumpf(indent, "(entries ");
1278 dump_insn_table(table->entries, indent+1, table->nr_entries);
1279 dumpf(indent, " )\n");
1280
1281 dumpf(indent, "(sibling ", table->sibling);
1282 dump_insn_table(table->sibling, indent+1, levels-1);
1283 dumpf(indent, " )\n");
1284
1285 dumpf(indent, "(parent ", table->parent);
1286 dump_insn_table(table->parent, indent+1, 0);
1287 dumpf(indent, " )\n");
1288
1289 }
1290 }
1291
1292
1293 /****************************************************************/
1294
1295
1296 void
1297 lf_print_copyleft(lf *file)
1298 {
1299 lf_putstr(file, "\
1300 /* This file is part of psim (model of the PowerPC(tm) architecture)
1301
1302 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
1303
1304 This library is free software; you can redistribute it and/or
1305 modify it under the terms of the GNU Library General Public License
1306 as published by the Free Software Foundation; either version 2 of
1307 the License, or (at your option) any later version.
1308
1309 This library is distributed in the hope that it will be useful, but
1310 WITHOUT ANY WARRANTY; without even the implied warranty of
1311 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1312 Library General Public License for more details.
1313
1314 You should have received a copy of the GNU Library General Public
1315 License along with this library; if not, write to the Free Software
1316 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1317
1318 --
1319
1320 PowerPC is a trademark of International Business Machines Corporation.
1321
1322 --
1323
1324 This file was generated by the program gen */
1325 ");
1326 }
1327
1328
1329 void
1330 lf_print_c_line_nr(lf *file, file_table_entry *entry)
1331 {
1332 #if WITH_LINE_NUMBERS
1333 lf_indent_suppress(file);
1334 lf_putstr(file, "#line ");
1335 lf_putint(file, entry->line_nr);
1336 lf_putstr(file, " \"");
1337 lf_putstr(file, entry->file_name);
1338 lf_putstr(file, "\"\n");
1339 #endif
1340 }
1341
1342
1343 void
1344 lf_print_c_code(lf *file, char *code)
1345 {
1346 char *chp = code;
1347 int in_bit_field = 0;
1348 while (*chp != '\0') {
1349 if (*chp == '\t')
1350 chp++;
1351 if (*chp == '#')
1352 lf_indent_suppress(file);
1353 while (*chp != '\0' && *chp != '\n') {
1354 if (chp[0] == '{' && !isspace(chp[1])) {
1355 in_bit_field = 1;
1356 lf_putchr(file, '_');
1357 }
1358 else if (in_bit_field && chp[0] == ':') {
1359 lf_putchr(file, '_');
1360 }
1361 else if (in_bit_field && *chp == '}') {
1362 lf_putchr(file, '_');
1363 in_bit_field = 0;
1364 }
1365 else {
1366 lf_putchr(file, *chp);
1367 }
1368 chp++;
1369 }
1370 if (in_bit_field)
1371 error("bit field paren miss match some where\n");
1372 if (*chp == '\n') {
1373 lf_putchr(file, '\n');
1374 chp++;
1375 }
1376 }
1377 lf_putchr(file, '\n');
1378 }
1379
1380
1381 void
1382 lf_print_binary(lf *file, int decimal, int width)
1383 {
1384 int bit;
1385 ASSERT(width > 0);
1386
1387 for (bit = 1 << (width-1); bit != 0; bit >>= 1) {
1388 if (decimal & bit)
1389 lf_putchr(file, '1');
1390 else
1391 lf_putchr(file, '0');
1392 }
1393
1394 }
1395
1396
1397 void
1398 lf_print_insn_bits(lf *file, insn_bits *bits)
1399 {
1400 if (bits == NULL)
1401 return;
1402 lf_print_insn_bits(file, bits->last);
1403 lf_putchr(file, '_');
1404 lf_putstr(file, bits->field->val_string);
1405 if (!bits->opcode->is_boolean || bits->value == 0) {
1406 if (bits->opcode->last < bits->field->last)
1407 lf_putint(file, bits->value << (bits->field->last - bits->opcode->last));
1408 else
1409 lf_putint(file, bits->value);
1410 }
1411 }
1412
1413 void
1414 lf_print_opcodes(lf *file,
1415 insn_table *table)
1416 {
1417 if (table != NULL) {
1418 while (1) {
1419 lf_printf(file, "_%d_%d",
1420 table->opcode->first,
1421 table->opcode->last);
1422 if (table->parent == NULL) break;
1423 lf_printf(file, "__%d", table->opcode_nr);
1424 table = table->parent;
1425 }
1426 }
1427 }
1428
1429 void
1430 lf_print_table_name(lf *file,
1431 insn_table *table)
1432 {
1433 lf_printf(file, "idecode_table");
1434 lf_print_opcodes(file, table);
1435 }
1436
1437
1438
1439 typedef enum {
1440 function_name_prefix_semantics,
1441 function_name_prefix_idecode,
1442 function_name_prefix_none
1443 } lf_function_name_prefixes;
1444
1445 void
1446 lf_print_function_name(lf *file,
1447 insn *instruction,
1448 insn_bits *expanded_bits,
1449 lf_function_name_prefixes prefix)
1450 {
1451 /* the prefix */
1452 switch (prefix) {
1453 case function_name_prefix_semantics:
1454 lf_putstr(file, "semantic_");
1455 break;
1456 case function_name_prefix_idecode:
1457 lf_printf(file, "idecode_");
1458 break;
1459 default:
1460 break;
1461 }
1462
1463 /* the function name */
1464 {
1465 char *pos;
1466 for (pos = instruction->file_entry->fields[insn_name];
1467 *pos != '\0';
1468 pos++) {
1469 switch (*pos) {
1470 case '/':
1471 case '-':
1472 break;
1473 case ' ':
1474 lf_putchr(file, '_');
1475 break;
1476 default:
1477 lf_putchr(file, *pos);
1478 break;
1479 }
1480 }
1481 }
1482
1483 /* the suffix */
1484 if (idecode_expand_semantics)
1485 lf_print_insn_bits(file, expanded_bits);
1486 }
1487
1488
1489 void
1490 lf_print_idecode_table(lf *file,
1491 insn_table *entry)
1492 {
1493 int can_assume_leaf;
1494 int rule;
1495
1496 /* have a look at the rule table, if all table rules follow all
1497 switch rules, I can assume that all end points are leaves */
1498 rule = 0;
1499 while (opcode_table[rule].valid
1500 && opcode_table[rule].use_switch)
1501 rule++;
1502 while (opcode_table[rule].valid
1503 && !opcode_table[rule].use_switch
1504 && !opcode_table[rule].special_rule)
1505 rule++;
1506 can_assume_leaf = !opcode_table[rule].valid;
1507
1508 lf_printf(file, "{\n");
1509 lf_indent(file, +2);
1510 {
1511 lf_printf(file, "idecode_table_entry *table = ");
1512 lf_print_table_name(file, entry);
1513 lf_printf(file, ";\n");
1514 lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n",
1515 entry->opcode->first, entry->opcode->last);
1516 lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n");
1517 lf_printf(file, "while (1) {\n");
1518 lf_indent(file, +2);
1519 {
1520 lf_printf(file, "while (table_entry->mask != 0) {\n");
1521 lf_indent(file, +2);
1522 {
1523 lf_printf(file, "table = ((idecode_table_entry*)\n");
1524 lf_printf(file, " table_entry->function_or_table);\n");
1525 lf_printf(file, "opcode = ((instruction & table_entry->mask)\n");
1526 lf_printf(file, " >> table_entry->shift);\n");
1527 lf_printf(file, "table_entry = table + opcode;\n");
1528 }
1529 lf_indent(file, -2);
1530 lf_printf(file, "}\n");
1531 if (!idecode_cache && can_assume_leaf) {
1532 lf_printf(file, "return (((idecode_semantic*)\n");
1533 lf_printf(file, " table_entry->function_or_table)\n");
1534 lf_printf(file, " (%s));\n", insn_actual);
1535 }
1536 else if (!idecode_cache && !can_assume_leaf) {
1537 lf_printf(file, "if (table_entry->shift == 0)");
1538 lf_printf(file, " return (((idecode_semantic*)\n");
1539 lf_printf(file, " table_entry->function_or_table)\n");
1540 lf_printf(file, " (%s));\n", insn_actual);
1541 }
1542 else if (idecode_cache == 1 && can_assume_leaf) {
1543 lf_printf(file, "ASSERT(!entry->shift);\n");
1544 lf_printf(file, "return ((idecode_semantic*)\n");
1545 lf_printf(file, " table_entry->function_or_table);\n");
1546 }
1547 else if (idecode_cache == 1 && !can_assume_leaf) {
1548 lf_printf(file, "if (table_entry->shift == 0)\n");
1549 lf_printf(file, " return ((idecode_semantic*)\n");
1550 lf_printf(file, " table_entry->function_or_table);\n");
1551 lf_printf(file, "else if (table_entry->shift == -1)\n");
1552 lf_printf(file, " return (((idecode_crack*)\n");
1553 lf_printf(file, " table_entry->function_or_table)\n");
1554 lf_printf(file, " (%s));\n", insn_actual);
1555 }
1556 else {
1557 lf_printf(file, "if (table_entry->shift == 0)\n");
1558 lf_printf(file, " return (((idecode_crack*)\n");
1559 lf_printf(file, " table_entry->function_or_table)\n");
1560 lf_printf(file, " (%s));\n", cache_idecode_actual);
1561 }
1562 if (!can_assume_leaf) {
1563 lf_printf(file, "opcode = (instruction & table_entry->shift) != 0;\n");
1564 lf_printf(file, "table = ((idecode_table_entry*)\n");
1565 lf_printf(file, " table_entry->function_or_table);\n");
1566 lf_printf(file, "table_entry = table + opcode;\n");
1567 }
1568 }
1569 lf_indent(file, -2);
1570 lf_printf(file, "}\n");
1571 }
1572 lf_indent(file, -2);
1573 lf_printf(file, "}\n");
1574 }
1575
1576
1577 void
1578 lf_print_my_prefix(lf *file,
1579 file_table_entry *file_entry)
1580 {
1581 lf_printf(file, "const char *const my_prefix = \n");
1582 lf_printf(file, " \"%s:%s:%d:cache\";\n",
1583 file_entry->file_name,
1584 file_entry->fields[insn_name],
1585 file_entry->line_nr);
1586 }
1587
1588
1589 void
1590 lf_print_ptrace(lf *file)
1591 {
1592 lf_printf(file, "\n");
1593 lf_putstr(file, "ITRACE(trace_semantics, (\"cia=0x%x\\n\", cia));\n");
1594 }
1595
1596
1597 /****************************************************************/
1598
1599 typedef void leaf_handler
1600 (insn_table *entry,
1601 void *data,
1602 int depth);
1603 typedef void padding_handler
1604 (insn_table *table,
1605 void *data,
1606 int depth,
1607 int opcode_nr);
1608
1609
1610 void
1611 insn_table_traverse_tree(insn_table *table,
1612 void *data,
1613 int depth,
1614 leaf_handler *start,
1615 leaf_handler *leaf,
1616 leaf_handler *end,
1617 padding_handler *padding)
1618 {
1619 insn_table *entry;
1620 int entry_nr;
1621
1622 ASSERT(table != NULL
1623 && table->opcode != NULL
1624 && table->nr_entries > 0
1625 && table->entries != 0);
1626
1627 if (start != NULL && depth >= 0)
1628 start(table, data, depth);
1629
1630 for (entry_nr = 0, entry = table->entries;
1631 entry_nr < (table->opcode->is_boolean
1632 ? 2
1633 : (1 << (table->opcode->last - table->opcode->first + 1)));
1634 entry_nr ++) {
1635 if (entry == NULL
1636 || (!table->opcode->is_boolean
1637 && entry_nr < entry->opcode_nr)) {
1638 if (padding != NULL && depth >= 0)
1639 padding(table, data, depth, entry_nr);
1640 }
1641 else {
1642 ASSERT(entry != NULL && (entry->opcode_nr == entry_nr
1643 || table->opcode->is_boolean));
1644 if (entry->opcode != NULL && depth != 0) {
1645 insn_table_traverse_tree(entry, data, depth+1,
1646 start, leaf, end, padding);
1647 }
1648 else if (depth >= 0) {
1649 if (leaf != NULL)
1650 leaf(entry, data, depth);
1651 }
1652 entry = entry->sibling;
1653 }
1654 }
1655 if (end != NULL && depth >= 0)
1656 end(table, data, depth);
1657 }
1658
1659
1660 typedef void insn_handler
1661 (insn_table *table,
1662 void *data,
1663 insn *instruction);
1664
1665 void
1666 insn_table_traverse_insn(insn_table *table,
1667 void *data,
1668 insn_handler *leaf)
1669 {
1670 insn *instruction;
1671 for (instruction = table->insns;
1672 instruction != NULL;
1673 instruction = instruction->next) {
1674 leaf(table, data, instruction);
1675 }
1676 }
1677
1678
1679 void
1680 update_depth(insn_table *entry,
1681 void *data,
1682 int depth)
1683 {
1684 int *max_depth = (int*)data;
1685 if (*max_depth < depth)
1686 *max_depth = depth;
1687 }
1688
1689
1690 int
1691 insn_table_depth(insn_table *table)
1692 {
1693 int depth = 0;
1694 insn_table_traverse_tree(table,
1695 &depth,
1696 1,
1697 NULL, /*start*/
1698 update_depth,
1699 NULL, /*end*/
1700 NULL); /*padding*/
1701 return depth;
1702 }
1703
1704
1705 /****************************************************************/
1706
1707 void
1708 dump_traverse_start(insn_table *table,
1709 void *data,
1710 int depth)
1711 {
1712 dumpf(depth*2, "(%d\n", table->opcode_nr);
1713 }
1714
1715 void
1716 dump_traverse_leaf(insn_table *entry,
1717 void *data,
1718 int depth)
1719 {
1720 ASSERT(entry->nr_entries == 0
1721 && entry->nr_insn == 1
1722 && entry->opcode == NULL);
1723 dumpf(depth*2, ".%d %s\n", entry->opcode_nr,
1724 entry->insns->file_entry->fields[insn_format]);
1725 }
1726
1727 void
1728 dump_traverse_end(insn_table *table,
1729 void *data,
1730 int depth)
1731 {
1732 dumpf(depth*2, ")\n");
1733 }
1734
1735 void
1736 dump_traverse_padding(insn_table *table,
1737 void *data,
1738 int depth,
1739 int opcode_nr)
1740 {
1741 dumpf(depth*2, ".<%d>\n", opcode_nr);
1742 }
1743
1744
1745 void
1746 dump_traverse(insn_table *table)
1747 {
1748 insn_table_traverse_tree(table, NULL, 1,
1749 dump_traverse_start,
1750 dump_traverse_leaf,
1751 dump_traverse_end,
1752 dump_traverse_padding);
1753 }
1754
1755
1756 /****************************************************************/
1757
1758
1759 void
1760 semantics_h_print_function(lf *file,
1761 insn *instruction,
1762 insn_bits *expanded_bits)
1763 {
1764 lf_printf(file, "\n");
1765 lf_printf(file, "INLINE_SEMANTICS unsigned_word ");
1766 lf_print_function_name(file,
1767 instruction,
1768 expanded_bits,
1769 function_name_prefix_semantics);
1770 lf_printf(file, "\n(%s);\n",
1771 idecode_cache > 1 ? cache_insn_formal : insn_formal);
1772 }
1773
1774
1775 void
1776 semantics_h_leaf(insn_table *entry,
1777 void *data,
1778 int depth)
1779 {
1780 lf *file = (lf*)data;
1781 ASSERT(entry->nr_insn == 1);
1782 semantics_h_print_function(file, entry->insns, entry->expanded_bits);
1783 }
1784
1785 void
1786 semantics_h_insn(insn_table *entry,
1787 void *data,
1788 insn *instruction)
1789 {
1790 lf *file = (lf*)data;
1791 semantics_h_print_function(file, instruction, NULL);
1792 }
1793
1794
1795 void
1796 gen_semantics_h(insn_table *table, lf *file)
1797 {
1798
1799 lf_print_copyleft(file);
1800 lf_printf(file, "\n");
1801 lf_printf(file, "#ifndef _SEMANTICS_H_\n");
1802 lf_printf(file, "#define _SEMANTICS_H_\n");
1803 lf_printf(file, "\n");
1804 lf_printf(file, "#ifndef INLINE_SEMANTICS\n");
1805 lf_printf(file, "#define INLINE_SEMANTICS\n");
1806 lf_printf(file, "#endif\n");
1807 lf_printf(file, "\n");
1808 lf_printf(file, "\n");
1809
1810 if (idecode_expand_semantics)
1811 insn_table_traverse_tree(table,
1812 file,
1813 1,
1814 NULL, /* start */
1815 semantics_h_leaf, /* leaf */
1816 NULL, /* end */
1817 NULL); /* padding */
1818 else
1819 insn_table_traverse_insn(table,
1820 file,
1821 semantics_h_insn);
1822
1823 lf_printf(file, "\n");
1824 lf_printf(file, "#endif /* _SEMANTICS_H_ */\n");
1825
1826 }
1827
1828 /****************************************************************/
1829
1830 typedef struct _icache_tree icache_tree;
1831 struct _icache_tree {
1832 char *name;
1833 icache_tree *next;
1834 icache_tree *children;
1835 };
1836
1837 icache_tree *
1838 icache_tree_new()
1839 {
1840 icache_tree *new_tree = (icache_tree*)zmalloc(sizeof(icache_tree));
1841 ASSERT(new_tree != NULL);
1842 return new_tree;
1843 }
1844
1845 icache_tree *
1846 icache_tree_insert(icache_tree *tree,
1847 char *name)
1848 {
1849 icache_tree *new_tree;
1850 /* find it */
1851 icache_tree **ptr_to_cur_tree = &tree->children;
1852 icache_tree *cur_tree = *ptr_to_cur_tree;
1853 while (cur_tree != NULL
1854 && strcmp(cur_tree->name, name) < 0) {
1855 ptr_to_cur_tree = &cur_tree->next;
1856 cur_tree = *ptr_to_cur_tree;
1857 }
1858 ASSERT(cur_tree == NULL
1859 || strcmp(cur_tree->name, name) >= 0);
1860 /* already in the tree */
1861 if (cur_tree != NULL
1862 && strcmp(cur_tree->name, name) == 0)
1863 return cur_tree;
1864 /* missing, insert it */
1865 ASSERT(cur_tree == NULL
1866 || strcmp(cur_tree->name, name) > 0);
1867 new_tree = icache_tree_new();
1868 new_tree->name = name;
1869 new_tree->next = cur_tree;
1870 *ptr_to_cur_tree = new_tree;
1871 return new_tree;
1872 }
1873
1874
1875 icache_tree *
1876 insn_table_cache_fields(insn_table *table)
1877 {
1878 icache_tree *tree = icache_tree_new();
1879 insn *instruction;
1880 for (instruction = table->insns;
1881 instruction != NULL;
1882 instruction = instruction->next) {
1883 insn_field *field;
1884 icache_tree *form =
1885 icache_tree_insert(tree,
1886 instruction->file_entry->fields[insn_form]);
1887 for (field = instruction->fields->first;
1888 field != NULL;
1889 field = field->next) {
1890 if (field->is_string)
1891 icache_tree_insert(form, field->val_string);
1892 }
1893 }
1894 return tree;
1895 }
1896
1897
1898
1899 void
1900 gen_icache_h(icache_tree *tree,
1901 lf *file)
1902 {
1903 lf_print_copyleft(file);
1904 lf_printf(file, "\n");
1905 lf_printf(file, "#ifndef _ICACHE_H_\n");
1906 lf_printf(file, "#define _ICACHE_H_\n");
1907 lf_printf(file, "\n");
1908 lf_printf(file, "#ifndef INLINE_ICACHE\n");
1909 lf_printf(file, "#define INLINE_ICACHE\n");
1910 lf_printf(file, "#endif\n");
1911 lf_printf(file, "\n");
1912 lf_printf(file, "\n");
1913
1914 /* create an instruction cache if being used */
1915 if (idecode_cache) {
1916 lf_printf(file, "typedef struct _idecode_cache {\n");
1917 lf_printf(file, " unsigned_word address;\n");
1918 lf_printf(file, " void *semantic;\n");
1919 if (idecode_cache == 1) {
1920 lf_printf(file, " instruction_word instruction;\n");
1921 }
1922 else {
1923 icache_tree *form;
1924 lf_printf(file, " union {\n");
1925 for (form = tree->children;
1926 form != NULL;
1927 form = form->next) {
1928 icache_tree *field;
1929 lf_printf(file, " struct {\n");
1930 for (field = form->children;
1931 field != NULL;
1932 field = field->next) {
1933 extraction_rules *rule;
1934 int found_rule = 0;
1935 for (rule = cachable_values;
1936 rule->valid;
1937 rule++) {
1938 if (strcmp(field->name, rule->old_name) == 0) {
1939 found_rule = 1;
1940 if (rule->new_name != NULL)
1941 lf_printf(file, " %s %s; /* %s */\n",
1942 rule->type == NULL ? "unsigned" : rule->type,
1943 rule->new_name, rule->old_name);
1944 }
1945 }
1946 if (!found_rule)
1947 lf_printf(file, " unsigned %s;\n", field->name);
1948 }
1949 lf_printf(file, " } %s;\n", form->name);
1950 }
1951 lf_printf(file, " } crack;\n");
1952 }
1953 lf_printf(file, "} idecode_cache;\n");
1954 }
1955
1956 /* define various fields according to the cache */
1957 if (idecode_cache <= 1) {
1958 extraction_rules *rule;
1959 lf_printf(file, "\n");
1960 for (rule = cachable_values;
1961 rule->valid;
1962 rule++) {
1963 if (rule->expression != NULL)
1964 lf_printf(file, "#define %s %s\n",
1965 rule->new_name, rule->expression);
1966 }
1967 }
1968
1969 lf_printf(file, "\n");
1970 lf_printf(file, "#endif /* _ICACHE_H_ */\n");
1971 }
1972
1973
1974
1975
1976 /****************************************************************/
1977
1978
1979 void
1980 lf_print_c_extraction(lf *file,
1981 insn *instruction,
1982 char *field_name,
1983 char *field_type,
1984 char *field_expression,
1985 insn_field *cur_field,
1986 insn_bits *bits,
1987 int get_value_from_cache,
1988 int put_value_in_cache)
1989 {
1990 ASSERT(field_name != NULL);
1991 if (bits != NULL
1992 && (!bits->opcode->is_boolean || bits->value == 0)
1993 && strcmp(field_name, cur_field->val_string) == 0) {
1994 ASSERT(bits->field == cur_field);
1995 ASSERT(field_type == NULL);
1996 lf_print_c_line_nr(file, instruction->file_entry);
1997 lf_printf(file, "const unsigned %s = ",
1998 field_name);
1999 if (bits->opcode->last < bits->field->last)
2000 lf_printf(file, "%d;\n",
2001 bits->value << (bits->field->last - bits->opcode->last));
2002 else
2003 lf_printf(file, "%d;\n", bits->value);
2004 }
2005 else {
2006 /* put the field in the local variable */
2007 lf_print_c_line_nr(file, instruction->file_entry);
2008 lf_printf(file, "%s const %s = ",
2009 field_type == NULL ? "unsigned" : field_type,
2010 field_name);
2011 /* getting it from the cache */
2012 if (get_value_from_cache || put_value_in_cache) {
2013 lf_printf(file, "cache_entry->crack.%s.%s",
2014 instruction->file_entry->fields[insn_form],
2015 field_name);
2016 if (put_value_in_cache) /* also put it in the cache? */
2017 lf_printf(file, " = ");
2018 }
2019 if (!get_value_from_cache) {
2020 if (strcmp(field_name, cur_field->val_string) == 0)
2021 lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
2022 cur_field->first, cur_field->last);
2023 else if (field_expression != NULL)
2024 lf_printf(file, "%s", field_expression);
2025 else
2026 lf_printf(file, "eval_%s", field_name);
2027 }
2028 lf_printf(file, ";\n");
2029 }
2030 }
2031
2032
2033 void
2034 lf_print_c_extractions(lf *file,
2035 insn *instruction,
2036 insn_bits *expanded_bits,
2037 int get_value_from_cache,
2038 int put_value_in_cache)
2039 {
2040 insn_field *cur_field;
2041
2042 /* extract instruction fields */
2043 lf_printf(file, "/* extraction: %s */\n",
2044 instruction->file_entry->fields[insn_format]);
2045
2046 for (cur_field = instruction->fields->first;
2047 cur_field->first < insn_size;
2048 cur_field = cur_field->next) {
2049 if (cur_field->is_string) {
2050 insn_bits *bits;
2051 int found_rule = 0;
2052 /* find any corresponding value */
2053 for (bits = expanded_bits;
2054 bits != NULL;
2055 bits = bits->last) {
2056 if (bits->field == cur_field)
2057 break;
2058 }
2059 /* try the cache rule table for what to do */
2060 if (get_value_from_cache || put_value_in_cache) {
2061 extraction_rules *field_rule;
2062 for (field_rule = cachable_values;
2063 field_rule->valid;
2064 field_rule++) {
2065 if (strcmp(cur_field->val_string, field_rule->old_name) == 0) {
2066 found_rule = 1;
2067 if (field_rule->valid > 1 && put_value_in_cache)
2068 lf_print_c_extraction(file,
2069 instruction,
2070 field_rule->new_name,
2071 field_rule->type,
2072 field_rule->expression,
2073 cur_field,
2074 bits,
2075 0,
2076 0);
2077 else if (field_rule->valid == 1)
2078 lf_print_c_extraction(file,
2079 instruction,
2080 field_rule->new_name,
2081 field_rule->type,
2082 field_rule->expression,
2083 cur_field,
2084 bits,
2085 get_value_from_cache,
2086 put_value_in_cache);
2087 }
2088 }
2089 }
2090 if (found_rule == 0)
2091 lf_print_c_extraction(file,
2092 instruction,
2093 cur_field->val_string,
2094 0,
2095 0,
2096 cur_field,
2097 bits,
2098 get_value_from_cache,
2099 put_value_in_cache);
2100 /* if any (XXX == 0), output a corresponding test */
2101 if (instruction->file_entry->annex != NULL) {
2102 char *field_name = cur_field->val_string;
2103 char *is_0_ptr = instruction->file_entry->annex;
2104 int field_len = strlen(field_name);
2105 if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) {
2106 is_0_ptr += field_len;
2107 while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) {
2108 if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0
2109 && !isalpha(is_0_ptr[ - field_len - 1])) {
2110 lf_print_c_line_nr(file, instruction->file_entry);
2111 lf_printf(file, "const unsigned %s_is_0 = (", field_name);
2112 if (bits != NULL)
2113 lf_printf(file, "%d", bits->value);
2114 else
2115 lf_printf(file, "%s", field_name);
2116 lf_printf(file, " == 0);\n");
2117 break;
2118 }
2119 is_0_ptr += strlen("_is_0");
2120 }
2121 }
2122 }
2123 /* any thing else ... */
2124 }
2125 }
2126 lf_print_file_line_nr(file);
2127 }
2128
2129 void
2130 lf_print_c_validate(lf *file,
2131 insn *instruction,
2132 opcode_field *opcodes)
2133 {
2134 unsigned check_mask = 0;
2135 unsigned check_val = 0;
2136 insn_field *field;
2137 opcode_field *opcode;
2138
2139 for (field = instruction->fields->first;
2140 field->first < insn_size;
2141 field = field->next) {
2142
2143 check_mask <<= field->width;
2144 check_val <<= field->width;
2145
2146 /* is it a constant that could need validating? */
2147 if (!field->is_int && !field->is_slash)
2148 continue;
2149
2150 /* has it been checked by a table? */
2151 for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) {
2152 if (field->first >= opcode->first
2153 && field->last <= opcode->last)
2154 break;
2155 }
2156 if (opcode != NULL)
2157 continue;
2158
2159 check_mask |= (1 << field->width)-1;
2160 check_val |= field->val_int;
2161 }
2162
2163 /* if any bits not checked by opcode tables, output code to check them */
2164 if (!it_is("illegal", instruction->file_entry->fields[insn_flags])
2165 && check_mask) {
2166 lf_printf(file, "\n");
2167 lf_printf(file, "/* validate: %s */\n",
2168 instruction->file_entry->fields[insn_format]);
2169 lf_printf(file, "if ((instruction & 0x%x) != 0x%x) {\n",
2170 check_mask, check_val);
2171 switch (idecode_cache) {
2172 case 0:
2173 lf_printf(file, " return semantic_illegal(%s);\n", insn_actual);
2174 break;
2175 case 1:
2176 lf_printf(file, " return semantic_illegal;\n");
2177 break;
2178 default:
2179 lf_printf(file, " return idecode_illegal(%s);\n", cache_idecode_actual);
2180 }
2181 lf_printf(file, "}\n");
2182 }
2183
2184 }
2185
2186
2187 void
2188 lf_print_c_cracker(lf *file,
2189 insn *instruction,
2190 insn_bits *expanded_bits,
2191 opcode_field *opcodes)
2192 {
2193
2194 /* function header */
2195 lf_printf(file, "{\n");
2196 lf_indent(file, +2);
2197
2198 lf_print_my_prefix(file,
2199 instruction->file_entry);
2200
2201 lf_print_ptrace(file);
2202
2203 lf_print_c_validate(file, instruction, opcodes);
2204
2205 lf_printf(file, "\n");
2206 lf_printf(file, "{\n");
2207 lf_indent(file, +2);
2208 lf_print_c_extractions(file,
2209 instruction,
2210 expanded_bits,
2211 0/*get_value_from_cache*/,
2212 1/*put_value_in_cache*/);
2213 lf_indent(file, -2);
2214 lf_printf(file, "}\n");
2215
2216 /* return the function propper (main sorts this one out) */
2217 lf_printf(file, "\n");
2218 lf_printf(file, "/* semantic routine */\n");
2219 lf_print_c_line_nr(file, instruction->file_entry);
2220 lf_printf(file, "return ");
2221 lf_print_function_name(file,
2222 instruction,
2223 expanded_bits,
2224 function_name_prefix_semantics);
2225 lf_printf(file, ";\n");
2226
2227 lf_print_file_line_nr(file);
2228 lf_indent(file, -2);
2229 lf_printf(file, "}\n");
2230 }
2231
2232
2233 void
2234 lf_print_c_semantic(lf *file,
2235 insn *instruction,
2236 insn_bits *expanded_bits,
2237 opcode_field *opcodes)
2238 {
2239
2240 lf_printf(file, "{\n");
2241 lf_indent(file, +2);
2242
2243 lf_print_my_prefix(file,
2244 instruction->file_entry);
2245 lf_putstr(file, insn_local);
2246 lf_printf(file, "\n");
2247
2248 lf_printf(file, "\n");
2249 lf_print_c_extractions(file,
2250 instruction,
2251 expanded_bits,
2252 idecode_cache > 1/*get_value_from_cache*/,
2253 0/*put_value_in_cache*/);
2254
2255 lf_print_ptrace(file);
2256
2257 /* generate code to check previously unchecked fields */
2258 if (idecode_cache < 2)
2259 lf_print_c_validate(file, instruction, opcodes);
2260
2261 /* if OEA and a floating point generate a check that fp is enabled */
2262 if (it_is("f", instruction->file_entry->fields[insn_flags])) {
2263 lf_printf(file, "\n");
2264 lf_printf(file, "/* verify FP is enabled */\n");
2265 lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n");
2266 lf_printf(file, " floating_point_unavailable_interrupt(processor, cia);\n");
2267 }
2268
2269 /* generate the code (or at least something */
2270 if (instruction->file_entry->annex != NULL) {
2271 /* true code */
2272 lf_printf(file, "\n");
2273 lf_print_c_line_nr(file, instruction->file_entry);
2274 lf_printf(file, "{\n");
2275 lf_indent(file, +2);
2276 lf_print_c_code(file, instruction->file_entry->annex);
2277 lf_indent(file, -2);
2278 lf_printf(file, "}\n");
2279 lf_print_file_line_nr(file);
2280 }
2281 else if (it_is("nop", instruction->file_entry->fields[insn_flags])) {
2282 lf_print_file_line_nr(file);
2283 }
2284 else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
2285 /* unimplemented floating point - call for assistance */
2286 lf_printf(file, "\n");
2287 lf_print_c_line_nr(file, instruction->file_entry);
2288 lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
2289 lf_print_file_line_nr(file);
2290 }
2291 else {
2292 /* abort so it is implemented now */
2293 lf_print_c_line_nr(file, instruction->file_entry);
2294 lf_putstr(file, "error(\"%s: unimplemented, cia=0x%x\\n\", my_prefix, cia);\n");
2295 lf_print_file_line_nr(file);
2296 lf_printf(file, "\n");
2297 }
2298
2299 /* the function footer */
2300 lf_printf(file, "return nia;\n");
2301 lf_indent(file, -2);
2302 lf_printf(file, "}\n");
2303 }
2304
2305 void
2306 lf_print_c_semantic_function(lf *file,
2307 insn *instruction,
2308 insn_bits *expanded_bits,
2309 opcode_field *opcodes)
2310 {
2311
2312 /* build the semantic routine to execute the instruction */
2313
2314 /* function header */
2315 lf_printf(file, "\n");
2316 lf_printf(file, "INLINE_SEMANTICS unsigned_word\n");
2317 lf_print_function_name(file,
2318 instruction,
2319 expanded_bits,
2320 function_name_prefix_semantics);
2321 lf_printf(file, "\n(%s)\n",
2322 idecode_cache > 1 ? cache_insn_formal : insn_formal);
2323
2324 lf_print_c_semantic(file,
2325 instruction,
2326 expanded_bits,
2327 opcodes);
2328
2329 }
2330
2331
2332 void
2333 semantics_c_leaf(insn_table *entry,
2334 void *data,
2335 int depth)
2336 {
2337 lf *file = (lf*)data;
2338 ASSERT(entry->nr_insn == 1
2339 && entry->opcode == NULL
2340 && entry->parent != NULL
2341 && entry->parent->opcode != NULL);
2342 lf_print_c_semantic_function(file,
2343 entry->insns,
2344 entry->expanded_bits,
2345 entry->parent->opcode);
2346 }
2347
2348 void
2349 semantics_c_insn(insn_table *table,
2350 void *data,
2351 insn *instruction)
2352 {
2353 lf *file = (lf*)data;
2354 lf_print_c_semantic_function(file, instruction,
2355 NULL, NULL);
2356 }
2357
2358
2359
2360 void
2361 gen_semantics_c(insn_table *table, lf *file)
2362 {
2363 lf_print_copyleft(file);
2364 lf_printf(file, "\n");
2365 lf_printf(file, "#ifndef _SEMANTICS_C_\n");
2366 lf_printf(file, "#define _SEMANTICS_C_\n");
2367 lf_printf(file, "\n");
2368 lf_printf(file, "#ifndef STATIC_INLINE_SEMANTICS\n");
2369 lf_printf(file, "#define STATIC_INLINE_SEMANTICS STATIC_INLINE\n");
2370 lf_printf(file, "#endif\n");
2371 lf_printf(file, "\n");
2372 lf_printf(file, "#include \"cpu.h\"\n");
2373 lf_printf(file, "#include \"idecode.h\"\n");
2374 lf_printf(file, "#include \"semantics.h\"\n");
2375 lf_printf(file, "\n");
2376
2377 if (idecode_expand_semantics)
2378 insn_table_traverse_tree(table,
2379 file,
2380 1,
2381 NULL, /* start */
2382 semantics_c_leaf,
2383 NULL, /* end */
2384 NULL); /* padding */
2385 else
2386 insn_table_traverse_insn(table,
2387 file,
2388 semantics_c_insn);
2389
2390 lf_printf(file, "\n");
2391 lf_printf(file, "#endif /* _SEMANTICS_C_ */\n");
2392 }
2393
2394
2395 /****************************************************************/
2396
2397 void
2398 gen_idecode_h(insn_table *table, lf *file)
2399 {
2400 lf_print_copyleft(file);
2401 lf_printf(file, "\n");
2402 lf_printf(file, "#ifndef _IDECODE_H_\n");
2403 lf_printf(file, "#define _IDECODE_H_\n");
2404 lf_printf(file, "\n");
2405 lf_printf(file, "#ifndef INLINE_IDECODE\n");
2406 lf_printf(file, "#define INLINE_IDECODE\n");
2407 lf_printf(file, "#endif\n");
2408 lf_printf(file, "\n");
2409 lf_printf(file, "#include \"idecode_insn.h\"\n");
2410 lf_printf(file, "#include \"idecode_expression.h\"\n");
2411 lf_printf(file, "#include \"idecode_fields.h\"\n");
2412 lf_printf(file, "#include \"idecode_branch.h\"\n");
2413 lf_printf(file, "\n");
2414 lf_printf(file, "#include \"icache.h\"\n");
2415 lf_printf(file, "\n");
2416 lf_printf(file, "typedef unsigned_word idecode_semantic\n(%s);\n",
2417 idecode_cache < 2 ? insn_formal : cache_insn_formal);
2418 lf_printf(file, "\n");
2419 if (!idecode_cache)
2420 lf_printf(file, "INLINE_IDECODE unsigned_word idecode_issue\n(%s);\n",
2421 insn_formal);
2422 else if (idecode_cache)
2423 lf_printf(file, "INLINE_IDECODE idecode_semantic *idecode\n(%s);\n",
2424 idecode_cache == 1 ? insn_formal : cache_idecode_formal);
2425 lf_printf(file, "\n");
2426 lf_printf(file, "#endif /* _IDECODE_H_ */\n");
2427 }
2428
2429
2430 /****************************************************************/
2431
2432
2433 void
2434 idecode_table_start(insn_table *table,
2435 void *data,
2436 int depth)
2437 {
2438 lf *file = (lf*)data;
2439 ASSERT(depth == 0);
2440 /* start of the table */
2441 if (!table->opcode_rule->use_switch) {
2442 lf_printf(file, "\n");
2443 lf_printf(file, "static idecode_table_entry ");
2444 lf_print_table_name(file, table);
2445 lf_printf(file, "[] = {\n");
2446 }
2447 }
2448
2449 void
2450 idecode_table_leaf(insn_table *entry,
2451 void *data,
2452 int depth)
2453 {
2454 lf *file = (lf*)data;
2455 ASSERT(entry->parent != NULL);
2456 ASSERT(depth == 0);
2457
2458 /* add an entry to the table */
2459 if (!entry->parent->opcode_rule->use_switch) {
2460 if (entry->opcode == NULL) {
2461 /* table leaf entry */
2462 lf_printf(file, " /*%d*/ { 0, 0, ", entry->opcode_nr);
2463 lf_print_function_name(file,
2464 entry->insns,
2465 entry->expanded_bits,
2466 (idecode_cache < 2
2467 ? function_name_prefix_semantics
2468 : function_name_prefix_idecode));
2469 lf_printf(file, " },\n");
2470 }
2471 else if (entry->opcode_rule->use_switch) {
2472 /* table calling switch statement */
2473 lf_printf(file, " /*%d*/ { -1, 0, ",
2474 entry->opcode_nr);
2475 lf_print_table_name(file, entry);
2476 lf_printf(file, " },\n");
2477 }
2478 else {
2479 /* table `calling' another table */
2480 lf_printf(file, " /*%d*/ { ", entry->opcode_nr);
2481 if (entry->opcode->is_boolean)
2482 lf_printf(file, "MASK32(%d,%d), 0, ",
2483 entry->opcode->first, entry->opcode->last);
2484 else
2485 lf_printf(file, "%d, MASK32(%d,%d), ",
2486 insn_size - entry->opcode->last - 1,
2487 entry->opcode->first, entry->opcode->last);
2488 lf_print_table_name(file, entry);
2489 lf_printf(file, " },\n");
2490 }
2491 }
2492 }
2493
2494 void
2495 idecode_table_end(insn_table *table,
2496 void *data,
2497 int depth)
2498 {
2499 lf *file = (lf*)data;
2500 ASSERT(depth == 0);
2501
2502 if (!table->opcode_rule->use_switch) {
2503 lf_printf(file, "};\n");
2504 }
2505 }
2506
2507 void
2508 idecode_table_padding(insn_table *table,
2509 void *data,
2510 int depth,
2511 int opcode_nr)
2512 {
2513 lf *file = (lf*)data;
2514 ASSERT(depth == 0);
2515
2516 if (!table->opcode_rule->use_switch) {
2517 lf_printf(file, " /*%d*/ { 0, 0, %s_illegal },\n",
2518 opcode_nr, idecode_cache > 1 ? "idecode" : "semantic");
2519 }
2520 }
2521
2522
2523 /****************************************************************/
2524
2525
2526 void lf_print_idecode_switch
2527 (lf *file,
2528 insn_table *table);
2529
2530
2531 void
2532 idecode_switch_start(insn_table *table,
2533 void *data,
2534 int depth)
2535 {
2536 lf *file = (lf*)data;
2537 ASSERT(depth == 0);
2538 ASSERT(table->opcode_rule->use_switch);
2539
2540 lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n",
2541 table->opcode->first, table->opcode->last);
2542 }
2543
2544
2545 void
2546 idecode_switch_leaf(insn_table *entry,
2547 void *data,
2548 int depth)
2549 {
2550 lf *file = (lf*)data;
2551 ASSERT(entry->parent != NULL);
2552 ASSERT(depth == 0);
2553 ASSERT(entry->parent->opcode_rule->use_switch);
2554
2555 lf_printf(file, "case %d:\n", entry->opcode_nr);
2556 lf_indent(file, +2);
2557 {
2558 if (entry->opcode == NULL) {
2559 /* switch calling leaf */
2560 lf_printf(file, "return ");
2561 lf_print_function_name(file,
2562 entry->insns,
2563 entry->expanded_bits,
2564 (idecode_cache < 2
2565 ? function_name_prefix_semantics
2566 : function_name_prefix_idecode));
2567 if (!idecode_cache)
2568 lf_printf(file, "(%s);\n", insn_actual);
2569 else if (idecode_cache == 1)
2570 lf_printf(file, ";\n");
2571 else
2572 lf_printf(file, "(%s);\n", cache_idecode_actual);
2573 }
2574 else if (entry->opcode_rule->use_switch) {
2575 /* switch calling switch */
2576 lf_print_idecode_switch(file, entry);
2577 }
2578 else {
2579 /* switch calling table */
2580 lf_printf(file, "return ");
2581 lf_print_idecode_table(file, entry);
2582 }
2583 lf_printf(file, "break;\n");
2584 }
2585 lf_indent(file, -2);
2586 }
2587
2588 lf_print_idecode_switch_illegal(lf *file)
2589 {
2590 switch (idecode_cache) {
2591 case 0:
2592 lf_printf(file, " return semantic_illegal(%s);\n", insn_actual);
2593 break;
2594 case 1:
2595 lf_printf(file, " return semantic_illegal;\n");
2596 break;
2597 default:
2598 lf_printf(file, " return idecode_illegal(%s);\n", cache_idecode_actual);
2599 }
2600 lf_printf(file, " break;\n");
2601 }
2602
2603 void
2604 idecode_switch_end(insn_table *table,
2605 void *data,
2606 int depth)
2607 {
2608 lf *file = (lf*)data;
2609 ASSERT(depth == 0);
2610 ASSERT(table->opcode_rule->use_switch);
2611
2612 if (table->opcode_rule->use_switch == 1) {
2613 lf_printf(file, "default:\n");
2614 lf_print_idecode_switch_illegal(file);
2615 }
2616 lf_printf(file, "}\n");
2617 }
2618
2619 void
2620 idecode_switch_padding(insn_table *table,
2621 void *data,
2622 int depth,
2623 int opcode_nr)
2624 {
2625 lf *file = (lf*)data;
2626
2627 ASSERT(depth == 0);
2628 ASSERT(table->opcode_rule->use_switch);
2629
2630 if (table->opcode_rule->use_switch > 1) {
2631 lf_printf(file, "case %d:\n", opcode_nr);
2632 lf_print_idecode_switch_illegal(file);
2633 }
2634 }
2635
2636
2637 void
2638 lf_print_idecode_switch(lf *file,
2639 insn_table *table)
2640 {
2641 insn_table_traverse_tree(table,
2642 file,
2643 0,
2644 idecode_switch_start,
2645 idecode_switch_leaf,
2646 idecode_switch_end,
2647 idecode_switch_padding);
2648 }
2649
2650
2651 void
2652 idecode_expand_if_switch(insn_table *table,
2653 void *data,
2654 int depth)
2655 {
2656 lf *file = (lf*)data;
2657
2658 if (table->opcode_rule->use_switch
2659 && table->parent != NULL /* don't expand the top one yet */
2660 && !table->parent->opcode_rule->use_switch) {
2661 lf_printf(file, "\n");
2662 lf_printf(file, "STATIC_INLINE_IDECODE void\n");
2663 lf_print_table_name(file, table);
2664 lf_printf(file, "\n(%s)\n",
2665 idecode_cache ? cache_idecode_formal : insn_formal);
2666 lf_printf(file, "{\n");
2667 {
2668 lf_indent(file, +2);
2669 lf_print_idecode_switch(file, table);
2670 lf_indent(file, -2);
2671 }
2672 lf_printf(file, "}\n");
2673 }
2674 }
2675
2676
2677 lf_print_c_cracker_function(lf *file,
2678 insn *instruction,
2679 insn_bits *expanded_bits,
2680 opcode_field *opcodes)
2681 {
2682 /* if needed, generate code to enter this routine into a cache */
2683 lf_printf(file, "\n");
2684 lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
2685 lf_print_function_name(file,
2686 instruction,
2687 expanded_bits,
2688 function_name_prefix_idecode);
2689 lf_printf(file, "\n(%s)\n", cache_idecode_formal);
2690
2691 lf_print_c_cracker(file,
2692 instruction,
2693 expanded_bits,
2694 opcodes);
2695 }
2696
2697 void
2698 idecode_crack_leaf(insn_table *entry,
2699 void *data,
2700 int depth)
2701 {
2702 lf *file = (lf*)data;
2703 ASSERT(entry->nr_insn == 1
2704 && entry->opcode == NULL
2705 && entry->parent != NULL
2706 && entry->parent->opcode != NULL);
2707 lf_print_c_cracker_function(file,
2708 entry->insns,
2709 entry->expanded_bits,
2710 entry->opcode);
2711 }
2712
2713 void
2714 idecode_crack_insn(insn_table *entry,
2715 void *data,
2716 insn *instruction)
2717 {
2718 lf *file = (lf*)data;
2719 lf_print_c_cracker_function(file,
2720 instruction,
2721 NULL,
2722 NULL);
2723 }
2724
2725 /****************************************************************/
2726
2727 gen_idecode_c(insn_table *table, lf *file)
2728 {
2729 int depth;
2730
2731 /* the intro */
2732 lf_print_copyleft(file);
2733 lf_printf(file, "\n");
2734 lf_printf(file, "\n");
2735 lf_printf(file, "#ifndef _IDECODE_C_\n");
2736 lf_printf(file, "#define _IDECODE_C_\n");
2737 lf_printf(file, "\n");
2738 lf_printf(file, "#ifndef STATIC_INLINE_IDECODE\n");
2739 lf_printf(file, "#define STATIC_INLINE_IDECODE STATIC_INLINE\n");
2740 lf_printf(file, "#endif\n");
2741 lf_printf(file, "\n");
2742 lf_printf(file, "#include \"cpu.h\"\n");
2743 lf_printf(file, "#include \"idecode.h\"\n");
2744 lf_printf(file, "#include \"semantics.h\"\n");
2745 lf_printf(file, "\n");
2746 lf_printf(file, "\n");
2747 lf_printf(file, "typedef idecode_semantic *idecode_crack\n(%s);\n",
2748 idecode_cache > 1 ? cache_idecode_formal : insn_formal);
2749 lf_printf(file, "\n");
2750 lf_printf(file, "typedef struct _idecode_table_entry {\n");
2751 lf_printf(file, " unsigned shift;\n");
2752 lf_printf(file, " unsigned mask;\n");
2753 lf_printf(file, " void *function_or_table;\n");
2754 lf_printf(file, "} idecode_table_entry;\n");
2755 lf_printf(file, "\n");
2756 lf_printf(file, "\n");
2757
2758 /* output cracking functions where needed */
2759 if (idecode_cache > 1) {
2760 if (idecode_expand_semantics)
2761 insn_table_traverse_tree(table,
2762 file,
2763 1,
2764 NULL,
2765 idecode_crack_leaf,
2766 NULL,
2767 NULL);
2768 else
2769 insn_table_traverse_insn(table,
2770 file,
2771 idecode_crack_insn);
2772 }
2773
2774
2775 /* output tables where needed */
2776 for (depth = insn_table_depth(table);
2777 depth > 0;
2778 depth--) {
2779 insn_table_traverse_tree(table,
2780 file,
2781 1-depth,
2782 idecode_table_start,
2783 idecode_table_leaf,
2784 idecode_table_end,
2785 idecode_table_padding);
2786 }
2787
2788 /* output switch functions where needed */
2789 insn_table_traverse_tree(table,
2790 file,
2791 1,
2792 idecode_expand_if_switch, /* START */
2793 NULL, NULL, NULL);
2794
2795 /* output the main idecode routine */
2796 lf_printf(file, "\n");
2797 if (!idecode_cache)
2798 lf_printf(file, "INLINE_IDECODE unsigned_word\nidecode_issue\n(%s)\n",
2799 insn_formal);
2800 else if (idecode_cache)
2801 lf_printf(file, "INLINE_IDECODE idecode_semantic *\nidecode\n(%s)\n",
2802 idecode_cache == 1 ? insn_formal : cache_idecode_formal);
2803 lf_printf(file, "{\n");
2804 lf_indent(file, +2);
2805 if (!idecode_cache)
2806 lf_printf(file, "cpu_increment_number_of_insns (processor);\n");
2807 if (table->opcode_rule->use_switch)
2808 lf_print_idecode_switch(file, table);
2809 else
2810 lf_print_idecode_table(file, table);
2811 lf_indent(file, -2);
2812 lf_printf(file, "}\n");
2813 lf_printf(file, "\n");
2814 lf_printf(file, "#endif\n");
2815 }
2816
2817
2818 /****************************************************************/
2819
2820
2821 typedef enum {
2822 spreg_name,
2823 spreg_reg_nr,
2824 spreg_readonly,
2825 spreg_length,
2826 nr_spreg_registers = file_table_max_fields
2827 } spreg_fields;
2828
2829 typedef struct _spreg_table_entry spreg_table_entry;
2830 struct _spreg_table_entry {
2831 char *name;
2832 int spreg_nr;
2833 int is_readonly;
2834 int length;
2835 file_table_entry *entry;
2836 spreg_table_entry *next;
2837 };
2838
2839 typedef struct _spreg_table spreg_table;
2840 struct _spreg_table {
2841 spreg_table_entry *sprs;
2842 };
2843
2844 spreg_table_entry *
2845 spreg_table_entry_new()
2846 {
2847 spreg_table_entry *new_entry =
2848 (spreg_table_entry*)zmalloc(sizeof(spreg_table_entry));
2849 ASSERT(new_entry != NULL);
2850 return new_entry;
2851 }
2852
2853 spreg_table *
2854 spreg_table_new()
2855 {
2856 spreg_table *new_table = (spreg_table*)zmalloc(sizeof(spreg_table));
2857 ASSERT(new_table != NULL);
2858 return new_table;
2859 }
2860
2861 void
2862 spreg_table_insert(spreg_table *table, file_table_entry *entry)
2863 {
2864 /* create a new spr entry */
2865 spreg_table_entry *new_spr = spreg_table_entry_new();
2866 new_spr->next = NULL;
2867 new_spr->entry = entry;
2868 new_spr->spreg_nr = atoi(entry->fields[spreg_reg_nr]);
2869 new_spr->is_readonly = (entry->fields[spreg_readonly]
2870 ? atoi(entry->fields[spreg_readonly])
2871 : 0);
2872 new_spr->length = atoi(entry->fields[spreg_length]);
2873 new_spr->name = (char*)zmalloc(strlen(entry->fields[spreg_name]) + 1);
2874 ASSERT(new_spr->name != NULL);
2875 {
2876 int i;
2877 for (i = 0; entry->fields[spreg_name][i] != '\0'; i++) {
2878 if (isupper(entry->fields[spreg_name][i]))
2879 new_spr->name[i] = tolower(entry->fields[spreg_name][i]);
2880 else
2881 new_spr->name[i] = entry->fields[spreg_name][i];
2882 }
2883 }
2884
2885 /* insert, by spreg_nr order */
2886 {
2887 spreg_table_entry **ptr_to_spreg_entry = &table->sprs;
2888 spreg_table_entry *spreg_entry = *ptr_to_spreg_entry;
2889 while (spreg_entry != NULL && spreg_entry->spreg_nr < new_spr->spreg_nr) {
2890 ptr_to_spreg_entry = &spreg_entry->next;
2891 spreg_entry = *ptr_to_spreg_entry;
2892 }
2893 ASSERT(spreg_entry == NULL || spreg_entry->spreg_nr != new_spr->spreg_nr);
2894 *ptr_to_spreg_entry = new_spr;
2895 new_spr->next = spreg_entry;
2896 }
2897
2898 }
2899
2900
2901 spreg_table *
2902 spreg_table_load(char *file_name)
2903 {
2904 file_table *file = file_table_open(file_name);
2905 spreg_table *table = spreg_table_new();
2906
2907 {
2908 file_table_entry *entry;
2909 while (entry = file_table_read(file)) {
2910 spreg_table_insert(table, entry);
2911 }
2912 }
2913
2914 return table;
2915 }
2916
2917
2918 /****************************************************************/
2919
2920 char *spreg_attributes[] = {
2921 "is_valid",
2922 "is_readonly",
2923 "name",
2924 "index",
2925 "length",
2926 0
2927 };
2928
2929 void
2930 gen_spreg_h(spreg_table *table, lf *file)
2931 {
2932 spreg_table_entry *entry;
2933 char **attribute;
2934
2935 lf_print_copyleft(file);
2936 lf_printf(file, "\n");
2937 lf_printf(file, "#ifndef _SPREG_H_\n");
2938 lf_printf(file, "#define _SPREG_H_\n");
2939 lf_printf(file, "\n");
2940 lf_printf(file, "#ifndef INLINE_SPREG\n");
2941 lf_printf(file, "#define INLINE_SPREG\n");
2942 lf_printf(file, "#endif\n");
2943 lf_printf(file, "\n");
2944 lf_printf(file, "typedef unsigned_word spreg;\n");
2945 lf_printf(file, "\n");
2946 lf_printf(file, "typedef enum {\n");
2947
2948 for (entry = table->sprs;
2949 entry != NULL ;
2950 entry = entry->next) {
2951 lf_printf(file, " spr_%s = %d,\n", entry->name, entry->spreg_nr);
2952 }
2953
2954 lf_printf(file, " nr_of_sprs = %d\n", nr_of_sprs);
2955 lf_printf(file, "} sprs;\n");
2956 lf_printf(file, "\n");
2957 for (attribute = spreg_attributes;
2958 *attribute != NULL;
2959 attribute++) {
2960 if (strcmp(*attribute, "name") == 0)
2961 lf_printf(file, "INLINE_SPREG char *spr_%s(sprs spr);\n",
2962 *attribute);
2963 else
2964 lf_printf(file, "INLINE_SPREG int spr_%s(sprs spr);\n",
2965 *attribute);
2966 }
2967 lf_printf(file, "\n");
2968 lf_printf(file, "#endif /* _SPREG_H_ */\n");
2969 }
2970
2971
2972 void
2973 gen_spreg_c(spreg_table *table, lf *file)
2974 {
2975 spreg_table_entry *entry;
2976 char **attribute;
2977 int spreg_nr;
2978
2979 lf_print_copyleft(file);
2980 lf_printf(file, "\n");
2981 lf_printf(file, "#ifndef _SPREG_C_\n");
2982 lf_printf(file, "#define _SPREG_C_\n");
2983 lf_printf(file, "\n");
2984 lf_printf(file, "#include \"words.h\"\n");
2985 lf_printf(file, "#include \"spreg.h\"\n");
2986
2987 lf_printf(file, "\n");
2988 lf_printf(file, "typedef struct _spreg_info {\n");
2989 lf_printf(file, " char *name;\n");
2990 lf_printf(file, " int is_valid;\n");
2991 lf_printf(file, " int length;\n");
2992 lf_printf(file, " int is_readonly;\n");
2993 lf_printf(file, " int index;\n");
2994 lf_printf(file, "} spreg_info;\n");
2995 lf_printf(file, "\n");
2996 lf_printf(file, "static spreg_info spr_info[nr_of_sprs+1] = {\n");
2997 entry = table->sprs;
2998 for (spreg_nr = 0; spreg_nr < nr_of_sprs+1; spreg_nr++) {
2999 if (entry == NULL || spreg_nr < entry->spreg_nr)
3000 lf_printf(file, " { 0, 0, 0, 0, %d},\n", spreg_nr);
3001 else {
3002 lf_printf(file, " { \"%s\", %d, %d, %d, spr_%s /*%d*/ },\n",
3003 entry->name, 1, entry->length, entry->is_readonly,
3004 entry->name, entry->spreg_nr);
3005 entry = entry->next;
3006 }
3007 }
3008 lf_printf(file, "};\n");
3009
3010 for (attribute = spreg_attributes;
3011 *attribute != NULL;
3012 attribute++) {
3013 lf_printf(file, "\n");
3014 if (strcmp(*attribute, "name") == 0)
3015 lf_printf(file, "INLINE_SPREG char *\n");
3016 else
3017 lf_printf(file, "INLINE_SPREG int\n");
3018 lf_printf(file, "spr_%s(sprs spr)\n", *attribute);
3019 lf_printf(file, "{\n");
3020 if (spreg_lookup_table
3021 || strcmp(*attribute, "name") == 0
3022 || strcmp(*attribute, "index") == 0)
3023 lf_printf(file, " return spr_info[spr].%s;\n",
3024 *attribute);
3025 else {
3026 spreg_table_entry *entry;
3027 lf_printf(file, " switch (spr) {\n");
3028 for (entry = table->sprs; entry != NULL; entry = entry->next) {
3029 lf_printf(file, " case %d:\n", entry->spreg_nr);
3030 if (strcmp(*attribute, "is_valid") == 0)
3031 lf_printf(file, " return 1;\n");
3032 else if (strcmp(*attribute, "is_readonly") == 0)
3033 lf_printf(file, " return %d;\n", entry->is_readonly);
3034 else if (strcmp(*attribute, "length") == 0)
3035 lf_printf(file, " return %d;\n", entry->length);
3036 else
3037 ASSERT(0);
3038 }
3039 lf_printf(file, " default:\n");
3040 lf_printf(file, " return 0;\n");
3041 lf_printf(file, " }\n");
3042 }
3043 lf_printf(file, "}\n");
3044 }
3045
3046 lf_printf(file, "\n");
3047 lf_printf(file, "#endif /* _SPREG_C_ */\n");
3048 }
3049
3050
3051
3052 /****************************************************************/
3053
3054
3055 int
3056 main(int argc,
3057 char **argv,
3058 char **envp)
3059 {
3060 insn_table *instructions = NULL;
3061 spreg_table *sprs = NULL;
3062 icache_tree *cache_fields = NULL;
3063 int ch;
3064
3065 while ((ch = getopt(argc, argv, "i:I:r:S:s:D:d:P:p:C:")) != -1) {
3066 fprintf(stderr, "\t-%c %s\n", ch, optarg);
3067 switch(ch) {
3068 case 'I':
3069 case 'i':
3070 instructions = insn_table_load_insns(optarg);
3071 fprintf(stderr, "\texpanding ...\n");
3072 insn_table_expand_insns(instructions);
3073 fprintf(stderr, "\tcache fields ...\n");
3074 cache_fields = insn_table_cache_fields(instructions);
3075 if (ch == 'I') {
3076 dump_traverse(instructions);
3077 dump_insn_table(instructions, 0, 1);
3078 }
3079 break;
3080 case 'r':
3081 sprs = spreg_table_load(optarg);
3082 break;
3083 default:
3084 {
3085 lf *file = lf_open(optarg);
3086 switch (ch) {
3087 case 'S':
3088 gen_semantics_h(instructions, file);
3089 break;
3090 case 's':
3091 gen_semantics_c(instructions, file);
3092 break;
3093 case 'P':
3094 gen_spreg_h(sprs, file);
3095 break;
3096 case 'p':
3097 gen_spreg_c(sprs, file);
3098 break;
3099 case 'D':
3100 gen_idecode_h(instructions, file);
3101 break;
3102 case 'd':
3103 gen_idecode_c(instructions, file);
3104 break;
3105 case 'C':
3106 gen_icache_h(cache_fields, file);
3107 break;
3108 }
3109 lf_close(file);
3110 }
3111 }
3112 }
3113 return 0;
3114 }
This page took 0.100407 seconds and 4 git commands to generate.