SXCMosBImpl.mesa
Copyright Ó 1984, 1986, 1987 by Xerox Corporation. All rights reserved.
Written by gbb, November 25, 1985 6:36:23 pm PST
Last edited by: gbb October 12, 1987 4:37:02 pm PDT
Last edited by: Christian Jacobi, November 7, 1986 1:51:35 pm PST
DIRECTORY
CD,
CDAtomicObjects USING [AtomicObsSpecific, DrawList],
CDBasics,
CDProperties USING [GetInstanceProp],
CDSimpleRules USING [MinSpace, MinWidth],
CMosB USING [bur, cmosB, cut, cut2, lambda, met, met2, ndif, nwell, nwellCont, pdif, pol, pwell, pwellCont, wellSurround, wndif, wpdif],
DesignRules USING [GetRuleSet, MinSpace, MinWidth, Rules],
IO USING [atom, char, int, Put, PutF, PutFR, PutRope, rope],
Properties 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 [PutRope];
SXCMosBImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDProperties, CMosB, DesignRules, IO, Properties, Rope, SX, SXAccess, SXAccessInternal, SXAtoms, SXOutputPrivate, SXTechnology, TerminalIO
~ BEGIN
Basic definitions and rules (Version with rules from Saguaro)
ruleSet: ATOM ~ $VTI;
l: CD.Number ~ CMosB.lambda;
Nodes: TYPE = LIST OF REF SX.CircuitNode;
ConstraintArray: TYPE ~ SX.ConstraintArray;
CIndex: TYPE ~ SX.ConstraintIndex;
Constraint: TYPE ~ SX.Constraint;
saguaroRules: DesignRules.Rules ~ DesignRules.GetRuleSet [ruleSet];
ndif summary for Dragon rules (not VTI)
N é P:  MinSpace [ndif, pdif] / l => 10
N é N: MinSpace [ndif, ndif] / l => 3ý
P é P:  MinSpace [pdif, pdif] / l => 3ý
N é N-well: MinSpace [ndif, nwell] / l => 5
P é P-well: MinSpace [pdif, pwell] / l => 5
N é P-well-contact: MinSpace [ndif, pwellCont] / l => 3ý [rule 6.3.3]
P é N-well-contact: MinSpace [pdif, nwellCont] / l => 3ý [rule 6.3.3]
N é N-well-contact: MinSpace [ndif, nwellCont] / l => 9
P é P-well-contact: MinSpace [pdif, pwellCont] / l => 9
N-well é P-well-contact: MinSpace [nwell, pwellCont] / l => 4 [rule 6.3.9]
P-well é N-well-contact: MinSpace [pwell, nwellCont] / l => 4 [rule 6.3.9]
N-well-contact é P-well-contact: MinSpace [nwellCont, pwellCont] / l => 8 [rule 6.3.6]
ndif layer
ndifSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.ndif].s;
ndifWidth: CD.Number = DesignRules.MinWidth [saguaroRules, CMosB.ndif].w;
ndifUncSubtrContSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.pwellCont].s;
n-Diffusion/unconnected p-substrate-contact spacing
ndifInnWell: CD.Number = 0 * l;
n-Diffusion in n-Well
ndifpSubstrCont: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.pwellCont].s;
n-Diffusion and p-substrate-contact
pdif layer
pdifSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.pdif, CMosB.pdif].s;
pdifWidth: CD.Number = DesignRules.MinWidth [saguaroRules, CMosB.pdif].w;
pdifUncnWellSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.pdif, CMosB.nwellCont].s;
p-Diffusion/unconnected n-Well-contact spacing
pdifnWellCont: CD.Number = 0 * l;
p-Diffusion and n-Well-contact
pol layer
polSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.pol, CMosB.pol].s;
polWidth: CD.Number = DesignRules.MinWidth [saguaroRules, CMosB.pol].w;
polUncDifSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.pol, CMosB.ndif].s;
Poly/unconnected Diffusion spacing
polDiffUncPolySpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.pol].s;
Diffusion/unconnected Poly spacing
polOverDiff: CD.Number = 0 * l;
Poly over Diffusion
met layer
metSeparation: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.met, CMosB.met].s;
metWidth: CD.Number = DesignRules.MinWidth [saguaroRules, CMosB.met].w;
metCutCutSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.cut, CMosB.cut].s;
Cut to Cut spacing
metViaViaSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.cut2, CMosB.cut2].s;
Via to Via spacing
metCutViaSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.cut, CMosB.cut2].s;
Cut to Via spacing
met2 layer
met2Separation: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.met2, CMosB.met2].s;
met2Width: CD.Number = DesignRules.MinWidth [saguaroRules, CMosB.met2].w;
Some of these numbers are half of the actual minimum distances we are checking for:
difSep: CD.Number = ndifSpacing / 2;
wellSep: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.nwell, CMosB.nwell].s;
wellWidth: CD.Number = DesignRules.MinWidth [saguaroRules, CMosB.nwell].w;
nDifToWell: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.nwell].s;
pDifToWell: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.pdif, CMosB.pwell].s;
nDifTopDif: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.pdif].s;
pdifUncSubtrContSpacing: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.pdif, CMosB.nwellCont].s;
nDifToSubtrCont: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.nwellCont].s;
pDifToSubtrCont: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.pdif, CMosB.pwellCont].s;
nDifLayerSep: CD.Number = MAX [difSep, nDifToWell - difSep];
extensionLength: CD.Number = 3 * l; -- source/drain extension [rule 6.3.18]
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.
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;
Basic definitions and rules (Version with rules from CDSimpleRules)
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:  MinSpace [ndif, pdif] / l => 10
N é N: MinSpace [ndif, ndif] / l => 3ý
P é P:  MinSpace [pdif, pdif] / l => 3ý
N é N-well: MinSpace [ndif, nwell] / l => 5
P é P-well: MinSpace [pdif, pwell] / l => 5
N é P-well-contact: MinSpace [ndif, pwellCont] / l => 3ý [rule 6.3.3]
P é N-well-contact: MinSpace [pdif, nwellCont] / l => 3ý [rule 6.3.3]
N é N-well-contact: MinSpace [ndif, nwellCont] / l => 9
P é P-well-contact: MinSpace [pdif, pwellCont] / l => 9
N-well é P-well-contact: MinSpace [nwell, pwellCont] / l => 4 [rule 6.3.9]
P-well é N-well-contact: MinSpace [pwell, nwellCont] / l => 4 [rule 6.3.9]
N-well-contact é P-well-contact: MinSpace [nwellCont, pwellCont] / l => 8 [rule 6.3.6]
ndif layer
ndifSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.ndif, CMosB.ndif]; -- (3ý l)
ndifWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.cmosB.key, CMosB.ndif];
ndifUncSubtrContSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, 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.MinSpace [CMosB.cmosB.key, CMosB.ndif, CMosB.pwellCont];
n-Diffusion and p-substrate-contact (3ý l)
pdif layer
pdifSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.pdif, CMosB.pdif]; -- (3ý l)
pdifWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.cmosB.key, CMosB.pdif];
pdifUncnWellSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, 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.MinSpace [CMosB.cmosB.key, CMosB.pol, CMosB.pol];
polWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.cmosB.key, CMosB.pol];
polUncDifSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.pol, CMosB.ndif];
Poly/unconnected Diffusion spacing (1 l)
polDiffUncPolySpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.ndif, CMosB.pol];
Diffusion/unconnected Poly spacing (1 l)
polOverDiff: CD.Number = 0 * l;
Poly over Diffusion
met layer
metSeparation: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.met, CMosB.met];
metWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.cmosB.key, CMosB.met];
metCutCutSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.cut, CMosB.cut];
Cut to Cut spacing (3 l)
metViaViaSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.cut2, CMosB.cut2];
Via to Via spacing (4 l)
metCutViaSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.cut, CMosB.cut2];
Cut to Via spacing (2 l)
met2 layer
met2Separation: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.met2, CMosB.met2];
met2Width: CD.Number = CDSimpleRules.MinWidth [CMosB.cmosB.key, 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.MinSpace [CMosB.cmosB.key, CMosB.nwell, CMosB.nwell]; -- (10 l)
wellWidth: CD.Number = CDSimpleRules.MinWidth [CMosB.cmosB.key, CMosB.nwell];  -- (12 l)
nDifToWell: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.ndif, CMosB.nwell]; -- (5 l)
pDifToWell: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.pdif, CMosB.pwell]; -- (5 l)
nDifTopDif: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.ndif, CMosB.pdif]; -- (10 l)
pdifUncSubtrContSpacing: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.pdif, CMosB.nwellCont]; -- (3ý l)
nDifToSubtrCont: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.ndif, CMosB.nwellCont]; -- (9 l)
pDifToSubtrCont: CD.Number = CDSimpleRules.MinSpace [CMosB.cmosB.key, CMosB.pdif, CMosB.pwellCont]; -- (9 l)
nDifLayerSep: CD.Number = MAX [difSep, nDifToWell - difSep];
extensionLength: CD.Number = 3 * l; -- source/drain extension [rule 6.3.18]
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.
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 ~ ndCh.SUCC; -- n-Diffusion in n-Well
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 ~ pChE.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 ← Properties.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 = ob.class.objectType;
isNType: BOOL = (ob.layer = CMosB.ndif);
isNWell: BOOL;
difSXLayer: SX.SpinifexLayerIndex;
difChannel, exclPol: REF SX.Constraint;
sep: CD.Number = DesignRules.MinSpace [saguaroRules, CMosB.ndif, CMosB.pol].s;
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 [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 [ob.specific, CDAtomicObjects.AtomicObsSpecific] THEN
FOR geom: CDAtomicObjects.DrawList ← NARROW [ob.specific, CDAtomicObjects.AtomicObsSpecific].rList, geom.rest WHILE geom # NIL DO
SELECT geom.first.layer 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.layer = 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;
IF (extL < extensionLength) THEN
ERROR SX.IllegalConstruct [errorRect, "Extension length too small"];
Process poly layer
gateNode ← SX.AddRect [cir: cir, lev: CMosB.pol, dim: polRect, trans: trans];
IF extL > sep THEN-- Add rectangles for poly exclusion over extensions
BEGIN
rect ← difExtRectNorth;
rect.y1 ← difExtRectNorth.y1 + sep; rect.y2 ← difExtRectNorth.y1 + polSpacing;
[] ← SX.AddBox [cir, polSpinifex, rect, trans, SXTechnology.WNEGrow [extSep], exclPol];
rect ← difExtRectSouth;
rect.y2 ← difExtRectSouth.y2 - sep; rect.y1 ← difExtRectSouth.y2 - polSpacing;
[] ← SX.AddBox [cir, polSpinifex, rect, trans, SXTechnology.ESWGrow [extSep], exclPol];
END;
Process channel lead-in
rect ← difExtRectNorth; rect.y2 ← rect.y1 + sep;
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, trans: trans, value: polCnstr[pChE]];
rect ← difExtRectSouth; rect.y1 ← rect.y2 - sep;
[] ← SX.AddBox [cir: cir, spinifexLayer: polSpinifex, dim: rect, trans: trans, 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, trans: trans,
interestBloat: [dx1: (DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/2), dy1: 0, dx2: (DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/2), dy2: 0],
value: difChannel];
Add rectangles for diff width spacing and connection
sourceNode ← SX.AddBox[cir: cir, spinifexLayer: difSXLayer,
dim: difExtRectNorth, trans: trans,
interestBloat: SXTechnology.WNEGrow[(DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/2)]];
drainNode ← SX.AddBox[cir: cir, spinifexLayer: difSXLayer,
dim: difExtRectSouth, trans: trans,
interestBloat: SXTechnology.ESWGrow[(DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/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, trans: trans];
wellNode.properties ← Properties.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;
IF (extL < extensionLength) THEN
ERROR SX.IllegalConstruct [errorRect, "Extension length too small"];
Process poly layer
gateNode ← SX.AddRect [cir: cir, lev: CMosB.pol, dim: polHor, trans: trans];
[] ← SX.AddRect [cir: cir, lev: CMosB.pol, dim: polVert, trans: trans, value: gateNode];
IF extL > sep THEN BEGIN -- Add rectangles for poly exclusion over extensions
d1: CD.Number ← extL + length + sep;
d2: CD.Number ← extL + polSpacing;
North:
rect ← [x1: diffSW.x, y1: diffSW.y+d1, x2: diffNE.x-d1, y2: diffSW.y+length+d2];
[] ← SX.AddBox [cir, polSpinifex, rect, trans, SXTechnology.WNGrow [extSep], exclPol];
West:
rect ← [x1: diffNE.x-length-d2, y1: diffSW.y+d1, x2: diffNE.x-d1, y2: diffNE.y];
[] ← SX.AddBox [cir, polSpinifex, rect, trans, SXTechnology.WNGrow [extSep], exclPol];
d1 ← extL - sep; d2 ← extL - polSpacing;
South:
rect ← [x1: diffSW.x, y1: diffSW.y+d2, x2: diffNE.x-d2, y2: diffSW.y+d1];
[] ← SX.AddBox [cir, polSpinifex, rect, trans, SXTechnology.ESWGrow [extSep], exclPol];
East:
rect ← [x1: diffNE.x-d1, y1: diffSW.y, x2: diffNE.x-d2, y2: diffNE.y];
[] ← SX.AddBox [cir, polSpinifex, rect, trans, SXTechnology.NESGrow [extSep], exclPol]
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, trans: trans, 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, trans: trans, 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, trans: trans, 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, trans: trans, 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, trans: trans,
interestBloat: [dx1: (DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/2), dy1: 0, dx2: 0, dy2: 0],
value: difChannel];
rect ← polVert; rect.y2 ← rect.y2 - extW;
[] ← SX.AddBox [cir: cir, spinifexLayer: difSXLayer,
dim: rect, trans: trans,
interestBloat: [dx1: 0, dy1: 0, dx2: 0, dy2: (DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/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, trans: trans,
interestBloat: SXTechnology.WNGrow[(DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/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, trans: trans,
interestBloat: SXTechnology.WNGrow[(DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/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, trans: trans,
interestBloat: SXTechnology.ESWGrow[(DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/2)]];
rect ← [x1: diffNE.x-extL, y1: rect.y2, x2: diffNE.x, y2: diffNE.y];
[] ← SX.AddBox[cir: cir, spinifexLayer: difSXLayer,
dim: rect, trans: trans,
interestBloat: SXTechnology.NESGrow[(DesignRules.MinSpace[saguaroRules, CMosB.ndif, CMosB.ndif].s/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, trans: trans];
wellNode.properties ← Properties.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, NEW[CD.InstanceRep←[ob: ob]], 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.PutRope [" $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 ← ob.bbox;
pDifBox: CD.Rect ← CDBasics.Extend[nWellBox, -CMosB.wellSurround];
IF ~CDBasics.NonEmpty[pDifBox] THEN
BEGIN
TerminalIO.PutRope [" this cell contains a w-pDif object whose pDif rectangle is empty\n"];
ERROR
END;
[] ← cir.AddRect [lev~CMosB.pdif, dim~pDifBox, trans~trans];
wellNode ← cir.AddRect [lev~CMosB.nwell, dim~nWellBox, trans~trans];
wellNode.properties ← Properties.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 = ob.class.objectType;
r: CD.Rect = CD.InterestRect [ob];
node: REF SX.CircuitNode ← NIL;
size: CD.Position;
sizeExceeded: BOOLFALSE;
SELECT classKey FROM
$C2SimpleCon, $C2WellSimpleCon, $C2LargeSimpleCon, $C2LargeWellSimpleCon, $C2DiffShortCon, $C2DifShortCon, $C2WellDifShortCon, $C2Via, $C2LargeVia =>
FOR geom: CDAtomicObjects.DrawList ← NARROW [ob.specific, CDAtomicObjects.AtomicObsSpecific].rList, geom.rest WHILE geom # NIL DO
SELECT geom.first.layer FROM
CMosB.ndif, CMosB.pdif => {
node ← SX.AddRect[cir: cir, lev: geom.first.layer, dim: geom.first.r, trans: trans, value: node];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: geom.first.r, trans: trans, value: polCnstr[(IF geom.first.layer = 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.layer, dim: geom.first.r, trans: trans, value: bridge];
wellNode.properties ← Properties.PutProp [wellNode.properties, wellNode, wellNode];
};
CMosB.nwellCont, CMosB.pwellCont => {
node ← SX.AddRect[cir: cir, lev: geom.first.layer, dim: geom.first.r, trans: trans, value: node];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: geom.first.r, trans: trans, value: polCnstr[(IF geom.first.layer = CMosB.nwellCont THEN pExNdCon ELSE pExPdCon)]];
};
CMosB.met, CMosB.met2, CMosB.pol =>
node ← SX.AddRect[cir: cir, lev: geom.first.layer, dim: geom.first.r, trans: trans, value: node];
CMosB.cut => { -- all but vias
[] ← SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, trans: trans, value: metCnstr[mCut]];
size ← Size [geom.first.r];
SELECT classKey FROM
$C2DifShortCon, $C2WellDifShortCon, $C2DiffShortCon =>
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, trans: trans, 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: Properties.PropList, fromNesting: LIST OF CD.Instance] RETURNS [Properties.PropList]
fromConnections: Nodes
NARROW [Properties.GetProp [propList: from, prop: wellConnection]];
toConnections: Nodes
NARROW [Properties.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 ← Properties.PutProp [propList: to, prop: wellConnection, val: toConnections];
IF (Properties.GetProp [propList: from, prop: wellNode] # NIL)
AND (Properties.GetProp [propList: to, prop: wellNode] = NIL) THEN
to ← Properties.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 ← (Properties.GetProp
[propList: nl.first.properties, prop: wellNode] # NIL);
hasConnection ← (Properties.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 = CDBasics.MapPoint [pointInCell: nl.first.loc.xy, cellInWorld: scl.first.trans];
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 ← (Properties.GetProp[propList: nl.first.properties, prop: wellNode] # NIL);
IF hasNode THEN {
wellConnects ← NARROW [Properties.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, trans: trans,
interestBloat: [l, l, l, l]];
IF node = NIL THEN ERROR;
wellCon.properties ← Properties.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,  ndInWel, ndWel,  ndCnt,  ndPWct, ndPdErr, ,,,,,,,],
[ nd,   nd,   ndCh,  ndInWel, ndInWel, ndCnt,  ndPdErr, ndPdErr, ,,,,,,,],
[ ndCh,  ndCh,  ndCh,  ndInWel, ndInWel, ndCh,  ndCh,  ndPdErr, ,,,,,,,],
[ ndInWel, ndInWel, ndInWel, ndInWel, ndInWel, ndCnt,  ndPdErr, ndPdErr, ,,,,,,,],
[ ndWel,  ndInWel, ndInWel, ndInWel, ndWel,  ndCnt,  ndPWct, ndPdErr, ,,,,,,,],
[ ndCnt,  ndCnt,  ndCh,  ndCnt,  ndCnt,  ndCnt,  ndPdErr, ndPdErr, ,,,,,,,],
[ ndPWct, ndPdErr, ndCh,  ndPdErr, ndPWct, ndPdErr, ndPWct, ndPdErr, ,,,,,,,],
[ ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ndPdErr, ,,,,,,,],
,,,,,,,
];
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,  pdCh,  ,,,,,,,,,],
[ pdNdErr, pdNdErr, pdNdErr, pdNdErr, pdNdErr, pdNdErr, ,,,,,,,,,],
[ pdCnt,  pdCnt,  pdCh,  pdNdErr, pdCnt,  pdNdErr, ,,,,,,,,,],
[ pdNWct, pdNdErr, pdCh,  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,  pDxorP, pDandP, pDErr,  ,,,,,],
[ nd,   nd,   pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  nd,   pDandP, pDErr,  ,,,,,],
[ pExnD,  pDErr,  pExnD,  pExpD,  pExNdCon, pExPdCon, pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pExpD,  pDErr,  pExpD,  pExpD,  pExPdCon, pExPdCon, pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pExNdCon, pDErr,  pExNdCon, pExPdCon, pExNdCon, pExPdCon, pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pExPdCon, pDErr,  pExPdCon, pExPdCon, pExPdCon, pExPdCon, pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pChE,  pDErr,  pChE,  pChE,  pChE,  pChE,  pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pDxorP, nd,   pChE,  pChE,  pChE,  pChE,  pChE,  pDxorP, pDandP, pDErr,  ,,,,,],
[ pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, ,,,,,],
[ pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDandP, pDErr,  ,,,,,],
,,,,,
];
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,  pDxorP, pDandP, pDErr,  ,,,,,],
[ nd,   nd,   pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  nd,   pDandP, pDErr,  ,,,,,],
[ pExnD,  pDErr,  pExnD,  pExpD,  pExNdCon, pExPdCon, pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pExpD,  pDErr,  pExpD,  pExpD,  pExPdCon, pExPdCon, pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pExNdCon, pDErr,  pExNdCon, pExPdCon, pExNdCon, pExPdCon, pExNdCon, pChE,  pDandP, pDErr,  ,,,,,],
[ pExPdCon, pDErr,  pExPdCon, pExPdCon, pExPdCon, pExPdCon, pExPdCon, pChE,  pDandP, pDErr,  ,,,,,],
[ pChE,  pDErr,  pChE,  pChE,  pExNdCon, pExPdCon, pChE,  pChE,  pDandP, pDErr,  ,,,,,],
[ pDxorP, nd,   pChE,  pChE,  pChE,  pChE,  pChE,  pDxorP, pDandP, pDErr,  ,,,,,],
[ pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, pDandP, ,,,,,],
[ pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDErr,  pDandP, pDErr,  ,,,,,],
,,,,,
];
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, polUncDifSpacing, polCnstr[pExnD]]];
cMosHandle.cdLayerMapping[CMosB.pdif] ← LIST [[pdifSpinifex, (pdifSpacing/2)], [polSpinifex, polUncDifSpacing, 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~ $C2DiffShortCon, 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.PutRope [IO.PutFR ["\nCMOS technology parameters loaded with values for rule set %g as specified in Saguaro.\n", IO.atom [ruleSet]]]
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.
gbb October 13, 1986 6:20:26 pm PDT
Tried to fix the separation between gates and between well and substrate contacts to unrelated diffusion.
changes to: extensionLength: new, difToPolExtSep: used to be 0
gbb October 23, 1986 1:01:40 pm PDT
Changed the way constraints are computed in order to allow local exceptions to rules.
changes to: ConvTransistor
gbb October 24, 1986 11:38:05 am PDT
Allowed well/substrate contacts to be closer to diffusion than the rules requires, if it is across a gate.
changes to: Init: constraint resolution ndPWct + ndCh = ndCh (was ndPdErr). Idem for p-diff
gbb May 14, 1987 12:23:57 pm PDT
Tracked new contact class $C2DiffShortCon.
changes to: ConvertContact, Init
gbb October 5, 1987 2:59:07 pm PDT
Values for design rules are now taken from Saguaro instead of ChipNDale.
changes to: DIRECTORY, IMPORTS, ndifSpacing, ndifWidth, ndifUncSubtrContSpacing, ndifInnWell, ndifpSubstrCont, pdifSpacing, pdifWidth, pdifUncnWellSpacing, polSpacing, polWidth, polUncDifSpacing, polDiffUncPolySpacing, metSeparation, metWidth, metCutCutSpacing, metViaViaSpacing, metCutViaSpacing, met2Separation, met2Width, difSep, wellSep, wellWidth, nDifToWell, pDifToWell, nDifTopDif, pdifUncSubtrContSpacing, nDifToSubtrCont, pDifToSubtrCont, ConvTransistor, TerminalIO
gbb October 12, 1987 4:30:37 pm PDT
Change constraint resolution PolExcludeByNDifContact  PolChannelEdge from PolExcludeByNDifContact to PolChannelEdge for both difusion sexes. This allows one to place diffusion contact guard rings at ýl from a gate instead of what the di to poly rule says.
changes to: Init