
/*
 * $Id: diagnostics.c,v 1.1.1.1 2003/11/04 23:34:56 mjames Exp $
 *
 * $Log: diagnostics.c,v $
 * Revision 1.1.1.1  2003/11/04 23:34:56  mjames
 * Imported into local repositrory
 *
 * Revision 1.4  2002/09/09 10:26:56  mjames
 * Removed set generic range and replaced it with a set generic value command
 * that takes both integers and ranges.
 *
 * Revision 1.3  2001/10/31 22:20:02  mjames
 * Tidying up problematical comments caused by CVS
 * 'intelligent' comment guessing
 *
 * Revision 1.2  2001/06/06 12:10:23  mjames
 * Move from HPUX
 *
 * Revision 1.1.1.1  2000/10/19 21:58:36  mjames
 * Mike put it here
 *
 *
 * Revision 1.20  2000/10/04  10:37:03  10:37:03  mjames (Mike James)
 * Modified for Vertical2 : support COMPONENTS and SIGNALS
 *
 * Revision 1.20  2000/10/04  10:37:03  10:37:03  mjames (Mike James)
 * Part of Release PSAVAT01
 *
 * Revision 1.19  2000/10/02  11:04:11  11:04:11  mjames (Mike James)
 * new_vhdl
 *

 * Revision 1.18  2000/09/27  14:42:11  14:42:11  mjames (Mike James)

 * Part of Release Sep_27_ST_2000

 *

 * Revision 1.17  2000/09/21  10:15:41  10:15:41  mjames (Mike James)

 * Part of Release Sep21Alpha

 *

 * Revision 1.16  2000/08/25  09:57:10  09:57:10  mjames (Mike James)

 * Part of Release Aug25_alpha

 *

 * Revision 1.15  2000/08/16  08:57:26  08:57:26  mjames (Mike James)

 * Part of Release CD01_Aug2000

 *

 * Revision 1.14  2000/08/14  14:45:08  14:45:08  mjames (Mike James)

 * Part of Release Aug_14_2000

 *

 * Revision 1.13  2000/08/11  08:30:28  08:30:28  mjames (Mike James)

 * Part of Release Aug_11_2000

 *

 * Revision 1.12  2000/08/09  10:31:42  10:31:42  mjames (Mike James)

 * Part of Release Aug__9_2000

 *

 * Revision 1.11  2000/05/31  11:42:50  11:42:50  mjames (Mike James)

 * Part of Release May_31_2000

 *

 * Revision 1.10  2000/05/08  17:01:33  17:01:33  mjames (Mike James)

 * Part of Release May__8_2000

 *

 * Revision 1.9  2000/05/08  16:59:26  16:59:26  mjames (Mike James)

 * Part of Release May__8_2000

 *

 * Revision 1.8  2000/05/08  16:57:03  16:57:03  mjames (Mike James)

 * Part of Release May__8_2000

 *

 * Revision 1.7  2000/03/08  16:18:54  16:18:54  mjames (Mike James)

 * New version including PC

 *

 * Revision 1.4  2000/01/20  15:58:42  15:58:42  mjames (Mike James)

 * Part of Release R22

 *

 * Revision 1.3  99/12/22  11:15:22  11:15:22  mjames (Mike James)

 * Part of Release Dec_22_1999

 *

 * Revision 1.2  99/06/25  14:34:43  14:34:43  mjames (Mike James)

 * Added in reference to expression.h, but no changes made

 * to the function of acfread yet.

 *

 * Revision 1.1  99/05/04  09:50:53  09:50:53  mjames (Mike James)

 * Initial revision

 *

 *

*/

#include "cmdlog.h"
#include "cmdparse.h"
#include "database.h"
#include "generic.h"
#include "printout.h"
#include "sorting.h"

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static char IDstr[] = "@(#)$Header: c:\\cygwin\\cvsroot/Vert03/spares/diagnostics.c,v 1.1.1.1 "
                      "2003/11/04 23:34:56 mjames Exp $";

/* decoding pin direction in ACF form */

/* see pindir_t in database.h */

static char *decode_pin[] =

    {

        "NONE",

        "INPUT_PIN",

        "OUTPUT_PIN",

        "output_pin", /* buffer is a sort of Output pin (lower case is for info only )*/

        "BIDIR_PIN ",

        "CONFIG_PIN"};

/* Decoding pin direction in VHDL */

