
/* $Id: print_vhdl.c,v 1.1.1.1 2003/11/04 23:34:57 mjames Exp $ */
/*
 * $Log: print_vhdl.c,v $
 * Revision 1.1.1.1  2003/11/04 23:34:57  mjames
 * Imported into local repositrory
 *
 * Revision 1.17  2003/01/02 21:37:16  mjames
 * Experiment on creating NOT_ROUTABLE_H and NOT_ROUTABLE_L
 * properties on the nets so that pin jumpers can be made without a problem.
 *
 * Still need to sort out pin assignments made to these not_routable nets
 * which will become legal in some cases so that pullups and pulldown
 * pins can be used on the FPGA.
 *
 * Revision 1.16  2002/09/30 13:23:05  MJAMES
 * Modified partition rules to include 'default assignment on declaration'
 * which maps to inputs being driven with default values on
 * productuion of a partition.
 *
 * signal c : std_logic := '0';
 *
 * becomes
 *
 * signal c: std_logic;
 *
 * begin
 *   c<= '0';
 *
 * Revision 1.15  2002/09/27 22:35:33  MJAMES
 * Added lhs_expr for cases like
 *
 * x(0) <= y
 *
 * where x is std_logic_vector(0 downto 0) and y is std_logic.
 *
 * Also added printing for default values on signals : this to be extended
 *
 * Revision 1.14  2002/09/09 10:12:02  mjames
 * Moved pin remapping function to pin ident editing function from
 * sorting pin name routine.
 *
 * Revision 1.13  2002/08/23 14:19:19  mjames
 * Introduced bundles and external sockets to VHDL from the Verilog printer.
 *
 * Revision 1.12  2001/12/13 22:18:52  mjames
 * Using #ident with header to identify file
 *
 * Corrected an attempt to reference a null net
 *
 * Revision 1.11  2001/11/19 10:41:35  mjames
 * Merged back DTC release
 *
 * Revision 1.10.2.1  2001/11/15 22:25:39  mjames
 * Removed unused variables, added brackets
 *
 * Revision 1.10  2001/11/01 11:04:36  mjames
 * Pin node identifier is printed out in a component declaration rather than
 * node name which is more a property of the attached net.
 *
 * Revision 1.9  2001/10/31 22:20:12  mjames
 * Tidying up problematical comments caused by CVS
 * 'intelligent' comment guessing
 *
 * Revision 1.8  2001/10/10 20:18:22  mjames
 * Added a vert_regcomp function to compile regular expressions
 * with '^' (match start string) and  '$' (match end string) bracketing
 * this => wildcard must match entire string not just a part of it.
 *
 * Revision 1.7  2001/09/21 14:22:27  mjames
 * Added prefix to instance name in order to avoid a Model Technology name
 * space collision  e.g.
 *
 * U1 : U1 port map () ...
 *
 * Now prints
 *
 * I_U1 : U1 port map which is safer.
 *
 * Revision 1.6  2001/06/22 11:06:19  mjames
 * Modified to tag VHDL code generated so that
 * Vertical can recognise it.
 *
 * Revision 1.5  2001/06/20 13:45:40  mjames
 * For all components defined by 'Component' declarations, forced the
 * printout of only one component for several instances sharing the same component declaration.
 *
 * Revision 1.4  2001/06/06 12:10:19  mjames
 * Move from HPUX
 *
 * Revision 1.3  2001/04/27 08:08:44  mjames
 * Extra tidying of the print_vhdl code
 *
 * Revision 1.2  2000/11/29 21:51:18  mjames
 * Fine tuning of software
 *
 * Revision 1.1.1.1  2000/10/19 21:58:39  mjames
 * Mike put it here
 *
 *
 * Revision 1.23  2000/10/12  15:32:32  15:32:32  mjames (Mike James)
 * Removed <cr>
 *
 * Revision 1.22  2000/10/12  14:25:55  14:25:55  mjames (Mike James)
 * changed listing vhdl signals to expand expressions
 * until a constant is located
 *
 * Revision 1.21  2000/10/04  10:37:08  10:37:08  mjames (Mike James)
 * Modified for Vertical2 : support COMPONENTS and SIGNALS
 *
 * Revision 1.21  2000/10/04  10:37:08  10:37:08  mjames (Mike James)
 * Part of Release PSAVAT01
 *
 * Revision 1.20  2000/10/02  11:04:17  11:04:17  mjames (Mike James)
 * new_vhdl
 *
 * Revision 1.18  2000/09/21  10:15:48  10:15:48  mjames (Mike James)
 * Part of Release Sep21Alpha
 *
 * Revision 1.17  2000/08/25  09:57:14  09:57:14  mjames (Mike James)
 * Part of Release Aug25_alpha
 *
 * Revision 1.16  2000/08/25  09:55:33  09:55:33  mjames (Mike James)
 * Corrected for the disappearance of generic information
 *
 * Revision 1.15  2000/08/16  08:57:30  08:57:30  mjames (Mike James)
 * Part of Release CD01_Aug2000
 *
 * Revision 1.14  2000/08/14  14:45:11  14:45:11  mjames (Mike James)
 * Part of Release Aug_14_2000
 *
 * Revision 1.13  2000/08/14  14:43:15  14:43:15  mjames (Mike James)
 * Added power pins
 *
 * Revision 1.12  2000/08/11  08:30:32  08:30:32  mjames (Mike James)
 * Part of Release Aug_11_2000
 *
 * Revision 1.11  2000/08/09  10:31:47  10:31:47  mjames (Mike James)
 * Part of Release Aug__9_2000
 *
 * Revision 1.10  2000/05/31  11:42:56  11:42:56  mjames (Mike James)
 * Part of Release May_31_2000
 *
 * Revision 1.9  2000/05/08  17:01:37  17:01:37  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.8  2000/05/08  16:59:30  16:59:30  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.7  2000/05/08  16:57:07  16:57:07  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.6  2000/03/08  16:19:22  16:19:22  mjames (Mike James)
 * New version including PC
 *
 * Revision 1.3  2000/01/20  15:58:47  15:58:47  mjames (Mike James)
 * Part of Release R22
 *
 * Revision 1.2  99/12/22  11:15:28  11:15:28  mjames (Mike James)
 * Part of Release Dec_22_1999
 *
 * Revision 1.1  99/11/23  13:52:14  13:52:14  mjames (Mike James)
 * Initial revision
 *
 */

