-- File CIFExtNMOS2.mesa
-- Written by Dan Fitzpatrick and Martin Newell, June 1980
-- Last updated: December 21, 1981 4:41 PM by DF

DIRECTORY

CWF: FROM "CWF",
Inline: FROM "Inline",
CIFDevicesDefs: FROM "CIFDevicesDefs" USING [MaxLENGTHLayerArray],
CIFExtDictDefs: FROM "CIFExtDictDefs" USING [Remember,
KnownName, KnownNumber, FindName, FindNumber],
CIFExtIODefs: FROM "CIFExtIODefs" USING [ReadStringDirect, ReadLineDirect,
WriteStringDirect, WriteLineDirect, ReadLong, WriteLong, GetLong, PutLong,
GetReal, PutReal, WriteShort, OpenFile, CloseStream, DeleteFile],
CIFExtNMOS2Defs: FROM "CIFExtNMOS2Defs",
CIFExtNMOSDefs: FROM "CIFExtNMOSDefs",
CIFExtScanDefs: FROM "CIFExtScanDefs" USING [Edge],
CIFExtUtilsDefs: FROM "CIFExtUtilsDefs" USING [
WriteLongDecimal, Tag],
RealFns: FROM "RealFns" USING [SqRt],
IODefs: FROM "IODefs" USING [WriteString, WriteLine, GetOutputStream,
SetOutputStream],
MergeDefs: FROM "MergeDefs" USING [Merge, Lookup, Lookup2,GenMergeValue],
Real: FROM "Real" USING [AppendReal, Fix],
StreamDefs: FROM "StreamDefs" USING[StreamHandle, DiskHandle, WriteBlock, ReadBlock],
StringDefs: FROM "StringDefs" USING[EqualString],
XFSPDefs: FROM "XFSPDefs" USING [XAllocateHeapNode];

CIFExtNMOS2: PROGRAM
IMPORTS CIFExtNMOS2Defs, CIFExtDictDefs, CIFExtIODefs, CIFExtUtilsDefs, RealFns, IODefs, MergeDefs, Real, StreamDefs, StringDefs, XFSPDefs, Inline, CWF
EXPORTS CIFExtNMOS2Defs =

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

HASHSIZE:
CARDINAL = 731;

hashIndex:
TYPE = [0..HASHSIZE);
hash:
ARRAY hashIndex OF NodeSegment;

ErrorFlag:
PUBLIC BOOLEAN;-- true when errors are on .extlog
AliasFlag: PUBLIC BOOLEAN ← FALSE;-- true when aliases are written on .al

NoEnhaTrans, NoDeplTrans:
PUBLIC LONG CARDINAL ← LONG[0];


FreeTransistors, AllocatedTransistors:
PUBLIC Transistor ← NIL;
FreeTransCount:
PUBLIC CARDINAL ← 0;
CapacitorFile, TransistorFile:
PUBLIC DiskHandle;
NodeFile, OutNodeFile:
PUBLIC DiskHandle;
errorStream, out1:
PUBLIC DiskHandle;
tmpErrorStream, defaultStream:
PUBLIC StreamHandle;
--LabelLocationFile, -- LabelNodeFile:
PUBLIC DiskHandle;

FreeDiffRecords:
PUBLIC LONG POINTER TO DiffRecord ← NIL;
FreeNodeSegments:
PUBLIC NodeSegment ← NIL;

FreeNodeLabels:
PUBLIC NodeLabel ← NIL;
LabelList:
PUBLIC NodeLabel ← NIL;

YCurr, YPrev:
PUBLIC REAL;
Scale:
PUBLIC REAL;

newNodeList, oldNodeList, NodeList:
PUBLIC ARRAY [0..MaxLENGTHLayerArray+2] OF NodeSegment;
ptrnewNodeList:
PUBLIC ARRAY [0..MaxLENGTHLayerArray+2] OF LONG POINTER TO NodeSegment;
NodeNumber:
PUBLIC NodeNumberType;

NoAllocTrans,NoAllocDiffRecord, NoAllocNodeSegment, NoAllocNodeLabel, NoAllocString:
PUBLIC LONG CARDINAL ← LONG[0];
scanCount, displayCount:
PUBLIC CARDINAL ← 1;

BaseFileName:
PUBLIC STRING ← [50];

trapleft:
PUBLIC ARRAY [0..MaxLENGTHLayerArray+2] OF Edge;
depl:
PUBLIC CARDINAL;
enha:
PUBLIC CARDINAL;