static char *decode_pin_VHDL[] =

    {

        "-NONE-",

        "IN",

        "OUT",

        "BUFFER", /* buffer is a sort of Output pin */

        "INOUT",

        "CONFIG_PIN"};

/* ********************************************************************** */

/* this prints out the contents of the working database */

/* prints a single net as a connection */

/* subnets are printed as having the how_routed field of their

   parent, because this is the how_routed value that is indicated

   by the routing */

void list_net_nodes (FILE *f, net_t *cnet, net_t *root_net)

{
        noderef_t *bnode;

        node_t *cnode;

        int wrapc;

        if (!cnet)

                return;

        fprintf (
            f,
            " CONNECTION \"%s\" \"%s\" %s; -- %d nodes\n ",

            cnet->identifier,

            check_null_str (root_net->name),

            decode_how_routed[root_net->how_routed],

            cnet->nodecount);

        fprintf (
            f,
            "-- partition port=%d in=%d need_buff=%d\n",

            cnet->leaves_partition,

            cnet->inside_partition,

            cnet->needs_buff_sig);

        bnode = cnet->nodes;

        wrapc = 0;

        while (bnode)
        {
                cnode = bnode->node;

                fprintf (f, " %s(%s)", cnode->socket->identifier, cnode->identifier);

                /* printout if any lines have fix_location flags set */

                if (cnode->fix_location)
                {
                        wrapc += 2; /* cant get as much on this line */

                        fprintf (f, " FIX_LOCATION");
                }

                if (cnode->fixed_pin)
                {
                        wrapc += 2; /* cant get as much on this line */

                        fprintf (f, " %s", decode_pin[cnode->pindir]);
                }

                if (cnode->pin_group)
                {
                        wrapc += 2; /* cant get as much on this line */

                        fprintf (f, " (%d)", cnode->pin_group);
                }

                fprintf (f, ";");

                wrapc++;

                if (wrapc >= 8)

                {
                        wrapc = 0;

                        fprintf (f, "\n ");
                }

                bnode = bnode->next;
        };

        if (wrapc)

                fprintf (f, "\n ");

        fprintf (f, "END_CONN;\n");
}

/* ********************************************************************** */

void list_net_structure (FILE *f, net_t *cnet, net_t *root_net, int alias_depth)

{
        net_t *subnet;

        subnet = cnet->subnets;

        if (cnet == root_net)

                fprintf (f, "--Top Level\n");

        if (cnet->how_joined == Jumpered && subnet)
        {
                fprintf (
                    f,
                    "-- Jumpered Connections to '%s' name '%s' found here --\n",

                    cnet->identifier,
                    cnet->name);

                while (subnet)
                {
                        list_net_structure (f, subnet, root_net, 0); /* depth = 0, not aliased
                                                                      */

                        subnet = subnet->joined_nets;
                }

                fprintf (f, "--\n");
        }

        else if (cnet->how_joined == Aliased && subnet)
        {
                list_net_nodes (f, subnet, root_net);

                fprintf (
                    f,
                    "-- %*s '%s' (name %s) created by Alias of  --\n",

                    alias_depth,
                    "",
                    cnet->identifier,
                    cnet->name);

                while (subnet)
                {
                        fprintf (f, "-- %*s  '%s' -- \n", alias_depth, "", subnet->identifier);

                        list_net_structure (f, subnet, root_net, 0 /*alias_depth+1*/);

                        subnet = subnet->joined_nets;
                }

                fprintf (f, "--\n");
        }

        else if (!subnet)

                list_net_nodes (f, cnet, root_net);

        else

                fprintf (f, "-- Id %s skip\n", cnet->identifier);
}

/* ********************************************************************** */

/* lists all the connections on the board */

void list_nets (FILE *f, net_t *cnet)

{
        while (cnet)
        {
                list_net_structure (f, cnet, cnet, 0);

                cnet = cnet->next;
        }
}

/* ********************************************************************** */

static void list_join (FILE *f, char *typ, net_t *cnet)

{
        int wrapc = 1;

        /*  printf("List join %s , cnet = %p, join_parent = %p , join_parent->id =%p\n",

                  typ,cnet,cnet->join_parent,cnet->join_parent->identifier); */

        fprintf (f, " %s %s = (", typ, cnet->join_parent->identifier);

        while (cnet)
        {
                if (cnet->external_node)

                        fprintf (
                            f,
                            "%s(%s); ",

                            cnet->external_node->socket->identifier,

                            cnet->external_node->identifier);

                else

                        fprintf (f, "%s; ", cnet->identifier);

                wrapc++;

                if (wrapc == 8)
                {
                        wrapc = 0;

                        fprintf (f, "\n  ");
                }

                cnet = cnet->joined_nets;
        }

        fprintf (f, ");\n");
}