#include "print_vhdl.h"

#include "cmdlog.h"
#include "cmdparse.h"
#include "database.h"
#include "expression.h"
#include "generic.h"
#include "print_vlog.h"
#include "printout.h"
#include "sorting.h"
#include "vertcl_main.h"

#include <ctype.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* for streq */
#include "lx_support.h"
/* ********************************************************************** */

/* Decoding pin direction in VHDL */
static char *decode_pin_VHDL[] = {"-NONE-",
                                  "IN",
                                  "OUT",
                                  "BUFFER", /* buffer is a sort of Output pin */
                                  "INOUT",
                                  "CONFIG_PIN",
                                  "POWER_PIN"};
/* ********************************************************************** */
/* VHDL output of the entities                                            */
/* ********************************************************************** */
static char illegal[] = "$:|/.\\ ";
static char replace[] = "Sxxxxx_";

char *make_vhdl_name (char *buffer, char *str)
{
        int i, j, l;
        buffer[0] = 0;
        if (str)
        {
                strcpy (buffer, str); /* should be a call to strncpy !! */
        }
        l = strlen (buffer);
        /* edit out illegal strings from the net name */
        for (i = 0; i < l; i++)
        {
                for (j = 0; j < sizeof (illegal); j++)
                        if (buffer[i] == illegal[j])
                                buffer[i] = replace[j];
        }
        i = l - 1;
        /* convert pin indices back from Altera form if we are looking at FIT files */
        if (l)
        {
                /* name ends in underscore, this forces mapping name_nn_ --> name(nn) */
                if (buffer[i] == '_')
                {
                        buffer[i--] = ')';
                        while (i >= 0 && buffer[i] != '_')
                                i--;
                        if (i >= 0)
                                buffer[i] = '(';
                }
        }
        return buffer;
}

/* ********************************************************************** */
/* decodes the 'vector' part of a bus , if known                           */
void decode_vhdl_bus (FILE *f, vhdl_t *vhdl, generic_print_style recurse_generics)
{
        if (!vhdl)
                vhdl = default_vhdl_datatype;
        if (vhdl->is_vector)
                print_range_expression (f, vhdl->expr, recurse_generics);
}

