SinixNMos:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDCells, CDLayers, CDProperties, CDRects, CDSymbolicObjects, CDTexts, NMos, CoreClasses, CoreGeometry, PWObjects, Sinix, SinixOps
SHARES CDCells, CDLayers, CDRects, CDSymbolicObjects, CDTexts =
BEGIN
Properties and extraction of common objects
mode: Sinix.Mode ←
NEW [Sinix.ModeRec ← [
extractProcProp: PWObjects.RegisterProp[$NMosExtractProc, TRUE],
decoration: CoreGeometry.CreateDecoration["NMos"],
nbOfLayers: NbOfInterestingLayers,
instanceLayer: InstanceLayer,
touchProc: CoreGeometry.Touch,
equalProc: Sinix.CompareProps
]];
InterestingLayers: ARRAY [0 .. NbOfInterestingLayers) OF CD.Layer ← [NMos.dif, NMos.pol, NMos.met, NMos.met2, NMos.cut, NMos.cut2, NMos.imp, NMos.imp0, NMos.impWeak, NMos.ovg, NMos.bur];
NbOfInterestingLayers:
NAT = 11;
lambda: CD.Number = NMos.nmos.lambda;
Transistors
TransistorFlattenProc:
TYPE =
PROC [obj:
CD.Object]
RETURNS [sList: CDAtomicObjects.DrawList ←
NIL, dList: CDAtomicObjects.DrawList ←
NIL, gList: CDAtomicObjects.DrawList ←
NIL, xList: CDAtomicObjects.DrawList ←
NIL];
This is necessary because CD does not keep the list of rectangles anywhere but generates them inline at drawing time. Return geometry for source, drain, gate and special unconnected layers.
AddRectList:
PROC [mode: Sinix.Mode, wire: Wire, list: CDAtomicObjects.DrawList] = {
WHILE list#
NIL
DO
CoreGeometry.PutPins[mode.decoration, wire, CONS [[CDRects.CreateRect[CDBasics.SizeOfRect[list.first.r], list.first.layer], [CDBasics.BaseOfRect[list.first.r]]], CoreGeometry.GetPins[mode.decoration, wire]]];
list ← list.rest;
ENDLOOP;
};
ExtractTransistor: Sinix.ExtractProc ~ {
tp: NMosTransistors.TransistorPtr = NARROW [obj.specific];
cellType: CellType;
gateWire, sourceWire, drainWire: Wire;
sList, dList, gList, xList: CDAtomicObjects.DrawList;
flatten: REF TransistorFlattenProc = NARROW [CDProperties.GetProp[from: obj.class, prop: $TransistorFlatten]];
cellType ← CoreClasses.CreateTransistor[[nE, tp.length, tp.width]];
gateWire ← cellType.public[0];
sourceWire ← cellType.public[1];
drainWire ← cellType.public[2];
[sList, dList, gList, xList] ← flatten[obj];
AddRectList[mode, sourceWire, sList];
AddRectList[mode, drainWire, dList];
AddRectList[mode, gateWire, gList];
CoreGeometry.PutObject[mode.decoration, cellType, obj];
result ← cellType;
};
depletionOverlap:
CD.Number = (3*lambda)/2;
New layers for transistors
source: CD.Layer ← MakeAbstract[CD.NewLayer[NMos.nmos, $NSource], NMos.dif];
drain: CD.Layer ← MakeAbstract[CD.NewLayer[NMos.nmos, $NDrain], NMos.dif];
Flatten a regular transistor
RegularTransistor: TransistorFlattenProc = {
size: CD.Position = CDBasics.SizeOfRect[obj.bbox];
class: NMosTransistors.TransistorPtr = NARROW [obj.specific];
sList ← CONS [[[x1: class.wExt, x2: class.wExt+class.width, y1: 0, y2: class.lExt],
source], sList];
dList ← CONS [[[x1: class.wExt, x2: class.wExt+class.width, y1: class.lExt+class.length, y2: size.y], drain], dList];
gList ← CONS [[[x1: 0, x2: size.x, y1: class.lExt, y2: class.lExt+class.length],
NMos.pol], gList];
IF class.implant>0
THEN xList ←
CONS [[
[x1: class.wExt-depletionOverlap, x2: size.x-class.wExt+depletionOverlap, y1: class.lExt-depletionOverlap, y2: size.y-class.lExt+depletionOverlap],
SELECT class.implant
FROM
NMosTransistors.strongDepletion => NMos.imp,
NMosTransistors.weakDepletion => NMos.impWeak,
NMosTransistors.zeroTresh => NMos.imp0,
NMosTransistors.enhancement => CD.errorLayer,
ENDCASE => CD.errorLayer
], xList];
};
Flatten an angle transistor
AngleTransistor: TransistorFlattenProc = {
size: CD.Position = CDBasics.SizeOfRect[obj.bbox];
class: NMosTransistors.TransistorPtr = NARROW [obj.specific];
ele: CD.Number = 2*class.lExt+class.length;
-- Warning: This code is absurd, but so is NMosTransistorsImpl.DrawMeForATransistors in CDNMos23. It is incorrect if ele+wExt > size (which may make sense).
-- The right code should compute the lowx/highy values for dif and go from there, not assuming the structure of the overlap. The CD graphics are wrong, and anyway it is impossible to stretch angle NMos transistors, so only one size is really available!
hPoly:
CD.Rect =
[x1: 0, x2: size.x-class.lExt, y1: class.lExt, y2: class.length+class.lExt]; -- horizontal
vPoly:
CD.Rect =
[x1: size.x-class.length-class.lExt, x2: hPoly.x2, y1: hPoly.y2, y2: size.y]; -- vertical
nDrain:
CD.Rect =
[x1: class.wExt, x2: size.x, y1: 0, y2: hPoly.y1]; -- north
eDrain:
CD.Rect =
[x1: vPoly.x2, x2: nDrain.x2, y1: nDrain.y2, y2: size.y-class.wExt]; -- east
wSource:
CD.Rect =
[x1: size.x-ele, x2: vPoly.x1, y1: vPoly.y1, y2: eDrain.y2]; -- west
sSource:
CD.Rect =
[x1: MIN[nDrain.x1, wSource.x1], x2: wSource.x1, y1: wSource.y1, y2: MIN[ele, wSource.y2]]; -- south
gList ← CONS [[hPoly, NMos.pol], gList];
gList ← CONS [[vPoly, NMos.pol], gList];
IF class.lExt>0
THEN
BEGIN
dList ← CONS [[nDrain, drain], dList];
dList ← CONS [[eDrain, drain], dList];
END;
sList ← CONS [[wSource, source], sList];
IF sSource.x1 < sSource.x2 THEN sList ← CONS [[sSource, source], sList];
IF class.implant>0
THEN
BEGIN
xList ←
CONS [
[[x1: nDrain.x1-depletionOverlap, x2: hPoly.x2+depletionOverlap, y1: hPoly.y1-depletionOverlap, y2: hPoly.y2+depletionOverlap],
NMos.imp], xList];
xList ←
CONS [
[[x1: vPoly.x1-depletionOverlap, x2: vPoly.x2+depletionOverlap, y1: vPoly.y1-depletionOverlap, y2: eDrain.y2+depletionOverlap],
NMos.imp], xList];
END;
};
Flatten a pullup transistor
PullUp: TransistorFlattenProc = {
size: CD.Position = CDBasics.SizeOfRect[obj.bbox];
class: NMosTransistors.TransistorPtr = NARROW [obj.specific];
middleX: CD.Number = size.x/2;
metal:
CD.Rect =
[x1: middleX-2*lambda, y1: middleX+2*lambda, x2: middleX+2*lambda, y2: size.y];
contact:
CD.Rect =
[x1: metal.x1+lambda, x2: metal.x2-lambda, y1: metal.y1+lambda, y2: metal.y2-lambda];
hPoly: CD.Rect = [x1: 0, x2: size.x, y1: class.lExt, y2: class.lExt+class.length];
gList ← CONS [[hPoly, NMos.pol], gList];
gList ← CONS [[contact, NMos.cut], gList];
dList ← CONS [[metal, NMos.met], dList];
dList ← CONS [[contact, NMos.cut], dList];
dList ← CONS [[[x1: metal.x1, x2: metal.x2, y1: hPoly.y2, y2: metal.y2], obj.layer], dList];
sList ← CONS [[[x1: class.wExt, x2: class.wExt+class.width, y1: 0, y2: hPoly.y1], obj.layer], sList];
xList ← CONS [[[x1: 0, x2: hPoly.x2, y1: 0, y2: size.y-lambda], NMos.imp], xList];
};
Initialization
InitContact:
PROC [className:
ATOM] = {
class: CD.ObjectClass = CD.FetchObjectClass[className, NMos.nmos];
CDProperties.PutProp[class, mode.extractProcProp, $ExtractAtomic];
};
InitTransistor:
PROC [className:
ATOM, flattenProc: TransistorFlattenProc] = {
class: CD.ObjectClass = CD.FetchObjectClass[className, NMos.nmos];
CDProperties.PutProp[class, mode.extractProcProp, $NMosExtractTransistor];
CDProperties.PutProp[class, $TransistorFlatten, NEW [TransistorFlattenProc ← flattenProc]];
};
Registering extract procs
Sinix.RegisterExtractProc[$NMosExtractTransistor, ExtractTransistor];
Cells, Abuts
CDProperties.PutProp[CDCells.pCellClass, mode.extractProcProp, $ExtractCell];
We could do hand-crafted contacts by calling ExtractCell or ExtractAtomic depending on some property
CDProperties.PutProp[PWObjects.abutXClass, mode.extractProcProp, $ExtractAbut];
CDProperties.PutProp[PWObjects.abutYClass, mode.extractProcProp, $ExtractAbut];
Pins
CDProperties.PutProp[CDSymbolicObjects.pinClass, mode.extractProcProp, $ExtractPin];
CDProperties.PutProp[CDSymbolicObjects.segmentClass, mode.extractProcProp, $ExtractPin];
CDProperties.PutProp[CDSymbolicObjects.markClass, mode.extractProcProp, $ExtractPin];
Rectangles
CDProperties.PutProp[CDRects.bareRectClass, mode.extractProcProp, $ExtractRect];
Contacts
InitContact[$NMosContactDifAndPol];
InitContact[$NMosContactBut];
InitContact[$NMosBurContact];
InitContact[$NMosMmContact];
Transistors
InitTransistor[$NMosTransistor, RegularTransistor];
InitTransistor[$NMosATransistor, AngleTransistor];
InitTransistor[$NMosPullUp, PullUp];
Texts
CDProperties.PutProp[CDTexts.rigidTextClass, mode.extractProcProp, $ExtractNull];
CDProperties.PutProp[CDTexts.flipTextClass, mode.extractProcProp, $ExtractNull];
Highlight for this technology
SinixOps.RegisterDefaultLayoutMode[mode, NMos.nmos];
END.