CMosSpinifexObjConvImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Written by Shand, September 12, 1983 11:40 pm
Last Edited by: Shand, September 4, 1984 9:03:48 pm PDT
DIRECTORY
CD USING [Rect, DesignNumber, DesignPosition, DesignRect, Level, ObjectProcs, ApplicationPtr],
CDInline USING [RectAt, Extend, NonEmpty, universe],
TerminalIO USING [WriteRope],
CMos USING [ndif, pdif, pol, met, met2, nwel, wellSurround, nwelCont, pwelCont],
CMosTransistors USING [TransistorPtr],
CMosContacts USING [ContactPtr, ContactType],
Atom USING [GetPropFromList, PutPropOnList],
IO USING [PutRope, Put, char, rope, PutF, int],
Rope USING [Cat, ROPE],
SpinifexCircuit USING [AddBox, AddRect, AdjustNode, AttachedNode, CellPostProcessProc, Circuit, CircuitConstraint, CircuitNode, CombineNodePropertyProc, ConversionProc, CreateLinkage, Dimension, FindRootNode, IllegalConstruct, LinkageAttach, LookupNode, NodeLinkage, PaintErrorRect, EnumerateGeometry, PerRectProc, Rectangle, RectDelta, SpinifexLayerIndex, TechHandle, BoxMapProc],
SpinifexOutput USING [LinkagePrintProc],
SpinifexExtras USING [ProcessMosTransistor, PerDrawRectProc, --SWNGrow, NESGrow,-- WNEGrow, ESWGrow],
CMosSpinifex
;
CMosSpinifexObjConvImpl: CEDAR PROGRAM
IMPORTS Atom, IO, Rope, CMos, CDInline, TerminalIO, SpinifexCircuit, SpinifexExtras, CMosSpinifex
EXPORTS CMosSpinifex
~ BEGIN
OPEN CMosSpinifex;
-- New Regime Transistor converters (IE the Shand unified xstr representaion)
ConvTransistor:
PUBLIC SpinifexCircuit.ConversionProc
-- [appl: CD.ApplicationPtr, cir: REF ] -- ~ {
p: CMosTransistors.TransistorPtr = NARROW[appl.ob.specificRef];
xstr: REF SpinifexCircuit.NodeLinkage;
gateNode, sourceNode, drainNode: REF SpinifexCircuit.CircuitNode;
difSpinifexLayer: SpinifexCircuit.SpinifexLayerIndex ~ IF appl.ob.level = CMos.ndif THEN ndifSpinifex ELSE pdifSpinifex;
difChannel: REF CircuitConstraint ~ IF appl.ob.level = CMos.ndif THEN nDifChannel ELSE pDifChannel;
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.level = 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];
polExtWest: CD.Rect ~ [pdBox.x1, pdBox.y1+p.lExt, pdBox.x1+p.wExt, pdBox.y2-p.lExt];
polExtEast: CD.Rect ~ [pdBox.x2-p.wExt, 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 CircuitConstraint ~ IF appl.ob.level = CMos.ndif THEN excludePolByNDif ELSE excludePolByPDif;
IF appl.ob.level # CMos.ndif
THEN {
polWellSurround: CD.DesignNumber ~ MAX[0, CMos.wellSurround-p.wExt];
wellNode: REF SpinifexCircuit.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[WellNodeAtom, WellNodeAtom];
};
-- Add poly boxes
gateNode ← cir.AddRect[ lev~CMos.pol, dim~polBox, appl~appl, pos~ pos, orient~ orient];
-- Add rects for poly exclusion and channel lead-in.
-- At the top
[] ← cir.AddBox[ spinifexLayer~ polSpinifex, dim~ [difExtNorth.x1, difExtNorth.y1, difExtNorth.x2, difExtNorth.y1+difToPolSep], appl~ appl, pos~ pos, orient~ orient, value~ channelEdge];
[] ← cir.AddBox[ spinifexLayer~ polSpinifex, dim~ [difExtNorth.x1, difExtNorth.y1+difToPolSep, difExtNorth.x2, difExtNorth.y2], appl~ appl, pos~ pos, orient~ orient,
interestBloat~ SpinifexExtras.WNEGrow[ difToPolExtSep],
value~ excludePol];
-- ... and the bottom
[] ← cir.AddBox[ spinifexLayer~ polSpinifex, dim~ [difExtSouth.x1, difExtSouth.y2-difToPolSep, difExtSouth.x2, difExtSouth.y2], appl~ appl, pos~ pos, orient~ orient, value~ channelEdge];
[] ← cir.AddBox[ spinifexLayer~ polSpinifex, dim~ [difExtSouth.x1, difExtSouth.y1, difExtSouth.x2, difExtSouth.y2-difToPolSep], appl~ appl, pos~ pos, orient~ orient, interestBloat~ SpinifexExtras.ESWGrow[ difToPolExtSep],
value~ excludePol];
-- Fill channel gap
[] ← cir.AddBox[ spinifexLayer~ difSpinifexLayer, dim~ channel, appl~ appl, pos~ pos, orient~ orient, value~ difChannel];
-- Add rects for diff width spacing and connection
sourceNode ← cir.AddBox[ spinifexLayer~difSpinifexLayer, dim~difExtNorth, appl~appl, pos~ pos, orient~ orient, interestBloat~SpinifexExtras.WNEGrow[difSep]];
drainNode ← cir.AddBox[ spinifexLayer~ difSpinifexLayer, dim~ difExtSouth, appl~ appl, pos~ pos, orient~ orient, interestBloat~ SpinifexExtras.ESWGrow[difSep]]
}
ELSE {
-- Oh no not a bent transistor yetcchh!
sourceDrainList: LIST OF REF SpinifexCircuit.CircuitNode;
sourceDrainCount: INTEGER;
[gateNode, sourceDrainList, sourceDrainCount] ← SpinifexExtras.ProcessMosTransistor[appl, pos, orient, cir, difSpinifexLayer, polSpinifex, difChannel, channelEdge, 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.
SpinifexCircuit.AdjustNode[ gateNode, polSpinifex, (p.width+2*p.wExt)*p.length, ((p.width+2*p.wExt)+p.length)*2, absolute];
SpinifexCircuit.AdjustNode[ sourceNode, difSpinifexLayer, p.lExt*p.width, 2*p.lExt + p.width, absolute];
SpinifexCircuit.AdjustNode[ drainNode, difSpinifexLayer, p.lExt*p.width, 2*p.lExt + p.width, absolute]; -- Ignore perim leading into channel.
SpinifexCircuit.LinkageAttach[link~xstr, attachType~$Gate, node~gateNode];
SpinifexCircuit.LinkageAttach[link~xstr, attachType~$Source, node~sourceNode];
SpinifexCircuit.LinkageAttach[link~xstr, attachType~$Drain, node~drainNode];
};
MapMaterial: SpinifexExtras.PerDrawRectProc
--
[r: CD.DesignRect, l: CD.Level, data: REF ANY] RETURNS [TransistorMaterial] -- ~ {
cir: REF SpinifexCircuit.Circuit ~ NARROW[ data, REF SpinifexCircuit.Circuit];
SELECT l
FROM
CMos.ndif, CMos.pdif => RETURN [diffusion];
CMos.pol => RETURN [polysilicon];
CMos.nwel => {
wellNode: REF SpinifexCircuit.CircuitNode ← cir.AddRect[ lev~ CMos.nwel, dim~ r];
wellNode.properties ← wellNode.properties.PutPropOnList[WellNodeAtom, WellNodeAtom];
RETURN [nothing];
};
ENDCASE => RETURN [nothing];
};
ConvertPDifRect:
PUBLIC SpinifexCircuit.ConversionProc
-- [appl: CD.ApplicationPtr, cir: REF SpinifexCircuit
.Circuit
] -- ~ {
wellNode: REF SpinifexCircuit.CircuitNode;
nWellBox: CD.Rect ← CDInline.RectAt[pos~[0,0], size~appl.ob.size];
pDifBox: CD.Rect ← CDInline.Extend[nWellBox, -CMos.wellSurround];
IF ~CDInline.NonEmpty[pDifBox] THEN ERROR;
[] ← 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[WellNodeAtom, WellNodeAtom];
};
-- Contact converters
ContactMap:
TYPE ~
RECORD [
rm: LIST OF RectMap,
bm: LIST OF BoxMap
];
MapRectDelta: TYPE ~ RECORD [dx1, dy1, dx2, dy2: INT];
RectMap:
TYPE ~
RECORD [
level: CD.Level,
delta: MapRectDelta
];
BoxMap:
TYPE ~
RECORD [
layer: SpinifexCircuit.SpinifexLayerIndex,
value: REF ANY,
delta: MapRectDelta
];
MapArray: TYPE ~ ARRAY {mnDif, mpDif, mnWCont, mpWCont, nDifShort, pDifShort, nbutt, pbutt, mPol, mm2 } OF ContactMap;
ContactMaps: REF MapArray;
InitContacts:
PUBLIC
PROCEDURE ~ {
ws: CD.DesignNumber ~ CMos.wellSurround;
ContactMaps ← NEW[MapArray ← ALL[ [NIL, NIL] ]];
`Normal' levels must precede nwelCont.
ContactMaps[mnDif].rm ← LIST[[CMos.ndif, [0,0,0,0]], [CMos.met, [0,0,0,0]] ];
ContactMaps[mpDif].rm ← LIST[[CMos.pdif, [0,0,0,0]], [CMos.met, [0,0,0,0]], [CMos.nwel, [ws,ws,ws,ws]] ];
ContactMaps[mnWCont].rm ← LIST[[CMos.met, [0,0,0,0]], [CMos.nwelCont, [0,0,0,0]] ];
ContactMaps[mpWCont].rm ← LIST[[CMos.met, [0,0,0,0]], [CMos.pwelCont, [0,0,0,0]] ];
ContactMaps[mPol].rm ← LIST[[CMos.pol, [0,0,0,0]], [CMos.met, [0,0,0,0]] ];
ContactMaps[mm2].rm ← LIST[[CMos.met2, [0,0,0,0]], [CMos.met, [0,0,0,0]] ];
ContactMaps[nDifShort].rm ← LIST[[CMos.ndif, [0,0,0,-4*l]], [CMos.met, [0,0,0,0]] ];
ContactMaps[pDifShort].rm ← LIST[[CMos.pdif, [0,0,0,-4*l]], [CMos.met, [0,0,0,0]], [CMos.nwel, [ws,ws,ws,ws-4*l]] ];
ContactMaps[nbutt].rm ← LIST[[CMos.ndif, [0,-3*l,0,0]], [CMos.pol, [0,0,0,-3*l]], [CMos.met, [0,0,0,0]] ];
ContactMaps[nbutt].bm ← LIST[[polSpinifex, channelEdge, [l, -3*l, l, -2*l]], [polSpinifex, polXorDif, [l, -2*l, -4*l, -3*l]], [polSpinifex, polXorDif, [-4*l, -2*l, l, -3*l]]--, [polSpinifex, polAndDif, [0, -2*l, 0, -3*l]]-- ]; -- Causes problems with false poly spacing reports if commented BoxMap is included.
ContactMaps[pbutt].rm ← LIST[[CMos.pdif, [0,-3*l,0,0]], [CMos.pol, [0,0,0,-3*l]], [CMos.met, [0,0,0,0]], [CMos.nwel, [ws,ws-2*l,ws,ws]] ];
ContactMaps[pbutt].bm ← ContactMaps[nbutt].bm;
};
ConvertContact:
PUBLIC SpinifexCircuit.ConversionProc
-- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SpinifexCircuit.Circuit] -- ~ {
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 [map: ContactMap] ~ {
node: REF SpinifexCircuit.CircuitNode ← NIL;
box: CD.Rect ← appl.ob.p.insideRect[appl.ob];
FOR r:
LIST
OF RectMap ← map.rm, r.rest
WHILE r #
NIL
DO
SELECT r.first.level
FROM
CMos.nwel => {
wellNode: REF SpinifexCircuit.CircuitNode ← cir.AddRect[ lev~r.first.level, dim~DeltaBox[box, r.first.delta], appl~appl, pos~ pos, orient~ orient];
wellNode.properties ← wellNode.properties.PutPropOnList[ WellNodeAtom, WellNodeAtom];
};
ENDCASE => node ← cir.AddRect[ lev~r.first.level, 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.layer, 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;
};
cp: CMosContacts.ContactPtr ~ NARROW[appl.ob.specificRef];
SELECT cp.typ
FROM
burr => {
-- Buried contacts come in three flavours, Pol-Surround, Dif-Surround and Crossing. The buried contacts in chipndale are parameterized by lExt and wExt, their interpretation is as follows: Diff always extends 1l to the left, material above/below and to the right is determined by lExt and wExt respectively. 2l is the pivotal value, below 2l the material is Pol, at 2l or above the material is Diff. (Note: some combinations give Diff on all four sides, it is assumed that such combinations will not be created.)
s: CD.DesignPosition ~ appl.ob.size;
node: REF SpinifexCircuit.CircuitNode ~ cir.AddRect[ lev~CMos.pol, dim~[2*l, cp.lExt, s.x-cp.wExt, s.y-cp.lExt], appl~appl, pos~ pos, orient~ orient];
IF appl.ob.level # CMos.ndif
THEN
ERROR SpinifexCircuit.IllegalConstruct[appl.ob.p.insideRect[appl.ob], "Buried Contact may only connect to n-Diffusion"];
[] ← cir.AddBox[ spinifexLayer~ ndifSpinifex, dim~ [2*l, 2*l, s.x-2*l, s.y-2*l], appl~ appl, pos~ pos, orient~ orient, value~ buriedNDifPol, interestBloat~ [difSep, difSep, difSep, difSep]];
SELECT
TRUE
FROM
cp.lExt < 2*
l
AND cp.wExt < 2*
l => {
Polysilicon Surround
wex: CD.DesignNumber ~ MAX[cp.wExt+l, 2*l];
lex: CD.DesignNumber ~ MAX[cp.lExt+l, 2*l];
[] ← cir.AddRect[ lev~appl.ob.level, dim~[l, lex, 2*l, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l-difToPolSep, lex, 2*l, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
[] ← cir.AddBox[ spinifexLayer~ndifSpinifex, dim~[2*l, lex, s.x-wex, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l, lex, s.x-wex, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~polAndDif];
};
cp.lExt < 2*
l
AND cp.wExt >= 2*
l => {
Polysilicon/Diffusion Crossing.
lex: CD.DesignNumber ~ MAX[cp.lExt+l, 2*l];
[] ← cir.AddBox[ spinifexLayer~ndifSpinifex, dim~[2*l, lex, s.x-cp.wExt, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l, lex, s.x-cp.wExt, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~polAndDif];
Left side.
[] ← cir.AddRect[ lev~appl.ob.level, dim~[l, lex, 2*l, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l-difToPolSep, lex, 2*l, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
Right side.
[] ← cir.AddRect[ lev~appl.ob.level, dim~[s.x-cp.wExt, lex, s.x-(cp.wExt-l), s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[s.x-cp.wExt, lex, s.x-(cp.wExt-difToPolSep), s.y-lex], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
};
cp.lExt >= 2*
l
AND cp.wExt < 2*
l => {
Diffusion Surround
wex: CD.DesignNumber ~ MAX[cp.wExt+l, 2*l];
lex: CD.DesignNumber ~ cp.lExt-l;
[] ← cir.AddBox[ spinifexLayer~ndifSpinifex, dim~[2*l, cp.lExt, s.x-cp.wExt, s.y-cp.lExt], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l, cp.lExt, s.x-cp.wExt, s.y-cp.lExt], appl~appl, pos~ pos, orient~ orient, value~polAndDif];
Left side.
[] ← cir.AddRect[ lev~appl.ob.level, dim~[l, lex, 2*l, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l-difToPolSep, lex, 2*l, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
Top.
[] ← cir.AddRect[ lev~appl.ob.level, dim~[2*l, s.y-cp.lExt, s.x-wex, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l, s.y-cp.lExt, s.x-wex, s.y-(cp.lExt-difToPolSep)], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
Bottom.
[] ← cir.AddRect[ lev~appl.ob.level, dim~[2*l, lex, s.x-wex, cp.lExt], appl~appl, pos~ pos, orient~ orient, value~node];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[2*l, cp.lExt-difToPolSep, s.x-wex, cp.lExt], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
};
cp.lExt >= 2*
l
AND cp.wExt >= 2*
l => {
Diffusion Surround ! on all sides ???
ERROR SpinifexCircuit.IllegalConstruct[appl.ob.p.insideRect[appl.ob], "Polysilicon surrounded by diffusion or all sides in Buried Contact"];
};
ENDCASE => ERROR;
};
mDif => SimpleMapping[ContactMaps[ SELECT appl.ob.level FROM CMos.ndif => mnDif, CMos.pdif => mpDif, CMos.nwelCont => mnWCont, CMos.pwelCont => mpWCont, ENDCASE => ERROR]];
difShort => SimpleMapping[ContactMaps[ SELECT appl.ob.level FROM CMos.ndif => nDifShort, CMos.pdif => pDifShort, ENDCASE => ERROR]];
butt => SimpleMapping[ContactMaps[ SELECT appl.ob.level FROM CMos.ndif => nbutt, CMos.pdif => pbutt, ENDCASE => ERROR]];
mPol => SimpleMapping[ContactMaps[mPol]];
mm2 => SimpleMapping[ContactMaps[mm2]];
ENDCASE => ERROR;
};
RoseTransistor:
PUBLIC SpinifexOutput.LinkagePrintProc
--
[ stream: IO.STREAM, linkage: REF NodeLinkage, name: Rope.ROPE, PrintNode: NodePrintProc] -- ~ {
PrintAttachment:
PROCEDURE [ key:
ATOM, portName: Rope.
ROPE] ~ {
stream.Put[ IO.rope[" (\""], IO.rope[portName], IO.rope["\" "]];
FOR attachments:
LIST
OF
REF SpinifexCircuit.AttachedNode ← linkage.nodes, attachments.rest
WHILE attachments #
NIL
DO
IF attachments.first.attachmentType = key
THEN {
PrintNode[stream, attachments.first.node];
stream.PutRope[")"];
RETURN
}
ENDLOOP;
stream.PutRope[ "\"?\")"];
};
p: CMosTransistors.TransistorPtr ~ NARROW[ linkage.source.ob.specificRef];
stream.Put[ IO.rope["(CI "], IO.rope[name], IO.rope[" \"Transistor[strength: drive, positive: "]];
stream.PutRope[
SELECT linkage.source.ob.level
FROM
CMos.ndif => "TRUE",
CMos.pdif => "FALSE",
ENDCASE => "UNKNOWN"
];
stream.PutRope[ ", mode: Enhancement, unidirectional: FALSE, biased: FALSE, offStrength: none]\""];
stream.PutRope[ " (CIC"];
PrintAttachment[ $Gate, "gate"];
PrintAttachment[ $Source, "ch1"];
PrintAttachment[ $Drain, "ch2"];
stream.PutRope[ "))"]
};
ThymeTransistor:
PUBLIC SpinifexOutput.LinkagePrintProc
--
[ stream: IO.STREAM, linkage: REF NodeLinkage, name: Rope.ROPE, PrintNode: NodePrintProc] -- ~ {
PrintAttachment:
PROCEDURE [ key:
ATOM] ~ {
FOR attachments:
LIST
OF
REF SpinifexCircuit.AttachedNode ← linkage.nodes, attachments.rest
WHILE attachments #
NIL
DO
IF attachments.first.attachmentType = key
THEN {
PrintNode[stream, attachments.first.node];
RETURN
}
ENDLOOP;
stream.Put[ IO.char['?]];
};
p: CMosTransistors.TransistorPtr ~ NARROW[ linkage.source.ob.specificRef];
defaultW: INTEGER ~ 4*l;
defaultL: INTEGER ~ 2*l;
stream.Put[ IO.rope[name], IO.rope[": "]];
stream.PutRope[
SELECT linkage.source.ob.level
FROM
CMos.ndif => "ETran[",
CMos.pdif => "CTran[",
ENDCASE => "FunnyTrans["
];
PrintAttachment[ $Gate];
stream.Put[ IO.char[',]];
PrintAttachment[ $Source];
stream.Put[ IO.char[',]];
PrintAttachment[ $Drain];
IF p.width # defaultW
OR p.length # defaultL
THEN {
stream.Put[ IO.char['|]];
IF p.width # defaultW THEN stream.PutF[" W←%g", IO.int[p.width/l]];
IF p.width # defaultW AND p.length # defaultL THEN stream.Put[ IO.char[',]];
IF p.length # defaultL THEN stream.PutF[" L←%g", IO.int[p.length/l]]
};
stream.PutRope[ "];"]
};
wellConnection: ATOM ~ $SpinifexCMosWellConnection;
WellNodeAtom: ATOM ~ $SpinifexCMosNWellNode;
CopyWellConnections:
PUBLIC SpinifexCircuit.CombineNodePropertyProc
--
[circuit: REF Circuit, to, from: Atom.PropList, fromNesting: LIST OF CD.ApplicationPtr] RETURNS [Atom.PropList] -- ~ {
fromConnections: LIST OF REF SpinifexCircuit.CircuitNode ← NARROW[from.GetPropFromList[ wellConnection]];
toConnections: LIST OF REF SpinifexCircuit.CircuitNode ← NARROW[to.GetPropFromList[ wellConnection]];
FOR fl:
LIST
OF
REF SpinifexCircuit.CircuitNode ← fromConnections, fl.rest
WHILE fl #
NIL
DO
fromNode: REF SpinifexCircuit.CircuitNode ~ IF fromNesting = NIL THEN fl.first ELSE circuit.FindRootNode[fl.first, fromNesting, TRUE].node; -- Side Effect !! may add fl.first to subcircuits ports.
FOR tl:
LIST
OF
REF SpinifexCircuit.CircuitNode ← toConnections, tl.rest
WHILE tl #
NIL
DO
IF fromNode.LookupNode[] = tl.first.LookupNode[] THEN EXIT;
REPEAT
FINISHED =>
toConnections ← CONS[fromNode, toConnections]
ENDLOOP
ENDLOOP;
IF toConnections #
NIL
THEN
to ← to.PutPropOnList[ wellConnection, toConnections];
IF from.GetPropFromList[ WellNodeAtom] #
NIL
AND to.GetPropFromList[ WellNodeAtom] =
NIL
THEN
to ← to.PutPropOnList[ WellNodeAtom, WellNodeAtom];
RETURN [ to ]
};
CheckWellConnections:
PUBLIC SpinifexCircuit.CellPostProcessProc
--
[cell: REF SpinifexCircuit.LogicalCell] -- ~ {
FOR nl:
LIST
OF
REF SpinifexCircuit.CircuitNode ← cell.circuit.nodes, nl.rest
WHILE nl #
NIL
DO
IF nl.first.properties.GetPropFromList[ WellNodeAtom] #
NIL
THEN {
wellConnects: LIST OF REF SpinifexCircuit.CircuitNode ← NARROW[nl.first.properties.GetPropFromList[ wellConnection]];
Clean up list to eliminate REFs to superceded nodes.
FOR wl:
LIST
OF
REF SpinifexCircuit.CircuitNode ← wellConnects, wl.rest
WHILE wl #
NIL
DO
wl.first ← wl.first.LookupNode[];
FOR restOfWl:
LIST
OF
REF SpinifexCircuit.CircuitNode ← wl, restOfWl.rest
WHILE restOfWl.rest #
NIL
DO
IF wl.first = restOfWl.rest.first.LookupNode[]
THEN
restOfWl.rest ← restOfWl.rest.rest -- Drop this list element.
ENDLOOP
ENDLOOP;
IF wellConnects =
NIL
OR wellConnects.rest #
NIL
THEN {
n-well ERROR
PaintWellErrorOverGeom: SpinifexCircuit.PerRectProc
-- [r: REF Rectangle, data: REF ANY] -- ~ {
IF r.nodeInformation = data
THEN
cell.PaintErrorRect[ errorBox~ r.Dimension[], message~ message]
};
message: Rope.ROPE ~ IF wellConnects = NIL THEN "Floating n-well" ELSE "n-well plugged to more than one node";
cell.circuit.EnumerateGeometry[wellSpinifex, CDInline.universe, PaintWellErrorOverGeom, nl.first]
}
}
ENDLOOP
};
AttachNWellContact:
PUBLIC SpinifexCircuit.BoxMapProc
-- [cir: REF Circuit, dim: CD.Rect, appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, node: REF CircuitNode] RETURNS [cirNode: REF CircuitNode ← NIL] -- ~ {
wellCon: REF SpinifexCircuit.CircuitNode ← cir.AddBox[ spinifexLayer~ wellSpinifex, dim~ dim, appl~appl, pos~ pos, orient~ orient, interestBloat~ [l, l, l, l]];
IF node = NIL THEN ERROR;
wellCon.properties ← wellCon.properties.PutPropOnList[ wellConnection, NARROW[ LIST[node], LIST OF REF SpinifexCircuit.CircuitNode] ];
};
END.