<> <> <> DIRECTORY CD USING [Instance, InstanceList, Layer, Number, Orientation, Position, Rect], CDAtomicObjects, CDBasics USING [Extend, NonEmpty, RectAt, ToRect], CDOrient USING [MapPoint], CMosB, 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], SXCMosB, SXTechnology USING [GetCircuitFromCDObject], TerminalIO USING [WriteRope]; SXCMosBContactsImpl: CEDAR PROGRAM IMPORTS CDBasics, CDOrient, CMosB, IO, Properties, SX, SXAccess, SXAccessInternal, SXCMosB, SXTechnology, TerminalIO EXPORTS SXCMosB = BEGIN OPEN SXCMosB; wellConnection: ATOM ~ $SXCMosBWellConnection; wellNode: ATOM ~ $SXCMosBNWellNode; Nodes: TYPE = LIST OF REF SX.CircuitNode; maxContSize: CD.Number ~ 5 * CMosB.lambda; splitContWidth: CD.Number ~ 2 * CMosB.lambda; splitContHeight: CD.Number ~ 6 * CMosB.lambda; 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, -CMosB.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~CMosB.pdif, dim~pDifBox, inst~inst, pos~ pos, orient~ orient]; wellNode _ cir.AddRect [lev~CMosB.nwell, dim~nWellBox, inst~inst, pos~ pos, orient~ orient]; wellNode.properties _ Properties.PutProp [wellNode.properties, wellNode, wellNode]; }; ConvertContact: PUBLIC SX.ConversionProc = BEGIN <<[appl: CD.Instance, pos: CD.Position, orient: CD.Orientation, cir: REF SX.Circuit]>> Size: PROC [r: CD.Rect] RETURNS [s: CD.Position] ~ INLINE BEGIN s.x _ (r.x2 - r.x1); s.y _ (r.y2 - r.y1) END; -- Size classKey: ATOM = inst.ob.class.objectType; r: CD.Rect = inst.ob.class.oldInsideRect[inst.ob]; node: REF SX.CircuitNode _ NIL; size: CD.Position; sizeExceeded: BOOL _ FALSE; SELECT classKey FROM $C2SimpleCon, $C2WellSimpleCon, $C2LargeSimpleCon, $C2LargeWellSimpleCon, $C2DifShortCon, $C2Via, $C2LargeVia => FOR geom: CDAtomicObjects.DrawList _ NARROW [inst.ob.specificRef, CDAtomicObjects.AtomicObsPtr].rList, geom.rest WHILE geom # NIL DO SELECT geom.first.lev FROM CMosB.ndif, CMosB.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 = CMosB.ndif THEN pExNdCon ELSE pExPdCon)]]; }; CMosB.nwell, CMosB.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]; }; CMosB.nwellCont, CMosB.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 = CMosB.nwellCont THEN pExNdCon ELSE pExPdCon)]]; }; CMosB.met, CMosB.met2, CMosB.pol => node _ SX.AddRect[cir: cir, lev: geom.first.lev, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: node]; CMosB.cut => { -- all but vias [] _ SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: metCnstr[mCut]]; size _ Size [geom.first.r]; SELECT classKey FROM $C2DifShortCon, $C2WellDifShortCon => sizeExceeded _ sizeExceeded OR ((MIN[size.x, size.y]#splitContWidth) OR (MAX[size.x, size.y]#splitContHeight)); ENDCASE => sizeExceeded _ sizeExceeded OR (size.x>maxContSize OR size.y>maxContSize)}; CMosB.cut2 => { -- vias [] _ SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: metCnstr[mVia]]; <<[] _ SX.AddBox[cir: cir, spinifexLayer: metSpinifex, dim: geom.first.r, inst: inst, pos: pos, orient: orient, value: metCnstr[mCut]];>> size _ Size [geom.first.r]; sizeExceeded _ sizeExceeded OR (size.x>maxContSize OR size.y>maxContSize)}; ENDCASE => ERROR SX.IllegalConstruct [geom.first.r, "Unknown simple contact geometry"]; ENDLOOP ENDCASE => SX.IllegalConstruct [r, "Unknown CMos-B contact type"]; IF sizeExceeded THEN SX.IllegalConstruct [r, "Maximum contact size exceeded"] END; -- ConvertContact PointRect: PROC [p: CD.Position] RETURNS [r: CD.Rect] = BEGIN r _ CDBasics.Extend [CDBasics.ToRect[p, p], 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 { < VIOLATION>> 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 { < 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 { < 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, inst: inst, pos: pos, orient: orient, interestBloat: [ IF node = NIL THEN ERROR; wellCon.properties _ Properties.PutProp [propList: wellCon.properties, prop: wellConnection, val: NARROW[LIST[node], Nodes]] END; -- AttachNWellContact END. <> <> <> <<>>