-- File CIFExtNMOS.mesa
-- Written by Dan Fitzpatrick and Martin Newell, June 1980
-- Last updated: December 21, 1981 3:55 PM by DF

DIRECTORY

CIFDevicesDefs: FROM "CIFDevicesDefs" USING [LENGTHLayerArray, LookupLayer],
CIFExtDictDefs: FROM "CIFExtDictDefs" USING [InitDictionary],
CIFExtIODefs: FROM "CIFExtIODefs" USING [OpenFile,CloseStream,DeleteFile],
CIFExtNMOS2Defs: FROM "CIFExtNMOS2Defs",
CIFExtNMOSDefs: FROM "CIFExtNMOSDefs",
CIFExtScanDefs: FROM "CIFExtScanDefs" USING [In, XatY, EdgeLength, Edge],
CIFExtUtilsDefs: FROM "CIFExtUtilsDefs" USING [
--DrawString, -- DrawNumber, WriteLongDecimal, Tag],
IODefs: FROM "IODefs" USING [
WriteString, WriteLine, GetOutputStream, SetOutputStream],
MergeDefs: FROM "MergeDefs" USING [InitMerge, FinishMerge, ConsolidateMerge],
Real: FROM "Real" USING [Fix],
SystemDefs: FROM "SystemDefs" USING [AllocateHeapString, FreeHeapString],
StreamDefs: FROM "StreamDefs" USING [StreamHandle, DiskHandle],
StringDefs: FROM "StringDefs" USING [AppendString];

CIFExtNMOS: PROGRAM
IMPORTS
CIFExtNMOS2Defs, CIFDevicesDefs, CIFExtDictDefs, CIFExtIODefs, CIFExtScanDefs,
CIFExtUtilsDefs, IODefs, MergeDefs, Real, SystemDefs, StringDefs
EXPORTS CIFExtNMOSDefs =

BEGIN
OPEN CIFExtNMOS2Defs, CIFDevicesDefs, CIFExtDictDefs, CIFExtIODefs,
CIFExtScanDefs, CIFExtUtilsDefs, IODefs, MergeDefs, Real, SystemDefs,
StreamDefs, StringDefs;

deplNodeList, enhaNodeList, diffNodeList: NodeSegment; -- place holders in their respective node lists

InitNMOS: PUBLIC PROCEDURE [str: STRING] =
BEGIN
ErrorFlag ← FALSE;
BaseFileName.length ← 0;
AppendString[BaseFileName, str];
InitMerge["Merge.tmp$"];
TransistorFile ← OpenFile["CIFExtractor.tmp$",’w];
CapacitorFile ← OpenFile["CIFExtractor.tmp2$",’w];
NodeFile ← OpenFile["CIFNodes.tmp$",’w];
LabelNodeFile ← OpenFile["CIFLabelNode.tmp$",’w];
errorStream ← OpenFile[Tag[BaseFileName, "extlog"],’w];
out1 ← OpenFile[Tag[BaseFileName, "sim"],’w];
newNodeList ← oldNodeList ← NodeList ← ALL[NIL];
NodeNumber ← LOOPHOLE[LONG[0]];
depl ← LookupLayer[[’G, ’A, ’T, ’D]];
enha ← LookupLayer[[’G, ’A, ’T, ’E]];
LabelList ← NIL;
-- Get the scale factor to convert from screen to CIF co-ordinates without translation
--kludge for now - expect scale to be unity
Scale ← 1;
END;

FinishNMOS: PUBLIC PROCEDURE =
BEGIN
InitSwath[YCurr, YCurr]; -- Done twice to free node segements created on last
InitSwath[YCurr, YCurr]; -- valid pass.
NodeFile.destroy[NodeFile];
OutputTransistors[]; -- Write out all the transistors
CloseStream[TransistorFile];
CloseStream[CapacitorFile];
CloseStream[LabelNodeFile];
-- End of extraction

