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