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]; }; 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; 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; 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] }; 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; 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 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; }; 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\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. nCDToCifImpl.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 CDVArrow, mainRect: CD.Rect, Global Variables mainRect: CD.Rect _ CDBasics.empty; set to design size in CIFMeasureArea, used to switch between ChipNDale and CIF coordinate systems flattenAtomics _ CDProperties.GetProp[$CDxCIFRegistrations, $CDxFlattenAtomic]=$TRUE; start outputting a new cell and assign its cellID CDProperties.PutObjectProp[obj, cellIDKey, cellID]; start outputting a new cell and assign its cellID but don't output the scaling CDProperties.PutObjectProp[obj, cellIDKey, cellID]; 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 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. 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 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]; }; 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]; }; .. adds the condition that cif/cifScaling is guaranteed to be an integer, so cif*cifScaling.denom MOD cifScaling.num = 0 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 ]]; mainRect: CDBasics.empty, 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["( 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]]]; 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]; define hybrid top layer object SymHeader[topLayerOb, cifH]; Flat CIF code the tesselation is in cif coordinates CStitching.PerTileProc only called on tiles with non-NIL values 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 CDVArrow.RemoveArrow[design: cifH.design]; CStitching.PerTileProc -- Be careful not to exceed the limits of a CD.Number, even temporarily rounds to rect beeing bigger CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxCIFUnitsPerLambda]; CDPropertyTools.Associate[$CDxCIFRegistrations, $CDxFlattenAtomic]; สb˜šœ™JšœH™HJšœ5™5Jšœ=™=Jšœ/™/Jšœ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˜K˜ —K˜šะln œœ˜Kšœœฅฯc œ œ ˜๋Kšœ˜Kšœ˜Kšœ œœ˜Kšœœœ Ÿœ˜.Kšœ œœŸœ˜+Kšœ œœœ˜.šœ œœœ˜%šœ œœ˜Kšœœ˜Kšœ œŸ$˜5K˜——šœœœœ˜/šœœœ˜ Kšœ œ˜Kšœœ˜Kšœ œŸ$˜5K˜——šœœœ ˜#šœ œœ˜Kšœ+œ˜0K˜K˜K˜——šœ œœ˜'šœœœ˜Kšœœ˜Kš œœœœœœŸ˜5K˜(Kšœ œœ˜Kšœ œœ˜Kšœ œŸ'˜=Kšœœ˜Kšœ œ˜Kšœ œœ˜K˜Kšœœœ˜%Kšœœ˜K˜Kšœ œ™Kšœœ˜Kšœ˜K˜K˜——K™Kšœ™Kš œ œœœœŸ˜=Kšœ œœŸ&˜@KšœœœŸ4˜UKšœ#™#Kšœa™aK™KšœŸ˜4K˜K˜š ฯn œœœ œœœ˜@Kšœœ˜6K˜K˜—š  œœœœœ˜IKšœœœœ˜&Kšœœœœ˜)šœœ˜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˜—š   œœœœœœ˜TKšœM˜PK˜K˜—š œœœ˜>šœHœ˜Wš œœœœ œœ˜5Kšœœ ˜Kšœ˜K˜—šœœ˜Kšœ˜K˜—šœœœ˜Kšœ˜K˜—šœ˜ K˜FKš˜K˜——K˜K™—š  œœœ˜7Kšœ1™1Kš œœœœœ*˜C˜%Kšœœœ˜T—K™3Kšœ/˜/K˜K˜—š œœœ˜AKšœ1™1Kšœ™Kš œœœœœ*˜CKšœœ˜4K™3Kšœ/˜/K˜K˜—š  œœ œœ˜(Kšœ™K˜K˜K˜—š  œœ ˜Kšœœ˜-Kšœœ˜K˜CK˜K˜—š œœ ˜Kšœœ˜-Kšœœ˜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šœœ˜-šœœ˜Kš œœ œœœ˜Hšœ"œ˜*K˜€Kšœœ˜3K˜—K˜—K˜K˜—š  œœ$˜4Kšœœœœ˜(šœœœ˜$Kšœœ&˜GKšœœ˜K˜—šœ'Ÿ&˜MKšœ(Ÿ œ˜8Kšœ(Ÿ œ˜7Kšœ(Ÿœ˜@Kšœ(Ÿœ˜A—K˜K˜—š  œœ"˜3Kšœœ"œ!˜bK˜K˜—š  œœœœœ˜\KšœœJ˜PKšœœ ˜(K˜K˜šœ œœœœ'œ œ˜]Kšœœ˜+Kšœœ#œ˜AKšœ˜—K˜K˜K˜—š œœ œ˜:K˜Kšœœ œ ˜DK˜K˜—š œœœ˜#K˜—š œœœœœœœœ˜\K˜š  œœœœœœœœœœ˜Ršœœœ˜šœœ˜Kšœœœ5˜PKš œœœœœS˜hKšœœœ=˜T—K˜—K˜—K˜š œ œœœ3œœ˜\K˜ˆKšœ˜—K˜K˜—šœ™KšœR™RKšœ"™"Kšœ™Kšœi™iKšœ™Kšœ>™>Kšœ ™ Kšœ™šœ™K˜——š  œœ ™Kš œœœœ'œ œ™fKšœ.™.Kšœœ4™NKšœ;œ™@Kšœœ"™;K™K™—š  œœ˜*Kšœœ!˜,KšœJŸ!˜kšœ œœœœ'œ œ˜]Kšœœ˜+K˜Kš œœœœœ˜LKšœœ˜'˜K˜Kšœ3œ3˜i—Kšœx™xKšœ˜—K˜K˜—š œ œ œœœœœœœœœ˜ฃšœ˜Kšœ.œ˜@Kšœœ˜KšœŸ˜ —K˜Kšœœ˜'Kšœ œ œœ ˜*Kšœœ˜ Kšœ œ˜Kš œ œœœœœ˜(Kš œœœœœœœ˜Jšœ œœ™,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šœœœ5˜XK˜BKšœc™cKšœM™OKšœ ™ Kšœœ˜2KšœNœ ˜YKšœ5œ˜KKšœPœ8œ8™ฤKšœ%œ˜6K˜Kšœ œ$™4KšœYœ™^Kšœ1œg™žKšœ$˜$Kšœ™K™KšœY˜Yšœ œœœœ'œ œ˜]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šœ[˜]KšœŸ˜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˜—š  œœœ œœ˜