SXCMosBImpl.mesa
Copyright © 1984, 1986 by Xerox Corporation. All rights reserved.
Written by gbb, November 25, 1985 6:36:23 pm PST
Last edited by: gbb June 10, 1986 6:54:54 pm PDT
DIRECTORY
CD USING [InstanceList, InterestRect, Layer, Number, Position, Rect],
CDAtomicObjects USING [AtomicObsPtr, DrawList],
CDBasics USING [empty, Extend, highposition, minposition, NonEmpty, RectAt, ToRect],
CDOrient USING [MapPoint],
CDProperties USING [GetInstanceProp],
CDSimpleRules USING [MinDist, MinWidth],
CMosB USING [bur, cmosB, cut, cut2, lambda, met, met2, ndif, nwell, nwellCont, pdif, pol, pwell, pwellCont, wellSurround, wndif, wpdif],
IO USING [atom, char, int, Put, PutF, PutFR, PutRope, rope],
PropertyLists USING [GetProp, PutProp],
Rope USING [Cat, ROPE],
SX USING [AddBox, AddRect, AdjustNode, AttachedNode, BoxMapProc, CellPostProcessProc, Circuit, CircuitNode, CombineNodePropertyProc, Constraint, ConstraintArray, ConstraintIndex, ConstraintResolution, ConversionProc, CreateLinkage, FindRootNode, GeometricRule, IllegalConstruct, LinkageAttach, LookupNode, nodeIndex, NodeLinkage, spaceIndex, SpinifexLayerIndex, techCIndexBase, TechHandle, violateIndex],
SXAccess USING [invocation, sxTech],
SXAccessInternal USING [PutError],
SXAtoms USING [crystalAttr],
SXOutput USING [LinkageHousekeeper, LinkagePrintProc],
SXOutputPrivate USING [GetANaming, NameTransType, Naming, PrintNaming, PrintRoseInstantiationTransformation, UnNameTransType],
SXTechnology USING [ESWGrow, GetCircuitFromCDObject, NESGrow, PerDrawRectProc, RegisterSpinifexObjectProcs, RegisterTechnologyHandle, ResolutionTable, SetUpResolution, WNEGrow, WNGrow],
TerminalIO USING [WriteRope];
SXCMosBImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDOrient, CDProperties, CDSimpleRules, CMosB, IO, PropertyLists, Rope, SX, SXAccess, SXAccessInternal, SXAtoms, SXOutputPrivate, SXTechnology, TerminalIO
~ BEGIN
Basic definitions and rules
l: CD.Number ~ CMosB.lambda;
Nodes: TYPE = LIST OF REF SX.CircuitNode;
ConstraintArray: TYPE ~ SX.ConstraintArray;
CIndex: TYPE ~ SX.ConstraintIndex;
Constraint: TYPE ~ SX.Constraint;
ndif summary
N é P:  MinDist [ndif, pdif] / l => 10
N é N: MinDist [ndif, ndif] / l => 3ý
P é P:  MinDist [pdif, pdif] / l => 3ý
N é N-well: MinDist [ndif, nwell] / l => 5
P é P-well: MinDist [pdif, pwell] / l => 5
N é P-well-contact: MinDist [ndif, pwellCont] / l => 3ý [rules 6.3.6 + 6.3.7]
P é N-well-contact: MinDist [pdif, nwellCont] / l => 3ý [rules 6.3.6 + 6.3.7]
N é N-well-contact: MinDist [ndif, nwellCont] / l => 9
P é P-well-contact: MinDist [pdif, pwellCont] / l => 9
N-well é P-well-contact: MinDist [nwell, pwellCont] / l => 4 [rule 6.3.9]
P-well é N-well-contact: MinDist [pwell, nwellCont] / l => 4 [rule 6.3.9]
N-well-contact é P-well-contact: MinDist [nwellCont, pwellCont] / l => 8 [rule 6.3.6]
ndif layer
ndifSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.ndif, CMosB.ndif]; -- (3ý l)
ndifWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.ndif];
ndifUncSubtrContSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.ndif, CMosB.pwellCont];
n-Diffusion/unconnected p-substrate-contact spacing (3ý l)
ndifInnWell: CD.Number = 0 * l;
n-Diffusion in n-Well (0 l)
ndifpSubstrCont: CD.Number = CDSimpleRules.MinDist [CMosB.ndif, CMosB.pwellCont];
n-Diffusion and p-substrate-contact (3ý l)
pdif layer
pdifSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.pdif, CMosB.pdif]; -- (3ý l)
pdifWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.pdif];
pdifUncnWellSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.pdif, CMosB.nwellCont];
p-Diffusion/unconnected n-Well-contact spacing (3ý l)
pdifnWellCont: CD.Number = 0 * l;
p-Diffusion and n-Well-contact
pol layer
polSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.pol, CMosB.pol];
polWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.pol];
polUncDifSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.pol, CMosB.ndif];
Poly/unconnected Diffusion spacing (1 l)
polDiffUncPolySpacing: CD.Number = CDSimpleRules.MinDist [CMosB.ndif, CMosB.pol];
Diffusion/unconnected Poly spacing (1 l)
polOverDiff: CD.Number = 0 * l;
Poly over Diffusion
met layer
metSeparation: CD.Number = CDSimpleRules.MinDist [CMosB.met, CMosB.met];
metWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.met];
metCutCutSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.cut, CMosB.cut];
Cut to Cut spacing (3 l)
metViaViaSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.cut2, CMosB.cut2];
Via to Via spacing (4 l)
metCutViaSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.cut, CMosB.cut2];
Cut to Via spacing (2 l)
met2 layer
met2Separation: CD.Number = CDSimpleRules.MinDist [CMosB.met2, CMosB.met2];
met2Width: CD.Number = CDSimpleRules.MinWidth [CMosB.met2];
Some of these numbers are half of the actual minimum distances we are checking for:
difSep: CD.Number = ndifSpacing / 2; -- (3ý l / 2)
wellSep: CD.Number = CDSimpleRules.MinDist [CMosB.nwell, CMosB.nwell]; -- (10 l)
wellWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.nwell];  -- (12 l)
nDifToWell: CD.Number = CDSimpleRules.MinDist [CMosB.ndif, CMosB.nwell]; -- (5 l)
pDifToWell: CD.Number = CDSimpleRules.MinDist [CMosB.pdif, CMosB.pwell]; -- (5 l)
nDifTopDif: CD.Number = CDSimpleRules.MinDist [CMosB.ndif, CMosB.pdif]; -- (10 l)
pdifUncSubtrContSpacing: CD.Number = CDSimpleRules.MinDist [CMosB.pdif, CMosB.nwellCont]; -- (3ý l)
nDifToSubtrCont: CD.Number = CDSimpleRules.MinDist [CMosB.ndif, CMosB.nwellCont]; -- (9 l)
pDifToSubtrCont: CD.Number = CDSimpleRules.MinDist [CMosB.pdif, CMosB.pwellCont]; -- (9 l)
nDifLayerSep: CD.Number = MAX [difSep, nDifToWell - difSep];
difToPolExtSep: CD.Number = 0;
Layer indices
ndifSpinifex: SX.SpinifexLayerIndex ~ SX.SpinifexLayerIndex.FIRST;
pdifSpinifex: SX.SpinifexLayerIndex ~ ndifSpinifex.SUCC;
polSpinifex: SX.SpinifexLayerIndex ~ pdifSpinifex.SUCC;
metSpinifex: SX.SpinifexLayerIndex ~ polSpinifex.SUCC;
m2Spinifex: SX.SpinifexLayerIndex ~ metSpinifex.SUCC;
wellSpinifex: SX.SpinifexLayerIndex ~ m2Spinifex.SUCC;
Constraints
n-Diffusion constraints.
ndCnstr: REF ConstraintArray ← NEW [ConstraintArray];
ndCh: CIndex ~ SX.techCIndexBase; -- n-Diffusion channel
ndBur: CIndex ~ ndCh.SUCC; -- Buried window here.
ndInWel: CIndex ~ ndBur.SUCC; -- n-Diffusion in n-Well
ndWel: CIndex ~ ndInWel.SUCC; -- Exclude n-Diffusion by n-Well
ndCnt: CIndex ~ ndWel.SUCC; -- n-Diffusion contact here.
ndPWct: CIndex ~ ndCnt.SUCC; -- p-Diffusion contact here.
ndPdErr: CIndex ~ ndPWct.SUCC; -- n-Diffusion & p-Diffusion together => Error.
p-Diffusion constraints
pdCnstr: REF ConstraintArray ← NEW [ConstraintArray];
pdCh: CIndex ~ SX.techCIndexBase; -- p-Diffusion channel
pdNdErr: CIndex ~ pdCh.SUCC; -- p-Diffusion & n-Diffusion together => Error.
pdCnt: CIndex ~ pdNdErr.SUCC; -- p-Diffusion contact here.
pdNWct: CIndex ~ pdCnt.SUCC; -- n-Diffusion contact here.
Poly constraints
polCnstr: REF ConstraintArray ← NEW [ConstraintArray];
pExnD: CIndex ~ SX.techCIndexBase; -- Poly not allowed here because of n-Diffusion.
pExpD: CIndex ~ pExnD.SUCC; -- Poly not allowed here because of p-Diffusion.
pExNdCon: CIndex ~ pExpD.SUCC; -- Poly not allowed here because of n-Diffusion Contact.
pExPdCon: CIndex ~ pExNdCon.SUCC; -- Poly not allowed here because of p-Diffusion Contact.
pChE: CIndex ~ pExPdCon.SUCC; -- Close to Xstr Gate, (Channel Edge).
pDExcl: CIndex ~ pChE.SUCC; -- No n-Diffusion permitted here due to buried contact.
pBur: CIndex ~ pDExcl.SUCC; -- Buried window here.
pBurErr: CIndex ~ pBur.SUCC; -- Buried Error, diffusion emerges from wrong side.
pDxorP: CIndex ~ pBurErr.SUCC; -- Diffusion XOR Poly allowed here.
pDandP: CIndex ~ pDxorP.SUCC; -- Diffusion AND Poly may appear together here.
pDErr: CIndex ~ pDandP.SUCC; -- Poly and Diffusion found together => Error.
Metal constraints
metCnstr: REF ConstraintArray ← NEW [ConstraintArray];
mCut: CIndex ~ SX.techCIndexBase; -- Cut from Metal to dif or pol (bloated).
mVia: CIndex ~ mCut.SUCC; -- Via from Metal to Metal2 (bloated).
mVC: CIndex ~ mVia.SUCC;  -- Via and Cut seperated by less than 2 lambda.
Rule Initialisation
InitRules: PROCEDURE [cMosHandle: REF SX.TechHandle] ~ {
Rule: TYPE ~ SX.GeometricRule;
TrigMap: TYPE ~ PACKED ARRAY CIndex OF BOOLEANALL [FALSE];
spaceRuleTrig, widthRuleTrig, nDifWidRuleTrig, polOverDifTrig1, polDifSepTrig1, polDifSepTrig2, nDifSpaceTrig1A, nDifSpaceTrig1B, nDifSpaceTrig2, pDifSpaceTrig1A, pDifSpaceTrig1B, pDifSpaceTrig2A, pDifSpaceTrig2B, pDifWidTrig, polSpaceTrig, polWidTrig, nDifSepNWellTrig1, nDifSepNWellTrig2, nDifInWellDifTrig1, nDifAndPDifTrig1, pDifAndNDifTrig1, alwaysErrorTrig2, nDifChannelTrig, metViaViaTrig, metCutViaTrig, metCutCutTrig, metSpTrig, metWTrig: TrigMap; -- ALL[FALSE]
detectOpaqueViolation: REF Rule;
Geometric rule triggers.
spaceRuleTrig[SX.nodeIndex] ← TRUE;
widthRuleTrig ← ALL[TRUE];
widthRuleTrig[SX.nodeIndex] ← FALSE;
Corners are defined by union of dif and gate
nDifSpaceTrig1A[SX.nodeIndex] ← TRUE;
nDifSpaceTrig1A[ndCh] ← TRUE;
nDifSpaceTrig1A[ndCnt] ← TRUE;
nDifSpaceTrig1B[ndPWct] ← TRUE;
nDifSpaceTrig2[SX.nodeIndex] ← TRUE;
nDifSpaceTrig2[ndCh] ← FALSE; -- there is no diff at channels
nDifSpaceTrig2[ndCnt] ← TRUE;
nDifSpaceTrig2[ndPWct] ← TRUE;
nDifChannelTrig[ndCh] ← TRUE;
nDifWidRuleTrig ← ALL[TRUE];
nDifWidRuleTrig[SX.nodeIndex] ← FALSE;
nDifWidRuleTrig[ndCnt] ← FALSE;
nDifWidRuleTrig[ndCh] ← FALSE;
Corners are defined by union of dif and gate
pDifSpaceTrig1A[SX.nodeIndex] ← TRUE;
pDifSpaceTrig1A[pdCh] ← TRUE;
pDifSpaceTrig1A[pdCnt] ← TRUE;
pDifSpaceTrig2A[SX.nodeIndex] ← TRUE;
pDifSpaceTrig2A[pdCh] ← FALSE; -- there is no diff at channels
pDifSpaceTrig2A[pdCnt] ← TRUE;
pDifSpaceTrig2A[pdNWct] ← TRUE;
pDifSpaceTrig1B[pdNWct] ← TRUE;
pDifSpaceTrig2B[SX.nodeIndex] ← TRUE;
pDifSpaceTrig2B[pdCnt] ← TRUE;
pDifWidTrig ← ALL[TRUE];
pDifWidTrig[SX.nodeIndex] ← FALSE;
pDifWidTrig[pdCnt] ← FALSE;
nDifSepNWellTrig1[SX.nodeIndex] ← TRUE;
nDifSepNWellTrig2[ndWel] ← TRUE;
polSpaceTrig[SX.nodeIndex] ← TRUE;
polSpaceTrig[pDandP] ← TRUE;
polWidTrig ← ALL[TRUE];
polWidTrig[SX.nodeIndex] ← FALSE;
polWidTrig[pDandP] ← FALSE;
polWidTrig[pDErr] ← FALSE;
polDifSepTrig1 [SX.nodeIndex] ← TRUE;
polDifSepTrig1 [pDandP] ← TRUE;
polDifSepTrig2 [pExnD] ← TRUE;
polDifSepTrig2 [pExpD] ← TRUE;
polDifSepTrig2 [pExNdCon] ← TRUE;
polDifSepTrig2 [pExPdCon] ← TRUE;
Metal
metSpTrig [SX.nodeIndex] ← TRUE;
metSpTrig [mCut] ← TRUE;
metSpTrig [mVia] ← TRUE;
metSpTrig [mVC] ← TRUE;
metWTrig ← ALL [TRUE];
metWTrig [SX.nodeIndex] ← FALSE;
metWTrig [mCut] ← FALSE;
metWTrig [mVia] ← FALSE;
metWTrig [mVC] ← FALSE;
Purely local errors are not handled in a natural manner by my scheme, so for every corner we find in polCnstr[pDErr] we generate an error if there is anything on any layer nearby, of course there is always something so we get our error.
polOverDifTrig1 [pDErr] ← TRUE;
nDifInWellDifTrig1 [ndInWel] ← TRUE;
nDifAndPDifTrig1 [ndPdErr] ← TRUE;
pDifAndNDifTrig1 [pdNdErr] ← TRUE;
metCutCutTrig [mCut] ← TRUE;
metCutViaTrig [mVC] ← TRUE;
metCutViaTrig [mVia] ← TRUE;
metViaViaTrig [mVia] ← TRUE;
alwaysErrorTrig2 ← ALL[TRUE];
The geometric rules.
detectOpaqueViolation ← NEW[ Rule ← [ extent~ l, message~ "Opaque cell boundary violated", trigger1~ ALL[TRUE], trigger2~ ALL[TRUE]]];
We set violateIndex = FALSE, ALL else TRUE so that corner checks face inward, which should result in more logically pleasing error reports.
detectOpaqueViolation.trigger1[SX.violateIndex] ← FALSE;
cMosHandle.rules [ndifSpinifex] ← LIST[
NEW [Rule ← [message~ "n-Diffusion spacing", extent~ ndifSpacing, okIfConnected~ TRUE, trigger1~ nDifSpaceTrig1A, trigger2~ nDifSpaceTrig2]],
NEW [Rule ← [message~ "n-Diffusion/unconnected p-substrate-contact spacing", extent~ ndifUncSubtrContSpacing, okIfConnected~ TRUE, trigger1~ nDifSpaceTrig1B, trigger2~ nDifSpaceTrig2]],
The above two rules are no longer applied to channels.
NEW [Rule ← [message~ "n-Diffusion width", extent~ ndifWidth, trigger1~ nDifWidRuleTrig, trigger2~ nDifWidRuleTrig]],
NEW [Rule ← [message~ "n-Diffusion/n-Well spacing", extent~ nDifToWell, trigger1~ nDifSepNWellTrig1, trigger2~ nDifSepNWellTrig2]],
NEW [Rule ← [message~ "n-Well/n-Diffusion spacing", extent~ nDifToWell, trigger1~ nDifSepNWellTrig2, trigger2~ nDifSepNWellTrig1]],
NEW [Rule ← [message~ "n-Diffusion in n-Well", extent~ ndifInnWell, trigger1~ nDifInWellDifTrig1, trigger2~ alwaysErrorTrig2]],
NEW [Rule ← [message~ "n-Diffusion and p-substrate-contact", extent~ ndifpSubstrCont, trigger1~ nDifAndPDifTrig1, trigger2~ alwaysErrorTrig2]],
detectOpaqueViolation
];
cMosHandle.rules [pdifSpinifex] ← LIST [
NEW [Rule ← [message~ "p-Diffusion spacing", extent~ pdifSpacing, okIfConnected~ TRUE, trigger1~ pDifSpaceTrig1A, trigger2~ pDifSpaceTrig2A]],
NEW [Rule ← [message~ "p-Diffusion/unconnected n-Well-contact spacing", extent~ pdifUncnWellSpacing, okIfConnected~ TRUE, trigger1~ pDifSpaceTrig1B, trigger2~ pDifSpaceTrig2B]],
NEW [Rule ← [message~ "p-Diffusion width", extent~ pdifWidth, trigger1~ pDifWidTrig, trigger2~ pDifWidTrig]],
NEW [Rule ← [message~ "p-Diffusion and n-Well-contact", extent~ pdifnWellCont, trigger1~ pDifAndNDifTrig1, trigger2~ alwaysErrorTrig2]],
detectOpaqueViolation
];
cMosHandle.rules [polSpinifex] ← LIST [
NEW [Rule ← [message~ "Poly spacing", extent~ polSpacing, okIfConnected~ TRUE, trigger1~ polSpaceTrig, trigger2~ polSpaceTrig]],
NEW [Rule ← [message~ "Poly width", extent~ polWidth, trigger1~ polWidTrig, trigger2~ polWidTrig]],
NEW [Rule ← [message~ "Poly/unconnected Diffusion spacing", extent~ polUncDifSpacing, okIfConnected~ TRUE, trigger1~ polDifSepTrig1, trigger2~ polDifSepTrig2]],
NEW [Rule ← [message~ "Diffusion/unconnected Poly spacing", extent~ polDiffUncPolySpacing, okIfConnected~ TRUE, trigger1~ polDifSepTrig2, trigger2~ polDifSepTrig1]],
NEW [Rule ← [message~ "Poly over Diffusion", extent~ polOverDiff, trigger1~ polOverDifTrig1, trigger2~ alwaysErrorTrig2]],
detectOpaqueViolation
];
cMosHandle.rules [metSpinifex] ← LIST [
NEW [Rule ← [message~ "Metal spacing", extent~ metSeparation, okIfConnected~ TRUE, trigger1~ metSpTrig, trigger2~ metSpTrig]],
NEW [Rule ← [message~ "Metal width", extent~ metWidth, trigger1~ metWTrig, trigger2~ metWTrig]],
NEW [Rule ← [message~ "Cut to Cut spacing", extent~ metCutCutSpacing, trigger1~ metCutCutTrig, trigger2~ metCutCutTrig]],
NEW [Rule ← [message~ "Via to Via spacing", extent~ metViaViaSpacing, trigger1~ metViaViaTrig, trigger2~ metViaViaTrig]],
NEW [Rule ← [message~ "Cut to Via spacing", extent~ metCutViaSpacing, trigger1~ metCutCutTrig, trigger2~ metCutViaTrig]],
detectOpaqueViolation
];
cMosHandle.rules [m2Spinifex] ← LIST[
NEW [Rule ← [message~ "Metal 2 spacing", extent~ met2Separation, okIfConnected~ TRUE, trigger1~ spaceRuleTrig, trigger2~ spaceRuleTrig]],
NEW [Rule ← [message~ "Metal 2 width", extent~ met2Width, trigger1~ widthRuleTrig, trigger2~ widthRuleTrig]],
detectOpaqueViolation
];
cMosHandle.rules [wellSpinifex] ← LIST[
NEW [Rule ← [message~ "Well spacing", extent~ wellSep, okIfConnected~ TRUE, trigger1~ spaceRuleTrig, trigger2~ spaceRuleTrig]],
NEW [Rule ← [message~ "Well width", extent~ wellWidth, trigger1~ widthRuleTrig, trigger2~ widthRuleTrig]],
detectOpaqueViolation
];
};
Transistors
MapMaterial: SXTechnology.PerDrawRectProc ~ {
[r: CD.Rect, l: CD.Layer, data: REF ANY] RETURNS [TransistorMaterial]
cir: REF SX.Circuit ~ NARROW [data, REF SX.Circuit];
SELECT l FROM
CMosB.ndif, CMosB.pdif => RETURN [diffusion];
CMosB.pol => RETURN [polysilicon];
CMosB.nwell => {
wellNode: REF SX.CircuitNode ← cir.AddRect [lev~ CMosB.nwell, dim~ r];
wellNode.properties ← PropertyLists.PutProp [wellNode.properties, wellNode, wellNode];
RETURN [nothing];
};
ENDCASE => RETURN [nothing];
}; -- MapMaterial
ConvTransistor: PUBLIC SX.ConversionProc =
New transistor conversion procedure for ChipNDale 2.1
PROCEDURE [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF Circuit]
BEGIN
transistor: REF SX.NodeLinkage;
gateNode, sourceNode, drainNode, wellNode: REF SX.CircuitNode;
tClass: ATOM = inst.ob.class.objectType;
isNType: BOOL = (inst.ob.layer = CMosB.ndif);
isNWell: BOOL;
difSXLayer: SX.SpinifexLayerIndex;
difChannel, exclPol: REF SX.Constraint;
sep: CD.Number = CDSimpleRules.MinDist[CMosB.ndif, CMosB.pol];
extSep: CD.Number = difToPolExtSep;
rect, wellRect: CD.Rect;
polList, difList, chList, difListSouth: LIST OF CD.Rect ← NIL;
length, width, extL, extW: CD.Number;
gateA, gateP, sourceA, sourceP, drainA, drainP: INT; -- ignore perimeter leading into channel
errorRect: CD.Rect = CD.InterestRect [inst.ob];
Determine diffusion layer and channel constraint
IF isNType THEN
{difSXLayer ← ndifSpinifex; difChannel ← ndCnstr[ndCh]; exclPol ← polCnstr[pExnD]}
ELSE
{difSXLayer ← pdifSpinifex; difChannel ← pdCnstr[pdCh]; exclPol ← polCnstr[pExpD]};
Get the geometry. Streching information has already been procesed by ChipNDale.
wellRect ← CDBasics.empty;
IF ISTYPE [inst.ob.specificRef, CDAtomicObjects.AtomicObsPtr] THEN
FOR geom: CDAtomicObjects.DrawList ← NARROW [inst.ob.specificRef, CDAtomicObjects.AtomicObsPtr].rList, geom.rest WHILE geom # NIL DO
SELECT geom.first.lev FROM
CMosB.pol => polList ← CONS [geom.first.r, polList];
CMosB.ndif, CMosB.pdif => difList ← CONS [geom.first.r, difList];
CMosB.nwell, CMosB.pwell => {wellRect ← geom.first.r; isNWell ← (geom.first.lev = CMosB.nwell)};
ENDCASE => ERROR SX.IllegalConstruct [geom.first.r, "Unknown transistor geometry"];
ENDLOOP
ELSE ERROR SX.IllegalConstruct [errorRect, "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 => -- straight transistors
BEGIN
difRect, polRect, chRect, difExtRectNorth, difExtRectSouth: CD.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;
length ← polRect.y2 - polRect.y1; width ← difRect.x2 - difRect.x1;
extL ← polRect.y1 - difRect.y1; extW ← difRect.x1 - polRect.x1;
gateA ← (width + 2*extW) * length; gateP ← (width + 2*extW + length) * 2;
sourceA ← drainA ← extL * width; sourceP ← drainP ← 2 * extL + width;
Process poly layer
gateNode ← SX.AddRect [cir: cir, lev: CMosB.pol, dim: polRect, inst: inst, pos: pos, orient: orient];
IF extL > sep THEN-- Add rectangles for poly exclusion
BEGIN
rect ← difExtRectNorth; rect.y1 ← rect.y1 + sep;
[] ← SX.AddBox [cir, polSpinifex, rect, inst, pos, orient, SXTechnology.WNEGrow [extSep], exclPol];
rect ← difExtRectSouth; rect.y2 ← rect.y2 - sep;
[] ← SX.AddBox [cir, polSpinifex, rect, inst, pos, orient, SXTechnology.ESWGrow [extSep], exclPol];
END;
Process channel lead-in
rect ← difExtRectNorth; rect.y2 ← rect.y1+sep;
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]];
rect ← difExtRectSouth; rect.y1 ← rect.y2-sep;
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]];
Fill channel gap. NOTE: The DRC of channels is affected by the change made to CMosSpinifexInitImpl on April 2, 1985.
[] ← SX.AddBox [cir: cir, spinifexLayer: difSXLayer,
dim: chRect, inst: inst, pos: pos, orient: orient,
interestBloat: [dx1: (CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2), dy1: 0, dx2: (CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2), dy2: 0],
value: difChannel];
Add rectangles for diff width spacing and connection
sourceNode ← SX.AddBox[cir: cir, spinifexLayer: difSXLayer,
dim: difExtRectNorth, inst: inst, pos: pos, orient: orient,
interestBloat: SXTechnology.WNEGrow[(CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2)]];
drainNode ← SX.AddBox[cir: cir, spinifexLayer: difSXLayer,
dim: difExtRectSouth, inst: inst, pos: pos, orient: orient,
interestBloat: SXTechnology.ESWGrow[(CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2)]];
Process well.
IF tClass = $C2WellTrans THEN
BEGIN
l: CD.Layer = IF isNWell THEN CMosB.nwell ELSE CMosB.pwell;
IF NOT CDBasics.NonEmpty[wellRect] THEN ERROR SX.IllegalConstruct [errorRect, "Well transistor must have a well"];
wellNode ← SX.AddRect [cir: cir, lev: l, dim: wellRect, inst: inst, pos: pos, orient: orient];
wellNode.properties ← PropertyLists.PutProp [propList: wellNode.properties, prop: wellNode, val: wellNode];
END;
END; -- case $CTrans
$C2LTrans, $C2LWellTrans => -- angle transistors
BEGIN
diffNE: CD.Position ← CDBasics.minposition;
diffSW, polSW: CD.Position ← CDBasics.highposition;
polHor, polVert: CD.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 CD.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;
width ← ((polHor.x2 - polHor.x1) - extW) + ((polVert.y2 - polVert.y1) - extW) - (length*3/2);
gateA ← ((width+length/2) + 2*extW) * length;
gateP ← ((polHor.x2 - polHor.x1) + (polVert.y2 - polVert.y1)) * 2;
sourceA ← ((diffNE.x - diffSW.x) + (diffNE.y - diffSW.y - extL)) * extL;
sourceP ← 2 * extL + (diffNE.x - diffSW.x) + (diffNE.y - diffSW.y);
drainP ← diffNE.x + diffNE.y - diffSW.x - diffSW.y - 2 * (extL + length);
drainA ← drainP * extL;
Process poly layer
gateNode ← SX.AddRect [cir: cir, lev: CMosB.pol, dim: polHor, inst: inst, pos: pos, orient: orient];
[] ← SX.AddRect [cir: cir, lev: CMosB.pol, dim: polVert, inst: inst, pos: pos, orient: orient, value: gateNode];
IF extL > sep THEN-- Add rectangles for poly exclusion
BEGIN
d: CD.Number ← extL + length + sep;
rect ← [x1: diffSW.x, y1: diffSW.y+d, x2: diffNE.x-d, y2: diffSW.y+length+2*extL];
[] ← SX.AddBox [cir, polSpinifex, rect, inst, pos, orient, SXTechnology.WNGrow [extSep], exclPol]; -- North
rect ← [x1: diffNE.x-length-2*extL, y1: diffSW.y+d, x2: diffNE.x-d, y2: diffNE.y];
[] ← SX.AddBox [cir, polSpinifex, rect, inst, pos, orient, SXTechnology.WNGrow [extSep], exclPol]; -- West
d ← extL - sep;
rect ← [x1: diffSW.x, y1: diffSW.y, x2: diffNE.x, y2: diffSW.y+d];
[] ← SX.AddBox [cir, polSpinifex, rect, inst, pos, orient, SXTechnology.ESWGrow [extSep], exclPol]; -- South
rect ← [x1: diffNE.x-d, y1: diffSW.y, x2: diffNE.x, y2: diffNE.y];
[] ← SX.AddBox [cir, polSpinifex, rect, inst, pos, orient, SXTechnology.NESGrow [extSep], exclPol] -- East
END; -- poly excl
Process channel lead-in
BEGIN
d: CD.Number ← extL + length + sep;
rect ← [x1: diffSW.x, y1: diffSW.y+extL+length, x2: diffNE.x-extL-length, y2: diffSW.y+d];
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]]; -- North
rect ← [x1: diffNE.x-d, y1: diffSW.y+extL+length, x2: diffNE.x-extL-length, y2: diffNE.y];
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]]; -- West
d ← extL - sep;
rect ← [x1: diffSW.x, y1: diffSW.y+d, x2: diffNE.x-d, y2: diffSW.y+extL];
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]]; -- South
rect ← [x1: diffNE.x-extL, y1: diffSW.y+d, x2: diffNE.x-d, y2: diffNE.y];
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]] -- East
END; -- ch lead-in
Fill channel gap. NOTE: The DRC of channels is affected by the change made to CMosSpinifexInitImpl on April 2, 1985.
rect ← polHor; rect.x1 ← rect.x1 + extW;
[] ← SX.AddBox [cir: cir, spinifexLayer: difSXLayer,
dim: rect, inst: inst, pos: pos, orient: orient,
interestBloat: [dx1: (CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2), dy1: 0, dx2: 0, dy2: 0],
value: difChannel];
rect ← polVert; rect.y2 ← rect.y2 - extW;
[] ← SX.AddBox [cir: cir, spinifexLayer: difSXLayer,
dim: rect, inst: inst, pos: pos, orient: orient,
interestBloat: [dx1: 0, dy1: 0, dx2: 0, dy2: (CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2)],
value: difChannel];
Add rectangles for diff width spacing and connection
rect ← [x1: diffSW.x, y1: diffSW.y+extL+length, x2: diffNE.x-extL-length, y2: diffSW.y+2*extL+length];
sourceNode ← SX.AddBox [cir: cir, spinifexLayer: difSXLayer,
dim: rect, inst: inst, pos: pos, orient: orient,
interestBloat: SXTechnology.WNGrow[(CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2)]];
IF difList.rest # NIL THEN -- supposed source is concave
BEGIN
rect ← [x1: diffNE.x-length-2*extL, y1: rect.y1, x2: rect.x2, y2: diffNE.y];
[] ← SX.AddBox [cir: cir, spinifexLayer: difSXLayer,
dim: rect, inst: inst, pos: pos, orient: orient,
interestBloat: SXTechnology.WNGrow[(CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2)],
value: sourceNode]
END;
rect ← [x1: diffSW.x, y1: diffSW.y, x2: diffNE.x, y2: diffSW.x+extL];
drainNode ← SX.AddBox[cir: cir, spinifexLayer: difSXLayer,
dim: rect, inst: inst, pos: pos, orient: orient,
interestBloat: SXTechnology.ESWGrow[(CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2)]];
rect ← [x1: diffNE.x-extL, y1: rect.y2, x2: diffNE.x, y2: diffNE.y];
[] ← SX.AddBox[cir: cir, spinifexLayer: difSXLayer,
dim: rect, inst: inst, pos: pos, orient: orient,
interestBloat: SXTechnology.NESGrow[(CDSimpleRules.MinDist[CMosB.ndif, CMosB.ndif]/2)],
value: drainNode];
Process well.
IF tClass = $C2LWellTrans THEN
BEGIN
l: CD.Layer = IF isNWell THEN CMosB.nwell ELSE CMosB.pwell;
IF NOT CDBasics.NonEmpty[wellRect] THEN ERROR SX.IllegalConstruct [errorRect, "Well transistor must have a well"];
wellNode ← SX.AddRect [cir: cir, lev: l, dim: wellRect, inst: inst, pos: pos, orient: orient];
wellNode.properties ← PropertyLists.PutProp [propList: wellNode.properties, prop: wellNode, val: wellNode];
END;
END; -- case $C2LTrans, $C2LWellTrans
$CLWellTrans => ERROR SX.IllegalConstruct [errorRect, "Antique transistor class $CLWellTrans is illegal"];
ENDCASE => ERROR SX.IllegalConstruct [errorRect, "Unknown or antique transistor class"];
transistor ← SX.CreateLinkage [cir, inst, length, width];
Adjust area and perimeter values
SX.AdjustNode [node: gateNode, layer: polSpinifex, area: gateA, perim: gateP, mode: absolute];
SX.AdjustNode [sourceNode, difSXLayer, sourceA, sourceP, absolute];
SX.AdjustNode [drainNode, difSXLayer, drainA, drainP, absolute];
SX.LinkageAttach [link: transistor, attachType: $Gate, node: gateNode];
SX.LinkageAttach [link: transistor, attachType: $Source, node: sourceNode];
SX.LinkageAttach [link: transistor, attachType: $Drain, node: drainNode]
END; -- ConvTransistor
RoseTransistor: PUBLIC SXOutput.LinkagePrintProc ~ {
[desWDir: ROPE, dfStream, cellStream: IO.STREAM, linkage: REF NodeLinkage, name: Rope.ROPE, PrintNode: NodePrintProc]
PrintAttachment: PROCEDURE [key: ATOM, portName: Rope.ROPE] ~ {
cellStream.Put [IO.rope[" (\""], IO.rope[portName], IO.rope["\" "]];
FOR attachments: LIST OF REF SX.AttachedNode ← linkage.nodes, attachments.rest WHILE attachments # NIL DO
IF attachments.first.attachmentType = key THEN {
PrintNode[cellStream, attachments.first.node];
cellStream.PutRope[")"];
RETURN
}
ENDLOOP;
cellStream.PutRope ["\"?\")"];
}; -- PrintAttachment
naming: SXOutputPrivate.Naming ← SXOutputPrivate.GetANaming [linkage.source];
cellStream.PutRope["(CI "];
SXOutputPrivate.PrintNaming[
cellStream,
naming,
Rope.Cat[" \"", SXOutputPrivate.NameTransType[
desWDir: desWDir,
obj: linkage.source.ob,
dfStream: dfStream,
type: SELECT linkage.source.ob.layer FROM
CMosB.ndif, CMosB.wndif => $n,
CMosB.pdif, CMosB.wpdif => $p,
ENDCASE => $funny,
mode: $E,
length: linkage.l,
width: linkage.w], "\""]
];
SXOutputPrivate.PrintRoseInstantiationTransformation[cellStream, linkage.source];
cellStream.PutRope [" (CIC"];
PrintAttachment [$Gate, "gate"];
PrintAttachment [$Source, "ch1"];
PrintAttachment [$Drain, "ch2"];
cellStream.PutRope ["))"]
}; -- RoseTransistor
ThymeTransistor: PUBLIC SXOutput.LinkagePrintProc ~ {
[desWDir: ROPE, dfStream, cellStream: IO.STREAM, linkage: REF NodeLinkage, name: Rope.ROPE, PrintNode: NodePrintProc]
PrintAttachment: PROCEDURE [key: ATOM] ~ {
FOR attachments: LIST OF REF SX.AttachedNode ← linkage.nodes, attachments.rest WHILE attachments # NIL DO
IF attachments.first.attachmentType = key THEN {
PrintNode[cellStream, attachments.first.node];
RETURN
}
ENDLOOP;
cellStream.Put [IO.char['?]];
}; -- PrintAttachment
defaultW: INTEGER = 4*lambda;
defaultL: INTEGER = 2*l;
propertyValue: REF;
cellStream.Put [IO.rope[name], IO.rope[": "]];
cellStream.PutRope [SELECT linkage.source.ob.layer FROM
CMosB.ndif, CMosB.wndif => "ETran[",
CMosB.pdif, CMosB.wpdif => "CTran[",
ENDCASE => "FunnyTran["
];
PrintAttachment [$Gate];
cellStream.Put [IO.char[',]];
PrintAttachment [$Source];
cellStream.Put [IO.char[',]];
PrintAttachment [$Drain];
cellStream.Put [IO.char['|]];
cellStream.PutF[" W←N*%g", IO.int[linkage.w/l]];
IF linkage.l # defaultL THEN cellStream.PutF[", L←%g", IO.int[linkage.l/l]];
The following is a quick hack to allow John Ousterhout to test Crystal. In a later stage, SX.AttachedNode shall receive an additional field for this info. At the moment it is not clear yet, how the user interface should be like.
propertyValue ← CDProperties.GetInstanceProp [from: linkage.source, prop: SXAtoms.crystalAttr];
WITH propertyValue SELECT FROM
crystalHack: Rope.ROPE => IO.Put [stream: cellStream, v1: IO.rope["; "], v2: IO.rope[crystalHack]];
ENDCASE => IF propertyValue # NIL THEN TerminalIO.WriteRope [" $Crystal property must be a rope./n"];
cellStream.PutRope ["];"]
}; -- ThymeTransistor
Contacts
wellConnection: ATOM ~ $SXCMosBWellConnection;
wellNode: ATOM ~ $SXCMosBNWellNode;
maxContSize: CD.Number ~ 5 * l;
splitContWidth: CD.Number ~ 2 * l;
splitContHeight: CD.Number ~ 6 * l;
ConvertPDifRect: PUBLIC SX.ConversionProc = BEGIN
[appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit]
wellNode: REF SX.CircuitNode;
nWellBox: CD.Rect ← CDBasics.RectAt[pos~[0,0], size~inst.ob.size];
pDifBox: CD.Rect ← CDBasics.Extend[nWellBox, -CMosB.wellSurround];
IF ~CDBasics.NonEmpty[pDifBox] THEN
BEGIN
TerminalIO.WriteRope [" this cell contains a w-pDif object whose pDif rectangle is empty\n"];
ERROR
END;
[] ← cir.AddRect [lev~CMosB.pdif, dim~pDifBox, inst~inst, pos~ pos, orient~ orient];
wellNode ← cir.AddRect [lev~CMosB.nwell, dim~nWellBox, inst~inst, pos~ pos, orient~ orient];
wellNode.properties ← PropertyLists.PutProp [wellNode.properties, wellNode, wellNode];
END; -- ConvertPDifRect
ConvertContact: PUBLIC SX.ConversionProc = BEGIN
[appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit]
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
classKey: ATOM = inst.ob.class.objectType;
r: CD.Rect = CD.InterestRect [inst.ob];
node: REF SX.CircuitNode ← NIL;
size: CD.Position;
sizeExceeded: BOOLFALSE;
SELECT classKey FROM
$C2SimpleCon, $C2WellSimpleCon, $C2LargeSimpleCon, $C2LargeWellSimpleCon, $C2DifShortCon, $C2WellDifShortCon, $C2Via, $C2LargeVia =>
FOR geom: CDAtomicObjects.DrawList ← NARROW [inst.ob.specificRef, CDAtomicObjects.AtomicObsPtr].rList, geom.rest WHILE geom # NIL DO
SELECT geom.first.lev FROM
CMosB.ndif, CMosB.pdif => {
node ← SX.AddRect[cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: polCnstr[(IF geom.first.lev = CMosB.ndif THEN pExNdCon ELSE pExPdCon)]];
};
CMosB.nwell, CMosB.pwell => {
bridge: REF SX.CircuitNode ← IF (classKey=$C2WellDifShortCon) THEN node ELSE NIL;
wellNode: REF SX.CircuitNode ← SX.AddRect [cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: bridge];
wellNode.properties ← PropertyLists.PutProp [wellNode.properties, wellNode, wellNode];
};
CMosB.nwellCont, CMosB.pwellCont => {
node ← SX.AddRect[cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: polCnstr[(IF geom.first.lev = CMosB.nwellCont THEN pExNdCon ELSE pExPdCon)]];
};
CMosB.met, CMosB.met2, CMosB.pol =>
node ← SX.AddRect[cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node];
CMosB.cut => { -- all but vias
[] ← SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: metCnstr[mCut]];
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)};
CMosB.cut2 => { -- vias
[] ← SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: metCnstr[mVia]];
size ← Size [geom.first.r];
sizeExceeded ← sizeExceeded OR (size.x>maxContSize OR size.y>maxContSize)};
ENDCASE => ERROR SX.IllegalConstruct [geom.first.r, "Unknown simple contact geometry"];
ENDLOOP
ENDCASE => SX.IllegalConstruct [r, "Unknown CMos-B contact type"];
IF sizeExceeded THEN SX.IllegalConstruct [r, "Maximum contact size exceeded"]
END; -- ConvertContact
PointRect: PROC [p: CD.Position] RETURNS [r: CD.Rect] = BEGIN
r ← CDBasics.Extend [CDBasics.ToRect[p, p], l]
END; -- PointRect
CopyWellConnections: PUBLIC SX.CombineNodePropertyProc ~ BEGIN
[circuit: REF Circuit, to, from: PropertyLists.PropList, fromNesting: LIST OF CD.Instance] RETURNS [PropertyLists.PropList]
fromConnections: Nodes
NARROW [PropertyLists.GetProp [propList: from, prop: wellConnection]];
toConnections: Nodes
NARROW [PropertyLists.GetProp [propList: to, prop: wellConnection]];
FOR fl: Nodes ← fromConnections, fl.rest WHILE fl # NIL DO
fromNode: REF SX.CircuitNode;
IF fromNesting = NIL THEN fromNode ← fl.first
ELSE-- Side effect !!! May add fl.first to subcircuits ports.
fromNode ← SX.FindRootNode [circuit: circuit,
subcircuitNode: fl.first,
qualifier: fromNesting,
insertIfNotInCircuit: TRUE].node;
FOR tl: Nodes ← toConnections, tl.rest WHILE tl # NIL DO
IF SX.LookupNode [l: fromNode] = SX.LookupNode [l: tl.first] THEN EXIT;
REPEAT FINISHED =>
toConnections ← CONS [fromNode, toConnections]
ENDLOOP
ENDLOOP;
IF toConnections # NIL THEN
to ← PropertyLists.PutProp [propList: to, prop: wellConnection, val: toConnections];
IF (PropertyLists.GetProp [propList: from, prop: wellNode] # NIL)
AND (PropertyLists.GetProp [propList: to, prop: wellNode] = NIL) THEN
to ← PropertyLists.PutProp [propList: to, prop: wellNode, val: wellNode];
RETURN [to]
END; -- CopyWellConnections
CheckWellConnections: PUBLIC SX.CellPostProcessProc = BEGIN
PROC [cell: REF SX.LogicalCell]
isRoot: BOOL ← (cell.rootOnInvocation = SXAccess.invocation);
hasNode, hasConnection, hasRoot: BOOL;
wellConnects: Nodes;
Process Subcells.
FOR scl: CD.InstanceList ← cell.circuit.subcircuits, scl.rest WHILE scl # NIL DO
subcir: REF SX.Circuit ~ SXTechnology.GetCircuitFromCDObject [cdOb: scl.first.ob];
FOR nl: Nodes ← subcir.nodes, nl.rest WHILE nl # NIL DO
hasNode ← (PropertyLists.GetProp
[propList: nl.first.properties, prop: wellNode] # NIL);
hasConnection ← (PropertyLists.GetProp
[propList: nl.first.properties, prop: wellConnection] # NIL);
IF hasNode AND ~ hasConnection THEN {
Potential floating well in subcircuit, is it merged to some node in this cell?
hasRoot ← (SX.FindRootNode [circuit: cell.circuit, subcircuitNode: nl.first, qualifier: LIST[scl.first]].rootQualifier # NIL);
IF hasRoot THEN {
The well node of the subcircuit is not merged into this circuit, so it may be floating => VIOLATION
eLoc: CD.Position = CDOrient.MapPoint [pointInCell: nl.first.loc.xy,
cellSize: scl.first.ob.size,
cellInstOrient: scl.first.orientation,
cellInstPos: scl.first.location];
SXAccessInternal.PutError [ob: cell.cellObj,
r: PointRect[eLoc],
message: "floating n-well in subcell"];
}
} -- if has unconnected node
ENDLOOP-- for all nodes
ENDLOOP; -- for all cells
Process the cell. In context of this cell floating n-well is only an error if this is a root cell for this particular invocation of Spinifex.
FOR nl: Nodes ← cell.circuit.nodes, nl.rest WHILE nl # NIL DO
hasNode ← (PropertyLists.GetProp[propList: nl.first.properties, prop: wellNode] # NIL);
IF hasNode THEN {
wellConnects ← NARROW [PropertyLists.GetProp [propList: nl.first.properties, prop: wellConnection]];
Clean up list of well connections to eliminate REFs to superceded nodes.
FOR wl: Nodes ← wellConnects, wl.rest WHILE wl # NIL DO
wl.first ← SX.LookupNode [l: wl.first];
FOR restOfWl: Nodes ← wl, restOfWl.rest WHILE restOfWl.rest # NIL DO
IF wl.first = SX.LookupNode [l: restOfWl.rest.first] THEN
restOfWl.rest ← restOfWl.rest.rest -- Drop this list element.
ENDLOOP
ENDLOOP; -- clean up
IF (wellConnects = NIL AND isRoot) THEN {
n-well unconnect in root cell => VIOLATION
eLoc: CD.Position = nl.first.loc.xy;
SXAccessInternal.PutError [ob: cell.cellObj,
r: PointRect[eLoc],
message: "floating n-well in root cell of analysis"];
}
ELSE IF wellConnects # NIL AND wellConnects.rest # NIL THEN {
n-well connect multiple times => VIOLATION
eLoc: CD.Position = nl.first.loc.xy;
SXAccessInternal.PutError [ob: cell.cellObj,
r: PointRect[eLoc],
message: "n-well connected to multiple nodes"];
FOR wc: Nodes ← wellConnects, wc.rest WHILE wc # NIL DO
eLoc: CD.Position = wc.first.loc.xy;
SXAccessInternal.PutError [ob: cell.cellObj,
r: PointRect[eLoc],
message: IO.PutFR ["node on %g connects to multiply connected n-Well",
IO
.atom[SXAccess.sxTech.spinifexLayerNames[wc.first.loc.layer].layerId]]];
ENDLOOP;
}
} -- has nWell node
ENDLOOP-- for all nodes
END; -- CheckWellConnections
AttachNWellContact: PUBLIC SX.BoxMapProc = BEGIN
PROC [cir: REF Circuit, dim: CD.Rect, appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, node: REF CircuitNode] RETURNS [cirNode: REF CircuitNode ← NIL]
wellCon: REF SX.CircuitNode ← SX.AddBox [cir: cir,
spinifexLayer: wellSpinifex,
dim: dim, inst: inst, pos: pos, orient: orient,
interestBloat: [l, l, l, l]];
IF node = NIL THEN ERROR;
wellCon.properties ← PropertyLists.PutProp [propList: wellCon.properties,
prop: wellConnection,
val: NARROW[LIST[node], Nodes]]
END; -- AttachNWellContact
Initialisation
Init: PROCEDURE ~ {
cMosHandle: REF SX.TechHandle;
ndifResolution: REF SX.ConstraintResolution;
pdifResolution: REF SX.ConstraintResolution;
polyResolution: REF SX.ConstraintResolution;
metalResolution: REF SX.ConstraintResolution;
Construction of the Layer Constraints.
Constraint: PUBLIC TYPE ~ RECORD [
name: ATOM,
index: ConstraintIndex, -- index into the constraint array
hasCorrespondingNode: BOOLEANFALSE, -- used where connectivity affects the rule and there is a corresponding layer which has the node associated with this region.
correspondingNodeLayer: SpinifexLayerIndex ← SpinifexLayerIndex.FIRST -- way to attach node values to constraints by looking at other layers.
];
ndCnstr[ndCh] ← NEW [Constraint ← [$NDifChannel, ndCh, TRUE, polSpinifex]];
ndCnstr[ndBur] ← NEW [Constraint ← [$BuriedNDifPol, ndBur]];
ndCnstr[ndInWel] ← NEW [Constraint ← [$NDifInWellError, ndInWel]];
ndCnstr[ndWel] ← NEW [Constraint ← [$ExcludeNDifByWell, ndWel]];
ndCnstr[ndCnt] ← NEW [Constraint ← [$ContactNDif, ndCnt, TRUE, ndifSpinifex]];
ndCnstr[ndPWct] ← NEW [Constraint ← [$ExcludeNDifByPWellCont, ndPWct, TRUE, pdifSpinifex]];
ndCnstr[ndPdErr] ← NEW [Constraint ← [$NDifAndPDifError, ndPdErr]];
pdCnstr[pdCh] ← NEW [Constraint ← [$PDifChannel, pdCh, TRUE, pdifSpinifex]];
pdCnstr[pdNdErr] ← NEW [Constraint ← [$PDifAndNDifError, pdNdErr]];
pdCnstr[pdCnt] ← NEW [Constraint ← [$ContactPDif, pdCnt, TRUE, pdifSpinifex]];
pdCnstr[pdNWct] ← NEW [Constraint ← [$ExcludePDifByNWellCont, pdNWct, TRUE, ndifSpinifex]];
polCnstr[pExnD] ← NEW [Constraint ← [$PolExcludeByNDif, pExnD, TRUE, ndifSpinifex]];
polCnstr[pExpD] ← NEW [Constraint ← [$PolExcludeByPDif, pExpD, TRUE, pdifSpinifex]];
polCnstr[pExNdCon] ← NEW [Constraint ← [$PolExcludeByNDifContact, pExNdCon, TRUE, ndifSpinifex]];
polCnstr[pExPdCon] ← NEW [Constraint ← [$PolExcludeByPDifContact, pExPdCon, TRUE, pdifSpinifex]];
polCnstr[pChE] ← NEW [Constraint ← [$PolChannelEdge, pChE]];
polCnstr[pDxorP] ← NEW [Constraint ← [$PolXorDif, pDxorP]];
polCnstr[pDandP] ← NEW [Constraint ← [$polAndDif, pDandP, TRUE, polSpinifex]];
polCnstr[pDErr] ← NEW [Constraint ← [$PolDifError, pDErr]];
polCnstr[pBur] ← NEW [Constraint ← [$PolBuried, pBur]];
polCnstr[pDExcl] ← NEW [Constraint ← [$PolExcludeNDif, pDExcl]];
polCnstr[pBurErr] ← NEW [Constraint ← [$PolBuriedNDifError, pBurErr]];
metCnstr[mCut] ← NEW [Constraint ← [$MetCut, mCut, TRUE, metSpinifex]];
metCnstr[mVia] ← NEW [Constraint ← [$MetVia, mVia, TRUE, metSpinifex]];
metCnstr[mVC] ← NEW [Constraint ← [$MetViaAndCutError, mVC]];
metCnstr[mVC] ← NEW [Constraint ← [$MetViaAndCutError, mVC, TRUE, metSpinifex]];
{
nd: SX.ConstraintIndex ~ SX.nodeIndex;
sp: SX.ConstraintIndex ~ SX.spaceIndex;
ndifResTab: SXTechnology.ResolutionTable ~ [
Constraint priority: sp < ndBur < nd < ndCnt < ndCh < ndWel < ndInWel < ndPWct < ndPdErr.
[ sp,   nd,   ndCh,  ndBur,  ndInWel, ndWel,  ndCnt,  ndPWct, ndPdErr, ,,,,,,],
[ nd,   nd,   ndCh,  nd,   ndInWel, ndInWel, ndCnt,  ndPdErr, ndPdErr, ,,,,,,],
[ ndCh,  ndCh,  ndCh,  ndCh,  ndInWel, ndInWel, ndCh,  ndPdErr, ndPdErr, ,,,,,,],
[ ndBur,  nd,   ndCh,  ndBur,  ndInWel, ndWel,  ndCnt,  ndPWct, ndPdErr, ,,,,,,],
[ ndInWel, ndInWel, ndInWel, ndInWel, ndInWel, ndInWel, ndCnt,  ndPdErr, ndPdErr, ,,,,,,],
[ ndWel,  ndInWel, ndInWel, ndWel,  ndInWel, ndWel,  ndCnt,  ndPWct, ndPdErr, ,,,,,,],
[ ndCnt,  ndCnt,  ndCh,  ndCnt,  ndCnt,  ndCnt,  ndCnt,  ndPdErr, ndPdErr, ,,,,,,],
[ ndPWct, ndPdErr, ndPdErr, ndPWct, ndPdErr, ndPWct, ndPdErr, ndPWct, ndPdErr, ,,,,,,],
[ ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ,,,,,,],
,,,,,,
];
pdifResTab: SXTechnology.ResolutionTable ~ [
Constraint priority: sp < nd < pdCnt < pdCh < pdNWct < pdNdErr
[ sp,   nd,   pdCh,  pdNdErr, pdCnt,  pdNWct, ,,,,,,,,,],
[ nd,   nd,   pdCh,  pdNdErr, pdCnt,  pdNdErr, ,,,,,,,,,],
[ pdCh,  pdCh,  pdCh,  pdNdErr, pdCh,  pdNdErr, ,,,,,,,,,],
[ pdNdErr, pdNdErr, pdNdErr, pdNdErr, pdNdErr, pdNdErr, ,,,,,,,,,],
[ pdCnt,  pdCnt,  pdCh,  pdNdErr, pdCnt,  pdNdErr, ,,,,,,,,,],
[ pdNWct, pdNdErr, pdNdErr, pdNdErr, pdNdErr, pdNWct, ,,,,,,,,,],
,,,,,,,,,
];
polyResTab: SXTechnology.ResolutionTable ~ [
Constraint priority: sp < pDxorP < pExnD < pExpD < pChE < pExNdCon < pExPdCon < pDExcl < pBur < nd < pBurErr < pDErr < pDandP
[ sp,   nd,   pExnD,  pExpD,  pExNdCon, pExPdCon, pChE,  pDExcl, pBur,  pBurErr, pDxorP, pDandP, pDErr,  ,,],
[ nd,   nd,   pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  nd,   nd,   pDErr,  nd,   pDandP, pDErr,  ,,],
[ pExnD,  pDErr,  pExnD,  pExpD,  pExNdCon, pExPdCon, pChE,  pBurErr, pBur,  pBurErr, pChE,  pDandP, pDErr,  ,,],
[ pExpD,  pDErr,  pExpD,  pExpD,  pExPdCon, pExPdCon, pChE,  pBurErr, pBur,  pBurErr, pChE,  pDandP, pDErr,  ,,],
[ pExNdCon, pDErr,  pExNdCon, pExPdCon, pExNdCon, pExPdCon, pExNdCon, pBurErr, pBur,  pBurErr, pChE,  pDandP, pDErr,  ,,],
[ pExPdCon, pDErr,  pExPdCon, pExPdCon, pExPdCon, pExPdCon, pExPdCon, pBurErr, pBur,  pBurErr, pChE,  pDandP, pDErr,  ,,],
[ pChE,  pDErr,  pChE,  pChE,  pExNdCon, pExPdCon, pChE,  pBurErr, pBur,  pBurErr, pChE,  pDandP, pDErr,  ,,],
[ pDExcl, nd,   pBurErr, pBurErr, pBurErr, pBurErr, pBurErr, pDExcl, pBur,  pBurErr, pDExcl, pDandP, pDErr,  ,,],
[ pBur,  nd,   pBur,  pBur,  pBur,  pBur,  pBur,  pBur,  pBur,  pBur,  pBur,  pDandP, pDErr,  ,,],
[ pBurErr, pDErr,  pBurErr, pBurErr, pBurErr, pBurErr, pBurErr, pBurErr, pBur,  pBurErr, pBurErr, pDandP, pDErr,  ,,],
[ pDxorP, nd,   pChE,  pChE,  pChE,  pChE,  pChE,  pDExcl, pBur,  pBurErr, pDxorP, pDandP, pDErr,  ,,],
[ pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, ,,],
[ pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDandP, pDErr,  ,,],
,,
];
metalResTab: SXTechnology.ResolutionTable ~ [
Constraint priority: sp < nd < mCut < mVia < mVC
[ sp,  nd,  mCut, mVia, mVC, ,,,,,,,,,,],
[ nd,  nd,  mCut, mVia, mVC, ,,,,,,,,,,],
[ mCut, mCut, mCut, mVC, mVC, ,,,,,,,,,,],
[ mVia, mVia, mVC, mVia, mVC, ,,,,,,,,,,],
[ mVC, mVC, mVC, mVC, mVC, ,,,,,,,,,,],
,,,,,,,,,,
];
ndifResolution ← SXTechnology.SetUpResolution [ndCnstr, ndifResTab];
pdifResolution ← SXTechnology.SetUpResolution [pdCnstr, pdifResTab];
polyResolution ← SXTechnology.SetUpResolution [polCnstr, polyResTab];
metalResolution ← SXTechnology.SetUpResolution [metCnstr, metalResTab];
};
Basic cMosHandle & cdLayerMappings.
cMosHandle ← NEW [SX.TechHandle ← [
numSpinifexLayers~ 6,
layerInterestBloat~ [nDifLayerSep, (ndifSpacing/2), (polSpacing/2), (metSeparation/2), (met2Separation/2), (wellSep/2),,],
combineNodeProperties~ CopyWellConnections,
cellPostProcess~ CheckWellConnections]
];
cMosHandle ← NEW[SX.TechHandle ← [
numSpinifexLayers~ 6,
layerInterestBloat~ [nDifLayerSep, (ndifSpacing/2), (polSpacing/2), (metSeparation/2), (met2Separation/2), l,,],
combineNodeProperties~ CopyWellConnections,
cellPostProcess~ CheckWellConnections]
];
cMosHandle.illegalLayer[CMosB.nwellCont] ← FALSE;
cMosHandle.illegalLayer[CMosB.pwellCont] ← FALSE;
cMosHandle.illegalLayer[CMosB.ndif] ← FALSE;
cMosHandle.illegalLayer[CMosB.pdif] ← FALSE;
cMosHandle.illegalLayer[CMosB.nwell] ← FALSE;
cMosHandle.illegalLayer[CMosB.pol] ← FALSE;
cMosHandle.illegalLayer[CMosB.met] ← FALSE;
cMosHandle.illegalLayer[CMosB.met2] ← FALSE;
cMosHandle.cdLayerMapping[CMosB.nwellCont] ← LIST [[ndifSpinifex, (ndifSpacing/2)], [wellSpinifex, l, NEW [SX.BoxMapProc ← AttachNWellContact]], [pdifSpinifex, (pdifSpacing/2), pdCnstr[pdNWct]], [ndifSpinifex, (ndifSpacing/2), ndCnstr[ndCnt]], [polSpinifex, difToPolExtSep, polCnstr[pExnD]]];
Order Important for well plugging, node is created in first mapping, and used in second.
cMosHandle.cdLayerMapping[CMosB.pwellCont] ← LIST [[pdifSpinifex, (pdifSpacing/2)], [ndifSpinifex, (ndifSpacing/2), ndCnstr[ndPWct]], [pdifSpinifex, (pdifSpinifex/2), pdCnstr[pdCnt]], [polSpinifex, difToPolExtSep, polCnstr[pExpD]]];
cMosHandle.cdLayerMapping[CMosB.ndif] ← LIST [[ndifSpinifex, (ndifSpacing/2)], [polSpinifex, difToPolExtSep, polCnstr[pExnD]]];
cMosHandle.cdLayerMapping[CMosB.pdif] ← LIST [[pdifSpinifex, (pdifSpacing/2)], [polSpinifex, difToPolExtSep, polCnstr[pExpD]]];
cMosHandle.cdLayerMapping[CMosB.nwell] ← LIST [[ndifSpinifex, nDifToWell-(ndifSpacing/2), ndCnstr[ndWel]], [wellSpinifex, (wellSep/2)]];
cMosHandle.cdLayerMapping[CMosB.nwell] ← LIST [[ndifSpinifex, nDifToWell-(ndifSpacing/2), ndCnstr[ndWel]], [wellSpinifex, l]]; -- INTERIM
cMosHandle.cdLayerMapping[CMosB.pol] ← LIST [[polSpinifex, (polSpacing/2)]];
cMosHandle.cdLayerMapping[CMosB.met] ← LIST [[metSpinifex, (metSeparation/2)]];
cMosHandle.cdLayerMapping[CMosB.met2] ← LIST [[m2Spinifex, (met2Separation/2)]];
Translations for Opaque Cells.
BEGIN
conInfl: CD.Number ~ l; -- Influence distance of contacts.
Using value $Opaque ensures we get an error if these are ever used as normal cdLayerMappings.
cMosHandle.cdLayerMapping[CMosB.cut] ← LIST [[ndifSpinifex, conInfl, $Opaque], [pdifSpinifex, conInfl, $Opaque], [polSpinifex, conInfl, $Opaque], [metSpinifex, conInfl, $Opaque]];
cMosHandle.cdLayerMapping[CMosB.cut2] ← LIST [[metSpinifex, conInfl, $Opaque], [m2Spinifex, conInfl, $Opaque]];
cMosHandle.cdLayerMapping[CMosB.bur] ← LIST [[ndifSpinifex, (met2Separation/2), $Opaque], [polSpinifex, conInfl, $Opaque]];
END;
Spinifex Layer Identification.
cMosHandle.spinifexLayerNames[ndifSpinifex].layerId ← $nDiffusion;
cMosHandle.spinifexLayerNames[pdifSpinifex].layerId ← $pDiffusion;
cMosHandle.spinifexLayerNames[polSpinifex].layerId ← $Poly;
cMosHandle.spinifexLayerNames[metSpinifex].layerId ← $Metal;
cMosHandle.spinifexLayerNames[m2Spinifex].layerId ← $Metal2;
cMosHandle.spinifexLayerNames[wellSpinifex].layerId ← $NWell;
Thyme stray capacitance layer names.
cMosHandle.spinifexLayerNames[ndifSpinifex].thymeName ← "nD";
cMosHandle.spinifexLayerNames[pdifSpinifex].thymeName ← "pD";
cMosHandle.spinifexLayerNames[polSpinifex].thymeName ← "P";
cMosHandle.spinifexLayerNames[metSpinifex].thymeName ← "M";
cMosHandle.spinifexLayerNames[m2Spinifex].thymeName ← "M2";
Set Constraint Resolutions for each layer into the TechHandle.
cMosHandle.constraintResolutions[ndifSpinifex] ← ndifResolution;
cMosHandle.constraintResolutions[pdifSpinifex] ← pdifResolution;
cMosHandle.constraintResolutions[polSpinifex] ← polyResolution;
cMosHandle.constraintResolutions[metSpinifex] ← metalResolution;
The geometric rules.
InitRules [cMosHandle];
Technology handle is attached to the ChipNDale technology.
SXTechnology.RegisterTechnologyHandle[cdTech~ CMosB.cmosB, technologyHandle~ cMosHandle];
Technology specific objects.
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2Trans, conv~ ConvTransistor, thyme~ ThymeTransistor, rose~ RoseTransistor, fini~ SXOutputPrivate.UnNameTransType];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2WellTrans, conv~ ConvTransistor, thyme~ ThymeTransistor, rose~ RoseTransistor, fini~ SXOutputPrivate.UnNameTransType];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2LTrans, conv~ ConvTransistor, thyme~ ThymeTransistor, rose~ RoseTransistor, fini~ SXOutputPrivate.UnNameTransType];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2LWellTrans, conv~ ConvTransistor, thyme~ ThymeTransistor, rose~ RoseTransistor, fini~ SXOutputPrivate.UnNameTransType];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $CLWellTrans, conv~ ConvTransistor, thyme~ ThymeTransistor, rose~ RoseTransistor, fini~ SXOutputPrivate.UnNameTransType];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2PDifRect, conv~ ConvertPDifRect];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2NDifRect, conv~ ConvertPDifRect];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2SimpleCon, conv~ ConvertContact];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2WellSimpleCon, conv~ ConvertContact];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2LargeSimpleCon, conv~ ConvertContact];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2LargeWellSimpleCon, conv~ ConvertContact];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2DifShortCon, conv~ ConvertContact];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2WellDifShortCon, conv~ ConvertContact];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2Via, conv~ ConvertContact];
SXTechnology.RegisterSpinifexObjectProcs [cdTech~ CMosB.cmosB, objectType~ $C2LargeVia, conv~ ConvertContact];
};
Main
Init [];
TerminalIO.WriteRope ["cMos technology parameters Loaded\n"];
END.
gbb January 14, 1986 2:56:00 pm PST
Fixed some rules.
gbb February 10, 1986 1:17:39 pm PST
Fixed bug in the verification of cuts.
gbb March 11, 1986 1:33:49 pm PST
The contact class C2WellDifShortCon was only partially implemented
changes to: ConvertContact: added as a valid contact, Init: added registration
gbb March 15, 1986 1:03:26 pm PST
Tracked change in design rules
changes to: metCutViaSpacing: changed from 3l to 2l.
gbb March 17, 1986 6:50:46 pm PST
Made better use of CDSimpleRules.
changes to: ndifSpacing, ndifUncSubtrContSpacing, ndifInnWell, ndifpSubstrCont, pdifUncnWellSpacing, pdifnWellCont, polUncDifSpacing, polDiffUncPolySpacing, polOverDiff, metCutCutSpacing, metViaViaSpacing, metCutViaSpacing, difSep, nDifToWell.
gbb March 19, 1986 11:29:42 am PST
Improved rules for diffusion
changes to: ndifSpacing, ndifUncSubtrContSpacing, ndifpSubstrCont, pdifSpacing, pdifUncnWellSpacing, difSep, nDifToWell, pDifToWell, nDifTopDif, pdifUncSubtrContSpacing, nDifToSubtrCont, pDifToSubtrCont, ndifSpinifex, InitRules
gbb June 2, 1986 2:24:48 pm PDT
Bug fix in split contacts.
changes to: ConvertContact: the well of split contacts no longer is a separate node.
gbb June 10, 1986 6:41:58 pm PDT
Tracked change of atom for p angle transistors and added a case for old classes
changes to: ConvTransistor: fixed atoms and made new case for old classes, Init: registers with ChipNDale both the new and some old classes in oreder to provide clearer error messages.