File: [Cherry]<Thyme>Cedar5.2>System>spAnalysis.mesa
Last Edited by: SChen, May 8, 1985 4:39:35 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: BOOLFALSE;
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.