DIRECTORY CD USING [Instance, InstanceList, 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], 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 [WriteRope]; SXCMosContactsImpl: CEDAR PROGRAM IMPORTS CDBasics, CDOrient, 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 -- [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 _ 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] ]]; 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, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit, map: ContactMap] ~ { node: REF SX.CircuitNode _ NIL; box: CD.Rect _ inst.ob.class.oldInsideRect [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 _ Properties.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 = inst.ob.class.oldInsideRect[inst.ob]; SELECT classKey FROM $CSimpleCon, $CVia, $CWellSimpleCon, $CDifShortCon, $CWellDifShortCon => {ConvSimpleCon[inst, pos, orient, cir]; RETURN}; $CButtingCont, $CWellButtingCont => { ConvButtingCon[inst, pos, orient, cir]; RETURN}; $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 _ Properties.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-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, 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 _ Properties.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[inst.ob.class.oldInsideRect[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+l, bur.y1-l, bur.x2-2*l, bur.y1], inst: inst, pos: pos, orient: orient, value: polCnstr[pDExcl]]; [] _ cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x1+l, bur.y2, bur.x2-2*l, bur.y2+l], inst: inst, pos: pos, orient: orient, 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+l, bur.y2, bur.x2, bur.y2+l], inst: inst, pos: pos, orient: orient, value: polCnstr[pDExcl]]; [] _ cir.AddBox [spinifexLayer: polSpinifex, dim: [bur.x2, bur.y1+2*l, bur.x2+l, bur.y2], inst: inst, pos: pos, orient: orient, value: polCnstr[pDExcl]]; }; ENDCASE => ERROR SX.IllegalConstruct [inst.ob.class.oldInsideRect[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 [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 = 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 _ (Properties.GetProp [propList: nl.first.properties, prop: wellNode] # NIL); hasConnection _ (Properties.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 = CDOrient.MapPoint [pointInCell: nl.first.loc.xy, cellSize: scl.first.ob.size, cellInstOrient: scl.first.orientation, cellInstPos: scl.first.location]; SXAccessInternal.PutError [ob: cell.cellObj, r: PointRect[eLoc], message: "floating n-well in subcell"]; } } -- if has unconnected node ENDLOOP -- for all nodes ENDLOOP; -- for all cells 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]]; 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, inst: inst, pos: pos, orient: orient, 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. PSXCMosContactsImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by: gbb November 6, 1985 6:09:12 pm PST Bowers, September 12, 1985 2:35:35 pm PDT `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 -- [appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit] -- = BEGIN cp: ATOM = inst.ob.class.objectType; s: CD.Position = inst.ob.size; SELECT cp FROM $CBurContS => { SimpleMapping[inst, pos, orient, cir, ContactMaps [burSim]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[0, s.y, s.x, s.y+l], inst~inst, pos~ pos, orient~ orient, value~polCnstr[pDExcl]]; }; $CBurContPS => { SimpleMapping[inst, pos, orient, cir, ContactMaps [burPolS]]; }; $CBurContDI => { SimpleMapping[inst, pos, orient, cir, ContactMaps [burDifI]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[l, -l, s.x-2*l, 0], inst~inst, pos~ pos, orient~ orient, value~polCnstr[pDExcl]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x-2*l, s.y+l], inst~inst, pos~ pos, orient~ orient, value~polCnstr[pDExcl]]; }; $CBurContDL => { SimpleMapping[inst, pos, orient, cir, ContactMaps [burDifL]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x, s.y+l], inst~inst, pos~ pos, orient~ orient, value~polCnstr[pDExcl]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[s.x, 2*l, s.x+l, s.y], inst~inst, pos~ pos, orient~ orient, 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™˜rMšžœ ˜—šž˜Mšžœ˜ MšÏgžœ˜Kšœžœ˜-Kšœ žœ˜"Kš œžœžœžœžœžœ ˜)—š ÏbœžœÐck!œ¢œ¢œ˜]Kšœ žœ˜Kšœ žœ6˜BKšœ žœ6˜Ašžœž˜#Kšž˜Kšœ]˜]Kšž˜Kšžœ˜—MšœS˜SKšœ[˜[KšœS˜SK˜—šœ žœžœ˜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—š £ œž œžœžœžœžœ!˜€Kšœžœžœ˜Kšœžœ.˜5š žœžœžœžœžœž˜8šžœž˜šœ˜Kšœ žœy˜†KšœS˜SK˜—Kšžœ~˜…—Kšžœ˜—š žœžœžœžœžœž˜7Kš œ„žœžœžœžœ˜¹Kšžœ˜—Kšœ¤˜—š¡œžœžœ¢Yœ˜„Kšž˜Kšœ˜Kšœ žœ˜*Kšœžœ-˜2šžœ ž˜šœH˜HKšœ(žœ˜0Kšœžœž™ 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šœ(žœ˜0Kšœžœž™ Jšœ™Jšœ™Jšžœžœ1™>K™b—šœžœž™5J™(Jšœ™Jšœ™Jšžœžœ6™CK™b—Kšœ™KšœÄ˜ÄKšžœžœ.˜;—Kšœ9˜9Kšžœ¤˜K˜—š¡œžœžœ˜*Jšž˜Kšœžœžœžœ˜KšœK˜KK˜šžœžœ5ž˜Dš žœ"žœFžœžœž˜„šžœž˜šœ˜Kšœžœn˜wKšœžœžœ žœ ˜¼Kšœ,˜,K˜—˜ Kšœžœh˜qKšœ˜K˜—šœ˜Kšœ žœžœžœd˜…KšœS˜SK˜—˜#Kšœžœn˜wKšœÁ˜ÁK˜—˜ Kšœžœh˜q—˜ Kšœ…˜…—KšžœžœžœD˜W——Kšœž˜ Kšœ> œ˜QKšœR œ˜UKšœ œ# œ œ˜SKšœ+ œ œ œ˜TK˜KšœÛ˜ÛKšœ†˜†Kšœˆ˜ˆKšœ‚˜‚Kšœƒ˜ƒK˜—Jšžœ˜ šžœ˜Kšœ˜—J˜J˜J˜—š¡ œžœžœ˜)Jšž˜Kšœžœžœžœ˜J˜šžœžœ5ž˜Bš žœ"žœFžœžœž˜„šžœž˜˜Kšœžœn˜wKš œžœxžœžœ žœ ˜¼K˜—šœ˜Kšœ žœžœžœd˜…KšœS˜SK˜—˜#Kšœžœn˜wKš œžœxžœ!žœ žœ ˜ÁK˜—˜ Kšœžœn˜w—˜ Kšœžœ~˜…—˜ Kšœžœ~˜…—KšžœžœžœD˜W—Kšœž˜——Jšžœžœ˜ Jšžœ˜J˜J˜—š¡œ¢eœ˜ŽJšœžœ+˜>šœ žœžœ¤˜1K˜Kšœžœ ˜Kšœžœ ˜K˜—Kšœžœžœ˜1šžœž˜Kš œ;žœžœ)žœžœ˜Kš œ?žœžœ1žœžœ˜œK™bKš œ;žœžœ)žœžœ˜KšœA˜AKšœ?˜?Kšœžœk˜xKšžœžœ˜—Kšœ¤˜K˜—š¡œžœžœ˜0Jšž˜Kšœžœžœžœ˜Kšœžœ˜Kšœžœ˜$K˜šžœžœ5žœ˜Dš žœ"žœFžœžœž˜„šžœž˜šœ˜Kšœžœi˜rKšœ˜K˜—˜ Kšœžœh˜qKšœ˜—˜ Kšœžœ˜†Kšœžœ~˜…Kšœ˜—KšžœžœžœD˜W——Kšžœ˜šžœž˜šœ˜K˜:Kšœžœz˜Kšœžœ¢˜©Kšœžœ–˜K˜—šœ˜K˜:Kšœžœz˜Kšœžœ ˜§K˜—šœ˜K˜:Kšœžœz˜Kšœžœ¤˜«Kš œ3 œ œ  œ  œK˜Kšœ9 œ œ  œB˜›K˜—šœ˜K˜:Kšœžœz˜Kšœžœ¤˜«Kšœ9 œ œC˜˜KšœD œ  œK˜šK˜—KšžœžœžœW˜j—K˜K˜—Jšžœžœ˜ šžœ˜Kšœ˜—J˜J˜J˜—K˜š¡œžœ¢Yœ™ŠKšž™Kšœžœ™$Kšœžœ™šžœž™šœ™Kšœ<™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šœQ˜Q—š žœžœ6žœžœžœ4žœž˜KšœF˜F—Kšžœ˜ K˜—š¡œžœžœ˜6Kšžœžœžœ ™Kšž˜Kšœžœ1˜=Kšœ!žœ˜&Kšœ˜M™š žœžœ3žœžœž˜PKšœžœžœD˜Ršžœ#žœžœž˜7KšœPžœ˜UKšœ\žœ˜ašžœ žœžœ˜%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]]šœžœ¢˜ªKšœh˜hK˜—Kšœ¤˜—Kšžœ¤˜—Kšžœ¤˜—MšœŽ™Žšžœ)žœžœž˜=KšœOžœ˜Tšžœ žœ˜KšœžœK˜aK™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šœ žœžœžœp œ œ œ œ˜Kšžœžœžœžœ˜Kšœbžœžœ˜|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™—…—T(€á