DIRECTORY BasicTime USING [GMT, Now, Period], CD USING [CreateDrawRef, Design, DrawProc, DrawRectProc, DrawRef, Instance, InstanceList, Layer, LayerKey, Number, Object, ObjectClass, Rect, Technology], CDBasics USING [Extend, NonEmpty], CDCommandOps USING [DoWithResource], CDErrors USING [IncludeMessage, RemoveMessages], CDEvents USING [EventProc, RegisterEventProc], CDOps USING [ObjectRope, InstList], CDProperties USING [CopyVal, GetObjectProp, InstallProcs, PutObjectProp, RegisterProperty], CDSequencer USING [Command, ImplementCommand, UseAbortFlag], CMosB USING [cmosB, lambda, ndif, nwell, nwellCont, pdif, pwell, pwellCont], 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 [PutRope], ViewerClasses USING [Viewer]; DiffInWellImpl: CEDAR PROGRAM IMPORTS BasicTime, CD, CDBasics, CDCommandOps, CDErrors, CDEvents, 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"]; nWellContact: Rule ~ [4 * l, "p-well contact too close to n-well"]; pWellContact: Rule ~ [4 * l, "n-well contact too close to p-well or field oxide"]; 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.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>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.ObjectRope[all.first.ob], Verify [all.first, comm.design, abort].errorTotal], errorSummary]; TerminalIO.PutRope ["."] END ENDLOOP END; -- VerifySelected TerminalIO.PutRope ["Checking well surround.\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:\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 ["Well surround 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 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) OR (l = CMosB.pwellCont) OR (l = CMosB.nwellCont) 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.trans, 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); isnDiff: BOOL ~ (layer = CMosB.ndif); ispCont: BOOL ~ (layer = CMosB.nwellCont); isnCont: BOOL ~ (layer = CMosB.pwellCont); isP: BOOL ~ (ispDiff OR ispCont); isN: BOOL ~ (isnDiff OR isnCont); IF NOT CDBasics.NonEmpty[r] THEN RETURN; -- empty rectangle IF state.abort^ THEN ERROR ABORTED; wells _ state.wellTess.ListArea [rect: r, skip: nothing]; FOR w: Region _ wells, w.rest WHILE w # NIL DO well: ATOM _ NARROW [w.first.value]; IF (isP AND (well = fieldOxide)) OR (isP AND (well = pWell)) THEN FlagViolation [PinP, w.first.rect, state]; IF (isN AND (well = nWell)) THEN FlagViolation [NinN, w.first.rect, state] ENDLOOP; IF (ispDiff OR isnDiff) THEN BEGIN bloatedRect _ CDBasics.Extend [r, nWellSurround.extent]; wells _ state.wellTess.ListArea [rect: bloatedRect, skip: nothing]; 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 (isnDiff AND (well = nWell)) THEN FlagViolation [pWellSurround, w.first.rect, state] ENDLOOP END ELSE BEGIN -- is contact bloatedRect _ CDBasics.Extend [r, nWellContact.extent]; wells _ state.wellTess.ListArea [rect: bloatedRect, skip: nothing]; FOR w: Region _ wells, w.rest WHILE w # NIL DO well: ATOM _ NARROW [w.first.value]; IF (ispCont AND (well = fieldOxide)) OR (ispCont AND (well = pWell)) THEN FlagViolation [nWellContact, w.first.rect, state]; IF (isnCont AND (well = nWell)) THEN FlagViolation [pWellContact, w.first.rect, state] ENDLOOP END 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.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 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, procs: [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]; TerminalIO.PutRope ["Diffusion in well checker loaded.\n"]; END. BDiffInWellImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Giordano Bruno Beretta, May 27, 1986 1:59:07 pm PDT gbb March 10, 1987 1:29:25 pm PST 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 CDMenus.CreateEntry [menu: $ProgramMenu, entry: "Diffusion in well (Gismo)", key: $GismoDIWSel]; 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. gbb March 10, 1987 1:29:10 pm PST Added well contacts. changes to: DIRECTORY, nWellContact, pWellContact, ExtractDiff, Inquire Κ Κ˜codešœ™Kšœ Οmœ1™—Iunitšœ žœžœ˜Kšœžœžœ˜(Kšœžœžœ˜(—head™ Lšœ œC™Gšœžœ˜Kšžœžœ žœžœ™1—Mšœ œ9˜UMšœ œ9˜UMšœ œ(˜CMšœ œ7˜RM™_Mšœ œ˜7Mšœ œ˜.Mšœ œ˜.—™EšΟnœžœžœžœžœ žœ žœžœžœžœ!žœž˜„K™UKšœ ˜ Kšœžœ˜Kšœ žœ1žœ˜CKšœžœ/˜LKšœ&˜&Kš œžœžœžœžœžœ˜?šžœ žœž˜Kšœžœ˜1Kšžœ˜—šžœ1žœžœž˜BKšœžœ˜1Kšžœ˜—šžœžœž˜*KšœN˜NKšžœžœ˜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šœ1˜1Kšœ˜Kšœ.˜.KšœE˜EKšœ˜šžœžœžœž˜"Kšœ*˜*šžœžœžœžœ žœžœžœžœž˜Tšžœž˜Kšœžœžœžœ˜R—Kšž˜—Kšžœ‘˜—Kšœ:˜:Kšžœžœ_˜m—Kšžœ‘˜—š ’ œžœžœžœ žœž˜LKšœ Πekœ £œ€œ%€£œ£ œ£œ1™ΝKšœ žœ˜Kšœžœ˜'Kšœžœ ˜Kšœžœ ˜Mšœžœžœ ˜$Kšœžœžœ+žœ˜NMšœžœžœ žœ˜-Kšœžœžœ+žœ ˜fMšœžœžœ žœ˜-Kšœžœžœ+žœ˜eKšžœ‘ ˜——™š’ œžœž˜%Kšœ ™ Kšœžœ˜0Kšžœžœžœžœ˜dKšžœ‘˜—š’ œžœž˜$Kšœ ™ Kšœžœ˜0Kš žœžœžœžœžœ˜tKšžœ‘˜—š ’œžœžœ žœž˜LKšœ7™7Kšœžœ žœ˜'Mšœžœžœžœ ˜:Kšœ˜Kšœ˜Kšœ+˜+Kšžœ‘˜——™'š’ œžœž˜'K™KšœB˜BKšžœ‘ ˜—š’ œžœž˜(K™Kšœ-˜-Kšœ*ž˜-Kšžœ‘ ˜—š ’ œžœžœžœž˜?KšœB™BKšœžœžœ˜#Kšœ žœ˜š’ œž˜)Kšœžœ$žœžœ™>šžœ žœž˜š œžœžœžœžœžœž˜*Kšžœžœžœ˜F—šžœ‘.Πce‘˜HKšœD˜D——Kšžœ‘˜—Mšžœžœžœžœ˜#KšœP˜PKšžœžœ/˜KKšžœ‘ ˜——™š ’œžœžœžœž˜AKšœt™tKšœ žœ˜Kšœ˜Kšœ žœ˜%Kšœ žœ˜%Kšœ žœ˜*Kšœ žœ˜*Kšœžœ žœ ˜!Kšœžœ žœ ˜!Mš žœžœžœžœ‘˜;Kšžœžœžœžœ˜#M™Kšœ9˜9šžœžœžœž˜.Kšœžœžœ˜$š žœžœžœžœž˜AKšœ*˜*—šžœžœž˜ Kšœ)˜)—Jšžœ˜—M™šžœ žœ žœž˜"Kšœ8˜8KšœC˜Cšžœžœžœž˜.Kšœžœžœ˜$š žœ žœžœ žœž˜IKšœ3˜3—šžœ žœž˜$Kšœ2˜2—Jšž˜——Jšž˜šžœžœ‘ ˜Kšœ7˜7KšœC˜Cšžœžœžœž˜.Kšœžœžœ˜$š žœ žœžœ žœž˜IKšœ2˜2—šžœ žœž˜$Kšœ1˜1—Jšž˜—Jšž˜—Kšžœ‘ ˜—š’ œžœžœž˜EK™OKš œžœžœ$žœžœžœ˜sMšœžœ˜1Kšœžœ˜1Kšœ$žœ˜)Kšžœžœžœ˜9šžœž˜ Kšœ8žœQ˜ŒKšžœžœ˜8Kšž˜—Kšžœ‘ ˜—š’ œž˜+Kš žœ žœžœžœžœ ˜5Kšžœ‘ ˜—š’ œž˜(Kš œžœ žœ žœžœžœžœ™DK™OKšœžœ žœžœ ˜(Kšœ?žœ˜DKšœ@žœ˜DKšžœ‘˜——™Lšœ7˜7KšœW˜WKšœ4˜4Kšœ6˜6LšœN˜NKšœE˜ELšœX˜XKšœ`™`Kšœ;˜;—Lšžœ˜™ Kšœ Οrœ ™B—™%K™Kšœ ¦)œ!™V—™!K™Kšœ ¦;™G—K™—…—,8DD