SXCMosBContactsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by: gbb February 3, 1986 7:03:23 pm PST
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;
l: CD.Number ~ CMosB.lambda;
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: BOOLFALSE;
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], 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 =
PROC [cell: REF SX.LogicalCell]
BEGIN
isRoot: BOOL ← (cell.rootOnInvocation = SXAccess.invocation);
hasNode, hasConnection, hasRoot: BOOL;
wellConnects: Nodes;
Process Subcells.
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 {
Potential floating well in subcircuit, is it merged to some node in this cell?
hasRoot ← (SX.FindRootNode [circuit: cell.circuit, subcircuitNode: nl.first, qualifier: LIST[scl.first]].rootQualifier # NIL);
IF hasRoot THEN {
The well node of the subcircuit is not merged into this circuit, so it may be floating => 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
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.
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]];
Clean up list of well connections to eliminate REFs to superceded nodes.
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 {
n-well unconnect in root cell => 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 {
n-well connect multiple times => 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: [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.
gbb January 14, 1986 2:56:48 pm PST
Introduced check for maximum contact size.
changes to: BEGIN maxContSize: new, ConvertContact: added hack via IllegalConstruct signal