/* "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. */ /* embed.c -- efficient exhaustive embedding algorithm for PROTOCHIP */ /* define to get reams of extra output */ #undef EXTREE_DEBUG /* define this to use ex_tree to test Exist() */ #undef EX_TREE_FOR_EXIST #include "config.h" #include #ifdef IBMPC #include #endif #ifdef TCL_NETGEN #include #endif #include "netgen.h" #include "hash.h" #include "objlist.h" #include "netfile.h" #include "print.h" #include "embed.h" int CountExists; /* count number of times test is performed */ #ifdef EX_TREE_FOR_EXIST /* safe, but excessive */ /* #define EX_SIZE (MAX_ELEMENTS * (MAX_LEAVES+1)) */ #ifdef VMUNIX #define EX_SIZE 250000 #else #define EX_SIZE 60000 #endif #endif /* EX_TREE_FOR_EXIST */ #ifdef EX_TREE_FOR_EXIST #if EX_SIZE > 64000 #define EX_TREE_WITH_POINTERS #else #undef EX_TREE_WITH_POINTERS #endif #ifdef EX_TREE_WITH_POINTERS struct ex { struct ex *zero; struct ex *one; }; typedef struct ex *EX_LIST_PTR; long free_list; /* index into ex_array */ #else typedef unsigned short EX_LIST_PTR; struct ex { EX_LIST_PTR zero; EX_LIST_PTR one; }; unsigned short free_list; /* index into ex_array */ #endif /* EX_TREE_WITH_POINTERS */ struct ex ex_array[EX_SIZE]; EX_LIST_PTR tree_root; #endif /* EX_TREE_FOR_EXIST */ #ifdef EX_TREE_FOR_EXIST #ifdef EX_TREE_WITH_POINTERS int InitializeExistTest(void) { #ifdef EXTREE_DEBUG Printf("called InitializeExistTest\n"); #endif tree_root = NULL; free_list = 0; memzero(ex_array, sizeof(ex_array)); return (1); } EX_LIST_PTR GetExListElement(void) /* return index of next free element */ { if (free_list >= EX_SIZE) { Fprintf(stderr,"Too many ExListElements; garbage list exhausted\n"); FatalError = 1; return(NULL); } return(&(ex_array[free_list++])); } void AddToExistSet(int E1, int E2) { char ownedleaves[MAX_LEAVES+1]; int i; EX_LIST_PTR ptr; #if 1 for (i = 1; i <= Leaves; i++) ownedleaves[i] = TestPackedArrayBit(MSTAR[E1],i) || TestPackedArrayBit(MSTAR[E2],i); #else memzero(ownedleaves, sizeof(ownedleaves)); for (i = 1; i <= Leaves; i++) if (TestPackedArrayBit(MSTAR[E1],i) || TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1; #endif if (tree_root == NULL) if ((tree_root = GetExListElement()) == NULL) return; ptr = tree_root; for (i = 1; i <= Leaves; i++) { if (ownedleaves[i] == 1) { if (ptr->one == NULL) if ((ptr->one = GetExListElement()) == NULL) return; ptr = ptr->one; } else { if (ptr->zero == NULL) if ((ptr->zero = GetExListElement()) == NULL) return; ptr = ptr->zero; } } } int Exists(int E1, int E2) { char ownedleaves[MAX_LEAVES+1]; int i; EX_LIST_PTR ptr; CountExists++; if (tree_root == NULL) { #ifdef EXTREE_DEBUG Printf("(%d,%d) does not exist (empty list)\n",E1,E2); #endif return(0); } memzero(ownedleaves, sizeof(ownedleaves)); for (i = 1; i <= Leaves; i++) if (TestPackedArrayBit(MSTAR[E1],i) || TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1; #ifdef EXTREE_DEBUG Printf("checking existence of :"); for (i = 1; i <= Leaves; i++) Printf(" %d",ownedleaves[i]); Printf(" "); #endif ptr = tree_root; for (i = 1; i <= Leaves; i++) { if (ownedleaves[i] == 1) { if (ptr->one == NULL) { #ifdef EXTREE_DEBUG Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i); #endif return(0); } ptr = ptr->one; } else { if (ptr->zero == NULL) { #ifdef EXTREE_DEBUG Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i); #endif return(0); } ptr = ptr->zero; } } #ifdef EXTREE_DEBUG Printf("(%d,%d) already exists (i = %d)\n",E1,E2,i); #endif return (1); } #else int InitializeExistTest(void) { #ifdef EXTREE_DEBUG Printf("called InitializeExistTest\n"); #endif tree_root = 0; free_list = 1; memzero(ex_array, sizeof(ex_array)); return (1); } EX_LIST_PTR GetExListElement(void) /* return index of next free element */ { if (free_list >= EX_SIZE) { Pprintf(stderr,"Too many ExListElements; garbage list exhausted\n"); FatalError = 1; return(NULL); } return(free_list++); } void AddToExistSet(int E1, int E2) { char ownedleaves[MAX_LEAVES+1]; int i; EX_LIST_PTR ptr; #if 1 for (i = 1; i <= Leaves; i++) ownedleaves[i] = TestPackedArrayBit(MSTAR[E1],i) || TestPackedArrayBit(MSTAR[E2],i); #else memzero(ownedleaves, sizeof(ownedleaves)); for (i = 1; i <= Leaves; i++) if (TestPackedArrayBit(MSTAR[E1],i) || TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1; #endif if (tree_root == 0) if ((tree_root = GetExListElement()) == 0) return; ptr = tree_root; for (i = 1; i <= Leaves; i++) { if (ownedleaves[i] == 1) { if (ex_array[ptr].one == 0) { /* add it to list */ if (i == Leaves) ex_array[ptr].one = ptr; else if ((ex_array[ptr].one = GetExListElement()) == 0) return; } ptr = ex_array[ptr].one; } else { if (ex_array[ptr].zero == 0) { /* add it to list */ if (i == Leaves) ex_array[ptr].zero = ptr; else if ((ex_array[ptr].zero = GetExListElement()) == 0) return; } ptr = ex_array[ptr].zero; } } } int Exists(int E1, int E2) { char ownedleaves[MAX_LEAVES+1]; int i; EX_LIST_PTR ptr; CountExists++; if (tree_root == 0) { #ifdef EXTREE_DEBUG Printf("(%d,%d) does not exist (empty list)\n",E1,E2); #endif return(0); } memzero(ownedleaves, sizeof(ownedleaves)); for (i = 1; i <= Leaves; i++) if (TestPackedArrayBit(MSTAR[E1],i) || TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1; #ifdef EXTREE_DEBUG Printf("checking existence of :"); for (i = 1; i <= Leaves; i++) Printf(" %d",ownedleaves[i]); Printf(" "); #endif ptr = tree_root; for (i = 1; i <= Leaves; i++) { if (ownedleaves[i] == 1) { if (ex_array[ptr].one == 0) { #ifdef EXTREE_DEBUG Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i); #endif return(0); } ptr = ex_array[ptr].one; } else { if (ex_array[ptr].zero == 0) { #ifdef EXTREE_DEBUG Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i); #endif return(0); } ptr = ex_array[ptr].zero; } } #ifdef EXTREE_DEBUG Printf("(%d,%d) already exists (i = %d)\n",E1,E2,i); #endif return (1); } void PrintExistSetStats(FILE *f) { Fprintf(f,"Free list = %d of %d entries; ",free_list,EX_SIZE); } #endif /* EX_TREE_WITH_POINTERS */ #else /* EX_TREE_FOR_EXIST */ struct ex_entry { unsigned long mstar[(MAX_LEAVES / BITS_PER_LONG) + 1]; struct ex_entry *next; }; #if 1 struct ex_entry *ex_tab[MAX_ELEMENTS]; #else #ifdef IBMPC struct ex_entry *ex_tab[4100]; #else struct ex_entry *ex_tab[66000]; #endif #endif void PRINTPACKED(unsigned long *mstar) { int i; for (i = 0; i <= PackedLeaves; i++) Printf("%lX ",mstar[i]); } #ifdef IBMPC static unsigned int lochash(unsigned long *mstar) #else static unsigned long lochash(unsigned long *mstar) #endif { int i; unsigned long hashval; hashval = *mstar; for (i = 1; i <= PackedLeaves; i++) hashval ^= mstar[i]; /* we now have a 32 bit field that we want to collapse to 16 / 12 bits */ #ifdef EXTREE_DEBUG Printf("hashval = %ld; ",(long)hashval); #endif #if 1 hashval = hashval % (MAX_ELEMENTS - 1); #else hashval = (hashval >> 16) ^ (hashval & 0x0000FFFFL); #ifdef IBMPC hasval = hashval >> 4; #endif #endif #ifdef EXTREE_DEBUG Printf("element hashed to %ld\n",(long)hashval); #endif #ifdef IBMPC return((int)hashval); #else return(hashval); #endif } struct ex_entry *hashlookup(unsigned long *mstar) { struct ex_entry *np; int i; for (np = ex_tab[lochash(mstar)]; np != NULL; np = np->next) for (i = 0; i <= PackedLeaves && mstar[i] == (np->mstar)[i]; i++) if (i == PackedLeaves) { #ifdef EXTREE_DEBUG Printf("element found in hash table\n"); #endif return(np); } #ifdef EXTREE_DEBUG Printf("element not in hash table\n"); #endif return(NULL); } static struct ex_entry *hashinstall(unsigned long *mstar) { struct ex_entry *np; #ifdef IBMPC unsigned int hashval; #else unsigned long hashval; #endif int i; hashval = lochash(mstar); for (np = ex_tab[hashval]; np != NULL; np = np->next) for (i = 0; i <= PackedLeaves && mstar[i] == (np->mstar)[i]; i++) if (i == PackedLeaves) { #ifdef EXTREE_DEBUG Printf("element found in hash table\n"); #endif return(np); } /* not found in hash table, so install it */ if ((np = (struct ex_entry *)CALLOC(1, sizeof(struct ex_entry))) == NULL) return(NULL); /* memcpy(np->mstar, mstar, (PackedLeaves + 1)*sizeof(long)); */ memcpy(np->mstar, mstar, sizeof(np->mstar)); np->next = ex_tab[hashval]; #ifdef EXTREE_DEBUG Printf("Element installed in hash table\n"); #endif return(ex_tab[hashval] = np); } int Exists(int E1, int E2) { int i; unsigned long mstar[(MAX_LEAVES / BITS_PER_LONG) + 1]; CountExists++; for (i = 0; i <= PackedLeaves; i++) mstar[i] = MSTAR[E1][i] | MSTAR[E2][i]; #ifdef EXTREE_DEBUG Printf("TESTING Existence of (%d,%d)",E1,E2); PRINTPACKED(mstar); Printf("\n"); #endif return (hashlookup(mstar) != NULL); } int InitializeExistTest(void) { #ifdef IBMPC int i; #else long i; #endif struct ex_entry *np; struct ex_entry *npnext; for (i = 0; i < sizeof(ex_tab) / sizeof(ex_tab[0]); i++) for (np = ex_tab[i]; np != NULL; np = npnext) { npnext = np->next; FREE(np); } memzero(ex_tab, sizeof(ex_tab)); return(1); } void AddToExistSet(int E1, int E2) { int i; unsigned long mstar[(MAX_LEAVES / BITS_PER_LONG) + 1]; for (i = 0; i <= PackedLeaves; i++) mstar[i] = MSTAR[E1][i] | MSTAR[E2][i]; #ifdef EXTREE_DEBUG Printf("Requesting installation of (%d,%d) in hash table\n",E1,E2); #endif hashinstall(mstar); } void PrintExistSetStats(FILE *f) { struct ex_entry *np; #ifdef IBMPC int i; #else long i; #endif long bins; long nodes; bins = 0; nodes = 0; for (i = 0; i < sizeof(ex_tab) / sizeof(ex_tab[0]); i ++) if ((np = ex_tab[i]) != NULL) { bins++; while (np != NULL) { nodes++; np = np->next; } } Fprintf(f,"Exist hash table stats: %ld of %ld bins used", (long)bins, (long)(sizeof(ex_tab) / sizeof(ex_tab[0]))); if (bins != 0) Fprintf(f,", %ld nodes (%.2f nodes/bin)", nodes, (float)nodes / (float)bins); Fprintf(f,"\n"); Fprintf(f,"Exist hash table memory usage: %ld bytes\n", (long)(sizeof(ex_tab) + nodes * sizeof(struct ex_entry))); } #endif /* EX_TREE_FOR_EXIST */ int linelength = 80; void FreeEmbeddingTree(struct embed *E) { if (E == NULL) return; if (E->left != NULL) FreeEmbeddingTree(E->left); if (E->right != NULL) FreeEmbeddingTree(E->right); FREE(E); } struct embed *EmbeddingTree(struct nlist *tp, int E) /* return element E embedded in a tree of 'struct embed' */ { struct embed *node; if (E == 0) return(NULL); if ((node = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL) return(NULL); node->cell = tp; #if 0 if (LEVEL(E) == 0) { #else if (L(E) == 0 && R(E) == 0) { #endif /* root element */ node->instancenumber = E; node->level = LEVEL(E); return(node); } /* not a root element */ node->right = EmbeddingTree(tp, R(E)); node->left = EmbeddingTree(tp, L(E)); if (R(E) == 0) node->level = node->left->level + 1; else if (L(E) == 0) node->level = node->right->level + 1; else node->level = MAX(node->left->level, node->right->level) + 1; return(node); } struct embed *FlattenEmbeddingTree(struct embed *E) /* flattens a forest of trees, returning a copy */ { struct embed *node; int index; if (E == NULL) return(NULL); if ((node = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL) return(NULL); node->cell = E->cell; node->level = E->level; if (E->left == NULL && E->right == NULL) { /* root element */ struct embed *tmp; struct nlist *tp; struct objlist *ob; ob = InstanceNumber(E->cell,E->instancenumber); tp = LookupCell(ob->model.class); if (tp->embedding != NULL) { tmp = FlattenEmbeddingTree((struct embed *)(tp->embedding)); node->left = tmp->left; node->right = tmp->right; node->level = E->level; node->instancenumber = 0; } else memcpy(node, E, sizeof(struct embed)); return(node); } /* not a root element */ node->right = FlattenEmbeddingTree(E->right); node->left = FlattenEmbeddingTree(E->left); node->level = E->level; /* make it a balanced tree */ for (index = E->right->level + 1; index < node->level; index++) { struct embed *tmp; if ((tmp = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL) return(NULL); tmp->level = index; tmp->left = NULL; tmp->right = node->right; node->right = tmp; } for (index = E->right->level + 1; index < node->level; index++) { struct embed *tmp; if ((tmp = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL) return(NULL); tmp->level = index; tmp->left = NULL; tmp->right = node->right; node->right = tmp; } return(node); } #define PRINT_INDENT 2 int LenEmbed(char *prefix, struct nlist *np, struct embed *E, int flatten) /* return the number of characters required to print element E */ { char longstr[200]; if (E == NULL) return(0); if (E->left == NULL && E->right == NULL) { /* this is a root in our cell's embedding heirarchy */ struct objlist *ob; char *instancename; char *model; struct nlist *np2; ob = InstanceNumber(np,E->instancenumber); instancename = ob->instance.name; model = ob->model.class; np2 = LookupCell(model); if (np2 == NULL) return(0); sprintf(longstr, "%s%s", prefix, instancename); if ((np2->class != CLASS_SUBCKT) || np2->embedding == NULL || !flatten) return(strlen(longstr)); /* else, prepend model */ strcat(longstr,SEPARATOR); return(LenEmbed(longstr, np2, (struct embed *)np2->embedding, flatten)); } /* else it is a compound element (with 2 parentheses) */ return(PRINT_INDENT + 2 + LenEmbed(prefix, np, E->left, flatten) + LenEmbed(prefix, np, E->right, flatten)); } void PrintEmb(FILE *outfile, char *prefix, struct nlist *np, struct embed *E, int indent, int flatten) /* just print out the element on a single line */ /* assumes that we have been indented enough to print it directly */ { if (E == NULL) return; if (E->left == NULL && E->right == NULL) { /* this is a root in our cell's embedding heirarchy */ struct objlist *ob; char *instancename; struct nlist *np2; char name[200]; ob = InstanceNumber(np,E->instancenumber); instancename = ob->instance.name; np2 = LookupCell(ob->model.class); if (np2 == NULL) return; sprintf(name,"%s%s", prefix, instancename); if ((np2->class != CLASS_SUBCKT) || np2->embedding == NULL || !flatten) Fprintf(outfile, "%s", name); else { strcat(name,SEPARATOR); PrintEmb(outfile, name, np2, (struct embed *)np2->embedding, indent + 2*PRINT_INDENT, flatten); } return; } /* it is a compound element */ Fprintf(outfile,"("); PrintEmb(outfile, prefix, np, E->left, indent, flatten); Fprintf(outfile," "); PrintEmb(outfile, prefix, np, E->right, indent, flatten); Fprintf(outfile,")"); } void PrintEmbed(FILE *outfile, char *prefix, struct nlist *np, struct embed *E, int indent, int flatten) /* assumes that cursor is on col. 1 of line at entry */ /* upon return, cursor is on col. 1 of next free line */ { int i; if (E == NULL) return; if (E->right == NULL && E->left == NULL) { /* it is a root element */ struct objlist *ob; char *instancename; struct nlist *np2; char name[200]; ob = InstanceNumber(np,E->instancenumber); instancename = ob->instance.name; np2 = LookupCell(ob->model.class); if (np2 == NULL) return; if (np2->embedding != NULL && flatten) { sprintf(name,"%s%s%s", prefix, instancename, SEPARATOR); PrintEmbed(outfile, name, np2, (struct embed *)np2->embedding, indent + PRINT_INDENT, flatten); return; } else { for (i = 0; i < indent; i++) Fprintf(outfile," "); PrintEmb(outfile, prefix, np, E, indent, flatten); Fprintf(outfile,"\n"); return; } } if (indent + LenEmbed(prefix, np, E, flatten) >= linelength) { for (i = 0; i < indent; i++) Fprintf(outfile," "); Fprintf(outfile,"(\n"); PrintEmbed(outfile, prefix, np, E->left, indent + PRINT_INDENT, flatten); PrintEmbed(outfile, prefix, np, E->right,indent + PRINT_INDENT, flatten); for (i = 0; i < indent; i++) Fprintf(outfile," "); Fprintf(outfile,")\n"); } else { for (i = 0; i < indent; i++) Fprintf(outfile," "); Fprintf(outfile,"("); PrintEmb(outfile, prefix, np, E->left, indent, flatten); Fprintf(outfile," "); PrintEmb(outfile, prefix, np, E->right, indent, flatten); Fprintf(outfile,")\n"); } } void PrintEmbeddingTree(FILE *outfile, char *cellname, int flatten) { struct nlist *np; if (outfile == NULL) return; np = LookupCell(cellname); if (np == NULL) return; if (np->embedding == NULL) Fprintf(outfile, "No embedding for '%s' has been determined.\n",cellname); else { Fprintf(outfile, "Embedding for %s (level %d):\n",cellname, ((struct embed *)(np->embedding))->level); PrintEmbed(outfile, "", np, (struct embed *)(np->embedding), 0, flatten); Fprintf(outfile, "\n"); } }