-- 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 filename> (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]<object>
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.