mirror of
https://github.com/RTimothyEdwards/netgen.git
synced 2026-08-22 22:17:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8300531858 | ||
|
|
80378d8816 | ||
|
|
80d981a672 | ||
|
|
809a3c16e9 | ||
|
|
8d976e5686 | ||
|
|
577dfb5a28 | ||
|
|
46252ad6b9 | ||
|
|
564fab9667 | ||
|
|
0df4190e19 | ||
|
|
2f661ea256 | ||
|
|
fca075e1ed | ||
|
|
cc2a5e0ee6 | ||
|
|
b7a8d3cfda | ||
|
|
0205902baa | ||
|
|
646b351ee5 | ||
|
|
31a0f10602 | ||
|
|
a2b1f5c85f | ||
|
|
9148edde69 | ||
|
|
bb07a84ae1 | ||
|
|
d753e2c208 | ||
|
|
bd3b88de4a | ||
|
|
668aa38340 | ||
|
|
d99bffa74f | ||
|
|
7ce3b1dcd8 | ||
|
|
366821fe7f |
@@ -20,7 +20,6 @@ int MaxCPUTime = 100; /* max number of seconds to burn */
|
||||
#define MAX_CHANGES_PER_ITER 2
|
||||
|
||||
#if 0
|
||||
/* INLINE */
|
||||
float RandomUniform(void)
|
||||
{
|
||||
/* DANGER! DANGER! Non-portable code below!! */
|
||||
|
||||
@@ -36,7 +36,6 @@ int CountFanoutOK;
|
||||
int CountSwallowedElements;
|
||||
|
||||
|
||||
INLINE
|
||||
int Independent(int E1, int E2)
|
||||
/* return 1 if E1 and E2 share no leaves in common */
|
||||
{
|
||||
@@ -47,7 +46,6 @@ int Independent(int E1, int E2)
|
||||
return(1);
|
||||
}
|
||||
|
||||
INLINE
|
||||
int FanoutOK(int E1, int E2)
|
||||
{
|
||||
int approxfanout;
|
||||
@@ -67,7 +65,6 @@ int FanoutOK(int E1, int E2)
|
||||
}
|
||||
|
||||
|
||||
INLINE
|
||||
int Swallowed(int Parent, int Child)
|
||||
/* returns 1 if Child's fanout is contained in Parent's */
|
||||
{
|
||||
@@ -107,7 +104,6 @@ int SmallEnough(int E1, int E2)
|
||||
}
|
||||
#endif
|
||||
|
||||
INLINE
|
||||
int SuccessfulEmbedding(int E)
|
||||
/* returns 1 if element E is a successful embedding */
|
||||
{
|
||||
|
||||
@@ -117,15 +117,6 @@
|
||||
#define memzero(ptr, len) memset(ptr, 0, len)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef INLINE
|
||||
#ifdef __GNUC__
|
||||
#define INLINE inline
|
||||
#else
|
||||
#define INLINE
|
||||
#endif /* __GNUC__ */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYSV_STRING
|
||||
#undef NEED_STRING
|
||||
#endif
|
||||
|
||||
@@ -348,7 +348,6 @@ void PRINTPACKED(unsigned long *mstar)
|
||||
#ifdef IBMPC
|
||||
static unsigned int lochash(unsigned long *mstar)
|
||||
#else
|
||||
INLINE
|
||||
static unsigned long lochash(unsigned long *mstar)
|
||||
#endif
|
||||
{
|
||||
@@ -432,7 +431,6 @@ static struct ex_entry *hashinstall(unsigned long *mstar)
|
||||
return(ex_tab[hashval] = np);
|
||||
}
|
||||
|
||||
/* INLINE */
|
||||
int Exists(int E1, int E2)
|
||||
{
|
||||
int i;
|
||||
@@ -470,7 +468,6 @@ int InitializeExistTest(void)
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* INLINE */
|
||||
void AddToExistSet(int E1, int E2)
|
||||
{
|
||||
int i;
|
||||
|
||||
+298
-230
@@ -1411,7 +1411,6 @@ int ElementListAllocated;
|
||||
int NodeListAllocated;
|
||||
#endif
|
||||
|
||||
INLINE
|
||||
struct Element *GetElement(void)
|
||||
{
|
||||
struct Element *new_element;
|
||||
@@ -1429,14 +1428,12 @@ struct Element *GetElement(void)
|
||||
return(new_element);
|
||||
}
|
||||
|
||||
INLINE
|
||||
void FreeElement(struct Element *old)
|
||||
{
|
||||
old->next = ElementFreeList;
|
||||
ElementFreeList = old;
|
||||
}
|
||||
|
||||
INLINE
|
||||
struct Node *GetNode(void)
|
||||
{
|
||||
struct Node *new_node;
|
||||
@@ -1454,14 +1451,12 @@ struct Node *GetNode(void)
|
||||
return(new_node);
|
||||
}
|
||||
|
||||
INLINE
|
||||
void FreeNode(struct Node *old)
|
||||
{
|
||||
old->next = NodeFreeList;
|
||||
NodeFreeList = old;
|
||||
}
|
||||
|
||||
INLINE
|
||||
struct ElementClass *GetElementClass(void)
|
||||
{
|
||||
struct ElementClass *new_elementclass;
|
||||
@@ -1481,14 +1476,12 @@ struct ElementClass *GetElementClass(void)
|
||||
return(new_elementclass);
|
||||
}
|
||||
|
||||
INLINE
|
||||
void FreeElementClass(struct ElementClass *old)
|
||||
{
|
||||
old->next = ElementClassFreeList;
|
||||
ElementClassFreeList = old;
|
||||
}
|
||||
|
||||
INLINE
|
||||
struct NodeClass *GetNodeClass(void)
|
||||
{
|
||||
struct NodeClass *new_nodeclass;
|
||||
@@ -1508,14 +1501,12 @@ struct NodeClass *GetNodeClass(void)
|
||||
return(new_nodeclass);
|
||||
}
|
||||
|
||||
INLINE
|
||||
void FreeNodeClass(struct NodeClass *old)
|
||||
{
|
||||
old->next = NodeClassFreeList;
|
||||
NodeClassFreeList = old;
|
||||
}
|
||||
|
||||
INLINE
|
||||
struct ElementList *GetElementList(void)
|
||||
{
|
||||
struct ElementList *new_elementlist;
|
||||
@@ -1534,14 +1525,12 @@ struct ElementList *GetElementList(void)
|
||||
return(new_elementlist);
|
||||
}
|
||||
|
||||
INLINE
|
||||
void FreeElementList(struct ElementList *old)
|
||||
{
|
||||
old->next = ElementListFreeList;
|
||||
ElementListFreeList = old;
|
||||
}
|
||||
|
||||
INLINE
|
||||
struct NodeList *GetNodeList(void)
|
||||
{
|
||||
struct NodeList *new_nodelist;
|
||||
@@ -1559,7 +1548,6 @@ struct NodeList *GetNodeList(void)
|
||||
return(new_nodelist);
|
||||
}
|
||||
|
||||
INLINE
|
||||
void FreeNodeList(struct NodeList *old)
|
||||
{
|
||||
old->next = NodeListFreeList;
|
||||
@@ -1809,35 +1797,53 @@ struct Node *CreateNodeList(char *name, short graph)
|
||||
/* creates two lists of the correct 'shape', then traverses nodes
|
||||
* in sequence to link up 'subelement' field of ElementList,
|
||||
* then 'node' field of NodeList structures.
|
||||
*
|
||||
* Return the number of devices combined by serial/parallel merging
|
||||
*/
|
||||
|
||||
void CreateLists(char *name, short graph)
|
||||
int CreateLists(char *name, short graph)
|
||||
{
|
||||
struct Element *ElementScan;
|
||||
struct ElementList *EListScan;
|
||||
struct NodeList *NListScan;
|
||||
struct objlist *ob;
|
||||
struct nlist *tp;
|
||||
int ppass, spass, pcnt, scnt, total;
|
||||
|
||||
/* get a pointer to the cell */
|
||||
tp = LookupCellFile(name, graph);
|
||||
if (tp == NULL) {
|
||||
Fprintf(stderr, "No cell '%s' found.\n", name);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Circuit1 == NULL) Circuit1 = tp;
|
||||
else if (Circuit2 == NULL) Circuit2 = tp;
|
||||
else {
|
||||
Fprintf(stderr, "Error: CreateLists() called more than twice without a reset.\n");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CombineParallel(name, graph);
|
||||
/* Parallel and serial combinations. Run until networks of */
|
||||
/* devices are resolved into a single device with the network */
|
||||
/* represented by a number of property records. */
|
||||
|
||||
total = 0;
|
||||
for (ppass = 0; ; ppass++) {
|
||||
pcnt = CombineParallel(name, graph);
|
||||
total += pcnt;
|
||||
if (ppass > 0 && pcnt == 0) break;
|
||||
for (spass = 0; ; spass++) {
|
||||
scnt = CombineSerial(name, graph);
|
||||
total += scnt;
|
||||
if (scnt == 0) break;
|
||||
}
|
||||
if (spass == 0) break;
|
||||
}
|
||||
|
||||
Elements = CreateElementList(name, graph);
|
||||
Nodes = CreateNodeList(name, graph);
|
||||
if (LookupElementList == NULL) return;
|
||||
if (LookupElementList == NULL) return total;
|
||||
|
||||
ElementScan = NULL;
|
||||
NListScan = NULL; /* just to stop the compiler from bitching */
|
||||
@@ -1863,6 +1869,7 @@ void CreateLists(char *name, short graph)
|
||||
|
||||
FREE(LookupElementList);
|
||||
LookupElementList = NULL;
|
||||
return total;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -1932,11 +1939,14 @@ struct Node *CreateNodeList(char *name, short graph)
|
||||
return (head);
|
||||
}
|
||||
|
||||
void CreateLists(char *name, short graph)
|
||||
/* creates two lists of the correct 'shape', then traverses nodes
|
||||
in sequence to link up 'subelement' field of ElementList,
|
||||
then 'node' field of NodeList structures.
|
||||
*/
|
||||
* in sequence to link up 'subelement' field of ElementList,
|
||||
* then 'node' field of NodeList structures.
|
||||
*
|
||||
* Return the number of devices combined by serial/parallel merging
|
||||
*/
|
||||
|
||||
int CreateLists(char *name, short graph)
|
||||
{
|
||||
struct Element *E, *ElementScan;
|
||||
struct Node *N, *NodeScan;
|
||||
@@ -1944,24 +1954,40 @@ void CreateLists(char *name, short graph)
|
||||
struct NodeList *NListScan;
|
||||
struct objlist *ob, *obscan;
|
||||
struct nlist *tp;
|
||||
int node;
|
||||
int node, ppass, spass, pcnt, scnt, total;
|
||||
|
||||
/* get a pointer to the cell */
|
||||
tp = LookupCellFile(name, graph);
|
||||
if (tp == NULL) {
|
||||
Fprintf(stderr, "No cell '%s' found.\n", name);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Circuit1 == NULL) Circuit1 = tp;
|
||||
else if (Circuit2 == NULL) Circuit2 = tp;
|
||||
else {
|
||||
Fprintf(stderr, "Error: CreateLists() called more than twice without a reset.\n");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConnectAllNodes(name, graph);
|
||||
CombineParallel(name, graph);
|
||||
|
||||
/* Parallel and serial combinations. Run until networks of */
|
||||
/* devices are resolved into a single device with the network */
|
||||
/* represented by a number of property records. */
|
||||
|
||||
total = 0;
|
||||
for (ppass = 0; ; ppass++) {
|
||||
pcnt = CombineParallel(name, graph);
|
||||
total += pcnt;
|
||||
if (ppass > 0 && pcnt == 0) break;
|
||||
for (spass = 0; ; spass++) {
|
||||
scnt = CombineSerial(name, graph);
|
||||
total += scnt;
|
||||
if (scnt == 0) break;
|
||||
}
|
||||
if (spass == 0) break;
|
||||
}
|
||||
|
||||
E = CreateElementList(name, graph);
|
||||
N = CreateNodeList(name, graph);
|
||||
@@ -2000,6 +2026,7 @@ void CreateLists(char *name, short graph)
|
||||
}
|
||||
Elements = E;
|
||||
Nodes = N;
|
||||
return total;
|
||||
}
|
||||
|
||||
#endif /* LOOKUP_INITIALIZATION */
|
||||
@@ -2682,8 +2709,8 @@ int FlattenUnmatched(struct nlist *tc, char *parent, int stoplevel, int loclevel
|
||||
if (loclevel == stoplevel && !(tc->flags & CELL_MATCHED)) {
|
||||
ClearDumpedList();
|
||||
if (Debug == TRUE) Fprintf(stdout, "Level %d ", loclevel);
|
||||
Fprintf(stdout, "Flattening unmatched subcell %s in circuit %s ",
|
||||
tc->name, parent);
|
||||
Fprintf(stdout, "Flattening unmatched subcell %s in circuit %s (%d)",
|
||||
tc->name, parent, tc->file);
|
||||
changed = flattenInstancesOf(parent, tc->file, tc->name);
|
||||
Fprintf(stdout, "(%d instance%s)\n", changed, ((changed == 1) ? "" : "s"));
|
||||
return 1;
|
||||
@@ -2982,6 +3009,7 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2)
|
||||
struct Element *El1;
|
||||
struct Node *N1;
|
||||
struct nlist *tc1, *tc2, *tcf;
|
||||
int modified;
|
||||
|
||||
ResetState();
|
||||
|
||||
@@ -3014,7 +3042,7 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2)
|
||||
}
|
||||
}
|
||||
|
||||
CreateLists(name1, file1);
|
||||
modified = CreateLists(name1, file1);
|
||||
if (Elements == NULL) {
|
||||
Printf("Circuit %s contains no devices.\n", name1);
|
||||
return;
|
||||
@@ -3059,7 +3087,7 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2)
|
||||
/* N1 now points to last element of list */
|
||||
|
||||
|
||||
CreateLists(name2, file2);
|
||||
modified += CreateLists(name2, file2);
|
||||
if (Elements == NULL) {
|
||||
Printf("Circuit %s contains no devices.\n", name2);
|
||||
ResetState();
|
||||
@@ -3072,6 +3100,17 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2)
|
||||
return;
|
||||
}
|
||||
|
||||
if (modified > 0) {
|
||||
Printf("Circuit was modified by parallel/serial device merging.\n");
|
||||
Printf("New circuit summary:\n\n");
|
||||
/* print preliminary statistics */
|
||||
Printf("Contents of circuit 1: ");
|
||||
DescribeInstance(name1, file1);
|
||||
Printf("Contents of circuit 2: ");
|
||||
DescribeInstance(name2, file2);
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
/* splice new lists into existing lists */
|
||||
El1->next = Elements;
|
||||
for (El1 = Elements; El1->next != NULL; El1 = El1->next) {
|
||||
@@ -3337,18 +3376,11 @@ void PropertyOptimize(struct objlist *ob, struct nlist *tp)
|
||||
vlist = (struct valuelist ***)CALLOC(pcount, sizeof(struct valuelist **));
|
||||
if (m_rec == NULL)
|
||||
vlist[0] = (struct valuelist **)CALLOC(icount, sizeof(struct valuelist *));
|
||||
pcount = 1;
|
||||
|
||||
while (ptop != NULL) {
|
||||
if (ptop->prop == m_rec) {
|
||||
plist[0] = m_rec;
|
||||
vlist[0] = (struct valuelist **)CALLOC(icount,
|
||||
plist[ptop->prop->idx] = ptop->prop;
|
||||
vlist[ptop->prop->idx] = (struct valuelist **)CALLOC(icount,
|
||||
sizeof(struct valuelist *));
|
||||
}
|
||||
else {
|
||||
plist[pcount] = ptop->prop;
|
||||
vlist[pcount++] = (struct valuelist **)CALLOC(icount,
|
||||
sizeof(struct valuelist *));
|
||||
}
|
||||
plink = ptop;
|
||||
FREE(ptop);
|
||||
ptop = plink->next;
|
||||
@@ -3377,6 +3409,17 @@ void PropertyOptimize(struct objlist *ob, struct nlist *tp)
|
||||
i++;
|
||||
}
|
||||
|
||||
// Check for "M" records with type double and promote them to integer
|
||||
for (i = 0; i < icount; i++) {
|
||||
vl = vlist[0][i];
|
||||
if (vl != NULL) {
|
||||
if (vl->type == PROP_DOUBLE) {
|
||||
vl->type = PROP_INTEGER;
|
||||
vl->value.ival = (int)(vl->value.dval + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now combine records with same properties by summing M.
|
||||
for (i = 0; i < icount - 1; i++) {
|
||||
for (j = 1; j < icount; j++) {
|
||||
@@ -3482,13 +3525,13 @@ void PropertyOptimize(struct objlist *ob, struct nlist *tp)
|
||||
vlist[0][j] = &nullvl; // Mark this position
|
||||
if (crit >= 0) {
|
||||
vl = vlist[crit][i];
|
||||
if (ctype == MERGE_ADD_CRIT) {
|
||||
if ((vl != NULL) && (ctype == MERGE_ADD_CRIT)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival += vlist[crit][j]->value.ival;
|
||||
else if (vl->type == PROP_DOUBLE)
|
||||
vl->value.dval += vlist[crit][j]->value.dval;
|
||||
}
|
||||
else { /* MERGE_PAR_CRIT */
|
||||
else if (vl != NULL) { /* MERGE_PAR_CRIT */
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
double di = vl->value.ival;
|
||||
double dj = vlist[crit][j]->value.ival;
|
||||
@@ -3508,7 +3551,7 @@ void PropertyOptimize(struct objlist *ob, struct nlist *tp)
|
||||
else if (vlist[0][i]->value.ival > 0) {
|
||||
if (crit >= 0) {
|
||||
vl = vlist[crit][i];
|
||||
if (ctype == MERGE_ADD_CRIT) {
|
||||
if ((vl != NULL) && (ctype == MERGE_ADD_CRIT)) {
|
||||
if (vl->type == PROP_INTEGER)
|
||||
vl->value.ival += vlist[0][j]->value.ival *
|
||||
vlist[crit][j]->value.ival;
|
||||
@@ -3516,7 +3559,7 @@ void PropertyOptimize(struct objlist *ob, struct nlist *tp)
|
||||
vl->value.dval += (double)vlist[0][j]->value.ival *
|
||||
vlist[crit][j]->value.dval;
|
||||
}
|
||||
else { /* MERGE_PAR_CRIT */
|
||||
else if (vl != NULL) { /* MERGE_PAR_CRIT */
|
||||
if (vl->type == PROP_INTEGER) {
|
||||
double d = (double)vlist[crit][j]->value.ival /
|
||||
(double)vlist[0][j]->value.ival;
|
||||
@@ -3588,6 +3631,7 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
int mismatches = 0, i, j;
|
||||
int vlstart, islop, t1type, t2type;
|
||||
int mult1, mult2, ival1, ival2;
|
||||
int rval = 1;
|
||||
double pd, dslop, dval1, dval2;
|
||||
|
||||
tc1 = LookupCellFile(ob1->model.class, Circuit1->file);
|
||||
@@ -3622,11 +3666,13 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
if (t1type == PROPERTY) PropertyOptimize(tp1, tc1);
|
||||
if (t2type == PROPERTY) PropertyOptimize(tp2, tc2);
|
||||
|
||||
if (t1type != PROPERTY) {
|
||||
// t1 has no properties. See if t2's properties are required
|
||||
// to be checked. If so, flag t1 as missing required properties
|
||||
while(1) {
|
||||
if (t1type != PROPERTY) {
|
||||
// t1 has no properties. See if t2's properties are required
|
||||
// to be checked. If so, flag t2 instance as unmatched
|
||||
|
||||
for (i = 0;; i++) {
|
||||
mismatches++;
|
||||
for (i = 0;; i++) {
|
||||
vl2 = &(tp2->instance.props[i]);
|
||||
if (vl2->type == PROP_ENDLIST) break;
|
||||
if (vl2 == NULL) continue;
|
||||
@@ -3637,21 +3683,22 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
if (vl2->type == PROP_INTEGER)
|
||||
mult2 = vl2->value.ival;
|
||||
}
|
||||
}
|
||||
if (vl2->type != PROP_ENDLIST) {
|
||||
if (do_print) Fprintf(stdout, "Circuit 2 %s instance %s missing"
|
||||
" required properties.\n",
|
||||
}
|
||||
if (vl2->type != PROP_ENDLIST) {
|
||||
if (do_print) Fprintf(stdout, "Circuit 2 %s instance %s has no"
|
||||
" property match in circuit 1.\n",
|
||||
Circuit2->name, ob2->instance.name);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if (t2type != PROPERTY) {
|
||||
// t2 has no properties. See if t1's properties are required
|
||||
// to be checked. If so, flag t1 as missing required properties
|
||||
rval = -1;
|
||||
}
|
||||
else
|
||||
rval = 0;
|
||||
}
|
||||
else if (t2type != PROPERTY) {
|
||||
// t2 has no properties. See if t1's properties are required
|
||||
// to be checked. If so, flag t1 instance as unmatched
|
||||
|
||||
for (i = 0;; i++) {
|
||||
mismatches++;
|
||||
for (i = 0;; i++) {
|
||||
vl1 = &(tp1->instance.props[i]);
|
||||
if (vl1->type == PROP_ENDLIST) break;
|
||||
if (vl1 == NULL) continue;
|
||||
@@ -3662,184 +3709,201 @@ int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print)
|
||||
if (vl1->type == PROP_INTEGER)
|
||||
mult1 = vl1->value.ival;
|
||||
}
|
||||
}
|
||||
if (vl1->type != PROP_ENDLIST) {
|
||||
if (do_print) Fprintf(stdout, "Circuit 1 %s instance %s missing"
|
||||
" required properties.\n",
|
||||
Circuit1->name, ob1->instance.name);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
vlstart = 0;
|
||||
for (i = 0;; i++) {
|
||||
vl1 = &(tp1->instance.props[i]);
|
||||
if (vl1->type == PROP_ENDLIST) break;
|
||||
if (vl1 == NULL) continue;
|
||||
if (vl1->key == NULL) continue;
|
||||
|
||||
/* Check if this is a "property of interest". */
|
||||
kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict));
|
||||
if (kl1 == NULL) continue;
|
||||
|
||||
/* Find the matching property in vl2. With luck, they're in order. */
|
||||
|
||||
for (j = vlstart;; j++) {
|
||||
vl2 = &(tp2->instance.props[j]);
|
||||
if (vl2->type == PROP_ENDLIST) break;
|
||||
if ((*matchfunc)(vl1->key, vl2->key)) break;
|
||||
}
|
||||
if (vl2->type == PROP_ENDLIST) continue;
|
||||
if (j == vlstart) vlstart++;
|
||||
|
||||
if (vl2 == NULL) continue;
|
||||
if (vl2->key == NULL) continue;
|
||||
|
||||
/* Both device classes must agree on the properties to compare */
|
||||
kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict));
|
||||
if (kl2 == NULL) continue;
|
||||
|
||||
/* Watch out for uninitialized entries in cell def */
|
||||
if (vl1->type == vl2->type) {
|
||||
if (kl1->type == PROP_STRING && kl1->pdefault.string == NULL)
|
||||
SetPropertyDefault(kl1, vl1);
|
||||
if (kl2->type == PROP_STRING && kl2->pdefault.string == NULL)
|
||||
SetPropertyDefault(kl2, vl2);
|
||||
}
|
||||
|
||||
if (vl1->type != vl2->type) {
|
||||
if (kl1->type != vl1->type) PromoteProperty(kl1, vl1);
|
||||
if (kl2->type != vl2->type) PromoteProperty(kl2, vl2);
|
||||
if (vl1->type != vl2->type) PromoteProperty(kl1, vl2);
|
||||
if (vl1->type != vl2->type) PromoteProperty(kl2, vl1);
|
||||
if (do_print && (vl1->type != vl2->type)) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
ob1->instance.name, ob2->instance.name);
|
||||
|
||||
Fprintf(stdout, " %s circuit1: ", kl1->key);
|
||||
switch (vl1->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
Fprintf(stdout, "%g", vl1->value.dval);
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
Fprintf(stdout, "%d", vl1->value.ival);
|
||||
break;
|
||||
case PROP_STRING:
|
||||
Fprintf(stdout, "\"%s\"", vl1->value.string);
|
||||
break;
|
||||
case PROP_EXPRESSION:
|
||||
Fprintf(stdout, "(unresolved expression)");
|
||||
break;
|
||||
}
|
||||
Fprintf(stdout, " ");
|
||||
switch (vl2->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
Fprintf(stdout, "%g", vl2->value.dval);
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
Fprintf(stdout, "%d", vl2->value.ival);
|
||||
break;
|
||||
case PROP_STRING:
|
||||
Fprintf(stdout, "\"%s\"", vl2->value.string);
|
||||
break;
|
||||
case PROP_EXPRESSION:
|
||||
Fprintf(stdout, "(unresolved expression)");
|
||||
break;
|
||||
}
|
||||
Fprintf(stdout, " (property type mismatch)\n");
|
||||
}
|
||||
if (vl1->type != vl2->type) mismatches++;
|
||||
if (vl1->type != PROP_ENDLIST) {
|
||||
if (do_print) Fprintf(stdout, "Circuit 1 %s instance %s has no"
|
||||
" property match in Circuit 2.\n",
|
||||
Circuit1->name, ob1->instance.name);
|
||||
rval = -1;
|
||||
}
|
||||
else
|
||||
rval = 0;
|
||||
}
|
||||
else switch (kl1->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
dval1 = vl1->value.dval;
|
||||
dval2 = vl2->value.dval;
|
||||
else {
|
||||
|
||||
dslop = MAX(kl1->slop.dval, kl2->slop.dval);
|
||||
pd = 2 * fabs(dval1 - dval2) / (dval1 + dval2);
|
||||
if (pd > dslop) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
vlstart = 0;
|
||||
for (i = 0;; i++) {
|
||||
vl1 = &(tp1->instance.props[i]);
|
||||
if (vl1->type == PROP_ENDLIST) break;
|
||||
if (vl1 == NULL) continue;
|
||||
if (vl1->key == NULL) continue;
|
||||
|
||||
/* Check if this is a "property of interest". */
|
||||
kl1 = (struct property *)HashLookup(vl1->key, &(tc1->propdict));
|
||||
if (kl1 == NULL) continue;
|
||||
|
||||
/* Find the matching property in vl2. With luck, they're in order. */
|
||||
|
||||
for (j = vlstart;; j++) {
|
||||
vl2 = &(tp2->instance.props[j]);
|
||||
if (vl2->type == PROP_ENDLIST) break;
|
||||
if ((*matchfunc)(vl1->key, vl2->key)) break;
|
||||
}
|
||||
if (vl2->type == PROP_ENDLIST) continue;
|
||||
if (j == vlstart) vlstart++;
|
||||
|
||||
if (vl2 == NULL) continue;
|
||||
if (vl2->key == NULL) continue;
|
||||
|
||||
/* Both device classes must agree on the properties to compare */
|
||||
kl2 = (struct property *)HashLookup(vl2->key, &(tc2->propdict));
|
||||
if (kl2 == NULL) continue;
|
||||
|
||||
/* Watch out for uninitialized entries in cell def */
|
||||
if (vl1->type == vl2->type) {
|
||||
if (kl1->type == PROP_STRING && kl1->pdefault.string == NULL)
|
||||
SetPropertyDefault(kl1, vl1);
|
||||
if (kl2->type == PROP_STRING && kl2->pdefault.string == NULL)
|
||||
SetPropertyDefault(kl2, vl2);
|
||||
}
|
||||
|
||||
/* Promote properties as necessary to make sure they all match */
|
||||
if (kl1->type != vl1->type) PromoteProperty(kl1, vl1);
|
||||
if (kl2->type != vl2->type) PromoteProperty(kl2, vl2);
|
||||
if (kl1->type != vl2->type) PromoteProperty(kl1, vl2);
|
||||
if (vl1->type != kl2->type) PromoteProperty(kl2, vl1);
|
||||
|
||||
if (vl1->type != vl2->type) {
|
||||
if (do_print && (vl1->type != vl2->type)) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
ob1->instance.name, ob2->instance.name);
|
||||
Fprintf(stdout, " %s circuit1: %g circuit2: %g ",
|
||||
kl1->key, dval1, dval2);
|
||||
if (vl1->value.dval > 0.0 && vl2->value.dval > 0.0)
|
||||
Fprintf(stdout, "(delta=%.3g%%, cutoff=%.3g%%)\n",
|
||||
100 * pd, 100 * dslop);
|
||||
else
|
||||
Fprintf(stdout, "\n");
|
||||
|
||||
Fprintf(stdout, " %s circuit1: ", kl1->key);
|
||||
switch (vl1->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
Fprintf(stdout, "%g", vl1->value.dval);
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
Fprintf(stdout, "%d", vl1->value.ival);
|
||||
break;
|
||||
case PROP_STRING:
|
||||
Fprintf(stdout, "\"%s\"", vl1->value.string);
|
||||
break;
|
||||
case PROP_EXPRESSION:
|
||||
Fprintf(stdout, "(unresolved expression)");
|
||||
break;
|
||||
}
|
||||
Fprintf(stdout, " ");
|
||||
switch (vl2->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
Fprintf(stdout, "%g", vl2->value.dval);
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
Fprintf(stdout, "%d", vl2->value.ival);
|
||||
break;
|
||||
case PROP_STRING:
|
||||
Fprintf(stdout, "\"%s\"", vl2->value.string);
|
||||
break;
|
||||
case PROP_EXPRESSION:
|
||||
Fprintf(stdout, "(unresolved expression)");
|
||||
break;
|
||||
}
|
||||
Fprintf(stdout, " (property type mismatch)\n");
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
ival1 = vl1->value.ival;
|
||||
ival2 = vl2->value.ival;
|
||||
}
|
||||
|
||||
islop = MAX(kl1->slop.ival, kl2->slop.ival);
|
||||
if (abs(ival1 - ival2) > islop) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
else switch (kl1->type) {
|
||||
case PROP_DOUBLE:
|
||||
case PROP_VALUE:
|
||||
dval1 = vl1->value.dval;
|
||||
dval2 = vl2->value.dval;
|
||||
|
||||
dslop = MAX(kl1->slop.dval, kl2->slop.dval);
|
||||
pd = 2 * fabs(dval1 - dval2) / (dval1 + dval2);
|
||||
if (pd > dslop) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
ob1->instance.name, ob2->instance.name);
|
||||
Fprintf(stdout, " %s circuit1: %d circuit2: %d ",
|
||||
kl1->key, ival1, ival2);
|
||||
if (ival1 > 0 && ival2 > 0)
|
||||
Fprintf(stdout, "(delta=%d, cutoff=%d)\n",
|
||||
abs(ival1 - ival2), islop);
|
||||
else
|
||||
Fprintf(stdout, "\n");
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
break;
|
||||
case PROP_STRING:
|
||||
islop = MAX(kl1->slop.ival, kl2->slop.ival);
|
||||
if (islop == 0) {
|
||||
if (strcasecmp(vl1->value.string, vl2->value.string)) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
Fprintf(stdout, " %s circuit1: %g circuit2: %g ",
|
||||
kl1->key, dval1, dval2);
|
||||
if (vl1->value.dval > 0.0 && vl2->value.dval > 0.0)
|
||||
Fprintf(stdout, "(delta=%.3g%%, cutoff=%.3g%%)\n",
|
||||
100 * pd, 100 * dslop);
|
||||
else
|
||||
Fprintf(stdout, "\n");
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
break;
|
||||
case PROP_INTEGER:
|
||||
ival1 = vl1->value.ival;
|
||||
ival2 = vl2->value.ival;
|
||||
|
||||
islop = MAX(kl1->slop.ival, kl2->slop.ival);
|
||||
if (abs(ival1 - ival2) > islop) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
ob1->instance.name, ob2->instance.name);
|
||||
Fprintf(stdout, " %s circuit1: \"%s\" circuit2: \"%s\" "
|
||||
"(exact match req'd)\n",
|
||||
kl1->key, vl1->value.string, vl2->value.string);
|
||||
}
|
||||
Fprintf(stdout, " %s circuit1: %d circuit2: %d ",
|
||||
kl1->key, ival1, ival2);
|
||||
if (ival1 > 0 && ival2 > 0)
|
||||
Fprintf(stdout, "(delta=%d, cutoff=%d)\n",
|
||||
abs(ival1 - ival2), islop);
|
||||
else
|
||||
Fprintf(stdout, "\n");
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
break;
|
||||
case PROP_STRING:
|
||||
islop = MAX(kl1->slop.ival, kl2->slop.ival);
|
||||
if (islop == 0) {
|
||||
if (strcasecmp(vl1->value.string, vl2->value.string)) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
ob1->instance.name, ob2->instance.name);
|
||||
Fprintf(stdout, " %s circuit1: \"%s\" "
|
||||
"circuit2: \"%s\" (exact match req'd)\n",
|
||||
kl1->key, vl1->value.string,
|
||||
vl2->value.string);
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (strncasecmp(vl1->value.string, vl2->value.string, islop)) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
ob2->instance.name, ob2->instance.name);
|
||||
Fprintf(stdout, " %s circuit1: \"%s\" "
|
||||
"circuit2: \"%s\" (check to %d chars.)\n",
|
||||
kl1->key, vl1->value.string,
|
||||
vl2->value.string, islop);
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_EXPRESSION:
|
||||
/* Expressions could potentially be compared. . . */
|
||||
if (do_print)
|
||||
Fprintf(stdout, " %s (unresolved expressions.)\n", kl1->key);
|
||||
mismatches++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (strncasecmp(vl1->value.string, vl2->value.string, islop)) {
|
||||
if (do_print) {
|
||||
if (mismatches == 0)
|
||||
Fprintf(stdout, "%s vs. %s:\n",
|
||||
ob2->instance.name, ob2->instance.name);
|
||||
Fprintf(stdout, " %s circuit1: \"%s\" circuit2: \"%s\" "
|
||||
"(check to %d chars.)\n",
|
||||
kl1->key, vl1->value.string, vl2->value.string, islop);
|
||||
}
|
||||
mismatches++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_EXPRESSION:
|
||||
/* Expressions could potentially be compared. . . */
|
||||
if (do_print)
|
||||
Fprintf(stdout, " %s (unresolved expressions.)\n", kl1->key);
|
||||
mismatches++;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
if ((vl1 == NULL && vl2 != NULL) || (vl1 != NULL && vl2 == NULL))
|
||||
rval = -1; /* Different number of properties of interest */
|
||||
}
|
||||
}
|
||||
if ((vl1 == NULL && vl2 != NULL) || (vl1 != NULL && vl2 == NULL))
|
||||
return -1; /* Different number of properties of interest */
|
||||
|
||||
/* Move to the next property record */
|
||||
|
||||
if (tp1) tp1 = tp1->next;
|
||||
if (tp2) tp2 = tp2->next;
|
||||
t1type = (tp1) ? tp1->type : 0;
|
||||
t2type = (tp2) ? tp2->type : 0;
|
||||
if ((t1type != PROPERTY) && (t2type != PROPERTY)) break;
|
||||
}
|
||||
return mismatches;
|
||||
|
||||
return (rval < 0) ? rval : mismatches;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
@@ -4547,13 +4611,13 @@ int EquivalenceNodes(char *name1, int file1, char *name2, int file2)
|
||||
/* database. */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
int IgnoreClass(char *name, int file)
|
||||
int IgnoreClass(char *name, int file, unsigned char type)
|
||||
{
|
||||
struct IgnoreList *newIgnore;
|
||||
|
||||
if ((file == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
|
||||
IgnoreClass(name, Circuit1->file);
|
||||
IgnoreClass(name, Circuit2->file);
|
||||
IgnoreClass(name, Circuit1->file, type);
|
||||
IgnoreClass(name, Circuit2->file, type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4563,9 +4627,13 @@ int IgnoreClass(char *name, int file)
|
||||
newIgnore->class = (char *)MALLOC(1 + strlen(name));
|
||||
strcpy(newIgnore->class, name);
|
||||
newIgnore->file = file;
|
||||
newIgnore->type = type;
|
||||
|
||||
/* Remove existing classes from database */
|
||||
ClassDelete(name, file);
|
||||
if (type == IGNORE_CLASS)
|
||||
ClassDelete(name, file);
|
||||
else
|
||||
RemoveShorted(name, file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ extern int PermuteForget(char *model, int filenum, char *pin1, char *pin2);
|
||||
extern int EquivalenceElements(char *name1, int file1, char *name2, int file2);
|
||||
extern int EquivalenceNodes(char *name1, int file1, char *name2, int file2);
|
||||
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2);
|
||||
extern int IgnoreClass(char *name, int file);
|
||||
extern int IgnoreClass(char *name, int file, unsigned char type);
|
||||
extern int MatchPins(struct nlist *tp1, struct nlist *tp2);
|
||||
|
||||
extern int CreateCompareQueue(char *, int, char *, int);
|
||||
|
||||
@@ -730,7 +730,6 @@ char *readbuf;
|
||||
int bytes_in_buffer;
|
||||
char *bufptr;
|
||||
|
||||
INLINE
|
||||
int READ(void *buf, int bytes)
|
||||
{
|
||||
if (bytes_in_buffer >= bytes) {
|
||||
|
||||
+476
-13
@@ -1212,6 +1212,10 @@ void CellDefNoCase(char *name, int file)
|
||||
CurrentCell->flags |= CELL_NOCASE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Return 0 if class 'name' is not being ignored (per the 'ignore' */
|
||||
/* command); 1 if it is ignored, and 2 if shorted instances should be */
|
||||
/* ignored. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int IsIgnored(char *name, int file)
|
||||
@@ -1223,7 +1227,7 @@ int IsIgnored(char *name, int file)
|
||||
{
|
||||
if ((file == -1) || (ilist->file == -1) || (file == ilist->file))
|
||||
if ((*matchfunc)(ilist->class, nptr))
|
||||
return 1;
|
||||
return ilist->type; /* IGNORE_CLASS or IGNORE_SHORTED */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1361,10 +1365,6 @@ void Instance(char *model, char *instancename)
|
||||
return;
|
||||
}
|
||||
fnum = CurrentCell->file;
|
||||
if (IsIgnored(model, fnum)) {
|
||||
Printf("Class '%s' instanced in input but is being ignored.\n", model);
|
||||
return;
|
||||
}
|
||||
instanced_cell = LookupCellFile(model, fnum);
|
||||
if (instanced_cell == NULL) {
|
||||
Printf("Attempt to instance undefined model '%s'\n", model);
|
||||
@@ -1504,7 +1504,7 @@ char *Cell(char *inststr, char *model, ...)
|
||||
struct objlist *namedporthead, *namedportp, *namedlisthead, *namedlistp;
|
||||
int portnum, portlist, done;
|
||||
char namedport[512]; /* tmp buffers */
|
||||
int filenum;
|
||||
int filenum, itype, samenode;
|
||||
|
||||
static char *instancename = NULL;
|
||||
char *instnameptr;
|
||||
@@ -1517,7 +1517,7 @@ char *Cell(char *inststr, char *model, ...)
|
||||
filenum = CurrentCell->file;
|
||||
|
||||
if (Debug) Printf(" calling cell: %s\n",model);
|
||||
if (IsIgnored(model, filenum)) {
|
||||
if ((itype = IsIgnored(model, filenum)) == IGNORE_CLASS) {
|
||||
Printf("Class '%s' instanced in input but is being ignored.\n", model);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1600,6 +1600,21 @@ char *Cell(char *inststr, char *model, ...)
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
/* Check for shorted pins */
|
||||
if ((itype == IGNORE_SHORTED) && (head != NULL)) {
|
||||
unsigned char shorted = (unsigned char)1;
|
||||
for (tp = head->next; tp; tp = tp->next) {
|
||||
if (strcasecmp(head->name, tp->name))
|
||||
shorted = (unsigned char)0;
|
||||
break;
|
||||
}
|
||||
if (shorted == (unsigned char)1) {
|
||||
Printf("Instance of '%s' is shorted, ignoring.\n", model);
|
||||
FreeObject(head);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (inststr == NULL) {
|
||||
if (instancename != NULL)
|
||||
FreeString(instancename);
|
||||
@@ -1992,7 +2007,7 @@ struct objlist *LinkProperties(char *model, struct keyvalue *topptr)
|
||||
else
|
||||
filenum = CurrentCell->file;
|
||||
|
||||
if (IsIgnored(model, filenum)) {
|
||||
if (IsIgnored(model, filenum) == IGNORE_CLASS) {
|
||||
Printf("Class '%s' instanced in input but is being ignored.\n", model);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2834,6 +2849,157 @@ void ConnectAllNodes(char *model, int file)
|
||||
if (ob->node == -1) ob->node = nodenum++;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Serial and Parallel combination: */
|
||||
/* All devices of the same type that exist in serial and parallel */
|
||||
/* combinations will be treated as a single device in a network. */
|
||||
/* Serial connections are only allowed for resistors and inductors. */
|
||||
/* Any device may be connected in parallel. For combinations of serial */
|
||||
/* and parallel, as in a resistor network, there is a set of rules: */
|
||||
/* */
|
||||
/* Running parallel and serial checks: */
|
||||
/* 1. Run parallel once. If a repeat run and no devices are merged, */
|
||||
/* then go to 4. */
|
||||
/* 2. Run serial until no devices are merged. */
|
||||
/* 3. If serial ran more than once, then go to 1. */
|
||||
/* 4. End merge */
|
||||
/* */
|
||||
/* Each merge procedure, when it finds two devices that can be merged, */
|
||||
/* removes the second device from the netlist and adds its properties */
|
||||
/* to the first device. If a serial merge, then the nodes are adjusted */
|
||||
/* appropriately. Where A is the property list of the first device and */
|
||||
/* B is the property list of the second device, the first and last */
|
||||
/* properties of A and the first property of B may require a marker to */
|
||||
/* indicate the topology of the network, as follows (in order): */
|
||||
/* */
|
||||
/* For a parallel merge: */
|
||||
/* 1) If A has serial components then tag first property of A with */
|
||||
/* "open" and tag first property of B with "close". */
|
||||
/* 2) If B has serial components then tag first property of B with */
|
||||
/* "open". */
|
||||
/* */
|
||||
/* For a serial merge: */
|
||||
/* 1) If A has unbalanced "opens", then add "close" to first */
|
||||
/* property of B to balance the "opens". */
|
||||
/* 2) Always tag B with "serial". */
|
||||
/* */
|
||||
/* Tags are indicated by a property named "_tag" which has a string */
|
||||
/* value of ordered characters, "S" for serial, "O" for open, and "C" */
|
||||
/* for close. A device with only one property record has no "_tag" */
|
||||
/* record. A device which is in parallel with the device(s) in front */
|
||||
/* of it is implicitly parallel by not having an "S" tag, and may not */
|
||||
/* have a tag at all. */
|
||||
/* */
|
||||
/* The property check routine is responsible for comparing device */
|
||||
/* serial/parallel networks against each other. Otherwise, each */
|
||||
/* serial/parallel network is considered topologically as a single */
|
||||
/* device, and any differences in the serial/parallel networks between */
|
||||
/* two circuits being matched will be treated as a property error. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/* add_prop_tag --- add the tag character tagc to the property list of */
|
||||
/* obr. obr points to the first property record. */
|
||||
|
||||
int add_prop_tag(struct objlist *obr, char tagc)
|
||||
{
|
||||
struct objlist *nob;
|
||||
int i, k, l;
|
||||
struct valuelist *kv, *kv2;
|
||||
int hastag;
|
||||
char *tmpstr;
|
||||
|
||||
hastag = FALSE;
|
||||
for (nob = obr; nob->next && nob->next->type == PROPERTY; nob = nob->next) {
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(nob->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
if (kv->type == PROP_STRING) {
|
||||
if (!strcmp(kv->key, "_tag")) {
|
||||
hastag = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hastag) {
|
||||
if (nob == obr) {
|
||||
// If _tag was first in the list, then just prepend tagc to the tag value
|
||||
tmpstr = kv->value.string;
|
||||
kv->value.string = (char *)MALLOC(strlen(tmpstr) + 2);
|
||||
sprintf(kv->value.string, "%c%s", tagc, tmpstr);
|
||||
FREE(tmpstr);
|
||||
}
|
||||
else {
|
||||
// Add a _tag key to the first property list and set value to tagc
|
||||
|
||||
kv = &(obr->instance.props[i]);
|
||||
k = 0;
|
||||
for (k = 0; ; k++) {
|
||||
kv = &(obr->instance.props[k]);
|
||||
if (kv->type == PROP_ENDLIST)
|
||||
break;
|
||||
}
|
||||
kv2 = (struct valuelist *)MALLOC((k + 2) * sizeof(struct valuelist));
|
||||
kv2->key = strsave("_tag");
|
||||
kv2->type = PROP_STRING;
|
||||
/* Value is set to tagc */
|
||||
kv2->value.string = (char *)MALLOC(2);
|
||||
sprintf(kv2->value.string, "%c", tagc);
|
||||
for (l = 0; l <= k; l++)
|
||||
kv2[l + 1] = obr->instance.props[l];
|
||||
FREE(obr->instance.props);
|
||||
obr->instance.props = kv2;
|
||||
}
|
||||
}
|
||||
return hastag;
|
||||
}
|
||||
|
||||
/* add_balancing_close --- find the number of unbalanced 'open' */
|
||||
/* records in ob1's property list, and prepend the correct number of */
|
||||
/* 'C' closures to the property list of ob2. */
|
||||
|
||||
void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
|
||||
{
|
||||
struct objlist *nob;
|
||||
int i, k, l;
|
||||
struct valuelist *kv, *kv2;
|
||||
int opentags;
|
||||
char *tmpstr, *tag;
|
||||
|
||||
/* Find the first property record in ob1. */
|
||||
for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == PROPERTY)
|
||||
break;
|
||||
if (nob->type != PROPERTY) return; // shouldn't happen
|
||||
|
||||
opentags = 0;
|
||||
for (; nob->next && nob->next->type == PROPERTY; nob = nob->next) {
|
||||
for (i = 0; ; i++) {
|
||||
kv = &(nob->instance.props[i]);
|
||||
if (kv->type == PROP_ENDLIST) break;
|
||||
if (kv->type == PROP_STRING) {
|
||||
if (!strcmp(kv->key, "_tag")) {
|
||||
for (tag == kv->value.string; *tag != '\0'; tag++) {
|
||||
if (*tag == 'O') opentags++;
|
||||
else if (*tag == 'C') opentags--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opentags == 0) return;
|
||||
|
||||
/* Find the first property record in ob2. */
|
||||
for (nob = ob2->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == PROPERTY)
|
||||
break;
|
||||
if (nob->type != PROPERTY) return; // shouldn't happen
|
||||
|
||||
// This is slow but it's the easiest way to do it
|
||||
while (opentags-- > 0) add_prop_tag(nob, 'C');
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Find all devices that are of the same class and check for parallel */
|
||||
/* combinations, and combine them where found, adjusting property "M" */
|
||||
@@ -2850,9 +3016,11 @@ void ConnectAllNodes(char *model, int file)
|
||||
/* */
|
||||
/* If the device has permutable pins, then duplicate hashes are made */
|
||||
/* for each permutation. */
|
||||
/* */
|
||||
/* Return the number of devices merged. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
void CombineParallel(char *model, int file)
|
||||
int CombineParallel(char *model, int file)
|
||||
{
|
||||
struct nlist *tp, *tsub;
|
||||
struct objlist *ob, *ob2, *nextob;
|
||||
@@ -2860,13 +3028,13 @@ void CombineParallel(char *model, int file)
|
||||
struct hashdict devdict;
|
||||
struct Permutation *perm;
|
||||
size_t pcnt;
|
||||
int dcnt = 0;
|
||||
int i, dcnt = 0, hastag;
|
||||
char *pstr, *p2str, *pptr;
|
||||
struct valuelist *kv;
|
||||
|
||||
if ((tp = LookupCellFile(model, file)) == NULL) {
|
||||
Printf("Cell: %s does not exist.\n", model);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
InitializeHashTable(&devdict, OBJHASHSIZE);
|
||||
@@ -2875,12 +3043,20 @@ void CombineParallel(char *model, int file)
|
||||
for (ob = tp->cell; ob; ) {
|
||||
if (ob->type == FIRSTPIN) {
|
||||
|
||||
/* Watch for devices prohibited from parallel combination. */
|
||||
/* All devices allow parallel combination by default. */
|
||||
|
||||
tsub = LookupCellFile(ob->model.class, file);
|
||||
if ((tsub != NULL) && (tsub->flags & COMB_NO_PARALLEL)) {
|
||||
ob = ob->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ------------------------------------*/
|
||||
/* Generate hash key from pins */
|
||||
/* Handle pin permuations */
|
||||
/* ------------------------------------*/
|
||||
|
||||
tsub = LookupCellFile(ob->model.class, file);
|
||||
if ((tsub != NULL) && (tsub->permutes != NULL))
|
||||
perm = tsub->permutes;
|
||||
else
|
||||
@@ -2956,7 +3132,7 @@ void CombineParallel(char *model, int file)
|
||||
lob = tlob;
|
||||
}
|
||||
else {
|
||||
/* Remove parallel device "ob" and append properties of */
|
||||
/* Find parallel device "ob" and append properties of */
|
||||
/* "sob" to it. If "ob" does not have properties, then */
|
||||
/* create a property record and set property "M" to 2. */
|
||||
|
||||
@@ -3005,6 +3181,15 @@ void CombineParallel(char *model, int file)
|
||||
pob->next = obr;
|
||||
}
|
||||
lob->next = nextob;
|
||||
|
||||
// Serial/Parallel logic:
|
||||
|
||||
// If obr has _tag in properties, then add an "open" tag at obr
|
||||
add_prop_tag(obr, 'O');
|
||||
|
||||
// if ob2 has _tag in properties then add an "open" tag to ob2
|
||||
// and a "close" tag to obr
|
||||
if (add_prop_tag(ob2, 'O')) add_prop_tag(obr, 'C');
|
||||
}
|
||||
FREE((char *)pstr);
|
||||
}
|
||||
@@ -3016,6 +3201,284 @@ void CombineParallel(char *model, int file)
|
||||
if (dcnt > 0) {
|
||||
Fprintf(stdout, "Class %s: Merged %d devices.\n", model, dcnt);
|
||||
}
|
||||
return dcnt;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* For the purposes of serial connection checking, find if all pins */
|
||||
/* of two instances after the first two pins are connected to the name */
|
||||
/* nodes. This depends on the definition of a serial device as having */
|
||||
/* two ports, but any additional ports (such as a substrate connection) */
|
||||
/* must be the same for all devices in series. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int check_pin_nodes(struct objlist *ob1, struct objlist *ob2)
|
||||
{
|
||||
struct objlist *nob, *pob;
|
||||
|
||||
/* A dummy device may have both terminals connected to the same */
|
||||
/* point, triggering a false check for a serial device. */
|
||||
if (ob1 == ob2) return FALSE;
|
||||
|
||||
for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next)
|
||||
if (nob->type == 3) break;
|
||||
|
||||
for (pob = ob2->next; pob && pob->type != FIRSTPIN; pob = pob->next)
|
||||
if (pob->type == 3) break;
|
||||
|
||||
while (nob && pob && nob->type > FIRSTPIN && pob->type > FIRSTPIN) {
|
||||
if (nob->node != pob->node)
|
||||
return FALSE;
|
||||
nob = nob->next;
|
||||
pob = pob->next;
|
||||
}
|
||||
|
||||
if (nob->type > FIRSTPIN || pob->type > FIRSTPIN) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Find all nodes that are connected to exactly two devices of the same */
|
||||
/* class. Where found, if the device is allowed to combine serially */
|
||||
/* (check properties), then remove the node and merge the devices into */
|
||||
/* one. */
|
||||
/* */
|
||||
/* This routine depends on CombineParallel() being run first so that no */
|
||||
/* parallel devices are reported as serial. */
|
||||
/* */
|
||||
/* Return the number of devices merged. */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
int CombineSerial(char *model, int file)
|
||||
{
|
||||
struct nlist *tp, *tp2;
|
||||
struct objlist ***instlist;
|
||||
struct objlist *ob, *ob2, *obs, *obp, *obn;
|
||||
int i, j, scnt = 0;
|
||||
struct valuelist *kv;
|
||||
|
||||
// To avoid posting a non-working version, serial combination is
|
||||
// disabled here until code is finished to compare the serial/parallel
|
||||
// property networks.
|
||||
return 0;
|
||||
|
||||
if ((tp = LookupCellFile(model, file)) == NULL) {
|
||||
Printf("Cell: %s does not exist.\n", model);
|
||||
return -1;
|
||||
}
|
||||
/* Diagnostic */
|
||||
/* Printf("CombineSerial start model = %s file = %d\n", model, file); */
|
||||
|
||||
instlist = (struct objlist ***)CALLOC((tp->nodename_cache_maxnodenum + 1),
|
||||
sizeof(struct objlist **));
|
||||
|
||||
for (ob = tp->cell; ob; ob = ob->next) {
|
||||
if ((ob->type >= FIRSTPIN) && (ob->node >= 0)) {
|
||||
if (ob->type == FIRSTPIN)
|
||||
obp = ob; // Save pointer to first pin of device
|
||||
|
||||
if (instlist[ob->node] == NULL) {
|
||||
/* Node has not been seen before, so add it to list */
|
||||
instlist[ob->node] = (struct objlist **)CALLOC(2,
|
||||
sizeof(struct objlist *));
|
||||
|
||||
/* Device must be marked as able to be combined in serial. */
|
||||
/* Note that devices with more than two pins are expected */
|
||||
/* to serial connect along the first two pins, and the */
|
||||
/* remaining pins must all connect to the same nodes. By */
|
||||
/* default, CLASS_RES, CLASS_RES3, and CLASS_INDUCTOR are */
|
||||
/* all allowed to combine in serial. All other devices */
|
||||
/* must have serial combination explicitly enabled. */
|
||||
/* NOTE: Arbitrarily, the first two pins of a device are */
|
||||
/* assumed to be the ones that make serial connections. */
|
||||
/* Additional pins, if any, do not. */
|
||||
|
||||
tp2 = LookupCellFile(ob->model.class, file);
|
||||
if ((tp2->flags & COMB_SERIAL) && (ob->type <= 2))
|
||||
instlist[ob->node][0] = obp;
|
||||
else
|
||||
/* invalidate node */
|
||||
instlist[ob->node][0] = NULL;
|
||||
}
|
||||
else if (instlist[ob->node][0] == NULL) {
|
||||
/* Node is not valid for serial connection */
|
||||
}
|
||||
else if (instlist[ob->node][1] == NULL) {
|
||||
/* Check if first instance is the same type */
|
||||
if ((*matchfunc)(instlist[ob->node][0]->model.class, ob->model.class)) {
|
||||
if (check_pin_nodes(instlist[ob->node][0], obp))
|
||||
instlist[ob->node][1] = obp;
|
||||
else
|
||||
/* invalidate node */
|
||||
instlist[ob->node][0] = NULL;
|
||||
}
|
||||
else
|
||||
/* invalidate node */
|
||||
instlist[ob->node][0] = NULL;
|
||||
}
|
||||
else {
|
||||
/* More than two devices connect here, so invalidate */
|
||||
instlist[ob->node][0] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i <= tp->nodename_cache_maxnodenum; i++) {
|
||||
if (instlist[i] != NULL) {
|
||||
if ((instlist[i][0] != NULL) && (instlist[i][1] != NULL)) {
|
||||
Fprintf(stdout, "Found serial instances %s and %s\n",
|
||||
instlist[i][0]->instance.name,
|
||||
instlist[i][1]->instance.name);
|
||||
scnt++;
|
||||
/* Diagnostic */
|
||||
/* Printf("CombineSerial: Merging serial instances %s (0x%x) and %s (0x%x)"
|
||||
", remove node %s (%d)\n",
|
||||
instlist[i][0]->instance.name,
|
||||
instlist[i][0],
|
||||
instlist[i][1]->instance.name,
|
||||
instlist[i][1],
|
||||
tp->nodename_cache[i]->name, i); */
|
||||
|
||||
/* To maintain knowledge of the topology, each device gets */
|
||||
/* a parameter '_tag', string value set to "S". */
|
||||
|
||||
for (j = 0; j <= 1; j++) {
|
||||
for (obp = instlist[i][j]; ; obp = obp->next) {
|
||||
int found = FALSE;
|
||||
int k, l;
|
||||
char *nodename1, *nodename2;
|
||||
struct valuelist *kv2;
|
||||
|
||||
nodename1 = tp->nodename_cache[instlist[i][j]->node]->name;
|
||||
nodename2 = tp->nodename_cache[instlist[i][j]->next->node]->name;
|
||||
if (obp->type == PROPERTY) {
|
||||
/* Add to properties */
|
||||
k = 0;
|
||||
for (k = 0; ; k++) {
|
||||
kv = &(obp->instance.props[k]);
|
||||
if (kv->type == PROP_ENDLIST)
|
||||
break;
|
||||
}
|
||||
kv2 = (struct valuelist *)MALLOC((k + 2) *
|
||||
sizeof(struct valuelist));
|
||||
kv2->key = strsave("_tag");
|
||||
kv2->type = PROP_STRING;
|
||||
/* Value is set to "S" */
|
||||
kv2->value.string = (char *)MALLOC(2);
|
||||
sprintf(kv2->value.string, "S");
|
||||
for (l = 0; l <= k; l++)
|
||||
kv2[l + 1] = obp->instance.props[l];
|
||||
FREE(obp->instance.props);
|
||||
obp->instance.props = kv2;
|
||||
found = TRUE;
|
||||
}
|
||||
if (obp->next == NULL || obp->next->type == FIRSTPIN) {
|
||||
struct objlist *nob;
|
||||
/* No property record, so insert one */
|
||||
if (found == FALSE) {
|
||||
nob = GetObject();
|
||||
nob->type = PROPERTY;
|
||||
nob->name = strsave("properties");
|
||||
nob->node = -2; /* Don't report as disconnected node */
|
||||
nob->model.class = (obp->model.class == NULL) ? NULL :
|
||||
strsave(obp->model.class);
|
||||
nob->instance.props = NewPropValue(2);
|
||||
|
||||
/* Create property record for property "_tag" */
|
||||
kv = &(nob->instance.props[0]);
|
||||
kv->key = strsave("_tag");
|
||||
kv->type = PROP_STRING;
|
||||
/* Value is set to "S" */
|
||||
kv->value.string = (char *)MALLOC(2);
|
||||
sprintf(kv->value.string, "S");
|
||||
|
||||
/* End of property list */
|
||||
kv = &(nob->instance.props[1]);
|
||||
kv->key = NULL;
|
||||
kv->type = PROP_ENDLIST;
|
||||
kv->value.ival = 0;
|
||||
|
||||
nob->next = obp->next;
|
||||
obp->next = nob;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Combine these two instances and remove node i */
|
||||
for (ob2 = instlist[i][0]; ob2; ob2 = ob2->next) {
|
||||
if (ob2->node == i)
|
||||
break;
|
||||
}
|
||||
for (obs = instlist[i][1]; obs; obs = obs->next) {
|
||||
if (obs->node != i) {
|
||||
ob2->node = obs->node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Excise the 2nd instance. instlist[i][1] remains as the */
|
||||
/* only pointer to it. */
|
||||
for (obp = instlist[i][0]; obp->next->type != FIRSTPIN; obp = obp->next);
|
||||
for (ob2 = obp; ob2->next != instlist[i][1]; ob2 = ob2->next);
|
||||
for (obs = ob2->next; obs->next && obs->next->type != FIRSTPIN;
|
||||
obs = obs->next);
|
||||
ob2->next = obs->next;
|
||||
if (obs->next) obs->next = NULL; // Terminate 2nd instance record
|
||||
|
||||
/* If 1st device has unbalanced 'open' records, then add 'close' */
|
||||
/* records to the 2nd device to balance. */
|
||||
add_balancing_close(instlist[i][0], instlist[i][1]);
|
||||
|
||||
/* Move property record(s) of the 2nd device to the first */
|
||||
for (obs = instlist[i][1]; obs && obs->type != PROPERTY; obs = obs->next);
|
||||
while (obs && (obs->type == PROPERTY)) {
|
||||
obn = obs->next;
|
||||
obs->next = obp->next;
|
||||
obp->next = obs;
|
||||
obs = obn;
|
||||
}
|
||||
|
||||
/* If 2nd device appears anywhere else in the serial device */
|
||||
/* list, replace it with the 1st device. */
|
||||
for (j = i + 1; j <= tp->nodename_cache_maxnodenum; j++) {
|
||||
if (instlist[j] == NULL) continue;
|
||||
|
||||
if (instlist[j][0] == instlist[i][1])
|
||||
instlist[j][0] = instlist[i][0];
|
||||
if (instlist[j][1] == instlist[i][1])
|
||||
instlist[j][1] = instlist[i][0];
|
||||
|
||||
/* If instlist[j]'s two entries point to the same device */
|
||||
/* then invalidate it. */
|
||||
if (instlist[j][0] == instlist[j][1]) {
|
||||
FREE(instlist[j]);
|
||||
instlist[j] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free 2nd device's object */
|
||||
for (obs = instlist[i][1]; obs && obs->type != PROPERTY; ) {
|
||||
obn = obs->next;
|
||||
FreeObjectAndHash(obs, tp);
|
||||
obs = obn;
|
||||
}
|
||||
|
||||
/* Free node i and remove from object hash */
|
||||
for (obp = tp->cell; obp->next; obp = obp->next) {
|
||||
if ((obp->next->type == NODE) && (obp->next->node == i)) {
|
||||
obn = obp->next;
|
||||
obp->next = obp->next->next;
|
||||
FreeObjectAndHash(obn, tp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
FREE(instlist[i]);
|
||||
}
|
||||
}
|
||||
FREE(instlist);
|
||||
return scnt;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
+4
-3
@@ -100,9 +100,9 @@ extern char *Res(char *fname, char *inststr, char *, char *);
|
||||
extern char *XLine(char *fname, char *inststr, char *, char *, char *, char *);
|
||||
extern char *Inductor(char *fname, char *inststr, char *, char *);
|
||||
|
||||
extern int StringIsValue(char *);
|
||||
extern int StringIsValue(char *);
|
||||
extern char *ConvertParam(char *);
|
||||
extern int ConvertStringToFloat(char *, double *);
|
||||
extern int ConvertStringToFloat(char *, double *);
|
||||
extern char *ScaleStringFloatValue(char *, double);
|
||||
extern void join(char *node1, char *node2);
|
||||
extern void Connect(char *tplt1, char *tplt2);
|
||||
@@ -116,7 +116,8 @@ extern void FlattenCurrent();
|
||||
extern void ConvertGlobals(char *name, int fnum);
|
||||
extern int CleanupPins(char *name, int fnum);
|
||||
extern void ConnectAllNodes(char *model, int fnum);
|
||||
extern void CombineParallel(char *model, int fnum);
|
||||
extern int CombineParallel(char *model, int fnum);
|
||||
extern int CombineSerial(char *model, int fnum);
|
||||
extern int NoDisconnectedNodes;
|
||||
extern int PropertyKeyMatch(char *, char *);
|
||||
extern int PropertyValueMatch(char *, char *);
|
||||
|
||||
+66
-1
@@ -340,6 +340,71 @@ void CellRehash(char *name, char *newname, int file)
|
||||
|
||||
struct nlist *OldCell;
|
||||
|
||||
int removeshorted(struct hashlist *p, int file)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
struct objlist *ob, *lob, *nob, *tob;
|
||||
unsigned char shorted;
|
||||
|
||||
ptr = (struct nlist *)(p->ptr);
|
||||
|
||||
if ((file != -1) && (ptr->file != file)) return;
|
||||
|
||||
lob = NULL;
|
||||
for (ob = ptr->cell; ob != NULL;) {
|
||||
nob = ob->next;
|
||||
if ((ob->type == FIRSTPIN) && (ob->model.class != NULL)) {
|
||||
if ((*matchfunc)(ob->model.class, OldCell->name)) {
|
||||
shorted = (unsigned char)1;
|
||||
for (tob = nob; tob->type > FIRSTPIN; tob = tob->next) {
|
||||
if (tob->node != ob->node) {
|
||||
shorted = (unsigned char)0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shorted == (unsigned char)0) {
|
||||
lob = ob;
|
||||
ob = nob;
|
||||
continue;
|
||||
}
|
||||
HashDelete(ob->instance.name, &(ptr->instdict));
|
||||
while (1) {
|
||||
FreeObjectAndHash(ob, ptr);
|
||||
ob = nob;
|
||||
if (ob == NULL) break;
|
||||
nob = ob->next;
|
||||
if (ob->type != PROPERTY && ob->type <= FIRSTPIN) break;
|
||||
}
|
||||
if (lob == NULL)
|
||||
ptr->cell = ob;
|
||||
else
|
||||
lob->next = ob;
|
||||
}
|
||||
else {
|
||||
lob = ob;
|
||||
ob = nob;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lob = ob;
|
||||
ob = nob;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove shorted instances of class "class" from the database */
|
||||
|
||||
void RemoveShorted(char *class, int file)
|
||||
{
|
||||
if (file == -1)
|
||||
OldCell = LookupCell(class);
|
||||
else
|
||||
OldCell = LookupCellFile(class, file);
|
||||
|
||||
if (OldCell == NULL) return;
|
||||
RecurseCellFileHashTable(removeshorted, file);
|
||||
}
|
||||
|
||||
int deleteclass(struct hashlist *p, int file)
|
||||
{
|
||||
struct nlist *ptr;
|
||||
@@ -360,7 +425,7 @@ int deleteclass(struct hashlist *p, int file)
|
||||
ob = nob;
|
||||
if (ob == NULL) break;
|
||||
nob = ob->next;
|
||||
if (ob->type <= FIRSTPIN) break;
|
||||
if (ob->type != PROPERTY && ob->type <= FIRSTPIN) break;
|
||||
}
|
||||
if (lob == NULL)
|
||||
ptr->cell = ob;
|
||||
|
||||
+10
-3
@@ -159,9 +159,16 @@ extern struct objlist *LastPlaced;
|
||||
struct IgnoreList {
|
||||
char *class;
|
||||
int file;
|
||||
unsigned char type;
|
||||
struct IgnoreList *next;
|
||||
};
|
||||
|
||||
/* Types used by IgnoreList above */
|
||||
|
||||
#define IGNORE_NONE (unsigned char)0
|
||||
#define IGNORE_CLASS (unsigned char)1
|
||||
#define IGNORE_SHORTED (unsigned char)2
|
||||
|
||||
/* Record structure for handling pin permutations in a cell */
|
||||
/* Linked list structure allows multiple permutations per cell. */
|
||||
|
||||
@@ -206,10 +213,10 @@ struct nlist {
|
||||
#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */
|
||||
#define CELL_DUPLICATE 0x20 /* cell has a duplicate */
|
||||
|
||||
/* Flags for combination allowances */
|
||||
/* Flags for combination allowances and prohibitions */
|
||||
|
||||
#define COMB_SERIAL 0x20
|
||||
#define COMB_PARALLEL 0x40
|
||||
#define COMB_SERIAL 0x40
|
||||
#define COMB_NO_PARALLEL 0x80
|
||||
|
||||
extern struct nlist *CurrentCell;
|
||||
extern struct objlist *CurrentTail;
|
||||
|
||||
@@ -315,7 +315,6 @@ void PrintE(FILE *outfile, int E)
|
||||
|
||||
|
||||
#if 0
|
||||
INLINE
|
||||
int UsedLeaves(int E1, int E2)
|
||||
/* returns the number of leaves in E1 + E2, which are assumed independent */
|
||||
{
|
||||
@@ -327,7 +326,6 @@ int UsedLeaves(int E1, int E2)
|
||||
#endif
|
||||
|
||||
|
||||
INLINE
|
||||
int CommonNodes(int E1, int E2, int IncludeGlobals)
|
||||
/* returns the number of nodes that E1 and E2 share */
|
||||
/* if IncludeGlobals == 0, do not count large connectivity nodes */
|
||||
@@ -350,7 +348,6 @@ int CommonNodes(int E1, int E2, int IncludeGlobals)
|
||||
return(result);
|
||||
}
|
||||
|
||||
INLINE
|
||||
int GlobalNodes(int E)
|
||||
/* return the number of global nodes that E contacts */
|
||||
/* for now, global nodes are just cell ports */
|
||||
|
||||
+53
-8
@@ -42,6 +42,20 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
// Global storage for parameters from .PARAM
|
||||
struct hashdict spiceparams;
|
||||
|
||||
// Check if a token represents a numerical value (with
|
||||
// units) or an expression. This is basically a hack
|
||||
// to see if it either passes StringIsValue() or is
|
||||
// enclosed in braces. Probably should attempt to
|
||||
// parse the expression, to be pedantic. Not sure all
|
||||
// expressions have to be in braces.
|
||||
|
||||
int StringIsValueOrExpression(char *token)
|
||||
{
|
||||
if (StringIsValue(token)) return TRUE;
|
||||
else if (*token == '{') return TRUE;
|
||||
else return FALSE;
|
||||
}
|
||||
|
||||
void SpiceSubCell(struct nlist *tp, int IsSubCell)
|
||||
{
|
||||
struct objlist *ob;
|
||||
@@ -956,7 +970,7 @@ skip_ends:
|
||||
|
||||
/* Get capacitor value (if present), save as property "value" */
|
||||
if (nexttok != NULL) {
|
||||
if (StringIsValue(nexttok)) {
|
||||
if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
@@ -984,7 +998,7 @@ skip_ends:
|
||||
if ((eqptr = strchr(model, ']')) != NULL)
|
||||
*eqptr = '\0';
|
||||
}
|
||||
else if (StringIsValue(nexttok)) {
|
||||
else if (StringIsValueOrExpression(nexttok)) {
|
||||
// Suport for value passed to modeled capacitor
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
}
|
||||
@@ -1050,7 +1064,7 @@ skip_ends:
|
||||
/* Get resistor value (if present); save as property "value" */
|
||||
|
||||
if (nexttok != NULL) {
|
||||
if (StringIsValue(nexttok)) {
|
||||
if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
@@ -1077,7 +1091,7 @@ skip_ends:
|
||||
if ((eqptr = strchr(model, ']')) != NULL)
|
||||
*eqptr = '\0';
|
||||
}
|
||||
else if (StringIsValue(nexttok)) {
|
||||
else if (StringIsValueOrExpression(nexttok)) {
|
||||
// Suport for value passed to modeled resistor
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
}
|
||||
@@ -1277,7 +1291,7 @@ skip_ends:
|
||||
/* Get inductance value (if present); save as property "value" */
|
||||
|
||||
if (nexttok != NULL) {
|
||||
if (StringIsValue(nexttok)) {
|
||||
if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
@@ -1368,7 +1382,7 @@ skip_ends:
|
||||
*eqptr = '\0';
|
||||
AddProperty(&kvlist, nexttok, eqptr + 1);
|
||||
}
|
||||
else if (StringIsValue(nexttok)) {
|
||||
else if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
@@ -1422,7 +1436,7 @@ skip_ends:
|
||||
*eqptr = '\0';
|
||||
AddProperty(&kvlist, nexttok, eqptr + 1);
|
||||
}
|
||||
else if (StringIsValue(nexttok)) {
|
||||
else if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
@@ -1485,7 +1499,7 @@ skip_ends:
|
||||
*eqptr = '\0';
|
||||
AddProperty(&kvlist, nexttok, eqptr + 1);
|
||||
}
|
||||
else if (StringIsValue(nexttok)) {
|
||||
else if (StringIsValueOrExpression(nexttok)) {
|
||||
AddProperty(&kvlist, "value", nexttok);
|
||||
SpiceTokNoNewline();
|
||||
}
|
||||
@@ -1516,6 +1530,8 @@ skip_ends:
|
||||
|
||||
else if (toupper(nexttok[0]) == 'X') { /* subcircuit instances */
|
||||
char instancename[100], subcktname[100];
|
||||
int itype;
|
||||
|
||||
instancename[99] = '\0';
|
||||
subcktname[99] = '\0';
|
||||
|
||||
@@ -1588,6 +1604,34 @@ skip_ends:
|
||||
if (scan->next != NULL) scan = scan->next;
|
||||
tail->next = NULL;
|
||||
|
||||
/* Check for ignored class */
|
||||
|
||||
if ((itype = IsIgnored(subcktname, filenum)) == IGNORE_CLASS) {
|
||||
Printf("Class '%s' instanced in input but is being ignored.\n", model);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for shorted pins */
|
||||
|
||||
if ((itype == IGNORE_SHORTED) && (head != NULL)) {
|
||||
unsigned char shorted = (unsigned char)1;
|
||||
struct portelement *p;
|
||||
for (p = head->next; p; p = p->next) {
|
||||
if (strcasecmp(head->name, p->name))
|
||||
shorted = (unsigned char)0;
|
||||
break;
|
||||
}
|
||||
if (shorted == (unsigned char)1) {
|
||||
Printf("Instance of '%s' is shorted, ignoring.\n", subcktname);
|
||||
while (head) {
|
||||
p = head->next;
|
||||
FREE(head);
|
||||
head = p;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create cell name and revise instance name based on the cell name */
|
||||
/* For clarity, if "instancename" does not contain the cellname, */
|
||||
/* then prepend the cellname to the instance name. HOWEVER, if any */
|
||||
@@ -1644,6 +1688,7 @@ skip_ends:
|
||||
}
|
||||
|
||||
/* nexttok is now NULL, scan->name points to class */
|
||||
|
||||
Instance(subcktname, instancename);
|
||||
pobj = LinkProperties(subcktname, kvlist);
|
||||
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
|
||||
|
||||
+70
-16
@@ -497,7 +497,9 @@ CommonParseCell(Tcl_Interp *interp, Tcl_Obj *objv,
|
||||
fnum = -1;
|
||||
}
|
||||
else
|
||||
filename = Tcl_GetString(fobj);
|
||||
/* Both file numbers have been provided, so a */
|
||||
/* filename is not required. */
|
||||
filename = NULL;
|
||||
}
|
||||
else {
|
||||
filename = NULL;
|
||||
@@ -2022,10 +2024,6 @@ _netcmp_compare(ClientData clientData,
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
// WIP!
|
||||
// CleanupPins(name1, fnum1); // Remove unconnected pins
|
||||
// CleanupPins(name2, fnum2); // Remove unconnected pins
|
||||
|
||||
UniquePins(name1, fnum1); // Check for and remove duplicate pins
|
||||
UniquePins(name2, fnum2); // Check for and remove duplicate pins
|
||||
|
||||
@@ -2039,10 +2037,6 @@ _netcmp_compare(ClientData clientData,
|
||||
// but define global nodes that are brought out as ports by
|
||||
// ConvertGlobals().
|
||||
|
||||
// WIP!
|
||||
// CleanupPins(name1, fnum1);
|
||||
// CleanupPins(name2, fnum2);
|
||||
|
||||
CreateTwoLists(name1, fnum1, name2, fnum2);
|
||||
while (PrematchLists(name1, fnum1, name2, fnum2) > 0) {
|
||||
Fprintf(stdout, "Making another compare attempt.\n");
|
||||
@@ -2518,10 +2512,10 @@ _netcmp_ignore(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
|
||||
{
|
||||
char *options[] = {
|
||||
"class", NULL
|
||||
"class", "shorted", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
CLASS_IDX
|
||||
CLASS_IDX, SHORTED_IDX
|
||||
};
|
||||
int result, index;
|
||||
int file = -1;
|
||||
@@ -2542,7 +2536,14 @@ _netcmp_ignore(ClientData clientData,
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "[class] valid_cellname");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
IgnoreClass(name, file);
|
||||
switch (index) {
|
||||
case CLASS_IDX:
|
||||
IgnoreClass(name, file, IGNORE_CLASS);
|
||||
break;
|
||||
case SHORTED_IDX:
|
||||
IgnoreClass(name, file, IGNORE_SHORTED);
|
||||
break;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
@@ -2966,6 +2967,13 @@ _netcmp_equate(ClientData clientData,
|
||||
/* merge --- set property merge behavior */
|
||||
/* or */
|
||||
/* netgen::property default */
|
||||
/* or */
|
||||
/* netgen::property <device>|<model> <option> */
|
||||
/* yes|no */
|
||||
/* Where <option> is one of: */
|
||||
/* serial --- allow/prohibit serial combination */
|
||||
/* parallel --- allow/prohibit parallel combination */
|
||||
/* */
|
||||
/* Formerly: (none) */
|
||||
/* Results: */
|
||||
/* Side Effects: */
|
||||
@@ -2983,10 +2991,12 @@ _netcmp_property(ClientData clientData,
|
||||
int ival, argstart;
|
||||
|
||||
char *options[] = {
|
||||
"add", "create", "remove", "delete", "tolerance", "merge", NULL
|
||||
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
|
||||
"parallel", NULL
|
||||
};
|
||||
enum OptionIdx {
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX
|
||||
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX,
|
||||
SERIAL_IDX, PARALLEL_IDX
|
||||
};
|
||||
int result, index, idx2;
|
||||
|
||||
@@ -3003,6 +3013,9 @@ _netcmp_property(ClientData clientData,
|
||||
enum MergeOptionIdx {
|
||||
NONE_IDX, ADD_ONLY_IDX, ADD_CRIT_IDX, PAR_ONLY_IDX, PAR_CRIT_IDX
|
||||
};
|
||||
char *yesno[] = {
|
||||
"on", "yes", "true", "enable", "allow", "off", "no", "false", "disable", "prohibit", NULL
|
||||
};
|
||||
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname ?option?");
|
||||
@@ -3018,8 +3031,8 @@ _netcmp_property(ClientData clientData,
|
||||
/* compare source/drain area and perimeter. */
|
||||
|
||||
tp = FirstCell();
|
||||
while (tp != NULL) {
|
||||
switch (tp->class) {
|
||||
while (tp != NULL) {
|
||||
switch (tp->class) {
|
||||
case CLASS_NMOS: case CLASS_PMOS: case CLASS_FET3:
|
||||
case CLASS_NMOS4: case CLASS_PMOS4: case CLASS_FET4:
|
||||
case CLASS_FET:
|
||||
@@ -3031,6 +3044,7 @@ _netcmp_property(ClientData clientData,
|
||||
break;
|
||||
case CLASS_RES: case CLASS_RES3:
|
||||
PropertyMerge(tp->name, tp->file, "l", MERGE_PAR_CRIT);
|
||||
tp->flags |= COMB_SERIAL;
|
||||
break;
|
||||
case CLASS_CAP: case CLASS_ECAP: case CLASS_CAP3:
|
||||
// NOTE: No attempt to combine area, width, or length;
|
||||
@@ -3039,6 +3053,7 @@ _netcmp_property(ClientData clientData,
|
||||
break;
|
||||
case CLASS_INDUCTOR:
|
||||
PropertyMerge(tp->name, tp->file, "value", MERGE_PAR_CRIT);
|
||||
tp->flags |= COMB_SERIAL;
|
||||
break;
|
||||
}
|
||||
tp = NextCell();
|
||||
@@ -3094,6 +3109,45 @@ _netcmp_property(ClientData clientData,
|
||||
argstart = 3;
|
||||
|
||||
switch (index) {
|
||||
case SERIAL_IDX:
|
||||
case PARALLEL_IDX:
|
||||
if (objc == 3) {
|
||||
if (index == SERIAL_IDX) {
|
||||
tobj1 = Tcl_NewBooleanObj((tp->flags & COMB_SERIAL) ? 1 : 0);
|
||||
Tcl_SetObjResult(interp, tobj1);
|
||||
return TCL_OK;
|
||||
}
|
||||
else {
|
||||
tobj1 = Tcl_NewBooleanObj((tp->flags & COMB_NO_PARALLEL) ? 0 : 1);
|
||||
Tcl_SetObjResult(interp, tobj1);
|
||||
return TCL_OK;
|
||||
}
|
||||
}
|
||||
else if (objc == 4) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[3],
|
||||
(CONST84 char **)yesno,
|
||||
"combine", 0, &idx2) != TCL_OK) {
|
||||
Tcl_WrongNumArgs(interp, 3, objv, "enable|disable");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (idx2 <= 4) { /* true, enable, etc. */
|
||||
if (index == SERIAL_IDX)
|
||||
tp->flags |= COMB_SERIAL;
|
||||
else
|
||||
tp->flags &= ~COMB_NO_PARALLEL;
|
||||
}
|
||||
else { /* false, disable, etc. */
|
||||
if (index == SERIAL_IDX)
|
||||
tp->flags &= ~COMB_SERIAL;
|
||||
else
|
||||
tp->flags |= COMB_NO_PARALLEL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "serial|parallel enable|disable");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case ADD_IDX:
|
||||
case CREATE_IDX:
|
||||
|
||||
Reference in New Issue
Block a user