-- ChipNetImpl.mesa
-- A package of routines that maintains net interconnect
-- structures.
-- last modified by E. McCreight, October 1, 1984 3:35 PM
-- written by E. McCreight, November 5, 1981 10:24 AM
DIRECTORY
ChipDRC,
ChipExpand,
ChipNetDefs,
ChipUserInt,
CWF,
InlineDefs,
ppdefs;
ChipNetImpl: PROGRAM
IMPORTS ChipDRC, ChipExpand, ChipNetDefs, ChipUserInt, CWF
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, cn2];
IF cn1.refs<cn2.refs THEN -- reverse cn1 and cn2
{cnTemp: CanonNetPtr ← cn1; cn1 ← cn2; cn2 ← cnTemp};
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[cn1];
END;
RETURN[cn1];
END; -- of MergeNets
JoinNetIds: PROCEDURE[cn1, cn2: CanonNetPtr] RETURNS[n: NetIdPtr] =
BEGIN
n1: NetIdPtr = cn1.id;
n2: NetIdPtr = cn2.id;
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;
ENDCASE =>
BEGIN
IF nid2.attachedTo#NIL THEN
BEGIN
cn: CanonNetPtr ← CanonNet[nid2.attachedTo];
AttachNetToWell[normal: cn, well: cn1];
cn ← DeRefNet[cn];
END;
n ← @nid1;
n2.details ← free[nextFree: freeIds];
freeIds ← LOOPHOLE[n2];
END;
ENDCASE => ERROR;
normal =>
WITH nid2: n2 SELECT FROM
normal => n ← JoinNormalNetIds[@nid1, @nid2];
ENDCASE => ERROR;
ENDCASE => ERROR;
END; -- of JoinNetIds
AttachNetToWell: PROC [normal: CanonNetPtr, well: CanonNetPtr] =
BEGIN
WITH w: well.id SELECT FROM
well =>
SELECT w.attachedTo FROM
NIL => w.attachedTo ← RefCanonNet[normal];
ENDCASE => -- not NIL
SELECT (w.attachedTo ← CanonNet[w.attachedTo]) FROM
normal => NULL; -- attaching to same net twice is NOP
ENDCASE =>
WITH n: normal.id SELECT FROM
normal =>
n.violations ← uz.NEW[ViolationList ← [
next: n.violations,
v: [
place: RefCoordPt[w.final.r],
info: differentNetsToWell[lev: w.final.lev,
wellNode: RefCanonNet[well],
n: RefCanonNet[normal]]]]];
ENDCASE => ERROR; -- normal doesn't point to normal NetId
ENDCASE => ERROR; -- well doesn't point to well NetId
END;
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;
ENDCASE => n ← n2;
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 => n ← n2;
ENDCASE => n ← n1;
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: ViolationListPtr ← 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 JoinNormalNetIds
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;
FeatureNet: PUBLIC PROC [f: FeaturePtr] RETURNS [CanonNetPtr] =
BEGIN
cn: CanonNetPtr;
IF f.net=NIL THEN
BEGIN
cn ← f.net ← NewNet[1];
cn.id.final ← [lev: f.lev, r: f.cover];
SELECT f.lev FROM
nwel, pwel => cn.id.details ← well[attachedTo: NIL];
ENDCASE => cn.id.details ←
normal[source: ChipExpand.NearestCellInstance[f.caller.head],
name: anonymous[]];
END
ELSE cn ← f.net ← CanonNet[f.net];
cn.id.final ← [lev: f.lev, r: f.cover];
RETURN[cn];
END;
MergeFeatureNets: PUBLIC PROC [f1, f2: FeaturePtr] =
BEGIN
-- Merge them unless they are of different types (e.g., node vs well).
-- In that case, relate them.
id: NetIdPtr;
IF f1.lev=f2.lev THEN
BEGIN
cn: CanonNetPtr;
SELECT f1.net FROM
#NIL =>
SELECT f2.net FROM
#NIL => cn ← MergeNets[f1.net, f2.net];
ENDCASE => cn ← RefCanonNet[f1.net];
ENDCASE => cn ← RefCanonNet[FeatureNet[f2]];
id ← (f1.net ← f2.net ← cn).id;
END
ELSE
BEGIN
cn1: CanonNetPtr ← FeatureNet[f1];
cn2: CanonNetPtr ← FeatureNet[f2];
IF cn1.id.type=cn2.id.type THEN
id ← (f1.net ← f2.net ← MergeNets[f1.net, f2.net]).id
ELSE
BEGIN
IF cn1.id.type#normal THEN -- exchange nets
{t: CanonNetPtr ← cn1; cn1 ← cn2; cn2 ← t};
IF NOT(cn1.id.type=normal AND cn2.id.type=well) THEN ERROR;
AttachNetToWell[normal: cn1, well: cn2];
RETURN;
END;
END;
IF id.final.r.x2<f1.cover.x2 THEN
id.final ← [lev: f1.lev, r: f1.cover];
IF id.final.r.x2<f2.cover.x2 THEN
id.final ← [lev: f2.lev, r: f2.cover];
END; -- of MergeFeatureNets
CountNetIds: PROCEDURE [examine: BOOLEAN ← FALSE] RETURNS
[ids, frees, wells, anonymi, numerics, qualifieds, zeroAreas: LONG INTEGER ← 0] =
BEGIN
FOR n: NetIdPtr ← allNets, n.next WHILE n#NIL DO
ids ← ids+1;
WITH dn: n SELECT FROM
free => frees ← frees+1;
well => wells ← wells+1;
normal =>
BEGIN
FOR c: Conductors IN Conductors DO
IF dn.caps[c] # [0,0,0,0] THEN EXIT;
REPEAT
FINISHED =>
IF dn.final.r.x2<currentX THEN
BEGIN
zeroAreas ← zeroAreas+1;
IF examine THEN
BEGIN
s: STRING ← [100];
CWF.SWF1[sto: s, s: "Zero-area node in %s here...", a: levelNames[dn.final.lev]];
RemarkAtPoint[RefCoordPt[dn.final.r], s];
END;
END;
ENDLOOP;
WITH ddn: dn SELECT FROM
anonymous => anonymi ← anonymi+1;
numeric => numerics ← numerics+1;
qualified => qualifieds ← qualifieds+1;
ENDCASE => ERROR;
END;
ENDCASE => ERROR;
ENDLOOP;
END;
END. -- of ChipNetImpl