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 [ToRope, 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.ToRope[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 [dr, inst.ob, inst.trans] 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. HDiffInWellImpl.mesa Copyright Σ 1986, 1987 by Xerox Corporation. All rights reserved. Giordano Bruno Beretta, May 27, 1986 1:59:07 pm PDT gbb April 6, 1987 12:32:29 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 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šœB™BKšœ3™3K™!—K˜K™„code2šΟk ˜ Kšœ œœ˜#Kšœœ’˜šKšœ œ˜"Kšœ œ˜$Kšœ œ"˜0Kšœ œ ˜.Kšœœ˜Kšœ œI˜[Kšœ œ+˜—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šœœžœ<˜tKšœ˜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™—…—,2D?