OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [sim/] [igen/] [gen.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* The IGEN simulator generator for GDB, the GNU Debugger.
/* The IGEN simulator generator for GDB, the GNU Debugger.
 
 
   Copyright 2002, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   Copyright 2002, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 
   Contributed by Andrew Cagney.
   Contributed by Andrew Cagney.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 
 
#include "misc.h"
#include "misc.h"
#include "lf.h"
#include "lf.h"
#include "table.h"
#include "table.h"
#include "filter.h"
#include "filter.h"
 
 
#include "igen.h"
#include "igen.h"
#include "ld-insn.h"
#include "ld-insn.h"
#include "ld-decode.h"
#include "ld-decode.h"
#include "gen.h"
#include "gen.h"
 
 
static insn_uint
static insn_uint
sub_val (insn_uint val, int val_last_pos, int first_pos, int last_pos)
sub_val (insn_uint val, int val_last_pos, int first_pos, int last_pos)
{
{
  return ((val >> (val_last_pos - last_pos))
  return ((val >> (val_last_pos - last_pos))
          & (((insn_uint) 1 << (last_pos - first_pos + 1)) - 1));
          & (((insn_uint) 1 << (last_pos - first_pos + 1)) - 1));
}
}
 
 
static void
static void
update_depth (lf *file, gen_entry *entry, int depth, void *data)
update_depth (lf *file, gen_entry *entry, int depth, void *data)
{
{
  int *max_depth = (int *) data;
  int *max_depth = (int *) data;
  if (*max_depth < depth)
  if (*max_depth < depth)
    *max_depth = depth;
    *max_depth = depth;
}
}
 
 
 
 
int
int
gen_entry_depth (gen_entry *table)
gen_entry_depth (gen_entry *table)
{
{
  int depth = 0;
  int depth = 0;
  gen_entry_traverse_tree (NULL, table, 1, NULL,        /*start */
  gen_entry_traverse_tree (NULL, table, 1, NULL,        /*start */
                           update_depth, NULL,  /*end */
                           update_depth, NULL,  /*end */
                           &depth);     /* data */
                           &depth);     /* data */
  return depth;
  return depth;
}
}
 
 
 
 
static void
static void
print_gen_entry_path (line_ref *line, gen_entry *table, error_func *print)
print_gen_entry_path (line_ref *line, gen_entry *table, error_func *print)
{
{
  if (table->parent == NULL)
  if (table->parent == NULL)
    {
    {
      if (table->top->model != NULL)
      if (table->top->model != NULL)
        print (line, "%s", table->top->model->name);
        print (line, "%s", table->top->model->name);
      else
      else
        print (line, "");
        print (line, "");
    }
    }
  else
  else
    {
    {
      print_gen_entry_path (line, table->parent, print);
      print_gen_entry_path (line, table->parent, print);
      print (NULL, ".%d", table->opcode_nr);
      print (NULL, ".%d", table->opcode_nr);
    }
    }
}
}
 
 
static void
static void
print_gen_entry_insns (gen_entry *table,
print_gen_entry_insns (gen_entry *table,
                       error_func *print,
                       error_func *print,
                       char *first_message, char *next_message)
                       char *first_message, char *next_message)
{
{
  insn_list *i;
  insn_list *i;
  char *message;
  char *message;
  message = first_message;
  message = first_message;
  for (i = table->insns; i != NULL; i = i->next)
  for (i = table->insns; i != NULL; i = i->next)
    {
    {
      insn_entry *insn = i->insn;
      insn_entry *insn = i->insn;
      print_gen_entry_path (insn->line, table, print);
      print_gen_entry_path (insn->line, table, print);
      print (NULL, ": %s.%s %s\n", insn->format_name, insn->name, message);
      print (NULL, ": %s.%s %s\n", insn->format_name, insn->name, message);
      if (next_message != NULL)
      if (next_message != NULL)
        message = next_message;
        message = next_message;
    }
    }
}
}
 
 
/* same as strcmp */
/* same as strcmp */
static int
static int
insn_field_cmp (insn_word_entry *l, insn_word_entry *r)
insn_field_cmp (insn_word_entry *l, insn_word_entry *r)
{
{
  while (1)
  while (1)
    {
    {
      int bit_nr;
      int bit_nr;
      if (l == NULL && r == NULL)
      if (l == NULL && r == NULL)
        return 0;                /* all previous fields the same */
        return 0;                /* all previous fields the same */
      if (l == NULL)
      if (l == NULL)
        return -1;              /* left shorter than right */
        return -1;              /* left shorter than right */
      if (r == NULL)
      if (r == NULL)
        return +1;              /* left longer than right */
        return +1;              /* left longer than right */
      for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
      for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
        {
        {
          if (l->bit[bit_nr]->field->type != insn_field_string)
          if (l->bit[bit_nr]->field->type != insn_field_string)
            continue;
            continue;
          if (r->bit[bit_nr]->field->type != insn_field_string)
          if (r->bit[bit_nr]->field->type != insn_field_string)
            continue;
            continue;
          if (l->bit[bit_nr]->field->conditions == NULL)
          if (l->bit[bit_nr]->field->conditions == NULL)
            continue;
            continue;
          if (r->bit[bit_nr]->field->conditions == NULL)
          if (r->bit[bit_nr]->field->conditions == NULL)
            continue;
            continue;
          if (0)
          if (0)
            printf ("%s%s%s VS %s%s%s\n",
            printf ("%s%s%s VS %s%s%s\n",
                    l->bit[bit_nr]->field->val_string,
                    l->bit[bit_nr]->field->val_string,
                    l->bit[bit_nr]->field->conditions->test ==
                    l->bit[bit_nr]->field->conditions->test ==
                    insn_field_cond_eq ? "=" : "!",
                    insn_field_cond_eq ? "=" : "!",
                    l->bit[bit_nr]->field->conditions->string,
                    l->bit[bit_nr]->field->conditions->string,
                    r->bit[bit_nr]->field->val_string,
                    r->bit[bit_nr]->field->val_string,
                    r->bit[bit_nr]->field->conditions->test ==
                    r->bit[bit_nr]->field->conditions->test ==
                    insn_field_cond_eq ? "=" : "!",
                    insn_field_cond_eq ? "=" : "!",
                    r->bit[bit_nr]->field->conditions->string);
                    r->bit[bit_nr]->field->conditions->string);
          if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq
          if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq
              && r->bit[bit_nr]->field->conditions->test ==
              && r->bit[bit_nr]->field->conditions->test ==
              insn_field_cond_eq)
              insn_field_cond_eq)
            {
            {
              if (l->bit[bit_nr]->field->conditions->type ==
              if (l->bit[bit_nr]->field->conditions->type ==
                  insn_field_cond_field
                  insn_field_cond_field
                  && r->bit[bit_nr]->field->conditions->type ==
                  && r->bit[bit_nr]->field->conditions->type ==
                  insn_field_cond_field)
                  insn_field_cond_field)
                /* somewhat arbitrary */
                /* somewhat arbitrary */
                {
                {
                  int cmp = strcmp (l->bit[bit_nr]->field->conditions->string,
                  int cmp = strcmp (l->bit[bit_nr]->field->conditions->string,
                                    r->bit[bit_nr]->field->conditions->
                                    r->bit[bit_nr]->field->conditions->
                                    string);
                                    string);
                  if (cmp != 0)
                  if (cmp != 0)
                    return cmp;
                    return cmp;
                  else
                  else
                    continue;
                    continue;
                }
                }
              if (l->bit[bit_nr]->field->conditions->type ==
              if (l->bit[bit_nr]->field->conditions->type ==
                  insn_field_cond_field)
                  insn_field_cond_field)
                return +1;
                return +1;
              if (r->bit[bit_nr]->field->conditions->type ==
              if (r->bit[bit_nr]->field->conditions->type ==
                  insn_field_cond_field)
                  insn_field_cond_field)
                return -1;
                return -1;
              /* The case of both fields having constant values should have
              /* The case of both fields having constant values should have
                 already have been handled because such fields are converted
                 already have been handled because such fields are converted
                 into normal constant fields. */
                 into normal constant fields. */
              continue;
              continue;
            }
            }
          if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq)
          if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq)
            return +1;          /* left = only */
            return +1;          /* left = only */
          if (r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq)
          if (r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq)
            return -1;          /* right = only */
            return -1;          /* right = only */
          /* FIXME: Need to some what arbitrarily order conditional lists */
          /* FIXME: Need to some what arbitrarily order conditional lists */
          continue;
          continue;
        }
        }
      l = l->next;
      l = l->next;
      r = r->next;
      r = r->next;
    }
    }
}
}
 
 
/* same as strcmp */
/* same as strcmp */
static int
static int
insn_word_cmp (insn_word_entry *l, insn_word_entry *r)
insn_word_cmp (insn_word_entry *l, insn_word_entry *r)
{
{
  while (1)
  while (1)
    {
    {
      int bit_nr;
      int bit_nr;
      if (l == NULL && r == NULL)
      if (l == NULL && r == NULL)
        return 0;                /* all previous fields the same */
        return 0;                /* all previous fields the same */
      if (l == NULL)
      if (l == NULL)
        return -1;              /* left shorter than right */
        return -1;              /* left shorter than right */
      if (r == NULL)
      if (r == NULL)
        return +1;              /* left longer than right */
        return +1;              /* left longer than right */
      for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
      for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
        {
        {
          if (l->bit[bit_nr]->mask < r->bit[bit_nr]->mask)
          if (l->bit[bit_nr]->mask < r->bit[bit_nr]->mask)
            return -1;
            return -1;
          if (l->bit[bit_nr]->mask > r->bit[bit_nr]->mask)
          if (l->bit[bit_nr]->mask > r->bit[bit_nr]->mask)
            return 1;
            return 1;
          if (l->bit[bit_nr]->value < r->bit[bit_nr]->value)
          if (l->bit[bit_nr]->value < r->bit[bit_nr]->value)
            return -1;
            return -1;
          if (l->bit[bit_nr]->value > r->bit[bit_nr]->value)
          if (l->bit[bit_nr]->value > r->bit[bit_nr]->value)
            return 1;
            return 1;
        }
        }
      l = l->next;
      l = l->next;
      r = r->next;
      r = r->next;
    }
    }
}
}
 
 
/* same as strcmp */
/* same as strcmp */
static int
static int
opcode_bit_cmp (opcode_bits *l, opcode_bits *r)
opcode_bit_cmp (opcode_bits *l, opcode_bits *r)
{
{
  if (l == NULL && r == NULL)
  if (l == NULL && r == NULL)
    return 0;                    /* all previous bits the same */
    return 0;                    /* all previous bits the same */
  if (l == NULL)
  if (l == NULL)
    return -1;                  /* left shorter than right */
    return -1;                  /* left shorter than right */
  if (r == NULL)
  if (r == NULL)
    return +1;                  /* left longer than right */
    return +1;                  /* left longer than right */
  /* most significant word */
  /* most significant word */
  if (l->field->word_nr < r->field->word_nr)
  if (l->field->word_nr < r->field->word_nr)
    return +1;                  /* left has more significant word */
    return +1;                  /* left has more significant word */
  if (l->field->word_nr > r->field->word_nr)
  if (l->field->word_nr > r->field->word_nr)
    return -1;                  /* right has more significant word */
    return -1;                  /* right has more significant word */
  /* most significant bit? */
  /* most significant bit? */
  if (l->first < r->first)
  if (l->first < r->first)
    return +1;                  /* left as more significant bit */
    return +1;                  /* left as more significant bit */
  if (l->first > r->first)
  if (l->first > r->first)
    return -1;                  /* right as more significant bit */
    return -1;                  /* right as more significant bit */
  /* nr bits? */
  /* nr bits? */
  if (l->last < r->last)
  if (l->last < r->last)
    return +1;                  /* left as less bits */
    return +1;                  /* left as less bits */
  if (l->last > r->last)
  if (l->last > r->last)
    return -1;                  /* right as less bits */
    return -1;                  /* right as less bits */
  /* value? */
  /* value? */
  if (l->value < r->value)
  if (l->value < r->value)
    return -1;
    return -1;
  if (l->value > r->value)
  if (l->value > r->value)
    return 1;
    return 1;
  return 0;
  return 0;
}
}
 
 
 
 
/* same as strcmp */
/* same as strcmp */
static int
static int
opcode_bits_cmp (opcode_bits *l, opcode_bits *r)
opcode_bits_cmp (opcode_bits *l, opcode_bits *r)
{
{
  while (1)
  while (1)
    {
    {
      int cmp;
      int cmp;
      if (l == NULL && r == NULL)
      if (l == NULL && r == NULL)
        return 0;                /* all previous bits the same */
        return 0;                /* all previous bits the same */
      cmp = opcode_bit_cmp (l, r);
      cmp = opcode_bit_cmp (l, r);
      if (cmp != 0)
      if (cmp != 0)
        return cmp;
        return cmp;
      l = l->next;
      l = l->next;
      r = r->next;
      r = r->next;
    }
    }
}
}
 
 
/* same as strcmp */
/* same as strcmp */
static opcode_bits *
static opcode_bits *
new_opcode_bits (opcode_bits *old_bits,
new_opcode_bits (opcode_bits *old_bits,
                 int value,
                 int value,
                 int first,
                 int first,
                 int last, insn_field_entry *field, opcode_field *opcode)
                 int last, insn_field_entry *field, opcode_field *opcode)
{
{
  opcode_bits *new_bits = ZALLOC (opcode_bits);
  opcode_bits *new_bits = ZALLOC (opcode_bits);
  new_bits->field = field;
  new_bits->field = field;
  new_bits->value = value;
  new_bits->value = value;
  new_bits->first = first;
  new_bits->first = first;
  new_bits->last = last;
  new_bits->last = last;
  new_bits->opcode = opcode;
  new_bits->opcode = opcode;
 
 
  if (old_bits != NULL)
  if (old_bits != NULL)
    {
    {
      opcode_bits *new_list;
      opcode_bits *new_list;
      opcode_bits **last = &new_list;
      opcode_bits **last = &new_list;
      new_list = new_opcode_bits (old_bits->next,
      new_list = new_opcode_bits (old_bits->next,
                                  old_bits->value,
                                  old_bits->value,
                                  old_bits->first,
                                  old_bits->first,
                                  old_bits->last,
                                  old_bits->last,
                                  old_bits->field, old_bits->opcode);
                                  old_bits->field, old_bits->opcode);
      while (*last != NULL)
      while (*last != NULL)
        {
        {
          int cmp = opcode_bit_cmp (new_bits, *last);
          int cmp = opcode_bit_cmp (new_bits, *last);
          if (cmp < 0)           /* new < new_list */
          if (cmp < 0)           /* new < new_list */
            {
            {
              break;
              break;
            }
            }
          if (cmp == 0)
          if (cmp == 0)
            {
            {
              ERROR ("Duplicated insn bits in list");
              ERROR ("Duplicated insn bits in list");
            }
            }
          last = &(*last)->next;
          last = &(*last)->next;
        }
        }
      new_bits->next = *last;
      new_bits->next = *last;
      *last = new_bits;
      *last = new_bits;
      return new_list;
      return new_list;
    }
    }
  else
  else
    {
    {
      return new_bits;
      return new_bits;
    }
    }
}
}
 
 
/* Same as strcmp().  */
/* Same as strcmp().  */
static int
static int
name_cmp (const char *l, const char *r)
name_cmp (const char *l, const char *r)
{
{
  if (l == NULL && r == NULL)
  if (l == NULL && r == NULL)
    return 0;
    return 0;
  if (l != NULL && r == NULL)
  if (l != NULL && r == NULL)
    return -1;
    return -1;
  if (l == NULL && r != NULL)
  if (l == NULL && r != NULL)
    return +1;
    return +1;
  return strcmp (l, r);
  return strcmp (l, r);
}
}
 
 
 
 
typedef enum
typedef enum
{
{
  merge_duplicate_insns,
  merge_duplicate_insns,
  report_duplicate_insns,
  report_duplicate_insns,
}
}
duplicate_insn_actions;
duplicate_insn_actions;
 
 
static insn_list *
static insn_list *
insn_list_insert (insn_list **cur_insn_ptr,
insn_list_insert (insn_list **cur_insn_ptr,
                  int *nr_insns,
                  int *nr_insns,
                  insn_entry * insn,
                  insn_entry * insn,
                  opcode_bits *expanded_bits,
                  opcode_bits *expanded_bits,
                  opcode_field *opcodes,
                  opcode_field *opcodes,
                  int nr_prefetched_words,
                  int nr_prefetched_words,
                  duplicate_insn_actions duplicate_action)
                  duplicate_insn_actions duplicate_action)
{
{
  /* insert it according to the order of the fields & bits */
  /* insert it according to the order of the fields & bits */
  for (; (*cur_insn_ptr) != NULL; cur_insn_ptr = &(*cur_insn_ptr)->next)
  for (; (*cur_insn_ptr) != NULL; cur_insn_ptr = &(*cur_insn_ptr)->next)
    {
    {
      int cmp;
      int cmp;
 
 
      /* key#1 sort according to the constant fields of each instruction */
      /* key#1 sort according to the constant fields of each instruction */
      cmp = insn_word_cmp (insn->words, (*cur_insn_ptr)->insn->words);
      cmp = insn_word_cmp (insn->words, (*cur_insn_ptr)->insn->words);
      if (cmp < 0)
      if (cmp < 0)
        break;
        break;
      else if (cmp > 0)
      else if (cmp > 0)
        continue;
        continue;
 
 
      /* key#2 sort according to the expanded bits of each instruction */
      /* key#2 sort according to the expanded bits of each instruction */
      cmp = opcode_bits_cmp (expanded_bits, (*cur_insn_ptr)->expanded_bits);
      cmp = opcode_bits_cmp (expanded_bits, (*cur_insn_ptr)->expanded_bits);
      if (cmp < 0)
      if (cmp < 0)
        break;
        break;
      else if (cmp > 0)
      else if (cmp > 0)
        continue;
        continue;
 
 
      /* key#3 sort according to the non-constant fields of each instruction */
      /* key#3 sort according to the non-constant fields of each instruction */
      cmp = insn_field_cmp (insn->words, (*cur_insn_ptr)->insn->words);
      cmp = insn_field_cmp (insn->words, (*cur_insn_ptr)->insn->words);
      if (cmp < 0)
      if (cmp < 0)
        break;
        break;
      else if (cmp > 0)
      else if (cmp > 0)
        continue;
        continue;
 
 
      if (duplicate_action == merge_duplicate_insns)
      if (duplicate_action == merge_duplicate_insns)
        {
        {
          /* key#4: If we're going to merge duplicates, also sort
          /* key#4: If we're going to merge duplicates, also sort
             according to the format_name.  Two instructions with
             according to the format_name.  Two instructions with
             identical decode patterns, but different names, are
             identical decode patterns, but different names, are
             considered different when merging.  Duplicates are only
             considered different when merging.  Duplicates are only
             important when creating a decode table (implied by
             important when creating a decode table (implied by
             report_duplicate_insns) as such a table only has the
             report_duplicate_insns) as such a table only has the
             instruction's bit code as a way of differentiating
             instruction's bit code as a way of differentiating
             between instructions.  */
             between instructions.  */
          int cmp = name_cmp (insn->format_name,
          int cmp = name_cmp (insn->format_name,
                              (*cur_insn_ptr)->insn->format_name);
                              (*cur_insn_ptr)->insn->format_name);
          if (cmp < 0)
          if (cmp < 0)
            break;
            break;
          else if (cmp > 0)
          else if (cmp > 0)
            continue;
            continue;
        }
        }
 
 
      if (duplicate_action == merge_duplicate_insns)
      if (duplicate_action == merge_duplicate_insns)
        {
        {
          /* key#5: If we're going to merge duplicates, also sort
          /* key#5: If we're going to merge duplicates, also sort
             according to the name.  See comment above for
             according to the name.  See comment above for
             format_name.  */
             format_name.  */
          int cmp = name_cmp (insn->name, (*cur_insn_ptr)->insn->name);
          int cmp = name_cmp (insn->name, (*cur_insn_ptr)->insn->name);
          if (cmp < 0)
          if (cmp < 0)
            break;
            break;
          else if (cmp > 0)
          else if (cmp > 0)
            continue;
            continue;
        }
        }
 
 
      /* duplicate keys, report problem */
      /* duplicate keys, report problem */
      switch (duplicate_action)
      switch (duplicate_action)
        {
        {
        case report_duplicate_insns:
        case report_duplicate_insns:
          /* It would appear that we have two instructions with the
          /* It would appear that we have two instructions with the
             same constant field values across all words and bits.
             same constant field values across all words and bits.
             This error can also occure when insn_field_cmp() is
             This error can also occure when insn_field_cmp() is
             failing to differentiate between two instructions that
             failing to differentiate between two instructions that
             differ only in their conditional fields. */
             differ only in their conditional fields. */
          warning (insn->line,
          warning (insn->line,
                   "Two instructions with identical constant fields\n");
                   "Two instructions with identical constant fields\n");
          error ((*cur_insn_ptr)->insn->line,
          error ((*cur_insn_ptr)->insn->line,
                 "Location of duplicate instruction\n");
                 "Location of duplicate instruction\n");
        case merge_duplicate_insns:
        case merge_duplicate_insns:
          /* Add the opcode path to the instructions list */
          /* Add the opcode path to the instructions list */
          if (options.trace.insn_insertion)
          if (options.trace.insn_insertion)
            {
            {
              notify ((*cur_insn_ptr)->insn->line,
              notify ((*cur_insn_ptr)->insn->line,
                      "%s.%s: insert merge %s.%s\n",
                      "%s.%s: insert merge %s.%s\n",
                      (*cur_insn_ptr)->insn->format_name,
                      (*cur_insn_ptr)->insn->format_name,
                      (*cur_insn_ptr)->insn->name,
                      (*cur_insn_ptr)->insn->name,
                      insn->format_name,
                      insn->format_name,
                      insn->name);
                      insn->name);
            }
            }
          if (opcodes != NULL)
          if (opcodes != NULL)
            {
            {
              insn_opcodes **last = &(*cur_insn_ptr)->opcodes;
              insn_opcodes **last = &(*cur_insn_ptr)->opcodes;
              while (*last != NULL)
              while (*last != NULL)
                {
                {
                  last = &(*last)->next;
                  last = &(*last)->next;
                }
                }
              (*last) = ZALLOC (insn_opcodes);
              (*last) = ZALLOC (insn_opcodes);
              (*last)->opcode = opcodes;
              (*last)->opcode = opcodes;
            }
            }
          /* Use the larger nr_prefetched_words */
          /* Use the larger nr_prefetched_words */
          if ((*cur_insn_ptr)->nr_prefetched_words < nr_prefetched_words)
          if ((*cur_insn_ptr)->nr_prefetched_words < nr_prefetched_words)
            (*cur_insn_ptr)->nr_prefetched_words = nr_prefetched_words;
            (*cur_insn_ptr)->nr_prefetched_words = nr_prefetched_words;
          return (*cur_insn_ptr);
          return (*cur_insn_ptr);
        }
        }
 
 
    }
    }
 
 
  /* create a new list entry and insert it */
  /* create a new list entry and insert it */
  {
  {
    insn_list *new_insn = ZALLOC (insn_list);
    insn_list *new_insn = ZALLOC (insn_list);
    if (options.trace.insn_insertion)
    if (options.trace.insn_insertion)
      {
      {
        notify (insn->line,
        notify (insn->line,
                "%s.%s: insert new\n",
                "%s.%s: insert new\n",
                insn->format_name,
                insn->format_name,
                insn->name);
                insn->name);
      }
      }
    new_insn->insn = insn;
    new_insn->insn = insn;
    new_insn->expanded_bits = expanded_bits;
    new_insn->expanded_bits = expanded_bits;
    new_insn->next = (*cur_insn_ptr);
    new_insn->next = (*cur_insn_ptr);
    new_insn->nr_prefetched_words = nr_prefetched_words;
    new_insn->nr_prefetched_words = nr_prefetched_words;
    if (opcodes != NULL)
    if (opcodes != NULL)
      {
      {
        new_insn->opcodes = ZALLOC (insn_opcodes);
        new_insn->opcodes = ZALLOC (insn_opcodes);
        new_insn->opcodes->opcode = opcodes;
        new_insn->opcodes->opcode = opcodes;
      }
      }
    (*cur_insn_ptr) = new_insn;
    (*cur_insn_ptr) = new_insn;
  }
  }
 
 
  *nr_insns += 1;
  *nr_insns += 1;
 
 
  return (*cur_insn_ptr);
  return (*cur_insn_ptr);
}
}
 
 
 
 
extern void
extern void
gen_entry_traverse_tree (lf *file,
gen_entry_traverse_tree (lf *file,
                         gen_entry *table,
                         gen_entry *table,
                         int depth,
                         int depth,
                         gen_entry_handler * start,
                         gen_entry_handler * start,
                         gen_entry_handler * leaf,
                         gen_entry_handler * leaf,
                         gen_entry_handler * end, void *data)
                         gen_entry_handler * end, void *data)
{
{
  gen_entry *entry;
  gen_entry *entry;
 
 
  ASSERT (table !=NULL);
  ASSERT (table !=NULL);
  ASSERT (table->opcode != NULL);
  ASSERT (table->opcode != NULL);
  ASSERT (table->nr_entries > 0);
  ASSERT (table->nr_entries > 0);
  ASSERT (table->entries != 0);
  ASSERT (table->entries != 0);
 
 
  /* prefix */
  /* prefix */
  if (start != NULL && depth >= 0)
  if (start != NULL && depth >= 0)
    {
    {
      start (file, table, depth, data);
      start (file, table, depth, data);
    }
    }
  /* infix leaves */
  /* infix leaves */
  for (entry = table->entries; entry != NULL; entry = entry->sibling)
  for (entry = table->entries; entry != NULL; entry = entry->sibling)
    {
    {
      if (entry->entries != NULL && depth != 0)
      if (entry->entries != NULL && depth != 0)
        {
        {
          gen_entry_traverse_tree (file, entry, depth + 1,
          gen_entry_traverse_tree (file, entry, depth + 1,
                                   start, leaf, end, data);
                                   start, leaf, end, data);
        }
        }
      else if (depth >= 0)
      else if (depth >= 0)
        {
        {
          if (leaf != NULL)
          if (leaf != NULL)
            {
            {
              leaf (file, entry, depth, data);
              leaf (file, entry, depth, data);
            }
            }
        }
        }
    }
    }
  /* postfix */
  /* postfix */
  if (end != NULL && depth >= 0)
  if (end != NULL && depth >= 0)
    {
    {
      end (file, table, depth, data);
      end (file, table, depth, data);
    }
    }
}
}
 
 
 
 
 
 
/* create a list element containing a single gen_table entry */
/* create a list element containing a single gen_table entry */
 
 
static gen_list *
static gen_list *
make_table (insn_table *isa, decode_table *rules, model_entry *model)
make_table (insn_table *isa, decode_table *rules, model_entry *model)
{
{
  insn_entry *insn;
  insn_entry *insn;
  gen_list *entry = ZALLOC (gen_list);
  gen_list *entry = ZALLOC (gen_list);
  entry->table = ZALLOC (gen_entry);
  entry->table = ZALLOC (gen_entry);
  entry->table->top = entry;
  entry->table->top = entry;
  entry->model = model;
  entry->model = model;
  entry->isa = isa;
  entry->isa = isa;
  for (insn = isa->insns; insn != NULL; insn = insn->next)
  for (insn = isa->insns; insn != NULL; insn = insn->next)
    {
    {
      if (model == NULL
      if (model == NULL
          || insn->processors == NULL
          || insn->processors == NULL
          || filter_is_member (insn->processors, model->name))
          || filter_is_member (insn->processors, model->name))
        {
        {
          insn_list_insert (&entry->table->insns, &entry->table->nr_insns, insn, NULL,  /* expanded_bits - none yet */
          insn_list_insert (&entry->table->insns, &entry->table->nr_insns, insn, NULL,  /* expanded_bits - none yet */
                            NULL,       /* opcodes - none yet */
                            NULL,       /* opcodes - none yet */
                            0,   /* nr_prefetched_words - none yet */
                            0,   /* nr_prefetched_words - none yet */
                            report_duplicate_insns);
                            report_duplicate_insns);
        }
        }
    }
    }
  entry->table->opcode_rule = rules;
  entry->table->opcode_rule = rules;
  return entry;
  return entry;
}
}
 
 
 
 
gen_table *
gen_table *
make_gen_tables (insn_table *isa, decode_table *rules)
make_gen_tables (insn_table *isa, decode_table *rules)
{
{
  gen_table *gen = ZALLOC (gen_table);
  gen_table *gen = ZALLOC (gen_table);
  gen->isa = isa;
  gen->isa = isa;
  gen->rules = rules;
  gen->rules = rules;
  if (options.gen.multi_sim)
  if (options.gen.multi_sim)
    {
    {
      gen_list **last = &gen->tables;
      gen_list **last = &gen->tables;
      model_entry *model;
      model_entry *model;
      filter *processors;
      filter *processors;
      if (options.model_filter != NULL)
      if (options.model_filter != NULL)
        processors = options.model_filter;
        processors = options.model_filter;
      else
      else
        processors = isa->model->processors;
        processors = isa->model->processors;
      for (model = isa->model->models; model != NULL; model = model->next)
      for (model = isa->model->models; model != NULL; model = model->next)
        {
        {
          if (filter_is_member (processors, model->name))
          if (filter_is_member (processors, model->name))
            {
            {
              *last = make_table (isa, rules, model);
              *last = make_table (isa, rules, model);
              last = &(*last)->next;
              last = &(*last)->next;
            }
            }
        }
        }
    }
    }
  else
  else
    {
    {
      gen->tables = make_table (isa, rules, NULL);
      gen->tables = make_table (isa, rules, NULL);
    }
    }
  return gen;
  return gen;
}
}
 
 
 
 
/****************************************************************/
/****************************************************************/
 
 
#if 0
#if 0
typedef enum
typedef enum
{
{
  field_is_not_constant = 0,
  field_is_not_constant = 0,
  field_constant_int = 1,
  field_constant_int = 1,
  field_constant_reserved = 2,
  field_constant_reserved = 2,
  field_constant_string = 3
  field_constant_string = 3
}
}
constant_field_types;
constant_field_types;
 
 
static constant_field_types
static constant_field_types
insn_field_is_constant (insn_field * field, decode_table *rule)
insn_field_is_constant (insn_field * field, decode_table *rule)
{
{
  switch (field->type)
  switch (field->type)
    {
    {
    case insn_field_int:
    case insn_field_int:
      /* field is an integer */
      /* field is an integer */
      return field_constant_int;
      return field_constant_int;
    case insn_field_reserved:
    case insn_field_reserved:
      /* field is `/' and treating that as a constant */
      /* field is `/' and treating that as a constant */
      if (rule->with_zero_reserved)
      if (rule->with_zero_reserved)
        return field_constant_reserved;
        return field_constant_reserved;
      else
      else
        return field_is_not_constant;
        return field_is_not_constant;
    case insn_field_wild:
    case insn_field_wild:
      return field_is_not_constant;     /* never constant */
      return field_is_not_constant;     /* never constant */
    case insn_field_string:
    case insn_field_string:
      /* field, though variable, is on the list of forced constants */
      /* field, though variable, is on the list of forced constants */
      if (filter_is_member (rule->constant_field_names, field->val_string))
      if (filter_is_member (rule->constant_field_names, field->val_string))
        return field_constant_string;
        return field_constant_string;
      else
      else
        return field_is_not_constant;
        return field_is_not_constant;
    }
    }
  ERROR ("Internal error");
  ERROR ("Internal error");
  return field_is_not_constant;
  return field_is_not_constant;
}
}
#endif
#endif
 
 
 
 
/****************************************************************/
/****************************************************************/
 
 
 
 
/* Is the bit, according to the decode rule, identical across all the
/* Is the bit, according to the decode rule, identical across all the
   instructions? */
   instructions? */