-- Start second phase: looking up node numbers for new values, replacing node numbers
-- with their coresponding label, if any
WriteLine["Extraction Phase Complete --- Creating Output Files"];
ConsolidateMerge[];
InitDictionary[];
CorrectLabelNodes[Tag[BaseFileName, "al"]];
-- deletes CIFLabelNode.tmp$
DeleteFile["CIFNodes.tmp$"];

-- Save standard output stream and Set output stream to file FileName
defaultStream ← GetOutputStream[];
SetOutputStream[out1];
ConvertTransToText[out1];
-- deletes CIFExtractor.tmp2$
DeleteFile["CIFExtractor.tmp$"];

-- Restore standard output stream
SetOutputStream[defaultStream];
CloseStream[out1];

-- Free the storage consumed by transistors
ReleaseTransistors[];
FinishMerge[];

-- Print out statisics on how much dynamic memory has not been freed
PrintAllocation[FALSE];

--Print the total number of transistors extracted
PrintTransistors[];
SetErrorStream[FALSE];
PrintTransistors[];
ResetErrorStream[];
CloseStream[errorStream];
WriteString["Simulation file is "];
WriteString[BaseFileName];
WriteString[".sim and node names are in "];
WriteString[BaseFileName];
WriteLine[".nodes"];
IF AliasFlag THEN {
WriteString["alias file is "];
WriteString[BaseFileName];
WriteLine[".al"];
};
IF ErrorFlag THEN {
WriteString["errors recorded on "];
WriteString[BaseFileName];
WriteLine[".extlog"];
};
END;

NameNMOS: PUBLIC PROCEDURE [name: STRING, x, y: REAL, layer:CARDINAL] =
BEGIN
label: NodeLabel ← AllocateNodeLabel[];
label.label ← AllocateHeapString[name.length];
NoAllocString ← NoAllocString + 1;
AppendString[label.label, name];
label.x ← x;
label.y ← y;
label.layer ← layer;
label.used ← FALSE;
label.next ← LabelList;
LabelList ← label;
END;

InitSwath: PUBLIC PROCEDURE [prev, curr: REAL] =
BEGIN
node: NodeSegment;
label, next: NodeLabel;
tranSeg, diffSeg, polySeg, metalSeg, cutSeg, lastDiffSeg, lastPolySeg:
NodeSegment;
i: CARDINAL;
YCurr ← curr;
YPrev ← prev;
-- the following statements mark the progression of the program on the screen
scanCount ← scanCount + 1;
IF scanCount > 100 THEN
BEGIN
DrawNumber[1, LOOPHOLE[LONG[displayCount]], 200, YCurr];
displayCount ← displayCount + 1;
scanCount ← 1;
END;

FOR i IN [0..LENGTHLayerArray) DO
-- Free old nodes
FOR node ← oldNodeList[i], oldNodeList[i] UNTIL node = NIL DO
oldNodeList[i] ← node.next;
IF node.mark THEN WriteNodeCap[node, CapacitorFile];
FreeNodeSegment[node];
ENDLOOP;

-- Set new nodes to current
oldNodeList[i] ← NodeList[i] ← newNodeList[i];
newNodeList[i] ← NIL;
ptrnewNodeList[i] ← @newNodeList[i];
ENDLOOP;
diffNodeList ← NodeList[diff];
deplNodeList ← NodeList[depl];
enhaNodeList ← NodeList[enha];

-- since both diffNodeList & NodeList[diff] march through the node list
-- it is necessary to delay freeing the nodes till now, that is the reason
-- for having oldNodeList

-- Free old labels
next ← LabelList;
LabelList ← NIL;
FOR label ← next, next UNTIL label = NIL DO
next ← label.next;
IF label.y < YPrev THEN
BEGIN
IF NOT label.used THEN
BEGIN
SetErrorStream[TRUE];
WriteFloat[label.x];
WriteString[" "];
WriteFloat[label.y];
WriteString[" The name ’"];
WriteString[label.label];
WriteLine["’ does not correspond to any node"];
ResetErrorStream[];
END;
FreeHeapString[label.label];
NoAllocString ← NoAllocString - 1;
FreeNodeLabel[label];
END
ELSE BEGIN label.next ← LabelList; LabelList ← label; END;
ENDLOOP;

