
/*
 * $Id: statistics.c,v 1.1.1.1 2003/11/04 23:34:57 mjames Exp $
 *
 * $Log: statistics.c,v $
 * Revision 1.1.1.1  2003/11/04 23:34:57  mjames
 * Imported into local repositrory
 *
 * Revision 1.9  2002/01/16 11:22:49  mjames
 * database.h header file is read in first as it undefined DLL stuff irrelevant
 * to HPUX
 *
 * Revision 1.8  2002/01/15 12:33:14  mjames
 * removed unused variable
 *
 * Revision 1.7  2001/10/31 22:20:18  mjames
 * Tidying up problematical comments caused by CVS
 * 'intelligent' comment guessing
 *
 * Revision 1.6  2001/10/31 16:18:04  mjames
 * Added a datastructure to hide regular expression information from programs.
 * Changed call to regexec to indicate 0 subexpressions to be matched
 * rather than a number dependent on strlen(string) which was wrong.
 *
 * Revision 1.5  2001/10/10 20:18:20  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.4  2001/10/07 20:50:51  mjames
 * Added wildcard checking (warn user about
 * using wildcard '*' on the end of a string in stead of wildcard '.*')
 *
 * Revision 1.3  2001/09/25 23:15:22  mjames
 * Converted wildcards to use proper regexp pattern match library
 *
 * Revision 1.2  2001/06/06 12:10:17  mjames
 * Move from HPUX
 *
 * Revision 1.1.1.1  2000/10/19 21:58:40  mjames
 * Mike put it here
 *
 *
 * Revision 1.37  2000/10/12  14:27:48  14:27:48  mjames (Mike James)
 * changed listing vhdl signals to expand expressions
 * until a constant is located
 *
 * Revision 1.36  2000/10/04  10:37:10  10:37:10  mjames (Mike James)
 * Modified for Vertical2 : support COMPONENTS and SIGNALS
 *
 * Revision 1.36  2000/10/04  10:37:10  10:37:10  mjames (Mike James)
 * Part of Release PSAVAT01
 *
 * Revision 1.35  2000/10/02  11:04:21  11:04:21  mjames (Mike James)
 * new_vhdl
 *
 * Revision 1.34  2000/09/27  14:42:21  14:42:21  mjames (Mike James)
 * Part of Release Sep_27_ST_2000
 *
 * Revision 1.33  2000/09/21  10:15:51  10:15:51  mjames (Mike James)
 * Part of Release Sep21Alpha
 *
 * Revision 1.32  2000/09/21  09:47:33  09:47:33  mjames (Mike James)
 * Corrected <cr> problem
 *
 * Revision 1.31  2000/08/25  09:57:17  09:57:17  mjames (Mike James)
 * Part of Release Aug25_alpha
 *
 * Revision 1.30  2000/08/16  08:57:33  08:57:33  mjames (Mike James)
 * Part of Release CD01_Aug2000
 *
 * Revision 1.29  2000/08/14  14:45:14  14:45:14  mjames (Mike James)
 * Part of Release Aug_14_2000
 *
 * Revision 1.28  2000/08/11  08:30:34  08:30:34  mjames (Mike James)
 * Part of Release Aug_11_2000
 *
 * Revision 1.27  2000/08/09  10:31:50  10:31:50  mjames (Mike James)
 * Part of Release Aug__9_2000
 *
 * Revision 1.26  2000/05/31  11:43:01  11:43:01  mjames (Mike James)
 * Part of Release May_31_2000
 *
 * Revision 1.25  2000/05/08  17:01:40  17:01:40  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.24  2000/05/08  16:59:33  16:59:33  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.23  2000/05/08  16:57:10  16:57:10  mjames (Mike James)
 * Part of Release May__8_2000
 *
 * Revision 1.22  2000/05/03  15:28:39  15:28:39  mjames (Mike James)
 * Corrected abuse of null pointers
 *
 * Revision 1.21  2000/03/08  16:19:33  16:19:33  mjames (Mike James)
 * New version including PC
 *
 * Revision 1.18  2000/01/20  15:58:51  15:58:51  mjames (Mike James)
 * Part of Release R22
 *
 * Revision 1.17  99/12/22  11:15:31  11:15:31  mjames (Mike James)
 * Part of Release Dec_22_1999
 *
 * Revision 1.16  99/06/25  14:35:52  14:35:52  mjames (Mike James)
 * Added in reference to expression.h, but no changes made
 * to the function of acfread yet.
 *
 * Revision 1.15  99/05/04  09:52:55  09:52:55  mjames (Mike James)
 * General checkin
 *
 * Revision 1.14  98/03/16  11:39:55  11:39:55  mjames (Mike James)
 * Altered XREF printout to use wildcards.
 *
 * Revision 1.13  98/02/11  11:27:25  11:27:25  mjames (Mike James)
 * Checked in for version 6.2a
 *
 * Revision 1.12  97/04/23  08:43:26  08:43:26  mjames (Mike James)
 * CHecked in for release rel23041997
 *
 * Revision 1.11  97/01/03  13:37:29  13:37:29  mjames (Mike James)
 * Tidied up the ensure_reserved() function. Added in a flag to
 * indicate that a net has been processed by ensure_reserved()
 * And so is not in error for only having 0 or 1 nodes names (which is the
 * case for a 1 or 2 node net that has been processed. One of the nodes will
 * remain unnnamed and this will result in 0 or 1 nodes apparently in use
 *
 * Revision 1.10  96/12/23  15:15:34  15:15:34  mjames (Mike James)
 * ?
 *
 * Revision 1.9  96/12/13  08:43:14  08:43:14  mjames (Mike James)
 * Update to v5.1, added Write ID , exact routing
 *
 * Revision 1.8  96/08/06  13:38:57  13:38:57  mjames (Mike James)
 * Added a count of nets with low numbers of nodes in the routed list.
 *
 * Revision 1.7  96/07/19  14:38:46  14:38:46  mjames (Mike James)
 * Update to give to PRL
 *
 * Revision 1.6  1996/07/12  15:52:12  mjames
 * Sorted out things like Alias and Jumpers
 * Work Correctly
 * Print COrrectly
 *
 * Revision 1.5  96/06/17  13:01:48  13:01:48  mjames (Mike James)
 * Altered the printing of JUMPERED and ALIASED nets
 * ,
 *
 * Revision 1.4  96/04/26  16:02:36  16:02:36  mjames (Mike James)
 * Altered inside/outside determination of signal directions
 *
 * Revision 1.3  96/04/15  14:19:38  14:19:38  mjames (Mike James)
 * Checkin before datatype printing
 * modifications
 *
 * Revision 1.2  96/03/29  14:46:34  14:46:34  mjames (Mike James)
 * Added VHDL netlist writing to the capabilities of ACFREAD
 *
 * Revision 1.1  96/03/26  07:47:46  07:47:46  mjames (Mike James)
 * Initial revision
 *  */