/* ********************************************************************** */

/* we are now one level down so it must be a join of some sort

   therefore join_parent is now valid */

static void list_subnets (FILE *f, net_t *cnet, JoinMode_t join)

{
        net_t *tnet = cnet;

        char *nettype;

        net_t *topname;

        while (tnet)
        {
                if (tnet->subnets)

                        list_subnets (f, tnet->subnets, join);

                tnet = tnet->joined_nets;
        }

        /* if we are interested in aliases, print these */

        /* Or if we are interested in joins print these */

        /*  printf("id %s join_parent %p howjoin %d\n",

              cnet->identifier,cnet->join_parent,cnet->how_joined); */

        if (cnet->join_parent->how_joined == join)
        {
                nettype = join == Aliased ? "ALIAS" : "JUMPER";

                list_join (f, nettype, cnet);

                topname = cnet;

                /* ascend jumper hierarchy to get the real name */

                while (topname->join_parent && ISNULLSTR (topname->name))

                        topname = topname->join_parent;

                if (join != Aliased && !ISNULLSTR (topname->name))

                        fprintf (f, " -- signal '%s' \n", topname->name);

                else

                        fprintf (f, "\n");
        };
}

/* ********************************************************************** */

/* this lists all joined nets. it is recursive. Any subnets will be explored

  before printing out the joins for this net if any are presaent */

static void list_joined_nets (FILE *f, net_t *cnet)

{
        if (!cnet)

                return;

        while (cnet)
        {
                /* if there are any subnets here, do the recursion on them */

                /*    printf("cnet = %p, subnets= %p \n",cnet,cnet->subnets); */

                if (cnet->subnets)

                        list_subnets (f, cnet->subnets, Jumpered);

                cnet = cnet->next;
        }
}

/************************************************************************/

static void list_routed_aliased_nets (FILE *f, net_t *cnet)

{
        if (!cnet)

                return;

        while (cnet)
        {
                net_t *unrouted = cnet->unrouted_reference;

                /* if there are any subnets here, do the recursion on them */

                /* this will find out aliases if they exist */

                if (unrouted && unrouted->subnets)

                        list_subnets (f, unrouted->subnets, Aliased);

                cnet = cnet->next;
        }
}

/************************************************************************/

static void list_aliased_nets (FILE *f, net_t *cnet)

{
        if (!cnet)

                return;

        while (cnet)
        {
                /* if there are any subnets here, do the recursion on them */

                /*    printf("cnet = %p, subnets= %p \n",cnet,cnet->subnets); */

                if (cnet->subnets)

                        list_subnets (f, cnet->subnets, Aliased);

                cnet = cnet->next;
        }
}

/************************************************************************/

void list_components (FILE *f)

{
        socket_t *cskt = sort_sockets (&socket_head);

        fprintf (f, "COMPONENTS\nBEGIN\n");

        while (cskt)
        {
                if (cskt->is_template)

                        fprintf (
                            f,
                            "-- %s : Socket Template\n",

                            cskt->type);

                else

                        fprintf (
                            f,
                            "  %s : \"%s\" \"%s\" \"%s\"; -- %s\n",

                            cskt->identifier,

                            check_null_str (cskt->name),

                            check_null_str (cskt->type),

                            check_null_str (cskt->value),

                            cskt->is_external ? "External" : "Internal");

                cskt = cskt->next;
        };

        fprintf (f, "END;\n\n");
}

/************************************************************************/

void list_database (FILE *f)

{
        list_components (f);

        fprintf (f, "WIRED_NETS\nBEGIN\n");

        fprintf (f, "-- Routed & Named nets follow   --\n");

        list_nets (f, named_list);

        fprintf (f, "-- Routed & unused nets follow   --\n");

        list_nets (f, routed_list);

        fprintf (f, "-- Unrouted nets follow --\n");

        list_nets (f, unrouted_list);

        fprintf (f, "END;\n\n");
}

/************************************************************************/

void list_jumper (FILE *f)

{
        fprintf (f, "-- Jumper list here --\n");

        fprintf (f, "JOINED_NETS\nBEGIN\n");

        list_joined_nets (f, named_list);

        list_joined_nets (f, routed_list);

        fprintf (f, "END;\n\n");
}

