<> <> <> <> <> <> <<>> <> DIRECTORY CD, CDBasics, CDCells, CDCurves, CDDefaultProcs, CDDirectory, CDImports, CDInstances, CDOps, CDRoutingObjects, CDToCif, CDProperties, CDPropertyTools, CDSatellites, CDSequencer, CDTexts, <> 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 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, <> flattenAtomics: BOOLEAN, cifLayerAnnounced: BOOLEAN, obToIdTab: RefTab.Ref ]; <<>> <> 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 <> <> <<>> 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[]; <> }; 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] = { <> cellID: REF INT _ NEW[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]]; <> [] _ RefTab.Store[cifH.obToIdTab, obj, cellID]; }; UnfinishedSymHeader: PROC [obj: CD.Object, cifH: WrCIFHandle] = { <> <> cellID: REF INT _ NEW[INT _ (cifH.cellCount _ cifH.cellCount + 1)]; cifH.cifFile.PutF["DS %d ", IO.int[cifH.cellCount]]; <> [] _ RefTab.Store[cifH.obToIdTab, obj, cellID]; }; SymTrailer: PROC[cifFile: IO.STREAM] = { <> 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] ELSE CD.DrawOb[ob: ob, trans: trans, pr: pr, readOnlyInstProps: readOnlyInstProps]; }; 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] = { <> <> cf: REF CD.ContextFilter _ NEW[CD.ContextFilter_ALL[FALSE]]; pr: CD.DrawRef; SymHeader[obj, cifH]; CIFDrawCellName[CDDirectory.Name[obj, cifH.design], cifH]; <> pr _ CD.CreateDrawRef[[ stopFlag: cifH.stopFlag, drawChild: CallChildren, drawRect: IgnoreRect, drawContext: IgnoreContext, devicePrivate: cifH, design: cifH.design ]]; CD.DrawOb[pr, obj]; <> 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; <=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] = { <> 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; <=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] = { <> cifFile: IO.STREAM = cifH.cifFile; CifPolygonOut: PROC [points: LIST OF CD.Position] = { <> 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: 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\l"]; }; SymTrailer[cifFile]; }; CIFDefineObject: PROC [obj: CD.Object, cifDrawRec: CD.DrawRef] = { <> CheckChildren: CDDirectory.EachObjectProc = { IF MakeCall[me, cifH] THEN CIFDefineObject[me, cifDrawRec] ELSE IF obj.class.composed THEN { [] _ CDDirectory.EnumerateChildObjects[me, CheckChildren, NIL]; }; }; cifH: WrCIFHandle _ NARROW[cifDrawRec.devicePrivate]; IF debugging THEN TerminalIO.PutRope["Entering CIFDefineObject\n"]; <> <> IF RefTab.Fetch[cifH.obToIdTab, obj].found THEN RETURN; <> 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]; <> { 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 dir: LIST OF REF ANY _ cifH.cifDirectives, dir.rest WHILE dir#NIL DO cifH.currentDirective _ NARROW[dir.first]; cifH.cifLayerAnnounced _ FALSE; <=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; <> { EachInst: CDCells.InstEnumerator = { <> 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, routing objects 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] = { <> <> 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"]; }; <> <> <> <> <> <> <<}; >> <<>> <> <> <> <> <<}; >> <<>> 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 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; }; <> <> < cifPerLambda _ ri^;>> < cifPerLambda _ 0;>> <> <> <> <> <<};>> <<};>> <> <> <> <> <> <> <<};>> <<>> 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\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 BOOL _ NEW[BOOL _ FALSE]; sharedCxFilter: REF CD.ContextFilter _ NEW[CD.ContextFilter _ ALL[FALSE]]; <> <> <> <> <> <> <<]];>> <> <> <> <> <> <> <<]];>> cifH: WrCIFHandle _ NEW[WrCIFHandleRec _ [ design: design, cifDirectives: CollectDirectives[design], specialProperties: SetUpSpecialClasses[design], stopFlag: NEW[BOOLEAN _ FALSE], cifPerLambda: cifPerLambda, cifFile: cifFile, sharedCxFilter: sharedCxFilter, <> 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"]; <> <> <> 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["( CIF KEY: %s );\n\l", IO.rope[cifKey]]; SetCIFScaling[cifH]; <> <> <> CIFDefineObject[mainOb, cifDrawRec]; <> <> 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 <> MakeFlatCIF: PROC [mainInst: CD.Instance, rectProc: PROC[r: CIFRect, cifH: WrCIFHandle], cifH: WrCIFHandle] = { mainOb: CD.Object _ mainInst.ob; AnalyzeTesselation: PROC [ms: MaskStateRef] = { <> 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] = { <> <> 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]; <> CD.DrawOb[pr: dr, ob: mainOb, trans: mainInst.trans, readOnlyInstProps: mainInst.properties]; AnalyzeTesselation[ms]; -- sends the current part to s ENDLOOP; ENDLOOP; TerminalIO.PutRope["+"]; <> 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] = { <> 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 { <> 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 ] = { <> 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]; <> <> END.