CDToCifImpl.mesa  
Copyright c 1984, 1986, 1987 by Xerox Corporation. All rights reserved.
Last Edited by: Kimr, October 15, 1984 5:15:13 pm PDT
Last Edited by: Christian Jacobi, June 5, 1987 6:31:34 pm PDT
Christian Le Cocq March 29, 1988 9:53:02 am PST
Last Edited by McCreight, October 17, 1984 7:02:18 pm PDT
A package to output CIF files from ChipNDale, from BrandyCifter.mesa
DIRECTORY
CD,
CDBasics,
CDCells,
CDCurves,
CDDefaultProcs,
CDDirectory,
CDImports,
CDInstances,
CDOps,
CDRoutingObjects,
CDToCif,
CDProperties,
CDPropertyTools,
CDSatellites,
CDSequencer,
CDTexts,
CDVArrow,
CStitching,
IO,
List USING [Append],
RefTab,
Rope,
TerminalIO;
CDToCifImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDCurves, CDDefaultProcs, CDDirectory, CDInstances, CDOps, CDProperties, CDPropertyTools, CDRoutingObjects, CDSatellites, CDSequencer, CDTexts, --CDVArrow,-- CStitching, IO, List, RefTab, Rope, TerminalIO
EXPORTS CDToCif
~ BEGIN
CIFUnits: TYPE = CD.Number;
CIFPos: TYPE = CD.Position -- in CIFUnits -- ;
CIFRect: TYPE = CD.Rect -- in CIFUnits -- ;
Rational: TYPE = RECORD [num, denom: INT ← 1];
CIFDest: TYPE = REF CIFDestRec ← NIL;
CIFDestRec: TYPE = RECORD [
cifDest: Rope.ROPE,
deltaRadius: INT -- nanometers, + means cif is bigger
];
CIFDirective: TYPE = REF CIFDirectiveRec ← NIL;
CIFDirectiveRec: TYPE = RECORD [
cdSource: CD.Layer,
cifDest: Rope.ROPE,
deltaRadius: INT -- nanometers, + means cif is bigger
];
MaskStateRef: TYPE = REF MaskState;
MaskState: TYPE = RECORD [
areas, unbloated: CStitching.Tesselation ← NIL,
partClip: CIFRect ← [0,0,0,0],
cifH: WrCIFHandle
];
WrCIFHandle: TYPE = REF WrCIFHandleRec;
WrCIFHandleRec: TYPE = RECORD [
design: CD.Design,
cifDirectives: LIST OF REF ANYNIL, -- CIFDirective
specialProperties: CDProperties.PropRef,
stopFlag: REF BOOL,
errorFound: REFNIL,
cellCount: INT ← 0, -- to assign consecutive CIF ID numbers
cifPerLambda: INT ← 100,
nmPerCIF: INT ← 10,
cifFile: IO.STREAM,
cifScaling: Rational,
sharedCxFilter: REF CD.ContextFilter,
lastCellName: Rope.ROPE,
currentDirective: CIFDirective,
mainRect: CD.Rect,
flattenAtomics: BOOLEAN,
cifLayerAnnounced: BOOLEAN,
obToIdTab: RefTab.Ref
];
Global Variables
cellIDKey: REF ATOM = NEW[ATOM ← $CellIDNo]; --not accessible
debugging: BOOLFALSE; -- for printing out debugging messages
satellitesSignals: BOOLTRUE; -- whether satellites should contribute signal names
mainRect: CD.Rect ← CDBasics.empty;
set to design size in CIFMeasureArea, used to switch between ChipNDale and CIF coordinate systems
partWidth: CIFUnits ← 800000; -- window for flat CIF
partHeight: CIFUnits ← 800000;
SimpleRect: PROC [ob: CD.Object] RETURNS [yes: BOOL] = INLINE {
yes ← ob.class.wireTyped AND ob.class.objectType=$Rect
};
MakeCall: PROC [ob: CD.Object, cifH: WrCIFHandle] RETURNS [yes: BOOL] = {
IF SimpleRect[ob] THEN RETURN [FALSE];
IF ob.class.symbolic THEN RETURN [FALSE];
IF cifH.flattenAtomics THEN {
IF ob.class.wireTyped THEN RETURN [FALSE];
IF ob.class.technology#NIL THEN RETURN [FALSE];
IF ob.class=CDRoutingObjects.routingClass THEN RETURN [FALSE];
};
IF CDTexts.IsText[ob] THEN {
FOR dir: LIST OF REF ANY ← cifH.cifDirectives, dir.rest WHILE dir#NIL DO
directive: CIFDirective ← NARROW[dir.first];
IF directive.cdSource=ob.layer THEN RETURN [TRUE];
ENDLOOP;
RETURN [FALSE];
};
RETURN [TRUE];
};
SetUpSpecialClasses: PROC [design: CD.Design] RETURNS [specialProperties: CD.PropRef ← CD.InitPropRef[]] = {
x: REF ← CDProperties.GetProp[$CDxCIFRegistrations, $CDxCIFTechnology];
IF design.technology.key#x AND design.technology#x THEN {
IF x=NIL THEN TerminalIO.PutRope["CIF commandfile not set up\n"]
ELSE TerminalIO.PutRope["CIF commandfile set up for different technology\n"];
ERROR ABORTED
};
WITH CDProperties.GetProp[$CDxCIFRegistrations, $CDxCIFSpecials] SELECT FROM
pRef: CDProperties.PropRef => specialProperties ← pRef;
ENDCASE => specialProperties ← CDProperties.InitPropRef[];
flattenAtomics ← CDProperties.GetProp[$CDxCIFRegistrations, $CDxFlattenAtomic]=$TRUE;
};
IsSpecialCase: PROC [ob: CD.Object, cifH: WrCIFHandle] RETURNS [yes: BOOLFALSE] = {
yes ← CDProperties.GetListProp[cifH.specialProperties^, ob.class.objectType]#NIL
};
HandleSpecialCase: PROC [ob: CD.Object, cifH: WrCIFHandle] = {
WITH CDProperties.GetListProp[cifH.specialProperties^, ob.class.objectType] SELECT FROM
rp: REF PROC [ob: CD.Object] RETURNS [Rope.ROPE] => {
r: Rope.ROPE ← rp^[ob];
IO.PutRope[cifH.cifFile, r];
};
r: Rope.ROPE => {
IO.PutRope[cifH.cifFile, r];
};
rt: REF TEXT => {
IO.PutText[cifH.cifFile, rt];
};
ENDCASE => {
TerminalIO.PutRope["object class handled specialy is inconsistent\n"];
ERROR
};
};
SymHeader: PROC [obj: CD.Object, cifH: WrCIFHandle] = {
start outputting a new cell and assign its cellID
cellID: REF INTNEW[INT ← (cifH.cellCount ← cifH.cellCount + 1)];
cifH.cifFile.PutF["DS %d %d %d;\n\l",
IO.int[cifH.cellCount], IO.int[cifH.cifScaling.num], IO.int[cifH.cifScaling.denom]];
CDProperties.PutObjectProp[obj, cellIDKey, cellID];
[] ← RefTab.Store[cifH.obToIdTab, obj, cellID];
};
UnfinishedSymHeader: PROC [obj: CD.Object, cifH: WrCIFHandle] = {
start outputting a new cell and assign its cellID
but don't output the scaling
cellID: REF INTNEW[INT ← (cifH.cellCount ← cifH.cellCount + 1)];
cifH.cifFile.PutF["DS %d ", IO.int[cifH.cellCount]];
CDProperties.PutObjectProp[obj, cellIDKey, cellID];
[] ← RefTab.Store[cifH.obToIdTab, obj, cellID];
};
SymTrailer: PROC[cifFile: IO.STREAM] = {
finish off cell description
cifFile.PutRope["DF;\n\l"];
};
CallChildren: CD.DrawProc = {
cifH: WrCIFHandle ← NARROW[pr.devicePrivate];
IF MakeCall[ob, cifH] THEN
CIFSymbolCall[ob, trans.orient, CDPosToCIF[trans.off, cifH], cifH];
};
DrawRectChilds: CD.DrawProc = {
cifH: WrCIFHandle ← NARROW[pr.devicePrivate];
IF ~MakeCall[ob, cifH] THEN
CD.DrawOb[ob: ob, trans: trans, pr: pr, readOnlyInstProps: readOnlyInstProps];
};
GenerateCompositeOb: PROC [obj: CD.Object, cifH: WrCIFHandle] = {
output composite objects
the children must be already defined
cf: REF CD.ContextFilter ← NEW[CD.ContextFilter←ALL[FALSE]];
pr: CD.DrawRef;
SymHeader[obj, cifH];
CIFDrawCellName[CDDirectory.Name[obj, cifH.design], cifH];
call the children
pr ← CD.CreateDrawRef[[
stopFlag: cifH.stopFlag,
drawChild: CallChildren,
drawRect: IgnoreRect,
drawContext: IgnoreContext,
devicePrivate: cifH,
design: cifH.design
]];
CD.DrawOb[pr, obj];
draw the rectangles
pr ← CD.CreateDrawRef[[
stopFlag: cifH.stopFlag,
drawChild: DrawRectChilds,
drawRect: CIFOrArea,
drawContext: CDDefaultProcs.DrawContext,
contextFilter: cf,
devicePrivate: cifH,
design: cifH.design
]];
FOR directives: LIST OF REF ANY ← cifH.cifDirectives, directives.rest WHILE directives#NIL DO
cifH.currentDirective ← NARROW[directives.first];
cifH.cifLayerAnnounced ← FALSE;
IF cifH.currentDirective.deltaRadius>=0 THEN redundant but easier to understand
cf[cifH.currentDirective.cdSource] ← TRUE;
CD.DrawOb[pr, obj];
cf[cifH.currentDirective.cdSource] ← FALSE;
ENDLOOP;
SymTrailer[cifH.cifFile];
};
GenerateGeometricOb: PROC [obj: CD.Object, cifDrawRec: CD.DrawRef] = {
output CIF for structures only identified as geometries
cifH: WrCIFHandle ← NARROW[cifDrawRec.devicePrivate];
IF IsSpecialCase[obj, cifH] THEN {
UnfinishedSymHeader[obj, cifH];
HandleSpecialCase[obj, cifH]
}
ELSE {
SymHeader[obj, cifH];
FOR directives: LIST OF REF ANY ← cifH.cifDirectives, directives.rest WHILE directives#NIL DO
cifH.currentDirective ← NARROW[directives.first];
cifH.cifLayerAnnounced ← FALSE;
IF cifH.currentDirective.deltaRadius>=0 THEN redundant but easier to understand
cifH.sharedCxFilter[cifH.currentDirective.cdSource] ← TRUE;
CD.DrawOb[cifDrawRec, obj];
cifH.sharedCxFilter[cifH.currentDirective.cdSource] ← FALSE;
ENDLOOP;
};
SymTrailer[cifH.cifFile];
};
MustCompensate: PROC [layer: CD.Layer, cifH: WrCIFHandle] RETURNS [BOOL] = {
FOR dList: LIST OF REF ANY ← cifH.cifDirectives, dList.rest WHILE dList#NIL DO
cdir: CIFDirective ← NARROW[dList.first];
IF cdir.cdSource=layer AND cdir.deltaRadius#0 THEN RETURN [TRUE];
ENDLOOP;
RETURN [FALSE];
};
GeneratePolygon: PROC [obj: CD.Object, cifH: WrCIFHandle] = {
output CIF for structures for polygons
cifFile: IO.STREAM = cifH.cifFile;
CifPolygonOut: PROC [points: LIST OF CD.Position] = {
points are in design coords, not yet CIF coords
IF NOT cifH.cifLayerAnnounced THEN {
cifFile.PutF["L %g;\n\l", IO.rope[cifH.currentDirective.cifDest]];
cifH.cifLayerAnnounced ← TRUE;
};
cifFile.PutRope["P"];
FOR p: LIST OF CD.Position ← points, p.rest WHILE p#NIL DO
cifPos: CD.Position = CDPosToCIF[p.first, cifH];
cifFile.PutRope[" "];
CIFOutPoint[cifPos, cifH];
ENDLOOP;
cifFile.PutRope[";\n\l"];
};
polygon: CDCurves.CurveSpecific = NARROW[obj.specific];
bad: BOOLFALSE;
SymHeader[obj, cifH];
FOR directives: LIST OF REF ANY ← cifH.cifDirectives, directives.rest WHILE directives#NIL DO
cifH.currentDirective ← NARROW[directives.first];
cifH.cifLayerAnnounced ← FALSE;
IF cifH.currentDirective.cdSource=obj.layer THEN {
IF cifH.currentDirective.deltaRadius#0 THEN bad ← TRUE;
CifPolygonOut[polygon.points];
}
ENDLOOP;
IF bad THEN {
TerminalIO.PutRope["**polygon shrink or bloat failed\n"];
cifFile.PutRope["( polygon has incorrect sizing );\n\l"];
};
SymTrailer[cifFile];
};
CIFDefineObject: PROC [obj: CD.Object, cifDrawRec: CD.DrawRef] = {
Print out CIF pertaining to object starting with the furthest object from the top; After leaving procedure, object will have been assigned a CIF ID # in its properties field
CheckChildren: CDDirectory.EachObjectProc = {
IF MakeCall[me, cifH] THEN CIFDefineObject[me, cifDrawRec]
};
cifH: WrCIFHandle ← NARROW[cifDrawRec.devicePrivate];
IF debugging THEN TerminalIO.PutRope["Entering CIFDefineObject\n"];
IF CDProperties.GetObjectProp[obj, cellIDKey]#NIL THEN RETURN;
non-NIL value indicates that object has already been assigned an ID # and is therefore already defined
IF RefTab.Fetch[cifH.obToIdTab, obj].found THEN RETURN;
We should also make a test here to decide whether any hierarchical geometry results from this object, and assign a special value to this object's attribute $CellIDNo if not.
IF obj.layer=CD.errorLayer THEN cifH.errorFound ← obj;
IF obj.class.composed THEN {
[] ← CDDirectory.EnumerateChildObjects[obj, CheckChildren, NIL];
};
WITH obj.specific SELECT FROM
rp: CDImports.ImportSpecific => {
IF rp.boundOb=NIL THEN ERROR;
CIFDefineObject[rp.boundOb, cifDrawRec];
SymHeader[obj, cifH];
CIFDrawCellName[Rope.Cat[rp.designName, ".", rp.objectName], cifH];
CIFSymbolCall[rp.boundOb,,,cifH];
SymTrailer[cifH.cifFile];
};
cp: CD.CellSpecific => {
name: Rope.ROPE ← CDDirectory.Name[obj, cifH.design];
IF Rope.IsEmpty[name] THEN name ← NARROW[CDProperties.GetObjectProp[obj, $Describe]];
IF satellitesSignals THEN [] ← CDSatellites.GetSatellites[obj];
SymHeader[obj, cifH];
CIFDrawCellName[name, cifH];
For each member of the instance list, determine whether obj is a cell. If so, determine transformations
{
EachInst: CDCells.InstEnumerator = {
IF MakeCall[inst.ob, cifH] THEN
CIFSymbolCall[inst.ob, inst.trans.orient, CDPosToCIF[inst.trans.off, cifH], cifH];
};
[] ← CDCells.EnumerateInstances[obj, EachInst];
};
for each layer, pick out the rectangles belonging to that layer
and output them
FOR dir: LIST OF REF ANY ← cifH.cifDirectives, dir.rest WHILE dir#NIL DO
cifH.currentDirective ← NARROW[dir.first];
cifH.cifLayerAnnounced ← FALSE;
IF cifH.currentDirective.deltaRadius>=0 THEN removed for simplicity
cifH.sharedCxFilter[cifH.currentDirective.cdSource] ← TRUE; {
EachInst: CDCells.InstEnumerator = {
IF ~MakeCall[inst.ob, cifH] THEN
inst.ob.class.drawMe[ob: inst.ob, trans: inst.trans, pr: cifDrawRec];
};
[] ← CDCells.EnumerateInstances[obj, EachInst];
};
cifH.sharedCxFilter[cifH.currentDirective.cdSource] ← FALSE;
ENDLOOP;
generate all signal names
{
EachInst: CDCells.InstEnumerator = {
we don't deal with signal names on p-diffusion;
sorry, but I have more important things to do right now
IF ~MakeCall[inst.ob, cifH] THEN {
WITH CDProperties.GetInstanceProp[inst, $SignalName] SELECT FROM
r: Rope.ROPE => CIFLabelTerminal[inst, r, inst.ob.layer, cifH];
ENDCASE => NULL;
IF satellitesSignals THEN {
FOR list: LIST OF Rope.ROPE ← CDSatellites.GetSatelliteRopes[inst], list.rest WHILE list#NIL DO
CIFLabelTerminal[inst, list.first, inst.ob.layer, cifH];
ENDLOOP;
};
}
};
[] ← CDCells.EnumerateInstances[obj, EachInst];
};
SymTrailer[cifH.cifFile];
}; -- of cell
ENDCASE => -- crazy or transistors or geometry or rects
IF obj.class.composed THEN GenerateCompositeOb[obj, cifH]
ELSE IF MakeCall[obj, cifH] THEN {
IF CDCurves.IsPolygon[obj] AND ~MustCompensate[obj.layer, cifH] THEN GeneratePolygon[obj, cifH]
ELSE GenerateGeometricOb[obj, cifDrawRec];
};
IF debugging THEN TerminalIO.PutRope["Leaving CIFDefineObject\n"];
};
CIFSymbolCall: PROC[ob: CD.Object, orient: CD.Orientation←original, pos: CD.Position← [0,0], cifH: WrCIFHandle] = {
pos in CIFUnits
indicate which cell is called using its ID number
cifFile: IO.STREAM ← cifH.cifFile;
found: BOOLEAN;
val: RefTab.Val;
iDNo: REF INT;
[found, val] ← RefTab.Fetch[cifH.obToIdTab, ob];
IF NOT found THEN ERROR;
iDNo ← NARROW[val];
cifFile.PutF["C %d", IO.int[iDNo^]];
IF orient#original THEN {
xrotation: CD.Orientation ← CDBasics.ConcentrateOnRotate90[orient];
IF xrotation#original THEN {
cifFile.PutRope[" R "];
cifFile.PutRope[SELECT xrotation FROM
rotate90 => "0,1" ,
rotate180=> "-1,0",
rotate270=> "0,-1",
ENDCASE=> "1,0" -- never use this one
];
};
IF CDBasics.IncludesMirrorX[orient] THEN cifFile.PutRope[" M X "];
};
IF pos#[0, 0] THEN {
cifFile.PutRope[" T "];
CIFOutPoint[pos, cifH];
};
cifFile.PutRope[";\n\l"];
};
Output Procedures
CIFMeasureArea: CD.DrawRectProc = {
Sets mainRect to be a large as is necessary to contain design.
cifH: WrCIFHandle ← NARROW[CDProperties.GetProp[pr.properties, $WrCIFHandle]];
r ← CDBasics.ReInterpreteRect[r];
IF CDBasics.NonEmpty[r] THEN cifH.mainRect ← CDBasics.Surround[cifH.mainRect, r];
};
CIFContextMeasureArea: CD.DrawContextProc = {
cifH: WrCIFHandle ← NARROW[CDProperties.GetProp[pr.properties, $WrCIFHandle]];
r: CD.Rect ← CDBasics.MapRect[ob.bbox, trans];
IF CDBasics.NonEmpty[r] THEN cifH.mainRect ← CDBasics.Surround[cifH.mainRect, r];
};
IgnoreRect: CD.DrawRectProc = {
};
IgnoreContext: CD.DrawContextProc = {
};
CIFOrArea: CD.DrawRectProc = {
cifH: WrCIFHandle ← NARROW[pr.devicePrivate];
IF CDBasics.NonEmpty[r] THEN {
IF l=CD.errorLayer AND cifH.errorFound=NIL THEN cifH.errorFound ← $TRUE;
IF l=cifH.currentDirective.cdSource THEN {
rd: CIFRect ← CDBasics.Extend[CDRectToCIF[CDBasics.ReInterpreteRect[r], cifH], cifH.currentDirective.deltaRadius/cifH.nmPerCIF];
IF CDBasics.NonEmpty[rd] THEN CIFRectOut[rd, cifH];
}
}
};
CIFRectOut: PROC [r: CIFRect, cifH: WrCIFHandle] = {
IF NOT CDBasics.NonEmpty[r] THEN RETURN;
IF NOT cifH.cifLayerAnnounced THEN {
cifH.cifFile.PutF["L %g;\n\l", IO.rope[cifH.currentDirective.cifDest]];
cifH.cifLayerAnnounced ← TRUE;
};
cifH.cifFile.PutF["B %d %d %d %d;\n\l",-- BOX command, in prescaled CIF units
IO.int[PrescaleCIF[[r.x2-r.x1, 1], cifH]] -- length -- ,
IO.int[PrescaleCIF[[r.y2-r.y1, 1], cifH]] -- width -- ,
IO.int[PrescaleCIF[[r.x1+r.x2, 2], cifH]] -- center x-coord -- ,
IO.int[PrescaleCIF[[r.y1+r.y2, 2], cifH]] -- center y-coord -- ];
};
CIFOutPoint: PROC[p: CIFPos, cifH: WrCIFHandle] = {
cifH.cifFile.PutF["%d,%d", IO.int[PrescaleCIF[[p.x,1], cifH]], IO.int[PrescaleCIF[[p.y,1], cifH]]]
};
CIFLabelTerminal: PROC [ap: CD.Instance, s: Rope.ROPE, lev: CD.Layer, cifH: WrCIFHandle] = {
pt: CD.Position ← CDBasics.Center[CDRectToCIF[CDInstances.InstRectO[ap], cifH]];
cifH.cifFile.PutF["94 %s ", IO.rope[s]];
CIFOutPoint[pt, cifH];
cifH.cifFile.PutChar[' ];
FOR directives: LIST OF REF ANY ← cifH.cifDirectives, directives.rest WHILE directives#NIL DO
d: CIFDirective = NARROW[directives.first];
IF d.cdSource = lev THEN {cifH.cifFile.PutRope[d.cifDest]; EXIT};
ENDLOOP;
cifH.cifFile.PutRope[";\n\l"];
};
CIFDrawCellName: PROC[s: Rope.ROPE, cifH: WrCIFHandle] = {
cifH.lastCellName ← s;
IF ~Rope.IsEmpty[s] THEN cifH.cifFile.PutF["9 %s;\n\l", IO.rope[s]];
};
CantRepresentExactly: ERROR = CODE;
CollectDirectives: PROC[design: CD.Design] RETURNS[cifDirectives: LIST OF REF ANYNIL] = {
GetDirectives: PROC [p: REF, lev: CD.Layer] RETURNS [l: LIST OF REF ANYNIL] = {
IF p#NIL THEN {
WITH p SELECT FROM
d: CIFDest => l ← LIST[NEW[CIFDirectiveRec ← [lev, d.cifDest, d.deltaRadius]]];
list: LIST OF REF ANY => l ← List.Append[GetDirectives[list.first, lev], GetDirectives[list.rest, lev]];
ENDCASE => l ← LIST[NEW[CIFDirectiveRec ← [lev, CDOps.ToRope[p, $Interactive], 0]]];
};
};
FOR layers: LIST OF CD.Layer ← design.technology.usedLayers, layers.rest WHILE layers#NIL DO
cifDirectives ← List.Append[GetDirectives[CDProperties.GetLayerProp[layers.first, $CDxCIFRegistrations], layers.first ], cifDirectives];
ENDLOOP;
};
GetCifPerLambda: PROC [] = {
WITH CDProperties.GetProp[$CDxCIFRegistrations, $CDxCIFUnitsPerLambda] SELECT FROM
ri: REF INT => cifPerLambda ← ri^;
ENDCASE => cifPerLambda ← 0;
TerminalIO.PutF["using %g cif units per lambda; (1 CIF unit = 0.01 microns)\n\l", IO.int[cifPerLambda]] ;
IF cifPerLambda<2 THEN {
TerminalIO.PutRope["cif units per lambda not reasonable\n\l"];
ERROR ABORTED
};
};
ClearCellIDs: CD.DrawProc = {
PROC [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation←[], readOnlyInstProps: CD.PropList←NIL];
used to set all CellIDNo's to NIL at the start
cifH: WrCIFHandle ← NARROW[CDProperties.GetProp[pr.properties, $WrCIFHandle]];
CDProperties.PutObjectProp[onto: ob, prop: cellIDKey, val: NIL];
IF ob.class.composed THEN ob.class.drawMe[pr: pr, ob: ob];
};
SetCIFScaling: PROC[cifH: WrCIFHandle] = {
lambda: INT ← cifH.design.technology.lambda;
cifH.cifScaling ← ReduceTerms[[num: cifH.cifPerLambda, denom: 2*lambda]]; -- the "2" allows for box centers
FOR directives: LIST OF REF ANY ← cifH.cifDirectives, directives.rest WHILE directives#NIL DO
d: CIFDirective = NARROW[directives.first];
cif: CIFUnits;
IF ABS[d.deltaRadius] MOD cifH.nmPerCIF # 0 THEN ERROR CantRepresentExactly;
cif ← ABS[d.deltaRadius]/cifH.nmPerCIF;
cifH.cifScaling ← ReduceTerms[[
num: cifH.cifScaling.num,
denom: (cifH.cifScaling.num*cifH.cifScaling.denom)/GCD[cif*cifH.cifScaling.denom, cifH.cifScaling.num]]];
.. adds the condition that cif/cifScaling is guaranteed to be an integer, so cif*cifScaling.denom MOD cifScaling.num = 0
ENDLOOP;
};
WriteCIF: PUBLIC PROC[design: CD.Design, mainInst: CD.Instance, cifFile: IO.STREAM, cifPerLambda: INT, flattenAtomics: BOOLFALSE] RETURNS [errMsg: Rope.ROPE]= {
ENABLE {
ABORTED => {errMsg ← " CIF generation aborted\n\l"; GOTO Exit};
UNWIND => NULL;
}; --enable
lambda: INT ← design.technology.lambda;
topLayerOb: CD.Object ← NEW[CD.ObjectRep];
mainOb: CD.Object ← mainInst.ob;
cifKey: Rope.ROPE;
stopFlag: REF BOOLNEW[BOOLFALSE];
sharedCxFilter: REF CD.ContextFilter ← NEW[CD.ContextFilter ← ALL[FALSE]];
clearIDsRec: CD.DrawRef ← CD.CreateDrawRef[[
interestClip: CDBasics.universe,
drawChild: ClearCellIDs,
drawContext: IgnoreContext,
stopFlag: stopFlag,
design: design
]];
cifMeasureR: CD.DrawRef ← CD.CreateDrawRef[[
interestClip: CDBasics.universe,
drawRect: CIFMeasureArea,
drawContext: CIFContextMeasureArea,
stopFlag: stopFlag,
design: design
]];
cifH: WrCIFHandle ← NEW[WrCIFHandleRec ← [
design: design,
cifDirectives: CollectDirectives[design],
specialProperties: SetUpSpecialClasses[design],
stopFlag: NEW[BOOLEANFALSE],
cifPerLambda: cifPerLambda,
cifFile: cifFile,
sharedCxFilter: sharedCxFilter,
mainRect: CDBasics.empty,
flattenAtomics: flattenAtomics,
cifLayerAnnounced: FALSE,
obToIdTab: RefTab.Create[]
]];
cifDrawRec: CD.DrawRef ← CD.CreateDrawRef[[
interestClip: CDBasics.universe,
drawRect: CIFOrArea,
drawContext: CDDefaultProcs.DrawContext,
contextFilter: sharedCxFilter,
stopFlag: stopFlag,
devicePrivate: cifH,
design: design
]];
CDSequencer.UseAbortFlag[design, stopFlag];
cifKey ← CDOps.ToRope[CDProperties.GetProp[$CDxCIFRegistrations, $CDxCIFName], $Interactive];
IF Rope.IsEmpty[cifKey] THEN RETURN["CIF layers for this technology are not defined\n"];
TerminalIO.PutRopes["Use CIF layer definitions [", cifKey, "]\n"];
Search world data structure: normalize coordinates, set mainRect to design size, mark used layers
CD.DrawOb[pr: cifMeasureR, ob: mainOb, readOnlyInstProps: mainInst.properties];
output header
cifFile.PutF["( %s );\n\l", IO.rope[design.name]];
cifFile.PutF["( generated %g by Xerox PARC ChipNDale and BrandyCIFter);\n\l", IO.time[]];
cifFile.PutF["( with lambda = %d CIF units );\n\l", IO.int[cifPerLambda]];
cifFile.PutF["( origin = [x: 0, y: 0], size = [x: %d, y: %d] CIF units );\n\l", IO.int[CDCIFUp[cifH.mainRect.x2-cifH.mainRect.x1, cifH]], IO.int[CDCIFUp[cifH.mainRect.y2-cifH.mainRect.y1, cifH]]];
cifFile.PutF["( CIF KEY: %s );\n\l", IO.rope[cifKey]];
SetCIFScaling[cifH];
ClearCellIDs[NIL, design.actual.first.dummyCell.ob];
CDProperties.PutObjectProp[onto: design.actual.first.dummyCell.ob, prop: cellIDKey, val: NIL];
IF design.actual.first.dummyCell.ob.class.composed THEN design.actual.first.dummyCell.ob.class.drawMe[pr: clearIDsRec, ob: design.actual.first.dummyCell.ob];
CIFDefineObject[mainOb, cifDrawRec];
define hybrid top layer object
SymHeader[topLayerOb, cifH];
CIFSymbolCall[mainOb, mainInst.trans.orient, CDPosToCIF[mainInst.trans.off, cifH], cifH];
FOR directives: LIST OF REF ANY ← cifH.cifDirectives, directives.rest WHILE directives#NIL DO
cifH.currentDirective ← NARROW[directives.first];
IF cifH.currentDirective.deltaRadius<0 THEN {
cifH.cifLayerAnnounced ← FALSE;
cifH.sharedCxFilter[cifH.currentDirective.cdSource] ← TRUE;
MakeFlatCIF[mainInst: mainInst, rectProc: CIFRectOut, cifH: cifH];
cifH.sharedCxFilter[cifH.currentDirective.cdSource] ← FALSE;
};
ENDLOOP;
cifFile.PutRope[";\n\lEnd ... \n\l"];
cifFile.Close[];
IF cifH.errorFound#NIL THEN errMsg ← " Warning: the design contained some error message(s)\n\l";
EXITS Exit => {};
}; -- of WriteCIF
Flat CIF code
MakeFlatCIF: PROC [mainInst: CD.Instance, rectProc: PROC[r: CIFRect, cifH: WrCIFHandle], cifH: WrCIFHandle] = {
mainOb: CD.Object ← mainInst.ob;
AnalyzeTesselation: PROC [ms: MaskStateRef] = {
the tesselation is in cif coordinates
active: CD.Rect = ms.areas.BBox[];
IF CDBasics.NonEmpty[active] THEN {
IF cifH.currentDirective.deltaRadius#0 THEN {
t: CStitching.Tesselation = ms.unbloated;
ms.unbloated ← ms.areas;
ms.areas ← t;
CStitching.ChangeRect[plane: ms.areas, rect: CDBasics.universe, new: NIL];
IF cifH.currentDirective.deltaRadius>0 THEN
CStitching.EnumerateArea[plane: ms.unbloated, rect: CDBasics.universe, eachTile: BloatTile, data: ms]
ELSE {
CStitching.ChangeRect[plane: ms.areas, rect: active, new: $covered];
CStitching.EnumerateArea[plane: ms.unbloated, rect: CDBasics.universe, eachTile: BloatTile, data: ms, skip: $covered];
};
};
CStitching.EnumerateArea[plane: ms.areas, rect: CDBasics.universe, eachTile: OutputTile, data: ms];
TerminalIO.PutRope["."];
};
};
OutputTile: PROCEDURE [tile: CStitching.Tile, data: REF ANY] = {
CStitching.PerTileProc
only called on tiles with non-NIL values
ms: MaskStateRef = NARROW[data];
cr: CIFRect = CDBasics.Intersection[tile.Area, ms.partClip];
rectProc[cr, ms.cifH];
};
designClip: CD.Rect;
cifClip: CD.Rect;
nRows, nCols: NAT;
ms: MaskStateRef = NEW[MaskState ← [
areas: CStitching.NewTesselation[],
unbloated: CStitching.NewTesselation[],
cifH: cifH
]];
dr: CD.DrawRef ← CD.CreateDrawRef[[
drawRect: NoteBoundingBox,
drawContext: NoteContextBoundingBox,
devicePrivate: NEW[CD.Rect ← CDBasics.empty],
interestClip: CDBasics.universe,
stopFlag: cifH.stopFlag,
design: cifH.design
]];
CD.DrawOb[pr: dr, ob: mainOb, trans: mainInst.trans, readOnlyInstProps: mainInst.properties]; -- measure design
designClip ← NARROW[dr.devicePrivate, REF CD.Rect]^;
cifClip ← Bloat[CDRectToCIF[designClip, cifH], ABS[cifH.currentDirective.deltaRadius]/cifH.nmPerCIF];
nRows ← Ceiling[num: cifClip.y2-cifClip.y1, denom: partHeight];
nCols ← Ceiling[num: cifClip.x2-cifClip.x1, denom: partWidth];
TerminalIO.PutF[".. in %d rows and %d columns..", IO.int[nRows], IO.int[nCols]];
dr.drawRect ← NoteRectangle;
dr.drawContext ← CDDefaultProcs.DrawContext;
dr.contextFilter ← cifH.sharedCxFilter;
dr.devicePrivate ← ms;
TerminalIO.PutF["%s -> %s", IO.rope[CDOps.ToRope[CD.LayerKey[cifH.currentDirective.cdSource], $Interactive]], IO.rope[cifH.currentDirective.cifDest]];
FOR col: NAT IN [0..nCols) DO
FOR row: NAT IN [0..nRows) DO
ms.areas.ChangeRect[rect: CDBasics.universe, new: NIL];
ms.partClip ← [ -- in cif space
x1: cifClip.x1+col*partWidth,
y1: cifClip.y1+row*partHeight,
x2: cifClip.x1+col*partWidth+MIN[partWidth, cifClip.x2-cifClip.x1-partWidth*col],
y2: cifClip.y1+row*partHeight+MIN[partHeight, cifClip.y2-cifClip.y1-partHeight*row]
];
dr.interestClip ← CIFRectToCD[CDBasics.Extend[ms.partClip, 1+ABS[cifH.currentDirective.deltaRadius]/cifH.nmPerCIF], cifH];
CDVArrow.ShowArrow[design: cifH.design, pos: [x: (dr.interestClip.x1+dr.interestClip.x2)/2, y: (dr.interestClip.y1+dr.interestClip.y2)/2]]; -- keep user happy
CD.DrawOb[pr: dr, ob: mainOb, trans: mainInst.trans, readOnlyInstProps: mainInst.properties];
AnalyzeTesselation[ms]; -- sends the current part to s
ENDLOOP;
ENDLOOP;
TerminalIO.PutRope["+"];
CDVArrow.RemoveArrow[design: cifH.design];
dr ← NIL;
};
NoteContextBoundingBox: CD.DrawContextProc = {
bb: REF CD.Rect = NARROW[pr.devicePrivate];
bb^ ← CDBasics.Surround[bb^, CDBasics.MapRect[ob.bbox, trans]];
};
NoteBoundingBox: CD.DrawRectProc = {
bb: REF CD.Rect = NARROW[pr.devicePrivate];
bb^ ← CDBasics.Surround[bb^, r];
};
NoteRectangle: CD.DrawRectProc = {
ms: MaskStateRef = NARROW[pr.devicePrivate];
IF l=ms.cifH.currentDirective.cdSource AND CDBasics.NonEmpty[r] THEN
ms.areas.ChangeRect[rect: CDRectToCIF[r, ms.cifH], new: $covered];
};
BloatTile: PROCEDURE [tile: CStitching.Tile, data: REF ANY] = {
CStitching.PerTileProc --
ms: MaskStateRef = NARROW[data];
cr: CD.Rect = CDBasics.Intersection[CDBasics.universe, Bloat[tile.Area, ABS[ms.cifH.currentDirective.deltaRadius/ms.cifH.nmPerCIF]]];
IF CDBasics.NonEmpty[cr] THEN
ms.areas.ChangeRect[rect: cr, new: tile.value];
};
Bloat: PROC [r: CD.Rect, delta: CD.Number] RETURNS [br: CD.Rect] = INLINE {
Be careful not to exceed the limits of a CD.Number, even temporarily
br ← [x1: MAX[FIRST[CD.Number]+delta, r.x1]-delta,
y1: MAX[FIRST[CD.Number]+delta, r.y1]-delta,
x2: MIN[LAST[CD.Number]-delta, r.x2]+delta,
y2: MIN[LAST[CD.Number]-delta, r.y2]+delta]
};
CDRectToCIF: PROC [cdr: CD.Rect, cifH: WrCIFHandle] RETURNS [cifr: CIFRect ] = {
lambda: INT ← cifH.design.technology.lambda;
cifr ← CDBasics.ReInterpreteRect[[
x1: cifH.cifPerLambda*cdr.x1/lambda,
y1: cifH.cifPerLambda*cdr.y1/lambda,
x2: cifH.cifPerLambda*cdr.x2/lambda,
y2: cifH.cifPerLambda*cdr.y2/lambda
]]
};
CDPosToCIF: PROC [ cdp: CD.Position, cifH: WrCIFHandle ] RETURNS [ cifp: CIFPos ] = {
lambda: INT ← cifH.design.technology.lambda;
cifp ← [x: cifH.cifPerLambda*cdp.x/lambda, y: cifH.cifPerLambda*cdp.y/lambda]
};
CDCIFUp: PROC [ n: CD.Number, cifH: WrCIFHandle ] RETURNS [ cif: CIFUnits ] = {
lambda: INT ← cifH.design.technology.lambda;
cif ← (cifH.cifPerLambda*n+lambda-1)/lambda
};
CIFRectToCD: PROC [ cifr: CIFRect, cifH: WrCIFHandle ] RETURNS [ cdr: CD.Rect ] = {
rounds to rect beeing bigger
lambda: INT ← cifH.design.technology.lambda;
cdr ← CDBasics.ReInterpreteRect[[
x1: lambda*cifr.x1/cifH.cifPerLambda,
y1: lambda*cifr.y1/cifH.cifPerLambda,
x2: (lambda*cifr.x2+cifH.cifPerLambda-1)/cifH.cifPerLambda,
y2: (lambda*cifr.y2+cifH.cifPerLambda-1)/cifH.cifPerLambda
]]
};
PrescaleCIF: PROC [cif: Rational, cifH: WrCIFHandle ] RETURNS [INT ] = {
n: INT = cif.num*cifH.cifScaling.denom;
d: INT = cif.denom*cifH.cifScaling.num;
IF ABS[n] MOD ABS[d] # 0 THEN ERROR CantRepresentExactly;
RETURN[n/d];
};
Ceiling: PROC [num, denom: CD.Number] RETURNS [ c: INT ] = {
c ← (num+denom-1)/denom
};
ReduceTerms: PROC [r: Rational ] RETURNS [Rational ] = {
gcd: INT = GCD[r.num, r.denom];
RETURN[[num: r.num/gcd, denom: r.denom/gcd]];
};
GCD: PROC [ m, n: INT ] RETURNS [ INT ] = {
r: INT;
SELECT m FROM
<0 => m ← -m;
ENDCASE => NULL;
SELECT n FROM
<0 => n ← -n;
>0 => NULL;
ENDCASE => RETURN[m];
r ← m MOD n;
WHILE r>0 DO m ← n; n ← r; r ← m MOD n; ENDLOOP;
RETURN[n];
};
CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxCIFName];
CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxCIFTechnology];
CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxCIFSpecials];
CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxCIFUnitsPerLambda];
CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxFlattenAtomic];
END.