diffSeg ← NodeList[diff];
lastPolySeg ← NodeList[poly];
-- Scan for Transistors
FOR tranSeg ← NodeList[depl], tranSeg.next UNTIL tranSeg = NIL DO
FOR diffSeg ← diffSeg, diffSeg.next UNTIL diffSeg = NIL
OR diffSeg.right >= tranSeg.left DO ENDLOOP;
WITH t: tranSeg SELECT TRUE FROM
TRUE =>
BEGIN
IF diffSeg # NIL AND diffSeg.right = t.left THEN
BEGIN
SetDiff[NodeToTransistor[t.number], diffSeg.number, t.leftLength];
diffSeg ← diffSeg.next;
END;
IF diffSeg # NIL AND diffSeg.left = t.right THEN
BEGIN
SetDiff[NodeToTransistor[t.number], diffSeg.number, t.rightLength];
END;
END;
ENDCASE;
-- Poly cannot end inside a transistor
FOR polySeg ← lastPolySeg, polySeg.next UNTIL polySeg = NIL
OR tranSeg.right <= polySeg.right DO ENDLOOP;
SetPoly[NodeToTransistor[tranSeg.number], polySeg.number];
ENDLOOP;
diffSeg ← NodeList[diff];
lastPolySeg ← NodeList[poly];
FOR tranSeg ← NodeList[enha], tranSeg.next UNTIL tranSeg = NIL DO
FOR diffSeg ← diffSeg, diffSeg.next UNTIL diffSeg = NIL
OR diffSeg.right >= tranSeg.left DO ENDLOOP;
WITH t: tranSeg SELECT TRUE FROM
TRUE =>
BEGIN
IF diffSeg # NIL AND diffSeg.right = t.left THEN
BEGIN
SetDiff[NodeToTransistor[t.number], diffSeg.number, t.leftLength];
diffSeg ← diffSeg.next;
END;
IF diffSeg # NIL AND diffSeg.left = t.right THEN
BEGIN
SetDiff[NodeToTransistor[t.number], diffSeg.number, t.rightLength];
END;
END;
ENDCASE;
-- Poly cannot end inside a transistor
FOR polySeg ← lastPolySeg, polySeg.next UNTIL polySeg = NIL
OR tranSeg.right <= polySeg.right DO ENDLOOP;
SetPoly[NodeToTransistor[tranSeg.number], polySeg.number];
ENDLOOP;

-- Connect nodes through contact cuts
lastDiffSeg ← NodeList[diff];
lastPolySeg ← NodeList[poly];
metalSeg ← NodeList[metal];
FOR cutSeg ← NodeList[contact], cutSeg.next UNTIL cutSeg = NIL DO
FOR metalSeg ← metalSeg, metalSeg.next UNTIL metalSeg = NIL
OR cutSeg.right <= metalSeg.right DO ENDLOOP;
IF metalSeg = NIL OR cutSeg.left < metalSeg.left THEN
BEGIN
SetErrorStream[TRUE];
WriteLongDecimal[Fix[cutSeg.left]];
WriteString[", "];
WriteLongDecimal[Fix[YPrev]];
WriteLine[" Metal doesn’t surround contact cut"];
ResetErrorStream[];
LOOP;
END;
FOR diffSeg ← lastDiffSeg, diffSeg.next UNTIL diffSeg = NIL
OR cutSeg.left <= diffSeg.right DO ENDLOOP;
lastDiffSeg ← diffSeg;
FOR diffSeg ← diffSeg, diffSeg.next UNTIL diffSeg = NIL
OR cutSeg.right < diffSeg.left DO
Combine[metalSeg, diffSeg, metal]; lastDiffSeg ← diffSeg; ENDLOOP;
FOR polySeg ← lastPolySeg, polySeg.next UNTIL polySeg = NIL
OR cutSeg.left < polySeg.right DO ENDLOOP;
lastPolySeg ← polySeg;
FOR polySeg ← polySeg, polySeg.next UNTIL polySeg = NIL
OR cutSeg.right < polySeg.left DO
Combine[metalSeg, polySeg, metal]; lastPolySeg ← polySeg; ENDLOOP;
ENDLOOP;

