-- ChipReticleImpl2.mesa
-- Auxiliary functions to support reticle production.
-- last modified by E. McCreight, November 23, 1982 1:40 PM
-- written by E. McCreight, May 19, 1982 3:32 PM
DIRECTORY
ChipFeature,
ChipNetDefs,
ChipReticle,
ChipUserInt,
CoordRectPQ,
FeaturePST,
InlineDefs,
ppdddefs,
ppddefs,
ppdefs,
ReticleBandFormat,
SegmentDefs,
StreamDefs,
StringDefs;
ChipReticleImpl2: PROGRAM
IMPORTS ChipFeature, ChipNetDefs,
ChipReticle, ChipUserInt,
CoordRectPQ, FeaturePST, InlineDefs,
ppdddefs, ppddefs, ppdefs,
StreamDefs, StringDefs
EXPORTS ChipReticle SHARES ChipReticle =
BEGIN OPEN StreamDefs, StringDefs, ppdddefs, ppddefs, ppdefs,
ChipUserInt, ChipNetDefs,
ChipReticle, FeaturePST, CoordRectPQ;
InitMaskStates: PUBLIC PROCEDURE[] =
BEGIN
hasPad, hasNBuriedContact, hasMetal2, hasCMOS, hasNDepletion:
BOOLEAN ← FALSE;
UnmarkList: PROC[lp: listPtr] =
BEGIN
FOR p: listPtr ← lp, p.nxt WHILE p#NIL DO
UnmarkObject[p.ob];
ENDLOOP;
END;
UnmarkObject: PROC[ob: obPtr] =
BEGIN
ob.marked ← FALSE;
WITH dob: ob SELECT FROM
cell => UnmarkList[dob.ptr];
ENDCASE => NULL;
END;
ScanListForLayers: PROC [lp: listPtr] =
BEGIN
FOR p: listPtr ← lp, p.nxt WHILE p#NIL DO
ScanObjectForLayers[p.ob];
ENDLOOP;
END;
ScanObjectForLayers: PROC [ob: obPtr] =
BEGIN
IF NOT ob.marked THEN
BEGIN
ob.marked ← TRUE;
WITH dob: ob SELECT FROM
rect, wire =>
SELECT ob.l FROM
imp => hasNDepletion ← TRUE;
met2, cut2 => hasMetal2 ← TRUE;
pdif, nwel => hasCMOS ← TRUE;
bur => hasNBuriedContact ← TRUE;
ovg => hasPad ← TRUE;
ENDCASE => NULL;
cont =>
SELECT dob.typ FROM
burr => hasNBuriedContact ← TRUE;
nwell, mPDif => hasCMOS ← TRUE;
mmPDif => hasMetal2 ← hasCMOS ← TRUE;
mmDif, mmPol, mmButt => hasMetal2 ← TRUE;
ENDCASE => NULL;
xstr =>
BEGIN
IF dob.impl OR dob.pullup THEN hasNDepletion ← TRUE;
IF dob.l = pdif THEN hasCMOS ← TRUE;
END;
cell => ScanListForLayers[dob.ptr];
ENDCASE => NULL;
END;
END;
UnmarkList[masterList];
ScanListForLayers[masterList];
FOR mask: Masks IN Masks DO
state: ReticleStatePtr ← @maskStates[mask];
state↑ ← [
mask: mask,
block: uz.NEW[CoordRectBlock],
slice: NewFeaturePST[featureZ],
cover: NewFeaturePST[featureZ],
inReticleSet: (SELECT mask FROM
pad => hasPad AND NOT HeSaysYes[IF hasMetal2
THEN "Merge pad mask with via mask?"L
ELSE "Merge pad mask with cut mask?"L],
nBuriedContact => hasNBuriedContact,
via, metal2 => hasMetal2,
nWell, nImplant, pImplant => hasCMOS,
nDepletion => hasNDepletion,
thinOx, poly, cut, metal => TRUE,
ENDCASE => FALSE),
fieldPolarity: (SELECT mask FROM
thinOx, poly, metal, metal2 => transparent,
ENDCASE => opaque)
];
ENDLOOP;
SetStretches[];
Explain["Set non-standard stretches now if you wish."];
END; -- of InitMaskStates
FinishMask: PUBLIC PROCEDURE[state: ReticleStatePtr,
mask: Masks,
showMasks: BOOLEAN, screenClip: CoordRect] =
BEGIN OPEN ReticleBandFormat;
deltaY: DeltaY = LAST[DeltaY];
BandBlock: TYPE = CARDINAL[0..100];
overflowRects: ARRAY BandBlock OF CARDINAL ← ALL[0];
overflowBandsInDeltaY: BandBlock = 1+
((deltaY-2)/herald.bandHeight);
ScaleToReticle: PROCEDURE[x: Coord] RETURNS[ReticleUnit] =
INLINE
{RETURN[InlineDefs.LowHalf[x/coordsPerReticle]]};
NextYMin: PROCEDURE[y: ReticleUnit] =
BEGIN
WHILE thisBand+herald.bandHeight<=y DO
IF overflowRects[0]>0 THEN
FOR b: BandBlock IN (0..overflowBandsInDeltaY) DO
overflowRects[b-1] ← overflowRects[b];
ENDLOOP;
overflowRects[overflowBandsInDeltaY-1] ← 0;
thisBand ← thisBand+herald.bandHeight;
[] ← WriteBlock[stream: reticleFile, address: @endObject,
words: SIZE[EndObject]];
ENDLOOP;
END;
ClaimBands: PROCEDURE[y1, y2: ReticleUnit]
RETURNS[midY: ReticleUnit] =
BEGIN
-- We would like to have this rectangle cover the interval from
-- [y1..y2). Unfortunately two conditions could prevent this.
-- The first is that that interval could be larger than DeltaY.
-- The second is that we are only allowed to carry 1000
-- rectangles from one band to the next.
b: BandBlock ← 0;
NextYMin[y1];
y2 ← MIN[y2, y1+deltaY];
FOR midY ← thisBand+herald.bandHeight,
midY+herald.bandHeight WHILE midY<y2 AND
overflowRects[b]<1000 DO
overflowRects[b] ← overflowRects[b]+1;
b ← b+1;
ENDLOOP;
midY ← MIN[midY, y2];
END; -- of ClaimBands
WriteRect: PROCEDURE[r: CoordRect] =
BEGIN
retRect: ReticleRect ← [
x1: ScaleToReticle[r.x1],
x2: ScaleToReticle[r.x2],
y1: ScaleToReticle[r.y1],
y2: ScaleToReticle[r.y2]];
midX: ReticleUnit ← maxReticle.y-
ClaimBands[maxReticle.y-retRect.x2, maxReticle.y-retRect.x1];
IF retRect.x1<midX THEN
BEGIN -- save the remainder for later
InsertCoordRectPQ[pending, [x1: r.x1,
x2: r.x1+coordsPerReticle*(midX-retRect.x1),
y1: r.y1, y2: r.y2]];
retRect.x1 ← midX;
END;
-- Here, for the first time, we have to know exactly how the
-- design will be fabricated. The reticle generator insists that
-- its rectangles be in increasing order by min y, while at this
-- point our CoordRect's are in decreasing order of max x.
-- This is handled by a 90-degree rotation. The design suffers
-- a further mirroring because the reticle is written
-- emulsion-up but projected emulsion-down. This is handled
-- by mirroring the CoordRect's y axis.
object ← [
xmin: maxReticle.x-retRect.y2, -- mirror in y
deltaX: retRect.y2-retRect.y1,
ymin: (maxReticle.y-retRect.x2)-thisBand,
deltaY: retRect.x2-retRect.x1];
[] ← WriteBlock[stream: reticleFile, address: @object,
words: SIZE[Object]];
END; -- of WriteRect
WriteRectOnScreen: PROCEDURE[r: CoordRect] =
BEGIN
p1: Point ← ScalePointToChipmonk[[
x: MAX[r.x1, screenClip.x1],
y: MAX[r.y1, screenClip.y1]]];
p2: Point ← ScalePointToChipmonk[[
x: MIN[r.x2, screenClip.x2],
y: MIN[r.y2, screenClip.y2]]];
IF p1.x<p2.x AND p1.y<p2.y THEN
masterList ← insertList[mp: masterList,
lp: makeList[
p: makeRect[x: p2.x-p1.x, y: p2.y-p1.y, l: met],
x: p1.x, y: p1.y, o: 0, refl: 0]];
END; -- of WriteRectOnScreen
RecoverOriginalMasterList: PROCEDURE[] =
BEGIN
IF showMasks THEN
BEGIN
flushDel[masterList];
masterList ← originalMasterList;
dChange ← TRUE
END;
END; -- of RecoverOriginalMasterList
object: Object ← [];
endObject: EndObject ← [];
maxReticle: ReticlePoint ← [
x: 16*herald.bandWidth-1,
y: herald.bandCount*herald.bandHeight-1];
reticleFile, reticleRectFile: DiskHandle ← NIL;
pending: CoordRectPQHandle ← NewCoordRectPQ[uz];
thisBand: ReticleUnit ← 0; -- increases by herald.bandHeight
name: STRING ← [50];
originalMasterList: listPtr ← masterList;
IF state.fieldPolarity=transparent AND
state.designAreaStarted AND
NOT state.designAreaFinished THEN
BEGIN -- finish complemented polarity region
FinishTransparentFeature[state: state, x: state.fieldRect.x2,
y: [state.fieldRect.y1, state.fieldRect.y2]];
state.designAreaFinished ← TRUE;
END;
IF state.file#NIL THEN
{TruncateDiskStream[state.file]; state.file ← NIL};
name.length ← 0;
AppendString[to: name, from: reticleName];
AppendChar[name, '-];
AppendString[to: name, from: levelNames[mask]];
AppendString[to: name, from: ".reticle"];
reticleFile ← NewWordStream[name, WriteAppend];
[] ← WriteBlock[stream: reticleFile, address: @herald,
words: SIZE[HeraldObject]];
BEGIN ENABLE UNWIND => RecoverOriginalMasterList[];
IF showMasks THEN
BEGIN
p1: Point ←
ScalePointToChipmonk[[x: screenClip.x1, y: screenClip.y1]];
p2: Point ←
ScalePointToChipmonk[[x: screenClip.x2, y: screenClip.y2]];
masterList ← makeList[
p: makeCell[sx: p2.x-p1.x, sy: p2.y-p1.y, cnt: 0, ptr: NIL],
x: p1.x, y: p1.y, o: 0, refl: 0];
masterList.selected ← TRUE;
END;
FOR i: LONG INTEGER
DECREASING IN [0..state.rectCount) DO
r: CoordRect;
IF ((i+1) MOD RectsPerBlock)=0 THEN
BEGIN
block: CoordRectBlock;
IF reticleRectFile=NIL THEN
reticleRectFile ← NewWordStream[
TempFileName[name, mask], ReadWrite];
SetPosition[stream: reticleRectFile,
pos: (i/RectsPerBlock)*2*SIZE[CoordRectBlock]];
-- pos is in bytes, first byte is 0
[] ← ReadBlock[stream: reticleRectFile, address: @block,
words: SIZE[CoordRectBlock]];
state.block↑ ← block;
END;
r ← state.block[InlineDefs.LowHalf[i MOD RectsPerBlock]];
WHILE CoordRectPQSize[pending]>0 AND
r.x2<=CoordRectPQMin[pending].x2 DO
WriteRect[ExtractCoordRectPQ[pending]];
ENDLOOP;
WriteRect[r];
IF showMasks THEN WriteRectOnScreen[r];
ENDLOOP;
WHILE CoordRectPQSize[pending]>0 DO
WriteRect[ExtractCoordRectPQ[pending]];
ENDLOOP;
IF showMasks THEN
BEGIN
dChange ← TRUE;
Explain[levelNames[mask], "(clipped mask)"L];
END;
END;
RecoverOriginalMasterList[];
NextYMin[maxReticle.y];
[] ← WriteBlock[stream: reticleFile, address: @endObject,
words: SIZE[EndObject]];
TruncateDiskStream[reticleFile];
IF reticleRectFile#NIL THEN
BEGIN
reticleRectFile.reset[reticleRectFile]; -- free up its disk space
TruncateDiskStream[reticleRectFile];
reticleRectFile ← NIL;
END;
pending ← DestroyCoordRectPQ[pending];
END; -- of FinishMask
WriteCoordRect: PUBLIC PROCEDURE[mask: Masks, r: CoordRect] =
BEGIN -- called in order of increasing r.x2
state: ReticleStatePtr ← @maskStates[mask];
IF state.inReticleSet AND r.x1<r.x2 AND r.y1<r.y2 THEN
BEGIN OPEN InlineDefs;
state.block[InlineDefs.LowHalf[
state.rectCount MOD RectsPerBlock]] ← r;
IF state.rectCount>0 AND r.x2<state.lastRect.x2 THEN
BEGIN
ChipUserInt.RemarkAtPoint[RefCoordPt[state.lastRect],
"Either this rectangle..."L];
ChipUserInt.DebugAtPoint[RefCoordPt[r],
"... or this one is out of order in x2."L];
END;
state.lastRect ← r;
state.rectCount ← state.rectCount+1;
IF (state.rectCount MOD RectsPerBlock)=0 THEN
BEGIN
block: CoordRectBlock ← state.block↑;
IF state.file=NIL THEN
BEGIN
name: STRING ← [50];
state.file ← NewWordStream[TempFileName[name, mask],
WriteAppend];
END;
[] ← WriteBlock[stream: state.file, address: @block,
words: SIZE[CoordRectBlock]];
END;
END;
END; -- of WriteCoordRect
TempFileName: PROCEDURE[name: STRING, mask: Masks]
RETURNS[STRING] =
BEGIN
name.length ← 0;
AppendString[to: name, from: "temp-"];
AppendString[to: name, from: levelNames[mask]];
AppendString[to: name, from: ".rects"];
RETURN[name];
END; -- TempFileName
NoteFeature: PUBLIC PROCEDURE[state: ReticleStatePtr,
f: FeaturePtr] =
BEGIN
IF state.inReticleSet THEN
-- There are two possibilities here. The first is that
-- we are outside the "aligned design" or we are inside
-- the aligned design but working on an opaque fieldPolarity
-- mask. In this case we output a cover on the features.
-- Otherwise we output a cover on the complement of
-- the features.
BEGIN
IF state.fieldPolarity=opaque THEN
StartTransparentFeature[state: state, x: f.cover.x1,
y: [f.cover.y1, f.cover.y2]]
ELSE -- must complement polarity of design area
BEGIN
CheckDesignBoundary[state: state, x: f.cover.x1];
SELECT TRUE FROM
NOT state.designAreaStarted,
state.designAreaFinished,
f.cover.y2<=state.fieldRect.y1,
state.fieldRect.y2<=f.cover.y1 =>
StartTransparentFeature[state: state, x: f.cover.x1,
y: [f.cover.y1, f.cover.y2]];
ENDCASE => -- complemented polarity region
StartOpaqueFeature[state: state, x: f.cover.x1,
y: [f.cover.y1, f.cover.y2]];
END;
END;
InsertFeaturePST[p: state.slice, item: f];
END; -- of NoteFeature
ForgetFeature: PUBLIC PROCEDURE[state: ReticleStatePtr,
f: FeaturePtr] =
BEGIN
DeleteFeaturePST[p: state.slice, item: f];
IF NOT state.inReticleSet THEN RETURN;
-- There are the same two possibilities here.
IF state.fieldPolarity=opaque THEN
FinishTransparentFeature[state: state, x: f.cover.x2,
y: [f.cover.y1, f.cover.y2]]
ELSE
BEGIN
CheckDesignBoundary[state: state, x: f.cover.x2];
SELECT TRUE FROM
NOT state.designAreaStarted,
state.designAreaFinished,
f.cover.y2<=state.fieldRect.y1,
state.fieldRect.y2<=f.cover.y1 =>
FinishTransparentFeature[state: state, x: f.cover.x2,
y: [f.cover.y1, f.cover.y2]];
ENDCASE => -- complemented polarity region
FinishOpaqueFeature[state: state, x: f.cover.x2,
y: [f.cover.y1, f.cover.y2]];
END;
END; -- of ForgetFeature
CheckDesignBoundary: PROCEDURE[state: ReticleStatePtr,
x: Coord] =
BEGIN -- only for fieldPolarity=transparent
IF state.fieldRect.x1<=x AND
NOT state.designAreaStarted THEN
BEGIN -- start complemented polarity region
StartTransparentFeature[state: state, x: state.fieldRect.x1,
y: [state.fieldRect.y1, state.fieldRect.y2]];
state.designAreaStarted ← TRUE;
END;
IF state.fieldRect.x2<x AND
NOT state.designAreaFinished THEN
BEGIN -- finish complemented polarity region
FinishTransparentFeature[state: state, x: state.fieldRect.x2,
y: [state.fieldRect.y1, state.fieldRect.y2]];
state.designAreaFinished ← TRUE;
END;
END; -- of CheckDesignBoundary
StartTransparentFeature: PROCEDURE[state: ReticleStatePtr, x: Coord,
y: Interval] =
BEGIN
-- cover is transparent, slice is transparent,
-- so cover is union of slice
minField: Interval ← MinField[p: state.cover, y: y];
IF minField.min<minField.max THEN
BEGIN
coverInt: Interval ← TerminateCover[p: state.cover, x: x,
y: minField, mask: state.mask];
InsertFeaturePST[p: state.cover,
item: NewReticleFeature[
cover: [x1: x, x2: 0 -- not used --,
y1: coverInt.min, y2: coverInt.max], mask: state.mask]];
END;
END; -- of StartTransparentFeature
StartOpaqueFeature: PROCEDURE[state: ReticleStatePtr, x: Coord,
y: Interval] =
BEGIN
-- cover is transparent, slice is opaque,
-- so cover is complement of union of slice
coverInt: Interval ← TerminateCover[p: state.cover, x: x, y: y,
mask: state.mask];
IF coverInt.min<y.min THEN
InsertFeaturePST[p: state.cover,
item: NewReticleFeature[
cover: [x1: x, x2: 0 -- not used --,
y1: coverInt.min, y2: y.min], mask: state.mask]];
IF y.max<coverInt.max THEN
InsertFeaturePST[p: state.cover,
item: NewReticleFeature[
cover: [x1: x, x2: 0 -- not used --,
y1: y.max, y2: coverInt.max], mask: state.mask]];
END; -- of StartOpaqueFeature
FinishTransparentFeature: PROCEDURE[state: ReticleStatePtr, x: Coord,
y: Interval] =
BEGIN
-- cover is transparent, slice is transparent,
-- so cover is union of slice
minField: Interval ← MinField[p: state.slice, y: y];
IF minField.min<minField.max THEN
BEGIN
RenewFeatureCover: PROCEDURE[int: Interval,
repItem: FeaturePtr] =
BEGIN
InsertFeaturePST[p: state.cover,
item: NewReticleFeature[
cover: [x1: x, x2: 0 -- not used --,
y1: int.min, y2: int.max], mask: state.mask]];
END; -- of RenewFeatureCover
coverInt: Interval ← TerminateCover[p: state.cover,
x: x, y: minField, mask: state.mask];
ClassifyFeaturePSTInterval[p: state.slice, int: coverInt,
covered: RenewFeatureCover, gap: ReticleNullGap];
END;
END; -- of FinishTransparentFeature
FinishOpaqueFeature: PROCEDURE[state: ReticleStatePtr, x: Coord,
y: Interval] =
BEGIN
-- cover is transparent, slice is opaque,
-- so cover is complement of union of slice
RenewFieldCover: PROCEDURE[int: Interval] =
BEGIN
InsertFeaturePST[p: state.cover,
item: NewReticleFeature[
cover: [x1: x, x2: 0 -- not used --,
y1: int.min, y2: int.max], mask: state.mask]];
END; -- of RenewFieldCover
coverInt: Interval ← TerminateCover[p: state.cover, x: x, y: y,
mask: state.mask];
ClassifyFeaturePSTInterval[p: state.slice, int: coverInt,
covered: ReticleNullCover, gap: RenewFieldCover];
END; -- of FinishOpaqueFeature
MinField: PROCEDURE[p: FeaturePSTHandle, y: Interval]
RETURNS[Interval] =
BEGIN
minField: Interval ← y;
ReduceField: PROCEDURE[int: Interval, repItem: FeaturePtr] =
BEGIN
SELECT TRUE FROM
int.min=y.min => minField.min ← int.max;
int.max=y.max => minField.max ← int.min;
ENDCASE => NULL;
END; -- of ReduceField
ClassifyFeaturePSTInterval[p: p, int: y,
covered: ReduceField, gap: ReticleNullGap];
RETURN[minField];
END; -- of MinField
TerminateCover: PROCEDURE[p: FeaturePSTHandle, x: Coord,
y: Interval, mask: Masks] RETURNS[Interval] =
BEGIN
TouchedFeatureList: TYPE = LONG POINTER TO
TouchedFeature ← NIL;
TouchedFeature: TYPE = RECORD[
next: TouchedFeatureList,
f: FeaturePtr];
list: TouchedFeatureList ← NIL;
int: Interval ← y;
TouchFeature: PROCEDURE[item: FeaturePtr] =
BEGIN
list ← uz.NEW[TouchedFeature ← [next: list, f: item]];
int ← [MIN[int.min, item.cover.y1],
MAX[int.max, item.cover.y2]];
END; -- of TouchFeature
SearchFeaturePST[p: p, int: y, touch: TouchFeature];
WHILE list#NIL DO
t: TouchedFeatureList ← list.next;
WriteCoordRect[mask: mask,
r: [x1: list.f.cover.x1, x2: x,
y1: list.f.cover.y1, y2: list.f.cover.y2]];
DeleteFeaturePST[p: p, item: list.f];
list.f ← ChipFeature.DestroyFeature[list.f];
uz.FREE[@list];
list ← t;
ENDLOOP;
RETURN[int];
END; -- of TerminateCover
ReticleNullCover: PROCEDURE[int: Interval, repItem: FeaturePtr] =
{NULL};
ReticleNullGap: PROCEDURE[int: Interval] = {NULL};
END. -- of ChipReticleImpl2