/************************************************************************/

void list_alias (FILE *f)

{
        fprintf (f, "-- Alias list here --\n");

        fprintf (f, "JOINED_NETS\nBEGIN\n");

        list_routed_aliased_nets (f, named_list);

        list_routed_aliased_nets (f, routed_list);

        list_aliased_nets (f, unrouted_list);

        fprintf (f, "END;\n\n");
}

/************************************************************************/

void list_joined (FILE *f)

{
        /* and now the joined nets */

        fprintf (f, "JOINED_NETS\nBEGIN\n");

        fprintf (f, "-- Jumper list here --\n");

        list_joined_nets (f, named_list);

        list_joined_nets (f, routed_list);

        fprintf (f, "-- Alias list here --\n");

        list_routed_aliased_nets (f, named_list);

        list_routed_aliased_nets (f, routed_list);

        list_aliased_nets (f, unrouted_list);

        fprintf (f, "END;\n\n");
}

/* ********************************************************************** */

/* if options & PRINT_ALL then print all known pins on the device */

/* if options & PRINT_TYPE then print the VHDL data type of this pin */

/* if options & PRINT_GENERIC then print out the device's generic map here also */

/* if options & PRINT_EXPAND_BUS then expand out the VHDL bus to individual wires */

/* if options & PRINT_GROUP      then print out the pin groups */

/* if options & PRINT_ROUTE_FLAGS then print out the routing flags  */

/* if options & PRINT_AS_UNROUTED then printout "UNROUTED" instead of any pindir info */

void print_device (FILE *f, socket_t *dev, int options)

{
        node_t *n;

        char *vhdl_bus_format = "_%d_";

        generic_info_t gen[1];

        /* sort all the nodes into alphabetical order */

        sort_nodes (dev);

        /* if we are using VHDL then look at the VHDL bus formatting tail*/

        if ((options & PRINT_EXPAND_BUS) &&

            get_generic_value (&global_generics, "vhdl_bus_format", gen) == IS_STRING)

                vhdl_bus_format = gen->valuename;

        /* if it hasnt got a name, use its identifier */

        if (!dev->is_template)
        {
                if (dev->name != NULL && dev->name[0])

                        fprintf (f, "CHIP %s\n", check_null_str (dev->name));

                else

                        fprintf (f, "CHIP %s\n", dev->identifier);

                fprintf (f, "BEGIN\n    DEVICE = \"%s\";\n", check_null_str (dev->type));

                fprintf (f, "--  DEV_IDENT \"%s\"\n", dev->identifier);

                if (options & PRINT_ROUTE_FLAGS && dev->route_flags)

                        fprintf (f, "    ROUTE_FLAGS = %d;\n", dev->route_flags);

                if (dev->is_external)

                        fprintf (f, "--  External Connection\n\n");

                else

                        fprintf (f, "--  Internal Socket\n\n");

                if (options & PRINT_GENERIC && dev->generics)

                        list_generic_values (f, &dev->generics, 2);
        }

        else
        {
                fprintf (f, "TEMPLATE \"%s\"\n", check_null_str (dev->name));

                fprintf (f, "BEGIN\n");
        };

        if (dev->is_template && dev->parent_template_ref)
        {
                fprintf (f, "  ALIAS \"%s\"\n", check_null_str (dev->name));

                n = NULL; /* alias templates have no nodes of their own */
        }

        else

                n = dev->nodes;

        while (n)
        {
                char tmp_name[MAXIDLEN], typ[MAXIDLEN], vhdltail[MAXIDLEN],
                    group_tail[MAXIDLEN];

                int iter, iter_hi, iter_low;

                vhdl_t *vhdl;

                if (n->net_assigned || (options & PRINT_ALL))
                {
                        /* there is a possibility here of printing

                           out a bus as separate signals */

                        if (n->orig_vhdltype) /* if a pin rename has taken place, use the
                                                 original name !! */

                                vhdl = n->orig_vhdltype;

                        else

                                vhdl = n->vhdltype;

                        if ((options & PRINT_EXPAND_BUS) && vhdl && vhdl->is_vector)
                        {
                                fprintf (
                                    f,
                                    "-- Bus expansion follows '%s'\n",

                                    decode_vhdl_bus (vhdltail, vhdl));

                                iter_hi = vhdl->high;

                                iter_low = vhdl->low;

                                if (iter_hi < iter_low)
                                {
                                        fprintf (f, "-- VHDL Range is backwards !! \n");

                                        iter_hi = vhdl->low;

                                        iter_low = vhdl->high;
                                };
                        }

                        else
                        {
                                iter_hi = 0;

                                iter_low = 0;
                        }

                        for (iter = iter_low; iter <= iter_hi; iter++)
                        {
                                /* create a tail on the signal name */

                                vhdltail[0] = '\0';

                                if (vhdl && vhdl->is_vector)

                                        sprintf (
                                            vhdltail,
                                            vhdl_bus_format,
                                            iter); /* this should be a template : setup in
                                                      symbol table */

                                if (options & PRINT_USABLE)
                                {
                                        if (n->routed_net)

                                                sprintf (
                                                    tmp_name,
                                                    "\"%s%s\"",
                                                    check_null_str (n->net->identifier),
                                                    vhdltail);

                                        else

                                                sprintf (tmp_name, "\"unknown_net\"");
                                }

                                else

                                        sprintf (
                                            tmp_name,
                                            "\"%s%s\"",
                                            check_null_str (n->name),
                                            vhdltail);

                                group_tail[0] = '\0';

                                if ((options & PRINT_GROUP) && n->pin_group)

                                        sprintf (group_tail, "(%d)", n->pin_group);

                                fprintf (
                                    f,
                                    "    %-32s : ",

                                    tmp_name);

                                if (options & PRINT_AS_UNROUTED)

                                        fprintf (f, "UNROUTED ");

                                else

                                        fprintf (
                                            f,
                                            "%s%s = %4s%s ",

                                            decode_pin[(int) n->pindir],

                                            group_tail,

                                            n->identifier,

                                            vhdltail);

                                if (options & PRINT_TYPE)
                                {
                                        if (!vhdl) /* VHDL base types only are printed here as

                                                             vectors are expanded */

                                                fprintf (
                                                    f,
                                                    " : %s",
                                                    default_vhdl_datatype->basetype);

                                        else

                                                fprintf (f, " : %s", vhdl->basetype);
                                }

                                fprintf (
                                    f,
                                    "; -- refs=%d %s %s %n\n",

                                    n->refcount,

                                    n->fixed_pin ? "fixed" : "",

                                    n->in_use ? "in use" : "unused",

                                    n->net_assigned ? "net assigned" : "");
                        };
                }

                n = n->sktnext; /* traverse to next pin on socket */
        };

        fprintf (f, "END;\n\n");
}

