<> <> <> <> DIRECTORY CD USING [Instance, InstanceList, InterestRect, Layer, Number, Orientation, Position, Rect], CDAtomicObjects, CDBasics USING [Extend, NonEmpty, RectAt, ToRect], CDOrient USING [MapPoint], CMos USING [lambda, bur, cut, cut2, met, met2, ndif, nwell, pwell, nwellCont, pdif, pol, pwellCont, wellSurround], IO USING [atom, PutFR], PropertyLists 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 [WriteRope]; SXCMosContactsImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDOrient, CMos, IO, PropertyLists, SX, SXAccess, SXAccessInternal, SXCMos, SXTechnology, TerminalIO EXPORTS SXCMos = BEGIN OPEN SXCMos; wellConnection: ATOM ~ $SXCMosWellConnection; wellNode: ATOM ~ $SXCMosNWellNode; Nodes: TYPE = LIST OF REF SX.CircuitNode; ConvertPDifRect: PUBLIC SX.ConversionProc -- [appl: CD.Instance, 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, -CMos.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~CMos.pdif, dim~pDifBox, inst~inst, pos~ pos, orient~ orient]; wellNode _ cir.AddRect [lev~CMos.nwell, dim~nWellBox, inst~inst, pos~ pos, orient~ orient]; wellNode.properties _ PropertyLists.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], [- ContactMaps[mpDif].rm _ LIST[[CMos.pdif], [CMos.met], [CMos.nwell, [ws,ws,ws,ws]] ]; ContactMaps[mpDif].bm _ LIST[[polSpinifex, polCnstr[pExPdCon]], [metSpinifex, metCnstr[mCut], [- 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], [- ContactMaps[mm2].rm _ LIST[[CMos.met2], [CMos.met] ]; <<-- ContactMaps[mm2].bm _ LIST[[metSpinifex, metCnstr[mVia], [>> <> ContactMaps[mm2].bm _ LIST[[metSpinifex, metCnstr[mVia], [0,0, 0,0]] ]; ContactMaps[nDifShort].rm _ LIST[[CMos.ndif, [0,0,0,-4* ContactMaps[nDifShort].bm _ ContactMaps[mnDif].bm; ContactMaps[pDifShort].rm _ LIST[[CMos.pdif, [0,0,0,-4* [ws,ws,ws,ws-4* ContactMaps[pDifShort].bm _ ContactMaps[mpDif].bm; ContactMaps[nbutt].rm _ LIST[[CMos.ndif, [0,-3* buttBaseBM _ LIST[[polSpinifex, polCnstr[pChE], [0,-3* [polSpinifex, polCnstr[pDxorP], [-4* metCnstr[mCut], [- ContactMaps[nbutt].bm _ CONS[[ndifSpinifex, ndCnstr[ndCh], [0,-2* ContactMaps[nbutt].bm _ CONS[[polSpinifex, polCnstr[pExNdCon], [0,-4* ContactMaps[pbutt].rm _ LIST[[CMos.pdif, [0,-3* ContactMaps[pbutt].bm _ CONS[[pdifSpinifex, pdCnstr[pdCh], [0,-2* ContactMaps[pbutt].bm _ CONS[[polSpinifex, polCnstr[pExPdCon], [0,-4* ContactMaps[burSim].rm _ LIST[[CMos.pol, [0,-2* ContactMaps[burSim].bm _ LIST[[polSpinifex, polCnstr[pDandP], [- [polSpinifex, polCnstr[pBur]], [ndifSpinifex, ndCnstr[ndBur]] ]; ContactMaps[burPolS].rm _ LIST[[CMos.pol, [0,0, -2* ContactMaps[burPolS].bm _ LIST[[polSpinifex, polCnstr[pDandP], [- [polSpinifex, polCnstr[pBur]], [ndifSpinifex, ndCnstr[ndBur]] ]; ContactMaps[burDifI].rm _ LIST[[CMos.pol, [0,- ContactMaps[burDifI].bm _ LIST[[polSpinifex, polCnstr[pDandP], [- [polSpinifex, polCnstr[pBur]], [ndifSpinifex, ndCnstr[ndBur]] ]; ContactMaps[burDifL].rm _ LIST[[CMos.pol, [0,-2* ContactMaps[burDifL].bm _ LIST[[polSpinifex, polCnstr[pDandP], [- [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: PROCEDURE [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit, map: ContactMap] ~ { node: REF SX.CircuitNode _ NIL; box: CD.Rect _ CD.InterestRect [inst.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], inst~inst, pos~ pos, orient~ orient]; wellNode.properties _ PropertyLists.PutProp [wellNode.properties, wellNode, wellNode]; }; ENDCASE => node _ cir.AddRect [lev~r.first.layer, dim~DeltaBox[box, r.first.delta], inst~inst, pos~ pos, orient~ orient, 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], inst~ inst, pos~ pos, orient~ orient, value~ IF b.first.value # NIL THEN b.first.value ELSE node]; ENDLOOP; }; -- SimpleMapping ConvertContact: PUBLIC SX.ConversionProc -- [appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit] -- = BEGIN type: ContactType; classKey: ATOM = inst.ob.class.objectType; r: CD.Rect _ CD.InterestRect [inst.ob]; SELECT classKey FROM $CSimpleCon, $CVia, $CWellSimpleCon, $CDifShortCon, $CWellDifShortCon => {ConvSimpleCon[inst, pos, orient, cir]; RETURN}; <> < mPol,>> < mpDif,>> < mnDif,>> < mnWCont,>> < mpWCont,>> < ERROR SX.IllegalConstruct [r, "Unknown simple contact"];>> <<$CWellSimpleCon => type _ SELECT inst.ob.layer FROM>> <> < mpDif,>> < mnDif,>> < mnWCont,>> < mpWCont,>> < ERROR SX.IllegalConstruct [r, "Unknown simple well contact"];>> <<$CDifShortCon => type _ SELECT inst.ob.layer FROM>> < nDifShort,>> < pDifShort,>> < ERROR SX.IllegalConstruct [r, "Unknown short contact"];>> <<$CWellDifShortCon => type _ SELECT inst.ob.layer FROM>> <> < nDifShort,>> < pDifShort,>> < ERROR SX.IllegalConstruct [r, "Unknown short well contact"];>> <<-- $CButtingCont => type _ nbutt;>> $CButtingCont, $CWellButtingCont => { ConvButtingCon[inst, pos, orient, cir]; RETURN}; <> < nbutt,>> < pbutt,>> < SX.IllegalConstruct [r, "Unknown butting contact"];>> <> <<$CWellButtingCont => type _ SELECT inst.ob.layer FROM>> <> < nbutt,>> < pbutt,>> < SX.IllegalConstruct [r, "Unknown butting well contact"];>> <> <<$CVia => type _ mm2;>> $CMosContactDifAndPol, $CMosContactWellDifAndPol, $CMosContactBut, $CMosContactWellBut, $CMosWellBurContact, $CMosMmContact, $CMosContactWellDifShort => ConvertOldContact [inst, pos, orient, cir]; ENDCASE => SX.IllegalConstruct [r, "Unknown contact type"]; SimpleMapping [inst, pos, orient, 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 [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 CMos.ndif, CMos.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 = CMos.ndif THEN pExNdCon ELSE pExPdCon)]]; dif _ geom.first.lev; difRect _ geom.first.r }; CMos.pol => { node _ SX.AddRect[cir: cir, lev: CMos.pol, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node]; polRect _ geom.first.r}; CMos.nwell, CMos.pwell => { wellNode: REF SX.CircuitNode _ SX.AddRect [cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient]; wellNode.properties _ PropertyLists.PutProp [wellNode.properties, wellNode, wellNode]; }; CMos.nwellCont, CMos.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 = CMos.nwellCont THEN pExNdCon ELSE pExPdCon)]]; }; CMos.met => node _ SX.AddRect[cir: cir, lev: CMos.met, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node]; CMos.cut => [] _ SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, 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- channelEdgeRect _ [x1: polRect.x1, x2: polRect.x2, y1: polRect.y2, y2: polRect.y2+ leftXor _ [x1: polRect.x1- rightXor _ [x1: polRect.x2, x2: polRect.x2+ [] _ SX.AddBox[cir: cir, spinifexLayer: (IF dif = CMos.ndif THEN ndifSpinifex ELSE pdifSpinifex), dim: channelRect, inst: inst, pos: pos, orient: orient, value: IF dif = CMos.ndif THEN ndCnstr[ndCh] ELSE pdCnstr[pdCh]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: channelRect, inst: inst, pos: pos, orient: orient, value: polCnstr[pDandP]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: channelEdgeRect, inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: leftXor, inst: inst, pos: pos, orient: orient, value: polCnstr[pDxorP]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: rightXor, inst: inst, pos: pos, orient: orient, value: polCnstr[pDxorP]]; } ELSE ERROR; END; ConvSimpleCon: PUBLIC SX.ConversionProc = BEGIN node: REF SX.CircuitNode _ NIL; 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 CMos.ndif, CMos.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 = CMos.ndif THEN pExNdCon ELSE pExPdCon)]]; }; CMos.nwell, CMos.pwell => { wellNode: REF SX.CircuitNode _ SX.AddRect [cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient]; wellNode.properties _ PropertyLists.PutProp [wellNode.properties, wellNode, wellNode]; }; CMos.nwellCont, CMos.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 = CMos.nwellCont THEN pExNdCon ELSE pExPdCon)]]; }; CMos.met, CMos.met2, CMos.pol => node _ SX.AddRect[cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node]; CMos.cut => [] _ SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: metCnstr[mCut]]; CMos.cut2 => [] _ SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: metCnstr[mVia]]; ENDCASE => ERROR SX.IllegalConstruct [geom.first.r, "Unknown simple contact geometry"]; ENDLOOP ELSE ERROR; END; ConvertOldContact: SX.ConversionProc -- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SX.Circuit] -- ~ { 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[inst.ob.specificRef]; SELECT cp.typ FROM mDif => SimpleMapping[inst, pos, orient, cir, ContactMaps [SELECT inst.ob.layer FROM CMos.ndif => mnDif, CMos.pdif => mpDif, ENDCASE => ERROR]]; difShort => SimpleMapping[inst, pos, orient, cir, ContactMaps [SELECT inst.ob.layer FROM CMos.ndif => nDifShort, CMos.pdif => pDifShort, ENDCASE => ERROR]]; <> butt => SimpleMapping[inst, pos, orient, cir, ContactMaps [SELECT inst.ob.layer FROM CMos.ndif => nbutt, CMos.pdif => pbutt, ENDCASE => ERROR]]; mPol => SimpleMapping[inst, pos, orient, cir, ContactMaps[mPol]]; mm2 => SimpleMapping[inst, pos, orient, cir, ContactMaps[mm2]]; burr => ERROR SX.IllegalConstruct [CD.InterestRect [inst.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 = inst.ob.class.objectType; 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 CMos.ndif => { node _ SX.AddRect[cir: cir, lev: CMos.ndif, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node]; dif _ geom.first.r }; CMos.pol => { node _ SX.AddRect[cir: cir, lev: CMos.pol, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node]; pol _ geom.first.r}; CMos.bur => { [] _ SX.AddBox[cir: cir, spinifexLayer: ndifSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: ndCnstr[ndBur]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, 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, inst: inst, pos: pos, orient: orient, value: polCnstr[pDandP]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1-l, active.x2, active.y2+l], inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [bur.x1, bur.y2, bur.x2, bur.y2+l], inst: inst, pos: pos, orient: orient, 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, inst: inst, pos: pos, orient: orient, value: polCnstr[pDandP]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1, active.x2+l, active.y2], inst: inst, pos: pos, orient: orient, 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, inst: inst, pos: pos, orient: orient, value: polCnstr[pDandP]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1-l, active.x2+l, active.y2+l], inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]]; [] _ cir.AddBox [spinifexLayer: polSpinifex, dim: [ bur.x1+ value: polCnstr[pDExcl]]; [] _ cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x1+ 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, inst: inst, pos: pos, orient: orient, value: polCnstr[pDandP]]; [] _ SX.AddBox[cir: cir, spinifexLayer: polSpinifex, dim: [active.x1, active.y1-l, active.x2+l, active.y2+l], inst: inst, pos: pos, orient: orient, value: polCnstr[pChE]]; [] _ cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x1+ value: polCnstr[pDExcl]]; [] _ cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x2, bur.y1+2* value: polCnstr[pDExcl]]; }; ENDCASE => ERROR SX.IllegalConstruct [CD.InterestRect [inst.ob], "Unknown buried contact type"] } ELSE ERROR; END; <> <> <> <> <