-- 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 PROCEDURE RETURNS[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(670)\135b9B1069b11B477b7B43b1B11b7B56b1B27b7B66b7B34b7B45b7B35b7B31b7B43b7B53b7B30b7B52b7B36b7B28b7B32b7B13b7B43b7B65b7B77b7B102b7B50b7B29b7B26b7B48b7B16b7B12b8B228b13B2b7B167b14B2b7B319b14B2b7B289b18B2b7B236b19B2b7B107b7B1791b18B2b7B19b4B195b4B29b4B32b4B35b4B65b4B23b4B19b18B2b7B254b14B2b7B167b15B2b7B498b19B2b7B276b15B2b7B169b7B2b7B1354b15B2b7B113b14B2b7B233b14B2b7B242b14B2b7B85b14B2b7B75b19B2b7B1802v15V591v15V2667v15V388b14B2b7B471b12B2b7B562b13B2b7B179b22B1077b15B2b7B737b17B2b7B56v5V2339b18B2b7B540b15B2b7B353b20B2b7B34b2B7b2B19b2B21b2B18v17V7v17V25b2B27b2B36b2B48b2B35b2B35b2B30b2B18b2B40b2B6b17B2b7B235b14B2b7B130b15B2b7B751b16B2b7B348b10B2b7B88b15B1038b14B2b7B134b16B2b7B END. (986)