DIRECTORY Atom USING [GetPName], CD, CDApplications USING [ARectO], CDBasics, CDCommandOps, CDDirectory, CDEnvironment, CDExtras, CDImports, CDIO, CDMenus, CDOps USING [DrawDesign], CDOrient, CDPolygons, CDProperties, CDSequencer USING [Command, ImplementCommand], CDViewer USING [ShowArrow, RemoveArrow], CornerStitching, FS USING [StreamOpen, Error], IO USING [ STREAM, time, PutRope, PutChar, CR, PutF, PutFR, int, rope, refAny, Close], List USING [Append], Rope, TerminalIO; BrandyCIFter: CEDAR PROGRAM IMPORTS Atom, CD, CDApplications, CDBasics, CDCommandOps, CDDirectory, CDEnvironment, CDExtras, CDImports, CDIO, CDMenus, CDOps, CDOrient, CDProperties, CDSequencer, CDViewer, CornerStitching, FS, IO, List, Rope, TerminalIO = 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: REF CornerStitching.Tesselation _ NIL, partClip: CIFRect _ [0,0,0,0] ]; cellIDKey: REF ATOM = NEW[ATOM _ $CellIDNo]; --not accessible debugging: BOOLEAN _ FALSE; -- used for printing out debugging messages design: CD.Design ; -- Chipndale data structure for which CIF will be written topLayerOb: CD.ObPtr _ NEW[CD.ObjectDefinition]; stopFlag: REF BOOLEAN _ NEW[BOOLEAN]; clearIDsRec: CD.DrawRef; cifMeasureR: CD.DrawRef; cifDrawRec: CD.DrawRef; --for CIFOrArea infinity: CD.DesignNumber _ LAST[CD.DesignNumber]; --used to initialize sizes and positions cellCount: INTEGER _ 0; -- used to assign consecutive CIF ID numbers cifLayerAnnounced: BOOLEAN _ FALSE; lambda: INT _ CD.lambda; cifPerLambda: INT _ 100; -- CIF units per lambda nmPerCIF: INT = 10; -- nanometers per CIF unit, given 0.01 microns per CIF unit cifPerCD: INT; -- cifPerLambda/l, since l is defined in CD units per lambda cifScaling: Rational; cifFile: IO.STREAM; -- file where output will be stored comment, base, name, lastCellName: Rope.ROPE; mainRect: CD.DesignRect _ [x1: infinity, y1: infinity, x2: -infinity, y2: -infinity]; cifDirectives: LIST OF REF ANY -- CIFDirective -- _ NIL; currentDirective: CIFDirective; partWidth: CIFUnits _ 800000; -- window for flat CIF partHeight: CIFUnits _ 800000; FreeStorage: PROC [] = BEGIN cifMeasureR _ clearIDsRec _ cifDrawRec _ NIL; --help the garbage collector design _ NIL; cifFile _ NIL; END; SimpleRect: PROC [ob: CD.ObPtr] RETURNS [yes: BOOL] = INLINE BEGIN yes _ ob.p.wireTyped AND (ob.p.objectType=$Rect OR ob.p.objectType=$SaveRect) END; ClearCellIDs: PROC [aptr: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, pr: REF CD.DrawInformation] -- CD.DrawProc -- = BEGIN CDProperties.PutPropOnObject[onto: aptr.ob, prop: cellIDKey, val: NIL]; IF aptr.ob.p.inDirectory THEN aptr.ob.p.drawMe[aptr: aptr, pos: aptr.location, orient: aptr.orientation, pr: clearIDsRec]; END; SymHeader: PROC [obj: CD.ObPtr]= BEGIN cellID: REF INT _ NEW[INT _ (cellCount _ cellCount + 1)]; cifFile.PutF["DS %d %d %d;\n", IO.int[cellCount], IO.int[cifScaling.num], IO.int[cifScaling.denom]]; CDProperties.PutPropOnObject[obj, cellIDKey, cellID]; END; SymTrailer: PROC = BEGIN cifFile.PutRope["DF;\n"]; END; CallChildren: CD.DrawProc = BEGIN IF ~SimpleRect[aptr.ob] THEN { cifPos: CIFPos _ CDPosToCIF[CDOrient.MapPoint[ pointInCell: [0, 0], cellSize: aptr.ob.size, cellInstOrient: orient, cellInstPos: pos ]]; CIFSymbolCall[aptr.ob, orient, cifPos]; }; END; DrawRectChilds: CD.DrawProc = BEGIN IF SimpleRect[aptr.ob] THEN { aptr.ob.p.drawMe[aptr: aptr, pos: pos, orient: orient, pr: cifDrawRec]; }; END; GenerateCompositeOb: PROC [obj: CD.ObPtr] = BEGIN pr: CD.DrawRef _ CD.CreateDrawRef[design]; dummyApPtr: CD.ApplicationPtr = NEW[CD.Application]; dummyApPtr^.ob _ obj; pr.stopFlag _ stopFlag; SymHeader[obj]; CIFDrawCellName[CDDirectory.Name[obj]]; pr.drawChild _ CallChildren; obj.p.drawMe[dummyApPtr, [0, 0], CD.original, pr]; pr.drawChild _ DrawRectChilds; pr.drawRect _ pr.saveRect _ CIFOrArea; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO currentDirective _ NARROW[directives.first]; cifLayerAnnounced _ FALSE; IF currentDirective.deltaRadius>=0 THEN obj.p.drawMe[dummyApPtr, [0, 0], CD.original, pr]; ENDLOOP; SymTrailer[]; END; GenerateGeometricOb: PROC [obj: CD.ObPtr] = BEGIN dummyApPtr: CD.ApplicationPtr = NEW[CD.Application]; dummyApPtr^.ob _ obj; SymHeader[obj]; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO currentDirective _ NARROW[directives.first]; cifLayerAnnounced _ FALSE; IF currentDirective.deltaRadius>=0 THEN obj.p.drawMe[aptr: dummyApPtr, pos: [0, 0], orient: 0, pr: cifDrawRec]; ENDLOOP; SymTrailer[]; END; GeneratePolygon: PROC [obj: CD.ObPtr] = BEGIN CifPolygonOut: PROC [points: LIST OF CD.DesignPosition] = BEGIN IF NOT cifLayerAnnounced THEN { cifFile.PutF["L %g;\n", IO.rope[currentDirective.cifDest]]; cifLayerAnnounced _ TRUE; }; cifFile.PutRope["P"]; FOR p: LIST OF CD.DesignPosition _ points, p.rest WHILE p#NIL DO cifPos: CD.Position = CDPosToCIF[p.first]; cifFile.PutRope[" "]; CIFOutPoint[cifPos.x, cifPos.y]; ENDLOOP; cifFile.PutRope[";\n"]; END; polygon: CDPolygons.PolygonPtr = NARROW[obj.specificRef]; bad: BOOL _ FALSE; SymHeader[obj]; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO currentDirective _ NARROW[directives.first]; cifLayerAnnounced _ FALSE; IF currentDirective.cdSource=obj.layer THEN { IF currentDirective.deltaRadius#0 THEN bad _ TRUE; CifPolygonOut[polygon.points]; } ENDLOOP; IF bad THEN { TerminalIO.WriteRope["**polygon shrink or bloat failed\n"]; cifFile.PutRope["( polygon has incorrect sizing );\n"]; }; SymTrailer[]; END; CIFDefineObject: PROC [obj: CD.ObPtr] = BEGIN CheckChildren: CDDirectory.EnumerateObjectsProc = { IF me.p.inDirectory AND CDEnvironment.Propagates[me] THEN { hasChildWhichPropagates _ TRUE } ELSE CIFDefineObject[me] }; hasChildWhichPropagates: BOOL _ FALSE; IF debugging THEN TerminalIO.WriteRope["Entering CIFDefineObject\n"]; IF CDProperties.GetPropFromObject[obj, cellIDKey]#NIL THEN RETURN; IF obj.p.inDirectory THEN { IF CDEnvironment.Propagates[obj] THEN ERROR; CDDirectory.EnumerateChildObjects[obj, CheckChildren, NIL]; }; IF hasChildWhichPropagates THEN { ob1: CD.ObPtr _ CDDirectory.ExpandHard[me: obj, from: design, to: NIL]; IF ob1#NIL AND ~CDEnvironment.Propagates[ob1] AND ~CDEnvironment.SomeChildPropagates[ob1] THEN { CIFDefineObject[ob1]; CDProperties.PutPropOnObject[ onto: obj, prop: cellIDKey, val: CDProperties.GetPropFromObject[ob1, cellIDKey] ]; } ELSE GenerateGeometricOb[obj: obj]; } ELSE WITH obj.specificRef SELECT FROM refPtr: CDImports.ReferencePtr => { IF refPtr.boundApp=NIL THEN ERROR; CIFDefineObject[refPtr.boundApp.ob]; SymHeader[obj]; CIFDrawCellName[Rope.Cat[refPtr.designName, ".", refPtr.objectName]]; CIFSymbolCall[refPtr.boundApp.ob, CD.original, [0, 0]]; SymTrailer[]; }; cellptr: CD.CellPtr => { SymHeader[obj]; CIFDrawCellName[cellptr.name]; FOR aplist: CD.ApplicationList _ cellptr.contents, aplist.rest WHILE aplist#NIL DO IF ~SimpleRect[aplist.first.ob] THEN { cifPos: CIFPos _ CDPosToCIF[CDOrient.MapPoint[ pointInCell: [0, 0], cellSize: aplist.first.ob.size, cellInstOrient: aplist.first.orientation, cellInstPos: aplist.first.location ]]; CIFSymbolCall[aplist.first.ob, aplist.first.orientation, cifPos]; }; ENDLOOP; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO currentDirective _ NARROW[directives.first]; cifLayerAnnounced _ FALSE; IF currentDirective.deltaRadius>=0 THEN FOR aplist: CD.ApplicationList _ cellptr.contents, aplist.rest WHILE aplist#NIL DO IF SimpleRect[aplist.first.ob] THEN { aplist.first.ob.p.drawMe[aptr: aplist.first, pos: aplist.first.location, orient: aplist.first.orientation, pr: cifDrawRec]; }; ENDLOOP; ENDLOOP; FOR aplist: CD.ApplicationList _ cellptr.contents, aplist.rest WHILE aplist#NIL DO value: REF = CDProperties.GetPropFromObject[aplist.first.ob, $signalName]; IF value#NIL THEN IF SimpleRect[aplist.first.ob] THEN CIFLabelTerminalIO[aplist.first, NARROW[value], aplist.first.ob.layer]; ENDLOOP; SymTrailer[]; }; -- of cell ENDCASE => -- crazy or transistors or geometry or rects IF obj.p.inDirectory THEN GenerateCompositeOb[obj] ELSE IF ~SimpleRect[obj] THEN { IF ISTYPE[obj.specificRef, CDPolygons.PolygonPtr] THEN GeneratePolygon[obj] ELSE GenerateGeometricOb[obj]; }; IF debugging THEN TerminalIO.WriteRope["Leaving CIFDefineObject\n"]; END; CIFSymbolCall: PROC[ob: CD.ObPtr, orient: CD.Orientation_CDOrient.original, pos: CD.Position_ [0,0]] = BEGIN WITH CDProperties.GetPropFromObject[ob, cellIDKey] SELECT FROM iDNo: REF INT => { cifFile.PutF["C %d", IO.int[iDNo^]]; IF orient#CD.original THEN { xrotation: CD.Orientation _ CDOrient.ConcentrateOnRotate90[orient]; IF xrotation#CD.original THEN { cifFile.PutRope[" R "]; cifFile.PutRope[SELECT xrotation FROM CDOrient.rotate90 => "0,1" , CDOrient.rotate180=> "-1,0", CDOrient.rotate270=> "0,-1", ENDCASE=> "1,0" -- never use this one ]; }; IF CDOrient.IncludesMirrorX[orient] THEN cifFile.PutRope[" M X "]; }; IF pos#[0, 0] THEN { cifFile.PutRope[" T "]; CIFOutPoint[pos.x, pos.y]; }; cifFile.PutRope[";\n"]; }; ENDCASE => ERROR; END; CIFMeasureArea: PROC [r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef] = BEGIN r _ CDBasics.NormalizeRect[r]; IF CDBasics.NonEmpty[r] THEN mainRect _ CDBasics.Surround[mainRect, r]; END; CIFOrArea: PROC [r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef] = BEGIN rd: CD.DesignRect; IF (l # currentDirective.cdSource) OR NOT CDBasics.NonEmpty[r] THEN RETURN; rd _ CDBasics.NormalizeRect[r]; CIFRectOut[CDBasics.Extend[r: CDRectToCIF[CDBasics.NormalizeRect[r]], ext: currentDirective.deltaRadius/nmPerCIF]]; END; CIFRectOut: PROC [r: CIFRect] = BEGIN IF NOT CDBasics.NonEmpty[r] THEN RETURN; IF NOT cifLayerAnnounced THEN { cifFile.PutF["L %g;\n", IO.rope[currentDirective.cifDest]]; cifLayerAnnounced _ TRUE; }; cifFile.PutF["B %d %d %d %d;\n",-- BOX command, in prescaled CIF units IO.int[PrescaleCIF[[r.x2-r.x1, 1]]] -- length -- , IO.int[PrescaleCIF[[r.y2-r.y1, 1]]] -- width -- , IO.int[PrescaleCIF[[r.x1+r.x2, 2]]] -- center x-coord -- , IO.int[PrescaleCIF[[r.y1+r.y2, 2]]] -- center y-coord -- ]; END; CIFOutPoint: PROC[x, y: CIFUnits] = BEGIN cifFile.PutF["%d,%d", IO.int[PrescaleCIF[[x,1]]], IO.int[PrescaleCIF[[y,1]]]] END; CIFLabelTerminalIO: PROC [ap: CD.ApplicationPtr, s: Rope.ROPE, lev: CD.Layer] = BEGIN pt: CD.Position _ CDBasics.Center[CDRectToCIF[CDApplications.ARectO[ap]]]; cifFile.PutF["94 %s ", IO.rope[s]]; CIFOutPoint[pt.x, pt.y]; cifFile.PutChar[' ]; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO d: CIFDirective = NARROW[directives.first]; IF d.cdSource = lev THEN {cifFile.PutRope[d.cifDest]; EXIT}; ENDLOOP; cifFile.PutRope[";\n"]; END; CIFDrawCellName: PROC[s: Rope.ROPE] = BEGIN lastCellName _ s; IF ~Rope.IsEmpty[s] THEN cifFile.PutF["9 %s;\n", IO.rope[s]]; END; RopeNeeded: SIGNAL [ ref: REF REF ] = CODE; ToRope: PROC [ ref: REF ] RETURNS [ rope: Rope.ROPE ] = BEGIN WITH ref SELECT FROM r: Rope.ROPE => rope _ r; rt: REF TEXT => rope _ Rope.FromRefText[rt]; a: ATOM => rope _ Atom.GetPName[a]; ri: REF INT => rope _ IO.PutFR[format: "%d", v1: IO.int[ri^]]; ENDCASE => IF ref=NIL THEN rope _ NIL ELSE { refRef: REF REF = NEW[REF _ ref]; SIGNAL RopeNeeded[refRef]; rope _ ToRope[refRef^ ! RopeNeeded => GOTO NoHelp]; EXITS NoHelp => ERROR; }; END; CantRepresentExactly: ERROR = CODE; SetCIFScaling: PROC = BEGIN cifScaling _ ReduceTerms[[num: cifPerLambda, denom: 2*lambda]]; -- the "2" allows for box centers FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO d: CIFDirective = NARROW[directives.first]; cif: CIFUnits; IF ABS[d.deltaRadius] MOD nmPerCIF # 0 THEN ERROR CantRepresentExactly; cif _ ABS[d.deltaRadius]/nmPerCIF; cifScaling _ ReduceTerms[[ num: cifScaling.num, denom: (cifScaling.num*cifScaling.denom)/GCD[cif*cifScaling.denom, cifScaling.num]]]; ENDLOOP; END; CollectDirectives: PROC = BEGIN GetDirectives: PROC [p: REF, lev: CD.Layer] RETURNS [l: LIST OF REF ANY _ NIL] = BEGIN 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, ToRope[p], 0]]]; }; END; cifDirectives _ NIL; FOR layers: LIST OF CD.Layer _ design.technology.usedLayers, layers.rest WHILE layers#NIL DO cifDirectives _ List.Append[GetDirectives[CDProperties.GetPropFromLayer[layers.first, $CDxCIFName], layers.first ], cifDirectives]; ENDLOOP; END; WriteCIF: PROC[ comm: CDSequencer.Command] = BEGIN ENABLE BEGIN ABORTED => {TerminalIO.WriteRope[" CIF generation aborted\n"]; GOTO Exit}; RopeNeeded => { explanation: Rope.ROPE = IO.PutFR[format: "Please enter a string corresponding to the value %g: ", v1: IO.refAny[ref^]]; ref^ _ TerminalIO.RequestRope[explanation]; RESUME; }; UNWIND => NULL; END; --enable mainOb: CD.ObPtr; cifKey: Rope.ROPE; design _ comm.design; cifKey _ ToRope[CDProperties.GetPropFromTechnology[design.technology, $CDxCIFName]]; IF Rope.IsEmpty[cifKey] THEN { TerminalIO.WriteRope["The CIF layers for this technology are not yet defined\n"]; RETURN }; TerminalIO.WriteRope["Use CIF layer definitions ["]; TerminalIO.WriteRope[cifKey]; TerminalIO.WriteRope["]\n"]; mainOb _ CDExtras.CreateDummyObject[design]; cellCount _ 0; stopFlag^ _ FALSE; cifMeasureR _ CD.CreateDrawRef[design]; cifMeasureR.interestClip _ CDBasics.universe; cifMeasureR.drawRect _ cifMeasureR.saveRect _ CIFMeasureArea; cifMeasureR.stopFlag _ stopFlag; clearIDsRec _ CD.CreateDrawRef[design]; clearIDsRec.interestClip _ CDBasics.universe; clearIDsRec.drawChild _ ClearCellIDs; clearIDsRec.stopFlag _ stopFlag; cifDrawRec _ CD.CreateDrawRef[design]; cifDrawRec.interestClip _ CDBasics.universe; cifDrawRec.drawRect _ cifDrawRec.saveRect _ CIFOrArea; cifDrawRec.stopFlag _ stopFlag; CDOps.DrawDesign[design, cifMeasureR]; TerminalIO.WriteRope["Input name of CIF file ("]; TerminalIO.WriteRope[CDIO.GetWorkingDirectory[design]]; TerminalIO.WriteRope[") "]; base _ TerminalIO.RequestRope[">> "]; IF Rope.IsEmpty[base] THEN base _ design.name; IF Rope.IsEmpty[base] THEN base _ "foo"; name _ CDIO.MakeName[base: base, ext: ".cif", wDir: CDIO.GetWorkingDirectory[design]]; cifFile _ FS.StreamOpen[name, create ! FS.Error => IF error.group#bug THEN { TerminalIO.WriteRope[error.explanation]; GOTO FileIOOpenFailed; } ]; TerminalIO.WriteRope["How many CIF units per lambda?\n"]; cifPerLambda _ TerminalIO.RequestInt[" (1 CIF unit = 0.01 microns) \n", ">> "]; IF cifPerLambda<2 THEN { TerminalIO.WriteRope["cif Per Lambda value not reasonable\n"]; RETURN }; IF debugging THEN { TerminalIO.WriteRope["cif Per Lambda = "]; TerminalIO.WriteInt[cifPerLambda]; TerminalIO.WriteRope["\n"]; }; cifPerCD _ cifPerLambda/lambda; 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[cifPerCD*(mainRect.x2-mainRect.x1)], IO.int[cifPerCD*(mainRect.y2-mainRect.y1)]]; cifFile.PutF["( CIF KEY: %s );\n", IO.rope[cifKey]]; cifFile.PutRope["(BRANDYCIFTER NOT YET TESTED);\n"]; TerminalIO.WriteRope["Comment line: \n"]; comment _ TerminalIO.RequestRope["(parens must balance, CR for no comment)\n", ">> "]; WHILE NOT Rope.IsEmpty[comment] DO cifFile.PutF["( %s )\n", IO.rope[comment]]; comment _ NIL; TerminalIO.WriteRope["Another comment line:\n"]; comment_TerminalIO.RequestRope[ "(parens must balance, CR for no further comments)\n", ">> "]; ENDLOOP; IO.PutChar[cifFile, IO.CR]; CollectDirectives[]; SetCIFScaling[]; ClearCellIDs[design.actual.first.dummyCell, [0,0], 0, NIL]; CIFDefineObject[mainOb]; SymHeader[topLayerOb]; CIFSymbolCall[mainOb]; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO currentDirective _ NARROW[directives.first]; IF currentDirective.deltaRadius<0 THEN BEGIN cifLayerAnnounced _ FALSE; MakeFlatCIF[rectProc: CIFRectOut]; END; ENDLOOP; SymTrailer[]; CIFSymbolCall[topLayerOb, CDOrient.original, [x: -cifPerCD*mainRect.x1, y: -cifPerCD*mainRect.y2]]; cifFile.PutRope[";\nEnd ... \n"]; cifFile.Close[]; TerminalIO.WriteLn[]; TerminalIO.WriteRope["CIF file on "]; TerminalIO.WriteRope[name]; TerminalIO.WriteLn[]; FreeStorage[] EXITS Exit => FreeStorage[]; FileIOOpenFailed => { TerminalIO.WriteRope["Open Failed\n"]; FreeStorage[] }; END; -- of WriteCIF MakeFlatCIF: PROC [rectProc: PROC[rect: CIFRect]] = BEGIN AnalyzeTesselation: PROC [ms: MaskStateRef] = BEGIN active: CD.Rect = ms.areas.ContentsBound[rect: CDBasics.universe]; IF CDBasics.NonEmpty[active] THEN { IF currentDirective.deltaRadius#0 THEN { t: REF CornerStitching.Tesselation = ms.unbloated; ms.unbloated _ ms.areas; ms.areas _ t; ms.areas.ChangeRect[rect: CDBasics.universe, newValue: NIL]; IF currentDirective.deltaRadius>0 THEN [] _ ms.unbloated.EnumerateArea[rect: CDBasics.universe, perTile: BloatTile, data: ms] ELSE { ms.areas.ChangeRect[rect: active, newValue: $covered]; [] _ ms.unbloated.EnumerateArea[rect: CDBasics.universe, perTile: BloatTile, data: ms, backgroundValue: $covered]; }; }; [] _ ms.areas.EnumerateArea[rect: CDBasics.universe, perTile: OutputTile, data: ms, backgroundValue: NIL]; TerminalIO.WriteRope["."]; }; END; OutputTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] = -- CornerStitching.PerTileProc BEGIN -- only called on tiles with non-NIL values ms: MaskStateRef = NARROW[data]; cr: CIFRect = CDBasics.Intersection[tile.Area, ms.partClip]; rectProc[cr]; END; designClip: CD.DesignRect; cifClip: CD.Rect; nRows, nCols: NAT; ms: MaskStateRef = NEW[MaskState _ [ areas: CornerStitching.NewTesselation[], unbloated: CornerStitching.NewTesselation[] ]]; dr: CD.DrawRef _ CD.CreateDrawRef[design]; dr.minimalSize _ 0; dr.drawRect _ dr.saveRect _ NoteBoundingBox; dr.devicePrivate _ NEW[CD.DesignRect _ CDBasics.empty]; dr.interestClip _ CDBasics.universe; dr.stopFlag _ stopFlag; CDOps.DrawDesign[design, dr]; -- measure design designClip _ NARROW[dr.devicePrivate, REF CD.DesignRect]^; cifClip _ Bloat[CDRectToCIF[designClip], ABS[currentDirective.deltaRadius]/nmPerCIF]; nRows _ Ceiling[num: cifClip.y2-cifClip.y1, denom: partHeight]; nCols _ Ceiling[num: cifClip.x2-cifClip.x1, denom: partWidth]; TerminalIO.WriteRope[IO.PutFR[format: ".. in %d rows and %d columns..", v1: IO.int[nRows], v2: IO.int[nCols]]]; dr.drawRect _ dr.saveRect _ NoteRectangle; dr.devicePrivate _ ms; TerminalIO.WriteRope[IO.PutFR["%s -> %s", IO.rope[ToRope[CD.LayerKey[currentDirective.cdSource]]], IO.rope[currentDirective.cifDest]]]; FOR col: NAT IN [0..nCols) DO FOR row: NAT IN [0..nRows) DO ms.areas.ChangeRect[rect: CDBasics.universe, newValue: 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[currentDirective.deltaRadius]/nmPerCIF]]; CDViewer.ShowArrow[design: design, pos: [x: (dr.interestClip.x1+dr.interestClip.x2)/2, y: (dr.interestClip.y1+dr.interestClip.y2)/2]]; -- keep user happy CDOps.DrawDesign[design, dr]; -- build tesselation of the relevant design rectangle AnalyzeTesselation[ms]; -- sends the current part to s ENDLOOP; ENDLOOP; TerminalIO.WriteRope["+"]; CDViewer.RemoveArrow[design: design]; dr _ NIL; END; NoteBoundingBox: PROC [ r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef ] = BEGIN bb: REF CD.DesignRect = NARROW[pr.devicePrivate]; bb^ _ CDBasics.Surround[bb^, r]; END; NoteRectangle: PROC [r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef] = BEGIN ms: MaskStateRef = NARROW[pr.devicePrivate]; IF l=currentDirective.cdSource AND CDBasics.NonEmpty[r] THEN ms.areas.ChangeRect[ rect: CDRectToCIF[r], newValue: $covered ]; END; BloatTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] = -- CornerStitching.PerTileProc -- BEGIN ms: MaskStateRef = NARROW[data]; cr: CD.Rect = CDBasics.Intersection[CDBasics.universe, Bloat[tile.Area, ABS[currentDirective.deltaRadius/nmPerCIF]]]; IF CDBasics.NonEmpty[cr] THEN ms.areas.ChangeRect[rect: cr, newValue: tile.Value]; END; Bloat: PROC [r: CD.Rect, delta: CD.Number] RETURNS [br: CD.Rect] = INLINE BEGIN 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] END; CDRectToCIF: PROC [ cdr: CD.DesignRect ] RETURNS [ cifr: CIFRect ] = BEGIN cifr _ CDBasics.NormalizeRect[[ x1: cifPerCD*cdr.x1, y1: cifPerCD*cdr.y1, x2: cifPerCD*cdr.x2, y2: cifPerCD*cdr.y2 ]] END; CDPosToCIF: PROC [ cdp: CD.DesignPosition ] RETURNS [ cifp: CIFPos ] = BEGIN cifp _ [x: cifPerCD*cdp.x, y: cifPerCD*cdp.y] END; CIFRectToCD: PROC [ cifr: CIFRect ] RETURNS [ cdr: CD.DesignRect ] = {cdr _ CDBasics.NormalizeRect[ [x1: cifr.x1/cifPerCD, y1: cifr.y1/cifPerCD, x2: cifr.x2/cifPerCD, y2: cifr.y2/cifPerCD]] }; PrescaleCIF: PROC [ cif: Rational ] RETURNS [ INT ] = BEGIN n: INT = cif.num*cifScaling.denom; d: INT = cif.denom*cifScaling.num; IF ABS[n] MOD ABS[d] # 0 THEN ERROR CantRepresentExactly; RETURN[n/d]; END; Ceiling: PROC [num, denom: CD.Number] RETURNS [ c: INT ] = {c _ (num+denom-1)/denom}; ReduceTerms: PROC [ r: Rational ] RETURNS [ Rational ] = BEGIN gcd: INT = GCD[r.num, r.denom]; RETURN[[num: r.num/gcd, denom: r.denom/gcd]]; END; GCD: PROC [ m, n: INT ] RETURNS [ INT ] = BEGIN 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]; END; WriteCIFComm: PROC [comm: CDSequencer.Command] = BEGIN TerminalIO.WriteRope["Hierarchical CIF output\n"]; TerminalIO.WriteRope["New version February 26, 1985 4:32:03 pm PST; which does no more mirror in Y\n"]; TerminalIO.WriteRope["***************\n"]; TerminalIO.WriteRope["NOT YET TESTED\n"]; TerminalIO.WriteRope["***************\n"]; TerminalIO.WriteRope["If you generate masks from this crab, it's your own risk\n"]; IF CDCommandOps.IsPushedIn[comm.design] THEN { TerminalIO.WriteRope["**Design is pushed in\n"]; RETURN }; IF CDImports.HasUnloadedImports[comm.design] THEN { TerminalIO.WriteRope["**Design has non bound imports\n"]; RETURN }; [] _ CDCommandOps.CallWithResource[WriteCIF, comm, $CIF, stopFlag]; END; CDSequencer.ImplementCommand[a: $WriteCif, p: WriteCIFComm, queue: doQueue]; CDMenus.CreateEntry[menu: $ProgramMenu, entry: "Hierarchical CIF", key: $WriteCif]; END. þBrandyCIFter.mesa A module to output CIF files from ChipNDale Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Last Edited by: Kimr, October 15, 1984 5:15:13 pm PDT Last Edited by: Jacobi, October 30, 1984 12:10:38 pm PST Last Edited by McCreight, October 17, 1984 7:02:18 pm PDT Last Edited by Jacobi, April 12, 1985 5:59:37 pm PST --TYPES --Global Variables --layer assumed to be unchanged until the next layer is announced --..output numbers*cifScaling = CIFUnits --..CIFUnits/cifScaling = output numbers --set to design size in CIFMeasureArea, used to switch between Chipndale and CIF coordinate systems --Procedures --used to set all CellIDNo's to NIL at the start --start outputting a new cell and assign its cellID --finish off cell description --logically local to GenerateCompositeOb --PROC [aptr: ApplicationPtr, pos: DesignPosition, orient: Orientation, pr: REF DrawInformation] --logically local to GenerateCompositeOb --PROC [aptr: ApplicationPtr, pos: DesignPosition, orient: Orientation, pr: REF DrawInformation] --output composite objects --the children must be already defined --match the type of drawMe parameter --call the children --draw the rectangles --output CIF for structures only identified as geometries --match the type of drawMe parameter --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 application 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 --generate all signal names --pos in CIFUnits --indicate which cell is called using its ID number --OUTPUT PROCEDURES -- CD.DrawRectProc -- Sets mainRect to be a large as is necessary to contain design. --.. adds the condition that cif/cifScaling is guaranteed to be an integer, so cif*cifScaling.denom MOD cifScaling.num = 0 --assign world variable from sequencer --initialize main object, layer names, resolution, cellCount, and draw records --Search world data structure: normalize coordinates, --set mainRect to design size, mark used layers --get file name --output header --ask for comment lines --define hybrid top layer object --Flat CIF code --the tesselation is in cif coordinates --Be careful not to exceed the limits of a CD.Number, even temporarily Êœ˜šœ?™?Jšœ Ïmœ7™BJšœ5™5Jšœ8™8J™9Jšœ4™4—J˜šÏk ˜ Jšœžœ ˜Jšžœ˜Jšœžœ ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ ˜ Jšžœ˜Jšœ˜Jšœžœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ žœ˜.Jšœ žœ˜(Jšœ˜Jšžœžœ˜Jšžœžœžœžœ)˜VJšœžœ ˜Jšœ˜Jšœ ˜ —Jšœ˜šÏb œžœž˜Jš žœžœNžœažœžœ˜á—Jšž˜J˜JšŸ™™Jšœ žœžœ˜Jšœžœžœ Ïcœ˜.Jšœ žœžœ œ˜+Jšœ žœžœžœ˜.Jšœ žœžœžœ˜%šœ žœžœ˜Jšœžœ˜Jšœ žœ $˜5Jšœ˜—Jšœžœžœžœ˜/šœžœžœ˜ Jšœ žœ˜Jšœžœ˜Jšœ žœ $˜5J˜—Jšœžœžœ ˜#šœ žœžœ˜Jšœžœžœ˜9Jšœ˜Jšœ˜J˜——J™JšŸ™˜Jš œ žœžœžœžœ ˜=J˜Jšœ žœžœ +˜HJ˜Jšœžœ  9˜MJšœ žœ žœžœ˜0Jš œ žœžœžœžœ˜%Jšœ žœ ˜Jšœ žœ ˜Jšœ žœ  ˜(J˜Jšœ žœžœžœ (˜\Jšœ˜Jšœ žœ ,˜FJ˜šœžœžœ˜#JšœA™A—J˜Jšœžœžœ˜Jšœžœ  ˜1Jšœ žœ ;˜OJšœ žœ Ðcg ¡ "˜LJ˜šœ˜Jšœ(™(Jšœ(™(—J˜Jšœ žœžœ $˜8Jšœ(žœ˜-J˜šœU˜UJšœc™c—J™Jš œžœžœžœž œžœ˜9Jšœ˜J˜Jšœ ˜4Jšœ˜J˜—Jšœ˜JšÏn ™ ˜š¢ œžœ˜Jšž˜Jšœ)žœ ˜JJšœ žœ˜ Jšœ žœ˜Jšžœ˜—J˜š ¢ œžœžœžœžœ˜5Jšž ˜ Jšœžœžœ˜MJšžœ˜——˜š¢ œžœžœžœžœžœžœ œ˜ŒJšœ0™0Jšž˜JšœBžœ˜Gšžœž˜Jšœ]˜]—Jšžœ˜—J˜š¢ œžœžœ˜ Jšœ3™3Jšž˜Jš œžœžœžœžœ ˜9šœ˜Jšžœžœžœ˜E—Jšœ5˜5Jšžœ˜J˜—š¢ œžœ˜Jšœ™Jšž˜Jšœ˜Jšžœ˜J˜—Jšœ(™(šŸ œžœ ˜Jšœ`™`Jšž˜šžœžœ˜šœ.˜.Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ'˜'Jšœ˜—Jšžœ˜—J˜Jšœ(™(šŸœžœ ˜Jšœ`™`Jšž˜šžœžœ˜JšœG˜GJšœ˜—Jšžœ˜—J˜š¢œžœžœ ˜+Jšœ™Jšœ&™&Jšž˜Jšœžœ žœ˜*šœ žœžœžœ˜5Jšœ$™$—Jšœ˜Jšœ˜Jšœ˜Jšœ'˜'Jšœ™Jšœ˜Jšœ2˜2Jšœ™Jšœ˜Jšœ&˜&šžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜,Jšœžœ˜šžœ!ž˜'Jšœ2˜2—Jšžœ˜—Jšœ ˜ Jšžœ˜—J˜š¢œžœžœ ˜+Jšœ9™9Jšž˜šœ žœžœžœ˜5Jšœ$™$—Jšœ˜Jšœ˜šžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜,Jšœžœ˜šžœ!ž˜'JšœG˜G—Jšžœ˜—Jšœ ˜ Jšžœ˜—J˜š¢œžœžœ ˜'Jšœ(™(Jšž˜J˜š ¢ œžœ žœžœžœ˜9Jšœ1™1Jšž˜šžœžœž˜Jšœžœ!˜;Jšœžœ˜Jšžœ˜—Jšœ˜š žœžœžœžœ!žœžœž˜@Jšœžœ ˜*Jšœ˜Jšœ ˜ Jšžœ˜—Jšœ˜Jšžœ˜—J˜Jšœ!žœ˜9Jšœžœžœ˜Jšœ˜šžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜,Jšœžœ˜šžœ%ž˜-Jšžœ žœž˜2Jšœ˜J˜—Jšžœ˜—šžœžœ˜ Jšœ;˜;Jšœ7˜7J˜—Jšœ ˜ Jšžœ˜—J˜š¢œžœžœ ˜'Jšœ°™°Jšž˜J˜šŸ œ&˜3šžœžœžœ˜šœžœžœ˜Jšœžœ ˜$šžœžœ žœ˜Jšœ žœ6˜Cšžœ žœ žœ˜Jšœ˜šœžœ ž˜%Jšœ˜Jšœ˜Jšœ˜Jšžœ  ˜%Jšœ˜—Jšœ˜—Jšžœ"žœ˜BJšœ˜—šžœ žœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ˜Jšžœ˜—Jšžœžœ˜—Jšžœ˜—Jšœ˜JšŸ™J˜Jšœ˜š Ðbnœžœžœžœ žœ ˜GJšœ™JšœA™AJšž˜Jšœ˜Jšžœžœ+˜GJšžœ˜—Jšœ˜š Ÿ œžœžœžœ žœ ˜BJšž˜Jšœžœ ˜Jš žœ!žœžœžœžœ˜KJšœ˜Jšœs˜sJšžœ˜—Jšœ˜š¢ œžœ˜Jšž˜Jšžœžœžœžœ˜(šžœžœž˜Jšœžœ!˜;Jšœžœ˜Jšžœ˜—šœ  &˜FJšžœ"  œ˜2Jšžœ"  œ˜1Jšžœ" œ˜:Jšžœ" œ˜;—Jšžœ˜J˜—š¢ œžœ˜#Jšž˜Jšœžœžœ˜MJšžœ˜J˜—š ¢œžœžœžœžœ ˜OJšž˜JšœJ˜JJšœžœ ˜#Jšœ˜Jšœ˜šžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜+Jšžœžœžœ˜šžœ˜ Jšžœžœžœž˜šžœ˜Jš œžœžœžœžœ˜!Jšžœ˜Jšœ&žœ ˜3Jšžœ žœ˜Jšœ˜———Jšžœ˜J˜—J˜Jšœžœžœ˜#J˜š¢ œžœ˜Jšž˜Jšœ@ !˜ašžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜+Jšœ˜šžœžœžœž˜+Jšžœ˜—Jšœžœ˜"šœ˜Jšœ˜Jšœ)žœ)˜UJšœz™z—Jšžœ˜—Jšžœ˜J˜J˜—š¢œžœ˜Jšž˜J˜š¢ œžœžœžœžœžœžœžœžœžœ˜PJšž˜šžœžœžœ˜šžœžœž˜Jšœžœžœ5˜PJš œžœžœžœžœS˜hJšžœžœžœ)˜@—Jšœ˜—Jšžœ˜J˜—Jšœžœ˜š žœ žœžœžœ3žœžœž˜\Jšœƒ˜ƒJšžœ˜—Jšžœ˜J˜Jšœ˜—š¢œžœ˜,šžœ˜Jšžœž˜ Jšžœ9žœ˜Kšœ˜JšœžœžœLžœ˜xJšœ+˜+Jšžœ˜Jšœ˜—Jšžœžœ˜Jšžœ ˜ —Jšœ˜Jšœ&™&Jšœ˜Jšœ žœ˜Jšœ˜JšœT˜Tšžœžœ˜JšœQ˜QJšž˜J˜Jšœ4˜4Jšœ˜Jšœ˜J˜—JšœO™OJ™J˜Jšœ,˜,Jšœ˜Jšœ žœ˜Jšœ˜Jšœžœ˜'Jšœ-˜-Jšœ=˜=Jšœ ˜ J˜Jšœžœ˜'Jšœ-˜-J˜%J˜ Jšœ˜Jšœžœ˜'Jšœ,˜,Jšœ6˜6Jšœ˜Jšœ˜Jšœ6™6Jšœ1™1J™Jšœ)˜)Jšœ˜Jšœ™Jšœ1˜1Jšœžœ˜7Jšœ˜Jšœ%˜%Jšžœžœ˜.Jšžœžœ˜(Jšœžœ)žœ˜Všœ žœ˜(šžœ ˜ šžœžœ˜Jšœ)˜)Jšžœ˜Jšœ˜—Jšœ˜Jšœ˜——Jšœ9˜9JšœO˜Ošžœžœ˜Jšœ>˜>Jšž˜J˜—šžœ žœ˜Jšœ*˜*Jšœ"˜"Jšœ˜Jšœ˜—Jšœ˜J˜Jšœ™Jšœžœ˜0JšœLžœ ˜WJšœ3žœ˜IJšœNžœ*žœ*˜¦Jšœ#žœ˜4Jšœ4˜4J˜Jšœ™Jšœ)˜)JšœV˜Všžœžœž˜"Jšœ+˜+Jšœ žœ˜Jšœ0˜0šœ˜Jšœ>˜>—Jšžœ˜—šžœžœžœ˜Jšœ˜J˜—Jšœ˜Jšœ˜Jšœ6žœ˜;Jšœ˜J˜Jšœ ™ Jšœ˜Jšœ˜šžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜,šžœ ž˜&Jšž˜Jšœžœ˜Jšœ"˜"Jšžœ˜—Jšžœ˜—J˜ J˜Jšœc˜cJšœ#˜#Jšœ˜Jšœ˜Jšœ%˜%Jšœ˜Jšœ˜Jšœ ˜ šž˜Jšœ˜šœ˜Jšœ'˜'Jšœ ˜ Jšœ˜——Jšžœ ˜J˜—J˜—šÑbls™J˜—™š¢ œžœ žœ˜3Jšž˜J˜š¢œžœ˜-Jšž˜Jšœ'™'Jšœžœ8˜Bšžœžœ˜#šžœ žœ˜(Jšœžœ,˜2Jšœ˜Jšœ ˜ Jšœ7žœ˜<šžœ ž˜&JšœV˜V—šžœ˜Jšœ6˜6Jšœr˜rJšœ˜—Jšœ˜—Jšœežœ˜jJšœ˜Jšœ˜—Jšžœ˜J˜—š ¢ œž œ'žœžœžœ ˜fJšžœ +˜1Jšœžœ˜ Jšœ<˜J˜Jšœžœ5žœžœ˜oJ™Jšœ*˜*J˜J˜Jš œžœžœ žœ(žœ"˜‡šžœžœžœ ž˜šžœžœžœ ž˜Jšœ7žœ˜<šœ ˜Jšœ˜Jšœ˜Jšœžœ1˜QJšœžœ2˜SJšœ˜—Jšœ=žœ*˜jšœ"˜"Jšœd ˜v—Jšœ 5˜SJšœ ˜6Jšžœ˜—Jšžœ˜—Jšœ˜J˜%Jšœžœ˜ Jšžœ˜J˜—š ¢œžœžœžœ žœ ˜IJšž˜Jšœžœžœžœ˜1Jšœ ˜ Jšžœ˜J˜—š ¢ œžœžœžœ žœ ˜EJšž˜Jšœžœ˜,šžœžœž˜<šœ˜Jšœ˜Jšœ˜Jšœ˜——Jšžœ˜J˜—š ¢ œž œ'žœžœžœ !œ˜hJšž˜Jšœžœ˜ JšœžœBžœ*˜ušžœž˜Jšœ4˜4—Jšžœ˜J˜—š ¢œžœžœžœ žœžœ ž˜IJšž˜JšœF™FJšœ žœžœžœ!žœžœžœ!žœžœžœ!žœžœžœ˜·Jšžœ˜—J˜š¢ œžœžœžœ˜DJšž˜šœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜—Jšžœ˜J˜—š¢ œžœžœžœ˜FJšž˜Jšœ-˜-Jšžœ˜J˜—š¢ œžœžœžœ˜Dšœ˜JšœY˜Y—Jšœ˜—J˜š¢ œžœžœžœ˜5Jšž˜Jšœžœ˜"Jšœžœ˜"Jš žœžœžœžœžœžœ˜9Jšžœ˜ šžœ˜J˜——š ¢œžœžœ žœžœ˜:Jšœ˜J˜—š¢ œžœžœ˜8Jšž˜Jšœžœžœ˜Jšžœ'˜-Jšžœ˜J˜—š Ðbkœžœ žœžœžœ˜)Jšž˜Jšœžœ˜šžœž˜ Jšœ ˜ Jšžœžœ˜—šžœž˜ Jšœ ˜ Jšœžœ˜ Jšžœžœ˜—Jšœžœ˜ Jšžœžœžœžœ˜0Jšžœ˜ Jšžœ˜——J˜J˜š£ œžœ˜0Jšžœ˜Jšœ3˜3Jšœh˜hJšœ+˜+Jšœ*˜*Jšœ+˜+JšœT˜Tšžœ&žœ˜.Jšœ1˜1Jšž˜J˜—šžœ+žœ˜3Jšœ:˜:Jšž˜J˜—JšœC˜CJšžœ˜J˜—JšœL˜LJšœS˜SJšžœ˜—…—[^…ø