Merge branch 'master' into netgen-1.5

This commit is contained in:
Tim Edwards 2025-08-27 02:00:03 -04:00
commit 5f5248b3d0
5 changed files with 242 additions and 10 deletions

View File

@ -1 +1 @@
1.5.297
1.5.298

View File

@ -8481,6 +8481,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. */

View File

@ -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();

View File

@ -594,6 +594,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

View File

@ -2572,6 +2572,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 +2674,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 +3433,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 +3482,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 +3504,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 +3557,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 +3579,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 +3593,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 +4039,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;