static int
static int
insns_bit_useless (insn_list *insns, decode_table *rule, int bit_nr)
insns_bit_useless (insn_list *insns, decode_table *rule, int bit_nr)
{
{
  insn_list *entry;
  insn_list *entry;
  int value = -1;
  int value = -1;
  int is_useless = 1;           /* cleared if something actually found */
  int is_useless = 1;           /* cleared if something actually found */
 
 
  /* check the instructions for some constant value in at least one of
  /* check the instructions for some constant value in at least one of
     the bit fields */
     the bit fields */
  for (entry = insns; entry != NULL; entry = entry->next)
  for (entry = insns; entry != NULL; entry = entry->next)
    {
    {
      insn_word_entry *word = entry->insn->word[rule->word_nr];
      insn_word_entry *word = entry->insn->word[rule->word_nr];
      insn_bit_entry *bit = word->bit[bit_nr];
      insn_bit_entry *bit = word->bit[bit_nr];
      switch (bit->field->type)
      switch (bit->field->type)
        {
        {
        case insn_field_invalid:
        case insn_field_invalid:
          ASSERT (0);
          ASSERT (0);
          break;
          break;
        case insn_field_wild:
        case insn_field_wild:
        case insn_field_reserved:
        case insn_field_reserved:
          /* neither useless or useful - ignore */
          /* neither useless or useful - ignore */
          break;
          break;
        case insn_field_int:
        case insn_field_int:
          switch (rule->search)
          switch (rule->search)
            {
            {
            case decode_find_strings:
            case decode_find_strings:
              /* an integer isn't a string */
              /* an integer isn't a string */
              return 1;
              return 1;
            case decode_find_constants:
            case decode_find_constants:
            case decode_find_mixed:
            case decode_find_mixed:
              /* an integer is useful if its value isn't the same
              /* an integer is useful if its value isn't the same
                 between all instructions.  The first time through the
                 between all instructions.  The first time through the
                 value is saved, the second time through (if the
                 value is saved, the second time through (if the
                 values differ) it is marked as useful. */
                 values differ) it is marked as useful. */
              if (value < 0)
              if (value < 0)
                value = bit->value;
                value = bit->value;
              else if (value != bit->value)
              else if (value != bit->value)
                is_useless = 0;
                is_useless = 0;
              break;
              break;
            }
            }
          break;
          break;
        case insn_field_string:
        case insn_field_string:
          switch (rule->search)
          switch (rule->search)
            {
            {
            case decode_find_strings:
            case decode_find_strings:
              /* at least one string, keep checking */
              /* at least one string, keep checking */
              is_useless = 0;
              is_useless = 0;
              break;
              break;
            case decode_find_constants:
            case decode_find_constants:
            case decode_find_mixed:
            case decode_find_mixed:
              if (filter_is_member (rule->constant_field_names,
              if (filter_is_member (rule->constant_field_names,
                                    bit->field->val_string))
                                    bit->field->val_string))
                /* a string field forced to constant? */
                /* a string field forced to constant? */
                is_useless = 0;
                is_useless = 0;
              else if (rule->search == decode_find_constants)
              else if (rule->search == decode_find_constants)
                /* the string field isn't constant */
                /* the string field isn't constant */
                return 1;
                return 1;
              break;
              break;
            }
            }
        }
        }
    }
    }
 
 
  /* Given only one constant value has been found, check through all
  /* Given only one constant value has been found, check through all
     the instructions to see if at least one conditional makes it
     the instructions to see if at least one conditional makes it
     usefull */
     usefull */
  if (value >= 0 && is_useless)
  if (value >= 0 && is_useless)
    {
    {
      for (entry = insns; entry != NULL; entry = entry->next)
      for (entry = insns; entry != NULL; entry = entry->next)
        {
        {
          insn_word_entry *word = entry->insn->word[rule->word_nr];
          insn_word_entry *word = entry->insn->word[rule->word_nr];
          insn_bit_entry *bit = word->bit[bit_nr];
          insn_bit_entry *bit = word->bit[bit_nr];
          switch (bit->field->type)
          switch (bit->field->type)
            {
            {
            case insn_field_invalid:
            case insn_field_invalid:
              ASSERT (0);
              ASSERT (0);
              break;
              break;
            case insn_field_wild:
            case insn_field_wild:
            case insn_field_reserved:
            case insn_field_reserved:
            case insn_field_int:
            case insn_field_int:
              /* already processed */
              /* already processed */
              break;
              break;
            case insn_field_string:
            case insn_field_string:
              switch (rule->search)
              switch (rule->search)
                {
                {
                case decode_find_strings:
                case decode_find_strings:
                case decode_find_constants:
                case decode_find_constants:
                  /* already processed */
                  /* already processed */
                  break;
                  break;
                case decode_find_mixed:
                case decode_find_mixed:
                  /* string field with conditions.  If this condition
                  /* string field with conditions.  If this condition
                     eliminates the value then the compare is useful */
                     eliminates the value then the compare is useful */
                  if (bit->field->conditions != NULL)
                  if (bit->field->conditions != NULL)
                    {
                    {
                      insn_field_cond *condition;
                      insn_field_cond *condition;
                      int shift = bit->field->last - bit_nr;
                      int shift = bit->field->last - bit_nr;
                      for (condition = bit->field->conditions;
                      for (condition = bit->field->conditions;
                           condition != NULL; condition = condition->next)
                           condition != NULL; condition = condition->next)
                        {
                        {
                          switch (condition->type)
                          switch (condition->type)
                            {
                            {
                            case insn_field_cond_value:
                            case insn_field_cond_value:
                              switch (condition->test)
                              switch (condition->test)
                                {
                                {
                                case insn_field_cond_ne:
                                case insn_field_cond_ne:
                                  if (((condition->value >> shift) & 1)
                                  if (((condition->value >> shift) & 1)
                                      == (unsigned) value)
                                      == (unsigned) value)
                                    /* conditional field excludes the
                                    /* conditional field excludes the
                                       current value */
                                       current value */
                                    is_useless = 0;
                                    is_useless = 0;
                                  break;
                                  break;
                                case insn_field_cond_eq:
                                case insn_field_cond_eq:
                                  if (((condition->value >> shift) & 1)
                                  if (((condition->value >> shift) & 1)
                                      != (unsigned) value)
                                      != (unsigned) value)
                                    /* conditional field requires the
                                    /* conditional field requires the
                                       current value */
                                       current value */
                                    is_useless = 0;
                                    is_useless = 0;
                                  break;
                                  break;
                                }
                                }
                              break;
                              break;
                            case insn_field_cond_field:
                            case insn_field_cond_field:
                              /* are these handled separatly? */
                              /* are these handled separatly? */
                              break;
                              break;
                            }
                            }
                        }
                        }
                    }
                    }
                }
                }
            }
            }
        }
        }
    }
    }
 
 
  return is_useless;
  return is_useless;
}
}
 
 
 
 
/* go through a gen-table's list of instruction formats looking for a
/* go through a gen-table's list of instruction formats looking for a
   range of bits that meet the decode table RULEs requirements */
   range of bits that meet the decode table RULEs requirements */
 
 