hashCode: PROCEDURE [name: NodeNumberType] RETURNS [hashIndex] =
BEGIN
i: hashIndex ← 0;
j: LONG CARDINAL;

j ← LOOPHOLE[name];
i ← Inline.LowHalf[j MOD HASHSIZE];
RETURN[IF i < 0 THEN i + HASHSIZE ELSE i];

END;



GenNodeNumber: PUBLIC PROCEDURE [layer: CARDINAL] RETURNS[NodeNumberType] =
BEGIN
IF layer = depl OR layer = enha THEN RETURN[MakeTransistor[]]
ELSE RETURN[GenMergeValue[]];
END;

MakeTransistor: PUBLIC PROCEDURERETURNS[trans: Transistor] =
BEGIN
trans ← AllocateTransistor[];
trans↑ ← TransistorRecord[
link:AllocatedTransistors,
polyNumber: NIL,
diffList: NIL,
ion: FALSE,
marked: FALSE,
old: FALSE,
newNode: NIL,
area: 0,
circumference: 0,
x: 0,
y: 0
];
AllocatedTransistors ← trans;
END;

FreeTransistor: PUBLIC PROCEDURE[trans: Transistor] =
BEGIN
diff, next: LONG POINTER TO DiffRecord;
FOR diff ← trans.diffList, next UNTIL diff = NIL DO
next ← diff.next;
FreeDiffRecord[diff];
ENDLOOP;
trans.link ← FreeTransistors;
FreeTransistors ← trans;
FreeTransCount ← FreeTransCount + 1;
END;

AllocateTransistor: PUBLIC PROCEDURE RETURNS[trans: Transistor] =
BEGIN
IF FreeTransCount = 0 THEN CollectTransistors[];--if no more transistors then get some
trans ← FreeTransistors;
FreeTransistors ← trans.link;
FreeTransCount ← FreeTransCount - 1;
END;

CollectTransistors
: PUBLIC PROCEDURE =
BEGIN
nodeSeg: NodeSegment;
i: CARDINAL;
ptr, next, tempList, trans: Transistor ← NIL;

Update: PROCEDURE [nodeSeg: NodeSegment] = INLINE
BEGIN
temp: Transistor ← nodeSeg.number;
FOR temp ← temp, temp.newNode WHILE temp.old DO ENDLOOP;
nodeSeg.number ← temp;
END;

-- mark the transistors on NodeList and newNodeList
FOR nodeSeg ← NodeList[depl], nodeSeg.next UNTIL nodeSeg = NIL DO
IF nodeSeg.number = NIL THEN LOOP;
Update[nodeSeg];
NodeToTransistor[nodeSeg.number].marked ← TRUE;
ENDLOOP;
FOR nodeSeg ← newNodeList[depl], nodeSeg.next UNTIL nodeSeg = NIL DO
IF nodeSeg.number = NIL THEN LOOP;
Update[nodeSeg];
NodeToTransistor[nodeSeg.number].marked ← TRUE;
ENDLOOP;

FOR nodeSeg ← NodeList[enha], nodeSeg.next UNTIL nodeSeg = NIL DO
IF nodeSeg.number = NIL THEN LOOP;
Update[nodeSeg];
NodeToTransistor[nodeSeg.number].marked ← TRUE;
ENDLOOP;
FOR nodeSeg ← newNodeList[enha], nodeSeg.next UNTIL nodeSeg = NIL DO
IF nodeSeg.number = NIL THEN LOOP;
Update[nodeSeg];
NodeToTransistor[nodeSeg.number].marked ← TRUE;
ENDLOOP;

-- Put the marked transistors on tempList
FOR ptr ← AllocatedTransistors, next UNTIL ptr = NIL DO
next ← ptr.link;
IF ptr.marked THEN BEGIN
ptr.marked ← FALSE;-- reset marked bit
ptr.link ← tempList;
tempList ← ptr;
END
ELSE BEGIN
IF NOT ptr.old THEN WriteTransistor[ptr];
FreeTransistor[ptr];
END;
ENDLOOP;

AllocatedTransistors ← tempList;