/* ********************************************************************** */

void decode_vhdl_type (FILE *f, vhdl_t *vhdl, generic_print_style recurse_generics)
{
        /* avoid crashing on a null pointer */
        if (!vhdl)
                vhdl = default_vhdl_datatype;
        fprintf (f, "%s ", vhdl->basetype);
        if (vhdl->is_vector)
                decode_vhdl_bus (f, vhdl, recurse_generics);
}

/* ********************************************************************** */

/* print out a VHDL component declaration */
void print_VHDL_component (FILE *f, socket_t *dev, int All)
{
        node_t *n;
        /* sort the identifiers of the nodes */
        sort_nodes (dev, NO_EXTRACT_XY);

        fprintf (f, "COMPONENT  %s\n", check_null_str (dev->type));
        fprintf (f, "--  DEV_IDENT \"%s\"\n\n", check_null_str (dev->identifier));
        if (dev->is_template)
                fprintf (f, "--  Defined by COMPONENT definition\n");

        if (dev->generics)
                list_VHDL_generic_values (f, &dev->generics);

        fprintf (f, "  PORT ( \n");
        /* sort the identifiers of the nodes */
        sort_nodes (dev, NO_EXTRACT_XY);
        n = dev->nodes;
        while (n)
        {
                vhdl_t *pin_datatype = default_vhdl_datatype;
                expression_t *default_expr = NULL;
                char nam[MAXIDLEN];
                if (n->orig_vhdltype)
                {
                        pin_datatype = n->orig_vhdltype;
                        default_expr = n->orig_vhdltype->default_expr;
                }
                else if (n->vhdltype)
                {
                        pin_datatype = n->vhdltype;
                        default_expr = n->vhdltype->default_expr;
                }
                if ((n->net_assigned && n->in_use) || (All || dev->is_template))
                {
                        fprintf (
                            f,
                            "  %-16s : %6s  ",
                            make_vhdl_name (nam, check_null_str (n->identifier)), /* was
                                                                                     n->name */
                            decode_pin_VHDL[(int) n->pindir]);
                        decode_vhdl_type (f, pin_datatype, NO_RECURSE); /* until a generic
                                                                           found */
                        /* ought to be optional dependent on synthesis style */
                        if (default_expr)
                        {
                                fprintf (f, ":= ");
                                print_expression (f, default_expr, NO_RECURSE);
                        }

                        if (n->sktnext)
                                fprintf (f, ";");
                        fprintf (f, " -- i=%s r=%d --\n", n->identifier, n->refcount);
                }
                n = n->sktnext; /* traverse to next pin on socket */
        };
        fprintf (f, ");\nEND COMPONENT;\n\n");
}

/* ********************************************************************** */
/* Printout an instance of a component */
/* ********************************************************************** */
void print_VHDL_instance (FILE *f, socket_t *dev, int All)
{
        node_t *n;
        int need_term = 0;
        char *prefix;
        /* only prefix devices with similar idents and types */
        if (!ISNULLSTR (dev->identifier) && !ISNULLSTR (dev->type) &&
            streq (dev->identifier, dev->type))
        {
                prefix = "I_";
        }
        else
        {
                prefix = "";
        }

        fprintf (
            f,
            "%s%s : %s \n",
            prefix,
            check_null_str (dev->identifier),
            check_null_str (dev->type));

        if (dev->generics)
                list_VHDL_generic_map_values (f, &dev->generics);

        fprintf (f, "  PORT MAP ( \n");
        /* sort the identifiers of the nodes */
        sort_nodes (dev, NO_EXTRACT_XY);
        n = dev->nodes;
        while (n)
        {
                vhdl_t *pin_datatype = default_vhdl_datatype;
                char nam1[MAXIDLEN], nam2[MAXIDLEN];
                if (n->vhdltype)
                        pin_datatype = n->vhdltype;
                if ((n->net_assigned && n->in_use) || All)
                {
                        char *sig_prefix;
                        if (need_term)
                                fprintf (f, ",\n");
                        else
                                fprintf (f, "\n");
                        need_term = 1;
                        /* is there a slice in the output */
                        if (n->net && n->net->needs_buff_sig)
                                sig_prefix = BUFPREFIX;
                        else
                                sig_prefix = "";

                        if (n->net)
                        {
                                fprintf (
                                    f,
                                    "  %s",
                                    make_vhdl_name (
                                        nam1, check_null_str (n->identifier))); /* was n->name
                                                                                 */
                                if (n->lhs_expr)
                                {
                                        print_range_expression (f, n->lhs_expr, RECURSE_CONST);
                                }
                                fprintf (
                                    f,
                                    "=> %s%s ",
                                    sig_prefix,
                                    make_vhdl_name (nam2, check_null_str (n->net->name)));
                        }
                        else
                        {
                                fprintf (
                                    f,
                                    "  %-20s => OPEN ",
                                    make_vhdl_name (
                                        nam1, check_null_str (n->identifier))); /* was n->name
                                                                                 */
                        }
                        /* do bus slicing only if the connected net is a bus */
                        if (n->net && n->net->vhdltype)
                        {
                                decode_vhdl_bus (f, n->net->vhdltype, RECURSE_CONST);
                        }
                        else
                        {
                                /*  fprintf(f,"\n"); */
                        }
                }
                n = n->sktnext; /* traverse to next pin on socket */
        };
        fprintf (f, "\n   );\n\n");
}

