-- ChipNetImpl.mesa
-- A package of routines that maintains net interconnect
-- structures.
-- last modified by E. McCreight, December 21, 1982 4:58 PM
-- written by E. McCreight, November 5, 1981 10:24 AM
DIRECTORY
ChipDRC,
ChipNetDefs,
ChipUserInt,
InlineDefs,
ppdefs;
ChipNetImpl: PROGRAM
IMPORTS ChipDRC, ChipNetDefs, ChipUserInt
EXPORTS ChipNetDefs =
BEGIN OPEN ppdefs, ChipUserInt, ChipNetDefs;
freeNets: LONG POINTER TO link Net ← NIL;
freeIds: FreeNetIdPtr ← NIL;
allNets: PUBLIC NetIdPtr ← NIL;
NewNet: PUBLIC PROCEDURE[initRefs: CARDINAL ← 1]
RETURNS[CanonNetPtr] =
BEGIN
cn: CanonNetPtr;
IF freeNets=NIL THEN
cn ← LOOPHOLE[netZ.NEW[net ←
[refs: initRefs, rest: canon[id: NewNetId[]]]]]
ELSE
BEGIN
cn ← LOOPHOLE[freeNets];
freeNets ← LOOPHOLE[freeNets.nxt];
cn↑ ← [refs: initRefs, rest: canon[id: NewNetId[]]];
END;
RETURN[cn];
END;
NewNetId: PROCEDURE[]
RETURNS[id: NetIdPtr] =
BEGIN
call: CellCallPtr ← NIL;
IF freeIds=NIL THEN
BEGIN
id ← netIdZ.NEW[NetId ← [next: allNets, details: normal[
name: anonymous[]]]];
allNets ← id;
END
ELSE
BEGIN
id ← freeIds; freeIds ← freeIds.nextFree;
id↑ ← [next: id.next, details: normal[
name: anonymous[]]];
END
END;
RefCanonNet: PUBLIC PROCEDURE[n: netPtr,
newRefs: INTEGER ← 1] RETURNS[CanonNetPtr] =
BEGIN
nInt: netIntPtr ← n;
canonNet: CanonNetPtr;
skipWeight: CARDINAL;
IF nInt=NIL THEN RETURN[NewNet[newRefs+1]];
DO
WITH dn: nInt SELECT FROM
link => nInt ← dn.nxt;
canon => {canonNet ← @dn; EXIT};
ENDCASE;
ENDLOOP;
nInt ← n;
skipWeight ← 1;
DO
np: netIntPtr ← nInt;
WITH dn: np SELECT FROM
link =>
BEGIN
newSkipWeight: CARDINAL ← dn.refs;
nInt ← dn.nxt;
IF (dn.refs ← dn.refs-skipWeight)=0 THEN
{dn.nxt ← freeNets; freeNets ← @dn}
ELSE dn.nxt ← canonNet;
-- the original incoming reference will now skip over
-- this link.
skipWeight ← newSkipWeight;
END;
canon =>
BEGIN
IF (dn.refs ← dn.refs+newRefs)=0 THEN
BEGIN
np.rest ← link[nxt: freeNets];
freeNets ← LOOPHOLE[np];
canonNet ← NIL;
END;
RETURN[canonNet];
END;
ENDCASE;
ENDLOOP;
END; -- of RefCanonNet
GetNormalNetId: PUBLIC PROCEDURE[n: LONG POINTER TO netPtr]
RETURNS[NormalNetIdPtr] =
BEGIN
cn: CanonNetPtr;
IF n=NIL THEN GOTO Malformed;
cn ← n↑ ← CanonNet[n↑];
WITH nid: cn.id SELECT FROM
normal => RETURN[@nid];
ENDCASE => GOTO Malformed;
EXITS
Malformed =>
BEGIN
Explain["GetNormalNetId called with improper arguments"];
RETURN[NIL]
END;
END; -- of GetNormalNetId
MergeNets: PUBLIC PROCEDURE[n1, n2: netPtr]
RETURNS[CanonNetPtr] =
BEGIN
cn1: CanonNetPtr ← CanonNet[n1];
cn2: CanonNetPtr ← CanonNet[n2];
IF cn1#cn2 THEN
BEGIN -- merging two canonical nets
nInt2: netIntPtr;
id: NetIdPtr ← JoinNetIds[cn1.id, cn2.id];
IF cn1.refs<cn2.refs THEN -- reverse cn1 and cn2
BEGIN
cnTemp: CanonNetPtr ← cn1;
cn1 ← cn2;
cn2 ← cnTemp;
END;
cn1.refs ← cn1.refs+cn2.refs;
cn1.id ← id;
nInt2 ← cn2; -- decommit cn2's variant
nInt2.rest ← link[nxt: cn1];
cn2 ← CanonNet[nInt2];
-- adjusts reference count of nInt2
IF id.violations#NIL THEN
ChipDRC.PurgeDRCViolations[id];
END;
RETURN[cn1];
END; -- of MergeNets
JoinNetIds: PROCEDURE[n1, n2: NetIdPtr]
RETURNS[n: NetIdPtr] =
BEGIN
IF n1=n2 THEN RETURN[n1];
WITH nid1: n1 SELECT FROM
well =>
WITH nid2: n2 SELECT FROM
well =>
SELECT TRUE FROM
nid1.attachedTo=NIL =>
BEGIN
n ← @nid2;
n1.details ← free[nextFree: freeIds];
freeIds ← LOOPHOLE[n1];
END;
nid2.attachedTo=NIL =>
BEGIN
n ← @nid1;
n2.details ← free[nextFree: freeIds];
freeIds ← LOOPHOLE[n2];
END;
ENDCASE =>
BEGIN
aid1: NormalNetIdPtr;
IF (aid1 ← GetNormalNetId[@nid1.attachedTo])#
GetNormalNetId[@nid2.attachedTo]
THEN
BEGIN
aid1.violations ← uz.NEW[ConditionalViolation ← [
next: aid1.violations,
otherNet:
(nid2.attachedTo ← CanonNet[nid2.attachedTo]),
v: [
place: RefCoordPt[nid1.final.r],
type: differentNetsToWell,
lev1: nid1.final.lev
]]];
END;
n ← @nid1;
n2.details ← free[nextFree: freeIds];
freeIds ← LOOPHOLE[n2];
END;
ENDCASE;
normal =>
WITH nid2: n2 SELECT FROM
normal =>
n ← JoinNormalNetIds[@nid1, @nid2];
ENDCASE;
ENDCASE;
END; -- of JoinNetIds
JoinNormalNetIds: PROCEDURE[n1, n2: NormalNetIdPtr]
RETURNS[n: NormalNetIdPtr] =
BEGIN
id: NetIdPtr;
caps: ARRAY Conductors OF LayerCap;
UpdateAreas[n1];
UpdateAreas[n2];
FOR cond: Conductors IN Conductors DO
caps[cond].cutSides ← n1.caps[cond].cutSides+
n2.caps[cond].cutSides;
caps[cond].cutWidth ← n1.caps[cond].cutWidth+
n2.caps[cond].cutWidth;
caps[cond].perimeter ← n1.caps[cond].perimeter+
n2.caps[cond].perimeter;
caps[cond].area ← n1.caps[cond].area+
n2.caps[cond].area;
ENDLOOP;
WITH dn1: n1 SELECT FROM
anonymous => n ← n2;
numeric =>
WITH dn2: n2 SELECT FROM
anonymous, numeric => n ← n1;
qualified => n ← n2;
ENDCASE;
qualified =>
WITH dn2: n2 SELECT FROM
anonymous, numeric => n ← n1;
qualified =>
n ← IF CallDepth[n1.source]<=CallDepth[n2.source]
THEN n1 ELSE n2; -- less qualified is better
ENDCASE;
ENDCASE;
n.caps ← caps;
n.final ←
(IF n1.final.r.x2<n2.final.r.x2 THEN n2.final ELSE n1.final);
n.hasPathToGnd ← n1.hasPathToGnd OR n2.hasPathToGnd;
n.hasPathToVdd ← n1.hasPathToVdd OR n2.hasPathToVdd;
n.hasDepletionPullup ← n1.hasDepletionPullup OR
n2.hasDepletionPullup;
n.couldBeLogo ← n1.couldBeLogo AND n2.couldBeLogo;
IF n2.violations#NIL THEN
BEGIN
FOR v: ConditionalViolationPtr ← n2.violations, v.next DO
IF v.next=NIL THEN {v.next ← n1.violations; EXIT};
ENDLOOP;
n.violations ← n2.violations;
END
ELSE n.violations ← n1.violations;
IF n=n1 THEN n1 ← n2;
id ← n1;
id.details ← free[nextFree: freeIds];
freeIds ← LOOPHOLE[id];
END; -- of JoinNetIds
UpdateAreas: PUBLIC PROCEDURE[n: NormalNetIdPtr] =
BEGIN
IF n.lastX<currentX THEN
FOR cond: Conductors IN Conductors DO
n.caps[cond].perimeter ← n.caps[cond].perimeter+
n.caps[cond].cutSides*ScaleToChipmonk[currentX-n.lastX];
n.caps[cond].area ← n.caps[cond].area+
n.caps[cond].cutWidth*
LONG[ScaleToChipmonk[currentX-n.lastX]];
ENDLOOP;
n.lastX ← currentX;
END; -- of UpdateAreas
CallDepth: PROCEDURE[c: InstancePtr]
RETURNS[d: CARDINAL] =
BEGIN
d ← 0;
FOR ancest: InstancePtr ← c, ancest.caller.head
WHILE ancest#NIL DO
d ← d+1;
ENDLOOP;
END;
END. -- of ChipNetImpl