-- Connect nodes through buried contacts
-- only affected nodes are those on poly and diffusion
-- Since diffusion overlaps poly only in buried contact region
-- there is no need to look at the buried layer
IF gotBuried THEN
BEGIN
-- don’t need to do following if there are no buried contacts
polySeg ← NodeList[poly];
FOR diffSeg ← NodeList[diff], diffSeg.next UNTIL diffSeg = NIL DO
-- skip all poly left of diffusion region
WHILE polySeg # NIL AND polySeg.right <= diffSeg.left DO
polySeg ← polySeg.next; ENDLOOP;
-- merge all poly that properly intersect the diffusion region
IF polySeg # NIL AND polySeg.left < diffSeg.right THEN {
polySegExtra: NodeSegment ← polySeg;
WHILE polySegExtra # NIL AND polySegExtra.left < diffSeg.right DO
Combine[polySegExtra, diffSeg, poly];
polySegExtra ← polySegExtra.next;
ENDLOOP;
};
ENDLOOP;
END; -- done with buried layer
trapleft ← ALL[NIL];
gotBuried ← FALSE;
END;

StartTrap: PUBLIC PROCEDURE [eleft: Edge, layer: CARDINAL] =
BEGIN
IF eleft = NIL THEN WriteLine["StartTrap called with NIL value for eleft"];
SELECT layer FROM
poly =>
BEGIN
IF In[diff] AND NOT In[buried] THEN
BEGIN
EndTrap[eleft, diff]; -- end of diffusion
IF In[implant] THEN StartTrap[eleft, depl] -- start of transistor
ELSE StartTrap[eleft, enha];
END;
trapleft[layer] ← eleft;
END;
diff =>
IF In[poly] AND NOT In[buried] THEN
BEGIN
IF In[implant] THEN StartTrap[eleft, depl] -- start of transistor
ELSE StartTrap[eleft, enha];
RETURN; -- do not record start of diffusion
END
ELSE trapleft[layer] ← eleft;
buried =>
BEGIN
trapleft[layer] ← eleft;
IF In[poly] AND In[diff] THEN
BEGIN
IF In[implant] THEN EndTrap[eleft, depl] --end of transistor
ELSE EndTrap[eleft, enha];
StartTrap[eleft, diff];
END;
END;
implant =>
BEGIN
IF In[poly] AND In[diff] AND NOT In[buried] THEN
BEGIN -- transistor is now deplection
EndTrap[eleft, enha]; -- end enhancement
StartTrap[eleft, depl]; -- start deplection
END;
trapleft[layer] ← eleft;
END;
ENDCASE => trapleft[layer] ← eleft;
END;

EndTrap: PUBLIC PROCEDURE [eright: Edge, layer: CARDINAL] =
BEGIN
eleft: Edge ← trapleft[layer];
xleft: REAL ← XatY[eleft, YPrev]; -- only if eleft # NIL
xright: REAL ← XatY[eright, YPrev];
leftTop: REAL ← XatY[eleft, YCurr];
rightTop: REAL ← XatY[eright, YCurr];
LLength: REAL ← EdgeLength[eleft, YCurr, YPrev];
RLength: REAL ← EdgeLength[eright, YCurr, YPrev];
node: NodeNumberType;

Propagate: PROCEDURE =
-- Propagate maintains node numbers
-- The node number is stored in node
BEGIN
nodeSeg, newNodeSeg, nodeSegExtra: NodeSegment;

-- DrawTrap[eleft,YPrev,eright,YCurr,layer]; ** on screen
FOR nodeSeg ← NodeList[layer], NodeList[layer] UNTIL nodeSeg = NIL
OR xleft <= nodeSeg.right DO NodeList[layer] ← nodeSeg.next; ENDLOOP;

