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:
BOOL←
FALSE]= {
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.ROPE ← NIL]= {
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:
BOOL ←
FALSE]
RETURNS[r: Rope.ROPE ← NIL]= {
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:
BOOL←
FALSE]
RETURNS[r: Rope.ROPE← NIL]= {
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:
BOOL←
TRUE]
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.ROPE ← IF 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
: nodePtr
← handle.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.