static opcode_field *
static opcode_field *
gen_entry_find_opcode_field (insn_list *insns,
gen_entry_find_opcode_field (insn_list *insns,
                             decode_table *rule, int string_only)
                             decode_table *rule, int string_only)
{
{
  opcode_field curr_opcode;
  opcode_field curr_opcode;
  ASSERT (rule != NULL);
  ASSERT (rule != NULL);
 
 
  memset (&curr_opcode, 0, sizeof (curr_opcode));
  memset (&curr_opcode, 0, sizeof (curr_opcode));
  curr_opcode.word_nr = rule->word_nr;
  curr_opcode.word_nr = rule->word_nr;
  curr_opcode.first = rule->first;
  curr_opcode.first = rule->first;
  curr_opcode.last = rule->last;
  curr_opcode.last = rule->last;
 
 
  /* Try to reduce the size of first..last in accordance with the
  /* Try to reduce the size of first..last in accordance with the
     decode rules */
     decode rules */
 
 
  while (curr_opcode.first <= rule->last)
  while (curr_opcode.first <= rule->last)
    {
    {
      if (insns_bit_useless (insns, rule, curr_opcode.first))
      if (insns_bit_useless (insns, rule, curr_opcode.first))
        curr_opcode.first++;
        curr_opcode.first++;
      else
      else
        break;
        break;
    }
    }
  while (curr_opcode.last >= rule->first)
  while (curr_opcode.last >= rule->first)
    {
    {
      if (insns_bit_useless (insns, rule, curr_opcode.last))
      if (insns_bit_useless (insns, rule, curr_opcode.last))
        curr_opcode.last--;
        curr_opcode.last--;
      else
      else
        break;
        break;
    }
    }
 
 
 
 
#if 0
#if 0
  for (entry = insns; entry != NULL; entry = entry->next)
  for (entry = insns; entry != NULL; entry = entry->next)
    {
    {
      insn_word_entry *fields = entry->insn->word[rule->word_nr];
      insn_word_entry *fields = entry->insn->word[rule->word_nr];
      opcode_field new_opcode;
      opcode_field new_opcode;
 
 
      ASSERT (fields != NULL);
      ASSERT (fields != NULL);
 
 
      /* find a start point for the opcode field */
      /* find a start point for the opcode field */
      new_opcode.first = rule->first;
      new_opcode.first = rule->first;
      while (new_opcode.first <= rule->last
      while (new_opcode.first <= rule->last
             && (!string_only
             && (!string_only
                 ||
                 ||
                 (insn_field_is_constant (fields->bit[new_opcode.first], rule)
                 (insn_field_is_constant (fields->bit[new_opcode.first], rule)
                  != field_constant_string)) && (string_only
                  != field_constant_string)) && (string_only
                                                 ||
                                                 ||
                                                 (insn_field_is_constant
                                                 (insn_field_is_constant
                                                  (fields->
                                                  (fields->
                                                   bit[new_opcode.first],
                                                   bit[new_opcode.first],
                                                   rule) ==
                                                   rule) ==
                                                  field_is_not_constant)))
                                                  field_is_not_constant)))
        {
        {
          int new_first = fields->bit[new_opcode.first]->last + 1;
          int new_first = fields->bit[new_opcode.first]->last + 1;
          ASSERT (new_first > new_opcode.first);
          ASSERT (new_first > new_opcode.first);
          new_opcode.first = new_first;
          new_opcode.first = new_first;
        }
        }
      ASSERT (new_opcode.first > rule->last
      ASSERT (new_opcode.first > rule->last
              || (string_only
              || (string_only
                  && insn_field_is_constant (fields->bit[new_opcode.first],
                  && insn_field_is_constant (fields->bit[new_opcode.first],
                                             rule) == field_constant_string)
                                             rule) == field_constant_string)
              || (!string_only
              || (!string_only
                  && insn_field_is_constant (fields->bit[new_opcode.first],
                  && insn_field_is_constant (fields->bit[new_opcode.first],
                                             rule)));
                                             rule)));
 
 
      /* find the end point for the opcode field */
      /* find the end point for the opcode field */
      new_opcode.last = rule->last;
      new_opcode.last = rule->last;
      while (new_opcode.last >= rule->first
      while (new_opcode.last >= rule->first
             && (!string_only
             && (!string_only
                 || insn_field_is_constant (fields->bit[new_opcode.last],
                 || insn_field_is_constant (fields->bit[new_opcode.last],
                                            rule) != field_constant_string)
                                            rule) != field_constant_string)
             && (string_only
             && (string_only
                 || !insn_field_is_constant (fields->bit[new_opcode.last],
                 || !insn_field_is_constant (fields->bit[new_opcode.last],
                                             rule)))
                                             rule)))
        {
        {
          int new_last = fields->bit[new_opcode.last]->first - 1;
          int new_last = fields->bit[new_opcode.last]->first - 1;
          ASSERT (new_last < new_opcode.last);
          ASSERT (new_last < new_opcode.last);
          new_opcode.last = new_last;
          new_opcode.last = new_last;
        }
        }
      ASSERT (new_opcode.last < rule->first
      ASSERT (new_opcode.last < rule->first
              || (string_only
              || (string_only
                  && insn_field_is_constant (fields->bit[new_opcode.last],
                  && insn_field_is_constant (fields->bit[new_opcode.last],
                                             rule) == field_constant_string)
                                             rule) == field_constant_string)
              || (!string_only
              || (!string_only
                  && insn_field_is_constant (fields->bit[new_opcode.last],
                  && insn_field_is_constant (fields->bit[new_opcode.last],
                                             rule)));
                                             rule)));
 
 
      /* now see if our current opcode needs expanding to include the
      /* now see if our current opcode needs expanding to include the
         interesting fields within this instruction */
         interesting fields within this instruction */
      if (new_opcode.first <= rule->last
      if (new_opcode.first <= rule->last
          && curr_opcode.first > new_opcode.first)
          && curr_opcode.first > new_opcode.first)
        curr_opcode.first = new_opcode.first;
        curr_opcode.first = new_opcode.first;
      if (new_opcode.last >= rule->first
      if (new_opcode.last >= rule->first
          && curr_opcode.last < new_opcode.last)
          && curr_opcode.last < new_opcode.last)
        curr_opcode.last = new_opcode.last;
        curr_opcode.last = new_opcode.last;
 
 
    }
    }
#endif
#endif
 
 
  /* did the final opcode field end up being empty? */
  /* did the final opcode field end up being empty? */
  if (curr_opcode.first > curr_opcode.last)
  if (curr_opcode.first > curr_opcode.last)
    {
    {
      return NULL;
      return NULL;
    }
    }
  ASSERT (curr_opcode.last >= rule->first);
  ASSERT (curr_opcode.last >= rule->first);
  ASSERT (curr_opcode.first <= rule->last);
  ASSERT (curr_opcode.first <= rule->last);
  ASSERT (curr_opcode.first <= curr_opcode.last);
  ASSERT (curr_opcode.first <= curr_opcode.last);
 
 
  /* Ensure that, for the non string only case, the opcode includes
  /* Ensure that, for the non string only case, the opcode includes
     the range forced_first .. forced_last */
     the range forced_first .. forced_last */
  if (!string_only && curr_opcode.first > rule->force_first)
  if (!string_only && curr_opcode.first > rule->force_first)
    {
    {
      curr_opcode.first = rule->force_first;
      curr_opcode.first = rule->force_first;
    }
    }
  if (!string_only && curr_opcode.last < rule->force_last)
  if (!string_only && curr_opcode.last < rule->force_last)
    {
    {
      curr_opcode.last = rule->force_last;
      curr_opcode.last = rule->force_last;
    }
    }
 
 
  /* For the string only case, force just the lower bound (so that the
  /* For the string only case, force just the lower bound (so that the
     shift can be eliminated) */
     shift can be eliminated) */
  if (string_only && rule->force_last == options.insn_bit_size - 1)
  if (string_only && rule->force_last == options.insn_bit_size - 1)
    {
    {
      curr_opcode.last = options.insn_bit_size - 1;
      curr_opcode.last = options.insn_bit_size - 1;
    }
    }
 
 
  /* handle any special cases */
  /* handle any special cases */
  switch (rule->type)
  switch (rule->type)
    {
    {
    case normal_decode_rule:
    case normal_decode_rule:
      /* let the above apply */
      /* let the above apply */
      curr_opcode.nr_opcodes =
      curr_opcode.nr_opcodes =
        (1 << (curr_opcode.last - curr_opcode.first + 1));
        (1 << (curr_opcode.last - curr_opcode.first + 1));
      break;
      break;
    case boolean_rule:
    case boolean_rule:
      curr_opcode.is_boolean = 1;
      curr_opcode.is_boolean = 1;
      curr_opcode.boolean_constant = rule->constant;
      curr_opcode.boolean_constant = rule->constant;
      curr_opcode.nr_opcodes = 2;
      curr_opcode.nr_opcodes = 2;
      break;
      break;
    }
    }
 
 
  {
  {
    opcode_field *new_field = ZALLOC (opcode_field);
    opcode_field *new_field = ZALLOC (opcode_field);
    memcpy (new_field, &curr_opcode, sizeof (opcode_field));
    memcpy (new_field, &curr_opcode, sizeof (opcode_field));
    return new_field;
    return new_field;
  }
  }
}
}
 
 
 
 
static void
static void
gen_entry_insert_insn (gen_entry *table,
gen_entry_insert_insn (gen_entry *table,
                       insn_entry * old_insn,
                       insn_entry * old_insn,
                       int new_word_nr,
                       int new_word_nr,
                       int new_nr_prefetched_words,
                       int new_nr_prefetched_words,
                       int new_opcode_nr, opcode_bits *new_bits)
                       int new_opcode_nr, opcode_bits *new_bits)
{
{
  gen_entry **entry = &table->entries;
  gen_entry **entry = &table->entries;
 
 
  /* find the new table for this entry */
  /* find the new table for this entry */
  while ((*entry) != NULL && (*entry)->opcode_nr < new_opcode_nr)
  while ((*entry) != NULL && (*entry)->opcode_nr < new_opcode_nr)
    {
    {
      entry = &(*entry)->sibling;
      entry = &(*entry)->sibling;
    }
    }
 
 
  if ((*entry) == NULL || (*entry)->opcode_nr != new_opcode_nr)
  if ((*entry) == NULL || (*entry)->opcode_nr != new_opcode_nr)
    {
    {
      /* insert the missing entry */
      /* insert the missing entry */
      gen_entry *new_entry = ZALLOC (gen_entry);
      gen_entry *new_entry = ZALLOC (gen_entry);
      new_entry->sibling = (*entry);
      new_entry->sibling = (*entry);
      (*entry) = new_entry;
      (*entry) = new_entry;
      table->nr_entries++;
      table->nr_entries++;
      /* fill it in */
      /* fill it in */
      new_entry->top = table->top;
      new_entry->top = table->top;
      new_entry->opcode_nr = new_opcode_nr;
      new_entry->opcode_nr = new_opcode_nr;
      new_entry->word_nr = new_word_nr;
      new_entry->word_nr = new_word_nr;
      new_entry->expanded_bits = new_bits;
      new_entry->expanded_bits = new_bits;
      new_entry->opcode_rule = table->opcode_rule->next;
      new_entry->opcode_rule = table->opcode_rule->next;
      new_entry->parent = table;
      new_entry->parent = table;
      new_entry->nr_prefetched_words = new_nr_prefetched_words;
      new_entry->nr_prefetched_words = new_nr_prefetched_words;
    }
    }
  /* ASSERT new_bits == cur_entry bits */
  /* ASSERT new_bits == cur_entry bits */
  ASSERT ((*entry) != NULL && (*entry)->opcode_nr == new_opcode_nr);
  ASSERT ((*entry) != NULL && (*entry)->opcode_nr == new_opcode_nr);
  insn_list_insert (&(*entry)->insns, &(*entry)->nr_insns, old_insn, NULL,      /* expanded_bits - only in final list */
  insn_list_insert (&(*entry)->insns, &(*entry)->nr_insns, old_insn, NULL,      /* expanded_bits - only in final list */
                    NULL,       /* opcodes - only in final list */
                    NULL,       /* opcodes - only in final list */
                    new_nr_prefetched_words,    /* for this table */
                    new_nr_prefetched_words,    /* for this table */
                    report_duplicate_insns);
                    report_duplicate_insns);
}
}
 
 
 
 
static void
static void
gen_entry_expand_opcode (gen_entry *table,
gen_entry_expand_opcode (gen_entry *table,
                         insn_entry * instruction,
                         insn_entry * instruction,
                         int bit_nr, int opcode_nr, opcode_bits *bits)
                         int bit_nr, int opcode_nr, opcode_bits *bits)
{
{
  if (bit_nr > table->opcode->last)
  if (bit_nr > table->opcode->last)
    {
    {
      /* Only include the hardwired bit information with an entry IF
      /* Only include the hardwired bit information with an entry IF
         that entry (and hence its functions) are being duplicated.  */
         that entry (and hence its functions) are being duplicated.  */
      if (options.trace.insn_expansion)
      if (options.trace.insn_expansion)
        {
        {
          print_gen_entry_path (table->opcode_rule->line, table, notify);
          print_gen_entry_path (table->opcode_rule->line, table, notify);
          notify (NULL, ": insert %d - %s.%s%s\n",
          notify (NULL, ": insert %d - %s.%s%s\n",
                  opcode_nr,
                  opcode_nr,
                  instruction->format_name,
                  instruction->format_name,
                  instruction->name,
                  instruction->name,
                  (table->opcode_rule->
                  (table->opcode_rule->
                   with_duplicates ? " (duplicated)" : ""));
                   with_duplicates ? " (duplicated)" : ""));
        }
        }
      if (table->opcode_rule->with_duplicates)
      if (table->opcode_rule->with_duplicates)
        {
        {
          gen_entry_insert_insn (table, instruction,
          gen_entry_insert_insn (table, instruction,
                                 table->opcode->word_nr,
                                 table->opcode->word_nr,
                                 table->nr_prefetched_words, opcode_nr, bits);
                                 table->nr_prefetched_words, opcode_nr, bits);
        }
        }
      else
      else
        {
        {
          gen_entry_insert_insn (table, instruction,
          gen_entry_insert_insn (table, instruction,
                                 table->opcode->word_nr,
                                 table->opcode->word_nr,
                                 table->nr_prefetched_words, opcode_nr, NULL);
                                 table->nr_prefetched_words, opcode_nr, NULL);
        }
        }
    }
    }
  else
  else
    {
    {
      insn_word_entry *word = instruction->word[table->opcode->word_nr];
      insn_word_entry *word = instruction->word[table->opcode->word_nr];
      insn_field_entry *field = word->bit[bit_nr]->field;
      insn_field_entry *field = word->bit[bit_nr]->field;
      int last_pos = ((field->last < table->opcode->last)
      int last_pos = ((field->last < table->opcode->last)
                      ? field->last : table->opcode->last);
                      ? field->last : table->opcode->last);
      int first_pos = ((field->first > table->opcode->first)
      int first_pos = ((field->first > table->opcode->first)
                       ? field->first : table->opcode->first);
                       ? field->first : table->opcode->first);
      int width = last_pos - first_pos + 1;
      int width = last_pos - first_pos + 1;
      switch (field->type)
      switch (field->type)
        {
        {
        case insn_field_int:
        case insn_field_int:
          {
          {
            int val;
            int val;
            val = sub_val (field->val_int, field->last, first_pos, last_pos);
            val = sub_val (field->val_int, field->last, first_pos, last_pos);
            gen_entry_expand_opcode (table, instruction,
            gen_entry_expand_opcode (table, instruction,
                                     last_pos + 1,
                                     last_pos + 1,
                                     ((opcode_nr << width) | val), bits);
                                     ((opcode_nr << width) | val), bits);
            break;
            break;
          }
          }
        default:
        default:
          {
          {
            if (field->type == insn_field_reserved)
            if (field->type == insn_field_reserved)
              gen_entry_expand_opcode (table, instruction,
              gen_entry_expand_opcode (table, instruction,
                                       last_pos + 1,
                                       last_pos + 1,
                                       ((opcode_nr << width)), bits);
                                       ((opcode_nr << width)), bits);
            else
            else
              {
              {
                int val;
                int val;
                int last_val = (table->opcode->is_boolean ? 2 : (1 << width));
                int last_val = (table->opcode->is_boolean ? 2 : (1 << width));
                for (val = 0; val < last_val; val++)
                for (val = 0; val < last_val; val++)
                  {
                  {
                    /* check to see if the value has been precluded
                    /* check to see if the value has been precluded
                       (by a conditional) in some way */
                       (by a conditional) in some way */
                    int is_precluded;
                    int is_precluded;
                    insn_field_cond *condition;
                    insn_field_cond *condition;
                    for (condition = field->conditions, is_precluded = 0;
                    for (condition = field->conditions, is_precluded = 0;
                         condition != NULL && !is_precluded;
                         condition != NULL && !is_precluded;
                         condition = condition->next)
                         condition = condition->next)
                      {
                      {
                        switch (condition->type)
                        switch (condition->type)
                          {
                          {
                          case insn_field_cond_value:
                          case insn_field_cond_value:
                            {
                            {
                              int value =
                              int value =
                                sub_val (condition->value, field->last,
                                sub_val (condition->value, field->last,
                                         first_pos, last_pos);
                                         first_pos, last_pos);
                              switch (condition->test)
                              switch (condition->test)
                                {
                                {
                                case insn_field_cond_ne:
                                case insn_field_cond_ne:
                                  if (value == val)
                                  if (value == val)
                                    is_precluded = 1;
                                    is_precluded = 1;
                                  break;
                                  break;
                                case insn_field_cond_eq:
                                case insn_field_cond_eq:
                                  if (value != val)
                                  if (value != val)
                                    is_precluded = 1;
                                    is_precluded = 1;
                                  break;
                                  break;
                                }
                                }
                              break;
                              break;
                            }
                            }
                          case insn_field_cond_field:
                          case insn_field_cond_field:
                            {
                            {
                              int value = -1;
                              int value = -1;
                              opcode_bits *bit;
                              opcode_bits *bit;
                              gen_entry *t = NULL;
                              gen_entry *t = NULL;
                              /* Try to find a value for the
                              /* Try to find a value for the
                                 conditional by looking back through
                                 conditional by looking back through
                                 the previously defined bits for one
                                 the previously defined bits for one
                                 that covers the designated
                                 that covers the designated
                                 conditional field */
                                 conditional field */
                              for (bit = bits; bit != NULL; bit = bit->next)
                              for (bit = bits; bit != NULL; bit = bit->next)
                                {
                                {
                                  if (bit->field->word_nr ==
                                  if (bit->field->word_nr ==
                                      condition->field->word_nr
                                      condition->field->word_nr
                                      && bit->first <= condition->field->first
                                      && bit->first <= condition->field->first
                                      && bit->last >= condition->field->last)
                                      && bit->last >= condition->field->last)
                                    {
                                    {
                                      /* the bit field fully specified
                                      /* the bit field fully specified
                                         the conditional field's value */
                                         the conditional field's value */
                                      value = sub_val (bit->value, bit->last,
                                      value = sub_val (bit->value, bit->last,
                                                       condition->field->
                                                       condition->field->
                                                       first,
                                                       first,
                                                       condition->field->
                                                       condition->field->
                                                       last);
                                                       last);
                                    }
                                    }
                                }
                                }
                              /* Try to find a value by looking
                              /* Try to find a value by looking
                                 through this and previous tables */
                                 through this and previous tables */
                              if (bit == NULL)
                              if (bit == NULL)
                                {
                                {
                                  for (t = table;
                                  for (t = table;
                                       t->parent != NULL; t = t->parent)
                                       t->parent != NULL; t = t->parent)
                                    {
                                    {
                                      if (t->parent->opcode->word_nr ==
                                      if (t->parent->opcode->word_nr ==
                                          condition->field->word_nr
                                          condition->field->word_nr
                                          && t->parent->opcode->first <=
                                          && t->parent->opcode->first <=
                                          condition->field->first
                                          condition->field->first
                                          && t->parent->opcode->last >=
                                          && t->parent->opcode->last >=
                                          condition->field->last)
                                          condition->field->last)
                                        {
                                        {
                                          /* the table entry fully
                                          /* the table entry fully
                                             specified the condition
                                             specified the condition
                                             field's value */
                                             field's value */
                                          /* extract the field's value
                                          /* extract the field's value
                                             from the opcode */
                                             from the opcode */
                                          value =
                                          value =
                                            sub_val (t->opcode_nr,
                                            sub_val (t->opcode_nr,
                                                     t->parent->opcode->last,
                                                     t->parent->opcode->last,
                                                     condition->field->first,
                                                     condition->field->first,
                                                     condition->field->last);
                                                     condition->field->last);
                                          /* this is a requirement of
                                          /* this is a requirement of
                                             a conditonal field
                                             a conditonal field
                                             refering to another field */
                                             refering to another field */
                                          ASSERT ((condition->field->first -
                                          ASSERT ((condition->field->first -
                                                   condition->field->last) ==
                                                   condition->field->last) ==
                                                  (first_pos - last_pos));
                                                  (first_pos - last_pos));
                                          printf
                                          printf
                                            ("value=%d, opcode_nr=%d, last=%d, [%d..%d]\n",
                                            ("value=%d, opcode_nr=%d, last=%d, [%d..%d]\n",
                                             value, t->opcode_nr,
                                             value, t->opcode_nr,
                                             t->parent->opcode->last,
                                             t->parent->opcode->last,
                                             condition->field->first,
                                             condition->field->first,
                                             condition->field->last);
                                             condition->field->last);
                                        }
                                        }
                                    }
                                    }
                                }
                                }
                              if (bit == NULL && t == NULL)
                              if (bit == NULL && t == NULL)
                                error (instruction->line,
                                error (instruction->line,
                                       "Conditional `%s' of field `%s' isn't expanded",
                                       "Conditional `%s' of field `%s' isn't expanded",
                                       condition->string, field->val_string);
                                       condition->string, field->val_string);
                              switch (condition->test)
                              switch (condition->test)
                                {
                                {
                                case insn_field_cond_ne:
                                case insn_field_cond_ne:
                                  if (value == val)
                                  if (value == val)
                                    is_precluded = 1;
                                    is_precluded = 1;
                                  break;
                                  break;
                                case insn_field_cond_eq:
                                case insn_field_cond_eq:
                                  if (value != val)
                                  if (value != val)
                                    is_precluded = 1;
                                    is_precluded = 1;
                                  break;
                                  break;
                                }
                                }
                              break;
                              break;
                            }
                            }
                          }
                          }
                      }
                      }
                    if (!is_precluded)
                    if (!is_precluded)
                      {
                      {
                        /* Only add additional hardwired bit
                        /* Only add additional hardwired bit
                           information if the entry is not going to
                           information if the entry is not going to
                           later be combined */
                           later be combined */
                        if (table->opcode_rule->with_combine)
                        if (table->opcode_rule->with_combine)
                          {
                          {
                            gen_entry_expand_opcode (table, instruction,
                            gen_entry_expand_opcode (table, instruction,
                                                     last_pos + 1,
                                                     last_pos + 1,
                                                     ((opcode_nr << width) |
                                                     ((opcode_nr << width) |
                                                      val), bits);
                                                      val), bits);
                          }
                          }
                        else
                        else
                          {
                          {
                            opcode_bits *new_bits =
                            opcode_bits *new_bits =
                              new_opcode_bits (bits, val,
                              new_opcode_bits (bits, val,
                                               first_pos, last_pos,
                                               first_pos, last_pos,
                                               field,
                                               field,
                                               table->opcode);
                                               table->opcode);
                            gen_entry_expand_opcode (table, instruction,
                            gen_entry_expand_opcode (table, instruction,
                                                     last_pos + 1,
                                                     last_pos + 1,
                                                     ((opcode_nr << width) |
                                                     ((opcode_nr << width) |
                                                      val), new_bits);
                                                      val), new_bits);
                          }
                          }
                      }
                      }
                  }
                  }
              }
              }
          }
          }
        }
        }
    }
    }
}
}
 
 
static void
static void
gen_entry_insert_expanding (gen_entry *table, insn_entry * instruction)
gen_entry_insert_expanding (gen_entry *table, insn_entry * instruction)
{
{
  gen_entry_expand_opcode (table,
  gen_entry_expand_opcode (table,
                           instruction,
                           instruction,
                           table->opcode->first, 0, table->expanded_bits);
                           table->opcode->first, 0, table->expanded_bits);
}
}
 
 
 
 
static int
static int
insns_match_format_names (insn_list *insns, filter *format_names)
insns_match_format_names (insn_list *insns, filter *format_names)
{
{
  if (format_names != NULL)
  if (format_names != NULL)
    {
    {
      insn_list *i;
      insn_list *i;
      for (i = insns; i != NULL; i = i->next)
      for (i = insns; i != NULL; i = i->next)
        {
        {
          if (i->insn->format_name != NULL
          if (i->insn->format_name != NULL
              && !filter_is_member (format_names, i->insn->format_name))
              && !filter_is_member (format_names, i->insn->format_name))
            return 0;
            return 0;
        }
        }
    }
    }
  return 1;
  return 1;
}
}
 
 
static int
static int
table_matches_path (gen_entry *table, decode_path_list *paths)
table_matches_path (gen_entry *table, decode_path_list *paths)
{
{
  if (paths == NULL)
  if (paths == NULL)
    return 1;
    return 1;
  while (paths != NULL)
  while (paths != NULL)
    {
    {
      gen_entry *entry = table;
      gen_entry *entry = table;
      decode_path *path = paths->path;
      decode_path *path = paths->path;
      while (1)
      while (1)
        {
        {
          if (entry == NULL && path == NULL)
          if (entry == NULL && path == NULL)
            return 1;
            return 1;
          if (entry == NULL || path == NULL)
          if (entry == NULL || path == NULL)
            break;
            break;
          if (entry->opcode_nr != path->opcode_nr)
          if (entry->opcode_nr != path->opcode_nr)
            break;
            break;
          entry = entry->parent;
          entry = entry->parent;
          path = path->parent;
          path = path->parent;
        }
        }
      paths = paths->next;
      paths = paths->next;
    }
    }
  return 0;
  return 0;
}
}
 
 
 
 
static int
static int
insns_match_conditions (insn_list *insns, decode_cond *conditions)
insns_match_conditions (insn_list *insns, decode_cond *conditions)
{
{
  if (conditions != NULL)
  if (conditions != NULL)
    {
    {
      insn_list *i;
      insn_list *i;
      for (i = insns; i != NULL; i = i->next)
      for (i = insns; i != NULL; i = i->next)
        {
        {
          decode_cond *cond;
          decode_cond *cond;
          for (cond = conditions; cond != NULL; cond = cond->next)
          for (cond = conditions; cond != NULL; cond = cond->next)
            {
            {
              int bit_nr;
              int bit_nr;
              if (i->insn->nr_words <= cond->word_nr)
              if (i->insn->nr_words <= cond->word_nr)
                return 0;
                return 0;
              for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
              for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
                {
                {
                  if (!cond->mask[bit_nr])
                  if (!cond->mask[bit_nr])
                    continue;
                    continue;
                  if (!i->insn->word[cond->word_nr]->bit[bit_nr]->mask)
                  if (!i->insn->word[cond->word_nr]->bit[bit_nr]->mask)
                    return 0;
                    return 0;
                  if ((i->insn->word[cond->word_nr]->bit[bit_nr]->value
                  if ((i->insn->word[cond->word_nr]->bit[bit_nr]->value
                       == cond->value[bit_nr]) == !cond->is_equal)
                       == cond->value[bit_nr]) == !cond->is_equal)
                    return 0;
                    return 0;
                }
                }
            }
            }
        }
        }
    }
    }
  return 1;
  return 1;
}
}
 
 
static int
static int
insns_match_nr_words (insn_list *insns, int nr_words)
insns_match_nr_words (insn_list *insns, int nr_words)
{
{
  insn_list *i;
  insn_list *i;
  for (i = insns; i != NULL; i = i->next)
  for (i = insns; i != NULL; i = i->next)
    {
    {
      if (i->insn->nr_words < nr_words)
      if (i->insn->nr_words < nr_words)
        return 0;
        return 0;
    }
    }
  return 1;
  return 1;
}
}
 
 
static int
static int
insn_list_cmp (insn_list *l, insn_list *r)
insn_list_cmp (insn_list *l, insn_list *r)
{
{
  while (1)
  while (1)
    {
    {
      insn_entry *insn;
      insn_entry *insn;
      if (l == NULL && r == NULL)
      if (l == NULL && r == NULL)
        return 0;
        return 0;
      if (l == NULL)
      if (l == NULL)
        return -1;
        return -1;
      if (r == NULL)
      if (r == NULL)
        return 1;
        return 1;
      if (l->insn != r->insn)
      if (l->insn != r->insn)
        return -1;              /* somewhat arbitrary at present */
        return -1;              /* somewhat arbitrary at present */
      /* skip this insn */
      /* skip this insn */
      insn = l->insn;
      insn = l->insn;
      while (l != NULL && l->insn == insn)
      while (l != NULL && l->insn == insn)
        l = l->next;
        l = l->next;
      while (r != NULL && r->insn == insn)
      while (r != NULL && r->insn == insn)
        r = r->next;
        r = r->next;
    }
    }
}
}
 
 
 
 
 
 
static void
static void
gen_entry_expand_insns (gen_entry *table)
gen_entry_expand_insns (gen_entry *table)
{
{
  decode_table *opcode_rule;
  decode_table *opcode_rule;
 
 
  ASSERT (table->nr_insns >= 1);
  ASSERT (table->nr_insns >= 1);
 
 
  /* determine a valid opcode */
  /* determine a valid opcode */
  for (opcode_rule = table->opcode_rule;
  for (opcode_rule = table->opcode_rule;
       opcode_rule != NULL; opcode_rule = opcode_rule->next)
       opcode_rule != NULL; opcode_rule = opcode_rule->next)
    {
    {
      char *discard_reason;
      char *discard_reason;
      if (table->top->model != NULL
      if (table->top->model != NULL
          && opcode_rule->model_names != NULL
          && opcode_rule->model_names != NULL
          && !filter_is_member (opcode_rule->model_names,
          && !filter_is_member (opcode_rule->model_names,
                                table->top->model->name))
                                table->top->model->name))
        {
        {
          /* the rule isn't applicable to this processor */
          /* the rule isn't applicable to this processor */
          discard_reason = "wrong model";
          discard_reason = "wrong model";
        }
        }
      else if (table->nr_insns == 1 && opcode_rule->conditions == NULL)
      else if (table->nr_insns == 1 && opcode_rule->conditions == NULL)
        {
        {
          /* for safety, require a pre-codition when attempting to
          /* for safety, require a pre-codition when attempting to
             apply a rule to a single instruction */
             apply a rule to a single instruction */
          discard_reason = "need pre-condition when nr-insn == 1";
          discard_reason = "need pre-condition when nr-insn == 1";
        }
        }
      else if (table->nr_insns == 1 && !opcode_rule->with_duplicates)
      else if (table->nr_insns == 1 && !opcode_rule->with_duplicates)
        {
        {
          /* Little point in expanding a single instruction when we're
          /* Little point in expanding a single instruction when we're
             not duplicating the semantic functions that this table
             not duplicating the semantic functions that this table
             calls */
             calls */
          discard_reason = "need duplication with nr-insns == 1";
          discard_reason = "need duplication with nr-insns == 1";
        }
        }
      else
      else
        if (!insns_match_format_names
        if (!insns_match_format_names
            (table->insns, opcode_rule->format_names))
            (table->insns, opcode_rule->format_names))
        {
        {
          discard_reason = "wrong format name";
          discard_reason = "wrong format name";
        }
        }
      else if (!insns_match_nr_words (table->insns, opcode_rule->word_nr + 1))
      else if (!insns_match_nr_words (table->insns, opcode_rule->word_nr + 1))
        {
        {
          discard_reason = "wrong nr words";
          discard_reason = "wrong nr words";
        }
        }
      else if (!table_matches_path (table, opcode_rule->paths))
      else if (!table_matches_path (table, opcode_rule->paths))
        {
        {
          discard_reason = "path failed";
          discard_reason = "path failed";
        }
        }
      else
      else
        if (!insns_match_conditions (table->insns, opcode_rule->conditions))
        if (!insns_match_conditions (table->insns, opcode_rule->conditions))
        {
        {
          discard_reason = "condition failed";
          discard_reason = "condition failed";
        }
        }
      else
      else
        {
        {
          discard_reason = "no opcode field";
          discard_reason = "no opcode field";
          table->opcode = gen_entry_find_opcode_field (table->insns,
          table->opcode = gen_entry_find_opcode_field (table->insns,
                                                       opcode_rule,
                                                       opcode_rule,
                                                       table->nr_insns == 1     /*string-only */
                                                       table->nr_insns == 1     /*string-only */
            );
            );
          if (table->opcode != NULL)
          if (table->opcode != NULL)
            {
            {
              table->opcode_rule = opcode_rule;
              table->opcode_rule = opcode_rule;
              break;
              break;
            }
            }
        }
        }
 
 
      if (options.trace.rule_rejection)
      if (options.trace.rule_rejection)
        {
        {
          print_gen_entry_path (opcode_rule->line, table, notify);
          print_gen_entry_path (opcode_rule->line, table, notify);
          notify (NULL, ": rule discarded - %s\n", discard_reason);
          notify (NULL, ": rule discarded - %s\n", discard_reason);
        }
        }
    }
    }
 
 
  /* did we find anything */
  /* did we find anything */
  if (opcode_rule == NULL)
  if (opcode_rule == NULL)
    {
    {
      /* the decode table failed, this set of instructions haven't
      /* the decode table failed, this set of instructions haven't
         been uniquely identified */
         been uniquely identified */
      if (table->nr_insns > 1)
      if (table->nr_insns > 1)
        {
        {
          print_gen_entry_insns (table, warning,
          print_gen_entry_insns (table, warning,
                                 "was not uniquely decoded",
                                 "was not uniquely decoded",
                                 "decodes to the same entry");
                                 "decodes to the same entry");
          error (NULL, "");
          error (NULL, "");
        }
        }
      return;
      return;
    }
    }
 
 
  /* Determine the number of words that must have been prefetched for
  /* Determine the number of words that must have been prefetched for
     this table to function */
     this table to function */
  if (table->parent == NULL)
  if (table->parent == NULL)
    table->nr_prefetched_words = table->opcode_rule->word_nr + 1;
    table->nr_prefetched_words = table->opcode_rule->word_nr + 1;
  else if (table->opcode_rule->word_nr + 1 >
  else if (table->opcode_rule->word_nr + 1 >
           table->parent->nr_prefetched_words)
           table->parent->nr_prefetched_words)
    table->nr_prefetched_words = table->opcode_rule->word_nr + 1;
    table->nr_prefetched_words = table->opcode_rule->word_nr + 1;
  else
  else
    table->nr_prefetched_words = table->parent->nr_prefetched_words;
    table->nr_prefetched_words = table->parent->nr_prefetched_words;
 
 
  /* back link what we found to its parent */
  /* back link what we found to its parent */
  if (table->parent != NULL)
  if (table->parent != NULL)
    {
    {
      ASSERT (table->parent->opcode != NULL);
      ASSERT (table->parent->opcode != NULL);
      table->opcode->parent = table->parent->opcode;
      table->opcode->parent = table->parent->opcode;
    }
    }
 
 
  /* report the rule being used to expand the instructions */
  /* report the rule being used to expand the instructions */
  if (options.trace.rule_selection)
  if (options.trace.rule_selection)
    {
    {
      print_gen_entry_path (table->opcode_rule->line, table, notify);
      print_gen_entry_path (table->opcode_rule->line, table, notify);
      notify (NULL,
      notify (NULL,
              ": decode - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d\n",
              ": decode - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d\n",
              table->opcode->word_nr,
              table->opcode->word_nr,
              i2target (options.hi_bit_nr, table->opcode->first),
              i2target (options.hi_bit_nr, table->opcode->first),
              i2target (options.hi_bit_nr, table->opcode->last),
              i2target (options.hi_bit_nr, table->opcode->last),
              i2target (options.hi_bit_nr, table->opcode_rule->first),
              i2target (options.hi_bit_nr, table->opcode_rule->first),
              i2target (options.hi_bit_nr, table->opcode_rule->last),
              i2target (options.hi_bit_nr, table->opcode_rule->last),
              table->opcode->nr_opcodes, table->nr_entries);
              table->opcode->nr_opcodes, table->nr_entries);
    }
    }
 
 
  /* expand the raw instructions according to the opcode */
  /* expand the raw instructions according to the opcode */
  {
  {
    insn_list *entry;
    insn_list *entry;
    for (entry = table->insns; entry != NULL; entry = entry->next)
    for (entry = table->insns; entry != NULL; entry = entry->next)
      {
      {
        if (options.trace.insn_expansion)
        if (options.trace.insn_expansion)
          {
          {
            print_gen_entry_path (table->opcode_rule->line, table, notify);
            print_gen_entry_path (table->opcode_rule->line, table, notify);
            notify (NULL, ": expand - %s.%s\n",
            notify (NULL, ": expand - %s.%s\n",
                    entry->insn->format_name, entry->insn->name);
                    entry->insn->format_name, entry->insn->name);
          }
          }
        gen_entry_insert_expanding (table, entry->insn);
        gen_entry_insert_expanding (table, entry->insn);
      }
      }
  }
  }
 
 
  /* dump the results */
  /* dump the results */
  if (options.trace.entries)
  if (options.trace.entries)
    {
    {
      gen_entry *entry;
      gen_entry *entry;
      for (entry = table->entries; entry != NULL; entry = entry->sibling)
      for (entry = table->entries; entry != NULL; entry = entry->sibling)
        {
        {
          insn_list *l;
          insn_list *l;
          print_gen_entry_path (table->opcode_rule->line, entry, notify);
          print_gen_entry_path (table->opcode_rule->line, entry, notify);
          notify (NULL, ": %d - entries %d -",
          notify (NULL, ": %d - entries %d -",
                  entry->opcode_nr, entry->nr_insns);
                  entry->opcode_nr, entry->nr_insns);
          for (l = entry->insns; l != NULL; l = l->next)
          for (l = entry->insns; l != NULL; l = l->next)
            notify (NULL, " %s.%s", l->insn->format_name, l->insn->name);
            notify (NULL, " %s.%s", l->insn->format_name, l->insn->name);
          notify (NULL, "\n");
          notify (NULL, "\n");
        }
        }
    }
    }
 
 
  /* perform a combine pass if needed */
  /* perform a combine pass if needed */
  if (table->opcode_rule->with_combine)
  if (table->opcode_rule->with_combine)
    {
    {
      gen_entry *entry;
      gen_entry *entry;
      for (entry = table->entries; entry != NULL; entry = entry->sibling)
      for (entry = table->entries; entry != NULL; entry = entry->sibling)
        {
        {
          if (entry->combined_parent == NULL)
          if (entry->combined_parent == NULL)
            {
            {
              gen_entry **last = &entry->combined_next;
              gen_entry **last = &entry->combined_next;
              gen_entry *alt;
              gen_entry *alt;
              for (alt = entry->sibling; alt != NULL; alt = alt->sibling)
              for (alt = entry->sibling; alt != NULL; alt = alt->sibling)
                {
                {
                  if (alt->combined_parent == NULL
                  if (alt->combined_parent == NULL
                      && insn_list_cmp (entry->insns, alt->insns) == 0)
                      && insn_list_cmp (entry->insns, alt->insns) == 0)
                    {
                    {
                      alt->combined_parent = entry;
                      alt->combined_parent = entry;
                      *last = alt;
                      *last = alt;
                      last = &alt->combined_next;
                      last = &alt->combined_next;
                    }
                    }
                }
                }
            }
            }
        }
        }
      if (options.trace.combine)
      if (options.trace.combine)
        {
        {
          int nr_unique = 0;
          int nr_unique = 0;
          gen_entry *entry;
          gen_entry *entry;
          for (entry = table->entries; entry != NULL; entry = entry->sibling)
          for (entry = table->entries; entry != NULL; entry = entry->sibling)
            {
            {
              if (entry->combined_parent == NULL)
              if (entry->combined_parent == NULL)
                {
                {
                  insn_list *l;
                  insn_list *l;
                  gen_entry *duplicate;
                  gen_entry *duplicate;
                  nr_unique++;
                  nr_unique++;
                  print_gen_entry_path (table->opcode_rule->line, entry,
                  print_gen_entry_path (table->opcode_rule->line, entry,
                                        notify);
                                        notify);
                  for (duplicate = entry->combined_next; duplicate != NULL;
                  for (duplicate = entry->combined_next; duplicate != NULL;
                       duplicate = duplicate->combined_next)
                       duplicate = duplicate->combined_next)
                    {
                    {
                      notify (NULL, "+%d", duplicate->opcode_nr);
                      notify (NULL, "+%d", duplicate->opcode_nr);
                    }
                    }
                  notify (NULL, ": entries %d -", entry->nr_insns);
                  notify (NULL, ": entries %d -", entry->nr_insns);
                  for (l = entry->insns; l != NULL; l = l->next)
                  for (l = entry->insns; l != NULL; l = l->next)
                    {
                    {
                      notify (NULL, " %s.%s",
                      notify (NULL, " %s.%s",
                              l->insn->format_name, l->insn->name);
                              l->insn->format_name, l->insn->name);
                    }
                    }
                  notify (NULL, "\n");
                  notify (NULL, "\n");
                }
                }
            }
            }
          print_gen_entry_path (table->opcode_rule->line, table, notify);
          print_gen_entry_path (table->opcode_rule->line, table, notify);
          notify (NULL,
          notify (NULL,
                  ": combine - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d, unique %d\n",
                  ": combine - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d, unique %d\n",
                  table->opcode->word_nr, i2target (options.hi_bit_nr,
                  table->opcode->word_nr, i2target (options.hi_bit_nr,
                                                    table->opcode->first),
                                                    table->opcode->first),
                  i2target (options.hi_bit_nr, table->opcode->last),
                  i2target (options.hi_bit_nr, table->opcode->last),
                  i2target (options.hi_bit_nr, table->opcode_rule->first),
                  i2target (options.hi_bit_nr, table->opcode_rule->first),
                  i2target (options.hi_bit_nr, table->opcode_rule->last),
                  i2target (options.hi_bit_nr, table->opcode_rule->last),
                  table->opcode->nr_opcodes, table->nr_entries, nr_unique);
                  table->opcode->nr_opcodes, table->nr_entries, nr_unique);
        }
        }
    }
    }
 
 
  /* Check that the rule did more than re-arange the order of the
  /* Check that the rule did more than re-arange the order of the
     instructions */
     instructions */
  {
  {
    gen_entry *entry;
    gen_entry *entry;
    for (entry = table->entries; entry != NULL; entry = entry->sibling)
    for (entry = table->entries; entry != NULL; entry = entry->sibling)
      {
      {
        if (entry->combined_parent == NULL)
        if (entry->combined_parent == NULL)
          {
          {
            if (insn_list_cmp (table->insns, entry->insns) == 0)
            if (insn_list_cmp (table->insns, entry->insns) == 0)
              {
              {
                print_gen_entry_path (table->opcode_rule->line, table,
                print_gen_entry_path (table->opcode_rule->line, table,
                                      warning);
                                      warning);
                warning (NULL,
                warning (NULL,
                         ": Applying rule just copied all instructions\n");
                         ": Applying rule just copied all instructions\n");
                print_gen_entry_insns (entry, warning, "Copied", NULL);
                print_gen_entry_insns (entry, warning, "Copied", NULL);
                error (NULL, "");
                error (NULL, "");
              }
              }
          }
          }
      }
      }
  }
  }
 
 
  /* if some form of expanded table, fill in the missing dots */
  /* if some form of expanded table, fill in the missing dots */
  switch (table->opcode_rule->gen)
  switch (table->opcode_rule->gen)
    {
    {
    case padded_switch_gen:
    case padded_switch_gen:
    case array_gen:
    case array_gen:
    case goto_switch_gen:
    case goto_switch_gen:
      if (!table->opcode->is_boolean)
      if (!table->opcode->is_boolean)
        {
        {
          gen_entry **entry = &table->entries;
          gen_entry **entry = &table->entries;
          gen_entry *illegals = NULL;
          gen_entry *illegals = NULL;
          gen_entry **last_illegal = &illegals;
          gen_entry **last_illegal = &illegals;
          int opcode_nr = 0;
          int opcode_nr = 0;
          while (opcode_nr < table->opcode->nr_opcodes)
          while (opcode_nr < table->opcode->nr_opcodes)
            {
            {
              if ((*entry) == NULL || (*entry)->opcode_nr != opcode_nr)
              if ((*entry) == NULL || (*entry)->opcode_nr != opcode_nr)
                {
                {
                  /* missing - insert it under our feet at *entry */
                  /* missing - insert it under our feet at *entry */
                  gen_entry_insert_insn (table, table->top->isa->illegal_insn, table->opcode->word_nr, 0,        /* nr_prefetched_words == 0 for invalid */
                  gen_entry_insert_insn (table, table->top->isa->illegal_insn, table->opcode->word_nr, 0,        /* nr_prefetched_words == 0 for invalid */
                                         opcode_nr, NULL);
                                         opcode_nr, NULL);
                  ASSERT ((*entry) != NULL);
                  ASSERT ((*entry) != NULL);
                  ASSERT ((*entry)->opcode_nr == opcode_nr);
                  ASSERT ((*entry)->opcode_nr == opcode_nr);
                  (*last_illegal) = *entry;
                  (*last_illegal) = *entry;
                  (*last_illegal)->combined_parent = illegals;
                  (*last_illegal)->combined_parent = illegals;
                  last_illegal = &(*last_illegal)->combined_next;
                  last_illegal = &(*last_illegal)->combined_next;
                }
                }
              entry = &(*entry)->sibling;
              entry = &(*entry)->sibling;
              opcode_nr++;
              opcode_nr++;
            }
            }
          /* oops, will have pointed the first illegal insn back to
          /* oops, will have pointed the first illegal insn back to
             its self.  Fix this */
             its self.  Fix this */
          if (illegals != NULL)
          if (illegals != NULL)
            illegals->combined_parent = NULL;
            illegals->combined_parent = NULL;
        }
        }
      break;
      break;
    case switch_gen:
    case switch_gen:
    case invalid_gen:
    case invalid_gen:
      /* ignore */
      /* ignore */
      break;
      break;
    }
    }
 
 
  /* and do the same for the newly created sub entries but *only*
  /* and do the same for the newly created sub entries but *only*
     expand entries that haven't been combined. */
     expand entries that haven't been combined. */
  {
  {
    gen_entry *entry;
    gen_entry *entry;
    for (entry = table->entries; entry != NULL; entry = entry->sibling)
    for (entry = table->entries; entry != NULL; entry = entry->sibling)
      {
      {
        if (entry->combined_parent == NULL)
        if (entry->combined_parent == NULL)
          {
          {
            gen_entry_expand_insns (entry);
            gen_entry_expand_insns (entry);
          }
          }
      }
      }
  }
  }
}
}
 
 
void
void
gen_tables_expand_insns (gen_table *gen)
gen_tables_expand_insns (gen_table *gen)
{
{
  gen_list *entry;
  gen_list *entry;
  for (entry = gen->tables; entry != NULL; entry = entry->next)
  for (entry = gen->tables; entry != NULL; entry = entry->next)
    {
    {
      gen_entry_expand_insns (entry->table);
      gen_entry_expand_insns (entry->table);
    }
    }
}
}
 
 
 
 
/* create a list of all the semantic functions that need to be
/* create a list of all the semantic functions that need to be
   generated.  Eliminate any duplicates. Verify that the decode stage
   generated.  Eliminate any duplicates. Verify that the decode stage
   worked. */
   worked. */
 
 