--allocate a new node segment for the trapezoid
newNodeSeg ← MakeNodeSegment[
NIL, XatY[eleft, YCurr], XatY[eright, YCurr],
(layer = depl OR layer = enha)];
ptrnewNodeList[layer]↑ ← newNodeSeg;
ptrnewNodeList[layer] ← @newNodeSeg.next;

--establish a node number for the trapezoid
IF nodeSeg = NIL OR xright < nodeSeg.left THEN
BEGIN
node ← GenNodeNumber[layer];
IF layer # depl AND layer # enha

THEN
WITH n: newNodeSeg SELECT FALSE FROM

FALSE =>
BEGIN
-- calculate the area and perimeter for the node
WriteNodeLocation[
node, (xleft + xright)/2, (YPrev + YCurr)/2, layer];
LLength ← EdgeLength[eleft, YCurr, YPrev];
RLength ← EdgeLength[eright, YCurr, YPrev];
n.circumference ← [0.0, 0.0, 0.0, 0.0];
n.area ← [0.0, 0.0, 0.0, 0.0];
n.area[layer] ←
(YCurr -
YPrev)*((xright - xleft) +
((xleft - leftTop) + (rightTop - xright))/2);
n.circumference[layer] ←
(xright - xleft) + (rightTop - leftTop) + LLength + RLength;
n.mark ← TRUE;
END
ENDCASE

ELSE
BEGIN
trans: Transistor ← NodeToTransistor[node];
trans.x ← (xleft + xright)/2;
trans.y ← (YPrev + YCurr)/2;
END;
END
ELSE
BEGIN --propogate from below

-- Adjust Node Segment for common perimeter
IF NOT (layer = depl OR layer = enha) THEN
WITH n2: nodeSeg SELECT FALSE FROM
FALSE =>
n2.circumference[layer] ← n2.circumference[layer] -
2*(MIN[xright,n2.right] - MAX[xleft,n2.left]);
ENDCASE;

FOR nodeSegExtra ← nodeSeg.next, nodeSeg.next UNTIL nodeSegExtra = NIL
OR nodeSegExtra.left > xright DO

-- propagate transistors
IF layer = depl OR layer = enha THEN
BEGIN
trans1: Transistor ← NodeToTransistor[nodeSeg.number];
trans2: Transistor ← NodeToTransistor[nodeSegExtra.number];
trans1.circumference ←
trans1.circumference + trans2.circumference -
(nodeSeg.right - MAX[xleft, nodeSeg.left]);
trans2.circumference ← 0;
END

-- propagate nodes
ELSE
WITH n2: nodeSegExtra SELECT FALSE FROM
FALSE =>
WITH n3: nodeSeg SELECT FALSE FROM

FALSE =>
BEGIN

-- Combine Node Areas
n3.area[diff] ← n2.area[diff] + n3.area[diff];
n3.area[poly] ← n2.area[poly] + n3.area[poly];
n3.area[metal] ← n2.area[metal] + n3.area[metal];

-- Combine Node Perimeters
n3.circumference[diff] ←
n2.circumference[diff] + n3.circumference[diff];
n3.circumference[poly] ←
n2.circumference[poly] + n3.circumference[poly];
n3.circumference[metal] ←
n2.circumference[metal] + n3.circumference[metal];

-- Correct Node Perimeter for current layer
n3.circumference[layer] ← n3.circumference[layer] -
2*(MIN[xright,n2.right] - MAX[xleft,n2.left]);

-- Mark and Unmark the three nodes
n2.mark ← FALSE;
n3.mark ← TRUE;
n2.circumference ← [0.0, 0.0, 0.0, 0.0];
n2.area ← [0.0, 0.0, 0.0, 0.0];

END
ENDCASE
ENDCASE;

Combine[nodeSeg, nodeSegExtra, layer];
NodeList[layer] ← nodeSeg ← nodeSegExtra;
ENDLOOP;

