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: 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;
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
BOOL ←
NIL]
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 [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;
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 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
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: BOOL ← FALSE;
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: 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;
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: 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
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: BOOL ← FALSE]
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