-- Check to see that there are enough transistor records free
-- If not free a bunch more (this prevents excessive garbage collection)
IF FreeTransCount < TransAllocConstant THEN
FOR i ← 1, i+1 UNTIL i > TransAllocConstant DO
trans ← XAllocateHeapNode[SIZE[TransistorRecord]];
trans.diffList ← NIL;
NoAllocTrans ← NoAllocTrans + 1;
FreeTransistor[trans];
ENDLOOP;
END;
ReleaseTransistors: PUBLIC PROCEDURE =
BEGIN
--**trans: Transistor;
-- Remove all references to transistors
NodeList[depl] ← NIL;
newNodeList[depl] ← NIL;
NodeList[enha] ← NIL;
newNodeList[enha] ← NIL;
-- Return heap space to the system
--**UNTIL FreeTransCount = 0 DO
--**trans ← AllocateTransistor[];
--**NoAllocTrans ← NoAllocTrans - 1;
--**trans.next ← FreeFreeTransistors; FreeFreeTransistors ← trans;
--**FreeHeapNode[trans];
--**ENDLOOP;
END;


AllocateDiffRecord: PUBLIC PROCEDURE RETURNS[d: LONG POINTER TO DiffRecord] =
BEGIN
NoAllocDiffRecord ← NoAllocDiffRecord + 1;
IF FreeDiffRecords#NIL THEN
{d ← FreeDiffRecords;
FreeDiffRecords ← FreeDiffRecords.next;
}
ELSE d ← XAllocateHeapNode[SIZE[DiffRecord]];
END;

FreeDiffRecord: PUBLIC PROCEDURE[diffptr: LONG POINTER TO DiffRecord] =
BEGIN
NoAllocDiffRecord ← NoAllocDiffRecord - 1;
diffptr.next ← FreeDiffRecords; FreeDiffRecords ← diffptr;
END;

MakeNodeSegment: PUBLIC PROCEDURE[nodeNumber: NodeNumberType, left,right: REAL, trans:BOOLEAN ← FALSE]
RETURNS[nodeSegment: NodeSegment] =
BEGIN
nodeSegment ← AllocateNodeSegment[trans];
IF trans THEN
nodeSegment↑ ← [
next: NIL,
number: nodeNumber,
left: left,
right: right,
mark: FALSE,
transistor: TRUE [0,0]
]
ELSE
nodeSegment↑ ← [
next: NIL,
number: nodeNumber,
left: left,
right: right,
mark: FALSE,
transistor: FALSE [ALL[0], ALL[0]]
];
END;

AllocateNodeSegment: PUBLIC PROCEDURE[trans: BOOLEAN] RETURNS[ns: NodeSegment] =
BEGIN
NoAllocNodeSegment ← NoAllocNodeSegment + 1;
IF FreeNodeSegments#NIL THEN
{ns ← FreeNodeSegments;
FreeNodeSegments ← FreeNodeSegments.next;
}
ELSE ns ← XAllocateHeapNode[SIZE[NodeSegmentRecord]];
END;

FreeNodeSegment: PUBLIC PROCEDURE[nodeSegment: NodeSegment] =
BEGIN
NoAllocNodeSegment ← NoAllocNodeSegment - 1;
nodeSegment.next ← FreeNodeSegments;
FreeNodeSegments ← nodeSegment;
END;

Combine: PUBLIC PROCEDURE[n1,n2: NodeSegment, layer: CARDINAL] =
BEGIN
temp: NodeSegment;
diffNode: LONG POINTER TO DiffRecord;
s: STRING ← [20];
--WriteString["Merge: "]; WriteNodeNumber[n1.number];
--WriteString[" with "]; WriteNodeNumber[n2.number];
IF EqualToNodeNumber[n2.number,n1.number] THEN RETURN;
IF LessThanNodeNumber[n2.number,n1.number] THEN BEGIN
temp←n2; n2←n1; n1←temp; END;
IF layer = depl OR layer = enha THEN BEGIN
trans1: Transistor ← NodeToTransistor[n1.number];
trans2: Transistor ← NodeToTransistor[n2.number];
SetPoly[trans1,trans2.polyNumber];
trans1.area ← trans2.area ← trans1.area + trans2.area;
trans1.circumference ← trans2.circumference ← trans1.circumference + trans2.circumference;
IF trans1.ion # trans2.ion THEN {
SetErrorStream[TRUE];
WriteLocation[trans1.x,trans1.y,errorStream];
WriteLine[" Design Error: Transistor is only partially in implant"];
ResetErrorStream[];
};
-- Now merge diffusion list
FOR diffNode ← trans2.diffList,diffNode.next UNTIL diffNode = NIL DO
SetDiff[trans1,diffNode.number, diffNode.length];
ENDLOOP;
trans2.old ← TRUE;
trans2.newNode ← trans1;
END
ELSE BEGIN

