DIRECTORY BasicTime USING [GMT, Now, Period], CD USING [CreateDrawRef, Design, DrawProc, DrawRectProc, DrawRef, Instance, InstanceList, Layer, LayerKey, Number, Object, ObjectClass, Orientation, Position, Rect, Technology], CDBasics USING [Extend, NonEmpty], CDCommandOps USING [CallWithResource], CDErrors USING [IncludeMessage, RemoveMessages], CDEvents USING [EventProc, RegisterEventProc], CDMenus USING [CreateEntry], CDOps USING [ObjectInfo, InstList], CDProperties USING [CopyVal, GetObjectProp, InstallProcs, PutObjectProp, RegisterProperty], CDSequencer USING [Command, ImplementCommand], CMosB USING [cmosB, ndif, nwell, pdif, pwell, lambda], CStitching USING [ChangeRect, DumpCache, Rect, ResetTesselation, ChangeEnumerateArea, ListArea, NewTesselation, RectProc, Region, Tesselation, Tile], CSMonitor USING [Monitor, PaintPredicate, Reset], DiffInWell USING [ErrorList, Rule], 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 [WriteChar, WriteRope], ViewerClasses USING [Viewer]; DiffInWellImpl: CEDAR PROGRAM IMPORTS BasicTime, CD, CDBasics, CDCommandOps, CDErrors, CDEvents, CDMenus, CDOps, CDProperties, CDSequencer, CMosB, CSMonitor, CStitching, FS, IO, Process, Rope, TerminalIO EXPORTS DiffInWell ~ 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 ~ $GismoDIW; -- used in traffic with external packages checkedKey: ATOM ~ $GismoDIWChecked; -- used to mark checked cells errorKey: ATOM ~ $GismoDIWError; doNotAnalyse: ATOM = $DoNotDRC; State: TYPE ~ REF StateRec; StateRec: TYPE ~ RECORD [design: CD.Design, abort: REF BOOL, wellTess: Tess, errors: ErrorList, errorTotal: INT _ 0, errorLog: IO.STREAM]; ErrorList: TYPE ~ DiffInWell.ErrorList; fieldOxide: ATOM ~ NIL; pWell: ATOM ~ CD.LayerKey [CMosB.pwell]; nWell: ATOM ~ CD.LayerKey [CMosB.nwell]; Rule: TYPE ~ DiffInWell.Rule; nWellSurround: Rule ~ [5 * l, "n-well too small or p-diffusion too close to p-well"]; pWellSurround: Rule ~ [5 * l, "n-diffusion too close to n-well or p-well too small"]; wellConflict: Rule ~ [2 * l, "p-well overlaps n-well"]; NinN: Rule ~ [2 * l, "n-diffusion in n-well"]; PinP: Rule ~ [2 * l, "p-diffusion in p-well"]; 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]]; debuggingViewer: ViewerClasses.Viewer; designName: Rope.ROPE = IF d#NIL THEN d.name ELSE "in the sky"; IF checked THEN BEGIN TerminalIO.WriteChar [':]; RETURN [oldErrors, -1] END; IF (CDProperties.GetObjectProp [o, doNotAnalyse] # NIL) THEN BEGIN TerminalIO.WriteChar [' ]; RETURN [oldErrors, -1] END; IF (d.technology # CMosB.cmosB) THEN BEGIN TerminalIO.WriteRope [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>DiffInWell.log", accessOptions: create, keep: 5, extendFileProc: NIL, remoteCheck: FALSE, wDir: NIL]; -- keep is 5 because of incremental use state.errorLog.PutF1 ["Error log by DiffInWell. Design: %g\n\n", IO.rope [designName]]; CreateTess [state]; IF debug THEN BEGIN debuggingViewer _ CSMonitor.Monitor [state.wellTess, "Well Tesselation", DarkNwell] END; EnumerateDesign [inst: c, state: state, wells: TRUE]; CSMonitor.Reset [debuggingViewer]; EnumerateDesign [inst: c, state: state, wells: FALSE]; IF NOT debug THEN 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.ObjectInfo[all.first.ob], Verify [all.first, comm.design, abort].errorTotal], errorSummary]; TerminalIO.WriteChar ['.] END ENDLOOP END; -- VerifySelected TerminalIO.WriteRope ["Checking well surround.\n"]; startTime _ BasicTime.Now []; [] _ CDCommandOps.CallWithResource [VerifySelected, comm, externalKey, abort]; stopTime _ BasicTime.Now []; IF (errorSummary # NIL) THEN BEGIN TerminalIO.WriteRope ["\nError summary:\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.WriteRope [IO.PutFR ["%g: %g.\n", IO.rope[e.first.c], IO.int[e.first.n]]] ENDLOOP END; -- write error summary TerminalIO.WriteRope ["Well surround verification done.\n"]; IF timing THEN TerminalIO.WriteRope [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 ExtractWells: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; IF (l = CMosB.nwell) OR (l = CMosB.pwell) THEN InsertWell [r: r, type: CD.LayerKey[l], state: state] END; -- ExtractWells ExtractDiff: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; IF (l = CMosB.ndif) OR (l = CMosB.pdif) THEN Inquire [r, l, state] END; -- ExtractDiff EnumerateDesign: PROC [inst: CD.Instance, state: State, wells: BOOL] ~ BEGIN dr: CD.DrawRef = CD.CreateDrawRef [[]]; dr.drawRect _ IF wells THEN ExtractWells ELSE ExtractDiff; dr.devicePrivate _ state; dr.stopFlag _ state.abort; inst.ob.class.drawMe [inst, inst.location, inst.orientation, dr] END; -- EnumerateDesign CreateTess: PROC [state: State] ~ BEGIN state.wellTess _ CStitching.NewTesselation [stopFlag: state.abort] END; -- CreateTess DestroyTess: PROC [state: State] ~ BEGIN CStitching.ResetTesselation [state.wellTess]; CStitching.DumpCache []; state.wellTess _ NIL END; -- DestroyTess InsertWell: PROC [r: CD.Rect, state: State, type: ATOM] ~ BEGIN wellSpacingViolation: BOOL _ FALSE; errorRect: CD.Rect; OccupyByWell: CStitching.RectProc = BEGIN WITH oldValue SELECT FROM well: ATOM => IF well=NIL THEN ERROR ELSE IF (well # type) THEN {wellSpacingViolation _ TRUE; errorRect _ rect}; ENDCASE => -- by Cedar definition we always come here if oldValue is NIL CStitching.ChangeRect [plane: state.wellTess, rect: rect, new: type] END; -- OccupyByWell IF state.abort^ THEN ERROR ABORTED; CStitching.ChangeEnumerateArea [state.wellTess, r, OccupyByWell, type, nothing]; IF wellSpacingViolation THEN FlagViolation [wellConflict, errorRect, state] END; -- InsertWell Inquire: PROC [r: CD.Rect, layer: CD.Layer, state: State] = BEGIN bloatedRect: CD.Rect; wells: Region; ispDiff: BOOL = (layer = CMosB.pdif); IF NOT CDBasics.NonEmpty[r] THEN RETURN; -- empty rectangle IF state.abort^ THEN ERROR ABORTED; wells _ CStitching.ListArea [plane: state.wellTess, rect: r]; FOR w: Region _ wells, w.rest WHILE w # NIL DO well: ATOM _ NARROW [w.first.value]; IF (ispDiff AND (well = fieldOxide)) OR (ispDiff AND (well = pWell)) THEN FlagViolation [PinP, w.first.rect, state]; IF ((NOT ispDiff) AND (well = nWell)) THEN FlagViolation [NinN, w.first.rect, state] ENDLOOP; bloatedRect _ CDBasics.Extend [r, nWellSurround.extent]; wells _ CStitching.ListArea [plane: state.wellTess, rect: bloatedRect]; FOR w: Region _ wells, w.rest WHILE w # NIL DO well: ATOM _ NARROW [w.first.value]; IF (ispDiff AND (well = fieldOxide)) OR (ispDiff AND (well = pWell)) THEN FlagViolation [nWellSurround, w.first.rect, state]; IF ((NOT ispDiff) AND (well = nWell)) THEN FlagViolation [pWellSurround, w.first.rect, state] ENDLOOP END; -- Inquire 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.WriteRope [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.WriteChar ['|] END END; -- FlagViolation DarkNwell: CSMonitor.PaintPredicate ~ BEGIN RETURN [(val # NIL) AND (NARROW [val, ATOM] = nWell)] END; -- DarkNwell ClearDIWData: 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; -- ClearDIWData [] _ CDProperties.RegisterProperty [externalKey, $gbb]; CDProperties.InstallProcs [prop: externalKey, new: [makeCopy: CDProperties.CopyVal]]; [] _ CDProperties.RegisterProperty [errorKey, $gbb]; [] _ CDProperties.RegisterProperty [checkedKey, $gbb]; CDEvents.RegisterEventProc [proc: ClearDIWData, event: $AfterCellReplacement]; CDEvents.RegisterEventProc [proc: ClearDIWData, event: $AfterChange]; CDSequencer.ImplementCommand [key: $GismoDIWSel, proc: InteractiveCall, queue: doQueue]; CDMenus.CreateEntry [menu: $ProgramMenu, entry: "Diffusion in well (Gismo)", key: $GismoDIWSel]; TerminalIO.WriteRope ["Diffusion in well checker loaded.\n"]; END. dDiffInWellImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Giordano Bruno Beretta, May 27, 1986 1:59:07 pm PDT gbb October 21, 1986 3:50:44 pm PDT Checks that diffusion is in the correct well. This implementation is "flat", because wells are not layed out hierarchically anyway. ErrorList: TYPE ~ LIST OF RECORD [rule: Rule; where: CD.Rect]; The rules In l 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 wells into a flat tesselation of interesting areas. Enumerate all diffusion rectangles and perform a query with bloated rectangles. For n-diff, an n-well is an a violation, while for p-dif both a pwell and fieldOxide are a violation. Enumerate the materialTess and check it for flatness. Called by ChipNDale upon activation of the command. Verifies all selected cells in background priority. 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 [r: Rect, l: Layer, pr: DrawRef] [r: Rect, l: Layer, pr: DrawRef] If wells is false, diffusion rectangles are enumerated. Operations on the corner-stitched plane Initialises the tesselations. Disposes the tesselations. Inserts a well. This procedure ensures that wells do not overlap. [plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] Implementation Algorithm: If there is antagonist material in a wellSurround-sphere from diffusion, then the a violation is flagged. Verify diffusion type. Verify surround. 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 diffufion in well checker data from a cell when it has been edited. Initialisation gbb July 31, 1986 6:15:24 pm PDT changes to: DIRECTORY, DestroyTess: now really disposes the tiles. gbb September 2, 1986 12:59:47 pm PDT Added an error log. changes to: DIRECTORY, IMPORTS, Verify, FlagViolation: puts long message in error log. Κ Ι˜codešœ™Kšœ Οmœ1™—Iunitšœ žœžœ˜Kšœžœžœ˜(Kšœžœžœ˜(—head™ Lšœ œC™Gšœžœ˜Kšžœžœ žœžœ™1—Mšœ œ9˜UMšœ œ9˜UM™_Mšœ œ˜7Mšœ œ˜.Mšœ œ˜.—™EšΟnœžœžœžœžœ žœ žœžœžœžœ!žœž˜„K™UKšœ ˜ Kšœžœ˜Kšœ žœ1žœ˜CKšœžœ/˜LKšœ&˜&Kš œžœžœžœžœžœ˜?šžœ žœž˜Kšœžœ˜2Kšžœ˜—šžœ1žœžœž˜BKšœžœ˜2Kšžœ˜—šžœžœž˜*KšœP˜PKšžœžœ˜Kšžœ˜—Kšžœžœžœ*˜;Kšœžœ˜%Kšœžœ žœžœžœžœžœžœ˜BKš œžœfžœžœžœ‘'˜ΕKšœBžœ˜XKšœ˜šžœžœž˜KšœS˜SKšžœ˜—K™9Kšœ/žœ˜5Kšœ"˜"KšœΆ™ΆKšœ/žœ˜6KšœΟe œ™5Kšžœžœžœ˜&Kšœ7˜7Kšœ:˜:KšœO˜OKšžœ!˜'Kšžœ‘˜—š’œžœž˜9K™3Kš œžœžœžœžœžœ˜%Kšœžœ‘˜7Kš œžœžœžœ žœžœ˜4š’œžœž˜8K™3Kšžœ4˜;š žœžœ7žœžœž˜Tšžœžœž˜ Kšžœžœ7žœ˜IKšœžœ#Ÿœ<˜xKšœ˜Kšž˜—Kšž˜—Kšžœ‘˜Mšœ3˜3Kšœ˜KšœN˜NKšœ˜šžœžœžœž˜"Kšœ,˜,šžœžœžœžœ žœžœžœžœž˜Tšžœž˜Kšœžœžœžœ˜T—Kšž˜—Kšžœ‘˜—Kšœ<˜šžœ žœž˜š œžœžœžœžœžœž˜*Kšžœžœžœ˜F—šžœ‘.Πce‘˜HKšœD˜D——Kšžœ‘˜—Mšžœžœžœžœ˜#KšœP˜PKšžœžœ/˜KKšžœ‘ ˜——™š ’œžœžœžœž˜AKšœt™tKšœ žœ˜Kšœ˜Kšœ žœ˜%Mš žœžœžœžœ‘˜;Kšžœžœžœžœ˜#M™Kšœ=˜=šžœžœžœž˜.Kšœžœžœ˜$š žœ žœžœ žœž˜IKšœ*˜*—šžœžœ žœž˜*Kšœ)˜)—Jšžœ˜—M™Kšœ8˜8KšœG˜Gšžœžœžœž˜.Kšœžœžœ˜$š žœ žœžœ žœž˜IKšœ3˜3—šžœžœ žœž˜*Kšœ2˜2—Jšž˜—Kšžœ‘ ˜—š’ œžœžœž˜EK™OKš œžœžœ$žœžœžœ˜sMšœžœ˜1Kšœžœ˜1Kšœ$žœ˜)Kšžœžœžœ˜;šžœž˜ Kšœ8žœQ˜ŒKšžœžœ˜9Kšž˜—Kšžœ‘ ˜—š’ œž˜+Kš žœ žœžœžœžœ ˜5Kšžœ‘ ˜—š’ œž˜(Kš œžœ žœ žœžœžœžœ™DK™OKšœžœ žœžœ ˜(Kšœ?žœ˜DKšœ@žœ˜DKšžœ‘˜——™Lšœ7˜7KšœU˜UKšœ4˜4Kšœ6˜6LšœN˜NKšœE˜ELšœX˜XKšœ`˜`Kšœ=˜=—Lšžœ˜™ Kšœ Οrœ ™B—™%K™Kšœ ¦)œ!™V—K™—…—)h?•