DiffInWellImpl.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.
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: BOOLFALSE;
timing: BOOLFALSE;
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;
ErrorList: TYPE ~ LIST OF RECORD [rule: Rule; where: CD.Rect];
fieldOxide: ATOM ~ NIL;
pWell: ATOM ~ CD.LayerKey [CMosB.pwell];
nWell: ATOM ~ CD.LayerKey [CMosB.nwell];
The rules
In l units from the minimal metal border of the via (not from the cut).
Rule: TYPE ~ DiffInWell.Rule;
TYPE ~ RECORD [extent: CD.Number, msg: Rope.ROPE]
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"];
In the following rules the extent is used only to determine the overlap of the error rectangle.
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"];
Environment: public procedures and interactive interface to ChipNDale
Verify: PUBLIC PROC [c: CD.Instance, d: CD.Design ← NIL, abort: REF BOOLNIL] RETURNS [errors: ErrorList, errorTotal: INT] ~ BEGIN
If a design is not provided, the error messages are displayed in the terminal viewer.
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 [BOOLFALSE];
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;
Smash wells into a flat tesselation of interesting areas.
EnumerateDesign [inst: c, state: state, wells: TRUE];
CSMonitor.Reset [debuggingViewer];
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.
EnumerateDesign [inst: c, state: state, wells: FALSE];
Enumerate the materialTess and check it for flatness.
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
Called by ChipNDale upon activation of the command.
abort: REF BOOLNEW [BOOLFALSE];
startTime, stopTime: BasicTime.GMT; -- for internal use
errorSummary: LIST OF RECORD [c: Rope.ROPE, n: INT];
VerifySelected: PROC [comm: CDSequencer.Command] ~ BEGIN
Verifies all selected cells in background priority.
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
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.
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
Operations on ChipNDale objects
ExtractWells: CD.DrawRectProc ~ BEGIN
[r: Rect, l: Layer, pr: DrawRef]
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
[r: Rect, l: Layer, pr: DrawRef]
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
If wells is false, diffusion rectangles are enumerated.
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
Operations on the corner-stitched plane
CreateTess: PROC [state: State] ~ BEGIN
Initialises the tesselations.
state.wellTess ← CStitching.NewTesselation [stopFlag: state.abort]
END; -- CreateTess
DestroyTess: PROC [state: State] ~ BEGIN
Disposes the tesselations.
CStitching.ResetTesselation [state.wellTess];
CStitching.DumpCache []; state.wellTess ← NIL
END; -- DestroyTess
InsertWell: PROC [r: CD.Rect, state: State, type: ATOM] ~ BEGIN
Inserts a well. This procedure ensures that wells do not overlap.
wellSpacingViolation: BOOLFALSE;
errorRect: CD.Rect;
OccupyByWell: CStitching.RectProc = BEGIN
[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF]
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
Implementation
Inquire: PROC [r: CD.Rect, layer: CD.Layer, state: State] = BEGIN
Algorithm: If there is antagonist material in a wellSurround-sphere from diffusion, then the a violation is flagged.
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;
Verify diffusion type.
wells ← state.wellTess.ListArea [rect: r, skip: nothing];
FOR w: Region ← wells, w.rest WHILE w # NIL DO
well: ATOMNARROW [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;
Verify surround.
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: ATOMNARROW [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: ATOMNARROW [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
Deletes the via from the tesselation and puts an error rectangle in the design.
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
[event: REF, design: CD.Design, x: REF] RETURNS [dont: BOOLFALSE]
Deletes the diffufion in well checker data from a cell when it has been edited.
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
Initialisation
[] ← 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];
CDMenus.CreateEntry [menu: $ProgramMenu, entry: "Diffusion in well (Gismo)", key: $GismoDIWSel];
TerminalIO.PutRope ["Diffusion in well checker loaded.\n"];
END.
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