DIRECTORY AMBridge, AMTypes, Ascii, Atom, Basics, BasicTime, CD, CDBasics, CDCells, CDCommandOps, CDImports, CDMEBES, CDMenus, 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, CDMenus, 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]; today: Date; Init: PROC ~ { CDSequencer.ImplementCommand[key~$MEBESMask , proc~StartMEBESMask, queue~doQueue]; CDMenus.CreateEntry[menu~$ProgramMenu, entry~"MEBES mask generation", key~$MEBESMask]; TerminalIO.WriteRope["ChipNDale MEBES mask generator loaded\n"]; }; StartMEBESMask: PUBLIC PROC [comm: CDSequencer.Command] = TRUSTED BEGIN TerminalIO.WriteRope["MEBES-mask generation\n"]; IF CDCells.IsPushedIn[comm.design] THEN { TerminalIO.WriteRope["**Design is pushed in; not done\n"]; RETURN }; IF CDImports.HasUnloadedImports[comm.design] THEN { TerminalIO.WriteRope["**Design has non bound imports; not done\n"]; RETURN }; TerminalIO.WriteRope["Releases lock of design, but design MUST NOT be changed\n"]; abortFlag^ _ FALSE; [] _ CDCommandOps.CallWithResource[proc: MEBESMask, comm: comm, resource: $MEBESMask, abortFlag: abortFlag]; END; MEBESMask: PROC [ comm: CDSequencer.Command ] = BEGIN NotePunt: PROC = {TerminalIO.WriteRope[IO.PutFR["\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.WriteRope[IO.PutFR[" .. 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.WriteRope[IO.PutFR["\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.WriteRope[IO.PutFR[" .. 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; 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.WriteRope[IO.PutFR["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] ]]; 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.WriteRope[IO.PutFR["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.WriteRope[IO.RopeFromROS[rs]]; END; ENDLOOP; -- m TerminalIO.WriteRope[IO.PutFR["\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; 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.WriteRope[IO.PutFR["\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.WriteRope[IO.PutFR[".%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.AddSize[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.WriteRope[IO.PutFR["\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 by Xerox Corporation. All rights reserved. written by E. McCreight, November 2, 1983 6:03 pm Last Edited by: Jacobi, December 17, 1985 10:56:41 am PST McCreight, December 11, 1986 2:40:14 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œ1™