DIRECTORY TerminalIO USING [RequestRope, RequestInt, WriteRope, WriteInt], CDOrient USING [MapRect, original, mirrorX, rotate90, rotate180, rotate270, ConcentrateOnRotate90, IncludesMirrorX, ComposeOrient], CD USING [Level, LevelKey, Rect, FetchLevel, lambda, ObPtr, CellPtr, Number, Position, DesignNumber, DesignPosition, DesignRect, Application, ApplicationPtr, ApplicationList, CellRecord, Orientation, ObjectDefinition, Properties, Design, NewNullDeviceDrawRef, DrawRectProc, DrawRef, DrawProc, DrawInformation], CDMenus, CornerStitching USING [ Tesselation, TilePtr, NewTesselation, ContentsBound, ChangeRect, EnumerateArea, Area, Value], IO USING [ STREAM, time, PutRope, PutChar, CR, PutF, PutFR, int, rope, refAny, Close], List USING [Append], FS USING [StreamOpen, Error], Rope USING [ROPE, Concat, IsEmpty, FromRefText], Atom USING [GetPropFromList, PutPropOnList, GetPName], CDApplications USING [ARectO], CDBasics USING [ empty, universe, Extend, NormalizeRect, NonEmpty, Intersection, Surround, Center], CDOps USING [DrawDesign], CDProperties USING [GetPropFromLevel, PutPropOnObject], CDSequencer USING [Command, ImplementCommand], CDViewer USING [ShowArrow, RemoveArrow]; BrandyCIFter: CEDAR PROGRAM IMPORTS List, CornerStitching, TerminalIO, CDMenus, CDOrient, CD, CDBasics, IO, FS, Rope, Atom, CDApplications, CDOps, CDProperties, CDSequencer, CDViewer = BEGIN CIFUnits: TYPE = CD.Number; CIFRect: TYPE = CD.Rect -- in CIFUnits -- ; Rational: TYPE = RECORD [num, denom: INT _ 1]; CoordRect: TYPE = RECORD [ x1, y1, x2, y2: CD.DesignNumber ]; 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.Level, 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] ]; debugging: BOOLEAN _ TRUE; -- used for printing out debugging messages design: CD.Design ; -- Chipndale data structure for which CIF will be written mainOb: CD.ObPtr _ NEW[CD.ObjectDefinition]; topLevelOb: CD.ObPtr _ NEW[CD.ObjectDefinition]; mainCellPtr: CD.CellPtr _ NEW[CD.CellRecord]; stopFlag: REF BOOLEAN _ NEW[BOOLEAN]; 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: CoordRect _ [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; clearIDsRec: CD.DrawRef _ NEW[CD.DrawInformation]; ClearCellIDs: PROC [ aptr: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, pr: REF CD.DrawInformation ] -- CD.DrawProc -- = BEGIN zeroID: REF INTEGER _ NIL; CDProperties.PutPropOnObject[onto: aptr.ob, prop: $CellIDNo, val: zeroID]; IF aptr.ob.p.inDirectory THEN aptr.ob.p.drawMe[aptr: aptr, pos: aptr.location, orient: aptr.orientation, pr: clearIDsRec]; END; ValueOf: PROC[ prop: CD.Properties, key: ATOM] RETURNS [REF ANY] = { RETURN [Atom.GetPropFromList[prop, key]]}; 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]]; obj.properties _ Atom.PutPropOnList[ obj.properties, $CellIDNo, cellID]; END; SymTrailer: PROC = BEGIN cifFile.PutRope["DF;\n"]; END; GenerateGeometricOb: PROC [obj: CD.ObPtr, ap: CD.ApplicationPtr, dr: CD.DrawRef] = BEGIN SymHeader[obj]; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO BEGIN currentDirective _ NARROW[directives.first]; cifLayerAnnounced _ FALSE; IF currentDirective.deltaRadius>=0 THEN ap.ob.p.drawMe[aptr: ap, pos: [x: 0, y: 0], orient: 0, pr: dr]; END; ENDLOOP; SymTrailer[]; END; -- of GenerateGeometricOb CIFDefineObject: PROC [obj: CD.ObPtr] = BEGIN ap: CD.ApplicationPtr;-- used as an abbrev. for "aplist.first" dummyApPtr: CD.ApplicationPtr _ NEW[CD.Application]; -- used to match the type a drawMe parameter requires value: Rope.ROPE;-- used to determine signal names IF debugging THEN TerminalIO.WriteRope["Entering CIFDefineObject\n"]; IF ValueOf[obj.properties, $CellIDNo] # NIL THEN RETURN; WITH obj.specificRef SELECT FROM cellptr: CD.CellPtr => BEGIN aplist: CD.ApplicationList; FOR aplist _ cellptr.contents, aplist.rest WHILE aplist # NIL DO CIFDefineObject[aplist.first.ob] ENDLOOP; SymHeader[obj]; CIFDrawCellName[cellptr.name]; FOR aplist _ cellptr.contents, aplist.rest WHILE aplist # NIL DO SELECT aplist.first.ob.specificRef FROM NIL => NULL;-- NIL indicates Rect ENDCASE => BEGIN cifRect: CIFRect; IF debugging THEN TerminalIO.WriteRope[" Transformations\n"]; ap _ aplist.first; cifRect _ CDRectToCIF[CDOrient.MapRect[ itemInCell: [0, 0, 0, 0], cellSize: [x: ap.ob.size.x, y: ap.ob.size.y], cellInstOrient: ap.orientation, cellInstPos: [x: ap.location.x, y: ap.location.y]]]; CIFSymbolCall[ap.ob, ap.orientation, [cifRect.x1, cifRect.y1]]; END; ENDLOOP; FOR directives: LIST OF REF ANY _ cifDirectives, directives.rest WHILE directives#NIL DO BEGIN currentDirective _ NARROW[directives.first]; cifLayerAnnounced _ FALSE; FOR aplist _ cellptr.contents, aplist.rest WHILE aplist # NIL DO BEGIN ap _ aplist.first; SELECT ap.ob.specificRef FROM NIL => -- indicates Rect IF currentDirective.deltaRadius>=0 THEN ap.ob.p.drawMe[ aptr: ap, pos: ap.location, orient: ap.orientation, pr: cifDrawRec]; ENDCASE => NULL; END; ENDLOOP; END; ENDLOOP; FOR aplist _ cellptr.contents, aplist.rest WHILE aplist # NIL DO BEGIN value _NARROW[ Atom.GetPropFromList[aplist.first.ob.properties,$signalName]]; IF ValueOf[aplist.first.ob.properties, $signalName] # NIL THEN SELECT aplist.first.ob.specificRef FROM NIL => CIFLabelTerminalIO[aplist.first, value, aplist.first.ob.level]; ENDCASE => NULL; END; ENDLOOP; SymTrailer[]; END; -- of cell ENDCASE => -- transistors or geometry or rects IF obj.specificRef = NIL THEN NULL ELSE BEGIN dummyApPtr^.ob _ obj; -- drawMe requires an ApplicationPtr GenerateGeometricOb[obj: obj, ap: dummyApPtr , dr: cifDrawRec]; END; IF debugging THEN TerminalIO.WriteRope["Leaving CIFDefineObject\n"]; END; -- of CIFDefineObject CIFSymbolCall: PROC[ob: CD.ObPtr, orient: CD.Orientation _ CDOrient.original, pos: CD.Position -- CIFUnits -- _ [0,0]] = BEGIN v: REF = ValueOf[ob.properties, $CellIDNo]; IF v = NIL THEN ERROR; WITH v SELECT FROM IDNo: REF INT => BEGIN cifFile.PutF["C %d", IO.int[IDNo^]]; IF orient # 0 THEN BEGIN xrotation: CD.Orientation _ CDOrient.ConcentrateOnRotate90[orient]; IF xrotation # 0 THEN BEGIN 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 END; IF CDOrient.IncludesMirrorX[orient] THEN cifFile.PutRope[" M X "]; END; IF (pos.x # 0) OR (pos.y # 0) THEN BEGIN cifFile.PutRope[" T "]; CIFOutPoint[pos.x, pos.y]; END; cifFile.PutRope[";\n"]; END; ENDCASE => NULL; END; cifMeasureR: CD.DrawRef _ CD.NewNullDeviceDrawRef[design: design]; cifMeasureArea: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef] -- CD.DrawRectProc -- = BEGIN r _ CDBasics.NormalizeRect[r]; IF NOT CDBasics.NonEmpty[r] THEN RETURN; mainRect _ [x1: MIN[r.x1, mainRect.x1], y1: MIN[r.y1, mainRect.y1], x2: MAX[r.x2, mainRect.x2], y2: MAX[r.y2, mainRect.y2]]; END; -- of cifMeasureArea cifDrawRec: CD.DrawRef _ CD.NewNullDeviceDrawRef[design: design]; cifOrArea: PROC [r: CD.DesignRect, l: CD.Level, 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 BEGIN cifFile.PutF["L %g;\n", IO.rope[currentDirective.cifDest]]; cifLayerAnnounced _ TRUE; END; 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] = {cifFile.PutF["%d,%d", IO.int[PrescaleCIF[[x,1]]], IO.int[PrescaleCIF[[y,1]]]]}; CIFLabelTerminalIO: PROC [ ap: CD.ApplicationPtr, s: Rope.ROPE, lev: CD.Level] = 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; cifFile.PutF["9 %s;\n", IO.rope[IF Rope.IsEmpty[s] THEN "unnamed cell" ELSE s]]; END; RopeNeeded: SIGNAL [ ref: REF REF ] = CODE; ToRope: PROC [ ref: REF ] RETURNS [ rope: Rope.ROPE ] = BEGIN IF ref = NIL THEN rope _ NIL ELSE 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 => BEGIN refRef: REF REF = NEW[REF _ ref]; SIGNAL RopeNeeded[refRef]; rope _ ToRope[refRef^ ! RopeNeeded => GOTO NoHelp]; EXITS NoHelp => ERROR; END; 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.Level] RETURNS [l: LIST OF REF ANY _ NIL] = BEGIN IF p#NIL THEN BEGIN 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; END; cifDirectives _ NIL; FOR levels: LIST OF CD.Level _ design.technology.usedLevels, levels.rest WHILE levels # NIL DO cifDirectives _ List.Append[GetDirectives[CDProperties.GetPropFromLevel[levels.first, $CDxCIFName], levels.first ], cifDirectives]; ENDLOOP; END; WriteCIF: PROC[ comm: CDSequencer.Command] = BEGIN ENABLE BEGIN ABORTED => {TerminalIO.WriteRope[" CIF generation aborted\n"]; GOTO Exit}; RopeNeeded => BEGIN explanation: Rope.ROPE = IO.PutFR[format: "Please enter a string corresponding to the value %g: ", v1: IO.refAny[ref^]]; ref^ _ TerminalIO.RequestRope[explanation]; RESUME; END; UNWIND => NULL; END; design _ comm.design; mainCellPtr _ design.actual.first.specific; mainOb^_ [ p: NIL, size: [x: infinity, y: infinity], level: CD.FetchLevel[t: design.technology, uniqueKey: $NOcOL], specificRef: mainCellPtr ]; cellCount _ 0; stopFlag^ _ FALSE; cifMeasureR.worldClip _ CD.DesignRect[ x1: -infinity, y1: -infinity, x2: infinity, y2: infinity]; cifMeasureR.drawRect _ cifMeasureArea; clearIDsRec.worldClip _ CD.DesignRect[ x1: -infinity, y1: -infinity, x2: infinity, y2: infinity]; clearIDsRec.drawChild _ ClearCellIDs; clearIDsRec.stopFlag _ stopFlag; cifDrawRec.worldClip _ CD.DesignRect[ x1: -infinity, y1: -infinity, x2: infinity, y2: infinity]; cifDrawRec.drawRect _ cifOrArea; CDOps.DrawDesign[design, cifMeasureR]; TerminalIO.WriteRope["Please input name of CIF file\n"]; base _ TerminalIO.RequestRope["(Extension will be '.cif')\n", ">> "]; IF Rope.IsEmpty[base] THEN base _ "foo"; name _ Rope.Concat[base, ".cif"]; TerminalIO.WriteRope["The name of the output file is "]; TerminalIO.WriteRope[name]; TerminalIO.WriteRope["\n"]; 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 debugging THEN BEGIN TerminalIO.WriteRope["cif Per Lambda = "]; TerminalIO.WriteInt[cifPerLambda]; TerminalIO.WriteRope["\n"]; END; 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)]]; 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[topLevelOb]; 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[topLevelOb, CDOrient.ComposeOrient[CDOrient.rotate180, CDOrient.mirrorX] -- mirrorY --, [x: -cifPerCD*mainRect.x1, y: cifPerCD*mainRect.y2]]; cifFile.PutRope[";\nEnd ... \n"]; cifFile.Close[]; IF debugging THEN TerminalIO.WriteRope[" End of WriteCIF\n"]; TerminalIO.WriteRope["CIF file completed"]; EXITS Exit => NULL; FileIOOpenFailed => {TerminalIO.WriteRope["Open Failed\n"]}; 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 of window }; 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.NewNullDeviceDrawRef[design]; dr.minimalSize _ 0; dr.drawRect _ dr.saveRect _ NoteLevel; dr.devicePrivate _ NEW[CD.DesignRect _ CDBasics.empty]; dr.worldClip _ CDBasics.universe; 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.LevelKey[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.worldClip _ CIFRectToCD[CDBasics.Extend[ms.partClip, 1+ABS[currentDirective.deltaRadius]/nmPerCIF]]; CDViewer.ShowArrow[design: design, pos: [x: (dr.worldClip.x1+dr.worldClip.x2)/2, y: (dr.worldClip.y1+dr.worldClip.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]; EXITS END; NoteLevel: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] = BEGIN bb: REF CD.DesignRect = NARROW[pr.devicePrivate]; bb^ _ CDBasics.Surround[bb^, r]; END; NoteRectangle: PROC [r: CD.DesignRect, l: CD.Level, 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 ] = {cifr _ CDBasics.NormalizeRect[ [x1: cifPerCD*cdr.x1, y1: cifPerCD*cdr.y1, x2: cifPerCD*cdr.x2, y2: cifPerCD*cdr.y2]]}; 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; CDSequencer.ImplementCommand[a: $WriteCif, p: WriteCIF]; CDMenus.CreateEntry[menu~$ProgramMenu, entry~"Hierarchical CIF", key~$WriteCif]; END. -- of BrandyCIFter öBrandyCIFter.mesa A module to output CIF files from Chipndale Copyright c 1984 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 TYPES Global Variables level assumed to be unchanged until the next level 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 Returns valueptr given key from object's property field start outputting a new cell and assign its cellID finish off cell description output CIF for structures only identified as geometries 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. trace each member of the list to the bottom before any output is made --write out the name of the cell For each member of the application list, determine whether obj is a cell. If so, determine transformations for each level, pick out the rectangles belonging to that level and output them --generate all signal names spit out properties other than signal names as comments spit out complaints about shorting contact indicate which cell is called using its ID number OUTPUT PROCEDURES used as a parameter to DrawDesign in order to call cifMeasureArea, fields initialized later Sets mainRect to be a large as is necessary to contain design. used as a parameter to drawMe in order to call cifOrArea, fields intitialized later .. 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 levels get file name output header ask for comment lines define hybrid top level object Flat CIF code --the tesselation is in cif coordinates --Be careful not to exceed the limits of a CD.Number, even temporarily ÊN˜šœ?™?Jšœ Ïmœ1™Jšœ žœžœžœ¡5˜jJšœ žœ¡!˜2J˜Jšžœ žœ4˜EJšœ˜šžœ&žœžœžœ˜;Jšœf™f—Jšœ˜Jšœ­™­J˜Jšžœžœž˜"šœ žœ ˜Jšž˜Jšœžœ˜JšœE™Ešžœ(žœ žœž˜@Jšœ ˜ —Jšžœ˜J˜Jšœ˜J˜Jšœ ™ Jšœ˜J˜Jšœj™jJ™šžœ(žœ žœž˜@šžœž˜(Jšžœžœ¡˜!šžœ˜ Jšž˜Jšœ˜Jšžœ žœ-˜>Jšœ˜šœ(˜(Jšœ˜Jšœ-˜-Jšœ˜Jšœ4˜4—Jšœ?˜?Jšžœ˜——Jšžœ˜—J˜Jšœ@™@Jšœ™J™šžœ žœžœžœžœ"žœ žœž˜XJšž˜Jšœžœ˜,Jšœžœ˜šžœ(žœ žœž˜@Jšž˜Jšœ˜šžœž˜šžœ¡˜šžœ!ž˜'JšœT˜T——Jšžœžœ˜—Jšžœ˜Jšžœ˜—Jšžœ˜Jšžœ˜—J˜Jšœ™šžœ(žœ žœž˜@Jšž˜Jšœžœ˜Jšœ>˜>šžœ4žœž˜>šžœž˜'JšžœC˜FJšžœžœ˜——Jšžœ˜Jšžœ˜—J˜Jšœ7™7Jšœ*™*Jšœ˜Jšœ ˜ Jšžœ¡ ˜—J˜šžœ¡#˜.Jšžœžœžœž˜"šž˜Jšž˜Jšœ¡$˜;Jšœ?˜?Jšžœ˜——Jšœ˜Jšžœ žœ3˜DJ˜Jšžœ¡˜—J˜J˜š £ œžœžœžœ'žœ ¡œ ˜xJšœ1™1Jšž˜Jšœžœ%˜+Jšžœžœžœžœ˜šžœžœž˜šœžœžœ˜Jšž˜Jšœžœ ˜$šžœ ž˜Jšž˜Jšœ žœ6˜Cšžœž˜Jšž˜Jšœ˜Jšœ˜šžœ ž˜Jšœ˜Jšœ˜Jšœ˜Jšžœ ¡˜(—Jšžœ˜—šžœ"ž˜(Jšœ˜—Jšžœ˜—šžœ žœ ž˜"Jšž˜Jšœ˜Jšœ˜Jšžœ˜—Jšœ˜Jšžœ˜—Jšžœžœ˜—Jšžœ˜—Jšœ˜Jš ™J˜Jšœ˜šœžœ žœ&˜CJšœ]™]—Jšœ˜š  œžœžœžœ žœ ¡œ˜^Jšœ>™>Jšž˜Jšœ˜Jšžœžœžœžœ˜)šœ ˜ Jšœžœžœ˜9Jšœžœžœ˜8—Jšžœ¡˜—J˜šœ žœ žœ&˜CJšœS™S—Jšœ˜š   œžœžœžœ žœ ˜BJšž˜Jšœžœ ˜Jš žœ!žœžœžœžœ˜KJšœ˜Jšœs˜sJšžœ˜J˜—Jšœ˜š£ œžœ˜Jšž˜Jšžœžœžœžœ˜(šžœžœž˜Jšž˜Jšœžœ!˜;Jšœžœ˜Jšžœ˜—šœ ¡&˜FJšžœ"¡ œ˜2Jšžœ"¡ œ˜1Jšžœ"¡œ˜:Jšžœ"¡œ˜;—Jšžœ˜J˜J˜—š£ œžœ˜#Jšœžœžœ˜PJ˜—š £œžœžœžœžœ ˜PJšž˜JšœJ˜JJšœžœ ˜#Jšœ˜Jšœ˜šžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜+Jšžœžœžœ˜šžœ˜ Jšž˜Jš œžœžœžœžœ˜!Jšžœ˜Jšœ&žœ ˜3šž˜Jšœ žœ˜—Jšžœ˜——Jšžœ˜J˜—J˜Jšœžœžœ˜#J˜š£ œžœ˜Jšž˜Jšœ@¡!˜ašžœ žœžœžœžœ"žœ žœž˜XJšœžœ˜+Jšœ˜šžœžœžœž˜+Jšžœ˜—Jšœžœ˜"šœ˜Jšœ˜Jšœ)žœ)˜UJšœx™x—Jšžœ˜—Jšžœ˜J˜J˜—š£œžœ˜Jšž˜J˜š£ œžœžœžœžœžœžœžœžœžœ˜PJšž˜šžœžœž˜ Jšž˜šžœžœž˜Jšœžœžœ5˜PJš œžœžœžœžœS˜hJšžœžœžœ)˜@—Jšžœ˜—Jšžœ˜J˜—Jšœžœ˜š žœ žœžœžœ3žœ žœž˜^Jšœƒ˜ƒJšžœ˜—Jšžœ˜J˜Jšœ˜—š£œžœ˜,šžœž˜ Jšž˜Jšžœ9žœ˜Kšœ ˜ Jšž˜JšœžœžœLžœ˜xJšœ+˜+Jšžœ˜Jšžœ˜—Jšžœžœ˜Jšžœ˜—Jšœ˜Jšœ$™$Jšœ˜Jšœ˜JšœM™MJ™Jšœ+˜+Jšœ˜šœ ˜ Jšœžœ˜Jšœ#˜#Jšœžœ5˜>Jšœ˜Jšœ˜—J˜Jšœ˜Jšœ žœ˜Jšœ˜šœžœ ˜'Jšœ˜Jšœ˜—Jšœ&˜&J˜Jšœ˜šœžœ ˜'Jšœ˜Jšœ˜—J˜%J˜ Jšœ˜šœžœ ˜%Jšœ˜Jšœ˜—Jšœ ˜ Jšœ˜Jšœ˜Jšœ4™4Jšœ/™/J™Jšœ)˜)Jšœ˜Jšœ ™ Jšœ8˜8JšœE˜EJšžœžœ˜(Jšœ!˜!Jšœ8˜8Jšœ˜Jšœ˜šœ žœ˜(šžœ ˜ Jšžœžœ˜Jšœ)˜)Jšžœ˜Jšœ˜Jšœ˜——Jšœ9˜9JšœO˜Ošžœ žœ˜Jšž˜Jšœ*˜*Jšœ"˜"Jšœ˜Jšžœ˜—Jšœ˜J˜Jšœ ™ Jšœžœ˜0JšœMžœ ˜XJšœ3žœ˜IJšœNžœ*žœ*˜¦J˜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šœW¡ œ7˜›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šœ:žœ*˜gšœ"˜"JšœX¡˜j—Jšœ¡5˜SJšœ¡˜6Jšžœ˜—Jšžœ˜—Jšœ˜J˜%Jšž˜Jšžœ˜J˜—š £ œžœžœžœ žœ ˜CJšž˜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˜š£ œžœžœžœ˜Dšœ˜JšœW˜W—J˜—š£ œžœžœžœ˜Dšœ˜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˜—Jšœ8˜8JšœP˜PJšžœ¡˜—…—OštÞ