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