mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-23 14:37:42 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45164bbf98 | ||
|
|
2ee286efb4 | ||
|
|
46cb8d6637 | ||
|
|
dae6919d4f | ||
|
|
017bdc6e48 | ||
|
|
2825b786b7 | ||
|
|
b371af9235 | ||
|
|
0af8c7ad49 | ||
|
|
b5432d139b | ||
|
|
0aa20dcf62 | ||
|
|
0e958bd45c | ||
|
|
7cbf15aab1 | ||
|
|
b59196fa81 | ||
|
|
1de6f88f1e | ||
|
|
6e6e9fb73f | ||
|
|
33fed391fd | ||
|
|
e84700a607 | ||
|
|
5f5248b3d0 | ||
|
|
0bee21ccc8 | ||
|
|
80f9263004 | ||
|
|
c269f1de89 |
+53
-14
@@ -1756,6 +1756,11 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
modified1++;
|
||||
}
|
||||
else if (ecomp->cell1 && (ecomp->num1 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell1->name, name1, file1);
|
||||
}
|
||||
if (ecomp->cell2 && (ecomp->num2 > 0) &&
|
||||
(!(ecomp->cell2->flags & CELL_PLACEHOLDER))) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
@@ -1764,6 +1769,11 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
modified2++;
|
||||
}
|
||||
else if (ecomp->cell2 && (ecomp->num2 > 0)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell2->name, name2, file2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset or apply the count adjustments */
|
||||
@@ -1854,6 +1864,11 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
flattenInstancesOf(name2, file2, ecomp->cell2->name);
|
||||
modified2++;
|
||||
}
|
||||
else if (ecomp->cell2) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell2->name, name2, file2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1920,6 +1935,11 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
flattenInstancesOf(name1, file1, ecomp->cell1->name);
|
||||
modified1++;
|
||||
}
|
||||
else if (ecomp->cell1) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
|
||||
" would make a better match but is prohibited.\n",
|
||||
ecomp->cell1->name, name1, file1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2271,13 +2291,23 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
ecompX0->cell1->file, &compdict);
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
"(%d) makes a better match\n",
|
||||
ecompX0->cell1->name, name1, file1);
|
||||
flattenInstancesOf(name1, file1, ecompX0->cell1->name);
|
||||
ecompX0->num1 = 0;
|
||||
ecomp0X->num1 += ecompX0->num1;
|
||||
modified1++;
|
||||
if (!(ecompX0->cell1->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell"
|
||||
" %s (%d) makes a better match\n",
|
||||
ecompX0->cell1->name, name1, file1);
|
||||
flattenInstancesOf(name1, file1,
|
||||
ecompX0->cell1->name);
|
||||
ecompX0->num1 = 0;
|
||||
ecomp0X->num1 += ecompX0->num1;
|
||||
modified1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Fprintf(stdout, "Flattening instances of %s in "
|
||||
"cell %s (%d) would make a better "
|
||||
"match but is prohibited.\n",
|
||||
ecompX0->cell1->name, name1, file1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2297,13 +2327,22 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
|
||||
ecomp0X->cell2->file, &compdict);
|
||||
if (dstr) *dstr = '[';
|
||||
if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell %s"
|
||||
" (%d) makes a better match\n",
|
||||
ecomp0X->cell2->name, name2, file2);
|
||||
flattenInstancesOf(name2, file2, ecomp0X->cell2->name);
|
||||
ecomp0X->num2 = 0;
|
||||
ecompX0->num2 += ecomp0X->num2;
|
||||
modified2++;
|
||||
if (!(ecomp0X->cell2->flags & CELL_PLACEHOLDER)) {
|
||||
Fprintf(stdout, "Flattening instances of %s in cell"
|
||||
" %s (%d) makes a better match\n",
|
||||
ecomp0X->cell2->name, name2, file2);
|
||||
flattenInstancesOf(name2, file2,
|
||||
ecomp0X->cell2->name);
|
||||
ecomp0X->num2 = 0;
|
||||
ecompX0->num2 += ecomp0X->num2;
|
||||
modified2++;
|
||||
}
|
||||
else {
|
||||
Fprintf(stdout, "Flattening instances of %s in "
|
||||
"cell %s (%d) would make a better "
|
||||
"match but is prohibited.\n",
|
||||
ecompX0->cell2->name, name2, file2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+281
-33
@@ -5218,14 +5218,23 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
|
||||
if (comb == TRUE) {
|
||||
double pd;
|
||||
int hascrit = FALSE;
|
||||
int mult, cidx = -1;
|
||||
struct valuelist *avl, *cvl = NULL;
|
||||
struct valuelist **avl, **cvl;
|
||||
struct valuelist *cvlp;
|
||||
|
||||
critval.type = PROP_ENDLIST;
|
||||
critval.value.dval = 0.0;
|
||||
|
||||
/* Track properties separately so that multiple properties can be
|
||||
* added together (e.g., area and perimeter)
|
||||
*/
|
||||
avl = (struct valuelist **)CALLOC(pcount, sizeof(struct valuelist *));
|
||||
cvl = (struct valuelist **)CALLOC(pcount, sizeof(struct valuelist *));
|
||||
|
||||
for (i = 0; i < run; i++) {
|
||||
avl = NULL;
|
||||
// if (vlist[0][i] == NULL) continue;
|
||||
// mult = vlist[0][i]->value.ival;
|
||||
for (p = 0; p < pcount; p++) avl[p] = NULL;
|
||||
|
||||
if (vlist[0][i] == NULL)
|
||||
mult = 1;
|
||||
else
|
||||
@@ -5242,6 +5251,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
|
||||
/* critical properties never combine, but track them */
|
||||
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) {
|
||||
hascrit = TRUE;
|
||||
pd = 2 * fabs(vl->value.dval - critval.value.dval) /
|
||||
(vl->value.dval + critval.value.dval);
|
||||
if ((vl->type != critval.type) || (pd > kl->slop.dval))
|
||||
@@ -5253,6 +5263,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
continue;
|
||||
}
|
||||
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) {
|
||||
hascrit = TRUE;
|
||||
pd = 2 * fabs(vl->value.dval - critval.value.dval) /
|
||||
(vl->value.dval + critval.value.dval);
|
||||
if ((vl->type != critval.type) || (pd > kl->slop.dval))
|
||||
@@ -5286,19 +5297,30 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
}
|
||||
}
|
||||
if (ctype & (MERGE_S_ADD | MERGE_P_ADD | MERGE_S_PAR | MERGE_P_PAR))
|
||||
avl = vl;
|
||||
avl[p] = vl;
|
||||
}
|
||||
if (cidx == i) cvl = avl;
|
||||
if (hascrit == FALSE) cidx = 0; /* No critical property */
|
||||
|
||||
/* Each time a new critical value is found, set the location */
|
||||
/* of the property record that will collect the summation or */
|
||||
/* parallel combination of values. */
|
||||
if (cidx == i) {
|
||||
for (p = 1; p < pcount; p++) {
|
||||
cvl[p] = avl[p];
|
||||
}
|
||||
}
|
||||
|
||||
/* Sorting should have put all records with the same critical */
|
||||
/* value together sequentially. So if there are still */
|
||||
/* multiple property records, then merge them into the first */
|
||||
/* record with the same critical property value. */
|
||||
/* record with the same critical property value. If no */
|
||||
/* critical value exists, then all records can be merged. */
|
||||
|
||||
if ((i > 0) && (cidx >= 0) && (cidx < i)) {
|
||||
for (p = 1; p < pcount; p++) {
|
||||
vl = vlist[p][i];
|
||||
ctype = clist[p][i];
|
||||
cvlp = cvl[p];
|
||||
|
||||
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
|
||||
if (!vlist[0][i]) {
|
||||
@@ -5307,21 +5329,21 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
sizeof(struct valuelist));
|
||||
}
|
||||
vlist[0][i]->value.ival = 0; /* set M to 0 */
|
||||
if (cvl && (cvl->type == PROP_INTEGER))
|
||||
if (cvlp && (cvlp->type == PROP_INTEGER))
|
||||
{
|
||||
if (vl->type == PROP_INTEGER)
|
||||
cvl->value.ival += vl->value.ival;
|
||||
cvlp->value.ival += vl->value.ival;
|
||||
else {
|
||||
cvl->type = PROP_DOUBLE;
|
||||
cvl->value.dval = (double)cvl->value.ival + vl->value.dval;
|
||||
cvlp->type = PROP_DOUBLE;
|
||||
cvlp->value.dval = (double)cvlp->value.ival + vl->value.dval;
|
||||
}
|
||||
}
|
||||
else if ((cvl && vl->type == PROP_DOUBLE))
|
||||
else if ((cvlp && vl->type == PROP_DOUBLE))
|
||||
{
|
||||
if (vl->type == PROP_INTEGER)
|
||||
cvl->value.dval += (double)vl->value.ival;
|
||||
cvlp->value.dval += (double)vl->value.ival;
|
||||
else
|
||||
cvl->value.dval += vl->value.dval;
|
||||
cvlp->value.dval += vl->value.dval;
|
||||
}
|
||||
}
|
||||
else if (ctype & (MERGE_S_PAR | MERGE_P_PAR)) {
|
||||
@@ -5331,21 +5353,22 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
sizeof(struct valuelist));
|
||||
}
|
||||
vlist[0][i]->value.ival = 0; /* set M to 0 */
|
||||
/* To do parallel combination, both types need to
|
||||
/* Parallel value combination: (X * Y) / (X + Y)
|
||||
* To do parallel combination, both types need to
|
||||
* be double, so recast them if they are integer.
|
||||
*/
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
vl->type = PROP_DOUBLE;
|
||||
vl->value.dval = (double)(vl->value.ival);
|
||||
}
|
||||
if (cvl && (cvl->type == PROP_INTEGER)) {
|
||||
cvl->type = PROP_DOUBLE;
|
||||
cvl->value.dval = (double)cvl->value.ival;
|
||||
if (cvlp && (cvlp->type == PROP_INTEGER)) {
|
||||
cvlp->type = PROP_DOUBLE;
|
||||
cvlp->value.dval = (double)cvlp->value.ival;
|
||||
}
|
||||
if ((cvl && (vl->type == PROP_DOUBLE))) {
|
||||
cvl->value.dval =
|
||||
sqrt(cvl->value.dval * cvl->value.dval
|
||||
+ vl->value.dval * vl->value.dval);
|
||||
if ((cvlp && (vl->type == PROP_DOUBLE))) {
|
||||
cvlp->value.dval =
|
||||
(vl->value.dval * cvlp->value.dval) /
|
||||
(vl->value.dval + cvlp->value.dval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5357,6 +5380,9 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
|
||||
Printf("Combined %d parallel devices.\n", changed);
|
||||
}
|
||||
}
|
||||
|
||||
FREE(avl);
|
||||
FREE(cvl);
|
||||
}
|
||||
|
||||
// Remove entries with M (S) = 0
|
||||
@@ -7601,6 +7627,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 P1, P2;
|
||||
int filenum = -1;
|
||||
int *correspond;
|
||||
char *ostr;
|
||||
@@ -7633,6 +7660,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
return 2;
|
||||
}
|
||||
|
||||
correspond = (int *)CALLOC((tc1->nodename_cache_maxnodenum + 1), sizeof(int));
|
||||
cover = (char *)CALLOC(numnodes, sizeof(char));
|
||||
numorig = numnodes;
|
||||
|
||||
@@ -7851,8 +7879,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
|
||||
ob1 = tc1->cell;
|
||||
|
||||
correspond = (int *)CALLOC((tc1->nodename_cache_maxnodenum + 1), sizeof(int));
|
||||
|
||||
for (i = 0; i < numorig; i++) {
|
||||
bangptr1 = strrchr(ob1->name, '!');
|
||||
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
|
||||
@@ -7973,7 +7999,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (bangptr2) *bangptr2 = '!';
|
||||
break;
|
||||
}
|
||||
else {
|
||||
else if (IsPort(ob1) && IsPort(ob2)) {
|
||||
struct Permutation *permute1, *permute2;
|
||||
struct objlist *ob1a = NULL, *ob2a = NULL;
|
||||
|
||||
@@ -7983,30 +8009,28 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
*/
|
||||
for (permute1 = tc1->permutes; permute1; permute1 = permute1->next) {
|
||||
if ((*matchfunc)(ob1->name, permute1->pin1)) {
|
||||
ob1a = LookupObject(permute1->pin1, tc1);
|
||||
ob2a = LookupObject(permute1->pin2, tc2);
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(ob1->name, permute1->pin2)) {
|
||||
ob1a = LookupObject(permute1->pin2, tc1);
|
||||
ob2a = LookupObject(permute1->pin1, tc2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (permute2 = tc2->permutes; permute2; permute2 = permute2->next) {
|
||||
if ((*matchfunc)(ob2->name, permute2->pin1)) {
|
||||
ob2a = LookupObject(permute2->pin1, tc2);
|
||||
ob1a = LookupObject(permute2->pin2, tc1);
|
||||
break;
|
||||
}
|
||||
else if ((*matchfunc)(ob2->name, permute2->pin2)) {
|
||||
ob2a = LookupObject(permute2->pin2, tc2);
|
||||
ob1a = LookupObject(permute2->pin1, tc1);
|
||||
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 */
|
||||
if ((correspond[ob1->node] == 0) ||
|
||||
(correspond[ob1->node] == ob2->node)) {
|
||||
ob2->model.port = i; /* save order */
|
||||
*(cover + i) = (char)1;
|
||||
|
||||
@@ -8172,6 +8196,14 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
hasproxy1 = 1;
|
||||
|
||||
HashPtrInstall(obn->name, obn, &(tc1->objdict));
|
||||
|
||||
/* If this is a black-box circuit, then the pin has not been output */
|
||||
if (NodeClasses == NULL) {
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", "(no matching pin)");
|
||||
output_string_right(ostr, "%s", ob2->name);
|
||||
output_string_print(ostr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8242,6 +8274,14 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
hasproxy2 = 1;
|
||||
|
||||
HashPtrInstall(obn->name, obn, &(tc2->objdict));
|
||||
|
||||
/* If this is a black-box circuit, then the pin has not been output */
|
||||
if (NodeClasses == NULL) {
|
||||
output_string_fill(ostr);
|
||||
output_string_left(ostr, "%s", ob1->name);
|
||||
output_string_right(ostr, "%s", "(no matching pin)");
|
||||
output_string_print(ostr);
|
||||
}
|
||||
}
|
||||
|
||||
else if (ob1 != NULL && ob1->type == PORT && ob1->node < 0) {
|
||||
@@ -8269,6 +8309,38 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
|
||||
if (Debug == 0)
|
||||
output_string_print_divider(ostr, FALSE);
|
||||
|
||||
/* Catch errors where disconnected ports get effectively hidden by */
|
||||
/* pin permutations. */
|
||||
|
||||
if (result == 1) {
|
||||
int found = 0;
|
||||
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
|
||||
P1 = P2 = 0;
|
||||
for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) {
|
||||
if (N1->graph == Circuit2->file)
|
||||
if (IsPort(N1->object)) P2++;
|
||||
if (N1->graph == Circuit1->file)
|
||||
if (IsPort(N1->object)) P1++;
|
||||
}
|
||||
if (P1 != P2) {
|
||||
if (found == 0)
|
||||
Fprintf(stdout, "\nPort connection errors found:\n");
|
||||
found = 1;
|
||||
for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) {
|
||||
obn = N1->object;
|
||||
|
||||
if (IsPort(obn))
|
||||
Fprintf(stdout, " %s (%d)\n", obn->name, N1->graph);
|
||||
else
|
||||
Fprintf(stdout, " %s (%d) (no port)\n", obn->name, N1->graph);
|
||||
if (N1->graph == Circuit1->file)
|
||||
correspond[obn->node] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found == 1) Fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
/* Run cleanuppins on circuit 1 */
|
||||
if (needclean1)
|
||||
CleanupPins(tc1->name, tc1->file);
|
||||
@@ -8481,6 +8553,182 @@ int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Structure and definitins used by derivedprops() */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
enum DerivedType {area_type, perimeter_type};
|
||||
|
||||
typedef struct _derivedpropdata {
|
||||
struct nlist *cell;
|
||||
int fnum;
|
||||
char *pwidth;
|
||||
char *plength;
|
||||
enum DerivedType type;
|
||||
} DerivedPropData;
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* derivedprops --- Callback function for a recursive */
|
||||
/* search over all cells with a pointer clientdata. */
|
||||
/* The pointer is a DerivedPropData structure that */
|
||||
/* contains the information needed to determine how to */
|
||||
/* generate an "area" or "perimeter" property based on */
|
||||
/* the device length and width. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct nlist *derivedprops(struct hashlist *p, void *clientdata)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob;
|
||||
struct valuelist *vl, *newvlist;
|
||||
struct nlist *tc;
|
||||
struct property *prop;
|
||||
int i;
|
||||
double valuew, valuel, valuea = 0.0, valuep = 0.0;
|
||||
int haswidth = FALSE, haslength = FALSE;
|
||||
int hasarea = FALSE, hasperimeter = FALSE;
|
||||
|
||||
DerivedPropData *dpd = (DerivedPropData *)clientdata;
|
||||
|
||||
tc = dpd->cell;
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
if (ptr->file != tc->file) return NULL;
|
||||
|
||||
/* Search all instances in the cell for properties, find those matching
|
||||
* the cell class to be modified, and create a new derived property for
|
||||
* area or perimeter for that instance.
|
||||
*/
|
||||
|
||||
for (ob = ptr->cell; ob; ob = ob->next) {
|
||||
if (ob->type == PROPERTY) {
|
||||
if ((*matchfunc)(ob->model.class, tc->name)) {
|
||||
for (i = 0;; i++) {
|
||||
vl = &(ob->instance.props[i]);
|
||||
if (vl->type == PROP_ENDLIST) break;
|
||||
prop = (struct property *)HashLookup(vl->key, &(tc->propdict));
|
||||
if (prop != NULL) {
|
||||
if ((*matchfunc)(vl->key, dpd->pwidth)) {
|
||||
haswidth = TRUE;
|
||||
if (vl->type == PROP_DOUBLE)
|
||||
valuew = vl->value.dval;
|
||||
else if (vl->type == PROP_INTEGER)
|
||||
valuew = (double)vl->value.ival;
|
||||
else
|
||||
haswidth = FALSE;
|
||||
}
|
||||
else if ((*matchfunc)(vl->key, dpd->plength)) {
|
||||
haslength = TRUE;
|
||||
if (vl->type == PROP_DOUBLE)
|
||||
valuel = vl->value.dval;
|
||||
else if (vl->type == PROP_INTEGER)
|
||||
valuel = (double)vl->value.ival;
|
||||
else
|
||||
haslength = FALSE;
|
||||
}
|
||||
else if ((dpd->type == area_type)
|
||||
&& ((*matchfunc)(vl->key, "area"))) {
|
||||
hasarea = TRUE;
|
||||
}
|
||||
else if ((dpd->type == perimeter_type)
|
||||
&& ((*matchfunc)(vl->key, "perimeter"))) {
|
||||
hasperimeter = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (haslength && haswidth) {
|
||||
|
||||
/* Once the property names for device width and length have
|
||||
* been found, and the values recorded, add the area or
|
||||
* perimeter value to the property list for the instance,
|
||||
* unless the instance already has the property.
|
||||
*/
|
||||
newvlist = (struct valuelist *)CALLOC(i + 1, sizeof(struct valuelist));
|
||||
vl = &newvlist[i];
|
||||
vl->key = NULL;
|
||||
vl->type = PROP_ENDLIST;
|
||||
vl->value.ival = 0;
|
||||
|
||||
vl = &newvlist[--i];
|
||||
if ((dpd->type == area_type) && (!hasarea)) {
|
||||
valuea = valuew * valuel;
|
||||
vl->key = strsave("area");
|
||||
vl->type = PROP_DOUBLE;
|
||||
vl->value.dval = valuea;
|
||||
|
||||
} else if ((dpd->type == perimeter_type) && (!hasperimeter)) {
|
||||
valuep = 2 * (valuew + valuel);
|
||||
vl->key = strsave("perimeter");
|
||||
vl->type = PROP_DOUBLE;
|
||||
vl->value.dval = valuep;
|
||||
}
|
||||
for (--i; i >= 0; i--) {
|
||||
vl = &newvlist[i];
|
||||
vl->key = ob->instance.props[i].key;
|
||||
vl->type = ob->instance.props[i].type;
|
||||
vl->value = ob->instance.props[i].value;
|
||||
}
|
||||
FREE(ob->instance.props);
|
||||
ob->instance.props = newvlist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Create a new "area" or "perimeter" property in all */
|
||||
/* instances of a given device, based on the specified */
|
||||
/* names for the width and length parameters. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
DeriveProperty(struct nlist *tc, int fnum, char *pwidth, char *plength,
|
||||
enum DerivedType type)
|
||||
{
|
||||
DerivedPropData dpd;
|
||||
|
||||
dpd.pwidth = pwidth;
|
||||
dpd.plength = plength;
|
||||
dpd.fnum = fnum;
|
||||
dpd.cell = tc;
|
||||
dpd.type = type;
|
||||
|
||||
/* Create the new derived property in the cell. */
|
||||
if (type == area_type)
|
||||
PropertyDouble(tc->name, fnum, "area", 0.01, 0.0);
|
||||
else if (type == perimeter_type)
|
||||
PropertyDouble(tc->name, fnum, "perimeter", 0.01, 0.0);
|
||||
else
|
||||
return;
|
||||
|
||||
/* Find all instances of the cell and add the derived property */
|
||||
RecurseCellHashTable2(derivedprops, (void *)(&dpd));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Create a new "area" property in all instances of a */
|
||||
/* given device, based on the specified width and */
|
||||
/* length parameter names. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
DeriveAreaProperty(struct nlist *tp, int fnum, char *pwidth, char *plength)
|
||||
{
|
||||
DeriveProperty(tp, fnum, pwidth, plength, area_type);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Create a new "perimeter" property in all instances */
|
||||
/* of a given device, based on the specified width and */
|
||||
/* length parameter names. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
void
|
||||
DerivePerimeterProperty(struct nlist *tp, int fnum, char *pwidth, char *plength)
|
||||
{
|
||||
DeriveProperty(tp, fnum, pwidth, plength, perimeter_type);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Flatten the two cells at the top of the compare */
|
||||
/* queue. */
|
||||
|
||||
@@ -70,6 +70,8 @@ extern int remove_group_tags(struct objlist *ob);
|
||||
#ifdef TCL_NETGEN
|
||||
extern int EquivalentNode();
|
||||
extern int EquivalentElement();
|
||||
extern void DeriveAreaProperty();
|
||||
extern void DerivePerimeterProperty();
|
||||
|
||||
extern void enable_interrupt();
|
||||
extern void disable_interrupt();
|
||||
|
||||
+6
-1
@@ -302,7 +302,7 @@ int GetNextLineNoNewline(char *delimiter)
|
||||
{
|
||||
char *newbuf;
|
||||
int testc;
|
||||
int nested = 0;
|
||||
static int nested = 0;
|
||||
int llen;
|
||||
|
||||
if (feof(infile)) return -1;
|
||||
@@ -329,6 +329,11 @@ int GetNextLineNoNewline(char *delimiter)
|
||||
llen = strlen(line);
|
||||
}
|
||||
while (llen == linesize - 1) {
|
||||
/* Note that in the rare case where a newline is in the last buffer
|
||||
* position, we're done.
|
||||
*/
|
||||
if (*(line + llen - 1) == '\n') break;
|
||||
|
||||
newbuf = (char *)MALLOC(linesize + 501);
|
||||
strcpy(newbuf, line);
|
||||
FREE(line);
|
||||
|
||||
+11
-2
@@ -532,8 +532,14 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
|
||||
|
||||
SkipTok(NULL); /* get the next token */
|
||||
if ((EndParseFile()) && (nexttok == NULL)) break;
|
||||
if (nexttok == NULL) break;
|
||||
|
||||
if (nexttok[0] == '*') SkipNewLine(NULL);
|
||||
/* Handle comment lines. Note that some variants of CDL format
|
||||
* use "*." for information that is transparent to SPICE simulators.
|
||||
* Handle "*.GLOBAL" entries. All others are ignored.
|
||||
*/
|
||||
if ((nexttok[0] == '*') && (!matchnocase(nexttok, "*.GLOBAL")))
|
||||
SkipNewLine(NULL);
|
||||
|
||||
else if (matchnocase(nexttok, ".SUBCKT")) {
|
||||
SpiceTokNoNewline();
|
||||
@@ -821,7 +827,10 @@ skip_ends:
|
||||
|
||||
// Handle some commonly-used cards
|
||||
|
||||
else if (matchnocase(nexttok, ".GLOBAL")) {
|
||||
/* .GLOBAL and *.GLOBAL. Note that *.GLOBAL is excepted from comment-line
|
||||
* handling, above, so any line starting with '*' is "*.GLOBAL".
|
||||
*/
|
||||
else if (matchnocase(nexttok, ".GLOBAL") || (nexttok[0] == '*')) {
|
||||
while (nexttok != NULL) {
|
||||
int numnodes = 0;
|
||||
SpiceTokNoNewline();
|
||||
|
||||
+7
-5
@@ -2614,13 +2614,15 @@ nextinst:
|
||||
if (scan == NULL) {
|
||||
char localnet[MAX_STR_LEN];
|
||||
|
||||
/* Assume an implicit unconnected pin */
|
||||
sprintf(localnet, "_noconnect_%d_", localcount++);
|
||||
Node(localnet);
|
||||
join(localnet, obptr->name);
|
||||
Fprintf(stdout,
|
||||
/* Assume an implicit unconnected pin, unless there are no pins */
|
||||
if (strcmp(obpinname, "(no pins)")) {
|
||||
sprintf(localnet, "_noconnect_%d_", localcount++);
|
||||
Node(localnet);
|
||||
join(localnet, obptr->name);
|
||||
Fprintf(stdout,
|
||||
"Note: Implicit pin %s in instance %s of %s in cell %s\n",
|
||||
obpinname, locinst, modulename, CurrentCell->name);
|
||||
}
|
||||
}
|
||||
else if (GetBus(scan->net, &wb) == 0) {
|
||||
char *bptr2;
|
||||
|
||||
@@ -477,6 +477,18 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
set cell2 [lindex $clist2 $cidx]
|
||||
}
|
||||
|
||||
# The "noflat" list is non-file-specific, so run on each file.
|
||||
foreach cell $noflat {
|
||||
set cidx [lsearch -regexp $clist1 ^$cell$]
|
||||
if {$cidx >= 0} {
|
||||
netgen::flatten prohibit "$fnum1 $cell"
|
||||
}
|
||||
set cidx [lsearch -regexp $clist2 ^$cell$]
|
||||
if {$cidx >= 0} {
|
||||
netgen::flatten prohibit "$fnum2 $cell"
|
||||
}
|
||||
}
|
||||
|
||||
netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2"
|
||||
|
||||
if {$setupfile == ""} {
|
||||
@@ -594,6 +606,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
|
||||
lappend properr [lindex $endval 0]
|
||||
} elseif {$uresult == -2} { ;# unmatched pins
|
||||
set doCheckFlatten 1
|
||||
} elseif {$uresult == -4} { ;# unmatched pins and properties
|
||||
lappend properr [lindex $endval 0]
|
||||
set doCheckFlatten 1
|
||||
}
|
||||
} else {
|
||||
# not equivalent
|
||||
|
||||
+72
-17
@@ -1021,7 +1021,7 @@ _netgen_flatten(ClientData clientData,
|
||||
{
|
||||
char *repstr, *file;
|
||||
int result, llen, filenum;
|
||||
struct nlist *tp, *tp2;
|
||||
struct nlist *tp, *tp2, *tptop;
|
||||
|
||||
if ((objc < 2) || (objc > 4)) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?class? valid_cellname");
|
||||
@@ -1035,7 +1035,7 @@ _netgen_flatten(ClientData clientData,
|
||||
if (objc >= 3) {
|
||||
char *argv = Tcl_GetString(objv[1]);
|
||||
if (!strcmp(argv, "class")) {
|
||||
tp = GetTopCell(filenum);
|
||||
tptop = GetTopCell(filenum);
|
||||
|
||||
if (objc == 4) {
|
||||
int numflat;
|
||||
@@ -1046,7 +1046,7 @@ _netgen_flatten(ClientData clientData,
|
||||
}
|
||||
else {
|
||||
Printf("Flattening instances of %s in cell %s within file %s\n",
|
||||
repstr, tp2->name, tp->name);
|
||||
repstr, tp2->name, tptop->name);
|
||||
numflat = flattenInstancesOf(tp2->name, filenum, repstr);
|
||||
if (numflat == 0) {
|
||||
Tcl_SetResult(interp, "No instances found to flatten.", NULL);
|
||||
@@ -1055,15 +1055,19 @@ _netgen_flatten(ClientData clientData,
|
||||
}
|
||||
}
|
||||
else {
|
||||
Printf("Flattening instances of %s in file %s\n", repstr, tp->name);
|
||||
Printf("Flattening instances of %s in file %s\n", repstr, tptop->name);
|
||||
FlattenInstancesOf(repstr, filenum);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv, "prohibit") || !strcmp(argv, "deny")) {
|
||||
tp = GetTopCell(filenum);
|
||||
Printf("Will not flatten instances of %s in file %s\n", repstr, tp->name);
|
||||
/* Mark cell as placeholder so it will not be flattened */
|
||||
tp->flags |= CELL_PLACEHOLDER;
|
||||
tptop = GetTopCell(filenum);
|
||||
if (tp == NULL)
|
||||
Printf("Error: Cell %s does not exist.\n", repstr);
|
||||
else {
|
||||
Printf("Will not flatten instances of %s in file %s\n", repstr, tptop->name);
|
||||
/* Mark cell as placeholder so it will not be flattened */
|
||||
tp->flags |= CELL_PLACEHOLDER;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "class valid_cellname");
|
||||
@@ -2572,6 +2576,7 @@ _netcmp_run(ClientData clientData,
|
||||
/* 0: not verified */
|
||||
/* -1: no elements or nodes */
|
||||
/* -3: verified with property error */
|
||||
/* -4: verified with property and port errors */
|
||||
/* equiv option */
|
||||
/* -2: pin mismatch */
|
||||
/* */
|
||||
@@ -2673,8 +2678,12 @@ _netcmp_verify(ClientData clientData,
|
||||
else if (automorphisms == -2) {
|
||||
if (index == EQUIV_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
|
||||
else if (index == UNIQUE_IDX)
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-2));
|
||||
else if (index == UNIQUE_IDX) {
|
||||
if (PropertyErrorDetected == 0)
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-2));
|
||||
else
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(-4));
|
||||
}
|
||||
else if (index > 0)
|
||||
Fprintf(stdout, "Circuits match uniquely with port errors.\n");
|
||||
}
|
||||
@@ -3428,13 +3437,21 @@ _netcmp_property(ClientData clientData,
|
||||
double dval;
|
||||
int ival, argstart;
|
||||
|
||||
char *topoptions[] = {
|
||||
"default", "series", "serial", "parallel", "topology", NULL
|
||||
};
|
||||
enum TopOptionIdx {
|
||||
TOP_DEFAULT_IDX, TOP_SERIES_IDX, TOP_SERIAL_IDX, TOP_PARALLEL_IDX,
|
||||
TOP_TOPOLOGY_IDX
|
||||
};
|
||||
|
||||
char *options[] = {
|
||||
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
|
||||
"series", "parallel", "associate", "topology", NULL
|
||||
"series", "parallel", "associate", "derive", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX,
|
||||
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX, TOPOLOGY_IDX
|
||||
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX, DERIVE_IDX
|
||||
};
|
||||
int result, index, idx2;
|
||||
|
||||
@@ -3469,6 +3486,14 @@ _netcmp_property(ClientData clientData,
|
||||
COMB_NONE_IDX, COMB_PAR_IDX, COMB_ADD_IDX, COMB_CRITICAL_IDX
|
||||
};
|
||||
|
||||
char *deriveoptions[] = {
|
||||
"area", "perimeter", NULL
|
||||
};
|
||||
|
||||
enum DeriveOptionIdx {
|
||||
AREA_IDX, PERIMETER_IDX
|
||||
};
|
||||
|
||||
char *yesno[] = {
|
||||
"on", "yes", "true", "enable", "allow",
|
||||
"off", "no", "false", "disable", "prohibit", NULL
|
||||
@@ -3483,8 +3508,13 @@ _netcmp_property(ClientData clientData,
|
||||
"strict", "relaxed", NULL
|
||||
};
|
||||
|
||||
/* Don't need to check return value */
|
||||
index = -1;
|
||||
Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)topoptions,
|
||||
"option", 0, &index);
|
||||
|
||||
/* Check for special command "property default" */
|
||||
if ((objc == 2) && (!strcmp(Tcl_GetString(objv[1]), "default"))) {
|
||||
if ((objc == 2) && (index == TOP_DEFAULT_IDX)) {
|
||||
|
||||
/* For each FET device, do "merge {w add_critical}" and */
|
||||
/* "remove as ad ps pd". This allows parallel devices */
|
||||
@@ -3531,7 +3561,7 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc == 3) && (!strcmp(Tcl_GetString(objv[1]), "parallel"))) {
|
||||
else if ((objc == 3) && (index == TOP_PARALLEL_IDX)) {
|
||||
if (!strcmp(Tcl_GetString(objv[2]), "none")) {
|
||||
GlobalParallelNone = TRUE;
|
||||
SetParallelCombine(FALSE);
|
||||
@@ -3553,8 +3583,7 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc == 3) && ((!strcmp(Tcl_GetString(objv[1]), "series")) ||
|
||||
(!strcmp(Tcl_GetString(objv[1]), "serial")))) {
|
||||
else if ((objc == 3) && ((index == TOP_SERIES_IDX) || (index == TOP_SERIAL_IDX))) {
|
||||
if (!strcmp(Tcl_GetString(objv[2]), "none")) {
|
||||
SetSeriesCombine(FALSE);
|
||||
}
|
||||
@@ -3568,7 +3597,7 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
else if ((objc > 1) && (!strcmp(Tcl_GetString(objv[1]), "topology"))) {
|
||||
else if ((objc > 1) && (index == TOP_TOPOLOGY_IDX)) {
|
||||
if (objc == 2) {
|
||||
if (ExactTopology)
|
||||
Tcl_SetResult(interp, "Strict topology property matching.",
|
||||
@@ -4014,6 +4043,32 @@ _netcmp_property(ClientData clientData,
|
||||
}
|
||||
break;
|
||||
|
||||
case DERIVE_IDX:
|
||||
/* Create a derived property. For now, this just creates
|
||||
* "area" or "perimeter" properties. There may not (?)
|
||||
* be enough cause to make other ones. Unlike other
|
||||
* "property" options, this option causes the whole circuit
|
||||
* database to be searched for the device in question, and
|
||||
* the new property is added.
|
||||
*/
|
||||
if (objc < 6) {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "{area|perimeter width length}");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
result = Tcl_GetIndexFromObj(interp, objv[3],
|
||||
(CONST84 char **)deriveoptions,
|
||||
"area|perimeter", 0, &idx2);
|
||||
if (result != TCL_OK) return result;
|
||||
switch (idx2) {
|
||||
case AREA_IDX:
|
||||
DeriveAreaProperty(tp, fnum, Tcl_GetString(objv[4]),
|
||||
Tcl_GetString(objv[5]));
|
||||
break;
|
||||
case PERIMETER_IDX:
|
||||
DerivePerimeterProperty(tp, fnum, Tcl_GetString(objv[4]),
|
||||
Tcl_GetString(objv[5]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TCL_OK;
|
||||
|
||||
Reference in New Issue
Block a user