CDToCifImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDCells, CDCurves, CDDefaultProcs, CDDirectory, CDInstances, CDOps, CDProperties, CDPropertyTools, CDSatellites, CDSequencer, CDTexts, CDVArrow, CStitching, IO, List, 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,
clearIDsRec,
cifMeasureR,
cifDrawRec: CD.DrawRef,
cifDirectives: LIST OF REF ANY ← NIL, -- CIFDirective
specialProperties: CDProperties.PropRef,
stopFlag: REF BOOL,
errorFound: REF ← NIL,
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
];
Global Variables
cellIDKey: REF ATOM = NEW[ATOM ← $CellIDNo]; --not accessible
debugging: BOOL ← FALSE; -- for printing out debugging messages
satellitesSignals: BOOL ← TRUE; -- whether satellites should contribute signal names
design: CD.Design;
errorFound: REF ← NIL;
stopFlag: REF BOOL;
topLayerOb: CD.Object ← NEW[CD.ObjectRep];
clearIDsRec: CD.DrawRef;
cifMeasureR: CD.DrawRef;
cifDrawRec: CD.DrawRef; - - for CIFOrArea
sharedCxFilter: REF CD.ContextFilter ← NEW[CD.ContextFilter𡤊LL[FALSE]]; - - used in cifDrawRec
cellCount: INT ← 0; - - to assign consecutive CIF ID numbers
cifLayerAnnounced: BOOL ← FALSE;
layer assumed to be unchanged until the next layer is announced
lambda: INT ← 0;
cifPerLambda: INT ← 100; - - CIF units per lambda
cifH.nmPerCIF: INT = 10; - - nanometers per CIF unit, given 0.01 microns per CIF unit
cifScaling: Rational;
..output numbers*cifScaling = CIFUnits
..CIFUnits/cifScaling = output numbers
cifFile: IO.STREAM; - - file where output will be stored
comment, base, lastCellName: Rope.ROPE;
mainRect: CD.Rect ← CDBasics.empty;
set to design size in CIFMeasureArea, used to switch between ChipNDale and CIF coordinate systems
currentDirective: CIFDirective;
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 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:
BOOL←
FALSE] = {
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 INT ← NEW[INT ← (cifH.cellCount ← cifH.cellCount + 1)];
cifH.cifFile.PutF["DS %d %d %d;\n",
IO.int[cifH.cellCount], IO.int[cifH.cifScaling.num], IO.int[cifH.cifScaling.denom]];
CDProperties.PutObjectProp[obj, cellIDKey, 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 INT ← NEW[INT ← (cifH.cellCount ← cifH.cellCount + 1)];
cifH.cifFile.PutF["DS %d ", IO.int[cifH.cellCount]];
CDProperties.PutObjectProp[obj, cellIDKey, cellID];
};
SymTrailer:
PROC[cifFile:
IO.
STREAM] = {
finish off cell description
cifFile.PutRope["DF;\n"];
};
CallChildren:
CD.DrawProc = {
cifH: WrCIFHandle ← NARROW[CDProperties.GetProp[pr.properties, $WrCIFHandle]];
IF MakeCall[ob, cifH] THEN
CIFSymbolCall[ob, trans.orient, CDPosToCIF[trans.off, cifH], cifH];
};
DrawRectChilds:
CD.DrawProc = {
cifH: WrCIFHandle ← NARROW[CDProperties.GetProp[pr.properties, $WrCIFHandle]];
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,
design: cifH.design,
properties: NEW[CDProperties.PropList←NIL]
]];
CDProperties.PutProp[pr.properties, $WrCIFHandle, cifH];
CD.DrawOb[pr, obj];
draw the rectangles
pr ←
CD.CreateDrawRef[[
stopFlag: cifH.stopFlag,
drawChild: DrawRectChilds,
drawRect: CIFOrArea,
drawContext: CDDefaultProcs.DrawContext,
contextFilter: cf,
design: cifH.design,
properties: NEW[CDProperties.PropList←NIL]
]];
CDProperties.PutProp[pr.properties, $WrCIFHandle, 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
cf[cifH.currentDirective.cdSource] ← TRUE;
CD.DrawOb[pr, obj];
cf[cifH.currentDirective.cdSource] ← FALSE;
ENDLOOP;
SymTrailer[cifH.cifFile];
};
GenerateGeometricOb:
PROC [obj:
CD.Object, cifH: WrCIFHandle] = {
output CIF for structures only identified as geometries
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[cifH.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", 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.x, cifPos.y, cifH];
ENDLOOP;
cifFile.PutRope[";\n"];
};
polygon: CDCurves.CurveSpecific = NARROW[obj.specific];
bad: BOOL ← FALSE;
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"];
};
SymTrailer[cifFile];
};
CIFDefineObject:
PROC [obj:
CD.Object, cifH: WrCIFHandle] = {
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, cifH]
};
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
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, cifH];
SymHeader[obj, cifH];
CIFDrawCellName[Rope.Cat[rp.designName, ".", rp.objectName], cifH];
CIFSymbolCall[rp.boundOb,,,cifH];
SymTrailer[cifH.cifFile];
};
cp:
CD.CellSpecific => {
IF satellitesSignals THEN [] ← CDSatellites.GetSatellites[obj];
SymHeader[obj, cifH];
CIFDrawCellName[CDDirectory.Name[obj, cifH.design], 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: cifH.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, cifH];
};
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;
WITH CDProperties.GetObjectProp[ob, cellIDKey]
SELECT
FROM
iDNo:
REF
INT => {
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.x, pos.y, cifH];
};
cifFile.PutRope[";\n"];
};
ENDCASE => ERROR;
};
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[CDProperties.GetProp[pr.properties, $WrCIFHandle]];
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", IO.rope[cifH.currentDirective.cifDest]];
cifH.cifLayerAnnounced ← TRUE;
};
cifH.cifFile.PutF["B %d %d %d %d;\n",
-- 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[x, y: CIFUnits, cifH: WrCIFHandle] = {
cifH.cifFile.PutF["%d,%d", IO.int[PrescaleCIF[[x,1], cifH]], IO.int[PrescaleCIF[[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.x, pt.y, 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"];
};
CIFDrawCellName:
PROC[s: Rope.
ROPE, cifH: WrCIFHandle] = {
cifH.lastCellName ← s;
IF ~Rope.IsEmpty[s] THEN cifH.cifFile.PutF["9 %s;\n", IO.rope[s]];
};
CantRepresentExactly:
ERROR =
CODE;
CollectDirectives:
PROC[design: CD.Design]
RETURNS[cifDirectives:
LIST
OF
REF
ANY ←
NIL] = {
GetDirectives:
PROC [p:
REF, lev:
CD.Layer]
RETURNS [l:
LIST
OF
REF
ANY ←
NIL] = {
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", IO.int[cifPerLambda]] ;
IF cifPerLambda<2 THEN {
TerminalIO.PutRope["cif units per lambda not reasonable\n"];
ERROR ABORTED
};
ClearCellIDs:
CD.DrawProc = {
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: cifH.clearIDsRec, 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:
BOOL ←
FALSE]
RETURNS [errMsg: Rope.
ROPE]= {
ENABLE {
ABORTED => {errMsg ← " CIF generation aborted\n"; 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 BOOL ← NEW[BOOL ← FALSE];
cifH: WrCIFHandle ←
NEW[WrCIFHandleRec ← [
design: design,
clearIDsRec:
CD.CreateDrawRef[[
interestClip: CDBasics.universe,
drawChild: ClearCellIDs,
drawContext: IgnoreContext,
stopFlag: stopFlag,
design: design
]],
cifMeasureR:
CD.CreateDrawRef[[
interestClip: CDBasics.universe,
drawRect: CIFMeasureArea,
drawContext: CIFContextMeasureArea,
stopFlag: stopFlag,
design: design
]],
cifDrawRec:
CD.CreateDrawRef[[
interestClip: CDBasics.universe,
drawRect: CIFOrArea,
drawContext: CDDefaultProcs.DrawContext,
contextFilter: cifH.sharedCxFilter,
stopFlag: stopFlag,
design: design
]],
cifDirectives: CollectDirectives[design],
specialProperties: SetUpSpecialClasses[design],
stopFlag: NEW[BOOLEAN ← FALSE],
cifPerLambda: cifPerLambda,
cifFile: cifFile,
sharedCxFilter: NEW[CD.ContextFilter←ALL[FALSE]],
mainRect: CDBasics.empty,
flattenAtomics: flattenAtomics,
cifLayerAnnounced: FALSE
]];
CDProperties.PutProp[cifH.cifDrawRec.properties, $WrCIFHandle, cifH];
CDProperties.PutProp[cifH.cifMeasureR.properties, $WrCIFHandle, cifH];
CDProperties.PutProp[cifH.clearIDsRec.properties, $WrCIFHandle, cifH];
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: cifH.cifMeasureR, ob: mainOb, readOnlyInstProps: mainInst.properties];
output header
cifFile.PutF["( %s );\n", IO.rope[design.name]];
cifFile.PutF["( generated %g by Xerox PARC ChipNDale and BrandyCIFter);\n", IO.time[]];
cifFile.PutF["( with lambda = %d CIF units );\n", IO.int[cifPerLambda]];
cifFile.PutF["( origin = [x: 0, y: 0], size = [x: %d, y: %d] CIF units );\n", 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", 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: cifH.clearIDsRec, ob: design.actual.first.dummyCell.ob];
CIFDefineObject[mainOb, cifH];
define hybrid top layer object
SymHeader[topLayerOb, cifH];
CIFSymbolCall[mainOb,,,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;
SymTrailer[cifFile];
CIFSymbolCall[topLayerOb, original, [x: -cifPerLambda*cifH.mainRect.x1/lambda, y: -cifPerLambda*cifH.mainRect.y2/lambda], cifH];
cifFile.PutRope[";\nEnd ... \n"];
cifFile.Close[];
IF cifH.errorFound#NIL THEN errMsg ← " Warning: the design contained some error message(s)\n";
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, 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, 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.