<> <> <> <> <> <> <> <<>> <> <> <<3392 Investment Boulevard>> <> <<>> 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; <> 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>> }; 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; -- row 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]; END; 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]]; }; }; <> <<>> Init[]; END. -- of CDMEBESMainImpl