File: [Cherry]<Thyme>System>Cedar5.1>spBomb.mesa
Last Edited by: SChen, September 17, 1984 4:59:19 pm PDT
DIRECTORY
IO USING [int, PutF, rope],
Rope USING [Cat, Concat, Equal, Fetch, Length, ROPE],
RopeFrom USING [String],
spGlobals USING[Aborted, argNames, branch, branchLink, branchLinkPtr, branchPtr, Canned, CapacitorBody, conLinkPtr, error, error2, ErrorSignal, ErrorStrings, eval, expressionPtr, FunctionBody, Handle, InductorBody, instTreeNode, instTreePtr, ISourceBody, modBrPtr, ModelBody, modelBranch, modFuncBlk, modFuncPtr, namePtr, next, node, nodePtr, nodePtrSeq, RealBranch, RealModel, RealNode, RealParm, realThingPtr, realThing, realThings, RefBranchRec, RefCircuitRec, RefCktInstRec, RefFunctionRec, RefModBody, RefModelRec, RefNodeRec, RefParmRec, refR, RefRealBranch, RefRealModel, RefRealNode, RefRealParm, RefUnReal, refUnReal, ValueSeq, VSourceBody];
spBomb: CEDAR PROGRAM
IMPORTS IO, Rope, RopeFrom, spGlobals
EXPORTS spGlobals=
BEGIN OPEN spGlobals;
pushCopies: PROC[nameList: namePtr]= {
For each namePtr linked with the nameList, allocate and initialize its new realCopy:
If the namePtr is for a circuit, a circuit instance, a model or a function, then the realCopy is NIL; Otherwise, the nextThing of the new realCopy is the original realCopy, its newLevel is the default (TRUE), and its thing is unReal, unless the namePtr is a parameter name pointer with default, in which case thing points to the default value.
r: realThingPtr;
WHILE nameList # NIL DO
WITH nameList.details SELECT FROM
x: RefCircuitRec => r← NIL;
x: RefCktInstRec => r← NIL;
x: RefFunctionRec => r← NIL;
p: RefParmRec => r← NEW[realThing← [
nextThing: nameList.realCopy,
thing: IF p.default THEN NEW[RealParm← [rp: p.dfltValue]] ELSE refUnReal] ];
ENDCASE => r← NEW[realThing← [nextThing: nameList.realCopy, thing: refUnReal] ];
nameList.realCopy← r;
nameList← nameList.srchLink;
ENDLOOP;
}; -- pushCopies
advanceLevel: PROC[nameList: namePtr]= {
For each namePtr linked with the nameList, set its realCopy.newLevel to FALSE.
UNTIL nameList=NIL DO
IF nameList.realCopy # NIL THEN nameList.realCopy.newLevel← FALSE;
nameList← nameList.srchLink;
ENDLOOP;
}; -- advanceLevel
popCopies: PROC[handle: Handle, nameList: namePtr]= {
For each namePtr linked with the nameList, pop up its realCopy.nextThing as its realCopy; if the original realCopy points to a nodePtr with nonNIL branches then pop the nodePtr on the handle.vars.nodeList, with original handle.vars.nodeList as its nextNode, and increment handle.vars.nodeCount; if the original realCopy points to a nodePtr with NIL branches then pop the nodePtr on top of handle.vars.unusedNodes with the original handle.vars.unusedNodes as its nextNode.
WHILE nameList # NIL DO
WITH nameList.details SELECT FROM
x: RefCircuitRec => NULL;
x: RefCktInstRec => NULL;
x: RefFunctionRec => NULL;
n: RefNodeRec =>
WITH nameList.realCopy.thing SELECT FROM
r: RefRealNode => {
IF r.rn.branches # NIL THEN {
handle.vars.nodeCount← handle.vars.nodeCount + 1;
r.rn.nextNode← handle.vars.nodeList;
handle.vars.nodeList← r.rn;
}
ELSE {
r.rn.nextNode← handle.vars.unusedNodes;
handle.vars.unusedNodes← r.rn;
};
nameList.realCopy← nameList.realCopy.nextThing;
};
ENDCASE => nameList.realCopy← nameList.realCopy.nextThing;
ENDCASE => nameList.realCopy← nameList.realCopy.nextThing;
nameList← nameList.srchLink;
ENDLOOP;
}; -- popCopies
getParmValue: PUBLIC PROC[handle: Handle, nPtr: namePtr] RETURNS[REAL]= {
ENABLE ErrorSignal => ErrorSignal[331, s];
getRealThing[handle, nPtr];
IF handle.vars.n # NIL THEN RETURN[LOOPHOLE[handle.vars.n]] ELSE
RETURN[handle.vars.p]; -- *
}; -- getParmValue
getRealThing: PROC[handle: Handle, nPtr: namePtr]= {
Reset n,b,m,and p; If nPtr and its realCopy is not NIL then depending on the type of its realCopy (or the non-nil nextThing of its realCopy, if its realCopy.newLevel is TRUE), set n,b,m, or p accordingly; but if its realCopy (or the nextThing, see above) is NIL and nPtr.details.default then set p with the default.
rCopy: realThingPtr;
handle.vars.n← NIL; handle.vars.b← NIL; handle.vars.m← NIL; handle.vars.p← 0.0;
IF nPtr=NIL THEN RETURN;
rCopy← nPtr.realCopy;
IF rCopy # NIL AND rCopy.newLevel THEN rCopy← rCopy.nextThing;
IF rCopy # NIL THEN
WITH rCopy.thing SELECT FROM
rt: RefRealNode => handle.vars.n← rt.rn;
rt: RefRealBranch => handle.vars.b← rt.rb;
rt: RefRealParm => handle.vars.p← rt.rp;
rt: RefRealModel => handle.vars.m← rt.rm;
rt: RefUnReal => ErrorSignal[330, nPtr.name];
ENDCASE
ELSE
WITH nPtr.details SELECT FROM
pn: RefParmRec =>
IF pn.default THEN handle.vars.p← pn.dfltValue ELSE ErrorSignal[331, nPtr.name];
ENDCASE => error2[handle, 390, nPtr];
}; -- getRealThing
putRealThing: PROC[handle: Handle, nPtr: namePtr, t: realThings]= {
Depending on the type of t, initialize nPtr.realCopy.thing to point to (the content of) n, b, p, or m.
rCopy: realThingPtr← nPtr.realCopy;
IF nPtr.realCopy # NIL THEN
SELECT t FROM
realNode => rCopy.thing← NEW[RealNode← [handle.vars.n]];
realBranch => rCopy.thing← NEW[RealBranch← [handle.vars.b]];
realParm => rCopy.thing← NEW[RealParm← [handle.vars.p]];
realModel => rCopy.thing← NEW[RealModel← [handle.vars.m]];
ENDCASE;
}; -- putRealThing
putParmValue: PUBLIC PROC[handle: Handle, nPtr: namePtr, val: REAL]= {
handle.vars.p← val;
putRealThing[handle, nPtr, realParm];
}; -- putParmValue
makeConnections: PROC[handle: Handle, connections: conLinkPtr, fakes: namePtr]= {
For each connection linked with connections, set n to its namedNode.realCopy.thing.rn; let fakes.realCopy.thing point to n, then proceed similarly (for connection.nextLink with fakes.nextName, and so on).
UNTIL fakes=NIL DO
getRealThing[handle, connections.namedNode];
putRealThing[handle, fakes, realNode];
fakes← fakes.nextName;
connections← connections.nextLink;
ENDLOOP;
}; -- makeConnections
apply: PROC[handle: Handle, apList: expressionPtr]= {
UNTIL apList=NIL DO
[]← eval[handle, apList];
apList← apList.next;
ENDLOOP;
}; -- apply
explodeInstance: PROC[handle: Handle, instNamePtr: namePtr] RETURNS[t: instTreePtr]= {
exp: expressionPtr;
inst: RefCktInstRec← NARROW[instNamePtr.details];
ckt: namePtr← NARROW[inst.of];
cktDetails: RefCircuitRec← NARROW[ckt.details];
pushCopies[cktDetails.names];
makeConnections[handle, inst.connections, cktDetails.fakeNodes];
apply[handle, inst.actualParms];
advanceLevel[cktDetails.names];
t← NEW[instTreeNode← [instance: instNamePtr] ];
exp← cktDetails.assertions;
UNTIL exp=NIL DO
IF eval[handle, exp]=0.0 THEN error2[handle, 341, instNamePtr];
exp← exp.next;
ENDLOOP;
explode[handle, ckt, t];
popCopies[handle, cktDetails.names];
}; -- explodeInstance
explodeModelFunc: PROC[handle: Handle, mfNamePtr: namePtr, newFunc: modFuncPtr]= {
index: NAT;
arguments: argNames;
parms, p: expressionPtr;
WITH mfNamePtr.details SELECT FROM
m: RefModelRec => {
newFunc.argVector← m.modelArgVec;
arguments← m.modelArgs;
parms← m.modelParms;
};
f: RefFunctionRec => {
newFunc.argVector← f.funcArgVec;
arguments← f.funcArgs;
parms← f.funcParms;
};
ENDCASE => error2[handle, 399, mfNamePtr];
IF arguments # NIL THEN {
newFunc.arguments← NEW[nodePtrSeq[arguments.size]];
-- initialize each argument
FOR index IN [0..arguments.size) DO
IF arguments[index] # NIL THEN getRealThing[handle, arguments[index]];
newFunc.arguments[index]← handle.vars.n;
ENDLOOP;
};
index← 0;
FOR p← parms, p.next UNTIL p=NIL DO index← index + 1; ENDLOOP;
newFunc.parmVector← NEW[ValueSeq[index]];
-- initialize each parameter of newFunc
UNTIL index=0 DO
index← index - 1;
newFunc.parmVector[index]← eval[handle, parms];
parms← parms.next;
ENDLOOP;
}; -- explodeModelFunc
explodeController: PROC[handle: Handle, branchNamePtr: namePtr, newB: branchPtr]= {
brDetails: RefBranchRec← NARROW[branchNamePtr.details];
oldmf: namePtr← brDetails.controller;
newFunc: modFuncPtr;
newModB: modBrPtr;
WITH oldmf.details SELECT FROM
fcn: RefFunctionRec => {
handle.vars.funcCount← handle.vars.funcCount + 1;
newFunc← NEW[modFuncBlk← [
nextMFPtr: handle.vars.functionList,
body: NEW[FunctionBody← [functionProc: fcn.functionProc, branch: newB]]
]];
handle.vars.functionList← newFunc; -- *
explodeModelFunc[handle, oldmf, newFunc];
newB.controller← newFunc;
};
mod: RefModelRec => {
mBody: RefModBody;
getRealThing[handle, oldmf];
mBody← NARROW[handle.vars.m.body];
newModB← NEW[modelBranch← [nextBranch: mBody.modelBranches, b: newB]];
mBody.modelBranches← newModB;
newB.controller← handle.vars.m;
newB.modelIndex← brDetails.modelIndex;
};
ENDCASE => error2[handle, 399, branchNamePtr];
}; -- explodeController
connectBranch: PROC[n: nodePtr, b: branchPtr, pos: BOOL]= {
newLink: branchLinkPtr;
IF n # NIL THEN {
newLink← NEW[branchLink← [nextLink: n.branches, branch: b, pos: pos]];
n.branches← newLink;
IF pos THEN b.posNode← n ELSE b.negNode← n;
}
ELSE ErrorSignal[242, b.branchName.name];
}; -- connectBranch
explodeBranch: PROC[handle: Handle, branchNamePtr: namePtr]
RETURNS[newB: branchPtr← NIL]= {
pNode, nNode: nodePtr;
newC, newL, newV, newI: branchPtr;
brDetails: RefBranchRec← NARROW[branchNamePtr.details];
handle.vars.branchCount← handle.vars.branchCount + 1;
getRealThing[handle, brDetails.posNode];
pNode← handle.vars.n;
getRealThing[handle, brDetails.negNode];
nNode← handle.vars.n;
IF pNode # nNode THEN {
SELECT brDetails.branchType FROM
resistor => newB← NEW[branch← [body: refR]];
capacitor=> {
newB← newC← NEW[branch←
[body: NEW[CapacitorBody← [nextCapacitor: handle.vars.capacitorList]] ] ];
handle.vars.capacitorList← newC;
};
inductor => {
newB← newL← NEW[branch←
[body: NEW[InductorBody← [nextInductor: handle.vars.inductorList ]] ] ];
handle.vars.inductorList← newL;
};
vSource => {
newB← newV← NEW[branch←
[body: NEW[VSourceBody← [nextvSource: handle.vars.vSourceList ]] ] ];
handle.vars.vSourceList← newV;
};
iSource => {
newB← newI← NEW[branch←
[body: NEW[ISourceBody← [nextiSource: handle.vars.iSourceList ]] ] ];
handle.vars.iSourceList← newI;
};
ENDCASE => error2[handle, 391, branchNamePtr];
handle.vars.b← newB;
putRealThing[handle, branchNamePtr, realBranch];
newB.branchName← branchNamePtr;
connectBranch[pNode, newB, TRUE];
connectBranch[nNode, newB, FALSE];
IF brDetails.controller # NIL THEN explodeController[handle, branchNamePtr, newB]
ELSE newB.comVal← eval[handle, brDetails.valExpr];
};
}; -- explodeBranch
explode: PROC[handle: Handle, ckt: namePtr, tree: instTreePtr]= {
curName: namePtr;
newNode: nodePtr← NIL;
newModel: modFuncPtr;
newB: branchPtr;
newTree: instTreePtr;
cktDetails: RefCircuitRec← NARROW[ckt.details];
IF Canned[handle] THEN SIGNAL Aborted;
curName← cktDetails.names;
UNTIL curName=NIL DO
WITH curName.details SELECT FROM
cn: RefNodeRec => {
newNode← NEW[node← [
nodeName: curName,
treeLevel: tree,
brotherNodes: tree.nodes] ];
tree.nodes← newNode;
handle.vars.n← newNode;
putRealThing[handle, curName, realNode];
};
ENDCASE;
curName← curName.srchLink;
ENDLOOP;
curName← cktDetails.names;
UNTIL curName=NIL DO
ENABLE ErrorSignal => {
ErrorStrings[handle, error, treeError[handle, tree, curName], s];
curName← curName.srchLink;
LOOP;
};
WITH curName.details SELECT FROM
cn: RefModelRec => {
handle.vars.modelCount← handle.vars.modelCount + 1;
newModel← NEW[modFuncBlk← [
nextMFPtr: handle.vars.functionList,
body: NEW[ModelBody←
[modelProc: cn.modelProc,
modelResults: cn.modelResults,
modelName: curName,
oldArgVector: cn.modelOldArgVec]]
]];
handle.vars.functionList← newModel;
explodeModelFunc[handle, curName, newModel];
handle.vars.m← newModel;
putRealThing[handle, curName, realModel];
};
ENDCASE;
curName← curName.srchLink;
ENDLOOP;
curName← cktDetails.names;
UNTIL curName=NIL DO
ENABLE ErrorSignal => {
ErrorStrings[handle, error, treeError[handle, tree, curName], s];
curName← curName.srchLink;
LOOP;
};
IF curName.expExpr=NIL OR eval[handle, curName.expExpr] # 0.0 THEN
WITH curName.details SELECT FROM
cn: RefBranchRec => {
newB← explodeBranch[handle, curName];
IF newB # NIL THEN {
newB.brotherBranches← tree.branches;
newB.treeLevel← tree;
tree.branches← newB;
};
};
cn: RefCktInstRec => {
newTree← explodeInstance[handle, curName];
newTree.father← tree;
newTree.brothers← tree.sons;
tree.sons← newTree;
};
ENDCASE;
curName← curName.srchLink;
ENDLOOP;
}; -- explode
treeError: PROC[handle: Handle, t: instTreePtr, n: namePtr] RETURNS[Rope.ROPE]= {
RETURN[Rope.Concat[printTree[handle, t, TRUE], n.name]];
}; -- treeError
AlphaNumeric: PROC[name: Rope.ROPE] RETURNS[an: BOOLFALSE]= {
tChar: CHAR← Rope.Fetch[name, 0];
an← tChar IN ['a..'z] OR tChar IN ['A..'Z]; -- first char should not be numeric
IF an THEN
FOR i: INT IN [1..Rope.Length[name]) DO
tChar← Rope.Fetch[name, i];
an← tChar IN ['a..'z] OR tChar IN ['A..'Z] OR tChar IN ['0..'9];
IF ~an THEN RETURN;
ENDLOOP;
}; -- AlphaNumeric
printTree: PROC[handle: Handle, t: instTreePtr, toRope: BOOL FALSE]
RETURNS[r: Rope.ROPENIL]= {
IF t # NIL AND t # handle.vars.treeRoot THEN {
tName: Rope.ROPE ← t.instance.name;
r ← printTree[handle, t.father, toRope].Concat[
IF AlphaNumeric[tName] THEN tName.Concat["/"] ELSE Rope.Cat["$", tName, "$/"] ];
};
IF toRope THEN RETURN ELSE {
handle.msgStream.PutF["%g", IO.rope[r]];
r ← NIL;
};
}; -- printTree
printNode: PROC[handle: Handle, n: nodePtr, ok, toRope: BOOLFALSE]
RETURNS[r: Rope.ROPENIL]= {
nName: Rope.ROPE ← n.nodeName.name;
r← printTree[handle, n.treeLevel, toRope].Concat[
IF ok OR AlphaNumeric[nName] THEN nName ELSE Rope.Cat["$", nName, "$"]
];
IF toRope THEN RETURN ELSE {
handle.msgStream.PutF["%g", IO.rope[r]];
r ← NIL;
};
}; -- printNode
printBranch: PROC[handle: Handle, b: branchPtr, ok, toRope: BOOLFALSE]
RETURNS[r: Rope.ROPENIL]= {
bName: Rope.ROPE ← b.branchName.name;
r← printTree[handle, b.treeLevel, toRope].Concat[
IF ok OR AlphaNumeric[bName] THEN bName ELSE Rope.Cat["$", bName, "$"]
];
IF toRope THEN RETURN ELSE {
handle.msgStream.PutF["%g", IO.rope[r]];
r ← NIL;
};
}; -- printBranch
makeStringNB: PUBLIC PROC[handle: Handle, n: nodePtr, b: branchPtr, ok: BOOLTRUE]
RETURNS[Rope.ROPE]= { -- NB: Node/Branch; ok: non-alphanumeric chars allowed.
RETURN[IF n # NIL THEN printNode[handle, n, ok, TRUE] ELSE printBranch[handle, b, ok, TRUE]];
}; -- makeStringNB
printTreeWithCktNames: PROC[handle: Handle, t: instTreePtr] = {
IF t = NIL OR t = handle.vars.treeRoot THEN handle.msgStream.PutF["\t"]
ELSE {
tInstDetails: RefCktInstRec ← IF ISTYPE[t.instance.details, RefCktInstRec] THEN NARROW[t.instance.details] ELSE NIL;
cktName: Rope.ROPEIF tInstDetails # NIL THEN tInstDetails.of.name ELSE NIL;
printTreeWithCktNames[handle, t.father];
handle.msgStream.PutF["%g(%g)/", IO.rope[t.instance.name], IO.rope[cktName]];
};
}; -- printTreeWithCktNames
printUnusedNodes: PROC[handle: Handle, n: nodePtr] = {
FOR n: nodePtrhandle.vars.unusedNodes, n.nextNode UNTIL n=NIL DO
nName: Rope.ROPE ← n.nodeName.name;
printTreeWithCktNames[handle, n.treeLevel];
handle.msgStream.PutF["%g", IO.rope[n.nodeName.name]];
handle.msgStream.PutF[IF n.nextNode = NIL THEN ".\n\n" ELSE ",\n"];
ENDLOOP;
}; -- printUnusedNodes
printHole: PUBLIC PROC[handle: Handle]= {
n: nodePtr;
bLink: branchLinkPtr;
handle.msgStream.PutF["\nNodes --\n"];
n← handle.vars.nodeList;
UNTIL n=NIL DO
[]← printNode[handle, n, TRUE];
handle.msgStream.PutF["← {"];
bLink← n.branches;
UNTIL bLink=NIL DO
[]← printBranch[handle, bLink.branch, TRUE];
IF bLink.branch.posNode=n THEN handle.msgStream.PutF["+"]
ELSE handle.msgStream.PutF["-"];
bLink← bLink.nextLink;
IF bLink # NIL THEN handle.msgStream.PutF[", "];
ENDLOOP;
handle.msgStream.PutF["}.\n"];
n← n.nextNode;
ENDLOOP;
}; -- printHole
findNB: PROC[handle: Handle, tree: instTreePtr] RETURNS[n: nodePtr← NIL, b: branchPtr← NIL]= {
i: instTreePtr;
IF handle.vars.item=name THEN {
i← tree.sons;
UNTIL i=NIL DO
IF Rope.Equal[i.instance.name, RopeFrom.String[handle.vars.newString]] THEN EXIT;
i← i.brothers;
ENDLOOP;
IF i # NIL THEN {
next[handle];
IF handle.vars.item=slash THEN next[handle]
ELSE error[handle, 300, FALSE];
[n, b]← findNB[handle, i];
}
ELSE {
n← tree.nodes;
UNTIL n=NIL DO
IF Rope.Equal[n.nodeName.name, RopeFrom.String[handle.vars.newString]] THEN EXIT;
n← n.brotherNodes;
ENDLOOP;
IF n=NIL THEN {
b← tree.branches;
UNTIL b=NIL DO
IF Rope.Equal[b.branchName.name, RopeFrom.String[handle.vars.newString]] THEN EXIT;
b← b.brotherBranches;
ENDLOOP;
};
next[handle];
};
}
ELSE error[handle, 301, FALSE];
}; -- findNB
findNodeOrBranch: PUBLIC PROC[handle: Handle] RETURNS[n: nodePtr, b: branchPtr]= {
[n, b]← findNB[handle, handle.vars.treeRoot];
}; -- findNodeOrBranch
fillInBranchLinks: PROC[handle: Handle]= {
nodes: nodePtr← handle.vars.nodeList;
links: branchLinkPtr;
UNTIL nodes=NIL DO
links← nodes.branches;
UNTIL links=NIL DO
links.otherNode← IF links.pos THEN links.branch.negNode ELSE links.branch.posNode;
links← links.nextLink;
ENDLOOP;
nodes← nodes.nextNode;
ENDLOOP;
}; -- fillInBranchLinks
bomb: PUBLIC PROC[handle: Handle]= {
cktRootDetails: RefCircuitRec← NARROW[handle.vars.cktRoot.details];
handle.vars.treeRoot← NEW[instTreeNode← []];
pushCopies[cktRootDetails.names];
advanceLevel[cktRootDetails.names];
explode[handle, handle.vars.cktRoot, handle.vars.treeRoot];
getRealThing[handle, handle.vars.gndNodeName];
handle.vars.gndNode← handle.vars.n;
popCopies[handle, cktRootDetails.names];
fillInBranchLinks[handle];
handle.msgStream.PutF[
"\n\nTotal %g nodes, %g models, %g functions, and %g branches.\n\n",
IO.int[handle.vars.nodeCount],
IO.int[handle.vars.modelCount],
IO.int[handle.vars.funcCount],
IO.int[handle.vars.branchCount]];
IF handle.vars.unusedNodes # NIL THEN {
handle.msgStream.PutF["Unused nodes:\n"];
printUnusedNodes[handle, handle.vars.unusedNodes];
};
}; -- bomb
END.
CHANGE LOG
Wilhelm, March 16, 1982 9:41 AM
Barth, 7-May-82 10:48:59 PDT
Chen, February 12, 1984 7:50 PM, modified to support oldArgVector.
Chen, June 10, 1984 9:47:59 pm PDT, cedarized.