-- 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