node ← nodeSeg.number;
IF layer = depl OR layer = enha THEN
BEGIN
trans: Transistor ← NodeToTransistor[node];
trans.circumference ←
trans.circumference -
(2*(MIN[nodeSeg.right, xright] - MAX[nodeSeg.left, xleft]));
END
ELSE
BEGIN
WITH n1: newNodeSeg SELECT FALSE FROM

FALSE =>
BEGIN
-- calculate the area and perimeter for the node
LLength ← EdgeLength[eleft, YCurr, YPrev];
RLength ← EdgeLength[eright, YCurr, YPrev];
n1.circumference ← [0.0, 0.0, 0.0, 0.0];
n1.area ← [0.0, 0.0, 0.0, 0.0];
n1.area[layer] ←
(YCurr -
YPrev)*((xright - xleft) +
((xleft - leftTop) + (rightTop - xright))/2);
n1.circumference[layer] ←
(xright - xleft) + (rightTop - leftTop) + LLength + RLength;
END
ENDCASE;

WITH n1: nodeSeg SELECT FALSE FROM
FALSE =>
WITH n3: newNodeSeg SELECT FALSE FROM
FALSE =>
BEGIN

-- Combine Node Areas
n3.area[diff] ← n1.area[diff] + n3.area[diff];
n3.area[poly] ← n1.area[poly] + n3.area[poly];
n3.area[metal] ← n1.area[metal] + n3.area[metal];

-- Combine Node Perimeters
n3.circumference[diff] ←
n1.circumference[diff] + n3.circumference[diff];
n3.circumference[poly] ←
n1.circumference[poly] + n3.circumference[poly];
n3.circumference[metal] ←
n1.circumference[metal] + n3.circumference[metal];

-- Mark and Unmark the three nodes
n1.mark ← FALSE;
n3.mark ← TRUE;
n1.circumference ← [0.0, 0.0, 0.0, 0.0];
n1.area ← [0.0, 0.0, 0.0, 0.0];

END
ENDCASE
ENDCASE
END;
END;

newNodeSeg.number ← node;
IF layer = depl OR layer = enha THEN
BEGIN
leftTop ← XatY[eleft, YCurr];
rightTop ← XatY[eright, YCurr];
WITH t: newNodeSeg SELECT TRUE FROM
TRUE =>
BEGIN
trans: Transistor ← NodeToTransistor[node];
t.leftLength ← EdgeLength[eleft, YCurr, YPrev];
t.rightLength ← EdgeLength[eright, YCurr, YPrev];
trans.area ←
trans.area +
(YCurr -
YPrev)*((xright - xleft) +
((xleft - leftTop) + (rightTop - xright))/2);
trans.circumference ←
trans.circumference + (xright - xleft) + (rightTop - leftTop) +
t.leftLength + t.rightLength;
END;
ENDCASE;
END;
CheckForLabel[eleft,eright,node,layer];
END;

FindGate: PROCEDURE = INLINE
BEGIN
length: REAL;
nodeSeg: NodeSegment;
FOR deplNodeList ← deplNodeList, deplNodeList.next UNTIL deplNodeList = NIL
OR deplNodeList.right > xleft DO ENDLOOP;
FOR nodeSeg ← deplNodeList, nodeSeg.next UNTIL nodeSeg = NIL
OR nodeSeg.left > xright DO
-- At this point we know that the transistor’s right side is past the
-- diffusion’s left and that the diffusion’s right is not past the
-- transistor’s left side,
-- therefore the transistor and the diffusion intersect.
length ← MIN[nodeSeg.right, xright] - MAX[nodeSeg.left, xleft];
SetDiff[NodeToTransistor[nodeSeg.number], node, length];
ENDLOOP;
FOR enhaNodeList ← enhaNodeList, enhaNodeList.next UNTIL enhaNodeList = NIL
OR enhaNodeList.right > xleft DO ENDLOOP;
FOR nodeSeg ← enhaNodeList, nodeSeg.next UNTIL nodeSeg = NIL
OR nodeSeg.left > xright DO
-- At this point we know that the transistor’s right side is past the
-- diffusion’s left and that the diffusion’s right is not past the
-- transistor’s left side,
-- therefore the transistor and the diffusion intersect.
length ← MIN[nodeSeg.right, xright] - MAX[nodeSeg.left, xleft];
SetDiff[NodeToTransistor[nodeSeg.number], node, length];
ENDLOOP;
END;

