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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [graph.c] - Diff between revs 154 and 816

Only display areas with differences | Details | Blame | View Log

Rev 154 Rev 816
/* Output routines for graphical representation.
/* Output routines for graphical representation.
   Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007
   Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it under
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
Software Foundation; either version 3, or (at your option) any later
version.
version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
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 GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include <config.h>
#include <config.h>
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "rtl.h"
#include "rtl.h"
#include "flags.h"
#include "flags.h"
#include "output.h"
#include "output.h"
#include "function.h"
#include "function.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "obstack.h"
#include "obstack.h"
#include "basic-block.h"
#include "basic-block.h"
#include "toplev.h"
#include "toplev.h"
#include "graph.h"
#include "graph.h"
 
 
static const char *const graph_ext[] =
static const char *const graph_ext[] =
{
{
  /* no_graph */ "",
  /* no_graph */ "",
  /* vcg */      ".vcg",
  /* vcg */      ".vcg",
};
};
 
 
static void start_fct (FILE *);
static void start_fct (FILE *);
static void start_bb (FILE *, int);
static void start_bb (FILE *, int);
static void node_data (FILE *, rtx);
static void node_data (FILE *, rtx);
static void draw_edge (FILE *, int, int, int, int);
static void draw_edge (FILE *, int, int, int, int);
static void end_fct (FILE *);
static void end_fct (FILE *);
static void end_bb (FILE *);
static void end_bb (FILE *);
 
 
/* Output text for new basic block.  */
/* Output text for new basic block.  */
static void
static void
start_fct (FILE *fp)
start_fct (FILE *fp)
{
{
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      fprintf (fp, "\
      fprintf (fp, "\
graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
               current_function_name (), current_function_name ());
               current_function_name (), current_function_name ());
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
}
}
 
 
static void
static void
start_bb (FILE *fp, int bb)
start_bb (FILE *fp, int bb)
{
{
#if 0
#if 0
  reg_set_iterator rsi;
  reg_set_iterator rsi;
#endif
#endif
 
 
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      fprintf (fp, "\
      fprintf (fp, "\
graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
label: \"basic block %d",
label: \"basic block %d",
               current_function_name (), bb, bb);
               current_function_name (), bb, bb);
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
 
 
#if 0
#if 0
  /* FIXME Should this be printed?  It makes the graph significantly larger.  */
  /* FIXME Should this be printed?  It makes the graph significantly larger.  */
 
 
  /* Print the live-at-start register list.  */
  /* Print the live-at-start register list.  */
  fputc ('\n', fp);
  fputc ('\n', fp);
  EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi)
  EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi)
    {
    {
      fprintf (fp, " %d", i);
      fprintf (fp, " %d", i);
      if (i < FIRST_PSEUDO_REGISTER)
      if (i < FIRST_PSEUDO_REGISTER)
        fprintf (fp, " [%s]", reg_names[i]);
        fprintf (fp, " [%s]", reg_names[i]);
    }
    }
