netgen/base/embed.c

768 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. */
/* 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 <stdio.h>
#ifdef IBMPC
#include <stdlib.h>
#endif
#ifdef TCL_NETGEN
#include <tcl.h>
#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[MAX_STR_LEN];
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[MAX_STR_LEN];
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[MAX_STR_LEN];
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");
}
}