DIRECTORY BasicTime USING [GMT, Now, Period], CD USING [CreateDrawRef, Design, DrawContextProc, DrawProc, DrawRectProc, DrawRef, Error, FetchObjectClass, Instance, InstanceList, Layer, Number, Object, ObjectClass, Rect, Technology, Transformation], CDAtomicObjects USING [AtomicObsSpecific, DrawList], CDBasics USING [Extend, Intersect, Intersection, MapRect, NonEmpty], CDCommandOps USING [DoWithResource], CDErrors USING [IncludeMessage, RemoveMessages], CDEvents USING [EventProc, RegisterEventProc], CDOps USING [ToRope, InstList], CDProperties USING [CopyVal, GetProp, GetObjectProp, InstallProcs, PutProp, PutObjectProp, RegisterProperty], CDSequencer USING [Command, ImplementCommand, UseAbortFlag], CDSimpleRules USING [GetLayer], CMosB USING [cmosB, cut2, lambda], CStitching USING [all, Area, ChangeRect, DumpCache, Rect, EnumerateArea, ResetTesselation, ChangeEnumerateArea, ListArea, NewTesselation, RectProc, TileProc, Region, Tesselation, Tile], CSMonitor USING [Monitor, PaintPredicate, Reset], FS USING [StreamOpen], IO USING [Close, int, PutF1, PutFR, PutFR1, PutRope, rope, STREAM], PrincOpsUtils USING [], Process USING [priorityBackground, SetPriority], Rope USING [Cat, ROPE], TerminalIO USING [PutRope], ViaFlatness USING [ErrorList, Rule], ViewerClasses USING [Viewer]; ViaFlatnessImpl: CEDAR PROGRAM IMPORTS BasicTime, CD, CDBasics, CDCommandOps, CDErrors, CDEvents, CDOps, CDProperties, CDSequencer, CDSimpleRules, CMosB, CStitching, CSMonitor, FS, IO, Process, Rope, TerminalIO EXPORTS ViaFlatness ~ BEGIN debug: BOOL _ FALSE; timing: BOOL _ FALSE; Region: TYPE ~ LIST OF REF CStitching.Region; Tess: TYPE ~ CStitching.Tesselation; Tile: TYPE ~ CStitching.Tile; empty: REF ~ NIL; nothing: REF INT ~ NEW [INT]; l: CD.Number ~ CMosB.lambda; externalKey: ATOM ~ $GismoVF; -- used in traffic with external packages checkedKey: ATOM ~ $GismoVFChecked; -- used to mark checked cells errorKey: ATOM ~ $GismoVFError; doNotAnalyse: ATOM ~ $DoNotDRC; State: TYPE ~ REF StateRec; StateRec: TYPE ~ RECORD [design: CD.Design, abort: REF BOOL, viaTess, materialTess: Tess, errors: ErrorList, errorTotal: INT _ 0, errorLog: IO.STREAM]; ErrorList: TYPE ~ ViaFlatness.ErrorList; ViaTileData: TYPE ~ REF ViaTileDataRec; ViaTileDataRec: TYPE ~ RECORD [ hasDiff: BOOL _ FALSE, -- diffusion hasPoly: BOOL _ FALSE, -- polysilicide hasFOx: BOOL _ FALSE]; -- field oxide MatTileData: TYPE ~ REF MatTileDataRec; MatTileDataRec: TYPE ~ RECORD [layerKey: ATOM, via: ViaTileData]; diffLayers: CD.Layer ~ 4; -- DANGER: if you changes this, see ConvertMat. diffKey: ARRAY [0 .. diffLayers) OF ATOM ~ [$ndif, $pdif, $nwelCont, $pwelCont]; genericDiff: ATOM ~ $diff; polyKey: ATOM ~ $pol; diffLayer: ARRAY [0 .. diffLayers) OF CD.Layer; polyLayer: CD.Layer; fieldOxide: REF ANY ~ NIL; Rule: TYPE ~ ViaFlatness.Rule; viaOnFieldOxideAvoidsDiff: Rule ~ [2 * l, "separation to diff (advisory)"]; viaOnFieldOxideAvoidsPoly: Rule ~ [2 * l, "separation to poly"]; fieldOxideSurroundsViaOnFieldOxide: Rule ~ [MAX [viaOnFieldOxideAvoidsDiff.extent, viaOnFieldOxideAvoidsPoly.extent], "separation to poly or diff"]; diffSurroundsViaOnDiff: Rule ~ [2 * l, "insufficient diff surround (advisory)"]; polySurroundsViaOnPoly: Rule ~ [3 * l, "insufficient poly surround"]; viaOnPolyAndDiff: Rule ~ [1 * l, "topology not flat"]; -- more for the sake of robustness viaSeparation: Rule ~ [1 * l, "via to via separation"]; -- only overlaps checked viaOverGate: Rule ~ [1 * l, "via not allowed over gate"]; viaOverPoly: Rule ~ [1 * l, "via not allowed over poly"]; Verify: PUBLIC PROC [c: CD.Instance, d: CD.Design _ NIL, abort: REF BOOL _ NIL] RETURNS [errors: ErrorList, errorTotal: INT] ~ BEGIN state: State; o: CD.Object = c.ob; checked: BOOL = (CDProperties.GetObjectProp [o, checkedKey] # NIL); oldErrors: ErrorList = NARROW [CDProperties.GetObjectProp [o, externalKey]]; designName: Rope.ROPE = IF d#NIL THEN d.name ELSE "in the sky"; viaViewer, matViewer: ViewerClasses.Viewer; IF checked THEN BEGIN TerminalIO.PutRope [":"]; RETURN [oldErrors, -1] END; IF (CDProperties.GetObjectProp [o, doNotAnalyse] # NIL) THEN BEGIN TerminalIO.PutRope [" "]; RETURN [oldErrors, -1] END; IF (d.technology # CMosB.cmosB) THEN BEGIN TerminalIO.PutRope [Rope.Cat ["Technology is not ", CMosB.cmosB.name, ".\n"]]; RETURN [NIL, -1] END; IF (d # NIL) THEN CDErrors.RemoveMessages [d, o, errorKey]; state _ NEW [StateRec _ [design: d]]; state.abort _ IF (abort # NIL) THEN abort ELSE NEW [BOOL _ FALSE]; state.errorLog _ FS.StreamOpen [fileName: "[]<>Temp>DRC>ViaFlatness.log", accessOptions: create, keep: 5, extendFileProc: NIL, remoteCheck: FALSE, wDir: NIL]; -- keep is 5 because of incremental use state.errorLog.PutF1 ["Error log by ViaFlatness. Design: %g\n\n", IO.rope [designName]]; CreateTess [state]; IF debug THEN BEGIN viaViewer _ CSMonitor.Monitor [state.viaTess, "Via Tesselation", NIL]; matViewer _ CSMonitor.Monitor [state.materialTess, "Material Tesselation", DarkPoly] END; EnumerateDesign [c, state, TRUE]; IF debug THEN CSMonitor.Reset [viaViewer]; EnumerateDesign [c, state, FALSE]; IF debug THEN CSMonitor.Reset [matViewer]; CStitching.EnumerateArea [plane: state.viaTess, rect: CStitching.all, eachTile: LookUnderneath, data: state, skip: empty]; IF debug THEN {CSMonitor.Reset [viaViewer]; CSMonitor.Reset [matViewer]} ELSE DestroyTess [state]; CDProperties.PutObjectProp [o, checkedKey, checkedKey]; CDProperties.PutObjectProp [o, externalKey, state.errors]; state.errorLog.PutRope ["\nDRC terminated normally."]; state.errorLog.Close []; RETURN [state.errors, state.errorTotal] END; -- Verify InteractiveCall: PROC [comm: CDSequencer.Command] ~ BEGIN abort: REF BOOL _ NEW [BOOL _ FALSE]; startTime, stopTime: BasicTime.GMT; -- for internal use errorSummary: LIST OF RECORD [c: Rope.ROPE, n: INT]; VerifySelected: PROC [comm: CDSequencer.Command] ~ BEGIN TRUSTED {Process.SetPriority [Process.priorityBackground]}; FOR all: CD.InstanceList _ CDOps.InstList [comm.design], all.rest WHILE all # NIL DO IF all.first.selected THEN BEGIN IF debug THEN CDProperties.PutObjectProp [all.first.ob, checkedKey, NIL]; errorSummary _ CONS [[CDOps.ToRope[all.first.ob], Verify [all.first, comm.design, abort].errorTotal], errorSummary]; TerminalIO.PutRope ["."] END ENDLOOP END; -- VerifySelected TerminalIO.PutRope ["Checking via flatness.\n"]; startTime _ BasicTime.Now []; CDSequencer.UseAbortFlag [comm.design, abort]; [] _ CDCommandOps.DoWithResource [VerifySelected, comm, externalKey]; stopTime _ BasicTime.Now []; IF (errorSummary # NIL) THEN BEGIN TerminalIO.PutRope ["\nError summary (via flatness):\n"]; FOR e: LIST OF RECORD [c: Rope.ROPE, n: INT] _ errorSummary, e.rest WHILE e # NIL DO IF (e.first.n > 0) THEN TerminalIO.PutRope [IO.PutFR ["%g: %g.\n", IO.rope[e.first.c], IO.int[e.first.n]]] ENDLOOP END; -- write error summary TerminalIO.PutRope ["Via flatness verification done.\n"]; IF timing THEN TerminalIO.PutRope [Rope.Cat ["Total elapsed time: ", TimeToRope [startTime, stopTime], "\n"]] END; -- InteractiveCall TimeToRope: PROC [from, to: BasicTime.GMT] RETURNS [time: Rope.ROPE] ~ BEGIN tmp: Rope.ROPE; sec: INT = BasicTime.Period [from, to]; min: INT = sec / 60; h: INT = min / 60; tmp _ IO.PutFR1 [value: IO.int [h]]; time _ SELECT h FROM = 0 => "00", < 10 => Rope.Cat ["0", tmp], ENDCASE => tmp; tmp _ IO.PutFR1 [value: IO.int [min MOD 60]]; time _ Rope.Cat [time, ":", SELECT min FROM = 0 => "00", < 10 => Rope.Cat ["0", tmp], ENDCASE => tmp]; tmp _ IO.PutFR1 [value: IO.int [sec MOD 60]]; time _ Rope.Cat [time, ":", SELECT sec FROM = 0 => "00", < 10 => Rope.Cat ["0", tmp], ENDCASE => tmp] END; -- TimeToRope ObjConversionProc: TYPE ~ PROCEDURE [ob: CD.Object, transf: CD.Transformation, state: State]; DoNotDrawContext: CD.DrawContextProc ~ {}; ExchangeCDInfo: PROC ~ BEGIN tech: CD.Technology = CMosB.cmosB; Register: PROC [tech: CD.Technology, class: ATOM, proc: ObjConversionProc] ~ BEGIN cl: CD.ObjectClass _ CD.FetchObjectClass [objectType: class, technology: tech]; IF cl = NIL THEN CD.Error [explanation: "Version mismatch."]; CDProperties.PutProp [onto: cl.properties, prop: externalKey, val: NEW [ObjConversionProc_proc]] END; -- Register Register [tech, $C2Via, ConvertVia]; Register [tech, $C2LargeVia, ConvertVia]; FOR l: CD.Layer IN [0 .. diffLayers) DO diffLayer[l] _ CDSimpleRules.GetLayer [tech, diffKey[l]] ENDLOOP; polyLayer _ CDSimpleRules.GetLayer [tech, polyKey] END; -- ExchangeCDInfo ConvertVia: ObjConversionProc ~ BEGIN data: ViaTileData _ NEW [ViaTileDataRec]; FOR geom: CDAtomicObjects.DrawList _ NARROW [ob.specific, CDAtomicObjects.AtomicObsSpecific].rList, geom.rest WHILE geom # NIL DO SELECT geom.first.layer FROM CMosB.cut2 => BEGIN r: CD.Rect = CDBasics.MapRect [itemInCell: geom.first.r, cellInWorld: transf]; InsertVia [r: r, state: state, data: data] END; ENDCASE => NULL ENDLOOP END; -- ConvertVia ConvertMat: PROC [r: CD.Rect, layer: CD.Layer, state: State] ~ BEGIN bloatedRect: CD.Rect; vias: Region; IF NOT CDBasics.NonEmpty[r] THEN RETURN; -- empty rectangle IF state.abort^ THEN ERROR ABORTED; SELECT layer FROM diffLayer[0], diffLayer[1], diffLayer[2], diffLayer[3] => BEGIN -- DANGER bloatedRect _ CDBasics.Extend [r, viaOnFieldOxideAvoidsDiff.extent]; vias _ CStitching.ListArea [plane: state.viaTess, rect: bloatedRect]; FOR v: Region _ vias, v.rest WHILE v # NIL DO via: ViaTileData _ NARROW [v.first.value]; IF via.hasPoly THEN BEGIN FlagViolation [viaOverGate, v.first.rect, state]; DeleteRect [state.viaTess, v.first.rect] END ENDLOOP; bloatedRect _ CDBasics.Extend [r, diffSurroundsViaOnDiff.extent]; vias _ CStitching.ListArea [plane: state.viaTess, rect: bloatedRect]; FOR v: Region _ vias, v.rest WHILE v # NIL DO via: ViaTileData = NARROW [v.first.value]; IF CDBasics.Intersect [v.first.rect, r] THEN via.hasDiff _ TRUE; bloatedRect _ CDBasics.Extend [v.first.rect, diffSurroundsViaOnDiff.extent]; InsertMat [genericDiff, CDBasics.Intersection[bloatedRect, r], via, state] ENDLOOP END; polyLayer => BEGIN vias _ CStitching.ListArea [plane: state.viaTess, rect: r]; FOR v: Region _ vias, v.rest WHILE v # NIL DO via: ViaTileData = NARROW [v.first.value]; IF (via # empty) THEN BEGIN FlagViolation [viaOverPoly, v.first.rect, state]; DeleteRect [state.viaTess, v.first.rect] END ENDLOOP; bloatedRect _ CDBasics.Extend [r, viaOnFieldOxideAvoidsPoly.extent]; vias _ CStitching.ListArea [plane: state.viaTess, rect: bloatedRect]; FOR v: Region _ vias, v.rest WHILE v # NIL DO via: ViaTileData = NARROW [v.first.value]; IF via.hasDiff THEN BEGIN FlagViolation [viaOverGate, v.first.rect, state]; DeleteRect [state.viaTess, v.first.rect] END ENDLOOP; bloatedRect _ CDBasics.Extend [r, polySurroundsViaOnPoly.extent]; vias _ CStitching.ListArea [plane: state.viaTess, rect: bloatedRect]; FOR v: Region _ vias, v.rest WHILE v # NIL DO via: ViaTileData = NARROW [v.first.value]; IF CDBasics.Intersect [v.first.rect, r] THEN via.hasPoly _ TRUE; bloatedRect _ CDBasics.Extend [v.first.rect, polySurroundsViaOnPoly.extent]; InsertMat [polyKey, CDBasics.Intersection[bloatedRect, r], via, state] ENDLOOP END; ENDCASE => NULL END; -- ConvertMat ExtractObject: CD.DrawProc ~ BEGIN convProc: REF ObjConversionProc; state: State ~ NARROW [pr.devicePrivate]; IF state.abort^ THEN ERROR ABORTED; SELECT ob.class.objectType FROM $Rect => NULL; $Cell => ob.class.drawMe [pr, ob, trans]; ENDCASE => BEGIN convProc _ NARROW [CDProperties.GetProp [from: ob.class.properties, prop: externalKey], REF ObjConversionProc]; IF convProc # NIL THEN convProc^[ob, trans, state] ELSE ob.class.drawMe [pr, ob, trans] END END; -- ExtractObject ExtractRect: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; ConvertMat [r, l, state] END; -- ExtractRect EnumerateDesign: PROC [inst: CD.Instance, state: State, vias: BOOL] ~ BEGIN dr: CD.DrawRef = CD.CreateDrawRef [[]]; IF vias THEN dr.drawChild _ ExtractObject ELSE dr.drawRect _ ExtractRect; dr.drawContext _ DoNotDrawContext; dr.devicePrivate _ state; dr.stopFlag _ state.abort; inst.ob.class.drawMe [dr, inst.ob, inst.trans] END; -- EnumerateDesign CreateTess: PROC [state: State] ~ BEGIN state.viaTess _ CStitching.NewTesselation [stopFlag: state.abort]; state.materialTess _ CStitching.NewTesselation [stopFlag: state.abort] END; -- CreateTess DestroyTess: PROC [state: State] ~ BEGIN CStitching.ResetTesselation [state.viaTess]; CStitching.ResetTesselation [state.materialTess]; CStitching.DumpCache []; state.viaTess _ state.materialTess _ NIL END; -- DestroyTess InsertVia: PROC [r: CD.Rect, state: State, data: ViaTileData] ~ BEGIN viaSpacingViolation, splitVia: BOOL _ FALSE; errorRect: CD.Rect; OccupyByVia: CStitching.RectProc = BEGIN Split: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [(rect.x1= r.x1) AND (rect.y1= r.y1) AND (rect.x2= r.x2) AND (rect.y2= r.y2)] END; -- Split WITH oldValue SELECT FROM v: ViaTileData => IF Split [] THEN splitVia _ TRUE ELSE {viaSpacingViolation _ TRUE; errorRect _ rect}; ENDCASE => IF NOT (viaSpacingViolation OR splitVia) THEN CStitching.ChangeRect [plane: state.viaTess, rect: rect, new: data] END; -- OccupyByVia CStitching.ChangeEnumerateArea [state.viaTess, r, OccupyByVia, data, nothing]; IF viaSpacingViolation THEN BEGIN DeleteRect [state.viaTess, r]; FlagViolation [viaSeparation, errorRect, state] END END; -- InsertVia InsertMat: PROC [mat: ATOM, rect: CD.Rect, via: ViaTileData, state: State] ~ BEGIN data: MatTileData = NEW [MatTileDataRec _ [mat, via]]; viaOverGateViolation: BOOL _ FALSE; errorRect: CD.Rect; OccupyByMaterial: CStitching.RectProc = BEGIN WITH oldValue SELECT FROM m: MatTileData => IF (m.layerKey # mat) THEN BEGIN viaOverGateViolation _ TRUE; errorRect _ rect END; ENDCASE => IF NOT viaOverGateViolation THEN CStitching.ChangeRect [plane: state.materialTess, rect: rect, new: data] END; -- OccupyByMaterial CStitching.ChangeEnumerateArea [state.materialTess, rect, OccupyByMaterial, data, nothing]; IF viaOverGateViolation THEN BEGIN DeleteRect [state.viaTess, rect]; FlagViolation [viaOnPolyAndDiff, errorRect, state] END END; -- InsertMat DeleteRect: PROC [plane: Tess, rect: CD.Rect] ~ BEGIN plane.ChangeRect [rect, empty] END; -- DeleteRect LookUnderneath: CStitching.TileProc ~ BEGIN -- PROC [tile: REF Tile, data: REF] state: State ~ NARROW [data]; via: ViaTileData ~ NARROW [tile.value]; rect: CStitching.Rect ~ CStitching.Area [tile]; IsOnFieldOxide: PROC RETURNS [d: BOOL _ TRUE] ~ INLINE BEGIN FOR cut: Region _ CStitching.ListArea [state.materialTess, rect], cut.rest WHILE cut # NIL DO IF (cut.first.value # NIL) THEN RETURN [FALSE] ENDLOOP END; -- IsOnFieldOxide Accumulate: CStitching.TileProc ~ BEGIN via: ViaTileData ~ NARROW [data]; mat: MatTileData ~ NARROW [tile.value]; IF (mat = fieldOxide) THEN via.hasFOx _ TRUE -- [field oxide is represented by L] ELSE BEGIN IF (mat.via # via) THEN ERROR; -- Consistency test: Tesselation screwed up SELECT mat.layerKey FROM genericDiff => via.hasDiff _ TRUE; polyKey => via.hasPoly _ TRUE; ENDCASE => ERROR END END; -- Accumulate IF state.abort^ THEN ERROR ABORTED; via.hasFOx _ NOT (via.hasDiff OR via.hasPoly); SELECT TRUE FROM via.hasDiff => BEGIN CStitching.EnumerateArea [plane: state.materialTess, rect: CDBasics.Extend [rect, diffSurroundsViaOnDiff.extent], eachTile: Accumulate, data: via, skip: $doNotSkipAnything]; IF via.hasFOx THEN IF IsOnFieldOxide[] THEN FlagViolation [viaOnFieldOxideAvoidsDiff, rect, state] ELSE FlagViolation [diffSurroundsViaOnDiff, rect, state] END; via.hasPoly => BEGIN CStitching.EnumerateArea [plane: state.materialTess, rect: CDBasics.Extend [rect, polySurroundsViaOnPoly.extent], eachTile: Accumulate, data: via, skip: $doNotSkipAnything]; IF via.hasFOx THEN IF IsOnFieldOxide[] THEN FlagViolation [viaOnFieldOxideAvoidsPoly, rect, state] ELSE FlagViolation [polySurroundsViaOnPoly, rect, state] END; via.hasFOx => BEGIN CStitching.EnumerateArea [plane: state.materialTess, rect: CDBasics.Extend [rect, fieldOxideSurroundsViaOnFieldOxide.extent], eachTile: Accumulate, data: via, skip: $doNotSkipAnything]; IF via.hasDiff THEN FlagViolation [viaOnFieldOxideAvoidsDiff, rect, state]; IF via.hasPoly THEN FlagViolation [viaOnFieldOxideAvoidsPoly, rect, state] END; ENDCASE => NULL -- no violation END; -- LookUnderneath FlagViolation: PROC [rule: Rule, rect: CD.Rect, state: State] ~ BEGIN longMsg: Rope.ROPE = IO.PutFR ["Error: %g at [%g, %g].\n", IO.rope [rule.msg], IO.int [rect.x1], IO.int [rect.y1]]; state.errorLog.PutF1 ["%g\n", IO.rope [longMsg]]; state.errors _ CONS [[rule, rect], state.errors]; state.errorTotal _ state.errorTotal.SUCC; IF (state.design = NIL) THEN TerminalIO.PutRope [longMsg] ELSE BEGIN [] _ CDErrors.IncludeMessage [design: state.design, ob: NIL, rect: CDBasics.Extend [rect, rule.extent], message: rule.msg, owner: errorKey]; IF (state.errorTotal < 30) THEN TerminalIO.PutRope ["|"] END END; -- FlagViolation DarkPoly: CSMonitor.PaintPredicate ~ BEGIN RETURN [(ISTYPE [val, MatTileData]) AND (NARROW[val,MatTileData].layerKey = polyKey)] END; -- DarkPoly ClearVFData: CDEvents.EventProc ~ BEGIN cell: CD.Object = NARROW [x, CD.Object]; CDProperties.PutObjectProp [onto: cell, prop: checkedKey, val: NIL]; CDProperties.PutObjectProp [onto: cell, prop: externalKey, val: NIL] END; -- ClearVFData [] _ CDProperties.RegisterProperty [externalKey, $gbb]; CDProperties.InstallProcs [prop: externalKey, procs: [makeCopy: CDProperties.CopyVal]]; [] _ CDProperties.RegisterProperty [errorKey, $gbb]; [] _ CDProperties.RegisterProperty [checkedKey, $gbb]; ExchangeCDInfo; CDEvents.RegisterEventProc [proc: ClearVFData, event: $AfterCellReplacement]; CDEvents.RegisterEventProc [proc: ClearVFData, event: $AfterChange]; CDSequencer.ImplementCommand [key: $GismoVFSel, proc: InteractiveCall, queue: doQueue]; TerminalIO.PutRope ["Via flatness checker loaded.\n"]; END. \ViaFlatnessImpl.mesa Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved. Giordano Bruno Beretta, January 21, 1986 2:54:32 pm PST gbb June 5, 1987 8:47:38 pm PDT Checks that vias are are on flat topology. The following flat topologies are accepted: diffusion (may be partial), poly, and field oxide. For the moment this implementation is "flat". ErrorList: TYPE ~ LIST OF RECORD [rule: Rule; where: CD.Rect]; The rules In  units from the minimal metal border of the via (not from the cut). TYPE ~ RECORD [extent: CD.Number, msg: Rope.ROPE] In the following rules the extent is used only to determine the overlap of the error rectangle. Environment: public procedures and interactive interface to ChipNDale If a design is not provided, the error messages are displayed in the terminal viewer. Smash vias into a flat tesselation of interesting areas. Throw intersecting diffusion and poly into materialTess. Conflicts are resolved on the fly by marking an error and discarding the interesting area (we are not interested in multiple errors). Enumerate the materialTess and check it for flatness. Called by ChipNDale upon activation of the command. Verifies all selected cells in background priority. IF (e.first.n = -1) THEN TerminalIO.PutRope [IO.PutFR ["%g: previously analysed.\n", IO.rope[e.first.c]]] Although the INT returned BasicTime.Period is the same as GMT and might hence be loopholed to use IO.time from Conversions, the latter uses BasicTime.Unpack which allows only values that give a valid date. Operations on ChipNDale objects Registers the procedures to extract vias from the design and gets the layers. [ob: CD.Object, transf: CD.Transformation, state: State] Algorithm: 1. If there is antagonist material in a viaOnFieldOxideAvoidsDiff-sphere from a via, then the topology cannot be flat. 2. If r is in a minSurround-sphere from a via, then insert it in the material tesselation. We insert material in the whole influence area of a via. Note that via always is a single and non-degenerated via, since collisions of vias are detected when the vias are input. We insert material in the whole influence area of a via. Note that via always is a single and non-degenerated via, since collisions of vias are detected when the vias are input. [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] [r: Rect, l: Layer, pr: DrawRef] If vias is false, rectangles are enumerated. Operations on the corner-stitched plane Initialises the tesselations. Disposes the tesselations. Inserts a via rectangle. This procedure ensures that vias do not overlap. [plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] Inserts a rectangle of material and does a weak check for via over gate. The latter is here only because it is easy. In practice a via over a gate is discovered before entering here. (Note that this check for via over gate is not sufficient.) [plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] Implementation Looks what is under a via cut. Is the via on field oxide ? At this point we know, what is immediately under the via cut and that there the rule viaOverGate is not violated. Deletes the via from the tesselation and puts an error rectangle in the design. [event: REF, design: CD.Design, x: REF] RETURNS [dont: BOOL _ FALSE] Deletes the via flatenes checker data from a cell when it has been edited. Initialisation CDMenus.CreateEntry [menu: $ProgramMenu, entry: "Via Flatness (Gismo)", key: $GismoVFSel]; gbb March 25, 1986 10:40:13 am PST Changed labels of menu entries. gbb July 31, 1986 6:17:41 pm PDT changes to: DIRECTORY, DestroyTess: now really disposes the tiles. gbb September 2, 1986 1:00:28 pm PDT Added an error log. changes to: DIRECTORY, IMPORTS, Verify, FlagViolation: puts long message in error log. gbb October 17, 1986 1:29:13 pm PDT Fixed the fact, that diffusion can be in different ChipNDale layers, but it counts all as being the same for the flatness test. changes to: ExchangeCDInfo, ConvertMat gbb October 20, 1986 5:51:28 pm PDT Fixed an uninitialized variable. Tuned performance. changes to: ConvertMat, InsertVia, InsertMat, DeleteTile, LookUnderneath ʬ˜codešœ™KšœB™BKšœ7™7K™—K˜K™¹code2šÏk ˜ Kšœ œœ˜#KšœœÂ˜ÊKšœœ˜4Kšœ œ6˜DKšœ œ˜$Kšœ œ"˜0Kšœ œ ˜.Kšœœ˜Kšœ œ[˜mKšœ œ+˜œœœ˜—šœ œ˜(Kš œ œœœœœ™>—Iunitšœ œœ˜'Kšœœœ œ œœ  œ œœ œœœ ˜Kšœ œœ˜'Kšœœœ œ˜AMšœ œ  Ðbc &˜IMšœ œœœ(˜PKšœ œ ˜Kšœ œ˜Mšœ œœœ˜/Kšœ œ˜Mšœ œœœ˜—head™ LšœG™Gšœœ˜Kšœœ œœ™1—Mšœ'Ÿœ#˜KMšœ'Ÿœ˜@Mšœ,œe˜”Mšœ$Ÿœ+˜PMšœ$Ÿœ ˜EM™_MšœŸœ ˜YMšœŸœ ˜PMšœŸœ˜9MšœŸœ˜9—™EšÏnœœœœœ œ œœœœ!œ˜„K™UKšœ ˜ Kšœœ˜Kšœ œ1œ˜CKšœœ/˜LKš œœœœœœ˜?Kšœ+˜+šœ œ˜Kšœœ˜1Kšœ˜—šœ1œœ˜BKšœœ˜1Kšœ˜—šœœ˜*KšœN˜NKšœœ˜Kšœ˜—Kšœœœ*˜;Kšœœ˜%Kšœœ œœœœœœ˜BKš œœgœœœ '˜ÆKšœCœ˜YKšœ˜šœœ˜KšœAœ˜FKšœT˜TKšœ˜—K™8Kšœœ˜!Kšœœ˜*Kšœ+Ïe œ‡™¾Kšœœ˜"Kšœœ˜*Kšœ£ œ™5Kšœ{˜{Kšœœ<˜IKšœ˜Kšœ7˜7Kšœ:˜:KšœO˜OKšœ!˜'Kšœ ˜—š¢œœ˜9K™3Kš œœœœœœ˜%Kšœœ ˜7Kš œœœœ œœ˜4š¢œœ˜8K™3Kšœ4˜;š œœ7œœ˜Tšœœ˜ Kšœœ7œ˜IKšœœÏlœ<˜tKšœ˜Kš˜—Kš˜—Kšœ ˜Mšœ0˜0Kšœ˜Kšœ.˜.KšœE˜EKšœ˜šœœœ˜"Kšœ9˜9šœœœœ œœœœ˜Tšœ™Kšœœ&œ™P—šœ˜Kšœœœœ˜R—Kš˜—Kšœ ˜—Kšœ9˜9Kšœœ_˜m—Kšœ ˜—š ¢ œœœœ œ˜LKšœ Ðekœ £œ¥œ%¥£œ£ œ£œ1™ÍKšœ œ˜Kšœœ˜'Kšœœ ˜Kšœœ ˜Mšœœœ ˜$Kšœœœ+œ˜NMšœœœ œ˜-Kšœœœ+œ ˜fMšœœœ œ˜-Kšœœœ+œ˜eKšœ  ˜——™Lš œœ œœœ˜]Lš¢œœ˜*š¢œœ˜K™MKšœœ˜"š ¢œœœœ˜RKšœœœ8˜OKšœœœœ*˜=KšœCœ˜`Kšœ ˜—Mšœ$˜$Kšœ)˜)šœœœ˜'Kšœ8˜8Kšœ˜—Kšœ2˜2Kšœ ˜—š¢ œ˜%Kšœœœ™8Kšœœ˜)š œ"œCœœ˜šœ˜šœ˜KšœœI˜NKšœ*˜*Kšœ˜—Kšœ˜—Kš˜—Kšœ  ˜—š ¢ œœœœ˜DKšœ‰£œS™ÝKšœ œ˜Kšœ ˜ Kš œœœœ ˜;Kšœœœœ˜#šœ˜šœ:œ ¡˜IKšœD˜DKšœE˜Ešœœœ˜-Kšœœ˜*šœ œ˜Kšœ1˜1Kšœ(˜(Kš˜—Jšœ˜—JšœA˜AKšœE˜Ešœœœ˜-Kšœœ˜*Kšœ&œœ˜@K™8KšœL˜LKšœJ˜JKšœ £œk™xJš˜—Jšœ˜—šœ ˜Kšœ;˜;šœœœ˜-Kšœœ˜*šœœ˜Kšœ1˜1Kšœ(˜(Kš˜—Jšœ˜—KšœD˜DKšœE˜Ešœœœ˜-Kšœœ˜*šœ œ˜Kšœ1˜1Kšœ(˜(Kš˜—Jšœ˜—JšœA˜AKšœE˜Ešœœœ˜-Kšœœ˜*Kšœ&œœ˜@K™8KšœL˜LKšœF˜FKšœ £œk™xJš˜—Jšœ˜—Kšœ˜—Kšœ  ˜—š¢ œœ ˜"Kš œœœœ'œ œ™`Kšœ œ˜ Kšœœ˜)Mšœœœœ˜#šœ˜Kšœ œ˜Kšœ)˜)šœ˜Kšœ œGœ˜oKšœ œœ˜2Kšœ ˜$Kš˜——Kšœ  ˜—š¢ œœ˜$Kšœ ™ Kšœœ˜0Kšœ˜Kšœ  ˜—š ¢œœœœ˜KKšœ£œ%™,Kšœœ œ˜'Mšœœœ˜IKšœ"˜"Kšœ4˜4Kšœ.˜.Kšœ ˜——™'š¢ œœ˜'K™KšœB˜BKšœF˜FKšœ  ˜—š¢ œœ˜(K™Kšœ,˜,Kšœ1˜1Kšœ>˜AKšœ  ˜—š¢ œœœ*˜EK™JKšœœœ˜,Kšœ œ˜š¢ œ˜(Kšœœ$œœ™>š ¢œœœœœ˜)Kšœœœœ˜TKšœ ˜ —šœ œ˜šœ˜Kšœ œ ˜ Kšœœ˜4—š œœœœ ˜8KšœC˜C——Kšœ ˜—MšœN˜Nšœœ˜!Kšœ˜Kšœ/˜/Kš˜—Kšœ  ˜—š ¢ œœœœ)˜RK™òKšœœ˜6Kšœœœ˜#Kšœ œ˜š¢œ˜-Kšœœ$œœ™>šœ œ˜šœœœ˜2Kšœœ˜.Kšœ˜—šœœœ˜+KšœH˜H——Kšœ ˜—Mšœ[˜[šœœ˜"Kšœ!˜!Kšœ2˜2Kš˜—Kšœ  ˜—š¢ œœœ ˜5Kšœ˜Kšœ  ˜——™š¢œœ #˜OK™Kšœœ˜Kšœœ˜'Kšœ/˜/š ¢œœœœœœ˜