diff --git a/alliance/src/lvx/Makefile.am b/alliance/src/lvx/Makefile.am new file mode 100644 index 00000000..ce9d1044 --- /dev/null +++ b/alliance/src/lvx/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = doc src diff --git a/alliance/src/lvx/configure.in b/alliance/src/lvx/configure.in new file mode 100644 index 00000000..0c6feb17 --- /dev/null +++ b/alliance/src/lvx/configure.in @@ -0,0 +1,33 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(src/lvx.c) + +LVX_MAJOR_VERSION=1 +LVX_MINOR_VERSION=2 +LVX_VERSION=$LVX_MAJOR_VERSION.$LVX_MINOR_VERSION + +AC_SUBST(LVX_MAJOR_VERSION) +AC_SUBST(LVX_MINOR_VERSION) +AC_SUBST(LVX_VERSION) + +# For automake. +VERSION=$LVX_VERSION +PACKAGE=lvx + +dnl Initialize automake stuff +AM_INIT_AUTOMAKE($PACKAGE, $VERSION) + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_MAKE_SET + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +AM_ALLIANCE + +AC_OUTPUT([ +Makefile +doc/Makefile +src/Makefile +]) diff --git a/alliance/src/lvx/doc/Makefile.am b/alliance/src/lvx/doc/Makefile.am new file mode 100644 index 00000000..3667cafc --- /dev/null +++ b/alliance/src/lvx/doc/Makefile.am @@ -0,0 +1,4 @@ +## Process this file with automake to produce Makefile.in + +man_MANS = lvx.1 +EXTRA_DIST = $(man_MANS) diff --git a/alliance/src/lvx/doc/lvx.1 b/alliance/src/lvx/doc/lvx.1 new file mode 100644 index 00000000..67f5514a --- /dev/null +++ b/alliance/src/lvx/doc/lvx.1 @@ -0,0 +1,188 @@ +.\" $Id: lvx.1,v 1.1 2002/03/20 17:07:59 xtof Exp $ +.\" @(#)lvx.l 0.0 92/11/27 UPMC; Author: Francois Nacabal +.TH LVX 1 "October 1, 1997" "ASIM/LIP6" "ALLIANCE USER COMMANDS" +.SH NAME +lvx \- Logical Versus eXtracted net-list comparator +.SH SYNOPSIS +.TP +\fBlvx \fIformat1 format2 filename1 filename2 \fB[ -a ] [ -o ] [ -f ]\fR +.br +.so man1/alc_origin.1 +.SH DESCRIPTION +.B lvx +compares two gate-level or block level net-list. The goal is to compare +a specification net-list (logical net-list), the input to a place and route tool, +with the physical net-list (extracted net-list) obtained by the +.BR lynx (1) +extractor. +.br +The net-list 1 is considered as the logical net-list and net-list 2 as the +extracted net-list. +.br +.br +.B lvx +is an one-level hierarchical tool: +.IP +The two net-list are flattened, if the \fB-f\fP option is present, to the cells +contained in the catalog file. The path to the catalog file is indicated in the +.BR MBK_CATA_LIB (1) +variable for the cell library, and in the +.BR MBK_WORK_LIB (1) +variable with the name +.BR MBK_CATAL_NAME (1) +for user blocks ( +.BR catal (5) +) that are not to be flattened. +.IP +For both net-list, the instances are considered as black-boxes. +.IP +The two net-list must have the same external connectors names. +.IP +The two net-list must have the same instances names. +.IP +The two net-list must have the same signals names for unconnected signals. +.IP +The two net-list cannot directly contain transistors. +.LP +Comparison is performed in three steps: +.IP +Compare terminals. +.IP +Compare instances. +.IP +Compare connections. +.IP +Compare unconnected signals. +.LP +If an error occurs during first or second step, a message is +immediately displayed and the third step will not start: +.B lvx +cannot compare connections (signals) if terminals +or instances are not equivalent. +.br +The +.B -o +option allows to order connectors if the steps described before have been +reached successfully. +.I Extracted_netlist +is then saved on disk. The file get the name +.I filename2 +suffixed by the value of +.BR MBK_OUT_LO (1) +variable. +.br +Routers add automatically empty feed-through cells. +These cells must not be taken into account in the comparison. +A cell that have the +.I F +attribute in the catalog file ( +.B catal (5) +) is considered as feed-through cell, and are deleted, in memory, from the +net-list where it appears. +.SH OPTIONS +.TP +.B "-a" +Some routers generate layout with several physical connectors for power and +ground ( +.I VDD +or +.I VSS +). +If those connectors are not internally connected, they will have different +indexed names ( +.I VDD1 +, +.I VDD2 +etc...) in the extracted net-list. +It is possible to perform reduction on those power and ground connectors before +comparison, using the -a option. +After reduction, each instance contains only one +.I VDD +connector and one +.I VSS +connector, as the main figure. +.TP +.B "-o" +In this case, +.B lvx +produces a modified net-list (saved with the name +.I filename2 +), which is a copy of net-list 2 with ordered connectors. +Terminals and instance connectors are relisted in the order of the models +in net-list 1. The saved net-list is done with the +.BR MBK_OUT_LO (1) +format, so user has to set this variable before running +.B lvx +\&. +If he does not, default value is used, and net-list 1 could be lost if +filename are identical and input format same as output format. +.br +If -a option is used, then the saved net-list is the reduced net-list with only +one +.I VDD +and one +.I VSS +\&. +.TP +.B "-f" +The two net-lists are flattened to the leaf cells contained in the catalog +file. Usually the extracted net-list is a flatten net-list, while the logical +one can be a hierarchical net-list. +.SH EXAMPLES +With +.I logical_netlist +named amd2901.vst and the corresponding +.I extracted_netlist +as amd2901.al containing multiple power connectors, the command line is : +.br +.IP +.B lvx +vst al amd2901 amd2901 -a +.br +.LP +.SH OUTPUT FILES +.TP 20 +\fIfilename2\fP.\f4xx\fP +Netlist view saved when the \fB-o\fP option is present. The suffixe depend on +the \f4MBK_OUT_LO\fP(1) environment variable. +.SH ENVIRONMENT VARIABLES +.TP 20 +\f4MBK_CATA_LIB\fR +contains the directories where the cell librtaries are. +\f4MBK_WORK_LIB\fR +contains the directory path of the working directory, usually set to +\f4.\fR (dot). +.TP +\f4MBK_OUT_LO\fR +contains the expected format of the netlist output. +.TP +\f4MBK_CATAL_NAME\fR +contains the name of the user cell catalog. +.SH SEE ALSO +.BR lynx (1), +.BR MBK_OUT_LO (1), +.BR MBK_WORK_LIB (1), +.BR MBK_CATA_LIB (1), +.BR MBK_CATAL_NAME (1), +.BR catal (5) +\&. +.SH DIAGNOSTICS +The string "_logic" is appended to the net-list 1 and the string "_extract", is +appended to the net-list 2. +.LP +Two kinds of error message can occur: +.IP +A fatal error causes the program to exit. +It happens when one of the net-lists is not correct, +.B lvx +cannot construct internal structure for compare. +.IP +A compare error occurs when the figures are not identical. +It happens when basic objects (instances, connectors) do not exist in both +net-list, or when connections (signals) do not connect same terminals or +instances in the two net-lists. +.LP +Exit code 0 is returned for identical net-lists. + +.so man1/alc_bug_report.1 + diff --git a/alliance/src/lvx/src/Makefile.am b/alliance/src/lvx/src/Makefile.am new file mode 100644 index 00000000..211f67eb --- /dev/null +++ b/alliance/src/lvx/src/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = lvx + +lvx_LDADD = @LIBS@ \ + -lMlu \ + -lMcl \ + -lMal \ + -lMsl \ + -lMel -lMgl \ + -lMhl \ + -lMvl \ + -lMlo \ + -lMut \ + -lRcn + +lvx_SOURCES = lvx.c diff --git a/alliance/src/lvx/src/lvx.c b/alliance/src/lvx/src/lvx.c new file mode 100644 index 00000000..fdb91639 --- /dev/null +++ b/alliance/src/lvx/src/lvx.c @@ -0,0 +1,1823 @@ +/* + * This file is part of the Alliance CAD System + * Copyright (C) Laboratoire LIP6 - Département ASIM + * Universite Pierre et Marie Curie + * + * Home page : http://www-asim.lip6.fr/alliance/ + * E-mail support : mailto:alliance-support@asim.lip6.fr + * + * This progam is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Alliance VLSI CAD System is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the GNU C Library; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ident "@(#)Gate Netlist Comparator" + +/****************************************************************************/ +/* 2.14 : Ressort avec un exit 1 si erreur mbk au chargement */ +/****************************************************************************/ + +/****************************************************************************/ +/* */ +/* ALLIANCE VLSI CAD LVX */ +/* */ +/* Tool : LVX (Netlist Comparator) */ +/* */ +/* (c) copyright 1992 Laboratory UPMC/MASI/CAO-VLSI */ +/* All rights reserved */ +/* Support : e-mail cao-vlsi@masi.ibp.fr */ +/* */ +/* Author : Francois NACABAL October, 1st 1992 */ +/* */ +/****************************************************************************/ +/* $Log: lvx.c,v $ +/* Revision 1.1 2002/03/20 17:07:59 xtof +/* Initial revision +/* +/* Revision 1.2 2000/10/23 16:33:37 syf +/* Big bug dans LVX (a se demander comment ca a pu marcher un jour ...) +/* +/* Revision 1.1.1.1 1998/10/02 15:25:15 alliance +/* Imported by czo +/* + * Revision 2.23 1994/01/19 14:57:20 lvx + * Now the -f option will not print invalid parameter + * + * Revision 2.22 1993/10/03 16:11:11 lvx + * The revision of Alliance is given in the Makefile with ALC define + * + * Revision 2.21 1993/09/08 21:15:48 lvx + * The alliancebanner() is now used. + * + * Revision 2.20 1993/09/08 21:04:55 lvx + * Now to flatten a netlist, you have to specify it using the -f option. + * The power supply names are defined by MBK_VDD and MBK_VSS. + * Unconnected signals are checked using their names. + * Tie cells are defined using the attribute F defined in the CATALOG file. + * + * Revision 2.13 1993/01/07 20:44:48 lvx + * The feed-through cells are detected with the attribute put in the catalog + * file. + * + * Revision 2.12 1992/11/27 18:36:58 lvx + * Models are put out of memory after loading. + * Models are put out of memory before orderring. + * + * Revision 2.11 1992/10/12 17:20:39 lvx + * LOCON list has been reversed with reverse() + * Best way should be modify the orderlocon algorithm + * + * Revision 2.10 1992/10/12 16:31:13 lvx + * The function orderlocon() has been modified to bug fixing + * + */ + +static char rcsid[] = "$Id: lvx.c,v 1.1 2002/03/20 17:07:59 xtof Exp $" ; + +#include +#include +#include +#include +#include + +#define TRUE 1 +#define FALSE 0 + +/* Marks in trees for compare functions */ +#define NET1 1 +#define NET2 2 +#define BOTH 3 + +/* Error codes */ +#define OK 0 +#define ERR 1 /* irregular netlist or comparison failed */ + +/*****************************************************************************/ +/*********** STRUCTURES DEFINITIONS ****************************************/ +/*****************************************************************************/ + +/* Binary Tree of terminals (root connectors) */ + +typedef struct rootlocon_node { + struct locon *LOCON; + unsigned char MARK; + struct rootlocon_node *LEFT; + struct rootlocon_node *RIGHT; + } rootlocon_tree; + + +/* Binary Tree of instances */ + +typedef struct loins_node { + struct loins *LOINS; + unsigned char MARK; + struct loins_node *LEFT; + struct loins_node *RIGHT; + } loins_tree; + + +/* Binary Tree of all connectors */ + +typedef struct locon_node { + struct locon *LOCON1; + struct locon *LOCON2; + struct locon_node *LEFT; + struct locon_node *RIGHT; + } locon_tree; + + +/*****************************************************************************/ +/******* GLOBAL VARIABLES **************************************************/ +/*****************************************************************************/ + +rootlocon_tree *rootlocon_head = NULL; /* Head of the Tree of terminals */ +loins_tree *loins_head = NULL; /* Head of the Tree of instances */ +locon_tree *locon_head = NULL; /* Head of the Tree of all connectors */ + +int rootlocon_count = 0; +int loins_count = 0; +int locon_count = 0; +int power_count = 0; +int error_count = 0; + +long int power_time; +long int rootlocon_time; +long int loins_time; +long int locon_time; +long int total_time; + +int unusig_flag = FALSE; +int exitcode = 2; + +/*****************************************************************************/ +/******* FUNCTIONS *********************************************************/ +/*****************************************************************************/ + +/*===========================================================================*/ + fatalerror (message) +/*===========================================================================*/ +char *message; + +/* Prints a error message, and EXIT with error code. +*/ +{ + (void)fprintf (stderr, "\n!!!!! %s", message); + (void)fprintf (stderr, " - Stop.\n\n"); + + exit (2); +} + + +/*===========================================================================*/ + rootlocon_tree *createrootlocon (ptlocon, mark) +/*===========================================================================*/ +locon_list *ptlocon; +unsigned char mark; + +/* Allocates a block in memory for a terminal node. + Never returns NULL, stop if impossible. +*/ +{ + rootlocon_tree *ptnode; + + if (ptlocon == (locon_list *)NULL) + fatalerror ("Fatal error on tree construction. (createrootlocon)"); + + if ((ptnode = (rootlocon_tree *)malloc (sizeof (rootlocon_tree))) == NULL) + fatalerror ("Fatal error on memory allocation. (createrootlocon)"); + + ptnode->LOCON = ptlocon; + ptnode->MARK = mark; + ptnode->LEFT = ptnode->RIGHT = (rootlocon_tree *)NULL; + + rootlocon_count ++; + if ( (error_count == 0) && ((rootlocon_count&3) == 0) ) + printf ("."); + return ( ptnode ); +} + + +/*===========================================================================*/ + loins_tree *createloins (ptloins, mark) +/*===========================================================================*/ +loins_list *ptloins; +unsigned char mark; + +/* Allocates a block in memory for an instance node. + Never returns NULL, stop if impossible. +*/ +{ + loins_tree *ptnode; + + if (ptloins == (loins_list *)NULL) + fatalerror ("Fatal error on tree construction. (createloins)"); + + if ((ptnode = (loins_tree *)malloc (sizeof (loins_tree))) == NULL) + fatalerror ("Fatal error on memory allocation. (createloins)"); + + ptnode->LOINS = ptloins; + ptnode->MARK = mark; + ptnode->LEFT = ptnode->RIGHT = (loins_tree *)NULL; + + loins_count ++; + if ( (error_count == 0) && ((loins_count&63) == 0) ) + printf ("."); + return ( ptnode ); +} + + +/*===========================================================================*/ + locon_tree *createlocon (ptlocon, mark) +/*===========================================================================*/ +locon_list *ptlocon; +unsigned char mark; + +/* Allocates a block in memory for a connector node. + Never returns NULL, stop if impossible. +*/ +{ + locon_tree *ptnode; + + if (ptlocon == (locon_list *)NULL) + fatalerror ("Fatal error on tree construction. (createlocon)"); + + if ((ptnode = (locon_tree *)malloc (sizeof (locon_tree))) == NULL) + fatalerror ("Fatal error on memory allocation. (createlocon)"); + + switch (mark) { + case NET1 : + ptnode->LOCON1 = ptlocon; + ptnode->LOCON2 = (struct locon *)NULL; + break; + + case NET2 : + ptnode->LOCON1 = (struct locon *)NULL; + ptnode->LOCON2 = ptlocon; + break; + + default : + fatalerror ("Fatal error on tree construction. (createlocon)"); + } + ptnode->LEFT = ptnode->RIGHT = (locon_tree *)NULL; + + locon_count ++; + if ( (error_count == 0) && ((locon_count&63) == 0)) + printf ("."); + return ( ptnode ); +} + + +/*===========================================================================*/ + int loinscmp (loins1, loins2) +/*===========================================================================*/ +loins_list *loins1, *loins2; + +/* Compares the two names (insname and figname) of the instances loins1 and + loins2. + Returns 0 if equal, 1 if less, and 2 if greater. + If insnames are equals, but fignames not, this function returns -1. It's an + error in the netlist(s). +*/ +{ + int result; + + if ( (loins1 == (loins_list *)NULL) || (loins2 == (loins_list *)NULL) ) + fatalerror ("Fatal error on instances compare. (loinscmp)"); + + if ( (result = strcmp (loins1->INSNAME, loins2->INSNAME)) != 0) + return ( (result < 0) ? 1 : 2 ); + + return ( (loins1->FIGNAME == loins2->FIGNAME) ? 0 : -1 ); + +} + + +/*===========================================================================*/ + int loconcmp (locon, ptnode) +/*===========================================================================*/ +locon_list *locon; +locon_tree *ptnode; +/* + Compares the name of the connector pointed by 'locon' with the name of + the connector pointed by one of LOCON1 and LOCON2 fields in the 'ptnode'. + Returns 0 if equal, 1 if less, and 2 if greater. + Returns -1 on error ( pointer to NULL or irregular instances ). +*/ +{ + locon_list *ptaux; + int result1, result2; + + if ( (locon == (locon_list *)NULL) || (ptnode == (locon_tree *)NULL) ) + return ( -1 ); + + /* find the first locon pointed by the node */ + if (ptnode->LOCON1 != NULL) ptaux = ptnode->LOCON1; + else if (ptnode->LOCON2 != NULL) ptaux = ptnode->LOCON2; + else return ( -1 ); + + /* if names different, return less or greater */ + if ( (result1 = strcmp (locon->NAME, ptaux->NAME)) != 0 ) + return ( (result1 < 0) ? 1 : 2 ); + + /* same names */ + /* if both terminals, return equal */ + if ( (locon->TYPE == EXTERNAL) && (ptaux->TYPE == EXTERNAL) ) return ( 0 ); + + /* if both internal, compare instance names and return that result */ + if ( (locon->TYPE == INTERNAL) && (ptaux->TYPE == INTERNAL) ) + return ( loinscmp (locon->ROOT, ptaux->ROOT) ); + + /* if only one is terminal, return it as greater */ + return ( (locon->TYPE == INTERNAL) ? 1 : 2 ); +} + + +/*===========================================================================*/ + int insertrootlocon (locon, mark) +/*===========================================================================*/ +locon_list *locon; +unsigned char mark; + +/* Inserts the connector pointed by 'locon' with his 'mark' in the Binary + Tree of root connectors, beginning with the 'rootlocon_head' global pointer. + Returns ERR if error on insertion, OK else. +*/ +{ + rootlocon_tree *prev_node, *ptnode, *ptaux; + unsigned char prev_mark; + int compar; + + if (locon == (locon_list *)NULL) + fatalerror ("Fatal error on tree construction. (insertrootlocon)"); + + if (rootlocon_head == NULL) { + rootlocon_head = createrootlocon (locon, mark); + return ( OK ); + } + + ptnode = rootlocon_head; + while ( (ptnode != NULL) && (locon->NAME != ptnode->LOCON->NAME) ) { + prev_node = ptnode; + ptnode = (compar = strcmp(locon->NAME, ptnode->LOCON->NAME)) < 0 ? + ptnode->LEFT : + ptnode->RIGHT; + } + + if (ptnode == NULL) { + ptaux = createrootlocon (locon, mark); + if (compar < 0) prev_node->LEFT = ptaux; + else prev_node->RIGHT = ptaux; + return ( OK ); + } + + prev_mark = ptnode->MARK; + if ( (prev_mark == BOTH) || (prev_mark == mark)) { + /* Error: two connectors with the same name in the same figure */ + error_count ++; + printf ("\n\nTerminal '%s' repeated in the netlist %i.", locon->NAME, mark); + return ( ERR ); + } + + if ( (prev_mark + mark) != (NET1 + NET2) ) + fatalerror ("Fatal error on tree construction. (insertrootlocon)"); + + ptnode->MARK = BOTH; + return ( OK ); +} + + +/*===========================================================================*/ + int insertloins (loins, mark) +/*===========================================================================*/ +loins_list *loins; +unsigned char mark; + +/* Inserts the instance pointed by 'loins' with his 'mark' in the Binary + Tree of instances, beginning with the 'loins_head' global pointer. + Returns ERR if error on insertion, OK else. +*/ +{ + loins_tree *prev_node, *ptnode, *ptaux; + unsigned char prev_mark; + int prev_compar, compar; + + if (loins == (loins_list *)NULL) + fatalerror ("Fatal error on tree construction. (insertloins)"); + + if (loins_head == NULL) { + loins_head = createloins (loins, mark); + return ( OK ); + } + + ptnode = loins_head; + while ( (ptnode != NULL) && ((compar=loinscmp (loins, ptnode->LOINS))>0) ) { + prev_node = ptnode; + prev_compar = compar; + ptnode = (compar == 1) ? ptnode->LEFT : ptnode->RIGHT; + } + + if (ptnode == NULL) { + if (prev_compar <= 0) + fatalerror ("Fatal error on tree construction. (insertloins)"); + + ptaux = createloins (loins, mark); + if (prev_compar == 1) prev_node->LEFT = ptaux; + else prev_node->RIGHT = ptaux; + return ( OK ); + } + + prev_mark = ptnode->MARK; + if (compar == -1) { /* two instances with same insname, but fignames differents */ + if (prev_mark == mark) { /* the two instances are in the same figure */ + error_count ++; + printf ("\n\nInstance '%s' repeated with different fignames in netlist %i:", + loins->INSNAME, mark); + printf ("'%s' and '%s'.", loins->FIGNAME, ptnode->LOINS->FIGNAME); + } + + else { /* one instance in each netlist */ + error_count ++; + printf ("\n\nInstance '%s' has different fignames in each netlist :", + loins->INSNAME); + if (mark == NET1) printf ("\n'%s' in netlist 1 and '%s' in netlist 2.", + loins->FIGNAME, ptnode->LOINS->FIGNAME); + else printf ("\n'%s' in netlist 1 and '%s' in netlist 2.", + ptnode->LOINS->FIGNAME, loins->FIGNAME); + } /* endelse prev_mark */ + return ( ERR ); + } /* endif compar */ + + if ( (prev_mark == BOTH) || (prev_mark == mark) ) { + /* Error : two instances with the same names (insname and figname) in the + same figure */ + error_count ++; + printf ("\n\nInstance '%s' repeated in the netlist %i.", loins->INSNAME, mark); + return ( ERR ); + } + + if ( (prev_mark + mark) != (NET1 + NET2) ) + fatalerror ("Fatal error on tree construction. (insertloins)"); + + ptnode->MARK = BOTH; + return ( OK ); +} + + +/*===========================================================================*/ + int insertlocon (locon, mark) +/*===========================================================================*/ +locon_list *locon; +unsigned char mark; + +/* Inserts the connector pointed by 'locon' in the Binary Tree of connectors, + beginning with the 'locon_head' global pointer. + Returns ERR if error on insertion, OK else. +*/ +{ + locon_tree *prev_node, *ptnode, *ptaux; + int prev_compar, compar; + + if (locon == (locon_list *)NULL) + fatalerror ("Fatal error on tree construction. (insertlocon)"); + + if (locon_head == NULL) { + locon_head = createlocon (locon, mark); + return ( OK ); + } + + ptnode = locon_head; + while ( (ptnode != NULL) && ((compar = loconcmp (locon, ptnode)) > 0) ) { + prev_node = ptnode; + prev_compar = compar; + ptnode = (compar == 1) ? ptnode->LEFT : ptnode->RIGHT; + } + + if (ptnode == NULL) { /* terminal node in the tree */ + ptaux = createlocon (locon, mark); + if (prev_compar == 1) prev_node->LEFT = ptaux; + else prev_node->RIGHT = ptaux; + return ( OK ); + } + + if (compar != 0) fatalerror ("Fatal error on tree construction. (insertlocon)"); + + switch (mark) { /* insert new locon in the current node */ + case NET1 : + if (ptnode->LOCON1 != NULL) { + /* Error : two connectors with the same name in the same figure */ + error_count ++; + printf("\n\nConnector '%s' repeated in the netlist 1.",locon->NAME); + return ( ERR ); + } + ptnode->LOCON1 = locon; + return ( OK ); + + case NET2 : + if (ptnode->LOCON2 != NULL) { + /* Error : two connectors with the same name in the same figure */ + error_count ++; + printf("\n\nConnector '%s' repeated in the netlist 2.",locon->NAME); + return ( ERR ); + } + ptnode->LOCON2 = locon; + return ( OK ); + } + + fatalerror ("Fatal error on tree construction. (insertlocon)"); +} + + +/*===========================================================================*/ + int makerootconnectors (lofig, mark) +/*===========================================================================*/ +lofig_list *lofig; +unsigned char mark; + +/* Constructs (creates or appends) the Binary Tree of root connectors of the + 'lofig' figure, with the 'mark' (NET1 or NET2), beginning with the + 'rootlocon_head' global pointer. + Returns ERR if one of the terminals is irregular, OK else. +*/ +{ + locon_list *ptlocon; + int result = OK; + + if (lofig == (struct lofig *)NULL) { + error_count ++; + printf ("\n\nNetlist %i is empty!\n", mark); + return ( ERR ); + } + + for (ptlocon = lofig->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) + result |= insertrootlocon (ptlocon, mark); + + return ( result ); +} + + +/*===========================================================================*/ + int makeinstances (lofig, mark) +/*===========================================================================*/ +lofig_list *lofig; +unsigned char mark; + +/* Constructs (creates or appends) the Binary Tree of the instances in the + 'lofig' figure, with the 'mark' (NET1 or NET2), beginning with the + 'loins_head' global pointer. + Returns ERR if one of the instances is irregular, OK else. +*/ +{ + loins_list *ptloins; + int result = OK; + + if (lofig == (struct lofig *)NULL) { + error_count ++; + printf ("\n\nNetlist %i is empty!\n", mark); + return ( ERR ); + } + + if (lofig->LOINS == NULL) return ( OK ); + + for (ptloins = lofig->LOINS; ptloins != NULL; ptloins = ptloins->NEXT) + result |= insertloins (ptloins, mark); + + return ( result ); +} + + +/*===========================================================================*/ + int makeconnections (lofig, mark) +/*===========================================================================*/ +lofig_list *lofig; +unsigned char mark; + +/* Constructs (creates or appends) the Binary Tree of all the connectors in the + 'lofig' figure, with the 'mark' (NET1 or NET2), beginning with the + 'locon_head' global pointer. + Returns ERR if one of the connectors is irregular, OK else. +*/ +{ + loins_list *ptloins; + locon_list *ptlocon; + int result = OK; + + if (lofig == (struct lofig*)NULL) { + error_count ++; + printf ("\n\nNetlist %i is empty!\n", mark); + return ( ERR ); + } + + /* terminals */ + for (ptlocon = lofig->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) + result |= insertlocon (ptlocon, mark); + + /* connectors of instances */ + for (ptloins = lofig->LOINS; ptloins != NULL; ptloins = ptloins->NEXT) + for (ptlocon = ptloins->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) + result |= insertlocon (ptlocon, mark); + + return ( result ); +} + + +/*===========================================================================*/ + int checkrootlocontree (ptnode) +/*===========================================================================*/ +rootlocon_tree *ptnode; + +/* check recursively if all the marks of the tree pointed by 'ptnode' are BOTH. + Returns OK if all are BOTH, ERR else. +*/ +{ + int checkleft, checkright; + + if (ptnode == NULL) return ( OK ); + + switch (ptnode->MARK) { + case BOTH : + /* this terminal is present in the two figures, continue */ + checkleft = checkrootlocontree (ptnode->LEFT); + checkright = checkrootlocontree (ptnode->RIGHT); + return ( ((checkleft == OK) && (checkright == OK)) ? OK : ERR ); + + case NET1 : + /* this terminal is not in the figure 2, continue */ + error_count ++; + printf ("\nTerminal '%s' only in netlist 1", ptnode->LOCON->NAME); + checkrootlocontree (ptnode->LEFT); + checkrootlocontree (ptnode->RIGHT); + return ( ERR ); + + case NET2 : + /* this terminal is not in the figure 1, continue */ + error_count ++; + printf ("\nTerminal '%s' only in netlist 2", ptnode->LOCON->NAME); + checkrootlocontree (ptnode->LEFT); + checkrootlocontree (ptnode->RIGHT); + return ( ERR ); + } + + fatalerror ("Fatal error on Terminals Tree checking. (checkrootlocontree)"); +} + + +/*===========================================================================*/ + int checkloinstree (ptnode) +/*===========================================================================*/ +loins_tree *ptnode; + +/* check recursively if all the marks of the tree pointed by 'ptnode' are BOTH. + Returns OK if all are BOTH, ERR else. +*/ +{ + int checkleft, checkright; + + if (ptnode == NULL) return ( OK ); + + switch (ptnode->MARK) { + case BOTH : + /* this instance is present in the two figures, continue */ + checkleft = checkloinstree (ptnode->LEFT); + checkright = checkloinstree (ptnode->RIGHT); + return ( ((checkleft == OK) && (checkright == OK)) ? OK : ERR ); + + case NET1 : + /* this instance is not in the figure 2, continue */ + error_count ++; + printf ("\nInstance '%s' only in netlist 1", ptnode->LOINS->INSNAME); + checkloinstree (ptnode->LEFT); + checkloinstree (ptnode->RIGHT); + return ( ERR ); + + case NET2 : + /* this instance is not in the figure 1, continue */ + error_count ++; + printf ("\nInstance '%s' only in netlist 2", ptnode->LOINS->INSNAME); + checkloinstree (ptnode->LEFT); + checkloinstree (ptnode->RIGHT); + return ( ERR ); + } + + fatalerror ("Fatal error on Instances Tree checking. (checkloinstree)"); +} + + +/*===========================================================================*/ + mylofigchain (lofig) +/*===========================================================================*/ +lofig_list *lofig; + +/* Same as lofigchain function, but with additionnal error tests about pointers, + and without transistors list. +*/ +{ +locon_list *ptcon = NULL; +losig_list *ptsig = NULL; +loins_list *ptins = NULL; +ptype_list *ptype = NULL; + + if (lofig->MODE != 'A') + fatalerror ("Fatal error on 'mylofigchain': figure is interface only"); + +/* cleaning ... */ + for (ptsig = lofig->LOSIG; ptsig != NULL; ptsig = ptsig->NEXT) { + ptype = getptype (ptsig->USER, (long)LOFIGCHAIN); + if (ptype != (ptype_list *)NULL) { + freechain ((chain_list *)ptype->DATA); + ptype->DATA = (void *)NULL; + } + else ptsig->USER = addptype (ptsig->USER, (long)LOFIGCHAIN, (void *)NULL); + } + +/* scan connector list */ + for (ptcon = lofig->LOCON; ptcon != NULL; ptcon = ptcon->NEXT) { + ptsig = ptcon->SIG; + if ( (ptype = getptype (ptsig->USER, (long)LOFIGCHAIN)) == NULL ) { + (void)fprintf (stderr, "\nInvalid signal on terminal %s (%s)", + ptcon->NAME, lofig->NAME); + fatalerror ("Fatal error on 'mylofigchain'"); + } + ptype->DATA = (void *)addchain ((chain_list *)ptype->DATA, (void*)ptcon); + } + +/* scan instance list */ + for (ptins = lofig->LOINS; ptins != NULL; ptins = ptins->NEXT) + for (ptcon = ptins->LOCON; ptcon != NULL; ptcon = ptcon->NEXT) { + ptsig = ptcon->SIG; + if ( (ptype = getptype (ptsig->USER, (long)LOFIGCHAIN)) == NULL ) { + (void)fprintf (stderr, "\nInvalid signal on connector %s of %s (%s)", + ptcon->NAME, ptins->INSNAME, lofig->NAME); + fatalerror ("Fatal error on 'mylofigchain'"); + } + ptype->DATA = (void *)addchain ((chain_list *)ptype->DATA,(void *)ptcon); + } /* endfor ptcon */ +} + + +/*===========================================================================*/ + locon_list *findlocon (locon, mark) +/*===========================================================================*/ +locon_list *locon; +unsigned char mark; + +/* Searchs in the Tree of all connectors the node corresponding to the 'locon', + and returns the pointer to the locon in the opposite figure. 'mark' is the + mark of the figure for the given locon. + Returns NULL if not found. +*/ +{ + locon_tree *ptnode; + int compar; + + ptnode = locon_head; + + while ( (ptnode != NULL) && ((compar = loconcmp (locon, ptnode)) > 0) ) + ptnode = (compar == 1) ? ptnode->LEFT : ptnode->RIGHT; + + /* not found */ + if ( ptnode == NULL ) return ( (locon_list *)NULL ); + + /* error on tree scanning */ + if (compar != 0) fatalerror ("Fatal error on tree construction. (findlocon)"); + + /* return opposite locon */ + return ( (mark == NET1) ? ptnode->LOCON2 : ptnode->LOCON1 ); +} + + +/*===========================================================================*/ + char *findrootname (locon) +/*===========================================================================*/ +locon_list *locon; + +/* Returns a char pointer to the name of the object it belongs to. + If 'locon' is INTERNAL, returns INSNAME of instance, + if 'locon' is EXTERNAL, returns NAME of figure, + else fatal error. +*/ +{ + switch (locon->TYPE) { + case INTERNAL : + return ( ((loins_list *)(locon->ROOT))->INSNAME ); + case EXTERNAL : + return ( ((lofig_list *)(locon->ROOT))->NAME ); + } + + fatalerror ("Fatal error on mbk structure: Illegal connector"); +} + + +/*===========================================================================*/ + int checkconnections (lofig, mark) +/*===========================================================================*/ +lofig_list *lofig; +unsigned char mark; + +/* + Checks that all the signals in the figure 'lofig' have same connectors in the + opposite figure. + Two types of error: + - the structure is not correct (invalid or inexistent pointers, bad lofigchain), + Stop on fatal error. + - the netlists are not identical (different signals in each netlist for one + connector, inexistent signal or connector), set the 'result' flag to ERR but + continue to find other errors, or other connectors for the same error. +*/ +{ + losig_list *ptlosig; + long int losig_count = 0; + int result = OK; + + if (lofig == (struct lofig *)NULL) { + error_count ++; + printf ("\n\nNetlist %i is empty!\n", mark); + return ( ERR ); + } + for (ptlosig = lofig->LOSIG; ptlosig != NULL; ptlosig = ptlosig->NEXT) { + ptype_list *ptype; + chain_list *ptchain; + locon_list *firstlocon, *ptlocon, *firstopplocon, *ptopplocon; + losig_list *ptequip; + + if ( (error_count == 0) && ((losig_count&63) == 0) ) { + printf ("."); + losig_count++; + } + ptype = getptype (ptlosig->USER, (long)LOFIGCHAIN); + if (ptype == NULL) { + (void)fprintf (stderr, + "\n\nInvalid ptype pointer for signal %s in netlist %i", + getsigname(ptlosig), mark); + fatalerror ("Fatal error on 'checkconnections'"); + } +/* + ptchain = (chain_list *)(ptype->DATA); + if (ptchain == NULL) { + (void)fprintf (stderr, "\n\nInvalid signal %s on netlist %i", + getsigname(ptlosig), mark); + fatalerror ("Fatal error on 'checkconnections'"); + } +*/ +/* + ptchain = (chain_list *)(ptype->DATA); + if (ptchain == NULL) { + if (strcmp(getsigname(ptlosig),"bulk")!=0) printf ("\nWarning: Signal %s without connector on netlist %i\n", + getsigname(ptlosig), mark); + continue; + } +*/ + ptchain = (chain_list *)(ptype->DATA); + if (ptchain == NULL) { + unusig_flag = TRUE; + continue; + } + + firstlocon = (locon_list *)(ptchain->DATA); + /* find equivalent locon in opposite figure */ + firstopplocon = findlocon ( firstlocon, mark); + if (firstopplocon == NULL) { + error_count ++; + printf ("\n\nConnector %s of '%s' (signal %s) in netlist %i", + firstlocon->NAME, findrootname (firstlocon), + getsigname(ptlosig), mark); + printf (" NOT found in netlist %i", (NET1+NET2-mark)); + result = ERR; + continue; + } + + /* read signal of opposite locon */ + ptequip = firstopplocon->SIG; + if (ptequip == NULL) { + error_count ++; + printf ("\nConnector '%s' without signal in netlist %i", + firstopplocon->NAME, (NET1+NET2-mark)); + result = ERR; + continue; + } + + /* for all other connectors of same signal : find it in opposite */ + for (ptchain = ptchain->NEXT; ptchain != NULL; ptchain = ptchain->NEXT) { + losig_list *ptsigfound; + + ptlocon = (locon_list *)(ptchain->DATA); + ptopplocon = findlocon ( ptlocon, mark); + if (ptopplocon == NULL) { + error_count ++; + printf ("\n\nConnector %s of '%s' (signal %s) in netlist %i", + ptlocon->NAME, findrootname (ptlocon), + getsigname(ptlosig), mark); + printf (" NOT found in netlist %i", (NET1+NET2-mark)); + result = ERR; + continue; + } + ptsigfound = ptopplocon->SIG; + if (ptsigfound == NULL) { + error_count ++; + printf ("\n\nConnector '%s' without signal in netlist %i", + ptopplocon->NAME, mark); + result = ERR; + } + else if (ptopplocon->SIG != ptequip) { + if (mark == NET1) { + error_count ++; + printf ("\n\n%s of '%s' is NOT connected to %s of '%s' in netlist 2", + ptopplocon->NAME, findrootname(ptopplocon), + firstopplocon->NAME, findrootname(firstopplocon)); + printf ("\nthrough signal %s but to signal %s", + getsigname(ptequip), getsigname(ptopplocon->SIG)); + } + else { /* short circuit */ + error_count ++; + printf ("\n\n%s of '%s' IS connected to %s of '%s' in netlist 2", + ptopplocon->NAME, findrootname(ptopplocon), + firstopplocon->NAME, findrootname(firstopplocon)); + printf ("\nthrough signal %s", + getsigname(firstlocon->SIG)); + } + result = ERR; + } /* endelse ptsigfound */ + } /* endfor ptchain */ + } /* endfor ptlosig */ + + return ( result ); +} + + +/*===========================================================================*/ + int comparerootconnectors (lofig1, lofig2) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; + +/* Calls the tree-construction and checking functions. + Returns OK if terminals are equivalent, ERR else. +*/ +{ + rootlocon_tree *ptnode; + int result; + + rootlocon_time = time( (long *)0 ); + + if ( makerootconnectors (lofig1, NET1) != OK ) return ( ERR ); + if ( makerootconnectors (lofig2, NET2) != OK ) return ( ERR ); + + result = checkrootlocontree (rootlocon_head); + + rootlocon_time = time( (long *)0 ) - rootlocon_time; + return ( result ); +} + + +/*===========================================================================*/ + int compareinstances (lofig1, lofig2) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; + +/* Calls the tree-construction and checking functions. + Returns OK if instances are equivalent, ERR else. +*/ +{ + int result; + + loins_time = time( (long *)0 ); + + if ( makeinstances (lofig1, NET1) != OK ) return ( ERR ); + if ( makeinstances (lofig2, NET2) != OK ) return ( ERR ); + + result = checkloinstree (loins_head); + + loins_time = time( (long *)0 ) - loins_time; + return ( result ); +} + + +/*===========================================================================*/ + int compareconnections (lofig1, lofig2) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; + +/* Constructs the Binary Tree of all connectors in the figure, and check that + all signals are connected to the same connectors in the two figures. + Returns OK if equivalent, ERR else. +*/ +{ + int result1, result2; + + locon_time = time( (long *)0 ); + + result1 = makeconnections (lofig1, NET1); + result2 = makeconnections (lofig2, NET2); + + if ( (result1 != OK) || (result2 != OK) ) return ( ERR ); + + mylofigchain ( lofig1 ); + mylofigchain ( lofig2 ); + + result1 = checkconnections (lofig1, NET1); + result2 = checkconnections (lofig2, NET2); + + locon_time = time( (long *)0 ) - locon_time; + return ( ((result1 == OK) && (result2 == OK)) ? OK : ERR ); +} + + +/*===========================================================================*/ + int compareunusedsignals (lofig1, lofig2) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; + +/* +*/ +{ + losig_list *ptlosig; + int result = OK; + + if (lofig1 == (struct lofig *)NULL) { + error_count ++; + printf ("\n\nNetlist 1 is empty!\n"); + return ( ERR ); + } + if (lofig2 == (struct lofig *)NULL) { + error_count ++; + printf ("\n\nNetlist 2 is empty!\n"); + return ( ERR ); + } + + for (ptlosig = lofig1->LOSIG; ptlosig != NULL; ptlosig = ptlosig->NEXT) { + ptype_list *ptype; + chain_list *ptchain; + losig_list *opplosig; + + ptype = getptype (ptlosig->USER, (long)LOFIGCHAIN); + if (ptype == NULL) { + (void)fprintf (stderr, + "\n\nInvalid ptype pointer for signal %s in netlist 1", + getsigname(ptlosig)); + fatalerror ("Fatal error on 'checkunusedsignals'"); + } + + ptchain = (chain_list *)(ptype->DATA); + if (ptchain == NULL) { + char *signame; + int found = FALSE; + + signame = getsigname(ptlosig); + + for (opplosig = lofig2->LOSIG; opplosig != NULL; opplosig = opplosig->NEXT) + if (getsigname(opplosig) == signame) found = TRUE; + if (found == FALSE) { + error_count ++; + printf ("\n\nNever assigned signal %s in netlist 1", + signame); + printf (" NOT found in netlist 2"); + result = ERR; + } + else + if (strcmp(signame,"bulk")!=0) + printf ("\nWarning: Never assigned signal %s in the 2 netlists\n", signame); + + } + } + + return ( result ); +} + + +/*===========================================================================*/ + int comparelofigs (lofig1, lofig2) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; + +/* Compare two logical figures (three phases if necessary). + Returns OK if the netlists are equivalent, ERR else. +*/ +{ + int result1, result2, result3, result4; + + if (lofig1 == (struct lofig *)NULL) { + error_count ++; + printf ("\n\nNetlist 1 is empty!\n"); + return ( ERR ); + } + if (lofig2 == (struct lofig *)NULL) { + error_count ++; + printf ("\n\nNetlist 2 is empty!\n"); + return ( ERR ); + } + + printf ("\n\n\n***** Compare Terminals .........."); + if ((result1 = comparerootconnectors (lofig1, lofig2)) == OK) + printf ("\n***** O.K.\t(%lu sec)", rootlocon_time); + + printf ("\n\n***** Compare Instances .........."); + if ((result2 = compareinstances (lofig1, lofig2)) == OK) + printf ("\n***** O.K.\t(%lu sec)", loins_time); + + if ((result1 != OK) || (result2 != OK)) return ( ERR ); + + printf ("\n\n***** Compare Connections ........"); + if ((result3 = compareconnections (lofig1, lofig2)) == OK) + printf ("\n***** O.K.\t(%lu sec)", locon_time); + + if (unusig_flag == TRUE) { + printf ("\n\n***** Compare Connectionless signals ........"); + if ((result4 = compareunusedsignals (lofig1, lofig2)) == OK) + printf ("\n***** O.K."); + } + else result4 = OK; + + printf ("\n\n===== Terminals .......... %-6lu\n", rootlocon_count); + printf ( "===== Instances .......... %-6lu\n", loins_count); + printf ( "===== Connectors ......... %-6lu\n", locon_count); + if (error_count) printf ( "\n===== Errors ............. %i\n", error_count); + + if ( (result3 == OK) && (result4 == OK)) return ( OK ); + else return ( ERR ); + } + + +/*===========================================================================*/ +void equivterminal (lofig, name1, name2, delete) +/*===========================================================================*/ +lofig_list *lofig; +char *name1, *name2; +int delete; + +/* Reduces the first (normally single) terminal called 'name1' to 'name2'. + All the connectors connected to terminal 'name1' are now connected to the + first 'name2' (could be internal or external, priority to external). + Stops if impossible, and returns (without error code) if OK. +*/ +{ + loins_list *ptloins; + locon_list *ptlocon, *ptaux; + locon_list *reflocon = NULL; + losig_list *oldlosig, *reflosig; + int found = FALSE; + + if (lofig == NULL) fatalerror ("Invalid figure. (equivterminal)"); + if ( (name1 == NULL) || (name2 == NULL) ) + fatalerror ("Invalid connector name. (equivterminal)"); + + name1 = namealloc (name1); + name2 = namealloc (name2); +/* Search name2 in terminals */ + for (ptlocon = lofig->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) + if (ptlocon->NAME == name2) break; + + reflocon = ptlocon; + if (reflocon == NULL) { /* Search name2 in internal connectors */ + for (ptloins = lofig->LOINS; (ptloins != NULL) && (found != TRUE); + ptloins = ptloins->NEXT) + for (ptlocon = ptloins->LOCON; (ptlocon != NULL) && (found != TRUE); + ptlocon = ptlocon->NEXT) + if (ptlocon->NAME == name2) { + found = TRUE; + reflocon = ptlocon; + } + } + + if (reflocon == NULL) { + (void)fprintf (stderr, "\n\nConnector %s NOT found in %s", name2, lofig->NAME); + fatalerror ("Fatal error in 'equivterminal'"); + } + + reflosig = reflocon->SIG; + if (reflosig == NULL) { + (void)fprintf (stderr, "\n\nInvalid signal for connector %s in %s", + reflocon->NAME, lofig->NAME); + fatalerror ("Fatal error in 'equivterminal'"); + } + +/* Search and reduce name1 in terminals */ + for (ptlocon = lofig->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) + if (ptlocon->NAME == name1) { /* found name1 */ + oldlosig = ptlocon->SIG; + if (oldlosig == NULL) { + (void)fprintf (stderr, "\n\nInvalid signal for connector %s in %s", + ptlocon->NAME, lofig->NAME); + fatalerror ("Fatal error in 'equivterminal'"); + } + /* branch all the connectors connected to name1 to name2 (ref) */ + for (ptaux = lofig->LOCON; ptaux != NULL; ptaux = ptaux->NEXT) + if ((ptaux != ptlocon)&&(ptaux->SIG == oldlosig)) ptaux->SIG = reflosig; + + for (ptloins = lofig->LOINS; ptloins != NULL; ptloins = ptloins->NEXT) + for (ptaux = ptloins->LOCON; ptaux != NULL; ptaux = ptaux->NEXT) + if ((ptaux != ptlocon)&&(ptaux->SIG == oldlosig)) ptaux->SIG = reflosig; + + if (oldlosig != reflosig) + if (dellosig (lofig, oldlosig->INDEX) != 1) + fatalerror ("Fatal error on signal deleting. (equivterminal)"); + + if (delete) + { + if (dellocon (lofig, name1) != 1) + fatalerror ("Fatal error on connector deleting. (equivterminal)"); + } + + break; + } +} + + +/*===========================================================================*/ +void equivinslocon (lofig, loins, name1, name2) +/*===========================================================================*/ +lofig_list *lofig; +loins_list *loins; +char *name1, *name2; + +/* Reduces the first connector called 'name1' to 'name2'. + All the connectors connected to 'name1' are now connected to 'name2', in the + instance pointed by 'loins'. + Stops if impossible, and returns (without error code) if OK. +*/ +{ + loins_list *ptloins; + locon_list *ptlocon, *ptaux, *prevlocon; + locon_list *reflocon = NULL; + losig_list *oldlosig, *reflosig; + int found = FALSE; + + if (lofig == NULL) fatalerror ("Invalid figure. (equivinslocon)"); + if (loins == NULL) fatalerror ("Invalid instance. (equivinslocon)"); + if ( (name1 == NULL) || (name2 == NULL) ) + fatalerror ("Invalid connector name. (equivinslocon)"); + + name1 = namealloc (name1); + name2 = namealloc (name2); +/* Search name2 */ + for (ptlocon = loins->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) + if (ptlocon->NAME == name2) break; + + reflocon = ptlocon; + if (reflocon == NULL) { + (void)fprintf (stderr, "\n\nConnector %s NOT found in %s of %s", + name2, loins->INSNAME, lofig->NAME); + fatalerror ("Fatal error in 'equivinslocon'"); + } + + reflosig = reflocon->SIG; + if (reflosig == NULL) { + (void)fprintf (stderr, "\n\nInvalid signal for connector %s in %s of %s", + reflocon->NAME, loins->INSNAME, lofig->NAME); + fatalerror ("Fatal error in 'equivinslocon'"); + } + +/* Search and reduce name1 */ + prevlocon = NULL; + for (ptlocon = loins->LOCON; ptlocon != NULL; prevlocon = ptlocon, + ptlocon = ptlocon->NEXT) + if (ptlocon->NAME == name1) { /* found name1 */ + oldlosig = ptlocon->SIG; + if (oldlosig == NULL) { + (void)fprintf (stderr, "\n\nInvalid signal for connector %s in %s", + ptlocon->NAME, loins->INSNAME); + fatalerror ("Fatal error in 'equivinslocon'"); + } + /* branch all the connectors connected to name1 to name2 (ref) */ + for (ptaux = lofig->LOCON; ptaux != NULL; ptaux = ptaux->NEXT) + if ((ptaux != ptlocon)&&(ptaux->SIG == oldlosig)) ptaux->SIG = reflosig; + + for (ptloins = lofig->LOINS; ptloins != NULL; ptloins = ptloins->NEXT) + for (ptaux = ptloins->LOCON; ptaux != NULL; ptaux = ptaux->NEXT) + if ((ptaux != ptlocon)&&(ptaux->SIG == oldlosig)) ptaux->SIG = reflosig; + + if (oldlosig != reflosig) if (dellosig (lofig, oldlosig->INDEX) != 1) + fatalerror ("Fatal error on signal deleting. (equivinslocon)"); + + if (prevlocon == NULL) loins->LOCON = ptlocon->NEXT; + else prevlocon->NEXT = ptlocon->NEXT; + break; + } +} + + +/*=========================================================================== + startid ( lofig, name1, name2) + +lofig_list *lofig; +char *name1, *name2; +{ + locon_list *ptlocon; + + if ( (name1 == NULL) || (name2 == NULL) ) + fatalerror ("Invalid connector name. (startid)"); + + name1 = namealloc (name1); + name2 = namealloc (name2); + if (name1 == name2) return; + for (ptlocon = lofig->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) + if (ptlocon->NAME == name2) ptlocon->NAME = name1; +} +===========================================================================*/ + + +/*===========================================================================*/ + localstartid ( ptlocon, name1, name2) +/*===========================================================================*/ +locon_list *ptlocon; +char *name1, *name2; + +/* All the connectors in the list beginning with 'ptlocon' named by 'name2' + are renamed by 'name1'. +*/ +{ + + if ( (name1 == NULL) || (name2 == NULL) ) + fatalerror ("Invalid connector name. (localstartid)"); + + name1 = namealloc (name1); + name2 = namealloc (name2); + if (name1 == name2) return; + for (; ptlocon != NULL; ptlocon = ptlocon->NEXT) + if (ptlocon->NAME == name2) ptlocon->NAME = name1; +} + + +/*===========================================================================*/ + reducepower (lofig1, lofig2) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; + +/* Deletes all the connectors (internal or external) beginning with 'vdd' or + 'vss', except one which is renamed by 'vdd' (or 'vss'). + All the connectors in the figure connected to 'vdd*' (or 'vss*') are now + connected to the last 'vdd' (or 'vss'). + Stops on error, returns without error code if OK. +*/ +{ + chain_list *Delete; + chain_list *ScanChain; + locon_list *ptlocon; + locon_list *next_locon; +char *firstvdd; +char *firstvss; + loins_list *ptloins; + + printf ("\n\n***** Reduce Power ..............."); + power_time = time( (long *)0 ); + power_count = 0; + +/* vdd */ + /* instance connectors */ + for (ptloins = lofig1->LOINS; ptloins != NULL; ptloins = ptloins->NEXT) { + power_count ++; + if((power_count&63) == 0 ) printf ("."); + firstvdd = NULL; + for (ptlocon = ptloins->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) { + if (firstvdd == NULL) { + if (isvdd (ptlocon->NAME)) firstvdd = ptlocon->NAME; + continue; + } + if (isvdd (ptlocon->NAME)) + equivinslocon (lofig1, ptloins, ptlocon->NAME, firstvdd); + } + if ( (firstvdd != NULL) && (firstvdd != namealloc (VDD)) ) + localstartid (ptloins->LOCON, VDD, firstvdd); + } + + /* terminals */ + firstvdd = NULL; + Delete = NULL; + for (ptlocon = lofig1->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) { + power_count ++; + if((power_count&63) == 0 ) printf ("."); + if (firstvdd == NULL) { + if ( isvdd (ptlocon->NAME)) firstvdd = ptlocon->NAME; + continue; + } + if (isvdd (ptlocon->NAME)) + { + equivterminal (lofig1, ptlocon->NAME, firstvdd, 0); + Delete = addchain( Delete, ptlocon ); + } + } + + if ( (firstvdd != NULL) && (firstvdd != namealloc (VDD)) ) + localstartid (lofig1->LOCON, VDD, firstvdd); + + for ( ScanChain = Delete; ScanChain != NULL; ScanChain = ScanChain->NEXT ) + { + ptlocon = (locon_list *)ScanChain->DATA; + dellocon( lofig1, ptlocon->NAME ); + } + + freechain( Delete ); + Delete = NULL; + +/* vss */ + /* instance connectors */ + for (ptloins = lofig1->LOINS; ptloins != NULL; ptloins = ptloins->NEXT) { + power_count ++; + if((power_count&63) == 0 ) printf ("."); + firstvss = NULL; + for (ptlocon = ptloins->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) { + if (firstvss == NULL) { + if (isvss (ptlocon->NAME)) firstvss = ptlocon->NAME; + continue; + } + if (isvss (ptlocon->NAME)) + equivinslocon (lofig1, ptloins, ptlocon->NAME, firstvss); + } + if ( (firstvss != NULL) && (firstvss!= namealloc (VSS)) ) + localstartid (ptloins->LOCON, VSS, firstvss); + } + + /* terminals */ + firstvss = NULL; + for (ptlocon = lofig1->LOCON; ptlocon != NULL; ptlocon = ptlocon->NEXT) { + power_count ++; + if((power_count&63) == 0 ) printf ("."); + if (firstvss == NULL) { + if (isvss (ptlocon->NAME)) firstvss = ptlocon->NAME; + continue; + } + if (isvss (ptlocon->NAME)) + { + equivterminal (lofig1, ptlocon->NAME, firstvss, 0); + Delete = addchain( Delete, ptlocon ); + } + } + + if ( (firstvss != NULL) && (firstvss!= namealloc (VSS)) ) + localstartid (lofig1->LOCON, VSS, firstvss); + + for ( ScanChain = Delete; ScanChain != NULL; ScanChain = ScanChain->NEXT ) + { + ptlocon = (locon_list *)ScanChain->DATA; + dellocon( lofig1, ptlocon->NAME ); + } + + freechain( Delete ); + Delete = NULL; + + power_time = time( (long *)0 ) - power_time; + printf ("\n***** O.K. (%lu sec)", power_time); +} + + +/*===========================================================================*/ + locon_list *orderlocon (list1, list2) +/*===========================================================================*/ +locon_list *list1, *list2; + +/* Reorders the connector list 'list2' seeking 'list1'. + Returns the new head of 'list2', or stops if error. +*/ +{ + locon_list *head, *headlist2; + locon_list *reflocon, *ptlocon, *prevlocon; + static long int count; + + if ( (list1 == NULL) || (list2 == NULL) ) + fatalerror ("Invalid connector lists. (orderlocon)"); + + head = NULL ; + headlist2 = list2 ; + for( reflocon = list1 ; reflocon != NULL ; reflocon = reflocon->NEXT ) { + prevlocon = NULL ; + for( ptlocon = headlist2 ; ptlocon != NULL ; ptlocon = ptlocon->NEXT ) { + count ++; + if ((count&63) == 0) printf ("."); + if( ptlocon->NAME == reflocon->NAME ) { + if( headlist2 == ptlocon ) headlist2 = ptlocon->NEXT ; + else prevlocon->NEXT = ptlocon->NEXT ; + ptlocon->NEXT = head ; + head = ptlocon ; + break ; + } + prevlocon = ptlocon ; + } + + if( ptlocon == NULL ) { + (void)fprintf (stderr, "Connector %s of '%s' NOT found in netlist2", + reflocon->NAME, findrootname (reflocon)); + fatalerror ("Fatal error in 'orderlocon'"); + } + } + return ((locon_list *)reverse((chain_list *)head)); +} + + +/*===========================================================================*/ + order (lofig1, lofig2) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; + +/* Calls orderlocon() function, for terminals and for instances connectors of + lofig2 (referring to model figures). + Stops on fatal error, returns without error code if OK. +*/ +{ + loins_list *ptloins; + long int order_time; + + printf ("***** Orderring ..................."); + + order_time = time( (long *)0 ); + + if (lofig1 == (struct lofig *)NULL) { + (void)fprintf (stderr, "\nNetlist 1 is empty!"); + fatalerror ("Fatal error in 'order'"); + } + if (lofig2 == (struct lofig *)NULL) { + (void)fprintf (stderr, "\nNetlist 2 is empty!"); + fatalerror ("Fatal error in 'order'"); + } + +/* order terminals */ + if ( (lofig2->LOCON = orderlocon (lofig1->LOCON, lofig2->LOCON)) == NULL ) { + (void)fprintf (stderr, "\nCan not order terminals of '%s'", lofig2->NAME); + fatalerror ("Fatal error in 'order'"); + } + +{ struct chain *mchain; + for(mchain=lofig2->MODELCHAIN;mchain!=NULL;mchain=mchain->NEXT) + if(mchain->DATA!=(void *)lofig2->NAME && mchain->DATA!=(void *)lofig1->NAME) + dellofig((char *)mchain->DATA); +} +{ struct chain *mchain; + for(mchain=lofig1->MODELCHAIN;mchain!=NULL;mchain=mchain->NEXT) + if(mchain->DATA!=(void *)lofig2->NAME && mchain->DATA!=(void *)lofig1->NAME) + dellofig((char *)mchain->DATA); +} + +/* order instances connectors */ + for (ptloins = lofig2->LOINS; ptloins != NULL; ptloins = ptloins->NEXT) { + lofig_list *ptmodel; + + if ( (ptmodel = getlofig (ptloins->FIGNAME, 'P'))== NULL ) { + (void)fprintf (stderr, + "\nModel %s NOT found in netlist 1", ptloins->FIGNAME); + fatalerror ("Fatal error in 'order'"); + } + if ((ptloins->LOCON = orderlocon(ptmodel->LOCON,ptloins->LOCON)) == NULL) { + (void)fprintf (stderr, + "\nCan not order connectors of '%s'",ptloins->INSNAME); + fatalerror ("Fatal error in 'order'"); + } + } + + order_time = time( (long *)0 ) - order_time; + printf ("\n***** O.K. (%lu sec)\n\n", order_time); +} + + +/*===========================================================================*/ + lofig_list *loadfigure (format, figname, flag_flatten) +/*===========================================================================*/ +char *format; +char *figname; +int flag_flatten; + +/* Load a figure in memory, and calls rflattenlofig(). + Returns a pointer to the figure, or Stops if error. +*/ +{ + lofig_list *ptlofig; + + if ( (format == NULL) || (figname == NULL) ) return ( NULL ); + + printf ("\n\n***** Loading%s %s (%s)...", + flag_flatten==TRUE?" and flattening":"",figname, format); + strcpy ( IN_LO, format); + ptlofig = getlofig (figname, 'A'); + + if (flag_flatten == TRUE) +/* 92/11/27 + * The rflatten keep the models in memory. First lvx loads an .al and then + * an .alx. The two instance sould not have the same interface, so the + * models must be destroyed of memory. + * + rflattenlofig (ptlofig, 'Y', 'Y'); + */ +{ +lofig_list *ptfig =ptlofig; +char concat='Y'; +char catal='Y'; + +loins_list *p; +chain_list *c; + + catal = catal == NO ? 0 : 1; + for (p = ptfig->LOINS; p != NULL;) { + if (!catal || !incatalog(p->FIGNAME)) { + dellofig(p->FIGNAME); + flattenlofig(ptfig, p->INSNAME, concat); + p = ptfig->LOINS; + } + else + p = p->NEXT; + } + freechain(ptfig->MODELCHAIN); + ptfig->MODELCHAIN = NULL; + p = ptfig->LOINS; + while (p != NULL) { + c = ptfig->MODELCHAIN; + while (c != NULL) { + if ((char *)c->DATA == p->FIGNAME) + break; + c = c->NEXT; + } + if (c == NULL) + ptfig->MODELCHAIN = addchain(ptfig->MODELCHAIN, (void *)p->FIGNAME); + p = p->NEXT; + } +} + + return ( ptlofig ); +} + + +/*===========================================================================*/ + void delfeed (lofig) +/*===========================================================================*/ +lofig_list *lofig; +{ + loins_list *loins, *temploins; + + for (loins = lofig->LOINS; loins != NULL; loins = temploins) { + temploins = loins->NEXT; + if (incatalogfeed(loins->FIGNAME)) + if (delloins (lofig, loins->INSNAME) != 1) + fatalerror ("Fatal error on instance deleting. (delins)"); + } +} + + +/*===========================================================================*/ + void delins (lofig, loinsname) +/*===========================================================================*/ +lofig_list *lofig; +char *loinsname; + +/* Deletes the instance named by 'loinsname' in the figure 'lofig'. + Returns if OK, stops else. +*/ +{ + loins_list *loins, *temploins; + char *ptname; + + ptname = namealloc (loinsname); + for (loins = lofig->LOINS; loins != NULL; loins = temploins) { + temploins = loins->NEXT; + if (loins->FIGNAME == ptname) + if (delloins (lofig, loins->INSNAME) != 1) + fatalerror ("Fatal error on instance deleting. (delins)"); + } +} + + +/*===========================================================================*/ + readparamfile (lofig1, lofig2, filename) +/*===========================================================================*/ +lofig_list *lofig1, *lofig2; +char *filename; + +/* Reads filename and calls 'equivterminal()'. +*/ +{ + FILE *paramfile; + static char locon1[10]; + static char locon2[10]; + static char str[10]; + int netlist; + int code = 3; + + if ((paramfile = fopen (filename, "r")) == NULL) { + (void)fprintf (stderr, "\nCan not open '%s'.\n", filename); + fatalerror ("Fatal error on reading paramfile"); + } + + for (;;) { + code = fscanf (paramfile, "equiv %s %s => %s\n", str, locon1, locon2); + if (code != 3) break; + sscanf ( str, "%i", &netlist); + if ( (netlist != NET1) && (netlist != NET2) ) { + (void)fprintf (stderr, "\nInvalid netlist %s in %s", str, filename); + fatalerror ("Fatal error on reading paramfile"); + } + equivterminal ( (netlist == NET1) ? lofig1 : lofig2, locon1, locon2, 1); + } + + fclose (paramfile); +} + + +/*===========================================================================*/ + presentation () +/*===========================================================================*/ +{ char revision[100] ; + + sscanf( rcsid, "$Id: lvx.c,v %s", revision ) ; + + alliancebanner("LVX",revision,"Gate Netlist Comparator","1992","5.0"); + +} + + +/*****************************************************************************/ + void lvx_exit() +/*****************************************************************************/ +{ + exit (exitcode); +} + +/*****************************************************************************/ + main (argc, argv) +/*****************************************************************************/ +int argc; +char **argv; + +/* Loads figures, calls comparefigures(), orders if demanded. +*/ +{ + static char figname1 [100], figname2 [100]; + lofig_list *lofig1 = NULL, *lofig2 = NULL; + int firstcount = 4, count = 4, flag_flatten = FALSE, flag_ord = FALSE, flag_tie = TRUE; + int result; + + presentation (); + + if (argc < 5) { + printf ("\nUsage : lvx [-a] [-o] [-f]\n"); + printf ( " [-i ] [-t ...]\n\n"); + exit (2); + } + signal (SIGTERM, lvx_exit); + mbkenv (); + + while (++firstcount < argc) { char *option; + option = argv[firstcount]; + if (option[0] == '-') if (option[1] == 'f') flag_flatten = TRUE; + } + + if ( (lofig1 = loadfigure (argv[1], argv[3], flag_flatten)) == NULL ) { + (void)fprintf (stderr, "\n!!!!! Can not load '%s'\n", argv[3]); + fatalerror ("Fatal error on loading figure"); + } + sprintf (figname1, "%s_logic", argv[3]); + lofig1->NAME = namealloc (figname1); + + if ( (lofig2 = loadfigure (argv[2], argv[4], flag_flatten)) == NULL ) { + (void)fprintf (stderr, "\n!!!!! Can not load '%s'\n", argv[4]); + fatalerror ("Fatal error on loading figure"); + } + sprintf (figname2, "%s_extract", argv[4]); + lofig2->NAME = namealloc (figname2); + + total_time = time( (long *)0 ); + while (++count < argc) { char *option; + option = argv[count]; + if (option[0] != '-') { + printf ("\n***** Invalid parameter '%s'\n\n", option); continue; + } + if (option[2] != 0) { + printf ("\n***** Invalid option '%s'\n\n", option); continue; + } + switch (option[1]) { + case 'a' : reducepower(lofig1,lofig2); reducepower(lofig2,lofig1);break; + case 'f' : break; + case 'o' : flag_ord = TRUE; break; + case 'i' : readparamfile (lofig1, lofig2, argv[++count]); break; + case 't' : flag_tie = FALSE; + while ((argv[count+1][0] != '-') && (++count < argc)) { + delins (lofig1, argv[count]); + delins (lofig2, argv[count]); + } + break; + default : printf ("\n***** Invalid option '%s'\n\n", option); continue; + } + } + + delfeed(lofig1);delfeed(lofig2); + + result = comparelofigs (lofig1, lofig2); + total_time = time( (long *)0 ) - total_time; + if (result != OK) { + printf ("\n\n***** Netlists are NOT Identical! *****\t(%lu sec)\n\n", + total_time); + exit (2); + } + printf ("\n\n***** Netlists are Identical. *****\t(%lu sec)\n\n", total_time); + + if (flag_ord) { + strcpy( IN_LO, argv[1] ) ; + order (lofig1, lofig2); + lofig2->NAME = namealloc (argv[4]); + printf ("***** Saving %s (%s)...\n\n", lofig2->NAME, OUT_LO); + savelofig (lofig2); + } + exit ( 0 ); +}