File: spAnalysis.mesa
Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Sweetsun Chen, July 22, 1985 7:57:56 pm PDT
DIRECTORY
IO,
spGlobals USING[
branchLinkPtr, branchPtr, elements, ErrorAtNB, Handle, makeStringNB, modFuncPtr, nodePtr, RefC, RefI, RefL, RefR, RefV];
spAnalysis: CEDAR PROGRAM IMPORTS IO, spGlobals EXPORTS spGlobals=
BEGIN
Handle: TYPE= spGlobals.Handle;
checkNode:
PROC[handle: Handle, n: spGlobals.nodePtr]= {
IF n.integrate OR n=handle.vars.gndNode OR n.curPtr # NIL THEN RETURN
ELSE {
n.integrate← TRUE;
n.nextIntNode← handle.vars.intNodeList;
handle.vars.intNodeList← n;
};
}; -- checkNode
assignIntNodes:
PROC[handle: Handle]= {
caps: spGlobals.branchPtr;
capsBody: spGlobals.RefC;
caps← handle.vars.capacitorList;
UNTIL caps=
NIL
DO
checkNode[handle, caps.posNode];
checkNode[handle, caps.negNode];
capsBody← NARROW[caps.body];
caps← capsBody.nextCapacitor
ENDLOOP;
}; -- assignIntNodes
allocateCurrent:
PROC[handle: Handle, v: spGlobals.branchPtr]= {
pCount, nCount: LONG CARDINAL← 0;
pAvail, nAvail: BOOL← FALSE;
pNode: spGlobals.nodePtr← v.posNode;
nNode: spGlobals.nodePtr← v.negNode;
blP: spGlobals.branchLinkPtr;
IF pNode=handle.vars.gndNode
THEN
{IF nNode.curPtr # v THEN spGlobals.ErrorAtNB[handle, 490, NIL, v]}
ELSE
IF nNode=handle.vars.gndNode
THEN
{IF pNode.curPtr # v THEN spGlobals.ErrorAtNB[handle, 490, NIL, v]}
ELSE {
pAvail← pNode.curPtr=NIL;
nAvail← nNode.curPtr=NIL;
IF ~pAvail AND ~nAvail THEN spGlobals.ErrorAtNB[handle, 490, NIL, v]
ELSE
IF pAvail AND ~nAvail THEN pNode.curPtr← v
ELSE
IF ~pAvail AND nAvail THEN nNode.curPtr← v
ELSE {
blP← pNode.branches;
UNTIL blP=
NIL
DO
WITH blP.branch.body
SELECT
FROM
x: spGlobals.RefV => pCount← pCount + 1;
ENDCASE;
blP← blP.nextLink;
ENDLOOP;
blP← nNode.branches;
UNTIL blP=
NIL
DO
WITH blP.branch.body
SELECT
FROM
x: spGlobals.RefV => nCount← nCount + 1;
ENDCASE;
blP← blP.nextLink;
ENDLOOP;
IF pCount < nCount THEN pNode.curPtr← v
ELSE nNode.curPtr← v;
};
};
}; -- allocateCurrent
assignCurrents:
PROC[handle: Handle]= {
branchP: spGlobals.branchPtr;
blP: spGlobals.branchLinkPtr;
vP: spGlobals.branchPtr;
Check connections to ground node first.
blP← handle.vars.gndNode.branches;
UNTIL blP=
NIL
DO
branchP← blP.branch;
WITH branchP.body
SELECT
FROM
x: spGlobals.RefV => {
IF branchP.posNode # handle.vars.gndNode
THEN
branchP.posNode.curPtr← branchP
ELSE branchP.negNode.curPtr← branchP;
};
ENDCASE;
blP← blP.nextLink;
ENDLOOP;
Do remaining branches.
vP← handle.vars.vSourceList;
UNTIL vP=
NIL
DO
vPBody: spGlobals.RefV← NARROW[vP.body];
allocateCurrent[handle, vP];
vP← vPBody.nextvSource;
ENDLOOP;
}; -- assignCurrents
dcPath:
PROC[n: spGlobals.nodePtr]= {
IF ~n.marked
THEN {
n.marked← TRUE;
FOR bLink: spGlobals.branchLinkPtr← n.branches, bLink.nextLink
UNTIL bLink=
NIL
DO
b: spGlobals.branchPtr = bLink.branch;
IF b^.eType # capacitor AND b^.eType # iSource THEN
WITH b.body
SELECT
FROM
x: spGlobals.RefC => NULL;
ENDCASE => dcPath[(IF b.posNode=n THEN b.negNode ELSE b.posNode)];
ENDLOOP;
};
}; -- dcPath
forceDcPaths:
PROC[handle: Handle]= {
problemNode: spGlobals.nodePtr ← NIL;
problemCount: INT ← 0;
dcPath[handle.vars.gndNode];
FOR n: spGlobals.nodePtr ← handle.vars.nodeList, n.nextNode
UNTIL n=
NIL
DO
IF ~n.marked
THEN {
FOR bLink: spGlobals.branchLinkPtr← n.branches, bLink.nextLink
UNTIL bLink=
NIL
DO
We know this branch is a capacitor
IF bLink.branch.negNode # handle.vars.gndNode
AND bLink.branch.posNode # handle.vars.gndNode
THEN {
spGlobals.ErrorAtNB[handle, 401, n, NIL]; -- doesn't go to Gnd
EXIT;
};
ENDLOOP;
problemNode ← n;
problemCount ← problemCount+1;
};
ENDLOOP;
IF problemCount>0
THEN {
handle.msgStream.PutF[
"\nThe branches to %d nodes, for example %g, are only capacitors to Gnd\n",
IO.int[problemCount],
IO.rope[spGlobals.makeStringNB[handle, problemNode, NIL, FALSE]]];
};
}; -- forceDcPaths
vsXPath:
PROC[n: spGlobals.nodePtr, skip: spGlobals.branchPtr,
type: spGlobals.elements]= {
bLink: spGlobals.branchLinkPtr;
b: spGlobals.branchPtr;
IF ~n.marked
THEN {
n.marked← TRUE;
bLink← n.branches;
UNTIL bLink=
NIL
DO
b← bLink.branch;
IF b # skip
THEN {
WITH b.body
SELECT
FROM
x: spGlobals.RefR => IF type=resistor THEN GOTO common;
x: spGlobals.RefC => IF type=capacitor THEN GOTO common;
x: spGlobals.RefL => IF type=inductor THEN GOTO common;
x: spGlobals.RefV => GOTO common;
x: spGlobals.RefI => IF type=iSource THEN GOTO common;
ENDCASE;
EXITS
common =>
IF b.posNode=n
THEN vsXPath[b.negNode,
NIL, type]
ELSE vsXPath[b.posNode, NIL, type];
};
bLink← bLink.nextLink;
ENDLOOP;
};
}; -- vsXPath
vsIndLoops:
PROC[handle: Handle]= {
n: spGlobals.nodePtr;
v: spGlobals.branchPtr← handle.vars.vSourceList;
vBody: spGlobals.RefV;
UNTIL v=
NIL
DO
n← handle.vars.nodeList;
UNTIL n=
NIL
DO
n.marked← FALSE;
n← n.nextNode;
ENDLOOP;
vsXPath[v.posNode, v, inductor];
IF v.negNode.marked THEN spGlobals.ErrorAtNB[handle, 402, NIL, v];
vBody← NARROW[v.body];
v← vBody.nextvSource;
ENDLOOP;
}; -- vsIndLoops
indNodes:
PROC[handle: Handle]= {
bLink: spGlobals.branchLinkPtr;
i: spGlobals.branchPtr;
iBody: spGlobals.RefL;
posOk, negOk: BOOL;
i← handle.vars.inductorList;
UNTIL i=NIL DO
bLink← i.posNode.branches;
posOk← FALSE;
UNTIL bLink=
NIL
DO
-- if anyone is not an inductor then posOk← TURE
WITH bLink.branch.body
SELECT
FROM
x: spGlobals.RefL => NULL; -- leave it as it is
ENDCASE => posOk← TRUE;
bLink← bLink.nextLink;
ENDLOOP;
bLink← i.negNode.branches;
negOk← FALSE;
UNTIL bLink=
NIL
DO
-- if anyone is not an inductor then negOk← TURE
WITH bLink.branch.body
SELECT
FROM
x: spGlobals.RefL => NULL; -- leave it as it is
ENDCASE => negOk← TRUE;
bLink← bLink.nextLink;
ENDLOOP;
IF ~(posOk AND negOk) THEN spGlobals.ErrorAtNB[handle, 403, NIL, i];
iBody← NARROW[i.body];
i← iBody.nextInductor;
ENDLOOP;
}; -- indNodes
separateFunctions:
PROC[handle: Handle]= {
nodes: spGlobals.nodePtr← handle.vars.nodeList;
state: REAL= 1.0;
other: REAL= 0.0;
gnd: spGlobals.nodePtr= handle.vars.gndNode;
mf: spGlobals.modFuncPtr;
nonState: BOOL;
UNTIL nodes=
NIL
DO
OPEN nodes;
nHist.y←
IF integrate
OR nodes=gnd
THEN state
ELSE
IF curPtr #
NIL
THEN
IF curPtr.controller=
NIL
THEN
IF curPtr.posNode=gnd
OR
curPtr.negNode=gnd THEN state
ELSE other
ELSE
IF curPtr.controller.argVector=
NIL
THEN
IF curPtr.posNode=gnd
OR
curPtr.negNode=gnd THEN state
ELSE other
ELSE
IF curPtr.controller.argVector.size=0
THEN
IF curPtr.posNode=gnd
OR
curPtr.negNode=gnd THEN state
ELSE other
ELSE other
ELSE other;
nHist.f0← other;
nodes← nextNode;
ENDLOOP;
UNTIL handle.vars.functionList=
NIL
DO
OPEN handle.vars;
nonState← FALSE;
IF functionList.arguments #
NIL
THEN
FOR i:
NAT
IN [0..functionList.arguments.size)
DO
nonState← functionList.arguments[i].nHist.y=other;
IF nonState THEN EXIT;
ENDLOOP;
mf← functionList.nextMFPtr;
IF nonState
THEN {
functionList.nextMFPtr← otherModFunc;
otherModFunc← functionList; }
ELSE {
functionList.nextMFPtr← intNodeModFunc;
intNodeModFunc← functionList;
};
functionList← mf;
ENDLOOP;
}; -- separateFunctions
topoAnalysis:
PUBLIC
PROC[handle: Handle]= {
forceDcPaths[handle];
vsIndLoops[handle];
indNodes[handle];
assignCurrents[handle];
assignIntNodes[handle];
separateFunctions[handle];
IF handle.vars.otherModFunc # NIL THEN
spGlobals.PutMsgLine[handle, "Non-state controlled functions."];
Commented the above until a better algorithm to check non-state controlled functions is employed. With the current algorithm, otherModFunc may be non-nil for the following example:
! ThymeBasics.thy
Vdd, fooNode: node;
?: voltage[Vdd, Gnd] = 5.0;
?: voltage[fooNode, Vdd] = 0.0;
?: Diffusion[fooNode, Vdd];
}; -- topoAnalysis
END.
CHANGE LOG.
Wilhelm, February 24, 1982 3:08 PM
Barth, 7-May-82 10:46:50 PDT
Chen, June 10, 1984 5:29:02 pm PDT, cedarized
McCreight, April 3, 1985 12:12:06 pm PST, added codes in "forceDcPaths" to provide more information for user.
Chen, July 22, 1985 7:55:49 pm PDT => Cedar6.0.