/* The statistics module . This counts the connections between the chip and
   other named chips. */

#include "statistics.h"

#include "chck_names.h"
#include "cmdlog.h"
#include "cmdparse.h"
#include "database.h"
#include "expression.h"
#include "generic.h"
#include "lx_support.h"
#include "sorting.h"
#include "vertcl_main.h"

#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

static char IDstr[] = "@(#)$Header: c:\\cygwin\\cvsroot/Vert03/vertlib/statistics.c,v 1.1.1.1 "
                      "2003/11/04 23:34:57 mjames Exp $";

/* this procedure counts paths from a named socket to all other named
   sockets. There are two wildcard options :
   no wildcard : all sockets are listed
   string*     : any string beginning 'string'
   *           : all named sockets  */

int count_paths (char *template)
{
        socket_t *skt_p, *skt_try;
        noderef_t *net_nodes;
        node_t *skt_nodes;
        net_t **list_member;
        int rc;

        char *pattern;
        /* compile regular expression */
        vert_regex_t *preg;

        skt_p = socket_head;
        /* clear all of the visit counters */
        while (skt_p)
        {
                skt_p->named_in_use_cnt = skt_p->named_cnt = skt_p->routed_cnt =
                    skt_p->unrouted_cnt = 0;
                skt_p = skt_p->next;
        }
        if (!ISNULLSTR (template))
        {
                pattern = template;
        }
        else
        {
                pattern = ".*";
        }

        rc = vert_regcomp (&preg, pattern);

        if (rc != 0)
        {
                char errbuff[100];
                regerror (rc, preg->preg, errbuff, 100);
                Log (
                    LOG_ERROR,
                    "-- Problem (rc=%d) %s with '%s' as regular expression\n",
                    rc,
                    errbuff,
                    pattern);

                return TCL_ERROR;
        }

        Log (
            LOG_GENERAL,
            "-- Listing xref for socket names '%s' --\n",
            template ? template : "[ALL Sockets]");

        skt_p = socket_head;
        while (skt_p)
        {
                int found;

                found = regexec (preg->preg, skt_p->name, 0, preg->regpatt, 0);
                if (!found)
                {
                        skt_nodes = skt_p->nodes;
                        /*
                          fprintf(f,"named = %p , routed = %p  unrouted = %p\n",
                                &named_list,&routed_list,&unrouted_list);
                        */
                        /* we have located the socket on the net . Let us now locate each net
                         */
                        /* some nodes on a socket will be unrouted nodes on unrouted nets that
                           have now been resolved , and the unrouted net will have been deleted
                           . These have the property that node->net->list_ref = NULL */
                        while (skt_nodes)
                        {
                                net_t *ref_net = skt_nodes->net;
                                if (ref_net)
                                {
                                        int high, low, width, net_high, net_low;

                                        net_nodes = ref_net->nodes;

                                        /* note the upper and lower bound of the bundle
                                         * connected from this pin of this socket to the net.
                                         * Also checking there is an associated VHDL type 4 May
                                         * 2000 */
                                        if (skt_nodes->vhdltype)
                                        {
                                                eval_vhdl_expression (
                                                    skt_nodes->vhdltype->expr,
                                                    &net_high,
                                                    &net_low);
                                        }
                                        else
                                        {
                                                net_low = 0;
                                                net_high = 0;
                                        }

                                        /* which list is this net on */
                                        list_member = ref_net->list_ref;
                                        /* visit each node */
                                        while (net_nodes)
                                        {
                                                node_t *n = net_nodes->node;
                                                vhdl_t *vhdl = net_nodes->vhdltype;
                                                int vhdl_high, vhdl_low;
                                                if (vhdl)
                                                {
                                                        /* to determine the intersection of the
                                                         * bundles, hence connection count :
                                                         * (15 downto 8) connected to (10
                                                         * downto 5) has intersection (10
                                                         * downto 8)
                                                         */
                                                        if (vhdl->expr)
                                                                eval_vhdl_expression (
                                                                    vhdl->expr,
                                                                    &vhdl_high,
                                                                    &vhdl_low);
                                                        else
                                                        {
                                                                vhdl_high = 0;
                                                                vhdl_low = 0;
                                                        }
                                                        /* use the lowest high bound of the
                                                         * node this net comes from */
                                                        high = vhdl_high > net_high
                                                                   ? net_high
                                                                   : vhdl_high;

                                                        /* use the highest low bound of the
                                                         * node this net comes from */
                                                        low = vhdl_low < net_low ? net_low
                                                                                 : vhdl_low;

                                                        /* now get the number of wires in the
                                                         * bundle */
                                                        width = high - low + 1;
                                                        if (list_member == &named_list)
                                                        {
                                                                if (n->in_use)
                                                                        n->socket
                                                                            ->named_in_use_cnt +=
                                                                            width;
                                                                else
                                                                        n->socket->named_cnt +=
                                                                            width;
                                                        }
                                                        else if (list_member == &routed_list)
                                                                n->socket->routed_cnt += width;
                                                        else if (list_member == &unrouted_list)
                                                                n->socket->unrouted_cnt +=
                                                                    width;
                                                        else if (list_member != NULL)
                                                                Log (
                                                                    LOG_ERROR,
                                                                    "# ERROR : Net %s is on "
                                                                    "unknown list pointer=%p "
                                                                    ", net \n",
                                                                    ref_net->name,
                                                                    list_member);
                                                }
                                                net_nodes = net_nodes->next;
                                        }
                                }
                                skt_nodes = skt_nodes->sktnext;
                        }
                        /* now have compiled a cross reference count */
                        skt_try = socket_head;
                        Log (
                            LOG_GENERAL, "--  Cross reference for socket '%s'\n", skt_p->name);
                        Log (
                            LOG_GENERAL,
                            "Name            : Named&Used, Named, Routed,Unrouted\n");
                        skt_try = socket_head;
                        while (skt_try)
                        {
                                if (!ISNULLSTR (skt_try->name))
                                {
                                        Log (
                                            LOG_GENERAL,
                                            "%16s :  %5d, %5d, %5d, %5d\n",
                                            skt_try->name,
                                            skt_try->named_in_use_cnt,
                                            skt_try->named_cnt,
                                            skt_try->routed_cnt,
                                            skt_try->unrouted_cnt);
                                }
                                skt_try->named_in_use_cnt = skt_try->named_cnt =
                                    skt_try->routed_cnt = skt_try->unrouted_cnt = 0;
                                skt_try = skt_try->next;
                        }
                }
                skt_p = skt_p->next;
        }

        vert_regfree (&preg);
        return OKCMD; /* success */
}

