<> <> <> <> <> <<>> <> <> <> DIRECTORY CD, CDAtomicObjects, CDBasics, CDCells, CDEvents, CDLayers, CDProperties, CDRects, CDSimpleRules, CDSimpleRulesBackdoor, CDOps, LRUCache, RealOps; <<>> CDStitchedViasImpl: CEDAR PROGRAM IMPORTS CD, CDAtomicObjects, CDBasics, CDCells, CDEvents, CDLayers, CDOps, CDProperties, CDRects, CDSimpleRules, CDSimpleRulesBackdoor, LRUCache, RealOps = BEGIN Rules: TYPE = CDSimpleRules.Rules; GetSimpleBigContact: PROC [size: CD.Position, layer1, layer2: CD.Layer] RETURNS [obj: CD.Object _ NIL] = { tech: CD.Technology _ CD.LayerTechnology[layer1]; IF tech#NIL THEN SELECT tech.key FROM $cmosB => { l1a: ATOM _ CD.LayerKey[layer1]; l2a: ATOM _ CD.LayerKey[layer2]; SELECT TRUE FROM (l1a = $met2 AND l2a = $met) OR (l1a = $met AND l2a = $met2) => obj _ CDAtomicObjects.CreateAtomicOb[$C2LargeVia, size, tech]; (l1a = $pol AND l2a = $met) => obj _ CDAtomicObjects.CreateAtomicOb[$C2LargeSimpleCon, size, tech, layer1]; (l1a = $met AND l2a = $pol) => obj _ CDAtomicObjects.CreateAtomicOb[$C2LargeSimpleCon, size, tech, layer2]; ENDCASE => NULL; }; ENDCASE => NULL }; GetSingleViaForStitching: PROC [rules: Rules, size: CD.Position, layer1, layer2: CD.Layer] RETURNS [via: CD.Object _ NIL] = { <<--this is semi technology dependent; >> tech: CD.Technology ~ CD.LayerTechnology[layer1]; minBigContact: CD.Object ~ GetSimpleBigContact[[1, 1], layer1, layer2]; IF minBigContact=NIL OR tech=NIL THEN { <<--no big contacts, must do it with small ones>> via _ CDSimpleRules.Contact[rules, layer1, layer2] } ELSE { -- big contact exists, determine size to use lambda: CD.Number ~ tech.lambda; ctSize: CD.Position ~ CD.InterestSize[minBigContact]; IF ctSize.x <= size.x AND ctSize.y <= size.y THEN { <<--use 2, 3, or 4 lambda square vias that give largest perimeter >> perim2x2: CD.Number ~ RealOps.ModalRound[size.x/(6*lambda), RealOps.FixMode]*RealOps.ModalRound[size.y/(6*lambda), RealOps.FixMode]*8*lambda; -- 2x2 contacts go in a 6x6 square perim3x3: CD.Number ~ RealOps.ModalRound[size.x/(7*lambda), RealOps.FixMode]*RealOps.ModalRound[size.y/(7*lambda), RealOps.FixMode]*12*lambda; -- 3x3 contacts go in a 7x7 square perim4x4: CD.Number ~ RealOps.ModalRound[size.x/(8*lambda), RealOps.FixMode]*RealOps.ModalRound[size.y/(8*lambda), RealOps.FixMode]*16*lambda; -- 4x4 contacts go in a 8x8 square SELECT TRUE FROM perim4x4 >= perim2x2 AND perim4x4 >= perim3x3 => via _ GetSimpleBigContact[[8*lambda, 8*lambda], layer1, layer2]; perim3x3 >= perim2x2 AND perim3x3 >= perim4x4 => via _ GetSimpleBigContact[[7*lambda, 7*lambda], layer1, layer2]; perim2x2 >= perim4x4 AND perim2x2 >= perim3x3 => via _ GetSimpleBigContact[[6*lambda, 6*lambda], layer1, layer2]; ENDCASE => ERROR; } ELSE { -- big contact too big, must do it with small ones via _ CDSimpleRules.Contact[rules, layer1, layer2] } } }; MinDist: PROC [rules: Rules, layer1, layer2: CD.Layer] RETURNS [m: CD.Number_-1] = { <<--sorry: halfway technology dependent>> <<-- assumes contact exists>> <<-- assumes contact is atomic object>> minCt: CD.Object = CDSimpleRules.Contact[rules, layer1, layer2]; ap: CDAtomicObjects.AtomicObsSpecific = NARROW[minCt.specific]; layer1 _ CDLayers.AbstractToPaint[layer1]; layer2 _ CDLayers.AbstractToPaint[layer2]; FOR dl: CDAtomicObjects.DrawList _ ap.rList, dl.rest WHILE dl#NIL DO IF ~CDBasics.Inside[dl.first.r, ap.ir] THEN LOOP; --ignore wells IF dl.first.layer=layer1 OR dl.first.layer=layer2 THEN LOOP; --ignore layer1, layer2 m _ MAX[m, CDSimpleRules.MinWidth[rules, dl.first.layer] + CDSimpleRules.MinSpace[rules, dl.first.layer, dl.first.layer]]; ENDLOOP; IF m<1 OR m>1000--catch in case of non implementation-- THEN ERROR; }; InternalStitchedVia: PROC [rules: Rules, size: CD.Position, layer1, layer2: CD.Layer] RETURNS [via: CD.Object] = { Incl: PROC [cell: CD.Object, ob: CD.Object, iPos: CD.Position_[0, 0]] = { [] _ CDCells.IncludeOb[cell: cell, ob: ob, trans: [CDBasics.SubPoints[iPos, CD.InterestBase[ob]]], mode: dontResize]; }; contact: CD.Object _ GetSingleViaForStitching[rules, size, layer1, layer2]; ctSize: CD.Position _ CD.InterestSize[contact]; IF ctSize.x >= size.x AND ctSize.y >= size.y THEN via _ contact ELSE { tech: CD.Technology ~ CD.LayerTechnology[layer1]; minDist: CD.Number _ MinDist[rules, layer1, layer2]; grid: CD.Number _ IF tech#NIL THEN tech.lambda ELSE 1; step: CD.Position _ [MAX[minDist, ctSize.x], MAX[minDist, ctSize.y]]; numY: INT _ MAX[1, size.y/step.y]; numX: INT _ MAX[1, size.x/step.x]; ctCov: CD.Position _ [(numX-1)*step.x+ctSize.x, (numY-1)*step.y+ctSize.y]; off: CD.Position _ [ (MAX[size.x-ctCov.x, 0]/(2*grid))*grid, (MAX[size.y-ctCov.y, 0]/(2*grid))*grid ]; via _ CDCells.CreateEmptyCell[]; FOR indexY: CD.Number IN [0 .. numY) DO FOR indexX: CD.Number IN [0 .. numX) DO Incl[via, contact, [off.x+indexX*step.x, off.y+indexY*step.y]]; ENDLOOP; ENDLOOP; Incl[via, CDRects.CreateRect[size, layer1]]; Incl[via, CDRects.CreateRect[size, layer2]]; CDCells.ToSequenceMode[via]; [] _ CDCells.ResizeCell[NIL, via]; CDProperties.PutObjectProp[via, $CreatedBy, $StitchedVias]; IF ~CDOps.MakeImmutable[via] THEN ERROR; }; }; DescRep: TYPE = RECORD [size: CD.Position, layer1, layer2: CD.Layer, ob: CD.Object_NIL, rules: Rules]; <<--Convention: layer1, layer2 are ordered!>> cache: LRUCache.Handle _ LRUCache.Create[17, Hash, Equal]; Hash: PROC [x: REF] RETURNS [h: CARDINAL] = { <<--it doesn't really matter whether the hash function is very good>> d: REF DescRep = NARROW[x]; h _ (d.size.x MOD 10000B)*3+(d.size.y MOD 1000B)*19+d.layer1+d.layer2*13 <<--layer1, layer2 are ordered>> }; Equal: PROC [x, y: REF] RETURNS [BOOL] = { d1: REF DescRep = NARROW[x]; d2: REF DescRep = NARROW[y]; RETURN [d1.size=d2.size AND d1.layer1=d2.layer1 AND d1.layer2=d2.layer2 AND d1.rules=d2.rules] <<--layer1, layer2 are ordered>> }; StitchedVia: PROC [rules: Rules, design: CD.Design, size: CD.Position, l1, l2: CD.Layer] RETURNS [via: CD.Object_NIL] = { d: REF DescRep _ NEW[DescRep_[ size: size, layer1: MIN[l1, l2], layer2: MAX[l1, l2], rules: CDSimpleRules.GetRulesKey[IF rules#NIL THEN rules ELSE CD.LayerTechnology[l1]] ]]; d _ NARROW[LRUCache.Include[cache, d].used]; IF d.ob#NIL THEN RETURN [via _ d.ob]; BEGIN --not found with exact size new: CD.Object _ InternalStitchedVia[size: size, layer1: l1, layer2: l2, rules: rules]; IF new=NIL OR size=CD.InterestSize[new] THEN RETURN [via _ d.ob _ new] ELSE { <<--size was not exact>> d1: REF DescRep _ NEW[DescRep_[ size: CD.InterestSize[new], layer1: d.layer1, layer2: d.layer2, rules: d.rules ]]; d1 _ NARROW[LRUCache.Include[cache, d1].used]; IF d1.ob#NIL THEN RETURN [via _ d.ob _ d1.ob]; --discard new to increase sharing RETURN [via _ d.ob _ d1.ob _ new]; }; END; <<--if we want to introduce caching per design, use cache _ CDValue.Fetch[...>> }; EachTechnology: CD.TechnologyEnumerator = { SELECT tech.key FROM $cmosB, $CMosA, $NMosA => CDSimpleRulesBackdoor.RegisterRules[[ key: NIL, technology: tech, largeContact: StitchedVia ]]; ENDCASE => NULL; }; RegisterTechnology: CDEvents.EventProc = { [] _ EachTechnology[NARROW[x]] }; CDEvents.RegisterEventProc[$RegisterTechnology, RegisterTechnology]; [] _ CD.EnumerateTechnologies[EachTechnology]; END.