#endif
#endif
 
 
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      fputs ("\"\n\n", fp);
      fputs ("\"\n\n", fp);
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
}
}
 
 
static void
static void
node_data (FILE *fp, rtx tmp_rtx)
node_data (FILE *fp, rtx tmp_rtx)
{
{
  if (PREV_INSN (tmp_rtx) == 0)
  if (PREV_INSN (tmp_rtx) == 0)
    {
    {
      /* This is the first instruction.  Add an edge from the starting
      /* This is the first instruction.  Add an edge from the starting
         block.  */
         block.  */
      switch (graph_dump_format)
      switch (graph_dump_format)
        {
        {
        case vcg:
        case vcg:
          fprintf (fp, "\
          fprintf (fp, "\
edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
                   current_function_name (),
                   current_function_name (),
                   current_function_name (), XINT (tmp_rtx, 0));
                   current_function_name (), XINT (tmp_rtx, 0));
          break;
          break;
        case no_graph:
        case no_graph:
          break;
          break;
        }
        }
    }
    }
 
 
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
      fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
label: \"%s %d\n",
label: \"%s %d\n",
               current_function_name (), XINT (tmp_rtx, 0),
               current_function_name (), XINT (tmp_rtx, 0),
               NOTE_P (tmp_rtx) ? "lightgrey"
               NOTE_P (tmp_rtx) ? "lightgrey"
               : NONJUMP_INSN_P (tmp_rtx) ? "green"
               : NONJUMP_INSN_P (tmp_rtx) ? "green"
               : JUMP_P (tmp_rtx) ? "darkgreen"
               : JUMP_P (tmp_rtx) ? "darkgreen"
               : CALL_P (tmp_rtx) ? "darkgreen"
               : CALL_P (tmp_rtx) ? "darkgreen"
               : LABEL_P (tmp_rtx) ?  "\
               : LABEL_P (tmp_rtx) ?  "\
darkgrey\n  shape: ellipse" : "white",
darkgrey\n  shape: ellipse" : "white",
               GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
               GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
 
 
  /* Print the RTL.  */
  /* Print the RTL.  */
  if (NOTE_P (tmp_rtx))
  if (NOTE_P (tmp_rtx))
    {
    {
      const char *name = "";
      const char *name = "";
      if (NOTE_LINE_NUMBER (tmp_rtx) < 0)
      if (NOTE_LINE_NUMBER (tmp_rtx) < 0)
        name =  GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (tmp_rtx));
        name =  GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (tmp_rtx));
      fprintf (fp, " %s", name);
      fprintf (fp, " %s", name);
    }
    }
  else if (INSN_P (tmp_rtx))
  else if (INSN_P (tmp_rtx))
    print_rtl_single (fp, PATTERN (tmp_rtx));
    print_rtl_single (fp, PATTERN (tmp_rtx));
  else
  else
    print_rtl_single (fp, tmp_rtx);
    print_rtl_single (fp, tmp_rtx);
 
 
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      fputs ("\"\n}\n", fp);
      fputs ("\"\n}\n", fp);
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
}
}
 
 
static void
static void
draw_edge (FILE *fp, int from, int to, int bb_edge, int class)
draw_edge (FILE *fp, int from, int to, int bb_edge, int class)
{
{
  const char * color;
  const char * color;
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      color = "";
      color = "";
      if (class == 2)
      if (class == 2)
        color = "color: red ";
        color = "color: red ";
      else if (bb_edge)
      else if (bb_edge)
        color = "color: blue ";
        color = "color: blue ";
      else if (class == 3)
      else if (class == 3)
        color = "color: green ";
        color = "color: green ";
      fprintf (fp,
      fprintf (fp,
               "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
               "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
               current_function_name (), from,
               current_function_name (), from,
               current_function_name (), to, color);
               current_function_name (), to, color);
      if (class)
      if (class)
        fprintf (fp, "class: %d ", class);
        fprintf (fp, "class: %d ", class);
      fputs ("}\n", fp);
      fputs ("}\n", fp);
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
}
}
 
 
static void
static void
end_bb (FILE *fp)
end_bb (FILE *fp)
{
{
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      fputs ("}\n", fp);
      fputs ("}\n", fp);
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
}
}
 
 
static void
static void
end_fct (FILE *fp)
end_fct (FILE *fp)
{
{
  switch (graph_dump_format)
  switch (graph_dump_format)
    {
    {
    case vcg:
    case vcg:
      fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
      fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
               current_function_name ());
               current_function_name ());
      break;
      break;
    case no_graph:
    case no_graph:
      break;
      break;
    }
    }
}
}


/* Like print_rtl, but also print out live information for the start of each
/* Like print_rtl, but also print out live information for the start of each
   basic block.  */
   basic block.  */
