1/*  This file is part of the program psim.
2
3    Copyright 1994, 1995, 1996, 2003 Andrew Cagney
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, see <http://www.gnu.org/licenses/>.
17
18    */
19
20
21#include "misc.h"
22#include "lf.h"
23#include "table.h"
24#include "filter.h"
25#include "ld-decode.h"
26#include "ld-cache.h"
27#include "ld-insn.h"
28
29#include "igen.h"
30
31static model *last_model;
32
33static insn *last_model_macro;
34static insn *last_model_function;
35static insn *last_model_internal;
36static insn *last_model_static;
37static insn *last_model_data;
38
39model *models;
40
41insn *model_macros;
42insn *model_functions;
43insn *model_internal;
44insn *model_static;
45insn *model_data;
46
47int max_model_fields_len;
48
49static void
50update_depth(insn_table *entry,
51	     lf *file,
52	     void *data,
53	     insn *instruction,
54	     int depth)
55{
56  int *max_depth = (int*)data;
57  if (*max_depth < depth)
58    *max_depth = depth;
59}
60
61
62int
63insn_table_depth(insn_table *table)
64{
65  int depth = 0;
66  insn_table_traverse_tree(table,
67			   NULL,
68			   &depth,
69			   1,
70			   NULL, /*start*/
71			   update_depth,
72			   NULL, /*end*/
73			   NULL); /*padding*/
74  return depth;
75}
76
77
78static insn_fields *
79parse_insn_format(table_entry *entry,
80		  const char *format)
81{
82  const char *chp;
83  insn_fields *fields = ZALLOC(insn_fields);
84
85  /* create a leading sentinal */
86  fields->first = ZALLOC(insn_field);
87  fields->first->first = -1;
88  fields->first->last = -1;
89  fields->first->width = 0;
90
91  /* and a trailing sentinal */
92  fields->last = ZALLOC(insn_field);
93  fields->last->first = insn_bit_size;
94  fields->last->last = insn_bit_size;
95  fields->last->width = 0;
96
97  /* link them together */
98  fields->first->next = fields->last;
99  fields->last->prev = fields->first;
100
101  /* now work through the formats */
102  chp = format;
103
104  while (*chp != '\0') {
105    const char *start_pos;
106    const char *start_val;
107    int strlen_val;
108    int strlen_pos;
109    insn_field *new_field;
110
111    /* sanity check */
112    if (!isdigit(*chp)) {
113      error("%s:%d: missing position field at `%s'\n",
114	    entry->file_name, entry->line_nr, chp);
115    }
116
117    /* break out the bit position */
118    start_pos = chp;
119    while (isdigit(*chp))
120      chp++;
121    strlen_pos = chp - start_pos;
122    if (*chp == '.' && strlen_pos > 0)
123      chp++;
124    else {
125      error("%s:%d: missing field value at %s\n",
126	    entry->file_name, entry->line_nr, chp);
127      break;
128    }
129
130    /* break out the value */
131    start_val = chp;
132    while ((*start_val == '/' && *chp == '/')
133	   || (isdigit(*start_val) && isdigit(*chp))
134	   || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_')))
135      chp++;
136    strlen_val = chp - start_val;
137    if (*chp == ',')
138      chp++;
139    else if (*chp != '\0' || strlen_val == 0) {
140      error("%s:%d: missing field terminator at %s\n",
141	    entry->file_name, entry->line_nr, chp);
142      break;
143    }
144
145    /* create a new field and insert it */
146    new_field = ZALLOC(insn_field);
147    new_field->next = fields->last;
148    new_field->prev = fields->last->prev;
149    new_field->next->prev = new_field;
150    new_field->prev->next = new_field;
151
152    /* the value */
153    new_field->val_string = (char*)zalloc(strlen_val+1);
154    strncpy(new_field->val_string, start_val, strlen_val);
155    if (isdigit(*new_field->val_string)) {
156      new_field->val_int = a2i(new_field->val_string);
157      new_field->is_int = 1;
158    }
159    else if (new_field->val_string[0] == '/') {
160      new_field->is_slash = 1;
161    }
162    else {
163      new_field->is_string = 1;
164    }
165
166    /* the pos */
167    new_field->pos_string = (char*)zalloc(strlen_pos+1);
168    strncpy(new_field->pos_string, start_pos, strlen_pos);
169    new_field->first = target_a2i(hi_bit_nr, new_field->pos_string);
170    new_field->last = new_field->next->first - 1; /* guess */
171    new_field->width = new_field->last - new_field->first + 1; /* guess */
172    new_field->prev->last = new_field->first-1; /*fix*/
173    new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/
174  }
175
176  /* fiddle first/last so that the sentinals `disapear' */
177  ASSERT(fields->first->last < 0);
178  ASSERT(fields->last->first >= insn_bit_size);
179  fields->first = fields->first->next;
180  fields->last = fields->last->prev;
181
182  /* now go over this again, pointing each bit position at a field
183     record */
184  {
185    int i;
186    insn_field *field;
187    field = fields->first;
188    for (i = 0; i < insn_bit_size; i++) {
189      while (field->last < i)
190	field = field->next;
191      fields->bits[i] = field;
192    }
193  }
194
195  /* go over each of the fields, and compute a `value' for the insn */
196  {
197    insn_field *field;
198    fields->value = 0;
199    for (field = fields->first;
200	 field->last < insn_bit_size;
201	 field = field->next) {
202      fields->value <<= field->width;
203      if (field->is_int)
204	fields->value |= field->val_int;
205    }
206  }
207  return fields;
208}
209
210
211static void
212parse_include_entry (table *file,
213                     table_entry *file_entry,
214		     filter *filters,
215		     table_include *includes)
216{
217  /* parse the include file_entry */
218  if (file_entry->nr_fields < 4)
219    error ("Incorrect nr fields for include record\n");
220  /* process it */
221  if (!is_filtered_out(file_entry->fields[include_flags], filters))
222    {
223      table_push (file, includes,
224                file_entry->fields[include_path],
225		file_entry->nr_fields, file_entry->nr_fields);
226    }
227}
228
229static void
230model_table_insert(insn_table *table,
231		   table_entry *file_entry)
232{
233  int len;
234
235  /* create a new model */
236  model *new_model = ZALLOC(model);
237
238  new_model->name = file_entry->fields[model_identifer];
239  new_model->printable_name = file_entry->fields[model_name];
240  new_model->insn_default = file_entry->fields[model_default];
241
242  while (*new_model->insn_default && isspace(*new_model->insn_default))
243    new_model->insn_default++;
244
245  len = strlen(new_model->insn_default);
246  if (max_model_fields_len < len)
247    max_model_fields_len = len;
248
249  /* append it to the end of the model list */
250  if (last_model)
251    last_model->next = new_model;
252  else
253    models = new_model;
254  last_model = new_model;
255}
256
257static void
258model_table_insert_specific(insn_table *table,
259			    table_entry *file_entry,
260			    insn **start_ptr,
261			    insn **end_ptr)
262{
263  insn *ptr = ZALLOC(insn);
264  ptr->file_entry = file_entry;
265  if (*end_ptr)
266    (*end_ptr)->next = ptr;
267  else
268    (*start_ptr) = ptr;
269  (*end_ptr) = ptr;
270}
271
272
273static void
274insn_table_insert_function(insn_table *table,
275			   table_entry *file_entry)
276{
277  /* create a new function */
278  insn *new_function = ZALLOC(insn);
279  new_function->file_entry = file_entry;
280
281  /* append it to the end of the function list */
282  if (table->last_function)
283    table->last_function->next = new_function;
284  else
285    table->functions = new_function;
286  table->last_function = new_function;
287}
288
289extern void
290insn_table_insert_insn(insn_table *table,
291		       table_entry *file_entry,
292		       insn_fields *fields)
293{
294  insn **ptr_to_cur_insn = &table->insns;
295  insn *cur_insn = *ptr_to_cur_insn;
296  table_model_entry *insn_model_ptr;
297  model *model_ptr;
298
299  /* create a new instruction */
300  insn *new_insn = ZALLOC(insn);
301  new_insn->file_entry = file_entry;
302  new_insn->fields = fields;
303
304  /* Check out any model information returned to make sure the model
305     is correct.  */
306  for(insn_model_ptr = file_entry->model_first; insn_model_ptr; insn_model_ptr = insn_model_ptr->next) {
307    const char *name = insn_model_ptr->fields[insn_model_name];
308    int len = strlen (insn_model_ptr->fields[insn_model_fields]);
309
310    while (len > 0 && isspace(*insn_model_ptr->fields[insn_model_fields])) {
311      len--;
312      insn_model_ptr->fields[insn_model_fields]++;
313    }
314
315    if (max_model_fields_len < len)
316      max_model_fields_len = len;
317
318    for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) {
319      if (strcmp(name, model_ptr->printable_name) == 0) {
320
321	/* Replace the name field with that of the global model, so that when we
322	   want to print it out, we can just compare pointers.  */
323	insn_model_ptr->fields[insn_model_name] = model_ptr->printable_name;
324	break;
325      }
326    }
327
328    if (!model_ptr)
329      error("%s:%d: machine model `%s' was not known about\n",
330	    file_entry->file_name, file_entry->line_nr, name);
331  }
332
333  /* insert it according to the order of the fields */
334  while (cur_insn != NULL
335	 && new_insn->fields->value >= cur_insn->fields->value) {
336    ptr_to_cur_insn = &cur_insn->next;
337    cur_insn = *ptr_to_cur_insn;
338  }
339
340  new_insn->next = cur_insn;
341  *ptr_to_cur_insn = new_insn;
342
343  table->nr_insn++;
344}
345
346
347
348insn_table *
349load_insn_table(const char *file_name,
350		decode_table *decode_rules,
351		filter *filters,
352		table_include *includes,
353		cache_table **cache_rules)
354{
355  table *file = table_open(file_name, nr_insn_table_fields, nr_insn_model_table_fields);
356  insn_table *table = ZALLOC(insn_table);
357  table_entry *file_entry;
358  table->opcode_rule = decode_rules;
359
360  while ((file_entry = table_entry_read(file)) != NULL) {
361    if (it_is("function", file_entry->fields[insn_flags])
362	|| it_is("internal", file_entry->fields[insn_flags])) {
363      insn_table_insert_function(table, file_entry);
364    }
365    else if ((it_is("function", file_entry->fields[insn_form])
366	      || it_is("internal", file_entry->fields[insn_form]))
367	     && !is_filtered_out(file_entry->fields[insn_flags], filters)) {
368      /* Ok, this is evil.  Need to convert a new style function into
369         an old style function.  Construct an old style table and then
370         copy it back.  */
371      char *fields[nr_insn_table_fields];
372      memset (fields, 0, sizeof fields);
373      fields[insn_flags] = file_entry->fields[insn_form];
374      fields[function_type] = file_entry->fields[insn_name];
375      fields[function_name] = file_entry->fields[insn_comment];
376      fields[function_param] = file_entry->fields[insn_field_6];
377      memcpy (file_entry->fields, fields,
378	      sizeof (fields[0]) * file_entry->nr_fields);
379      insn_table_insert_function(table, file_entry);
380#if 0
381      ":" "..."
382       ":" <filter-flags>
383       ":" <filter-models>
384       ":" <typedef>
385       ":" <name>
386       [ ":" <parameter-list> ]
387       <nl>
388       [ <function-model> ]
389       <code-block>
390#endif
391    }
392    else if (it_is("model", file_entry->fields[insn_flags])) {
393      model_table_insert(table, file_entry);
394    }
395    else if (it_is("model-macro", file_entry->fields[insn_flags])) {
396      model_table_insert_specific(table, file_entry, &model_macros, &last_model_macro);
397    }
398    else if (it_is("model-function", file_entry->fields[insn_flags])) {
399      model_table_insert_specific(table, file_entry, &model_functions, &last_model_function);
400    }
401    else if (it_is("model-internal", file_entry->fields[insn_flags])) {
402      model_table_insert_specific(table, file_entry, &model_internal, &last_model_internal);
403    }
404    else if (it_is("model-static", file_entry->fields[insn_flags])) {
405      model_table_insert_specific(table, file_entry, &model_static, &last_model_static);
406    }
407    else if (it_is("model-data", file_entry->fields[insn_flags])) {
408      model_table_insert_specific(table, file_entry, &model_data, &last_model_data);
409    }
410    else if (it_is("include", file_entry->fields[insn_form])
411             && !is_filtered_out(file_entry->fields[insn_flags], filters)) {
412      parse_include_entry (file, file_entry, filters, includes);
413    }
414    else if ((it_is("cache", file_entry->fields[insn_form])
415	      || it_is("compute", file_entry->fields[insn_form])
416	      || it_is("scratch", file_entry->fields[insn_form]))
417	     && !is_filtered_out(file_entry->fields[insn_flags], filters)) {
418      append_cache_rule (cache_rules,
419			 file_entry->fields[insn_form], /* type */
420			 file_entry->fields[cache_name],
421			 file_entry->fields[cache_derived_name],
422			 file_entry->fields[cache_type_def],
423			 file_entry->fields[cache_expression],
424			 file_entry);
425    }
426    else {
427      insn_fields *fields;
428      /* skip instructions that aren't relevant to the mode */
429      if (is_filtered_out(file_entry->fields[insn_flags], filters)) {
430	fprintf(stderr, "Dropping %s - %s\n",
431		file_entry->fields[insn_name],
432		file_entry->fields[insn_flags]);
433      }
434      else {
435	/* create/insert the new instruction */
436	fields = parse_insn_format(file_entry,
437				   file_entry->fields[insn_format]);
438	insn_table_insert_insn(table, file_entry, fields);
439      }
440    }
441  }
442  return table;
443}
444
445
446extern void
447insn_table_traverse_tree(insn_table *table,
448			 lf *file,
449			 void *data,
450			 int depth,
451			 leaf_handler *start,
452			 insn_handler *leaf,
453			 leaf_handler *end,
454			 padding_handler *padding)
455{
456  insn_table *entry;
457  int entry_nr;
458
459  ASSERT(table != NULL
460	 && table->opcode != NULL
461	 && table->nr_entries > 0
462	 && table->entries != 0);
463
464  if (start != NULL && depth >= 0)
465    start(table, file, data, depth);
466
467  for (entry_nr = 0, entry = table->entries;
468       entry_nr < (table->opcode->is_boolean
469		   ? 2
470		   : (1 << (table->opcode->last - table->opcode->first + 1)));
471       entry_nr ++) {
472    if (entry == NULL
473	|| (!table->opcode->is_boolean
474	    && entry_nr < entry->opcode_nr)) {
475      if (padding != NULL && depth >= 0)
476	padding(table, file, data, depth, entry_nr);
477    }
478    else {
479      ASSERT(entry != NULL && (entry->opcode_nr == entry_nr
480			       || table->opcode->is_boolean));
481      if (entry->opcode != NULL && depth != 0) {
482	insn_table_traverse_tree(entry, file, data, depth+1,
483				 start, leaf, end, padding);
484      }
485      else if (depth >= 0) {
486	if (leaf != NULL)
487	  leaf(entry, file, data, entry->insns, depth);
488      }
489      entry = entry->sibling;
490    }
491  }
492  if (end != NULL && depth >= 0)
493    end(table, file, data, depth);
494}
495
496
497extern void
498insn_table_traverse_function(insn_table *table,
499			     lf *file,
500			     void *data,
501			     function_handler *leaf)
502{
503  insn *function;
504  for (function = table->functions;
505       function != NULL;
506       function = function->next) {
507    leaf(table, file, data, function->file_entry);
508  }
509}
510
511extern void
512insn_table_traverse_insn(insn_table *table,
513			 lf *file,
514			 void *data,
515			 insn_handler *handler)
516{
517  insn *instruction;
518  for (instruction = table->insns;
519       instruction != NULL;
520       instruction = instruction->next) {
521    handler(table, file, data, instruction, 0);
522  }
523}
524
525
526/****************************************************************/
527
528typedef enum {
529  field_constant_int = 1,
530  field_constant_slash = 2,
531  field_constant_string = 3
532} constant_field_types;
533
534
535static int
536insn_field_is_constant(insn_field *field,
537		       decode_table *rule)
538{
539  /* field is an integer */
540  if (field->is_int)
541    return field_constant_int;
542  /* field is `/' and treating that as a constant */
543  if (field->is_slash && rule->force_slash)
544    return field_constant_slash;
545  /* field, though variable is on the list */
546  if (field->is_string && rule->force_expansion != NULL) {
547    const char *forced_fields = rule->force_expansion;
548    while (*forced_fields != '\0') {
549      int field_len;
550      const char *end = strchr(forced_fields, ',');
551      if (end == NULL)
552	field_len = strlen(forced_fields);
553      else
554	field_len = end-forced_fields;
555      if (strncmp(forced_fields, field->val_string, field_len) == 0
556	  && field->val_string[field_len] == '\0')
557	return field_constant_string;
558      forced_fields += field_len;
559      if (*forced_fields == ',')
560	forced_fields++;
561    }
562  }
563  return 0;
564}
565
566
567static opcode_field *
568insn_table_find_opcode_field(insn *insns,
569			     decode_table *rule,
570			     int string_only)
571{
572  opcode_field *curr_opcode = ZALLOC(opcode_field);
573  insn *entry;
574  ASSERT(rule);
575
576  curr_opcode->first = insn_bit_size;
577  curr_opcode->last = -1;
578  for (entry = insns; entry != NULL; entry = entry->next) {
579    insn_fields *fields = entry->fields;
580    opcode_field new_opcode;
581
582    /* find a start point for the opcode field */
583    new_opcode.first = rule->first;
584    while (new_opcode.first <= rule->last
585	   && (!string_only
586	       || insn_field_is_constant(fields->bits[new_opcode.first],
587					 rule) != field_constant_string)
588	   && (string_only
589	       || !insn_field_is_constant(fields->bits[new_opcode.first],
590					  rule)))
591      new_opcode.first = fields->bits[new_opcode.first]->last + 1;
592    ASSERT(new_opcode.first > rule->last
593	   || (string_only
594	       && insn_field_is_constant(fields->bits[new_opcode.first],
595					 rule) == field_constant_string)
596	   || (!string_only
597	       && insn_field_is_constant(fields->bits[new_opcode.first],
598					 rule)));
599
600    /* find the end point for the opcode field */
601    new_opcode.last = rule->last;
602    while (new_opcode.last >= rule->first
603	   && (!string_only
604	       || insn_field_is_constant(fields->bits[new_opcode.last],
605					 rule) != field_constant_string)
606	   && (string_only
607	       || !insn_field_is_constant(fields->bits[new_opcode.last],
608					  rule)))
609      new_opcode.last = fields->bits[new_opcode.last]->first - 1;
610    ASSERT(new_opcode.last < rule->first
611	   || (string_only
612	       && insn_field_is_constant(fields->bits[new_opcode.last],
613					 rule) == field_constant_string)
614	   || (!string_only
615	       && insn_field_is_constant(fields->bits[new_opcode.last],
616					 rule)));
617
618    /* now see if our current opcode needs expanding */
619    if (new_opcode.first <= rule->last
620	&& curr_opcode->first > new_opcode.first)
621      curr_opcode->first = new_opcode.first;
622    if (new_opcode.last >= rule->first
623	&& curr_opcode->last < new_opcode.last)
624      curr_opcode->last = new_opcode.last;
625
626  }
627
628  /* was any thing interesting found? */
629  if (curr_opcode->first > rule->last) {
630    ASSERT(curr_opcode->last < rule->first);
631    return NULL;
632  }
633  ASSERT(curr_opcode->last >= rule->first);
634  ASSERT(curr_opcode->first <= rule->last);
635
636  /* if something was found, check it includes the forced field range */
637  if (!string_only
638      && curr_opcode->first > rule->force_first) {
639    curr_opcode->first = rule->force_first;
640  }
641  if (!string_only
642      && curr_opcode->last < rule->force_last) {
643    curr_opcode->last = rule->force_last;
644  }
645  /* handle special case elminating any need to do shift after mask */
646  if (string_only
647      && rule->force_last == insn_bit_size-1) {
648    curr_opcode->last = insn_bit_size-1;
649  }
650
651  /* handle any special cases */
652  switch (rule->type) {
653  case normal_decode_rule:
654    /* let the above apply */
655    break;
656  case expand_forced_rule:
657    /* expand a limited nr of bits, ignoring the rest */
658    curr_opcode->first = rule->force_first;
659    curr_opcode->last = rule->force_last;
660    break;
661  case boolean_rule:
662    curr_opcode->is_boolean = 1;
663    curr_opcode->boolean_constant = rule->special_constant;
664    break;
665  default:
666    error("Something is going wrong\n");
667  }
668
669  return curr_opcode;
670}
671
672
673static void
674insn_table_insert_expanded(insn_table *table,
675			   insn *old_insn,
676			   int new_opcode_nr,
677			   insn_bits *new_bits)
678{
679  insn_table **ptr_to_cur_entry = &table->entries;
680  insn_table *cur_entry = *ptr_to_cur_entry;
681
682  /* find the new table for this entry */
683  while (cur_entry != NULL
684	 && cur_entry->opcode_nr < new_opcode_nr) {
685    ptr_to_cur_entry = &cur_entry->sibling;
686    cur_entry = *ptr_to_cur_entry;
687  }
688
689  if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) {
690    insn_table *new_entry = ZALLOC(insn_table);
691    new_entry->opcode_nr = new_opcode_nr;
692    new_entry->expanded_bits = new_bits;
693    new_entry->opcode_rule = table->opcode_rule->next;
694    new_entry->sibling = cur_entry;
695    new_entry->parent = table;
696    *ptr_to_cur_entry = new_entry;
697    cur_entry = new_entry;
698    table->nr_entries++;
699  }
700  /* ASSERT new_bits == cur_entry bits */
701  ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr);
702  insn_table_insert_insn(cur_entry,
703			 old_insn->file_entry,
704			 old_insn->fields);
705}
706
707static void
708insn_table_expand_opcode(insn_table *table,
709			 insn *instruction,
710			 int field_nr,
711			 int opcode_nr,
712			 insn_bits *bits)
713{
714
715  if (field_nr > table->opcode->last) {
716    insn_table_insert_expanded(table, instruction, opcode_nr, bits);
717  }
718  else {
719    insn_field *field = instruction->fields->bits[field_nr];
720    if (field->is_int || field->is_slash) {
721      ASSERT(field->first >= table->opcode->first
722	     && field->last <= table->opcode->last);
723      insn_table_expand_opcode(table, instruction, field->last+1,
724			       ((opcode_nr << field->width) + field->val_int),
725			       bits);
726    }
727    else {
728      int val;
729      int last_pos = ((field->last < table->opcode->last)
730			? field->last : table->opcode->last);
731      int first_pos = ((field->first > table->opcode->first)
732			 ? field->first : table->opcode->first);
733      int width = last_pos - first_pos + 1;
734      int last_val = (table->opcode->is_boolean
735		      ? 2 : (1 << width));
736      for (val = 0; val < last_val; val++) {
737	insn_bits *new_bits = ZALLOC(insn_bits);
738	new_bits->field = field;
739	new_bits->value = val;
740	new_bits->last = bits;
741	new_bits->opcode = table->opcode;
742	insn_table_expand_opcode(table, instruction, last_pos+1,
743				 ((opcode_nr << width) | val),
744				 new_bits);
745      }
746    }
747  }
748}
749
750static void
751insn_table_insert_expanding(insn_table *table,
752			    insn *entry)
753{
754  insn_table_expand_opcode(table,
755			   entry,
756			   table->opcode->first,
757			   0,
758			   table->expanded_bits);
759}
760
761
762extern void
763insn_table_expand_insns(insn_table *table)
764{
765
766  ASSERT(table->nr_insn >= 1);
767
768  /* determine a valid opcode */
769  while (table->opcode_rule) {
770    /* specials only for single instructions */
771    if ((table->nr_insn > 1
772	 && table->opcode_rule->special_mask == 0
773	 && table->opcode_rule->type == normal_decode_rule)
774	|| (table->nr_insn == 1
775	    && table->opcode_rule->special_mask != 0
776	    && ((table->insns->fields->value
777		 & table->opcode_rule->special_mask)
778		== table->opcode_rule->special_value))
779	|| (generate_expanded_instructions
780	    && table->opcode_rule->special_mask == 0
781	    && table->opcode_rule->type == normal_decode_rule))
782      table->opcode =
783	insn_table_find_opcode_field(table->insns,
784				     table->opcode_rule,
785				     table->nr_insn == 1/*string*/
786				     );
787    if (table->opcode != NULL)
788      break;
789    table->opcode_rule = table->opcode_rule->next;
790  }
791
792  /* did we find anything */
793  if (table->opcode == NULL) {
794    return;
795  }
796  ASSERT(table->opcode != NULL);
797
798  /* back link what we found to its parent */
799  if (table->parent != NULL) {
800    ASSERT(table->parent->opcode != NULL);
801    table->opcode->parent = table->parent->opcode;
802  }
803
804  /* expand the raw instructions according to the opcode */
805  {
806    insn *entry;
807    for (entry = table->insns; entry != NULL; entry = entry->next) {
808      insn_table_insert_expanding(table, entry);
809    }
810  }
811
812  /* and do the same for the sub entries */
813  {
814    insn_table *entry;
815    for (entry = table->entries; entry != NULL; entry =  entry->sibling) {
816      insn_table_expand_insns(entry);
817    }
818  }
819}
820
821
822
823
824#ifdef MAIN
825
826static void
827dump_insn_field(insn_field *field,
828		int indent)
829{
830  printf ("(insn_field*)%p\n", field);
831  dumpf (indent, "(first %d)\n", field->first);
832  dumpf (indent, "(last %d)\n", field->last);
833  dumpf (indent, "(width %d)\n", field->width);
834  if (field->is_int)
835    dumpf (indent, "(is_int %d)\n", field->val_int);
836  if (field->is_slash)
837    dumpf (indent, "(is_slash)\n");
838  if (field->is_string)
839    dumpf (indent, "(is_string `%s')\n", field->val_string);
840  dumpf (indent, "(next %p)\n", field->next);
841  dumpf (indent, "(prev %p)\n", field->prev);
842}
843
844static void
845dump_insn_fields(insn_fields *fields,
846		 int indent)
847{
848  int i;
849
850  printf("(insn_fields*)%p\n", fields);
851
852  dumpf(indent, "(first %p)\n", fields->first);
853  dumpf(indent, "(last %p)\n", fields->last);
854
855  dumpf(indent, "(value 0x%x)\n", fields->value);
856
857  for (i = 0; i < insn_bit_size; i++) {
858    dumpf(indent, "(bits[%d]", i);
859    dump_insn_field(fields->bits[i], indent+1);
860    dumpf(indent, " )\n");
861  }
862
863}
864
865
866static void
867dump_opcode_field(opcode_field *field, int indent, int levels)
868{
869  printf("(opcode_field*)%p\n", field);
870  if (levels && field != NULL) {
871    dumpf(indent, "(first %d)\n", field->first);
872    dumpf(indent, "(last %d)\n", field->last);
873    dumpf(indent, "(is_boolean %d)\n", field->is_boolean);
874    dumpf(indent, "(parent ");
875    dump_opcode_field(field->parent, indent, levels-1);
876  }
877}
878
879
880static void
881dump_insn_bits(insn_bits *bits, int indent, int levels)
882{
883  printf("(insn_bits*)%p\n", bits);
884
885  if (levels && bits != NULL) {
886    dumpf(indent, "(value %d)\n", bits->value);
887    dumpf(indent, "(opcode ");
888    dump_opcode_field(bits->opcode, indent+1, 0);
889    dumpf(indent, " )\n");
890    dumpf(indent, "(field ");
891    dump_insn_field(bits->field, indent+1);
892    dumpf(indent, " )\n");
893    dumpf(indent, "(last ");
894    dump_insn_bits(bits->last, indent+1, levels-1);
895  }
896}
897
898
899
900static void
901dump_insn(insn *entry, int indent, int levels)
902{
903  printf("(insn*)%p\n", entry);
904
905  if (levels && entry != NULL) {
906
907    dumpf(indent, "(file_entry ");
908    dump_table_entry(entry->file_entry, indent+1);
909    dumpf(indent, " )\n");
910
911    dumpf(indent, "(fields ");
912    dump_insn_fields(entry->fields, indent+1);
913    dumpf(indent, " )\n");
914
915    dumpf(indent, "(next ");
916    dump_insn(entry->next, indent+1, levels-1);
917    dumpf(indent, " )\n");
918
919  }
920
921}
922
923
924static void
925dump_insn_table(insn_table *table,
926		int indent, int levels)
927{
928
929  printf("(insn_table*)%p\n", table);
930
931  if (levels && table != NULL) {
932
933    dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr);
934
935    dumpf(indent, "(expanded_bits ");
936    dump_insn_bits(table->expanded_bits, indent+1, -1);
937    dumpf(indent, " )\n");
938
939    dumpf(indent, "(int nr_insn %d)\n", table->nr_insn);
940
941    dumpf(indent, "(insns ");
942    dump_insn(table->insns, indent+1, table->nr_insn);
943    dumpf(indent, " )\n");
944
945    dumpf(indent, "(opcode_rule ");
946    dump_decode_rule(table->opcode_rule, indent+1);
947    dumpf(indent, " )\n");
948
949    dumpf(indent, "(opcode ");
950    dump_opcode_field(table->opcode, indent+1, 1);
951    dumpf(indent, " )\n");
952
953    dumpf(indent, "(nr_entries %d)\n", table->nr_entries);
954    dumpf(indent, "(entries ");
955    dump_insn_table(table->entries, indent+1, table->nr_entries);
956    dumpf(indent, " )\n");
957
958    dumpf(indent, "(sibling ");
959    dump_insn_table(table->sibling, indent+1, levels-1);
960    dumpf(indent, " )\n");
961
962    dumpf(indent, "(parent ");
963    dump_insn_table(table->parent, indent+1, 0);
964    dumpf(indent, " )\n");
965
966  }
967}
968
969int insn_bit_size = max_insn_bit_size;
970int hi_bit_nr;
971int generate_expanded_instructions;
972
973int
974main(int argc, char **argv)
975{
976  filter *filters = NULL;
977  decode_table *decode_rules = NULL;
978  insn_table *instructions = NULL;
979  cache_table *cache_rules = NULL;
980
981  if (argc != 5)
982    error("Usage: insn <filter> <hi-bit-nr> <decode-table> <insn-table>\n");
983
984  filters = new_filter(argv[1], filters);
985  hi_bit_nr = a2i(argv[2]);
986  ASSERT(hi_bit_nr < insn_bit_size);
987  decode_rules = load_decode_table(argv[3], hi_bit_nr);
988  instructions = load_insn_table(argv[4], decode_rules, filters, NULL,
989				 &cache_rules);
990  insn_table_expand_insns(instructions);
991
992  dump_insn_table(instructions, 0, -1);
993  return 0;
994}
995
996#endif
997