File: [Cherry]<Thyme>Cedar5.1>System>spAnalysis.mesa
Last Edited by: SChen, September 16, 1984 4:26:35 pm PDT
DIRECTORY
spGlobals USING[
branchLinkPtr, branchPtr, elements, ErrorAtNB, Handle, modFuncPtr, nodePtr, RefC, RefI, RefL, RefR, RefV];
spAnalysis: CEDAR PROGRAM
IMPORTS 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]= {
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^.eType # capacitor AND b^.eType # iSource THEN
WITH b.body SELECT FROM
x: spGlobals.RefC => NULL;
ENDCASE => IF b.posNode=n THEN dcPath[b.negNode]
ELSE dcPath[b.posNode];
bLink← bLink.nextLink
ENDLOOP;
};
};
-- dcPath

forceDcPaths: PROC[handle: Handle]= {
n: spGlobals.nodePtr;
dcPath[handle.vars.gndNode];
n← handle.vars.nodeList;
UNTIL n=NIL DO
IF ~n.marked THEN spGlobals.ErrorAtNB[handle, 401, n, NIL];
n← n.nextNode;
ENDLOOP;
};
-- 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