-- File CIFTran.mesa -- Output module for CIF 2.0 -- Written by Martin Newell, March 1981 -- Last updated: June 15, 1981 3:45 PM DIRECTORY AuxIntDefs: FROM "AuxIntDefs" USING [IExpand, IGetRootID, IGetFirstSymbol, IGetNextSymbol, IStop], AuxOutputDefs: FROM "AuxOutputDefs", CIFDevicesDefs: FROM "CIFDevicesDefs" USING [DeviceDescriptor, DeviceDescriptorRecord, RegisterDevice, MaxLENGTHLayerArray], CIFUtilitiesDefs: FROM "CIFUtilitiesDefs" USING [Rectangle, SetClipRectangle, DrawClipRectangle, GetDisplayContext], Graphics: FROM "Graphics" USING [DisplayContext, PopContext, PushContext, Scale], InlineDefs: FROM "InlineDefs" USING [LowHalf, BITSHIFT, BITAND], IntStorageDefs: FROM "IntStorageDefs" USING [ObjectName, NilObjectName], IntTransDefs: FROM "IntTransDefs" USING [Transform, TransformRecord], IODefs: FROM "IODefs" USING [CR, SP, NUL, WriteLine, WriteString, WriteChar, GetOutputStream, SetOutputStream, WriteDecimal], JaMFnsDefs: FROM "JaMFnsDefs" USING [PopString, GetJaMBreak, SetJaMBreak, PopBoolean], ParserTypeDefs: FROM "ParserTypeDefs" USING [Point, Path, RemovePoint], Real: FROM "Real" USING [Fix, WriteReal], StreamDefs: FROM "StreamDefs" USING [StreamHandle, NewByteStream, Write, Append], StringDefs: FROM "StringDefs" USING[AppendChar, AppendString, AppendLongDecimal], SystemDefs: FROM "SystemDefs" USING [AllocateHeapNode, FreeHeapNode]; CIFTran: PROGRAM IMPORTS AuxIntDefs, CIFDevicesDefs, CIFUtilitiesDefs, Graphics, InlineDefs, IODefs, JaMFnsDefs, ParserTypeDefs, Real, StreamDefs, StringDefs, SystemDefs EXPORTS AuxOutputDefs = BEGIN OPEN AuxIntDefs, AuxOutputDefs, CIFDevicesDefs, CIFUtilitiesDefs, Graphics, InlineDefs, IntStorageDefs, IntTransDefs, IODefs, JaMFnsDefs, ParserTypeDefs, Real, StreamDefs, StringDefs, SystemDefs; -- CIF procedures CIFDeviceRecord: DeviceDescriptorRecord _ [ next: NIL, name: "ciftran", deviceSelect: CIFSelect, deviceDrawFrame: CIFDrawFrame, deviceSetScale: CIFSetScale, deviceSetClipRegion: CIFSetClipRegion, deviceOutput: CIFOutput, deviceLayer: CIFLayer, deviceLoadLayer: CIFLoadLayer, deviceRectangle: CIFRectangle, deviceStartPoly: CIFStartPoly, devicePolyVertex: CIFPolyVertex, deviceEndPoly: CIFEndPoly, deviceText: CIFText ]; --the following types are copied from CIFOutput UserObjectType: TYPE = {User9, User94, other}; UserObject: TYPE = POINTER TO UserObjectRecord; UserObjectRecord: TYPE = RECORD[ SELECT type: UserObjectType FROM User9 => [ --Symbol name name: PACKED ARRAY [0..0) OF CHARACTER], User94 => [ --Named point x: REAL, y: REAL, name: PACKED ARRAY [0..0) OF CHARACTER], ENDCASE]; CIFSelect: PROCEDURE RETURNS[BOOLEAN] = BEGIN RETURN[TRUE]; END; CIFDrawFrame: PROCEDURE = BEGIN DrawClipRectangle[]; END; CIFSetScale: PROCEDURE [factor: REAL] = BEGIN dc: DisplayContext _ GetDisplayContext[]; PopContext[dc]; PushContext[dc]; Scale[dc, [factor,factor]]; END; CIFSetClipRegion: PROCEDURE [rt: Rectangle] = BEGIN SetClipRectangle[rt]; END; CIFOutput: PROCEDURE = --expects (boolean is true for ALL symbols, false for REFERENCED only) BEGIN symbol: ObjectName; cifNum: CARDINAL; fileName: STRING _ [100]; allSymbols: BOOLEAN; orient: CARDINAL; PopString[fileName]; allSymbols _ PopBoolean[]; IF ~DotinName[fileName] THEN AppendString[fileName,".cif"]; Aborted _ FALSE; InitDict[256]; IF allSymbols THEN --get handle on all symbols, even if not referenced { FOR s:ObjectName _ IGetFirstSymbol[],IGetNextSymbol[] UNTIL s=NilObjectName DO [] _ Lookup[s, 0]; ENDLOOP; }; --provoke initial entries in dictionary ScanningTopLevel _ TRUE; Rotation _ 0; Mirror _ FALSE; IExpand[IGetRootID[]]; IF Aborted THEN { Abort[]; RETURN; }; ScanningTopLevel _ FALSE; --output symbols DoHeader[fileName]; [symbol,orient,cifNum] _ GetNonProcessedEntry[]; UNTIL cifNum=0 DO DoSymbolHeader[symbol,orient]; IExpand[symbol]; IF Aborted THEN { Abort[]; RETURN; }; DoSymbolTrailer[symbol]; [symbol,orient,cifNum] _ GetNonProcessedEntry[]; ENDLOOP; --output mainline CIFStream.put[CIFStream,CR]; Rotation _ 0; Mirror _ FALSE; IExpand[IGetRootID[]]; IF Aborted THEN { Abort[]; RETURN; }; DoTrailer[]; FreeDict[]; END; Abort: PROCEDURE[] = BEGIN save: StreamHandle _ GetOutputStream[]; SetOutputStream[CIFStream]; WriteLine["***Aborted***"]; SetOutputStream[save]; WriteLine["***Aborted***"]; DoTrailer[]; FreeDict[]; END; DoHeader: PROCEDURE[fileName: STRING] = BEGIN save: StreamHandle _ GetOutputStream[]; CIFStream _ NewByteStream[fileName, Write+Append]; SetOutputStream[CIFStream]; WriteString["(File: "]; WriteString[fileName]; WriteLine[". Created by CIFTran to have no Rotations or Mirrors);"]; SetOutputStream[save]; CurrentLayer _ 32000; --i.e. not set END; DoTrailer: PROCEDURE = BEGIN save: StreamHandle _ GetOutputStream[]; SetOutputStream[CIFStream]; WriteLine["End"]; SetOutputStream[save]; CIFStream.destroy[CIFStream]; CIFStream _ NIL; END; DoSymbolHeader: PROCEDURE [symbol: ObjectName, orient: CARDINAL] = BEGIN save: StreamHandle _ GetOutputStream[]; Rotation _ BITSHIFT[orient,-1]; Mirror _ BITAND[orient,1]#0; SetOutputStream[CIFStream]; WriteChar[CR]; WriteString["DS "]; WriteDecimal[Lookup[symbol,orient]]; WriteLine[";"]; SaveLayer _ CurrentLayer; CurrentLayer _ 32000; SetOutputStream[save]; END; DoSymbolTrailer: PROCEDURE[symbol: ObjectName] = BEGIN save: StreamHandle _ GetOutputStream[]; SetOutputStream[CIFStream]; WriteLine["DF;"]; SetOutputStream[save]; CurrentLayer _ SaveLayer; END; CIFLayer: PROCEDURE [layer: CARDINAL] = BEGIN END; CIFLoadLayer: PROCEDURE[layer:CARDINAL, v0,v1,v2,v3: CARDINAL] = BEGIN END; CIFRectangle: PROCEDURE [r: Rectangle] = BEGIN END; CIFStartPoly: PROCEDURE [x,y: REAL] = BEGIN END; CIFPolyVertex: PROCEDURE [x,y: REAL] = BEGIN END; CIFEndPoly: PROCEDURE = BEGIN END; CIFText: PROCEDURE[text: STRING, x,y: REAL] = BEGIN END; --Orientation is packed as a 3 bit field, [0..3][0..1] representing ccw rotation in units of 90 degrees, and mirroring of the x coordinate. These are considered to be applied to the object in the order: mirror, rotation. Rotation: CARDINAL; --current ccw rotation of symbol being expanded Mirror: BOOLEAN; --current mirror status of symbol being expanded --Procedures that export AuxOutputDefs-- AuxWire: PUBLIC PROCEDURE [layerName: CARDINAL, width: LONG CARDINAL, a: ParserTypeDefs.Path] = BEGIN save: StreamHandle _ GetOutputStream[]; gotone: BOOLEAN; p: Point; IF ScanningTopLevel THEN RETURN; IF a.length=0 THEN RETURN; SetOutputStream[CIFStream]; SetLayer[layerName]; WriteString["W "]; WriteLongDecimal[width]; [gotone,p] _ RemovePoint[a]; WHILE gotone DO x,y: LONG INTEGER; [x,y] _ RotMirXY[Rotation, Mirror, p.x,p.y]; WriteChar[SP]; WriteLongDecimal[x]; WriteChar[SP]; WriteLongDecimal[y]; [gotone,p] _ RemovePoint[a]; ENDLOOP; WriteLine[";"]; SetOutputStream[save]; END; AuxFlash: PUBLIC PROCEDURE [layerName: CARDINAL, diameter: LONG CARDINAL, center: ParserTypeDefs.Point] = BEGIN save: StreamHandle _ GetOutputStream[]; xc,yc: LONG INTEGER; IF ScanningTopLevel THEN RETURN; SetOutputStream[CIFStream]; SetLayer[layerName]; WriteString["R "]; WriteLongDecimal[diameter]; [xc,yc] _ RotMirXY[Rotation, Mirror, center.x,center.y]; WriteChar[SP]; WriteLongDecimal[xc]; WriteChar[SP]; WriteLongDecimal[yc]; WriteLine[";"]; SetOutputStream[save]; END; AuxPolygon: PUBLIC PROCEDURE [layerName: CARDINAL, a: ParserTypeDefs.Path] = BEGIN save: StreamHandle _ GetOutputStream[]; gotone: BOOLEAN; p: Point; IF ScanningTopLevel THEN RETURN; IF a.length=0 THEN RETURN; SetOutputStream[CIFStream]; SetLayer[layerName]; WriteString["P"]; [gotone,p] _ RemovePoint[a]; WHILE gotone DO x,y: LONG INTEGER; [x,y] _ RotMirXY[Rotation, Mirror, p.x,p.y]; WriteChar[SP]; WriteLongDecimal[x]; WriteChar[SP]; WriteLongDecimal[y]; [gotone,p] _ RemovePoint[a]; ENDLOOP; WriteLine[";"]; SetOutputStream[save]; END; AuxBox: PUBLIC PROCEDURE [layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] = BEGIN save: StreamHandle _ GetOutputStream[]; len,wid: LONG CARDINAL; xc,yc: LONG INTEGER; IF GetJaMBreak[] THEN { IStop[]; SetJaMBreak[FALSE]; Aborted _ TRUE; RETURN; }; IF ScanningTopLevel THEN RETURN; SetOutputStream[CIFStream]; SetLayer[layerName]; IF Rotation=0 OR Rotation=2 THEN {len _ length; wid _ width; } ELSE {len _ width; wid _ length; }; [xc,yc] _ RotMirXY[Rotation, Mirror, center.x,center.y]; WriteString["B "]; WriteLongDecimal[len]; WriteChar[SP]; WriteLongDecimal[wid]; WriteChar[SP]; WriteLongDecimal[xc]; WriteChar[SP]; WriteLongDecimal[yc]; IF yRotation#0 OR xRotation<0 THEN { WriteChar[SP]; WriteLongDecimal[xRotation]; --still applies WriteChar[SP]; WriteLongDecimal[yRotation]; }; WriteLine[";"]; SetOutputStream[save]; END; AuxUserObject: PUBLIC PROCEDURE [layerName: CARDINAL, size: CARDINAL, data: POINTER TO UNSPECIFIED] = BEGIN userObject: UserObject _ data; save: StreamHandle _ GetOutputStream[]; IF ScanningTopLevel THEN RETURN; WITH userObject SELECT FROM User9 => { string: STRING _ [100]; i,stringlength: INTEGER; SetOutputStream[CIFStream]; stringlength _ (size-SIZE[User9 UserObjectRecord])*2; FOR i IN [0..stringlength) DO AppendChar[string,IF name[i]=SP THEN '* ELSE name[i]]; ENDLOOP; IF stringlength>0 AND name[stringlength-1]=NUL THEN string.length _ string.length - 1; WriteString["9 "]; WriteString[string]; WriteLine[";"]; SetOutputStream[save]; }; User94 => { string: STRING _ [100]; i,stringlength: INTEGER; xp,yp: LONG INTEGER; SetOutputStream[CIFStream]; stringlength _ (size-SIZE[User94 UserObjectRecord])*2; FOR i IN [0..stringlength) DO AppendChar[string,IF name[i]=SP THEN '* ELSE name[i]]; ENDLOOP; IF stringlength>0 AND name[stringlength-1]=NUL THEN string.length _ string.length - 1; WriteString["94 "]; WriteString[string]; [xp,yp] _ RotMirXY[Rotation, Mirror, Fix[x],Fix[y]]; WriteChar[SP]; WriteLongDecimal[xp]; WriteChar[SP]; WriteLongDecimal[yp]; WriteLine[";"]; SetOutputStream[save]; }; ENDCASE => WriteLine["unknown user object"]; END; AuxCall: PUBLIC PROCEDURE [symbol: ObjectName, cifNumber: LONG CARDINAL, transform: Transform] = BEGIN save: StreamHandle _ GetOutputStream[]; t: TransformRecord; mx: BOOLEAN _ FALSE; rot: INTEGER _ 0; tx: LONG INTEGER _ 0; ty: LONG INTEGER _ 0; orient: INTEGER; c,s: REAL; cifNum: INTEGER; --unpick transform in [tran][rot][mx] t _ transform^; --get local mirror IF (t.a11*t.a22-t.a21*t.a12)<0 THEN --determinant negative - need mirror { t.a11 _ -t.a11; t.a12 _ -t.a12; mx _ TRUE; }; --get local rotate c _ t.a11/t.a33; s _ t.a12/t.a33; IF s#0 OR c<0 THEN { SELECT TRUE FROM c=0 => rot _ IF s<0 THEN 3 ELSE 1; s=0 => rot _ IF c<0 THEN 2 ELSE 4; ENDCASE => WriteLine["CIFTran can't handle non-90 degree rotations"]; }; --get local translation IF t.a31#0 OR t.a32#0 THEN {tx _ Fix[t.a31/t.a33]; ty _ Fix[t.a32/t.a33];}; --compose local transformation with current Rotation and Mirror IF Mirror THEN { rot _ (4-rot) MOD 4; mx _ NOT mx; }; IF Rotation#0 THEN rot _ (rot + Rotation) MOD 4; [tx,ty] _ RotMirXY[Rotation, Mirror, tx,ty]; orient _ (rot + rot) + (IF mx THEN 1 ELSE 0); --look up symbol, either to make initial entry or to use it cifNum _ Lookup[symbol,orient]; --need to do this always IF ScanningTopLevel THEN RETURN; --output call with only translate SetOutputStream[CIFStream]; WriteString["C "]; WriteLongDecimal[cifNum]; IF tx#0 OR ty#0 THEN { WriteString[" T "]; WriteLongDecimal[tx]; WriteChar[SP]; WriteLongDecimal[ty]; }; WriteLine[";"]; SetOutputStream[save]; END; two22: LONG INTEGER _ 10000000000B; SetLayer: PUBLIC PROCEDURE [layerName: CARDINAL] = BEGIN IF CurrentLayer#layerName THEN { save: StreamHandle _ GetOutputStream[]; SetOutputStream[CIFStream]; WriteString["L N"]; WriteChar[LayerChar[layerName]]; WriteString["; "]; SetOutputStream[save]; CurrentLayer _ layerName; }; END; RotMirXY: PROCEDURE [r: INTEGER, m: BOOLEAN, x,y: LONG UNSPECIFIED] RETURNS[LONG UNSPECIFIED,LONG UNSPECIFIED] = -- mirror x,y in x if m TRUE, then rotate result by r*90 degrees --works for both REAL and LONG INTEGER for x and y BEGIN IF m THEN x _ -x; SELECT r FROM 0 => RETURN[x,y]; 1 => RETURN[-y,x]; 2 => RETURN[-x,-y]; 3 => RETURN[y,-x]; ENDCASE => { x1,y1: LONG UNSPECIFIED; [x1,y1] _ RotMirXY[r MOD 4, FALSE, x,y]; RETURN[x1,y1]; }; END; --Dictionary --Each entry in the dictionary has an ObjectName for a key, and an array of CARDINALs for values. On Lookup, both the ObjectName and an index are provided, and the indexed entry in the corresponding entry is returned as the value DictEntry: TYPE = POINTER TO DictEntryRecord; DictEntryRecord: TYPE = RECORD [ next: DictEntry, --global list in order in which entries are made ovflow: DictEntry, --overflow list from entry in hash table key: ObjectName, --internal ID of symbol value: ARRAY [0..7] OF INTEGER --generated CIF symbols # for output, one for each possible rotation and mirroring. -ve means not yet processed and symbol is -.value[i], 0 means unset ]; DictHead: DictEntry; DictTail: DictEntry; HTable: DESCRIPTOR FOR ARRAY OF DictEntry; LastProcessedEntry: DictEntry; --points to last processed entry Value: CARDINAL; InitDict: PROCEDURE[hashlength: CARDINAL] = BEGIN i: CARDINAL; DictHead _ NIL; DictTail _ NIL; HTable _ DESCRIPTOR[AllocateHeapNode[hashlength*SIZE[DictEntry]],hashlength]; FOR i IN [0..hashlength) DO HTable[i] _ NIL; ENDLOOP; LastProcessedEntry _ NIL; Value _ 0; END; Lookup: PROCEDURE[key: ObjectName, index: CARDINAL] RETURNS[INTEGER] = --Return value[index] associated with key. If key not found, or -- value[index] not set, then generate a value, and return it. BEGIN de: DictEntry; h: CARDINAL; [de,h] _ Where[key]; IF de=NIL THEN { de _ AllocateHeapNode[SIZE[DictEntryRecord]]; de^ _ [ next: NIL, ovflow: HTable[h], key: key, value: ALL[0]]; HTable[h] _ de; IF DictTail=NIL THEN DictHead _ DictTail _ de ELSE { DictTail.next _ de; DictTail _ de; }; }; IF de.value[index]=0 THEN { Value _ Value + 1; de.value[index] _ -Value; --sign bit used to indicate not yet expanded }; RETURN[ABS[de.value[index]]]; END; GetNonProcessedEntry: PROCEDURE RETURNS[key: ObjectName, index: CARDINAL, value: CARDINAL] = --Search all entries, starting at LastProcessedEntry, and return its key, index, and value, if any, having marked it as processed BEGIN startEntry: DictEntry _ LastProcessedEntry; DO --check LastProcessedEntry to see if it contains any unprocessed element IF LastProcessedEntry#NIL THEN { FOR i:CARDINAL IN [0..7] DO IF LastProcessedEntry.value[i]<0 THEN { LastProcessedEntry.value[i] _ -LastProcessedEntry.value[i]; RETURN[LastProcessedEntry.key, i, LastProcessedEntry.value[i]]; }; ENDLOOP; }; --step LastProcessedEntry by one IF LastProcessedEntry=NIL THEN LastProcessedEntry _ DictHead ELSE LastProcessedEntry _ LastProcessedEntry.next; -- IF LastProcessedEntry=startEntry THEN RETURN[NilObjectName,0,0]; --been all round ENDLOOP; END; FreeDict: PROCEDURE = BEGIN de,nextde: DictEntry; FOR de _ DictHead, nextde UNTIL de=NIL DO nextde _ de.next; FreeHeapNode[de]; ENDLOOP; FreeHeapNode[BASE[HTable]]; END; Where: PROCEDURE[key: ObjectName] RETURNS[de: DictEntry, h: CARDINAL] = --h is result of hashing name BEGIN h _ Hash[key, LENGTH[HTable]]; FOR de _ HTable[h], de.ovflow UNTIL de=NIL OR key=de.key DO --nothing-- ENDLOOP; END; Hash: PROCEDURE[key: ObjectName, range: CARDINAL] RETURNS[h: CARDINAL] = --h is result of hashing name into [0..range) BEGIN i: CARDINAL _ LowHalf[key]; RETURN[i MOD range]; END; --Utilities WriteLongDecimal: PROCEDURE[n: LONG INTEGER] = BEGIN s: STRING _ [50]; AppendLongDecimal[s,n]; WriteString[s]; END; WriteFloat: PROCEDURE[r: REAL] = BEGIN WriteReal[WriteChar,r]; END; DotinName: PROCEDURE[name: STRING] RETURNS[BOOLEAN] = BEGIN FOR i:CARDINAL IN [0..name.length) DO IF name[i]='. THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; --CIF parameters ScanningTopLevel: BOOLEAN; CIFStream: StreamHandle _ NIL; SaveLayer: CARDINAL; CurrentLayer: CARDINAL; Aborted: BOOLEAN; LayerChar: ARRAY [0..MaxLENGTHLayerArray) OF CHARACTER _ ALL['X]; LayerChar[0] _ 'I; --implant LayerChar[1] _ 'D; --diffusion LayerChar[2] _ 'P; --poly LayerChar[3] _ 'C; --contact LayerChar[4] _ 'M; --metal LayerChar[5] _ 'B; --buried LayerChar[6] _ 'G; --glass LayerChar[7] _ 'X; --undef --set up context RegisterDevice[@CIFDeviceRecord]; END. (635)\131b9B1241b7B920b14B33b10B38b16B231b9B60b12B50b11B150b16B67b9B1226b5B209b8B349b9B190b14B364b15B188b8B46b12B67b12B43b12B40b13B40b10B28b7B453b7B604b8B483b10B556b6B925b13B1343b7B1575b8B295b8B1307b8B273b6B683b20B860b8B173b5B228b4B193b16B106b10B62b9B