void
void
print_rtl_graph_with_bb (const char *base, rtx rtx_first)
print_rtl_graph_with_bb (const char *base, rtx rtx_first)
{
{
  rtx tmp_rtx;
  rtx tmp_rtx;
  size_t namelen = strlen (base);
  size_t namelen = strlen (base);
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
  char *buf = alloca (namelen + extlen);
  char *buf = alloca (namelen + extlen);
  FILE *fp;
  FILE *fp;
 
 
  if (basic_block_info == NULL)
  if (basic_block_info == NULL)
    return;
    return;
 
 
  memcpy (buf, base, namelen);
  memcpy (buf, base, namelen);
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
 
 
  fp = fopen (buf, "a");
  fp = fopen (buf, "a");
  if (fp == NULL)
  if (fp == NULL)
    return;
    return;
 
 
  if (rtx_first == 0)
  if (rtx_first == 0)
    fprintf (fp, "(nil)\n");
    fprintf (fp, "(nil)\n");
  else
  else
    {
    {
      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
      int max_uid = get_max_uid ();
      int max_uid = get_max_uid ();
      int *start = XNEWVEC (int, max_uid);
      int *start = XNEWVEC (int, max_uid);
      int *end = XNEWVEC (int, max_uid);
      int *end = XNEWVEC (int, max_uid);
      enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid);
      enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid);
      basic_block bb;
      basic_block bb;
      int i;
      int i;
 
 
      for (i = 0; i < max_uid; ++i)
      for (i = 0; i < max_uid; ++i)
        {
        {
          start[i] = end[i] = -1;
          start[i] = end[i] = -1;
          in_bb_p[i] = NOT_IN_BB;
          in_bb_p[i] = NOT_IN_BB;
        }
        }
 
 
      FOR_EACH_BB_REVERSE (bb)
      FOR_EACH_BB_REVERSE (bb)
        {
        {
          rtx x;
          rtx x;
          start[INSN_UID (BB_HEAD (bb))] = bb->index;
          start[INSN_UID (BB_HEAD (bb))] = bb->index;
          end[INSN_UID (BB_END (bb))] = bb->index;
          end[INSN_UID (BB_END (bb))] = bb->index;
          for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
          for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
            {
            {
              in_bb_p[INSN_UID (x)]
              in_bb_p[INSN_UID (x)]
                = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
                = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
                 ? IN_ONE_BB : IN_MULTIPLE_BB;
                 ? IN_ONE_BB : IN_MULTIPLE_BB;
              if (x == BB_END (bb))
              if (x == BB_END (bb))
                break;
                break;
            }
            }
        }
        }
 
 
      /* Tell print-rtl that we want graph output.  */
      /* Tell print-rtl that we want graph output.  */
      dump_for_graph = 1;
      dump_for_graph = 1;
 
 
      /* Start new function.  */
      /* Start new function.  */
      start_fct (fp);
      start_fct (fp);
 
 
      for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
      for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
           tmp_rtx = NEXT_INSN (tmp_rtx))
           tmp_rtx = NEXT_INSN (tmp_rtx))
        {
        {
          int edge_printed = 0;
          int edge_printed = 0;
          rtx next_insn;
          rtx next_insn;
 
 
          if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
          if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
            {
            {
              if (BARRIER_P (tmp_rtx))
              if (BARRIER_P (tmp_rtx))
                continue;
                continue;
              if (NOTE_P (tmp_rtx)
              if (NOTE_P (tmp_rtx)
                  && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
                  && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
                continue;
                continue;
            }
            }
 
 
          if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
          if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
            {
            {
              /* We start a subgraph for each basic block.  */
              /* We start a subgraph for each basic block.  */
              start_bb (fp, i);
              start_bb (fp, i);
 
 
              if (i == 0)
              if (i == 0)
                draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
                draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
            }
            }
 
 
          /* Print the data for this node.  */
          /* Print the data for this node.  */
          node_data (fp, tmp_rtx);
          node_data (fp, tmp_rtx);
          next_insn = next_nonnote_insn (tmp_rtx);
          next_insn = next_nonnote_insn (tmp_rtx);
 
 
          if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
          if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
            {
            {
              edge e;
              edge e;
              edge_iterator ei;
              edge_iterator ei;
 
 
              bb = BASIC_BLOCK (i);
              bb = BASIC_BLOCK (i);
 
 
              /* End of the basic block.  */
              /* End of the basic block.  */
              end_bb (fp);
              end_bb (fp);
 
 
              /* Now specify the edges to all the successors of this
              /* Now specify the edges to all the successors of this
                 basic block.  */
                 basic block.  */
              FOR_EACH_EDGE (e, ei, bb->succs)
              FOR_EACH_EDGE (e, ei, bb->succs)
                {
                {
                  if (e->dest != EXIT_BLOCK_PTR)
                  if (e->dest != EXIT_BLOCK_PTR)
                    {
                    {
                      rtx block_head = BB_HEAD (e->dest);
                      rtx block_head = BB_HEAD (e->dest);
 
 
                      draw_edge (fp, INSN_UID (tmp_rtx),
                      draw_edge (fp, INSN_UID (tmp_rtx),
                                 INSN_UID (block_head),
                                 INSN_UID (block_head),
                                 next_insn != block_head,
                                 next_insn != block_head,
                                 (e->flags & EDGE_ABNORMAL ? 2 : 0));
                                 (e->flags & EDGE_ABNORMAL ? 2 : 0));
 
 
                      if (block_head == next_insn)
                      if (block_head == next_insn)
                        edge_printed = 1;
                        edge_printed = 1;
                    }
                    }
                  else
                  else
                    {
                    {
                      draw_edge (fp, INSN_UID (tmp_rtx), 999999,
                      draw_edge (fp, INSN_UID (tmp_rtx), 999999,
                                 next_insn != 0,
                                 next_insn != 0,
                                 (e->flags & EDGE_ABNORMAL ? 2 : 0));
                                 (e->flags & EDGE_ABNORMAL ? 2 : 0));
 
 
                      if (next_insn == 0)
                      if (next_insn == 0)
                        edge_printed = 1;
                        edge_printed = 1;
                    }
                    }
                }
                }
            }
            }
 
 
          if (!edge_printed)
          if (!edge_printed)
            {
            {
              /* Don't print edges to barriers.  */
              /* Don't print edges to barriers.  */
              if (next_insn == 0
              if (next_insn == 0
                  || !BARRIER_P (next_insn))
                  || !BARRIER_P (next_insn))
                draw_edge (fp, XINT (tmp_rtx, 0),
                draw_edge (fp, XINT (tmp_rtx, 0),
                           next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
                           next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
              else
              else
                {
                {
                  /* We draw the remaining edges in class 3.  We have
                  /* We draw the remaining edges in class 3.  We have
                     to skip over the barrier since these nodes are
                     to skip over the barrier since these nodes are
                     not printed at all.  */
                     not printed at all.  */
                  do
                  do
                    next_insn = NEXT_INSN (next_insn);
                    next_insn = NEXT_INSN (next_insn);
                  while (next_insn
                  while (next_insn
                         && (NOTE_P (next_insn)
                         && (NOTE_P (next_insn)
                             || BARRIER_P (next_insn)));
                             || BARRIER_P (next_insn)));
 
 
                  draw_edge (fp, XINT (tmp_rtx, 0),
                  draw_edge (fp, XINT (tmp_rtx, 0),
                             next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
                             next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
                }
                }
            }
            }
        }
        }
 
 
      dump_for_graph = 0;
      dump_for_graph = 0;
 
 
      end_fct (fp);
      end_fct (fp);
 
 
      /* Clean up.  */
      /* Clean up.  */
      free (start);
      free (start);
      free (end);
      free (end);
      free (in_bb_p);
      free (in_bb_p);
    }
    }
 
 
  fclose (fp);
  fclose (fp);
}
}
 
 
 
 
/* Similar as clean_dump_file, but this time for graph output files.  */
/* Similar as clean_dump_file, but this time for graph output files.  */
 
 
void
void
clean_graph_dump_file (const char *base)
clean_graph_dump_file (const char *base)
{
{
  size_t namelen = strlen (base);
  size_t namelen = strlen (base);
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
  char *buf = alloca (namelen + extlen);
  char *buf = alloca (namelen + extlen);
  FILE *fp;
  FILE *fp;
 
 
  memcpy (buf, base, namelen);
  memcpy (buf, base, namelen);
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
 
 
  fp = fopen (buf, "w");
  fp = fopen (buf, "w");
 
 
  if (fp == NULL)
  if (fp == NULL)
    fatal_error ("can't open %s: %m", buf);
    fatal_error ("can't open %s: %m", buf);
 
 
  gcc_assert (graph_dump_format == vcg);
  gcc_assert (graph_dump_format == vcg);
  fputs ("graph: {\nport_sharing: no\n", fp);
  fputs ("graph: {\nport_sharing: no\n", fp);
 
 
  fclose (fp);
  fclose (fp);
}
}
 
 
 
 
/* Do final work on the graph output file.  */
/* Do final work on the graph output file.  */
void
void
finish_graph_dump_file (const char *base)
finish_graph_dump_file (const char *base)
{
{
  size_t namelen = strlen (base);
  size_t namelen = strlen (base);
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
  char *buf = alloca (namelen + extlen);
  char *buf = alloca (namelen + extlen);
  FILE *fp;
  FILE *fp;
 
 
  memcpy (buf, base, namelen);
  memcpy (buf, base, namelen);
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
 
 
  fp = fopen (buf, "a");
  fp = fopen (buf, "a");
  if (fp != NULL)
  if (fp != NULL)
    {
    {
      gcc_assert (graph_dump_format == vcg);
      gcc_assert (graph_dump_format == vcg);
      fputs ("}\n", fp);
      fputs ("}\n", fp);
      fclose (fp);
      fclose (fp);
    }
    }
}
}
 
 

powered by: WebSVN 2.1.0

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