n1.number ← Merge[n1.number,n2.number];
--WriteString[" returns "]; WriteNodeNumber[n1.number];
END;
--WriteLine[""];
n2.number ← n1.number;
END;
WriteNodeNumber: PUBLIC PROCEDURE[n: NodeNumberType] =
BEGIN
i: LONG CARDINAL ← LOOPHOLE[n,LONG CARDINAL];
WriteLongDecimal[i];
END;

WriteNodeName
: PUBLIC PROCEDURE[n: NodeNumberType] =
BEGIN
m: NodeNumberType;

m ← Lookup2[n];
n ← Lookup[n];
IF KnownNumber[n] THEN BEGIN
name: STRING ← [50];
name ← FindNumber[n];
WriteString[name];
END
ELSE WriteNodeNumber[m];
END;

WriteLocation
: PUBLIC PROCEDURE[x,y: REAL, s:StreamHandle] =
BEGIN
--rely on unity
[x,y] ← InverseTransform[x,y];
-- WriteStringDirect["(",s];
WriteLong[Fix[x],s];
WriteStringDirect[" ",s];
WriteLong[Fix[y],s];
-- WriteStringDirect[")",s];
END;

GetNodeNumber
: PUBLIC PROCEDURE [s: DiskHandle] RETURNS[x: NodeNumberType] =
BEGIN
x ← GetLong[s];
END;

PutNodeNumber
: PUBLIC PROCEDURE [x: NodeNumberType, s: DiskHandle] =
BEGIN
PutLong[x,s];
END;

ConvertTransToText
: PUBLIC PROCEDURE [s:StreamHandle]
= BEGIN
count,i: CARDINAL;
CapNode: CapRecord;
localNode: NodeSegmentRecord;
newNodeSeg: NodeSegment;
trans: Transistor ← MakeTransistor[];

-- Open transistor and capacitor file
TransistorFile ← OpenFile["CIFExtractor.tmp$", ’r];
CapacitorFile ← OpenFile["CIFExtractor.tmp2$", ’r];

-- Read capacitors and build internal node record table
FOR i IN hashIndex DO
hash[i] ← NIL;
ENDLOOP;
UNTIL CapacitorFile.endof[CapacitorFile] DO
ReadCapacitor[CapacitorFile, @CapNode];
EnterCapacitor[@CapNode];
ENDLOOP;
CloseStream[CapacitorFile];
DeleteFile["CIFExtractor.tmp2$"];

-- reset transistor counters and initialize local node record
NoEnhaTrans ← 0;
NoDeplTrans ← 0;
WITH L1:localNode SELECT FALSE FROM
FALSE => BEGIN
L1.circumference ← [0.0, 0.0, 0.0, 0.0];
L1.area ← [0.0, 0.0, 0.0, 0.0];
END;
ENDCASE;

