SXOutputImplA.mesa
Copyright © 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
Written by Shand, July 16, 1984 2:58:45 pm PDT
Last Edited by: Shand, March 12, 1985 1:23:35 am PST
Last Edited by: Spreitzer, January 16, 1985 11:53:05 am PST
Last edited by: Christian Jacobi, April 4, 1985 10:03:17 am PST
Last edited by: Christian Jacobi, February 24, 1987 1:29:47 pm PST
Last edited by: gbb June 6, 1986 7:41:03 pm PDT
DIRECTORY
Ascii USING [Letter, Digit],
CD USING [Describe, Design, Instance, InstanceList, InterestRect, Object, Rect],
CDDirectory USING [Name],
CDIO USING [GetWorkingDirectory],
CDProperties USING [GetProp, GetInstanceProp, PutInstanceProp],
Convert USING [RopeFromInt, RopeFromRope],
FS USING [ComponentPositions, Error, ExpandName, FileInfo, StreamOpen],
IO USING [atom, char, Close, GetLength, int, Put, PutF, PutFR, PutR, PutRope, real, refAny, rope, RopeFromROS, ROS, STREAM, time],
Properties USING [GetProp, PropList, PutProp],
RefTab USING [Key, Pairs, Ref, Val],
Rope USING [Cat, Equal, Fetch, Find, Length, Replace, ROPE, Substr],
SX USING [AreaPerimRec, Circuit, CircuitNode, FindRootNode, LogicalCell, MergeRec, MergeRecList, NodeLinkage, NodeLocation, SignalName, TechHandle],
SXAccess USING [design, invocation, sxTech],
SXAccessInternal USING [GetLogicalCell],
SXAtoms USING [fini, init, InstanceName, rosePrint, SignalName, spinifexCircuitDescription, thymePrint],
SXOutput USING [LinkageHousekeeper, LinkagePrintProc, NodePrintProc],
SXOutputPrivate,
SymTab USING [Create, Fetch, Ref, Store],
TerminalIO USING [PutRope],
TiogaFileOps USING [AddLooks, CreateRoot, InsertAsLastChild, InsertNode, Ref, SetContents, SetFormat, SetStyle, Store],
TiogaOps USING [PutProp],
UserCredentials USING [Get];
SXOutputImplA: CEDAR PROGRAM
IMPORTS Ascii, CD, CDDirectory, CDIO, CDProperties, Convert, FS, IO, Properties, RefTab, Rope, SX, SXAccess, SXAccessInternal, SXAtoms, SXOutputPrivate, SymTab, TerminalIO, TiogaFileOps, TiogaOps, UserCredentials
EXPORTS SXOutput, SXOutputPrivate =
BEGIN OPEN SXOutputPrivate;
Name generator customization
CountSep: ROPE ~ "-";
portBase: ROPE ~ "p";
localBase: ROPE ~ "n";
stopperBase: ROPE ~ "tn";
transBase: ROPE ~ "Q";
circuitBase: ROPE ~ "C";
shortestNamesOnly: PUBLIC BOOLFALSE;
propCollisions: BOOLFALSE;
outputGeometricInfo: PUBLIC BOOLTRUE;
printLocalNodeLocation: PUBLIC BOOLFALSE;
Note: This two switches are different, especially in the case of Rosemary output. Unfortunately they are not orthogonal
isPort: PUBLIC ATOM ← $SXIsPort;
actualCellInstanceName: PUBLIC ATOM ← $SXCellInstName;
actualSignalName: PUBLIC ATOM ← $SXActualSignalName;
releaseDirectory: ROPE;
PrintCircuit: PUBLIC PROCEDURE [cellList: LIST OF REF LogicalCell, formatKey: REF ANY] ~ {
HierarchyRoot: PROCEDURE [cellList: LIST OF REF LogicalCell] RETURNS [CD.Object] ~ INLINE {
FOR cl: LIST OF REF LogicalCell ← cellList, cl.rest WHILE cl # NIL DO
IF cl.rest = NIL THEN RETURN[cl.first.cellObj];
ENDLOOP;
ERROR
}; -- end HierarchyRoot
ReadGlobalSignals: PROCEDURE [glob: SymTab.Ref] ~ {
SymTab keyed by signal names, value is use count.
globFile: IO.STREAM;
[] ← glob.Store[ "Gnd", $GlobalSignal];
globFile ← FS.StreamOpen[ FS.ExpandName["chip.wspec", desWDir].fullFName ! FS.Error => IF error.group = user THEN { GOTO NoFile } ];
TerminalIO.PutRope[Rope.Cat["\nProcessing wiring spec file \"", "chip.wspec", "\"\n"]];
DO
tok: IO.TokenKind;
id: ROPE;
[tok, id] ← globFile.GetCedarTokenRope[ ! IO.Error => EXIT; IO.EndOfStream => EXIT];
IF tok = tokenID THEN
[] ← glob.Store[ id, $GlobalSignal];
ENDLOOP;
EXITS NoFile => NULL;
}; -- end ReadGlobalSignals
CheckFileName: PROC [org: ROPE] RETURNS [full: ROPE] = BEGIN
cp: FS.ComponentPositions;
[full, cp, ] ← FS.ExpandName [org, desWDir];
IF NOT org.Equal[full.Substr[start: cp.base.start, len: cp.ext.start+cp.ext.length - cp.base.start]] THEN ERROR FS.Error[[user, $illegalName, IO.PutFR["%g not a valid base and extension", IO.refAny[org]] ]];
END; -- end CheckFileName
globals: SymTab.Ref;
desWDir: ROPE = CDIO.GetWorkingDirectory [SXAccess.design];
globals ← SymTab.Create [mod: 553, case: TRUE];
FOR cl: LIST OF REF LogicalCell ← cellList, cl.rest WHILE cl # NIL DO
NameObj: PROC [obj: CD.Object, name: ROPE] = BEGIN
naming: Naming ← NEW [NamingRep ← [next: NIL, named: obj, prefixes: NIL, name: name]];
IF ~globals.Store [name, naming] THEN {
TerminalIO.PutRope ["Cell "];
TerminalIO.PutRope [name];
TerminalIO.PutRope [" was reported twice by ChipNDale. Inserting two copies of the first circuit reported.\n"]};
Should be ERROR Duplicate name.
END; -- NameObj
NameObj [cl.first.cellObj, CDDirectory.Name[cl.first.cellObj, SXAccess.design]];
ENDLOOP;
ReadGlobalSignals [globals];
AddIntermediateNodes [cellList];
SELECT formatKey FROM
Thyme
SXAtoms.thymePrint => {
thymeFileName: ROPE;
thymeFile: TiogaFileOps.Ref ~ TiogaFileOps.CreateRoot [];
defnTextNode: TiogaFileOps.Ref;
{ ENABLE FS.Error =>
IF error.group = user THEN {
IF error.code = $illegalName THEN {
thymeFileName ← FS.ExpandName ["ExtractedOutput.thy", desWDir].fullFName;
TerminalIO.PutRope [Rope.Cat[ "\n\t", error.explanation, "\n\tExtracted output will appear in \"", thymeFileName, "\"\n"]];
GOTO AbleToOutput
}
ELSE { TerminalIO.PutRope[error.explanation]; GOTO IOProblems }
};
thymeFileName ← CheckFileName [CDDirectory.Name[ HierarchyRoot[ cellList], SXAccess.design].Cat[ ".thy"]];
EXITS AbleToOutput => NULL
};
TerminalIO.PutRope [IO.PutR [IO.rope ["Commencing output of thyme file to \""], IO.rope [thymeFileName], IO.rope ["\""]] ];
thymeFile.SetStyle ["Cedar"];
defnTextNode ← thymeFile.InsertAsLastChild [];
defnTextNode.SetContents [IO.PutR [IO.rope[thymeFileName], IO.rope[", Written by Spinifex, "], IO.time[]] ];
Following LOOPHOLE caused by `opaque type' compiler problems.
TRUSTED { TiogaOps.PutProp[LOOPHOLE[defnTextNode], $Comment, NEW[BOOLEANTRUE]] };
FOR cl: LIST OF REF LogicalCell ← cellList, cl.rest WHILE cl # NIL DO
defnTextNode ← thymeFile.InsertAsLastChild [defnTextNode];
defnTextNode.SetFormat ["unit"];
IF cl.first.circuit.properties.GetProp [SXAtoms.spinifexCircuitDescription] # NIL THEN {
defnTextNode.SetContents [IO.PutFR["-- Opaque cell \"%g\" elided from circuit description at this point --", IO.rope[CD.Describe[cl.first.cellObj, NIL, SXAccess.design]]] ];
TRUSTED { TiogaOps.PutProp[LOOPHOLE[defnTextNode], $Comment, NEW[BOOLEANTRUE]] }
}
ELSE {
PrintSubcircuit [desWDir, NIL, thymeFile, defnTextNode, cl.first.cellObj, globals, formatKey]
};
ENDLOOP;
thymeFile.Store [thymeFileName ! FS.Error => {
IF error.group = user THEN {
IF error.code = $illegalName THEN {
thymeFile.Store ["///temp/ThymeOut.thy" ];
TerminalIO.PutRope [Rope.Cat[ "\n\t", error.explanation, "\n\tExtracted output will appear in \"///temp/ThymeOut.thy\""]];
CONTINUE
}
ELSE { TerminalIO.PutRope[error.explanation]; GOTO IOProblems }
};
} ];
TerminalIO.PutRope [" — done.\n"];
EXITS IOProblems => TerminalIO.PutRope [" — failed.\n"];
};
Rosemary
SXAtoms.rosePrint => {
GenKey: INT ← 0;
rootName: ROPE ← CDDirectory.Name [HierarchyRoot[cellList], SXAccess.design];
fullRootName, DFFileName: ROPE;
DFfile: IO.STREAM;
{ ENABLE FS.Error =>
IF error.group = user THEN {
IF error.code = $illegalName THEN {
rootName ← "ExtractedRoseOut";
fullRootName ← FS.ExpandName [rootName, desWDir].fullFName;
DFfile ← FS.StreamOpen [DFFileName ← fullRootName.Cat["-str.df"], $create];
TerminalIO.PutRope [ Rope.Cat ["\n\t", error.explanation, "\n\tExtracted output will appear in \"", DFFileName, "\"\n"]];
GOTO AbleToOutput
}
ELSE { TerminalIO.PutRope[error.explanation]; GOTO IOProblems }
};
Try the cell name
fullRootName ← CheckFileName [rootName];
DFfile ← FS.StreamOpen [DFFileName ← fullRootName.Cat["-str.df"], $create];
EXITS AbleToOutput => NULL
};
TerminalIO.PutRope [IO.PutR [IO.rope["Commencing output rosemary file to \""], IO.rope[DFFileName], IO.rope["\""]] ];
DFfile.PutF ["-- %g.df written by Spinifex structure capturer, %g\n", IO.rope[rootName], IO.time[]];
DFfile.PutF ["-- from design %g\n\n\n", IO.rope[SXAccess.design.name]];
DFfile.PutF ["Directory ??\n\t%g-str.df\n", IO.rope[rootName]];
FOR cl: LIST OF REF LogicalCell ← cellList, cl.rest WHILE cl # NIL DO
KeepHouse [cl.first, DFfile, SXAtoms.init];
ENDLOOP;
FOR cl: LIST OF REF LogicalCell ← cellList, cl.rest WHILE cl # NIL DO
cellFileName: ROPE ← CDDirectory.Name [cl.first.cellObj, SXAccess.design];
IF cl.first.circuit.properties.GetProp [SXAtoms.spinifexCircuitDescription] # NIL THEN {
DFfile.PutF ["-- (CellType \"%g\") Opaque cell elided from output at this point\n", IO.rope[CDDirectory.Name[cl.first.cellObj, SXAccess.design]]]
}
ELSE {
cellFile: TiogaFileOps.Ref ~ TiogaFileOps.CreateRoot [];
firstNode: TiogaFileOps.Ref ~ cellFile.InsertAsLastChild [];
cellFile.SetStyle ["Cedar"];
firstNode.SetFormat ["unit"];
PrintSubcircuit [desWDir, DFfile, cellFile, firstNode, cl.first.cellObj, globals, formatKey];
{ ENABLE FS.Error =>
IF error.group = user THEN {
IF error.code = $illegalName THEN {
cellFileName ← rootName.Cat ["-", Convert.RopeFromInt[GenKey]];
GenKey ← GenKey.SUCC;
cellFile.Store [FS.ExpandName[cellFileName.Cat[".sch"], desWDir].fullFName];
CONTINUE
}
ELSE { TerminalIO.PutRope [error.explanation]; GOTO IOProblems }
};
fName: ROPE ~ CheckFileName [cellFileName.Cat[".sch"]];
cellFile.Store [fName]
};
DFfile.PutF ["-- (CellType \"%g\")\n %g.sch\n", IO.rope[CDDirectory.Name[cl.first.cellObj, SXAccess.design]], IO.rope[cellFileName]]
};
ENDLOOP;
FOR cl: LIST OF REF LogicalCell ← cellList, cl.rest WHILE cl # NIL DO
KeepHouse [cl.first, DFfile, SXAtoms.fini];
ENDLOOP;
DFfile.PutRope [Rope.Cat["\nExports Imports ", releaseDirectory, "StructuralPrimitives.DF Of ~=\n"]];
DFfile.Close [];
TerminalIO.PutRope [" — done.\n"];
EXITS IOProblems => TerminalIO.PutRope [" — failed.\n"];
};
ENDCASE => {
TerminalIO.PutRope ["Warning: Unknown output format, no file written.\n"];
};
CleanUp [cellList];
}; -- end PrintCircuit
KeepHouse: PROC [lc: REF LogicalCell, dfStream: IO.STREAM, key: ATOM] = BEGIN
FOR links: LIST OF REF NodeLinkage ← lc.circuit.linkages, links.rest WHILE links # NIL DO
housekeeper: REF ANY ← CDProperties.GetProp [from: links.first.source.ob.class.properties, prop: key];
IF housekeeper#NIL THEN {
NARROW [housekeeper, REF SXOutput.LinkageHousekeeper]^[dfStream, links.first];
};
ENDLOOP;
END; -- end KeepHouse
QuoteRose: QuoteProc = {RETURN [Convert.RopeFromRope [name]]};
QuoteThyme: QuoteProc = BEGIN
l: INT ~ name.Length[];
IF l = 0 THEN RETURN ["$$"];
FOR i: INT IN [0..l) DO
c: CHAR = name.Fetch[i];
IF ~Ascii.Letter[c] AND ~Ascii.Digit[c] THEN EXIT;
REPEAT FINISHED => RETURN [name]
ENDLOOP;
{
Name has non-alphanumerics.
constructedName: ROPE ← Rope.Cat ["$", name];
dollarPosnSUCC: INT ← 1;
WHILE (dollarPosnSUCC ← constructedName.Find["$", dollarPosnSUCC]) # -1 DO
constructedName ← constructedName.Replace[dollarPosnSUCC, 1, "$$"];
dollarPosnSUCC ← dollarPosnSUCC + 2 -- Jump over inserted $$
ENDLOOP;
RETURN [constructedName.Cat["$"]]
}
END; -- end QuoteThyme
PrintSubcircuit: PROCEDURE [desWDir: ROPE, dfStream: IO.STREAM, root, circuitDefn: TiogaFileOps.Ref, cellObj: CD.Object, GlobalNames: SymTab.Ref, formatKey: REF ANY] ~ {
Format specific routines.
PrintRoseStray: PrintStrayProc ~ {
[Stream: IO.STREAM, node: REF CircuitNode]
startedAPList: BOOLEANFALSE;
FOR apList: LIST OF AreaPerimRec ← node.dim, apList.rest WHILE apList # NIL DO
r: ROPE = tech.spinifexLayerNames [apList.first.layer].thymeName;
IF r = NIL THEN LOOP;
IF apList.first.area = 0 AND apList.first.perim = 0 THEN LOOP;
IF ~startedAPList THEN {
Stream.Put [IO.rope[" (MOSStray"]];
};
IF apList.first.area # 0 THEN
Stream.PutF [" (a %g %g)", IO.rope[r], IO.int[apList.first.area/(SXAccess.design.technology.lambda*SXAccess.design.technology.lambda)]];
IF apList.first.perim # 0 THEN
Stream.PutF [" (p %g %g)", IO.rope[r], IO.int[apList.first.perim/SXAccess.design.technology.lambda]];
startedAPList ← TRUE
ENDLOOP;
IF startedAPList THEN
Stream.PutRope [")"];
}; -- end PrintRoseStray
PrintThymeStray: PrintStrayProc ~ {
[Stream: IO.STREAM, node: REF CircuitNode]
startedAPList: BOOLEANFALSE;
FOR apList: LIST OF AreaPerimRec ← node.dim, apList.rest WHILE apList # NIL DO
r: ROPE ~ tech.spinifexLayerNames [apList.first.layer].thymeName;
IF r = NIL THEN LOOP;
IF apList.first.area = 0 AND apList.first.perim = 0 THEN LOOP;
IF ~startedAPList THEN {
IF Stream.GetLength[] # 0 THEN Stream.PutRope [" "];
Stream.PutRope ["?: Stray["];
PrintNode [Stream, node];
Stream.Put [IO.rope["|"]]
}
ELSE
Stream.Put [IO.char[ ',]];
Stream.PutF [" a%g←N*%g, p%g←N*%g", IO.rope[r], IO.int[apList.first.area/(SXAccess.design.technology.lambda*SXAccess.design.technology.lambda)], IO.rope[r], IO.int[apList.first.perim/SXAccess.design.technology.lambda]];
startedAPList ← TRUE
ENDLOOP;
IF startedAPList THEN
Stream.PutRope ["];"];
}; -- end PrintThymeStray
PrintRoseNodeLoc: PrintNodeLocProc ~ {
[Stream: IO.STREAM, node: REF CircuitNode]
IF outputGeometricInfo THEN {
a: ATOM ~ tech.spinifexLayerNames [node.loc.layer].layerId;
Stream.PutF [" (locHint %g %g %g)", IO.int[node.loc.xy.x/SXAccess.design.technology.lambda], IO.int[node.loc.xy.y/SXAccess.design.technology.lambda], IO.atom[a]]
}
}; -- end PrintRoseNodeLoc
PrintThymeNodeLoc: PrintNodeLocProc ~ {
[Stream: IO.STREAM, node: REF CircuitNode]
IF outputGeometricInfo THEN {
a: ATOM ~ tech.spinifexLayerNames [node.loc.layer].layerId;
Stream.PutRope ["-- "];
PrintNode [Stream, node];
Stream.PutF [" in %g at %g %g --", IO.atom[a], IO.int[node.loc.xy.x/SXAccess.design.technology.lambda], IO.int[node.loc.xy.y/SXAccess.design.technology.lambda]]
}
}; -- end PrintThymeNodeLoc
SXOutput.NodePrintProc
QNodeName: PROCEDURE [node: REF CircuitNode] RETURNS [name: ROPE] ~ {
Returns Quoted name of node.
name ← Quote [GetAName[node]];
}; -- end QNodeName
PortHead: TiogaFileOps.Ref;
PrintRoseHead: PrintHeadProc ~ {
output.PutF ["-- %g", IO.rope[ name]];
circuitDefn.SetContents [output.RopeFromROS[]];
Following LOOPHOLE caused by `opaque type' compiler problems.
TRUSTED { TiogaOps.PutProp[LOOPHOLE[circuitDefn], $Comment, NEW[BOOLEANTRUE]] };
output ← output.ROS [];
output.PutF ["(CreatingUser \"%g\")", IO.rope[UserCredentials.Get[].name]];
AppendTiogaNode [output];
output ← output.ROS [];
output.PutF ["(CreationTime \"%g\")", IO.time[]];
AppendTiogaNode [output];
output ← output.ROS [];
AppendTiogaNode [output];
output ← output.ROS [];
output.PutRope ["(DerivingProgram \"Spinifex\" \"July 6, 1985 6:50:16 pm PDT\")"];
AppendTiogaNode [output];
output ← output.ROS [];
output.PutF ["(CellTypeName %g)", IO.rope[name]];
AppendTiogaNode [output];
IF outputGeometricInfo THEN {
b: CD.Rect ← CD.InterestRect [obj];
output ← output.ROS [];
output.PutF ["(scale %g \"lambda\")", IO.int[1]];
AppendTiogaNode [output];
output ← output.ROS [];
output.PutF ["(bb %g %g %g %g)",
IO.real [REAL[b.x1]/SXAccess.design.technology.lambda],
IO.real [REAL[b.y1]/SXAccess.design.technology.lambda],
IO.real [REAL[b.x2]/SXAccess.design.technology.lambda],
IO.real [REAL[b.y2]/SXAccess.design.technology.lambda]];
AppendTiogaNode[output];
};
output ← output.ROS [];
output.Put [IO.rope["(Ports"]];
AppendTiogaNode [output];
Introduce 3rd level sub-structure.
PortHead ← currLine;
output ← output.ROS []
}; -- end PrintRoseHead
PrintThymeHead: PrintHeadProc ~ {
[obj: CD.Object, name: ROPE]
output.Put [IO.rope [name], IO.rope [": circuit["]];
}; -- end PrintThymeHead
PrintRoseFormal: PrintFormalProc ~ {
[qName: ROPE, first: BOOL, node: REF CircuitNode]
portDef: TiogaFileOps.Ref ~ PortHead.InsertAsLastChild[];
naming: Naming ← GetANaming[node];
INTERIM, EC if present should go here.
output.PutRope ["("];
PrintNaming [output, naming];
output.PutRope [")"];
portDef.SetContents [output.RopeFromROS[]];
portDef.SetFormat ["code"];
output ← output.ROS [];
output.PutRope ["(N "];
PrintNaming [output, naming];
PrintStray [output, node];
PrintNodeLoc [output, node];
output.PutRope [")"];
AppendTiogaNode [output];
output ← output.ROS [];
Port node defs, e.g. (PN "Vdd" "Vdd")
output.PutF ["(PN %g %g)", IO.rope[qName], IO.rope[qName]];
AppendTiogaNode [output];
output ← output.ROS []
}; -- end PrintRoseFormal
PrintThymeFormal: PrintFormalProc ~ {
[qName: ROPE, first: BOOL, node: REF CircuitNode]
strayROS: IO.STREAM ~ IO.ROS[];
output.Put [IO.rope[IF first THEN " " ELSE ", "], IO.rope[qName]];
IF printLocalNodeLocation THEN
BEGIN
locROS: IO.STREAM ~ IO.ROS[];
locLine: TiogaFileOps.Ref ← NIL;
PrintNodeLoc [locROS, node];
locLine ← circuitDefn.InsertAsLastChild [];
locLine.SetContents [locROS.RopeFromROS[]];
-- Following LOOPHOLE caused by `opaque type' compiler problems.
TRUSTED {TiogaOps.PutProp[LOOPHOLE[locLine], $Comment, NEW[BOOLEANTRUE]]};
END;
PrintStray [strayROS, node];
IF strayROS.GetLength [] # 0 THEN
circuitDefn.InsertAsLastChild[].SetContents [strayROS.RopeFromROS[]];
}; -- end PrintThymeFormal
PrintRoseStartBody: PrintStartBodyProc ~ {
[cellName: ROPE]
portClose: TiogaFileOps.Ref ~ PortHead.InsertAsLastChild[];
privateStart: TiogaFileOps.Ref ~ PortHead.InsertNode[];
portClose.SetContents [")"];
portClose.SetFormat ["code"];
privateStart.SetContents ["(PrivateFollows)"];
portClose.SetFormat ["code"];
}; -- end PrintRoseStartBody
PrintThymeStartBody: PrintStartBodyProc ~ {
[cellName: ROPE]
output.Put [IO.rope["| N𡤁] = {"]];
circuitDefn.SetContents [output.RopeFromROS[]];
circuitDefn.AddLooks [0, cellName.Length[], 'b, root];
output ← output.ROS []
}; -- end PrintThymeStartBody
PrintRoseLocalNode: PrintLocalNodeProc ~ {
[node: REF CircuitNode]
Local node defs, e.g. (N "Vdd")
naming: Naming ← GetANaming [node];
output.PutRope ["(N "];
PrintNaming [output, naming];
PrintStray [output, node];
PrintNodeLoc [output, node];
output.PutRope [")"];
AppendTiogaNode [output];
output ← output.ROS [];
}; -- end PrintRoseLocalNode
PrintThymeLocalNode: PrintLocalNodeProc ~ {
[node: REF CircuitNode]
naming: Naming;
goodNode: BOOLFALSE;
FOR apList: LIST OF AreaPerimRec ← node.dim, apList.rest WHILE apList # NIL DO
IF (tech.spinifexLayerNames [apList.first.layer].thymeName # NIL) THEN BEGIN
goodNode ← TRUE; LOOP
END
ENDLOOP;
IF (NOT goodNode) THEN BEGIN
TerminalIO.PutRope ["\n Warning: Empty node omitted from circuit, probably an unconnected well.\n"];
RETURN
END;
naming ← GetANaming[node];
IF (NOT goodNode) THEN BEGIN
TerminalIO.PutRope ["\nNode "];
TerminalIO.PutRope [naming.name];
TerminalIO.PutRope [" has no strays. "]
END;
IF printLocalNodeLocation THEN
BEGIN
locROS: IO.STREAM ~ IO.ROS [];
locLine: TiogaFileOps.Ref ← NIL;
PrintNodeLoc [locROS, node];
locLine ← circuitDefn.InsertAsLastChild [];
locLine.SetContents [locROS.RopeFromROS[]];
Following LOOPHOLE caused by `opaque type' compiler problems.
TRUSTED { TiogaOps.PutProp[LOOPHOLE[locLine], $Comment, NEW[BOOLEANTRUE]] };
END;
IF naming.next # NIL THEN PrintNodeAliases [node, naming.next];
PrintNode [output, node];
output.Put [IO.rope [": node;"]];
PrintStray [output, node];
AppendTiogaNode [output];
output ← output.ROS [];
}; -- end PrintThymeLocalNode
PrintRoseNodeAlias: PrintNodeAliasesProc ~ {
[node: REF CircuitNode, alias: Naming]
ERROR -- should have been taken care of by PrintNaming -- ;
}; -- end PrintRoseNodeAlias
PrintThymeNodeAlias: PrintNodeAliasesProc ~ {
[node: REF CircuitNode, alias: Naming]
IF node.properties.GetProp [isPort] = isPort THEN RETURN;
output.Put [IO.rope [ "-- ALIAS[ "]];
PrintNode [output, node];
FOR alias ← alias, alias.next WHILE alias # NIL DO
IF Valid [alias] THEN output.Put [IO.rope [", "], IO.rope[Quote[NamingName[alias]]]];
ENDLOOP;
output.Put [IO.rope[ "] --"]];
AppendTiogaNode [output];
Following LOOPHOLE caused by `opaque type' compiler problems.
TRUSTED { TiogaOps.PutProp[LOOPHOLE[currLine], $Comment, NEW[BOOLEANTRUE]] };
output ← output.ROS[]
}; -- end PrintThymeNodeAlias
PrintRoseInstanceHead: PrintInstanceHeadProc ~ {
[inst: CD.Instance, defName: ROPE]
naming: Naming ← GetANaming [inst];
output.PutRope ["(CI "];
PrintNaming [output, naming, Rope.Cat[" ", Quote[defName]]];
PrintRoseInstantiationTransformation [output, inst];
output.PutRope [" (CIC"];
}; -- end PrintRoseInstanceHead
PrintThymeInstanceHead: PrintInstanceHeadProc ~ {
[inst: CD.Instance, defName: ROPE]
output.PutF ["%g: %g[", IO.rope[Quote[GetAName[inst]]], IO.rope[Quote[defName]]];
}; -- end PrintThymeInstanceHead
PrintRoseActual: PrintActualProc ~ {
[qActualNode, qFormalPort: ROPE, actualNum: CARDINAL]
output.PutF [" (%g %g)", IO.rope[qFormalPort], IO.rope[qActualNode] ]
}; -- end PrintRoseActual
PrintThymeActual: PrintActualProc ~ {
[qActualNode, qFormalPort: ROPE, actualNum: CARDINAL]
IF actualNum # CountBase THEN output.PutRope[ ", "];
output.PutRope [qActualNode];
}; -- end PrintThymeActual
PrintRoseInstanceEnd: PrintInstanceEndProc ~ {
output.PutRope [ "))"];
AppendTiogaNode [output];
output ← output.ROS []
}; -- end PrintRoseInstanceEnd
PrintThymeInstanceEnd: PrintInstanceEndProc ~ {
output.PutRope ["| N←N];"];
AppendTiogaNode [output];
output ← output.ROS []
}; -- end PrintThymeInstanceEnd
PrintRoseBodyEnd: PrintBodyEndProc ~ {
};
PrintThymeBodyEnd: PrintBodyEndProc ~ {
output.PutRope ["};"];
AppendTiogaNode [output];
output ← output.ROS []
}; -- end PrintThymeBodyEnd
End of format specific routines
AppendTiogaNode: PROCEDURE [Stream: IO.STREAM] ~ {
currLine ← circuitDefn.InsertAsLastChild [currLine];
currLine.SetContents [Stream.RopeFromROS[]];
currLine.SetFormat ["code"]
}; -- end AppendTiogaNode
Symbols: SymTab.Ref;
UsedSymbol: PROCEDURE [r: ROPE] RETURNS [BOOLEAN] ~ {
RETURN [GlobalNames.Fetch[r].found OR Symbols.Fetch[r].found]
}; -- end UsedSymbol
FindUnique: PROCEDURE [ base: ROPE, start: INTEGER, val: REF ANYNIL] RETURNS [rope: ROPE, count: INTEGER] ~ {
-- Finds first string of form base-int where int>=start where base-int is not in Symbols. Enters the found string in Symbols.
count ← start;
DO
rope ← base.Cat [Convert.RopeFromInt[count]];
IF ~UsedSymbol [rope] THEN {
[] ← Symbols.Store [rope, val];
RETURN
};
count ← count.SUCC;
ENDLOOP;
}; -- end FindUnique
Lookup: PROC [name: ROPE] RETURNS [naming: Naming] = {
found: BOOL;
val: REF ANY;
[found, val] ← GlobalNames.Fetch [name];
IF found THEN RETURN [NARROW[val]];
[found, val] ← Symbols.Fetch [name];
IF found THEN RETURN [NARROW[val]];
naming ← NIL;
}; -- end Lookup
NameThing: PROC [thing: REF ANY, qual: ROPENIL, short: ROPE, explicit, squash, onlyCollide: BOOLFALSE] = {
NoteNewNaming: PROC = {
WITH thing SELECT FROM
node: REF CircuitNode => node.properties ← node.properties.PutProp [actualSignalName, this];
appl: CD.Instance => CDProperties.PutInstanceProp [onto~appl, prop~actualCellInstanceName, val~this];
ENDCASE => ERROR
}; -- end NoteNewNaming
user: Naming ← Lookup [short];
next, this: Naming;
name: ROPE ← short;
doingNets: BOOLISTYPE [thing, REF CircuitNode];
IF explicit AND qual # NIL THEN ERROR;
IF user # NIL AND user.named = thing AND NOT onlyCollide THEN {
IF explicit # user.explicit THEN ERROR;
IF qual # NIL AND user.prefixes = NIL THEN user.prefixes ← LIST[NIL];
IF user.prefixes # NIL THEN user.prefixes ← CONS [qual, user.prefixes];
RETURN;
};
WITH thing SELECT FROM
node: REF CircuitNode => next ← NARROW[ node.properties.GetProp[ actualSignalName]];
appl: CD.Instance => next ← NARROW[ CDProperties.GetInstanceProp[ from~appl, prop~actualCellInstanceName]];
ENDCASE => ERROR;
this ← NEW [NamingRep ← [next: next, named: IF NOT onlyCollide THEN thing ELSE NIL, prefixes: IF qual # NIL THEN LIST[qual] ELSE NIL, name: short, explicit: explicit, collided: onlyCollide, squash: squash]];
IF user # NIL THEN Rename [short, user, doingNets];
IF user = NIL OR onlyCollide THEN {
[] ← Symbols.Store [short, this]; NoteNewNaming []; RETURN};
IF qual # NIL THEN {
long: ROPE ← qual.Cat [".", short];
NameThing [thing, NIL, long];
RETURN;
};
NoteNewNaming [];
this.explicit ← FALSE;
[this.name, user.count] ← FindUnique [base~IF squash THEN short ELSE (short.Cat[CountSep]), start~user.count+1, val~this];
}; -- end NameThing
Rename: PROC [key: ROPE, tomb: Naming, doingNets: BOOL] = {
thing: REF ANY ← tomb.named;
nameNIL: BOOLFALSE;
IF tomb.collided THEN RETURN;
tomb.collided ← TRUE;
WITH tomb.named SELECT FROM
n: REF CircuitNode => NULL;
a: CD.Instance => IF doingNets THEN RETURN;
o: CD.Object => RETURN;
ENDCASE => ERROR;
tomb.named ← NIL;
IF tomb.prefixes = NIL THEN {
NameThing [thing~thing, short~key, squash~tomb.squash]; RETURN};
FOR prefixes: ROPEList ← tomb.prefixes, prefixes.rest WHILE prefixes # NIL DO
IF prefixes.first = NIL THEN nameNIL ← TRUE ELSE NameThing [thing, NIL, prefixes.first.Cat[".", tomb.name]];
ENDLOOP;
tomb.prefixes ← NIL;
IF nameNIL THEN NameThing [thing~thing, short~tomb.name, squash~tomb.squash];
}; -- end Rename
Output format customization
PrintStray: PrintStrayProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeStray,
SXAtoms.rosePrint => PrintRoseStray,
ENDCASE => ERROR;
PrintNodeLoc: PrintNodeLocProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeNodeLoc,
SXAtoms.rosePrint => PrintRoseNodeLoc,
ENDCASE => ERROR;
Quote: QuoteProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => QuoteThyme,
SXAtoms.rosePrint => QuoteRose,
ENDCASE => ERROR;
PrintNode: SXOutput.NodePrintProc -- [ stream: IO.STREAM, node: REF CircuitNode] -- ~ {
printName: ROPE ← GetAName [node];
stream.PutRope [Quote[printName]];
};
PrintHead: PrintHeadProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeHead,
SXAtoms.rosePrint => PrintRoseHead,
ENDCASE => ERROR;
PrintFormal: PrintFormalProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeFormal,
SXAtoms.rosePrint => PrintRoseFormal,
ENDCASE => ERROR;
PrintStartBody: PrintStartBodyProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeStartBody,
SXAtoms.rosePrint => PrintRoseStartBody,
ENDCASE => ERROR;
PrintLocalNode: PrintLocalNodeProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeLocalNode,
SXAtoms.rosePrint => PrintRoseLocalNode,
ENDCASE => ERROR;
PrintNodeAliases: PrintNodeAliasesProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeNodeAlias,
SXAtoms.rosePrint => PrintRoseNodeAlias,
ENDCASE => ERROR;
PrintInstanceHead: PrintInstanceHeadProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeInstanceHead,
SXAtoms.rosePrint => PrintRoseInstanceHead,
ENDCASE => ERROR;
PrintActual: PrintActualProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeActual,
SXAtoms.rosePrint => PrintRoseActual,
ENDCASE => ERROR;
PrintInstanceEnd: PrintInstanceEndProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeInstanceEnd,
SXAtoms.rosePrint => PrintRoseInstanceEnd,
ENDCASE => ERROR;
PrintBodyEnd: PrintBodyEndProc ~ SELECT formatKey FROM
SXAtoms.thymePrint => PrintThymeBodyEnd,
SXAtoms.rosePrint => PrintRoseBodyEnd,
ENDCASE => ERROR;
ignoreChildNames: BOOLEAN ~ formatKey = SXAtoms.rosePrint;
sxData: REF SX.LogicalCell ← SXAccessInternal.GetLogicalCell [cellObj];
circuit: REF Circuit ← sxData.circuit;
tech: REF TechHandle = SXAccess.sxTech;
localNodes: CARDINAL ← CountBase;
nodeStoppers: CARDINAL ← CountBase;
output: IO.STREAMIO.ROS[];
currLine: TiogaFileOps.Ref ← NIL;
First we must count how many times each symbol is used. The reason we do this is to avoid suffixing counts to symbols which are used only once.
{
count: INTEGER ← 17;
FOR nl: LIST OF REF CircuitNode ← circuit.nodes, nl.rest WHILE nl # NIL DO
count ← count.SUCC;
ENDLOOP;
Symbols ← SymTab.Create[mod~ count, case~ TRUE]
};
Naming of subcircuits.
FOR appls: CD.InstanceList ← circuit.subcircuits, appls.rest WHILE appls # NIL DO
WITH CDProperties.GetInstanceProp[appls.first, SXAtoms.InstanceName] SELECT FROM
r: ROPE => NameThing [appls.first, NIL, r, TRUE];
ENDCASE => NameThing [thing~appls.first, short~circuitBase, squash~TRUE];
ENDLOOP;
Naming of linkages.
FOR links: LIST OF REF NodeLinkage ← circuit.linkages, links.rest WHILE links # NIL DO
PrintProc: REF ANY ← CDProperties.GetProp [from~links.first.source.ob.class.properties, prop~formatKey];
IF PrintProc # NIL THEN {
WITH CDProperties.GetInstanceProp [links.first.source, SXAtoms.InstanceName] SELECT FROM
r: ROPE => NameThing [links.first.source, NIL, r, TRUE];
ENDCASE => NameThing [thing~links.first.source, short~transBase, squash~TRUE];
};
ENDLOOP;
Naming of Nodes.
FOR nl: LIST OF REF CircuitNode ← circuit.nodes, nl.rest WHILE nl # NIL DO
FOR signalName: REF SignalName ← NARROW [nl.first.properties.GetProp [SXAtoms.SignalName]], signalName.alias WHILE signalName # NIL DO
IF signalName.depth # 0 THEN LOOP;
NameThing [nl.first, NIL, signalName.name, TRUE];
ENDLOOP;
ENDLOOP;
{
InheritNameFromConnections: PROC [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN] -- RefTab.EachPairAction -- ~ {
subNode: REF CircuitNode ← NARROW [key];
quit ← FALSE;
FOR ml: MergeRecList ← NARROW [val], ml.rest WHILE ml # NIL DO
supNode: REF CircuitNode ← ml.first.becomes;
instName: ROPE;
InheritName: PROC [name: ROPE, valid: BOOL] = {
IF valid THEN NameThing [supNode, instName, name] ELSE
IF propCollisions THEN NameThing [thing: supNode, short: name, onlyCollide: TRUE];
};
IF NOT ValidMerge [ml.first] THEN LOOP;
IF HasAskedName [supNode] THEN LOOP;
Don't inherit for explicitly named nodes.
instName ← GetAName [ml.first.applChain.first];
EnumerateNames [thing: subNode, PerName: InheritName, onlyValid: FALSE];
ENDLOOP;
quit ← quit;
};
IF circuit.mergeDirectory # NIL THEN [] ← circuit.mergeDirectory.Pairs [action~ InheritNameFromConnections];
}; -- end InheritNameFromConnections
FOR nl: LIST OF REF CircuitNode ← circuit.nodes, nl.rest WHILE nl # NIL DO
IF GetAName [nl.first] = NIL THEN NameThing [thing~nl.first, short~localBase, squash~TRUE];
ENDLOOP;
Now we put the names in a good order.
FOR nl: LIST OF REF CircuitNode ← circuit.nodes, nl.rest WHILE nl # NIL DO
oldFirst: Naming ← NARROW [nl.first.properties.GetProp[ actualSignalName]];
newFirst: Naming ← SortNamings [oldFirst];
nl.first.properties ← nl.first.properties.PutProp [actualSignalName, newFirst];
ENDLOOP;
Now we start the actual output.
{
Cell name and formal Parameter list (ports).
logicalCellName: ROPE ~ Quote [CDDirectory.Name[cellObj, SXAccess.design]];
first: BOOLTRUE;
isRoot: BOOL;
PrintHead [cellObj, logicalCellName];
Find out whether this is a root cell
isRoot ← sxData.rootOnInvocation = SXAccess.invocation;
Now check all nodes to determine whether they are formal parameters
FOR nl: LIST OF REF CircuitNode ← circuit.nodes, nl.rest WHILE nl # NIL DO
isRootPort: BOOLFALSE;
sn: REF SX.SignalName ← NIL;
IF isRoot THEN sn ← NARROW [Properties.GetProp[nl.first.properties, SXAtoms.SignalName], REF SX.SignalName];
isRootPort ← IF sn=NIL THEN FALSE ELSE (isRoot AND sn.makePort);
IF (nl.first.properties.GetProp[isPort] = isPort) OR isRootPort THEN {
PrintFormal [Quote[GetAName[nl.first]], first, nl.first];
first ← FALSE;
}
ENDLOOP;
PrintStartBody[logicalCellName]
};
Instantiation of local nodes.
FOR nl: LIST OF REF CircuitNode ← circuit.nodes, nl.rest WHILE nl # NIL DO
IF nl.first.properties.GetProp [isPort] = NIL THEN {
PrintLocalNode [nl.first];
}
ENDLOOP;
Instantiation of linkages.
FOR links: LIST OF REF NodeLinkage ← circuit.linkages, links.rest WHILE links # NIL DO
PrintProc: REF ANY ← CDProperties.GetProp [from~links.first.source.ob.class.properties, prop~formatKey];
IF PrintProc # NIL THEN {
qTName: ROPE;
qTName ← Quote [GetAName[links.first.source]];
NARROW [PrintProc, REF SXOutput.LinkagePrintProc]^[ desWDir, dfStream, output, links.first, qTName, PrintNode];
}
ELSE {
output.Put [IO.rope["Mystery object in Linkage List; ObjType ~ "], IO.atom[links.first.source.ob.class.objectType]];
};
{AppendTiogaNode[output]; output ← output.ROS[]};
ENDLOOP;
Instantiation of subcircuits.
FOR appls: CD.InstanceList ← circuit.subcircuits, appls.rest WHILE appls # NIL DO
actualsCount: CARDINAL ← CountBase;
subcircuit: REF Circuit = SXAccessInternal.GetLogicalCell [appls.first.ob].circuit;
PrintInstanceHead [appls.first, CDDirectory.Name [appls.first.ob, SXAccess.design] ];
FOR nl: LIST OF REF CircuitNode ← subcircuit.nodes, nl.rest WHILE nl # NIL DO
IF nl.first.properties.GetProp[isPort] # NIL THEN {
parentNode: REF CircuitNode;
IF circuit.mergeDirectory # NIL THEN {
qual: LIST OF CD.Instance;
[node: parentNode, rootQualifier: qual] ← SX.FindRootNode [circuit: circuit, subcircuitNode: nl.first, qualifier: LIST[appls.first]];
IF qual # NIL THEN parentNode ← NIL
}
ELSE
parentNode ← NIL;
IF parentNode # NIL THEN
PrintActual [QNodeName[parentNode], QNodeName[nl.first], actualsCount]
ELSE ERROR;
actualsCount ← actualsCount.SUCC;
}
ENDLOOP;
PrintInstanceEnd[];
ENDLOOP;
PrintBodyEnd[];
}; -- end PrintSubcircuit
Start: PROC = {
attachment, full: ROPENIL;
cp: FS.ComponentPositions;
[attachedTo~attachment] ← FS.FileInfo [name~"SX.BCD", remoteCheck~FALSE !FS.Error => CONTINUE];
IF attachment # NIL THEN {
[full, cp, ] ← FS.ExpandName [attachment];
releaseDirectory ← full.Substr [start: 0, len: cp.base.start];
}
ELSE releaseDirectory ← NIL;
}; -- end Start
Start [];
END.
Edited on January 28, 1985 12:44:59 pm PST, by Beretta
Commented out April 1st joke.
Edited on February 15, 1985 2:05:23 pm PST, by Shand
Printing of stray capcitances associated with port nodes.
changes to: PrintRoseFormal (local of PrintSubcircuit) although PrintRoseStray is currently NULL calls to PrintStray were added for future consistency, PrintThymeFormal (local of PrintSubcircuit) calls to PrintStray to add child nodes to Thyme Port Defn line, PrintRoseLocalNode (local of PrintSubcircuit) as for PrintRoseFormal, DIRECTORY, PrintThymeStray (local of PrintSubcircuit), PrintThymeFormal (local of PrintSubcircuit), machineName, PrintRoseHead (local of PrintSubcircuit), IMPORTS
Edited on March 7, 1985 4:35:40 pm PST, by Shand
Thyme output changes: n* Multiplier for McCreight.
Edited on March 10, 1985 8:55:14 pm PST, by Shand
Rose format now includes node areas & perimeter.
changes to: PrintRoseStray (local of PrintSubcircuit), PrintThymeStray (local of PrintSubcircuit), PrintRoseFormal (local of PrintSubcircuit), PrintRoseLocalNode (local of PrintSubcircuit), PrintRoseInvented (local of PrintSubcircuit)
Edited on March 10, 1985 10:06:06 pm PST, by Shand
Added new procedures to output geometric node loactions.
Deleted obsolete procedures PrintRoseInvented PrintThymeInvented and variable lastNodeNode
changes to: PrintSubcircuit, PrintRoseNodeLoc (local of PrintSubcircuit) New proc, PrintThymeNodeLoc (local of PrintSubcircuit) New proc, PrintRoseFormal (local of PrintSubcircuit), PrintThymeFormal (local of PrintSubcircuit), PrintRoseLocalNode (local of PrintSubcircuit), PrintThymeLocalNode (local of PrintSubcircuit), PrintRoseHead (local of PrintSubcircuit)
Edited on March 12, 1985 1:23:35 am PST, by Shand
changes to: DIRECTORY, PrintCircuit, PrintCircuit
Edited on March 19, 1985 2:36:17 pm PST, by Beretta
Thyme output change: substituted `n' coefficient for Ed McCreight by `N'
changes to: PrintThymeStray (local of PrintSubcircuit), PrintThymeStartBody (local of PrintSubcircuit), PrintThymeInstanceEnd (local of PrintSubcircuit)
Edited on May 6, 1985 5:29:17 pm PDT, by Beretta
Converted to ChipNDale version CD20.
Edited on May 15, 1985 12:37:48 pm PDT, by Beretta
Added boolean printLocalNodeLocation
changes to: PrintThymeFormal, PrintThymeLocalNode (local of PrintSubcircuit): node location printed only if printLocalNodeLocation.
Edited on June 18, 1985 6:02:12 pm PDT, by Beretta
Spinifex.bcd has become SX.bcd.
changes to: Start
Edited on June 19, 1985 8:09:52 pm PDT, by Beretta
Output unit for measures now is lambda instead of CD units.
changes to: PrintRoseHead (local of PrintSubcircuit): scale now is 1 instead of 1/lambda. Divided coordinates for bounding box by lambda.
Edited on July 8, 1985 5:58:51 pm PDT, by Beretta
If an object has the property export and if the value is $TRUE and the cell is at the root of analysis, then the signal name of the node with this property will be used as a parameter (port).
changes to: PrintSubcircuit.
gbb July 31, 1985 6:45:16 pm PDT
Adding Core output.
changes to: DIRECTORY, PrintSubcircuit
gbb August 7, 1985 2:54:16 pm PDT
Due to storage overflow problems in the compiler, the stuff pertaining to Core has been move to a new module SXOutputImplC. The shared types are now declared in SXOutputPrivate.
changes to: DIRECTORY, SXOutputImplA, isPort, actualCellInstanceName, actualSignalName, releaseDirectory, PrintCircuit, KeepHouse, QuoteThyme, PrintSubcircuit, PrintThymeStray (local of PrintSubcircuit), PrintThymeHead (local of PrintSubcircuit), PrintThymeFormal (local of PrintSubcircuit), PrintThymeStartBody (local of PrintSubcircuit), PrintThymeLocalNode (local of PrintSubcircuit), PrintThymeNodeAlias (local of PrintSubcircuit), PrintThymeInstanceHead (local of PrintSubcircuit), PrintThymeActual (local of PrintSubcircuit), PrintRoseInstanceEnd (local of PrintSubcircuit), PrintRoseBodyEnd (local of PrintSubcircuit), Start, Start
gbb August 20, 1985 1:43:11 pm PDT
Core definition module was changed. CoreRecordCells became CoreClasses, RecordCell became RecordCellType, InstanceRec became CellInstanceRec, Instance became CellInstance, InstanceList became CellInstanceList, RecordCellRec became RecordCellTypeRec
gbb November 24, 1985 4:14:58 pm PST
Removed Core output.
changes to: DIRECTORY, PrintCircuit, PrintSubcircuit, Start
gbb March 15, 1986 5:08:54 pm PST
Unconnected wells caused a node without strays to be put in the Thyme file. Such nodes are now skipped and a warning is issued.
changes to: PrintThymeLocalNode (local of PrintSubcircuit): test whether there is any stray that goes in the Thyme file.
gbb June 6, 1986 7:41:04 pm PDT
The same thing happens also if there are instances with unconnected ports. An empty node is now inserted in the Thyme output and the warning message is much less visible (people complained they were anoyed by it).
changes to: PrintThymeLocalNode (local of PrintSubcircuit)., NameObj (local of PrintCircuit)