LichenFromExt.Mesa
Last tweaked by Mike Spreitzer on August 28, 1987 11:45:21 am PDT
DIRECTORY Asserting, Atom, Basics, BasicTime, Buttons, Containers, FS, Icons, IO, LichenArrayStuff, Collections, LichenDataOps, LichenDataStructure, PairCollections, List, PieViewers, Process, ProcessProps, RedBlackTree, RefTab, RefText, Rope, RopeHash, ViewerClasses, ViewerOps, ViewerTools;
LichenFromExt:
CEDAR
MONITOR
LOCKS dr USING dr: DesignReading
IMPORTS Asserting, Atom, BasicTime, Buttons, Containers, FS, Icons, IO, LichenArrayStuff, Collections, LichenDataOps, LichenDataStructure, PairCollections, List, PieViewers, Process, ProcessProps, RedBlackTree, RefTab, RefText, Rope, RopeHash, ViewerOps, ViewerTools
=
BEGIN OPEN Asserting, LichenDataStructure, LichenArrayStuff, LichenDataOps, Sets:Collections, Fns:PairCollections;
REFTEXT: TYPE = REF TEXT;
Viewer: TYPE = ViewerClasses.Viewer;
SourceList: TYPE = LIST OF Source;
Source: TYPE = RECORD [stream: IO.STREAM ← NIL, name: ROPE ← NIL];
Reader: TYPE = REF ReaderRep;
ReaderRep:
TYPE =
RECORD [
keyword: ROPE,
read:
PROC [s: Source, reader: Reader, cr: CellReading],
Consumes newline at end of line.
data: REF ANY];
readers: VarFunction ← Fns.CreateHashDictionary[TRUE];
DesignReading: TYPE = REF DesignReadingRep;
DesignReadingRep:
TYPE =
MONITORED
RECORD [
design: Design,
wDir: ROPE,
cellTypesByName: VarFunction,
fetTypes: RefTab.Ref,
unkosherArrays: Set,
toMerge: RedBlackTree.Table,
mostRecentPathToMerge: Path ← NIL,
impossibleMerges: ImpossibleMergeList ← NIL,
buffer: REFTEXT,
pacifier, pie, label, pause: Viewer,
stop: BOOL ← FALSE,
stack: SourceList ← NIL,
curCellTypeName, suffix: ROPE ← NIL,
curArray: BOOL ← FALSE,
curCellFileLength: REAL ← 0,
change: CONDITION];
undefinedINT: INT = FIRST[INT];
ImpossibleMergeList: TYPE = LIST OF ImpossibleMerge;
ImpossibleMerge:
TYPE =
RECORD [
arrayInstance: CellInstance, path1, path2: Path];
CellReading: TYPE = REF CellReadingRep;
CellReadingRep:
TYPE =
RECORD [
dr: DesignReading,
ct: CellType,
name: ROPE,
firstMerge: BOOL ← TRUE,
resistClasses: INT ← undefinedINT,
rScale: REAL--ohms-- ← 1.0E-3,
cScale: REAL--farads-- ← 1.0E-18,
lUnits: REAL--meters-- ← 1.0E-8,
scalingDefined: BOOL ← FALSE,
fetCount: INT ← 0,
waitingMerges: PathPairList ← NIL
];
PathPairList: TYPE = LIST OF PathPair;
Path: TYPE = LIST OF REF ANY--UNION [ROPE, REF Range2]--;
VertexArray: TYPE = REF VertexArrayRep;
VertexArrayRep:
TYPE =
RECORD [
shape: Size2,
vertices: SEQUENCE length: NAT OF Vertex];
Use: TYPE = RECORD [childName: ROPE, as: ArraySpec];
ArraySpec:
TYPE =
RECORD [
variant:
SELECT kind: *
FROM
scalar => [],
array => [
range: Range2,
sep: Int2
]
ENDCASE];
FetTerminal:
TYPE =
RECORD [
name: SteppyName,
length: INT,
attrs: Assertions];
IntBox: TYPE = RECORD [xmin, ymin, xmax, ymax: INT];
TransformAsTerms: TYPE = Terms;
PathPair: TYPE = REF PathPairPrivate;
PathPairPrivate: TYPE = RECORD [p1, p2: Path];
pacifierIcon: Icons.IconFlavor ← Icons.NewIconFromFile["Lichen.icons", 0];
labelHeight: INTEGER ← 17;
pauseWidth: INTEGER ← 60;
pieDiameter: INTEGER ← 50;
ReadDesign:
PROC [rootCellFileName:
ROPE, oldDR: DesignReading ←
NIL]
RETURNS [dr: DesignReading] =
BEGIN
Doit:
PROC = {
dr.stack ← NIL;
[] ← ReadCellType[dr.design, rootCellFileName, dr]};
IF oldDR =
NIL
THEN {
cp: FS.ComponentPositions;
fullFName, designName: ROPE;
[fullFName, cp, ] ← FS.ExpandName[rootCellFileName];
designName ← fullFName.Substr[start: cp.base.start, len: cp.base.length];
dr ←
NEW [DesignReadingRep ← [
design:
NEW [DesignPrivate ← [
cellTypes: Sets.CreateHashSet[],
other: Assert1[nameReln, designName, NIL]
]],
wDir: fullFName.Substr[len: cp.base.start],
cellTypesByName: Fns.CreateHashDictionary[TRUE],
fetTypes: RefTab.Create[hash: HashFetType, equal: CompareFetTypes],
unkosherArrays: Sets.CreateHashSet[],
toMerge: RedBlackTree.Create[Id, ComparePaths],
buffer: RefText.New[200],
pacifier: Containers.Create[info: [name: designName.Cat[" pacifier"], icon: pacifierIcon]],
pie: NIL,
label: NIL,
pause: NIL
]];
TRUSTED {
Process.InitializeCondition[@dr.change, Process.SecondsToTicks[60]];
Process.EnableAborts[@dr.change]};
dr.pause ← Buttons.Create[info: [name: "Pause", parent: dr.pacifier, wx: 0, wy: 0, ww: pauseWidth, wh: labelHeight], proc: TogglePause, clientData: dr];
dr.label ← ViewerTools.MakeNewTextViewer[info: [parent: dr.pacifier, wx: dr.pause.wx+dr.pause.ww, wy: 0, ww: 100, wh: labelHeight]];
Containers.ChildXBound[container: dr.pacifier, child: dr.label];
dr.pie ← PieViewers.Create[parent: dr.pacifier, x: 0, y: dr.label.wy+dr.label.wh, diameter: pieDiameter, total: 1.0, divisions: 100];
Containers.ChildXBound[container: dr.pacifier, child: dr.pie];
Containers.ChildYBound[container: dr.pacifier, child: dr.pie];
ViewerOps.SetOpenHeight[dr.pacifier, dr.pie.wy+dr.pie.wh];
TRUSTED {Process.Detach[FORK Pacify[dr]]};
}
ProcessProps.PushPropList[List.PutAssoc[$WorkingDirectory, dr.wDir, NIL], Doit];
END;
Pacify:
PROC [dr: DesignReading] = {
lastStack: SourceList ← NIL;
lastIndex: INT ← 0;
ViewerOps.OpenIcon[icon: dr.pacifier, bottom: FALSE];
WHILE
NOT dr.pacifier.destroyed
DO
WithLock:
ENTRY
PROC [dr: DesignReading] = {
ENABLE UNWIND => NULL;
IF dr.stack =
NIL
THEN {
IF dr.stack # lastStack
THEN {
lastStack ← dr.stack;
ViewerTools.SetContents[dr.label, "Idle"];
PieViewers.Set[dr.pie, 0];
};
}
ELSE {
index: INT = dr.stack.first.stream.GetIndex[];
IF dr.stack # lastStack
OR index # lastIndex
THEN {
lastStack ← dr.stack;
lastIndex ← index;
ViewerTools.SetContents[dr.label, IO.PutFR["%g%g[%g]%g", [rope[dr.curCellTypeName]], [rope[IF dr.curArray THEN ".aext" ELSE ""]], [integer[index]], [rope[dr.suffix]]]];
PieViewers.Set[dr.pie, index/dr.curCellFileLength];
};
};
};
Process.Pause[Process.MsecToTicks[pacifyPeriod]];
WithLock[dr];
ENDLOOP;
RETURN};
pacifyPeriod: Process.Milliseconds ← 2500;
TogglePause: Buttons.ButtonProc = {
dr: DesignReading = NARROW[clientData];
Flip:
ENTRY
PROC [dr: DesignReading] = {
ENABLE UNWIND => NULL;
dr.stop ← NOT dr.stop;
BROADCAST dr.change};
Flip[dr];
Buttons.ReLabel[dr.pause, IF dr.stop THEN "Continue" ELSE "Pause"];
};
PrintImpossibles:
PROC [to:
IO.
STREAM, dr: DesignReading] = {
FOR ims: ImpossibleMergeList ← dr.impossibleMerges, ims.rest
WHILE ims #
NIL
DO
im: ImpossibleMerge = ims.first;
to.PutF["%g: %g & %g\n", [rope[Describe[im.arrayInstance, dr.design]]], [rope[FmtPath[im.path1]]], [rope[FmtPath[im.path2]]]];
ENDLOOP;
};
fromExtClass: CellClass ← NEW [CellClassPrivate ← []];
DoPushed:
PROC [dr: DesignReading, cellTypeName:
ROPE, array:
BOOL, s: Source,
Proc:
PROC [Source]] = {
cooler: SourceList = dr.stack;
oldCellTypeName: ROPE = dr.curCellTypeName;
oldArray: BOOL = dr.curArray;
oldSuffix: ROPE = dr.suffix;
oldCellFileLength: REAL = dr.curCellFileLength;
newSuffix: ROPE = FmtStack[cooler];
newCellFileLength: INT = MAX[s.stream.GetLength[], 1];
Push:
ENTRY
PROC [dr: DesignReading] = {
ENABLE UNWIND => NULL;
dr.stack ← CONS[s, dr.stack];
dr.curCellTypeName ← cellTypeName;
dr.curArray ← array;
dr.suffix ← newSuffix;
dr.curCellFileLength ← newCellFileLength;
};
Pop:
ENTRY
PROC [dr: DesignReading] = {
ENABLE UNWIND => NULL;
dr.stack ← cooler;
dr.curCellTypeName ← oldCellTypeName;
dr.curArray ← oldArray;
dr.suffix ← oldSuffix;
dr.curCellFileLength ← oldCellFileLength;
};
Push[dr];
Proc[s !UNWIND => Pop[dr]];
Pop[dr];
};
ReadCellType:
PROC [design: Design, cellFileName:
ROPE, dr: DesignReading]
RETURNS [ct: CellType] = {
cp: FS.ComponentPositions;
fullFName, cellTypeName: ROPE;
from: IO.STREAM;
s: Source;
cr: CellReading;
Pushed: PROC [s: Source] = {PushedRead[dr, cr, s, FALSE]};
[fullFName, cp] ← ExpandName[cellFileName, "ext"];
cellTypeName ← fullFName.Substr[start: cp.base.start, len: cp.base.length];
ct ← LocalCreateCellType[design, dr, cellTypeName, TRUE, NIL, NIL];
cr ← NEW[CellReadingRep ← [dr: dr, ct: ct, name: cellTypeName]];
s ← [from ← FS.StreamOpen[fullFName], fullFName];
DoPushed[dr, cellTypeName, FALSE, s, Pushed];
from.Close[];
};
TryArrayFile:
PROC [cr: CellReading] = {
fullFName: ROPE = ExpandName[cr.name, "aext"].fullFName;
s: Source = [FS.StreamOpen[fullFName], fullFName];
Pushed:
PROC [s: Source] = {
PushedRead[cr.dr, cr, s, TRUE];
FinishWaitingMerges[cr];
};
IF cr.dr.toMerge.Size[] # 0 OR cr.waitingMerges # NIL THEN ERROR;
DoPushed[cr.dr, cr.name, TRUE, s, Pushed];
s.stream.Close[];
};
PushedRead:
PROC [dr: DesignReading, cr: CellReading, s: Source, nested:
BOOL] = {
from: IO.STREAM = s.stream;
ct: CellType = cr.ct;
DO
keyword: ROPE;
reader: Reader;
Process.CheckForAbort[];
[] ← from.SkipWhitespace[];
IF from.EndOf[] THEN EXIT;
IF dr.stop THEN Wait[dr];
keyword ← from.GetTokenRope[TokenBreak].token;
reader ← NARROW[readers.Apply[keyword].DVal];
IF reader #
NIL
THEN reader.read[s, reader, cr]
ELSE {
terms: Terms ← GetLineTerms[from];
reln: ATOM ← Atom.MakeAtom[keyword];
ct.otherPublic ← Assert[reln, terms, ct.otherPublic];
};
ENDLOOP;
IF dr.toMerge.Size[] # 0
THEN {
IF cr.firstMerge THEN ERROR;
DoMerges[s, cr];
}
ELSE IF cr.firstMerge THEN {cr.firstMerge ← FALSE; TryArrayFile[cr]};
IF nested THEN RETURN;
ct.publicKnown ← TRUE;
ct.privateKnown ← TRUE;
{
CleanupChild:
PROC [ra:
REF
ANY] = {
ci: CellInstance = NARROW[ra];
childType: CellType = ci.type;
IF childType.asArray #
NIL
THEN {
IF childType.useCount # 1 THEN ERROR;
<<we should no longer have to do this:
RetractFalseHypotheses[childType];
Instead we only check:>> IF IsIncompleteArray[childType] THEN ERROR;
TrimArray[childType.asArray];
};
};
ct.asUnorganized.containedInstances.Enumerate[CleanupChild];
}};
FinishWaitingMerges:
PROC [cr: CellReading] = {
DO
progress: BOOL ← FALSE;
wml: PathPairList ← cr.waitingMerges;
cr.waitingMerges ← NIL;
FOR wml ← wml, wml.rest
WHILE wml #
NIL
DO
progress ← MergeWork[cr, wml.first.p1, wml.first.p2] OR progress;
ENDLOOP;
IF NOT progress THEN EXIT;
ENDLOOP;
IF cr.waitingMerges # NIL THEN ERROR;
};
Wait:
ENTRY
PROC [dr: DesignReading] = {
ENABLE UNWIND => NULL;
WHILE dr.stop DO WAIT dr.change ENDLOOP};
FmtStack:
PROC [stack: SourceList]
RETURNS [suffix:
ROPE] = {
suffix ← NIL;
FOR stack ← stack, stack.rest
WHILE stack #
NIL
DO
full: ROPE;
cp: FS.ComponentPositions;
[full, cp, ] ← FS.ExpandName[stack.first.name];
suffix ← IO.PutFR["%g, %g[%g]", [rope[suffix]], [rope[full.Substr[cp.base.start, cp.base.length]]], [integer[IO.GetIndex[stack.first.stream]]]];
ENDLOOP;
suffix ← suffix;
};
GetLineTerms:
PROC [from:
IO.
STREAM]
RETURNS [terms: Terms] = {
tail: Terms ← terms ← NIL;
WHILE
NOT from.EndOf[]
DO
peek: CHAR ← from.PeekChar[];
SELECT peek
FROM
'\n => {IF from.GetChar[] # peek THEN ERROR; RETURN};
IN [0C .. ' ] => IF from.GetChar[] # peek THEN ERROR;
ENDCASE => {
this: LORA ← LIST[from.GetRefAny[]];
IF tail = NIL THEN terms ← this ELSE tail.rest ← this;
tail ← this};
ENDLOOP;
};
GetSteppyName:
PROC [s: Source]
RETURNS [name: SteppyName] ~ {
raw: ROPE ~ GetName[s];
name ← ParseSteppyName[raw];
};
GetName:
PROC [s: Source]
RETURNS [name:
ROPE] = {
from: IO.STREAM = s.stream;
[] ← from.SkipWhitespace[];
SELECT from.PeekChar[]
FROM
'" => name ← from.GetRopeLiteral[];
ENDCASE => name ← from.GetTokenRope[TokenBreak].token;
};
TokenBreak:
PROC [char:
CHAR]
RETURNS [cc:
IO.CharClass] =
{cc ←
SELECT char
FROM
'\n => break,
IN [0C .. ' ] => sepr,
ENDCASE => other};
EndLine:
PROC [from:
IO.
STREAM, buffer:
REFTEXT] = {
IF NOT from.EndOf[] THEN [] ← from.GetLine[buffer];
};
ReadTech:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
techname: ROPE ← GetName[s];
ct.otherPublic ← Assert1[$tech, techname, ct.otherPublic];
EndLine[from, cr.dr.buffer];
};
ReadTimestamp:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
unixTime: INT ← from.GetInt[];
time: BasicTime.GMT ← BasicTime.Update[unixOrigin, unixTime];
ct.otherPublic ← Assert[$Source, LIST[cr.name.Cat[".mag"], IO.PutFR["%g", IO.time[time]]], ct.otherPublic];
EndLine[from, cr.dr.buffer];
};
unixOrigin: BasicTime.
GMT ← BasicTime.Pack[[
year: 1970,
month: January,
day: 1,
hour: 0,
minute: 0,
second: 0,
zone: 0--GMT, I hope--,
dst: no]];
ReadVersion:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
version: ROPE ← GetName[s];
deriver: ROPE = "UCB's Magic .extractor";
ct.otherPublic ← Assert[$DerivingProgram, LIST[deriver, version], ct.otherPublic];
EndLine[from, cr.dr.buffer];
};
ReadScale:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
rscale: INT ← from.GetInt[];
cscale: INT ← from.GetInt[];
lscale: INT ← from.GetInt[];
meters: ROPE = "meters";
IF cr.scalingDefined THEN Warn[s, "More than one scale statment"];
cr.scalingDefined ← TRUE;
cr.rScale ← rscale * cr.rScale;
cr.cScale ← cscale * cr.cScale;
cr.lUnits ← lscale * cr.lUnits;
ct.otherPublic ← AssertFn[$scale, LIST[NEW[REAL𡤌r.lUnits], meters], ct.otherPublic];
EndLine[from, cr.dr.buffer];
};
ReadResistClasses:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
n: INT ← 0;
IF cr.resistClasses # undefinedINT THEN Warn[s, "More than one resistclasses statment"];
DO
token: ROPE = from.GetTokenRope[TokenBreak].token;
IF token.Equal["\n"] THEN EXIT;
n ← n + 1;
ENDLOOP;
cr.resistClasses ← n;
};
keepCruft: BOOL ← FALSE;
ReadNode:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
fullName: SteppyName ~ GetSteppyName[s];
nodeName: NameStep ~ IF fullName.rest=NIL THEN fullName.first ELSE ERROR;
R: INT = from.GetInt[];
C: INT = from.GetInt[];
x: INT = from.GetInt[];
y: INT = from.GetInt[];
ok: BOOL = SkipNTokens[from, cr.resistClasses*2, cr.dr.buffer];
attrs: Assertions = ReadAttrs[s];
nv: Wire ← NARROW[LookupPart[ct, nodeName]];
IF nv =
NIL
THEN {
nv ← CreateWire[
containingCT: ct,
names: CreateSteppyNames[LIST[fullName]]
];
}
IF keepCruft
THEN nv.other ←
Assert1[$R, NEW[REAL ← R*cr.rScale],
Assert1[$C, NEW[REAL ← C*cr.cScale],
Assert[$locHint, LIST[NEW[INT←x], NEW[INT←y], $UnspecifiedLayer],
Asserting.Union[attrs, nv.other, TRUE]]]];
EndLine[from, cr.dr.buffer];
};
ReadAttrs:
PROC [s: Source, zeroNIL:
BOOL ←
FALSE]
RETURNS [allTogetherNow: Assertions] = {
from: IO.STREAM = s.stream;
toke: ROPE ← NIL;
allTogetherNow ← NIL;
IF zeroNIL
THEN {
[] ← from.SkipWhitespace[];
IF from.PeekChar[] = '0
THEN {
IF from.GetChar[] # '0 THEN ERROR;
RETURN};
};
{
DO
attr: ROPE ← NIL;
toke ← from.GetTokenRope[AttrBreak !IO.EndOfStream => EXIT].token;
IF toke.Equal[","] THEN {Warn[s, "Extra comma"]; LOOP};
IF NOT toke.Equal["\""] THEN GOTO Return;
from.Backup['"];
attr ← from.GetRopeLiteral[ !IO.Error, IO.EndOfStream => {Warn[s, "not a rope literal"]; CONTINUE}];
IF attr # NIL THEN allTogetherNow ← Assert1[$attr, attr, allTogetherNow];
toke ← from.GetTokenRope[AttrBreak !IO.EndOfStream => EXIT].token;
IF NOT toke.Equal[","] THEN GOTO Return;
ENDLOOP;
EXITS
Return => {
FOR i:
INT
DECREASING
IN [0 .. toke.Length[])
DO
s.stream.Backup[toke.Fetch[i]];
ENDLOOP;
};
}};
AttrBreak:
PROC [char:
CHAR]
RETURNS [cc:
IO.CharClass] =
{cc ← SELECT char FROM ',, '\n, '" => break, ENDCASE => sepr};
ReadEquiv:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
name1: SteppyName = GetSteppyName[s];
name2: SteppyName = GetSteppyName[s];
v: Vertex ← LookupPart[ct, name1.first];
otherName: SteppyName ← name2;
IF name1.rest#NIL OR name2.rest#NIL THEN ERROR;
IF v=NIL THEN {v ← LookupPart[ct, name2.first]; otherName ← name1};
IF v=NIL THEN ERROR;
KnowVertexName[v, otherName];
EndLine[from, cr.dr.buffer];
};
ReadFet:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
type: ROPE ← GetName[s];
xl: INT ← from.GetInt[];
yl: INT ← from.GetInt[];
xh: INT ← from.GetInt[];
yh: INT ← from.GetInt[];
area: INT ← from.GetInt[];
perim: INT ← from.GetInt[];
sub: SteppyName ← GetSteppyName[s];
GATE: FetTerminal ← GetFetTerminal[s];
T1: FetTerminal ← GetFetTerminal[s];
T2: FetTerminal ← GetFetTerminal[s];
sct: CellType;
tv: CellInstance;
DoTerm:
PROC [portIndex:
INT, ft: FetTerminal] = {
nv: Wire = GetNet[s, ct, ft.name];
Connect[tv, nv, portIndex];
};
sct ← GetFetType[cr.dr, type, [xl, yl, xh, yh], area, perim, T1.length+T2.length];
tv ← Instantiate[sct, ct, CreateSteppyNames[LIST[LIST[IO.PutFR["Q%g#", IO.int[cr.fetCount ← cr.fetCount + 1]]]]]];
DoTerm[0, GATE];
DoTerm[1, T1];
DoTerm[2, T2];
EndLine[from, cr.dr.buffer];
};
Connect:
PROC [ci: CellInstance, wire: Wire, portIndex:
INT] = {
[] ← AddEdge[vs: [cellward: ci, wireward: wire], port: ci.type.port.SubPort[portIndex]];
};
GetFetTerminal:
PROC [s: Source]
RETURNS [ft: FetTerminal] = {
from: IO.STREAM = s.stream;
ft.name ← GetSteppyName[s];
ft.length ← from.GetInt[];
ft.attrs ← ReadAttrs[s, TRUE];
};
GetFetType:
PROC [dr: DesignReading, className:
ROPE, innerGate: IntBox, area, perim, sumChannelLengths:
INT]
RETURNS [ct: CellType] = {
design: Design = dr.design;
ft: FetType = NEW [FetTypeRep ← [className, area, perim, sumChannelLengths]];
rft: FetType;
rft ← NARROW[dr.fetTypes.Fetch[ft].val];
IF rft =
NIL
THEN {
cellTypeName: ROPE = IO.PutFR["%g[%g,%g,%g]", IO.rope[ft.className], IO.int[ft.area], IO.int[ft.perim], IO.int[ft.twiceLength]];
Set:
PROC [type, mode:
ATOM] = {
ft.ct.otherPublic ← AssertFn1[$MOSFETFlavor, LIST[type, mode], ft.ct.otherPublic];
ft.ct.otherPublic ← AssertFn1[$EquivClass, Rope.Cat["MOSFET", Atom.GetPName[type], Atom.GetPName[mode]], ft.ct.otherPublic];
};
rft ← ft;
ft.ct ← LocalCreateCellType[design, dr, cellTypeName, FALSE, AssertFn1[$MOSFETShape, LIST[NEW[REAL ← ft.twiceLength/2.0], NEW[REAL ← area*2.0/ft.twiceLength]], NIL], NIL];
FetPort[ft.ct.port];
SELECT
TRUE
FROM
className.Equal["nfet"] => Set[$n, $E];
className.Equal["pfet"] => Set[$p, $E];
ENDCASE => ERROR;
IF NOT dr.fetTypes.Insert[ft, ft] THEN ERROR;
};
ct ← rft.ct;
};
FetPort:
PROC [fp: Port] = {
[] ← AddPort[[parent: fp, names: CreateSteppyNames[LIST[LIST[R["gate"]]]]]];
[] ← AddPort[[parent: fp, names: CreateSteppyNames[LIST[LIST[R["ch1"]]]]]];
[] ← AddPort[[parent: fp, names: CreateSteppyNames[LIST[LIST[R["ch2"]]]]]];
};
R: PROC [r: ROPE] RETURNS [r2: ROPE] = INLINE {r2 ← r}--stupid goddam anachronism--;
FetType: TYPE = REF FetTypeRep;
FetTypeRep:
TYPE =
RECORD [
className: ROPE,
area, perim, twiceLength: INT,
ct: CellType ← NIL];
HashFetType:
PROC [ra:
REF
ANY]
RETURNS [hash:
CARDINAL]
--RefTab.HashProc-- = {
ft: FetType = NARROW[ra];
hash ← RopeHash.FromRope[ft.className];
hash ← (hash + 3*ft.area + 11*ft.perim + 101*ft.twiceLength) MOD 65536;
};
CompareFetTypes:
PROC [key1, key2:
REF
ANY]
RETURNS [equal:
BOOL]
--RefTab.EqualProc-- = {
k1: FetType = NARROW[key1];
k2: FetType = NARROW[key2];
equal ← k1.className.Equal[k2.className] AND k1.area = k2.area AND k1.perim = k2.perim AND k1.twiceLength = k2.twiceLength;
};
ReadUse:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
typeName: ROPE = GetName[s];
useId: ROPE = GetName[s];
ok: BOOL = SkipNTokens[from, 6, cr.dr.buffer];
u: Use = ParseUseDef[useId];
type: CellType = EnsureType[cr.dr, typeName, u.as, ct, u.childName];
ci: CellInstance = FullyInstantiate[type, ct, CreateSteppyNames[LIST[LIST[u.childName]]]];
EndLine[from, cr.dr.buffer];
};
ParseUseDef:
PROC [useId:
ROPE]
RETURNS [u: Use] = {
in: IO.STREAM = IO.RIS[useId];
u.childName ← in.GetTokenRope[UseNameBreak].token;
IF in.EndOf[]
THEN {
in.Close[];
RETURN [[u.childName, [scalar[]]]]
}
ELSE {
as: ArraySpec.array ← [array[range: ALL[[0, 0]], sep: [0, 0]]];
Get:
PROC [d: Dim] = {
IF in.GetChar[] # '[ THEN ERROR;
as.range[d].min ← in.GetInt[];
IF in.GetChar[] # ': THEN ERROR;
as.range[d].maxPlusOne ← in.GetInt[]+1;
IF in.GetChar[] # ': THEN ERROR;
as.sep[d] ← in.GetInt[];
IF in.GetChar[] # '] THEN ERROR;
};
Get[Foo];
Get[Bar];
IF NOT in.EndOf[] THEN ERROR;
in.Close[];
RETURN [[u.childName, as]];
};
};
UseNameBreak:
PROC [char:
CHAR]
RETURNS [cc:
IO.CharClass]
--IO.BreakProc-- = {
cc ←
SELECT char
FROM
'[, '], ': => break,
ENDCASE => other;
};
EnsureType:
PROC [dr: DesignReading, typeName:
ROPE, as: ArraySpec, parent: CellType, childName:
ROPE]
RETURNS [ct: CellType] = {
design: Design = dr.design;
WITH as
SELECT
FROM
x: ArraySpec.scalar => {
ct ← NARROW[dr.cellTypesByName.Apply[typeName].DVal];
IF ct = NIL THEN ct ← ReadCellType[design, typeName, dr];
};
x: ArraySpec.array => {
ec: ROPE = typeName.Cat[FmtAS[as]];
cellTypeName: ROPE = IO.PutFR["%g(%g.%g)", IO.rope[ec], IO.rope[CTName[parent]], IO.rope[childName]];
eltType: CellType ← EnsureType[dr, typeName, [scalar[]], NIL, NIL];
size: Size2 = RangeShape[x.range];
ct ← LocalCreateArray[design, dr, cellTypeName, eltType, size, [1, 1], [[1, 1], [1, 1]], AssertFn1[$EquivClass, ec, NIL], AssertFn1[$ArraySpec, NEW [ArraySpec.array ← x], NIL]];
};
ENDCASE => ERROR;
};
EmptyRange2:
PROC [r: Range2]
RETURNS [empty:
BOOL] = {
empty ← r[Foo].maxPlusOne<=r[Foo].min OR r[Bar].maxPlusOne<=r[Bar].min;
};
NameElt:
PROC [i:
INT]
RETURNS [eltName: NameStep] ~
{eltName ← NewInt[i]};
FmtAS:
PROC [as: ArraySpec]
RETURNS [r:
ROPE] = {
r ←
WITH as
SELECT
FROM
scalar => "scalar",
array =>
IO.PutFLR["[%g:%g:%g][%g:%g:%g]",
LIST[
IO.int[range[Foo].min],
IO.int[range[Foo].maxPlusOne-1],
IO.int[sep[Foo]],
IO.int[range[Bar].min],
IO.int[range[Bar].maxPlusOne-1],
IO.int[sep[Bar]]]],
ENDCASE => ERROR;
};
FmtShape:
PROC [shape: Size2]
RETURNS [r:
ROPE] = {
r ← IO.PutFR["[Foo: %g, Bar: %g]", IO.int[shape[Foo]], IO.int[shape[Bar]]];
};
FmtPath:
PROC [path: Path]
RETURNS [r:
ROPE] = {
r ← NIL;
FOR path ← path, path.rest
WHILE path #
NIL
DO
step:
ROPE ←
WITH path.first
SELECT
FROM
x: ROPE => x,
x: REF Range2 => IO.PutFR["[%g:%g,%g:%g]", [integer[x[Foo].min]], [integer[x[Foo].maxPlusOne-1]], [integer[x[Bar].min]], [integer[x[Bar].maxPlusOne-1]]],
ENDCASE => ERROR;
r ← (IF r # NIL THEN r.Concat["/"] ELSE r).Concat[step];
ENDLOOP;
};
ReadMerge:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
IF cr.firstMerge THEN {cr.firstMerge ← FALSE; TryArrayFile[cr]};
{name1: ROPE = GetName[s];
name2: ROPE = GetName[s];
path1: Path = ParsePath[s, ct, name1];
path2: Path = ParsePath[s, ct, name2];
IF PathCompare[path1, cr.dr.mostRecentPathToMerge]#equal
THEN {
DoMerges[s, cr];
cr.dr.toMerge.Insert[path1, path1];
};
cr.dr.toMerge.Insert[path2, path2];
cr.dr.mostRecentPathToMerge ← path2;
EndLine[from, cr.dr.buffer];
}};
DoMerges:
PROC [s: Source, cr: CellReading] = {
from: CellType = cr.ct;
dr: DesignReading = cr.dr;
lastPath: Path ← NIL;
DoAMerge:
PROC [data:
REF
ANY]
RETURNS [stop:
BOOL ←
FALSE]
--RedBlackTree.EachNode-- = {
path: Path = NARROW[data];
IF lastPath # NIL THEN [] ← MergeWork[cr, lastPath, path];
lastPath ← path;
};
dr.toMerge.EnumerateIncreasing[DoAMerge];
dr.toMerge.DestroyTable[];
dr.mostRecentPathToMerge ← NIL;
};
Pathify:
PROC [s: Source, from: CellType, steppy: SteppyName]
RETURNS [p: Path] ~ {
t: Path ← p ← NIL;
Append:
PROC [ra:
REF
ANY] = {
this: Path ← LIST[ra];
IF t = NIL THEN p ← this ELSE t.rest ← this;
t ← this};
WHILE steppy#
NIL
DO
ras: REF ArraySpec.array = NARROW[FnVal[$ArraySpec, from.otherPrivate]];
WITH steppy.first
SELECT
FROM
x:
REF
INT => {
food: BOOL ~ ras.range[Foo].min # ras.range[Foo].maxPlusOne-1;
bard: BOOL ~ ras.range[Bar].min # ras.range[Bar].maxPlusOne-1;
r2: Range2 ← ras.range;
IF food=bard THEN ERROR;
r2[IF food THEN Foo ELSE Bar] ← [min: x^, maxPlusOne: x^+1];
Append[NEW [Range2 ← r2]];
from ← from.asArray.eltType;
steppy ← steppy.rest};
x:
ROPE => {
Append[x];
WITH LookupPart[from, x]
SELECT
FROM
ci: CellInstance => from ← ci.type;
w: Wire => {IF steppy.rest#NIL THEN ERROR; from ← NIL};
ENDCASE => ERROR;
steppy ← steppy.rest};
ENDCASE => ERROR;
ENDLOOP;
RETURN};
ParsePath:
PROC [s: Source, from: CellType, asRope:
ROPE]
RETURNS [p: Path] = {
in: IO.STREAM = IO.RIS[asRope];
t: Path ← p ← NIL;
Append:
PROC [ra:
REF
ANY] = {
this: Path ← LIST[ra];
IF t = NIL THEN p ← this ELSE t.rest ← this;
t ← this};
GetRange:
PROC
RETURNS [x: Range] = {
x.maxPlusOne ← (x.min ← in.GetInt[]) + 1;
SELECT in.PeekChar[]
FROM
': => {
IF in.GetChar[] # ': THEN ERROR;
x.maxPlusOne ← in.GetInt[] + 1;
};
',, '] => NULL;
ENDCASE => ERROR;
};
WHILE
NOT in.EndOf[]
DO
toke: ROPE ← in.GetTokenRope[PathNameBreak].token;
ras: REF ArraySpec.array = NARROW[FnVal[$ArraySpec, from.otherPrivate]];
SELECT
TRUE
FROM
toke.Equal["/"] => LOOP;
toke.Equal["["] => {
food: BOOL = ras.range[Foo].min # ras.range[Foo].maxPlusOne-1;
bard: BOOL = ras.range[Bar].min # ras.range[Bar].maxPlusOne-1;
r2: Range2 ← ras.range;
twoD: BOOL ← FALSE;
IF NOT (food OR bard) THEN ERROR;
IF bard THEN r2[Bar] ← GetRange[] ELSE r2[Foo] ← GetRange[];
toke ← in.GetTokenRope[PathNameBreak].token;
SELECT
TRUE
FROM
toke.Equal["]"] => NULL;
toke.Equal[","] => {
twoD ← TRUE;
r2[Foo] ← GetRange[];
toke ← in.GetTokenRope[PathNameBreak].token;
IF NOT toke.Equal["]"] THEN ERROR;
};
ENDCASE => ERROR;
IF twoD # (food AND bard) THEN ERROR;
Append[NEW [Range2 ← r2]];
from ← from.asArray.eltType;
};
toke.Equal["]"] => ERROR;
toke.Equal[":"] => ERROR;
toke.Equal[","] => ERROR;
ENDCASE => {
Append[toke];
WITH LookupPart[from, toke]
SELECT
FROM
ci: CellInstance => from ← ci.type;
w: Wire => {IF NOT in.EndOf[] THEN ERROR; from ← NIL};
ENDCASE => ERROR;
};
ENDLOOP;
in.Close[];
};
PathNameBreak:
PROC [char:
CHAR]
RETURNS [cc:
IO.CharClass]
--IO.BreakProc-- = {
cc ←
SELECT char
FROM
'[, '], ':, '/, ', => break,
ENDCASE => other;
};
SubType:
PROC [ct: CellType, subscript:
INT]
RETURNS [sct: CellType] = {
ci: CellInstance = NARROW[LookupPart[ct, NameElt[subscript]]];
sct ← ci.type};
MergeWork:
PROC [cr: CellReading, path1, path2: Path]
RETURNS [success:
BOOL] = {
ct: CellType = cr.ct;
IF ct.asArray # NIL THEN ERROR;
IF path1.rest #
NIL
AND path2.rest #
NIL
THEN
WITH path1.first
SELECT
FROM
x:
ROPE =>
WITH path2.first
SELECT
FROM
y:
ROPE =>
IF x.Equal[y]
THEN {
ci: CellInstance = NARROW[LookupPart[ct, x]];
IF ci.type.asArray #
NIL
THEN {
IF ci.type.useCount # 1 THEN ERROR;
success ← ArrayMerge[cr, ci, x, path1.rest, path2.rest, cr.dr.curArray];
IF cr.dr.curArray AND NOT success THEN cr.waitingMerges ← CONS[NEW [PathPairPrivate ← [path1, path2]], cr.waitingMerges];
IF cr.dr.curArray OR success THEN RETURN;
};
};
y: REF Range2 => ERROR;
ENDCASE => ERROR;
x: REF Range2 => ERROR;
ENDCASE => ERROR;
MergeFinal[ct, path1, path2];
success ← TRUE;
};
flg1: BOOL ← TRUE; --do we avoid making some self-connections because of edge conditions?
flg2: BOOL ← FALSE; --do we look only at the critical edge?
ArrayMerge:
PROC [cr: CellReading, arrayInstance: CellInstance, instanceName:
ROPE, path1, path2: Path, may:
BOOL]
RETURNS [merged:
BOOL] = {
act: CellType = arrayInstance.type;
a: Array = act.asArray;
ras: REF ArraySpec.array = NARROW[FnVal[$ArraySpec, act.otherPrivate]];
et: CellType = a.eltType;
rr1: REF Range2 = NARROW[path1.first];
rr2: REF Range2 = NARROW[path2.first];
r1: Range2 = rr1^;
r2: Range2 = rr2^;
size: Size2 = RangeShape[r2];
xlate: Int2 = [-ras.range[Foo].min, -ras.range[Bar].min];
s1: Range2 = Range2Off[r1, xlate];
s2: Range2 = Range2Off[r2, xlate];
mai1: ArrayIndex = Range2Min[r1];
mai2: ArrayIndex = Range2Min[r2];
D: Int2 = Int2Sub[mai2, mai1];
p1: Port = PortGet[et, path1.rest, may];
p2: Port = PortGet[et, path2.rest, may];
IF RangeShape[r1] # size THEN ERROR;
IF p1=NIL OR p2=NIL THEN {IF may THEN ERROR ELSE RETURN [FALSE]};
merged ← TRUE;
SELECT
TRUE
FROM
D = [0, 0] =>
IF
NOT PathEquiv[et, path1.rest, path2.rest]
THEN {
IF a.size[Foo] < 2 AND a.size[Bar] < 2 THEN ERROR nyet--the following won't work because there are no joints--;
merged ← FALSE;
FOR d: Dim
IN Dim
DO
FOR side: End
IN End
DO
lowRange: Range2 ← s1;
tooMuch: BOOL;
SELECT side
FROM
low => lowRange[d].maxPlusOne ← MIN[lowRange[d].maxPlusOne, a.size[d]-1];
high => lowRange[d] ← RangeOffClip[lowRange[d], -1];
ENDCASE => ERROR;
tooMuch ← flg1
AND
(SELECT side
FROM
low => lowRange[d].min = 1 AND (flg2 OR lowRange[d].maxPlusOne = a.size[d]-1),
high => lowRange[d].maxPlusOne = a.size[d]-2 AND (flg2 OR lowRange[d].min = 0),
ENDCASE => ERROR);
IF NOT (tooMuch OR EmptyRange2[lowRange]) THEN merged ← MakeArrayConnection[act, d, lowRange, [side, p1], [side, p2], may] OR merged;
ENDLOOP;
ENDLOOP;
};
ABS[
D[Foo]]=1
AND
ABS[
D[Bar]]=1 => {
merged ← FALSE;
FOR d: Dim
IN Dim
DO
o: Dim = OtherDim[d];
lowRange: Range2 ← s1;
highRange: Range2 ← s2;
lowPort, midPort, highPort, pf, pt: Port;
Do: INT ← D[o];
SELECT
D[d]
FROM
1 => {lowPort ← p1; highPort ← p2};
-1 => {lowPort ← p2; highPort ← p1; lowRange ← s2; highRange ← s1; Do ← -Do};
ENDCASE => ERROR;
midPort ← CrossATie[act, d, lowPort, low];
IF midPort #
NIL
THEN {
lowRange[d] ← RangeOff[lowRange[d], 1];
SELECT
D
o
FROM
1 => {pf ← midPort; pt ← highPort};
-1 => {pf ← highPort; pt ← midPort; lowRange[o] ← RangeOff[lowRange[o], -1]};
ENDCASE => ERROR;
merged ← MakeArrayConnection[act, o, lowRange, [low, pf], [high, pt], may];
IF merged THEN EXIT;
};
midPort ← CrossATie[act, d, highPort, high];
IF midPort #
NIL
THEN {
lowRange ← highRange;
lowRange[d] ← RangeOff[lowRange[d], -1];
SELECT
D
o
FROM
1 => {pf ← lowPort; pt ← midPort; lowRange[o] ← RangeOff[lowRange[o], -1]};
-1 => {pf ← midPort; pt ← lowPort};
ENDCASE => ERROR;
merged ← MakeArrayConnection[act, o, lowRange, [low, pf], [high, pt], may];
IF merged THEN EXIT;
};
ENDLOOP;
};
ABS[
D[Foo]] +
ABS[
D[Bar]] = 1 => {
merged ←
SELECT
TRUE
FROM
D=[-1, 0]=> MakeArrayConnection[act,Foo, s2,[low,p2], [high,p1], may],
D=[ 1, 0]=> MakeArrayConnection[act,Foo, s1,[low,p1], [high,p2], may],
D=[0, -1]=> MakeArrayConnection[act,Bar, s2,[low,p2], [high,p1], may],
D=[0, 1]=> MakeArrayConnection[act,Bar, s1,[low,p1], [high,p2], may],
ENDCASE=> ERROR;
};
may => {
--might as well give up now, it will never get easier--cr.dr.impossibleMerges ← CONS[[arrayInstance, path1, path2], cr.dr.impossibleMerges];
merged ← TRUE;--maybe "merged" isn't exactly the right word for it--
};
ENDCASE => {
IF size # [1, 1] THEN ERROR;
merged ← ArrayEltPortsConnected[a, mai1, mai2, p1, p2];
};
merged ← merged;
};
MergeFinal:
PROC [ct: CellType, path1, path2: Path] = {
w1, w2, nw: Wire;
w1 ← PathGet[ct, path1, TRUE];
w2 ← PathGet[ct, path2, TRUE];
nw ← MergeNets[w1, w2].merged;
RETURN};
VAFetch:
PROC [va: VertexArray, f, b:
NAT]
RETURNS [v: Vertex] = {
v ← va[f*va.shape[Bar]+b];
};
VAStore:
PROC [va: VertexArray, f, b:
NAT, v: Vertex] = {
va[f*va.shape[Bar]+b] ← v;
};
PathGet:
PROC [from: CellType, path: Path, mayAdd:
BOOL]
RETURNS [w: Wire] = {
WITH path.first
SELECT
FROM
r:
ROPE => {
child: Vertex = LookupPart[from, r];
WITH child
SELECT
FROM
x: Wire => w ← x;
ci: CellInstance => {
childPort: Port = PortGet[ci.type, path.rest, mayAdd];
IF childPort #
NIL
THEN {
w ← FindTransitiveConnection[ci, childPort];
IF w=NIL THEN ERROR;
};
};
ENDCASE => ERROR;
};
x: REF Range2 => ERROR;
ENDCASE => ERROR;
};
PortGet:
PROC [from: CellType, path: Path, mayAdd:
BOOL]
RETURNS [port: Port] = {
WITH path.first
SELECT
FROM
x:
REF Range2 => {
ras: REF ArraySpec.array = NARROW[FnVal[$ArraySpec, from.otherPrivate]];
a: Array = from.asArray;
eltPort: Port = PortGet[a.eltType, path.rest, mayAdd];
IF eltPort=
NIL
THEN port ←
NIL
ELSE {
index: ArrayIndex = Int2Sub[Range2Min[x^], Range2Min[ras.range]];
IF NOT Range2IsSingleton[x^] THEN ERROR;
port ← GetArrayPortForPort[from, a, index, eltPort, mayAdd];
};
};
x:
ROPE => {
child: Vertex = LookupPart[from, x];
WITH child
SELECT
FROM
w: Wire =>
IF path.rest #
NIL
THEN
ERROR
ELSE {
port ← PortForWire[from, w, NIL, mayAdd].port;
};
ci: CellInstance =>
IF path.rest =
NIL
THEN
ERROR
ELSE {
childPort: Port = PortGet[ci.type, path.rest, mayAdd];
IF childPort =
NIL
THEN port ←
NIL
ELSE {
w: Wire = FindTransitiveConnection[ci, childPort];
IF w=NIL THEN ERROR;
port ← PortForWire[from, w, NIL, mayAdd].port;
};
};
ENDCASE => ERROR;
};
ENDCASE => ERROR;
port ← port;
};
WithTestRA:
PROC [x:
REF
ANY]
RETURNS [kind:
ROPE] = {
WITH x
SELECT
FROM
ci: CellInstance => RETURN ["CellInstance"];
v: Vertex => RETURN ["Vertex"];
ENDCASE => RETURN ["ENDCASE"];
};
WithTestV:
PROC [x: Vertex]
RETURNS [kind:
ROPE] = {
WITH x
SELECT
FROM
ci: CellInstance => RETURN ["CellInstance"];
v: Vertex => RETURN ["Vertex"];
ENDCASE => RETURN ["ENDCASE"];
};
GetNet:
PROC [s: Source, from: CellType, name: SteppyName]
RETURNS [w: Wire] = {
path: Path ~ Pathify[s, from, name];
w ← PathGet[from, path, TRUE];
};
ReadCap:
PROC [s: Source, reader: Reader, cr: CellReading] = {
ct: CellType = cr.ct;
from: IO.STREAM = s.stream;
name1: ROPE ← GetName[s];
name2: ROPE ← GetName[s];
C: INT ← from.GetInt[];
EndLine[from, cr.dr.buffer];
};
SkipNTokens:
PROC [from:
IO.
STREAM, n:
INT, buffer:
REFTEXT]
RETURNS [ok:
BOOL] = {
WHILE n > 0
DO
token: REFTEXT = from.GetToken[TokenBreak, buffer].token;
IF RefText.Equal[token, "\n"] THEN RETURN [FALSE];
n ← n - 1;
ENDLOOP;
ok ← TRUE;
};
Warn:
PROC [s: Source, msg:
ROPE, v1, v2, v3, v4, v5:
IO.Value ← [null[]]] = {
IF s.name # NIL THEN msg ← IO.PutFR["At %g[%g]: %g", [rope[s.name]], [integer[s.stream.GetIndex[]]], [rope[msg]]];
msg ← IO.PutFR[msg, v1, v2, v3, v4, v5];
Log["%g", LIST[msg]];
};
LocalCreateArray:
PROC [design: Design, dr: DesignReading, cellTypeName:
ROPE, eltType: CellType, size, jointsPeriod: Size2, borders:
ARRAY Dim
OF
ARRAY End
OF
NAT, otherPublic, otherPrivate: Assertions ←
NIL]
RETURNS [ct: CellType] = {
ct ← CreateArray[design, cellTypeName, fromExtClass, eltType, size, jointsPeriod, borders, otherPublic, otherPrivate];
IF NOT dr.cellTypesByName.Store[[cellTypeName, ct]] THEN ERROR;
};
LocalCreateCellType:
PROC [design: Design, dr: DesignReading, cellTypeName:
ROPE, internals:
BOOL, otherPublic, otherPrivate: Assertions ←
NIL]
RETURNS [ct: CellType] = {
ct ← CreateCellType[design, cellTypeName, fromExtClass, internals, otherPublic, otherPrivate];
IF NOT dr.cellTypesByName.Store[[cellTypeName, ct]] THEN ERROR;
};
LookupPart:
PROC [ct: CellType, step: NameStep]
RETURNS [v: Vertex] = {
pbn: VarFunction = Fns.DeRef[FnVal[partsByNameKey, ct.otherPrivate]].AsVar;
v ← NARROW[pbn.Apply[LIST[step]].DVal];
};
CTName:
PROC [cellType: CellType]
RETURNS [name:
ROPE] = {
name ← NARROW[FnVal[nameReln, cellType.otherPublic]];
};
PathEquiv:
PROC [from: CellType, path1, path2: Path]
RETURNS [equiv:
BOOL] = {
Work:
PROC [from: CellType, path1, path2: Path]
RETURNS [equiv:
BOOL, p1, p2: Port] = {
WITH path1.first
SELECT
FROM
r1:
ROPE =>
WITH path2.first
SELECT
FROM
r2:
ROPE => {
v1: Vertex = LookupPart[from, r1];
v2: Vertex = LookupPart[from, r2];
IF ISTYPE[v1, Wire] # (path1.rest=NIL) OR ISTYPE[v2, Wire] # (path2.rest=NIL) THEN ERROR;
IF path1.rest=
NIL
OR path2.rest=
NIL
THEN {
w1: Wire =
WITH v1
SELECT
FROM
w: Wire => w,
ci: CellInstance => PathGet[from, path1, FALSE],
ENDCASE => ERROR;
w2: Wire =
WITH v2
SELECT
FROM
w: Wire => w,
ci: CellInstance => PathGet[from, path2, FALSE],
ENDCASE => ERROR;
p1 ← PortForWire[from, w1, NIL, FALSE].port;
p2 ← PortForWire[from, w2, NIL, FALSE].port;
equiv ← w1=w2;
}
ELSE {
ci1: CellInstance = NARROW[v1];
ci2: CellInstance = NARROW[v2];
w1, w2: Wire;
IF ci1=ci2
THEN {
[equiv, p1, p2] ← Work[ci1.type, path1.rest, path2.rest];
IF equiv OR p1=NIL OR p2=NIL THEN RETURN;
w1 ← NARROW[FindTransitiveConnection[ci1, p1]];
w2 ← NARROW[FindTransitiveConnection[ci2, p2]];
IF w1=NIL OR w2=NIL THEN ERROR;
}
ELSE {
w1 ← PathGet[from, path1, FALSE];
w2 ← PathGet[from, path2, FALSE];
};
p1 ← PortForWire[from, w1, NIL, FALSE].port;
p2 ← PortForWire[from, w2, NIL, FALSE].port;
equiv ← w1=w2;
};
};
x2: REF Range2 => RETURN [FALSE, NIL, NIL];
ENDCASE => ERROR;
s1:
REF Range2 =>
WITH path2.first
SELECT
FROM
r2: ROPE => RETURN [FALSE, NIL, NIL];
s2:
REF Range2 => {
a: Array = from.asArray;
IF RangeShape[s1^] # [1, 1] OR RangeShape[s2^] # [1, 1] THEN RETURN [s1^ = s2^, NIL, NIL];
{ep1: Port = PortGet[a.eltType, path1.rest, FALSE];
ep2: Port = PortGet[a.eltType, path1.rest, FALSE];
D: Int2 = Int2Sub[Range2Min[s2^], Range2Min[s1^]];
Try:
PROC [d: Dim, lowIndex: ArrayIndex, rp1, rp2: SidedPort]
RETURNS [connected:
BOOL] = {
equiv ← connected ← ArrayEltPortsConnectedByJoint[a, d, lowIndex, rp1, rp2].really};
p1 ← GetArrayPortForPort[from, a, Range2Min[s1^], ep1, FALSE];
p2 ← GetArrayPortForPort[from, a, Range2Min[s2^], ep2, FALSE];
SELECT
TRUE
FROM
D = [0, 0] => {
FOR d: Dim
IN Dim
DO
FOR side: End
IN End
DO
lowIndex: ArrayIndex ← Range2Min[s1^];
IF side = high THEN lowIndex[d] ← lowIndex[d] - 1;
IF Try[d, lowIndex, [side, ep1], [side, ep2]] THEN RETURN;
ENDLOOP;
ENDLOOP;
};
ABS[
D[Foo]] +
ABS[
D[Bar]] = 1 => {
d: Dim = IF ABS[D[Foo]] = 1 THEN Foo ELSE Bar;
lowPort, highPort: Port;
lowS: REF Range2;
SELECT
D[d]
FROM
1 => {lowS ← s1; lowPort ← ep1; highPort ← ep2};
-1 => {lowS ← s2; lowPort ← ep2; highPort ← ep1};
ENDCASE => ERROR;
[] ← Try[d, Range2Min[lowS^], [low, lowPort], [high, highPort]];
};
ENDCASE => ERROR nyet;
}};
ENDCASE => ERROR;
ENDCASE => ERROR;
};
IF path1 = NIL OR path2 = NIL THEN ERROR;
RETURN [Work[from, path1, path2].equiv];
};
Id:
PROC [data:
REF
ANY]
RETURNS [ans:
REF
ANY] = {
ans ← data};
ComparePaths:
PROC [k, data:
REF
ANY]
RETURNS [c: Basics.Comparison] = {
k1: Path = NARROW[k];
k2: Path = NARROW[data];
c ← PathCompare[k1, k2]};
PathCompare:
PROC [path1, path2: Path]
RETURNS [c: Basics.Comparison] = {
DO
IF path1 = path2 THEN RETURN [equal];
IF path1 = NIL THEN RETURN [less];
IF path2 = NIL THEN RETURN [greater];
WITH path1.first
SELECT
FROM
r1:
ROPE =>
WITH path2.first
SELECT
FROM
r2: ROPE => c ← r1.Compare[r2];
x2: REF Range2 => c ← less;
ENDCASE => ERROR;
s1:
REF Range2 =>
WITH path2.first
SELECT
FROM
r2: ROPE => c ← greater;
s2:
REF Range2 =>
IF (c ← IntCompare[s1[Foo].min, s2[Foo].min]) = equal THEN
IF (c ← IntCompare[s1[Foo].maxPlusOne, s2[Foo].maxPlusOne]) = equal THEN
IF (c ← IntCompare[s1[Bar].min, s2[Bar].min]) = equal THEN
c ← IntCompare[s1[Bar].maxPlusOne, s2[Bar].maxPlusOne];
ENDCASE => ERROR;
ENDCASE => ERROR;
IF c # equal THEN RETURN;
path1 ← path1.rest;
path2 ← path2.rest;
ENDLOOP;
};
PathPairEqual:
PROC [k1, k2:
REF
ANY]
RETURNS [equal:
BOOL] = {
pp1: PathPair = NARROW[k1];
pp2: PathPair = NARROW[k2];
equal ← (PathCompare[pp1.p1, pp2.p1] = equal AND PathCompare[pp1.p2, pp2.p2] = equal) OR (PathCompare[pp1.p1, pp2.p2] = equal AND PathCompare[pp1.p2, pp2.p1] = equal);
};
HashPathPair:
PROC [key:
REF
ANY]
RETURNS [hash:
CARDINAL] = {
pp: PathPair = NARROW[key];
hash ← HashPath[pp.p1] + HashPath[pp.p2];
};
HashPath:
PROC [path: Path]
RETURNS [hash:
CARDINAL] = {
hash ← 0;
FOR path ← path, path.rest
WHILE path #
NIL
DO
WITH path.first
SELECT
FROM
r: ROPE => hash ← hash + RopeHash.FromRope[r];
x: REF Range2 => hash ← hash + Sets.HashIntI[x[Foo].min] + Sets.HashIntI[x[Foo].maxPlusOne] + Sets.HashIntI[x[Bar].min] + Sets.HashIntI[x[Bar].maxPlusOne];
ENDCASE => ERROR;
ENDLOOP;
};
IntCompare:
PROC [i1, i2:
INT]
RETURNS [c: Basics.Comparison] = {
c ←
SELECT i1 - i2
FROM
>0 => greater,
=0 => equal,
<0 => less,
ENDCASE => ERROR;
};
Lg:
PROC [i:
INT]
RETURNS [lg:
CARDINAL] = {
IF i < 0 THEN ERROR;
IF i = 0 THEN RETURN [0];
lg ← 1 + (
SELECT i
FROM
<=00000001H => 00,
<=00000002H => 01,
<=00000004H => 02,
<=00000008H => 03,
<=00000010H => 04,
<=00000020H => 05,
<=00000040H => 06,
<=00000080H => 07,
<=00000100H => 08,
<=00000200H => 09,
<=00000400H => 10,
<=00000800H => 11,
<=00001000H => 12,
<=00002000H => 13,
<=00004000H => 14,
<=00008000H => 15,
<=00010000H => 16,
<=00020000H => 17,
<=00040000H => 18,
<=00080000H => 19,
<=00100000H => 20,
<=00200000H => 21,
<=00400000H => 22,
<=00800000H => 23,
<=01000000H => 24,
<=02000000H => 25,
<=04000000H => 26,
<=08000000H => 27,
<=10000000H => 28,
<=20000000H => 29,
<=40000000H => 30,
ENDCASE => 31);
};
Register:
PROC [keyword:
ROPE, read:
PROC [s: Source, reader: Reader, cr: CellReading], data:
REF
ANY ←
NIL] = {
r: Reader ← NEW [ReaderRep ← [keyword, read, data]];
IF NOT readers.Store[[keyword, r]] THEN ERROR;
};
Start:
PROC = {
Register["tech", ReadTech];
Register["timestamp", ReadTimestamp];
Register["version", ReadVersion];
Register["scale", ReadScale];
Register["resistclasses", ReadResistClasses];
Register["node", ReadNode];
Register["equiv", ReadEquiv];
Register["fet", ReadFet];
Register["use", ReadUse];
Register["merge", ReadMerge];
Register["adjust", ReadAdjust];
Register["cap", ReadCap];
};
Start[];
END.