/* ********************************************************************** */

void print_VHDL_sigs (FILE *f)
{
        net_t *net = named_list;
        char nam[MAXIDLEN], *sig_prefix;
        while (net)
        {
                if (net->needs_buff_sig)
                        sig_prefix = BUFPREFIX;
                else
                        sig_prefix = "";
                /* May 21 2001 only print nets that connect to 'external' tagged modules */
                if ((IS_ROUTABLE (net->how_routed)) &&
                    ((net->bundle_member) || ((net->inside_partition) && net->has_external)))
                {
                        fprintf (f, "    ");
                }
                else
                {
                        fprintf (f, "  --");
                }

                fprintf (f, " signal %s%s : ", sig_prefix, make_vhdl_name (nam, net->name));
                decode_vhdl_type (f, net->vhdltype, RECURSE_CONST);
                if (net->vhdltype)
                {
                        if (net->vhdltype->decl_expr)
                        {
                                print_expression (f, net->vhdltype->decl_expr, NO_RECURSE);
                        }
                        if (net->vhdltype->default_expr)
                        {
                                fprintf (f, ":= ");
                                print_expression (f, net->vhdltype->default_expr, NO_RECURSE);
                        }
                }
                fprintf (
                    f,
                    "; -- partition : %s %s %s %s %s\n",
                    net->inside_partition ? "used in," : "unused in,",
                    net->leaves_partition ? "leaves," : "buried,",
                    net->needs_buff_sig ? ", buffered," : "",
                    net->has_external ? "external skt" : "internal skt",
                    net->bundle_member ? "bundle member" : " not bundled");
                net = net->next;
        }
}
/* ********************************************************************** */

void print_VHDL_assignments (FILE *f)
{
        net_t *net = named_list;
        socket_t *socket = socket_head;

        /* code borrowed from Verilog */
        fprintf (f, "-- Bundled signals\n\n");

        while (socket)
        {
                node_t *nodes = socket->nodes;
                if (socket->highest_bundle &&
                    (socket->bundle_width > MINBUNDLE)) /* will not do assigns on small bundles
                                                         */
                        while (nodes)
                        {
                                if (nodes->bundle_index >= 0)
                                {
                                        char nam[MAXIDLEN];
                                        net_t *net = nodes->net;
                                        make_vhdl_name (nam, net->name);
                                        fprintf (
                                            f,
                                            " %s <= %s(%d);\n",
                                            nam,
                                            socket->identifier,
                                            nodes->bundle_index);
                                }
                                nodes = nodes->sktnext;
                        }
                /*    else
                      fprintf(f,"-- %s;\n",
                               net->name);
                */

                socket = socket->next;
        }

        fprintf (f, "-- Buffered signals\n\n");
        while (net)
        {
                if (net->inside_partition && net->needs_buff_sig)
                {
                        char nam[MAXIDLEN];
                        make_vhdl_name (nam, net->name),

                            fprintf (f, " %-20s <= " BUFPREFIX "%s; -- buffer\n", nam, nam);
                }
                if (net->vhdl_connect_net && net->subnets)
                {
                        char nam[MAXIDLEN], nam1[MAXIDLEN];
                        make_vhdl_name (nam, net->identifier);
                        make_vhdl_name (nam1, net->subnets->identifier);
                        fprintf (f, " %-20s <= %s; -- connector\n", nam, nam1);
                }
                else if (net->inside_partition && net->vhdltype && net->vhdltype->default_expr)
                {
                        char nam[MAXIDLEN];
                        make_vhdl_name (nam, net->identifier);
                        fprintf (f, " %-20s <= ", nam);
                        print_range_expression (f, net->vhdltype->default_expr, NO_RECURSE);
                        fprintf (f, "; -- Defined default drive value\n");
                }

                net = net->next;
        }
        fprintf (f, "-- \n\n");
}

