-- File DisjointIO.mesa -- Get input from Magic database and make direct calls on Disjoint -- translates and rotates are removed on the fly -- also has routines to output CIF -- Written by Martin Newell/Dan Fitzpatrick, March 1981 -- Last updated (Pilot): August 27, 1981 3:34 PM DIRECTORY AuxIntDefs: FROM "AuxIntDefs" USING [IExpand, IGetRootID, IGetFirstSymbol, IGetNextSymbol, IStop, ISymBB], AuxOutputDefs: FROM "AuxOutputDefs", DisjointIODefs: FROM "DisjointIODefs", DisjointAllocDefs: FROM "DisjointAllocDefs" USING [MakeSymbol, MakeInstance, MakeGeometry, AllocateRectangle, FreeRectangle, EnumerateSymbols], DisjointPropDefs: FROM "DisjointPropDefs" USING [AllocPropID, PutProp, GetProp], DisjointTypes: FROM "DisjointTypes" USING [DisCell, Symbol, Rectangle, Instance, Geometry, PIP, PropID], Inline: FROM "Inline" USING [LowHalf, BITSHIFT, BITAND], IntDefs: FROM "IntDefs" USING [IBoundBox], IntStorageDefs: FROM "IntStorageDefs" USING [ObjectName, NilObjectName], IntTransDefs: FROM "IntTransDefs" USING [Transform, TransformRecord], IODefs: FROM "IODefs" USING [CR, WriteLine, WriteString, WriteDecimal, WriteChar, GetOutputStream, SetOutputStream], JaMFnsDefs: FROM "JaMFnsDefs" USING [GetJaMBreak, SetJaMBreak], ParserTypeDefs: FROM "ParserTypeDefs" USING [Point, Path], Real: FROM "Real" USING [Fix, WriteReal], StreamDefs: FROM "StreamDefs" USING [StreamHandle, NewByteStream, Append, Write], String: FROM "String" USING[AppendDecimal, AppendLongDecimal], SystemDefs: FROM "SystemDefs" USING [AllocateHeapNode, FreeHeapNode]; DisjointIO: PROGRAM IMPORTS AuxIntDefs, DisjointAllocDefs, DisjointPropDefs, Inline, IntDefs, IODefs, JaMFnsDefs, Real, StreamDefs, String, SystemDefs EXPORTS DisjointIODefs, AuxOutputDefs = BEGIN OPEN AuxIntDefs, AuxOutputDefs, DisjointAllocDefs, DisjointPropDefs, DisjointTypes, Inline, IntDefs, IntStorageDefs, IntTransDefs, IODefs, JaMFnsDefs, ParserTypeDefs, Real, StreamDefs, String, SystemDefs; CIFInput: PUBLIC PROCEDURE[allSymbols: BOOLEAN, parent: Symbol] = --Get layout from Magic database and make direct calls on Disjoint --allSymbols is true for ALL symbols, false for REFERENCED only --mainline will be hung on parent BEGIN symbol: ObjectName; cifNum: CARDINAL; orient: CARDINAL; ParentSymbol _ parent; 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[]; [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 CurrentSymbol _ ParentSymbol; Rotation _ 0; Mirror _ FALSE; IExpand[IGetRootID[]]; IF Aborted THEN { Abort[]; RETURN; }; DoTrailer[]; FreeDict[]; END; Abort: PROCEDURE[] = BEGIN WriteLine["***Aborted***"]; DoTrailer[]; FreeDict[]; END; DoHeader: PROCEDURE = BEGIN l,b,r,t: LONG INTEGER; rec,next: Rectangle; window: Rectangle _ AllocateRectangle[]; --set window of parent to be BB of whole layout [l,r,b,t] _ IBoundBox[]; window^ _ [ next: NIL, l:l, b:b, r:r, t:t ]; FOR rec _ ParentSymbol.windows, next UNTIL rec=NIL DO next _ rec.next; FreeRectangle[rec]; ENDLOOP; ParentSymbol.windows _ window; CurrentLayer _ 32000; --i.e. not set END; DoTrailer: PROCEDURE = BEGIN END; DoSymbolHeader: PROCEDURE [symbol: ObjectName, orient: CARDINAL] = BEGIN n: INTEGER; name: STRING _ [20]; l,b,r,t: LONG INTEGER; --set up current Rotation and Mirror from orient Rotation _ BITSHIFT[orient,-1]; Mirror _ BITAND[orient,1]#0; n _ Lookup[symbol,orient]; name.length _ 0; AppendDecimal[name,n]; [l,r,b,t] _ ISymBB[symbol]; --Rotate and mirror bb [l,b] _ RotMirXY[Rotation, Mirror, l,b]; [r,t] _ RotMirXY[Rotation, Mirror, r,t]; CurrentSymbol _ MakeSymbol[name, MIN[l,r],MIN[b,t],MAX[l,r],MAX[b,t]]; SaveLayer _ CurrentLayer; CurrentLayer _ 32000; END; DoSymbolTrailer: PROCEDURE[symbol: ObjectName] = BEGIN CurrentLayer _ SaveLayer; 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 WriteLine["Wire not implemented in CIFDJ"]; END; AuxFlash: PUBLIC PROCEDURE [layerName: CARDINAL, diameter: LONG CARDINAL, center: ParserTypeDefs.Point] = BEGIN WriteLine["Flash not implemented in CIFDJ"]; END; AuxPolygon: PUBLIC PROCEDURE [layerName: CARDINAL, a: ParserTypeDefs.Path] = BEGIN WriteLine["Polygon not implemented in CIFDJ"]; END; AuxBox: PUBLIC PROCEDURE [layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] = BEGIN len,wid,length2,width2: LONG CARDINAL; xc,yc: LONG INTEGER; rot: BOOLEAN; IF GetJaMBreak[] THEN { IStop[]; SetJaMBreak[FALSE]; Aborted _ TRUE; RETURN; }; IF ScanningTopLevel THEN RETURN; IF yRotation#0 AND xRotation#0 THEN { WriteLine["CIFDisjoint - oblique rectangles not implemented"]; RETURN; }; SetLayer[layerName]; rot _ ((Rotation=0 OR Rotation=2) AND yRotation#0) OR ((Rotation=1 OR Rotation=3) AND yRotation=0); --xor IF rot THEN {len _ width; wid _ length; } ELSE {len _ length; wid _ width; }; [xc,yc] _ RotMirXY[Rotation, Mirror, center.x,center.y]; length2 _ len/2; IF length2+length2 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["CIFDJ 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 name.length _ 0; AppendDecimal[name,cifNum]; [] _ MakeInstance[CurrentSymbol, name, tx,ty]; END; two22: LONG INTEGER _ 20000000B; SetLayer: PUBLIC PROCEDURE [layerName: CARDINAL] = BEGIN 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[LOOPHOLE[key,LONG UNSPECIFIED]]; RETURN[i MOD range]; END; --Utilities WriteLongDecimal: PUBLIC PROCEDURE[n: LONG INTEGER] = BEGIN s: STRING _ [50]; AppendLongDecimal[s,n]; WriteString[s]; END; WriteFloat: PUBLIC PROCEDURE[r: REAL] = BEGIN WriteReal[WriteChar,r]; END; -- parameters ScanningTopLevel: BOOLEAN; SaveLayer: CARDINAL; CurrentLayer: CARDINAL; CurrentSymbol: Symbol; ParentSymbol: Symbol; Aborted: BOOLEAN; -- Output Procedures CIFOutput: PUBLIC PROCEDURE [symbol: Symbol, callOnce: BOOLEAN, fileName: STRING] = BEGIN countID: PropID _ AllocPropID[]; markID: PropID _ AllocPropID[]; Mark: PROC[s: Symbol] RETURNS[BOOLEAN] = BEGIN -- mark = 1 means symbol has not yet been output -- count#0 means symbol can still be called count _ count + 1; PutProp[@s.prop,markID,1]; PutProp[@s.prop,countID,count]; RETURN[FALSE]; END; WriteSymbolNumber: PROC[s: Symbol] = BEGIN --str: STRING _ [50]; --AppendLongNumber[str,s,8]; --WriteString[str]; WriteDecimal[GetProp[s.prop,countID]]; END; WriteLongDecimal: PROC[n: LONG INTEGER] = BEGIN str: STRING _ [50]; AppendLongDecimal[str,n]; WriteString[str]; END; Out: PROC[s: Symbol] RETURNS[BOOLEAN] = BEGIN PutProp[@s.prop,markID,0]; FOR in: Instance _ s.insts,in.next UNTIL in = NIL DO IF GetProp[in.symbol.prop,markID] = 1 THEN [] _ Out[in.symbol]; ENDLOOP; WriteLine[""]; WriteString["DS "]; WriteSymbolNumber[s]; WriteLine[";"]; -- write geometry FOR g:Geometry _ s.geom,g.next UNTIL g = NIL DO WriteString["L N"]; WriteChar[LayerChar[g.layer]]; -- layer WriteString["; B "]; WriteLongDecimal[Fix[g.r-g.l]]; WriteString[" "]; -- length WriteLongDecimal[Fix[g.t-g.b]]; WriteString[" "]; -- width WriteLongDecimal[Fix[(g.r+g.l)/2]]; WriteString[" "]; -- x Center WriteLongDecimal[Fix[(g.t+g.b)/2]]; WriteLine[";"]; -- y Center ENDLOOP; FOR in: Instance _ s.insts,in.next UNTIL in = NIL DO IF GetProp[in.symbol.prop,countID]#0 THEN { WriteString["C "]; WriteSymbolNumber[in.symbol]; WriteString[" T "]; WriteLongDecimal[Fix[in.xOffset]]; WriteString[" "]; WriteLongDecimal[Fix[in.yOffset]]; WriteLine[";"]; IF callOnce THEN PutProp[@in.symbol.prop,countID,0]; }; ENDLOOP; WriteLine["DF;"]; RETURN[FALSE]; END; count: CARDINAL _ 0; IF symbol # NIL THEN { cifFile: StreamHandle _ NewByteStream[fileName,Write+Append]; default: StreamHandle _ GetOutputStream[]; cifFile.reset[cifFile]; SetOutputStream[cifFile]; WriteString["(Generated by Disjoint from symbol "]; WriteString[symbol.name]; WriteLine[");"]; -- mark all the symbols [] _ EnumerateSymbols[Mark]; [] _ Out[symbol]; WriteLine[""]; WriteString["C "]; WriteSymbolNumber[symbol]; WriteLine[";"]; cifFile.destroy[cifFile]; SetOutputStream[default]; WriteDecimal[count]; WriteString[" symbols from "]; WriteString[symbol.name]; WriteString[" in "]; WriteLine[fileName]; }; END; PrintDisCells: PUBLIC PROCEDURE[disCellList: DisCell] = BEGIN FOR dc:DisCell _ disCellList, dc.next UNTIL dc=NIL DO PrintDisCell[dc]; ENDLOOP; END; PrintDisCell: PUBLIC PROCEDURE[disCell: DisCell] = BEGIN OPEN disCell; w: DisjointTypes.Rectangle; WriteLine["DisCell"]; WriteString[" geom: "]; FOR g:Geometry _ disCell.geom, g.next UNTIL g=NIL DO WriteChar['[]; WriteChar['N]; WriteChar[LayerChar[g.layer]]; WriteChar[',]; WriteReal[WriteChar, g.l]; WriteChar[',]; WriteReal[WriteChar, g.b]; WriteChar[',]; WriteReal[WriteChar, g.r]; WriteChar[',]; WriteReal[WriteChar, g.t]; WriteChar[']]; ENDLOOP; WriteChar[CR]; WriteString[" instances: "]; FOR p:PIP _ disCell.insts, p.next UNTIL p=NIL DO i: Instance _ p.inst; WriteString["{"""]; WriteString[i.symbol.name]; WriteChar['"]; WriteChar[',]; WriteReal[WriteChar, i.xOffset]; WriteChar[',]; WriteReal[WriteChar, i.yOffset]; WriteChar['}]; ENDLOOP; WriteChar[CR]; WriteString[" windows: "]; FOR w _ disCell.windows, w.next UNTIL w=NIL DO WriteChar['[]; WriteReal[WriteChar, w.l]; WriteChar[',]; WriteReal[WriteChar, w.b]; WriteChar[',]; WriteReal[WriteChar, w.r]; WriteChar[',]; WriteReal[WriteChar, w.t]; WriteChar[']]; ENDLOOP; WriteChar[CR]; END; PrintSymbols: PUBLIC PROCEDURE = BEGIN PS: PROC[s: Symbol] RETURNS[BOOLEAN] = BEGIN PrintSymbol[s]; RETURN[FALSE]; END; [] _ EnumerateSymbols[PS]; END; PrintSymbol: PUBLIC PROCEDURE[s: Symbol] = BEGIN w: DisjointTypes.Rectangle; WriteString["Symbol: "]; WriteLine[s.name]; WriteString[" geom: "]; FOR g:Geometry _ s.geom, g.next UNTIL g=NIL DO WriteChar['[]; WriteChar['N]; WriteChar[LayerChar[g.layer]]; WriteChar[',]; WriteReal[WriteChar,g.l]; WriteChar[',]; WriteReal[WriteChar,g.b]; WriteChar[',]; WriteReal[WriteChar,g.r]; WriteChar[',]; WriteReal[WriteChar,g.t]; WriteChar[']]; ENDLOOP; WriteChar[CR]; WriteString[" instances: "]; FOR i:Instance _ s.insts,i.next UNTIL i=NIL DO WriteString["{"""]; WriteString[i.symbol.name]; WriteChar['"]; WriteChar[',]; WriteReal[WriteChar,i.xOffset]; WriteChar[',]; WriteReal[WriteChar,i.yOffset]; WriteChar['}]; ENDLOOP; WriteChar[CR]; WriteString[" windows: "]; FOR w _ s.windows, w.next UNTIL w=NIL DO WriteChar['[]; WriteReal[WriteChar,w.l]; WriteChar[',]; WriteReal[WriteChar,w.b]; WriteChar[',]; WriteReal[WriteChar,w.r]; WriteChar[',]; WriteReal[WriteChar,w.t]; WriteChar[']]; ENDLOOP; WriteChar[CR]; END; LayerChar: ARRAY [0..15] OF CHARACTER _ ALL['X]; --Set up CIF Layer names 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 END. (672)\11709b16B113b10B