DrcCMOSBimpl.Mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Written by gbb, January 12, 1987 11:55:49 am PST
gbb March 27, 1987 12:10:10 pm 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, errorLayer, Layer, LayerKey, NewLayer, Number, Object, outlineLayer, Position, Rect, selectionLayer, shadeLayer, Technology, undefLayer],
CDAtomicObjects USING [AtomicObsSpecific, DrawList],
CDBasics USING [highposition, MapRect, minposition, NonEmpty],
CDOps USING [LayerRope],
CDProperties USING [GetObjectProp, PutObjectProp, RegisterProperty],
CDRects USING [CreateRect],
CDSimpleRules USING [MaxWidth, MinDist, MinWidth, NotKnown],
CMosB USING [cmosB, cut, cut2, lambda, met, met2, ndif, nwell, nwellCont, ovg, pdif, pol, pwell, pwellCont, wndif, wpdif],
CoreGeometry USING [BBox, CellInstance, EachInstanceProc, EnumerateGeometry, FlattenInstance, Instance, Instances, HasGeometry, Layer, Object, PutGeometry, Rect],
CoreProperties USING [propPrint, PropPrintProc, Props, RegisterProperty, StoreProperties],
CoreOps USING [GetShortWireName],
CoreView USING [AddRectangle, debugViewer],
CStitching USING [all, Area, ChangeRect, Rect, EnumerateArea, ResetTesselation, ChangeEnumerateArea, ListArea, NewTesselation, RectProc, TileProc, Region, Tesselation, Tile],
Drc USING [AtomicWireHull, CellProc, CoreCell, MarkError, State, Tech, Transf, WirePairProc, WireProc],
DrcCMOSB USING [],
DrcDebug USING [break, debug, dLog, pause, trace],
IO USING [atom, card, int, Put1, PutF, PutFR, rope],
Rope USING [Cat, IsEmpty, ROPE],
UserProfile USING [Boolean, CallWhenProfileChanges, ProfileChangedProc];
DrcCMOSBimpl: CEDAR PROGRAM
IMPORTS Atom, CD, CDBasics, CDOps, CDProperties, CDRects, CDSimpleRules, CMosB, CoreGeometry, CoreOps, CoreProperties, CoreView, CStitching, Drc, DrcDebug, IO, Rope, UserProfile
EXPORTS DrcCMOSB
SHARES Drc
~ BEGIN
OPEN CMosB, Drc;
Types and constants
cMosBsimple, cMosBcomplete: PUBLIC Tech;
cMosBsimple does the same thing SoS did; cMosBcomplete verifies all VTI rules eccept for wells and transistors, which are not in Core.
simpleCheck: ATOM ~ CoreProperties.RegisterProperty [$simpleGenista];
completeCheck: ATOM ~ CoreProperties.RegisterProperty [$completeGenista];
CdInsts: TYPE ~ CoreGeometry.Instances;
CdObj: TYPE ~ CoreGeometry.Object;
CoreInst: TYPE ~ CoreGeometry.CellInstance;
FakeInst: TYPE ~ CoreGeometry.Instance;
Layer: TYPE ~ CoreGeometry.Layer;
Rect: TYPE ~ CoreGeometry.Rect;
ROPE: TYPE ~ Rope.ROPE;
Region: TYPE ~ LIST OF REF CStitching.Region;
Tess: TYPE ~ CStitching.Tesselation;
Tile: TYPE ~ CStitching.Tile;
empty: REF ~ NIL;
nothing: REF INT ~ NEW [INT];
rectClass: ATOM ~ $Rect;
aRectClassP: ATOM ~ $C2PDifRect;
aRectClassN: ATOM ~ $C2NDifRect;
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 ~ CD.NewLayer [cmosB, gateKey];
fieldOxide: REF ANY ~ NIL;
illegalLayer: ARRAY Layer OF BOOLALL [TRUE];
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.
maxSep: CD.Number; -- convenience
lambda: CD.Number ~ CMosB.lambda;
ignoreConnectivity: BOOL ← UserProfile.Boolean ["Genista.EmulateMayday", FALSE];
Via flatness rules
In  units from the minimal metal border of the via (not from the cut).
Rule: TYPE ~ RECORD [extent: CD.Number, msg: ROPE];
viaOnFieldOxideAvoidsDiff: Rule ~ [2 * lambda, "separation to diff (advisory)"];
viaOnFieldOxideAvoidsPoly: Rule ~ [2 * lambda, "separation to poly"];
fieldOxideSurroundsViaOnFieldOxide: Rule ~ [MAX [viaOnFieldOxideAvoidsDiff.extent, viaOnFieldOxideAvoidsPoly.extent], "separation to poly or diff"];
diffSurroundsViaOnDiff: Rule ~ [2 * lambda, "insufficient diff surround (advisory)"];
polySurroundsViaOnPoly: Rule ~ [3 * lambda, "insufficient poly surround"];
In the following rules the extent is used only to determine the overlap of the error rectangle.
viaOnPolyAndDiff: Rule ~ [1 * lambda, "topology not flat"]; -- more for the sake of robustness
viaSeparation: Rule ~ [1 * lambda, "via to via separation"]; -- only overlaps checked
viaOverGate: Rule ~ [1 * lambda, "via not allowed over gate"];
viaOverPoly: Rule ~ [1 * lambda, "via not allowed over poly"];
Other rules
diffCutToGate: CD.Number ~ 2 * lambda; -- rule 6.5.1.6
largeDiffCutToGate: CD.Number ~ 3 * lambda; -- rule 6.5.1.6
substrateContToGate: CD.Number ~ 3 * lambda; -- rule 6.5.2.3
wellContToGate: CD.Number ~ 3 * lambda; -- rule 6.5.2.3
gateToGate: CD.Number ~ (5 * lambda) / 2; -- 2.5 l [assume l = 0 (mod 2)]
Utilities
IsCut: PROC [layer: Layer] RETURNS [BOOL] ~ INLINE BEGIN
RETURN [(layer = cut) OR (layer = cut2)]
END; -- IsCut
IsWell: PROC [layer: Layer] RETURNS [BOOL] ~ INLINE BEGIN
RETURN [(layer = pwell) OR (layer = nwell)]
END; -- IsWell
IsAbstract: PROC [layer: Layer] RETURNS [BOOL] ~ INLINE BEGIN
RETURN [(layer = wndif) OR (layer = wpdif)]
END; -- IsAbstract
SameRect: PROC [r1, r2: Rect, l1, l2: Layer] RETURNS [BOOL] ~ INLINE BEGIN
RETURN [(l1 = l2) AND (r1 = r2)]
END; -- SameRect
Intersecting: PROC [r1, r2: Rect] RETURNS [BOOL] ~ INLINE BEGIN
r1 and r2 are assumed to be closed.
RETURN [(r1.x1 <= r2.x2) AND (r2.x1 <= r1.x2) AND (r1.y1 <= r2.y2) AND (r2.y1 <= r1.y2)]
END; -- Intersecting
IntersectingOpen: PROC [r1, r2: Rect] RETURNS [BOOL] ~ INLINE BEGIN
r1 and r2 are assumed to be open.
RETURN [(r1.x1 < r2.x2) AND (r2.x1 < r1.x2) AND (r1.y1 < r2.y2) AND (r2.y1 < r1.y2)]
END; -- IntersectingOpen
Intersection: PROC [r1, r2: Rect] RETURNS [Rect] ~ INLINE BEGIN
r1 and r2 are assumed to be closed and intersecting.
RETURN [[MAX [r1.x1, r2.x1], MAX [r1.y1, r2.y1], MIN [r1.x2, r2.x2], MIN [r1.y2, r2.y2]]]
END; -- Intersection
Size: PROC [r: CD.Rect] RETURNS [s: CD.Position] ~ INLINE BEGIN
s.x ← (r.x2 - r.x1); s.y ← (r.y2 - r.y1)
END; -- Size
Bloat: PROC [r: Rect, a: CD.Number] RETURNS [Rect] ~ INLINE BEGIN
r1 and r2 are assumed to be closed and intersecting.
RETURN [[(r.x1 - a), (r.y1 - a), (r.x2 + a), (r.y2 + a)]]
END; -- Bloat
DeleteRect: PROC [plane: Tess, rect: Rect] ~ BEGIN
plane.ChangeRect [rect, empty]
END;
LayerName: PROC [l: Layer] RETURNS [ROPE] ~ INLINE BEGIN
RETURN [Atom.GetPName [CD.LayerKey [l]]]
END; -- LayerName
PrintChecked: CoreProperties.PropPrintProc ~ BEGIN
to.Put1 [IO.rope ["Verified by Genista. "]]
END; -- PrintChecked
EmulateMayday: UserProfile.ProfileChangedProc ~ BEGIN
ignoreConnectivity ← UserProfile.Boolean ["Genista.EmulateMayday", FALSE]
END; -- EmulateMayday
AddDrcProcs: PUBLIC PROC [tech: ATOM, w: WireProc ← NIL, wp: WirePairProc ← NIL, c: CellProc ← NIL] ~ BEGIN
Only one implementation can own the variable, other have to use this procedure. If a proc is NIL, it is not set.
SELECT tech FROM
cMosBsimple.checkedBy => BEGIN
IF (w # NIL) THEN cMosBsimple.verifyWire ← w;
IF (wp # NIL) THEN cMosBsimple.verifyWirePair ← wp;
IF (c # NIL) THEN cMosBsimple.verifyCell ← c
END;
cMosBcomplete.checkedBy => BEGIN
IF (w # NIL) THEN cMosBcomplete.verifyWire ← w;
IF (wp # NIL) THEN cMosBcomplete.verifyWirePair ← wp;
IF (c # NIL) THEN cMosBcomplete.verifyCell ← c
END;
ENDCASE => ERROR
END; -- AddDrcProcs
Width Verification Procedures
SimpleWidthCheck: 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.BBox [instance];
IF DrcDebug.debug 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 THEN CDProperties.PutObjectProp [o, DrcDebug.trace, DrcDebug.trace];
IF illegalLayer[l] THEN BEGIN
MarkError [cell, state, [r, Rope.Cat ["Illegal layer ", LayerName [l], " (wire ", CoreOps.GetShortWireName[w], ")"]]];
RETURN
END;
min ← CDSimpleRules.MinWidth [l]; max ← CDSimpleRules.MaxWidth [l];
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, Rope.Cat ["Width violation on layer ", Atom.GetPName [CD.LayerKey [l]], " (wire ", CoreOps.GetShortWireName[w], ")"]]]
END; -- VerifyRect
[] ← state.attributes.EnumerateGeometry [w, VerifyRect]
END; -- SimpleWidthCheck
maxContSize: CD.Number ~ CDSimpleRules.MaxWidth [cut];
minContSize: CD.Number ~ CDSimpleRules.MinWidth [cut];
maxViaSize: CD.Number ~ CDSimpleRules.MaxWidth [cut2];
minViaSize: CD.Number ~ CDSimpleRules.MinWidth [cut2];
splitContWidth: CD.Number ~ minContSize;
splitContHeight: CD.Number ~ maxContSize + lambda;
minPadSize: CD.Number ~ 117 * lambda;
FullWireCheck: WireProc ~ BEGIN
[cell: CoreCell, w: Wire, state: State]
Intendend to converge towards 100% coverage.
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.BBox [instance];
size: CD.Position ~ Size [r];
IF DrcDebug.debug 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
aRectClassP, aRectClassN => BEGIN
quit ← CoreGeometry.FlattenInstance [instance, VerifyRect]; RETURN
END;
$C2SimpleCon, $C2WellSimpleCon, $C2LargeSimpleCon, $C2LargeWellSimpleCon, $C2DifShortCon, $C2WellDifShortCon, $C2Via, $C2LargeVia => BEGIN
VerifyContact [o, r]; RETURN
VerifyContact does all necessary verifications, no "flattening" necessary.
END;
markClass, segmentClass, pinClass => RETURN;
$CLWellTrans => BEGIN
MarkError [cell, state, [r, "Antique transistor class $CLWellTrans is illegal"]];
RETURN
END;
$C2Trans, $C2WellTrans, $C2LTrans, $C2LWellTrans => BEGIN
MakeTransistor [o, cell, state, r];
RETURN-- Atomic object correct by construction
END;
ENDCASE => BEGIN
quit ← CoreGeometry.FlattenInstance [instance, VerifyRect]; RETURN
END;
IF DrcDebug.debug THEN CDProperties.PutObjectProp [o, DrcDebug.trace, DrcDebug.trace];
IF 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 ", CoreOps.GetShortWireName[w], ")"]]];
RETURN
END;
min ← CDSimpleRules.MinWidth [l]; max ← CDSimpleRules.MaxWidth [l];
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
MarkError [cell, state, [r, Rope.Cat ["Width violation on layer ", Atom.GetPName [CD.LayerKey [l]], " (wire ", CoreOps.GetShortWireName[w], ")"]]]
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;
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, $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 ", CoreOps.GetShortWireName[w], ")"]]]
END; -- VerifyContact
[] ← state.attributes.EnumerateGeometry [w, VerifyRect]
END; -- FullWireCheck
MakeTransistor: PROC [obj: CdObj, cell: CoreCell, state: State, bb: Rect] ~ BEGIN
DrcImpl executes this procedure before it calls the WirePairProc. Ignore wells since all of Core ignores them, so what the heck, it's a hack anyway !
MakeInst: PROC [r: Rect, l: Layer] RETURNS [CoreGeometry.Instance] ~ INLINE BEGIN
RETURN [[CDRects.CreateRect [Size[r], l], [[r.x1, r.y1], original]]]
END; -- MakeInst
tClass: ATOM ~ obj.class.objectType;
isNType: BOOL ~ (obj.layer = ndif);
source, drain, channel: CoreGeometry.Instances;
sep: CD.Number ~ CDSimpleRules.MinDist [ndif, pol];
difToPolExtSep: CD.Number ~ 0; -- polSpacing - extensionLength;
this constant used to be zero and was used to control the separation between transistor gates, the separation of well and substrate contacts to unrelated diffusion. Grow terms are packed and may not be negative. Therefore unmade change.
extensionLength: CD.Number ~ 3 * lambda; -- source/drain extension [rule 6.3.18]
extSep: CD.Number ~ difToPolExtSep;
rect: Rect;
polList, difList, chList, difListSouth: LIST OF Rect ← NIL;
length, width, extL, extW: CD.Number;
IF state.attributes.HasGeometry [cell.public[0]] AND state.attributes.HasGeometry [cell.public[1]] AND state.attributes.HasGeometry [cell.public[2]] THEN RETURN;
Get the geometry. Streching information has already been procesed by ChipNDale.
IF ISTYPE [obj.specific, CDAtomicObjects.AtomicObsSpecific] THEN
FOR geom: CDAtomicObjects.DrawList ← NARROW [obj.specific, CDAtomicObjects.AtomicObsSpecific].rList, geom.rest WHILE geom # NIL DO
SELECT geom.first.layer FROM
pol => polList ← CONS [geom.first.r, polList];
ndif, pdif => difList ← CONS [geom.first.r, difList];
nwell, pwell => NULL;
ENDCASE => MarkError [cell, state, [geom.first.r, "Unknown transistor geometry"]]
ENDLOOP
ELSE MarkError [cell, state, [bb, "Replace this old Chipmonk transistor"]];
Process the geometry according to the transistor class. The ChipNDale transistors are fully supported for p substrate.
SELECT tClass FROM
$C2Trans, $C2WellTrans => BEGIN-- straight transistors
difRect, polRect, chRect, difExtRectNorth, difExtRectSouth, polExtEast, polExtWest: Rect;
difRect ← difList.first; polRect ← polList.first;
chRect ← [difRect.x1, polRect.y1, difRect.x2, polRect.y2];
difExtRectNorth ← difExtRectSouth ← difRect;
difExtRectNorth.y1 ← polRect.y2; difExtRectSouth. y2 ← polRect.y1;
polExtWest ← [polRect.x1, polRect.y1, difRect.x1, polRect.y2];
polExtEast ← [difRect.x2, polRect.y1, polRect.x2, polRect.y2];
length ← polRect.y2 - polRect.y1; width ← difRect.x2 - difRect.x1;
extL ← polRect.y1 - difRect.y1; extW ← difRect.x1 - polRect.x1;
IF (extL < extensionLength) THEN MarkError [cell, state, [bb, "Extension length too small"]];
channel ← LIST [MakeInst [polExtEast, pol], MakeInst [polExtWest, pol], MakeInst [chRect, gate]];
source ← LIST [MakeInst [difExtRectNorth, obj.layer]];
drain ← LIST [MakeInst [difExtRectSouth, obj.layer]];
END; -- case $CTrans
$C2LTrans, $C2LWellTrans => BEGIN-- angle transistors
diffNE: CD.Position ← CDBasics.minposition;
diffSW, polSW: CD.Position ← CDBasics.highposition;
polHor, polVert, polExtWest, polExtNorth, chRectH, chRectV: Rect;
IF ((polList.first.y2-polList.first.y1) < (polList.rest.first.y2-polList.rest.first.y1)) THEN
{polHor ← polList.first; polVert ← polList.rest.first}
ELSE {polHor ← polList.rest.first; polVert ← polList.first};
FOR diff: LIST OF Rect ← difList, diff.rest WHILE diff # NIL DO
IF (diff.first.x1 <= diffSW.x) AND (diff.first.y1 <= diffSW.y) THEN
diffSW ← [diff.first.x1, diff.first.y1];
IF (diff.first.x2 >= diffNE.x) AND (diff.first.y2 >= diffNE.y) THEN
diffNE ← [diff.first.x2, diff.first.y2];
ENDLOOP;
polSW ← [polHor.x1, polHor.y1];
extW ← diffSW.x - polSW.x;
extL ← polSW.y - diffSW.y;
length ← polHor.y2 - polHor.y1;
IF (extL < extensionLength) THEN MarkError [cell, state, [bb, "Extension length too small"]];
polExtWest ← [polSW.x, polSW.y, diffSW.x, polHor.y2];
polExtNorth ← [diffNE.x-extL-length, diffNE.y, diffNE.x-extL, polHor.y2];
chRectH ← polHor; chRectH.x1 ← chRectH.x1 + extW;
chRectV ← polVert;
chRectV.y1 ← chRectV.y1 + length; chRectV.y2 ← chRectV.y2 - extW;
channel ← LIST [MakeInst [polExtWest, pol], MakeInst [polExtNorth, pol], MakeInst [chRectH, gate], MakeInst [chRectV, gate]];
Process channel lead-in
BEGIN-- Bogus but first approx. for a fast impl.
d: CD.Number ← extL + length + sep;
rect ← [x1: diffSW.x, y1: diffSW.y+extL+length, x2: diffNE.x-extL-length, y2: diffSW.y+d];
source ← LIST [MakeInst [rect, obj.layer]]; -- North
rect ← [x1: diffNE.x-d, y1: diffSW.y+extL+length, x2: diffNE.x-extL-length, y2: diffNE.y];
source ← CONS [MakeInst [rect, obj.layer], source]; -- West
d ← extL - sep;
rect ← [x1: diffSW.x, y1: diffSW.y+d, x2: diffNE.x-d, y2: diffSW.y+extL];
drain ← LIST [MakeInst [rect, obj.layer]]; -- South
rect ← [x1: diffNE.x-extL, y1: diffSW.y+d, x2: diffNE.x-d, y2: diffNE.y];
drain ← CONS [MakeInst [rect, obj.layer], drain] -- East
END-- ch lead-in
END; -- case $C2LTrans, $C2LWellTrans
ENDCASE => MarkError [cell, state, [bb, "Unknown or antique transistor class"]];
state.attributes.PutGeometry [cell.public[0], channel];
state.attributes.PutGeometry [cell.public[1], source];
state.attributes.PutGeometry [cell.public[2], drain]
END; -- MakeTransistor
Separation Verification Procedures
SimpleMaterialSeparation: WirePairProc ~ BEGIN
[cell: CoreCell, w1, w2: WireInstance, 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;
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 (illegalLayer[l2]) THEN RETURN;
r2 ← CDBasics.MapRect [CoreGeometry.BBox [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 ← CDSimpleRules.MinDist [l1, l2 ! CDSimpleRules.NotKnown => {sep ← 0; ERROR}];
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 THEN CoreView.AddRectangle [CoreView.debugViewer, r1, w1.local];
IF IntersectingOpen [b1, b2] THEN BEGIN
msg: ROPE ~ "Separation violation between ";
n1: ROPE ~ LayerName[l1].Cat [" (wire ", CoreOps.GetShortWireName[w1.local], ")"];
n2: ROPE ~ LayerName[l2].Cat [" (wire ", CoreOps.GetShortWireName[w2.local], ")"];
MarkError [cell, state, [Intersection [b1, b2], msg.Cat [n1, " 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 (illegalLayer[l1]) THEN RETURN;
r1 ← CDBasics.MapRect [CoreGeometry.BBox [instance], w1.transf];
quit ← state.attributes.EnumerateGeometry [w2.local, VerifyInner]
END; -- VerifyOuter
IF (Intersecting [(Bloat [AtomicWireHull[w1, state], maxSep]),
(Bloat [AtomicWireHull[w2, state], maxSep])]) THEN
[] ← state.attributes.EnumerateGeometry [w1.local, VerifyOuter]
END; -- SimpleMaterialSeparation
cachedTess1, cachedTess2: Tess; -- Assume: no concurrency !!!
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: WirePairProc ~ BEGIN
[cell: CoreCell, w1, w2: WireInstance, 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);
viaTess: Tess ~ IF (cachedTess1 # NIL) THEN cachedTess1 ELSE CStitching.NewTesselation [stopFlag: state.abort];
materialTess: Tess ~ IF (cachedTess2 # NIL) THEN cachedTess2 ELSE CStitching.NewTesselation [stopFlag: state.abort];
currentTransf: Transf;
impiccatiUno, impiccatiDue, strozzatiUno, strozzatiDue: BOOLFALSE;
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 mi viene concesso. Quindi non mi resta altro da fare che simularlo. @#&!
VerifyOuter: CoreGeometry.EachInstanceProc ~ BEGIN
PROC [instance: CdInsts] RETURNS [quit: BOOLFALSE]
r1: Rect; o1: CdObj ~ instance.obj; l1: Layer ~ o1.layer;
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;
quit ← state.abort^;
SELECT o2.class.objectType FROM
rectClass => IF (l2 <= specialLayers) OR (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.
aRectClassP, aRectClassN => BEGIN
quit ← CoreGeometry.FlattenInstance [instance, VerifyInner]; RETURN
END;
markClass, segmentClass, pinClass => RETURN;
ENDCASE => BEGIN-- vedasi commento al livello pi u esterno
impiccatiDue ← ((o2.class.objectType = $C2SimpleCon) AND (l2 = ndif)) OR ((o2.class.objectType = $C2WellSimpleCon) AND (l2 = pdif));
strozzatiDue ← ((o2.class.objectType = $C2LargeSimpleCon) AND (l2 = ndif)) OR ((o2.class.objectType = $C2LargeWellSimpleCon) AND (l2 = pdif));
quit ← CoreGeometry.FlattenInstance [instance, VerifyInner];
RETURN
END;
IF (IsAbstract [l1] OR IsAbstract [l2]) OR ((o1.class.objectType # rectClass) OR (o2.class.objectType # rectClass)) THEN
SIGNAL DrcDebug.break; -- should never happen
r2 ← CDBasics.MapRect [CoreGeometry.BBox [instance], w2.transf];
IF (l2 = cut2) THEN CStitching.ChangeEnumerateArea [viaTess, r2, OccupyTile, NEW [ViaTileDataRec], nothing];
IF (IsCut [l1] AND IsCut [l2]) THEN {IF (SameRect [r1, r2, l1, l2]) THEN RETURN}
ELSE BEGIN
IF ignoreConnectivity THEN {IF (Intersecting [r1, r2]) THEN RETURN}
ELSE {IF aequipotential THEN RETURN}
END;
IF (l1 = gate) OR (l2 = gate) THEN BEGIN
otherLayer: Layer ~ IF (l1 = gate) THEN l2 ELSE l1;
sep ← SELECT otherLayer FROM
gate => gateToGate,
nwellCont => wellContToGate,
pwellCont => substrateContToGate,
cut => SELECT TRUE FROM
Dato che uno e forzatamente un transistor, ce ne freghiamo.
(impiccatiUno OR impiccatiDue) => diffCutToGate,
(strozzatiUno OR strozzatiDue) => largeDiffCutToGate,
ENDCASE => 0,
ENDCASE => 0
END
ELSE sep ← CDSimpleRules.MinDist [l1, l2 ! CDSimpleRules.NotKnown => {sep ← 0; DrcDebug.break}];
IF (sep = 0) THEN RETURN;
b1 ← Bloat [r1, sep / 2]; b2 ← Bloat [r2, sep / 2];
IF DrcDebug.debug 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, b2] THEN BEGIN
msg: ROPE ~ "Separation violation between ";
name1: ROPE ← CoreOps.GetShortWireName [w1.local];
name2: ROPE ← CoreOps.GetShortWireName [w2.local];
n1, n2: ROPE;
IF name1.IsEmpty THEN name1 ← CoreOps.GetShortWireName [w1.global];
IF name2.IsEmpty THEN name2 ← CoreOps.GetShortWireName [w2.global];
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;
MarkError [cell, state, [Intersection [b1, b2], msg.Cat [n1, " and ", n2]]]
END;
quit ← state.abort^
END; -- VerifyInner
quit ← state.abort^;
SELECT o1.class.objectType FROM
rectClass => IF (l1 <= specialLayers) OR (illegalLayer[l1]) THEN RETURN;
aRectClassP, aRectClassN => BEGIN
quit ← CoreGeometry.FlattenInstance [instance, VerifyOuter]; RETURN
END;
markClass, segmentClass, pinClass => RETURN;
ENDCASE => BEGIN-- vedasi commento al livello pi u esterno
impiccatiUno ← ((o1.class.objectType = $C2SimpleCon) AND (l1 = ndif)) OR ((o1.class.objectType = $C2WellSimpleCon) AND (l1 = pdif));
strozzatiUno ← ((o1.class.objectType = $C2LargeSimpleCon) AND (l1 = ndif)) OR ((o1.class.objectType = $C2LargeWellSimpleCon) AND (l1 = pdif));
quit ← CoreGeometry.FlattenInstance [instance, VerifyOuter];
RETURN
END;
r1 ← CDBasics.MapRect [CoreGeometry.BBox [instance], w1.transf];
IF (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 ← CDBasics.MapRect [CoreGeometry.BBox [instance], currentTransf];
IF NOT (CDBasics.NonEmpty [r]) THEN RETURN; -- empty rectangle
SELECT instance.obj.layer FROM
ndif, pdif, pwellCont, nwellCont => BEGIN
bloatedRect ← Bloat [r, 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, viaOverGate.msg]];
DeleteRect [viaTess, v.first.rect]
END
ENDLOOP;
bloatedRect ← Bloat [r, 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, 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, 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, viaOverGate.msg]];
DeleteRect [viaTess, v.first.rect]
END
ENDLOOP;
bloatedRect ← Bloat [r, 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, 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, diffSurroundsViaOnDiff.extent],
eachTile: Accumulate,
data: via,
skip: $doNotSkipAnything];
IF via.hasFOx THEN
IF IsOnFieldOxide[] THEN MarkError [cell, state, [rect, viaOnFieldOxideAvoidsDiff.msg]]
ELSE MarkError [cell, state, [rect, diffSurroundsViaOnDiff.msg]]
END;
via.hasPoly => BEGIN
CStitching.EnumerateArea [plane: materialTess,
rect: Bloat [rect, polySurroundsViaOnPoly.extent],
eachTile: Accumulate,
data: via,
skip: $doNotSkipAnything];
IF via.hasFOx THEN
IF IsOnFieldOxide[] THEN MarkError [cell, state, [rect, viaOnFieldOxideAvoidsPoly.msg]]
ELSE MarkError [cell, state, [rect, polySurroundsViaOnPoly.msg]]
END;
via.hasFOx => BEGIN
CStitching.EnumerateArea [plane: materialTess,
rect: Bloat [rect, fieldOxideSurroundsViaOnFieldOxide.extent],
eachTile: Accumulate,
data: via,
skip: $doNotSkipAnything];
IF via.hasDiff THEN MarkError [cell, state, [rect, viaOnFieldOxideAvoidsDiff.msg]];
IF via.hasPoly THEN MarkError [cell, state, [rect, viaOnFieldOxideAvoidsPoly.msg]]
END;
ENDCASE => NULL-- no violation
END; -- LookUnderneath
Main
IF (Intersecting [(Bloat [AtomicWireHull[w1, state], maxSep]),
(Bloat [AtomicWireHull[w2, state], maxSep])]) THEN
[] ← state.attributes.EnumerateGeometry [w1.local, VerifyOuter];
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];
CStitching.EnumerateArea [plane: viaTess, rect: CStitching.all, eachTile: LookUnderneath, data: state, skip: empty];
CStitching.ResetTesselation [viaTess];
CStitching.ResetTesselation [materialTess]
END; -- CompleteSeparation
Initialisation
ComputeMaxSeparation: PROC [target: ATOM] RETURNS [max: CD.Number] ~ BEGIN
Conservative (looks at all layers, not only the legal ones).
sep: CD.Number;
max ← 0;
FOR s1: Layer IN Layer DO
IF illegalLayer[s1] THEN LOOP;
FOR s2: Layer IN Layer DO
IF illegalLayer[s2] THEN LOOP;
SELECT target FROM
cMosBsimple.checkedBy => NULL; -- all standard
cMosBcomplete.checkedBy =>
Extractor cannot handle wells adequately.
IF (IsWell [s1] AND IsWell [s2]) THEN LOOP;
ENDCASE => ERROR;
Try to filter out inappropriate layers.
sep CDSimpleRules.MinDist [s1, s2 ! CDSimpleRules.NotKnown => LOOP];
max ← MAX [max, sep]
ENDLOOP
ENDLOOP
END; -- ComputeMaxSeparation
[] ← CDProperties.RegisterProperty [simpleCheck, $gbb];
[] ← CDProperties.RegisterProperty [completeCheck, $gbb];
[] ← CDProperties.RegisterProperty [gateKey, $gbb];
CoreProperties.StoreProperties [prop: simpleCheck, properties: CoreProperties.Props [[CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc ← PrintChecked]]]];
CoreProperties.StoreProperties [prop: completeCheck, properties: CoreProperties.Props [[CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc ← PrintChecked]]]];
IF (CD.undefLayer # 0) THEN ERROR; -- check the definition of specialLayers
illegalLayer[ndif] ← illegalLayer[pdif] ← illegalLayer[pwell] ← illegalLayer[nwell] ← illegalLayer[pwellCont] ← illegalLayer[nwellCont] ← illegalLayer[pol] ← illegalLayer[met] ← illegalLayer[met2] ← illegalLayer[cut] ← illegalLayer[cut2] ← illegalLayer[ovg] ← illegalLayer[gate] ← FALSE;
maxSep ← ComputeMaxSeparation [cMosBsimple.checkedBy];
cMosBsimple ← [simpleCheck, maxSep, lambda, SimpleWidthCheck, SimpleMaterialSeparation];
cMosBcomplete.checkedBy ← completeCheck;
cMosBcomplete.maxSeparation ← ComputeMaxSeparation [cMosBcomplete.checkedBy];
cMosBcomplete.lambda ← lambda;
cMosBcomplete.verifyWire ← FullWireCheck;
cMosBcomplete.verifyWirePair ← CompleteSeparation;
UserProfile.CallWhenProfileChanges [EmulateMayday]
END.