/* this procedure counts up and displays the number of nets with less than a certain
 threshold number of nodes actually in use. */
void count_nets_with_few_nodes (int limit)
{
        long lowcount = 0;
        net_t *routed_net = named_list;
        Log (
            LOG_GENERAL,
            "-- Checking for nets with less than or equal to %d nodes in use\n",
            limit);
        while (routed_net)
        {
                int nodecount = 0;
                noderef_t *routed_nodes = routed_net->nodes;
                while (routed_nodes)
                {
                        /*        node_t *cnode = routed_nodes->node;  */
                        if (routed_nodes->node->net_assigned != 0)
                                nodecount++;

                        routed_nodes = routed_nodes->next;
                }
                /* turn off warning if low nodecount is due to ensure_reserved processing in
                 * routing.c */
                if (nodecount <= limit && !routed_net->nodes_reserved)
                {
                        Log (
                            LOG_GENERAL,
                            "-- Net '%s' (name '%s') has only %d node(s) in use\n",
                            routed_net->identifier,
                            routed_net->name,
                            nodecount);
                        lowcount++;
                }
                routed_net = routed_net->next;
        }
        Log (LOG_GENERAL, "-- Found %d nets with less than %d nodes used\n", lowcount, limit);
}

/* keep some cc's happy */
void statistics_waste (void)
{
        char *s = IDstr;
        s = s;
}