<> <> <> <> <> <> <> DIRECTORY Atom USING [GetPropFromList, PutPropOnList], CD USING [ApplicationList, ApplicationPtr, DesignNumber, DesignPosition, DesignRect, lambda, Layer, ObjectProcs, Orientation, Position, Rect], <> CDBasics USING [Extend, NonEmpty, RectAt, ToRect], CDOrient USING [MapPoint], CDProperties USING [GetPropFromApplication], CMos USING [met, met2, ndif, nwel, nwelCont, pdif, pol, pwelCont, wellSurround], <> CMosContacts USING [ContactPtr, ContactType], CMosTransistors USING [TransistorPtr], IO USING [atom, char, int, Put, PutF, PutFR, PutRope, rope], Rope USING [Cat, ROPE], SX, SXAccess, SXAccessInternal, SXCMos, SXCMosBasicRules USING [difSep, difToPolExtSep, difToPolSep], SXOutput USING [LinkagePrintProc], SXOutputPrivate, SXTechnology, TerminalIO USING [WriteRope]; SXCMosObjectsImpl: CEDAR PROGRAM IMPORTS Atom, CDBasics, CDOrient, CDProperties, CMos, IO, Rope, SX, SXAccess, SXAccessInternal, SXCMos, SXOutputPrivate, SXTechnology, TerminalIO EXPORTS SXCMos = BEGIN OPEN SXCMos; <<-- New Regime Transistor converters (IE the Shand unified xstr representaion)>> <<-- Hee hee, I'll get to use variables with greek looks yet!!!>> wellConnection: ATOM ~ $SXCMosWellConnection; wellNode: ATOM ~ $SXCMosNWellNode; Nodes: TYPE = LIST OF REF SX.CircuitNode; PointRect: PROC [p: CD.Position] RETURNS [r: CD.Rect] = BEGIN r _ CDBasics.Extend[CDBasics.ToRect[p, p], CD.lambda] END; ConvTransistor: PUBLIC SX.ConversionProc -- [appl: CD.ApplicationPtr, cir: REF ] -- ~ { p: CMosTransistors.TransistorPtr = NARROW[appl.ob.specificRef]; xstr: REF SX.NodeLinkage; gateNode, sourceNode, drainNode: REF SX.CircuitNode; difSpinifexLayer: SX.SpinifexLayerIndex ~ IF appl.ob.layer = CMos.ndif THEN ndifSpinifex ELSE pdifSpinifex; difChannel: REF SX.Constraint ~ IF appl.ob.layer = CMos.ndif THEN ndCnstr[ndCh] ELSE pdCnstr[pdCh]; <> IF ~ p.angle THEN { -- Oh this is easy! <<-- Get the Xstr bounding box exclusive of nwel, i.e. only pol and dif.>> wellPolSurround: CD.DesignNumber ~ MAX[0, CMos.wellSurround-p.wExt]; pdBox: CD.Rect ~ IF appl.ob.layer = CMos.ndif THEN [0, 0, appl.ob.size.x, appl.ob.size.y] ELSE [wellPolSurround, CMos.wellSurround, appl.ob.size.x-wellPolSurround, appl.ob.size.y-CMos.wellSurround]; polBox: CD.Rect ~ [pdBox.x1, pdBox.y1+p.lExt, pdBox.x2, pdBox.y2-p.lExt]; channel: CD.Rect ~ [pdBox.x1+p.wExt, pdBox.y1+p.lExt, pdBox.x2-p.wExt, pdBox.y2-p.lExt]; difExtSouth: CD.Rect ~ [pdBox.x1+p.wExt, pdBox.y1, pdBox.x2-p.wExt, pdBox.y1+p.lExt]; difExtNorth: CD.Rect ~ [pdBox.x1+p.wExt, pdBox.y2-p.lExt, pdBox.x2-p.wExt, pdBox.y2]; excludePol: REF SX.Constraint ~ IF appl.ob.layer = CMos.ndif THEN polCnstr[pExnD] ELSE polCnstr[pExpD]; IF appl.ob.layer # CMos.ndif THEN { polWellSurround: CD.DesignNumber ~ MAX[0, CMos.wellSurround-p.wExt]; wellNode: REF SX.CircuitNode _ cir.AddRect [lev~ CMos.nwel, dim~ [0, polWellSurround, appl.ob.size.x, appl.ob.size.y-polWellSurround], appl~ appl, pos~ pos, orient~ orient]; wellNode.properties _ wellNode.properties.PutPropOnList[wellNode, wellNode]; }; <<-- Add poly boxes>> gateNode _ cir.AddRect [lev~CMos.pol, dim~polBox, appl~appl, pos~ pos, orient~ orient]; <<-- Add rects for poly exclusion.>> IF p.lExt-SXCMosBasicRules.difToPolSep > 0 THEN { <<-- At the top>> [] _ cir.AddBox [spinifexLayer~ polSpinifex, dim~ [difExtNorth.x1, difExtNorth.y1+SXCMosBasicRules.difToPolSep, difExtNorth.x2, difExtNorth.y2], appl~ appl, pos~ pos, orient~ orient, interestBloat~ SXTechnology.WNEGrow [SXCMosBasicRules.difToPolExtSep], value~ excludePol]; <<-- ... and the bottom>> [] _ cir.AddBox [spinifexLayer~ polSpinifex, dim~ [difExtSouth.x1, difExtSouth.y1, difExtSouth.x2, difExtSouth.y2-SXCMosBasicRules.difToPolSep], appl~ appl, pos~ pos, orient~ orient, interestBloat~ SXTechnology.ESWGrow [SXCMosBasicRules.difToPolExtSep], value~ excludePol] }; <<-- Add rects for channel lead-in.>> <<-- At the top>> [] _ cir.AddBox [spinifexLayer~ polSpinifex, dim~ [difExtNorth.x1, difExtNorth.y1, difExtNorth.x2, difExtNorth.y1+SXCMosBasicRules.difToPolSep], appl~ appl, pos~ pos, orient~ orient, value~ polCnstr[pChE]]; <<-- ... and the bottom>> [] _ cir.AddBox [spinifexLayer~ polSpinifex, dim~ [difExtSouth.x1, difExtSouth.y2-SXCMosBasicRules.difToPolSep, difExtSouth.x2, difExtSouth.y2], appl~ appl, pos~ pos, orient~ orient, value~ polCnstr[pChE]]; <<-- Fill channel gap>> <> [] _ cir.AddBox [spinifexLayer~ difSpinifexLayer, dim~ channel, appl~ appl, pos~ pos, orient~ orient, interestBloat~ [dx1~ SXCMosBasicRules.difSep, dy1~ 0, dx2~ SXCMosBasicRules.difSep, dy2~ 0], value~ difChannel]; <<-- Add rects for diff width spacing and connection>> sourceNode _ cir.AddBox [spinifexLayer~difSpinifexLayer, dim~difExtNorth, appl~appl, pos~ pos, orient~ orient, interestBloat~SXTechnology.WNEGrow[SXCMosBasicRules.difSep]]; drainNode _ cir.AddBox [spinifexLayer~ difSpinifexLayer, dim~ difExtSouth, appl~ appl, pos~ pos, orient~ orient, interestBloat~ SXTechnology.ESWGrow[SXCMosBasicRules.difSep]] } ELSE { -- Oh no not a bent transistor yetcchh! sourceDrainList: Nodes; sourceDrainCount: INTEGER; [gateNode, sourceDrainList, sourceDrainCount] _ SXTechnology.ProcessMosTransistor[appl, pos, orient, cir, difSpinifexLayer, polSpinifex, difChannel, polCnstr[pChE], SXCMosBasicRules.difSep, SXCMosBasicRules.difToPolSep, MapMaterial, cir]; IF sourceDrainCount = 2 THEN { sourceNode _ sourceDrainList.first; drainNode _ sourceDrainList.rest.first; } ELSE { TerminalIO.WriteRope [Rope.Cat["Xstr with ", (SELECT sourceDrainCount FROM 0 => "no", 1 => "only 1", ENDCASE => "more than 2"), " sources/drains not included in circuit description\n"]]; RETURN } }; xstr _ cir.CreateLinkage[appl]; <<-- We're a lot smarter than this program, so let's adjust the area and perim values its got.>> SX.AdjustNode [gateNode, polSpinifex, (p.width+2*p.wExt)*p.length, ((p.width+2*p.wExt)+p.length)*2, absolute]; SX.AdjustNode [sourceNode, difSpinifexLayer, p.lExt*p.width, 2*p.lExt + p.width, absolute]; SX.AdjustNode [drainNode, difSpinifexLayer, p.lExt*p.width, 2*p.lExt + p.width, absolute]; -- Ignore perim leading into channel. SX.LinkageAttach[link~xstr, attachType~$Gate, node~gateNode]; SX.LinkageAttach[link~xstr, attachType~$Source, node~sourceNode]; SX.LinkageAttach[link~xstr, attachType~$Drain, node~drainNode]; }; MapMaterial: SXTechnology.PerDrawRectProc -- [r: CD.DesignRect, l: CD.Layer, data: REF ANY] RETURNS [TransistorMaterial] -- ~ { cir: REF SX.Circuit ~ NARROW [data, REF SX.Circuit]; SELECT l FROM CMos.ndif, CMos.pdif => RETURN [diffusion]; CMos.pol => RETURN [polysilicon]; CMos.nwel => { wellNode: REF SX.CircuitNode _ cir.AddRect [lev~ CMos.nwel, dim~ r]; wellNode.properties _ wellNode.properties.PutPropOnList[wellNode, wellNode]; RETURN [nothing]; }; ENDCASE => RETURN [nothing]; }; ConvertPDifRect: PUBLIC SX.ConversionProc -- [appl: CD.ApplicationPtr, cir: REF SX.Circuit] -- ~ { wellNode: REF SX.CircuitNode; nWellBox: CD.Rect _ CDBasics.RectAt[pos~[0,0], size~appl.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, appl~appl, pos~ pos, orient~ orient]; wellNode _ cir.AddRect [lev~CMos.nwel, dim~nWellBox, appl~appl, pos~ pos, orient~ orient]; wellNode.properties _ wellNode.properties.PutPropOnList[wellNode, wellNode]; }; <<-- Contact converters>> 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] ]; MapArray: TYPE ~ ARRAY {mnDif, mpDif, mnWCont, mpWCont, nDifShort, pDifShort, nbutt, pbutt, mPol, mm2, burSim, burPolS, burDifI, burDifL } OF ContactMap; <> ContactMaps: REF MapArray; InitContacts: PUBLIC PROCEDURE ~ { ws: CD.DesignNumber ~ CMos.wellSurround; buttBaseBM: LIST OF BoxMap; ContactMaps _ NEW[MapArray _ ALL [[NIL, NIL] ]]; <<`Normal' layers must precede nwelCont.>> 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.nwel, [ws,ws,ws,ws]] ]; ContactMaps[mpDif].bm _ LIST[[polSpinifex, polCnstr[pExPdCon]], [metSpinifex, metCnstr[mCut], [- ContactMaps[mnWCont].rm _ LIST[[CMos.met], [CMos.nwelCont] ]; ContactMaps[mnWCont].bm _ ContactMaps[mnDif].bm; ContactMaps[mpWCont].rm _ LIST[[CMos.met], [CMos.pwelCont] ]; 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* <<-- Buried contact maps are now created in ConvertBuriedContact.>> 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 [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SX.Circuit, map: ContactMap] ~ { node: REF SX.CircuitNode _ NIL; box: CD.Rect _ appl.ob.p.oldInsideRect [appl.ob]; FOR r: LIST OF RectMap _ map.rm, r.rest WHILE r # NIL DO SELECT r.first.layer FROM CMos.nwel => { wellNode: REF SX.CircuitNode _ cir.AddRect [lev~r.first.layer, dim~DeltaBox[box, r.first.delta], appl~appl, pos~ pos, orient~ orient]; wellNode.properties _ wellNode.properties.PutPropOnList [wellNode, wellNode]; }; ENDCASE => node _ cir.AddRect [lev~r.first.layer, dim~DeltaBox[box, r.first.delta], appl~appl, 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], appl~ appl, pos~ pos, orient~ orient, value~ IF b.first.value # NIL THEN b.first.value ELSE node]; ENDLOOP; }; -- SimpleMapping ConvertContact: PUBLIC SX.ConversionProc -- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SX.Circuit] -- ~ { cp: CMosContacts.ContactPtr ~ NARROW[appl.ob.specificRef]; SELECT cp.typ FROM mDif => SimpleMapping[appl, pos, orient, cir, ContactMaps [SELECT appl.ob.layer FROM CMos.ndif => mnDif, CMos.pdif => mpDif, CMos.nwelCont => mnWCont, CMos.pwelCont => mpWCont, ENDCASE => ERROR]]; difShort => SimpleMapping[appl, pos, orient, cir, ContactMaps [SELECT appl.ob.layer FROM CMos.ndif => nDifShort, CMos.pdif => pDifShort, ENDCASE => ERROR]]; <> butt => SimpleMapping[appl, pos, orient, cir, ContactMaps [SELECT appl.ob.layer FROM CMos.ndif => nbutt, CMos.pdif => pbutt, ENDCASE => ERROR]]; mPol => SimpleMapping[appl, pos, orient, cir, ContactMaps[mPol]]; mm2 => SimpleMapping[appl, pos, orient, cir, ContactMaps[mm2]]; burr => ERROR SX.IllegalConstruct[appl.ob.p.oldInsideRect[appl.ob], "Old-style Buried Contact no longer supported"]; ENDCASE => ERROR; }; -- ConvertContact ConvertBuriedContact: PUBLIC SX.ConversionProc -- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SX.Circuit] -- ~ { cp: ATOM ~ NARROW[appl.ob.p.objectType]; s: CD.DesignPosition ~ appl.ob.size; SELECT cp FROM $CBurContS => { SimpleMapping[appl, pos, orient, cir, ContactMaps [burSim]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[0, s.y, s.x, s.y+ }; $CBurContPS => { SimpleMapping[appl, pos, orient, cir, ContactMaps [burPolS]]; }; $CBurContDI => { SimpleMapping[appl, pos, orient, cir, ContactMaps [burDifI]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[ [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[ value~polCnstr[pDExcl]]; }; $CBurContDL => { SimpleMapping[appl, pos, orient, cir, ContactMaps [burDifL]]; [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[ [] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[s.x, 2* value~polCnstr[pDExcl]]; }; ENDCASE => ERROR; }; -- ConvertBuriedContact <> <> <> <> <> <<-- Build contact map.>> <> <> <> <> <<$simple => {>> <> <<[] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[0, s.y, s.x, s.y+ value~polCnstr[pDExcl]];>> <<};>> <<$polySurround => {>> <> <<};>> <<$difI => {>> <> <<[] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[>> <<[] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[ value~polCnstr[pDExcl]];>> <<};>> <<$difL => {>> <> <<[] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[ value~polCnstr[pDExcl]];>> <<[] _ cir.AddBox [spinifexLayer~polSpinifex, dim~[s.x, 2* value~polCnstr[pDExcl]];>> <<};>> < ERROR;>> <<};>> RoseTransistor: PUBLIC SXOutput.LinkagePrintProc -- [desWDir: ROPE, dfStream, cellStream: IO.STREAM, linkage: REF NodeLinkage, name: Rope.ROPE, PrintNode: NodePrintProc] -- ~ { PrintAttachment: PROCEDURE [key: ATOM, portName: Rope.ROPE] ~ { cellStream.Put [IO.rope[" (\""], IO.rope[portName], IO.rope["\" "]]; FOR attachments: LIST OF REF SX.AttachedNode _ linkage.nodes, attachments.rest WHILE attachments # NIL DO IF attachments.first.attachmentType = key THEN { PrintNode[cellStream, attachments.first.node]; cellStream.PutRope[")"]; RETURN } ENDLOOP; cellStream.PutRope ["\"?\")"]; }; -- PrintAttachment p: CMosTransistors.TransistorPtr ~ NARROW [linkage.source.ob.specificRef]; naming: SXOutputPrivate.Naming _ SXOutputPrivate.GetANaming [linkage.source]; cellStream.PutRope["(CI "]; SXOutputPrivate.PrintNaming[ cellStream, naming, Rope.Cat[" \"", SXOutputPrivate.NameTransType[ desWDir: desWDir, obj: linkage.source.ob, dfStream: dfStream, type: SELECT linkage.source.ob.layer FROM CMos.ndif => $n, CMos.pdif => $p, ENDCASE => $funny, mode: $E, length: p.length, width: p.width], "\""] ]; SXOutputPrivate.PrintRoseInstantiationTransformation[cellStream, linkage.source]; cellStream.PutRope [" (CIC"]; PrintAttachment [$Gate, "gate"]; PrintAttachment [$Source, "ch1"]; PrintAttachment [$Drain, "ch2"]; cellStream.PutRope ["))"] }; -- RoseTransistor ThymeTransistor: PUBLIC SXOutput.LinkagePrintProc -- [desWDir: ROPE, dfStream, cellStream: IO.STREAM, linkage: REF NodeLinkage, name: Rope.ROPE, PrintNode: NodePrintProc] -- ~ { PrintAttachment: PROCEDURE [key: ATOM] ~ { FOR attachments: LIST OF REF SX.AttachedNode _ linkage.nodes, attachments.rest WHILE attachments # NIL DO IF attachments.first.attachmentType = key THEN { PrintNode[cellStream, attachments.first.node]; RETURN } ENDLOOP; cellStream.Put [IO.char['?]]; }; -- PrintAttachment p: CMosTransistors.TransistorPtr ~ NARROW [linkage.source.ob.specificRef]; <> defaultL: INTEGER ~ 2* propertyValue: REF; cellStream.Put [IO.rope[name], IO.rope[": "]]; cellStream.PutRope [SELECT linkage.source.ob.layer FROM CMos.ndif => "ETran[", CMos.pdif => "CTran[", ENDCASE => "FunnyTran[" ]; PrintAttachment [$Gate]; cellStream.Put [IO.char[',]]; PrintAttachment [$Source]; cellStream.Put [IO.char[',]]; PrintAttachment [$Drain]; cellStream.Put [IO.char['|]]; cellStream.PutF[" W_N*%g", IO.int[p.width/ IF p.length # defaultL THEN cellStream.PutF[", L_%g", IO.int[p.length/ <> propertyValue _ CDProperties.GetPropFromApplication [from: linkage.source, prop: $Crystal]; WITH propertyValue SELECT FROM crystalHack: Rope.ROPE => IO.Put [stream: cellStream, v1: IO.rope["; "], v2: IO.rope[crystalHack]]; ENDCASE => IF propertyValue # NIL THEN TerminalIO.WriteRope [" $Crystal property must be a rope. /n"]; cellStream.PutRope ["];"] }; -- ThymeTransistor CopyWellConnections: PUBLIC SX.CombineNodePropertyProc -- [circuit: REF Circuit, to, from: Atom.PropList, fromNesting: LIST OF CD.ApplicationPtr] RETURNS [Atom.PropList] -- ~ { fromConnections: Nodes _ NARROW [Atom.GetPropFromList [propList: from, prop: wellConnection]]; toConnections: Nodes _ NARROW [Atom.GetPropFromList [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 _ Atom.PutPropOnList [propList: to, prop: wellConnection, val: toConnections]; IF (Atom.GetPropFromList [propList: from, prop: wellNode] # NIL) AND (Atom.GetPropFromList [propList: to, prop: wellNode] = NIL) THEN to _ Atom.PutPropOnList [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.ApplicationList _ 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 _ (Atom.GetPropFromList [propList: nl.first.properties, prop: wellNode] # NIL); hasConnection _ (Atom.GetPropFromList [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 _ (Atom.GetPropFromList [propList: nl.first.properties, prop: wellNode] # NIL); IF hasNode THEN { wellConnects _ NARROW [Atom.GetPropFromList [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.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, node: REF CircuitNode] RETURNS [cirNode: REF CircuitNode _ NIL] >> BEGIN wellCon: REF SX.CircuitNode _ SX.AddBox [cir: cir, spinifexLayer: wellSpinifex, dim: dim, appl: appl, pos: pos, orient: orient, interestBloat: [ IF node = NIL THEN ERROR; wellCon.properties _ Atom.PutPropOnList [propList: wellCon.properties, prop: wellConnection, val: NARROW[LIST[node], Nodes]] END; -- AttachNWellContact END. <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>>