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 ]]]; }; 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; 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]]; 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]]; 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; 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 ]; 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, April 30, 1987 6:36:33 pm PDT Last edited by: Christian Jacobi, May 7, 1987 5:11:20 pm PDT Last Edited by: McCreight December 2, 1987 1:17:55 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˜š‘œž œ˜9Jšžœž˜ Jšœ.˜.šžœ!žœ˜)Jšœ9˜9Jšž˜J˜—šžœ/žœ˜7Jšœ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šžœ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•StartOfExpansion'[t: CD.Technology, uniqueKey: ATOM]šœžœ<˜WJ˜Jšœ˜šœžœ4ž˜LJšœ=žœ(˜i—Jšœžœ ˜7Jšœžœ#˜=Jšœ6˜6Jšœ˜J˜šœ9žœ ˜FJšœ)žœ ˜7J˜—Jš œžœžœžœžœžœžœ˜KJ˜Jšœžœžœ˜,J˜šžœžœžœžœžœžœžœž˜Ašžœ žœž˜šœ!˜!Jšœ,˜,—Jšžœžœ˜—Jšžœ’˜ —šžœžœ ž˜$Jšœ6˜6—Jšœžœ˜J˜šžœž˜$Jš žœžœžœ$žœžœžœ ˜ξJ˜—Jšœ.˜.J˜šžœžœ˜Jšœ˜šœžœ˜.Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ žœ˜Jšœ žœ˜Jšœ˜Jšœ˜JšœD™D—J˜—J˜Jšžœžœ#žœ˜LJ˜šœ&˜&Jšœ˜Jšœ9˜9Jšœ˜—J˜šžœžœžœžœžœžœžœž˜Cšžœ žœž˜Jšœ9˜9Jšžœ˜%—Jšžœ˜J˜—šœz˜zJšžœ˜ Jšžœ˜Jšžœ˜Jšžœ.˜0Jšžœ-˜/Jšœ˜—šžœžœ˜JšœI˜I—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˜—š‘œžœ(˜Cšžœžœž˜š œžœžœžœžœ˜šžœžœžœžœžœžœžœž˜6Jšœ#˜#Jšžœ˜——Jšœ7žœ˜šœžœ žœ˜"Jšœ˜Jšœ(žœW˜‚Jšœ˜Jšœžœ(˜?Jšœ˜Jšœ žœ˜Jšœ žœ˜Jšœ˜Jšœ˜J˜—š žœžœžœžœžœž˜AJšœ˜Jšœžœ˜Jšœ!žœ3˜XJšžœ+žœžœ˜8Jšœžœ$˜6Jšžœ˜J˜—Jšœ!’)˜JJšžœ˜—Jšžœ˜J˜—š ‘œžœžœ žœ žœ ˜DJšž˜Jšœžœ˜(šžœžœž˜2Jšž˜Jšœ.˜.šžœ ž˜&Jšœ+˜+—Jšœ-˜-Jšžœ˜—Jšžœ˜J˜J˜—š ‘ œž œžœžœ’œ˜[Jšžœ’+˜1J˜š‘œžœ˜Jšž˜Jšœžœ˜Jšœ,’˜=šœ ˜ Jšœ6˜6JšœA˜AJšœ˜—JšœM˜Mšžœž˜Jšž˜šœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜J™'—Jšœ+˜+Jšœ*˜*Jšžœ˜—Jšžœ˜J˜—šžœ žœž˜šœžœ˜ šžœž˜ Jšœ˜Jšžœžœ˜——Jšžœžœ˜—Jšžœ˜J˜—J˜š‘œžœžœ˜!Jšžœž˜ Jšœ=˜=Jšœ žœžœ#žœžœ žœ žœžœžœ˜•Jšžœ žœžœžœ˜AJšžœ˜J˜J˜—š ‘œžœ+žœ žœžœžœ˜pJšž˜Jšœžœ˜Jšœžœ7˜Lšžœž˜šœ˜Jšœžœ žœHžœžœžœžœžœ ˜ΘJšœ˜—šœ ˜ Jšžœ žœ žœžœ˜!JšœžœžœHžœ˜†Jšœ˜—Jšžœžœ˜—Jšœ7˜7Jšžœ˜J˜J˜—š ‘ œžœžœžœžœ’œ˜MJšœ˜J˜J˜—š‘œžœžœžœ˜KJš œžœ žœ žœžœ˜BJ˜J˜—š‘ œžœžœžœžœžœžœ˜7Jš œžœžœžœžœžœžœ˜2J˜J˜—š‘œžœ-˜CJšœžœ˜Jšœ%žœžœ˜Bšžœžœ˜%Jšœ™žœ˜―Jšœ˜Jšœžœ!˜7šžœžœžœž˜.Jšœ,žœ˜E—J˜—J˜J˜J˜—Jšœ™J™šœ˜J˜—Jšžœ’˜—J˜—…—VZuΠ