/************************************************************************/

/* this function prints the 'entity' of a top level of a partition as an

   ACFP file */

void print_ACF_entity (FILE *f, char *entityname)

{
        net_t *net = named_list;

        int pin_num = 1;

        fprintf (f, "CHIP %s\n", entityname);

        fprintf (f, "BEGIN\n    DEVICE = \"VHDL-TOP\";\n");

        while (net)
        {
                if (net->leaves_partition)
                {
                        char nam[MAXIDLEN], typ[MAXIDLEN];

                        sprintf (nam, "\"%s\"", check_null_str (net->name));

                        fprintf (
                            f,
                            "    %-32s : %5s = \"%d\" ",

                            nam,

                            decode_pin[(int) net->ext_dir],

                            pin_num++);

                        fprintf (
                            f,
                            " : \"%s\";\n",

                            decode_vhdl_type (typ, net->vhdltype));
                }

                net = net->next;
        }

        fprintf (f, "END; -- %s\n\n", entityname);
}

/************************************************************************/

/* devices are always listed in acfp files with VHDL data types */

void list_devices (FILE *f)

{
        socket_t *dev;

        dev = socket_head;

        while (dev)

        {
                /* only print named devices !!! */

                if (dev->name[0] != 0 && dev->name != nullstr)

                        print_device (
                            f,
                            dev,

                            PRINT_TYPE | PRINT_EXPAND_BUS |

                                PRINT_GENERIC | PRINT_GROUP |

                                PRINT_ROUTE_FLAGS);

                dev = dev->next;
        };
}

/************************************************************************/

/* devices are always listed in acfp files with VHDL data types */

/* only those with their is_external flags set */

void list_extern_devices (FILE *f)

{
        socket_t *dev;

        dev = socket_head;

        while (dev)

        {
                /* only print external devices !!! */

                if (dev->is_external)

                        print_device (f, dev, PRINT_TYPE);

                dev = dev->next;
        };
}

/************************************************************************/

