ThymeInput:
CEDAR
PROGRAM
IMPORTS
Convert,
CoreClasses,
CoreOps,
CoreProperties,
IO,
ElectricalCoreClasses,
Real,
RefTab,
RefText,
Rope,
SinixOps,
Sisyph,
TerminalIO,
ThymeGlobals
EXPORTS
ThymeGlobals
InputGlobals:
TYPE ~
RECORD [
gndNodeName,
undefNode,
cktRoot,
currentCkt: ThymeGlobals.namePtr ← NIL
];
CellType: TYPE ~ Core.CellType;
CellInstance: TYPE ~ CoreClasses.CellInstance;
Wire: TYPE ~ Core.Wire;
Wires: TYPE ~ Core.Wires;
ROPE: TYPE ~ Rope.ROPE;
WireFilterProc: TYPE = PROC [wire: Wire] RETURNS [BOOL];
wId, cId, iId: INT ← 0; -- Used in naming unnamed wires, cells and instances
isPublic: ATOM ← CoreProperties.RegisterProperty[$CoreThymeIsPublic, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
pathNameProp: ATOM ← CoreProperties.RegisterProperty[$CoreThymePathName, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
probeWireProp: ATOM ← CoreProperties.RegisterProperty[$CoreThymeProbeWire, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
savedNameProp: ATOM ← CoreProperties.RegisterProperty[$CoreThymeSavedName, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
savedNameValidProp: ATOM ← CoreProperties.RegisterProperty[$CoreThymeSavedNameValid, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
PutTopLevelCircuit:
PUBLIC PROC [cellType: CellType, handle: ThymeGlobals.Handle, cktRoot, gndNodeName: ThymeGlobals.namePtr] = {
plotSpec, initSpec: ROPE;
resultList: LIST OF CellInstance;
thymePanelCT: CellType;
thymePanel: ElectricalCoreClasses.Panel;
inputGlobals: InputGlobals;
inputGlobals.undefNode ← NEW[ThymeGlobals.nameBlk ← [name: "Undefined", details: NEW[ThymeGlobals.NodeRec] ] ];
inputGlobals.gndNodeName ← gndNodeName;
PutGlobalParameters[tNode, "CIRCUIT[Lambda ← 1, TDegC ← 25] = {"];
InsertNode["Vdd: Node;"];
InsertFunctions["! /DATools/DATools6.1/Thyme/SignalGenerators"];
InsertModels["! /DATools/DATools6.1/Thyme/BSIM"];
InsertPower["powerSupply: voltage[Vdd, Gnd] = 5.0;"];
[resultList, thymePanelCT] ← PutRecordCellType[cellType, handle, inputGlobals, cktRoot, TRUE];
IF thymePanelCT=NIL
THEN {TerminalIO.PutRope["** Error: Sorry, no ThymePanel in cell\n"]; RETURN};
thymePanel ← NARROW[thymePanelCT.data, ElectricalCoreClasses.Panel];
Put Init Specs from the init CellType
FOR l:
LIST
OF CellInstance ← resultList, l.rest
WHILE l#
NIL
DO
inst: CellInstance ← l.first;
instType: CellType ← RecastIcon[inst.type];
IF instType.class=ElectricalCoreClasses.initCellClass
THEN {
init: ElectricalCoreClasses.Init ← NARROW[instType.data];
pathName: ROPE ← NARROW[CoreProperties.GetCellInstanceProp[inst, pathNameProp]];
SELECT init.type
FROM
Voltage => initSpec ← Rope.Cat[
Rope.Cat["IC[", ElectricalCoreClasses.RopeFromns[init.time]],
,
Rope.Cat[", ", pathName],
Rope.Cat["← ", Convert.RopeFromReal[init.value], "];"]];
Current => ERROR; -- No Init Current for the moment
ENDCASE => ERROR;
};
ENDLOOP;
Put Plot Specs
plotSpec ← Rope.Cat[
Rope.Cat["Plot[\"", thymePanel.title, "\", "],
Rope.Cat[":", ElectricalCoreClasses.RopeFromns[thymePanel.tScale], ", "],
Rope.Cat[Convert.RopeFromReal[thymePanel.yMin], ", "],
Rope.Cat[Convert.RopeFromReal[thymePanel.yMax], ", "],
Rope.Cat["powerSupply^: ", ElectricalCoreClasses.RopeFrommA[thymePanel.iScale]]];
handle.vars.plots[0].title ← thymePanel.title;
handle.vars.plots[0].ymin ← thymePanel.yMin;
handle.vars.plots[0].ymax ← thymePanel.yMax;
FOR l:
LIST
OF CellInstance ← resultList, l.rest
WHILE l#
NIL
DO
inst: CellInstance ← l.first;
instType: CellType ← RecastIcon[inst.type];
IF instType.class=ElectricalCoreClasses.probeCellClass
THEN {
probe: ElectricalCoreClasses.Probe ← NARROW[instType.data];
pathName: ROPE ← NARROW[CoreProperties.GetCellInstanceProp[inst, pathNameProp]];
SELECT probe.type
FROM
Voltage => plotSpec ← Rope.Cat[plotSpec, ", ", pathName, ": ", Convert.RopeFromReal[probe.scale]];
Voltage => plotSpec ← Rope.Cat[plotSpec, ", ", pathName, ": ", Convert.RopeFromReal[probe.scale]];
Current => plotSpec ← Rope.Cat[plotSpec, ", ", pathName, "^: ", ElectricalCoreClasses.RopeFrommA[probe.scale]];
ENDCASE => ERROR;
};
ENDLOOP;
plotSpec ← Rope.Cat[plotSpec, "];"];
Put Run Specs
[] ← Rope.Cat["Run[",
Rope.Cat["tMin ← ", ElectricalCoreClasses.RopeFromns[thymePanel.tMin], ", "],
Rope.Cat["tMax ← ", ElectricalCoreClasses.RopeFromns[thymePanel.tMax], "];"]];
};
PutRecordCellType:
PROC [cellType: CellType, handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, ckt: ThymeGlobals.namePtr, topLevel:
BOOL]
RETURNS [resultList:
LIST
OF CellInstance ←
NIL, thymePanel: CellType ←
NIL] = {
OPEN handle.vars;
EnsureInternalNames: CoreOps.EachWireProc = {
IF wire#recordCT.internal
THEN [] ← EnsureWireName[wire]
};
MarkPublicWire: CoreOps.EachWireProc = {
[] ← CoreProperties.PutWireProp[wire, isPublic, isPublic]
};
curCktDetails: ThymeGlobals.RefCircuitRec ← NEW[ThymeGlobals.CircuitRec← [father: inputGlobals.currentCkt]];
recordCT: CoreClasses.RecordCellType ← NARROW[cellType.data];
subCellTypeTab: RefTab.Ref ← RefTab.Create[];
cellTypeName: ROPE ← EnsureCellTypeName[cellType];
IF ThymeGlobals.Canned[handle] THEN SIGNAL ThymeGlobals.Aborted;
ckt.details ← curCktDetails;
inputGlobals.currentCkt ← ckt;
IF topLevel
THEN {
curCktDetails.names ← inputGlobals.gndNodeName;
EnterWires[recordCT.internal, Filter[WireToAtomicWires[recordCT.internal], VddOnly], handle, inputGlobals];
};
Ensure names on internal, mark public, and delete fullname caches
[] ← CoreOps.VisitWire[recordCT.internal, EnsureInternalNames];
[] ← CoreOps.VisitWire[cellType.public, MarkPublicWire];
CoreOps.FlushNameCaches[recordCT.internal];
CoreOps.FlushNameCaches[cellType.public];
Put circuit header if needed
IF ~topLevel
THEN {
cellTypeName, was written there
WiresToRope[cellType.public, WireToAtomicWires[cellType.public]]
fakes: ThymeGlobals.namePtr;
[fakes, curCktDetails.conCount] ← GetWireNames[cellType.public, WireToAtomicWires[cellType.public], handle, inputGlobals];
curCktDetails.fakeNodes ← fakes;
FOR fn: ThymeGlobals.namePtr ← fakes, fn.nextName
UNTIL fn=
NIL
DO
fn.details ← NEW[ThymeGlobals.ConRec];
ENDLOOP;
};
If top-level then put internal nodes except Vdd&Gnd else put internal minus public
EnterWires[recordCT.internal, Filter[WireToAtomicWires[recordCT.internal], IF topLevel THEN IsVddOrGnd ELSE IsPublic], handle, inputGlobals];
Now put the instances
FOR i:
NAT
IN [0..recordCT.size)
DO
inst: CellInstance ← recordCT.instances[i];
instType: CellType ← RecastIcon[inst.type];
instType: CellType ← CoreOps.ToBasic[inst.type];
curCktDetails: ThymeGlobals.RefCircuitRec ← NARROW[inputGlobals.currentCkt.details];
nPtr: ThymeGlobals.namePtr ← NEW[ThymeGlobals.nameBlk ← [srchLink: curCktDetails.names, name: EnsureCellTypeName[instType]]];
curCktDetails.names← nPtr;
SELECT instType.class
FROM
CoreClasses.recordCellClass => {
instName: ROPE ← EnsureInstName[inst];
found: BOOL;
val: RefTab.Val;
subCellTypeResultList: LIST OF CellInstance;
Put the definition if it isn't there already
[found, val] ← RefTab.Fetch[subCellTypeTab, instType];
IF found
THEN subCellTypeResultList ←
NARROW[val,
LIST
OF CellInstance]
ELSE {
subCellTypeResultList ← PutRecordCellType[instType, handle, inputGlobals, nPtr, FALSE].resultList;
[] ← RefTab.Insert[subCellTypeTab, instType, subCellTypeResultList]
};
Put the instance
[] ← Rope.Cat[
Rope.Cat[instName, ": ", EnsureCellTypeName[instType]],
"[",
ActualsToRope[cellType.public, recordCT.internal, WireToAtomicWires[inst.actual, FALSE], topLevel],
"];"];
Put the results in subCellTypeResultList onto resultList
FOR l:
LIST
OF CellInstance ← subCellTypeResultList, l.rest
WHILE l#
NIL
DO
subCellInst: CellInstance ← CopyCellInstance[l.first];
pathName: ROPE ← NARROW[CoreProperties.GetCellInstanceProp[subCellInst, pathNameProp]];
voltageProbeOnPublicWire: BOOL ← FALSE;
subCellInstType: CellType ← RecastIcon[subCellInst.type];
Compute the new path name if its a voltage probe on a public wire; this new path name will be the path name of the actual
IF subCellInstType.class=ElectricalCoreClasses.probeCellClass
THEN {
probe: ElectricalCoreClasses.Probe ← NARROW[subCellInstType.data];
IF probe.type=Voltage
THEN {
probeWire: Wire ← NARROW[CoreProperties.GetCellInstanceProp[subCellInst, probeWireProp]];
ForEachBinding: CoreOps.EachWirePairProc = {
IF publicWire=probeWire
THEN {
voltageProbeOnPublicWire ← TRUE;
pathName ← WiresToRope[recordCT.internal, WireToAtomicWires[actualWire]];
CoreProperties.PutCellInstanceProp[subCellInst, probeWireProp, actualWire];
};
};
[] ← CoreOps.VisitBinding[inst.actual, instType.public, ForEachBinding]
};
};
IF ~voltageProbeOnPublicWire THEN pathName ← Rope.Cat[instName, "/", pathName];
[] ← CoreProperties.PutCellInstanceProp[subCellInst, pathNameProp, pathName];
resultList ← CONS[subCellInst, resultList];
ENDLOOP;
};
CoreClasses.transistorCellClass =>
PutTransistorInstance[recordCT.internal, inst, instType, handle];
ElectricalCoreClasses.resistorCellClass =>
PutResistorInstance[recordCT.internal, inst, instType, handle];
ElectricalCoreClasses.inductorCellClass =>
PutInductorInstance[recordCT.internal, inst, instType, handle];
ElectricalCoreClasses.capacitorCellClass =>
PutCapacitorInstance[recordCT.internal, inst, instType, handle];
ElectricalCoreClasses.signalGeneratorCellClass =>
PutSignalGeneratorInstance[recordCT.internal, inst, instType, handle];
ElectricalCoreClasses.probeCellClass => {
probe: ElectricalCoreClasses.Probe ← NARROW[instType.data];
SELECT probe.type
FROM
Voltage => {
[] ← CoreProperties.PutCellInstanceProp[inst, pathNameProp, WiresToRope[recordCT.internal, WireToAtomicWires[inst.actual]]];
[] ← CoreProperties.PutCellInstanceProp[inst, probeWireProp, inst.actual.elements[0]];
};
Current => {
useResistor: BOOL ← probe.resistance>0.001;
instName: ROPE ← EnsureInstName[inst];
[] ← CoreProperties.PutCellInstanceProp[inst, pathNameProp, instName];
PutResistorInstance[...
[] ← Rope.Cat[
Rope.Cat[instName, IF useResistor THEN ": Resistor[" ELSE ": Voltage["],
ActualsToRope[cellType.public, recordCT.internal, WireToAtomicWires[inst.actual, FALSE], topLevel],
"] = ",
IF useResistor THEN ElectricalCoreClasses.RopeFromKOhms[probe.resistance] ELSE ElectricalCoreClasses.RopeFromVolts[0.0],
";"];
};
ENDCASE => ERROR;
resultList ← CONS[inst, resultList];
};
ElectricalCoreClasses.initCellClass => {
init: ElectricalCoreClasses.Init ← NARROW[instType.data];
SELECT init.type
FROM
Voltage => [] ← CoreProperties.PutCellInstanceProp[inst, pathNameProp, WiresToRope[recordCT.internal, WireToAtomicWires[inst.actual]]];
Current => ERROR;
ENDCASE => ERROR;
resultList ← CONS[inst, resultList];
};
ElectricalCoreClasses.panelCellClass => thymePanel ← instType;
ENDCASE => ERROR;
ENDLOOP;
};
EnsureCellTypeName:
PROC [cellType: CellType]
RETURNS [name:
ROPE] = {
name ← CoreOps.GetCellTypeName[cellType];
IF CoreProperties.GetCellTypeProp[cellType, savedNameValidProp]#NIL THEN RETURN;
CoreProperties.PutCellTypeProp[cellType, savedNameProp, name];
CoreProperties.PutCellTypeProp[cellType, savedNameValidProp, savedNameValidProp];
IF name=NIL
THEN name ← Rope.Cat["Cell", Convert.RopeFromInt[cId]]
ELSE name ← Rope.Cat[Rope.Translate[base: name, translator: NameTranslator], Convert.RopeFromInt[cId]];
cId ← cId+1;
[] ← CoreOps.SetCellTypeName[cellType, name];
};
EnsureInstName:
PROC [inst: CellInstance]
RETURNS [name:
ROPE] = {
name ← CoreClasses.GetCellInstanceName[inst];
IF CoreProperties.GetCellInstanceProp[inst, savedNameValidProp]#NIL THEN RETURN;
CoreProperties.PutCellInstanceProp[inst, savedNameProp, name];
CoreProperties.PutCellInstanceProp[inst, savedNameValidProp, savedNameValidProp];
IF name=NIL
THEN {name ← Rope.Cat["Inst", Convert.RopeFromInt[iId]]; iId ← iId+1}
ELSE name ← Rope.Translate[base: name, translator: NameTranslator];
[] ← CoreClasses.SetCellInstanceName[inst, name];
};
RecastIcon:
PROC [ct: CellType]
RETURNS [result: CellType] = {
result ← ct;
WHILE SinixOps.IsIcon[Sisyph.mode.decoration, result]
DO
result ← CoreOps.Recast[result];
ENDLOOP;
};
PutTransistorInstance:
PROC [rootWire: Wire, inst: CellInstance, instType: CellType, handle: ThymeGlobals.Handle] = {
tNodeContents: ROPE;
transistor: CoreClasses.Transistor ← NARROW[instType.data];
instName: ROPE ← EnsureInstName[inst];
transistorLength: INT ← NARROW[CoreProperties.GetCellTypeProp[instType, CoreClasses.lengthProp], REF INT]^;
transistorWidth: INT ← NARROW[CoreProperties.GetCellTypeProp[instType, CoreClasses.widthProp], REF INT]^;
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": "],
SELECT transistor.type
FROM
nE => "ETran",
pE => "CTran"
ENDCASE => ERROR,
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], " | "],
Rope.Cat["L ← ", Convert.RopeFromInt[transistorLength], ", "],
Rope.Cat["W ← ", Convert.RopeFromInt[transistorWidth], ", sdExtend ← 6];"]
];
};
PutResistorInstance:
PROC [rootWire: Wire, inst: CellInstance, instType: CellType, handle: ThymeGlobals.Handle] = {
tNodeContents: ROPE;
resistor: ElectricalCoreClasses.Resistor ← NARROW[instType.data];
instName: ROPE ← EnsureInstName[inst];
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": Resistor"],
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], "] = "],
Rope.Cat[ElectricalCoreClasses.RopeFromKOhms[resistor.value], ";"]
];
};
PutInductorInstance:
PROC [rootWire: Wire, inst: CellInstance, instType: CellType, handle: ThymeGlobals.Handle] = {
tNodeContents: ROPE;
inductor: ElectricalCoreClasses.Inductor ← NARROW[instType.data];
instName: ROPE ← EnsureInstName[inst];
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": Inductor"],
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], "] = "],
Rope.Cat[ElectricalCoreClasses.RopeFromuH[inductor.value], ";"]
];
};
PutCapacitorInstance:
PROC [rootWire: Wire, inst: CellInstance, instType: CellType, handle: ThymeGlobals.Handle] = {
tNodeContents: ROPE;
capacitor: ElectricalCoreClasses.Capacitor ← NARROW[instType.data];
instName: ROPE ← EnsureInstName[inst];
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": Capacitor"],
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], "] = "],
Rope.Cat[ElectricalCoreClasses.RopeFrompF[capacitor.value], ";"]
];
};
PutSignalGeneratorInstance:
PROC [rootWire: Wire, inst: CellInstance, instType: CellType, handle: ThymeGlobals.Handle] = {
tNodeContents: ROPE;
signalGenerator: ElectricalCoreClasses.SignalGenerator ← NARROW[instType.data];
instName: ROPE ← EnsureInstName[inst];
SELECT signalGenerator.type
FROM
RectWave => {
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": RectWave"],
Rope.Cat[
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], " | "],
Rope.Cat["OnLevel ← ", ElectricalCoreClasses.RopeFromVolts[signalGenerator.onLevel], ", "],
Rope.Cat["OffLevel ← ", ElectricalCoreClasses.RopeFromVolts[signalGenerator.offLevel], ", "],
Rope.Cat["period ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.period], ", "],
Rope.Cat["width ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.width], ", "]],
Rope.Cat[
Rope.Cat["tRise ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tRise], ", "],
Rope.Cat["tFall ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tFall], ", "],
Rope.Cat["tDelay ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tDelay], "];"]]
];
};
OneShot => {
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": OneShot"],
Rope.Cat[
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], " | "],
Rope.Cat["OnLevel ← ", ElectricalCoreClasses.RopeFromVolts[signalGenerator.onLevel], ", "],
Rope.Cat["OffLevel ← ", ElectricalCoreClasses.RopeFromVolts[signalGenerator.offLevel], ", "],
Rope.Cat["width ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.width], ", "]],
Rope.Cat[
Rope.Cat["tRise ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tRise], ", "],
Rope.Cat["tFall ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tFall], ", "],
Rope.Cat["tDelay ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tDelay], "];"]]
];
};
Step => {
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": Step"],
Rope.Cat[
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], " | "],
Rope.Cat["OnLevel ← ", ElectricalCoreClasses.RopeFromVolts[signalGenerator.onLevel], ", "],
Rope.Cat["OffLevel ← ", ElectricalCoreClasses.RopeFromVolts[signalGenerator.offLevel], ", "]],
Rope.Cat[
Rope.Cat["tRise ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tRise], ", "],
Rope.Cat["tDelay ← ", ElectricalCoreClasses.RopeFromns[signalGenerator.tDelay], "];"]]
];
};
DC => {
tNodeContents ← Rope.Cat[
Rope.Cat[instName, ": Voltage"],
Rope.Cat["[", WiresToRope[rootWire, WireToAtomicWires[inst.actual]], ", Gnd] = "],
Rope.Cat[ElectricalCoreClasses.RopeFromVolts[signalGenerator.onLevel], ";"]
];
};
ENDCASE => ERROR;
};
CopyCellInstance:
PROC [inst: CellInstance]
RETURNS [copy: CellInstance] = {
ForEachProp:
PROC [a:
ATOM, v:
REF
ANY] = {
copy.properties ← CoreProperties.PutProp[copy.properties, a, v]
};
copy ← NEW [CoreClasses.CellInstanceRec];
copy.actual ← inst.actual;
copy.type ← inst.type;
copy.properties ← NIL;
CoreProperties.Enumerate[inst.properties, ForEachProp]
};
WireToAtomicWires:
PROC [wire: Wire, unique:
BOOL ←
TRUE]
RETURNS [wires: Wires] = {
AddToWires:
PROC [subWire: Wire] = {
IF unique
THEN
FOR l: Wires ← wires, l.rest
WHILE l#
NIL
DO
IF l.first=subWire THEN RETURN;
ENDLOOP;
wires ← CONS[subWire, wires];
};
wires ← NIL;
IF wire.size=0 THEN AddToWires[wire] ELSE CoreOps.VisitRootAtomics[wire, AddToWires];
wires ← CoreOps.Reverse[wires]
};
Filter:
PROC [in: Wires, filter: WireFilterProc]
RETURNS [out: Wires] = {
out ← NIL;
FOR l: Wires ← in, l.rest
WHILE l#
NIL
DO
IF ~filter[l.first] THEN out ← CONS[l.first, out]
ENDLOOP;
out ← CoreOps.Reverse[out];
};
IsPublic: WireFilterProc = {
RETURN [CoreProperties.GetWireProp[wire, isPublic]#NIL]
};
IsVddOrGnd: WireFilterProc = {
name: ROPE ← CoreOps.GetShortWireName[wire];
RETURN [Rope.Equal[name, "Vdd"] OR Rope.Equal[name, "Gnd"]];
};
VddOnly: WireFilterProc = {
name: ROPE ← CoreOps.GetShortWireName[wire];
RETURN [~Rope.Equal[name, "Vdd"]];
};
GetWireNames:
PROC[wire: Wire, wires: Wires, handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]
RETURNS[names: ThymeGlobals.namePtr←
NIL, nameCount:
NAT← 0]= {
enter (unique) name strings on the current circuits search link
OPEN handle.vars;
nPtr: ThymeGlobals.namePtr;
FOR l: Wires ← wires, l.rest
WHILE l#
NIL
DO
nPtr ← EnterName[handle];
curCktDetails: ThymeGlobals.RefCircuitRec ← NARROW[inputGlobals.currentCkt.details];
nPtr ← NEW[ThymeGlobals.nameBlk ← [srchLink: curCktDetails.names, name: Rope.Translate[base: CoreOps.GetFullWireName[wire, l.first], translator: NameTranslator]]];
curCktDetails.names ← nPtr;
IF nPtr #
NIL
THEN {
-- usually not nil
nPtr.nextName ← names;
names ← nPtr;
};
nameCount ← nameCount + 1;
ENDLOOP
}; -- GetWireNames
EnterWires:
PROC[wire: Wire, wires: Wires, handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]= {
nPtr: ThymeGlobals.namePtr;
[nPtr, ] ← GetWireNames[wire, wires, handle, inputGlobals];
UNTIL nPtr=
NIL
DO
nPtr.details ← NEW[ThymeGlobals.NodeRec];
nPtr ← nPtr.nextName;
ENDLOOP;
}; -- EnterWires
WiresToRope:
PROC [root: Wire, wires: Wires]
RETURNS [rope:
ROPE] = {
separator: ROPE ← ", ";
rope ← NIL;
FOR l: Wires ← wires, l.rest
WHILE l#
NIL
DO
rope ← Rope.Cat[rope, separator, CoreOps.GetFullWireName[root, l.first]]
ENDLOOP;
IF rope#NIL THEN rope ← Rope.Substr[rope, Rope.Length[separator], Rope.Length[rope]];
rope ← Rope.Translate[base: rope, translator: NameTranslator];
};
ActualsToRope:
PROC [public, internal: Wire, wires: Wires, topLevel:
BOOL]
RETURNS [rope:
ROPE] = {
separator: ROPE ← ", ";
rope ← NIL;
FOR l: Wires ← wires, l.rest
WHILE l#
NIL
DO
rope ← Rope.Cat[rope, separator, CoreOps.GetFullWireName[IF IsPublic[l.first]AND~topLevel THEN public ELSE internal, l.first]]
ENDLOOP;
IF rope#NIL THEN rope ← Rope.Substr[rope, Rope.Length[separator], Rope.Length[rope]];
rope ← Rope.Translate[base: rope, translator: NameTranslator];
};
NameTranslator: Rope.TranslatorType = {
SELECT old
FROM
'* => new ← 'X;
'. => new ← 'x;
'- => new ← 'Z;
ENDCASE => new ← old;
};
EnsureWireName:
PROC [wire: Wire]
RETURNS [name:
ROPE] = {
name ← CoreOps.GetShortWireName[wire];
IF CoreProperties.GetWireProp[wire, savedNameValidProp]#NIL THEN RETURN;
CoreProperties.PutWireProp[wire, savedNameProp, name];
CoreProperties.PutWireProp[wire, savedNameValidProp, savedNameValidProp];
IF name=NIL
THEN {name ← Rope.Cat["Node", Convert.RopeFromInt[wId]]; wId ← wId+1}
ELSE name ← Rope.Translate[base: name, translator: NameTranslator];
[] ← CoreOps.SetShortWireName[wire, name];
};
EnterName:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]
RETURNS[newCktNames: ThymeGlobals.namePtr←
NIL]= {
enter a (one level unique) name string to the search link of currentCkt
OPEN handle.vars;
IF SearchName[newString, oneLevel, inputGlobals.currentCkt]=
NIL
THEN {
curCktDetails: ThymeGlobals.RefCircuitRec ← NARROW[inputGlobals.currentCkt.details];
newCktNames ← NEW[ThymeGlobals.nameBlk ← [srchLink: curCktDetails.names, name: Rope.FromRefText[newString]]];
curCktDetails.names← newCktNames;
}
ELSE ThymeGlobals.Error[handle, 250];
}; -- EnterName
SearchName:
PROC[nameString:
REF
TEXT, level: ThymeGlobals.LevelType ← oneLevel, oldCktNames: ThymeGlobals.namePtr]
RETURNS[newCktNames: ThymeGlobals.namePtr←
NIL]= {
usually oldCktNames=currentCkt and nameString=newString
lastNamePtr: ThymeGlobals.namePtr;
oldDetails: ThymeGlobals.RefCircuitRec;
nameRope: Rope.ROPE ← Rope.FromRefText[nameString];
UNTIL oldCktNames=
NIL
DO
oldDetails ← NARROW[oldCktNames.details];
newCktNames ← oldDetails.names;
lastNamePtr ← NIL;
UNTIL newCktNames=
NIL
DO
IF Rope.Equal[nameRope, newCktNames.name] THEN GOTO found;
lastNamePtr ← newCktNames;
newCktNames ← newCktNames.srchLink;
ENDLOOP;
IF level=oneLevel THEN EXIT;
oldCktNames ← oldDetails.father;
REPEAT
found =>
IF lastNamePtr #
NIL
THEN {
lastNamePtr.srchLink ← newCktNames.srchLink;
newCktNames.srchLink ← oldDetails.names;
oldDetails.names ← newCktNames;
};
ENDLOOP;
}; -- SearchName
GetNames:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]
RETURNS[names: ThymeGlobals.namePtr←
NIL, nameCount:
NAT← 0]= {
enter (unique) name strings on the current circuits search link
nPtr: ThymeGlobals.namePtr;
UNTIL handle.vars.item # name
DO
nPtr ← EnterName[handle, inputGlobals];
IF nPtr #
NIL
THEN {
-- usually not nil
nPtr.nextName ← names;
names ← nPtr;
};
nameCount ← nameCount + 1;
ThymeGlobals.Next[handle];
IF handle.vars.item # comma THEN EXIT ELSE ThymeGlobals.Next[handle];
IF handle.vars.item # name THEN ThymeGlobals.Error[handle, 208]
ENDLOOP
}; -- GetNames
GetName:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]
RETURNS[nPtr: ThymeGlobals.namePtr←
NIL]= {
OPEN handle.vars;
IF item # name THEN ThymeGlobals.Error[handle, 208]
ELSE nPtr ← SearchName[newString, allLevels, inputGlobals.currentCkt];
IF nPtr=NIL THEN ThymeGlobals.Error[handle, 251];
ThymeGlobals.Next[handle];
}; -- GetName
Variable:
PUBLIC
PROC[handle: ThymeGlobals.Handle, string:
REF
TEXT, context: ThymeGlobals.namePtr, level: ThymeGlobals.LevelType ← oneLevel]
RETURNS[nPtr: ThymeGlobals.namePtr←
NIL]= {
nPtr ←
IF context #
NIL
THEN SearchName[string, level, context]
ELSE ERROR; --Which thyme module did such an horror ?
ELSE SearchName[string, allLevels, inputGlobals.currentCkt];
IF nPtr=NIL THEN ThymeGlobals.Error[handle, 252]
ELSE -- check if nPtr has an acceptable type
WITH nPtr.details
SELECT
FROM
x: ThymeGlobals.RefParmRec => NULL;
x: ThymeGlobals.RefNodeRec => NULL;
x: ThymeGlobals.RefConRec => NULL;
ENDCASE => ThymeGlobals.Error[handle, 221];
ThymeGlobals.Next[handle];
}; -- Variable
FindNode:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]
RETURNS[n: ThymeGlobals.namePtr]= {
search RefNodeRec or RefConRec with name newString on all levels of currentCkt
nPtr: ThymeGlobals.namePtr ← GetName[handle, inputGlobals];
IF nPtr=NIL THEN RETURN[inputGlobals.undefNode]
ELSE
WITH nPtr.details
SELECT
FROM
x: ThymeGlobals.RefNodeRec => n ← nPtr;
x: ThymeGlobals.RefConRec => n ← nPtr;
ENDCASE => ThymeGlobals.Error[handle, 222];
}; -- FindNode
GetFunction: PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, na, np: NAT]
RETURNS[args: ThymeGlobals.argNames←
NIL, actual: ThymeGlobals.expressionPtr←
NIL]= {
get na arguments and np parameters(expressions)
iArg, iParm: NAT← 0;
aname: ThymeGlobals.namePtr;
newExpr: ThymeGlobals.expressionPtr;
IF handle.vars.item=leftB
THEN {
ThymeGlobals.Next[handle];
arguments
IF na > 0
THEN {
args← NEW[ThymeGlobals.namePtrSeq[na]];
args.visited ← FALSE;
UNTIL iArg=na
DO
aname ← GetName[handle, inputGlobals];
args[iArg] ← aname;
IF aname # NIL THEN
WITH aname.details
SELECT
FROM
x: ThymeGlobals.RefNodeRec => NULL;
x: ThymeGlobals.RefConRec => NULL;
ENDCASE => ThymeGlobals.Error[handle, 222];
IF handle.vars.item=quote THEN {ThymeGlobals.Next[handle]; ThymeGlobals.Error[handle, 299]};
iArg ← iArg + 1;
IF handle.vars.item=comma THEN ThymeGlobals.Next[handle] ELSE EXIT;
ENDLOOP;
};
parameters
IF na=0
OR handle.vars.item=vertical
THEN {
IF handle.vars.item=vertical THEN ThymeGlobals.Next[handle];
UNTIL iParm=np
DO
newExpr ← ThymeGlobals.Expression[handle, inputGlobals.currentCkt];
newExpr.next ← actual;
actual ← newExpr;
iParm ← iParm + 1;
IF handle.vars.item=comma THEN ThymeGlobals.Next[handle] ELSE EXIT;
ENDLOOP;
};
IF handle.vars.item=rightB THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 202, , TRUE];
};
IF iArg # na THEN ThymeGlobals.Error[handle, 231];
IF iParm # np THEN ThymeGlobals.Error[handle, 232];
}; -- GetFunction
ControlFunc:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, thisBranch: ThymeGlobals.namePtr]= {
nPtr, f: ThymeGlobals.namePtr;
na, np: NAT;
bDetails: ThymeGlobals.RefBranchRec← NARROW[thisBranch.details];
ThymeGlobals.Next[handle];
IF handle.vars.item=name
THEN {
nPtr ← SearchName[handle.vars.newString, allLevels, inputGlobals.currentCkt];
IF nPtr=
NIL
THEN {
fTableEntry: REF ThymeGlobals.FuncTableBlk = ThymeGlobals.FindFunction[Rope.FromRefText[handle.vars.newString]];
fDetails: ThymeGlobals.RefFunctionRec ← NEW[ThymeGlobals.FunctionRec← [branch: thisBranch] ];
f ← NEW[ThymeGlobals.nameBlk ← [details: fDetails]];
get values for other fields in f.details, and assign f as the controller for this branch:
fDetails.functionProc ← fTableEntry.proc;
fDetails.data ← fTableEntry.data;
na ← fTableEntry.numArgs;
np ← fTableEntry.numParms;
IF fDetails.functionProc=NIL THEN ThymeGlobals.Error[handle, 502, FALSE];
ThymeGlobals.Next[handle];
bDetails.controller ← f;
[fDetails.funcArgs, fDetails.funcParms] ← GetFunction[handle, inputGlobals, na, np];
fDetails.funcArgVec ← InitArgList[na];
}
ELSE
WITH nPtr.details
SELECT
FROM
n: ThymeGlobals.RefModelRec => {
bDetails.controller← nPtr;
ThymeGlobals.Next[handle];
IF handle.vars.item=leftB THEN ThymeGlobals.Next[handle]
ELSE ThymeGlobals.Error[handle, 201,, TRUE];
IF handle.vars.item=number
THEN {
bDetails.modelIndex← Real.InlineFixC[handle.vars.value];
IF n.modelResults=
NIL
THEN {
-- unlikely, though
IF handle.vars.value > 0 THEN ThymeGlobals.Error[handle, 233]
}
ELSE IF handle.vars.value >= n.modelResults.size
THEN ThymeGlobals.Error[handle, 233];
ThymeGlobals.Next[handle];
}
ELSE ThymeGlobals.Error[handle, 209];
IF handle.vars.item=rightB THEN ThymeGlobals.Next[handle]
ELSE ThymeGlobals.Error[handle, 202,, TRUE];
};
ENDCASE => ThymeGlobals.Error[handle, 223];
}
ELSE ThymeGlobals.Error[handle, 208];
}; -- ControlFunc
InitArgList:
PROC[size:
NAT]
RETURNS [a: ThymeGlobals.argList] = {
a ← NEW[ThymeGlobals.ValueSeq[size]];
a.visited ← FALSE;
a.handle ← NIL;
a.modFunc ← NIL;
FOR i:
NAT
IN [0..size)
DO
a.value[i] ← 0.0; ENDLOOP;
}; -- InitArgList
EnterBranches:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, bName: ThymeGlobals.namePtr, branchKey: ThymeGlobals.keys]= {
pNode, nNode: ThymeGlobals.namePtr;
bDetails: ThymeGlobals.RefBranchRec;
kind: ThymeGlobals.elements;
IF handle.vars.item=leftB THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 201,, TRUE];
pNode ← FindNode[handle, inputGlobals];
IF handle.vars.item=comma THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 200,, TRUE];
nNode ← FindNode[handle, inputGlobals];
IF handle.vars.item=rightB THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 202,, TRUE];
kind ←
SELECT branchKey
FROM
resKey => resistor,
capKey => capacitor,
indKey => inductor,
vsKey => vSource,
isKey => iSource,
ENDCASE => nullElement;
IF kind=nullElement THEN ThymeGlobals.Error[handle, 224, TRUE];
IF pNode=nNode THEN ThymeGlobals.Error[handle, 241];
IF bName # NIL THEN -- else error! ...
bName.details ← bDetails ←
NEW[ThymeGlobals.BranchRec←
[branchType: kind,
posNode: pNode,
negNode: nNode ] ];
IF handle.vars.item=equal
THEN {
ThymeGlobals.Next[handle];
bDetails.valExpr← ThymeGlobals.Expression[handle, inputGlobals.currentCkt];
}
ELSE
IF handle.vars.item=leftArrow THEN ControlFunc[handle, inputGlobals, bName]
ELSE ThymeGlobals.Error[handle, 205];
}; -- EnterBranches
EnterModel:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, mName: ThymeGlobals.namePtr]= {
na, np, nr: NAT;
IF handle.vars.item=leftArrow THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 210];
IF handle.vars.item=name
THEN {
mTableEntry: REF ThymeGlobals.ModelTableBlk = ThymeGlobals.FindModel[Rope.FromRefText[handle.vars.newString]];
mDetails: ThymeGlobals.RefModelRec ← NEW[ThymeGlobals.ModelRec← []];
mDetails.modelProc ← mTableEntry.proc;
mDetails.data ← mTableEntry.data;
na ← mTableEntry.numArgs;
np ← mTableEntry.numParms;
nr ← mTableEntry.numResults;
IF mDetails.modelProc=NIL THEN ThymeGlobals.Error[handle, 501, FALSE];
ThymeGlobals.Next[handle];
[mDetails.modelArgs, mDetails.modelParms] ← GetFunction[handle, inputGlobals, na, np];
mDetails.modelResults ← InitArgList[nr];
mDetails.modelArgVec ← InitArgList[na];
mDetails.modelOldArgVec ← InitArgList[na];
mName.details ← mDetails;
}
ELSE ThymeGlobals.Error[handle, 208];
}; -- EnterModel
GetCircuitTree:
PROC[ckt: ThymeGlobals.namePtr]
RETURNS[r: Rope.
ROPE]= {
GetTree:
PROC[c: ThymeGlobals.namePtr]= {
cktDetail: ThymeGlobals.RefCircuitRec← NARROW[c.details];
IF c #
NIL
AND cktDetail #
NIL
AND cktDetail.father #
NIL
THEN {
GetTree[cktDetail.father];
r← Rope.Cat[r, c.name, "."];
};
}; -- GetTree
GetTree[ckt];
}; -- GetCircuitTree
GetNewParameters:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]
RETURNS[plist: ThymeGlobals.namePtr←
NIL]= {
n: ThymeGlobals.namePtr;
nparms: NAT← 0;
IF handle.vars.item=vertical THEN ThymeGlobals.Next[handle];
UNTIL handle.vars.item # name
DO
n ← EnterName[handle, inputGlobals];
ThymeGlobals.Next[handle];
nparms← nparms + 1;
n.details← NEW[ThymeGlobals.ParmRec← [nextParm: plist]];
IF handle.vars.item=leftArrow
THEN {
ENABLE ThymeGlobals.ErrorSignal => {
ThymeGlobals.ErrorStrings[handle, error, GetCircuitTree[inputGlobals.currentCkt], s];
CONTINUE; -- GOTO badEnd
};
nDetails: ThymeGlobals.RefParmRec ← NARROW[n.details];
ThymeGlobals.Next[handle];
nDetails.default ← TRUE;
nDetails.dfltValue ← ThymeGlobals.Eval[handle, ThymeGlobals.Expression[handle, inputGlobals.currentCkt]];
};
plist← n;
IF handle.vars.item=comma THEN ThymeGlobals.Next[handle] ELSE EXIT;
IF handle.vars.item # name THEN ThymeGlobals.Error[handle, 208]
ENDLOOP;
}; -- GetNewParameters
DefineCircuit: PUBLIC PROC[handle: ThymeGlobals.Handle, ckt: ThymeGlobals.namePtr, root: BOOL]= {
OPEN handle.vars;
exp: ThymeGlobals.expressionPtr;
curCktDetails: ThymeGlobals.RefCircuitRec ← NEW[ThymeGlobals.CircuitRec← [father: currentCkt]];
IF ThymeGlobals.Canned[handle] THEN SIGNAL ThymeGlobals.Aborted;
ckt.details ← curCktDetails;
currentCkt ← ckt;
IF root AND cktRoot=NIL THEN {
cktRoot ← currentCkt;
undefNode ← NEW[ThymeGlobals.nameBlk ← [name: "Undefined", details: NEW[ThymeGlobals.NodeRec] ] ];
gndNodeName ← NEW[ThymeGlobals.nameBlk ← [name: "Gnd", details: NEW[ThymeGlobals.NodeRec] ] ];
curCktDetails.names ← gndNodeName;
};
IF ~root THEN {
enter (unique) connection names on currentCkt: Get public names
fakes: ThymeGlobals.namePtr;
[fakes, curCktDetails.conCount] ← GetNames[handle];
curCktDetails.fakeNodes ← fakes;
FOR fn: ThymeGlobals.namePtr ← fakes, fn.nextName UNTIL fn=NIL DO
fn.details ← NEW[ThymeGlobals.ConRec];
ENDLOOP;
};
IF root OR item=vertical THEN curCktDetails.parms ← GetNewParameters[handle];
Get parameters from cell.data and/or cell.properties
IF item=name AND SearchKey[handle]=assertsKey THEN {
Next[handle];
IF item=leftB THEN {
Next[handle];
DO
exp ← Expression[handle];
exp.next ← curCktDetails.assertions;
curCktDetails.assertions ← exp;
IF item=comma THEN Next[handle] ELSE EXIT;
ENDLOOP;
IF item=rightB THEN Next[handle] ELSE Error[handle, 202,, TRUE];
}
ELSE Error[handle, 201];
};
Then explore the instances and internals of the cell
DO
IF item=name THEN EnterDefinition[handle];
IF item=rightC OR item= eof THEN EXIT;
IF item=semi THEN Next[handle] ELSE Error[handle, 206, TRUE, FALSE];
ENDLOOP;
curCktDetails ← NARROW[currentCkt.details];
currentCkt ← curCktDetails.father;
}; -- DefineCircuit
DefineCircuit:
PUBLIC
PROC[handle: ThymeGlobals.Handle, cktRoot, gndNodeName: ThymeGlobals.namePtr]= {
inputGlobals: InputGlobals;
inputGlobals.undefNode ← NEW[ThymeGlobals.nameBlk ← [name: "Undefined", details: NEW[ThymeGlobals.NodeRec] ] ];
inputGlobals.gndNodeName ← gndNodeName;
DefineCircuitInternal[handle, inputGlobals, cktRoot, TRUE];
};
DefineCircuitInternal:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, ckt: ThymeGlobals.namePtr, root:
BOOL]= {
OPEN handle.vars;
exp: ThymeGlobals.expressionPtr;
curCktDetails: ThymeGlobals.RefCircuitRec ← NEW[ThymeGlobals.CircuitRec← [father: inputGlobals.currentCkt]];
IF ThymeGlobals.Canned[handle] THEN SIGNAL ThymeGlobals.Aborted;
ckt.details ← curCktDetails;
inputGlobals.currentCkt ← ckt;
IF root AND inputGlobals.cktRoot=NIL THEN {
IF root
THEN {
inputGlobals.cktRoot ← inputGlobals.currentCkt;
inputGlobals.undefNode ← NEW[ThymeGlobals.nameBlk ← [name: "Undefined", details: NEW[ThymeGlobals.NodeRec] ] ];
inputGlobals.gndNodeName ← NEW[ThymeGlobals.nameBlk ← [name: "Gnd", details: NEW[ThymeGlobals.NodeRec] ] ];
curCktDetails.names ← inputGlobals.gndNodeName;
ThymeGlobals.Next[handle];
};
IF item=leftB
THEN {
ThymeGlobals.Next[handle];
IF ~root
AND item # vertical
THEN {
enter (unique) connection names on currentCkt
fakes: ThymeGlobals.namePtr;
[fakes, curCktDetails.conCount] ← GetNames[handle, inputGlobals];
curCktDetails.fakeNodes← fakes;
FOR fn: ThymeGlobals.namePtr ← fakes, fn.nextName
UNTIL fn=
NIL
DO
fn.details ← NEW[ThymeGlobals.ConRec];
ENDLOOP;
};
IF root OR item=vertical THEN curCktDetails.parms ← GetNewParameters[handle, inputGlobals];
IF item=rightB THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 202,, TRUE];
};
IF item=name
AND ThymeGlobals.SearchKey[handle]=assertsKey
THEN {
ThymeGlobals.Next[handle];
IF item=leftB
THEN {
ThymeGlobals.Next[handle];
DO
exp ← ThymeGlobals.Expression[handle, inputGlobals.currentCkt];
exp.next ← curCktDetails.assertions;
curCktDetails.assertions ← exp;
IF item=comma THEN ThymeGlobals.Next[handle] ELSE EXIT;
ENDLOOP;
IF item=rightB THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 202,, TRUE];
}
ELSE ThymeGlobals.Error[handle, 201];
};
IF item=equal THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 205, TRUE, TRUE];
IF item=leftC THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 203, TRUE, FALSE];
DO
IF item=name THEN EnterDefinition[handle, inputGlobals];
IF item=rightC OR item= eof THEN EXIT;
IF item=semi THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 206, TRUE, FALSE];
ENDLOOP;
curCktDetails ← NARROW[inputGlobals.currentCkt.details];
inputGlobals.currentCkt ← curCktDetails.father;
ThymeGlobals.Next[handle];
}; -- DefineCircuit
GetActualParameters:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, ckt: ThymeGlobals.namePtr]
RETURNS[apList: ThymeGlobals.expressionPtr←
NIL]= {
e: ThymeGlobals.expressionPtr;
IF handle.vars.item=vertical THEN ThymeGlobals.Next[handle];
IF handle.vars.item=rightB THEN RETURN;
DO
IF handle.vars.item # name THEN GOTO nameErr;
e ← ThymeGlobals.AssignExpr[handle, inputGlobals.currentCkt, ckt];
e.next ← apList;
apList ← e;
IF handle.vars.item=comma THEN ThymeGlobals.Next[handle] ELSE EXIT;
REPEAT
nameErr => ThymeGlobals.Error[handle, 208];
ENDLOOP;
}; -- GetActualParameters
DefCktInstance:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals, cn:
REF
TEXT, iName: ThymeGlobals.namePtr]= {
cktName: ThymeGlobals.namePtr;
n: ThymeGlobals.namePtr;
cons: ThymeGlobals.conLinkPtr← NIL;
cCnt: NAT← 0;
noConnections: BOOL;
actuals: ThymeGlobals.expressionPtr← NIL;
cktName ← SearchName[cn, allLevels, inputGlobals.currentCkt];
IF cktName # NIL THEN
WITH cktName.details
SELECT
FROM
c: ThymeGlobals.RefCircuitRec => {
IF handle.vars.item=leftB
THEN {
ThymeGlobals.Next[handle];
noConnections← (c.conCount=0);
IF ~noConnections THEN
WHILE handle.vars.item=name
DO
n← FindNode[handle, inputGlobals];
cons← NEW[ThymeGlobals.conLink← [nextLink: cons, namedNode: n]];
cCnt← cCnt + 1;
IF handle.vars.item=comma THEN ThymeGlobals.Next[handle] ELSE EXIT;
ENDLOOP;
IF noConnections OR handle.vars.item=vertical THEN
actuals← GetActualParameters[handle, inputGlobals, cktName];
IF handle.vars.item=rightB THEN ThymeGlobals.Next[handle]
ELSE ThymeGlobals.Error[handle, 202,, TRUE];
};
IF cCnt # c.conCount THEN ThymeGlobals.Error[handle, 260];
iName.details←
NEW[ThymeGlobals.CktInstance←
[of: cktName, connections: cons, actualParms: actuals] ];
};
ENDCASE => ThymeGlobals.Error[handle, 225, TRUE]
ELSE ThymeGlobals.Error[handle, 251, TRUE];
}; -- DefCktInstance
EnterDefinition:
PROC[handle: ThymeGlobals.Handle, inputGlobals: InputGlobals]= {
key: ThymeGlobals.keys;
nameCount: NAT;
nPtr: ThymeGlobals.namePtr;
s: REF TEXT ← RefText.New[256];
explodeExpr: ThymeGlobals.expressionPtr ← NIL;
[nPtr, nameCount] ← GetNames[handle, inputGlobals];
IF nPtr=NIL THEN ThymeGlobals.Error[handle, 208];
IF handle.vars.item # colon THEN ThymeGlobals.Error[handle, 207,, TRUE] ELSE ThymeGlobals.Next[handle];
IF handle.vars.item=leftP
THEN {
explodeExpr ← ThymeGlobals.Expression[handle, inputGlobals.currentCkt];
IF nPtr # NIL THEN nPtr.expExpr ← explodeExpr;
IF handle.vars.item=implies THEN ThymeGlobals.Next[handle] ELSE ThymeGlobals.Error[handle, 215,, TRUE];
};
IF handle.vars.item=name
THEN {
key ← ThymeGlobals.SearchKey[handle];
s.length ← 0;
s ← RefText.Append[s, handle.vars.newString];
ThymeGlobals.Next[handle];
IF key # nodeKey AND nameCount # 1 THEN ThymeGlobals.Error[handle, 261];
SELECT key
FROM
nodeKey => {
IF nPtr.expExpr # NIL THEN ThymeGlobals.Error[handle, 253];
UNTIL nPtr=
NIL
DO
nPtr.details ← NEW[ThymeGlobals.NodeRec];
nPtr ← nPtr.nextName;
ENDLOOP;
};
resKey, capKey, indKey, vsKey, isKey => EnterBranches[handle, inputGlobals, nPtr, key];
circuitKey => {
IF nPtr.expExpr # NIL THEN ThymeGlobals.Error[handle, 253];
DefineCircuitInternal[handle: handle, inputGlobals: inputGlobals, ckt: nPtr, root: FALSE];
};
modelKey => {
IF nPtr.expExpr # NIL THEN ThymeGlobals.Error[handle, 253];
EnterModel[handle, inputGlobals, nPtr];
};
ENDCASE => DefCktInstance[handle, inputGlobals, s, nPtr];
}
ELSE ThymeGlobals.Error[handle, 208, TRUE]
}; -- EnterDefinition
LevelSpace:
PROC[stream:
IO.
STREAM, level:
NAT]= {
UNTIL level=0
DO
stream.PutF[" "];
level ← level - 1
ENDLOOP
}; -- LevelSpace
Output:
PUBLIC
PROC[handle: ThymeGlobals.Handle, ckt: ThymeGlobals.namePtr, level:
NAT]= {
cLink: ThymeGlobals.conLinkPtr;
np: ThymeGlobals.namePtr;
cktDetails: ThymeGlobals.RefCircuitRec ← NARROW[ckt.details];
np ← cktDetails.names;
UNTIL np=
NIL
DO
LevelSpace[handle.msgStream, level];
handle.msgStream.PutF["%g", IO.rope[np.name]];
WITH np.details
SELECT
FROM
n: ThymeGlobals.RefNodeRec => NULL;
n: ThymeGlobals.RefBranchRec => handle.msgStream.PutF[": branch[%s, %s]", IO.rope[n.posNode.name], IO.rope[n.negNode.name]];
n: ThymeGlobals.RefCircuitRec => {
handle.msgStream.PutF[": circuit.\n"];
Output[handle, np, level + 1];
};
n: ThymeGlobals.RefConRec => NULL;
n: ThymeGlobals.RefParmRec => {
handle.msgStream.PutF[": parameter"];
IF n.default THEN handle.msgStream.PutF["← %13.5f", IO.real[n.dfltValue]];
};
n: ThymeGlobals.RefCktInstRec => {
handle.msgStream.PutF[": %g[", IO.rope[n.of.name]];
cLink← n.connections;
UNTIL cLink=
NIL
DO
handle.msgStream.PutF["%g", IO.rope[cLink.namedNode.name]];
cLink← cLink.nextLink;
IF cLink # NIL THEN handle.msgStream.PutF[", "]
ENDLOOP;
handle.msgStream.PutF["]"]
};
ENDCASE;
np ← np.srchLink;
handle.msgStream.PutF[".\n"];
ENDLOOP;
}; -- Output
}.