LichenNormal.Mesa
Last Edited by: Spreitzer, July 15, 1985 7:38:18 pm PDT
DIRECTORY Basics, DFUtilities, FS, IO, LichenDataStructure, LichenOps, List, RedBlackTree, RedBlackTreeExtras, RefTab, Rope, ViewerIO;
LichenNormal: CEDAR PROGRAM
IMPORTS IO, LichenDataStructure, LichenOps, RedBlackTree, RedBlackTreeExtras, RefTab, Rope
EXPORTS LichenOps =
BEGIN OPEN LichenDataStructure, LichenOps;
When in normal form:
ANNetUsed: Each net is attached to at least one thing.
n  ci, p ci.p é n
(note that we allow a ci to be the outside world)
ANPortUsedI: Each net attached to a port is also attached to something else.
n, p [n é p Ò  ci, p' ` p n é ci.p']
ANPortsMergedI: Each net connected to at most one port.
n ¬  p ` p' n é p & n é p'
Implies nets merged.
The following duals are NOT required to be true:
ANPortUsedO: Each port is used for something interesting at least once.
p  p', ci ` world, ci', n ci.p é n ' ci'.p' é n ' (ci ` ci' ( p ` p')
ANPortsMergedO: Each port distinction is used at least once.
p ` p' of ct  ci ` world, n, n' ci.p é n ' ci.p' é n' ' ¬ n H n'
For a design to be comparable, we must also have:
ACCellTypeEquivd: The structural equivalence class of a cell type is clear.
ct.equivClass # implicitClass COR |ct.names.designed| = 1 OR |ct.names.designed| = 0 CAND (|ct.names.unknown| = 1 OR |ct.names.unknown| = 0 CAND |ct.names.progged| = 1)
ACPortEquivd: The structural equivalence class of a port is clear.
p.equivClass # implicitClass COR |p.names.designed| = 1 OR |p.names.designed| = 0 CAND (|p.names.unknown| = 1 OR |p.names.unknown| = 0 CAND |p.names.progged| = 1)
Broken: ERROR = CODE;
BadData: ERROR = CODE;
NotNormal: PUBLIC ERROR [msg: ROPE] = CODE;
NotComparable: PUBLIC ERROR [msg: ROPE] = CODE;
debugging: BOOLTRUE;
OutersToo: BOOL = FALSE;
CheckDesign: PROC [design: Design, norm: AssertionOp, comparable: MerelyCheckableAssertionOp] = {
PerCellType: PROC [ra: REF ANY] RETURNS [quit: BOOL] = {
ct: CellType ← NARROW[ra];
quit ← FALSE;
CheckType[ct, norm, comparable];
};
SELECT norm FROM
ignore => NULL;
report, check, establish => EnsureAllIn[design];
ENDCASE => ERROR;
RedBlackTreeExtras.StatelessEnumerateIncreasing[design.cellTypesByAddress, PerCellType, GetIDKey];
};
PortData: TYPE = REF PortDataRep;
PortDataRep: TYPE = RECORD [data: SEQUENCE length: NAT OF PortDatum];
PortDatum: TYPE = RECORD [
used, seen, deleted: BOOLFALSE,
assoc: LIST OF NATNIL,
newPortIndex: NAT ← NullPortIndex];
CheckType: PUBLIC PROC [ct: CellType, norm: AssertionOp, comparable: MerelyCheckableAssertionOp, ignoreInstances: BOOLFALSE] = {
lastInstance: Vertex ← NIL;
netCount, cellCount: NAT ← 0;
portData: PortData;
consequences: RefTab.Ref ← SELECT norm FROM
establish => RefTab.Create[],
ignore, report, check => NIL,
ENDCASE => ERROR;
altered: BOOLFALSE;
PerPart: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
a: Alias ← NARROW[ra];
v: Vertex ← NARROW[a.thing];
stop ← FALSE;
IF PickAName[v.names] # a.name THEN RETURN;
IF IsMirror[v] THEN ERROR Broken; --AM1
IF v.parent # ct THEN ERROR Broken;
CheckAllDictness[v.names, ct.parts, v, TRUE];
SELECT v.class FROM
net => {netCount ← netCount + 1; IF CheckNet[v, norm, comparable, consequences] THEN altered ← TRUE};
cell => {cellCount ← cellCount + 1; CheckComponent[v]};
ENDCASE => ERROR;
};
portsDict: SymbolTable ← RedBlackTree.Create[GetIDKey, CompareRopes];
SELECT norm FROM
ignore, report, check => NULL;
establish => IF ignoreInstances THEN ERROR;
ENDCASE => ERROR;
IF ct.privateKnown AND NOT ct.publicKnown THEN ERROR Broken;
CheckAllDictness[ct.names, ct.design.cellTypesByName, ct, TRUE];
EnsureParts[ct];
EnsurePorts[ct];
IF ct.privateKnown AND NOT ct.publicKnown THEN ERROR Broken;
SELECT comparable FROM
ignore => NULL;
report, check => CheckComparable[ct.names, ct.equivClass, comparable, GlobalCellTypeName[ct], "ACCellTypeEquivd"];
ENDCASE => ERROR;
FOR pi: PortIndex IN [0 .. ct.ports.length) DO
CheckNames: PROC [nameList: RopeList] = {
FOR nameList ← nameList, nameList.rest WHILE nameList # NIL DO
portsDict.Insert[nameList.first, nameList.first !RedBlackTree.DuplicateKey => ERROR BadData];
ENDLOOP};
IF ExpansionKnown[ct] THEN SELECT GetInternalStyle[ct] FROM
graph => {
theNet: Vertex ← NARROW[Lookup[ct.parts, ct.ports[pi].netNames.first]];
IF theNet = NIL THEN ERROR BadData;
FOR nnl: RopeList ← ct.ports[pi].netNames.rest, nnl.rest WHILE nnl # NIL DO
IF Lookup[ct.parts, nnl.first] # theNet THEN ERROR BadData;
ENDLOOP;
};
array => NULL;
ENDCASE => ERROR;
SELECT comparable FROM
ignore => NULL;
report, check => CheckComparable[ct.ports[pi].names, ct.ports[pi].equivClass, comparable, GlobalPortName[ct, pi], "ACPortEquivd"];
ENDCASE => ERROR;
CheckNames[ct.ports[pi].names.designed];
CheckNames[ct.ports[pi].names.unknown];
CheckNames[ct.ports[pi].names.progged];
ENDLOOP;
portsDict.DestroyTable[];
IF NOT ignoreInstances THEN {
SELECT norm FROM
ignore => NULL;
report, check, establish => {
ct.wasntNormalized ← FALSE;
portData ← NEW [PortDataRep[ct.ports.length]];
FOR i: NAT IN [0 .. portData.length) DO portData[i] ← [] ENDLOOP;
};
ENDCASE => ERROR;
FOR v: Vertex ← ct.firstInstance, v.nextInstance WHILE v # NIL DO
IF v.prevInstance # lastInstance THEN ERROR Broken;
IF v.type # ct THEN ERROR Broken;
IF IsMirror[v] THEN ERROR Broken; --AM2
CheckAllDictness[v.names, v.parent.parts, v, TRUE];
CheckInstance[v: v, portData: portData, norm: norm];
lastInstance ← v;
ENDLOOP;
IF ct.lastInstance # lastInstance THEN ERROR Broken;
SELECT norm FROM
ignore => NULL;
report, check => IF OutersToo THEN {
FOR pi: NAT IN [0 .. portData.length) DO
IF NOT portData[pi].used THEN Fail[normal, norm, "%g fails ANPortUsedO", IO.rope[GlobalPortName[ct, pi]]];
IF portData[pi].assoc # NIL THEN Fail[normal, norm, "%g fails ANPortsMergedO", IO.rope[GlobalPortName[ct, pi]]];
Note that we depend on ANPortsMergedO being true for some other cellTypes, and ANPortsMergedI being true for this and some other cellTypes, in making this test.
ENDLOOP;
};
establish => IF OutersToo THEN {
pi: NAT ← 0;
WHILE pi < portData.length DO
IF (NOT portData[pi].used) AND (portData[pi].assoc # NIL) THEN ERROR;
IF NOT portData[pi].used THEN {
IF debugging THEN Log["Deleting %g\n", IO.rope[GlobalPortName[ct, pi]]];
portData ← DeletePort[ct, pi, portData, consequences];
ct.wasntNormalized ← TRUE;
CheckType[ct, ignore, comparable]}
ELSE IF portData[pi].assoc # NIL THEN {
IF debugging THEN {
Log["On Type %g, merging ports", IO.rope[GlobalCellTypeName[ct]]];
FOR pil: LIST OF NAT ← portData[pi].assoc, pil.rest WHILE pil # NIL DO
Log[" %g", IO.rope[PickAName[ct.ports[pil.first].names]]];
ENDLOOP;
Log[".\n"]};
[portData, pi] ← MergePorts[ct, CONS[pi, portData[pi].assoc], portData, pi, consequences];
ct.wasntNormalized ← TRUE;
CheckType[ct, ignore, comparable]}
ELSE pi ← pi + 1;
ENDLOOP;
};
ENDCASE => ERROR;
};
IF ExpansionKnown[ct] THEN SELECT GetInternalStyle[ct] FROM
graph => {
IF ct.mirror = NIL THEN ERROR Broken;
IF ct.mirror.type # ct THEN ERROR Broken;
IF ct.mirror.parent # ct THEN ERROR Broken;
CheckAllDictness[ct.mirror.names, ct.parts, ct.mirror, FALSE];
RedBlackTreeExtras.StatelessEnumerateIncreasing[ct.parts, PerPart, GetAliasKey];
IF (NOT altered) AND (netCount # ct.netCount OR cellCount # ct.cellCount) THEN ERROR Broken;
CheckComponent[ct.mirror];
};
array => CheckArray[ct];
ENDCASE => ERROR;
IF NOT ignoreInstances THEN SELECT norm FROM
ignore => NULL;
report, check => IF ct.wasntNormalized THEN ERROR Broken;
establish => {
SELECT consequences.Fetch[ct].val FROM
$T => {
[] ← consequences.Delete[ct];
CheckType[ct, establish, comparable];
};
ENDCASE => IF ct.wasntNormalized THEN CheckType[ct, check, comparable];
[] ← consequences.Pairs[FixAffectedType];
};
ENDCASE => ERROR;
};
CheckArray: PROC [ct: CellType] = {
a: Array ← ct.asArray;
IF a.portConnections.arrayPorts # ct.ports.length THEN ERROR Broken;
IF a.eltPorts # a.eltType.ports.length THEN ERROR Broken;
FOR d: Dim IN Dim DO FOR perp: EO IN EO DO FOR parl: EO IN EO DO
j: Joint ← a.joints[d][perp][parl];
IF j = NIL THEN LOOP;
FOR pi: PortIndex IN [0 .. a.eltPorts) DO
lpi: PortIndex ← j[pi].low;
hpi: PortIndex ← j[pi].high;
IF lpi#NullPortIndex AND j[lpi].high # pi THEN ERROR;
IF hpi#NullPortIndex AND j[hpi].low # pi THEN ERROR;
ENDLOOP;
ENDLOOP ENDLOOP ENDLOOP;
FOR api: PortIndex IN [0 .. a.portConnections.arrayPorts) DO
FOR e: End IN End DO FOR d: Dim IN Dim DO
od: Dim ← OtherDim[d];
r: Range ← [0, 0];
FOR asl: ArraySocketList ← a.portConnections[api][e][d].sockets, asl.rest WHILE asl # NIL DO
ei: INTSELECT e FROM low => a.shape[d].min, high => (a.shape[d].maxPlusOne-1), ENDCASE => ERROR;
IF asl.first.ai[d] # ei THEN ERROR Broken;
IF r = [0, 0]
THEN r ← [asl.first.ai[od], asl.first.ai[od]+1]
ELSE {
IF r.maxPlusOne # asl.first.ai[od] THEN ERROR Broken;
r.maxPlusOne ← asl.first.ai[od] + 1;
};
IF GetArrayPort[a, asl.first.ai, asl.first.pi] # api THEN ERROR Broken;
ENDLOOP;
IF a.portConnections[api][e][d].range # r THEN ERROR Broken;
ENDLOOP ENDLOOP;
ENDLOOP;
};
CheckComparable: PROC [names: Names, equivClass: EquivClass, how: FailableAssertionOp, who, what: ROPE] = {
IF
equivClass = implicitClass AND
NOT (
IF names.designed # NIL THEN names.designed.rest = NIL ELSE
IF names.unknown # NIL THEN names.unknown.rest = NIL ELSE
IF names.progged # NIL THEN names.progged.rest = NIL ELSE
FALSE)
THEN Fail[comparable, how, "%g fails %g", IO.rope[who], IO.rope[what]];
};
CheckAllDictness: PROC [names: Names, dict: SymbolTable, obj: REF ANY, shouldFind: BOOL] = {
Work: PROC [rl: RopeList] = {
FOR rl ← rl, rl.rest WHILE rl # NIL DO
IF shouldFind # (AntiAlias[Lookup[dict, rl.first]] = obj) THEN ERROR Broken;
ENDLOOP;
rl ← rl};
Work[names.designed];
Work[names.unknown];
Work[names.progged]};
CheckInstance: PROC [v: Vertex, portData: PortData, norm: AssertionOp] = {
portIndex: NAT ← 0;
SELECT norm FROM
ignore => {
FOR e: Edge ← v.firstEdge, e.sides[cell].next WHILE e # NIL DO
net: Vertex ← e.sides[net].v;
IF e.sides[cell].v # v THEN ERROR Broken;
IF e.portIndex # portIndex THEN ERROR Broken;
portIndex ← portIndex + 1;
ENDLOOP;
IF portIndex # v.type.ports.length THEN ERROR Broken;
};
report, check, establish => {
FOR e: Edge ← v.firstEdge, e.sides[cell].next WHILE e # NIL DO
net: Vertex ← e.sides[net].v;
IF e.sides[cell].v # v THEN ERROR Broken;
IF e.portIndex # portIndex THEN ERROR Broken;
FOR pi: NAT IN [0 .. portData.length) DO portData[pi].seen ← FALSE ENDLOOP;
FOR f: Edge ← net.firstEdge, f.sides[net].next WHILE f # NIL DO
u: Vertex ← f.sides[cell].v;
IF f.sides[net].v # net THEN ERROR Broken;
IF f.sides[cell].v = v THEN portData[f.portIndex].seen ← TRUE;
IF f.sides[cell].v # v OR f.portIndex # portIndex THEN portData[portIndex].used ← TRUE;
ENDLOOP;
IF NOT portData[portIndex].seen THEN ERROR Broken;
IF v = v.type.firstInstance THEN {
portData[portIndex].assoc ← NIL;
FOR pi: NAT IN [0 .. portData.length) DO
IF portData[pi].seen AND pi # portIndex THEN portData[portIndex].assoc ← CONS[pi, portData[portIndex].assoc];
ENDLOOP;
}
ELSE {
lastAssoc: LIST OF NATNIL;
FOR la: LIST OF NAT ← portData[portIndex].assoc, la.rest WHILE la # NIL DO
IF NOT portData[la.first].seen THEN {
IF lastAssoc = NIL THEN portData[portIndex].assoc ← la.rest ELSE lastAssoc.rest ← la.rest
}
ELSE lastAssoc ← la;
ENDLOOP;
};
portIndex ← portIndex + 1;
ENDLOOP;
IF portIndex # v.type.ports.length THEN ERROR Broken;
};
ENDCASE => ERROR;
};
CheckNet: PROC [v: Vertex, norm: AssertionOp, comparable: MerelyCheckableAssertionOp, noteIn: RefTab.Ref] RETURNS [altered: BOOL] = {
lastEdge: Edge ← NIL;
portCount, otherCount: NAT ← 0;
portIndices: LIST OF NATNIL;
altered ← FALSE;
FOR e: Edge ← v.firstEdge, e.sides[net].next WHILE e # NIL DO
w: Vertex ← e.sides[cell].v;
IF e.sides[net].v # v THEN ERROR Broken;
IF e.sides[net].prev # lastEdge THEN ERROR Broken;
IF IsMirror[w] THEN {
portCount ← portCount + 1;
portIndices ← CONS[e.portIndex, portIndices];
}
ELSE otherCount ← otherCount + 1;
lastEdge ← e;
ENDLOOP;
IF v.lastEdge # lastEdge THEN ERROR Broken;
SELECT norm FROM
ignore => NULL;
report, check => {
IF portCount + otherCount = 0 THEN Fail[normal, norm, "%g fails ANNetUsed", IO.rope[GlobalVertexName[v]]];
IF portCount = 1 AND otherCount = 0 THEN Fail[normal, norm, "%g fails ANPortUsedI", IO.rope[GlobalVertexName[v]]];
IF portCount > 1 THEN Fail[normal, norm, "%g fails ANPortsMergedI", IO.rope[GlobalVertexName[v]]];
};
establish => {
IF portCount + otherCount = 0 THEN {
IF debugging THEN Log["Deleting net %g\n", IO.rope[GlobalVertexName[v]]];
altered ← TRUE;
[] ← noteIn.Store[v.parent, $T];
DeleteVertex[v];
v.parent.wasntNormalized ← TRUE;
CheckType[v.parent, ignore, comparable]};
IF portCount = 1 AND otherCount = 0 THEN {
IF debugging THEN Log["Deleting port %g\n", IO.rope[GlobalPortName[v.parent, portIndices.first]]];
altered ← TRUE;
[] ← noteIn.Store[v.parent, $T];
[] ← DeletePort[v.parent, portIndices.first, NIL, noteIn];
v.parent.wasntNormalized ← TRUE;
CheckType[v.parent, ignore, comparable]};
IF portCount > 1 THEN {
IF debugging THEN {
Log["On Type %g, merging ports", IO.rope[GlobalCellTypeName[v.parent]]];
FOR pil: LIST OF NAT ← portIndices, pil.rest WHILE pil # NIL DO
Log[" %g", IO.rope[PickAName[v.parent.ports[pil.first].names]]];
ENDLOOP;
Log[".\n"]};
altered ← TRUE;
[] ← noteIn.Store[v.parent, $T];
[] ← MergePorts[v.parent, portIndices, NIL, NullPortIndex, noteIn];
v.parent.wasntNormalized ← TRUE;
CheckType[v.parent, ignore, comparable]};
};
ENDCASE => ERROR;
};
CheckComponent: PROC [v: Vertex] = {
portIndex: NAT ← 0;
lastEdge: Edge ← NIL;
EnsurePorts[v.type];
FOR e: Edge ← v.firstEdge, e.sides[cell].next WHILE e # NIL DO
IF e.sides[cell].v # v THEN ERROR Broken;
IF e.sides[cell].prev # lastEdge THEN ERROR Broken;
IF e.portIndex # portIndex THEN ERROR Broken;
portIndex ← portIndex + 1;
lastEdge ← e;
ENDLOOP;
IF v.lastEdge # lastEdge THEN ERROR Broken;
IF portIndex # v.type.ports.length THEN ERROR Broken;
};
MergeNets: PUBLIC PROC [net1, net2: Vertex] RETURNS [merged, doomed: Vertex] =
BEGIN
Rename: PROC [name: ROPE, class: ATOM--UNION[$designed, $unknown, $progged]--] = {
a: Alias ← NARROW[net1.parent.parts.Lookup[name]];
IF a.thing # net2 THEN ERROR;
a.thing ← net1;
};
Relink: PROC [item: REF ANY] RETURNS [stop: BOOL] = {
ec: ExtraConnection ← NARROW[item];
stop ← FALSE;
IF ec.parentNet # net2 THEN ERROR;
IF net2.extraConnections.Delete[ec].data # ec THEN ERROR;
ec.parentNet ← net1;
IF net1.extraConnections = NIL THEN net1.extraConnections ← RedBlackTree.Create[GetIDKey, CompareECSubCellThenChildNet];
net1.extraConnections.Insert[ec, ec];
};
IF net1.parent # net2.parent THEN ERROR;
IF net1.class # net OR net2.class # net THEN ERROR;
IF net1 = net2 THEN RETURN [net1, NIL];
merged ← net1;
doomed ← net2;
EnumerateNames[net2.names, Rename];
net1.names ← MergeNames[net1.names, net2.names];
FOR e: Edge ← net2.firstEdge, e.sides[net].next WHILE e # NIL DO
IF e.sides[net].v # net2 THEN ERROR;
e.sides[net].v ← net1;
ENDLOOP;
IF net2.firstEdge # NIL THEN {
IF net1.lastEdge # NIL THEN net1.lastEdge.sides[net].next ← net2.firstEdge ELSE net1.firstEdge ← net2.firstEdge;
net1.lastEdge ← net2.lastEdge;
net2.firstEdge.sides[net].prev ← net1.lastEdge;
net2.firstEdge ← NIL;
net2.lastEdge ← NIL;
};
IF net2.extraConnections # NIL THEN RedBlackTreeExtras.StatelessEnumerateIncreasing[net2.extraConnections, Relink, GetIDKey];
END;
MergePorts: PROC [ct: CellType, portIndices: LIST OF NAT, oldPortData: PortData, oldPortIndex: NAT, noteIn: RefTab.Ref] RETURNS [newPortData: PortData, newPortIndex: NAT] = {
Length: PROC [ln: LIST OF NAT] RETURNS [len: NAT ← 0] =
{FOR ln ← ln, ln.rest WHILE ln # NIL DO len ← len+1 ENDLOOP};
designed, unked, progged, recent, old: LIST OF NATNIL;
oldest: INTEGER ← 0;
surviver: NAT ← NullPortIndex;
siNet: Vertex;
numIndices: NAT ← Length[portIndices];
updatePortData: BOOL ← oldPortData # NIL;
newPI: NAT ← 0;
oldPorts: PortS ← ct.ports;
newPorts: PortS ← NEW [PortSeq[oldPorts.length - (numIndices-1)]];
IF numIndices < 2 THEN ERROR;
IF numIndices >= 2 AND oldPortData # NIL THEN ERROR--code below might exhibit bugs--;
EnsureAllIn[ct.design];
IF oldPortData = NIL THEN oldPortData ← NEW [PortDataRep[ct.ports.length]];
FOR pi: NAT IN [0 .. ct.ports.length) DO oldPortData[pi].seen ← FALSE ENDLOOP;
FOR pil: LIST OF NAT ← portIndices, pil.rest WHILE pil # NIL DO
SELECT TRUE FROM
ct.ports[pil.first].names.designed # NIL => designed ← CONS[pil.first, designed];
ct.ports[pil.first].names.unknown # NIL => unked ← CONS[pil.first, unked];
ct.ports[pil.first].names.progged # NIL => progged ← CONS[pil.first, progged];
ENDCASE => ERROR Broken;
IF oldPortData[pil.first].seen THEN ERROR Broken;
oldPortData[pil.first].seen ← TRUE;
ENDLOOP;
SELECT Length[designed] FROM
>0 => surviver ← designed.first;
=0 => SELECT Length[unked] FROM
>0 => surviver ← unked.first;
=0 => SELECT Length[progged] FROM
>0 => surviver ← progged.first;
ENDCASE;
ENDCASE;
ENDCASE;
IF surviver = NullPortIndex THEN ERROR Broken;
FOR pi: NAT IN [0 .. ct.ports.length) DO oldPortData[pi].seen ← FALSE ENDLOOP;
FOR pil: LIST OF NAT ← portIndices, pil.rest WHILE pil # NIL DO
IF pil.first # surviver THEN {
oldPortData[pil.first].seen ← TRUE;
ct.ports[surviver].names ← MergeNames[ct.ports[surviver].names, ct.ports[pil.first].names];
ct.ports[surviver].netNames ← MergeRopeLists[ct.ports[surviver].netNames, ct.ports[pil.first].netNames];
ct.ports[surviver].equivClass ← MergeEquivClasses[ct.ports[surviver].equivClass, ct.ports[pil.first].equivClass];
};
ENDLOOP;
FOR oldPI: NAT IN [0 .. oldPorts.length) DO
IF oldPI = surviver OR NOT oldPortData[oldPI].seen THEN {
oldPortData[oldPI].newPortIndex ← newPI;
newPorts[newPI] ← oldPorts[oldPI];
newPI ← newPI + 1}
ELSE oldPortData[oldPI].newPortIndex ← NullPortIndex;
ENDLOOP;
IF newPI # newPorts.length THEN ERROR Broken;
ct.ports ← newPorts;
IF ExpansionKnown[ct] THEN {
pi: PortIndex ← 0;
nextEdge: Edge;
FOR e: Edge ← ct.mirror.firstEdge, e.sides[cell].next WHILE e # NIL DO
IF e.sides[cell].v # ct.mirror THEN ERROR Broken;
IF e.portIndex # pi THEN ERROR Broken;
IF e.portIndex = surviver THEN {siNet ← e.sides[net].v; EXIT};
pi ← pi + 1;
REPEAT FINISHED => ERROR Broken;
ENDLOOP;
pi ← 0;
FOR e: Edge ← ct.mirror.firstEdge, nextEdge WHILE e # NIL DO
iNet: Vertex ← e.sides[net].v;
IF e.sides[cell].v # ct.mirror THEN ERROR Broken;
IF e.portIndex # pi THEN ERROR Broken;
nextEdge ← e.sides[cell].next;
IF oldPortData[e.portIndex].seen AND iNet # siNet
THEN {RemoveEdge[e]; [] ← MergeNets[siNet, iNet]}
ELSE e.portIndex ← oldPortData[e.portIndex].newPortIndex;
pi ← pi + 1;
ENDLOOP;
IF pi # oldPortData.length THEN ERROR Broken;
};
FOR v: Vertex ← ct.firstInstance, v.nextInstance WHILE v # NIL DO
pi: NAT ← 0;
soNet: Vertex;
nextEdge: Edge;
FOR e: Edge ← v.firstEdge, e.sides[cell].next WHILE e # NIL DO
IF e.sides[cell].v # v THEN ERROR Broken;
IF e.portIndex # pi THEN ERROR Broken;
IF e.portIndex = surviver THEN {soNet ← e.sides[net].v; EXIT};
pi ← pi + 1;
REPEAT FINISHED => ERROR Broken;
ENDLOOP;
pi ← 0;
FOR e: Edge ← v.firstEdge, nextEdge WHILE e # NIL DO
oNet: Vertex ← e.sides[net].v;
IF e.sides[cell].v # v THEN ERROR Broken;
IF e.portIndex # pi THEN ERROR Broken;
nextEdge ← e.sides[cell].next;
IF oldPortData[e.portIndex].seen AND oNet # soNet
THEN {RemoveEdge[e]; [] ← MergeNets[soNet, oNet]}
ELSE e.portIndex ← oldPortData[e.portIndex].newPortIndex;
pi ← pi + 1;
ENDLOOP;
[] ← noteIn.Store[v.parent, $T];
ENDLOOP;
IF updatePortData THEN {
newPortData ← NEW [PortDataRep[newPorts.length]];
newPI ← 0;
FOR oldPI: NAT IN [0 .. oldPorts.length) DO
oldAssoc: LIST OF NAT;
IF NOT oldPortData[oldPI].seen THEN {
newPortData[newPI] ← oldPortData[oldPI];
oldAssoc ← oldPortData[oldPI].assoc;
newPortData[newPI].assoc ← NIL;
FOR oldAssoc ← oldAssoc, oldAssoc.rest WHILE oldAssoc # NIL DO
SELECT TRUE FROM
oldAssoc.first = oldPI => ERROR Broken;
oldPortData[oldAssoc.first].newPortIndex = NullPortIndex => NULL;
oldPortData[oldAssoc.first].newPortIndex # NullPortIndex => newPortData[newPI].assoc ← CONS[oldPortData[oldAssoc.first].newPortIndex, newPortData[newPI].assoc];
ENDCASE => ERROR Broken;
ENDLOOP;
};
ENDLOOP;
FOR oldPortIndex ← oldPortIndex, oldPortIndex + 1 WHILE oldPortIndex < oldPorts.length AND oldPortData[oldPortIndex].newPortIndex = NullPortIndex DO NULL ENDLOOP;
newPortIndex ← IF oldPortIndex < oldPorts.length THEN oldPortData[oldPortIndex].newPortIndex ELSE newPorts.length;
};
};
DeletePort: PROC [ct: CellType, portIndex: NAT, oldPortData: PortData, noteIn: RefTab.Ref] RETURNS [newPortData: PortData] = {
oldPorts: PortS ← ct.ports;
newPorts: PortS ← NEW [PortSeq[oldPorts.length-1]];
EnsureAllIn[ct.design];
IF ExpansionKnown[ct] THEN {
pi: NAT ← 0;
nextEdge: Edge;
FOR e: Edge ← ct.mirror.firstEdge, nextEdge WHILE e # NIL DO
IF e.sides[cell].v # ct.mirror THEN ERROR Broken;
IF e.portIndex # pi THEN ERROR Broken;
nextEdge ← e.sides[cell].next;
IF e.portIndex = portIndex THEN RemoveEdge[e] ELSE
IF e.portIndex > portIndex THEN e.portIndex ← e.portIndex - 1;
pi ← pi + 1;
ENDLOOP;
IF pi # oldPorts.length THEN ERROR Broken;
};
FOR pi: NAT IN [0 .. newPorts.length) DO
newPorts[pi] ← oldPorts[IF pi < portIndex THEN pi ELSE (pi + 1)];
ENDLOOP;
ct.ports ← newPorts;
IF oldPortData # NIL THEN {
newPortData ← NEW [PortDataRep[oldPortData.length-1]];
FOR pi: NAT IN [0 .. newPortData.length) DO
oldAssoc: LIST OF NAT;
newPortData[pi] ← oldPortData[IF pi < portIndex THEN pi ELSE (pi + 1)];
oldAssoc ← newPortData[pi].assoc;
newPortData[pi].assoc ← NIL;
FOR oldAssoc ← oldAssoc, oldAssoc.rest WHILE oldAssoc # NIL DO
SELECT oldAssoc.first FROM
< portIndex => newPortData[pi].assoc ← CONS[oldAssoc.first, newPortData[pi].assoc];
= portIndex => ERROR Broken;
> portIndex => newPortData[pi].assoc ← CONS[oldAssoc.first - 1, newPortData[pi].assoc];
ENDCASE => ERROR;
ENDLOOP;
ENDLOOP;
};
FOR v: Vertex ← ct.firstInstance, v.nextInstance WHILE v # NIL DO
pi: NAT ← 0;
nextEdge: Edge;
FOR e: Edge ← v.firstEdge, nextEdge WHILE e # NIL DO
IF e.sides[cell].v # v THEN ERROR Broken;
IF e.portIndex # pi THEN ERROR Broken;
nextEdge ← e.sides[cell].next;
IF e.portIndex < portIndex THEN NULL ELSE
IF e.portIndex = portIndex THEN RemoveEdge[e] ELSE
IF e.portIndex > portIndex THEN e.portIndex ← e.portIndex - 1;
pi ← pi + 1;
ENDLOOP;
[] ← noteIn.Store[v.parent, $T];
ENDLOOP;
};
FixAffectedType: PROC [key, val: REF ANY] RETURNS [quit: BOOL] = {
parent: CellType ← NARROW[key];
CheckType[parent, establish, ignore];
quit ← FALSE};
CheckPerType: PUBLIC PROC [key, val: REF ANY] RETURNS [quit: BOOL] = {
parent: CellType ← NARROW[key];
args: LORANARROW[val];
CheckType[ct: parent, norm: ToAO[args.first], comparable: ToAO[args.rest.first], ignoreInstances: IF args.rest.rest # NIL THEN ToBOOL[args.rest.rest.first] ELSE FALSE];
quit ← FALSE};
ToAO: PROC [ra: REF ANY] RETURNS [ao: AssertionOp] = {
ao ← SELECT ra FROM
$ignore => ignore,
$report => report,
$check => check,
$establish => establish,
ENDCASE => ERROR};
ToBOOL: PROC [ra: REF ANY] RETURNS [b: BOOL] = {
b ← SELECT ra FROM
$FALSE => FALSE,
$TRUE => TRUE,
ENDCASE => ERROR};
MergeNames: PROC [n1, n2: Names] RETURNS [m: Names] = {
st: SymbolTable ← RedBlackTree.Create[GetAliasKey, CompareAliases];
Add: PROC [rl: RopeList, ns: ATOM] = {
FOR rl ← rl, rl.rest WHILE rl # NIL DO
a: Alias ← NARROW[st.Lookup[rl.first]];
IF a = NIL THEN st.Insert[NEW [AliasRep ← [name: rl.first, thing: ns]], rl.first] ELSE IF a.thing # ns THEN ERROR Broken;
ENDLOOP;
};
Dump: PROC [ra: REF ANY] RETURNS [stop: BOOL] = {
a: Alias ← NARROW[ra];
stop ← FALSE;
SELECT a.thing FROM
$D => m.designed ← CONS[a.name, m.designed];
$U => m.unknown ← CONS[a.name, m.unknown];
$P => m.progged ← CONS[a.name, m.progged];
ENDCASE => ERROR BadData;
};
m ← [];
Add[n1.designed, $D];
Add[n1.unknown, $U];
Add[n1.progged, $P];
Add[n2.designed, $D];
Add[n2.unknown, $U];
Add[n2.progged, $P];
st.EnumerateIncreasing[Dump];
};
MergeRopeLists: PROC [a, b: RopeList] RETURNS [c: RopeList] = {
c ← b;
FOR a ← a, a.rest WHILE a # NIL DO
IF NOT RopeListIncludes[c, a.first] THEN c ← CONS[a.first, c];
ENDLOOP;
};
MergeEquivClasses: PROC [a, b: EquivClass] RETURNS [c: EquivClass] = {
IF a = implicitClass THEN RETURN [b];
IF b = implicitClass THEN RETURN [a];
IF NOT a.Equal[b] THEN ERROR;
c ← a;
};
END.