NMosSpinifex.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Written by Shand, September 12, 1983 11:40 pm
Last Edited by: Shand, September 2, 1984 5:42:21 pm PDT
DIRECTORY
CD USING [lambda, Rect, DesignNumber, DesignPosition, DesignRect, Level, ObjectProcs, FetchObjectProcs, ApplicationPtr, highLightError, Error],
CDObjectProcs USING [RegisterFurther, StoreFurther],
CDInline USING [RectAt],
CDProperties USING [PutPropOnTechnology],
TerminalIO USING [WriteRope],
NMos USING [nmos, dif, pol, met, ovg, cut],
NMosTransistors USING [TransistorPtr, enhancement, strongDepletion],
NMosContacts USING [ContactPtr],
IO USING [PutRope, Put, PutF, char, int, rope],
Rope USING [Cat, ROPE],
SpinifexAtoms USING [ spinifex, thymePrint, rosePrint],
SpinifexCircuit USING [Circuit, NodeLinkage, CircuitNode, CircuitConstraint, ConstraintResolution, SpinifexLayerIndex, TechHandle, MapRec, ConversionProc, AddRect, AddBox, CreateLinkage, LinkageAttach, IllegalConstruct, RectDelta, GeometricRule, SpinifexConstraintIndex, spaceIndex, nodeIndex, AttachedNode, AdjustNode, MergeNode],
SpinifexOutput USING [LinkagePrintProc],
SpinifexExtras USING [ProcessMosTransistor, PerDrawRectProc, SWNGrow, NESGrow, WNEGrow, ESWGrow, ReportDifProc]
;
NMosSpinifex: CEDAR PROGRAM
IMPORTS NMos, CD, CDObjectProcs, TerminalIO, CDInline, CDProperties, IO, Rope, SpinifexAtoms, SpinifexCircuit, SpinifexExtras
~ BEGIN
l: CD.DesignNumber ~ CD.lambda;
-- New Regime Transistor converters (IE the Shand unified xstr representaion)
ConvertNMosTransistor: SpinifexCircuit.ConversionProc
-- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF ] -- ~ {
p: NMosTransistors.TransistorPtr = NARROW[appl.ob.specificRef];
size: CD.DesignPosition ← appl.ob.size;
xstr: REF SpinifexCircuit.NodeLinkage;
gateNode, sourceNode, drainNode, metNode: REF SpinifexCircuit.CircuitNode;
polExt: CD.DesignNumber ~ IF p.pullup THEN MIN[ (size.x-contactWidth)/2, p.wExt] ELSE p.wExt;
IF p.bendList = NIL THEN { -- Oh this is easy!
IF ~ p.angle
THEN {
-- Oh this is easy!
-- Add poly boxes
gateNode ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[0, p.lExt, polExt, p.lExt+p.length], appl~appl, pos~ pos, orient~ orient, interestBloat~SpinifexExtras.SWNGrow[polSep]];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[polExt, p.lExt, size.x-polExt, p.lExt+p.length], appl~appl, pos~ pos, orient~ orient, value~gateNode];
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[size.x-polExt, p.lExt, size.x, p.lExt+p.length], appl~appl, pos~ pos, orient~ orient, interestBloat~SpinifexExtras.NESGrow[polSep], value~gateNode];
-- Add rects for poly exclusion
IF p.lExt-difToPolSep > 0
THEN {
-- At the top
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[polExt, p.lExt+p.length+difToPolSep, size.x-polExt, size.y], appl~appl, pos~ pos, orient~ orient,
interestBloat~SpinifexExtras.WNEGrow[ difToPolExtSep],
value~excludePol];
-- ... and the bottom
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[p.wExt, 0, size.x-p.wExt, p.lExt-difToPolSep], appl~appl, pos~ pos, orient~ orient, interestBloat~SpinifexExtras.ESWGrow[ difToPolExtSep],
value~excludePol]
};
-- Add rects for channel lead-in.
-- At the top
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[polExt, p.lExt+p.length, size.x-polExt, p.lExt+p.length+difToPolSep], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
-- ... and the bottom
[] ← cir.AddBox[ spinifexLayer~polSpinifex, dim~[p.wExt, p.lExt-difToPolSep, size.x-p.wExt, p.lExt], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
-- Fill channel gap
[] ← cir.AddBox[ spinifexLayer~difSpinifex, dim~[p.wExt, p.lExt, size.x-p.wExt, p.lExt+p.length], appl~appl, pos~ pos, orient~ orient, value~difChannel];
IF polExt < p.wExt THEN [] ← cir.AddBox[ spinifexLayer~difSpinifex, dim~[polExt, p.lExt+p.length-l, size.x-polExt, p.lExt+p.length], appl~appl, pos~ pos, orient~ orient, value~difChannel];
-- Add rects for diff width spacing and connection
sourceNode ← cir.AddBox[ spinifexLayer~difSpinifex, dim~[polExt, p.lExt+p.length, size.x-polExt, size.y], appl~appl, pos~ pos, orient~ orient, interestBloat~SpinifexExtras.WNEGrow[difSep]];
drainNode ← cir.AddBox[ spinifexLayer~difSpinifex, dim~[p.wExt, 0, size.x-p.wExt, p.lExt], appl~appl, pos~ pos, orient~ orient, interestBloat~SpinifexExtras.ESWGrow[difSep]];
IF p.pullup
THEN {
metNode ← cir.AddRect[ lev~NMos.met, dim~[ (size.x-contactWidth)/2, size.y-6*l, (size.x+contactWidth)/2, size.y], appl~appl, pos~ pos, orient~ orient];
}
ELSE metNode ← NIL
}
ELSE {
-- Oh no not a bent transistor yetcchh!
sourceDrainList: LIST OF REF SpinifexCircuit.CircuitNode;
sourceDrainCount: INTEGER;
sourceHint: REF SpinifexCircuit.CircuitNode ← NIL;
NoteSourceHint: SpinifexExtras.ReportDifProc ~ {
sourceHint ← difNode
};
[gateNode, sourceDrainList, sourceDrainCount] ← SpinifexExtras.ProcessMosTransistor[appl, pos, orient, cir, difSpinifex, polSpinifex, difChannel, channelEdge, difToPolSep, MapMaterial, cir, NoteSourceHint];
IF sourceDrainCount = 2
THEN {
sourceNode ← sourceDrainList.first;
drainNode ← sourceDrainList.rest.first;
IF p.pullup
THEN {
SELECT sourceHint
FROM
sourceNode => NULL;
drainNode => {
drainNode ← sourceNode;
sourceNode ← sourceHint
};
ENDCASE => ERROR -- Including case when sourceHint = NIL
}
}
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
}
};
-- Add Linkages for transistor.
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, size.y*p.length, (size.y+p.length)*2, absolute];
SpinifexCircuit.AdjustNode[ sourceNode, difSpinifex, (size.y-(p.lExt+p.length))*(size.x-2*polExt), (size.y-(p.lExt+p.length))*2 + size.x-2*polExt, absolute]; -- Ignore perim leading into channel.
SpinifexCircuit.AdjustNode[ drainNode, difSpinifex, p.lExt*p.width, 2*p.lExt + p.width, absolute]; -- Ignore perim leading into channel.
IF p.pullup
THEN {
cir.MergeNode[ gateNode, sourceNode]; sourceNode ← gateNode;
cir.MergeNode[ gateNode, metNode]; metNode ← gateNode;
};
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
NMos.dif => RETURN [diffusion];
NMos.pol => RETURN [polysilicon];
NMos.met => {
[] ← cir.AddRect[ lev~ NMos.met, dim~ r];
RETURN [nothing];
};
NMos.cut => {
RETURN [postProcess];
};
ENDCASE => RETURN [nothing];
};
-- Contact converters
ConvertNMosContactDifAndPol: SpinifexCircuit.ConversionProc
-- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SpinifexCircuit
.Circuit
] -- ~ {
box: CD.Rect ← CDInline.RectAt[pos~[0,0], size~appl.ob.size];
node: REF SpinifexCircuit.CircuitNode;
node ← cir.AddRect[ lev~NMos.met, dim~box, appl~appl, pos~ pos, orient~ orient];
[] ← cir.AddRect[ lev~appl.ob.level, dim~box, appl~appl, pos~ pos, orient~ orient, value~node];
};
ConvertNMosButtingContact: SpinifexCircuit.ConversionProc
-- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SpinifexCircuit.Circuit
] -- ~ {
rimWidth: CD.DesignNumber ~ l;
polSize: CD.DesignNumber ~ appl.ob.size.y/2;
box: CD.Rect ← CDInline.RectAt[pos~[0,0], size~appl.ob.size];
node: REF SpinifexCircuit.CircuitNode;
node ← cir.AddRect[ lev~NMos.met, dim~box, appl~appl, pos~ pos, orient~ orient];
[] ← cir.AddRect[ lev~NMos.pol, dim~[0,0, appl.ob.size.x, polSize], appl~appl, pos~ pos, orient~ orient, value~node];
-- Add rect for poly exclusion
[] ← cir.AddBox[ spinifexLayer~polSpinifex,
dim~[-rimWidth,polSize, appl.ob.size.x+rimWidth, polSize+difToPolSep], appl~appl, pos~ pos, orient~ orient, value~channelEdge];
[] ← cir.AddBox[ spinifexLayer~polSpinifex,
dim~[-rimWidth,polSize-rimWidth, 0, polSize], appl~appl, pos~ pos, orient~ orient, value~polXorDif];
[] ← cir.AddBox[ spinifexLayer~polSpinifex,
dim~[appl.ob.size.x,polSize-rimWidth, appl.ob.size.x+rimWidth, polSize], appl~appl, pos~ pos, orient~ orient, value~polXorDif];
[] ← cir.AddBox[ spinifexLayer~polSpinifex,
dim~[0,polSize+difToPolSep, appl.ob.size.x, appl.ob.size.y], appl~appl, pos~ pos, orient~ orient,
interestBloat~SpinifexExtras.WNEGrow[ difToPolExtSep],
value~excludePol];
-- Add rect for diff width spacing and connection
[] ← cir.AddBox[ spinifexLayer~difSpinifex,
dim~[0,polSize, appl.ob.size.x, appl.ob.size.y], appl~appl, pos~ pos, orient~ orient,
interestBloat~[ difSep, difSep, difSep, difSep], value~node];
};
ConvertNMosBuriedContact: SpinifexCircuit.ConversionProc
-- [appl: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, cir: REF SpinifexCircuit
.Circuit
] -- ~ {
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;
cp: NMosContacts.ContactPtr ~ NARROW[appl.ob.specificRef];
node: REF SpinifexCircuit.CircuitNode ~ cir.AddRect[ lev~NMos.pol, dim~[2*l, cp.lExt, s.x-cp.wExt, s.y-cp.lExt], appl~appl, pos~ pos, orient~ orient];
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~polSpinifex, dim~[2*l, lex, s.x-wex, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~polAndDif];
[] ← cir.AddBox[ spinifexLayer~difSpinifex, dim~[2*l, lex, s.x-wex, s.y-lex], appl~appl, pos~ pos, orient~ orient, value~node];
};
cp.lExt < 2*
l
AND cp.wExt >= 2*
l => {
Polysilicon/Diffusion Crossing.
lex: CD.DesignNumber ~ MAX[cp.lExt+l, 2*l];
[] ← cir.AddBox[ spinifexLayer~difSpinifex, 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~difSpinifex, 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;
};
RoseNMosTransistor: 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: NMosTransistors.TransistorPtr ~ NARROW[ linkage.source.ob.specificRef];
stream.Put[ IO.rope["(C "], IO.rope[name], IO.rope[" \"Transistor[strength: drive, positive: TRUE, mode: "]];
stream.PutRope[
IF p.pullup
THEN "Depletion"
ELSE
SELECT linkage.source.ob.level
FROM
NMosTransistors.enhancement => "Enhancement",
NMosTransistors.strongDepletion => "Depletion",
ENDCASE => "UNKNOWN"
];
stream.Put[
IO.rope[", unidirectional: UNKNOWN, biased: FALSE, offStrength: "],
IO.rope[
IF p.pullup
THEN "weak"
ELSE
SELECT linkage.source.ob.level
FROM
NMosTransistors.enhancement => "none",
NMosTransistors.strongDepletion => "weak",
ENDCASE => "UNKNOWN"],
IO.rope["]\""]
];
PrintAttachment[ $Gate, "gate"];
PrintAttachment[ $Source, "in"];
PrintAttachment[ $Drain, "out"];
stream.PutRope[ ")"]
};
ThymeNMosTransistor: SpinifexOutput.LinkagePrintProc
--
[ stream: IO.STREAM, linkage: REF NodeLinkage, 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: NMosTransistors.TransistorPtr ~ NARROW[ linkage.source.ob.specificRef];
defaultW: INTEGER ~ 2*l;
defaultL: INTEGER ~ 2*l;
stream.Put[ IO.rope[name], IO.rope[": "]];
stream.PutRope[
IF ~p.pullup
THEN
SELECT p.implant
FROM
NMosTransistors.enhancement => "ETrans[",
NMosTransistors.strongDepletion => "DTrans[",
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[ "];"];
};
-- Module Initialization
nMosHandle: REF SpinifexCircuit.TechHandle;
difSpinifex: SpinifexCircuit.SpinifexLayerIndex ~ 0;
polSpinifex: SpinifexCircuit.SpinifexLayerIndex ~ 1;
metSpinifex: SpinifexCircuit.SpinifexLayerIndex ~ 2;
-- These numbers are halved (sorry about any confusion this may cause)
difSep: CD.DesignNumber~3*l/2;
difToPolExtSep: CD.DesignNumber~0;
polSep: CD.DesignNumber~l;
metSep: CD.DesignNumber~3*l/2;
difToPolSep: CD.DesignNumber~difToPolExtSep+polSep; -- not halved!
contactWidth: CD.DesignNumber~4*l;
CircuitConstraint: TYPE ~ SpinifexCircuit.CircuitConstraint;
excludePol: REF CircuitConstraint;
polXorDif: REF CircuitConstraint;
polAndDif: REF CircuitConstraint;
channelEdge: REF CircuitConstraint;
difChannel: REF CircuitConstraint;
polDifError: REF CircuitConstraint;
Init:
PROCEDURE ~ {
ObjConverter:
PROCEDURE [objectType:
ATOM, conv: SpinifexCircuit.ConversionProc, thyme: SpinifexOutput.LinkagePrintProc ←
NIL, rose: SpinifexOutput.LinkagePrintProc ←
NIL] ~ {
op: REF CD.ObjectProcs;
IF (op←CD.FetchObjectProcs[ objectType~objectType, technology~NMos.nmos]) = NIL THEN ERROR;
CDObjectProcs.StoreFurther[ p~op, key~SpinifexAtoms.spinifex, value~ NEW[SpinifexCircuit.ConversionProc𡤌onv]];
IF thyme #
NIL
THEN
CDObjectProcs.StoreFurther[ p~op, key~SpinifexAtoms.thymePrint, value~ NEW[SpinifexOutput.LinkagePrintProc←thyme]];
IF rose #
NIL
THEN
CDObjectProcs.StoreFurther[ p~op, key~SpinifexAtoms.rosePrint, value~ NEW[SpinifexOutput.LinkagePrintProc←thyme]];
};
GeometricRule: TYPE ~ SpinifexCircuit.GeometricRule;
difSpacingRule, difWidthRule: REF GeometricRule;
polSpacingRule, polWidthRule, polDifSepRuleA, polDifSepRuleB, polOverDifRule: REF GeometricRule;
metSpacingRule, metWidthRule: REF GeometricRule;
TriggerMap: TYPE ~ PACKED ARRAY SpinifexCircuit.SpinifexConstraintIndex OF BOOLEAN ← ALL[FALSE];
spaceRuleTrigger: TriggerMap;
widthRuleTrigger: TriggerMap;
polOverDifTrigger1, polOverDifTrigger2, polDifSepTrigger1, polDifSepTrigger2: TriggerMap;
difSpaceTrigger1: TriggerMap;
polWidthTrigger: TriggerMap;
-- Layer Constraints.
difChannel ← NEW[ CircuitConstraint ← [ $DifChannel, 2]];
channelEdge ← NEW[ CircuitConstraint ← [ $ChannelEdge, SpinifexCircuit.spaceIndex]];
excludePol ← NEW[ CircuitConstraint ← [ $ExcludePol, 2]];
polXorDif ← NEW[ CircuitConstraint ← [ $PolXorDif, SpinifexCircuit.spaceIndex]];
polAndDif ← NEW[ CircuitConstraint ← [ $polAndDif, SpinifexCircuit.nodeIndex]];
polDifError ← NEW[ CircuitConstraint ← [ $PolDifError, 3]];
excludePol.withNode ← channelEdge.withNode ← polDifError.withNode ← polDifError;
channelEdge.withConstraint ← LIST[ [excludePol, channelEdge]];
polDifError.withConstraint ← LIST[ [excludePol, polDifError], [channelEdge, polDifError]];
polXorDif.withConstraint ← LIST[ [excludePol, channelEdge]];
polAndDif.withNode ← polAndDif;
polAndDif.withConstraint ← LIST[ [excludePol, polAndDif], [polXorDif, polAndDif], [polDifError, polAndDif], [channelEdge, polAndDif]];
-- Basic nMosHandle & cdLayerMappings.
nMosHandle ← NEW[SpinifexCircuit.TechHandle ← [ errorLevel~CD.highLightError, numSpinifexLayers~3, layerInterestBloat~[difSep,polSep,metSep,,,,,]] ];
nMosHandle.illegalLevel[NMos.dif] ← FALSE;
nMosHandle.illegalLevel[NMos.pol] ← FALSE;
nMosHandle.illegalLevel[NMos.met] ← FALSE;
nMosHandle.illegalLevel[NMos.ovg] ← FALSE;
nMosHandle.cdLayerMapping[NMos.dif] ← LIST[ [difSpinifex,difSep], [polSpinifex,difToPolExtSep,excludePol]];
nMosHandle.cdLayerMapping[NMos.pol] ← LIST[ [polSpinifex,polSep]];
nMosHandle.cdLayerMapping[NMos.met] ← LIST[ [metSpinifex,metSep]];
CDProperties.PutPropOnTechnology[onto~ NMos.nmos, prop~SpinifexAtoms.spinifex, val~nMosHandle];
-- Thyme stray capacitance layer names.
nMosHandle.spinifexLayerNames[difSpinifex].thymeName ← "D";
nMosHandle.spinifexLayerNames[polSpinifex].thymeName ← "P";
nMosHandle.spinifexLayerNames[metSpinifex].thymeName ← "M";
-- Geometric rule triggers.
spaceRuleTrigger[SpinifexCircuit.nodeIndex] ← TRUE;
widthRuleTrigger[SpinifexCircuit.spaceIndex] ← TRUE;
Corners are defined by union of dif and gate, but checking only looks at dif
difSpaceTrigger1[SpinifexCircuit.nodeIndex] ← TRUE;
difSpaceTrigger1[2] ← TRUE;
polWidthTrigger[SpinifexCircuit.spaceIndex] ← TRUE;
polWidthTrigger[2] ← TRUE;
polDifSepTrigger1[ SpinifexCircuit.nodeIndex] ← TRUE;
polDifSepTrigger2[ excludePol.index] ← TRUE;
-- What follows is a real hack! Purely local errors are not handled in a natural manner by my scheme, so for every corner we find in polDifError we generate an error if there is anything on any layer nearby, of course there is always something so we get our error.
polOverDifTrigger1[ polDifError.index] ← TRUE;
polOverDifTrigger2 ← ALL[TRUE];
-- The geometric rules.
difSpacingRule ← NEW[ GeometricRule ← [extent~3*l, message~"Diffusion spacing", okIfConnected~TRUE, trigger1~difSpaceTrigger1, trigger2~spaceRuleTrigger]];
difWidthRule ← NEW[ GeometricRule ← [extent~2*l, message~"Diffusion width", trigger1~widthRuleTrigger, trigger2~widthRuleTrigger]];
polSpacingRule ← NEW[ GeometricRule ← [extent~2*l, message~"Poly spacing", okIfConnected~TRUE, trigger1~spaceRuleTrigger, trigger2~spaceRuleTrigger]];
polWidthRule ← NEW[ GeometricRule ← [extent~2*l, message~"Poly width", trigger1~polWidthTrigger, trigger2~polWidthTrigger]];
polDifSepRuleA ← NEW[ GeometricRule ← [extent~l, message~"Poly/Diffusion spacing[debug:A]", trigger1~polDifSepTrigger1, trigger2~polDifSepTrigger2]];
polDifSepRuleB ← NEW[ GeometricRule ← [extent~l, message~"Poly/Diffusion spacing[debug:B]", trigger1~polDifSepTrigger2, trigger2~polDifSepTrigger1]];
polOverDifRule ← NEW[ GeometricRule ← [extent~l, message~"Poly over Diffusion", trigger1~polOverDifTrigger1, trigger2~polOverDifTrigger2]];
metSpacingRule ← NEW[ GeometricRule ← [extent~3*l, message~"Metal spacing", okIfConnected~TRUE, trigger1~spaceRuleTrigger, trigger2~spaceRuleTrigger]];
metWidthRule ← NEW[ GeometricRule ← [extent~3*l, message~"Metal width", trigger1~widthRuleTrigger, trigger2~widthRuleTrigger]];
nMosHandle.rules[ difSpinifex] ← LIST[difSpacingRule, difWidthRule];
nMosHandle.rules[ polSpinifex] ← LIST[polSpacingRule, polWidthRule, polDifSepRuleA, polDifSepRuleB, polOverDifRule];
nMosHandle.rules[ metSpinifex] ← LIST[metSpacingRule, metWidthRule];
-- Technology specific objects.
CDObjectProcs.RegisterFurther[key~SpinifexAtoms.spinifex, technology~NMos.nmos ! CD.Error => IF ec = doubleRegistration THEN CONTINUE];
CDObjectProcs.RegisterFurther[key~SpinifexAtoms.thymePrint, technology~NMos.nmos ! CD.Error => IF ec = doubleRegistration THEN CONTINUE];
CDObjectProcs.RegisterFurther[key~SpinifexAtoms.rosePrint, technology~NMos.nmos ! CD.Error => IF ec = doubleRegistration THEN CONTINUE];
ObjConverter[ objectType~$NMosTransistor, conv~ConvertNMosTransistor, thyme~ThymeNMosTransistor, rose~RoseNMosTransistor];
ObjConverter[ objectType~$NMosATransistor, conv~ConvertNMosTransistor, thyme~ThymeNMosTransistor, rose~RoseNMosTransistor];
ObjConverter[ objectType~$NMosPullUp, conv~ConvertNMosTransistor, thyme~ThymeNMosTransistor, rose~RoseNMosTransistor];
ObjConverter[ objectType~$NMosContactDifAndPol, conv~ConvertNMosContactDifAndPol];
ObjConverter[ objectType~$NMosContactBut, conv~ConvertNMosButtingContact];
ObjConverter[ objectType~$NMosBurContact, conv~ConvertNMosBuriedContact];
};
Init[];
TerminalIO.WriteRope["nMos technology parameters Loaded\n"];
END.