static int list_pin_renames (net_t *list, FILE *f, int any_renames_seen)
{
        noderef_t *nodes, *ref;

        int ref_renames_seen;

        char vhdltext[MAXIDLEN];

        if (!list)
                return any_renames_seen;

        while (list)
        {
                nodes = list->nodes;

                while (nodes)
                {
                        ref = nodes->base_noderef;

                        if (ref->orig_name)
                        {
                                if (!any_renames_seen)
                                { /* overall, start the list if there is a rename */

                                        fprintf (f, "RENAME_PINS\n BEGIN\n");

                                        any_renames_seen = 1;
                                }

                                if (ref->orig_vhdltype)

                                        fprintf (
                                            f,
                                            "  %s%s = ( ",
                                            list->identifier,
                                            decode_vhdl_bus (vhdltext, ref->vhdltype));

                                else

                                        fprintf (f, "  %s = ( ", list->identifier);

                                fprintf (
                                    f, "%s.%s;);\n", ref->node->socket->name, ref->orig_name);
                        }

                        nodes = nodes->next;
                }

                list = list->next;
        }

        return (any_renames_seen);
}

/************************************************************************/

void print_pin_renames (FILE *f)
{
        int any_renames_seen = 0;

        fprintf (f, "-- pin renames on unrouted list follow --\n");

        list_pin_renames (unrouted_list, f, any_renames_seen);

        fprintf (f, "-- pin renames on routed list follow   --\n");

        any_renames_seen = list_pin_renames (routed_list, f, any_renames_seen);

        fprintf (f, "-- pin renames on named list follow    --\n");

        any_renames_seen = list_pin_renames (named_list, f, any_renames_seen);

        if (any_renames_seen)

                fprintf (f, "END;\n");
}

/************************************************************************/

/************************************************************************/

/* and now for the FRB formatted stuff                                  */

/* prints a frb formatted net   */

void frb_list_net (FILE *f, net_t *cnet)

{
        noderef_t *bnode;

        node_t *cnode;

        bnode = cnet->nodes;

        if (bnode)
        { /* only print out a net that has at leat one node on it */

                cnode = bnode->node;

                fprintf (
                    f,
                    ".ADD_TER %s %s %s\n",

                    cnode->socket->identifier,

                    cnode->identifier,

                    cnet->identifier);

                bnode = bnode->next;

                if (bnode)

                        fprintf (f, ".TER\n");

                while (bnode)
                {
                        cnode = bnode->node;

                        fprintf (f, "%s %s\n", cnode->socket->identifier, cnode->identifier);

                        bnode = bnode->next;
                };

                fprintf (f, "\n");
        };
}

/* ********************************************************************** */

/* only jumpered nets are permitted to be listed as separate physical nets*/

/* aliased nets cannot, as they are asingle physical net */

void frb_list_net_connections (FILE *f, net_t *cnet)

{
        while (cnet)
        {
                net_t *subnet = cnet->subnets;

                if (subnet && cnet->how_joined == Jumpered)
                {
                        while (subnet)
                        {
                                frb_list_net (f, subnet);

                                subnet = subnet->subnets;
                        }
                }

                else

                        frb_list_net (f, cnet);

                cnet = cnet->next;
        };
}

/* ********************************************************************** */

void produce_frb (FILE *f)

{
        time_t now;

        struct tm *tim;

        socket_t *dev;

        time (&now);

        tim = localtime (&now);

        fprintf (
            f,
            ".HEA\n.TIM		%4d %02d %02d %02d %02d %02d\n",

            tim->tm_year + 1900,

            tim->tm_mon + 1, /* tm_mon has range 0..11 (jan=0) */

            tim->tm_mday, /* but tm_mday has range 1..31 !! */

            tim->tm_hour,

            tim->tm_min,

            tim->tm_sec);

        fprintf (f, ".JOB		J_%d\n", now);

        fprintf (f, ".TYP		FULL\n");

        fprintf (f, ".APP		\"Neutral Architecture File\"\n\n");

        dev = socket_head;

        while (dev)
        {
                /* only print named devices !!! */

                fprintf (
                    f,
                    ".ADD_COM %s %s %s\n",

                    dev->identifier,

                    dev->type,

                    dev->value);

                dev = dev->next;
        }

        fprintf (f, "\n\n");

        frb_list_net_connections (f, named_list);

        frb_list_net_connections (f, routed_list);

        fprintf (f, ".END\n");
}

