mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 14:07:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab0165b16c | ||
|
|
bf4112db07 | ||
|
|
5197eb6186 | ||
|
|
fcee934580 | ||
|
|
48ed1f7583 | ||
|
|
2d427aef3c | ||
|
|
e63593c7e2 | ||
|
|
fd0c8c87ea | ||
|
|
3d180f778d | ||
|
|
178af5f493 | ||
|
|
035fef5c72 | ||
|
|
ac8956c32e | ||
|
|
202ea0431f | ||
|
|
94754dbc4e | ||
|
|
b87f0fd5db | ||
|
|
bf67d3c275 | ||
|
|
21e9207924 | ||
|
|
62feed812e | ||
|
|
8392721885 | ||
|
|
d1c2848e4b | ||
|
|
6b0bd4d97b | ||
|
|
79bab50a79 | ||
|
|
d69fbc23bb | ||
|
|
b83800d69b | ||
|
|
c7fa0324d9 | ||
|
|
93b9cf6577 | ||
|
|
eb27a18ae3 | ||
|
|
bf53d52970 | ||
|
|
1817f4dd6a | ||
|
|
4250525e19 | ||
|
|
a7e859fcde |
@@ -1230,6 +1230,10 @@ int UniquePins(char *name, int filenum)
|
||||
* Removed the code 9/1/2023. But---Not sure if any code depends
|
||||
* on shorted pins being adjacent.
|
||||
*/
|
||||
/* When two pins are shorted, they are by definition permutable */
|
||||
PermuteSetup(ThisCell->name, ThisCell->file, ob->name,
|
||||
firstport[ob->node]->name);
|
||||
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
|
||||
+145
-24
@@ -4204,6 +4204,28 @@ static int compsort(const void *p1, const void *p2)
|
||||
return (s1->value > s2->value) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* compdsort() is like compsort() but uses the definition for */
|
||||
/* "slop" used for type double instead of type integer. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
static int compdsort(const void *p1, const void *p2)
|
||||
{
|
||||
propsort *s1, *s2;
|
||||
double smax, ddiff;
|
||||
|
||||
s1 = (propsort *)p1;
|
||||
s2 = (propsort *)p2;
|
||||
|
||||
smax = fmax(s1->slop, s2->slop);
|
||||
ddiff = fabs(s1->value - s2->value) /
|
||||
fabs(s1->value + s2->value);
|
||||
if (ddiff <= smax)
|
||||
return (s1->avalue > s2->avalue) ? 1 : 0;
|
||||
else
|
||||
return (s1->value > s2->value) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Sort properties of ob1 starting at property idx1 up to */
|
||||
/* property (idx1 + run). Use series critical property for */
|
||||
@@ -4221,7 +4243,8 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
struct valuelist *vl, *sl;
|
||||
int i, p, sval, merge_type;
|
||||
// double cval, slop;
|
||||
int has_crit;
|
||||
int (*sortfunc)() = compsort;
|
||||
int has_crit, is_float;
|
||||
char ca, co;
|
||||
double tval, tslop;
|
||||
double aval, pval, oval, aslop, pslop;
|
||||
@@ -4241,6 +4264,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
for (i = 0; i < run; i++) {
|
||||
has_crit = FALSE;
|
||||
merge_type = MERGE_NONE;
|
||||
is_float = FALSE;
|
||||
ca = co = (char)0;
|
||||
|
||||
for (p = 0;; p++) {
|
||||
@@ -4273,6 +4297,8 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
else {
|
||||
tval = vl->value.dval;
|
||||
tslop = kl->slop.dval;
|
||||
sortfunc = compdsort;
|
||||
is_float = TRUE;
|
||||
}
|
||||
|
||||
if (kl->merge & MERGE_S_CRIT) {
|
||||
@@ -4327,10 +4353,11 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
|
||||
obn = obp; /* Link from last property */
|
||||
|
||||
qsort(&proplist[0], run, sizeof(propsort), compsort);
|
||||
qsort(&proplist[0], run, sizeof(propsort), sortfunc);
|
||||
|
||||
// Re-sort list
|
||||
obp = ob1;
|
||||
for (i = 0; i < idx1; i++) obp = obp->next;
|
||||
for (i = 0; i < run; i++) {
|
||||
obp->next = proplist[i].ob;
|
||||
obp = obp->next;
|
||||
@@ -4416,6 +4443,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
propsort *proplist;
|
||||
struct property *kl;
|
||||
struct valuelist *vl;
|
||||
int (*sortfunc)() = compsort;
|
||||
int i, p, mval, merge_type;
|
||||
int has_crit;
|
||||
char ca, co;
|
||||
@@ -4439,9 +4467,9 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
proplist = (propsort *)MALLOC(run * sizeof(propsort));
|
||||
|
||||
obp = obn;
|
||||
mval = 1;
|
||||
pval = aval = oval = 0.0;
|
||||
for (i = 0; i < run; i++) {
|
||||
mval = 1;
|
||||
has_crit = FALSE;
|
||||
merge_type = MERGE_NONE;
|
||||
ca = co = (char)0;
|
||||
@@ -4476,6 +4504,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
else {
|
||||
tval = vl->value.dval;
|
||||
tslop = kl->slop.dval;
|
||||
sortfunc = compdsort;
|
||||
}
|
||||
|
||||
if (kl->merge & MERGE_P_CRIT) {
|
||||
@@ -4530,10 +4559,11 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
|
||||
|
||||
obn = obp; /* Link from last property */
|
||||
|
||||
qsort(&proplist[0], run, sizeof(propsort), compsort);
|
||||
qsort(&proplist[0], run, sizeof(propsort), sortfunc);
|
||||
|
||||
// Re-sort list
|
||||
obp = ob1;
|
||||
for (i = 0; i < idx1; i++) obp = obp->next;
|
||||
for (i = 0; i < run; i++) {
|
||||
obp->next = proplist[i].ob;
|
||||
obp = obp->next;
|
||||
@@ -6122,7 +6152,9 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
||||
if (kl2 != NULL)
|
||||
break; // Property is required
|
||||
}
|
||||
else if (vl2->value.ival != 1)
|
||||
else if ((vl2->type == PROP_INTEGER) && (vl2->value.ival != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
else if ((vl2->type == PROP_DOUBLE) && (vl2->value.dval != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
}
|
||||
if (vl2->type != PROP_ENDLIST) {
|
||||
@@ -6179,7 +6211,9 @@ PropertyMatch(struct Element *E1, struct Element *E2,
|
||||
if (kl1 != NULL)
|
||||
break; // Property is required
|
||||
}
|
||||
else if (vl1->value.ival != 1)
|
||||
else if ((vl1->type == PROP_INTEGER) && (vl1->value.ival != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
else if ((vl1->type == PROP_DOUBLE) && (vl1->value.dval != 1))
|
||||
break; // Property M != 1 or S != 1 is a mismatch.
|
||||
}
|
||||
if (vl1->type != PROP_ENDLIST) {
|
||||
@@ -7170,8 +7204,6 @@ int EquivalenceClasses(char *name1, int file1, char *name2, int file2, int douni
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Callback function used by MatchPins */
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -7180,7 +7212,7 @@ int reorderpins(struct hashlist *p, int file)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct nlist *tc2 = Circuit2;
|
||||
struct objlist *ob, *ob2, *firstpin;
|
||||
struct objlist *ob, *ob2, *firstpin, *oblast, *newob;
|
||||
int i, numports, *nodes, unordered;
|
||||
char **names;
|
||||
|
||||
@@ -7232,6 +7264,7 @@ int reorderpins(struct hashlist *p, int file)
|
||||
names[ob2->model.port] = ob->name;
|
||||
}
|
||||
|
||||
oblast = ob;
|
||||
ob = ob->next;
|
||||
ob2 = ob2->next;
|
||||
if (i < numports - 1) {
|
||||
@@ -7239,7 +7272,34 @@ int reorderpins(struct hashlist *p, int file)
|
||||
Fprintf(stderr, "Instance of %s has only "
|
||||
"%d of %d ports\n",
|
||||
tc2->name, i + 1, numports);
|
||||
break;
|
||||
if (ptr->flags & CELL_VERILOG) {
|
||||
/* If parent cell is verilog, and the cells
|
||||
* have been matched, then the instance can
|
||||
* be assumed to be using an implicit pin.
|
||||
*/
|
||||
Fprintf(stderr, "Assuming implicit verilog pin \"%s\".\n",
|
||||
ob2->name);
|
||||
newob = (struct objlist *)CALLOC(1,
|
||||
sizeof(struct objlist));
|
||||
newob->name = (char *)MALLOC(strlen(oblast->instance.name)
|
||||
+ strlen(ob2->name) + 2);
|
||||
sprintf(newob->name, "%s/%s",
|
||||
oblast->instance.name, ob2->name);
|
||||
newob->type = oblast->type + 1;
|
||||
newob->model.class = strsave(oblast->model.class);
|
||||
newob->instance.name = strsave(oblast->instance.name);
|
||||
newob->flags = 0;
|
||||
ptr->nodename_cache_maxnodenum++;
|
||||
newob->node = ptr->nodename_cache_maxnodenum;
|
||||
newob->next = ob;
|
||||
oblast->next = newob; /* Splice into object list */
|
||||
/* Fill in the missing entries */
|
||||
nodes[ob2->model.port] = newob->node;
|
||||
names[ob2->model.port] = newob->name;
|
||||
ob = newob;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (ob2 == NULL || ob2->type != PORT) {
|
||||
Fprintf(stderr, "Instance of %s has "
|
||||
@@ -7441,6 +7501,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
int hasproxy1 = 0, hasproxy2 = 0;
|
||||
int needclean1 = 0, needclean2 = 0;
|
||||
int nomatch = 0;
|
||||
int filenum = -1;
|
||||
int *correspond;
|
||||
char *ostr;
|
||||
#ifdef TCL_NETGEN
|
||||
@@ -7558,10 +7619,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ob3 = NULL;
|
||||
break; /* All pins w/the same node should be together */
|
||||
}
|
||||
}
|
||||
if (ob3 == NULL) {
|
||||
if (Debug == 0) {
|
||||
@@ -7609,15 +7666,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
/* If there are multiple pins on the same net, cycle through them; */
|
||||
/* otherwise, move to the next entry in the partition. */
|
||||
if (ob1->next && (ob1->next->type == PORT) && (ob1->next->node == ob1->node)) {
|
||||
ob1 = ob1->next;
|
||||
ob2 = tc2->cell; /* Restart search for matching pin */
|
||||
i++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ob2 == NULL) {
|
||||
@@ -7843,6 +7892,72 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
else {
|
||||
struct Permutation *permute1, *permute2;
|
||||
struct objlist *ob1a = NULL, *ob2a = NULL;
|
||||
|
||||
/* Check the permutation list. If any permutable pin
|
||||
* matches, and both nodes equal the nodes of their
|
||||
* pin permutations, then the pins also match.
|
||||
*/
|
||||
for (permute1 = tc1->permutes; permute1; permute1 = permute1->next) {
|
||||
if ((*matchfunc)(ob1->name, permute1->pin1)) {
|
||||
ob1a = LookupObject(permute1->pin1, tc1);
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(ob1->name, permute1->pin2)) {
|
||||
ob1a = LookupObject(permute1->pin2, tc1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (permute2 = tc2->permutes; permute2; permute2 = permute2->next) {
|
||||
if ((*matchfunc)(ob2->name, permute2->pin1)) {
|
||||
ob2a = LookupObject(permute2->pin1, tc2);
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(ob2->name, permute2->pin2)) {
|
||||
ob2a = LookupObject(permute2->pin2, tc2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ob1a && ob2a) {
|
||||
if ((ob1->node == ob1a->node) && (ob2->node == ob2a->node)) {
|
||||
/* This should be enough to prove equivalency */
|
||||
if ((correspond[ob1->node] == 0) || (correspond[ob1->node] == ob2->node)) {
|
||||
|
||||
correspond[ob1->node] = ob2->node; /* remember corresponding node */
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
if (Debug == 0) {
|
||||
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
|
||||
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
|
||||
snprintf(ostr, left_col_end, "%s", ob1->name);
|
||||
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
|
||||
for (m = 0; m < right_col_end + 1; m++)
|
||||
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
|
||||
Fprintf(stdout, ostr);
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Circuit %s port %d \"%s\""
|
||||
" = cell %s port %d \"%s\"\n",
|
||||
tc1->name, i, ob1->name,
|
||||
tc2->name, j, ob2->name);
|
||||
}
|
||||
#ifdef TCL_NETGEN
|
||||
if (dolist) {
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist1,
|
||||
Tcl_NewStringObj(ob1->name, -1));
|
||||
Tcl_ListObjAppendElement(netgeninterp, plist2,
|
||||
Tcl_NewStringObj(ob2->name, -1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
@@ -8118,7 +8233,11 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
/* Reorder pins in Circuit2 instances to match Circuit1 */
|
||||
|
||||
RecurseCellFileHashTable(reorderpins, Circuit2->file);
|
||||
if (Circuit2 != NULL)
|
||||
filenum = Circuit2->file;
|
||||
else
|
||||
filenum = tc2->file;
|
||||
RecurseCellFileHashTable(reorderpins, filenum);
|
||||
|
||||
/* Reorder pins in Circuit2 cell to match Circuit1 */
|
||||
/* Unlike the instance records, the structures are swapped, */
|
||||
@@ -8291,6 +8410,8 @@ void FlattenCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCL_NETGEN
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Handler is only used when netgen is run from a */
|
||||
/* terminal, not the Tk console. */
|
||||
|
||||
+14
-2
@@ -587,6 +587,12 @@ void SkipTokNoNewline(char *delimiter)
|
||||
/* */
|
||||
/* Modified 3/30/2015 to include the condition where a comment line is */
|
||||
/* in the middle of a series of continuation lines. */
|
||||
/* */
|
||||
/* Modified 1/3/2024 to avoid skipping two lines if a line has only the */
|
||||
/* comment character '*' followed by a newline. It seems that '\n' is */
|
||||
/* being ignored in WHITESPACE_DELIMITER, but it's easier to write the */
|
||||
/* code to find the exception rather than track down the problem in */
|
||||
/* GetNextLine(). */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void SpiceTokNoNewline(void)
|
||||
@@ -598,8 +604,14 @@ void SpiceTokNoNewline(void)
|
||||
while (nexttok == NULL) {
|
||||
contline = getc(infile);
|
||||
if (contline == '*') {
|
||||
GetNextLine(WHITESPACE_DELIMITER);
|
||||
SkipNewLine(NULL);
|
||||
char testline = ' ';
|
||||
while ((testline == ' ') || (testline == '\t'))
|
||||
testline = getc(infile);
|
||||
if (testline != '\n') {
|
||||
ungetc(testline, infile);
|
||||
GetNextLine(WHITESPACE_DELIMITER);
|
||||
SkipNewLine(NULL);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (contline != '+') {
|
||||
|
||||
+8
-4
@@ -300,7 +300,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
|
||||
tstr = sstr - 1;
|
||||
numlast = 1;
|
||||
}
|
||||
break;
|
||||
/* But might not be. . . */
|
||||
if ((dval != 0) || (sstr > estr))
|
||||
break;
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
@@ -320,7 +322,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
|
||||
tstr = sstr - 1;
|
||||
numlast = 1;
|
||||
}
|
||||
break;
|
||||
/* But might not be. . . */
|
||||
if ((dval != 0) || (sstr > estr))
|
||||
break;
|
||||
}
|
||||
/* Not a number, so must be arithmetic */
|
||||
*tstr = '\0';
|
||||
@@ -3090,7 +3094,7 @@ void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
|
||||
for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == PROPERTY)
|
||||
break;
|
||||
if (nob->type != PROPERTY) return; // shouldn't happen
|
||||
if (nob == NULL || nob->type != PROPERTY) return; // shouldn't happen
|
||||
|
||||
opentags = 0;
|
||||
for (; nob->next && nob->next->type == PROPERTY; nob = nob->next) {
|
||||
@@ -3640,7 +3644,7 @@ int CombineSeries(char *model, int file)
|
||||
nob->type = PROPERTY;
|
||||
nob->name = strsave("properties");
|
||||
nob->node = -2; /* Don't report as disconnected node */
|
||||
nob->model.class = (obp->model.class == NULL) ? NULL :
|
||||
nob->model.class = (obp == NULL || obp->model.class == NULL) ? NULL :
|
||||
strsave(obp->model.class);
|
||||
nob->instance.props = NewPropValue(2);
|
||||
|
||||
|
||||
+68
-68
@@ -596,65 +596,65 @@ int freeprop(struct hashlist *p)
|
||||
|
||||
void CellDelete(char *name, int fnum)
|
||||
{
|
||||
/* delete all the contents of cell 'name', and remove 'name' from
|
||||
the cell hash table. NOTE: this procedure does not care or check
|
||||
if 'name' has been instanced anywhere. It is assumed that if this
|
||||
is the case, the user will (quickly) define a new cell of that name.
|
||||
*/
|
||||
struct objlist *ob, *obnext;
|
||||
struct nlist *tp;
|
||||
/* delete all the contents of cell 'name', and remove 'name' from
|
||||
the cell hash table. NOTE: this procedure does not care or check
|
||||
if 'name' has been instanced anywhere. It is assumed that if this
|
||||
is the case, the user will (quickly) define a new cell of that name.
|
||||
*/
|
||||
struct objlist *ob, *obnext;
|
||||
struct nlist *tp;
|
||||
|
||||
tp = LookupCellFile(name, fnum);
|
||||
if (tp == NULL) {
|
||||
Printf ("No cell '%s' found.\n", name);
|
||||
return;
|
||||
}
|
||||
tp = LookupCellFile(name, fnum);
|
||||
if (tp == NULL) {
|
||||
Printf ("No cell '%s' found.\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
HashIntDelete(name, fnum, &cell_dict);
|
||||
/* now make sure that we free all the fields of the nlist struct */
|
||||
if (tp->name != NULL) FREE(tp->name);
|
||||
HashKill(&(tp->objdict));
|
||||
HashKill(&(tp->instdict));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
FreeNodeNames(tp);
|
||||
ob = tp->cell;
|
||||
while (ob != NULL) {
|
||||
obnext = ob->next;
|
||||
FreeObject (ob);
|
||||
ob = obnext;
|
||||
}
|
||||
HashIntDelete(name, fnum, &cell_dict);
|
||||
/* now make sure that we free all the fields of the nlist struct */
|
||||
if (tp->name != NULL) FREE(tp->name);
|
||||
HashKill(&(tp->objdict));
|
||||
HashKill(&(tp->instdict));
|
||||
RecurseHashTable(&(tp->propdict), freeprop);
|
||||
HashKill(&(tp->propdict));
|
||||
FreeNodeNames(tp);
|
||||
ob = tp->cell;
|
||||
while (ob != NULL) {
|
||||
obnext = ob->next;
|
||||
FreeObject (ob);
|
||||
ob = obnext;
|
||||
}
|
||||
}
|
||||
|
||||
static int PrintCellHashTableElement(struct hashlist *p)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct nlist *ptr;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
|
||||
|
||||
if (ptr->class != CLASS_SUBCKT) {
|
||||
/* only print primitive cells if Debug is enabled */
|
||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||
if ((ptr->class != CLASS_SUBCKT) && (ptr->class != CLASS_MODULE)) {
|
||||
/* only print primitive cells if Debug is enabled */
|
||||
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
|
||||
ptr->name, ptr->number);
|
||||
else if (Debug == 3) { /* list */
|
||||
else if (Debug == 3) { /* list */
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
#else
|
||||
Printf("%s ", ptr->name);
|
||||
Printf("%s ", ptr->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||
}
|
||||
}
|
||||
else if ((Debug == 2) || (Debug == 3)) { /* list only */
|
||||
#ifdef TCL_NETGEN
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
Tcl_AppendElement(netgeninterp, ptr->name);
|
||||
#else
|
||||
Printf("%s ", ptr->name);
|
||||
Printf("%s ", ptr->name);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
Printf("Cell: %s (instanced %d times)\n",ptr->name,ptr->number);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
Printf("Cell: %s (instanced %d times)\n", ptr->name, ptr->number);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Print the contents of the cell hash table. */
|
||||
@@ -663,65 +663,65 @@ static int PrintCellHashTableElement(struct hashlist *p)
|
||||
|
||||
void PrintCellHashTable(int full, int filenum)
|
||||
{
|
||||
int total, bins;
|
||||
int OldDebug;
|
||||
int total, bins;
|
||||
int OldDebug;
|
||||
|
||||
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
PrintCellHashTable(full, Circuit1->file);
|
||||
PrintCellHashTable(full, Circuit2->file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TopFile = filenum;
|
||||
TopFile = filenum;
|
||||
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full < 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
|
||||
total = RecurseHashTable(&cell_dict, CountHashTableEntries);
|
||||
if (full < 2)
|
||||
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
|
||||
bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
|
||||
(float)((float)total / (float)bins));
|
||||
|
||||
OldDebug = Debug;
|
||||
Debug = full;
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
OldDebug = Debug;
|
||||
Debug = full;
|
||||
RecurseHashTable(&cell_dict, PrintCellHashTableElement);
|
||||
Debug = OldDebug;
|
||||
#ifndef TCL_NETGEN
|
||||
if (full >= 2) Printf("\n");
|
||||
if (full >= 2) Printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
struct nlist *FirstCell(void)
|
||||
{
|
||||
return((struct nlist *)HashFirst(&cell_dict));
|
||||
return((struct nlist *)HashFirst(&cell_dict));
|
||||
}
|
||||
|
||||
struct nlist *NextCell(void)
|
||||
{
|
||||
return((struct nlist *)HashNext(&cell_dict));
|
||||
return((struct nlist *)HashNext(&cell_dict));
|
||||
}
|
||||
|
||||
static int ClearDumpedElement(struct hashlist *np)
|
||||
{
|
||||
struct nlist *p;
|
||||
struct nlist *p;
|
||||
|
||||
p = (struct nlist *)(np->ptr);
|
||||
p->dumped = 0;
|
||||
return(1);
|
||||
p = (struct nlist *)(np->ptr);
|
||||
p->dumped = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
void ClearDumpedList(void)
|
||||
{
|
||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||
RecurseHashTable(&cell_dict, ClearDumpedElement);
|
||||
}
|
||||
|
||||
int RecurseCellHashTable(int (*foo)(struct hashlist *np))
|
||||
{
|
||||
return RecurseHashTable(&cell_dict, foo);
|
||||
return RecurseHashTable(&cell_dict, foo);
|
||||
}
|
||||
|
||||
int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||
{
|
||||
return RecurseHashTableValue(&cell_dict, foo, value);
|
||||
return RecurseHashTableValue(&cell_dict, foo, value);
|
||||
}
|
||||
|
||||
/* Yet another version, passing one parameter that is a pointer */
|
||||
@@ -729,7 +729,7 @@ int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
|
||||
struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
|
||||
void *), void *pointer)
|
||||
{
|
||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||
return RecurseHashTablePointer(&cell_dict, foo, pointer);
|
||||
}
|
||||
|
||||
/************************** WILD-CARD STUFF *******************************/
|
||||
|
||||
+75
-6
@@ -43,6 +43,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "print.h"
|
||||
#include "query.h"
|
||||
#include "objlist.h"
|
||||
#include "netcmp.h"
|
||||
|
||||
// Global storage for parameters from .PARAM
|
||||
struct hashdict spiceparams;
|
||||
@@ -519,7 +520,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
char *eqptr, devtype, in_subckt;
|
||||
struct keyvalue *kvlist = NULL;
|
||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN];
|
||||
struct nlist *tp;
|
||||
struct nlist *tp, *tpsave;
|
||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
|
||||
|
||||
inst[MAX_STR_LEN-1] = '\0';
|
||||
@@ -557,6 +558,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
tpsave = NULL;
|
||||
|
||||
/* Check for name conflict with duplicate cell names */
|
||||
/* This may mean that the cell was used before it was */
|
||||
@@ -595,11 +597,46 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
}
|
||||
else if (tp != NULL) { /* Make a new definition for an empty cell */
|
||||
FreePorts(nexttok);
|
||||
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
update = 1; /* Will need to update existing instances */
|
||||
/* Handle issue with SPICE read after verilog, where a placeholder
|
||||
* was created from the verilog. (1) If the pin names are "1", "2",
|
||||
* "3", then this is a SPICE placeholder, and just remove the CellDef
|
||||
* and re-create it. Otherwise, create new cell "_PLACEHOLDER_".
|
||||
* (2) After encountering .ends, run MatchPins between the two cells.
|
||||
* (3) delete the original cell and rename the new cell.
|
||||
*/
|
||||
int i = 1;
|
||||
char pname[10];
|
||||
for (pobj = tp->cell; pobj && pobj->type == PORT; pobj = pobj->next) {
|
||||
sprintf(pname, "%d", i);
|
||||
if (!matchnocase(pobj->name, pname)) break;
|
||||
i++;
|
||||
}
|
||||
if ((pobj == NULL) || (pobj->type != PORT)) {
|
||||
/* This is a SPICE placeholder created because the cell was instanced
|
||||
* before it was defined. However, the pins can be assumed to be in
|
||||
* the correct order, and pin reordering does not need to be done.
|
||||
*/
|
||||
FreePorts(nexttok);
|
||||
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
update = 1; /* Will need to update existing instances */
|
||||
}
|
||||
else {
|
||||
/* This is (probably) a verilog placeholder created because the
|
||||
* verilog was read before the (SPICE) definitions. The verilog
|
||||
* netlist should have named the pins of the parent cell. However,
|
||||
* there is no guarantee the order of pins is correct. The MatchPins()
|
||||
* routine from netcmp.c can be used here to match the cell against
|
||||
* the placeholder, and reorder the pins in all instances to match.
|
||||
* Note that we cannot just reorder the SPICE pins to match the
|
||||
* verilog order, because there may be other SPICE netlists which
|
||||
* instance the cell with the correct SPICE port order.
|
||||
*/
|
||||
tpsave = tp;
|
||||
CellDef("_PLACEHOLDER_", filenum);
|
||||
tp = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
}
|
||||
}
|
||||
else if (tp == NULL) { /* Completely new cell, no name conflict */
|
||||
CellDef(model, filenum);
|
||||
@@ -691,6 +728,38 @@ skip_ends:
|
||||
if (*CellStackPtr) PopStack(CellStackPtr);
|
||||
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||
SkipNewLine(NULL);
|
||||
|
||||
if (tpsave != NULL) {
|
||||
struct nlist *tpplace;
|
||||
char *savename;
|
||||
|
||||
/* Handle a placeholder from a verilog file that has been replaced
|
||||
* by a netlist with pins in a different order. The pins need to
|
||||
* be matched, corrected in the original cell and all instances,
|
||||
* and the new cell deleted.
|
||||
*/
|
||||
|
||||
Printf("Verilog placeholder %s replaced by SPICE definition\n",
|
||||
tpsave->name);
|
||||
tpplace = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
/* MatchPins is part of netcmp and normally Circuit2 is the
|
||||
* circuit being matched, so set Circuit2 to the original
|
||||
* verilog black-box cell, and MatchPins() will force its
|
||||
* pins to be rearranged to match the SPICE definition just
|
||||
* read.
|
||||
*/
|
||||
Circuit2 = tpsave;
|
||||
MatchPins(tpplace, tpsave, 0);
|
||||
savename = strsave(tpsave->name);
|
||||
/* Now the original verilog black-box cell can be removed */
|
||||
FreePorts(savename);
|
||||
CellDelete(savename, filenum);
|
||||
/* And _PLACEHOLDER_ is renamed to the original name of the cell. */
|
||||
CellRehash("_PLACEHOLDER_", savename, filenum);
|
||||
tpsave = NULL;
|
||||
Circuit2 = NULL;
|
||||
FREE(savename);
|
||||
}
|
||||
}
|
||||
else if (matchnocase(nexttok, ".MODEL")) {
|
||||
unsigned char class = CLASS_SUBCKT;
|
||||
|
||||
+38
-30
@@ -57,6 +57,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "netfile.h"
|
||||
#include "print.h"
|
||||
#include "hash.h"
|
||||
#include "netcmp.h"
|
||||
|
||||
// See netfile.c for explanation of delimiters. 'X'
|
||||
// separates single-character delimiters from two-character delimiters.
|
||||
@@ -1018,7 +1019,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
char *eqptr, *matchptr;
|
||||
struct keyvalue *kvlist = NULL;
|
||||
char inst[MAX_STR_LEN], model[MAX_STR_LEN], portname[MAX_STR_LEN], pkey[MAX_STR_LEN];
|
||||
struct nlist *tp;
|
||||
struct nlist *tp, *tpsave;
|
||||
struct objlist *parent, *sobj, *nobj, *lobj, *pobj, *cref;
|
||||
|
||||
inst[MAX_STR_LEN-1] = '\0';
|
||||
@@ -1152,6 +1153,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
|
||||
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
tpsave = NULL;
|
||||
hasports = (char)0;
|
||||
|
||||
/* Check for name conflict with duplicate cell names */
|
||||
@@ -1191,35 +1193,9 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
tp = LookupCellFile(nexttok, filenum);
|
||||
}
|
||||
else if (tp != NULL) { /* Cell exists, but as a placeholder */
|
||||
struct nlist *tptmp = NULL;
|
||||
char ctemp[8];
|
||||
int n = 0;
|
||||
|
||||
/* This redefines a placeholder module to an unused temporary cell name */
|
||||
while (1) {
|
||||
sprintf(ctemp, "%d", n);
|
||||
tptmp = LookupCellFile(ctemp, filenum);
|
||||
if (tptmp == NULL) break;
|
||||
n++;
|
||||
}
|
||||
CellRehash(nexttok, ctemp, filenum);
|
||||
tptmp = LookupCellFile(ctemp, filenum);
|
||||
|
||||
/* Create a new module definition */
|
||||
CellDef(model, filenum);
|
||||
tp = LookupCellFile(model, filenum);
|
||||
|
||||
/* Find an instance of this module in the netlist */
|
||||
cref = FindInstanceOf(tp);
|
||||
if ((cref != NULL) && (cref->name != NULL)) {
|
||||
hasports = (char)1;
|
||||
/* Copy ports from the original parent cell to the new parent cell */
|
||||
for (pobj = tptmp->cell; pobj && (pobj->type == PORT); pobj = pobj->next)
|
||||
Port(pobj->name);
|
||||
}
|
||||
/* Remove the original cell definition */
|
||||
FreePorts(ctemp);
|
||||
CellDelete(ctemp, filenum); /* This removes any PLACEHOLDER flag */
|
||||
tpsave = tp;
|
||||
CellDef("_PLACEHOLDER_", filenum);
|
||||
tp = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
}
|
||||
else if (tp == NULL) { /* Completely new cell, no name conflict */
|
||||
CellDef(model, filenum);
|
||||
@@ -1428,6 +1404,38 @@ skip_endmodule:
|
||||
if (*CellStackPtr) PopStack(CellStackPtr);
|
||||
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
|
||||
SkipNewLine(VLOG_DELIMITERS);
|
||||
|
||||
if (tpsave != NULL) {
|
||||
struct nlist *tpplace;
|
||||
char *savename;
|
||||
|
||||
/* Handle a placeholder from a verilog file that has been replaced
|
||||
* by a netlist with pins in a different order. The pins need to
|
||||
* be matched, corrected in the original cell and all instances,
|
||||
* and the new cell deleted.
|
||||
*/
|
||||
|
||||
Printf("Verilog placeholder module %s replaced by module definition\n",
|
||||
tpsave->name);
|
||||
tpplace = LookupCellFile("_PLACEHOLDER_", filenum);
|
||||
/* MatchPins is part of netcmp and normally Circuit2 is the
|
||||
* circuit being matched, so set Circuit2 to the original
|
||||
* verilog black-box cell, and MatchPins() will force its
|
||||
* pins to be rearranged to match the module definition just
|
||||
* read.
|
||||
*/
|
||||
Circuit2 = tpsave;
|
||||
MatchPins(tpplace, tpsave, 0);
|
||||
savename = strsave(tpsave->name);
|
||||
/* Now the original verilog black-box cell can be removed */
|
||||
FreePorts(savename);
|
||||
CellDelete(savename, filenum);
|
||||
/* And _PLACEHOLDER_ is renamed to the original name of the cell. */
|
||||
CellRehash("_PLACEHOLDER_", savename, filenum);
|
||||
tpsave = NULL;
|
||||
Circuit2 = NULL;
|
||||
FREE(savename);
|
||||
}
|
||||
}
|
||||
|
||||
else if (match(nexttok, "`include")) {
|
||||
|
||||
Vendored
+1
-52
@@ -668,7 +668,6 @@ XMKMF
|
||||
HAVE_PYTHON3
|
||||
EGREP
|
||||
GREP
|
||||
M4
|
||||
RANLIB
|
||||
INSTALL_DATA
|
||||
INSTALL_SCRIPT
|
||||
@@ -3702,56 +3701,6 @@ else
|
||||
fi
|
||||
|
||||
|
||||
for ac_prog in gm4 gnum4 m4
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_M4+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $M4 in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_M4="$M4" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_M4="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
M4=$ac_cv_path_M4
|
||||
if test -n "$M4"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
|
||||
$as_echo "$M4" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
test -n "$M4" && break
|
||||
done
|
||||
test -n "$M4" || M4="no"
|
||||
|
||||
if test x$M4 = xno; then
|
||||
as_fn_error $? "M4 is required" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
if test "$CPP" = "$CC -E" ; then
|
||||
CPP="$CPP -x c"
|
||||
@@ -6302,7 +6251,7 @@ fi
|
||||
|
||||
*darwin*)
|
||||
SHDLIB_EXT=".dylib"
|
||||
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||
;;
|
||||
|
||||
@@ -26,12 +26,6 @@ AC_ISC_POSIX
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_RANLIB
|
||||
|
||||
dnl GNU M4 is preferred due to some of the option switches.
|
||||
AC_PATH_PROGS([M4], [gm4 gnum4 m4], [no])
|
||||
if test x$M4 = xno; then
|
||||
AC_MSG_ERROR([M4 is required])
|
||||
fi
|
||||
|
||||
dnl check size of pointer for correct behavior on 64-bit systems
|
||||
dnl If the C preprocessor is GCC, we need to force the flag to
|
||||
dnl assert that input files are of type C, or else the preprocessing
|
||||
@@ -1033,7 +1027,7 @@ fi
|
||||
|
||||
*darwin*)
|
||||
SHDLIB_EXT=".dylib"
|
||||
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind"
|
||||
LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
|
||||
LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
|
||||
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
|
||||
;;
|
||||
|
||||
+1
-2
@@ -1595,8 +1595,7 @@ _netgen_model(ClientData clientData,
|
||||
return result;
|
||||
|
||||
if (objc == 3) {
|
||||
model = Tcl_GetString(objv[2]);
|
||||
nports = NumberOfPorts(model, fnum);
|
||||
nports = NumberOfPorts(tp->name, fnum);
|
||||
|
||||
if (Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)modelclasses,
|
||||
"class", 0, &index) != TCL_OK) {
|
||||
|
||||
Reference in New Issue
Block a user