DIRECTORY CD, CDBasics, CDCells, CDCurves, CDDefaultProcs, CDDirectory, CDImports, CDInstances, CDOps, CDToCif, CDProperties, CDPropertyTools, CDSatellites, CDSequencer, CDTexts, CDVArrow, CStitching, IO, List USING [Append], Rope, TerminalIO; 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 ]; 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 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", 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] = { 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] = { 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] = { 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, design: cifH.design, properties: NEW[CDProperties.PropList_NIL] ]]; CDProperties.PutProp[pr.properties, $WrCIFHandle, cifH]; CD.DrawOb[pr, obj]; 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; 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] = { 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; 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] = { cifFile: IO.STREAM = cifH.cifFile; CifPolygonOut: PROC [points: LIST OF CD.Position] = { 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] = { 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; 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]; { 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; 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; { 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 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] = { 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; }; CIFMeasureArea: CD.DrawRectProc = { 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; }; ClearCellIDs: CD.DrawProc = { 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]]]; 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"]; CD.DrawOb[pr: cifH.cifMeasureR, ob: mainOb, readOnlyInstProps: mainInst.properties]; 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]; 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]; 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 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, 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] = { 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]; CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxCIFUnitsPerLambda]; CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxFlattenAtomic]; END. ธ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 September 4, 1987 6:32:51 pm PDT Last Edited by McCreight, October 17, 1984 7:02:18 pm PDT A package to output CIF files from ChipNDale, from BrandyCifter.mesa Global Variables 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_ALL[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; flattenAtomics _ CDProperties.GetProp[$CDxCIFRegistrations, $CDxFlattenAtomic]=$TRUE; start outputting a new cell and assign its cellID start outputting a new cell and assign its cellID but don't output the scaling finish off cell description output composite objects the children must be already defined call the children draw the rectangles IF cifH.currentDirective.deltaRadius>=0 THEN redundant but easier to understand output CIF for structures only identified as geometries IF cifH.currentDirective.deltaRadius>=0 THEN redundant but easier to understand output CIF for structures for polygons points are in design coords, not yet CIF coords 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 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. For each member of the instance list, determine whether obj is a cell. If so, determine transformations for each layer, pick out the rectangles belonging to that layer and output them IF cifH.currentDirective.deltaRadius>=0 THEN removed for simplicity generate all signal names we don't deal with signal names on p-diffusion; sorry, but I have more important things to do right now pos in CIFUnits indicate which cell is called using its ID number Output Procedures Sets mainRect to be a large as is necessary to contain design. 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 }; }; used to set all CellIDNo's to NIL at the start .. adds the condition that cif/cifScaling is guaranteed to be an integer, so cif*cifScaling.denom MOD cifScaling.num = 0 Search world data structure: normalize coordinates, set mainRect to design size, mark used layers output header ClearCellIDs[NIL, design.actual.first.dummyCell.ob]; define hybrid top layer object Flat CIF code the tesselation is in cif coordinates CStitching.PerTileProc only called on tiles with non-NIL values CStitching.PerTileProc -- Be careful not to exceed the limits of a CD.Number, even temporarily rounds to rect beeing bigger สD˜šœ™JšœH™HJšœ5™5Jšœ=™=Jšœ2™2Jšœ9™9—J™JšœD™DIcode˜šฯk ˜ Kšœ˜K˜ K˜K˜ K˜K˜ K˜ K˜ K˜Kšœ˜K˜ K˜K˜ K˜ K˜K˜ K˜ Kšœ˜Kšœœ ˜K˜K˜ —K˜šะln œœ˜Kšœœฉœ˜อKšœ˜Kšœ˜Kšœ œœ˜Kšœœœ ฯcœ˜.Kšœ œœŸœ˜+Kšœ œœœ˜.šœ œœœ˜%šœ œœ˜Kšœœ˜Kšœ œŸ$˜5K˜——šœœœœ˜/šœœœ˜ Kšœ œ˜Kšœœ˜Kšœ œŸ$˜5K˜——šœœœ ˜#šœ œœ˜Kšœ+œ˜0K˜K˜K˜——šœ œœ˜'šœœœ˜Kšœœ˜K˜ K˜ Kšœ œ ˜Kš œœœœœœŸ˜5K˜(Kšœ œœ˜Kšœ œœ˜Kšœ œŸ'˜=Kšœœ˜Kšœ œ˜Kšœ œœ˜K˜Kšœœœ˜%Kšœœ˜K˜Kšœ œ˜Kšœœ˜Kšœ˜K˜——K™Kšœ™Kš œ œœœœŸ˜=Kšœ œœŸ&˜@KšœœœŸ4˜UKšœ™Kšœ™Kšœ™Kšœ*™*Kšœ™Kšœ™Kšœ+™+Kšœ`™`K˜Kšœ@™@Kšœ ™ Kšœ?™?Kšœ™Kšœ4™4KšœW™WKšœ™Kšœ&™&Kšœ&™&Kšœ;™;Kšœ'™'Kšœ#™#Kšœa™aK™Kšœ™KšœŸ˜4K˜K˜š ฯn œœœ œœœ˜@Kšœœ˜6K˜—š  œœœœœ˜IKšœœœœ˜&Kšœœœœ˜)šœœ˜Kšœœœœ˜*Kš œœœœœ˜/K˜—šœœ˜šœœœœœ œœ˜HKšœœ ˜,Kšœœœœ˜2Kšœ˜—Kšœœ˜K˜—Kšœœ˜K˜K™—š  œœ œ œœ œ˜lKšœœA˜Gšœœœ˜9Kšœœœ3˜@KšœI˜MKšœ˜ K˜—šœ=œ˜LK˜7Kšœ3˜:—KšœU™UK˜K˜—š   œœœœœœ˜TšœM˜PK˜—K˜—š œœœ˜>šœHœ˜Wš œœœœ œœ˜5Kšœœ ˜Kšœ˜K˜—šœœ˜Kšœ˜K˜—šœœœ˜Kšœ˜K˜—Kšœ˜ K˜FKš˜K˜—K˜K™—š  œœœ˜7Kšœ1™1Kš œœœœœ*˜C˜#Kšœœœ˜T—K˜3K˜K˜—š œœœ˜AKšœ1™1Kšœ™Kš œœœœœ*˜CKšœœ˜4K˜3K˜K˜—š  œœ œœ˜(Kšœ™K˜K˜K˜—š  œœ ˜Kšœœ4˜NKšœœ˜K˜CK˜K˜—š œœ ˜Kšœœ4˜NKšœœ˜KšœL˜NK˜K˜—š œœœ˜AKšœ™Kšœ$™$Kš œœœœœœœ˜™>Kšœœ4˜NK˜!Kšœœ5˜QK˜K˜—š œœ˜-Kšœœ4˜NKšœœ)˜.Kšœœ5˜QK˜K˜—š  œœ˜K˜K˜—š  œœ˜%K˜K˜—š  œœ˜Kšœœ4˜Nšœœ˜Kš œœ œœœ˜Hšœ"œ˜*K˜€Kšœœ˜3K˜—K˜—K˜K˜—š  œœ$˜4Kšœœœœ˜(šœœœ˜$Kšœœ&˜EKšœœ˜K˜—šœ%Ÿ&˜KKšœ(Ÿ œ˜8Kšœ(Ÿ œ˜7Kšœ(Ÿœ˜@Kšœ(Ÿœ˜A—K˜K˜—š  œœ'˜8Kšœœ œ˜^K˜K˜—š  œœœœœ˜\KšœœJ˜PKšœœ ˜(K˜K˜šœ œœœœ'œ œ˜]Kšœœ˜+Kšœœ#œ˜AKšœ˜—K˜K˜K˜—š œœ œ˜:K˜Kšœœœ ˜BK˜K˜—š œœœ˜#K˜—š œœœœœœœœ˜\K˜š  œœœœœœœœœœ˜Ršœœœ˜šœœ˜Kšœœœ5˜PKš œœœœœS˜hKšœœœ=˜T—K˜—K˜—K˜š œ œœœ3œœ˜\K˜ˆKšœ˜—K˜K˜—šœ™KšœR™RKšœ"™"Kšœ™Kšœg™gKšœ™Kšœ<™Kšœœ˜KšœŸ˜ —K˜Kšœœ˜'Kšœ œ œœ ˜*Kšœœ˜ Kšœ œ˜Kš œ œœœœœ˜(šœœ˜*K˜šœ œ˜K˜ K˜K˜K˜K˜K˜—šœ œ˜K˜ K˜K˜#K˜K˜K˜—šœ œ˜K˜ K˜K˜(K˜#K˜K˜K˜—Kšœ)˜)K˜/Kšœ œœœ˜Kšœ˜K˜Kš œœœœœ˜1K˜K˜Kšœ˜K˜—K˜EK˜FK˜FK˜+K˜]Kšœœœ5˜XK˜BKšœc™cKšœR˜TKšœ ™ Kšœœ˜0KšœLœ ˜WKšœ3œ˜IKšœNœ8œ8˜ยKšœ#œ˜4K˜Kšœ œ$™4KšœYœ˜^Kšœ1œl˜ฃK˜Kšœ™K˜K˜šœ œœœœ'œ œ˜]Kšœœ˜1šœ%œ˜-Kšœœ˜Kšœ6œ˜;K˜BKšœ6œ˜Kšœ2œ œ ˜PK˜K˜,K˜'K˜Kšœœœ;œ&˜–šœœœ ˜šœœœ ˜Kšœ2œ˜7šœŸ˜K˜K˜Kšœœ1˜QKšœœ2˜SK˜—Kšœ=œ:˜zKšœŒŸ˜žKšœD˜FKšœŸ˜6Kšœ˜—Kšœ˜—K˜K˜*Kšœœ˜ K˜K˜—š œœ˜.Kšœœœœ˜+K˜?K˜K˜—š œœ˜$Kšœœœœ˜+K˜ K˜K˜—š  œœ˜"Kšœœ˜,Kšœ%œ˜DK˜BK˜K˜—š  œ œœœ˜?Kšœ™Kšœœ˜ KšœœBœ:˜…Kšœ˜K˜/K˜K˜—š œœœœ œœ œ˜KKšœD™Dšœ œœœ˜2Kšœœœœ˜,Kšœœœœ˜+Kšœœœœ˜+—˜K˜——š  œœœœ˜PKšœœ!˜,˜"K˜$K˜$K˜$K˜#K˜—K˜K˜—š  œœœœ˜UKšœœ!˜,K˜MK˜K˜—š œœœœ˜OKšœœ!˜,K˜+K˜K˜—š  œœ&œœ ˜SKšœ™Kšœœ!˜,˜!K˜%K˜%K˜;K˜:K˜—K˜K˜—š  œœ%œœ˜HKšœœ!˜'Kšœœ!˜'Kš œœœœœœ˜9Kšœ˜ K˜K˜—š  œœœ œœ˜