DIRECTORY Atom, CD, CDBasics, CDCommandOps, CDMenus, CDOps, CDSequencer, CDProperties, CDVArrow, CStitching, FS, IO, Process, Rope, TerminalIO; FlatCif: CEDAR PROGRAM IMPORTS Atom, CD, CDBasics, CDCommandOps, CDMenus, CDOps, CDSequencer, CDProperties, CDVArrow, CStitching, FS, IO, Process, Rope, TerminalIO EXPORTS = BEGIN Rational: TYPE = RECORD [num, denom: INT _ 1]; MaskStateRef: TYPE = REF MaskState; MaskState: TYPE = RECORD [ s: IO.STREAM, -- stream where rectangles are to be drawn scale: Rational, layer: CD.Layer _ CD.undefLayer, bloat: CD.Number _ 0, areas, unbloated: CStitching.Tesselation _ NIL, partClip: CD.Rect _ [0,0,0,0], -- in cif coordinates offset: CD.Position _ [0, 0] -- in cif coordinates ]; DesignDataRef: TYPE = REF DesignData; DesignData: TYPE = RECORD [ bbox: REF CD.Rect, used: REF PACKED ARRAY CD.Layer OF BOOL ]; partWidth: CD.Number _ 50000; --cif space partHeight: CD.Number _ 50000; --cif space localFileName: Rope.ROPE _ "///temp/FlatCif.cif"; cifKey: Rope.ROPE; abortMask: REF BOOL = NEW[BOOL_FALSE]; Init: PROC ~ { CDSequencer.ImplementCommand[key~$FlatCif , proc~FlatCIFCommand]; CDSequencer.ImplementCommand[key~$FlatCIF , proc~FlatCIFCommand]; CDMenus.CreateEntry[menu~$ProgramMenu, entry~"Flat CIF output", key~$FlatCIF]; TerminalIO.WriteRope["ChipNDale flat CIF mask generator loaded\n"]; }; FlatCIFCommand: PROC [comm: CDSequencer.Command] = BEGIN TerminalIO.WriteRope["Flat CIF mask generation\n"]; [] _ CDCommandOps.CallWithResource[ProtectedFlatCIFCommand, comm, $FlatCif, abortMask]; END; ProtectedFlatCIFCommand: PROC [comm: CDSequencer.Command] = BEGIN ENABLE BEGIN ABORTED => {TerminalIO.WriteRope[" flat CIF mask 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; tape: IO.STREAM _ NIL; cifKey _ ToRope[CDProperties.GetTechnologyProp[comm.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"]; tape _ FS.StreamOpen[localFileName, $create ! FS.Error => IF error.group#bug THEN { TerminalIO.WriteRope[" file not opened\n"]; GOTO Exit }; ]; MakeMask[comm.design, tape]; tape.Close[]; TerminalIO.WriteRope["Cif file written to "]; TerminalIO.WriteRope[localFileName]; TerminalIO.WriteLn[]; EXITS Exit => NULL; END; MakeMask: PROC [design: CD.Design, tape: IO.STREAM _ NIL] = BEGIN designClip: CD.Rect; cifClip, temClip: CD.Rect; nRows, nCols: NAT; maskCount: NAT _ 0; masks: LIST OF CD.Layer _ NIL; maxBloat: CD.Number _ 0; -- CIF space ms: MaskStateRef = NEW[ MaskState _ [ areas: CStitching.NewTesselation[], unbloated: CStitching.NewTesselation[], offset: [0, 0], s: tape ]]; dd: DesignDataRef = NEW[DesignData _ [bbox: NIL, used: NEW[PACKED ARRAY CD.Layer OF BOOL _ ALL[FALSE]]]]; dr: CD.DrawRef = CD.CreateDrawRef[[ drawRect: NoteLayer, devicePrivate: dd, interestClip: CDBasics.universe, design: design ]]; nmPerLambda, nmPerCIFUnit: INT; abortMask^ _ FALSE; nmPerCIFUnit _ 10; SELECT TerminalIO.RequestSelection[label: "Microns per lambda", choice: LIST[" 2.0", " 1.5", " 1.0"] ] FROM 1 => {nmPerLambda _ 2000; TerminalIO.WriteRope[" 2.0\n"]}; 2 => {nmPerLambda _ 1500; TerminalIO.WriteRope[" 1.5\n"]}; 3 => {nmPerLambda _ 1000; TerminalIO.WriteRope[" 1.0\n"]}; ENDCASE => nmPerLambda _ TerminalIO.RequestInt["OK, wise guy, how many nanometers per lambda? "]; ms.scale _ ReduceRational[[num: nmPerLambda, denom: design.technology.lambda*nmPerCIFUnit]]; TerminalIO.WriteRope["analyzing design\n"]; TRUSTED {Process.SetPriority[Process.priorityBackground]}; CIFOutComment[tape, IO.PutFR[format: "internal design name: %g", v1: IO.rope[design.name]]]; CIFOutComment[tape, IO.PutFR[format: "cif produced: %t", v1: IO.time[]]]; CIFOutComment[tape, "using Chipndale's flat CIF generator; Xerox PARC"]; CIFOutComment[tape, IO.PutFR[format: "nm per lambda: %d", v1: IO.int[nmPerLambda]]]; CIFOutComment[tape, IO.PutFR[format: "CIF KEY: %s", v1: IO.rope[cifKey]]]; CDOps.DrawDesign[design, dr]; -- mark used levels and measure design designClip _ dd.bbox^; FOR lev: CD.Layer IN CD.Layer DO layerMsg: Rope.ROPE _ NIL; IF dd.used[lev] THEN { x: REF _ CDProperties.GetLayerProp[from: lev, prop: $CDxCIFMakeMask]; IF x#NIL THEN dd.used[lev] _ NARROW[x, REF BOOL]^; layerMsg _ layerMsg.Cat["layer ", Atom.GetPName[CD.LayerKey[lev]], (IF dd.used[lev] THEN " used" ELSE " suppressed") ]; }; IF dd.used[lev] THEN { x: REF _ CDProperties.GetLayerProp[from: lev, prop: $CDxCIFBloatActive]; levelBloat: CD.Number_0; -- in nm IF x#NIL THEN levelBloat _ NARROW[x, REF INT]^; IF levelBloat#0 THEN layerMsg _ layerMsg.Cat[IO.PutFR[format: "; blown up by %d nm", v1: IO.int[levelBloat]]]; maskCount _ maskCount+1; masks _ CONS[lev, masks]; maxBloat _ MAX[maxBloat, ABS[levelBloat/nmPerCIFUnit]]; -- in cif units }; IF layerMsg#NIL THEN { TerminalIO.WriteRope[layerMsg]; TerminalIO.WriteLn[]; layerMsg _ layerMsg.Cat["; cif name: ", CifLevelName[lev]]; CIFOutComment[tape, layerMsg] } ENDLOOP; temClip _ Bloat[ScaleCDToCIF[ms, designClip], maxBloat]; ms.offset _ CDBasics.NegOffset[CDBasics.BaseOfRect[temClip]]; -- [0, 0] at lower left corner cifClip _ Bloat[ScaleCDToCIF[ms, designClip], maxBloat]; nRows _ Ceiling[num: cifClip.y2-cifClip.y1, denom: partHeight]; nCols _ Ceiling[num: cifClip.x2-cifClip.x1, denom: partWidth]; TerminalIO.WriteRope[IO.PutFR[format: "..making %d layers in %d rows and %d columns..", v1: IO.int[maskCount], v2: IO.int[nRows], v3: IO.int[nCols]]]; CIFOutComment[tape, IO.PutFR[format: "making %d layers in %d rows and %d columns", v1: IO.int[maskCount], v2: IO.int[nRows], v3: IO.int[nCols]]]; CIFOutComment[tape, IO.PutFR[format: "Chipndale's origin is mapped to x: %d y: %d in cif units", v1: IO.int[ms.offset.x], v2: IO.int[ms.offset.y]]]; CIFOutComment[tape, IO.PutFR[format: " ... or to x: %d y: %d in nanometers", v1: IO.int[ms.offset.x*nmPerCIFUnit], v2: IO.int[ms.offset.y*nmPerCIFUnit]]]; CIFOutComment[tape, IO.PutFR[format: "feature space minx: %d miny: %d maxx: %d maxy: %d in cif units", v1: IO.int[cifClip.x1], v2: IO.int[cifClip.y1], v3: IO.int[cifClip.x2], v4: IO.int[cifClip.y2]]]; dr.drawRect _ NoteRectangle; dr.devicePrivate _ ms; FOR m: LIST OF CD.Layer _ masks, m.rest WHILE m#NIL DO ms.layer _ m.first; ms.bloat _ 0; BEGIN x: REF _ CDProperties.GetLayerProp[from: ms.layer, prop: $CDxCIFBloatActive]; IF x#NIL THEN ms.bloat _ NARROW[x, REF INT]^/nmPerCIFUnit; END; TerminalIO.WriteRope[Atom.GetPName[CD.LayerKey[ms.layer]]]; CIFOutLevel[ms.s, ms.layer]; FOR col: NAT IN [0..nCols) DO FOR row: NAT IN [0..nRows) DO IF abortMask^ THEN GOTO AbortMask; ms.areas.ChangeRect[rect: CDBasics.universe, new: NIL]; ms.partClip _ [ -- is 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 _ ScaleCIFToCD[ms,CDBasics.Extend[ms.partClip, 1+ABS[ms.bloat]]]; CDVArrow.ShowArrow[design: design, pos: [x: (dr.interestClip.x1+dr.interestClip.x2)/2, y: (dr.interestClip.y1+dr.interestClip.y2)/2]]; -- keep user happy CDSequencer.CheckAborted[design]; CDOps.DrawDesign[design, dr]; -- build tesselation of the relevant design rectangle AnalyzeTesselation[ms]; -- sends the current part to s ENDLOOP; ENDLOOP; TerminalIO.WriteRope["+"]; ENDLOOP; CIFOutEnd[tape]; TerminalIO.WriteRope["finished\n"]; EXITS AbortMask => {TerminalIO.WriteRope["aborted\n"]}; END; NoteLayer: PROC [ r: CD.Rect, l: CD.Layer, pr: CD.DrawRef ] = BEGIN dd: DesignDataRef = NARROW[pr.devicePrivate]; IF dd.bbox=NIL THEN dd.bbox _ NEW[CD.Rect _ r]; dd.bbox^ _ CDBasics.Surround[dd.bbox^, r]; dd.used[l] _ TRUE; END; NoteRectangle: PROC [r: CD.Rect, l: CD.Layer, pr: CD.DrawRef] = BEGIN ms: MaskStateRef = NARROW[pr.devicePrivate]; IF l=ms.layer AND CDBasics.NonEmpty[r] THEN ms.areas.ChangeRect[ rect: ScaleCDToCIF[ms, r], new: $covered ]; END; AnalyzeTesselation: PROC [ms: MaskStateRef] = BEGIN active: CD.Rect = ms.areas.BBox[rect: CDBasics.universe]; IF CDBasics.NonEmpty[active] THEN { IF ms.bloat#0 THEN { t: CStitching.Tesselation = ms.unbloated; ms.unbloated _ ms.areas; ms.areas _ t; ms.areas.ChangeRect[rect: CDBasics.universe, new: NIL]; IF ms.bloat>0 THEN [] _ ms.unbloated.EnumerateArea[rect: CDBasics.universe, eachTile: BloatTile, data: ms] ELSE { ms.areas.ChangeRect[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.WriteRope["."]; -- end of stripe }; END; BloatTile: PROCEDURE [tile: CStitching.Tile, data: REF ANY] = BEGIN ms: MaskStateRef = NARROW[data]; cr: CD.Rect = CDBasics.Intersection[CDBasics.universe, Bloat[tile.Area, ABS[ms.bloat]]]; IF CDBasics.NonEmpty[cr] THEN ms.areas.ChangeRect[rect: cr, new: tile.value]; END; OutputTile: PROCEDURE [tile: CStitching.Tile, data: REF ANY] = BEGIN -- only called on tiles with non-NIL values ms: MaskStateRef = NARROW[data]; cr: CD.Rect = CDBasics.Intersection[tile.Area, ms.partClip]; IF CDBasics.NonEmpty[cr] THEN CIFOutBox[ms.s, cr]; 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; 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; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- CifLevelName: PROC[layer: CD.Layer] RETURNS [Rope.ROPE] = BEGIN name: Rope.ROPE _ ToRope[CDProperties.GetLayerProp[from: layer, prop: $CDxCIFName]]; IF name=NIL THEN { TerminalIO.WriteRope[Rope.Cat["Enter CIF layer name for ", Atom.GetPName[CD.LayerKey[layer]]]]; name _ TerminalIO.RequestRope[" > "]; CDProperties.PutLayerProp[onto: layer, prop: $CDxCIFName, val: name]; }; RETURN [name] END; CIFOutEnd: PROC [cifFile: IO.STREAM] = BEGIN IO.PutRope[cifFile, "End ... \n"]; END; CIFOutLevel: PROC [cifFile: IO.STREAM, layer: CD.Layer] = BEGIN IO.PutRope[cifFile, "L "]; IO.Put[cifFile, IO.rope[CifLevelName[layer]]]; IO.PutChar[cifFile, ';]; IO.PutChar[cifFile, IO.CR]; END; CIFOutBox: PROC [cifFile: IO.STREAM, rect: CD.Rect] = BEGIN IF (rect.x2+rect.x1) MOD 2 # 0 OR (rect.y2+rect.y1) MOD 2 # 0 THEN TerminalIO.WriteRope["Scaling problem\n"]; IO.PutRope[cifFile, "B "]; IO.Put[cifFile, IO.int[(rect.x2-rect.x1)]]; IO.PutChar[cifFile, ' ]; IO.Put[cifFile, IO.int[(rect.y2-rect.y1)]]; IO.PutChar[cifFile, ' ]; IO.Put[cifFile, IO.int[(rect.x2+rect.x1)/2]]; IO.PutChar[cifFile, ' ]; IO.Put[cifFile, IO.int[(rect.y2+rect.y1)/2]]; IO.PutChar[cifFile, ';]; IO.PutChar[cifFile, IO.CR]; END; CIFOutComment: PROC [cifFile: IO.STREAM, comment: Rope.ROPE] = BEGIN Translator: Rope.TranslatorType --PROC [old: CHAR] RETURNS [new: CHAR]-- = { new _ IF old='( THEN'< ELSE IF old=') THEN '> ELSE old }; IO.PutRope[cifFile, "( "]; IO.PutRope[cifFile, Rope.Translate[base: comment, translator: Translator]]; IO.PutRope[cifFile, " );\n"]; END; -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ScaleCDToCIF: PROC [ ms: MaskStateRef, cdr: CD.Rect ] RETURNS [ cifr: CD.Rect ] = BEGIN -- scales and offsets cifr _ CDBasics.NormalizeRect[CDBasics.MoveRect[ [x1: RatMul[ms.scale, cdr.x1], y1: RatMul[ms.scale, cdr.y1], x2: RatMul[ms.scale, cdr.x2], y2: RatMul[ms.scale, cdr.y2]], ms.offset]]; END; ScaleCIFToCD: PROC [ ms: MaskStateRef, cifr: CD.Rect ] RETURNS [ cdr: CD.Rect ] = BEGIN -- scales and offsets r: CD.Rect = CDBasics.MoveRect[cifr, CDBasics.NegOffset[ms.offset]]; cdr _ CDBasics.NormalizeRect[ [x1: RatDiv[ms.scale, r.x1], y1: RatDiv[ms.scale, r.y1], x2: RatDiv[ms.scale, r.x2], y2: RatDiv[ms.scale, r.y2]]]; END; Ceiling: PROC [num, denom: CD.Number] RETURNS [ c: INT ] = BEGIN c _ num/denom; IF num*denom>0 AND num MOD denom # 0 THEN c _ c+1; END; ReduceRational: PROC [ r: Rational ] RETURNS [ Rational ] = BEGIN gcd: INT = IF r.num=0 THEN r.denom ELSE GCD[r.num, r.denom]; RETURN[[num: r.num/gcd, denom: r.denom/gcd]]; END; RatMul: PROC [ mul: Rational, z: INT ] RETURNS [ INT ] = INLINE {RETURN[(mul.num*z)/mul.denom]}; RatDiv: PROC [ div: Rational, z: INT ] RETURNS [ INT ] = INLINE {RETURN[(div.denom*z)/div.num]}; GCD: PROC [ m, n: INT ] RETURNS [ INT ] = BEGIN r: INT; SELECT m FROM <0 => m _ -m; >0 => NULL; ENDCASE => ERROR; SELECT n FROM <0 => n _ -n; >0 => NULL; ENDCASE => ERROR; r _ m MOD n; WHILE r>0 DO m _ n; n _ r; r _ m MOD n; ENDLOOP; RETURN[n]; END; Init[]; END. ΎFlatCif.mesa A package to output a ChipnDale design in flat CIF format. Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. by: Ch. Jacobi, June 13, 1984 3:12:53 pm last edited by: Ch. Jacobi, March 25, 1986 6:16:11 pm PST --the tesselation is in cif coordinates --in cif coordinates --Be careful not to exceed the limits of a CD.Number, even temporarily --c = SGN[num]*SGN[denom]*FLOOR[ABS[num]/ABS[denom]] if denom#0 ΚΉ˜šœ ™ Jšœ<™ ˜\J˜Jšœ8˜8J˜Jšœ?˜?J˜>J˜Jš œžœEžœžœžœ˜–Jš œžœAžœžœžœ˜‘JšœžœPžœžœ˜•Jšœžœ?žœ$žœ!˜žJš œžœWžœžœžœžœ˜ΚJšœ˜J˜J˜š žœžœžœžœžœžœž˜6Jšœ˜Jšœ ˜ šž˜JšœžœG˜MJš žœžœžœ žœžœžœ˜;Jšžœ˜—Jšœ#žœ˜;Jšœ˜šžœžœžœ ž˜šžœžœžœ ž˜Jšžœ žœžœ ˜"Jšœ2žœ˜7šœ ˜"Jšœ˜Jšœ˜Jšœžœ1˜QJšœžœ2˜SJšœ˜—JšœAžœ ˜Qšœ"˜"Jšœd ˜v—Jšœ!˜!Jšœ 5˜SJšœ ˜6Jšžœ˜—Jšžœ˜—Jšœ˜Jšžœ˜—Jšœ˜Jšœ#˜#šž˜Jšœ1˜1—Jšžœ˜J˜—š ‘ œžœžœ žœ žœ ˜=Jšž˜Jšœžœ˜-Jš žœ žœžœ žœžœ ˜/Jšœ*˜*Jšœ žœ˜Jšžœ˜J˜—š ‘ œžœžœ žœ žœ ˜?Jšž˜Jšœžœ˜,šžœ žœž˜+šœ˜Jšœ˜Jšœ ˜ Jšœ˜——Jšžœ˜J˜—š‘œžœ˜-Jšž˜Jšœ'™'Jšœžœ/˜9šžœž˜#šžœ žœ˜Jšœ)˜)Jšœ˜Jšœ ˜ Jšœ2žœ˜7šžœ ž˜JšœW˜W—šžœ˜Jšœ1˜1Jšœv˜vJšœ˜—Jšœ˜—Jšœc˜cJšœ ˜+Jšžœ˜—Jšžœ˜J˜—š ‘ œž œžœžœž˜=Jšž˜Jšœžœ˜ JšœžœBžœ ˜Xšžœž˜Jšœ/˜/—Jšžœ˜J˜—š ‘ œž œžœžœž˜>Jšžœ +˜1Jšœžœ˜ Jšœžœ6˜šžœ˜ Jšž˜Jš œžœžœžœžœ˜!Jšžœ˜Jšœ&žœ ˜3šž˜Jšœ žœ˜—Jšžœ˜——Jšžœ˜J˜—š ‘œžœžœžœ žœžœ ž˜IJšž˜JšœF™FJšœ žœžœžœ!žœžœžœ!žœžœžœ!žœžœžœ˜·Jšžœ˜—J˜J˜0J˜š ‘ œžœžœžœžœ˜9Jšž˜Jšœ žœE˜Tšžœžœžœ˜JšœIžœ˜_Jšœ%˜%JšœE˜EJšœ˜—Jšžœ˜ Jšžœ˜—J˜š‘ œžœ žœžœ˜&Jšž˜J˜"Jšžœ˜J˜—š ‘ œžœ žœžœ žœ ˜9Jšž˜Jšžœ˜Jšžœžœ˜.Jšžœ˜Jšžœžœžœ˜Jšžœ˜J˜—š ‘ œžœ žœžœžœ˜5Jšž˜š žœžœžœžœžœ˜CJšœ*˜*—Jšžœ˜Jšžœžœ˜,Jšžœ˜Jšžœžœ˜+Jšžœ˜Jšžœžœ˜-Jšžœ˜Jšžœžœ˜-Jšžœ˜Jšžœžœžœ˜Jšžœ˜J˜—š ‘ œžœ žœžœžœ˜>Jšž˜šŸ œ (œ˜LJš œžœžœžœžœžœžœ˜6Jšœ˜—Jšžœ˜JšžœI˜KJšžœ˜Jšžœ˜J˜—J˜0J˜š ‘ œžœžœžœ žœ ˜QJšžœ ˜šœ0˜0Jšœy˜yJšœ ˜ —Jšžœ˜J˜—š ‘ œžœžœžœžœ ˜QJšžœ ˜Jšœžœ?˜Dšœ˜Jšœr˜r—Jšžœ˜—J˜š ‘œžœžœ žœžœ˜:Jšž˜šœ˜Jšœ?™?—Jšžœ žœžœ žœ ˜2Jšžœ˜J˜—š‘œžœžœ˜;Jšž˜Jš œžœžœ žœ žœžœ˜