FindDiff: PROCEDURE = INLINE
BEGIN
length: REAL;
nodeSeg: NodeSegment;
FOR diffNodeList ← diffNodeList, diffNodeList.next UNTIL diffNodeList = NIL
OR diffNodeList.right > xleft DO ENDLOOP;
FOR nodeSeg ← diffNodeList, nodeSeg.next UNTIL nodeSeg = NIL
OR nodeSeg.left > xright DO
-- At this point we know that the transistor’s right side is past the
-- diffusion’s left and that the diffusion’s right is not past the
-- transistor’s left side,
-- therefore the transistor and the diffusion intersect.
length ← MIN[nodeSeg.right, xright] - MAX[nodeSeg.left, xleft];
SetDiff[NodeToTransistor[node], nodeSeg.number, length];
ENDLOOP;
END;

MakeContact: PROCEDURE = INLINE
BEGIN
nodeSeg: NodeSegment;
node ← LOOPHOLE[LONG[0]];
nodeSeg ← MakeNodeSegment[node, XatY[eleft, YCurr], XatY[eright, YCurr]];
ptrnewNodeList[layer]↑ ← nodeSeg;
ptrnewNodeList[layer] ← @nodeSeg.next;
END;

IF eleft # NIL THEN xleft ← XatY[eleft, YPrev] ELSE xleft ← 0;
-- Avoid zero width trapezoids
IF xleft = xright AND XatY[eleft, YCurr] = XatY[eright, YCurr] THEN RETURN;

SELECT layer FROM
metal => Propagate[];
poly =>
BEGIN
Propagate[];
IF In[diff] AND NOT In[buried] THEN
BEGIN
IF In[implant] THEN EndTrap[eright, depl] ELSE EndTrap[eright, enha];
StartTrap[eright, diff];
END;
END;
diff =>
IF In[poly] AND NOT In[buried] THEN
IF In[implant] THEN EndTrap[eright, depl] ELSE EndTrap[eright, enha]
ELSE
BEGIN
Propagate;
-- see if there is a gate below
FindGate;
END;
depl, enha =>
BEGIN
Propagate;
IF layer = depl THEN NodeToTransistor[node].ion ← TRUE;
-- see if there is diffusion below
FindDiff;
END;
buried =>
BEGIN
gotBuried ← TRUE;
IF In[diff] AND In[poly] THEN
BEGIN
EndTrap[eright, diff];
IF In[implant] THEN StartTrap[eright, depl] -- start of transistor
ELSE StartTrap[eright, enha];
END;
END;
implant =>
IF In[poly] AND In[diff] AND NOT In[buried] THEN
BEGIN -- End of deplection
EndTrap[eright, depl];
StartTrap[eright, enha]; -- Start enhancement
END;
contact => MakeContact[];

ENDCASE -- => DrawTrap[eleft,YPrev,eright,YCurr,layer] -- ;
END;

CheckForLabel: PROCEDURE[eleft,eright: Edge, node: NodeNumberType, layer:CARDINAL] = INLINE
BEGIN
label: NodeLabel;
FOR label ← LabelList,label.next UNTIL label = NIL DO
IF XatY[eleft,label.y] < label.x AND label.x < XatY[eright,label.y]
AND YPrev <= label.y AND label.y <= YCurr THEN
IF label.layer = undef OR label.layer = layer THEN {
WriteNodeLabel[label,node];
WriteNodeLocation[node,label.x,label.y,7];
--DrawString[label.label,label.x,label.y];
label.used ← TRUE;
};
ENDLOOP;
END;



gotBuried: BOOLEAN;
END.