DrcCmosbMainImpl.Mesa
Copyright Ó 1987, 1988 by Xerox Corporation. All rights reserved.
Written by gbb, January 12, 1987 11:55:49 am PST
gbb January 22, 1988 10:48:48 am PST
Genista is the grandson of Spinifex. It is a hierarchical design rule checker that monkeys around in a Core design and tries to find all the ChipNDale geometry in order to check as many design rules as it possibly can.
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;
Types and constants
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];
undefLayer, highLightShade, highLightError, pinRepresentation, outlineLayer, selectionLayer, commentLayer
Warning: CD.undefLayer could not be included in the list because of a minor bug in the compiler, but it should so once the bug is fixed.
lambda: CD.Number ~ CMosB.lambda;
detail: BOOLFALSE;
Ze rulez
Moved to own module:
Cedar 7 Compiler of December 18, 1987 5:21:06 pm PST
DrcCMOSBimpl.errlog -- January 18, 1988 3:05:25 pm PST
Storage overflow in Pass 4
Width Verification Procedures
SimpleWidthCheck: PUBLIC WireProc ~ BEGIN
[cell: CoreCell, w: Wire, state: State]
At the moment our simplicistic approach does not have any knowledge of the topology. Therefore we cannot really test this rule.
VerifyRect: CoreGeometry.EachInstanceProc ~ BEGIN
PROC [instance: [obj: Object, trans: Transformation]] RETURNS [quit: BOOLFALSE]
Note, that although the rectangle r is examinated in isolation and his position is not relevant for verification purposes, the correct position is necessary to indicate violations.
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
CDProperties.PutObjectProp [ob, $break, $break]
END;
SELECT o.class.objectType FROM
rectClass => IF (l <= specialLayers) THEN RETURN;
markClass, segmentClass, pinClass => RETURN;
ENDCASE => quit ← CoreGeometry.FlattenInstance [instance, VerifyRect];
IF (o.class.objectType # rectClass) OR (l <= specialLayers) OR (IsCut [l]) THEN RETURN;
Note: the width rules for cuts depend on the class.
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]
Intendend to converge towards 100% coverage. It will throw everything in a set of corner stitched planes and check the width, separation on the same layer and find notches.
rt: CMosbTable ~ NARROW [state.tech.ruleTables];
minPadSize: CD.Number ~ rt.minPadSize.extent;
VerifyRect: CoreGeometry.EachInstanceProc ~ BEGIN
PROC [instance: [obj: Object, trans: Transformation]] RETURNS [quit: BOOLFALSE]
Note, that although the rectangle r is examinated in isolation and his position is not relevant for verification purposes, the correct position is necessary to indicate violations.
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
CDProperties.PutObjectProp [ob, $break, $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
VerifyContact does all necessary verifications, no "flattening" necessary.
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
The width rules for cuts depend on the class.
size: CD.Position;
sizeExceeded: BOOLFALSE;
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
Separation Verification Procedures
SimpleMaterialSeparation: PUBLIC WirePairProc ~ BEGIN
[where: Context, w1, w2: WireInstance, relatedWires: REF ANYNIL, window: Rect, state: State]
If two unrelated bloated rectangles of material intersect, an error is flagged.
The parameter cell selects the cell receiving possible error messages. It must be the father of the cell containing w1 and the cell containing w2.
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
PROC [instance: CdInsts] RETURNS [quit: BOOLFALSE]
VerifyInner: CoreGeometry.EachInstanceProc ~ BEGIN
PROC [instance: CdInsts] RETURNS [quit: BOOLFALSE]
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: BOOLFALSE, -- diffusion
hasPoly: BOOLFALSE, -- polysilicide
hasFOx: BOOLFALSE]; -- 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 ANYNIL, window: Rect, state: State]
If two unrelated bloated rectangles of material intersect, an error is flagged.
The parameter where selects the cell receiving possible error messages. It should be the father of the cell containing w1 and the cell containing w2.
aequipotential: BOOL ~ (w1.global = w2.global);
viaTess, materialTess: Tess;
currentTransf: Transf;
outer: FakeInst;
outerIsDiffCont, outerIsLargeDiffCont, innerIsDiffCont, innerIsLargeDiffCont: BOOLFALSE;
Storage of current context. La seconda gran coglionata della settimana: CoreGeometry.EachInstanceProc dovrebbe fornire come parametro la classe dell'oggetto che sta essendo traversato. Sfortunatamente per motivi pi u che altro politici, cio non viene concesso. Quindi non mi resta altro da fare che simularlo.
rt: CMosbTable ~ NARROW [state.tech.ruleTables];
VerifyOuter: CoreGeometry.EachInstanceProc ~ BEGIN
PROC [instance: CdInsts] RETURNS [quit: BOOLFALSE]
r1, maxBloat1: Rect; o1: CdObj ~ instance.obj;
l1: Layer ~ o1.layer; c1: ATOM ~ o1.class.objectType;
VerifyInner: CoreGeometry.EachInstanceProc ~ BEGIN
PROC [instance: CdInsts] RETURNS [quit: BOOLFALSE]
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;
In Core wells are considered part of the node to which the diffusion that brought them with them came, not of VDD. Hence all wells automatically violate the separation rule. Wells in the sense of the well layer usually used in DA tools do not exist in Core, so nothing can go wrong simply filtering out wells altogether and treating them in a special hack bypassing Core.
wellRectClass => NULL;
markClass, segmentClass, pinClass => RETURN;
ENDCASE => BEGIN-- vedasi commento al livello pi u esterno
Prune "distant" contacts.
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;
IF (IsAbstract [l1] OR IsAbstract [l2]) OR ((o1.class.objectType # rectClass) OR (c2 # rectClass)) THEN
SIGNAL DrcDebug.break; -- should never happen
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];
Special case for parallel transistors: a channel of one transistor may intersect the gate of another transistor.
IF ((l1 = gate) AND ((l2 = pdif) OR (l2 = ndif))) OR ((l2 = gate) AND ((l1 = pdif) OR (l1 = ndif))) THEN {Anathema [2, state]; RETURN};
The ChipNDale atomic objects for transistors have fixed channels of length 3l. When transistors are put in series, they are placed at 2.5l. Therefore, a channel must be allowed to abut to a gate extension. In the current implementation we are very lax and do not check the separation among channels and gate extensions:
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};
Mirroed cells are quite frequent, especially in memories. Moreover, each cel is compared against itself in order to perform correctly the above statement for the via flatness. Note that this test is stronger than testing pointers.
IF (aequipotential AND SameRect [r1, r2, l1, l2]) THEN RETURN;
The VTI rule 6.7.1.2 allows vias over poly. However, rule 6.7.6. requires a spacing if there is no overlap. Hence, in the simple test the check for vias over poly is skipped. Rule 6.7.7. for minimum poly overlap of a via inside poly is verified by the via flatness check.
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
Core data structure is incorrect: w1 ` w2, but they actually are connected.
BothRec: TYPE ~ RECORD [a, b: WireInstance];
both: REF BothRec ← NEW [BothRec ← [w1, w2]];
IF DrcDebug.debug THEN
coreInconsistent ["w1 # w2, but they actually are connected", both]
ELSE BEGIN
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
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;
Discrimination between poly and diff contacts. (VTI rules 6.3.3, 6.7.8, and 6.5.1.7)
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]];
DrcDebug.break
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: BOOLTRUE;
Special case VTI rule 6.3.4.
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 at this point we have two cuts, there is a mis-registration, which always is an error.
IF ignoreConnectivity AND (SameLayer [l1, l2]) THEN BEGIN
Must renormalize because gap is smaller than separation rule.
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};
Transistors are atomic objects and used as such in ChipNDale, but cells in Core. This means that the requirement that cells be correct in isolation cannot be enforced for transistors. The variable relatedWires contains wires that could contain geometry that fixes a design rule violation at a different hierarchical level.
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
Core data structure is incorrect: w1 ` w2, but they actually are connected.
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
coreInconsistent ["w1 # w2, but they actually are connected", both]
END
END;
errorRegion ← GapIsFilled [gap, l2, w2, state];
IF (errorRegion = empty) THEN BEGIN
IF aequipotential THEN {Anathema [1, state]; RETURN}
ELSE BEGIN
Core data structure is incorrect: w1 ` w2, but they actually are connected.
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
coreInconsistent ["w1 # w2, but they actually are connected", both]
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
PROC [instance: CdInsts] RETURNS [quit: BOOLFALSE]
Algorithm: 1. If there is antagonist material in a viaOnFieldOxideAvoidsDiff-sphere from a via, then the topology cannot be flat. 2. If r is in a minSurround-sphere from a via, then insert it in the material tesselation.
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
Date: Fri, 5 Jun 87 11:23:27 PDT
From: Hoel.PA
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 2l and that diffusion surround vias on diffusion by 2l is withdrawn.
ndif, pdif, pwellCont, nwellCont => BEGIN
bloatedRect ← Bloat [r, rt.viaOnFieldOxideAvoidsDiff.extent];
vias ← CStitching.ListArea [plane: viaTess, rect: bloatedRect];
FOR v: Region ← vias, v.rest WHILE v # NIL DO
via: ViaTileData ← NARROW [v.first.value];
IF via.hasPoly THEN BEGIN
MarkError [cell, state, [v.first.rect, rt.viaOverGate.msg]];
DeleteRect [viaTess, v.first.rect]
END
ENDLOOP;
bloatedRect ← Bloat [r, rt.diffSurroundsViaOnDiff.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 ← [genericDiff, via]];
IF Intersecting [v.first.rect, r] THEN via.hasDiff ← TRUE;
We insert material in the whole influence area of a via.
bloatedRect ← Bloat [v.first.rect, rt.diffSurroundsViaOnDiff.extent];
CStitching.ChangeEnumerateArea [materialTess, Intersection [bloatedRect, r], OccupyTile, data, nothing]
Note that via always is a single and non-degenerated via, since collisions of vias are detected when the vias are input.
ENDLOOP
END;
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];
IF via.hasDiff THEN BEGIN
MarkError [cell, state, [v.first.rect, rt.viaOverGate.msg]];
DeleteRect [viaTess, v.first.rect]
END
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;
We insert material in the whole influence area of a via.
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]
Looks what is under a via cut.
via: ViaTileData ~ NARROW [tile.value];
rect: CStitching.Rect ~ CStitching.Area [tile];
IsOnFieldOxide: PROC RETURNS [d: BOOLTRUE] ~ INLINE BEGIN
Is the via on field oxide ?
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 L]
ELSE BEGIN
IF (mat.via # via) THEN ERROR; -- Consistency test: Tesselation screwed up
SELECT mat.layerKey FROM
genericDiff => via.hasDiff ← TRUE;
polyKey => via.hasPoly ← TRUE;
ENDCASE => ERROR
END
END; -- Accumulate
At this point we know, what is immediately under the via cut and that there the rule viaOverGate is not violated.
via.hasFOx ← NOT (via.hasDiff OR via.hasPoly);
SELECT TRUE FROM
via.hasDiff => BEGIN
CStitching.EnumerateArea [plane: materialTess,
rect: Bloat [rect, rt.diffSurroundsViaOnDiff.extent],
eachTile: Accumulate,
data: via,
skip: $doNotSkipAnything];
IF via.hasFOx THEN
IF IsOnFieldOxide[] THEN MarkError [cell, state, [rect, rt.viaOnFieldOxideAvoidsDiff.msg]]
ELSE MarkError [cell, state, [rect, rt.diffSurroundsViaOnDiff.msg]]
END;
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.hasDiff THEN MarkError [cell, state, [rect, rt.viaOnFieldOxideAvoidsDiff.msg]];
IF via.hasPoly THEN
MarkError [where.cell, state, [CDBasicsInline.DeMapRect [rect, where.t], rt.viaOnFieldOxideAvoidsPoly.msg]]
END;
ENDCASE => NULL-- no violation
END; -- LookUnderneath
MOVED TO OWN MODULE:
Cedar 7 Compiler of December 18, 1987 5:21:06 pm PST
DrcCmosbMainImpl.errlog -- January 21, 1988 5:25:32 pm PST
Storage overflow in Pass 4
GapIsFilled: PROC [gap: Rect, l: Layer, w: WireInstance, state: State, additionalWire: WireInstance ← notChannel, additionalCells: LIST OF WireSet ← NIL] RETURNS [notch: LIST OF Rect] ~ BEGIN
Main
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
You might think the following: I can make this faster by checking the via flatness for each wire in the per-wire procedure. Then here I just compare the vias of one wire with the material of the other wire. Since every wire is compared with all other wires, there is quite some redundancy the way the bloody first implementor did it. Well, you lose, because you have to look underneath everything to assess flatness.
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
Wells, Etc.
Does the checks concerning wells that cannot be made by Genista because of the lack of wells in the Core data structure. This implementation is "flat", because wells are not layed out hierarchically anyway.
Warning: while I am writing this code I am physically exausted. It starts out to work for n-, p-, and twin-wells. I am making compromises to get the thing flying. Do not try to understand this code.
Types and constants
GenistaCMosBwells: PUBLIC Tech;
Verifies the wells and related stuff taking its information from the ChipNDale design.
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 !!!
Interface
VerifyWells: PUBLIC CellProc ~ BEGIN
In principio questa e una gran coglionata, pi u di natura politica che tecnica. Nella struttura Core non ci sono i cassoni, sostanzialmente perch e l'implentatore dell'estrattore sostiene che non servono a niente. A parte il fatto che non e vero (fanno parte di VDD fintanto che sono connessi), non essendo accessiblili ai clienti (CoreGeometry.EachInstanceProc, ecc. non chiamano i clienti sui cassoni) non possono venir verificati. Dato che nel C-MOS la meta della diffusione e in un cassone e che l'IFU ha dimostrato che errori del genere di diffusione e contatti del tipo sbagliato sono abbastanza frequenti, e vitale verificare queste cose.
In pratica i cassoni di soliti non seguono la gerarchia, per cui questo modulo e "piatto". Dato che i cassoni di solito sono grandi aree connesse, questo non dovrebbe essere troppo grave per la memoria.
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];
Smash wells into a flat tesselation of interesting areas.
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];
Enumerate all diffusion rectangles and perform a query with bloated rectangles. For n-diff, an n-well is an a violation, while for p-dif both a pwell and fieldOxide are a violation.
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
Operations on ChipNDale objects
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]
Ignores sex of contacts since it already has been verified.
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]
Ignores sex of contacts since it already has been verified.
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]
Ignores sex of contacts since it already has been verified.
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
If wells is false, diffusion rectangles are enumerated.
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
Operations on the corner-stitched plane
InsertWell: PROC [r: Rect, state: LocalState, type: ATOM] ~ BEGIN
Inserts a well. This procedure ensures that wells do not overlap.
rt: CMosbTable ~ NARROW [state.globalState.tech.ruleTables];
wellSpacingViolation: BOOLFALSE;
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
Changes the value of the tile with a contact into a contact. Ignores sex of contacts since it already has been verified.
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
Propagates the connectedness of a tile in order to isolate islands.
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
DESTRUCTIVE !!! Verifies that the maximum well contact spacing is fulfilled. Ignores sex of contacts since it already has been verified.
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
Implementation
Inquire: PROC [r: Rect, layer: Layer, state: LocalState] ~ BEGIN
Algorithm: If there is antagonist material in a wellSurround-sphere from diffusion, then the a violation is flagged.
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
Verify diffusion type.
wells ← state.wellTess.ListArea [rect: r, skip: nothing];
FOR w: Region ← wells, w.rest WHILE w # NIL DO
well: ATOMNARROW [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;
Verify surround.
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: ATOMNARROW [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: ATOMNARROW [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: ATOMNARROW [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
Initialisation
END.
gbb May 15, 1987 11:10:37 am PDT
The VTI rule 6.7.1.2 allows vias over poly. However, rule 6.7.6. requires a spacing if there is no overlap. Hence, in the simple test the check for vias over poly is skipped. Rule 6.7.7. for minimum poly overlap of a via inside poly is verified by the via flatness check.
changes to: VerifyInner (local of VerifyOuter, local of CompleteSeparation)
gbb May 27, 1987 11:49:35 am PDT
Changed the default for ignoring the connectivity information in Core.
changes to: ignoreConnectivity: default = TRUE, EmulateMayday: idem.
gbb May 28, 1987 1:38:01 pm PDT
If a gap is found, the wires are re-traversed to determine whether the gap is patched.
changes to: Contains, Intersection, VerifyInner (local of VerifyOuter, local of CompleteSeparation), GapIsFilled (local of CompleteSeparation), FindPatch (local of GapIsFilled, local of CompleteSeparation)
gbb June 2, 1987 4:18:11 pm PDT
Generalised gap finder to detect notches.
changes to: DIRECTORY, VerifyInner (local of VerifyOuter, local of CompleteSeparation), GapIsFilled (local of CompleteSeparation), FindPatch (local of GapIsFilled, local of CompleteSeparation)
gbb June 5, 1987 2:01:03 pm PDT
Speed tweak in the inner loop; eliminated via flatness check of diffusion: 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 2l and that diffusion surround vias on diffusion by 2l is withdrawn. Hoel.PA Fri, 5 Jun 87 11:23:27 PDT; see [Indigo]<Dragon>Top>DragonCMOSDesignRules.df
changes to: VerifyInner (local of VerifyOuter, local of CompleteSeparation), FindMaterial (local of CompleteSeparation), Accumulate (local of LookUnderneath, local of CompleteSeparation), LookUnderneath (local of CompleteSeparation)
gbb June 8, 1987 6:20:21 pm PDT
Sometimes contacts of the class $C2DifShortCon get an additional f: $C2DiffShortCon.
Added correct handling of VTI rule 6.3.4 in the default Mayday emulation mode, which Dracula cannot handle.
changes to: IsDiffContact: additional class $C2DiffShortCon, VerifyInner (local of VerifyOuter, local of CompleteSeparation): a very complex if statement of which I hope the compiler will not generate garbage.
gbb June 24, 1987 3:40:51 pm PDT
Added a check for misregistrations
changes to: VerifyInner (local of VerifyOuter, local of CompleteSeparation)
gbb June 29, 1987 6:19:19 pm PDT
Optimized GapIsFilled.
changes to: GapIsFilled (local of CompleteSeparation), FindPatch (local of GapIsFilled, local of CompleteSeparation), FindFancyPatch (local of GapIsFilled, local of CompleteSeparation)
gbb September 21, 1987 11:20:46 am PDT
The ChipNDale atomic objects for transistors have fixed channels of length 3l. When transistors are put in series, they are placed at 2.5l. Therefore, a channel must be allowed to abut to a gate extension. In the current implementation we are very lax and do not check the separation among channels and gate extensions.
changes to: VerifyInner (local of VerifyOuter, local of CompleteSeparation)
gbb September 23, 1987 5:42:26 pm PDT
Display a message every time the violation of a violation of a dogma but not a rule is encountered.
changes to: DoNotDrawObject, Anathema, VerifyInner (local of VerifyOuter, local of SimpleMaterialSeparation), VerifyOuter (local of SimpleMaterialSeparation), VerifyInner (local of VerifyOuter, local of CompleteSeparation)
gbb September 25, 1987 4:35:39 pm PDT
Relaxed dogma of pairwise width correctness because broken all to often in cell library.
changes to: DIRECTORY, Layer, Anathema, VerifyInner (local of VerifyOuter, local of CompleteSeparation)
gbb October 5, 1987 1:00:41 pm PDT
Made nwellCont the same layer as pdif.
changes to: SameLayer, VerifyInner (local of VerifyOuter, local of CompleteSeparation)
gbb October 5, 1987 2:25:00 pm PDT
Added wnwellCont and wpwellCont to the diffusion contact layers.
changes to: diffContactLayer
gbb January 4, 1988 2:31:24 pm PST
Spinned off DrcUtilities because of a compiler problem: Storage overflow in Pass 4
changes to: DIRECTORY, DrcCMOSBimpl, ~, FakeInst, Region, NewTechnology
gbb January 18, 1988 3:29:09 pm PST
Spinned off DrcCMOSBRules because of a compiler problem: Storage overflow in Pass 4
Worked around false violation reports because of cells incorrect in isolation but correct flat.
changes to: DIRECTORY, DrcCMOSBimpl, ~, cachedTech, sl (local of VerifyInner, local of VerifyOuter, local of CompleteSeparation), GapIsFilled (local of CompleteSeparation)
gbb January 21, 1988 5:38:42 pm PST
Introiduced 2nd coordinate system to flag errors for gaps not found.
Cedar 7 Compiler of December 18, 1987 5:21:06 pm PST
DrcCmosbMainImpl.errlog -- January 21, 1988 5:25:32 pm PST
Storage overflow in Pass 4
GapIsFilled moved to own module.
changes to: DIRECTORY, DrcCmosbMainImpl, ~, SimpleMaterialSeparation, VerifyInner (local of VerifyOuter, local of SimpleMaterialSeparation), CompleteSeparation, VerifyInner (local of VerifyOuter, local of CompleteSeparation), LookUnderneath (local of CompleteSeparation)