DIRECTORY CD, CDAtomicObjects, CDBasics, 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 [PutRope]; SXCMosContactsImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CMos, IO, PropertyLists, 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 -- [appl: CD.Instance, cir: REF SX.Circuit] -- ~ { wellNode: REF SX.CircuitNode; sixe: CD.Position _ CDBasics.SizeOfRect[inst.ob.bbox]; nWellBox: CD.Rect _ inst.ob.bbox; pDifBox: CD.Rect _ CDBasics.Extend[nWellBox, -CMos.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~CMos.pdif, dim~pDifBox, trans~trans]; wellNode _ cir.AddRect [lev~CMos.nwell, dim~nWellBox, trans~trans]; 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] ]]; 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], [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: PROCEDURE [inst: CD.Instance, trans: CD.Transformation, 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], trans~trans]; wellNode.properties _ PropertyLists.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 -- [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, trans, cir]; RETURN}; $CButtingCont, $CWellButtingCont => { ConvButtingCon[inst, trans, cir]; RETURN}; $CMosContactDifAndPol, $CMosContactWellDifAndPol, $CMosContactBut, $CMosContactWellBut, $CMosWellBurContact, $CMosMmContact, $CMosContactWellDifShort => ConvertOldContact [inst, trans, cir]; ENDCASE => SX.IllegalConstruct [r, "Unknown contact type"]; SimpleMapping [inst, 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 [inst.ob.specific, CDAtomicObjects.AtomicObsSpecific] THEN { FOR geom: CDAtomicObjects.DrawList _ NARROW [inst.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 _ PropertyLists.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 [inst.ob.specific, CDAtomicObjects.AtomicObsSpecific] THEN FOR geom: CDAtomicObjects.DrawList _ NARROW [inst.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 _ PropertyLists.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 -- [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.specific]; SELECT cp.typ FROM mDif => SimpleMapping[inst, trans, cir, ContactMaps [SELECT inst.ob.layer FROM CMos.ndif => mnDif, CMos.pdif => mpDif, ENDCASE => ERROR]]; difShort => SimpleMapping[inst, trans, cir, ContactMaps [SELECT inst.ob.layer FROM CMos.ndif => nDifShort, CMos.pdif => pDifShort, ENDCASE => ERROR]]; butt => SimpleMapping[inst, trans, cir, ContactMaps [SELECT inst.ob.layer FROM CMos.ndif => nbutt, CMos.pdif => pbutt, ENDCASE => ERROR]]; mPol => SimpleMapping[inst, trans, cir, ContactMaps[mPol]]; mm2 => SimpleMapping[inst, trans, 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.specific, CDAtomicObjects.AtomicObsSpecific] THEN { FOR geom: CDAtomicObjects.DrawList _ NARROW [inst.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 [inst.ob], "Unknown buried contact type"] } ELSE ERROR; END; 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 [PropertyLists.GetProp [propList: from, prop: wellConnection]]; toConnections: Nodes _ NARROW [PropertyLists.GetProp [propList: to, prop: wellConnection]]; FOR fl: Nodes _ fromConnections, fl.rest WHILE fl # NIL DO fromNode: REF SX.CircuitNode; IF fromNesting = NIL THEN fromNode _ fl.first ELSE -- Side effect !!! May add fl.first to subcircuits ports. fromNode _ SX.FindRootNode [circuit: circuit, subcircuitNode: fl.first, qualifier: fromNesting, insertIfNotInCircuit: TRUE].node; FOR tl: Nodes _ toConnections, tl.rest WHILE tl # NIL DO IF SX.LookupNode [l: fromNode] = SX.LookupNode [l: tl.first] THEN EXIT; REPEAT FINISHED => toConnections _ CONS [fromNode, toConnections] ENDLOOP ENDLOOP; IF toConnections # NIL THEN to _ PropertyLists.PutProp [propList: to, prop: wellConnection, val: toConnections]; IF (PropertyLists.GetProp [propList: from, prop: wellNode] # NIL) AND (PropertyLists.GetProp [propList: to, prop: wellNode] = NIL) THEN to _ PropertyLists.PutProp [propList: to, prop: wellNode, val: wellNode]; RETURN [to] }; CheckWellConnections: PUBLIC SX.CellPostProcessProc = BEGIN isRoot: BOOL _ (cell.rootOnInvocation = SXAccess.invocation); hasNode, hasConnection, hasRoot: BOOL; wellConnects: Nodes; FOR scl: CD.InstanceList _ cell.circuit.subcircuits, scl.rest WHILE scl # NIL DO subcir: REF SX.Circuit ~ SXTechnology.GetCircuitFromCDObject [cdOb: scl.first.ob]; FOR nl: Nodes _ subcir.nodes, nl.rest WHILE nl # NIL DO hasNode _ (PropertyLists.GetProp [propList: nl.first.properties, prop: wellNode] # NIL); hasConnection _ (PropertyLists.GetProp [propList: nl.first.properties, prop: wellConnection] # NIL); IF hasNode AND ~ hasConnection THEN { hasRoot _ (SX.FindRootNode [circuit: cell.circuit, subcircuitNode: nl.first, qualifier: LIST[scl.first]].rootQualifier # NIL); IF hasRoot THEN { 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 FOR nl: Nodes _ cell.circuit.nodes, nl.rest WHILE nl # NIL DO hasNode _ (PropertyLists.GetProp[propList: nl.first.properties, prop: wellNode] # NIL); IF hasNode THEN { wellConnects _ NARROW [PropertyLists.GetProp [propList: nl.first.properties, prop: wellConnection]]; 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 { 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 { 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 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 _ PropertyLists.PutProp [propList: wellCon.properties, prop: wellConnection, val: NARROW[LIST[node], Nodes]] END; -- AttachNWellContact END. จSXCMosContactsImpl.mesa Copyright c 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 `Normal' layers must precede nwellCont. -- ContactMaps[mm2].bm _ LIST[[metSpinifex, metCnstr[mVia], [l,l, l,l]] ]; The following line is a temporary fix ! type _ SELECT inst.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 inst.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 inst.ob.layer FROM CMos.ndif => nDifShort, CMos.pdif => pDifShort, ENDCASE => ERROR SX.IllegalConstruct [r, "Unknown short contact"]; $CWellDifShortCon => type _ SELECT inst.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; type _ SELECT inst.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 inst.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; NOTE: The DRC of buttings is affected by the change made to CMosSpinifexInitImpl on April 2, 1985. ConvertBuriedContact: PUBLIC SX.ConversionProc = BEGIN cp: ATOM = inst.ob.class.objectType; s: CD.Position = inst.ob.size; SELECT cp FROM $CBurContS => { SimpleMapping[inst, trans, cir, ContactMaps [burSim]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[0, s.y, s.x, s.y+l], trans~trans, value~polCnstr[pDExcl]]; }; $CBurContPS => { SimpleMapping[inst, trans, cir, ContactMaps [burPolS]]; }; $CBurContDI => { SimpleMapping[inst, 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[inst, 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 PROC [cell: REF SX.LogicalCell] Process Subcells. Potential floating well in subcircuit, is it merged to some node in this cell? The well node of the subcircuit is not merged into this circuit, so it may be floating => VIOLATION 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. Clean up list of well connections to eliminate REFs to superceded nodes. n-well unconnect in root cell => VIOLATION n-well connect multiple times => VIOLATION -- PROC [cir: REF Circuit, dim: CD.Rect, appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, node: REF CircuitNode] RETURNS [cirNode: REF CircuitNode _ NIL] 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. สI˜code™Kšœ ฯmœ1™˜oMšžœ ˜—šž˜Mšžœ˜ Mšฯgžœ˜Kšœžœ˜-Kšœ žœ˜"Kš œžœžœžœžœžœ ˜)—š ฯbœžœะck!œขœขœ˜]Kšœ žœ˜Kšœ6˜6Kšœ žœ˜!Kšœ žœ6˜Ašžœž˜#Kšž˜Kšœ[˜[Kšž˜Kšžœ˜—Mšœ;˜;KšœC˜CKšœV˜VK˜—šœ žœžœ˜Kšœžœžœ ˜Kšœžœžœ˜K˜—Kšœžœžœžœ˜6šœ žœžœ˜Kšœžœ˜Kšœ˜K˜—šœžœžœ˜Kšœ ˜ Kšœžœžœ˜Kšœ˜K˜—Mšœ žœv˜‡Mšœ žœžœ žœ ˜1Mšœ žœ ˜šฯn œžœž œ˜"Kšœžœ˜"Kšœ žœžœ˜Kš œžœ žœžœžœ˜0Kšœ'™'Kšœžœ˜7Kš œžœD œ œ œ œ˜pKšœžœ8˜TKš œžœD œ œ œ œ˜pKšœžœ ˜>Kšœ0˜0Kšœžœ ˜>Kšœ0˜0Kšœžœ˜5Kš œžœ! œ œ œ œ˜LKšœžœ˜5Kš œžœ  œ œ œ œ™JK™'Kš œžœ  œ œ œ œ˜GKšœžœ œ œ˜iKšœ2˜2Kš œžœ œ œ0 œ˜ŠKšœ2˜2Kšœžœ œ œ˜_Kš#œ žœ% œ œ% œ œ œ œ( œ œ œ œ* œ œ$ œ œ œ œ˜’Kšœžœ% œ œ˜ZKšœžœ) œ˜eKš œžœ œ œ& œ ˜€Kšœžœ% œ œ˜ZKšœžœ) œ˜eMš œžœ œ œ œ œ˜VKšœžœ# œ œ œ œ$ œ œ œF˜ฟKš œžœ œ œ œ œ˜WKšœžœ# œ œ œ œ$ œ œ œ œD˜มKš œžœ œ œ œ œ œ˜XKšœžœ# œ œ œ œ$ œ œF˜ฟKš œžœ œ œ œ œ œ ˜XKšœžœ# œ œ œ œ$ œ œI˜ฟKšœฯc˜—š ฃœž œžœžœžœ ž˜RKšœžœ`˜h—š ฃ œž œžœžœžœžœ˜pKšœžœžœžœ˜Kšœžœžœ˜)š žœžœžœžœžœž˜8šžœž˜šœ˜Kšœ žœžœ^˜nKšœV˜VK˜—Kšžœf˜m—Kšžœ˜—š žœžœžœžœžœž˜7Kš œlžœžœžœžœ˜กKšžœ˜—Kšœค˜—šกœžœžœขYœ˜„Kšž˜Kšœ˜Kšœ žœ˜*Kšœžœžœ˜'šžœ ž˜šœH˜HKšœ"žœ˜*Kšœžœž™ Jšœ™Jšœ™Jšœ™Jšœ™Jšœ™Jšžœžœžœ0™C—šœžœž™3J™(Jšœ™Jšœ™Jšœ™Jšœ™Jšžœžœžœ5™H—šœžœž™1Jšœ™Jšœ™Jšžœžœžœ/™B—šœžœž™5J™(Jšœ™Jšœ™Jšžœžœžœ4™G—Jšœ!™!šœ&˜&Kšœ"žœ˜*Kšœžœž™ Jšœ™Jšœ™Jšžœžœ1™>K™b—šœžœž™5J™(Jšœ™Jšœ™Jšžœžœ6™CK™b—Kšœ™Kšœพ˜พKšžœžœ.˜;—Kšœ3˜3Kšžœค˜K˜—šกœžœžœ˜*Jšž˜Kšœžœžœžœ˜KšœK˜KK˜šžœžœ7ž˜Fš žœ"žœHžœžœž˜†šžœž˜šœ˜KšœžœX˜aKšœgžœžœ žœ ˜ฆKšœ.˜.K˜—˜ KšœžœP˜YKšœ˜K˜—šœ˜Kšœ žœžœžœL˜mKšœV˜VK˜—˜#KšœžœX˜aKšœซ˜ซK˜—˜ KšœžœP˜Y—˜ Kšœm˜m—KšžœžœžœD˜W——Kšœž˜ Kšœ> œ˜QKšœR œ˜UKšœ œ# œ œ˜SKšœ+ œ œ œ˜TK˜Kšœร˜รKšœn˜nKšœp˜pKšœj˜jKšœk˜kK˜—Jšžœ˜ šžœ˜Kšœ˜—J˜J˜J˜—šก œžœžœ˜)Jšž˜Kšœžœžœžœ˜J˜šžœžœ7ž˜Dš žœ"žœHžœžœž˜†šžœž˜˜KšœžœX˜aKš œžœ`žœžœ žœ ˜ฆK˜—šœ˜Kšœ žœžœžœL˜mKšœV˜VK˜—˜#KšœžœX˜aKš œžœ`žœ#žœ žœ ˜ซK˜—˜ KšœžœX˜a—˜ Kšœžœf˜m—˜ Kšœžœf˜m—KšžœžœžœD˜W—Kšœž˜——Jšžœžœ˜ Jšžœ˜J˜J˜—šกœขeœ˜ŽJšœžœ+˜>šœ žœžœค˜1K˜Kšœžœ ˜Kšœžœ ˜K˜—Kšœžœžœ˜.šžœž˜Kš œ5žœžœ)žœžœ˜ŠKš œ9žœžœ1žœžœ˜–K™bKš œ5žœžœ)žœžœ˜ŠKšœ;˜;Kšœ9˜9KšœžœžœI˜nKšžœžœ˜—Kšœค˜K˜—šกœžœžœ˜0Jšž˜Kšœžœžœžœ˜Kšœžœ˜Kšœžœ˜$K˜šžœžœ7žœ˜Fš žœ"žœHžœžœž˜†šžœž˜šœ˜KšœžœQ˜ZKšœ˜K˜—˜ KšœžœP˜YKšœ˜—˜ Kšœžœg˜nKšœžœf˜mKšœ˜—KšžœžœžœD˜W——Kšžœ˜šžœž˜šœ˜K˜:Kšœžœb˜iKšœžœŠ˜‘Kšœžœ~˜…K˜—šœ˜K˜:Kšœžœb˜iKšœžœˆ˜K˜—šœ˜K˜:Kšœžœb˜iKšœžœŒ˜“Kš œ3 œ œ  œ  œ2˜„Kšœ9 œ œ  œ*˜ƒK˜—šœ˜K˜:Kšœžœb˜iKšœžœŒ˜“Kšœ9 œ œ*˜KšœD œ  œ2˜K˜—Kšžœžœžœžœ7˜_—K˜K˜—Jšžœžœ˜ Jšžœ˜—K˜šกœžœขœ™1Kšž™Kšœžœ™$Kšœžœ™šžœž™šœ™Kšœ6™6KšœB œ(™kK™—šœ™Kšœ7™7K™—šœ™Kšœ7™7Kšœ1 œ œ œ+™jKšœ1 œ  œ œ(™oK™—šœ™Kšœ7™7Kšœ1 œ œ(™kKšœ8 œ œ-™mK™—KšžœžœžœW™j—Kšžœค™—š ฃ œžœžœ žœžœ˜7Kšž˜Kšœ, œ˜/Kšžœค ˜—šกœžœคขiคœ˜ชKšœžœ?˜_Kšœžœ=˜[šžœ&žœžœž˜:Kšœ žœ˜Kšžœžœžœ˜-šžค6˜>K•StartOfExpansion’[circuit: REF SX.Circuit, subcircuitNode: REF SX.CircuitNode, qualifier: LIST OF CD.ApplicationPtr, insertIfNotInCircuit: BOOLEAN _ FALSE]šœvžœ˜—šžœ$žœžœž˜8Kš žœžœžœžœžœ˜Gšžœžœ˜Kšœžœ˜.—Kšž˜—Kšžœ˜—šžœžœž˜KšœT˜T—š žœžœ9žœžœžœ7žœž˜‡KšœI˜I—Kšžœ˜ K˜—šกœžœžœ˜6Kšžœžœžœ ™Kšž˜Kšœžœ1˜=Kšœ!žœ˜&Kšœ˜M™š žœžœ3žœžœž˜PKšœžœžœD˜Ršžœ#žœžœž˜7KšœSžœ˜XKšœ_žœ˜dšžœ žœžœ˜%K™NK–ฌ[circuit: REF SpinifexCircuit.Circuit, subcircuitNode: REF SpinifexCircuit.CircuitNode, qualifier: LIST OF CD.ApplicationPtr, insertIfNotInCircuit: BOOLEAN _ FALSE]šœ žœKžœžœ˜~šžœ žœ˜K™cK–†[pointInCell: CD.Position, cellSize: CD.Position, cellInstOrient: CD.Orientation, cellInstPos: CD.Position _ [x: 0, y: 0]]šœžœ[˜cKšœh˜hK˜—Kšœค˜—Kšžœค˜—Kšžœค˜—MšœŽ™Žšžœ)žœžœž˜=KšœRžœ˜Wšžœ žœ˜KšœžœN˜dK™Hšžœ#žœžœž˜7Kšœ žœ˜'šžœ%žœžœž˜Dšžœ žœ%ž˜9Kšœ$ค˜>—Kšž˜—Kšžœค ˜—šžœžœžœ žœ˜)K™*Kšœžœ˜$Kšœv˜vKšœ˜—š žœžœžœžœžœžœ˜=K™*Kšœžœ˜$Kšœp˜pšžœ#žœžœž˜7Kšœžœ˜$KšœHžœ;žœH˜าKšžœ˜—K˜—Kšœค˜—Kšžœค˜—Kšžœค˜—šกœžœžœ˜,Kšœฆ™ฆKšž˜Kšœ žœžœžœX œ œ œ œ˜…Kšžœžœžœžœ˜Kšœežœžœ˜Kšžœค˜—Mšžœ˜™5KšœCฯeœ ™UKšœ ฯr œW™o—™0K™ใKšœ ฆ@œ ฆ™‚—™1K™ŽKšœ ฆ(™4—™1K™TKšœ ฆ™!—™3K™ท—šœ3™3K™)Kšœ™—™3Kšœ ฆœ4™O—™1K™—™0K™Kšœ ฆœฆ™1—K™—…—O{