/* ********************************************************************** */

/* puts a comment on the head of the file */

void print_header (FILE *f, char *tool)

{
        time_t now;

        struct tm *tim;

        time (&now);

        tim = localtime (&now);

        fprintf (f, "--       Altera EPLD / PCB / VHDL tools        --\n");

        fprintf (f, "-- (c) Philips Semiconductors Southampton 1996-1999 --\n\n");

        fprintf (f, "-- by: Mike James (Mike.James@soton.sc.philips.com)\n\n");

        fprintf (
            f,
            "-- Produced by %s\n-- at %02d:%02d:%02d	on %02d/%02d/%4d \n\n",

            tool,

            tim->tm_hour,

            tim->tm_min,

            tim->tm_sec,

            tim->tm_mday,

            tim->tm_mon + 1,

            tim->tm_year + 1900);
}

/* ********************************************************************** */

/* VHDL output of the entities                                            */

/* ********************************************************************** */

char *make_vhdl_name (char *buffer, char *str)

{
        int i, l;

        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++)
        {
                if (buffer[i] == ':' || buffer[i] == '|')

                        buffer[i] = 'X';
        }

        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;
}

/* ********************************************************************** */

/* 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);

        fprintf (f, "COMPONENT  %s\n", check_null_str (dev->name));

        fprintf (f, "--  DEV_IDENT \"%s\"\n\n", check_null_str (dev->identifier));

        fprintf (f, "  PORT ( \n");

        /* sort the identifiers of the nodes */

        sort_nodes (dev);

        n = dev->nodes;

        while (n)

        {
                vhdl_t *pin_datatype = default_vhdl_datatype;

                char nam[MAXIDLEN], typ[MAXIDLEN];

                if (n->orig_vhdltype)

                        pin_datatype = n->orig_vhdltype;

                else if (n->vhdltype)

                        pin_datatype = n->vhdltype;

                if (n->net_assigned && n->in_use || All)
                {
                        fprintf (
                            f,
                            "  %-16s : %6s %10s ",

                            make_vhdl_name (nam, check_null_str (n->name)),

                            decode_pin_VHDL[(int) n->pindir],

                            decode_vhdl_type (typ, pin_datatype));

                        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;

        fprintf (
            f,
            "%s_inst :  %s \n",

            check_null_str (dev->name),

            check_null_str (dev->name));

        fprintf (f, "--  DEV_IDENT \"%s\"\n\n", check_null_str (dev->identifier));

        fprintf (f, "  PORT MAP ( \n");

        /* sort the identifiers of the nodes */

        sort_nodes (dev);

        n = dev->nodes;

        while (n)

        {
                vhdl_t *pin_datatype = default_vhdl_datatype;

                char nam1[MAXIDLEN], nam2[MAXIDLEN], vhdlname[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->needs_buff_sig)

                                sig_prefix = BUFPREFIX;

                        else

                                sig_prefix = "";

                        fprintf (
                            f,
                            "  %-20s => %s%s %s ",

                            make_vhdl_name (nam1, check_null_str (n->name)),

                            sig_prefix,

                            make_vhdl_name (nam2, check_null_str (n->net->name)),

                            decode_vhdl_bus (vhdlname, n->vhdltype));
                }

                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], typ[MAXIDLEN], *sig_prefix;

        while (net)
        {
                if (net->needs_buff_sig)

                        sig_prefix = BUFPREFIX;

                else

                        sig_prefix = "";

                if (net->inside_partition)
                {
                        fprintf (
                            f,
                            " SIGNAL %s%s : %s;",

                            sig_prefix,

                            make_vhdl_name (nam, net->name),

                            decode_vhdl_type (typ, net->vhdltype));
                }

                else

                        fprintf (
                            f,
                            "  -- net '%s%s : %sl",

                            sig_prefix,

                            make_vhdl_name (nam, net->name),

                            decode_vhdl_type (typ, net->vhdltype));

                fprintf (
                    f,
                    " -- partition : %s, %s, %s --\n",

                    net->inside_partition ? "used in" : "unused in",

                    net->leaves_partition ? "leaves" : "buried ",

                    net->needs_buff_sig ? ", buffered" : "");

                net = net->next;
        }
}

/* ********************************************************************** */

void print_VHDL_assignments (FILE *f)

{
        net_t *net = named_list;

        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,
                                " %s <= " BUFPREFIX "%s;\n",

                                nam,
                                nam);
                }

                net = net->next;
        }

        fprintf (f, "-- \n\n");
}