-- Read transistors and output sim file
UNTIL TransistorFile.endof[TransistorFile] DO
FreeTransistor[trans];
trans ← MakeTransistor[];
trans.ion ← (TransistorFile.get[TransistorFile] = 1);
SetPoly[trans,Lookup[GetNodeNumber[TransistorFile]]];
trans.area ← GetReal[TransistorFile];
trans.circumference ← GetReal[TransistorFile];
count ← TransistorFile.get[TransistorFile];
FOR i ← 1,i+1 UNTIL i > count DO BEGIN
node: NodeNumberType ← GetNodeNumber[TransistorFile];
length: REAL ← GetReal[TransistorFile];
node ← Lookup[node];
SetDiff[trans,node,length];
END;
ENDLOOP;
trans.x ← GetReal[TransistorFile];
trans.y ← GetReal[TransistorFile];
IF trans.diffList = NIL THEN BEGIN
SetErrorStream[TRUE];
WriteLocation[trans.x,trans.y,errorStream];
WriteStringDirect[" Error: Found transistor with no diffusion; Poly #",errorStream];
WriteLong[trans.polyNumber,errorStream];
WriteLineDirect["",errorStream];
ResetErrorStream[];
LOOP;
END;
IF trans.diffList.next = NIL THEN
IF trans.diffList.number = trans.polyNumber THEN LOOP
ELSE BEGIN
l,w: LONG INTEGER; --len & width of trans (CIF units)
xint,yint: LONG INTEGER;-- area & perim of trans
SetErrorStream[TRUE];
WriteLocation[trans.x,trans.y,errorStream];
WriteStringDirect[" Warning: Transistor with source & drain connected; gate=", errorStream];
WriteNodeName[trans.polyNumber];
WriteStringDirect[", source=", errorStream];
WriteNodeName[trans.diffList.number];
WriteLineDirect["",errorStream];
ResetErrorStream[];
--Adjust Diff Node data to reflect lack of side wall cap
WITH L1:localNode SELECT FALSE FROM
FALSE => {
CapNode.number ← trans.diffList.number;
CapNode.perimeter ← -(trans.diffList.length);CapNode.area ← L1.area[diff];
CapNode.layer ← diff;
EnterCapacitor[@CapNode];
};
ENDCASE;
IF trans.ion THEN {
NoDeplTrans ← NoDeplTrans + 1;
CWF.FWF [s,"d "];
}
ELSE {
NoEnhaTrans ← NoEnhaTrans + 1;
CWF.FWF [s,"e "];
};
WriteNodeName[trans.polyNumber];
WriteString[" "];
WriteNodeName[trans.diffList.number];
WriteString[" "];
WriteNodeName[trans.diffList.number];
l ← Fix[trans.diffList.length]/2;
w ← Fix[trans.area/l];
xint ←Fix[trans.x];
yint ←Fix[trans.y];
CWF.FWF [s," %ld %ld %ld %ld*n",@w,@l,@xint,@yint];
LOOP;
END;
IF trans.diffList.next.next = NIL THEN BEGIN-- Normal transistor
l,w: LONG INTEGER; --Len & width of the trans in CIF units
xint,yint: LONG INTEGER; -- area & perimeter of the trans

--Adjust Diff Node data to reflect lack of side wall Capacitance
WITH L1:localNode SELECT FALSE FROM
FALSE => BEGIN
CapNode.number ← trans.diffList.number;
CapNode.perimeter ← -(trans.diffList.length);CapNode.area ← L1.area[diff];
CapNode.layer ← diff;
EnterCapacitor[@CapNode];
END;
ENDCASE;
WITH L1:localNode SELECT FALSE FROM
FALSE => BEGIN
CapNode.number ← trans.diffList.next.number;
CapNode.perimeter ← -(trans.diffList.next.length);CapNode.area ← L1.area[diff];
CapNode.layer ← diff;
EnterCapacitor[@CapNode];
END;
ENDCASE;

IF trans.ion THEN BEGIN
NoDeplTrans ← NoDeplTrans + 1;
CWF.FWF [s,"d "];
END
ELSE BEGIN
NoEnhaTrans ← NoEnhaTrans + 1;
CWF.FWF [s,"e "];
END;
WriteNodeName[trans.polyNumber];
WriteString[" "];
WriteNodeName[trans.diffList.number];
WriteString[" "];
WriteNodeName[trans.diffList.next.number];
WriteString[" "];
[l,w] ← FindTransRatio[trans.area, trans.circumference, trans.diffList.length, trans.diffList.next.length];
xint ←Fix[trans.x];
yint ←Fix[trans.y];
--rely on unity
[trans.x,trans.y] ← InverseTransform[trans.x,trans.y];
CWF.FWF [s," %ld %ld %ld %ld*n",@l,@w,@xint,@yint];
LOOP;
END;
SetErrorStream[TRUE];
WriteLocation[trans.x,trans.y,errorStream];
WriteLineDirect[" Error: Don’t know how to handle funny transistors; gate=", errorStream];
WriteNodeName[trans.polyNumber];
WriteLineDirect["",errorStream];
ResetErrorStream[];
ENDLOOP;

-- Output the Capacitor Records to the SIM file
FOR i IN hashIndex DO
FOR newNodeSeg ← hash[i], newNodeSeg.next UNTIL newNodeSeg = NIL DO
WriteCapacitor[newNodeSeg, s];
ENDLOOP;
ENDLOOP;

-- Clean up our files and allocated space
FreeTransistor[trans];
AllocatedTransistors ← NIL;
CloseStream[TransistorFile];
END;

WriteCapacitor: PUBLIC PROCEDURE[n: NodeSegment, s:StreamHandle] =
BEGIN

-- Write out the capacitance data for the node
IF n = NIL THEN RETURN
ELSE WITH n1:n SELECT FALSE FROM

