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.