DIRECTORY
AMBridge, AMTypes, Ascii, Atom, Basics, BasicTime, CD, CDBasics, CDCells, CDCommandOps, CDImports, CDMEBES, CDOps, CDProperties, CDSequencer, CDVArrow, CStitching, FS, IO, PrintTV, Process, Rope, TerminalIO;
CDMEBESMainImpl:
CEDAR
PROGRAM
IMPORTS AMBridge, Ascii, Atom, Basics, BasicTime, CD, CDBasics, CDCells, CDCommandOps, CDImports, CDMEBES, CDOps, CDProperties, CDSequencer, CDVArrow, CStitching, FS, IO, PrintTV, Process, Rope, TerminalIO
EXPORTS CDMEBES =
BEGIN OPEN CDMEBES;
Global Variables
stripesPerClump: PUBLIC INT ← 10;
defaultTadsPerNm: PUBLIC INT ← 1;
wDir: PUBLIC ROPE ← "///MEBES";
findBBoxByEnumeration: BOOL ← FALSE;
abortFlag: PUBLIC REF BOOL ← NEW[BOOL];
foundErrorLayer: BOOL ← FALSE;
today: Date;
Init:
PROC ~ {
CDSequencer.ImplementCommand[key~$MEBESMask , proc~StartMEBESMask, queue~doQueue];
CDCommandOps.RegisterWithMenu[menu~$ProgramMenu, entry~"MEBES mask generation", key~$MEBESMask, proc~StartMEBESMask];
TerminalIO.PutRope["ChipNDale MEBES mask generator loaded\n"];
};
StartMEBESMask:
PUBLIC PROC [comm: CDSequencer.Command] =
TRUSTED BEGIN
TerminalIO.PutRope["MEBES-mask generation\n"];
IF CDCells.IsPushedIn[comm.design]
THEN {
TerminalIO.PutRope["**Design is pushed in; not done\n"];
RETURN
};
IF CDImports.HasUnloadedImports[comm.design].yes
THEN {
TerminalIO.PutRope["**Design has non bound imports; not done\n"];
RETURN
};
TerminalIO.PutRope["Releases lock of design, but design MUST NOT be changed\n"];
abortFlag^ ← FALSE;
[] ← CDCommandOps.DoWithResource[proc: MEBESMask, comm: comm, resource: $MEBESMask];
END;
MEBESMask:
PROC [ comm: CDSequencer.Command ] =
BEGIN
NotePunt: PROC = {TerminalIO.PutF["\n*** MEBES mask generation aborted at %g\n", IO.time[]]};
BEGIN
ENABLE
BEGIN
ABORTED => GOTO Punt;
TerminalIO.UserAbort => GOTO Punt;
UNWIND => NotePunt[];
END;
MakeMasks[comm: comm, streamGen: SimpleStreamGen];
IF abortFlag^ THEN NotePunt[];
EXITS Punt => NotePunt[];
END;
END;
StreamGenProc: TYPE = PROC [ ms: MaskState ] RETURNS [ dest: IO.STREAM ];
SimpleStreamGen:
PROC [ ms: MaskState ]
RETURNS [ dest:
IO.
STREAM ]
-- StreamGenProc -- =
BEGIN
dest ←
FS.StreamOpen[
fileName:
IO.PutFR[format: "%g%g/%g",
v1: IO.rope[wDir], v2: IO.rope[ms.maskSetName], v3: IO.rope[ms.patternFileNames.first]
],
accessOptions: create
];
END;
Prop:
PROC [ms: MaskState, prop:
REF, default:
REF ← $Error]
RETURNS [value:
REF] = {
value ← CDProperties.GetDesignProp[ms.design, prop];
IF value = NIL THEN value ← CDProperties.GetTechnologyProp[ms.design.technology, prop];
IF value = NIL THEN value ← CDProperties.GetAtomProp[$CDMEBES, prop];
IF value = NIL THEN value ← default;
IF value = $Error
THEN
BEGIN
TerminalIO.PutF[" .. no value for property %g.. ", IO.rope[ToRope[prop]]];
ERROR TerminalIO.UserAbort;
END;
};
NumericProp:
PROC [ms: MaskState, prop:
REF, default:
REF ←
NIL]
RETURNS [value:
INT] = {
value ← NARROW[Prop[ms, prop, default], REF INT]^;
};
MakeMasks:
PROC [comm: CDSequencer.Command, streamGen: StreamGenProc ] =
BEGIN
ms: MaskState =
NEW[ MaskStateRec ← [
design: comm.design,
drawCommand: NEW[DrawRectangle]]];
TRUSTED {Process.SetPriority[Process.priorityBackground]};
TerminalIO.PutF["\nMEBES Mask Generation\nPreliminary analysis begun at %g.\n", IO.time[]];
IF
NOT abortFlag^
THEN
BEGIN
ENABLE
-- for ERRORs
BEGIN
UNWIND => ms.s ← AbortFile[ms.s];
END;
ComputeReticleClip:
PROC [cdToNm: Rational]
RETURNS [clip: NmRect] =
BEGIN
AdjustReticleSize:
PROC [coord:
ROPE, z1, z2: Nm, zSizeProp:
ATOM, zOffset: Nm ← 0]
RETURNS [newZ1, newZ2: Nm] =
BEGIN
zSize: Nm = NumericProp[ms, zSizeProp, NEW[Nm ← z2-z1]];
IF z2-z1 > zSize
THEN
{TerminalIO.PutF[" .. design %g size of %d nanometers is larger than allowed die size of %d nanometers ..", IO.rope[coord], IO.int[z2-z1], IO.int[zSize]];
ERROR TerminalIO.UserAbort};
newZ1 ← (z1+z2-zSize)/2-zOffset;
newZ2 ← newZ1+zSize;
END;
smallestScribedDesignNm: NmRect ← Bloat[
r: ScaleRect[ms.designClip^, cdToNm],
deltaDiameter: 2*(maxBloat+activeToScribeCenter)];
[clip.x1, clip.x2] ← AdjustReticleSize["x", smallestScribedDesignNm.x1, smallestScribedDesignNm.x2, $CDMEBESNmDieSizeX, ms.dieOffset.x];
[clip.y1, clip.y2] ← AdjustReticleSize["y", smallestScribedDesignNm.y1, smallestScribedDesignNm.y2, $CDMEBESNmDieSizeY, ms.dieOffset.y];
END; -- of ComputeReticleClip
maxBloat: Nm ← NumericProp[ms, $CDMEBESNmMaxBloat, NEW[Nm ← 10000]];
activeToScribeCenter: Nm ← NumericProp[ms, $CDMEBESActiveToScribeCenter];
maskCount, otherCount: INT ← 0;
cf: REF CD.ContextFilter ← NEW[CD.ContextFilter ← ALL[TRUE]];
commentLayer: CD.Layer = CD.FetchLayer[t: comm.design.technology, uniqueKey: $comment];
today ← Today[];
ms.maskSetName ← (
IF Prop[ms, $CDMEBESMaskSetName, $default] = $default
THEN
TerminalIO.RequestRope["Project name? (9 chars, alphanum) "] ELSE ToRope[Prop[ms, $CDMEBESMaskSetName]]);
ms.toolingSpec ← NARROW[Prop[ms, $CDMEBESToolingSpec]];
ms.derivationSpec ← NARROW[Prop[ms, $CDMEBESDerivationSpec]];
ms.nmPerLambda ← NumericProp[ms, $CDMEBESNmPerLambda];
ComputeTadsPerNm[ms];
ms.dieOffset ← [x: NumericProp[ms, $CDMEBESNmDieOffsetX,
NEW[Nm ← 0]],
y: NumericProp[ms, $CDMEBESNmDieOffsetY, NEW[Nm ← 0]]];
ms.dropInList ← NARROW[Prop[ms, $CDMEBESDropInList, NIL], LIST OF REF ANY];
ms.designClip ← NEW[CD.Rect ← [0, 0, 0, 0]];
FOR d:
LIST
OF
REF
ANY ← ms.derivationSpec, d.rest
WHILE d#
NIL
DO
WITH d.first
SELECT
FROM
derivation: DerivationMaskSpec =>
MarkInterestingLayers[ms, derivation.cover];
ENDCASE => NULL;
ENDLOOP; -- d
IF commentLayer #
CD.errorLayer
THEN
cf[commentLayer] ← ms.interestingLayers[commentLayer];
foundErrorLayer ← FALSE;
IF CDCells.IsPushedIn[ms.design]
AND
NOT TerminalIO.Confirm[IO.PutFR["WARNING: CDMEBES working on pushed cell %g in design %g. This probably isn't what you want. Confirm to continue...\n", IO.rope[ms.design.actual.first.desc], IO.rope[ms.design.name]]] THEN GOTO AbortMask;
ms.designClip^ ← CDOps.BoundingBox[ms.design];
IF findBBoxByEnumeration
THEN {
ms.designClip^ ← [0, 0, 0, 0];
CDOps.DrawDesign[ms.design,
CD.CreateDrawRef[[
interestClip~CDBasics.universe,
drawRect~NoteLayer,
stopFlag~abortFlag,
devicePrivate~ms,
contextFilter~cf,
symbolics~FALSE,
showErrors~FALSE,
design~ms.design
]]];
.. measure design in ChipNDale units, leaves result in ms.designClip
};
IF NOT CDBasics.NonEmpty[ms.designClip^] THEN ms.designClip^ ← [0, 0, 0, 0];
ms.nmReticleClip ← ComputeReticleClip[
cdToNm: ReduceRational[
[num: ms.nmPerLambda, denom: ms.design.technology.lambda]
]];
FOR d:
LIST
OF
REF
ANY ← ms.derivationSpec, d.rest
WHILE d #
NIL
DO
WITH d.first
SELECT
FROM
derivation: DerivationMaskSpec => maskCount ← maskCount+1
ENDCASE => otherCount ← otherCount+1;
ENDLOOP;
TerminalIO.PutF["Preliminary analysis finished at %g. Making %d real masks and %d other things at %d (x) x %d (y) nm.\n",
IO.time[],
IO.int[maskCount],
IO.int[otherCount],
IO.int[CDBasics.SizeOfRect[ms.nmReticleClip].x],
IO.int[CDBasics.SizeOfRect[ms.nmReticleClip].y]
];
IF foundErrorLayer
THEN
TerminalIO.PutRope[" WARNING: CDMEBES found geometry on error layer\n"];
FOR d:
LIST
OF
REF
ANY ← ms.derivationSpec, d.rest
WHILE d#
NIL
DO
ms.data ← NIL;
WITH d.first
SELECT
FROM
derivation: DerivationMaskSpec => {
tooling: ToolingMaskSpec = NARROW[ms.toolingSpec.GetPropFromList[derivation.maskId]];
ms.curMask ← derivation;
IF tooling#
NIL
THEN MakeMEBESMask[ms, derivation, tooling, streamGen
! TadTooLarge => {
ComputeTadsPerNm[ms, 2*ms.tadsPerNm];
RETRY
} ] -- a real mask
ELSE TerminalIO.PutF["Mask %g, a part of the derivation spec, is not part of the tooling spec.\n", IO.atom[derivation.maskId]];
};
spec: CoverSpec =>
-- we're doing analysis, probably
DoAnalysisPass[ms, spec];
ENDCASE => NULL;
IF abortFlag^ THEN GOTO AbortMask;
IF ms.data #
NIL
THEN
BEGIN
tv: AMTypes.TV;
rs: IO.STREAM = IO.ROS[];
rs.Put[IO.rope["\nAnalysis result .. "]];
TRUSTED {tv ← AMBridge.TVForReferent[ms.data]};
PrintTV.Print[tv: tv, put: rs, depth: 10, width: 1000];
rs.Put[IO.rope["\n"]];
TerminalIO.PutRope[IO.RopeFromROS[rs]];
END;
ENDLOOP; -- d
TerminalIO.PutF["\nMEBES mask generation finished at %g\n", IO.time[]];
EXITS
AbortMask => {ms.s ← AbortFile[ms.s]};
END;
END;
MarkInterestingLayers:
PROC [ ms: MaskState, cover: CoverSpec ] = {
WITH cover
SELECT
FROM
lora:
LIST
OF
REF
ANY =>
FOR l:
LIST
OF
REF
ANY ← lora, l.rest
WHILE l #
NIL
DO
MarkInterestingLayers[ms, l.first];
ENDLOOP;
layer: CDLayer => ms.interestingLayers[layer.source] ← TRUE;
ENDCASE => NULL;
};
NoteLayer:
PROC [ pr:
CD.DrawRef, r:
CD.Rect, l:
CD.Layer ] =
BEGIN
ms: MaskState = NARROW[pr.devicePrivate];
IF abortFlag^ THEN ERROR TerminalIO.UserAbort;
ms.designClip^ ← IF CDBasics.NonEmpty[ms.designClip^] THEN CDBasics.Surround[ms.designClip^, r] ELSE r;
IF l=
CD.errorLayer
THEN {
foundErrorLayer ← TRUE;
pr.contextFilter[CD.errorLayer] ← FALSE; -- found one, don't need more
};
END;
MakeMEBESMask:
PROC [ms: MaskState, derivation: DerivationMaskSpec, tooling: ToolingMaskSpec, streamGen: StreamGenProc] =
BEGIN
RestateAddrUnit:
PROC [ nm: Nm
-- 10^-3 micrometer -- ]
RETURNS [ extModeAddrUnits:
INT
-- 2^-28 micrometer -- ] = {
extModeAddrUnits ← nm/1000;
nm ← nm MOD 1000;
FOR i:
INT
IN [0..28)
DO
-- manual high-precision binary divide, (nm/1000)
extModeAddrUnits ← extModeAddrUnits+extModeAddrUnits;
nm ← nm+nm;
IF nm > 1000
THEN {
extModeAddrUnits ← extModeAddrUnits+1;
nm ← nm-1000;
};
ENDLOOP;
};
blockCountFileIndex:
INT;
... index where the block count CARDINAL is stored in extended or reticle mode files
mebesReticleClip: MEBESRect = ScaleRect[ms.nmReticleClip,
[num: 1, denom: tooling.addrUnit -- nm/MEBES pixel --]];
nRows:
NAT = Ceiling[[
num: CDBasics.SizeOfRect[mebesReticleClip].y -- MEBES pixels -- ,
denom: maskHeight -- MEBES pixels --
]];
nCols:
NAT = Ceiling[[
num: CDBasics.SizeOfRect[mebesReticleClip].x -- MEBES pixels -- ,
denom: maskWidth -- MEBES pixels --]];
extModeAddrUnits: INT = RestateAddrUnit[tooling.addrUnit];
ms.mebesPixelPitch ← tooling.addrUnit;
ms.mode ← tooling.mode;
ms.scale ← ReduceRational[[num: ms.nmPerLambda*ms.tadsPerNm, denom: ms.design.technology.lambda]];
FOR col:
NAT
IN [0..nCols)
DO
left: MEBESPixels = mebesReticleClip.x1+col*maskWidth;
FOR row: NAT IN [0..nRows) DO
bottom: MEBESPixels = mebesReticleClip.y1+row*maskHeight;
topmostStripe: INT = MIN[maxStripes, Ceiling[[num: CDBasics.SizeOfRect[mebesReticleClip].y-maskHeight*row, denom: stripeHeight]]];
IF ms.mode # reticle
OR (row = 0
AND col = 0)
THEN {
.. open a new pattern file and generate a header
ms.patternFileNames ←
CONS[
GenPatternFileName[mode: ms.mode, maskSetName: ms.maskSetName,
maskName: tooling.maskNo, row: row, col: col],
ms.patternFileNames];
ms.s ← EBESOpen[streamGen[ms]];
TerminalIO.PutF["\nStarting mask %g at %g ", IO.rope[ms.patternFileNames.first], IO.time[]];
SendCommand[s: ms.s, comm: (
SELECT tooling.mode
FROM
oneTwo =>
NEW[Mode12StartDrawing ← [
addressCode: (
SELECT tooling.addrUnit
FROM
500 => Nm500,
250 => Nm250,
ENDCASE => ERROR),
cx: MIN[maskWidth, CDBasics.SizeOfRect[mebesReticleClip].x-col*maskWidth],
cy: MIN[maskHeight, CDBasics.SizeOfRect[mebesReticleClip].y-row*maskHeight],
moDayYr: today,
patternFileName: RopeToPatternFileName[ms.patternFileNames.first]
]],
extended =>
NEW[ExtAddrModeStartDrawing ← [
addrUnitHigh: Basics.HighHalf[extModeAddrUnits],
addrUnitLow: Basics.LowHalf[extModeAddrUnits],
cxLow: MIN[maskWidth, CDBasics.SizeOfRect[mebesReticleClip].x-col*maskWidth],
cyLow: MIN[maskHeight, CDBasics.SizeOfRect[mebesReticleClip].y-row*maskHeight],
moDayYr: today,
patternFileName: RopeToPatternFileName[ms.patternFileNames.first]
]],
reticle =>
NEW[ExtAddrModeStartDrawing ← [
addrUnitHigh: Basics.HighHalf[extModeAddrUnits],
addrUnitLow: Basics.LowHalf[extModeAddrUnits],
cxHigh: Basics.HighHalf[CDBasics.SizeOfRect[mebesReticleClip].x],
cxLow: Basics.LowHalf[CDBasics.SizeOfRect[mebesReticleClip].x],
cyHigh: Basics.HighHalf[CDBasics.SizeOfRect[mebesReticleClip].y],
cyLow: Basics.LowHalf[CDBasics.SizeOfRect[mebesReticleClip].y],
moDayYr: today,
patternFileName: RopeToPatternFileName[ms.patternFileNames.first],
field2Size: (SIZE[CARDINAL]+SIZE[SegDirectoryEntry]*nCols)*Basics.bytesPerWord/bytesPerMebesWord
]],
ENDCASE => ERROR)];
IF ms.mode # oneTwo
THEN {
blockCountFileIndex ← ms.s.GetIndex[];
SendCommand[s: ms.s, comm:
NEW[
CARDINAL ← 0]];
.. to be filled in later with block count
IF ms.mode = reticle
THEN {
.. leave room for the segment (column) directory
de: REF SegDirectoryEntry = NEW[SegDirectoryEntry];
FOR segment:
INT
IN [0..nCols)
DO
SendCommand[s: ms.s, comm: de];
ENDLOOP;
};
};
IF ms.mode = reticle
AND row = 0
THEN {
-- fill in segment directory for new column
oldIndex: INT = ms.s.GetIndex[];
ms.s.SetIndex[blockCountFileIndex+(Basics.bytesPerWord*(SIZE[CARDINAL]+SIZE[SegDirectoryEntry]*col))];
SendCommand[s: ms.s, comm:
NEW[SegDirectoryEntry ← [
firstBlock: 1+(oldIndex/mebesBlockSize),
firstWordWithinBlock: 1+(oldIndex MOD mebesBlockSize)/bytesPerMebesWord
]]];
ms.s.SetIndex[oldIndex];
SendCommand[s: ms.s, comm: NEW[StartSegment ← [segmentNumber: segmentOrigin+col]]];
};
FOR stripeBase: INT -- [0..maxStripes) -- ← 0, stripeBase+stripesPerClump WHILE stripeBase < topmostStripe DO
rects: Tesselation ← NIL;
IF abortFlag^
THEN
RETURN;
ms.tadStripeClip ← ScaleRect[
CDBasics.Intersection[mebesReticleClip, [
x1: left,
y1: bottom+stripeBase*stripeHeight,
x2: left+maskWidth,
y2: bottom+(stripeBase+stripesPerClump)*stripeHeight
]],
[num: ms.mebesPixelPitch*ms.tadsPerNm, denom: 1]];
ms.designStripeClip ← ScaleTadToCD[ms,
CDBasics.Extend[ms.tadStripeClip, ms.mebesPixelPitch*ms.tadsPerNm]];
ms.viewerArrow ← CDBasics.Center[ms.designStripeClip];
CDVArrow.ShowArrow[design: ms.design, pos: ms.viewerArrow];
.. keep user happy
rects ← GenerateCover[ms, LIST[$Enlarge, NEW[Nm ← 2*tooling.skewPerSide], derivation.cover]];
AddScribe[ms, rects];
FOR stripe:
INT
IN [stripeBase..
MIN[stripeBase+stripesPerClump, topmostStripe])
DO
ms.tadStripeClip ← ScaleRect[
CDBasics.Intersection[mebesReticleClip, [
x1: left,
y1: bottom+stripe*stripeHeight,
x2: left+maskWidth,
y2: bottom+(stripe+1)*stripeHeight
]],
[num: ms.mebesPixelPitch*ms.tadsPerNm, denom: 1]];
ms.stripeRectCount ← 0;
SendCommand[s: ms.s, comm: (
SELECT ms.mode
FROM
oneTwo => NEW[Mode12StartStripe ← [stripeNumber: stripe+stripeOrigin]],
extended => NEW[ExtAddrModeStartStripe ← [stripeNumber: stripe+stripeOrigin]],
reticle =>
NEW[ExtAddrModeStartStripe ←
[stripeNumber: row*maxStripes+stripe+stripeOrigin]],
ENDCASE => ERROR)];
FOR dil:
LIST
OF
REF
ANY ← ms.dropInList, dil.rest
WHILE dil #
NIL
DO
di: DropIn = NARROW[dil.first];
ddi: Atom.PropList = NARROW[derivation.props.GetPropFromList[$DropIns]];
val:
REF
ANY ← InsertDropIn[ms: ms, rects: rects, di: di,
data: ddi.GetPropFromList[di.name]];
derivation.props ← derivation.props.PutPropOnList[
prop: $DropIns,
val: ddi.PutPropOnList[prop: di.name, val: val]
];
ENDLOOP;
[] ← rects.EnumerateArea[rect: ms.tadStripeClip,
eachTile: OutputTile, data: ms];
SendCommand[s: ms.s, comm: NEW[BasicCommand ← endStripe]];
TerminalIO.PutF[".%d", IO.int[ms.stripeRectCount]]; -- end of stripe
ENDLOOP; -- stripe
rects ← DisposeTesselation[rects];
ENDLOOP; -- stripeBase
IF ms.mode # reticle
THEN {
SendCommand[s: ms.s, comm: NEW[BasicCommand ← endDrawing]];
ms.s.Flush[];
IF ms.mode # oneTwo
THEN {
oldIndex: INT = ms.s.GetIndex[];
ms.s.SetIndex[blockCountFileIndex];
SendCommand[s: ms.s, comm:
NEW[
CARDINAL ← oldIndex/mebesBlockSize]];
.. fill in the number of blocks needed
ms.s.SetIndex[oldIndex];
};
ms.s.Close[];
ms.s ← NIL;
};
ENDLOOP; -- col
IF ms.mode = reticle
THEN {
oldIndex: INT;
SendCommand[s: ms.s, comm: NEW[BasicCommand ← endDrawing]];
ms.s.Flush[];
oldIndex ← ms.s.GetIndex[];
ms.s.SetIndex[blockCountFileIndex];
SendCommand[s: ms.s, comm:
NEW[
CARDINAL ← oldIndex/mebesBlockSize]];
.. fill in the number of blocks needed
ms.s.SetIndex[oldIndex];
ms.s.Close[];
ms.s ← NIL;
};
END;
DoAnalysisPass:
PROC [ ms: MaskState, spec: CoverSpec ] =
BEGIN
END;
GenerateCover:
PUBLIC
PROC [ ms: MaskState, spec: CoverSpec, extInfluenceDiameter: Tad ← 0 ]
RETURNS [ rects: Tesselation ] =
BEGIN
WITH spec
SELECT
FROM
list:
LIST
OF
REF
ANY =>
BEGIN
(e.g., LIST[$Bletch, NEW[INT ← 2], NEW[CDLayer ← []], NEW[CDLayer ← []]] )
ref: REF ANY = Atom.GetProp[$CDMEBESCoverProcs, list.first];
rects ← NARROW[ref, REF CoverProc]^[ms, list.rest, extInfluenceDiameter];
layer: CDLayer =>
SELECT layer.deltaDiameter
FROM
>=0 =>
BEGIN
rects ← NewTesselation[NIL];
DrawLayersWithPosDeltas[ms: ms, rects: rects, layers: LIST[layer], extInfluenceDiameter: extInfluenceDiameter];
END;
ENDCASE => rects ← GenerateCover[
ms,
LIST[$Enlarge,
NEW[Nm ← layer.deltaDiameter],
NEW[CDLayerRec ← [source: layer.source, deltaDiameter: 0]]],
extInfluenceDiameter];
ENDCASE => IF spec = NIL THEN rects ← NewTesselation[NIL] ELSE ERROR;
END;
AddScribe:
PROC [ms: MaskState, rects: Tesselation] =
BEGIN
IF
NARROW[Prop[ms, $CDMEBESAddScribe,
NEW[
BOOL ←
FALSE]],
REF
BOOL]^
THEN {
-- insert the scribe line
scaleFactor: Rational = [num: ms.tadsPerNm, denom: 1]; -- from Nm to Tads
r: NmRect = ms.nmReticleClip;
rSize: NmPosition = CDBasics.SizeOfRect[r];
tooling: ToolingMaskSpec = NARROW[ms.toolingSpec.GetPropFromList[ms.curMask.maskId]];
outer: Nm = tooling.scribeOffset;
inner: Nm = tooling.scribeOffset+tooling.scribeWidth;
IF inner > outer
THEN {
-- nontrivial scribe structure
ChRect:
PROC [b: NmRect] = {
FOR xRepeat:
INT
IN [-1..1]
DO
FOR yRepeat:
INT
IN [-1..1]
DO
offsetRect: NmRect = CDBasics.MoveRect[r: b,
offset: CDBasics.AddPoints[p: ms.dieOffset,
s: [x: xRepeat*rSize.x, y: yRepeat*rSize.y]]
];
clippedMebesRect: MEBESRect = ScaleRect[CDBasics.Intersection[offsetRect, r], scaleFactor];
IF CDBasics.NonEmpty[clippedMebesRect]
THEN
rects.ChangeRect[clippedMebesRect, $covered];
ENDLOOP;
ENDLOOP;
};
ChRect[[x1: r.x1+outer, y1: r.y1+outer, x2: r.x1+inner, y2: r.y2-outer]]; -- left side
ChRect[[x1: r.x2-inner, y1: r.y1+outer, x2: r.x2-outer, y2: r.y2-outer]]; -- right side
ChRect[[x1: r.x1+outer, y1: r.y1+outer, x2: r.x2-outer, y2: r.y1+inner]]; -- bottom
ChRect[[x1: r.x1+outer, y1: r.y2-inner, x2: r.x2-outer, y2: r.y2-outer]]; -- top
};
};
END;
DrawInfo: TYPE = REF DrawInfoRec;
DrawInfoRec:
TYPE =
RECORD [
layers: ARRAY CD.Layer OF RECORD [ used: BOOL ← FALSE, deltaDiameter: Tad ← 0 ],
rects: Tesselation ← NIL,
ms: MaskState ← NIL ];
DrawLayersWithPosDeltas:
PUBLIC
PROC [ms: MaskState, rects: Tesselation, layers:
LIST
OF CDLayer, extInfluenceDiameter: Nm ← 0] =
BEGIN
IF layers #
NIL
THEN
BEGIN
biggestDelta: Nm ← 0;
di: DrawInfo;
cf: REF CD.ContextFilter ← NEW[CD.ContextFilter ← ALL[FALSE]];
dr:
CD.DrawRef←
CD.CreateDrawRef[[
stopFlag~abortFlag,
interestClip~Bloat[ms.designStripeClip, MIN[(ms.design.technology.lambda*(extInfluenceDiameter+biggestDelta))/ms.nmPerLambda, 0]],
drawRect~IncludeRectangle,
devicePrivate~(di ← NEW[DrawInfoRec ← [rects: rects, ms: ms]]),
contextFilter~cf,
symbolics~FALSE,
showErrors~FALSE,
design~ms.design
]];
FOR list:
LIST
OF CDLayer ← layers, list.rest
WHILE list #
NIL
DO
layer: CDLayer ← list.first;
cf[layer.source] ← TRUE;
di.layers[layer.source] ← [used: TRUE, deltaDiameter: layer.deltaDiameter*ms.tadsPerNm];
IF di.layers[layer.source].deltaDiameter < 0 THEN ERROR;
biggestDelta ← MAX[biggestDelta, layer.deltaDiameter];
ENDLOOP;
CDOps.DrawDesign[ms.design, dr]; -- enumerate design rectangles into rects
END;
END;
IncludeRectangle:
PROC [ pr:
CD.DrawRef, r:
CD.Rect, l:
CD.Layer ] =
BEGIN
di: DrawInfo = NARROW[pr.devicePrivate];
IF di.layers[l].used
AND CDBasics.NonEmpty[r]
THEN
BEGIN
tr: TadRect ← ScaleCDToTad[ms: di.ms, cdr: r];
IF di.layers[l].deltaDiameter # 0
THEN
tr ← Bloat[tr, di.layers[l].deltaDiameter];
di.rects.ChangeRect[rect: tr, new: $covered];
END;
END;
OutputTile:
PROCEDURE [tile: CStitching.Tile, data:
REF
ANY]
-- CStitching.PerTileProc -- =
BEGIN -- only called on tiles with non-NIL values
DoOutput:
PROC =
BEGIN
ms: MaskState = NARROW[data];
tpp: Tad = ms.tadsPerNm*ms.mebesPixelPitch; -- tads per pixel
tr: TadRect = CDBasics.MoveRect[
r: CDBasics.Intersection[tile.Area, ms.tadStripeClip],
offset: CDBasics.NegOffset[CDBasics.BaseOfRect[ms.tadStripeClip]]
];
mr: MEBESRect = [x1: tr.x1/tpp, y1: tr.y1/tpp, x2: tr.x2/tpp, y2: tr.y2/tpp];
IF CDBasics.NonEmpty[mr]
THEN
BEGIN
ms.drawCommand^ ← [
x: mr.x1,
y: mr.y1,
w: mr.x2-mr.x1,
h: mr.y2-mr.y1
];
... think very carefully about this ...
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;
GenPatternFileName:
PROC [ mode: MEBESMode, maskSetName, maskName:
ROPE, row, col:
NAT ]
RETURNS [ rfn:
ROPE ] =
BEGIN
r: ROPE;
twoCharMaskName: ROPE = Rope.Substr[base: Rope.Cat[maskName, "xx"], len: 2];
SELECT mode
FROM
oneTwo, extended => {
r ← IO.PutFR[format: "%s%s.%g%g",
v1: IO.rope[Rope.Substr[base: Rope.Cat[maskSetName, "xxxxxxx"], len: 7]],
v2: IO.rope[twoCharMaskName],
v3: IO.char[LOOPHOLE['A+col]], v4: IO.char[LOOPHOLE['A+row]]];
};
reticle => {
IF row # 0 OR col # 0 THEN ERROR;
r ← IO.PutFR[format: "%s.%s",
v1: IO.rope[Rope.Substr[base: Rope.Cat[maskSetName, "xxxxxxx"], len: 9]],
v2: IO.rope[twoCharMaskName]];
};
ENDCASE => ERROR;
rfn ← Rope.Translate[base: r, translator: ToUpperCase];
END;
ToUpperCase:
PROC [old:
CHAR]
RETURNS [new:
CHAR]
-- Rope.TranslatorType -- =
{new ← Ascii.Upper[old]};
RopeToPatternFileName:
PROC [ rfn:
ROPE ]
RETURNS [ fn: PatternFileName ] =
{FOR i: [0..12) IN [0..12) DO fn[i] ← Rope.Fetch[rfn, i] ENDLOOP};
AbortFile:
PROC [s:
IO.
STREAM ]
RETURNS [
IO.
STREAM ] =
{IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]};
ComputeTadsPerNm:
PROC [ ms: MaskState, minAllowable: Tad ← 1 ] = {
prop: ATOM = $CDMEBESTadsPerNm;
ms.tadsPerNm ← NumericProp[ms, prop, NEW[INT ← defaultTadsPerNm]];
IF ms.tadsPerNm < minAllowable
THEN {
TerminalIO.PutF["\n\nSorry, your basic unit of measure of 1/%d nm was too large. I've made it smaller for you. Restarting conversion of this mask.\n", IO.int[ms.tadsPerNm]];
ms.tadsPerNm ← minAllowable;
defaultTadsPerNm ← MAX[defaultTadsPerNm, minAllowable];
IF Prop[ms, $CDMEBESTadsPerNm,
NIL] #
NIL
THEN
CDProperties.PutDesignProp[ms.design, prop, NEW[Tad ← minAllowable]];
};
};
Module START code...
END. -- of CDMEBESMainImpl