688 lines
18 KiB
C
688 lines
18 KiB
C
/* "NETGEN", a netlist-specification tool for VLSI
|
|
Copyright (C) 1989, 1990 Massimo A. Sivilotti
|
|
Author's address: mass@csvax.cs.caltech.edu;
|
|
Caltech 256-80, Pasadena CA 91125.
|
|
|
|
This program 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 (any version).
|
|
|
|
This program 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 this program; see the file copying. If not, write to
|
|
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
/* bottomup.c -- Bottom-up graph partitioning algorithm for embedding
|
|
netlists on hierarchical prototyping chip.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
|
|
#include "hash.h"
|
|
#include "objlist.h"
|
|
#include "timing.h"
|
|
#include "embed.h"
|
|
#include "dbug.h"
|
|
#include "print.h"
|
|
|
|
/* count invokations of different test procedures */
|
|
int CountIndependent;
|
|
int CountFanoutOK;
|
|
int CountSwallowedElements;
|
|
|
|
|
|
int Independent(int E1, int E2)
|
|
/* return 1 if E1 and E2 share no leaves in common */
|
|
{
|
|
int leafelement;
|
|
CountIndependent++;
|
|
for (leafelement = 0; leafelement <= PackedLeaves; leafelement++)
|
|
if (MSTAR[E1][leafelement] & MSTAR[E2][leafelement]) return (0);
|
|
return(1);
|
|
}
|
|
|
|
int FanoutOK(int E1, int E2)
|
|
{
|
|
int approxfanout;
|
|
int node;
|
|
|
|
CountFanoutOK++;
|
|
|
|
/* trivial exclusion based on fanout upper bound */
|
|
/* remember, the current PROTOCHIP requires allocation of
|
|
an output even for swallowed nodes */
|
|
|
|
approxfanout = 0;
|
|
for (node = 1; node <= Nodes; node++)
|
|
if (C[E1][node] || C[E2][node]) approxfanout++;
|
|
if (approxfanout > TreeFanout[MAX(LEVEL(E1),LEVEL(E2)) + 1]) return(0);
|
|
return(1);
|
|
}
|
|
|
|
|
|
int Swallowed(int Parent, int Child)
|
|
/* returns 1 if Child's fanout is contained in Parent's */
|
|
{
|
|
int node;
|
|
|
|
for (node = 1; node <= Nodes; node++)
|
|
if (C[Child][node] && !(C[Parent][node])) return(0);
|
|
|
|
#ifdef PLACE_DEBUG
|
|
Printf("Element %d swallowed by %d\n",Child,Parent);
|
|
#endif
|
|
return(1);
|
|
}
|
|
|
|
#if 1
|
|
#define SmallEnough(a,b) 0
|
|
#else
|
|
int SmallEnough(int E1, int E2)
|
|
/* returns 1 if fanout(E1+E2) is less than MAX(fanout(E1),fanout(E2)) */
|
|
{
|
|
int node;
|
|
int fanout;
|
|
|
|
return(0); /* for now */
|
|
|
|
fanout = 0;
|
|
for (node = 1; node <= Nodes; node++)
|
|
if (C[E1][node] || C[E2][node])
|
|
if (CSTAR[E1][node] + CSTAR[E2][node] < CSTAR[0][node]) fanout++;
|
|
|
|
return (fanout <= MAX(PINS(E1), PINS(E2)));
|
|
|
|
#ifdef PLACE_DEBUG
|
|
Printf("Element %d,%d is SmallEnough\n",E1,E2);
|
|
#endif
|
|
return(1);
|
|
}
|
|
#endif
|
|
|
|
int SuccessfulEmbedding(int E)
|
|
/* returns 1 if element E is a successful embedding */
|
|
{
|
|
int testleaf;
|
|
|
|
#if 1
|
|
for (testleaf = 0; testleaf <= PackedLeaves; testleaf++)
|
|
if (MSTAR[E][testleaf] != MSTAR[0][testleaf]) return (0);
|
|
#else
|
|
for (testleaf = 1; testleaf <= Leaves; testleaf++)
|
|
if (!TestPackedArrayBit(MSTAR[E],testleaf)) return(0);
|
|
#endif
|
|
return(1);
|
|
}
|
|
|
|
|
|
void STARTPASS(FILE *f, int level1, int level2)
|
|
{
|
|
if (f == NULL) return;
|
|
Fprintf(f,"%2d: ",Pass);
|
|
if (Exhaustive)
|
|
Fprintf(f,"to level %d: (%d) ",level1,CountInLevel(level1,1));
|
|
else Fprintf(f,"(%d,%d) [%5d,%5d]",
|
|
level1,level2,CountInLevel(level1,0),CountInLevel(level2,0));
|
|
#ifdef PLACE_DEBUG
|
|
Fprintf(f,"\n");
|
|
#endif
|
|
Fflush(f);
|
|
}
|
|
|
|
void ENDPASS(FILE *f, int level1, int level2)
|
|
{
|
|
if (f == NULL) return;
|
|
Fprintf(f,"%5dA,%3dS,%5dT",
|
|
NewElements, NewSwallowed, Elements);
|
|
#if 1
|
|
if (NewElements) {
|
|
int level;
|
|
level = MAX(level1, level2) + 1;
|
|
Fprintf(f," (%4.1fP %4.1fC %4.1fL)(%2d %2d %2d)",
|
|
(float)SumPINS / NewElements, (float)SumCommonNodes / NewElements,
|
|
(float)SumUsedLeaves / NewElements,
|
|
TreeFanout[level], MinCommonNodes[level], MinUsedLeaves[level] );
|
|
}
|
|
#else
|
|
if (NewElements) Fprintf(f," (%4.1fP <= %2d, %4.1fC >= %2d, %4.1fL >= %2d)",
|
|
(float)SumPINS / (float)NewElements,
|
|
TreeFanout[MAX(level1,level2) + 1],
|
|
(float)SumCommonNodes / (float)NewElements,
|
|
MinCommonNodes[MAX(level1,level2) + 1],
|
|
(float)SumUsedLeaves / (float)NewElements,
|
|
MinUsedLeaves[MAX(level1,level2) + 1] );
|
|
#endif
|
|
Fprintf(f,"\n");
|
|
Fflush(f);
|
|
}
|
|
|
|
static float StartTime;
|
|
|
|
void EPILOG(FILE *f, int element)
|
|
{
|
|
if (f == NULL) return;
|
|
Fprintf(f,"Stats: Passes = %d, Elements = %d", Pass, Elements);
|
|
if (element) Fprintf(f, ", Level = %d",LEVEL(element));
|
|
Fprintf(f, ", Elapsed CPU time = %.2f s\n", ElapsedCPUTime(StartTime));
|
|
|
|
Fprintf(f,"Tests: Indep. = %d, Conn. = %d, Fanout = %d, Exists = %d\n",
|
|
CountIndependent, CountAnyCommonNodes, CountFanoutOK, CountExists);
|
|
|
|
PrintExistSetStats(f);
|
|
Fprintf(f,"Swallowed elements = %d", CountSwallowedElements);
|
|
if (Exhaustive) Fprintf(f,", EXHAUSTIVE");
|
|
Fprintf(f,"\n\n");
|
|
Fflush(f);
|
|
}
|
|
|
|
void SwallowSubTree(int E, int level)
|
|
{
|
|
if (E != 0 && !(SWALLOWED(E))) {
|
|
SWALLOWED(E) = level;
|
|
CountSwallowedElements++;
|
|
NewSwallowed++;
|
|
|
|
SwallowSubTree(L(E),level);
|
|
SwallowSubTree(R(E),level);
|
|
}
|
|
}
|
|
|
|
int Logging(int level1, int level2)
|
|
/* return 1 if we should log this level */
|
|
{
|
|
if (!logging) return(0);
|
|
if (!selectivelogging) return(1);
|
|
if (level2 == -1) return(level1 == LogLevel1);
|
|
if (LogLevel2 == -1) return(level1 == LogLevel1);
|
|
if (LogLevel1 == -1) return(level2 == LogLevel2);
|
|
return((level1 == LogLevel1) && (level2 == LogLevel2));
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
int DoAPass(int Level1, int Level2)
|
|
/* tries to merge elements of level 'Level1' with elements of level 'Level2' */
|
|
/* returns element number if successful embedding found */
|
|
{
|
|
int E1, E2;
|
|
int PossiblyDone;
|
|
int MaxLevel, MinLevel, ThisLevel;
|
|
int MinDoneLevel, junk;
|
|
int found;
|
|
|
|
Pass++;
|
|
STARTPASS(stdout,Level1,Level2);
|
|
STARTPASS(outfile,Level1,Level2);
|
|
if (logging) STARTPASS(logfile,Level1,Level2);
|
|
|
|
/* determine the minimum embedding level */
|
|
MaxLevel = MAX(Level1, Level2);
|
|
MinLevel = MIN(Level1, Level2);
|
|
ThisLevel = MaxLevel + 1; /* level at which any new element will go */
|
|
junk = Leaves - 1;
|
|
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
|
|
PossiblyDone = (MaxLevel >= MinDoneLevel - 1);
|
|
|
|
NewElements = 0;
|
|
NewSwallowed = 0;
|
|
SumPINS = 0;
|
|
SumCommonNodes = 0;
|
|
SumUsedLeaves = 0;
|
|
|
|
found = 0;
|
|
/* make first pass to determine what we can swallow */
|
|
#if 1
|
|
for (E1 = 1; E1 <= Elements; E1++) {
|
|
#else
|
|
for (E1 = Elements; E1 > 0; E1--) {
|
|
#endif
|
|
if ((LEVEL(E1) != MaxLevel && LEVEL(E1) != MinLevel)) continue;
|
|
/* might exclude SWALLOWED elements as well */
|
|
if (SWALLOWED(E1) && SWALLOWED(E1) != Pass) continue;
|
|
for (E2 = E1 - 1; E2 > 0; E2--) {
|
|
if ((LEVEL(E2) != MaxLevel && LEVEL(E1) == MinLevel) ||
|
|
(LEVEL(E2) != MinLevel && LEVEL(E1) == MaxLevel)) continue;
|
|
/* might exclude SWALLOWED elements as well */
|
|
if (SWALLOWED(E2) && SWALLOWED(E2) != Pass) continue;
|
|
|
|
if (Independent(E1,E2)
|
|
#ifdef CHECK_MINUSEDLEAVES
|
|
&& UsedLeaves(E1,E2) >= MinUsedLeaves[MaxLevel + 1]
|
|
#endif
|
|
&& AnyCommonNodes(E1,E2)
|
|
&& FanoutOK(E1,E2)
|
|
&& !Exists(E1,E2)
|
|
&& (Swallowed(E1, E2) || Swallowed(E2, E1) || SmallEnough(E1,E2))) {
|
|
SwallowSubTree(E1, Pass);
|
|
SwallowSubTree(E2, Pass);
|
|
AddNewElement(E1,E2);
|
|
#ifdef PLACE_DEBUG
|
|
Printf("Swallowing (%d,%d) (%d common nodes) into element %d\n",
|
|
E1,E2,CommonNodes(E1,E2,1),NewN);
|
|
#endif
|
|
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
|
|
found = NewN;
|
|
goto done;
|
|
}
|
|
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
|
|
if (FatalError) goto done;
|
|
/* break; do not consider E1 or E2 any further */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* make second pass to consider merging everything else */
|
|
#if 1
|
|
for (E1 = 1; E1 <= Elements; E1++) {
|
|
#else
|
|
for (E1 = Elements; E1 > 0; E1--) {
|
|
#endif
|
|
if ((LEVEL(E1) != MinLevel && LEVEL(E1) != MaxLevel) ||
|
|
SWALLOWED(E1)) continue;
|
|
#ifdef CHECK_MINCOMMONNODES
|
|
if (PINS(E1) < MinCommonNodes[MaxLevel + 1]) continue;
|
|
#endif
|
|
for (E2 = E1 - 1; E2 > 0; E2--) {
|
|
if ((LEVEL(E2) != MaxLevel && LEVEL(E1) == MinLevel) ||
|
|
(LEVEL(E2) != MinLevel && LEVEL(E1) == MaxLevel) ||
|
|
SWALLOWED(E2)) continue;
|
|
|
|
#ifdef CHECK_MINCOMMONNODES
|
|
if (PINS(E2) < MinCommonNodes[MaxLevel + 1]) continue;
|
|
#endif
|
|
if (Independent(E1,E2)
|
|
#ifdef CHECK_MINUSEDLEAVES
|
|
&& UsedLeaves(E1,E2) >= MinUsedLeaves[MaxLevel + 1]
|
|
#endif
|
|
&& AnyCommonNodes(E1,E2)
|
|
&& FanoutOK(E1,E2)
|
|
&& !Exists(E1,E2)) {
|
|
#ifdef CHECK_MINCOMMONNODES
|
|
int commonnodes;
|
|
commonnodes = CommonNodes(E1, E2, 1);
|
|
|
|
if (commonnodes < MinCommonNodes[MaxLevel + 1])
|
|
continue;
|
|
Printf("Adding element (%d,%d) with %d common nodes\n",
|
|
E1,E2,commonnodes);
|
|
#endif
|
|
AddNewElement(E1,E2);
|
|
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
|
|
found = NewN;
|
|
goto done;
|
|
}
|
|
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
|
|
if (FatalError) goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
done:
|
|
Elements = NewN;
|
|
|
|
ENDPASS(stdout, Level1, Level2);
|
|
#ifdef PLACE_DEBUG
|
|
EPILOG(stdout, found);
|
|
#endif
|
|
ENDPASS(outfile, Level1, Level2);
|
|
EPILOG(outfile, found);
|
|
if (logging) {
|
|
ENDPASS(logfile, Level1, Level2);
|
|
EPILOG(logfile, found);
|
|
if (NewElements && Logging(Level1,Level2)) {
|
|
PrintOwnership(logfile); PrintC(logfile);
|
|
PrintCSTAR(logfile); Fflush(logfile);
|
|
}
|
|
}
|
|
|
|
return(found);
|
|
}
|
|
|
|
#else
|
|
|
|
int DoAPass(int Level1, int Level2)
|
|
/* tries to merge elements of level 'Level1' with elements of level 'Level2' */
|
|
/* returns element number if successful embedding found */
|
|
{
|
|
int E1, E2;
|
|
int PossiblyDone;
|
|
int MaxLevel, MinLevel;
|
|
int MinDoneLevel, junk;
|
|
int found;
|
|
|
|
Pass++;
|
|
STARTPASS(stdout,Level1,Level2);
|
|
STARTPASS(outfile,Level1,Level2);
|
|
if (logging) STARTPASS(logfile,Level1,Level2);
|
|
|
|
/* determine the minimum embedding level */
|
|
MaxLevel = MAX(Level1, Level2);
|
|
MinLevel = MIN(Level1, Level2);
|
|
junk = Leaves - 1;
|
|
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
|
|
PossiblyDone = (MaxLevel >= MinDoneLevel - 1);
|
|
|
|
NewElements = 0;
|
|
NewSwallowed = 0;
|
|
SumPINS = 0;
|
|
SumCommonNodes = 0;
|
|
SumUsedLeaves = 0;
|
|
|
|
found = 0;
|
|
|
|
/* make single pass to consider merging and swallow */
|
|
#if 1
|
|
for (E1 = 1; E1 <= Elements; E1++) {
|
|
#else
|
|
for (E1 = Elements; E1 > 0; E1--) {
|
|
#endif
|
|
if ((LEVEL(E1) != MinLevel && LEVEL(E1) != MaxLevel) ||
|
|
/* (SWALLOWED(E1) && SWALLOWED(E1) != Pass)) */
|
|
SWALLOWED(E1))
|
|
continue;
|
|
#ifdef CHECK_MINCOMMONNODES
|
|
if (PINS(E1) < MinCommonNodes[MaxLevel + 1]) continue;
|
|
#endif
|
|
for (E2 = E1 - 1; E2 > 0; E2--) {
|
|
if ((LEVEL(E2) != MaxLevel && LEVEL(E1) == MinLevel) ||
|
|
(LEVEL(E2) != MinLevel && LEVEL(E1) == MaxLevel) ||
|
|
/* (SWALLOWED(E2) && SWALLOWED(E2) != Pass)) */
|
|
SWALLOWED(E2))
|
|
continue;
|
|
|
|
#ifdef CHECK_MINCOMMONNODES
|
|
if (PINS(E2) < MinCommonNodes[MaxLevel + 1]) continue;
|
|
#endif
|
|
if (Independent(E1,E2)
|
|
#ifdef CHECK_MINUSEDLEAVES
|
|
&& UsedLeaves(E1,E2) >= MinUsedLeaves[MaxLevel + 1]
|
|
#endif
|
|
&& AnyCommonNodes(E1,E2)
|
|
&& FanoutOK(E1,E2)
|
|
&& !Exists(E1,E2)) {
|
|
#ifdef CHECK_MINCOMMONNODES
|
|
int commonnodes;
|
|
commonnodes = CommonNodes(E1, E2, 1);
|
|
|
|
if (commonnodes < MinCommonNodes[MaxLevel + 1])
|
|
continue;
|
|
#ifdef PLACE_DEBUG
|
|
Printf("Adding element (%d,%d) with %d common nodes\n",
|
|
E1,E2,commonnodes);
|
|
#endif
|
|
#endif
|
|
AddNewElement(E1,E2);
|
|
if (Swallowed(E1, E2) || Swallowed(E2, E1) || SmallEnough(E1,E2)) {
|
|
SwallowSubTree(E1, Pass);
|
|
SwallowSubTree(E2, Pass);
|
|
#ifdef PLACE_DEBUG
|
|
Printf("Swallowing (%d,%d) (%d common nodes) into element %d\n",
|
|
E1,E2,CommonNodes(E1,E2,1),NewN);
|
|
#endif
|
|
}
|
|
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
|
|
found = NewN;
|
|
goto done;
|
|
}
|
|
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
|
|
if (FatalError) goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
done:
|
|
Elements = NewN;
|
|
|
|
ENDPASS(stdout, Level1, Level2);
|
|
#ifdef PLACE_DEBUG
|
|
EPILOG(stdout, found);
|
|
#endif
|
|
ENDPASS(outfile, Level1, Level2);
|
|
EPILOG(outfile, found);
|
|
if (logging) {
|
|
ENDPASS(logfile, Level1, Level2);
|
|
EPILOG(logfile, found);
|
|
/* if (NewElements && Logging(Level1,Level2)) { */
|
|
if (Logging(Level1,Level2)) {
|
|
PrintOwnership(logfile); PrintC(logfile);
|
|
PrintCSTAR(logfile); Fflush(logfile);
|
|
}
|
|
}
|
|
|
|
return(found);
|
|
}
|
|
#endif
|
|
|
|
int ExhaustivePass(int Level)
|
|
/* tries to merge elements of level 'Level' and below */
|
|
/* returns element number if successful embedding found */
|
|
{
|
|
int E1, E2;
|
|
int found;
|
|
int PossiblyDone;
|
|
int MinDoneLevel, junk;
|
|
|
|
Pass++;
|
|
STARTPASS(stdout, Level, Level);
|
|
STARTPASS(outfile, Level, Level);
|
|
if (logging) STARTPASS(logfile, Level, Level);
|
|
/* determine the minimum embedding level */
|
|
junk = Leaves - 1;
|
|
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
|
|
PossiblyDone = (Level >= MinDoneLevel - 1);
|
|
|
|
NewElements = 0;
|
|
SumPINS = 0;
|
|
SumCommonNodes = 0;
|
|
SumUsedLeaves = 0;
|
|
|
|
found = 0;
|
|
for (E1 = 1; E1 <= Elements; E1++) {
|
|
if (LEVEL(E1) != Level) continue;
|
|
#if 1
|
|
for (E2 = E1 - 1; E2 > 0; E2--)
|
|
#else
|
|
for (E2 = 1; E2 < E1; E2++) /* statistically, slightly worse */
|
|
#endif
|
|
if (LEVEL(E2) <= LEVEL(E1)
|
|
&& Independent(E1,E2)
|
|
&& AnyCommonNodes(E1,E2)
|
|
&& FanoutOK(E1,E2)
|
|
&& !Exists(E1,E2)) {
|
|
|
|
AddNewElement(E1,E2);
|
|
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
|
|
found = NewN;
|
|
goto done;
|
|
}
|
|
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
|
|
#if 0
|
|
if (Swallowed(E1,E2)) break; /* works OK, but makes csrlntk 5 deep*/
|
|
#endif
|
|
#if 0
|
|
if (Swallowed(E2,E1)) break; /* largely untested: csrlntk in 5 */
|
|
#endif
|
|
if (FatalError) goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
Elements = NewN;
|
|
|
|
ENDPASS(stdout, Level, Level);
|
|
ENDPASS(outfile, Level, Level);
|
|
#ifdef PLACE_DEBUG
|
|
EPILOG(stdout, found);
|
|
EPILOG(outfile, found);
|
|
#endif
|
|
if (logging) {
|
|
ENDPASS(logfile, Level, Level);
|
|
EPILOG(logfile, found);
|
|
if (NewElements && Logging(Level,-1)) {
|
|
PrintOwnership(logfile); PrintC(logfile);
|
|
PrintCSTAR(logfile); Fflush(logfile);
|
|
}
|
|
}
|
|
|
|
return(found);
|
|
}
|
|
|
|
|
|
void PROLOG(FILE *f)
|
|
{
|
|
long totalsize;
|
|
int junk, MinDoneLevel;
|
|
|
|
/* determine the minimum embedding level */
|
|
junk = Leaves - 1;
|
|
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
|
|
|
|
Fprintf(f,"MAX_ELEMENTS = %d, ",MAX_ELEMENTS);
|
|
Fprintf(f,"MAX_LEAVES = %d, ",MAX_LEAVES);
|
|
Fprintf(f,"MAX_NODES = %d, ",MAX_NODES);
|
|
Fprintf(f,"MAX_TREE_DEPTH = %d\n",MAX_TREE_DEPTH);
|
|
|
|
Fprintf(f,"Matrix sizes: M = %ldK, MSTAR = %ldK, C = %ldK, CSTAR = %ldK\n",
|
|
(long)sizeof(M)/1024,(long)sizeof(MSTAR)/1024,
|
|
(long)sizeof(C)/1024, (long)sizeof(CSTAR)/1024);
|
|
totalsize = sizeof(M) + sizeof(MSTAR) + sizeof(C) + sizeof(CSTAR);
|
|
#ifdef EX_TREE_FOR_EXIST
|
|
totalsize += sizeof(ex_array);
|
|
Fprintf(f," ex_array = %ldK, total = %ldK\n",
|
|
(long)sizeof(ex_array)/1024, (long)totalsize/1024);
|
|
#else
|
|
Fprintf(f," total = %ldK\n", (long)totalsize/1024);
|
|
#endif
|
|
|
|
Fprintf(f,
|
|
" 0: %d elements, %d nodes, %d ports. Earliest embedding level = %d\n",
|
|
Elements, Nodes, PINS(0), MinDoneLevel);
|
|
Fflush(f);
|
|
}
|
|
|
|
void EmbedCell(char *cellname, char *filename)
|
|
{
|
|
int found;
|
|
int level1, level2;
|
|
int FillingLevel;
|
|
/* int SomeNewElements; */
|
|
|
|
if (!OpenEmbeddingFile(cellname, filename)) return;
|
|
|
|
StartTime = CPUTime();
|
|
if (!InitializeMatrices(cellname)) return;
|
|
if (!InitializeExistTest()) return;
|
|
FatalError = 0;
|
|
NewN = Elements;
|
|
Pass = 0;
|
|
CountIndependent = 0;
|
|
CountAnyCommonNodes = 0;
|
|
CountFanoutOK = 0;
|
|
CountExists = 0;
|
|
CountSwallowedElements = 0;
|
|
|
|
Fprintf(stdout,"Embedding cell: %s\n",cellname);
|
|
PROLOG(stdout);
|
|
Fprintf(outfile,"Embedding cell: %s\n",cellname);
|
|
PROLOG(outfile);
|
|
|
|
if (logging) {
|
|
Fprintf(logfile,"Embedding cell: %s\n",cellname);
|
|
PROLOG(logfile);
|
|
PrintOwnership(logfile);
|
|
PrintC(logfile);
|
|
PrintCSTAR(logfile);
|
|
Fflush(logfile);
|
|
}
|
|
|
|
if (Exhaustive) {
|
|
for (level1 = 0; level1 < MAX_TREE_DEPTH; level1++) {
|
|
found = ExhaustivePass(level1);
|
|
if (found || FatalError) goto done;
|
|
}
|
|
}
|
|
else {
|
|
#if 1
|
|
/* do not try to be clever about minimizing passes */
|
|
found = -1; /* fake-out to first call below */
|
|
for (FillingLevel = 0; FillingLevel < MAX_TREE_DEPTH; FillingLevel++) {
|
|
for (level1 = FillingLevel - 1; level1 >= 0 || found == -1; level1--){
|
|
if (found == -1) level1 = 0;
|
|
found = DoAPass(FillingLevel, level1);
|
|
if (found || FatalError) goto done;
|
|
/* now try to go up the ladder */
|
|
/* NewElements = 1; only do it if we added something in DoAPass */
|
|
for (level2 = FillingLevel + 1;
|
|
NewElements && level2 < MAX_TREE_DEPTH; level2++) {
|
|
found = DoAPass(level2, level2);
|
|
if (found || FatalError) goto done;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
/* try to minimize number of passes; only works for trees with
|
|
leaves at level 0 */
|
|
found = -1; /* fake-out to first call below */
|
|
SomeNewElements = 1;
|
|
for (FillingLevel = 0;
|
|
FillingLevel < MAX_TREE_DEPTH && SomeNewElements; FillingLevel++) {
|
|
SomeNewElements = 0;
|
|
for (level1 = FillingLevel - 1; level1 >= 0 || found == -1; level1--){
|
|
if (found == -1) level1 = 0;
|
|
found = DoAPass(FillingLevel, level1);
|
|
if (NewElements) SomeNewElements = 1;
|
|
if (found || FatalError) goto done;
|
|
/* now try to go up the ladder */
|
|
NewElements = 1;
|
|
for (level2 = FillingLevel + 1;
|
|
NewElements && level2 < MAX_TREE_DEPTH; level2++) {
|
|
found = DoAPass(level2, level2);
|
|
if (found || FatalError) goto done;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
done:
|
|
if (FatalError) {
|
|
Fprintf(stdout,"Internal Fatal Error\n");
|
|
Fprintf(outfile,"Internal Fatal Error\n");
|
|
found = 0;
|
|
}
|
|
if (found >= MAX_ELEMENTS) found = 0;
|
|
|
|
if (found) {
|
|
struct nlist *tp;
|
|
|
|
tp = LookupCell(cellname);
|
|
FreeEmbeddingTree((struct embed *)(tp->embedding));
|
|
tp->embedding = EmbeddingTree(tp, found);
|
|
#if 0
|
|
PrintEmbedding(stdout,cellname,found);
|
|
PrintEmbedding(outfile,cellname,found);
|
|
if (logging) PrintEmbedding(logfile,cellname,found);
|
|
#endif
|
|
PrintEmbeddingTree(stdout,cellname,1);
|
|
PrintEmbeddingTree(outfile,cellname,1);
|
|
if (logging) PrintEmbeddingTree(logfile,cellname,1);
|
|
}
|
|
else {
|
|
Fprintf(stdout,"No embedding found. Sorry.\n");
|
|
Fprintf(outfile,"No embedding found. Sorry.\n");
|
|
if (logging) Fprintf(logfile,"No embedding found. Sorry.\n");
|
|
}
|
|
EPILOG(stdout, found);
|
|
EPILOG(outfile, found);
|
|
if (logging) EPILOG(logfile, found);
|
|
|
|
CloseEmbeddingFile();
|
|
}
|
|
|