<> <> <> <> <> DIRECTORY Atom USING [GetPName], CD USING [backgroundLayer, commentLayer, CreateDrawRef, DrawProc, DrawContextProc, DrawRectProc, DrawRef, errorLayer, LayerKey, Number, Object, outlineLayer, Position, Rect, selectionLayer, shadeLayer, undefLayer], CDAtomicObjects USING [AtomicObsSpecific, DrawList], CDBasics USING [NonEmpty], CDBasicsInline USING [DeMapRect, MapRect], CDOps USING [LayerRope, ToRope], CDProperties USING [GetObjectProp, PutObjectProp], CMosB USING [cut, cut2, lambda, ndif, nwell, nwellCont, ovg, pdif, pol, pwell, pwellCont], CoreGeometry USING [CellInstance, EachInstanceProc, EnumerateGeometry, FlattenInstance, GetObject, InlineBBox, Instance, Instances, Object], CoreProperties USING [RegisterProperty], CoreView USING [AddRectangle, debugViewer], CStitching USING [all, Area, ChangeEnumerateArea, ChangeRect, EEdge, EN, EnumerateArea, EnumerateNeighborhood, FindTile, ListArea, NE, NEdge, NewTesselation, Rect, RectProc, Region, SEdge, SW, Tesselation, Tile, TileProc, TrustedDisposeTesselation, WEdge, WS], Drc USING [AtomicWireHull, CellProc, Context, CoreCell, MarkError, Rect, State, Tech, Transf, Wire, WireInstance, WirePairProc, WireProc, WireSet], DrcCmosb USING [CMosbTableRec, Rule], DrcCmosbMain, DrcDebug USING [break, debug, dLog, GeometryInWire, pause, trace], DrcCmosbGapHack USING [GapIsFilled], DrcUtilities USING [Anathema, Bloat, CoreWireName, diffContactLayer, DoNotDrawContext, ignoreConnectivity, Intersecting, IntersectingOpen, Intersection, IsCut, IsDiffContact, IsLargeDiffContact, IsWell, Layer, LayerName, Normalize, ROPE, SameLayer, SameRect, Size, Tess, WireName], IO USING [atom, card, int, PutF, PutFR, rope], Rope USING [Cat, Equal, ROPE], Saguaro USING [gate]; DrcCmosbMainImpl: CEDAR PROGRAM IMPORTS Atom, CD, CDBasics, CDBasicsInline, CDOps, CDProperties, CMosB, CoreGeometry, CoreProperties, CoreView, CStitching, Drc, DrcDebug, DrcCmosbGapHack, DrcUtilities, IO, Rope, Saguaro EXPORTS DrcCmosbMain SHARES Drc ~ BEGIN OPEN CMosB, Drc, DrcCmosbGapHack, DrcUtilities; <> CMosbTable: TYPE ~ REF CMosbTableRec; CMosbTableRec: PUBLIC TYPE ~ DrcCmosb.CMosbTableRec; CdInsts: TYPE ~ CoreGeometry.Instances; CdObj: TYPE ~ CoreGeometry.Object; CoreInst: TYPE ~ CoreGeometry.CellInstance; FakeInst: TYPE ~ CoreGeometry.Instance; Region: TYPE ~ LIST OF REF CStitching.Region; Tile: TYPE ~ CStitching.Tile; empty: REF ~ NIL; nothing: REF INT ~ NEW [INT]; none: ATOM ~ NIL; universe: Rect ~ CStitching.all; rectClass: ATOM ~ $Rect; wellRectClass: ATOM ~ $WellRect; pinClass: ATOM ~ $PinOb0; markClass: ATOM ~ $AlignmentMarkOb; segmentClass: ATOM ~ $SymbolicSegment; cutKey: ATOM ~ CD.LayerKey [cut]; cut2Key: ATOM ~ CD.LayerKey [cut2]; genericDiff: ATOM ~ $diff; polyKey: ATOM ~ CD.LayerKey [pol]; gateKey: ATOM ~ CoreProperties.RegisterProperty [$gateGenista]; gate: Layer ~ Saguaro.gate; fieldOxide: REF ANY ~ NIL; notChannel: WireInstance ~ [NIL, NIL, [], NIL]; specialLayers: Layer ~ MAX [CD.shadeLayer, CD.errorLayer, CD.backgroundLayer, CD.outlineLayer, CD.selectionLayer, CD.commentLayer]; <> <> lambda: CD.Number ~ CMosB.lambda; detail: BOOL _ FALSE; <> <> <> <> SimpleWidthCheck: PUBLIC WireProc ~ BEGIN <<[cell: CoreCell, w: Wire, state: State]>> <> VerifyRect: CoreGeometry.EachInstanceProc ~ BEGIN <> <> min, max, a, b: CD.Number; o: CdObj ~ instance.obj; l: Layer ~ o.layer; r: Rect ~ CoreGeometry.InlineBBox [instance]; rt: CMosbTable ~ NARROW [state.tech.ruleTables, CMosbTable]; IF DrcDebug.debug AND detail THEN BEGIN DrcDebug.dLog.PutF ["Class = %g. ", IO.atom [o.class.objectType]]; DrcDebug.dLog.PutF [format: "Checking rectangle at [%g, %g] %l %g%l\n", v1: IO.int [instance.trans.off.x / lambda], v2: IO.int [instance.trans.off.y / lambda], v3: IO.rope ["b"], v4: IO.rope [CDOps.LayerRope [o.layer]], v5: IO.rope ["B"]]; IF (CDProperties.GetObjectProp [o, DrcDebug.pause] # NIL) THEN DrcDebug.break <> END; SELECT o.class.objectType FROM rectClass => IF (l <= specialLayers) THEN RETURN; markClass, segmentClass, pinClass => RETURN; ENDCASE => quit _ CoreGeometry.FlattenInstance [instance, VerifyRect]; <> <> IF DrcDebug.debug AND detail THEN CDProperties.PutObjectProp [o, DrcDebug.trace, DrcDebug.trace]; IF state.tech.illegalLayer[l] THEN BEGIN MarkError [cell, state, [r, Rope.Cat ["Illegal layer ", LayerName [l], " (wire ", CoreWireName [w], ")"]]]; RETURN END; min _ rt.minWidth[l].extent; max _ rt.maxWidth[l].extent; a _ MAX [(r.x2 - r.x1), (r.y2 - r.y1)]; b _ MIN [(r.x2 - r.x1), (r.y2 - r.y1)]; -- a and b are such that a > b IF (a < min) OR (b < min) OR (a > max) OR (b > max) THEN MarkError [cell, state, [r, rt.minWidth[l].msg.Cat [" (wire ", CoreWireName [w], ")"]]] END; -- VerifyRect [] _ state.attributes.EnumerateGeometry [w, VerifyRect] END; -- SimpleWidthCheck FullWireCheck: PUBLIC WireProc ~ BEGIN -- INTERIM <<[cell: CoreCell, w: Wire, state: State]>> <> rt: CMosbTable ~ NARROW [state.tech.ruleTables]; minPadSize: CD.Number ~ rt.minPadSize.extent; VerifyRect: CoreGeometry.EachInstanceProc ~ BEGIN <> <> min, max, a, b: CD.Number; o: CdObj ~ instance.obj; l: Layer ~ o.layer; r: Rect ~ CoreGeometry.InlineBBox [instance]; size: CD.Position ~ Size [r]; IF DrcDebug.debug AND detail THEN BEGIN DrcDebug.dLog.PutF ["Class = %g. ", IO.atom [o.class.objectType]]; DrcDebug.dLog.PutF [format: "Checking rectangle at [%g, %g] %l %g%l\n", v1: IO.int [instance.trans.off.x / lambda], v2: IO.int [instance.trans.off.y / lambda], v3: IO.rope ["b"], v4: IO.rope [CDOps.LayerRope [o.layer]], v5: IO.rope ["B"]]; IF (CDProperties.GetObjectProp [o, DrcDebug.pause] # NIL) THEN DrcDebug.break <> END; SELECT o.class.objectType FROM rectClass => IF (l <= specialLayers) OR (IsCut [l]) THEN RETURN; -- width rules for cuts depend on class wellRectClass => NULL; $C2SimpleCon, $C2WellSimpleCon, $C2LargeSimpleCon, $C2LargeWellSimpleCon, $C2DifShortCon, $C2WellDifShortCon, $C2DiffShortCon, $C2Via, $C2LargeVia => BEGIN VerifyContact [o, r]; RETURN <> END; markClass, segmentClass, pinClass => RETURN; ENDCASE => BEGIN quit _ CoreGeometry.FlattenInstance [instance, VerifyRect]; RETURN END; IF DrcDebug.debug AND detail THEN CDProperties.PutObjectProp [o, DrcDebug.trace, DrcDebug.trace]; IF state.tech.illegalLayer[l] OR ((l = ovg) AND ((size.x < minPadSize) OR (size.y < minPadSize))) THEN BEGIN MarkError [cell, state, [r, Rope.Cat ["Illegal layer ", LayerName [l], " (wire ", CoreWireName [w], ")"]]]; RETURN END; min _ rt.minWidth[l].extent; max _ rt.maxWidth[l].extent; a _ MAX [size.x, size.y]; b _ MIN [size.x, size.y]; -- a and b are such that a > b IF (a < min) OR (b < min) OR (a > max) OR (b > max) THEN BEGIN ruleHint: ROPE ~ IO.PutFR ["%g (%g%g ): %g (wire %g)", IO.rope [rt.minWidth[l].msg], IO.int [rt.minWidth[l].extent/lambda], IO.rope [IF (rt.minWidth[l].extent MOD lambda # 0) THEN ".5" ELSE NIL], IO.rope [LayerName [l]], IO.rope [CoreWireName [w]]]; MarkError [cell, state, [r, ruleHint]] END END; -- VerifyRect VerifyContact: PROC [contact: CdObj, bb: Rect] ~ BEGIN <> size: CD.Position; sizeExceeded: BOOL _ FALSE; classKey: ATOM ~ contact.class.objectType; maxContSize: CD.Number ~ rt.maxWidth[cut].extent; minContSize: CD.Number ~ rt.minWidth[cut].extent; maxViaSize: CD.Number ~ rt.maxWidth[cut2].extent; minViaSize: CD.Number ~ rt.minWidth[cut2].extent; splitContWidth: CD.Number ~ minContSize; splitContHeight: CD.Number ~ maxContSize + lambda; FOR geom: CDAtomicObjects.DrawList _ NARROW [contact.specific, CDAtomicObjects.AtomicObsSpecific].rList, geom.rest WHILE geom # NIL DO SELECT geom.first.layer FROM cut => BEGIN -- all but vias size _ Size [geom.first.r]; SELECT classKey FROM $C2DifShortCon, $C2DiffShortCon, $C2WellDifShortCon => sizeExceeded _ sizeExceeded OR ((MIN[size.x, size.y] # splitContWidth) OR (MAX[size.x, size.y] # splitContHeight)); ENDCASE => sizeExceeded _ sizeExceeded OR (size.x > maxContSize OR size.y > maxContSize) OR (size.x < minContSize OR size.y < minContSize) END; cut2 => BEGIN -- vias size _ Size [geom.first.r]; IF (size.x < minPadSize) OR (size.y < minPadSize) THEN sizeExceeded _ sizeExceeded OR (size.x > maxViaSize OR size.y > maxViaSize) OR (size.x < minViaSize OR size.y < minViaSize) END; ENDCASE => NULL ENDLOOP; IF sizeExceeded THEN MarkError [cell, state, [bb, Rope.Cat ["Contact size exceeded for ", Atom.GetPName [classKey], " (wire ", CoreWireName [w], ")"]]] END; -- VerifyContact [] _ state.attributes.EnumerateGeometry [w, VerifyRect] END; -- FullWireCheck <> SimpleMaterialSeparation: PUBLIC WirePairProc ~ BEGIN <<[where: Context, w1, w2: WireInstance, relatedWires: REF ANY _ NIL, window: Rect, state: State]>> <> <> aequipotential: BOOL ~ (w1.global = w2.global); r1, r2, b1, b2: Rect; l1, l2: Layer; o1, o2: CdObj; rt: CMosbTable ~ NARROW [state.tech.ruleTables]; VerifyOuter: CoreGeometry.EachInstanceProc ~ BEGIN <> VerifyInner: CoreGeometry.EachInstanceProc ~ BEGIN <> sep: CD.Number; o2 _ instance.obj; l2 _ o2.layer; quit _ state.abort^; IF (o2.class.objectType # rectClass) OR (l2 <= specialLayers) OR (state.tech.illegalLayer[l2]) THEN RETURN; r2 _ CDBasicsInline.MapRect [CoreGeometry.InlineBBox [instance], w2.transf]; IF (NOT (IsCut [l1] AND IsCut [l2])) THEN BEGIN IF ignoreConnectivity THEN BEGIN IF (Intersecting [r1, r2]) THEN RETURN END ELSE BEGIN IF aequipotential THEN RETURN END END; sep _ rt.separation[l1][l2].extent; IF (sep = 0) THEN RETURN; IF aequipotential AND (SameRect [r1, r2, l1, l2]) THEN RETURN; -- e.g. cuts b1 _ Bloat [r1, sep / 2]; b2 _ Bloat [r2, sep / 2]; IF DrcDebug.debug AND detail THEN CoreView.AddRectangle [CoreView.debugViewer, r1, w1.local]; IF IntersectingOpen [b1, b2] THEN BEGIN n1: ROPE ~ rt.separation[l1][l2].msg.Cat [" (wire ", WireName [w1], ")"]; n2: ROPE ~ Rope.Cat [" (wire ", WireName [w2], ")"]; vr: Rect ~ CDBasicsInline.DeMapRect [Intersection [b1, b2], where.t]; MarkError [where.cell, state, [vr, n1.Cat [" and ", n2]]] END; quit _ state.abort^ END; -- VerifyInner o1 _ instance.obj; l1 _ o1.layer; quit _ state.abort^; IF (o1.class.objectType # rectClass) OR (l1 <= specialLayers) OR (state.tech.illegalLayer[l1]) THEN RETURN; r1 _ CDBasicsInline.MapRect [CoreGeometry.InlineBBox [instance], w1.transf]; quit _ state.attributes.EnumerateGeometry [w2.local, VerifyInner] END; -- VerifyOuter IF (Intersecting [(Bloat [AtomicWireHull[w1, state], state.tech.maxSeparation]), (AtomicWireHull[w2, state])]) THEN [] _ state.attributes.EnumerateGeometry [w1.local, VerifyOuter] END; -- SimpleMaterialSeparation ViaTileData: TYPE ~ REF ViaTileDataRec; ViaTileDataRec: TYPE ~ RECORD [ hasDiff: BOOL _ FALSE, -- diffusion hasPoly: BOOL _ FALSE, -- polysilicide hasFOx: BOOL _ FALSE]; -- field oxide MatTileData: TYPE ~ REF MatTileDataRec; MatTileDataRec: TYPE ~ RECORD [layerKey: ATOM, via: ViaTileData]; OccupyTile: CStitching.RectProc = BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> WITH oldValue SELECT FROM v: ViaTileData => NULL; -- vias are often repeated on top of each other ENDCASE => CStitching.ChangeRect [plane, rect, data] END; -- OccupyTile CompleteSeparation: PUBLIC WirePairProc ~ BEGIN <<[where: Context, w1, w2: WireInstance, relatedWires: REF ANY _ NIL, window: Rect, state: State]>> <> <> aequipotential: BOOL ~ (w1.global = w2.global); viaTess, materialTess: Tess; currentTransf: Transf; outer: FakeInst; outerIsDiffCont, outerIsLargeDiffCont, innerIsDiffCont, innerIsLargeDiffCont: BOOL _ FALSE; <> rt: CMosbTable ~ NARROW [state.tech.ruleTables]; VerifyOuter: CoreGeometry.EachInstanceProc ~ BEGIN <> r1, maxBloat1: Rect; o1: CdObj ~ instance.obj; l1: Layer ~ o1.layer; c1: ATOM ~ o1.class.objectType; VerifyInner: CoreGeometry.EachInstanceProc ~ BEGIN <> r2, b1, b2: Rect; sep: CD.Number; o2: CdObj ~ instance.obj; l2: Layer ~ o2.layer; c2: ATOM ~ o2.class.objectType; quit _ state.abort^; SELECT c2 FROM rectClass => IF (l2 <= specialLayers) OR (state.tech.illegalLayer[l2]) OR ((IsWell [l1]) AND (IsWell [l2])) THEN RETURN; <> wellRectClass => NULL; markClass, segmentClass, pinClass => RETURN; ENDCASE => BEGIN -- vedasi commento al livello pi u esterno <> r: Rect ~ CDBasicsInline.MapRect [CoreGeometry.InlineBBox [instance], w2.transf]; IF (instance = outer) OR (NOT Intersecting [r, window]) OR (NOT IntersectingOpen [maxBloat1, r]) THEN RETURN; innerIsDiffCont _ IsDiffContact [c2, l2]; innerIsLargeDiffCont _ IsLargeDiffContact [c2, l2]; quit _ CoreGeometry.FlattenInstance [instance, VerifyInner]; RETURN END; <> <> r2 _ CDBasicsInline.MapRect [CoreGeometry.InlineBBox [instance], w2.transf]; IF NOT Intersecting [r2, window] THEN RETURN; IF state.viaFlatness AND (l2 = cut2) THEN CStitching.ChangeEnumerateArea [viaTess, r2, OccupyTile, NEW [ViaTileDataRec], nothing]; <> IF ((l1 = gate) AND ((l2 = pdif) OR (l2 = ndif))) OR ((l2 = gate) AND ((l1 = pdif) OR (l1 = ndif))) THEN {Anathema [2, state]; RETURN}; <> IF ((((l1 = pol) AND (diffContactLayer[l2])) OR ((diffContactLayer[l1]) AND (l2 = pol))) AND ((w1.gateHint # NIL) AND (w2.gateHint # NIL))) THEN {Anathema [2, state]; RETURN}; <> IF (aequipotential AND SameRect [r1, r2, l1, l2]) THEN RETURN; <> IF ((((l1 = pol) AND (l2 = cut2)) OR ((l1 = cut2) AND (l2 = pol))) AND (Intersecting [r1, r2])) THEN RETURN; IF NOT (IsCut [l1] AND IsCut [l2]) THEN BEGIN IF ignoreConnectivity THEN BEGIN IF (IntersectingOpen [r1, r2]) AND (SameLayer [l1, l2]) THEN BEGIN IF NOT aequipotential THEN BEGIN <> BothRec: TYPE ~ RECORD [a, b: WireInstance]; both: REF BothRec _ NEW [BothRec _ [w1, w2]]; <> <> <> msg: ROPE ~ IO.PutFR ["Short-cut: %g [%g] # %g [%g], but they are connected on layer %g", IO.rope [WireName [w1]], IO.card [LOOPHOLE [w1.global]], IO.rope [WireName [w2]], IO.card [LOOPHOLE [w2.global]], IO.rope [LayerName [l1]]]; vr: Rect ~ CDBasicsInline.DeMapRect [Intersection [r1, r2], where.t]; MarkError [where.cell, state, [Bloat [vr, lambda], msg]] <> END ELSE BEGIN min: CD.Number ~ rt.minWidth[l1].extent; i: Rect _ Intersection [r1, r2]; IF (i.x2 - i.x1 < min) AND (i.y2 - i.y1 < min) THEN BEGIN dx: CD.Number ~ (min - i.x2 - i.x1) / 2; dy: CD.Number ~ (min - i.y2 - i.y1) / 2; i _ [i.x1 - dx, i.y1 - dy, i.x2 + dx, i.y2 + dy]; -- beat it if you can IF (GapIsFilled [i, l1, w1, state] = empty) THEN Anathema [1, state] ELSE BEGIN vr: Rect ~ CDBasicsInline.DeMapRect [i, where.t]; MarkError [where.cell, state, [vr, rt.minWidth[l1].msg.Cat [" width violation for intersection of rectangle pair on layer ", LayerName[l1]]]] END END END; RETURN END END ELSE {IF aequipotential THEN RETURN} END; sep _ rt.separation[l1][l2].extent; <> IF (((l1 = cut) OR (l2 = cut)) AND ((innerIsDiffCont OR outerIsDiffCont OR innerIsLargeDiffCont OR outerIsLargeDiffCont))) THEN BEGIN SELECT TRUE FROM ((l1 = gate) OR (l2 = gate)) => SELECT TRUE FROM -- VTI 6.5.2.3 innerIsDiffCont, outerIsDiffCont => sep _ rt.diffCutToGate.extent; innerIsLargeDiffCont, outerIsLargeDiffCont => sep _rt.largeDiffCutToGate.extent; ENDCASE => NULL; (((l1 = cut) AND (l2 = cut2)) OR ((l1 = cut2) AND (l2 = cut))) => sep _ rt.difCutViaSpace.extent; -- 6.7.8 (((l1 = cut) AND (diffContactLayer[l2])) OR ((l2 = cut) AND (diffContactLayer[l1]))) => sep _ 0; -- VTI 6.5.1.7 ENDCASE => NULL END; IF (sep = 0) THEN RETURN; b1 _ Bloat [r1, sep]; IF DrcDebug.debug AND detail THEN BEGIN CoreView.AddRectangle [CoreView.debugViewer, r2, w2.global]; DrcDebug.dLog.PutF [" checking separation between rectangle on %g at [%g, %g, %g, %g]", IO.rope [LayerName[l1]], IO.int [r1.x1/lambda], IO.int [r1.y1/lambda], IO.int [r1.x2/lambda], IO.int [r1.y2/lambda]]; DrcDebug.dLog.PutF [" and %g at [%g, %g, %g, %g].\n", IO.rope [LayerName[l2]], IO.int [r2.x1/lambda], IO.int [r2.y1/lambda], IO.int [r2.x2/lambda], IO.int [r2.y2/lambda]]; <> END; IF IntersectingOpen [b1, r2] THEN BEGIN -- Separation violation errorRegion: LIST OF Rect; ruleType: ROPE _ ": Separation between "; name1: ROPE ~ WireName [w1]; name2: ROPE ~ WireName [w2]; n1, n2, layoutHint, ruleHint: ROPE; violationIsSeparation: BOOL _ TRUE; <> IF (aequipotential AND ((((l1 = ndif) AND (l2 = pwellCont)) OR ((l1 = pwellCont) AND (l2 = ndif)) AND name1.Equal ["Gnd"]) OR (((l1 = pdif) AND (l2 = nwellCont)) OR ((l1 = nwellCont) AND (l2 = pdif)) AND name1.Equal ["Vdd"])) AND (Intersecting [r1, r2] AND (NOT IntersectingOpen [r1, r2]))) THEN {Anathema [3, state]; RETURN}; IF DrcDebug.debug THEN BEGIN n1 _ IO.PutFR ["%g (wire %g [%g])", IO.rope [LayerName[l1]], IO.rope [name1], IO.card [LOOPHOLE[w1.local]]]; n2 _ IO.PutFR ["%g (wire %g [%g])", IO.rope [LayerName[l2]], IO.rope [name2], IO.card [LOOPHOLE[w2.local]]] END ELSE BEGIN n1 _ LayerName[l1].Cat [" (wire ", name1, ")"]; n2 _ LayerName[l2].Cat [" (wire ", name2, ")"] END; layoutHint _ n1.Cat [" and ", n2]; b1 _ Bloat [r1, sep / 2]; b2 _ Bloat [r2, sep / 2]; errorRegion _ LIST [Intersection [b1, b2]]; IF NOT (IsCut [l1] AND IsCut [l2]) THEN <> IF ignoreConnectivity AND (SameLayer [l1, l2]) THEN BEGIN <> gap: Rect ~ Normalize [Bloat [errorRegion.first, -sep/2]]; IF aequipotential AND (GapIsFilled [gap, l1, w1, state, w2] = empty) THEN {Anathema [1, state]; RETURN}; IF diffContactLayer[l1] THEN BEGIN -- could be a channel a, b: WireInstance; IF (w1.gateHint # NIL) AND (w1.gateHint = w2.gateHint) THEN {Anathema [2, state]; RETURN}; a _ IF (w1.gateHint = NIL) THEN w1 ELSE w1.gateHint^; b _ IF (w2.gateHint = NIL) THEN w2 ELSE w2.gateHint^; IF ((GapIsFilled [gap, gate, a, state] = empty) OR (GapIsFilled [gap, gate, b, state] = empty)) THEN {Anathema [1, state]; RETURN}; <> WITH relatedWires SELECT FROM s: WireSet => -- channel fills diff gap FOR i: NAT IN [0 .. s.size) DO IF (s[i].global = w1.global) THEN IF (GapIsFilled [gap, l1, s[i], state] = empty) THEN {Anathema [0, state]; RETURN} ENDLOOP; sl: LIST OF WireSet => BEGIN -- channel fills diff gap FOR l: LIST OF WireSet _ sl, l.rest WHILE l # NIL DO FOR i: NAT IN [0 .. l.first.size) DO IF (i = 0) OR (l.first[i].global = w1.global) THEN BEGIN IF (GapIsFilled [gap, l1, l.first[i], state] = empty) THEN {Anathema [0, state]; RETURN}; IF (GapIsFilled [gap, l1, w1, state, l.first[i]] = empty) THEN {Anathema [0, state]; Anathema [1, state]; RETURN} END ENDLOOP ENDLOOP; IF (GapIsFilled [gap, l1, w1, state, notChannel, sl] = empty) THEN {Anathema [0, state]; RETURN}; IF DrcDebug.debug THEN BEGIN DrcDebug.dLog.PutF ["***Failed to fill gap [%g, %g, %g, %g] ", IO.int [gap.x1], IO.int [gap.y1], IO.int [gap.x2], IO.int [gap.y2]]; DrcDebug.dLog.PutF [" formed by %g and %g\n", IO.rope [n1], IO.rope [n2]]; FOR l: LIST OF WireSet _ sl, l.rest WHILE l # NIL DO FOR i: NAT IN [0 .. l.first.size) DO DrcDebug.GeometryInWire [l.first[i].local, l.first[i].transf, state.attributes] ENDLOOP ENDLOOP END END; list: LIST OF WireInstance => -- diff gap separated by gate FOR gates: LIST OF WireInstance _ list, gates.rest WHILE gates # NIL DO IF (GapIsFilled [gap, gate, gates.first, state] = empty) THEN {Anathema [0, state]; RETURN} ENDLOOP; ENDCASE => IF (relatedWires # NIL) THEN ERROR END ELSE BEGIN -- same layer, but not diffusion transistors: LIST OF WireSet _ NIL; IF SameLayer [l1, gate] AND ISTYPE [relatedWires, LIST OF WireSet] THEN transistors _ NARROW [relatedWires, LIST OF WireSet]; errorRegion _ GapIsFilled [gap, l1, w1, state, w2, transistors]; IF (errorRegion = empty) THEN {Anathema [1, state]; RETURN} END; errorRegion _ GapIsFilled [gap, l1, w1, state]; IF (errorRegion = empty) THEN BEGIN IF aequipotential THEN {Anathema [1, state]; RETURN} ELSE BEGIN <> BothRec: TYPE ~ RECORD [a, b: WireInstance]; both: REF BothRec _ NEW [BothRec _ [w1, w2]]; ruleType _ "Short-cut: w1 # w2, but they actually are connected"; IF DrcDebug.debug THEN DrcDebug.break <> END END; errorRegion _ GapIsFilled [gap, l2, w2, state]; IF (errorRegion = empty) THEN BEGIN IF aequipotential THEN {Anathema [1, state]; RETURN} ELSE BEGIN <> BothRec: TYPE ~ RECORD [a, b: WireInstance]; both: REF BothRec _ NEW [BothRec _ [w1, w2]]; ruleType _ "Short-cut: w1 # w2, but they actually are connected"; IF DrcDebug.debug THEN DrcDebug.break <> END END; IF aequipotential THEN BEGIN ruleType _ ": Possible notch on "; violationIsSeparation _ FALSE END END; IF (diffContactLayer[l1] AND (l2 = pol)) OR (diffContactLayer[l2] AND (l1 = pol)) THEN BEGIN gap: Rect ~ Normalize [Bloat [errorRegion.first, -sep/2]]; WITH relatedWires SELECT FROM sl: LIST OF WireSet => -- gate allows poly FOR l: LIST OF WireSet _ sl, l.rest WHILE l # NIL DO IF (GapIsFilled [gap, l1, w1, state, l.first[0]] = empty) THEN {Anathema [2, state]; RETURN} ENDLOOP; ENDCASE => NULL END; IF violationIsSeparation THEN ruleHint _ IO.PutFR [" should be %g%g ", IO.int [sep/lambda], IO.rope [IF (sep MOD lambda # 0) THEN ".5" ELSE NIL]]; ruleHint _ rt.separation[l1][l2].msg.Cat [ruleType, layoutHint, ruleHint]; FOR r: LIST OF Rect _ errorRegion, r.rest WHILE r # NIL DO vr: Rect ~ CDBasicsInline.DeMapRect [r.first, where.t]; MarkError [where.cell, state, [Bloat [vr, sep/2], ruleHint]] ENDLOOP END; quit _ state.abort^ END; -- VerifyInner quit _ state.abort^; SELECT c1 FROM rectClass => IF (l1 <= specialLayers) OR (state.tech.illegalLayer[l1]) THEN RETURN; wellRectClass => NULL; markClass, segmentClass, pinClass => RETURN; ENDCASE => BEGIN r: Rect ~ CDBasicsInline.MapRect [CoreGeometry.InlineBBox [instance], w1.transf]; IF (NOT Intersecting [r, window]) THEN RETURN; outer _ instance; outerIsDiffCont _ IsDiffContact [c1, l1]; outerIsLargeDiffCont _ IsLargeDiffContact [c1, l1]; quit _ CoreGeometry.FlattenInstance [instance, VerifyOuter]; RETURN END; r1 _ CDBasicsInline.MapRect [CoreGeometry.InlineBBox [instance], w1.transf]; IF NOT Intersecting [r1, window] THEN RETURN; maxBloat1 _ Bloat [r1, state.tech.maxSeparation]; IF state.viaFlatness AND (l1 = cut2) THEN CStitching.ChangeEnumerateArea [viaTess, r1, OccupyTile, NEW [ViaTileDataRec], nothing]; quit _ state.attributes.EnumerateGeometry [w2.local, VerifyInner] END; -- VerifyOuter FindMaterial: CoreGeometry.EachInstanceProc ~ BEGIN <> <> bloatedRect, r: Rect; vias: Region; IF (instance.obj.class.objectType # rectClass) THEN RETURN; IF state.abort^ THEN RETURN [TRUE]; r _ CDBasicsInline.MapRect [CoreGeometry.InlineBBox [instance], currentTransf]; IF NOT (CDBasics.NonEmpty [r]) THEN RETURN; -- empty rectangle SELECT instance.obj.layer FROM <> <> <<1. Via Flatness: VTI's Greg Spadea says they no longer have a problem with vias that straddle field oxide and diffusion. So the advisory comment that recommended that vias on field oxide avoid diffusion by 2 diffusion by 2>> < BEGIN>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> pol => BEGIN bloatedRect _ Bloat [r, rt.viaOnFieldOxideAvoidsPoly.extent]; vias _ CStitching.ListArea [plane: viaTess, rect: bloatedRect]; FOR v: Region _ vias, v.rest WHILE v # NIL DO via: ViaTileData = NARROW [v.first.value]; <> <> <> <> ENDLOOP; bloatedRect _ Bloat [r, rt.polySurroundsViaOnPoly.extent]; vias _ CStitching.ListArea [plane: viaTess, rect: bloatedRect]; FOR v: Region _ vias, v.rest WHILE v # NIL DO via: ViaTileData ~ NARROW [v.first.value]; data: MatTileData ~ NEW [MatTileDataRec _ [polyKey, via]]; IF Intersecting [v.first.rect, r] THEN via.hasPoly _ TRUE; <> bloatedRect _ Bloat [v.first.rect, rt.polySurroundsViaOnPoly.extent]; CStitching.ChangeEnumerateArea [materialTess, Intersection [bloatedRect, r], OccupyTile, data, nothing] ENDLOOP END; ENDCASE => NULL END; -- FindMaterial LookUnderneath: CStitching.TileProc ~ BEGIN -- PROC [tile: REF Tile, data: REF] <> via: ViaTileData ~ NARROW [tile.value]; rect: CStitching.Rect ~ CStitching.Area [tile]; IsOnFieldOxide: PROC RETURNS [d: BOOL _ TRUE] ~ INLINE BEGIN <> FOR cut: Region _ CStitching.ListArea [materialTess, rect], cut.rest WHILE cut # NIL DO IF (cut.first.value # NIL) THEN RETURN [FALSE] ENDLOOP END; -- IsOnFieldOxide Accumulate: CStitching.TileProc ~ BEGIN via: ViaTileData ~ NARROW [data]; mat: MatTileData ~ NARROW [tile.value]; IF (mat = fieldOxide) THEN via.hasFOx _ TRUE -- [field oxide is represented by ELSE BEGIN IF (mat.via # via) THEN ERROR; -- Consistency test: Tesselation screwed up SELECT mat.layerKey FROM < via.hasDiff _ TRUE;>> polyKey => via.hasPoly _ TRUE; ENDCASE => ERROR END END; -- Accumulate <> via.hasFOx _ NOT (via.hasDiff OR via.hasPoly); SELECT TRUE FROM < BEGIN>> <> <> <> <> <> via.hasPoly => BEGIN CStitching.EnumerateArea [plane: materialTess, rect: Bloat [rect, rt.polySurroundsViaOnPoly.extent], eachTile: Accumulate, data: via, skip: $doNotSkipAnything]; IF via.hasFOx THEN BEGIN vr: Rect ~ CDBasicsInline.DeMapRect [rect, where.t]; IF IsOnFieldOxide[] THEN MarkError [where.cell, state, [vr, rt.viaOnFieldOxideAvoidsPoly.msg]] ELSE MarkError [where.cell, state, [vr, rt.polySurroundsViaOnPoly.msg]] END END; via.hasFOx => BEGIN CStitching.EnumerateArea [plane: materialTess, rect: Bloat [rect, rt.fieldOxideSurroundsViaOnFieldOxide.extent], eachTile: Accumulate, data: via, skip: $doNotSkipAnything]; <> IF via.hasPoly THEN MarkError [where.cell, state, [CDBasicsInline.DeMapRect [rect, where.t], rt.viaOnFieldOxideAvoidsPoly.msg]] END; ENDCASE => NULL -- no violation END; -- LookUnderneath <> <> <> <
> IF (Intersecting [(Bloat [AtomicWireHull[w1, state], state.tech.maxSeparation]), AtomicWireHull[w2, state]]) THEN BEGIN IF state.viaFlatness THEN BEGIN viaTess _ CStitching.NewTesselation [stopFlag: state.abort]; materialTess _ CStitching.NewTesselation [stopFlag: state.abort] END; [] _ state.attributes.EnumerateGeometry [w1.local, VerifyOuter]; IF state.viaFlatness THEN BEGIN <> currentTransf _ w1.transf; [] _ state.attributes.EnumerateGeometry [w1.local, FindMaterial]; currentTransf _ w2.transf; [] _ state.attributes.EnumerateGeometry [w2.local, FindMaterial]; viaTess.EnumerateArea [rect: CStitching.all, eachTile: LookUnderneath, data: state, skip: empty]; viaTess.TrustedDisposeTesselation []; materialTess.TrustedDisposeTesselation [] END END END; -- CompleteSeparation <> <> <> <> GenistaCMosBwells: PUBLIC Tech; <> LocalState: TYPE ~ REF LocalStateRec; -- needed to mark errors LocalStateRec: TYPE ~ RECORD [globalState: State, obj: CoreCell, wellTess: Tess]; CornerCheckData: TYPE ~ REF CornerCheckDataRec; CornerCheckDataRec: TYPE ~ RECORD [state: LocalState, key: ATOM, rule: DrcCmosb.Rule, detail: Rect _ universe]; doNotAnalyse: ATOM = $DoNotDRC; pWellKey: ATOM ~ CD.LayerKey [pwell]; nWellKey: ATOM ~ CD.LayerKey [nwell]; cachedTess: Tess; -- Assume: no concurrency !!! <> VerifyWells: PUBLIC CellProc ~ BEGIN <> <> rt: CMosbTable ~ NARROW [state.tech.ruleTables, CMosbTable]; localState: LocalState ~ NEW [LocalStateRec _ [state, cell, NIL]]; cornerData: CornerCheckData ~ NEW [CornerCheckDataRec _ [state: localState]]; o: CD.Object ~ CoreGeometry.GetObject [state.attributes, cell]; localState.globalState.currentCell^ _ CDOps.ToRope [o]; localState.wellTess _ IF (cachedTess # NIL) THEN cachedTess ELSE CStitching.NewTesselation [stopFlag: state.abort]; <> EnumerateChipNDale [obj: o, state: localState, how: $getWells]; cornerData.key _ nWellKey; cornerData.rule _ rt.minWidth[nwell]; localState.wellTess.EnumerateArea [universe, CheckCorner, cornerData, none]; cornerData.key _ none; cornerData.rule _ rt.separation[nwell][nwell]; localState.wellTess.EnumerateArea [universe, CheckCorner, cornerData, nWellKey]; <> EnumerateChipNDale [obj: o, state: localState, how: $sex]; EnumerateChipNDale [obj: o, state: localState, how: $contactsPos]; EnumerateChipNDale [obj: o, state: localState, how: $connection]; localState.wellTess.ChangeEnumerateArea [universe, FlagIsland, localState, empty]; EnumerateChipNDale [obj: o, state: localState, how: $contactsInfl]; localState.wellTess.ChangeEnumerateArea [universe, FlagUnconnected, localState, empty]; CStitching.TrustedDisposeTesselation [localState.wellTess] END; -- VerifyWells <> ExtractWells: CD.DrawRectProc ~ BEGIN <<[r: Rect, l: Layer, pr: DrawRef]>> state: LocalState ~ NARROW [pr.devicePrivate]; IF (l = nwell) OR (l = pwell) THEN InsertWell [r: r, type: CD.LayerKey[l], state: state] END; -- ExtractWells InsertContact: CD.DrawRectProc ~ BEGIN <<[r: Rect, l: Layer, pr: DrawRef]>> <> state: LocalState ~ NARROW [pr.devicePrivate]; IF (l = pwellCont) OR (l = nwellCont) THEN ConnectTile [r: r, state: state] END; -- InsertContact PropagateContact: CD.DrawRectProc ~ BEGIN <<[r: Rect, l: Layer, pr: DrawRef]>> <> state: LocalState ~ NARROW [pr.devicePrivate]; IF (l = pwellCont) OR (l = nwellCont) THEN PercolateContact [r: r, state: state] END; -- PropagateContact DeleteContact: CD.DrawRectProc ~ BEGIN <<[r: Rect, l: Layer, pr: DrawRef]>> <> state: LocalState ~ NARROW [pr.devicePrivate]; IF (l = pwellCont) OR (l = nwellCont) THEN DeleteConnected [r: r, state: state] END; -- DeleteContact ExtractDiff: CD.DrawRectProc ~ BEGIN <<[r: Rect, l: Layer, pr: DrawRef]>> state: LocalState ~ NARROW [pr.devicePrivate]; IF (l = ndif) OR (l = pdif) OR (l = pwellCont) OR (l = nwellCont) THEN Inquire [r, l, state] END; -- ExtractDiff EnumerateChipNDale: PROC [obj: CD.Object, state: LocalState, how: ATOM] ~ BEGIN <> dr: CD.DrawRef = CD.CreateDrawRef [[]]; dr.drawRect _ SELECT how FROM $getWells => ExtractWells, $sex => ExtractDiff, $contactsPos => InsertContact, $connection => PropagateContact, $contactsInfl => DeleteContact, ENDCASE => ERROR; dr.drawContext _ DoNotDrawContext; dr.devicePrivate _ state; dr.stopFlag _ state.globalState.abort; obj.class.drawMe [dr, obj] END; -- EnumerateChipNDale <> InsertWell: PROC [r: Rect, state: LocalState, type: ATOM] ~ BEGIN <> rt: CMosbTable ~ NARROW [state.globalState.tech.ruleTables]; wellSpacingViolation: BOOL _ FALSE; errorRect: Rect; OccupyByWell: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> WITH oldValue SELECT FROM well: ATOM => IF (well # type) THEN {wellSpacingViolation _ TRUE; errorRect _ rect}; ENDCASE => -- by Cedar definition we always come here if oldValue is NIL CStitching.ChangeRect [plane: state.wellTess, rect: rect, new: type] END; -- OccupyByWell state.wellTess.ChangeEnumerateArea [r, OccupyByWell, type, nothing]; IF wellSpacingViolation THEN MarkError [state.obj, state.globalState, [errorRect, rt.wellConflict.msg]] END; -- InsertWell ConnectTile: PROC [r: Rect, state: LocalState] ~ BEGIN <> Contact: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> WITH oldValue SELECT FROM well: ATOM => state.wellTess.ChangeRect [rect: rect, new: $hasContact]; ENDCASE => NULL -- a well contact on substrate gave an error in the sex check, maximum separation of substrate contacts not checkd for the moment END; -- Contact state.wellTess.ChangeEnumerateArea [r, Contact, NIL, empty] END; -- ConnectTile PercolateContact: PROC [r: Rect, state: LocalState] ~ BEGIN <> DoTile: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> tile: Tile ~ state.wellTess.FindTile [[rect.x1+1, rect.y1+1]]; WITH oldValue SELECT FROM cond: ATOM => IF (cond = $hasContact) THEN BEGIN tile.value _ $expanding; state.wellTess.EnumerateNeighborhood [tile, Expand, Expand, Expand, Expand, NIL, empty]; tile.value _ $expanded END; ENDCASE => ERROR END; -- DoTile Expand: CStitching.TileProc ~ BEGIN <<[tile: Tile, data: REF]>> WITH tile.value SELECT FROM cond: ATOM => IF (cond = $expanded) OR (cond = $expanding) THEN NULL ELSE BEGIN tile.value _ $expanding; state.wellTess.EnumerateNeighborhood [tile, Expand, Expand, Expand, Expand, NIL, empty]; tile.value _ $expanded END; ENDCASE => NULL -- substrate stops expansion END; -- Expand state.wellTess.ChangeEnumerateArea [r, DoTile, NIL, empty] END; -- PercolateContact DeleteConnected: PROC [r: Rect, state: LocalState] ~ BEGIN <> rt: CMosbTable ~ NARROW [state.globalState.tech.ruleTables]; DeleteRectangle: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> WITH oldValue SELECT FROM any: ATOM => state.wellTess.ChangeRect [rect: rect, new: empty]; ENDCASE => ERROR END; -- DeleteRectangle state.wellTess.ChangeEnumerateArea [Bloat [r, rt.wellContactSpacing.extent], DeleteRectangle, NIL, empty] END; -- DeleteConnected <> Inquire: PROC [r: Rect, layer: Layer, state: LocalState] ~ BEGIN <> rt: CMosbTable ~ NARROW [state.globalState.tech.ruleTables]; bloatedRect: Rect; wells: Region; ispDiff: BOOL ~ (layer = pdif); ispCont: BOOL ~ (layer = nwellCont); isnDiff: BOOL ~ (layer = ndif); isnCont: BOOL ~ (layer = pwellCont); isP: BOOL ~ (ispDiff OR ispCont); isN: BOOL ~ (isnDiff OR isnCont); IF NOT CDBasics.NonEmpty[r] THEN RETURN; -- empty rectangle <> wells _ state.wellTess.ListArea [rect: r, skip: nothing]; FOR w: Region _ wells, w.rest WHILE w # NIL DO well: ATOM _ NARROW [w.first.value]; IF (isP AND (well = fieldOxide)) OR (isP AND (well = pWellKey)) THEN MarkError [state.obj, state.globalState, [w.first.rect, rt.PinP.msg]]; IF (isN AND (well = nWellKey)) THEN MarkError [state.obj, state.globalState, [w.first.rect, rt.NinN.msg]] ENDLOOP; <> IF (ispDiff OR isnDiff) THEN BEGIN bloatedRect _ Bloat [r, rt.nWellSurround.extent]; wells _ state.wellTess.ListArea [rect: bloatedRect, skip: nothing]; FOR w: Region _ wells, w.rest WHILE w # NIL DO well: ATOM _ NARROW [w.first.value]; IF (ispDiff AND (well = fieldOxide)) OR (ispDiff AND (well = pWellKey)) THEN MarkError [state.obj, state.globalState, [w.first.rect, rt.nWellSurround.msg]]; IF (isnDiff AND (well = nWellKey)) THEN MarkError [state.obj, state.globalState, [w.first.rect, rt.pWellSurround.msg]] ENDLOOP END ELSE BEGIN -- is contact bloatedRect _ Bloat [r, rt.nWellContact.extent]; wells _ state.wellTess.ListArea [rect: bloatedRect, skip: nothing]; FOR w: Region _ wells, w.rest WHILE w # NIL DO well: ATOM _ NARROW [w.first.value]; IF (ispCont AND (well = fieldOxide)) OR (ispCont AND (well = pWellKey)) THEN MarkError [state.obj, state.globalState, [w.first.rect, rt.nWellContact.msg]]; IF (isnCont AND (well = nWellKey)) THEN MarkError [state.obj, state.globalState, [w.first.rect, rt.pWellContact.msg]] ENDLOOP END END; -- Inquire CheckCorner: CStitching.TileProc ~ BEGIN <<[tile: Tile, data: REF] for EnumerateArea>> t: ATOM ~ NARROW [tile.value]; task: CornerCheckData ~ NARROW [data]; IF (t = task.key) THEN IF (tile.value # tile.SW.value) AND (tile.value # tile.WS.value) THEN BEGIN task.detail _ [tile.WEdge, tile.SEdge, tile.WEdge + task.rule.extent, tile.SEdge + task.rule.extent]; task.state.wellTess.EnumerateArea [task.detail, FlagIfNot, task, nothing] END; IF (tile.value # tile.EN.value) AND (tile.value # tile.NE.value) THEN BEGIN task.detail _ [tile.EEdge - task.rule.extent, tile.NEdge - task.rule.extent, tile.EEdge, tile.NEdge]; task.state.wellTess.EnumerateArea [task.detail, FlagIfNot, task, nothing] END END; -- CheckCorner FlagIsland: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> state: LocalState ~ NARROW [data]; rt: CMosbTable ~ NARROW [state.globalState.tech.ruleTables]; value: ATOM _ NARROW [oldValue]; IF (value = nWellKey) OR (value = pWellKey) THEN MarkError [state.obj, state.globalState, [rect, rt.isolatedWell.msg]] END; -- FlagIsland FlagUnconnected: CStitching.RectProc ~ BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]>> state: LocalState ~ NARROW [data]; rt: CMosbTable ~ NARROW [state.globalState.tech.ruleTables]; MarkError [state.obj, state.globalState, [rect, rt.wellContactSpacing.msg]] END; -- FlagUnconnected FlagIfNot: CStitching.TileProc ~ BEGIN <<[tile: Tile, data: REF]>> task: CornerCheckData ~ NARROW [data]; IF (tile.value # task.key) THEN BEGIN r: Rect ~ Intersection [tile.Area, task.detail]; MarkError [task.state.obj, task.state.globalState, [r, task.rule.msg]] END END; -- FlagIfNot <> END. <> <> <> <> <> <> <> <> <> <> <> <> <> <Top>DragonCMOSDesignRules.df>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>>