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"; 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] 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; foundErrorLayer _ FALSE; 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]]; CDOps.DrawDesign[ms.design, CD.CreateDrawRef[[ interestClip~CDBasics.universe, drawRect~NoteLayer, stopFlag~abortFlag, devicePrivate~ms, design~ms.design ]]]; 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: 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; -- m TerminalIO.PutF["\nMEBES mask generation finished at %g\n", IO.time[]]; EXITS AbortMask => {ms.s _ AbortFile[ms.s]}; END; END; NoteLayer: PROC [ r: CD.Rect, l: CD.Layer, pr: CD.DrawRef ] = 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; 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; 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 { 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]]; IF ms.mode = reticle THEN { 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]; 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]]; derivation.props _ derivation.props.PutPropOnList[ prop: $DropIns, val: ddi.PutPropOnList[ prop: di.name, val: InsertDropIn[ ms: ms, rects: rects, di: di, data: ddi.GetPropFromList[di.name] ] ] ]; 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]]; 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]]; 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 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; 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]]), design~ms.design ]]; FOR list: LIST OF CDLayer _ layers, list.rest WHILE list # NIL DO layer: CDLayer _ list.first; 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 [ r: CD.Rect, l: CD.Layer, pr: CD.DrawRef ] = 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.Intersection[tile.Area, ms.tadStripeClip]; IF CDBasics.NonEmpty[tr] THEN BEGIN ms.drawCommand^ _ [ x: (tr.x1-ms.tadStripeClip.x1)/tpp, y: (tr.y1-ms.tadStripeClip.y1)/tpp, w: (tr.x2-tr.x1)/tpp, h: (tr.y2-tr.y1)/tpp ]; 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 °CDMEBESMainImpl.mesa Copyright c 1985, 1987 by Xerox Corporation. All rights reserved. written by E. McCreight, November 2, 1983 6:03 pm McCreight, December 11, 1986 2:40:14 pm PST Last edited by: Christian Jacobi, March 23, 1987 6:16:50 pm PST A package to output a ChipnDale design in MEBES format for a Perkin-Elmer Lithographic System. Files produced herein should conform to the MEBES Mode I/II, extended mode, or reticle mode pattern file format described in the MEBES Software Manual, document A900-0102C, Data Files, document A900-0024D, publication of Perkin-Elmer Electron Beam Technology 3392 Investment Boulevard Hayward, CA 94545 Global Variables .. measure design in ChipNDale units, leaves result in ms.designClip ... index where the block count CARDINAL is stored in extended or reticle mode files .. open a new pattern file and generate a header .. to be filled in later with block count .. leave room for the segment (column) directory .. keep user happy .. fill in the number of blocks needed .. fill in the number of blocks needed (e.g., LIST[$Bletch, NEW[INT _ 2], NEW[CDLayer _ []], NEW[CDLayer _ []]] ) ... think very carefully about this ... Module START code... Κ=˜šœ™Icodešœ Οmœ7™BJšœ1™1K™+K™?—J˜JšœΌ™Ό™J™ J™J™J™—J˜J™šΟk ˜ Jš œ3žœ.žœ:žœžœ%˜ΟJ˜—šΠbnœžœž˜Jš žœ+žœ.žœ:žœžœ$˜ΝJšžœžœ˜Jšžœžœžœ˜˜J˜—JšΟb™J˜Jšœžœžœ˜!Jšœžœžœ˜!Jšœžœžœ˜Jš œ žœžœžœžœžœ˜'Jšœžœžœ˜J˜ J˜šΟnœžœ˜JšœR˜RJšœu˜uJšœ>˜>J˜J˜—J™J˜š‘œž œ˜9Jšžœž˜ Jšœ.˜.šžœ!žœ˜)Jšœ9˜9Jšž˜J˜—šžœ+žœ˜3JšœB˜BJšž˜J˜—JšœP˜PJšœ žœ˜JšœU˜UJšžœ˜J˜J˜—š‘ œžœ ˜/Jšž˜J˜Jš‘œžœCžœ ˜]˜šžœž˜ Jšž˜Jšžœžœ˜Jšœžœ˜"Jšžœ˜Jšžœ˜—Jšœ2˜2Jšžœ žœ ˜Jšžœ˜Jšžœ˜—Jšžœ˜J˜J˜—Jš œžœžœžœ žœžœ˜IJ˜š ‘œžœžœ žœžœΟcœ˜YJšž˜šœžœ ˜šœ žœ˜&Jšœžœžœžœ ˜VJšœ˜—Jšœ˜Jšœ˜—Jšžœ˜J˜J˜—š ‘œžœžœ žœ žœ žœ˜UJšœ4˜4Jšžœ žœžœD˜WJšžœ žœžœ2˜EJšžœ žœžœ˜$šžœž˜Jšž˜Jšœ3žœ˜JJšžœ˜Jšžœ˜—Jšœ˜J˜—š‘ œžœžœ žœžœžœ žœ˜YJšœžœžœžœ˜2Jšœ˜J˜J˜—š‘ œžœ9˜HJ˜Jšž˜J˜J˜šœžœ˜%Jšœ˜Jšœ žœ˜"—J˜Jšžœ3˜:J˜JšœPžœ ˜[J˜šžœžœ ž˜šžœžœ’ ˜Jšž˜Jšžœ˜!Jšžœ˜J˜—š‘œžœžœ˜DJšž˜J˜š ‘œžœ žœžœžœ˜pJšž˜Jšœ'žœ˜8šžœž˜Jšœlžœžœ žœ ˜šJšžœ˜—Jšœ ˜ Jšœ˜Jšžœ˜J˜—šœ(˜(Jšœ%˜%Jšœ2˜2—Jšœˆ˜ˆJšœˆ˜ˆJšžœ’˜J˜—Jšœ3žœ˜DJšœI˜IJšœžœ˜J˜Jšœžœ˜Jšœ˜šœžœ4ž˜LJšœ=žœ(˜i—Jšœžœ ˜7Jšœžœ#˜=Jšœ6˜6Jšœ˜J˜šœ9žœ ˜FJšœ)žœ ˜7J˜—Jš œžœžœžœžœžœžœ˜KJ˜Jšœžœžœ˜,šœžœ˜.Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜JšœD™D—J˜šœ&˜&Jšœ˜Jšœ9˜9Jšœ˜—J˜šžœžœžœžœžœžœžœž˜Cšžœ žœž˜Jšœ9˜9Jšžœ˜%—Jšžœ˜J˜—šœz˜zJšžœ˜ Jšžœ˜Jšžœ˜Jšžœ.˜0Jšžœ-˜/Jšœ˜—šžœžœ˜JšœA˜A—J˜šžœžœžœžœžœžœžœž˜AJšœ žœ˜šžœ žœž˜šœ#˜#Jšœžœ4˜UJšœ˜šžœ ž˜šžœ1˜5šœ˜Jšœ%˜%Jšž˜Jšœ’˜——Jšžœ_žœ˜—J˜—šœ’!˜4Jšœ˜—Jšžœžœ˜J˜—Jšžœ žœžœ ˜"J˜šžœ žœž˜Jšž˜Jšœ žœ˜Jš œžœžœžœžœ˜Jšœžœ ˜)Jšžœ(˜/Jšœ7˜7Jšœžœ ˜Jšœžœ˜'Jšžœ˜—Jšžœ’˜ J˜—Jšœ<žœ ˜Gšž˜Jšœ&˜&—Jšžœ˜—Jšžœ˜J˜J˜—š ‘ œžœžœ žœ žœ ˜=Jšž˜Jšœžœ˜)Jšžœ žœžœ˜.Jšœžœ#žœ&žœ˜gJšžœžœ žœžœ˜/Jšžœ˜—˜J˜—J˜š‘ œžœf˜yJšž˜J˜š ‘œžœ ’œžœžœ’œ˜tJšœ˜Jšœžœ˜š žœžœžœ žœ’2˜KJšœ5˜5Jšœ ˜ šžœ žœ˜Jšœ&˜&Jšœ ˜ Jšœ˜—Jšžœ˜—Jšœ˜J˜—šœžœ˜JšœT™T—J˜šœ9˜9Jšœ!’œ˜8—šœžœ ˜Jšœ-’œ˜AJšœ’˜$Jšœ˜—šœžœ ˜Jšœ-’œ˜AJšœ’œ˜&J˜—Jšœžœ%˜:J˜Jšœ&˜&Jšœ˜J˜Jšœb˜bJ˜šžœžœžœ ž˜Jšœ6˜6J˜Jšžœžœžœ ž˜Jšœ9˜9˜Jšœžœžœj˜‚J˜šžœžœ žœ žœ˜4Jšœ0™0šœžœ˜Jšœm˜mJšœ˜—Jšœ˜Jšœ-žœ"žœ ˜\J˜šœžœž˜4šœ žœ˜$šœžœž˜*J˜ J˜ Jšžœžœ˜—JšœžœC˜JJšœžœE˜LJšœ˜JšœA˜AJšœ˜—šœ žœ˜+Jšœ0˜0Jšœ.˜.JšœžœC˜MJšœžœE˜OJšœ˜JšœA˜AJšœ˜—šœ žœ˜*Jšœ0˜0Jšœ.˜.JšœA˜AJšœ?˜?JšœA˜AJšœ?˜?Jšœ˜JšœB˜BJšœ žœžœžœ@˜`Jšœ˜—Jšžœžœ˜J˜—šžœžœ˜Jšœ&˜&šœžœžœ˜.J™)—šžœžœ˜J™0Jšœžœžœ˜3šžœ žœžœ ž˜!Jšœ˜Jšžœ˜—Jšœ˜—J˜—˜J˜——šžœžœ žœ’+˜SJšœ žœ˜ Jšœ8žœžœžœ˜fšœžœ˜4Jšœ(˜(Jšœ"žœ"˜GJšœ˜—J˜Jšœžœ5˜SJšœ˜J˜—Jš žœ žœ’œ!žœž˜m˜Jšœžœ˜J˜šžœ žœžœ˜J˜—šœ˜šœ)˜)Jšœ ˜ Jšœ#˜#Jšœ˜Jšœ4˜4Jšœ˜—šœ2˜2J˜——šœ&˜&JšœD˜DJ˜—Jšœ6˜6šœ;˜;Jšœ™J˜—Jšœžœ žœ1˜]J˜J˜š žœ žœžœžœ-ž˜Ršœ˜šœ)˜)Jšœ ˜ Jšœ˜Jšœ˜Jšœ"˜"Jšœ˜—Jšœ2˜2—Jšœ˜šœžœ ž˜/Jšœ žœ:˜GJšœ žœ?˜Nšœ žœ˜'Jšœ4˜4—Jšžœžœ˜—šžœžœžœžœžœžœžœž˜EJšœ žœ ˜Jšœžœ-˜Hšœ2˜2Jšœ˜šœ˜Jšœ˜šœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ"˜"Jšœ˜—Jšœ˜—Jšœ˜—Jšžœ˜—JšœQ˜QJšœžœ˜:Jšœžœ’˜DJšžœ’ ˜J˜—Jšœ"˜"Jšžœ’ ˜J˜—šžœžœ˜Jšœžœ˜;Jšœ ˜ šžœžœ˜Jšœ žœ˜ Jšœ#˜#šœžœžœ˜DJšœ&™&—J˜Jšœ˜—Jšœ ˜ Jšœžœ˜ J˜——˜Jšžœ’˜—Jšžœ’˜J˜—šžœžœ˜Jšœ žœ˜Jšœžœ˜;Jšœ ˜ Jšœ˜Jšœ#˜#šœžœžœ˜DJšœ&™&—J˜Jšœ ˜ Jšœžœ˜ J˜J˜—Jšžœ˜J˜J˜—š‘œžœ%˜9Jšž˜Jšžœ˜J˜J˜—š‘ œžœžœCžœ˜}Jšž˜šžœžœž˜š œžœžœžœžœ˜Jšž˜Jš’J™JJšœžœžœ0˜