SXCMosContactsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by: gbb March 21, 1986 5:27:31 pm PST
Bowers, September 12, 1985 2:35:35 pm PDT
Last edited by: Christian Jacobi, November 7, 1986 4:55:27 pm PST
DIRECTORY
CD,
CDAtomicObjects,
CDBasics,
CMos USING [lambda, bur, cut, cut2, met, met2, ndif, nwell, pwell, nwellCont, pdif, pol, pwellCont, wellSurround],
IO USING [atom, PutFR],
Properties USING [GetProp, PutProp],
Rope USING [ROPE],
SX USING [AddBox, AddRect, BoxMapProc, CellPostProcessProc, Circuit, CircuitNode, CombineNodePropertyProc, Constraint, ConversionProc, FindRootNode, IllegalConstruct, LookupNode, SpinifexLayerIndex],
SXAccess USING [invocation, sxTech],
SXAccessInternal USING [PutError],
SXCMos USING [mCut, metCnstr, metSpinifex, mVia, ndBur, ndCh, ndCnstr, ndifSpinifex, pBur, pChE, pDandP, pdCh, pdCnstr, pDExcl, pdifSpinifex, pDxorP, pExNdCon, pExPdCon, polCnstr, polSpinifex, wellSpinifex],
SXTechnology USING [GetCircuitFromCDObject],
TerminalIO USING [PutRope];
SXCMosContactsImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CMos, IO, Properties, SX, SXAccess, SXAccessInternal, SXCMos, SXTechnology, TerminalIO
EXPORTS SXCMos =
BEGIN
OPEN SXCMos;
l: CD.Number ~ CMos.lambda;
wellConnection: ATOM ~ $SXCMosWellConnection;
wellNode: ATOM ~ $SXCMosNWellNode;
Nodes: TYPE = LIST OF REF SX.CircuitNode;
ConvertPDifRect: PUBLIC SX.ConversionProc ~ {
wellNode: REF SX.CircuitNode;
sixe: CD.Position ← CDBasics.SizeOfRect[ob.bbox];
nWellBox: CD.Rect ← ob.bbox;
pDifBox: CD.Rect ← CDBasics.Extend[nWellBox, -CMos.wellSurround];
IF ~CDBasics.NonEmpty[pDifBox] THEN {
TerminalIO.PutRope [" this cell contains a w-pDif object whose pDif rectangle is empty\n"];
ERROR
};
[] ← cir.AddRect [lev~CMos.pdif, dim~pDifBox, trans~trans];
wellNode ← cir.AddRect [lev~CMos.nwell, dim~nWellBox, trans~trans];
wellNode.properties ← Properties.PutProp [wellNode.properties, wellNode, wellNode];
};
ContactMap: TYPE ~ RECORD [
rm: LIST OF RectMap,
bm: LIST OF BoxMap
];
MapRectDelta: TYPE ~ RECORD [dx1, dy1, dx2, dy2: INT];
RectMap: TYPE ~ RECORD [
layer: CD.Layer,
delta: MapRectDelta ← [0,0,0,0]
];
BoxMap: TYPE ~ RECORD [
layerInd: SX.SpinifexLayerIndex,
value: REF ANY,
delta: MapRectDelta ← [0,0,0,0]
];
ContactType: TYPE = {mnDif, mpDif, mnWCont, mpWCont, nDifShort, pDifShort, nbutt, pbutt, mPol, mm2, burSim, burPolS, burDifI, burDifL};
MapArray: TYPE ~ ARRAY ContactType OF ContactMap;
ContactMaps: REF MapArray;
InitContacts: PUBLIC PROCEDURE ~ {
ws: CD.Number ~ CMos.wellSurround;
buttBaseBM: LIST OF BoxMap;
ContactMaps ← NEW[MapArray ← ALL [[NIL, NIL] ]];
`Normal' layers must precede nwellCont.
ContactMaps[mnDif].rm ← LIST[[CMos.ndif], [CMos.met] ];
ContactMaps[mnDif].bm ← LIST[[polSpinifex, polCnstr[pExNdCon]], [metSpinifex, metCnstr[mCut], [-l,-l, -l,-l]] ];
ContactMaps[mpDif].rm ← LIST[[CMos.pdif], [CMos.met], [CMos.nwell, [ws,ws,ws,ws]] ];
ContactMaps[mpDif].bm ← LIST[[polSpinifex, polCnstr[pExPdCon]], [metSpinifex, metCnstr[mCut], [-l,-l, -l,-l]] ];
ContactMaps[mnWCont].rm ← LIST[[CMos.met], [CMos.nwellCont] ];
ContactMaps[mnWCont].bm ← ContactMaps[mnDif].bm;
ContactMaps[mpWCont].rm ← LIST[[CMos.met], [CMos.pwellCont] ];
ContactMaps[mpWCont].bm ← ContactMaps[mpDif].bm;
ContactMaps[mPol].rm ← LIST[[CMos.pol], [CMos.met] ];
ContactMaps[mPol].bm ← LIST[[metSpinifex, metCnstr[mCut], [-l,-l, -l,-l]] ];
ContactMaps[mm2].rm ← LIST[[CMos.met2], [CMos.met] ];
-- ContactMaps[mm2].bm ← LIST[[metSpinifex, metCnstr[mVia], [l,l, l,l]] ];
The following line is a temporary fix !
ContactMaps[mm2].bm ← LIST[[metSpinifex, metCnstr[mVia], [0,0, 0,0]] ];
ContactMaps[nDifShort].rm ← LIST[[CMos.ndif, [0,0,0,-4*l]], [CMos.pwellCont, [0,-4*l,0,0]], [CMos.met] ];
ContactMaps[nDifShort].bm ← ContactMaps[mnDif].bm;
ContactMaps[pDifShort].rm ← LIST[[CMos.pdif, [0,0,0,-4*l]], [CMos.nwellCont, [0,-4*l,0,0]], [CMos.met], [CMos.nwell, [ws,ws,ws,ws-4*l]] ];
ContactMaps[pDifShort].bm ← ContactMaps[mpDif].bm;
ContactMaps[nbutt].rm ← LIST[[CMos.ndif, [0,-3*l,0,0]], [CMos.pol, [0,0,0,-3*l]], [CMos.met] ];
buttBaseBM ← LIST[[polSpinifex, polCnstr[pChE], [0,-3*l, 0,-2*l]], [polSpinifex, polCnstr[pDxorP], [l,-2*l, -4*l,-2*l]], [polSpinifex, polCnstr[pDxorP], [-4*l,-2*l, l,-2*l]], [polSpinifex, polCnstr[pDandP], [0,-2*l, 0,-3*l]], [metSpinifex, metCnstr[mCut], [-l,-l, -l,-l]] ];
ContactMaps[nbutt].bm ← CONS[[ndifSpinifex, ndCnstr[ndCh], [0,-2*l, 0,-3*l]], buttBaseBM];
ContactMaps[nbutt].bm ← CONS[[polSpinifex, polCnstr[pExNdCon], [0,-4*l,0,0]], ContactMaps[nbutt].bm];
ContactMaps[pbutt].rm ← LIST[[CMos.pdif, [0,-3*l,0,0]], [CMos.pol, [0,0,0,-3*l]], [CMos.met], [CMos.nwell, [ws,ws-2*l,ws,ws]] ];
ContactMaps[pbutt].bm ← CONS[[pdifSpinifex, pdCnstr[pdCh], [0,-2*l, 0,-3*l]], buttBaseBM];
ContactMaps[pbutt].bm ← CONS[[polSpinifex, polCnstr[pExPdCon], [0,-4*l,0,0]], ContactMaps[pbutt].bm];
ContactMaps[burSim].rm ← LIST[[CMos.pol, [0,-2*l, 0,-l]], [CMos.ndif, [-l,0, -l,0]] ];
ContactMaps[burSim].bm ← LIST[[polSpinifex, polCnstr[pDandP], [-l,-2*l, -l,-l]], [polSpinifex, polCnstr[pChE], [-l,-l, -l,0]], [polSpinifex, polCnstr[pBur]], [ndifSpinifex, ndCnstr[ndBur]] ];
ContactMaps[burPolS].rm ← LIST[[CMos.pol, [0,0, -2*l,0]], [CMos.ndif, [-l,-l, 0,-l]] ];
ContactMaps[burPolS].bm ← LIST[[polSpinifex, polCnstr[pDandP], [-l,-l, -2*l,-l]], [polSpinifex, polCnstr[pChE], [-l,-l, -l,-l]], [polSpinifex, polCnstr[pBur]], [ndifSpinifex, ndCnstr[ndBur]] ];
ContactMaps[burDifI].rm ← LIST[[CMos.pol, [0,-l, -2*l,-l]], [CMos.ndif, [-l,0, 0,-l]] ];
ContactMaps[burDifI].bm ← LIST[[polSpinifex, polCnstr[pDandP], [-l,-l, -2*l,-l]], [polSpinifex, polCnstr[pChE], [-l,0, -l,0]], [polSpinifex, polCnstr[pBur]], [ndifSpinifex, ndCnstr[ndBur]] ];
ContactMaps[burDifL].rm ← LIST[[CMos.pol, [0,-2*l, -l,-l]], [CMos.ndif, [-l,-l, 0,0]] ];
ContactMaps[burDifL].bm ← LIST[[polSpinifex, polCnstr[pDandP], [-l,-2*l, -l,-l]], [polSpinifex, polCnstr[pChE], [-l,-l, 0,0]], [polSpinifex, polCnstr[pBur]], [ndifSpinifex, ndCnstr[ndBur]] ];
}; -- InitContacts
DeltaBox: PROCEDURE [box: CD.Rect, delta: MapRectDelta] RETURNS [CD.Rect] ~ INLINE
{ RETURN [[x1~ box.x1-delta.dx1, y1~ box.y1-delta.dy1, x2~ box.x2+delta.dx2, y2~ box.y2+delta.dy2] ] };
SimpleMapping: PROC [ob: CD.Object, trans: CD.Transformation, cir: REF SX.Circuit, map: ContactMap] ~ {
node: REF SX.CircuitNode ← NIL;
box: CD.Rect ← CD.InterestRect [ob];
FOR r: LIST OF RectMap ← map.rm, r.rest WHILE r # NIL DO
SELECT r.first.layer FROM
CMos.nwell => {
wellNode: REF SX.CircuitNode ← cir.AddRect [lev~r.first.layer, dim~DeltaBox[box, r.first.delta], trans~trans];
wellNode.properties ← Properties.PutProp [wellNode.properties, wellNode, wellNode];
};
ENDCASE => node ← cir.AddRect [lev~r.first.layer, dim~DeltaBox[box, r.first.delta], trans~trans, value~node];
ENDLOOP;
FOR b: LIST OF BoxMap ← map.bm, b.rest WHILE b # NIL DO
node ← cir.AddBox [spinifexLayer~ b.first.layerInd, dim~ DeltaBox[box, b.first.delta], trans~ trans, value~ IF b.first.value # NIL THEN b.first.value ELSE node];
ENDLOOP;
}; -- SimpleMapping
ConvertContact: PUBLIC SX.ConversionProc =
BEGIN
type: ContactType;
classKey: ATOM = ob.class.objectType;
r: CD.Rect ← CD.InterestRect [ob];
SELECT classKey FROM
$CSimpleCon, $CVia, $CWellSimpleCon, $CDifShortCon, $CWellDifShortCon =>
{ConvSimpleCon[ob, trans, cir]; RETURN};
type ← SELECT ob.layer FROM
CMos.pol => mPol,
CMos.pdif => mpDif,
CMos.ndif => mnDif,
CMos.nwellCont => mnWCont,
CMos.pwellCont => mpWCont,
ENDCASE => ERROR SX.IllegalConstruct [r, "Unknown simple contact"];
$CWellSimpleCon => type ← SELECT ob.layer FROM
It is not checked that the well is there
CMos.wpdif => mpDif,
CMos.wndif => mnDif,
CMos.nwellCont => mnWCont,
CMos.pwellCont => mpWCont,
ENDCASE => ERROR SX.IllegalConstruct [r, "Unknown simple well contact"];
$CDifShortCon => type ← SELECT ob.layer FROM
CMos.ndif => nDifShort,
CMos.pdif => pDifShort,
ENDCASE => ERROR SX.IllegalConstruct [r, "Unknown short contact"];
$CWellDifShortCon => type ← SELECT ob.layer FROM
It is not checked that the well is there
CMos.wndif => nDifShort,
CMos.wpdif => pDifShort,
ENDCASE => ERROR SX.IllegalConstruct [r, "Unknown short well contact"];
-- $CButtingCont => type ← nbutt;
$CButtingCont, $CWellButtingCont => {
ConvButtingCon[ob, trans, cir]; RETURN};
type ← SELECT ob.layer FROM
CMos.ndif => nbutt,
CMos.pdif => pbutt,
ENDCASE => SX.IllegalConstruct [r, "Unknown butting contact"];
NOTE: The DRC of buttings is affected by the change made to CMosSpinifexInitImpl on April 2, 1985.
$CWellButtingCont => type ← SELECT ob.layer FROM
It is not checked that the well is there
CMos.wndif => nbutt,
CMos.wpdif => pbutt,
ENDCASE => SX.IllegalConstruct [r, "Unknown butting well contact"];
NOTE: The DRC of buttings is affected by the change made to CMosSpinifexInitImpl on April 2, 1985.
$CVia => type ← mm2;
$CMosContactDifAndPol, $CMosContactWellDifAndPol, $CMosContactBut, $CMosContactWellBut, $CMosWellBurContact, $CMosMmContact, $CMosContactWellDifShort => ConvertOldContact [ob, trans, cir];
ENDCASE => SX.IllegalConstruct [r, "Unknown contact type"];
SimpleMapping [ob, trans, cir, ContactMaps[type]]
END; -- ConvertContact
ConvButtingCon: PUBLIC SX.ConversionProc =
BEGIN
node: REF SX.CircuitNode ← NIL;
polRect, difRect, channelRect, channelEdgeRect, leftXor, rightXor: CD.Rect;
dif: CD.Layer;
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
CMos.ndif, CMos.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 = CMos.ndif THEN pExNdCon ELSE pExPdCon)]];
dif ← geom.first.layer; difRect ← geom.first.r
};
CMos.pol => {
node ← SX.AddRect[cir: cir, lev: CMos.pol, dim: geom.first.r, trans: trans, value: node];
polRect ← geom.first.r};
CMos.nwell, CMos.pwell => {
wellNode: REF SX.CircuitNode ← SX.AddRect [cir: cir, lev: geom.first.layer, dim: geom.first.r, trans: trans];
wellNode.properties ← Properties.PutProp [wellNode.properties, wellNode, wellNode];
};
CMos.nwellCont, CMos.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 = CMos.nwellCont THEN pExNdCon ELSE pExPdCon)]];
};
CMos.met =>
node ← SX.AddRect[cir: cir, lev: CMos.met, dim: geom.first.r, trans: trans, value: node];
CMos.cut =>
[] ← SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, trans: trans, value: metCnstr[mCut]];
ENDCASE => ERROR SX.IllegalConstruct [geom.first.r, "Unknown simple contact geometry"];
ENDLOOP;
channelRect ← [x1: polRect.x1, x2: polRect.x2, y1: polRect.y2-l, y2: polRect.y2];
channelEdgeRect ← [x1: polRect.x1, x2: polRect.x2, y1: polRect.y2, y2: polRect.y2+l];
leftXor ← [x1: polRect.x1-l, x2: polRect.x1, y1: polRect.y2 - l, y2: polRect.y2+l];
rightXor ← [x1: polRect.x2, x2: polRect.x2+l, y1: polRect.y2 - l, y2: polRect.y2+l];
[] ← SX.AddBox[cir: cir, spinifexLayer: (IF dif = CMos.ndif THEN ndifSpinifex ELSE pdifSpinifex), dim: channelRect, trans: trans, value: IF dif = CMos.ndif THEN ndCnstr[ndCh] ELSE pdCnstr[pdCh]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: channelRect, trans: trans, value: polCnstr[pDandP]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: channelEdgeRect, trans: trans, value: polCnstr[pChE]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: leftXor, trans: trans, value: polCnstr[pDxorP]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: rightXor, trans: trans, value: polCnstr[pDxorP]];
}
ELSE ERROR;
END;

ConvSimpleCon: PUBLIC SX.ConversionProc =
BEGIN
node: REF SX.CircuitNode ← NIL;
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
CMos.ndif, CMos.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 = CMos.ndif THEN pExNdCon ELSE pExPdCon)]];
};
CMos.nwell, CMos.pwell => {
wellNode: REF SX.CircuitNode ← SX.AddRect [cir: cir, lev: geom.first.layer, dim: geom.first.r, trans: trans];
wellNode.properties ← Properties.PutProp [wellNode.properties, wellNode, wellNode];
};
CMos.nwellCont, CMos.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 = CMos.nwellCont THEN pExNdCon ELSE pExPdCon)]];
};
CMos.met, CMos.met2, CMos.pol =>
node ← SX.AddRect[cir: cir, lev: geom.first.layer, dim: geom.first.r, trans: trans, value: node];
CMos.cut =>
[] ← SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, trans: trans, value: metCnstr[mCut]];
CMos.cut2 =>
[] ← SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, trans: trans, value: metCnstr[mVia]];
ENDCASE => ERROR SX.IllegalConstruct [geom.first.r, "Unknown simple contact geometry"];
ENDLOOP
ELSE ERROR;
END;
ConvertOldContact: SX.ConversionProc ~ {
CDContactType: TYPE = {burr, mDif, difShort, butt, mPol, mm2};
ContactRec: TYPE = RECORD [  -- from CMosContacts
typ: CDContactType,
wExt: CD.Number ← 0,
lExt: CD.Number ← 0
];
cp: REF ContactRec = NARROW[ob.specific];
SELECT cp.typ FROM
mDif => SimpleMapping[ob, trans, cir, ContactMaps [SELECT ob.layer FROM CMos.ndif => mnDif, CMos.pdif => mpDif, ENDCASE => ERROR]];
difShort => SimpleMapping[ob, trans, cir, ContactMaps [SELECT ob.layer FROM CMos.ndif => nDifShort, CMos.pdif => pDifShort, ENDCASE => ERROR]];
NOTE: The DRC of buttings is affected by the change made to CMosSpinifexInitImpl on April 2, 1985.
butt => SimpleMapping[ob, trans, cir, ContactMaps [SELECT ob.layer FROM CMos.ndif => nbutt, CMos.pdif => pbutt, ENDCASE => ERROR]];
mPol => SimpleMapping[ob, trans, cir, ContactMaps[mPol]];
mm2 => SimpleMapping[ob, trans, cir, ContactMaps[mm2]];
burr => ERROR SX.IllegalConstruct [CD.InterestRect [ob], "Old-style Buried Contact no longer supported"];
ENDCASE => ERROR;
}; -- ConvertOldContact
ConvertBuriedContact: PUBLIC SX.ConversionProc =
BEGIN
node: REF SX.CircuitNode ← NIL;
pol, dif, bur, active: CD.Rect;
cp: ATOM = ob.class.objectType;
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
CMos.ndif => {
node ← SX.AddRect[cir: cir, lev: CMos.ndif, dim: geom.first.r, trans: trans, value: node];
dif ← geom.first.r
};
CMos.pol => {
node ← SX.AddRect[cir: cir, lev: CMos.pol, dim: geom.first.r, trans: trans, value: node];
pol ← geom.first.r};
CMos.bur => {
[] ← SX.AddBox[cir: cir, spinifexLayer: ndifSpinifex, dim: geom.first.r, trans: trans, value: ndCnstr[ndBur]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: geom.first.r, trans: trans, value: polCnstr[pBur]];
bur ← geom.first.r};
ENDCASE => ERROR SX.IllegalConstruct [geom.first.r, "Unknown simple contact geometry"];
ENDLOOP;
SELECT cp FROM
$CBurContS => {
active ← [x1: dif.x1, x2: dif.x2, y1: pol.y1, y2: pol.y2];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: active, trans: trans, value: polCnstr[pDandP]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1-l, active.x2, active.y2+l], trans: trans, value: polCnstr[pChE]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [bur.x1, bur.y2, bur.x2, bur.y2+l], trans: trans, value: polCnstr[pDExcl]];
};
$CBurContPS => {
active ← [x1: dif.x1, x2: pol.x2, y1: dif.y1, y2: dif.y2];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: active, trans: trans, value: polCnstr[pDandP]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1, active.x2+l, active.y2], trans: trans, value: polCnstr[pChE]];
};
$CBurContDI => {
active ← [x1: dif.x1, x2: pol.x2, y1: pol.y1, y2: pol.y2];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: active, trans: trans, value: polCnstr[pDandP]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1-l, active.x2+l, active.y2+l], trans: trans, value: polCnstr[pChE]];
[] ← cir.AddBox [spinifexLayer: polSpinifex, dim: [ bur.x1+l, bur.y1-l, bur.x2-2*l, bur.y1], trans: trans, value: polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x1+l, bur.y2, bur.x2-2*l, bur.y2+l], trans: trans, value: polCnstr[pDExcl]];
};
$CBurContDL => {
active ← [x1: dif.x1, x2: pol.x2, y1: pol.y1, y2: pol.y2];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: active, trans: trans, value: polCnstr[pDandP]];
[] ← SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1-l, active.x2+l, active.y2+l], trans: trans, value: polCnstr[pChE]];
[] ← cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x1+l, bur.y2, bur.x2, bur.y2+l], trans: trans, value: polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x2, bur.y1+2*l, bur.x2+l, bur.y2], trans: trans, value: polCnstr[pDExcl]];
};
ENDCASE => ERROR SX.IllegalConstruct [CD.InterestRect [ob], "Unknown buried contact"]
}
ELSE ERROR;
END;
ConvertBuriedContact: PUBLIC SX.ConversionProc =
BEGIN
cp: ATOM = inst.ob.class.objectType;
s: CD.Position = inst.ob.size;
SELECT cp FROM
$CBurContS => {
SimpleMapping[ob, trans, cir, ContactMaps [burSim]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[0, s.y, s.x, s.y+l], trans~trans, value~polCnstr[pDExcl]];
};
$CBurContPS => {
SimpleMapping[ob, trans, cir, ContactMaps [burPolS]];
};
$CBurContDI => {
SimpleMapping[ob, trans, cir, ContactMaps [burDifI]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, -l, s.x-2*l, 0], trans~trans, value~polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x-2*l, s.y+l], trans~trans, value~polCnstr[pDExcl]];
};
$CBurContDL => {
SimpleMapping[ob, trans, cir, ContactMaps [burDifL]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x, s.y+l], trans~trans, value~polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[s.x, 2*l, s.x+l, s.y], trans~trans, value~polCnstr[pDExcl]];
};
ENDCASE => ERROR SX.IllegalConstruct [inst.ob.class.oldInsideRect[inst.ob], "Unknown buried contact type"]
END; -- ConvertBuriedContact
PointRect: PROC [p: CD.Position] RETURNS [r: CD.Rect] =
BEGIN
r ← CDBasics.Extend [CDBasics.ToRect[p, p], l]
END; -- PointRect
CopyWellConnections: PUBLIC SX.CombineNodePropertyProc -- [circuit: REF Circuit, to, from: Atom.PropList, fromNesting: LIST OF CD.Instance] RETURNS [Atom.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]
};
CheckWellConnections: PUBLIC SX.CellPostProcessProc =
PROC [cell: REF SX.LogicalCell]
BEGIN
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 =
-- PROC [cir: REF Circuit, dim: CD.Rect, appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, node: REF CircuitNode] RETURNS [cirNode: REF CircuitNode ← NIL]
BEGIN
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
END.
Edited on February 20, 1985 12:26:18 pm PST, by Shand
Completed conversion specification for split contacts (also called DifShort contacts)
changes to: InitContacts extra rects in converion specification of split contacts for well conecting diffusion.
Edited on March 7, 1985 1:45:48 pm PST, by Shand
New method for handling Floating n-well, where possible check is postponed to containing cell. Error is reported only if well is unconnected and is not merged into containing cell or if well is unconnected in a top layer cell.
changes to: DIRECTORY, IMPORTS, CheckWellConnections, PaintWellErrorOverGeom (local of CheckWellConnections), CheckWellConnections
Edited on March 11, 1985 2:59:40 am PST, by Shand
Changed report of n-Well connection errors to mark a point on the offending nodes rather than all the material of which the nodes is comprised
changes to: DIRECTORY, CheckWellConnections, IMPORTS
Edited on March 12, 1985 4:27:23 pm PST, by Shand
Rule extensions to handle Contact rules (DifCon to Poly, PolCon to Gate, Cut to Via)
changes to: IMPORTS, InitContacts
Edited on March 16, 1985 5:50:52 pm PST, by Beretta
Introduced hack to handle burried contacts represented as atomic Chipndale object. In a possibly near future this hack shall be replaced by an analysis of the atomic Chipndale object.
Edited on March 25, 1985 6:57:21 pm PST, by Beretta
Temporary fix: set delta for via to zero.
changes to: InitContacts.
Edited on April 23, 1985 3:00:58 pm PST, by Beretta
changes to: ConvertPDifRect: added an error message for the case of empty pDif.
Edited on May 6, 1985 11:26:55 am PDT, by Beretta
Converted to ChipNDale CD20
Last edited by: gbb July 18, 1985 4:47:07 pm PDT
Converted to ChipNDale 2.1.
changes to: ConvertContact: Completely rewritten.