EBESMaskImpl:
CEDAR
PROGRAM
IMPORTS Ascii, Atom, BasicTime, CD, CDCommandOps, CDBasics, CDMenus, CDOps, CDProperties, CDSequencer, CDViewer, CornerStitching, FS, IO, List, Process, Rope, TerminalIO
EXPORTS =
BEGIN
Basic Types
Nm: TYPE = CD.Number;
EBESPixels: TYPE = CD.Number;
EBESRect: TYPE = CD.Rect;
Rational: TYPE = RECORD [num, denom: INT ← 1];
ROPE: TYPE = Rope.ROPE;
Tesselation: TYPE = REF CornerStitching.Tesselation;
TessList: TYPE = LIST OF Tesselation;
Maskmaking State Record
MaskState: TYPE = REF MaskStateRec;
MaskStateRec:
TYPE =
RECORD [
design: CD.Design,
nmPerLambda: INT ← 1000,
designClip: REF CD.DesignRect ← NIL,
designStripeClip: CD.Rect ← [0,0,0,0],
maskSetName, patternFileName: ROPE ← NIL,
maskSetSpec: MaskSetSpec ← NIL,
s: IO.STREAM, -- EBES stream where rectangles are to be drawn
scale: Rational,
drawCommand: REF DrawRectangle,
stripeClip: EBESRect ← [0,0,0,0],
reticleClip: EBESRect ← [0,0,0,0],
stripe: [0..maxStripes] ← 0,
stripeRectCount: INT ← 0,
scribe: Scribe,
data: REF ← NIL
];
Mask Set Specifications
MaskSetSpec: TYPE = LIST OF REF ANY -- MaskSpec -- ;
MaskSpec: TYPE = REF MaskSpecRec;
MaskSpecRec: TYPE = RECORD [ name: ROPE, cover: CoverSpec ];
Cover Specifications (which points on the mask are covered)
CoverSpec: TYPE = REF ANY -- Atom ($NOT, $AND, $OR) followed by list of Coverspec, CDLayer, Scribe, Enlarge -- ;
... for example, LIST[$OR, NEW[CDLayerRec ← [source: %CMos.ndif, deltaDiameter: 1000 -- nm --]], NEW[CDLayerRec ← [source: %CMos.pdif, deltaDiameter: 1000 -- nm --]], NEW[CDLayerRec ← [source: %CMos.pwelCont, deltaDiameter: 1000 -- nm --]], NEW[CDLayerRec ← [source: %CMos.nwelCont, deltaDiameter: 1000 -- nm --]], NEW[ScribeRec ← [dieEdgeToLineCenter: 0, lineWidth: 110000 -- nm --]]]]
Enlarge: TYPE = REF EnlargeRec ← NIL;
EnlargeRec:
TYPE =
RECORD [
basis: CoverSpec,
deltaDiameter: Nm ← 0
];
CDLayer: TYPE = REF CDLayerRec ← NIL;
CDLayerRec:
TYPE =
RECORD [
source: CD.Layer,
deltaDiameter: Nm ← 0 -- + means mask feature is bigger than layer feature
];
Scribe: TYPE = REF ScribeRec ← NIL;
ScribeRec:
TYPE =
RECORD [
dieEdgeToLineCenter, lineWidth: Nm ← 0
];
EBES Command Formats
stripeHeight: INT = 256; -- in EBES units
maxStripes: INT = 255;
maskHeight: INT = maxStripes*stripeHeight;
maskWidth: INT = 32768;
StartDrawing:
TYPE =
MACHINE
DEPENDENT
RECORD [
nFields (0: 0..7): [0..256) ← 2,
addressCode (0: 8..15): AddressCode ← Nm500,
cx (1): CARDINAL[0..maskWidth], -- 0 is illegal
cy (2): CARDINAL[0..maskHeight], -- 0 is illegal
moDayYr (3): Date,
field1Size (6): CARDINAL ← 6,
patternFileName (7): FileName,
field2Size (13): CARDINAL ← 2,
maskInfo (14): PACKED ARRAY [0..4) OF CHAR ← ALL[' ]
];
AddressCode: TYPE = MACHINE DEPENDENT {Nm1000(0), Nm500(3), Nm250(6)};
Date:
TYPE =
PACKED
ARRAY [0..6)
OF
CHAR ←
ALL[' ];
month [01..12], day [01..31], year [00..99]
FileName:
TYPE =
PACKED
ARRAY [0..12)
OF
CHAR ←
ALL[' ];
[9] must be '. , [10] is column ['A..'Z], [11] is row ['A..'Z]
DrawRectangle:
TYPE =
MACHINE
DEPENDENT
RECORD [
h (0: 0..9): [1..stripeHeight], -- Mesa biases subrange so 1 is represented as 0
commandCode (0: 10..15): [0..64) ← 16,
w (1): CARDINAL[0..maskWidth], -- 0 is illegal
x (2): CARDINAL[0..maskWidth),
unused (3: 0..7): [0..256) ← 0,
y (3: 8..15): [0..stripeHeight)];
StartStripe:
TYPE =
MACHINE
DEPENDENT
RECORD [
stripeNumber (0: 0..7): [0..maxStripes] ← 0, -- 0 is illegal
commandCode (0: 8..15): [0..256) ← 7];
BasicCommand: TYPE = MACHINE DEPENDENT RECORD [commandCode (0): NAT ←];
endStripe: BasicCommand = [commandCode: 8];
endRecord: BasicCommand = [commandCode: 9];
endDrawing: BasicCommand = [commandCode: 4];
Global Variables
nmPerEBESPixel: INT ← 250;
stripesPerClump: INT ← 10;
wDir: ROPE ← "///";
Init:
PROC ~ {
Atom.PutProp[$EBESOpProcs, $RestrictNImplant, NEW[CoverProc ← RestrictNImplant]];
CDSequencer.ImplementCommand[a~$EBESMask , p~StartEBESMask, queue~doQueue];
CDMenus.CreateEntry[menu~$ProgramMenu, entry~"EBES mask generation", key~$EBESMask];
TerminalIO.WriteRope["ChipNDale EBES mask generator loaded\n"];
};
abortFlag: REF BOOL ← NEW[BOOL];
StartEBESMask:
PROC [comm: CDSequencer.Command] =
TRUSTED BEGIN
TerminalIO.WriteRope[" EBES-mask generation\n"];
TerminalIO.WriteRope[" not yet debugged\n"];
TerminalIO.WriteRope["Releases lock of design, but design MUST NOT be changed\n"];
abortFlag^ ← FALSE;
[] ← CDCommandOps.CallWithResource[proc: EBESMask, comm: comm, resource: $EBESMask, abortFlag: abortFlag];
END;
EBESMask:
PROC [ comm: CDSequencer.Command ] =
BEGIN
NotePunt: PROC = {TerminalIO.WriteRope[IO.PutFR["\n*** EBES mask generation aborted at %g\n", IO.time[]]]};
BEGIN
ENABLE
BEGIN
ABORTED => GOTO Punt;
TerminalIO.UserAbort => GOTO Punt;
UNWIND => NotePunt[];
END;
MakeMask[comm: comm, streamGen: SimpleStreamGen];
IF abortFlag^ THEN NotePunt[];
EXITS Punt => NotePunt[];
END;
END;
SimpleStreamGen:
PROC [ ms: MaskState ]
RETURNS [ dest:
IO.
STREAM ] =
BEGIN
dest ←
FS.StreamOpen[
fileName:
IO.PutFR[format: "%g%g/%g",
v1: IO.rope[wDir], v2: IO.rope[ms.maskSetName], v3: IO.rope[ms.patternFileName]
],
accessOptions: create
];
END;
MakeMask:
PROC [comm: CDSequencer.Command,
streamGen: PROC [ ms: MaskState ] RETURNS [ dest: IO.STREAM ],
data: REF ← NIL ] =
BEGIN
Prop:
PROC [prop:
REF, default:
REF ←
NIL, nilOK:
BOOL ←
FALSE]
RETURNS [value:
REF] =
BEGIN
value ← CDProperties.GetPropFromDesign[ms.design, prop];
IF value = NIL THEN value ← CDProperties.GetPropFromTechnology[ms.design.technology, prop];
IF value = NIL THEN value ← CDProperties.GetPropFromAtom[$EBESMask, prop];
IF value = NIL THEN value ← default;
IF value =
NIL
AND
NOT nilOK
THEN
BEGIN
TerminalIO.WriteRope[IO.PutFR[" .. no value for property %g.. ", IO.rope[ToRope[prop]]]];
ERROR TerminalIO.UserAbort;
END;
END;
NumericProp:
PROC [prop:
REF, default:
REF ←
NIL]
RETURNS [value:
INT] =
{value ← NARROW[Prop[prop], REF INT]^};
ms: MaskState =
NEW[ MaskStateRec ← [
design: comm.design,
drawCommand: NEW[DrawRectangle],
data: data]];
dr: CD.DrawRef;
ebesSize: CD.Position;
ebesActiveToScribeCenter: EBESPixels;
maxBloat: EBESPixels ← NumericProp[$CDxEBESNmMaxBloat, NEW[Nm ← 10000]]/nmPerEBESPixel;
TRUSTED {Process.SetPriority[Process.priorityBackground]};
TerminalIO.WriteRope[IO.PutFR["\nEBES Mask Generation\nPreliminary analysis begun at %g.\n", IO.time[]]];
nmPerEBESPixel ← NumericProp[$CDxEBESNmPerEBESPixel];
ms.nmPerLambda ← NumericProp[$CDxEBESNmPerLambda];
ms.maskSetName ← ToRope[Prop[$CDxEBESMaskSetName]];
ms.maskSetSpec ← NARROW[Prop[$CDxEBESMaskSetSpec]];
ms.scale ← ReduceRational[[num: ms.nmPerLambda, denom: CD.lambda*nmPerEBESPixel]];
ebesSize.x ← NumericProp[$CDxEBESXNmPerDie]/nmPerEBESPixel;
ebesSize.y ← NumericProp[$CDxEBESYNmPerDie]/nmPerEBESPixel;
ebesActiveToScribeCenter ← NumericProp[$CDxEBESActiveToScribeCenter]/nmPerEBESPixel;
dr ← CD.CreateDrawRef[ms.design];
dr.minimalSize ← 0;
dr.interestClip ← CDBasics.universe;
dr.stopFlag ← abortFlag;
dr.drawRect ← dr.saveRect ← NoteLayer;
dr.devicePrivate ← ms;
CDOps.DrawDesign[ms.design, dr]; -- measure design
IF
NOT abortFlag^
THEN
BEGIN
ENABLE
-- for ERRORs
BEGIN
UNWIND => ms.s ← AbortFile[ms.s];
END;
ComputeReticleClip:
PROC
RETURNS [c: EBESRect] =
BEGIN
AdjustReticleSize:
PROC [coord:
ROPE, z1, z2, zSize: EBESPixels]
RETURNS [newZ1, newZ2: EBESPixels] =
BEGIN
IF z2-z1 > zSize
THEN
{TerminalIO.WriteRope[IO.PutFR[" .. design %g size of %d EBES units is larger than allowed die size of %d EBES units ..", IO.rope[coord], IO.int[c.x2-c.x1+1], IO.int[zSize]]];
ERROR TerminalIO.UserAbort};
newZ1 ← (z1+z2-zSize)/2;
newZ2 ← newZ1+zSize;
END;
c ← CDBasics.Extend[Bloat[ScaleCDToEBES[ms, ms.designClip^], maxBloat], ebesActiveToScribeCenter];
[c.x1, c.x2] ← AdjustReticleSize["x", c.x1, c.x2, ebesSize.x];
[c.y1, c.y2] ← AdjustReticleSize["y", c.y1, c.y2, ebesSize.y];
END;
today: Date = Today[];
reticleClip: EBESRect ← ms.reticleClip ← ComputeReticleClip[];
nRows: NAT = Ceiling[[num: reticleClip.y2-reticleClip.y1, denom: maskHeight]];
nCols: NAT = Ceiling[[num: reticleClip.x2-reticleClip.x1, denom: maskWidth]];
maskCount: INT;
TRUSTED {maskCount ← List.Length[LOOPHOLE[ms.maskSetSpec]]};
TerminalIO.WriteRope[IO.PutFR["Preliminary analysis finished at %g. Making %d masks at %d (x) x %d (y) EBES pixels.\n", IO.time[], IO.int[maskCount], IO.int[reticleClip.x2-reticleClip.x1], IO.int[reticleClip.y2-reticleClip.y1]]];
WriteTapeDirectory[streamGen, ms, nRows, nCols, today];
FOR m:
LIST
OF
REF
ANY ← ms.maskSetSpec, m.rest
WHILE m#
NIL
DO
maskSpec: MaskSpec = NARROW[m.first];
FOR col:
NAT
IN [0..nCols)
DO
FOR row:
NAT
IN [0..nRows)
DO
ms.patternFileName ← PatternFileName[maskSetName: ms.maskSetName,
maskName: maskSpec.name, row: row, col: col];
ms.s ← EBESOpen[streamGen[ms]];
TerminalIO.WriteRope[IO.PutFR["\nStarting mask %g at %g ", IO.rope[ms.patternFileName], IO.time[]]];
SendCommand[s: ms.s, comm:
NEW[StartDrawing ← [
patternFileName: RopeToFileName[ms.patternFileName],
cx: MIN[maskWidth, reticleClip.x2-reticleClip.x1-col*maskWidth],
cy: MIN[maskHeight, reticleClip.y2-reticleClip.y1-row*maskHeight],
moDayYr: today,
addressCode: (
SELECT nmPerEBESPixel
FROM
1000 => Nm1000,
500 => Nm500,
250 => Nm250,
ENDCASE => Nm500)]]];
FOR stripeBase:
INT
-- [0..maxStripes) -- 𡤀, stripeBase+stripesPerClump
WHILE stripeBase <
MIN[maxStripes, Ceiling[[num: reticleClip.y2-reticleClip.y1-maskHeight*row, denom: stripeHeight]]]
DO
rects: Tesselation ← NIL;
IF abortFlag^
THEN
GOTO AbortMask;
ms.designStripeClip ← ScaleEBESToCD[ms, [
x1: ms.reticleClip.x1+col*maskWidth-1,
y1: ms.reticleClip.y1+row*maskHeight+stripeBase*stripeHeight-1,
x2: ms.reticleClip.x1+(col+1)*maskWidth+1,
y2: ms.reticleClip.y1+row*maskHeight+(stripeBase+stripesPerClump)*stripeHeight+1
]];
CDViewer.ShowArrow[
design: ms.design, pos: CDBasics.Center[ms.designStripeClip]];
.. keep user happy
rects ← GenerateCover[ms, maskSpec.cover];
FOR stripe:
INT
-- [0..maxStripes) --
IN [stripeBase..
MIN[stripeBase+stripesPerClump, maxStripes, Ceiling[[num: reticleClip.y2-reticleClip.y1-maskHeight*row, denom: stripeHeight]]])
DO
ms.stripeClip ← CDBasics.Intersection[ms.reticleClip, [
x1: ms.reticleClip.x1+col*maskWidth,
y1: ms.reticleClip.y1+row*maskHeight+stripe*stripeHeight,
x2: ms.reticleClip.x1+(col+1)*maskWidth,
y2: ms.reticleClip.y1+row*maskHeight+(stripe+1)*stripeHeight
]];
ms.stripeRectCount ← 0;
SendCommand[s: ms.s, comm: NEW[StartStripe ← [stripeNumber: stripe+1]]];
[] ← rects.EnumerateArea[rect: ms.stripeClip,
perTile: OutputTile, data: ms];
SendCommand[s: ms.s, comm: NEW[BasicCommand ← endStripe]];
TerminalIO.WriteRope[IO.PutFR[".%d", IO.int[ms.stripeRectCount]]]; -- end of stripe
ENDLOOP;
rects ← DisposeTesselation[rects];
ENDLOOP;
SendCommand[s: ms.s, comm: NEW[BasicCommand ← endDrawing]];
ms.s.Close[];
ms.s ← NIL;
ENDLOOP;
ENDLOOP;
ENDLOOP;
TerminalIO.WriteRope[IO.PutFR["\nEBES mask generation finished at %g\n", IO.time[]]];
EXITS
AbortMask => {ms.s ← AbortFile[ms.s]};
END;
END;
NoteLayer:
PROC [ r:
CD.DesignRect, l:
CD.Layer, pr:
CD.DrawRef ] =
BEGIN
ms: MaskState = NARROW[pr.devicePrivate];
IF abortFlag^ THEN ERROR TerminalIO.UserAbort;
IF ms.designClip=NIL THEN ms.designClip ← NEW[CD.DesignRect ← r];
ms.designClip^ ← CDBasics.Surround[ms.designClip^, r];
END;
NewTesselation:
PROC [ initValue:
REF ←
NIL ]
RETURNS [ tess: Tesselation ] =
BEGIN
tess ← CornerStitching.NewTesselation[];
tess.ChangeRect[CDBasics.universe, initValue];
END;
DisposeTesselation:
PROC [ tess: Tesselation ]
RETURNS [ Tesselation ] =
BEGIN
CornerStitching.FreeTesselation[plane: tess, freeCache: FALSE];
RETURN[NIL];
END;
CoverProc: TYPE = PROC [ ms: MaskState, spec: LIST OF REF ANY, extInfluenceDiameter: Nm ← 0 ] RETURNS [ result: Tesselation ];
GenerateCover:
PROC [ ms: MaskState, spec: CoverSpec, extInfluenceDiameter: Nm ← 0 ]
RETURNS [ rects: Tesselation ] =
BEGIN
WITH spec
SELECT
FROM
list:
LIST
OF
REF
ANY =>
BEGIN
atom: ATOM = NARROW[list.first];
SELECT atom
FROM
$NOT =>
BEGIN
ComplementTile:
PROC [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
{rects.ChangeRect[CDBasics.Intersection[CDBasics.universe, tile.Area], $covered]};
basis: Tesselation ← GenerateCover[ms, list.rest.first, extInfluenceDiameter];
rects ← NewTesselation[NIL];
[] ← basis.EnumerateArea[rect: CDBasics.universe, perTile: ComplementTile, backgroundValue: $covered];
basis ← DisposeTesselation[basis];
END;
$AND =>
BEGIN
NilTile:
PROC [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
{rects.ChangeRect[tile.Area, NIL]};
rects ← GenerateCover[ms, list.rest.first, extInfluenceDiameter];
FOR rest:
LIST
OF
REF
ANY ← list.rest.rest, rest.rest
WHILE rest #
NIL
DO
term: Tesselation ← GenerateCover[ms, rest.first, extInfluenceDiameter];
[] ← term.EnumerateArea[rect: CDBasics.universe, perTile: NilTile, backgroundValue: $covered];
term ← DisposeTesselation[term];
ENDLOOP;
END;
$OR =>
BEGIN
CoverTile:
PROC [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
{rects.ChangeRect[tile.Area, $covered]};
rects ← GenerateCover[ms, list.rest.first, extInfluenceDiameter];
FOR rest:
LIST
OF
REF
ANY ← list.rest.rest, rest.rest
WHILE rest #
NIL
DO
term: Tesselation ← GenerateCover[ms, rest.first, extInfluenceDiameter];
[] ← term.EnumerateArea[rect: CDBasics.universe, perTile: CoverTile];
term ← DisposeTesselation[term];
ENDLOOP;
END;
ENDCASE =>
-- atom has a procedure registered for it
BEGIN
(e.g., LIST[$Bletch, NEW[INT ← 2], NEW[CDLayer ← []], NEW[CDLayer ← []]] )
ref: REF ANY = Atom.GetProp[$EBESOpProcs, atom];
rects ← NARROW[ref, REF CoverProc]^[ms, list.rest, extInfluenceDiameter];
END;
enlarge: Enlarge =>
BEGIN
deltaDiameter: EBESPixels = enlarge.deltaDiameter/nmPerEBESPixel;
basis: Tesselation ← GenerateCover[ms, enlarge.basis, extInfluenceDiameter+enlarge.deltaDiameter];
SELECT deltaDiameter
FROM
<0 => ERROR;
=0 => rects ← basis;
ENDCASE =>
BEGIN
EnlargeTile:
PROC [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
{rects.ChangeRect[Bloat[tile.Area, deltaDiameter], tile.Value]};
rects ← NewTesselation[NIL];
[] ← basis.EnumerateArea[rect: CDBasics.universe, perTile: EnlargeTile];
basis ← DisposeTesselation[basis];
END;
END;
layer: CDLayer =>
SELECT layer.deltaDiameter
FROM
>=0 =>
BEGIN
dr: CD.DrawRef;
deltaDiameter: EBESPixels = layer.deltaDiameter/nmPerEBESPixel;
rects ← NewTesselation[NIL];
dr ← CD.CreateDrawRef[ms.design];
dr.minimalSize ← 0;
dr.stopFlag ← abortFlag;
dr.interestClip ← Bloat[ms.designStripeClip, MIN[(CD.lambda*(extInfluenceDiameter+layer.deltaDiameter))/ms.nmPerLambda, 0]];
dr.drawRect ← dr.saveRect ← IncludeRectangle;
dr.devicePrivate ←
NEW[DrawInfoRec ← [layer: layer.source, deltaDiameter: deltaDiameter, rects: rects, ms: ms]];
CDOps.DrawDesign[ms.design, dr]; -- enumerate design rectangles into rects
END;
ENDCASE => rects ← GenerateCover[ms,
LIST[$NOT, NEW[EnlargeRec ← [basis: LIST[$NOT, NEW[CDLayerRec ← [source: layer.source]]], deltaDiameter: -layer.deltaDiameter]]],
extInfluenceDiameter];
scribe: Scribe =>
BEGIN
r: CD.Rect = ms.reticleClip;
outer: EBESPixels = MAX[scribe.dieEdgeToLineCenter-scribe.lineWidth/2, 0]/nmPerEBESPixel;
inner: EBESPixels = (scribe.dieEdgeToLineCenter+scribe.lineWidth/2)/nmPerEBESPixel;
rects ← NewTesselation[NIL];
rects.ChangeRect[[x1: r.x1+outer, y1: r.y1+outer, x2: r.x1+inner, y2: r.y2-outer], $covered];
rects.ChangeRect[[x1: r.x2-inner, y1: r.y1+outer, x2: r.x2-outer, y2: r.y2-outer], $covered];
rects.ChangeRect[[x1: r.x1+outer, y1: r.y1+outer, x2: r.x2-outer, y2: r.y1+inner], $covered];
rects.ChangeRect[[x1: r.x1+outer, y1: r.y2-inner, x2: r.x2-outer, y2: r.y2-outer], $covered];
END;
ENDCASE => ERROR;
END;
DrawInfo: TYPE = REF DrawInfoRec;
DrawInfoRec: TYPE = RECORD [ layer: CD.Layer, deltaDiameter: EBESPixels, rects: Tesselation, ms: MaskState ];
IncludeRectangle:
PROC [ r:
CD.DesignRect, l:
CD.Layer, pr:
CD.DrawRef ] =
BEGIN
di: DrawInfo = NARROW[pr.devicePrivate];
IF l = di.layer
AND CDBasics.NonEmpty[r]
THEN
BEGIN
er: CD.Rect ← ScaleCDToEBES[ms: di.ms, cdr: r];
IF di.deltaDiameter#0 THEN er ← Bloat[er, di.deltaDiameter];
di.rects.ChangeRect[rect: er, newValue: $covered];
END;
END;
RestrictNImplant:
PROC [ ms: MaskState, spec:
LIST
OF
REF
ANY, extInfluenceDiameter: Nm ← 0 ]
RETURNS [ result: Tesselation ]
-- CoverProc -- =
BEGIN
PlaceNImplant:
PROCEDURE [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
BEGIN
InteractWithPImplant:
PROCEDURE [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
BEGIN
Relationship: TYPE = {pNn, pEn, pSn, pWn};
pTile: CornerStitching.TilePtr = tile;
pTileArea: EBESRect = pTile.Area;
bestDir: Relationship;
bestGap: EBESPixels ← -1;
tGap: EBESPixels;
gaps: ARRAY Relationship OF EBESPixels ← ALL[maxRadialExtension];
deInsertedArea: EBESRect;
IF (tGap ← nTileArea.x1-pTileArea.x2)>bestGap
THEN
{bestDir ← $pWn; bestGap ← tGap};
IF (tGap ← pTileArea.x1-nTileArea.x2)>bestGap
THEN
{bestDir ← $pEn; bestGap ← tGap};
IF (tGap ← nTileArea.y1-pTileArea.y2)>bestGap
THEN
{bestDir ← $pSn; bestGap ← tGap};
IF (tGap ← pTileArea.y1-nTileArea.y2)>bestGap
THEN
{bestDir ← $pNn; bestGap ← tGap};
IF bestGap<0 THEN ERROR; -- design rule violation
IF
NOT anyInteractingPImplant
THEN
BEGIN
anyInteractingPImplant ← TRUE;
nImplPieces.ChangeRect[CDBasics.universe, NIL];
nImplPieces.ChangeRect[desiredNImplant, $covered];
END;
gaps[bestDir] ← bestGap/2;
deInsertedArea ← [x1: pTileArea.x1-gaps[$pEn], y1: pTileArea.y1-gaps[$pNn], x2: pTileArea.x2+gaps[$pWn], y2: pTileArea.y2+gaps[$pSn]];
IF CDBasics.NonEmpty[deInsertedArea] THEN nImplPieces.ChangeRect[deInsertedArea, NIL];
END;
CoverNegotiatedPiece:
PROCEDURE [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
{area: EBESRect = tile.Area; result.ChangeRect[area, $covered]};
nTile: CornerStitching.TilePtr = tile;
nTileArea: EBESRect = nTile.Area;
desiredNImplant: EBESRect = CDBasics.Extend[nTileArea, maxRadialExtension];
anyInteractingPImplant: BOOL ← FALSE;
[] ← pDif.EnumerateArea[rect: CDBasics.Extend[nTileArea, 2*maxRadialExtension], perTile: InteractWithPImplant];
IF NOT anyInteractingPImplant THEN result.ChangeRect[desiredNImplant, $covered]
ELSE [] ← nImplPieces.EnumerateArea[desiredNImplant, CoverNegotiatedPiece];
END;
maxRadialExtension: EBESPixels = NARROW[spec.first, REF INT]^/nmPerEBESPixel;
nDif: Tesselation ← GenerateCover[ms, spec.rest.first, extInfluenceDiameter+2*maxRadialExtension];
pDif: Tesselation ← GenerateCover[ms, spec.rest.rest.first, extInfluenceDiameter+2*maxRadialExtension];
nImplPieces: Tesselation ← NewTesselation[];
result ← NewTesselation[];
[] ← nDif.EnumerateArea[rect: CDBasics.universe, perTile: PlaceNImplant];
nDif ← DisposeTesselation[nDif];
pDif ← DisposeTesselation[pDif];
nImplPieces ← DisposeTesselation[nImplPieces];
END;
OutputTile:
PROCEDURE [tile: CornerStitching.TilePtr, data:
REF
ANY]
-- CornerStitching.PerTileProc -- =
BEGIN -- only called on tiles with non-NIL values
DoOutput:
PROC =
BEGIN
ms: MaskState = NARROW[data];
cr: CD.Rect = CDBasics.Intersection[tile.Area, ms.stripeClip];
IF CDBasics.NonEmpty[cr]
THEN
BEGIN
ms.drawCommand^ ← [x: cr.x1-ms.stripeClip.x1, y: cr.y1-ms.stripeClip.y1, w: cr.x2-cr.x1, h: cr.y2-cr.y1];
SendCommand[s: ms.s, comm: ms.drawCommand];
ms.stripeRectCount ← ms.stripeRectCount+1;
END;
END;
WITH tile.Value
SELECT
FROM
a:
ATOM =>
SELECT a
FROM
$covered => DoOutput[];
ENDCASE => ERROR;
ENDCASE => ERROR;
END;
Today:
PROC
RETURNS [ d: Date ] =
TRUSTED BEGIN
time: BasicTime.Unpacked = BasicTime.Unpack[BasicTime.Now[]];
moDayYr: ROPE = IO.PutFR[format: "%02d%02d%02d",
v1: IO.card[LOOPHOLE[time.month, CARDINAL]+1], v2: IO.int[time.day], v3: IO.int[time.year MOD 100]];
FOR i: [0..6) IN [0..6) DO d[i] ← Rope.Fetch[moDayYr, i] ENDLOOP;
END;
PatternFileName:
PROC [ maskSetName, maskName:
ROPE, row, col:
NAT ]
RETURNS [ rfn:
ROPE ] =
BEGIN
r: ROPE = IO.PutFR[format: "%s%s.%g%g",
v1: IO.rope[Rope.Substr[base: Rope.Cat[maskSetName, "xxxxxxx"], len: 7]],
v2: IO.rope[Rope.Substr[base: Rope.Cat[maskName, "xx"], len: 2]],
v3: IO.char[LOOPHOLE['A+col]], v4: IO.char[LOOPHOLE['A+row]]];
rfn ← Rope.Translate[base: r, translator: ToUpperCase];
END;
ToUpperCase:
PROC [old:
CHAR]
RETURNS [new:
CHAR]
-- Rope.TranslatorType -- =
{new ← Ascii.Upper[old]};
RopeToFileName:
PROC [ rfn:
ROPE ]
RETURNS [ fn: FileName ] =
{FOR i: [0..12) IN [0..12) DO fn[i] ← Rope.Fetch[rfn, i] ENDLOOP};
WriteTapeDirectory:
PROC [ streamGen:
PROC [ms: MaskState]
RETURNS [dest:
IO.
STREAM], ms: MaskState, nRows, nCols:
NAT, today: Date] =
BEGIN
s: IO.STREAM;
nMasks: NAT ← 0;
FOR m:
LIST
OF
REF
ANY ← ms.maskSetSpec, m.rest
WHILE m#
NIL
DO
nMasks ← nMasks+1;
ENDLOOP;
ms.patternFileName ← IO.PutFR["%g.arch", IO.rope[ms.maskSetName]];
s ← EBESOpen[dest: streamGen[ms], eor: FALSE];
SendCommand[s, NEW[CARDINAL ← 0]]; -- marked "reserved" in Varian Figure A-1
SendCommand[s, NEW[CARDINAL ← nRows*nCols*nMasks]]; -- count of files
FOR m:
LIST
OF
REF
ANY ← ms.maskSetSpec, m.rest
WHILE m#
NIL
DO
maskSpec: MaskSpec = NARROW[m.first];
FOR col:
NAT
IN [0..nCols)
DO
FOR row:
NAT
IN [0..nRows)
DO
s.PutF[format: "%s ", v1: IO.rope[PatternFileName[ms.maskSetName, maskSpec.name, row, col]]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
SendCommand[s, NEW[Date ← today]];
s.Close[];
END;
AbortFile:
PROC [s:
IO.
STREAM ]
RETURNS [
IO.
STREAM ] =
{IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]};
SendCommand:
PROC [ s:
IO.
STREAM, comm:
REF ] =
BEGIN
sizeInWords: NAT;
WITH comm
SELECT
FROM
c: REF DrawRectangle => sizeInWords ← SIZE[DrawRectangle];
c: REF BasicCommand => sizeInWords ← SIZE[BasicCommand];
c: REF StartStripe => sizeInWords ← SIZE[StartStripe];
c: REF StartDrawing => sizeInWords ← SIZE[StartDrawing];
c: REF Date => sizeInWords ← SIZE[Date];
c: REF FileName => sizeInWords ← SIZE[FileName];
c: REF CARDINAL => sizeInWords ← SIZE[CARDINAL];
ENDCASE => ERROR;
TRUSTED {s.UnsafePutBlock[[base: LOOPHOLE[comm], startIndex: 0, count: 2*sizeInWords]]};
END;
EBES IO Stream Types and Procedures
EBESStreamStateRef: TYPE = REF EBESStreamState;
EBESStreamState:
TYPE =
RECORD [
dest: IO.STREAM,
eor: BOOL,
buf: REF TEXT];
ebesStreamProcs:
REF
IO.StreamProcs =
IO.CreateStreamProcs[
variety: output,
class: $EBESOutputStream,
putChar: PutEBESChar,
unsafePutBlock: PutEBESBlock,
flush: FlushEBES,
close: CloseEBES
];
EBESOpen:
PROC [ dest:
IO.
STREAM, eor:
BOOL ←
TRUE ]
RETURNS [ self:
IO.
STREAM ] =
BEGIN
state: EBESStreamStateRef = NEW[EBESStreamState ←
[dest: dest, eor: eor, buf: NEW[TEXT[2048]]]];
state.buf.length ← 0;
self ←
IO.CreateStream[
streamProcs: ebesStreamProcs,
streamData: state
];
END;
PutEBESChar:
PROC [ self:
IO.
STREAM, char:
CHAR ] =
TRUSTED BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
FlushEBESIfNecessary[state, 1];
state.buf[state.buf.length] ← char;
state.buf.length ← state.buf.length+1;
END;
PutEBESBlock:
PROC [ self:
IO.
STREAM, block:
IO.UnsafeBlock ] =
TRUSTED BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
FlushEBESIfNecessary[state, block.count];
FOR i:
INT
IN [0..block.count)
DO
CharArrayPtr: TYPE = LONG POINTER TO PACKED ARRAY [0..0) OF CHAR;
state.buf[state.buf.length+i] ← LOOPHOLE[block.base, CharArrayPtr][block.startIndex+i];
ENDLOOP;
state.buf.length ← state.buf.length+block.count;
END;
FlushEBESIfNecessary:
PROC [state: EBESStreamStateRef, newBytes:
NAT] =
INLINE
BEGIN
IF state.buf.maxLength<state.buf.length+newBytes+
(
IF state.eor
THEN 2*
SIZE[BasicCommand]
-- for end of record --
ELSE 0)
THEN
DoFlushEBES[state];
END;
FlushEBES:
PROC [ self:
IO.
STREAM ] = {DoFlushEBES[
NARROW[self.streamData]]};
DoFlushEBES:
PROC [ state: EBESStreamStateRef ] =
BEGIN
IF state.buf.length>0
THEN
BEGIN
IF state.eor
THEN
BEGIN
IF state.buf.length+2<=state.buf.maxLength
THEN
TRUSTED BEGIN -- append an end-of-record command to the buffer
endRec: PACKED ARRAY [0..2) OF CHAR = LOOPHOLE[endRecord];
state.buf[state.buf.length] ← endRec[0];
state.buf[state.buf.length+1] ← endRec[1];
state.buf.length ← state.buf.length+2;
END
ELSE ERROR; -- can't terminate buffer properly
END;
FOR i:
CARDINAL
IN [state.buf.length..state.buf.maxLength)
DO
state.buf[i] ← 000C; -- pad out with 0's
ENDLOOP;
state.buf.length ← state.buf.maxLength;
state.dest.PutBlock[state.buf];
END;
state.buf.length ← 0;
END;
CloseEBES:
PROC [ self:
IO.
STREAM, abort:
BOOL ←
FALSE ] =
BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
self.Flush[];
state.dest.Close[];
END;
Auxiliary Procedures
RopeNeeded: SIGNAL [ ref: REF REF ] = CODE;
ToRope:
PROC [ ref:
REF ]
RETURNS [ rope:
ROPE ] =
BEGIN
IF ref = NIL THEN rope ← NIL
ELSE
WITH ref
SELECT
FROM
r: ROPE => rope ← r;
rt: REF TEXT => rope ← Rope.FromRefText[rt];
a: ATOM => rope ← Atom.GetPName[a];
ri: REF INT => rope ← IO.PutFR[format: "%d", v1: IO.int[ri^]];
ENDCASE =>
BEGIN
refRef: REF REF = NEW[REF ← ref];
SIGNAL RopeNeeded[refRef];
rope ← ToRope[refRef^ ! RopeNeeded => GOTO NoHelp];
END;
END;
ScaleCDToEBES:
PROC [ ms: MaskState, cdr:
CD.DesignRect ]
RETURNS [ ebr:
CD.Rect ] =
BEGIN
ebr ← CDBasics.NormalizeRect[
[x1: RatMul[ms.scale, cdr.x1],
y1: RatMul[ms.scale, cdr.y1],
x2: RatMul[ms.scale, cdr.x2],
y2: RatMul[ms.scale, cdr.y2]]];
END;
ScaleEBESToCD:
PROC [ ms: MaskState, ebr:
CD.Rect ]
RETURNS [ cdr:
CD.DesignRect ] =
BEGIN
cdr ← CDBasics.NormalizeRect[
[x1: RatDiv[ms.scale, ebr.x1],
y1: RatDiv[ms.scale, ebr.y1],
x2: RatDiv[ms.scale, ebr.x2],
y2: RatDiv[ms.scale, ebr.y2]]];
END;
Bloat:
PROC [ r:
CD.Rect, deltaDiameter:
CD.Number ]
RETURNS [ br:
CD.Rect ] =
BEGIN
b0: NAT = deltaDiameter/2; -- split in "half" for radius
b1: NAT = deltaDiameter-b0;
Be careful not to exceed the limits of a CD.Number, even temporarily
br ← [x1: MAX[FIRST[CD.Number]+b0, r.x1]-b0,
y1: MAX[FIRST[CD.Number]+b0, r.y1]-b0,
x2: MIN[LAST[CD.Number]-b1, r.x2]+b1,
y2: MIN[LAST[CD.Number]-b1, r.y2]+b1];
END;
Ceiling:
PROC [ r: Rational ]
RETURNS [ c:
INT ] =
BEGIN
c ← r.num/r.denom;
c = SGN[r.num]*SGN[r.denom]*FLOOR[ABS[r.num]/ABS[r.denom]] if r.denom#0
IF ((r.num>0) = (r.denom>0)) AND r.num MOD r.denom # 0 THEN c ← c+1;
END;
ReduceRational:
PROC [ r: Rational ]
RETURNS [ Rational ] =
BEGIN
gcd: INT = IF r.num=0 THEN r.denom ELSE GCD[r.num, r.denom];
RETURN[[num: r.num/gcd, denom: r.denom/gcd]];
END;
RatMul:
PROC [ mul: Rational, z:
INT ]
RETURNS [
INT ] =
INLINE {RETURN[(mul.num*z)/mul.denom]};
RatDiv:
PROC [ div: Rational, z:
INT ]
RETURNS [
INT ] =
INLINE {RETURN[(div.denom*z)/div.num]};
GCD:
PROC [ m, n:
INT ]
RETURNS [
INT ] =
BEGIN
r: INT;
SELECT m
FROM
<0 => m ← -m;
ENDCASE => NULL;
SELECT n
FROM
<0 => n ← -n;
>0 => NULL;
ENDCASE => RETURN[m];
r ← m MOD n;
WHILE r>0 DO m ← n; n ← r; r ← m MOD n; ENDLOOP;
RETURN[n];
END;
Module START code...
END. -- of EBESMaskImpl