Fix mistake from Brendan's last checkin.
[deliverable/binutils-gdb.git] / sim / ppc / igen.c
CommitLineData
c143ef62
MM
1/* This file is part of the program psim.
2
3 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21#include <stdio.h>
22#include <ctype.h>
c143ef62
MM
23#include <getopt.h>
24
25#include "misc.h"
26#include "lf.h"
27#include "table.h"
c494cadd
MM
28#include "config.h"
29
30#ifdef HAVE_STRING_H
31#include <string.h>
32#else
33#ifdef HAVE_STRINGS_H
34#include <strings.h>
35#endif
36#endif
37
f2181eff
MM
38#ifdef HAVE_STDLIB_H
39#include <stdlib.h>
40#endif
41
c143ef62
MM
42
43
44/****************************************************************/
45
46enum {
a983c8f0 47 max_insn_size = 32,
c143ef62
MM
48};
49
a3114052
MM
50static int hi_bit_nr = 0;
51static int insn_size = max_insn_size;
52static int idecode_expand_semantics = 0;
53static int idecode_cache = 0;
f2181eff 54static int semantics_use_cache_struct = 0;
a3114052 55static int number_lines = 1;
c143ef62
MM
56
57
58/****************************************************************/
59
60
a3114052
MM
61static char *cache_idecode_formal =
62"cpu *processor,\n\
63 instruction_word instruction,\n\
64 unsigned_word cia,\n\
65 idecode_cache *cache_entry";
c143ef62 66
a3114052 67static char *cache_idecode_actual = "processor, instruction, cia, cache_entry";
c143ef62 68
a3114052
MM
69static char *cache_semantic_formal =
70"cpu *processor,\n\
71 idecode_cache *cache_entry,\n\
72 unsigned_word cia";
73
74static char *semantic_formal =
75"cpu *processor,\n\
76 instruction_word instruction,\n\
77 unsigned_word cia";
78
79static char *semantic_actual = "processor, instruction, cia";
c143ef62 80
c143ef62
MM
81
82
83/****************************************************************/
84
85
86typedef struct _filter filter;
87struct _filter {
88 char *flag;
89 filter *next;
90};
a3114052 91static filter *filters = NULL;
c143ef62
MM
92
93
94/****************************************************************/
95
96
97typedef struct _cache_rules cache_rules;
98struct _cache_rules {
99 int valid;
100 char *old_name;
101 char *new_name;
102 char *type;
103 char *expression;
104 cache_rules *next;
105};
a3114052 106static cache_rules *cache_table;
c143ef62
MM
107
108
109enum {
110 ca_valid,
111 ca_old_name,
112 ca_new_name,
113 ca_type,
114 ca_expression,
115 nr_cache_rule_fields,
116};
117
118static cache_rules *
119load_cache_rules(char *file_name)
120{
a3114052 121 table *file = table_open(file_name, nr_cache_rule_fields, 0);
c143ef62
MM
122 table_entry *entry;
123 cache_rules *table = NULL;
124 cache_rules **curr_rule = &table;
125 while ((entry = table_entry_read(file)) != NULL) {
126 cache_rules *new_rule = ZALLOC(cache_rules);
a983c8f0 127 new_rule->valid = target_a2i(hi_bit_nr, entry->fields[ca_valid]);
c143ef62
MM
128 new_rule->old_name = entry->fields[ca_old_name];
129 new_rule->new_name = entry->fields[ca_new_name];
130 new_rule->type = (strlen(entry->fields[ca_type])
131 ? entry->fields[ca_type]
132 : NULL);
133 new_rule->expression = (strlen(entry->fields[ca_expression]) > 0
134 ? entry->fields[ca_expression]
135 : NULL);
136 *curr_rule = new_rule;
137 curr_rule = &new_rule->next;
138 }
139 return table;
140}
141
142
143
144static void
145dump_cache_rule(cache_rules* rule,
146 int indent)
147{
148 dumpf(indent, "((cache_rules*)0x%x\n", rule);
149 dumpf(indent, " (valid %d)\n", rule->valid);
150 dumpf(indent, " (old_name \"%s\")\n", rule->old_name);
151 dumpf(indent, " (new_name \"%s\")\n", rule->new_name);
152 dumpf(indent, " (type \"%s\")\n", rule->type);
153 dumpf(indent, " (expression \"%s\")\n", rule->expression);
154 dumpf(indent, " (next 0x%x)\n", rule->next);
155 dumpf(indent, " )\n");
156}
157
158
159static void
160dump_cache_rules(cache_rules* rule, int indent)
161{
162 while (rule) {
163 dump_cache_rule(rule, indent);
164 rule = rule->next;
165 }
166}
167
168
169/****************************************************************/
170
171
172typedef struct _opcode_rules opcode_rules;
173struct _opcode_rules {
174 int first;
175 int last;
176 int force_first;
177 int force_last;
178 int force_slash;
179 char *force_expansion;
180 int use_switch;
181 unsigned special_mask;
182 unsigned special_value;
183 unsigned special_rule;
184 opcode_rules *next;
185};
a3114052 186static opcode_rules *opcode_table;
c143ef62
MM
187
188
189enum {
190 op_first,
191 op_last,
192 op_force_first,
193 op_force_last,
194 op_force_slash,
195 op_force_expansion,
196 op_use_switch,
197 op_special_mask,
198 op_special_value,
199 op_special_rule,
200 nr_opcode_fields,
201};
202
203
204static opcode_rules *
205load_opcode_rules(char *file_name)
206{
a3114052 207 table *file = table_open(file_name, nr_opcode_fields, 0);
c143ef62
MM
208 table_entry *entry;
209 opcode_rules *table = NULL;
210 opcode_rules **curr_rule = &table;
211 while ((entry = table_entry_read(file)) != NULL) {
212 opcode_rules *new_rule = ZALLOC(opcode_rules);
a983c8f0
MM
213 new_rule->first = target_a2i(hi_bit_nr, entry->fields[op_first]);
214 new_rule->last = target_a2i(hi_bit_nr, entry->fields[op_last]);
215 new_rule->force_first = target_a2i(hi_bit_nr, entry->fields[op_force_first]);
216 new_rule->force_last = target_a2i(hi_bit_nr, entry->fields[op_force_last]);
c143ef62
MM
217 new_rule->force_slash = a2i(entry->fields[op_force_slash]);
218 new_rule->force_expansion = entry->fields[op_force_expansion];
219 new_rule->use_switch = a2i(entry->fields[op_use_switch]);
220 new_rule->special_mask = a2i(entry->fields[op_special_mask]);
221 new_rule->special_value = a2i(entry->fields[op_special_value]);
222 new_rule->special_rule = a2i(entry->fields[op_special_rule]);
223 *curr_rule = new_rule;
224 curr_rule = &new_rule->next;
225 }
226 return table;
227}
228
229
230static void
231dump_opcode_rule(opcode_rules *rule,
232 int indent)
233{
234 dumpf(indent, "((opcode_rules*)%p\n", rule);
235 if (rule) {
236 dumpf(indent, " (first %d)\n", rule->first);
237 dumpf(indent, " (last %d)\n", rule->last);
238 dumpf(indent, " (force_first %d)\n", rule->force_first);
239 dumpf(indent, " (force_last %d)\n", rule->force_last);
240 dumpf(indent, " (force_slash %d)\n", rule->force_slash);
241 dumpf(indent, " (force_expansion \"%s\")\n", rule->force_expansion);
242 dumpf(indent, " (use_switch %d)\n", rule->use_switch);
243 dumpf(indent, " (special_mask 0x%x)\n", rule->special_mask);
244 dumpf(indent, " (special_value 0x%x)\n", rule->special_value);
245 dumpf(indent, " (special_rule 0x%x)\n", rule->special_rule);
246 dumpf(indent, " (next 0x%x)\n", rule->next);
247 }
248 dumpf(indent, " )\n");
249}
250
251
252static void
253dump_opcode_rules(opcode_rules *rule,
254 int indent)
255{
256 while (rule) {
257 dump_opcode_rule(rule, indent);
258 rule = rule->next;
259 }
260}
261
262
263/****************************************************************/
264
265typedef struct _insn_field insn_field;
266struct _insn_field {
267 int first;
268 int last;
269 int width;
270 int is_int;
271 int is_slash;
272 int is_string;
273 int val_int;
274 char *pos_string;
275 char *val_string;
276 insn_field *next;
277 insn_field *prev;
278};
279
280typedef struct _insn_fields insn_fields;
281struct _insn_fields {
a983c8f0 282 insn_field *bits[max_insn_size];
c143ef62
MM
283 insn_field *first;
284 insn_field *last;
285 unsigned value;
286};
287
288static insn_fields *
289parse_insn_format(table_entry *entry,
290 char *format)
291{
292 char *chp;
293 insn_fields *fields = ZALLOC(insn_fields);
294
295 /* create a leading sentinal */
296 fields->first = ZALLOC(insn_field);
297 fields->first->first = -1;
298 fields->first->last = -1;
299 fields->first->width = 0;
300
301 /* and a trailing sentinal */
302 fields->last = ZALLOC(insn_field);
303 fields->last->first = insn_size;
304 fields->last->last = insn_size;
305 fields->last->width = 0;
306
307 /* link them together */
308 fields->first->next = fields->last;
309 fields->last->prev = fields->first;
310
311 /* now work through the formats */
312 chp = format;
313
314 while (*chp != '\0') {
315 char *start_pos;
316 char *start_val;
317 int strlen_val;
318 int strlen_pos;
319 insn_field *new_field;
320
321 /* sanity check */
322 if (!isdigit(*chp)) {
323 error("%s:%d: missing position field at `%s'\n",
324 entry->file_name, entry->line_nr, chp);
325 }
326
327 /* break out the bit position */
328 start_pos = chp;
329 while (isdigit(*chp))
330 chp++;
331 strlen_pos = chp - start_pos;
332 if (*chp == '.' && strlen_pos > 0)
333 chp++;
334 else {
335 error("%s:%d: missing field value at %s\n",
336 entry->file_name, entry->line_nr, chp);
337 break;
338 }
339
340 /* break out the value */
341 start_val = chp;
342 while ((*start_val == '/' && *chp == '/')
343 || (isdigit(*start_val) && isdigit(*chp))
344 || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_')))
345 chp++;
346 strlen_val = chp - start_val;
347 if (*chp == ',')
348 chp++;
349 else if (*chp != '\0' || strlen_val == 0) {
350 error("%s:%d: missing field terminator at %s\n",
351 entry->file_name, entry->line_nr, chp);
352 break;
353 }
354
355 /* create a new field and insert it */
356 new_field = ZALLOC(insn_field);
357 new_field->next = fields->last;
358 new_field->prev = fields->last->prev;
359 new_field->next->prev = new_field;
360 new_field->prev->next = new_field;
361
362 /* the value */
363 new_field->val_string = (char*)zalloc(strlen_val+1);
364 strncpy(new_field->val_string, start_val, strlen_val);
365 if (isdigit(*new_field->val_string)) {
366 new_field->val_int = a2i(new_field->val_string);
367 new_field->is_int = 1;
368 }
369 else if (new_field->val_string[0] == '/') {
370 new_field->is_slash = 1;
371 }
372 else {
373 new_field->is_string = 1;
374 }
375
376 /* the pos */
377 new_field->pos_string = (char*)zalloc(strlen_pos+1);
378 strncpy(new_field->pos_string, start_pos, strlen_pos);
a983c8f0 379 new_field->first = target_a2i(hi_bit_nr, new_field->pos_string);
c143ef62
MM
380 new_field->last = new_field->next->first - 1; /* guess */
381 new_field->width = new_field->last - new_field->first + 1; /* guess */
382 new_field->prev->last = new_field->first-1; /*fix*/
383 new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/
384 }
385
386 /* fiddle first/last so that the sentinals `disapear' */
387 ASSERT(fields->first->last < 0);
388 ASSERT(fields->last->first >= insn_size);
389 fields->first = fields->first->next;
390 fields->last = fields->last->prev;
391
392 /* now go over this again, pointing each bit position at a field
393 record */
394 {
395 int i;
396 insn_field *field;
397 field = fields->first;
398 for (i = 0; i < insn_size; i++) {
399 while (field->last < i)
400 field = field->next;
401 fields->bits[i] = field;
402 }
403 }
404
405 /* go over each of the fields, and compute a `value' for the insn */
406 {
407 insn_field *field;
408 fields->value = 0;
409 for (field = fields->first;
410 field->last < insn_size;
411 field = field->next) {
412 fields->value <<= field->width;
413 if (field->is_int)
414 fields->value |= field->val_int;
415 }
416 }
417 return fields;
418}
419
420
421typedef enum {
422 field_constant_int = 1,
423 field_constant_slash = 2,
424 field_constant_string = 3
425} constant_field_types;
426
427
428static int
429insn_field_is_constant(insn_field *field,
430 opcode_rules *rule)
431{
432 /* field is an integer */
433 if (field->is_int)
434 return field_constant_int;
435 /* field is `/' and treating that as a constant */
436 if (field->is_slash && rule->force_slash)
437 return field_constant_slash;
438 /* field, though variable is on the list */
439 if (field->is_string && rule->force_expansion != NULL) {
440 char *forced_fields = rule->force_expansion;
441 while (*forced_fields != '\0') {
442 int field_len;
443 char *end = strchr(forced_fields, ',');
444 if (end == NULL)
445 field_len = strlen(forced_fields);
446 else
447 field_len = end-forced_fields;
448 if (strncmp(forced_fields, field->val_string, field_len) == 0
449 && field->val_string[field_len] == '\0')
450 return field_constant_string;
451 forced_fields += field_len;
452 if (*forced_fields == ',')
453 forced_fields++;
454 }
455 }
456 return 0;
457}
458
459
460static void
461dump_insn_field(insn_field *field,
462 int indent)
463{
464
465 printf("(insn_field*)0x%x\n", (unsigned)field);
466
467 dumpf(indent, "(first %d)\n", field->first);
468
469 dumpf(indent, "(last %d)\n", field->last);
470
471 dumpf(indent, "(width %d)\n", field->width);
472
473 if (field->is_int)
474 dumpf(indent, "(is_int %d)\n", field->val_int);
475
476 if (field->is_slash)
477 dumpf(indent, "(is_slash)\n");
478
479 if (field->is_string)
480 dumpf(indent, "(is_string `%s')\n", field->val_string);
481
482 dumpf(indent, "(next 0x%x)\n", field->next);
483
484 dumpf(indent, "(prev 0x%x)\n", field->prev);
485
486
487}
488
489static void
490dump_insn_fields(insn_fields *fields,
491 int indent)
492{
493 int i;
494
495 printf("(insn_fields*)%p\n", fields);
496
497 dumpf(indent, "(first 0x%x)\n", fields->first);
498 dumpf(indent, "(last 0x%x)\n", fields->last);
499
500 dumpf(indent, "(value 0x%x)\n", fields->value);
501
502 for (i = 0; i < insn_size; i++) {
503 dumpf(indent, "(bits[%d] ", i, fields->bits[i]);
504 dump_insn_field(fields->bits[i], indent+1);
505 dumpf(indent, " )\n");
506 }
507
508}
509
510
511/****************************************************************/
512
513typedef struct _opcode_field opcode_field;
514struct _opcode_field {
515 int first;
516 int last;
517 int is_boolean;
518 opcode_field *parent;
519};
520
c143ef62
MM
521static void
522dump_opcode_field(opcode_field *field, int indent, int levels)
523{
524 printf("(opcode_field*)%p\n", field);
525 if (levels && field != NULL) {
526 dumpf(indent, "(first %d)\n", field->first);
527 dumpf(indent, "(last %d)\n", field->last);
528 dumpf(indent, "(is_boolean %d)\n", field->is_boolean);
529 dumpf(indent, "(parent ");
530 dump_opcode_field(field->parent, indent, levels-1);
531 }
532}
533
534
535/****************************************************************/
536
537typedef struct _insn_bits insn_bits;
538struct _insn_bits {
539 int is_expanded;
540 int value;
541 insn_field *field;
542 opcode_field *opcode;
543 insn_bits *last;
544};
545
546
547static void
548dump_insn_bits(insn_bits *bits, int indent, int levels)
549{
550 printf("(insn_bits*)%p\n", bits);
551
552 if (levels && bits != NULL) {
553 dumpf(indent, "(value %d)\n", bits->value);
554 dumpf(indent, "(opcode ");
555 dump_opcode_field(bits->opcode, indent+1, 0);
556 dumpf(indent, " )\n");
557 dumpf(indent, "(field ");
558 dump_insn_field(bits->field, indent+1);
559 dumpf(indent, " )\n");
560 dumpf(indent, "(last ");
561 dump_insn_bits(bits->last, indent+1, levels-1);
562 }
563}
564
565
566/****************************************************************/
567
568
569typedef enum {
570 insn_format,
571 insn_form,
572 insn_flags,
1dc7c0ed 573 insn_mnemonic,
c143ef62
MM
574 insn_name,
575 insn_comment,
a3114052 576 nr_insn_table_fields
c143ef62 577} insn_table_fields;
c143ef62
MM
578
579typedef enum {
580 function_type = insn_format,
581 function_name = insn_name,
a3114052 582 function_param = insn_comment
c143ef62
MM
583} function_table_fields;
584
a3114052 585typedef enum {
1dc7c0ed 586 model_name = insn_mnemonic,
28816f45 587 model_identifer = insn_name,
80948f39 588 model_default = insn_comment,
a3114052 589} model_table_fields;
c143ef62
MM
590
591typedef struct _insn insn;
592struct _insn {
593 table_entry *file_entry;
594 insn_fields *fields;
595 insn *next;
596};
597
f2181eff
MM
598typedef struct _insn_undef insn_undef;
599struct _insn_undef {
600 insn_undef *next;
601 char *name;
602};
603
604static insn_undef *first_undef, *last_undef;
605
a3114052
MM
606typedef struct _model model;
607struct _model {
608 model *next;
609 char *name;
28816f45 610 char *printable_name;
80948f39
MM
611 char *insn_default;
612 table_model_entry *func_unit_start;
613 table_model_entry *func_unit_end;
a3114052
MM
614};
615
c143ef62
MM
616typedef struct _insn_table insn_table;
617struct _insn_table {
618 int opcode_nr;
619 insn_bits *expanded_bits;
620 int nr_insn;
621 insn *insns;
622 insn *functions;
a3114052 623 insn *last_function;
c143ef62
MM
624 opcode_rules *opcode_rule;
625 opcode_field *opcode;
626 int nr_entries;
627 insn_table *entries;
628 insn_table *sibling;
629 insn_table *parent;
630};
631
a3114052
MM
632typedef enum {
633 insn_model_name,
80948f39 634 insn_model_fields,
a3114052
MM
635 nr_insn_model_table_fields
636} insn_model_table_fields;
637
638static model *models;
639static model *last_model;
c143ef62 640
28816f45
MM
641static insn *model_macros;
642static insn *last_model_macro;
c143ef62 643
eb4ef197
MM
644static insn *model_functions;
645static insn *last_model_function;
646
1dc7c0ed
MM
647static insn *model_internal;
648static insn *last_model_internal;
649
4a0351ab
MM
650static insn *model_static;
651static insn *last_model_static;
652
1dc7c0ed
MM
653static insn *model_data;
654static insn *last_model_data;
655
845ff5a4
MM
656static int max_model_fields_len;
657
c143ef62
MM
658static void
659insn_table_insert_function(insn_table *table,
660 table_entry *file_entry)
661{
c143ef62
MM
662 /* create a new function */
663 insn *new_function = ZALLOC(insn);
664 new_function->file_entry = file_entry;
665
666 /* append it to the end of the function list */
a3114052
MM
667 if (table->last_function)
668 table->last_function->next = new_function;
669 else
670 table->functions = new_function;
671 table->last_function = new_function;
672}
673
c143ef62
MM
674static void
675insn_table_insert_insn(insn_table *table,
676 table_entry *file_entry,
677 insn_fields *fields)
678{
679 insn **ptr_to_cur_insn = &table->insns;
680 insn *cur_insn = *ptr_to_cur_insn;
a3114052
MM
681 table_model_entry *insn_model_ptr;
682 model *model_ptr;
c143ef62
MM
683
684 /* create a new instruction */
685 insn *new_insn = ZALLOC(insn);
686 new_insn->file_entry = file_entry;
687 new_insn->fields = fields;
688
a3114052
MM
689 /* Check out any model information returned to make sure the model
690 is correct. */
691 for(insn_model_ptr = file_entry->model_first; insn_model_ptr; insn_model_ptr = insn_model_ptr->next) {
692 char *name = insn_model_ptr->fields[insn_model_name];
845ff5a4
MM
693 int len = strlen (insn_model_ptr->fields[insn_model_fields]);
694
695 while (len > 0 && isspace(*insn_model_ptr->fields[insn_model_fields])) {
696 len--;
697 insn_model_ptr->fields[insn_model_fields]++;
698 }
699
700 if (max_model_fields_len < len)
701 max_model_fields_len = len;
a3114052
MM
702
703 for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
80948f39 704 if (strcmp(name, model_ptr->printable_name) == 0) {
a3114052
MM
705
706 /* Replace the name field with that of the global model, so that when we
707 want to print it out, we can just compare pointers. */
80948f39 708 insn_model_ptr->fields[insn_model_name] = model_ptr->printable_name;
a3114052
MM
709 break;
710 }
711 }
712
713 if (!model_ptr)
714 error("%s:%d: machine model `%s' was not known about\n",
715 file_entry->file_name, file_entry->line_nr, name);
716 }
717
c143ef62
MM
718 /* insert it according to the order of the fields */
719 while (cur_insn != NULL
720 && new_insn->fields->value >= cur_insn->fields->value) {
721 ptr_to_cur_insn = &cur_insn->next;
722 cur_insn = *ptr_to_cur_insn;
723 }
724
725 new_insn->next = cur_insn;
726 *ptr_to_cur_insn = new_insn;
727
728 table->nr_insn++;
729}
730
731
732static opcode_field *
733insn_table_find_opcode_field(insn *insns,
734 opcode_rules *rule,
735 int string_only)
736{
1dc7c0ed 737 opcode_field *curr_opcode = ZALLOC(opcode_field);
c143ef62 738 insn *entry;
c143ef62
MM
739 ASSERT(rule);
740
1dc7c0ed
MM
741 curr_opcode->first = insn_size;
742 curr_opcode->last = -1;
c143ef62
MM
743 for (entry = insns; entry != NULL; entry = entry->next) {
744 insn_fields *fields = entry->fields;
745 opcode_field new_opcode;
746
747 /* find a start point for the opcode field */
748 new_opcode.first = rule->first;
749 while (new_opcode.first <= rule->last
750 && (!string_only
751 || insn_field_is_constant(fields->bits[new_opcode.first],
752 rule) != field_constant_string)
753 && (string_only
754 || !insn_field_is_constant(fields->bits[new_opcode.first],
755 rule)))
756 new_opcode.first = fields->bits[new_opcode.first]->last + 1;
757 ASSERT(new_opcode.first > rule->last
758 || (string_only
759 && insn_field_is_constant(fields->bits[new_opcode.first],
760 rule) == field_constant_string)
761 || (!string_only
762 && insn_field_is_constant(fields->bits[new_opcode.first],
763 rule)));
764
765 /* find the end point for the opcode field */
766 new_opcode.last = rule->last;
767 while (new_opcode.last >= rule->first
768 && (!string_only
769 || insn_field_is_constant(fields->bits[new_opcode.last],
770 rule) != field_constant_string)
771 && (string_only
772 || !insn_field_is_constant(fields->bits[new_opcode.last],
773 rule)))
774 new_opcode.last = fields->bits[new_opcode.last]->first - 1;
775 ASSERT(new_opcode.last < rule->first
776 || (string_only
777 && insn_field_is_constant(fields->bits[new_opcode.last],
778 rule) == field_constant_string)
779 || (!string_only
780 && insn_field_is_constant(fields->bits[new_opcode.last],
781 rule)));
782
783 /* now see if our current opcode needs expanding */
784 if (new_opcode.first <= rule->last
785 && curr_opcode->first > new_opcode.first)
786 curr_opcode->first = new_opcode.first;
787 if (new_opcode.last >= rule->first
788 && curr_opcode->last < new_opcode.last)
789 curr_opcode->last = new_opcode.last;
790
791 }
792
793 /* was any thing interesting found? */
794 if (curr_opcode->first > rule->last) {
795 ASSERT(curr_opcode->last < rule->first);
796 return NULL;
797 }
798 ASSERT(curr_opcode->last >= rule->first);
799 ASSERT(curr_opcode->first <= rule->last);
800
801 /* if something was found, check it includes the forced field range */
802 if (!string_only
803 && curr_opcode->first > rule->force_first) {
804 curr_opcode->first = rule->force_first;
805 }
806 if (!string_only
807 && curr_opcode->last < rule->force_last) {
808 curr_opcode->last = rule->force_last;
809 }
810 /* handle special case elminating any need to do shift after mask */
811 if (string_only
812 && rule->force_last == insn_size-1) {
813 curr_opcode->last = insn_size-1;
814 }
815
816 /* handle any special cases */
817 switch (rule->special_rule) {
818 case 0: /* let the above apply */
819 break;
820 case 1: /* expand a limited nr of bits, ignoring the rest */
821 curr_opcode->first = rule->force_first;
822 curr_opcode->last = rule->force_last;
823 break;
824 case 2: /* boolean field */
825 curr_opcode->is_boolean = 1;
826 break;
827 }
828
829 return curr_opcode;
830}
831
832
833static void
834insn_table_insert_expanded(insn_table *table,
835 insn *old_insn,
836 int new_opcode_nr,
837 insn_bits *new_bits)
838{
839 insn_table **ptr_to_cur_entry = &table->entries;
840 insn_table *cur_entry = *ptr_to_cur_entry;
841
842 /* find the new table for this entry */
843 while (cur_entry != NULL
844 && cur_entry->opcode_nr < new_opcode_nr) {
845 ptr_to_cur_entry = &cur_entry->sibling;
846 cur_entry = *ptr_to_cur_entry;
847 }
848
849 if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) {
850 insn_table *new_entry = ZALLOC(insn_table);
851 new_entry->opcode_nr = new_opcode_nr;
852 new_entry->expanded_bits = new_bits;
853 new_entry->opcode_rule = table->opcode_rule->next;
854 new_entry->sibling = cur_entry;
855 new_entry->parent = table;
856 *ptr_to_cur_entry = new_entry;
857 cur_entry = new_entry;
858 table->nr_entries++;
859 }
860 /* ASSERT new_bits == cur_entry bits */
861 ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr);
862 insn_table_insert_insn(cur_entry,
863 old_insn->file_entry,
864 old_insn->fields);
865}
866
867static void
868insn_table_expand_opcode(insn_table *table,
869 insn *instruction,
870 int field_nr,
871 int opcode_nr,
872 insn_bits *bits)
873{
874
875 if (field_nr > table->opcode->last) {
876 insn_table_insert_expanded(table, instruction, opcode_nr, bits);
877 }
878 else {
879 insn_field *field = instruction->fields->bits[field_nr];
880 if (field->is_int || field->is_slash) {
881 ASSERT(field->first >= table->opcode->first
882 && field->last <= table->opcode->last);
883 insn_table_expand_opcode(table, instruction, field->last+1,
884 ((opcode_nr << field->width) + field->val_int),
885 bits);
886 }
887 else {
888 int val;
889 int last_pos = ((field->last < table->opcode->last)
890 ? field->last : table->opcode->last);
891 int first_pos = ((field->first > table->opcode->first)
892 ? field->first : table->opcode->first);
893 int width = last_pos - first_pos + 1;
894 int last_val = (table->opcode->is_boolean
895 ? 2 : (1 << width));
896 for (val = 0; val < last_val; val++) {
897 insn_bits *new_bits = ZALLOC(insn_bits);
898 new_bits->field = field;
899 new_bits->value = val;
900 new_bits->last = bits;
901 new_bits->opcode = table->opcode;
902 insn_table_expand_opcode(table, instruction, last_pos+1,
903 ((opcode_nr << width) | val),
904 new_bits);
905 }
906 }
907 }
908}
909
910static void
911insn_table_insert_expanding(insn_table *table,
912 insn *entry)
913{
914 insn_table_expand_opcode(table,
915 entry,
916 table->opcode->first,
917 0,
918 table->expanded_bits);
919}
920
921
922static void
923insn_table_expand_insns(insn_table *table)
924{
925
926 ASSERT(table->nr_insn >= 1);
927
928 /* determine a valid opcode */
929 while (table->opcode_rule) {
930 /* specials only for single instructions */
931 if ((table->nr_insn > 1
932 && table->opcode_rule->special_mask == 0
933 && table->opcode_rule->special_rule == 0)
934 || (table->nr_insn == 1
935 && table->opcode_rule->special_mask != 0
936 && ((table->insns->fields->value
937 & table->opcode_rule->special_mask)
938 == table->opcode_rule->special_value))
939 || (idecode_expand_semantics
940 && table->opcode_rule->special_mask == 0
941 && table->opcode_rule->special_rule == 0))
942 table->opcode =
943 insn_table_find_opcode_field(table->insns,
944 table->opcode_rule,
945 table->nr_insn == 1/*string*/
946 );
947 if (table->opcode != NULL)
948 break;
949 table->opcode_rule = table->opcode_rule->next;
950 }
951
952 /* did we find anything */
953 if (table->opcode == NULL) {
954 return;
955 }
956 ASSERT(table->opcode != NULL);
957
958 /* back link what we found to its parent */
959 if (table->parent != NULL) {
960 ASSERT(table->parent->opcode != NULL);
961 table->opcode->parent = table->parent->opcode;
962 }
963
964 /* expand the raw instructions according to the opcode */
965 {
966 insn *entry;
967 for (entry = table->insns; entry != NULL; entry = entry->next) {
968 insn_table_insert_expanding(table, entry);
969 }
970 }
971
972 /* and do the same for the sub entries */
973 {
974 insn_table *entry;
975 for (entry = table->entries; entry != NULL; entry = entry->sibling) {
976 insn_table_expand_insns(entry);
977 }
978 }
979}
980
981
1dc7c0ed
MM
982static void
983model_table_insert(insn_table *table,
984 table_entry *file_entry)
985{
845ff5a4
MM
986 int len;
987
1dc7c0ed
MM
988 /* create a new model */
989 model *new_model = ZALLOC(model);
1dc7c0ed
MM
990
991 new_model->name = file_entry->fields[model_identifer];
992 new_model->printable_name = file_entry->fields[model_name];
80948f39 993 new_model->insn_default = file_entry->fields[model_default];
1dc7c0ed 994
845ff5a4
MM
995 while (*new_model->insn_default && isspace(*new_model->insn_default))
996 new_model->insn_default++;
997
998 len = strlen(new_model->insn_default);
999 if (max_model_fields_len < len)
1000 max_model_fields_len = len;
1001
1dc7c0ed
MM
1002 /* append it to the end of the model list */
1003 if (last_model)
1004 last_model->next = new_model;
1005 else
1006 models = new_model;
1007 last_model = new_model;
1dc7c0ed
MM
1008}
1009
1010static void
1011model_table_insert_specific(insn_table *table,
1012 table_entry *file_entry,
1013 insn **start_ptr,
1014 insn **end_ptr)
1015{
1016 insn *ptr = ZALLOC(insn);
1017 ptr->file_entry = file_entry;
1018 if (*end_ptr)
1019 (*end_ptr)->next = ptr;
1020 else
1021 (*start_ptr) = ptr;
1022 (*end_ptr) = ptr;
1023}
1024
1025
c143ef62
MM
1026
1027static insn_table *
1028insn_table_load_insns(char *file_name)
1029{
a3114052 1030 table *file = table_open(file_name, nr_insn_table_fields, nr_insn_model_table_fields);
c143ef62
MM
1031 insn_table *table = ZALLOC(insn_table);
1032 table_entry *file_entry;
1033 table->opcode_rule = opcode_table;
1034
1035 while ((file_entry = table_entry_read(file)) != NULL) {
1036 if (it_is("function", file_entry->fields[insn_flags])
1037 || it_is("internal", file_entry->fields[insn_flags])) {
1038 insn_table_insert_function(table, file_entry);
1039 }
a3114052
MM
1040 else if (it_is("model", file_entry->fields[insn_flags])) {
1041 model_table_insert(table, file_entry);
1042 }
28816f45 1043 else if (it_is("model-macro", file_entry->fields[insn_flags])) {
1dc7c0ed 1044 model_table_insert_specific(table, file_entry, &model_macros, &last_model_macro);
eb4ef197
MM
1045 }
1046 else if (it_is("model-function", file_entry->fields[insn_flags])) {
1dc7c0ed
MM
1047 model_table_insert_specific(table, file_entry, &model_functions, &last_model_function);
1048 }
1049 else if (it_is("model-internal", file_entry->fields[insn_flags])) {
1050 model_table_insert_specific(table, file_entry, &model_internal, &last_model_internal);
1051 }
4a0351ab
MM
1052 else if (it_is("model-static", file_entry->fields[insn_flags])) {
1053 model_table_insert_specific(table, file_entry, &model_static, &last_model_static);
1054 }
1dc7c0ed
MM
1055 else if (it_is("model-data", file_entry->fields[insn_flags])) {
1056 model_table_insert_specific(table, file_entry, &model_data, &last_model_data);
28816f45 1057 }
c143ef62
MM
1058 else {
1059 insn_fields *fields;
1060 /* skip instructions that aren't relevant to the mode */
1061 filter *filt = filters;
1062 while (filt != NULL) {
1063 if (it_is(filt->flag, file_entry->fields[insn_flags]))
1064 break;
1065 filt = filt->next;
1066 }
1067 if (filt == NULL) {
1068 /* create/insert the new instruction */
1069 fields = parse_insn_format(file_entry,
1070 file_entry->fields[insn_format]);
1071 insn_table_insert_insn(table, file_entry, fields);
1072 }
1073 }
1074 }
1075 return table;
1076}
1077
1078
1079static void
1080dump_insn(insn *entry, int indent, int levels)
1081{
1082 printf("(insn*)%p\n", entry);
1083
1084 if (levels && entry != NULL) {
1085
1086 dumpf(indent, "(file_entry ");
1087 dump_table_entry(entry->file_entry, indent+1);
1088 dumpf(indent, " )\n");
1089
1090 dumpf(indent, "(fields ");
1091 dump_insn_fields(entry->fields, indent+1);
1092 dumpf(indent, " )\n");
1093
1094 dumpf(indent, "(next ");
1095 dump_insn(entry->next, indent+1, levels-1);
1096 dumpf(indent, " )\n");
1097
1098 }
1099
1100}
1101
1102
1103static void
1104dump_insn_table(insn_table *table,
1105 int indent, int levels)
1106{
1107
1108 printf("(insn_table*)%p\n", table);
1109
1110 if (levels && table != NULL) {
1111
1112 dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr);
1113
1114 dumpf(indent, "(expanded_bits ");
1115 dump_insn_bits(table->expanded_bits, indent+1, -1);
1116 dumpf(indent, " )\n");
1117
1118 dumpf(indent, "(int nr_insn %d)\n", table->nr_insn);
1119
1120 dumpf(indent, "(insns ");
1121 dump_insn(table->insns, indent+1, table->nr_insn);
1122 dumpf(indent, " )\n");
1123
1124 dumpf(indent, "(opcode_rule ");
1125 dump_opcode_rule(table->opcode_rule, indent+1);
1126 dumpf(indent, " )\n");
1127
1128 dumpf(indent, "(opcode ");
1129 dump_opcode_field(table->opcode, indent+1, 1);
1130 dumpf(indent, " )\n");
1131
1132 dumpf(indent, "(nr_entries %d)\n", table->entries);
1133 dumpf(indent, "(entries ");
1134 dump_insn_table(table->entries, indent+1, table->nr_entries);
1135 dumpf(indent, " )\n");
1136
1137 dumpf(indent, "(sibling ", table->sibling);
1138 dump_insn_table(table->sibling, indent+1, levels-1);
1139 dumpf(indent, " )\n");
1140
1141 dumpf(indent, "(parent ", table->parent);
1142 dump_insn_table(table->parent, indent+1, 0);
1143 dumpf(indent, " )\n");
1144
1145 }
1146}
1147
1148
1149/****************************************************************/
1150
1151
1152static void
1153lf_print_insn_bits(lf *file, insn_bits *bits)
1154{
1155 if (bits == NULL)
1156 return;
1157 lf_print_insn_bits(file, bits->last);
1158 lf_putchr(file, '_');
1159 lf_putstr(file, bits->field->val_string);
1160 if (!bits->opcode->is_boolean || bits->value == 0) {
1161 if (bits->opcode->last < bits->field->last)
1162 lf_putint(file, bits->value << (bits->field->last - bits->opcode->last));
1163 else
1164 lf_putint(file, bits->value);
1165 }
1166}
1167
1168static void
1169lf_print_opcodes(lf *file,
1170 insn_table *table)
1171{
1172 if (table != NULL) {
1173 while (1) {
1174 lf_printf(file, "_%d_%d",
1175 table->opcode->first,
1176 table->opcode->last);
1177 if (table->parent == NULL) break;
1178 lf_printf(file, "__%d", table->opcode_nr);
1179 table = table->parent;
1180 }
1181 }
1182}
1183
1184static void
1185lf_print_table_name(lf *file,
1186 insn_table *table)
1187{
1188 lf_printf(file, "idecode_table");
1189 lf_print_opcodes(file, table);
1190}
1191
1192
1193
1194typedef enum {
1195 function_name_prefix_semantics,
1196 function_name_prefix_idecode,
1197 function_name_prefix_itable,
1198 function_name_prefix_none
1199} lf_function_name_prefixes;
1200
1201static void
1202lf_print_function_name(lf *file,
1203 char *basename,
1204 insn_bits *expanded_bits,
1205 lf_function_name_prefixes prefix)
1206{
1207
1208 /* the prefix */
1209 switch (prefix) {
1210 case function_name_prefix_semantics:
1211 lf_putstr(file, "semantic_");
1212 break;
1213 case function_name_prefix_idecode:
1214 lf_printf(file, "idecode_");
1215 break;
1216 case function_name_prefix_itable:
1217 lf_putstr(file, "itable_");
1218 break;
1219 default:
1220 break;
1221 }
1222
1223 /* the function name */
1224 {
1225 char *pos;
1226 for (pos = basename;
1227 *pos != '\0';
1228 pos++) {
1229 switch (*pos) {
1230 case '/':
1231 case '-':
1232 break;
1233 case ' ':
1234 lf_putchr(file, '_');
1235 break;
1236 default:
1237 lf_putchr(file, *pos);
1238 break;
1239 }
1240 }
1241 }
1242
1243 /* the suffix */
1244 if (idecode_expand_semantics)
1245 lf_print_insn_bits(file, expanded_bits);
1246}
1247
1248
1249static void
1250lf_print_idecode_table(lf *file,
1251 insn_table *entry)
1252{
1253 int can_assume_leaf;
1254 opcode_rules *opcode_rule;
1255
1256 /* have a look at the rule table, if all table rules follow all
1257 switch rules, I can assume that all end points are leaves */
1258 opcode_rule = opcode_table;
1259 while (opcode_rule != NULL
1260 && opcode_rule->use_switch)
1261 opcode_rule = opcode_rule->next;
1262 while (opcode_rule != NULL
1263 && opcode_rule->use_switch
1264 && opcode_rule->special_rule)
1265 opcode_rule = opcode_rule->next;
1266 can_assume_leaf = opcode_rule == NULL;
1267
1268 lf_printf(file, "{\n");
1269 lf_indent(file, +2);
1270 {
1271 lf_printf(file, "idecode_table_entry *table = ");
1272 lf_print_table_name(file, entry);
1273 lf_printf(file, ";\n");
1274 lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n",
a983c8f0
MM
1275 i2target(hi_bit_nr, entry->opcode->first),
1276 i2target(hi_bit_nr, entry->opcode->last));
c143ef62
MM
1277 lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n");
1278 lf_printf(file, "while (1) {\n");
1279 lf_indent(file, +2);
1280 {
1dc7c0ed 1281 lf_printf(file, "/* nonzero mask -> another table */\n");
c143ef62
MM
1282 lf_printf(file, "while (table_entry->mask != 0) {\n");
1283 lf_indent(file, +2);
1284 {
1285 lf_printf(file, "table = ((idecode_table_entry*)\n");
1286 lf_printf(file, " table_entry->function_or_table);\n");
1287 lf_printf(file, "opcode = ((instruction & table_entry->mask)\n");
1288 lf_printf(file, " >> table_entry->shift);\n");
1289 lf_printf(file, "table_entry = table + opcode;\n");
1290 }
1291 lf_indent(file, -2);
1292 lf_printf(file, "}\n");
1dc7c0ed
MM
1293 lf_printf(file, "ASSERT(table_entry->mask == 0);\n");
1294 if (can_assume_leaf)
1295 lf_printf(file, "ASSERT(table_entry->shift == 0);\n");
1296 else {
1297 lf_printf(file, "if (table_entry->shift == 0)\n");
1298 lf_indent(file, +2);
c143ef62 1299 }
1dc7c0ed
MM
1300 if (idecode_cache) {
1301 lf_printf(file, "return (((idecode_crack*)\n");
1302 lf_printf(file, " table_entry->function_or_table)\n");
1303 lf_printf(file, " (%s));\n", cache_idecode_actual);
c143ef62
MM
1304 }
1305 else {
1dc7c0ed
MM
1306 lf_printf(file, "return (((idecode_semantic*)\n");
1307 lf_printf(file, " table_entry->function_or_table)\n");
1308 lf_printf(file, " (%s));\n", semantic_actual);
c143ef62
MM
1309 }
1310 if (!can_assume_leaf) {
1dc7c0ed
MM
1311 lf_indent(file, -2);
1312 lf_printf(file, "/* must be a boolean */\n");
c143ef62
MM
1313 lf_printf(file, "opcode = (instruction & table_entry->shift) != 0;\n");
1314 lf_printf(file, "table = ((idecode_table_entry*)\n");
1315 lf_printf(file, " table_entry->function_or_table);\n");
1316 lf_printf(file, "table_entry = table + opcode;\n");
1317 }
1318 }
1319 lf_indent(file, -2);
1320 lf_printf(file, "}\n");
1321 }
1322 lf_indent(file, -2);
1323 lf_printf(file, "}\n");
1324}
1325
1326
1327static void
1328lf_print_my_prefix(lf *file,
1329 table_entry *file_entry,
1330 int idecode)
1331{
45525d8d 1332 lf_printf(file, "const char *const my_prefix __attribute__((__unused__)) = \n");
c143ef62
MM
1333 lf_printf(file, " \"%s:%s:%s:%d\";\n",
1334 filter_filename (file_entry->file_name),
1335 (idecode ? "idecode" : "semantics"),
1336 file_entry->fields[insn_name],
1337 file_entry->line_nr);
45525d8d 1338 lf_printf(file, "const itable_index my_index __attribute__((__unused__)) = ");
4a0351ab
MM
1339 lf_print_function_name(file,
1340 file_entry->fields[insn_name],
1341 NULL,
1342 function_name_prefix_itable);
1343 lf_printf(file, ";\n");
c143ef62
MM
1344}
1345
1346
1347static void
1348lf_print_ptrace(lf *file,
1349 int idecode)
1350{
1351 lf_printf(file, "\n");
1352 lf_printf(file, "ITRACE(trace_%s, (\"\\n\"));\n",
1353 (idecode ? "idecode" : "semantics"));
1354}
1355
1356
1357/****************************************************************/
1358
1359typedef void leaf_handler
1360(insn_table *entry,
1361 void *data,
1362 int depth);
1363typedef void padding_handler
1364(insn_table *table,
1365 void *data,
1366 int depth,
1367 int opcode_nr);
1368
1369
1370static void
1371insn_table_traverse_tree(insn_table *table,
1372 void *data,
1373 int depth,
1374 leaf_handler *start,
1375 leaf_handler *leaf,
1376 leaf_handler *end,
1377 padding_handler *padding)
1378{
1379 insn_table *entry;
1380 int entry_nr;
1381
1382 ASSERT(table != NULL
1383 && table->opcode != NULL
1384 && table->nr_entries > 0
1385 && table->entries != 0);
1386
1387 if (start != NULL && depth >= 0)
1388 start(table, data, depth);
1389
1390 for (entry_nr = 0, entry = table->entries;
1391 entry_nr < (table->opcode->is_boolean
1392 ? 2
1393 : (1 << (table->opcode->last - table->opcode->first + 1)));
1394 entry_nr ++) {
1395 if (entry == NULL
1396 || (!table->opcode->is_boolean
1397 && entry_nr < entry->opcode_nr)) {
1398 if (padding != NULL && depth >= 0)
1399 padding(table, data, depth, entry_nr);
1400 }
1401 else {
1402 ASSERT(entry != NULL && (entry->opcode_nr == entry_nr
1403 || table->opcode->is_boolean));
1404 if (entry->opcode != NULL && depth != 0) {
1405 insn_table_traverse_tree(entry, data, depth+1,
1406 start, leaf, end, padding);
1407 }
1408 else if (depth >= 0) {
1409 if (leaf != NULL)
1410 leaf(entry, data, depth);
1411 }
1412 entry = entry->sibling;
1413 }
1414 }
1415 if (end != NULL && depth >= 0)
1416 end(table, data, depth);
1417}
1418
1419
1420typedef void function_handler
1421(insn_table *table,
1422 void *data,
1423 table_entry *function);
1424
1425static void
1426insn_table_traverse_function(insn_table *table,
1427 void *data,
1428 function_handler *leaf)
1429{
1430 insn *function;
1431 for (function = table->functions;
1432 function != NULL;
1433 function = function->next) {
1434 leaf(table, data, function->file_entry);
1435 }
1436}
1437
1438
1439typedef void insn_handler
1440(insn_table *table,
1441 void *data,
1442 insn *instruction);
1443
1444static void
1445insn_table_traverse_insn(insn_table *table,
1446 void *data,
1447 insn_handler *leaf)
1448{
1449 insn *instruction;
1450 for (instruction = table->insns;
1451 instruction != NULL;
1452 instruction = instruction->next) {
1453 leaf(table, data, instruction);
1454 }
1455}
1456
1457
1458static void
1459update_depth(insn_table *entry,
1460 void *data,
1461 int depth)
1462{
1463 int *max_depth = (int*)data;
1464 if (*max_depth < depth)
1465 *max_depth = depth;
1466}
1467
1468
1469static int
1470insn_table_depth(insn_table *table)
1471{
1472 int depth = 0;
1473 insn_table_traverse_tree(table,
1474 &depth,
1475 1,
1476 NULL, /*start*/
1477 update_depth,
1478 NULL, /*end*/
1479 NULL); /*padding*/
1480 return depth;
1481}
1482
1483
1484/****************************************************************/
1485
1486static void
1487dump_traverse_start(insn_table *table,
1488 void *data,
1489 int depth)
1490{
1491 dumpf(depth*2, "(%d\n", table->opcode_nr);
1492}
1493
1494static void
1495dump_traverse_leaf(insn_table *entry,
1496 void *data,
1497 int depth)
1498{
1499 ASSERT(entry->nr_entries == 0
1500 && entry->nr_insn == 1
1501 && entry->opcode == NULL);
1502 dumpf(depth*2, ".%d %s\n", entry->opcode_nr,
1503 entry->insns->file_entry->fields[insn_format]);
1504}
1505
1506static void
1507dump_traverse_end(insn_table *table,
1508 void *data,
1509 int depth)
1510{
1511 dumpf(depth*2, ")\n");
1512}
1513
1514static void
1515dump_traverse_padding(insn_table *table,
1516 void *data,
1517 int depth,
1518 int opcode_nr)
1519{
1520 dumpf(depth*2, ".<%d>\n", opcode_nr);
1521}
1522
1523
1524static void
1525dump_traverse(insn_table *table)
1526{
1527 insn_table_traverse_tree(table, NULL, 1,
1528 dump_traverse_start,
1529 dump_traverse_leaf,
1530 dump_traverse_end,
1531 dump_traverse_padding);
1532}
1533
1534
1535/****************************************************************/
1536
1537
1538static void
1dc7c0ed
MM
1539lf_print_semantic_function_header(lf *file,
1540 char *basename,
1541 insn_bits *expanded_bits,
1542 int is_function_definition,
1543 int is_inline_function)
c143ef62
MM
1544{
1545 lf_printf(file, "\n");
8a1d8a0b
MM
1546 lf_print_function_type(file, "unsigned_word", "EXTERN_SEMANTICS",
1547 " ");
c143ef62
MM
1548 lf_print_function_name(file,
1549 basename,
1550 expanded_bits,
1551 function_name_prefix_semantics);
1dc7c0ed 1552 lf_printf(file, "\n(%s)",
c143ef62 1553 (idecode_cache ? cache_semantic_formal : semantic_formal));
1dc7c0ed
MM
1554 if (!is_function_definition)
1555 lf_printf(file, ";");
1556 lf_printf(file, "\n");
c143ef62
MM
1557}
1558
1559
1560static void
1561semantics_h_leaf(insn_table *entry,
1562 void *data,
1563 int depth)
1564{
1565 lf *file = (lf*)data;
1566 ASSERT(entry->nr_insn == 1);
1dc7c0ed
MM
1567 lf_print_semantic_function_header(file,
1568 entry->insns->file_entry->fields[insn_name],
1569 entry->expanded_bits,
1570 0/* isnt function definition*/,
1571 !idecode_cache && entry->parent->opcode_rule->use_switch);
c143ef62
MM
1572}
1573
1574static void
1575semantics_h_insn(insn_table *entry,
1576 void *data,
1577 insn *instruction)
1578{
1579 lf *file = (lf*)data;
1dc7c0ed
MM
1580 lf_print_semantic_function_header(file,
1581 instruction->file_entry->fields[insn_name],
1582 NULL,
1583 0/*isnt function definition*/,
1584 0/*isnt inline function*/);
c143ef62
MM
1585}
1586
1587static void
1588semantics_h_function(insn_table *entry,
1589 void *data,
1590 table_entry *function)
1591{
1592 lf *file = (lf*)data;
1593 if (function->fields[function_type] == NULL
1594 || function->fields[function_type][0] == '\0') {
1dc7c0ed
MM
1595 lf_print_semantic_function_header(file,
1596 function->fields[function_name],
1597 NULL,
1598 0/*isnt function definition*/,
1599 1/*is inline function*/);
c143ef62
MM
1600 }
1601 else {
1602 lf_printf(file, "\n");
8a1d8a0b
MM
1603 lf_print_function_type(file, function->fields[function_type],
1604 "INLINE_SEMANTICS", " ");
1605 lf_printf(file, "%s\n(%s);\n",
c143ef62
MM
1606 function->fields[function_name],
1607 function->fields[function_param]);
1608 }
1609}
1610
1611
1612static void
1613gen_semantics_h(insn_table *table, lf *file)
1614{
1615
1616 lf_print_copyleft(file);
1617 lf_printf(file, "\n");
1618 lf_printf(file, "#ifndef _SEMANTICS_H_\n");
1619 lf_printf(file, "#define _SEMANTICS_H_\n");
1620 lf_printf(file, "\n");
c143ef62
MM
1621
1622 /* output a declaration for all functions */
1623 insn_table_traverse_function(table,
1624 file,
1625 semantics_h_function);
1626
1627 /* output a declaration for all instructions */
1628 if (idecode_expand_semantics)
1629 insn_table_traverse_tree(table,
1630 file,
1631 1,
1632 NULL, /* start */
1633 semantics_h_leaf, /* leaf */
1634 NULL, /* end */
1635 NULL); /* padding */
1636 else
1637 insn_table_traverse_insn(table,
1638 file,
1639 semantics_h_insn);
1640
1641 lf_printf(file, "\n");
1642 lf_printf(file, "#endif /* _SEMANTICS_H_ */\n");
1643
1644}
1645
1646/****************************************************************/
1647
1648typedef struct _icache_tree icache_tree;
1649struct _icache_tree {
1650 char *name;
1651 icache_tree *next;
1652 icache_tree *children;
1653};
1654
1655static icache_tree *
1656icache_tree_insert(icache_tree *tree,
1657 char *name)
1658{
1659 icache_tree *new_tree;
1660 /* find it */
1661 icache_tree **ptr_to_cur_tree = &tree->children;
1662 icache_tree *cur_tree = *ptr_to_cur_tree;
1663 while (cur_tree != NULL
1664 && strcmp(cur_tree->name, name) < 0) {
1665 ptr_to_cur_tree = &cur_tree->next;
1666 cur_tree = *ptr_to_cur_tree;
1667 }
1668 ASSERT(cur_tree == NULL
1669 || strcmp(cur_tree->name, name) >= 0);
1670 /* already in the tree */
1671 if (cur_tree != NULL
1672 && strcmp(cur_tree->name, name) == 0)
1673 return cur_tree;
1674 /* missing, insert it */
1675 ASSERT(cur_tree == NULL
1676 || strcmp(cur_tree->name, name) > 0);
1677 new_tree = ZALLOC(icache_tree);
1678 new_tree->name = name;
1679 new_tree->next = cur_tree;
1680 *ptr_to_cur_tree = new_tree;
1681 return new_tree;
1682}
1683
1684
1685static icache_tree *
1686insn_table_cache_fields(insn_table *table)
1687{
1688 icache_tree *tree = ZALLOC(icache_tree);
1689 insn *instruction;
1690 for (instruction = table->insns;
1691 instruction != NULL;
1692 instruction = instruction->next) {
1693 insn_field *field;
1694 icache_tree *form =
1695 icache_tree_insert(tree,
1696 instruction->file_entry->fields[insn_form]);
1697 for (field = instruction->fields->first;
1698 field != NULL;
1699 field = field->next) {
1700 if (field->is_string)
1701 icache_tree_insert(form, field->val_string);
1702 }
1703 }
1704 return tree;
1705}
1706
1707
1708
1709static void
1710gen_icache_h(icache_tree *tree,
1711 lf *file)
1712{
1713 lf_print_copyleft(file);
1714 lf_printf(file, "\n");
1715 lf_printf(file, "#ifndef _ICACHE_H_\n");
1716 lf_printf(file, "#define _ICACHE_H_\n");
1717 lf_printf(file, "\n");
c143ef62
MM
1718
1719 lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n",
1720 idecode_cache);
1721 lf_printf(file, "\n");
1722
1723 /* create an instruction cache if being used */
1724 if (idecode_cache) {
1725 icache_tree *form;
1726 lf_printf(file, "typedef struct _idecode_cache {\n");
1727 lf_printf(file, " unsigned_word address;\n");
1728 lf_printf(file, " void *semantic;\n");
1729 lf_printf(file, " union {\n");
1730 for (form = tree->children;
1731 form != NULL;
1732 form = form->next) {
1733 icache_tree *field;
1734 lf_printf(file, " struct {\n");
1735 for (field = form->children;
1736 field != NULL;
1737 field = field->next) {
1738 cache_rules *cache_rule;
1739 int found_rule = 0;
1740 for (cache_rule = cache_table;
1741 cache_rule != NULL;
1742 cache_rule = cache_rule->next) {
1743 if (strcmp(field->name, cache_rule->old_name) == 0) {
1744 found_rule = 1;
1745 if (cache_rule->new_name != NULL)
1746 lf_printf(file, " %s %s; /* %s */\n",
1747 (cache_rule->type == NULL
1748 ? "unsigned"
1749 : cache_rule->type),
1750 cache_rule->new_name,
1751 cache_rule->old_name);
1752 }
1753 }
1754 if (!found_rule)
1755 lf_printf(file, " unsigned %s;\n", field->name);
1756 }
1757 lf_printf(file, " } %s;\n", form->name);
1758 }
1759 lf_printf(file, " } crack;\n");
1760 lf_printf(file, "} idecode_cache;\n");
1761 }
1762 else {
1763 /* alernativly, since no cache, #define the fields to be
4220dcd6
MM
1764 extractions from the instruction variable. Emit a dummy
1765 definition for idecode_cache to allow model_issue to not
1766 be #ifdefed at the call level */
c143ef62
MM
1767 cache_rules *cache_rule;
1768 lf_printf(file, "\n");
4220dcd6
MM
1769 lf_printf(file, "typedef void idecode_cache;\n");
1770 lf_printf(file, "\n");
c143ef62
MM
1771 for (cache_rule = cache_table;
1772 cache_rule != NULL;
1773 cache_rule = cache_rule->next) {
1774 if (cache_rule->expression != NULL
1775 && strlen(cache_rule->expression) > 0)
1776 lf_printf(file, "#define %s %s\n",
1777 cache_rule->new_name, cache_rule->expression);
1778 }
1779 }
1780
1781 lf_printf(file, "\n");
1782 lf_printf(file, "#endif /* _ICACHE_H_ */\n");
1783}
1784
1785
1786
1787
1788/****************************************************************/
1789
1790
1791static void
1792lf_print_c_extraction(lf *file,
1793 insn *instruction,
1794 char *field_name,
1795 char *field_type,
1796 char *field_expression,
1797 insn_field *cur_field,
1798 insn_bits *bits,
1799 int get_value_from_cache,
1800 int put_value_in_cache)
1801{
1802 ASSERT(field_name != NULL);
1803 if (bits != NULL
1804 && (!bits->opcode->is_boolean || bits->value == 0)
1805 && strcmp(field_name, cur_field->val_string) == 0) {
1806 ASSERT(bits->field == cur_field);
1807 ASSERT(field_type == NULL);
1808 table_entry_lf_c_line_nr(file, instruction->file_entry);
45525d8d 1809 lf_printf(file, "const unsigned %s __attribute__((__unused__)) = ",
c143ef62
MM
1810 field_name);
1811 if (bits->opcode->last < bits->field->last)
1812 lf_printf(file, "%d;\n",
1813 bits->value << (bits->field->last - bits->opcode->last));
1814 else
1815 lf_printf(file, "%d;\n", bits->value);
1816 }
f2181eff
MM
1817 else if (get_value_from_cache && !put_value_in_cache
1818 && semantics_use_cache_struct) {
1819 insn_undef *undef = ZALLOC(insn_undef);
1820 /* Use #define to reference the cache struct directly, rather than putting
1821 them into local variables */
1822 lf_indent_suppress(file);
1823 lf_printf(file, "#define %s (cache_entry->crack.%s.%s)\n",
1824 field_name,
1825 instruction->file_entry->fields[insn_form],
1826 field_name);
1827
1828 if (first_undef)
1829 last_undef->next = undef;
1830 else
1831 first_undef = undef;
1832 last_undef = undef;;
1833 undef->name = field_name;
1834 }
c143ef62
MM
1835 else {
1836 /* put the field in the local variable */
1837 table_entry_lf_c_line_nr(file, instruction->file_entry);
45525d8d 1838 lf_printf(file, "%s const %s __attribute__((__unused__)) = ",
c143ef62
MM
1839 field_type == NULL ? "unsigned" : field_type,
1840 field_name);
1841 /* getting it from the cache */
1842 if (get_value_from_cache || put_value_in_cache) {
1843 lf_printf(file, "cache_entry->crack.%s.%s",
1844 instruction->file_entry->fields[insn_form],
1845 field_name);
1846 if (put_value_in_cache) /* also put it in the cache? */
1847 lf_printf(file, " = ");
1848 }
1849 if (!get_value_from_cache) {
1850 if (strcmp(field_name, cur_field->val_string) == 0)
1851 lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
a983c8f0
MM
1852 i2target(hi_bit_nr, cur_field->first),
1853 i2target(hi_bit_nr, cur_field->last));
c143ef62
MM
1854 else if (field_expression != NULL)
1855 lf_printf(file, "%s", field_expression);
1856 else
1857 lf_printf(file, "eval_%s", field_name);
1858 }
1859 lf_printf(file, ";\n");
1860 }
1861}
1862
1863
1864static void
1865lf_print_c_extractions(lf *file,
1866 insn *instruction,
1867 insn_bits *expanded_bits,
1868 int get_value_from_cache,
1869 int put_value_in_cache)
1870{
1871 insn_field *cur_field;
1872
1873 /* extract instruction fields */
1874 lf_printf(file, "/* extraction: %s */\n",
1875 instruction->file_entry->fields[insn_format]);
1876
1877 for (cur_field = instruction->fields->first;
1878 cur_field->first < insn_size;
1879 cur_field = cur_field->next) {
1880 if (cur_field->is_string) {
1881 insn_bits *bits;
1882 int found_rule = 0;
1883 /* find any corresponding value */
1884 for (bits = expanded_bits;
1885 bits != NULL;
1886 bits = bits->last) {
1887 if (bits->field == cur_field)
1888 break;
1889 }
1890 /* try the cache rule table for what to do */
1891 if (get_value_from_cache || put_value_in_cache) {
1892 cache_rules *cache_rule;
1893 for (cache_rule = cache_table;
1894 cache_rule != NULL;
1895 cache_rule = cache_rule->next) {
1896 if (strcmp(cur_field->val_string, cache_rule->old_name) == 0) {
1897 found_rule = 1;
1898 if (cache_rule->valid > 1 && put_value_in_cache)
1899 lf_print_c_extraction(file,
1900 instruction,
1901 cache_rule->new_name,
1902 cache_rule->type,
1903 cache_rule->expression,
1904 cur_field,
1905 bits,
1906 0,
1907 0);
1908 else if (cache_rule->valid == 1)
1909 lf_print_c_extraction(file,
1910 instruction,
1911 cache_rule->new_name,
1912 cache_rule->type,
1913 cache_rule->expression,
1914 cur_field,
1915 bits,
1916 get_value_from_cache,
1917 put_value_in_cache);
1918 }
1919 }
1920 }
1921 if (found_rule == 0)
1922 lf_print_c_extraction(file,
1923 instruction,
1924 cur_field->val_string,
1925 0,
1926 0,
1927 cur_field,
1928 bits,
1929 get_value_from_cache,
1930 put_value_in_cache);
1931 /* if any (XXX == 0), output a corresponding test */
1932 if (instruction->file_entry->annex != NULL) {
1933 char *field_name = cur_field->val_string;
1934 char *is_0_ptr = instruction->file_entry->annex;
1935 int field_len = strlen(field_name);
1936 if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) {
1937 is_0_ptr += field_len;
1938 while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) {
1939 if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0
1940 && !isalpha(is_0_ptr[ - field_len - 1])) {
1941 table_entry_lf_c_line_nr(file, instruction->file_entry);
45525d8d 1942 lf_printf(file, "const unsigned %s_is_0 __attribute__((__unused__)) = (", field_name);
c143ef62
MM
1943 if (bits != NULL)
1944 lf_printf(file, "%d", bits->value);
1945 else
1946 lf_printf(file, "%s", field_name);
1947 lf_printf(file, " == 0);\n");
1948 break;
1949 }
1950 is_0_ptr += strlen("_is_0");
1951 }
1952 }
1953 }
1954 /* any thing else ... */
1955 }
1956 }
1957 lf_print_lf_c_line_nr(file);
1958}
1959
1960
1961static void
1962lf_print_idecode_illegal(lf *file)
1963{
1964 if (idecode_cache)
1965 lf_printf(file, "return idecode_illegal(%s);\n", cache_idecode_actual);
1966 else
1967 lf_printf(file, "return semantic_illegal(%s);\n", semantic_actual);
1968}
1969
1970
1971static void
1972lf_print_idecode_floating_point_unavailable(lf *file)
1973{
1974 if (idecode_cache)
1975 lf_printf(file, "return idecode_floating_point_unavailable(%s);\n",
1976 cache_idecode_actual);
1977 else
1978 lf_printf(file, "return semantic_floating_point_unavailable(%s);\n",
1979 semantic_actual);
1980}
1981
1982
1983/* Output code to do any final checks on the decoded instruction.
1984 This includes things like verifying any on decoded fields have the
1985 correct value and checking that (for floating point) floating point
1986 hardware isn't disabled */
1987
1988static void
1989lf_print_c_validate(lf *file,
1990 insn *instruction,
1991 opcode_field *opcodes)
1992{
1993 /* Validate: unchecked instruction fields
1994
1995 If any constant fields in the instruction were not checked by the
1996 idecode tables, output code to check that they have the correct
1997 value here */
1998 {
1999 unsigned check_mask = 0;
2000 unsigned check_val = 0;
2001 insn_field *field;
2002 opcode_field *opcode;
2003
2004 /* form check_mask/check_val containing what needs to be checked
2005 in the instruction */
2006 for (field = instruction->fields->first;
2007 field->first < insn_size;
2008 field = field->next) {
2009
2010 check_mask <<= field->width;
2011 check_val <<= field->width;
2012
2013 /* is it a constant that could need validating? */
2014 if (!field->is_int && !field->is_slash)
2015 continue;
2016
2017 /* has it been checked by a table? */
2018 for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) {
2019 if (field->first >= opcode->first
2020 && field->last <= opcode->last)
2021 break;
2022 }
2023 if (opcode != NULL)
2024 continue;
2025
2026 check_mask |= (1 << field->width)-1;
2027 check_val |= field->val_int;
2028 }
2029
2030 /* if any bits not checked by opcode tables, output code to check them */
2031 if (check_mask) {
2032 lf_printf(file, "\n");
2033 lf_printf(file, "/* validate: %s */\n",
2034 instruction->file_entry->fields[insn_format]);
a3114052 2035 lf_printf(file, "if (WITH_RESERVED_BITS && (instruction & 0x%x) != 0x%x)\n",
c143ef62
MM
2036 check_mask, check_val);
2037 lf_indent(file, +2);
2038 lf_print_idecode_illegal(file);
2039 lf_indent(file, -2);
2040 }
2041 }
2042
2043 /* Validate floating point hardware
2044
2045 If the simulator is being built with out floating point hardware
2046 (different to it being disabled in the MSR) then floating point
2047 instructions are invalid */
2048 {
2049 if (it_is("f", instruction->file_entry->fields[insn_flags])) {
2050 lf_printf(file, "\n");
2051 lf_printf(file, "/* Validate: FP hardware exists */\n");
2052 lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n");
2053 lf_indent(file, +2);
2054 lf_print_idecode_illegal(file);
2055 lf_indent(file, -2);
2056 }
2057 }
2058
2059 /* Validate: Floating Point available
2060
2061 If floating point is not available, we enter a floating point
2062 unavailable interrupt into the cache instead of the instruction
2063 proper.
2064
2065 The PowerPC spec requires a CSI after MSR[FP] is changed and when
2066 ever a CSI occures we flush the instruction cache. */
2067
2068 {
2069 if (it_is("f", instruction->file_entry->fields[insn_flags])) {
2070 lf_printf(file, "\n");
2071 lf_printf(file, "/* Validate: FP available according to MSR[FP] */\n");
2072 lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n");
2073 lf_indent(file, +2);
2074 lf_print_idecode_floating_point_unavailable(file);
2075 lf_indent(file, -2);
2076 }
2077 }
2078}
2079
2080
2081static void
2082lf_print_c_cracker(lf *file,
2083 insn *instruction,
2084 insn_bits *expanded_bits,
2085 opcode_field *opcodes)
2086{
2087
2088 /* function header */
2089 lf_printf(file, "{\n");
2090 lf_indent(file, +2);
2091
2092 lf_print_my_prefix(file,
2093 instruction->file_entry,
2094 1/*putting-value-in-cache*/);
2095
2096 lf_print_ptrace(file,
2097 1/*putting-value-in-cache*/);
2098
2099 lf_print_c_validate(file, instruction, opcodes);
2100
2101 lf_printf(file, "\n");
2102 lf_printf(file, "{\n");
2103 lf_indent(file, +2);
2104 lf_print_c_extractions(file,
2105 instruction,
2106 expanded_bits,
2107 0/*get_value_from_cache*/,
2108 1/*put_value_in_cache*/);
2109 lf_indent(file, -2);
2110 lf_printf(file, "}\n");
2111
2112 /* return the function propper (main sorts this one out) */
2113 lf_printf(file, "\n");
2114 lf_printf(file, "/* semantic routine */\n");
2115 table_entry_lf_c_line_nr(file, instruction->file_entry);
2116 lf_printf(file, "return ");
2117 lf_print_function_name(file,
2118 instruction->file_entry->fields[insn_name],
2119 expanded_bits,
2120 function_name_prefix_semantics);
2121 lf_printf(file, ";\n");
2122
2123 lf_print_lf_c_line_nr(file);
2124 lf_indent(file, -2);
2125 lf_printf(file, "}\n");
2126}
2127
2128
2129static void
2130lf_print_c_semantic(lf *file,
2131 insn *instruction,
2132 insn_bits *expanded_bits,
2133 opcode_field *opcodes)
2134{
2135
2136 lf_printf(file, "{\n");
2137 lf_indent(file, +2);
2138
2139 lf_print_my_prefix(file,
2140 instruction->file_entry,
2141 0/*not putting value in cache*/);
a983c8f0 2142 lf_printf(file, "unsigned_word nia = cia + %d;\n", insn_size / 8);
c143ef62
MM
2143
2144 lf_printf(file, "\n");
2145 lf_print_c_extractions(file,
2146 instruction,
2147 expanded_bits,
2148 idecode_cache/*get_value_from_cache*/,
2149 0/*put_value_in_cache*/);
2150
2151 lf_print_ptrace(file,
2152 0/*put_value_in_cache*/);
2153
2154 /* validate the instruction, if a cache this has already been done */
2155 if (!idecode_cache)
2156 lf_print_c_validate(file, instruction, opcodes);
2157
84bbbc35 2158 /* generate the profiling call - this is delayed until after the
c143ef62
MM
2159 instruction has been verified */
2160 lf_printf(file, "\n");
84bbbc35 2161 lf_printf(file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE) {\n");
c143ef62
MM
2162 lf_printf(file, " mon_issue(");
2163 lf_print_function_name(file,
2164 instruction->file_entry->fields[insn_name],
2165 NULL,
2166 function_name_prefix_itable);
2167 lf_printf(file, ", processor, cia);\n");
84bbbc35
MM
2168 lf_printf(file, "}\n");
2169 lf_printf(file, "\n");
c143ef62
MM
2170
2171 /* generate the code (or at least something */
2172 if (instruction->file_entry->annex != NULL) {
2173 /* true code */
2174 lf_printf(file, "\n");
2175 table_entry_lf_c_line_nr(file, instruction->file_entry);
2176 lf_printf(file, "{\n");
2177 lf_indent(file, +2);
2178 lf_print_c_code(file, instruction->file_entry->annex);
2179 lf_indent(file, -2);
2180 lf_printf(file, "}\n");
2181 lf_print_lf_c_line_nr(file);
2182 }
2183 else if (it_is("nop", instruction->file_entry->fields[insn_flags])) {
2184 lf_print_lf_c_line_nr(file);
2185 }
2186 else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
2187 /* unimplemented floating point instruction - call for assistance */
2188 lf_printf(file, "\n");
2189 lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n");
2190 table_entry_lf_c_line_nr(file, instruction->file_entry);
2191 lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
2192 lf_print_lf_c_line_nr(file);
2193 }
2194 else {
2195 /* abort so it is implemented now */
2196 table_entry_lf_c_line_nr(file, instruction->file_entry);
2197 lf_putstr(file, "error(\"%s: unimplemented, cia=0x%x\\n\", my_prefix, cia);\n");
2198 lf_print_lf_c_line_nr(file);
2199 lf_printf(file, "\n");
2200 }
2201
c143ef62
MM
2202 lf_printf(file, "return nia;\n");
2203 lf_indent(file, -2);
2204 lf_printf(file, "}\n");
2205}
2206
c143ef62
MM
2207static void
2208lf_print_c_semantic_function(lf *file,
2209 insn *instruction,
2210 insn_bits *expanded_bits,
1dc7c0ed
MM
2211 opcode_field *opcodes,
2212 int is_inline_function)
c143ef62 2213{
f2181eff 2214 insn_undef *undef, *next;
c143ef62
MM
2215
2216 /* build the semantic routine to execute the instruction */
1dc7c0ed
MM
2217 lf_print_semantic_function_header(file,
2218 instruction->file_entry->fields[insn_name],
2219 expanded_bits,
2220 1/*is-function-definition*/,
2221 is_inline_function);
c143ef62
MM
2222 lf_print_c_semantic(file,
2223 instruction,
2224 expanded_bits,
2225 opcodes);
f2181eff
MM
2226
2227 /* If we are referencing the cache structure directly instead of putting the values
2228 in local variables, undef any defines we created */
2229 for(undef = first_undef; undef; undef = next) {
2230 next = undef->next;
2231 lf_indent_suppress(file);
2232 lf_printf(file, "#undef %s\n", undef->name);
2233 free((void *)undef);
2234 }
2235 first_undef = (insn_undef *)0;
2236 last_undef = (insn_undef *)0;
c143ef62
MM
2237}
2238
2239
2240static void
2241semantics_c_leaf(insn_table *entry,
2242 void *data,
2243 int depth)
2244{
2245 lf *file = (lf*)data;
2246 ASSERT(entry->nr_insn == 1
2247 && entry->opcode == NULL
2248 && entry->parent != NULL
2249 && entry->parent->opcode != NULL);
2250 lf_print_c_semantic_function(file,
2251 entry->insns,
2252 entry->expanded_bits,
1dc7c0ed
MM
2253 entry->parent->opcode,
2254 !idecode_cache && entry->parent->opcode_rule->use_switch);
c143ef62
MM
2255}
2256
2257static void
2258semantics_c_insn(insn_table *table,
2259 void *data,
2260 insn *instruction)
2261{
2262 lf *file = (lf*)data;
2263 lf_print_c_semantic_function(file, instruction,
1dc7c0ed
MM
2264 NULL, NULL,
2265 0/*isnt_inline_function*/);
c143ef62
MM
2266}
2267
2268static void
2269semantics_c_function(insn_table *table,
2270 void *data,
2271 table_entry *function)
2272{
2273 lf *file = (lf*)data;
2274 if (function->fields[function_type] == NULL
2275 || function->fields[function_type][0] == '\0') {
1dc7c0ed
MM
2276 lf_print_semantic_function_header(file,
2277 function->fields[function_name],
2278 NULL,
2279 1/*is function definition*/,
2280 1/*is inline function*/);
c143ef62
MM
2281 }
2282 else {
2283 lf_printf(file, "\n");
8a1d8a0b
MM
2284 lf_print_function_type(file, function->fields[function_type],
2285 "INLINE_SEMANTICS", "\n");
2286 lf_printf(file, "%s(%s)\n",
c143ef62
MM
2287 function->fields[function_name],
2288 function->fields[function_param]);
2289 }
2290 table_entry_lf_c_line_nr(file, function);
2291 lf_printf(file, "{\n");
2292 lf_indent(file, +2);
2293 lf_print_c_code(file, function->annex);
2294 lf_indent(file, -2);
2295 lf_printf(file, "}\n");
2296 lf_print_lf_c_line_nr(file);
2297}
2298
2299
2300
2301static void
2302gen_semantics_c(insn_table *table, lf *file)
2303{
2304 lf_print_copyleft(file);
2305 lf_printf(file, "\n");
2306 lf_printf(file, "#ifndef _SEMANTICS_C_\n");
2307 lf_printf(file, "#define _SEMANTICS_C_\n");
2308 lf_printf(file, "\n");
c143ef62
MM
2309 lf_printf(file, "#include \"cpu.h\"\n");
2310 lf_printf(file, "#include \"idecode.h\"\n");
2311 lf_printf(file, "#include \"semantics.h\"\n");
2312 lf_printf(file, "\n");
2313
2314 /* output a definition (c-code) for all functions */
2315 insn_table_traverse_function(table,
2316 file,
2317 semantics_c_function);
2318
2319 /* output a definition (c-code) for all instructions */
2320 if (idecode_expand_semantics)
2321 insn_table_traverse_tree(table,
2322 file,
2323 1,
2324 NULL, /* start */
2325 semantics_c_leaf,
2326 NULL, /* end */
2327 NULL); /* padding */
2328 else
2329 insn_table_traverse_insn(table,
2330 file,
2331 semantics_c_insn);
2332
2333 lf_printf(file, "\n");
2334 lf_printf(file, "#endif /* _SEMANTICS_C_ */\n");
2335}
2336
2337
2338/****************************************************************/
2339
2340static void
2341gen_idecode_h(insn_table *table, lf *file)
2342{
2343 lf_print_copyleft(file);
2344 lf_printf(file, "\n");
2345 lf_printf(file, "#ifndef _IDECODE_H_\n");
2346 lf_printf(file, "#define _IDECODE_H_\n");
2347 lf_printf(file, "\n");
c143ef62
MM
2348 lf_printf(file, "#include \"idecode_expression.h\"\n");
2349 lf_printf(file, "#include \"idecode_fields.h\"\n");
2350 lf_printf(file, "#include \"idecode_branch.h\"\n");
2351 lf_printf(file, "\n");
2352 lf_printf(file, "#include \"icache.h\"\n");
2353 lf_printf(file, "\n");
2354 lf_printf(file, "typedef unsigned_word idecode_semantic\n(%s);\n",
2355 (idecode_cache ? cache_semantic_formal : semantic_formal));
2356 lf_printf(file, "\n");
8a1d8a0b
MM
2357 if (idecode_cache) {
2358 lf_print_function_type(file, "idecode_semantic *", "INLINE_IDECODE", " ");
2359 lf_printf(file, "idecode\n(%s);\n", cache_idecode_formal);
2360 }
2361 else {
2362 lf_print_function_type(file, "unsigned_word", "INLINE_IDECODE", " ");
2363 lf_printf(file, "idecode_issue\n(%s);\n", semantic_formal);
2364 }
c143ef62
MM
2365 lf_printf(file, "\n");
2366 lf_printf(file, "#endif /* _IDECODE_H_ */\n");
2367}
2368
2369
2370/****************************************************************/
2371
2372
2373static void
2374idecode_table_start(insn_table *table,
2375 void *data,
2376 int depth)
2377{
2378 lf *file = (lf*)data;
2379 ASSERT(depth == 0);
2380 /* start of the table */
2381 if (!table->opcode_rule->use_switch) {
2382 lf_printf(file, "\n");
2383 lf_printf(file, "static idecode_table_entry ");
2384 lf_print_table_name(file, table);
2385 lf_printf(file, "[] = {\n");
2386 }
2387}
2388
2389static void
2390idecode_table_leaf(insn_table *entry,
2391 void *data,
2392 int depth)
2393{
2394 lf *file = (lf*)data;
2395 ASSERT(entry->parent != NULL);
2396 ASSERT(depth == 0);
2397
2398 /* add an entry to the table */
2399 if (!entry->parent->opcode_rule->use_switch) {
2400 if (entry->opcode == NULL) {
2401 /* table leaf entry */
2402 lf_printf(file, " /*%d*/ { 0, 0, ", entry->opcode_nr);
2403 lf_print_function_name(file,
2404 entry->insns->file_entry->fields[insn_name],
2405 entry->expanded_bits,
2406 (idecode_cache
2407 ? function_name_prefix_idecode
2408 : function_name_prefix_semantics));
2409 lf_printf(file, " },\n");
2410 }
2411 else if (entry->opcode_rule->use_switch) {
2412 /* table calling switch statement */
1dc7c0ed 2413 lf_printf(file, " /*%d*/ { 0, 0, ",
c143ef62
MM
2414 entry->opcode_nr);
2415 lf_print_table_name(file, entry);
2416 lf_printf(file, " },\n");
2417 }
2418 else {
2419 /* table `calling' another table */
2420 lf_printf(file, " /*%d*/ { ", entry->opcode_nr);
2421 if (entry->opcode->is_boolean)
2422 lf_printf(file, "MASK32(%d,%d), 0, ",
a983c8f0
MM
2423 i2target(hi_bit_nr, entry->opcode->first),
2424 i2target(hi_bit_nr, entry->opcode->last));
c143ef62
MM
2425 else
2426 lf_printf(file, "%d, MASK32(%d,%d), ",
2427 insn_size - entry->opcode->last - 1,
a983c8f0
MM
2428 i2target(hi_bit_nr, entry->opcode->first),
2429 i2target(hi_bit_nr, entry->opcode->last));
c143ef62
MM
2430 lf_print_table_name(file, entry);
2431 lf_printf(file, " },\n");
2432 }
2433 }
2434}
2435
2436static void
2437idecode_table_end(insn_table *table,
2438 void *data,
2439 int depth)
2440{
2441 lf *file = (lf*)data;
2442 ASSERT(depth == 0);
2443
2444 if (!table->opcode_rule->use_switch) {
2445 lf_printf(file, "};\n");
2446 }
2447}
2448
2449static void
2450idecode_table_padding(insn_table *table,
2451 void *data,
2452 int depth,
2453 int opcode_nr)
2454{
2455 lf *file = (lf*)data;
2456 ASSERT(depth == 0);
2457
2458 if (!table->opcode_rule->use_switch) {
2459 lf_printf(file, " /*%d*/ { 0, 0, %s_illegal },\n",
2460 opcode_nr, (idecode_cache ? "idecode" : "semantic"));
2461 }
2462}
2463
2464
2465/****************************************************************/
2466
2467
2468void lf_print_idecode_switch
2469(lf *file,
2470 insn_table *table);
2471
2472
2473static void
2474idecode_switch_start(insn_table *table,
2475 void *data,
2476 int depth)
2477{
2478 lf *file = (lf*)data;
2479 ASSERT(depth == 0);
2480 ASSERT(table->opcode_rule->use_switch);
2481
2482 lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n",
a983c8f0
MM
2483 i2target(hi_bit_nr, table->opcode->first),
2484 i2target(hi_bit_nr, table->opcode->last));
c143ef62
MM
2485}
2486
2487
2488static void
2489idecode_switch_leaf(insn_table *entry,
2490 void *data,
2491 int depth)
2492{
2493 lf *file = (lf*)data;
2494 ASSERT(entry->parent != NULL);
2495 ASSERT(depth == 0);
2496 ASSERT(entry->parent->opcode_rule->use_switch);
1dc7c0ed 2497 ASSERT(entry->parent->opcode);
c143ef62 2498
1dc7c0ed
MM
2499 if (!entry->parent->opcode->is_boolean
2500 || entry->opcode_nr == 0)
2501 lf_printf(file, "case %d:\n", entry->opcode_nr);
2502 else
2503 lf_printf(file, "default:\n");
c143ef62
MM
2504 lf_indent(file, +2);
2505 {
2506 if (entry->opcode == NULL) {
2507 /* switch calling leaf */
2508 lf_printf(file, "return ");
2509 lf_print_function_name(file,
2510 entry->insns->file_entry->fields[insn_name],
2511 entry->expanded_bits,
2512 (idecode_cache
2513 ? function_name_prefix_idecode
2514 : function_name_prefix_semantics));
2515 if (idecode_cache)
2516 lf_printf(file, "(%s);\n", cache_idecode_actual);
2517 else
2518 lf_printf(file, "(%s);\n", semantic_actual);
2519 }
2520 else if (entry->opcode_rule->use_switch) {
2521 /* switch calling switch */
2522 lf_print_idecode_switch(file, entry);
2523 }
2524 else {
1dc7c0ed 2525 /* switch looking up a table */
c143ef62
MM
2526 lf_print_idecode_table(file, entry);
2527 }
2528 lf_printf(file, "break;\n");
2529 }
2530 lf_indent(file, -2);
2531}
2532
2533
2534static void
2535lf_print_idecode_switch_illegal(lf *file)
2536{
2537 lf_indent(file, +2);
2538 lf_print_idecode_illegal(file);
2539 lf_printf(file, "break;\n");
2540 lf_indent(file, -2);
2541}
2542
2543static void
2544idecode_switch_end(insn_table *table,
2545 void *data,
2546 int depth)
2547{
2548 lf *file = (lf*)data;
2549 ASSERT(depth == 0);
2550 ASSERT(table->opcode_rule->use_switch);
1dc7c0ed 2551 ASSERT(table->opcode);
c143ef62 2552
8a1d8a0b 2553 lf_printf(file, "default:\n");
1dc7c0ed
MM
2554 if (table->opcode_rule->use_switch == 1
2555 && !table->opcode->is_boolean) {
c143ef62
MM
2556 lf_print_idecode_switch_illegal(file);
2557 }
8a1d8a0b
MM
2558 else {
2559 lf_printf(file, " error(\"igen internal error - bad switch generated\n\");\n");
2560 }
c143ef62
MM
2561 lf_printf(file, "}\n");
2562}
2563
2564static void
2565idecode_switch_padding(insn_table *table,
2566 void *data,
2567 int depth,
2568 int opcode_nr)
2569{
2570 lf *file = (lf*)data;
2571
2572 ASSERT(depth == 0);
2573 ASSERT(table->opcode_rule->use_switch);
2574
2575 if (table->opcode_rule->use_switch > 1) {
2576 lf_printf(file, "case %d:\n", opcode_nr);
2577 lf_print_idecode_switch_illegal(file);
2578 }
2579}
2580
2581
2582void
2583lf_print_idecode_switch(lf *file,
2584 insn_table *table)
2585{
2586 insn_table_traverse_tree(table,
2587 file,
2588 0,
2589 idecode_switch_start,
2590 idecode_switch_leaf,
2591 idecode_switch_end,
2592 idecode_switch_padding);
2593}
2594
2595
1dc7c0ed
MM
2596static void
2597lf_print_idecode_switch_function_header(lf *file,
2598 insn_table *table,
2599 int is_function_definition)
2600{
2601 lf_printf(file, "\n");
2602 lf_printf(file, "static ");
2603 if (idecode_cache)
2604 lf_printf(file, "idecode_semantic *");
2605 else
2606 lf_printf(file, "unsigned_word");
2607 if (is_function_definition)
2608 lf_printf(file, "\n");
2609 else
2610 lf_printf(file, " ");
2611 lf_print_table_name(file, table);
2612 lf_printf(file, "\n(%s)",
2613 (idecode_cache ? cache_idecode_formal : semantic_formal));
2614 if (!is_function_definition)
2615 lf_printf(file, ";");
2616 lf_printf(file, "\n");
2617}
2618
2619
2620static void
2621idecode_declare_if_switch(insn_table *table,
2622 void *data,
2623 int depth)
2624{
2625 lf *file = (lf*)data;
2626
2627 if (table->opcode_rule->use_switch
2628 && table->parent != NULL /* don't declare the top one yet */
2629 && !table->parent->opcode_rule->use_switch) {
2630 lf_print_idecode_switch_function_header(file,
2631 table,
2632 0/*isnt function definition*/);
2633 }
2634}
2635
2636
c143ef62
MM
2637static void
2638idecode_expand_if_switch(insn_table *table,
2639 void *data,
2640 int depth)
2641{
2642 lf *file = (lf*)data;
2643
2644 if (table->opcode_rule->use_switch
2645 && table->parent != NULL /* don't expand the top one yet */
2646 && !table->parent->opcode_rule->use_switch) {
1dc7c0ed
MM
2647 lf_print_idecode_switch_function_header(file,
2648 table,
2649 1/*is function definition*/);
c143ef62
MM
2650 lf_printf(file, "{\n");
2651 {
2652 lf_indent(file, +2);
2653 lf_print_idecode_switch(file, table);
2654 lf_indent(file, -2);
2655 }
2656 lf_printf(file, "}\n");
2657 }
2658}
2659
2660
2661static void
2662lf_print_c_cracker_function(lf *file,
2663 insn *instruction,
2664 insn_bits *expanded_bits,
1dc7c0ed
MM
2665 opcode_field *opcodes,
2666 int is_inline_function)
c143ef62
MM
2667{
2668 /* if needed, generate code to enter this routine into a cache */
2669 lf_printf(file, "\n");
8a1d8a0b 2670 lf_printf(file, "static idecode_semantic *\n");
c143ef62
MM
2671 lf_print_function_name(file,
2672 instruction->file_entry->fields[insn_name],
2673 expanded_bits,
2674 function_name_prefix_idecode);
2675 lf_printf(file, "\n(%s)\n", cache_idecode_formal);
2676
2677 lf_print_c_cracker(file,
2678 instruction,
2679 expanded_bits,
2680 opcodes);
2681}
2682
2683static void
2684idecode_crack_leaf(insn_table *entry,
2685 void *data,
2686 int depth)
2687{
2688 lf *file = (lf*)data;
2689 ASSERT(entry->nr_insn == 1
2690 && entry->opcode == NULL
2691 && entry->parent != NULL
1dc7c0ed
MM
2692 && entry->parent->opcode != NULL
2693 && entry->parent->opcode_rule != NULL);
c143ef62
MM
2694 lf_print_c_cracker_function(file,
2695 entry->insns,
2696 entry->expanded_bits,
1dc7c0ed
MM
2697 entry->opcode,
2698 entry->parent->opcode_rule->use_switch);
c143ef62
MM
2699}
2700
2701static void
2702idecode_crack_insn(insn_table *entry,
2703 void *data,
2704 insn *instruction)
2705{
2706 lf *file = (lf*)data;
2707 lf_print_c_cracker_function(file,
2708 instruction,
2709 NULL,
1dc7c0ed
MM
2710 NULL,
2711 0/*isnt inline function*/);
c143ef62
MM
2712}
2713
2714static void
2715idecode_c_internal_function(insn_table *table,
2716 void *data,
2717 table_entry *function)
2718{
2719 lf *file = (lf*)data;
2720 ASSERT(idecode_cache != 0);
2721 if (it_is("internal", function->fields[insn_flags])) {
2722 lf_printf(file, "\n");
8a1d8a0b
MM
2723 lf_print_function_type(file, "idecode_semantic *", "STATIC_INLINE_IDECODE",
2724 "\n");
c143ef62
MM
2725 lf_print_function_name(file,
2726 function->fields[insn_name],
2727 NULL,
2728 function_name_prefix_idecode);
2729 lf_printf(file, "\n(%s)\n", cache_idecode_formal);
2730 lf_printf(file, "{\n");
2731 lf_indent(file, +2);
2732 lf_printf(file, "/* semantic routine */\n");
2733 table_entry_lf_c_line_nr(file, function);
2734 lf_printf(file, "return ");
2735 lf_print_function_name(file,
2736 function->fields[insn_name],
2737 NULL,
2738 function_name_prefix_semantics);
2739 lf_printf(file, ";\n");
2740
2741 lf_print_lf_c_line_nr(file);
2742 lf_indent(file, -2);
2743 lf_printf(file, "}\n");
2744 }
2745}
2746
2747
2748/****************************************************************/
2749
2750static void
2751gen_idecode_c(insn_table *table, lf *file)
2752{
2753 int depth;
2754
2755 /* the intro */
2756 lf_print_copyleft(file);
2757 lf_printf(file, "\n");
2758 lf_printf(file, "\n");
2759 lf_printf(file, "#ifndef _IDECODE_C_\n");
2760 lf_printf(file, "#define _IDECODE_C_\n");
2761 lf_printf(file, "\n");
c143ef62
MM
2762 lf_printf(file, "#include \"cpu.h\"\n");
2763 lf_printf(file, "#include \"idecode.h\"\n");
2764 lf_printf(file, "#include \"semantics.h\"\n");
2765 lf_printf(file, "\n");
2766 lf_printf(file, "\n");
2767 lf_printf(file, "typedef idecode_semantic *idecode_crack\n(%s);\n",
2768 (idecode_cache ? cache_idecode_formal : semantic_formal));
2769 lf_printf(file, "\n");
2770 lf_printf(file, "typedef struct _idecode_table_entry {\n");
2771 lf_printf(file, " unsigned shift;\n");
2772 lf_printf(file, " unsigned mask;\n");
2773 lf_printf(file, " void *function_or_table;\n");
2774 lf_printf(file, "} idecode_table_entry;\n");
2775 lf_printf(file, "\n");
2776 lf_printf(file, "\n");
2777
2778 /* output `internal' invalid/floating-point unavailable functions
2779 where needed */
2780 if (idecode_cache) {
2781 insn_table_traverse_function(table,
2782 file,
2783 idecode_c_internal_function);
2784 }
2785
2786 /* output cracking functions where needed */
2787 if (idecode_cache) {
2788 if (idecode_expand_semantics)
2789 insn_table_traverse_tree(table,
2790 file,
2791 1,
2792 NULL,
2793 idecode_crack_leaf,
2794 NULL,
2795 NULL);
2796 else
2797 insn_table_traverse_insn(table,
2798 file,
2799 idecode_crack_insn);
2800 }
2801
1dc7c0ed
MM
2802 /* output switch function declarations where needed by tables */
2803 insn_table_traverse_tree(table,
2804 file,
2805 1,
2806 idecode_declare_if_switch, /* START */
2807 NULL, NULL, NULL);
c143ef62
MM
2808
2809 /* output tables where needed */
2810 for (depth = insn_table_depth(table);
2811 depth > 0;
2812 depth--) {
2813 insn_table_traverse_tree(table,
2814 file,
2815 1-depth,
2816 idecode_table_start,
2817 idecode_table_leaf,
2818 idecode_table_end,
2819 idecode_table_padding);
2820 }
2821
2822 /* output switch functions where needed */
2823 insn_table_traverse_tree(table,
2824 file,
2825 1,
2826 idecode_expand_if_switch, /* START */
2827 NULL, NULL, NULL);
2828
2829 /* output the main idecode routine */
2830 lf_printf(file, "\n");
8a1d8a0b
MM
2831 if (idecode_cache) {
2832 lf_print_function_type(file, "idecode_semantic *", "INLINE_IDECODE", "\n");
2833 lf_printf(file, "idecode\n(%s)\n", cache_idecode_formal);
2834 }
2835 else {
2836 lf_print_function_type(file, "unsigned_word", "INLINE_IDECODE", "\n");
2837 lf_printf(file, "idecode_issue\n(%s)\n", semantic_formal);
2838 }
c143ef62
MM
2839 lf_printf(file, "{\n");
2840 lf_indent(file, +2);
2841 if (table->opcode_rule->use_switch)
2842 lf_print_idecode_switch(file, table);
2843 else
2844 lf_print_idecode_table(file, table);
2845 lf_indent(file, -2);
2846 lf_printf(file, "}\n");
2847 lf_printf(file, "\n");
1dc7c0ed 2848 lf_printf(file, "#endif /* _IDECODE_C_ */\n");
c143ef62
MM
2849}
2850
2851
2852/****************************************************************/
2853
2854static void
2855itable_h_insn(insn_table *entry,
2856 void *data,
2857 insn *instruction)
2858{
2859 lf *file = (lf*)data;
2860 lf_printf(file, " ");
2861 lf_print_function_name(file,
2862 instruction->file_entry->fields[insn_name],
2863 NULL,
2864 function_name_prefix_itable);
2865 lf_printf(file, ",\n");
2866}
2867
2868
2869static void
2870gen_itable_h(insn_table *table, lf *file)
2871{
2872
2873 lf_print_copyleft(file);
2874 lf_printf(file, "\n");
2875 lf_printf(file, "#ifndef _ITABLE_H_\n");
2876 lf_printf(file, "#define _ITABLE_H_\n");
2877 lf_printf(file, "\n");
c143ef62
MM
2878
2879 /* output an enumerated type for each instruction */
2880 lf_printf(file, "typedef enum {\n");
2881 insn_table_traverse_insn(table,
2882 file,
2883 itable_h_insn);
2884 lf_printf(file, " nr_itable_entries,\n");
2885 lf_printf(file, "} itable_index;\n");
2886 lf_printf(file, "\n");
2887
2888 /* output the table that contains the actual instruction info */
2889 lf_printf(file, "typedef struct _itable_instruction_info {\n");
2890 lf_printf(file, " itable_index nr;\n");
2891 lf_printf(file, " char *format;\n");
2892 lf_printf(file, " char *form;\n");
2893 lf_printf(file, " char *flags;\n");
1dc7c0ed 2894 lf_printf(file, " char *mnemonic;\n");
c143ef62
MM
2895 lf_printf(file, " char *name;\n");
2896 lf_printf(file, "} itable_info;\n");
2897 lf_printf(file, "\n");
2898 lf_printf(file, "extern itable_info itable[nr_itable_entries];\n");
2899
2900 lf_printf(file, "\n");
2901 lf_printf(file, "#endif /* _ITABLE_C_ */\n");
2902
2903}
2904
2905/****************************************************************/
2906
2907static void
2908itable_c_insn(insn_table *entry,
2909 void *data,
2910 insn *instruction)
2911{
2912 lf *file = (lf*)data;
2913 char **fields = instruction->file_entry->fields;
2914 lf_printf(file, " { ");
2915 lf_print_function_name(file,
2916 instruction->file_entry->fields[insn_name],
2917 NULL,
2918 function_name_prefix_itable);
2919 lf_printf(file, ",\n");
2920 lf_printf(file, " \"%s\",\n", fields[insn_format]);
2921 lf_printf(file, " \"%s\",\n", fields[insn_form]);
2922 lf_printf(file, " \"%s\",\n", fields[insn_flags]);
1dc7c0ed 2923 lf_printf(file, " \"%s\",\n", fields[insn_mnemonic]);
c143ef62
MM
2924 lf_printf(file, " \"%s\",\n", fields[insn_name]);
2925 lf_printf(file, " },\n");
2926}
2927
2928
2929static void
2930gen_itable_c(insn_table *table, lf *file)
2931{
2932
2933 lf_print_copyleft(file);
2934 lf_printf(file, "\n");
2935 lf_printf(file, "#ifndef _ITABLE_C_\n");
2936 lf_printf(file, "#define _ITABLE_C_\n");
2937 lf_printf(file, "\n");
c143ef62
MM
2938 lf_printf(file, "#include \"itable.h\"\n");
2939 lf_printf(file, "\n");
2940
2941 /* output the table that contains the actual instruction info */
2942 lf_printf(file, "itable_info itable[nr_itable_entries] = {\n");
2943 insn_table_traverse_insn(table,
2944 file,
2945 itable_c_insn);
2946 lf_printf(file, "};\n");
2947 lf_printf(file, "\n");
2948
2949 lf_printf(file, "\n");
2950 lf_printf(file, "#endif /* _ITABLE_C_ */\n");
a3114052
MM
2951}
2952
2953/****************************************************************/
2954
eb4ef197 2955static void
1dc7c0ed
MM
2956model_c_or_h_data(insn_table *table,
2957 lf *file,
2958 table_entry *data)
2959{
2960 if (data->annex) {
2961 table_entry_lf_c_line_nr(file, data);
2962 lf_print_c_code(file, data->annex);
2963 lf_print_lf_c_line_nr(file);
2964 lf_printf(file, "\n");
2965 }
2966}
2967
2968static void
2969model_c_or_h_function(insn_table *entry,
2970 lf *file,
2971 table_entry *function,
2972 char *prefix)
eb4ef197
MM
2973{
2974 if (function->fields[function_type] == NULL
2975 || function->fields[function_type][0] == '\0') {
1dc7c0ed 2976 error("Model function type not specified for %s", function->fields[function_name]);
eb4ef197 2977 }
8a1d8a0b
MM
2978 lf_printf(file, "\n");
2979 lf_print_function_type(file, function->fields[function_type], prefix, " ");
2980 lf_printf(file, "%s\n(%s);\n",
2981 function->fields[function_name],
2982 function->fields[function_param]);
1dc7c0ed 2983 lf_printf(file, "\n");
eb4ef197
MM
2984}
2985
a3114052
MM
2986static void
2987gen_model_h(insn_table *table, lf *file)
2988{
eb4ef197 2989 insn *insn_ptr;
a3114052 2990 model *model_ptr;
28816f45 2991 insn *macro;
80948f39
MM
2992 char *name;
2993 int model_create_p = 0;
2994 int model_init_p = 0;
2995 int model_halt_p = 0;
80948f39
MM
2996 int model_mon_info_p = 0;
2997 int model_mon_info_free_p = 0;
a3114052
MM
2998
2999 lf_print_copyleft(file);
3000 lf_printf(file, "\n");
3001 lf_printf(file, "#ifndef _MODEL_H_\n");
3002 lf_printf(file, "#define _MODEL_H_\n");
3003 lf_printf(file, "\n");
eb4ef197 3004
1dc7c0ed 3005 for(macro = model_macros; macro; macro = macro->next) {
ac79ccd4 3006 model_c_or_h_data(table, file, macro->file_entry);
eb4ef197
MM
3007 }
3008
a3114052
MM
3009 lf_printf(file, "typedef enum _model_enum {\n");
3010 lf_printf(file, " MODEL_NONE,\n");
3011 for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
3012 lf_printf(file, " MODEL_%s,\n", model_ptr->name);
3013 }
3014 lf_printf(file, " nr_models\n");
3015 lf_printf(file, "} model_enum;\n");
3016 lf_printf(file, "\n");
3017
28816f45
MM
3018 lf_printf(file, "#define DEFAULT_MODEL MODEL_%s\n", (models) ? models->name : "NONE");
3019 lf_printf(file, "\n");
3020
80948f39
MM
3021 lf_printf(file, "typedef struct _model_data model_data;\n");
3022 lf_printf(file, "typedef struct _model_time model_time;\n");
3023 lf_printf(file, "\n");
a3114052 3024
80948f39 3025 lf_printf(file, "extern model_enum current_model;\n");
8a1d8a0b
MM
3026 lf_printf(file, "extern const char *model_name[ (int)nr_models ];\n");
3027 lf_printf(file, "extern const char *const *const model_func_unit_name[ (int)nr_models ];\n");
3028 lf_printf(file, "extern const model_time *const model_time_mapping[ (int)nr_models ];\n");
28816f45 3029 lf_printf(file, "\n");
eb4ef197
MM
3030
3031 for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) {
1dc7c0ed 3032 model_c_or_h_function(table, file, insn_ptr->file_entry, "INLINE_MODEL");
80948f39
MM
3033 name = insn_ptr->file_entry->fields[function_name];
3034 if (strcmp (name, "model_create") == 0)
3035 model_create_p = 1;
3036 else if (strcmp (name, "model_init") == 0)
3037 model_init_p = 1;
3038 else if (strcmp (name, "model_halt") == 0)
3039 model_halt_p = 1;
80948f39
MM
3040 else if (strcmp (name, "model_mon_info") == 0)
3041 model_mon_info_p = 1;
3042 else if (strcmp (name, "model_mon_info_free") == 0)
3043 model_mon_info_free_p = 1;
3044 }
3045
3046 if (!model_create_p) {
8a1d8a0b
MM
3047 lf_print_function_type(file, "model_data *", "INLINE_MODEL", " ");
3048 lf_printf(file, "model_create\n");
80948f39
MM
3049 lf_printf(file, "(cpu *processor);\n");
3050 lf_printf(file, "\n");
3051 }
3052
3053 if (!model_init_p) {
8a1d8a0b
MM
3054 lf_print_function_type(file, "void", "INLINE_MODEL", " ");
3055 lf_printf(file, "model_init\n");
4220dcd6 3056 lf_printf(file, "(model_data *model_ptr);\n");
eb4ef197
MM
3057 lf_printf(file, "\n");
3058 }
3059
80948f39 3060 if (!model_halt_p) {
8a1d8a0b
MM
3061 lf_print_function_type(file, "void", "INLINE_MODEL", " ");
3062 lf_printf(file, "model_halt\n");
4220dcd6 3063 lf_printf(file, "(model_data *model_ptr);\n");
80948f39
MM
3064 lf_printf(file, "\n");
3065 }
3066
80948f39 3067 if (!model_mon_info_p) {
8a1d8a0b
MM
3068 lf_print_function_type(file, "model_print *", "INLINE_MODEL", " ");
3069 lf_printf(file, "model_mon_info\n");
80948f39
MM
3070 lf_printf(file, "(model_data *model_ptr);\n");
3071 lf_printf(file, "\n");
3072 }
3073
3074 if (!model_mon_info_free_p) {
8a1d8a0b
MM
3075 lf_print_function_type(file, "void", "INLINE_MODEL", " ");
3076 lf_printf(file, "model_mon_info_free\n");
80948f39
MM
3077 lf_printf(file, "(model_data *model_ptr,\n");
3078 lf_printf(file, " model_print *info_ptr);\n");
3079 lf_printf(file, "\n");
3080 }
3081
8a1d8a0b
MM
3082 lf_print_function_type(file, "void", "INLINE_MODEL", " ");
3083 lf_printf(file, "model_set\n");
80948f39 3084 lf_printf(file, "(const char *name);\n");
a3114052
MM
3085 lf_printf(file, "\n");
3086 lf_printf(file, "#endif /* _MODEL_H_ */\n");
3087}
3088
3089/****************************************************************/
3090
1dc7c0ed
MM
3091typedef struct _model_c_passed_data model_c_passed_data;
3092struct _model_c_passed_data {
a3114052
MM
3093 lf *file;
3094 model *model_ptr;
3095};
3096
3097static void
3098model_c_insn(insn_table *entry,
3099 void *data,
3100 insn *instruction)
3101{
1dc7c0ed 3102 model_c_passed_data *data_ptr = (model_c_passed_data *)data;
a3114052 3103 lf *file = data_ptr->file;
80948f39 3104 char *current_name = data_ptr->model_ptr->printable_name;
a3114052 3105 table_model_entry *model_ptr = instruction->file_entry->model_first;
a3114052
MM
3106
3107 while (model_ptr) {
28816f45 3108 if (model_ptr->fields[insn_model_name] == current_name) {
845ff5a4
MM
3109 lf_printf(file, " { %-*s }, /* %s */\n",
3110 max_model_fields_len,
80948f39
MM
3111 model_ptr->fields[insn_model_fields],
3112 instruction->file_entry->fields[insn_name]);
a3114052
MM
3113 return;
3114 }
3115
3116 model_ptr = model_ptr->next;
3117 }
3118
845ff5a4
MM
3119 lf_printf(file, " { %-*s }, /* %s */\n",
3120 max_model_fields_len,
80948f39
MM
3121 data_ptr->model_ptr->insn_default,
3122 instruction->file_entry->fields[insn_name]);
a3114052
MM
3123}
3124
eb4ef197
MM
3125static void
3126model_c_function(insn_table *table,
3127 lf *file,
1dc7c0ed
MM
3128 table_entry *function,
3129 const char *prefix)
eb4ef197
MM
3130{
3131 if (function->fields[function_type] == NULL
3132 || function->fields[function_type][0] == '\0') {
1dc7c0ed 3133 error("Model function return type not specified for %s", function->fields[function_name]);
eb4ef197
MM
3134 }
3135 else {
3136 lf_printf(file, "\n");
8a1d8a0b
MM
3137 lf_print_function_type(file, function->fields[function_type], prefix, "\n");
3138 lf_printf(file, "%s(%s)\n",
eb4ef197
MM
3139 function->fields[function_name],
3140 function->fields[function_param]);
3141 }
3142 table_entry_lf_c_line_nr(file, function);
3143 lf_printf(file, "{\n");
3144 if (function->annex) {
3145 lf_indent(file, +2);
3146 lf_print_c_code(file, function->annex);
3147 lf_indent(file, -2);
3148 }
3149 lf_printf(file, "}\n");
3150 lf_print_lf_c_line_nr(file);
1dc7c0ed 3151 lf_printf(file, "\n");
eb4ef197
MM
3152}
3153
a3114052
MM
3154static void
3155gen_model_c(insn_table *table, lf *file)
3156{
eb4ef197 3157 insn *insn_ptr;
a3114052 3158 model *model_ptr;
80948f39
MM
3159 char *name;
3160 int model_create_p = 0;
3161 int model_init_p = 0;
3162 int model_halt_p = 0;
80948f39
MM
3163 int model_mon_info_p = 0;
3164 int model_mon_info_free_p = 0;
a3114052
MM
3165
3166 lf_print_copyleft(file);
3167 lf_printf(file, "\n");
3168 lf_printf(file, "#ifndef _MODEL_C_\n");
3169 lf_printf(file, "#define _MODEL_C_\n");
3170 lf_printf(file, "\n");
a3114052 3171 lf_printf(file, "#include \"cpu.h\"\n");
80948f39
MM
3172 lf_printf(file, "#include \"mon.h\"\n");
3173 lf_printf(file, "\n");
3174 lf_printf(file, "#ifdef HAVE_STDLIB_H\n");
3175 lf_printf(file, "#include <stdlib.h>\n");
3176 lf_printf(file, "#endif\n");
a3114052
MM
3177 lf_printf(file, "\n");
3178
1dc7c0ed
MM
3179 for(insn_ptr = model_data; insn_ptr; insn_ptr = insn_ptr->next) {
3180 model_c_or_h_data(table, file, insn_ptr->file_entry);
3181 }
3182
4a0351ab 3183 for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) {
8a1d8a0b 3184 model_c_or_h_function(table, file, insn_ptr->file_entry, "/*h*/STATIC");
4a0351ab
MM
3185 }
3186
1dc7c0ed
MM
3187 for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) {
3188 model_c_or_h_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL");
3189 }
3190
4a0351ab 3191 for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) {
8a1d8a0b 3192 model_c_function(table, file, insn_ptr->file_entry, "/*c*/STATIC");
4a0351ab
MM
3193 }
3194
1dc7c0ed
MM
3195 for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) {
3196 model_c_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL");
3197 }
3198
eb4ef197 3199 for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) {
1dc7c0ed 3200 model_c_function(table, file, insn_ptr->file_entry, "INLINE_MODEL");
80948f39
MM
3201 name = insn_ptr->file_entry->fields[function_name];
3202 if (strcmp (name, "model_create") == 0)
3203 model_create_p = 1;
3204 else if (strcmp (name, "model_init") == 0)
3205 model_init_p = 1;
3206 else if (strcmp (name, "model_halt") == 0)
3207 model_halt_p = 1;
80948f39
MM
3208 else if (strcmp (name, "model_mon_info") == 0)
3209 model_mon_info_p = 1;
3210 else if (strcmp (name, "model_mon_info_free") == 0)
3211 model_mon_info_free_p = 1;
3212 }
3213
3214 if (!model_create_p) {
8a1d8a0b
MM
3215 lf_print_function_type(file, "model_data *", "INLINE_MODEL", "\n");
3216 lf_printf(file, "model_create(cpu *processor)\n");
80948f39
MM
3217 lf_printf(file, "{\n");
3218 lf_printf(file, " return (model_data *)0;\n");
3219 lf_printf(file, "}\n");
3220 lf_printf(file, "\n");
eb4ef197
MM
3221 }
3222
80948f39 3223 if (!model_init_p) {
8a1d8a0b
MM
3224 lf_print_function_type(file, "void", "INLINE_MODEL", "\n");
3225 lf_printf(file, "model_init(model_data *model_ptr)\n");
80948f39
MM
3226 lf_printf(file, "{\n");
3227 lf_printf(file, "}\n");
3228 lf_printf(file, "\n");
3229 }
3230
3231 if (!model_halt_p) {
8a1d8a0b
MM
3232 lf_print_function_type(file, "void", "INLINE_MODEL", "\n");
3233 lf_printf(file, "model_halt(model_data *model_ptr)\n");
80948f39
MM
3234 lf_printf(file, "{\n");
3235 lf_printf(file, "}\n");
3236 lf_printf(file, "\n");
3237 }
3238
80948f39 3239 if (!model_mon_info_p) {
8a1d8a0b
MM
3240 lf_print_function_type(file, "model_print *", "INLINE_MODEL", "\n");
3241 lf_printf(file, "model_mon_info(model_data *model_ptr)\n");
80948f39
MM
3242 lf_printf(file, "{\n");
3243 lf_printf(file, " return (model_print *)0;\n");
3244 lf_printf(file, "}\n");
3245 lf_printf(file, "\n");
3246 }
3247
3248 if (!model_mon_info_free_p) {
8a1d8a0b
MM
3249 lf_print_function_type(file, "void", "INLINE_MODEL", "\n");
3250 lf_printf(file, "model_mon_info_free(model_data *model_ptr,\n");
3251 lf_printf(file, " model_print *info_ptr)\n");
80948f39
MM
3252 lf_printf(file, "{\n");
3253 lf_printf(file, "}\n");
3254 lf_printf(file, "\n");
3255 }
3256
845ff5a4
MM
3257 lf_printf(file, "/* Insn functional unit info */\n");
3258 for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
3259 model_c_passed_data data;
3260
3261 lf_printf(file, "static const model_time model_time_%s[] = {\n", model_ptr->name);
3262 data.file = file;
3263 data.model_ptr = model_ptr;
3264 insn_table_traverse_insn(table,
3265 (void *)&data,
3266 model_c_insn);
3267
3268 lf_printf(file, "};\n");
3269 lf_printf(file, "\n");
3270 lf_printf(file, "\f\n");
3271 }
3272
8a1d8a0b
MM
3273 lf_printf(file, "#ifndef _INLINE_C_\n");
3274 lf_printf(file, "const model_time *const model_time_mapping[ (int)nr_models ] = {\n");
845ff5a4
MM
3275 lf_printf(file, " (const model_time *const)0,\n");
3276 for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
3277 lf_printf(file, " model_time_%s,\n", model_ptr->name);
3278 }
3279 lf_printf(file, "};\n");
8a1d8a0b 3280 lf_printf(file, "#endif\n");
845ff5a4
MM
3281 lf_printf(file, "\n");
3282
80948f39
MM
3283 lf_printf(file, "\f\n");
3284 lf_printf(file, "/* map model enumeration into printable string */\n");
8a1d8a0b
MM
3285 lf_printf(file, "#ifndef _INLINE_C_\n");
3286 lf_printf(file, "const char *model_name[ (int)nr_models ] = {\n");
80948f39
MM
3287 lf_printf(file, " \"NONE\",\n");
3288 for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
3289 lf_printf(file, " \"%s\",\n", model_ptr->printable_name);
3290 }
3291 lf_printf(file, "};\n");
8a1d8a0b 3292 lf_printf(file, "#endif\n");
80948f39
MM
3293 lf_printf(file, "\n");
3294
8a1d8a0b 3295 lf_print_function_type(file, "void", "INLINE_MODEL", "\n");
28816f45
MM
3296 lf_printf(file, "model_set(const char *name)\n");
3297 lf_printf(file, "{\n");
3298 if (models) {
3299 lf_printf(file, " model_enum model;\n");
3300 lf_printf(file, " for(model = MODEL_%s; model < nr_models; model++) {\n", models->name);
fe439e0f 3301 lf_printf(file, " if(strcmp(name, model_name[model]) == 0) {\n");
28816f45
MM
3302 lf_printf(file, " current_model = model;\n");
3303 lf_printf(file, " return;\n");
3304 lf_printf(file, " }\n");
3305 lf_printf(file, " }\n");
3306 lf_printf(file, "\n");
3307 lf_printf(file, " error(\"Unknown model '%%s', Models which are known are:%%s\n\",\n");
3308 lf_printf(file, " name,\n");
3309 lf_printf(file, " \"");
3310 for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
3311 lf_printf(file, "\\n\\t%s", model_ptr->printable_name);
3312 }
3313 lf_printf(file, "\");\n");
3314 } else {
3315 lf_printf(file, " error(\"No models are currently known about\");\n");
3316 }
3317
3318 lf_printf(file, "}\n");
3319 lf_printf(file, "\n");
3320
a3114052 3321 lf_printf(file, "#endif /* _MODEL_C_ */\n");
c143ef62
MM
3322
3323}
3324
3325/****************************************************************/
3326
3327
3328int
3329main(int argc,
3330 char **argv,
3331 char **envp)
3332{
3333 insn_table *instructions = NULL;
3334 icache_tree *cache_fields = NULL;
3335 char *real_file_name = NULL;
3336 int ch;
3337
3338 if (argc == 1) {
3339 printf("Usage:\n");
a983c8f0
MM
3340 printf(" igen <config-opts> ... <input-opts>... <output-opts>...\n");
3341 printf("Config options:\n");
3342 printf(" -f <filter-out-flag> eg -f 64 to skip 64bit instructions\n");
f2181eff
MM
3343 printf(" -e Expand (duplicate) semantic functions\n");
3344 printf(" -r <icache-size> Generate cracking cache version\n");
3345 printf(" -R Use defines to reference cache vars\n");
3346 printf(" -l Supress line numbering in output files\n");
3347 printf(" -b <bit-size> Set the number of bits in an instruction\n");
3348 printf(" -h <high-bit> Set the nr of the high (msb bit)\n");
3349 printf("\n");
a983c8f0
MM
3350 printf("Input options (ucase version also dumps loaded table):\n");
3351 printf(" -[Oo] <opcode-rules>\n");
3352 printf(" -[Kk] <cache-rules>\n");
3353 printf(" -[Ii] <instruction-table>\n");
f2181eff 3354 printf("\n");
a983c8f0
MM
3355 printf("Output options:\n");
3356 printf(" -[Cc] <output-file> output icache.h(C) invalid(c)\n");
3357 printf(" -[Dd] <output-file> output idecode.h(D) idecode.c(d)\n");
a3114052 3358 printf(" -[Mm] <output-file> output model.h(M) model.c(M)\n");
a983c8f0 3359 printf(" -[Ss] <output-file> output schematic.h(S) schematic.c(s)\n");
f2181eff 3360 printf(" -[Tt] <table> output itable.h(T) itable.c(t)\n");
c143ef62
MM
3361 }
3362
3363 while ((ch = getopt(argc, argv,
f2181eff 3364 "leb:h:r:Rf:I:i:O:o:K:k:M:m:n:S:s:D:d:T:t:C:")) != -1) {
c143ef62
MM
3365 fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : ""));
3366 switch(ch) {
3367 case 'l':
3368 number_lines = 0;
3369 break;
3370 case 'e':
3371 idecode_expand_semantics = 1;
3372 break;
3373 case 'r':
3374 idecode_cache = a2i(optarg);
3375 break;
f2181eff
MM
3376 case 'R':
3377 semantics_use_cache_struct = 1;
3378 break;
a983c8f0
MM
3379 case 'b':
3380 insn_size = a2i(optarg);
3381 ASSERT(insn_size > 0 && insn_size <= max_insn_size
3382 && (hi_bit_nr == insn_size-1 || hi_bit_nr == 0));
3383 break;
3384 case 'h':
3385 hi_bit_nr = a2i(optarg);
3386 ASSERT(hi_bit_nr == insn_size-1 || hi_bit_nr == 0);
3387 break;
c143ef62
MM
3388 case 'f':
3389 {
3390 filter *new_filter = ZALLOC(filter);
3391 new_filter->flag = strdup(optarg);
3392 new_filter->next = filters;
3393 filters = new_filter;
3394 break;
3395 }
3396 case 'I':
3397 case 'i':
3398 ASSERT(opcode_table != NULL);
3399 ASSERT(cache_table != NULL);
3400 instructions = insn_table_load_insns(optarg);
3401 fprintf(stderr, "\texpanding ...\n");
3402 insn_table_expand_insns(instructions);
3403 fprintf(stderr, "\tcache fields ...\n");
3404 cache_fields = insn_table_cache_fields(instructions);
3405 if (ch == 'I') {
3406 dump_traverse(instructions);
3407 dump_insn_table(instructions, 0, 1);
3408 }
3409 break;
3410 case 'O':
3411 case 'o':
3412 opcode_table = load_opcode_rules(optarg);
3413 if (ch == 'O')
3414 dump_opcode_rules(opcode_table, 0);
3415 break;
3416 case 'K':
3417 case 'k':
3418 cache_table = load_cache_rules(optarg);
3419 if (ch == 'K')
3420 dump_cache_rules(cache_table, 0);
3421 break;
3422 case 'n':
3423 real_file_name = strdup(optarg);
3424 break;
3425 case 'S':
3426 case 's':
3427 case 'D':
3428 case 'd':
a3114052
MM
3429 case 'M':
3430 case 'm':
c143ef62
MM
3431 case 'T':
3432 case 't':
3433 case 'C':
3434 {
3435 lf *file = lf_open(optarg, real_file_name, number_lines);
3436 ASSERT(instructions != NULL);
3437 switch (ch) {
3438 case 'S':
3439 gen_semantics_h(instructions, file);
3440 break;
3441 case 's':
3442 gen_semantics_c(instructions, file);
3443 break;
3444 case 'D':
3445 gen_idecode_h(instructions, file);
3446 break;
3447 case 'd':
3448 gen_idecode_c(instructions, file);
3449 break;
a3114052
MM
3450 case 'M':
3451 gen_model_h(instructions, file);
3452 break;
3453 case 'm':
3454 gen_model_c(instructions, file);
3455 break;
c143ef62
MM
3456 case 'T':
3457 gen_itable_h(instructions, file);
3458 break;
3459 case 't':
3460 gen_itable_c(instructions, file);
3461 break;
3462 case 'C':
3463 gen_icache_h(cache_fields, file);
3464 break;
3465 }
3466 lf_close(file);
3467 }
3468 real_file_name = NULL;
3469 break;
3470 default:
3471 error("unknown option\n");
3472 }
3473 }
3474 return 0;
3475}
This page took 0.189432 seconds and 4 git commands to generate.