static void
static void
make_gen_semantics_list (lf *file, gen_entry *entry, int depth, void *data)
make_gen_semantics_list (lf *file, gen_entry *entry, int depth, void *data)
{
{
  gen_table *gen = (gen_table *) data;
  gen_table *gen = (gen_table *) data;
  insn_list *insn;
  insn_list *insn;
  /* Not interested in an entrie that have been combined into some
  /* Not interested in an entrie that have been combined into some
     other entry at the same level */
     other entry at the same level */
  if (entry->combined_parent != NULL)
  if (entry->combined_parent != NULL)
    return;
    return;
 
 
  /* a leaf should contain exactly one instruction. If not the decode
  /* a leaf should contain exactly one instruction. If not the decode
     stage failed. */
     stage failed. */
  ASSERT (entry->nr_insns == 1);
  ASSERT (entry->nr_insns == 1);
 
 
  /* Enter this instruction into the list of semantic functions. */
  /* Enter this instruction into the list of semantic functions. */
  insn = insn_list_insert (&gen->semantics, &gen->nr_semantics,
  insn = insn_list_insert (&gen->semantics, &gen->nr_semantics,
                           entry->insns->insn,
                           entry->insns->insn,
                           entry->expanded_bits,
                           entry->expanded_bits,
                           entry->parent->opcode,
                           entry->parent->opcode,
                           entry->insns->nr_prefetched_words,
                           entry->insns->nr_prefetched_words,
                           merge_duplicate_insns);
                           merge_duplicate_insns);
  /* point the table entry at the real semantic function */
  /* point the table entry at the real semantic function */
  ASSERT (insn != NULL);
  ASSERT (insn != NULL);
  entry->insns->semantic = insn;
  entry->insns->semantic = insn;
}
}
 
 
 
 
void
void
gen_tables_expand_semantics (gen_table *gen)
gen_tables_expand_semantics (gen_table *gen)
{
{
  gen_list *entry;
  gen_list *entry;
  for (entry = gen->tables; entry != NULL; entry = entry->next)
  for (entry = gen->tables; entry != NULL; entry = entry->next)
    {
    {
      gen_entry_traverse_tree (NULL, entry->table, 1,   /* depth */
      gen_entry_traverse_tree (NULL, entry->table, 1,   /* depth */
                               NULL,    /* start-handler */
                               NULL,    /* start-handler */
                               make_gen_semantics_list, /* leaf-handler */
                               make_gen_semantics_list, /* leaf-handler */
                               NULL,    /* end-handler */
                               NULL,    /* end-handler */
                               gen);    /* data */
                               gen);    /* data */
    }
    }
}
}
 
 
 
 
 
 
#ifdef MAIN
#ifdef MAIN
 
 
 
 
static void
static void
dump_opcode_field (lf *file,
dump_opcode_field (lf *file,
                   char *prefix,
                   char *prefix,
                   opcode_field *field, char *suffix, int levels)
                   opcode_field *field, char *suffix, int levels)
{
{
  lf_printf (file, "%s(opcode_field *) 0x%lx", prefix, (long) field);
  lf_printf (file, "%s(opcode_field *) 0x%lx", prefix, (long) field);
  if (levels && field != NULL)
  if (levels && field != NULL)
    {
    {
      lf_indent (file, +1);
      lf_indent (file, +1);
      lf_printf (file, "\n(first %d)", field->first);
      lf_printf (file, "\n(first %d)", field->first);
      lf_printf (file, "\n(last %d)", field->last);
      lf_printf (file, "\n(last %d)", field->last);
      lf_printf (file, "\n(nr_opcodes %d)", field->nr_opcodes);
      lf_printf (file, "\n(nr_opcodes %d)", field->nr_opcodes);
      lf_printf (file, "\n(is_boolean %d)", field->is_boolean);
      lf_printf (file, "\n(is_boolean %d)", field->is_boolean);
      lf_printf (file, "\n(boolean_constant %d)", field->boolean_constant);
      lf_printf (file, "\n(boolean_constant %d)", field->boolean_constant);
      dump_opcode_field (file, "\n(parent ", field->parent, ")", levels - 1);
      dump_opcode_field (file, "\n(parent ", field->parent, ")", levels - 1);
      lf_indent (file, -1);
      lf_indent (file, -1);
    }
    }
  lf_printf (file, "%s", suffix);
  lf_printf (file, "%s", suffix);
}
}
 
 
 
 
static void
static void
dump_opcode_bits (lf *file,
dump_opcode_bits (lf *file,
                  char *prefix, opcode_bits *bits, char *suffix, int levels)
                  char *prefix, opcode_bits *bits, char *suffix, int levels)
{
{
  lf_printf (file, "%s(opcode_bits *) 0x%lx", prefix, (long) bits);
  lf_printf (file, "%s(opcode_bits *) 0x%lx", prefix, (long) bits);
 
 
  if (levels && bits != NULL)
  if (levels && bits != NULL)
    {
    {
      lf_indent (file, +1);
      lf_indent (file, +1);
      lf_printf (file, "\n(value %d)", bits->value);
      lf_printf (file, "\n(value %d)", bits->value);
      dump_opcode_field (file, "\n(opcode ", bits->opcode, ")", 0);
      dump_opcode_field (file, "\n(opcode ", bits->opcode, ")", 0);
      dump_insn_field (file, "\n(field ", bits->field, ")");
      dump_insn_field (file, "\n(field ", bits->field, ")");
      dump_opcode_bits (file, "\n(next ", bits->next, ")", levels - 1);
      dump_opcode_bits (file, "\n(next ", bits->next, ")", levels - 1);
      lf_indent (file, -1);
      lf_indent (file, -1);
    }
    }
  lf_printf (file, "%s", suffix);
  lf_printf (file, "%s", suffix);
}
}
 
 
 
 
 
 
static void
static void
dump_insn_list (lf *file, char *prefix, insn_list *entry, char *suffix)
dump_insn_list (lf *file, char *prefix, insn_list *entry, char *suffix)
{
{
  lf_printf (file, "%s(insn_list *) 0x%lx", prefix, (long) entry);
  lf_printf (file, "%s(insn_list *) 0x%lx", prefix, (long) entry);
 
 
  if (entry != NULL)
  if (entry != NULL)
    {
    {
      lf_indent (file, +1);
      lf_indent (file, +1);
      dump_insn_entry (file, "\n(insn ", entry->insn, ")");
      dump_insn_entry (file, "\n(insn ", entry->insn, ")");
      lf_printf (file, "\n(next 0x%lx)", (long) entry->next);
      lf_printf (file, "\n(next 0x%lx)", (long) entry->next);
      lf_indent (file, -1);
      lf_indent (file, -1);
    }
    }
  lf_printf (file, "%s", suffix);
  lf_printf (file, "%s", suffix);
}
}
 
 
 
 
static void
static void
dump_insn_word_entry_list_entries (lf *file,
dump_insn_word_entry_list_entries (lf *file,
                                   char *prefix,
                                   char *prefix,
                                   insn_list *entry, char *suffix)
                                   insn_list *entry, char *suffix)
{
{
  lf_printf (file, "%s", prefix);
  lf_printf (file, "%s", prefix);
  while (entry != NULL)
  while (entry != NULL)
    {
    {
      dump_insn_list (file, "\n(", entry, ")");
      dump_insn_list (file, "\n(", entry, ")");
      entry = entry->next;
      entry = entry->next;
    }
    }
  lf_printf (file, "%s", suffix);
  lf_printf (file, "%s", suffix);
}
}
 
 
 
 
static void
static void
dump_gen_entry (lf *file,
dump_gen_entry (lf *file,
                char *prefix, gen_entry *table, char *suffix, int levels)
                char *prefix, gen_entry *table, char *suffix, int levels)
{
{
 
 
  lf_printf (file, "%s(gen_entry *) 0x%lx", prefix, (long) table);
  lf_printf (file, "%s(gen_entry *) 0x%lx", prefix, (long) table);
 
 
  if (levels && table !=NULL)
  if (levels && table !=NULL)
    {
    {
 
 
      lf_indent (file, +1);
      lf_indent (file, +1);
      lf_printf (file, "\n(opcode_nr %d)", table->opcode_nr);
      lf_printf (file, "\n(opcode_nr %d)", table->opcode_nr);
      lf_printf (file, "\n(word_nr %d)", table->word_nr);
      lf_printf (file, "\n(word_nr %d)", table->word_nr);
      dump_opcode_bits (file, "\n(expanded_bits ", table->expanded_bits, ")",
      dump_opcode_bits (file, "\n(expanded_bits ", table->expanded_bits, ")",
                        -1);
                        -1);
      lf_printf (file, "\n(nr_insns %d)", table->nr_insns);
      lf_printf (file, "\n(nr_insns %d)", table->nr_insns);
      dump_insn_word_entry_list_entries (file, "\n(insns ", table->insns,
      dump_insn_word_entry_list_entries (file, "\n(insns ", table->insns,
                                         ")");
                                         ")");
      dump_decode_rule (file, "\n(opcode_rule ", table->opcode_rule, ")");
      dump_decode_rule (file, "\n(opcode_rule ", table->opcode_rule, ")");
      dump_opcode_field (file, "\n(opcode ", table->opcode, ")", 0);
      dump_opcode_field (file, "\n(opcode ", table->opcode, ")", 0);
      lf_printf (file, "\n(nr_entries %d)", table->nr_entries);
      lf_printf (file, "\n(nr_entries %d)", table->nr_entries);
      dump_gen_entry (file, "\n(entries ", table->entries, ")",
      dump_gen_entry (file, "\n(entries ", table->entries, ")",
                      table->nr_entries);
                      table->nr_entries);
      dump_gen_entry (file, "\n(sibling ", table->sibling, ")", levels - 1);
      dump_gen_entry (file, "\n(sibling ", table->sibling, ")", levels - 1);
      dump_gen_entry (file, "\n(parent ", table->parent, ")", 0);
      dump_gen_entry (file, "\n(parent ", table->parent, ")", 0);
      lf_indent (file, -1);
      lf_indent (file, -1);
    }
    }
  lf_printf (file, "%s", suffix);
  lf_printf (file, "%s", suffix);
}
}
 
 
static void
static void
dump_gen_list (lf *file,
dump_gen_list (lf *file,
               char *prefix, gen_list *entry, char *suffix, int levels)
               char *prefix, gen_list *entry, char *suffix, int levels)
{
{
  while (entry != NULL)
  while (entry != NULL)
    {
    {
      lf_printf (file, "%s(gen_list *) 0x%lx", prefix, (long) entry);
      lf_printf (file, "%s(gen_list *) 0x%lx", prefix, (long) entry);
      dump_gen_entry (file, "\n(", entry->table, ")", levels);
      dump_gen_entry (file, "\n(", entry->table, ")", levels);
      lf_printf (file, "\n(next (gen_list *) 0x%lx)", (long) entry->next);
      lf_printf (file, "\n(next (gen_list *) 0x%lx)", (long) entry->next);
      lf_printf (file, "%s", suffix);
      lf_printf (file, "%s", suffix);
    }
    }
}
}
 
 
 
 
static void
static void
dump_gen_table (lf *file,
dump_gen_table (lf *file,
                char *prefix, gen_table *gen, char *suffix, int levels)
                char *prefix, gen_table *gen, char *suffix, int levels)
{
{
  lf_printf (file, "%s(gen_table *) 0x%lx", prefix, (long) gen);
  lf_printf (file, "%s(gen_table *) 0x%lx", prefix, (long) gen);
  lf_printf (file, "\n(isa (insn_table *) 0x%lx)", (long) gen->isa);
  lf_printf (file, "\n(isa (insn_table *) 0x%lx)", (long) gen->isa);
  lf_printf (file, "\n(rules (decode_table *) 0x%lx)", (long) gen->rules);
  lf_printf (file, "\n(rules (decode_table *) 0x%lx)", (long) gen->rules);
  dump_gen_list (file, "\n(", gen->tables, ")", levels);
  dump_gen_list (file, "\n(", gen->tables, ")", levels);
  lf_printf (file, "%s", suffix);
  lf_printf (file, "%s", suffix);
}
}
 
 
 
 
igen_options options;
igen_options options;
 
 
int
int
main (int argc, char **argv)
main (int argc, char **argv)
{
{
  decode_table *decode_rules;
  decode_table *decode_rules;
  insn_table *instructions;
  insn_table *instructions;
  gen_table *gen;
  gen_table *gen;
  lf *l;
  lf *l;
 
 
  if (argc != 7)
  if (argc != 7)
    error (NULL,
    error (NULL,
           "Usage: insn <filter-in> <hi-bit-nr> <insn-bit-size> <widths> <decode-table> <insn-table>\n");
           "Usage: insn <filter-in> <hi-bit-nr> <insn-bit-size> <widths> <decode-table> <insn-table>\n");
 
 
  INIT_OPTIONS (options);
  INIT_OPTIONS (options);
 
 
  filter_parse (&options.flags_filter, argv[1]);
  filter_parse (&options.flags_filter, argv[1]);
 
 
  options.hi_bit_nr = a2i (argv[2]);
  options.hi_bit_nr = a2i (argv[2]);
  options.insn_bit_size = a2i (argv[3]);
  options.insn_bit_size = a2i (argv[3]);
  options.insn_specifying_widths = a2i (argv[4]);
  options.insn_specifying_widths = a2i (argv[4]);
  ASSERT (options.hi_bit_nr < options.insn_bit_size);
  ASSERT (options.hi_bit_nr < options.insn_bit_size);
 
 
  instructions = load_insn_table (argv[6], NULL);
  instructions = load_insn_table (argv[6], NULL);
  decode_rules = load_decode_table (argv[5]);
  decode_rules = load_decode_table (argv[5]);
  gen = make_gen_tables (instructions, decode_rules);
  gen = make_gen_tables (instructions, decode_rules);
 
 
  gen_tables_expand_insns (gen);
  gen_tables_expand_insns (gen);
 
 
  l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn");
  l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn");
 
 
  dump_gen_table (l, "(", gen, ")\n", -1);
  dump_gen_table (l, "(", gen, ")\n", -1);
  return 0;
  return 0;
}
}
 
 
#endif
#endif
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.