FALSE =>
BEGIN
CWF.FWF [s,"N "];
WriteNodeName [n1.number];
CWF.FWF [s," %f %f %f %f",
@n1.circumference[metal],@n1.circumference[poly],
@n1.area[metal],@n1.area[poly]];
CWF.FWF [s," %f %f *n",
@n1.area[diff],@n1.circumference[diff]];
END;
ENDCASE;
END;

WriteNodeCap: PUBLIC PROCEDURE[n: NodeSegment, s:DiskHandle] =
BEGIN
localNode: CapRecord;

-- Write out the Node Record which holds the capacitance data
WITH n1:n SELECT FALSE FROM
FALSE =>
BEGIN
L:Layers;
localNode.number ← n1.number;
FOR L IN Layers DO
IF n1.area[L]#0.0
THEN BEGIN
localNode.layer ← L;
localNode.area ← n1.area[L];
localNode.perimeter ← n1.circumference[L];
[] ← StreamDefs.WriteBlock[s,@localNode,
SIZE[CapRecord]];
END;
ENDLOOP;
END;
ENDCASE;

END;


ReadCapacitor: PUBLIC PROCEDURE[s:DiskHandle, n: POINTER TO CapRecord] =
BEGIN

-- Read in the Node Record which holds the capacitance data
[] ← StreamDefs.ReadBlock[s, n, SIZE[CapRecord]];

END;

EnterCapacitor: PUBLIC PROCEDURE[newNode: POINTER TO CapRecord] =
BEGIN
node : NodeSegment;
j: NodeNumberType;
i : INTEGER;

-- Find entry in the Hash Table
j ← newNode.number ← Lookup[newNode.number];
i ← hashCode[j];
FOR node ← LOOPHOLE[hash[i]], node.next UNTIL node=NIL OR node.number=j DO
ENDLOOP;

IF node = NIL
THEN BEGIN
node ← MakeNodeSegment
[newNode.number,0.0,0.0,FALSE];
WITH n1:node SELECT FALSE FROM
FALSE =>
BEGIN OPEN c1:newNode;
L:Layers ← c1.layer;
n1.number ← c1.number;
n1.area[L] ← c1.area;
n1.circumference[L] ← c1.perimeter;
END;
ENDCASE;
node.next ← hash[i];
hash[i] ← node;
END
ELSE WITH n3: node SELECT FALSE FROM
FALSE =>
BEGIN OPEN c1:newNode;
L:Layers ← c1.layer;

-- Combine Node Areas
n3.area[L] ← n3.area[L] + c1.area;

-- Combine Node Perimeters
n3.circumference[L] ← n3.circumference[L] +
c1.perimeter;

END

ENDCASE

END;


WriteTransistor: PUBLIC PROCEDURE[n: Transistor] =
BEGIN
diffptr: LONG POINTER TO DiffRecord;
--
i: CARDINAL ← LOOPHOLE[n,CARDINAL];
count: CARDINAL ← 0;

IF n.ion THEN BEGIN
TransistorFile.put[TransistorFile,1];
END
ELSE TransistorFile.put[TransistorFile,0];
PutNodeNumber[n.polyNumber,TransistorFile];
PutReal[n.area,TransistorFile];
PutReal[n.circumference,TransistorFile];
FOR diffptr ← n.diffList, diffptr.next UNTIL diffptr = NIL DO
count ← count + 1;
ENDLOOP;
TransistorFile.put[TransistorFile,count];
FOR diffptr ← n.diffList, diffptr.next UNTIL diffptr = NIL DO
PutNodeNumber[diffptr.number,TransistorFile];
PutReal[diffptr.length,TransistorFile];
ENDLOOP;
PutReal[n.x,TransistorFile];
PutReal[n.y,TransistorFile];
END;