/* ********************************************************************** */
/* code lists bundles although they are probably broken */
void print_VHDL_entity (FILE *f, char *entityname)
{
        net_t *net;
        int need_term = 0;
        socket_t *skt;
        char nam[MAXIDLEN];

        fprintf (f, "ENTITY %s IS\n", entityname);
        /* print out global generic settings */
        /*
          list_VHDL_generic_values (f,&partition_generics);
        */
        fprintf (f, "  PORT (\n");

        skt = socket_head;
        /* bundles of pins are replaced by signals named the same as a socket which
           they are bundled through , unless the bundles are too small in which case they
           are replaced by separate wires */
        while (skt)
        {
                if (skt->highest_bundle)
                {
                        if (skt->bundle_width > MINBUNDLE)
                        {
                                if (need_term)
                                {
                                        fprintf (f, ";\n");
                                        need_term = 0;
                                }
                                else
                                {
                                        fprintf (f, "\n");
                                }
                                fprintf (
                                    f,
                                    "  %-15s : %6s %s (%d downto 0) ",
                                    make_vhdl_name (nam, skt->identifier),
                                    decode_pin_VHDL[BIDIR],
                                    default_vhdl_bustype->basetype,
                                    skt->bundle_width - 1);

                                need_term = 1;
                        }
                        else
                        /* if the 'bundle' has less than MINBUNDLE pins, */
                        /* list out all of the nets in turn as pins      */
                        {
                                node_t *node;
                                node = skt->nodes;
                                while (node)
                                {
                                        net = node->net;
                                        /*
                                            printf("node %s\n",node->identifier);
                                        */
                                        if (net && IS_ROUTABLE (net->how_routed) &&
                                            net->bundle_member)
                                        {
                                                if (need_term)
                                                {
                                                        fprintf (f, ";\n");
                                                        need_term = 0;
                                                }
                                                else
                                                {
                                                        fprintf (f, "\n");
                                                }
                                                fprintf (
                                                    f,
                                                    "  %-15s : %6s ",
                                                    make_vhdl_name (nam, net->name),
                                                    decode_pin_VHDL[net->ext_dir]);
                                                decode_vhdl_type (
                                                    f, net->vhdltype, RECURSE_NUMBER);
                                                need_term = 1;
                                        }
                                        node = node->sktnext;
                                }
                        }
                }

                skt = skt->next;
        }

        /* go back and list all of the non-bundle pins */

        net = named_list;

        while (net)
        {
                /* print out only unbundled nets as ports of the pcb */
                if (net->leaves_partition && !net->bundle_member)
                {
                        if (need_term)
                        {
                                fprintf (f, ";\n");
                        }
                        else
                        {
                                fprintf (f, "\n");
                        }
                        fprintf (
                            f,
                            "  %-15s : %6s ",
                            make_vhdl_name (nam, net->name),
                            decode_pin_VHDL[net->ext_dir]);
                        decode_vhdl_type (f, net->vhdltype, RECURSE_NUMBER);

                        need_term = 1;
                }
                net = net->next;
        }
        fprintf (f, "\n     );\n");
        fprintf (f, "END %s;\n\n", entityname);
}

/* ********************************************************************** */
/* generate default VHDL Libraries */
/* ********************************************************************** */
void print_VHDL_libs (FILE *f)
{
        fprintf (f, "LIBRARY IEEE,WORK;\nUSE IEEE.std_logic_1164.ALL;\n\n");
}

