/* "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 #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(); }