CorrectLabelNodes: PUBLIC PROCEDURE [name: STRING] =
BEGIN
str: STRING ← [50];
dummy: STRING ← [50];
node, newNode: NodeNumberType;
AliasFile,trc:DiskHandle;
s:StreamHandle;
x,y: LONG INTEGER;
rx,ry: REAL ← 0;
LabelNodeFile ← OpenFile["CIFLabelNode.tmp$",’r];
AliasFile ← OpenFile[name,’w];
IF trace THEN trc ← OpenFile["Extractor.trace",’w];
UNTIL LabelNodeFile.endof[LabelNodeFile] DO
ReadStringDirect[str, LabelNodeFile];
node ← ReadLong[LabelNodeFile];
ReadLineDirect[dummy, LabelNodeFile];
newNode ← Lookup[node];
IF KnownName[str] AND newNode # FindName[str] THEN BEGIN
SetErrorStream[TRUE];
WriteString["0 0 The name ’"];
WriteString[str];
WriteLine["’ is attached to more than one node"];
ResetErrorStream[];
END;
IF KnownNumber[newNode] AND NOT EqualString[str,FindNumber[newNode]] THEN BEGIN
SetErrorStream[TRUE];
WriteString["0 0 "];
WriteString[str];
WriteString[" is connected to "];
WriteLine[FindNumber[newNode]];
ResetErrorStream[];
WriteStringDirect["= ", AliasFile];
WriteStringDirect[str, AliasFile];
WriteStringDirect[" ", AliasFile];
WriteLong[newNode, AliasFile];
WriteLineDirect["", AliasFile];
AliasFlag ← TRUE;
END;
Remember[str,newNode];
IF trace THEN BEGIN
WriteStringDirect[str, trc];
WriteStringDirect[" ", trc];
WriteLong[newNode, trc];
WriteLineDirect["", trc];
END;
ENDLOOP;
IF trace THEN CloseStream[trc];
CloseStream[LabelNodeFile];
CloseStream[AliasFile];
DeleteFile["CIFLabelNode.tmp$"];
NodeFile ← OpenFile["CIFNodes.tmp$",’r];
OutNodeFile ← OpenFile[Tag[BaseFileName,"nodes"],’w];
s ← GetOutputStream[];
SetOutputStream[OutNodeFile];
UNTIL NodeFile.endof[NodeFile] DO
node ← ReadLong[NodeFile];
x ← ReadLong[NodeFile];
y ← ReadLong[NodeFile];
ReadLineDirect[str,NodeFile];
--rely on unity
[rx,ry] ← Transform[x,y];
rx ← x; ry ← y;
node ← Lookup[node];
--IF KnownNumber[node] THEN BEGIN
--name: STRING ← [50];
--name ← FindNumber[node];
--DrawString[name, rx, ry];
--END
--ELSE DrawNumber[0, node, rx, ry];
WriteString["94 "];
WriteNodeName[node];
WriteString[" "];
WriteLong[x,OutNodeFile];
WriteString[" "];
WriteLong[y,OutNodeFile];
WriteLine[";"];
ENDLOOP;
SetOutputStream[s];
CloseStream[OutNodeFile];
CloseStream[NodeFile];
END;

WriteNodeLocation
: PUBLIC PROCEDURE[n: NodeNumberType, x,y: REAL, layer:CARDINAL] =
BEGIN
a,b: LONG INTEGER;
--defaultStream:StreamHandle ← GetOutputStream[];
--rely on unity
[x,y] ← InverseTransform[x,y];
a ← Fix[x];
b ← Fix[y];
--SetOutputStream[NodeFile];
WriteLong[n, NodeFile];
WriteStringDirect[" ", NodeFile];
WriteLong[a, NodeFile];
WriteStringDirect[", ", NodeFile];
WriteLong[b, NodeFile];
WriteStringDirect[" (", NodeFile];
WriteShort[layer, NodeFile];
WriteLineDirect[")", NodeFile];
--SetOutputStream[defaultStream];
END;

WriteNodeLabel
: PUBLIC PROCEDURE[label: NodeLabel, n: NodeNumberType] =
BEGIN
defaultStream:StreamHandle ← GetOutputStream[];
SetOutputStream[LabelNodeFile];
WriteString[label.label];
WriteString[" "];
WriteNodeNumber[n];
WriteString[" "];
WriteFloat[label.x];
WriteString[" "];
WriteFloat[label.y];
WriteLine[""];
SetOutputStream[defaultStream];
END;

--ReadLabelLocation
: PUBLIC PROCEDURE RETURNS[n:NodeLabel] =
--BEGIN
--s:STRING ← [50];
--x,y: LONG INTEGER;
--IF NoNameFile OR LabelLocationFile.endof[LabelLocationFile] THEN RETURN[n ← NIL];
--n ← AllocateNodeLabel[];
--n.label ← AllocateHeapString[50];
--ReadStringDirect[n.label, LabelLocationFile];
--x ← ReadLong[LabelLocationFile];
--y ← ReadLong[LabelLocationFile];
--[n.x,n.y] ← Transform[x,y];
--n.used ← FALSE;
--ReadLineDirect[s, LabelLocationFile];
--END;