/* ********************************************************************** */
/* generate a VHDL architecture forselected sockets */
/* ********************************************************************** */
void print_VHDL_architecture (FILE *f, char *entityname)
{
        socket_t *skt;
        char *arch_name;
        generic_info_t gen[1];
        /* if we are using VHDL then look at the VHDL architecture name if  defined*/

        arch_name =
            (get_generic_value (&global_generics, "vhdl_arch_name", gen) == IS_ENV_VAL &&
             gen->expr)
                ? gen->expr->left.s
                : "top_arch";
        fprintf (f, "\n\nARCHITECTURE %s OF  %s IS\n\n", arch_name, entityname);
        /* not allowed to have generics at the top level so put them here */
        list_VHDL_constants (f, &partition_generics);

        list_VHDL_constants (f, &global_generics);
        /* clear type seen flags on all socket templates = components */
        clr_type_seen ();

        skt = socket_head;
        /* list out templates for those sockets selected */
        while (skt)
        {
                if (skt->is_external && skt->highest_bundle == 0)
                {
                        /* suppress printout of duplicate components .... */
                        if (skt->template_socket)
                        {
                                if (skt->template_socket->socket_type_seen == 0)
                                {
                                        print_VHDL_component (f, skt->template_socket, 0);
                                        skt->template_socket->socket_type_seen = 1;
                                }
                        }
                        else
                                /* no components, use socket/entity as its own component */
                                print_VHDL_component (f, skt, 0);
                }
                skt = skt->next;
        }

        print_VHDL_sigs (f);
        fprintf (f, "\n\nBEGIN\n\n");
        skt = socket_head;
        while (skt)
        {
                if (skt->is_external && skt->highest_bundle == 0)
                        print_VHDL_instance (f, skt, 0);
                skt = skt->next;
        }
        print_VHDL_assignments (f);
        fprintf (f, "END %s;\n\n", arch_name);
}

/* ********************************************************************** */
/* generate a VHDL file */
/* ********************************************************************** */

void produce_VHDL (FILE *f, char *entityname, char *template)
{
        char linebuff[256];
        int done_entity = 0, done_architecture = 0;
        if (!template || !template[0])
        { /* check null pointer or empty string */
                fprintf (f, "-- vertical vhdl\n");
                print_header (f, "WRITE VHDL");
                print_VHDL_libs (f);
                fprintf (f, "\n-- vertical read_off\n");
                print_VHDL_entity (f, entityname);
                fprintf (f, "\n-- vertical read_on\n");
                print_VHDL_libs (f);
                print_VHDL_architecture (f, entityname);
                fprintf (f, "\n-- vertical end;\n");
        }
        else
        { /* there is a template file */
                FILE *tp;
                tp = fopen (template, "r");
                if (tp)
                {
                        fprintf (f, "-- vertical vhdl\n");
                        print_header (f, "WRITE VHDL");
                        fprintf (f, "-- Using template '%s'\n", template);
                        while (!feof (tp))
                        {
                                if (fgets (linebuff, 256, tp))
                                {
                                        if (strstr (linebuff, "$ENT"))
                                        {
                                                fprintf (f, "\n-- vertical read_off\n");
                                                print_VHDL_entity (f, entityname);
                                                fprintf (f, "\n-- vertical read_on\n");
                                                done_entity++;
                                        }
                                        else if (strstr (linebuff, "$ARCH"))
                                        {
                                                print_VHDL_architecture (f, entityname);
                                                done_architecture++;
                                        }
                                        else
                                                fprintf (f, "%s", linebuff); /* it already has
                                                                                a '\n' on the
                                                                                end */
                                }
                        }
                        fprintf (f, "\n-- vertical end;\n");
                        fclose (tp);
                        if (done_entity != 1)
                                Log (
                                    LOG_ERROR,
                                    "-- Error: %d  $ENT$ tags counted in template '%s'\n",
                                    template);
                        if (done_architecture != 1)
                                Log (
                                    LOG_ERROR,
                                    "-- Error: %d  $ARCH$ tags counted in template '%s'\n",
                                    template);
                }
                else
                        Log (
                            LOG_ERROR,
                            "-- Error: Cannot open VHDL  template '%s'\n",
                            template);
        }
}