/* ********************************************************************** */

void print_VHDL_entity (FILE *f, char *entityname)

{
        net_t *net = named_list;

        int need_term = 0;

        fprintf (f, "ENTITY %s IS\n  PORT (\n", entityname);

        while (net)
        {
                char nam[MAXIDLEN], typ[MAXIDLEN];

                if (net->leaves_partition)
                {
                        if (need_term)

                                fprintf (f, ";\n");

                        else

                                fprintf (f, "\n");

                        fprintf (
                            f,
                            "  %-15s : %6s %10s",

                            make_vhdl_name (nam, net->name),

                            decode_pin_VHDL[net->ext_dir],

                            decode_vhdl_type (typ, net->vhdltype));

                        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;

        fprintf (f, "\n\nARCHITECTURE top OF  %s IS\n\n", entityname);

        skt = socket_head;

        while (skt)
        {
                if (skt->selected)

                        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->selected)

                        print_VHDL_instance (f, skt, 0);

                skt = skt->next;
        }

        print_VHDL_assignments (f);

        fprintf (f, "END top;\n\n");
}

/* ********************************************************************** */

/* 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 */

                print_header (f, "WRITE VHDL");

                print_VHDL_libs (f);

                print_VHDL_entity (f, entityname);

                print_VHDL_libs (f);

                print_VHDL_architecture (f, entityname);
        }

        else
        { /* there is a template file */

                FILE *tp;

                tp = fopen (template, "r");

                if (tp)
                {
                        print_header (f, "WRITE VHDL");

                        fprintf (f, "-- Using template '%s'\n", template);

                        while (!feof (tp))
                        {
                                if (fgets (linebuff, 256, tp))
                                {
                                        if (strstr (linebuff, "$ENT"))
                                        {
                                                print_VHDL_entity (f, entityname);

                                                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 */
                                }
                        }

                        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);
        }
}

/**********************************************************/

/* Database diagnostics                                   */

/**********************************************************/

void deb_print_node (FILE *f, node_t *n)

{
        fprintf (f, "--Node--\n");

        /*  struct node * sktnext; linked to a socket */

        fprintf (f, "next->%p\n", n->sktnext);

        /* char * identifier;   e.g 102, A22 */

        fprintf (f, "identifier %s\n", n->identifier);

        /* char * name;        signal name (actually same as netname )  */

        fprintf (f, "name      %s\n", check_null_str (n->name));

        /* vhdl_t * vhdltype; */

        fprintf (f, "vhdltype  %p\n", decode_vhdl_type (n->vhdltype));

        /* vhdl_t * orig_vhdltype; */

        fprintf (f, "orig_vhdltype  %p\n", decode_vhdl_type (n->orig_vhdltype));

        /* pindir_t   pindir;       final pin type input? output? bidir? unknown? */

        fprintf (f, "pindir    %s\n", decode_pin[n->pindir]);

        /* struct net * net;     refer to net this node is on (if known) */

        fprintf (f, "net       %p\n", n->net);

        if (n->net)

                fprintf (f, "  (id '%s')\n", check_null_str (n->net->identifier));

        /* struct net * net;     refer to net this node is on (if known) */

        fprintf (f, "routed net       %p\n", n->net);

        if (n->net)

                fprintf (f, "  (id '%s')\n", check_null_str (n->net->identifier));

        /*  int    refcount;     how many nets refer to this node */

        fprintf (f, "refcount  %d\n", n->refcount);

        /* struct socket * socket;   refer to socket this node is part of   */

        fprintf (f, "socket    %p\n", n->socket);

        if (n->socket)

                fprintf (f, "  socket (id '%s')\n", check_null_str (n->socket->identifier));

        /* unsigned int fixed_pin:1; if fixed_pin = 1 then this pin can only be used

                                    to connect to the net in a particular

                                    direction */

        fprintf (f, "fixed_pin:  %s\n", n->fixed_pin ? "yes" : "no");

        /* unsigned int in_use:1;    if '1' the node is used by a pin

                                    if '0' the node has had a dummy name assigned*/

        fprintf (f, "in_use:     %s\n", n->in_use ? "yes" : "no");

        /* unsigned int net_assigned:1;  if '1' the node (name) has a net assigned

                                        to it by routing */

        fprintf (f, "net_assigned:  %s\n", n->net_assigned ? "yes" : "no");

        fprintf (f, "-- End Node--\n");
}