AllocateNodeLabel: PUBLIC PROCEDURE RETURNS[n: NodeLabel] =
BEGIN
NoAllocNodeLabel ← NoAllocNodeLabel + 1;
IF FreeNodeLabels#NIL THEN
{n ← FreeNodeLabels;
FreeNodeLabels ← FreeNodeLabels.next;
}
ELSE n ← XAllocateHeapNode[SIZE[NodeLabelRecord]];
END;

FreeNodeLabel
: PUBLIC PROCEDURE [n: NodeLabel] =
BEGIN
NoAllocNodeLabel ← NoAllocNodeLabel - 1;
n.next ← FreeNodeLabels; FreeNodeLabels ← n;
END;


PrintAllocation: PUBLIC PROCEDURE[force: BOOLEAN] =
BEGIN
IF NOT force AND NoAllocTrans = FreeTransCount AND
NoAllocDiffRecord = 0 AND NoAllocNodeSegment = 0 AND
NoAllocNodeLabel = 0 AND NoAllocString = 0 THEN RETURN;

WriteLine["*** Allocation Summary ***"];
WriteString["Transistors: "]; WriteLongDecimal[NoAllocTrans]; WriteLine[""];
WriteString["Free Transistors: "]; WriteLongDecimal[FreeTransCount]; WriteLine[""];
WriteString["DiffRecords: "]; WriteLongDecimal[NoAllocDiffRecord]; WriteLine[""];
WriteString["NodeSegments: "]; WriteLongDecimal[NoAllocNodeSegment]; WriteLine[""];
WriteString["NodeLabels: "]; WriteLongDecimal[NoAllocNodeLabel]; WriteLine[""];
WriteString["Strings: "]; WriteLongDecimal[NoAllocString]; WriteLine[""];
END;

PrintTransistors: PUBLIC PROCEDURE =
BEGIN
WriteLine["*** Transistor Count ***"];
WriteString["Enhancement mode Transistors: "]; WriteLongDecimal[NoEnhaTrans]; WriteLine[""];
WriteString["Depletion mode Transistors: "]; WriteLongDecimal[NoDeplTrans]; WriteLine[""];
WriteString["Total Transistors: "]; WriteLongDecimal[NoEnhaTrans+NoDeplTrans]; WriteLine[""];
END;

WriteFloat: PUBLIC PROCEDURE[r: REAL] =
BEGIN
s: STRING ← [50];
AppendReal[s,r];
WriteString[s];
END;

FindTransRatio
: PROCEDURE[area,cir,d1,d2: REAL] RETURNS [l,w: LONG INTEGER] =
BEGIN
W,L,k,j,r,s: REAL;
IF d1 + (d2/1024) >= d2 AND d2 >= d1 - (d2/1024) THEN BEGIN -- d1 = d2
L ← cir/2 - d1;
W ← area/L;
END
ELSE BEGIN
IF d1 > d2 THEN BEGIN-- Insure that d2 > d1
temp: REAL ← d1;
d1 ← d2;
d2 ← temp;
END;
L ← cir/2 - d2;
IF cir > 2.2 * d2 THEN BEGIN -- assume transistor is T shaped
-- transistor can be T shaped only if cir - d1 - d2 > d2 -d1
-- thus only if cir > 2 * d2; 2.2 is a fudge factor.
k ← (area - (d1 * L))/(d2 - d1);-- length of wide part of T
j ← L - k;-- length of skinny part of T
s ← MIN[(d2-d1)/2,k];-- transition length
r ← (j/d1) + (s*2/(d1+d2)) + ((k-s)/d2);-- resistance
W ← L/r;-- effective width
END
ELSE BEGIN-- can’t be T shaped; use heuristic
fudgeFactor: REAL ← SqRt[d2/d1];
L ← (area/d2)*fudgeFactor;
W ← d1*fudgeFactor;
END;
END;
w ← Fix[W*Scale + half];
l ← Fix[L*Scale + half];
END;

SetErrorStream: PUBLIC PROCEDURE[p: BOOLEAN] =
BEGIN
IF p THEN ErrorFlag ← TRUE;
tmpErrorStream ← GetOutputStream[];
SetOutputStream[errorStream];
END;

ResetErrorStream: PUBLIC PROCEDURE[] =
BEGIN
SetOutputStream[tmpErrorStream];
END;

trace: BOOLEAN = FALSE;
-- set if trace output is to be stored in files

END.