SXCMosObjectsImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Written by Shand, September 12, 1983 11:40 pm
Last Edited by: Shand, March 13, 1985 3:37:18 am PST
Last Edited by: Spreitzer, January 14, 1985 10:35:23 pm PST
Last Edited by: Jacobi, December 18, 1984 4:51:35 pm PST
Last Edited by: Beretta, June 18, 1985 4:59:56 pm PDT
DIRECTORY
Atom USING [GetPropFromList, PutPropOnList],
CD USING [ApplicationList, ApplicationPtr, DesignNumber, DesignPosition, DesignRect, lambda, Layer, ObjectProcs, Orientation, Position, Rect],
CDAtomicObjects USING [AtomicObsPtr, DrawList],
CDBasics USING [Extend, NonEmpty, RectAt, ToRect],
CDOrient USING [MapPoint],
CDProperties USING [GetPropFromApplication],
CMos USING [met, met2, ndif, nwel, nwelCont, pdif, pol, pwelCont, wellSurround],
CMosBuriedContacts USING [BuriedContactPtr],
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!!!
l: CD.DesignNumber ~ CD.lambda;
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.bendList = NIL THEN { -- Oh this is easy!
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
NOTE: The DRC of channels is affected by the change made to CMosSpinifexInitImpl on April 2, 1985.
[] ← 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;
NEW MapArray: TYPE ~ ARRAY {mnDif, mpDif, mnWCont, mpWCont, nDifShort, pDifShort, nbutt, pbutt, mPol, mm2, bur} 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], [-l,-l, -l,-l]] ];
ContactMaps[mpDif].rm ← LIST[[CMos.pdif], [CMos.met], [CMos.nwel, [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.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], [-l,-l, -l,-l]] ];
ContactMaps[mm2].rm ← LIST[[CMos.met2], [CMos.met] ];
-- ContactMaps[mm2].bm ← LIST[[metSpinifex, metCnstr[mVia], [l,l, l,l]] ];
The following line is a temporary fix !
ContactMaps[mm2].bm ← LIST[[metSpinifex, metCnstr[mVia], [0,0, 0,0]] ];
ContactMaps[nDifShort].rm ← LIST[[CMos.ndif, [0,0,0,-4*l]], [CMos.pwelCont, [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.nwelCont, [0,-4*l,0,0]], [CMos.met], [CMos.nwel, [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.nwel, [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];
-- Buried contact maps are now created in ConvertBuriedContact.
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 [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]];
NOTE: The DRC of buttings is affected by the change made to CMosSpinifexInitImpl on April 2, 1985.
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+l], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
};
$CBurContPS => {
SimpleMapping[appl, pos, orient, cir, ContactMaps [burPolS]];
};
$CBurContDI => {
SimpleMapping[appl, pos, orient, cir, ContactMaps [burDifI]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, -l, s.x-2*l, 0], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x-2*l, s.y+l], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
};
$CBurContDL => {
SimpleMapping[appl, pos, orient, cir, ContactMaps [burDifL]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x, s.y+l], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[s.x, 2*l, s.x+l, s.y], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
};
ENDCASE => ERROR;
}; -- ConvertBuriedContact
ConvertBuriedContact: PUBLIC SX.ConversionProc -- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SX.Circuit] -- ~ {
Since there is only a limited number of buried contacts, in the future it may be worth to cache them.
geom: CDAtomicObjects.DrawList ~ JOIN [appl.ob.specificRef.rList, appl.ob.specificRef.sList];
size: CD.DesignPosition ~ appl.ob.size;
constr: BoxMap; -- constraint
-- Build contact map.
ContactMaps[bur].rm ← ContactMaps[bur].bm ← NIL;
FOR g: LIST OF CDAtomicObjects.DrawList ← geom, g.rest WHILE g # NIL DO
ContactMaps[bur].rm ← CONS [ContactMaps[bur].rm, [g.first.lev, [g.first.r.x1, g.first.r.y1, g.first.r.x2, g.first.r.y2]];
SELECT g.first.lev FROM
TestList => Statement;
TestList => Statement;
TestList => Statement;
TestList => Statement;
ENDCASE => Statement;
ContactMaps[bur].bm ← CONS [ContactMaps[bur].bm,
cp: CMosBuriedContacts.BuriedContactPtr ~ NARROW[appl.ob.specificRef];
s: CD.DesignPosition ~ appl.ob.size;
SELECT cp.kind FROM
$simple => {
SimpleMapping[appl, pos, orient, cir, ContactMaps [burSim]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[0, s.y, s.x, s.y+l], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
};
$polySurround => {
SimpleMapping[appl, pos, orient, cir, ContactMaps [burPolS]];
};
$difI => {
SimpleMapping[appl, pos, orient, cir, ContactMaps [burDifI]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, -l, s.x-2*l, 0], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x-2*l, s.y+l], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
};
$difL => {
SimpleMapping[appl, pos, orient, cir, ContactMaps [burDifL]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[l, s.y, s.x, s.y+l], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
[] ← cir.AddBox [spinifexLayer~polSpinifex, dim~[s.x, 2*l, s.x+l, s.y], appl~appl, pos~ pos, orient~ orient, value~polCnstr[pDExcl]];
};
ENDCASE => 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];
defaultW: INTEGER ~ 4*lambda;
defaultL: INTEGER ~ 2*l;
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/l]];
IF p.length # defaultL THEN cellStream.PutF[", L←%g", IO.int[p.length/l]];
The following is a quick hack to allow John Ousterhout to test Crystal. In a later stage, SX.AttachedNode shall receive an additional field for this info. At the moment it is not clear yet, how the user interface should be like.
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 =
PROC [cell: REF SX.LogicalCell]
BEGIN
isRoot: BOOL ← (cell.rootOnInvocation = SXAccess.invocation);
hasNode, hasConnection, hasRoot: BOOL;
wellConnects: Nodes;
Process Subcells.
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 {
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 ← (Atom.GetPropFromList
[propList: nl.first.properties, prop: wellNode] # NIL);
IF hasNode THEN {
wellConnects ← NARROW [Atom.GetPropFromList [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.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: [l, l, l, l]];
IF node = NIL THEN ERROR;
wellCon.properties ← Atom.PutPropOnList [propList: wellCon.properties,
prop: wellConnection,
val: NARROW[LIST[node], Nodes]]
END; -- AttachNWellContact
END.
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:44:59 am PST, by Shand
changes to: ConvTransistor Added Interest bloat to $DifChannel constraint to detect Dif to Channel spacing interactions.
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 7, 1985 4:30:02 pm PST, by Shand
Transistor Output changes: n*W multiplier for McCreight
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 1:42:54 pm PST, by Shand
changes to: ConvTransistor
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 19, 1985 12:41:05 pm PST, by Beretta
Thyme output change: substituted `n' coefficient for Ed McCreight by `N'
changes to: ThymeTransistor
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 1, 1985 4:15:10 pm PDT, by Beretta
Added a quick hack to the Thyme output to allow John Ousterhout to test Crystal.
changes to: ThymeTransistor: If a transistor has a property $Crystal, then its rope value is placed in the parameter list, preceded by a semicolon.
Edited on May 6, 1985 11:26:55 am PDT, by Beretta
Converted to ChipNDale CD20
Edited on June 18, 1985 4:59:38 pm PDT, by Beretta
Changed transistor types from FooTrans to FooTran, as Thyme expects.
changes to: ThymeTransistor