ThymeAnalysis.mesa
Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Christian LeCocq January 23, 1987 1:53:44 pm PST
Sweetsun Chen, July 22, 1985 7:57:56 pm PDT
DIRECTORY
IO,
ThymeGlobals USING[branchLinkPtr, branchPtr, elements, ErrorAtNB, Handle, MakeStringNB, modFuncPtr, nodePtr, RefC, RefI, RefL, RefR, RefV];
ThymeAnalysis: CEDAR PROGRAM
IMPORTS
IO,
ThymeGlobals
EXPORTS
ThymeGlobals
= BEGIN
Handle: TYPE= ThymeGlobals.Handle;
CheckNode: PROC[handle: Handle, n: ThymeGlobals.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: ThymeGlobals.branchPtr;
capsBody: ThymeGlobals.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: ThymeGlobals.branchPtr]= {
pCount, nCount: LONG CARDINAL ← 0;
pAvail, nAvail: BOOLFALSE;
pNode: ThymeGlobals.nodePtr ← v.posNode;
nNode: ThymeGlobals.nodePtr ← v.negNode;
blP: ThymeGlobals.branchLinkPtr;
IF pNode=handle.vars.gndNode THEN
{IF nNode.curPtr # v THEN ThymeGlobals.ErrorAtNB[handle, 490, NIL, v]}
ELSE
IF nNode=handle.vars.gndNode THEN
{IF pNode.curPtr # v THEN ThymeGlobals.ErrorAtNB[handle, 490, NIL, v]}
ELSE {
pAvail ← pNode.curPtr=NIL;
nAvail ← nNode.curPtr=NIL;
IF ~pAvail AND ~nAvail THEN ThymeGlobals.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: ThymeGlobals.RefV => pCount ← pCount + 1;
ENDCASE;
blP← blP.nextLink;
ENDLOOP;
blP ← nNode.branches;
UNTIL blP=NIL DO
WITH blP.branch.body SELECT FROM
x: ThymeGlobals.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: ThymeGlobals.branchPtr;
blP: ThymeGlobals.branchLinkPtr;
vP: ThymeGlobals.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: ThymeGlobals.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: ThymeGlobals.RefV ← NARROW[vP.body];
AllocateCurrent[handle, vP];
vP← vPBody.nextvSource;
ENDLOOP;
}; -- AssignCurrents
DCPath: PROC[n: ThymeGlobals.nodePtr]= {
IF ~n.marked THEN {
n.marked ← TRUE;
FOR bLink: ThymeGlobals.branchLinkPtr← n.branches, bLink.nextLink UNTIL bLink=NIL DO
b: ThymeGlobals.branchPtr = bLink.branch;
IF b^.eType # capacitor AND b^.eType # iSource THEN
WITH b.body SELECT FROM
x: ThymeGlobals.RefC => NULL;
ENDCASE => DCPath[(IF b.posNode=n THEN b.negNode ELSE b.posNode)];
ENDLOOP;
};
}; -- DCPath
ForceDCPaths: PROC[handle: Handle]= {
problemNode: ThymeGlobals.nodePtr ← NIL;
problemCount: INT ← 0;
DCPath[handle.vars.gndNode];
FOR n: ThymeGlobals.nodePtr ← handle.vars.nodeList, n.nextNode UNTIL n=NIL DO
IF ~n.marked THEN {
FOR bLink: ThymeGlobals.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 {
ThymeGlobals.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[ThymeGlobals.MakeStringNB[handle, problemNode, NIL, FALSE]]];
};
}; -- ForceDCPaths
VsXPath: PROC[n: ThymeGlobals.nodePtr, skip: ThymeGlobals.branchPtr,
type: ThymeGlobals.elements]= {
bLink: ThymeGlobals.branchLinkPtr;
b: ThymeGlobals.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: ThymeGlobals.RefR => IF type=resistor THEN GOTO common;
x: ThymeGlobals.RefC => IF type=capacitor THEN GOTO common;
x: ThymeGlobals.RefL => IF type=inductor THEN GOTO common;
x: ThymeGlobals.RefV => GOTO common;
x: ThymeGlobals.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: ThymeGlobals.nodePtr;
v: ThymeGlobals.branchPtr← handle.vars.vSourceList;
vBody: ThymeGlobals.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 ThymeGlobals.ErrorAtNB[handle, 402, NIL, v];
vBody ← NARROW[v.body];
v ← vBody.nextvSource;
ENDLOOP;
}; -- VsIndLoops
IndNodes: PROC[handle: Handle]= {
bLink: ThymeGlobals.branchLinkPtr;
i: ThymeGlobals.branchPtr;
iBody: ThymeGlobals.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: ThymeGlobals.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: ThymeGlobals.RefL => NULL; -- leave it as it is
ENDCASE => negOk← TRUE;
bLink ← bLink.nextLink;
ENDLOOP;
IF ~(posOk AND negOk) THEN ThymeGlobals.ErrorAtNB[handle, 403, NIL, i];
iBody← NARROW[i.body];
i ← iBody.nextInductor;
ENDLOOP;
}; -- IndNodes
SeparateFunctions: PROC[handle: Handle]= {
nodes: ThymeGlobals.nodePtr← handle.vars.nodeList;
state: REAL= 1.0;
other: REAL= 0.0;
gnd: ThymeGlobals.nodePtr= handle.vars.gndNode;
mf: ThymeGlobals.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
ThymeGlobals.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.
Christian LeCocq January 23, 1987 9:48:10 am PST
capitalized procs, change spMumble into ThymeMumble