<> <> <> <> <> <> <<>> <> <<>> <> <> <<3392 Investment Boulevard>> <> <> <> <> <<>> DIRECTORY Ascii, Atom, CD, CDCommandOps, CDViewer, CDBasics, CDMenus, CDOps, CDSequencer, CDProperties, CornerStitching, FS, List, IO, Process, Rope, TerminalIO, BasicTime; EBESMaskImpl: CEDAR PROGRAM IMPORTS Ascii, Atom, BasicTime, CD, CDCommandOps, CDBasics, CDMenus, CDOps, CDProperties, CDSequencer, CDViewer, CornerStitching, FS, IO, List, Process, Rope, TerminalIO EXPORTS = BEGIN <> <<>> Nm: TYPE = CD.Number; EBESPixels: TYPE = CD.Number; EBESRect: TYPE = CD.Rect; Rational: TYPE = RECORD [num, denom: INT _ 1]; ROPE: TYPE = Rope.ROPE; Tesselation: TYPE = REF CornerStitching.Tesselation; TessList: TYPE = LIST OF Tesselation; <> MaskState: TYPE = REF MaskStateRec; MaskStateRec: TYPE = RECORD [ design: CD.Design, nmPerLambda: INT _ 1000, designClip: REF CD.DesignRect _ NIL, designStripeClip: CD.Rect _ [0,0,0,0], maskSetName, patternFileName: ROPE _ NIL, maskSetSpec: MaskSetSpec _ NIL, s: IO.STREAM, -- EBES stream where rectangles are to be drawn scale: Rational, drawCommand: REF DrawRectangle, stripeClip: EBESRect _ [0,0,0,0], reticleClip: EBESRect _ [0,0,0,0], stripe: [0..maxStripes] _ 0, stripeRectCount: INT _ 0, scribe: Scribe, data: REF _ NIL ]; <> MaskSetSpec: TYPE = LIST OF REF ANY -- MaskSpec -- ; MaskSpec: TYPE = REF MaskSpecRec; MaskSpecRec: TYPE = RECORD [ name: ROPE, cover: CoverSpec ]; <> CoverSpec: TYPE = REF ANY -- Atom ($NOT, $AND, $OR) followed by list of Coverspec, CDLayer, Scribe, Enlarge -- ; <<... for example, LIST[$OR, NEW[CDLayerRec _ [source: %CMos.ndif, deltaDiameter: 1000 -- nm --]], NEW[CDLayerRec _ [source: %CMos.pdif, deltaDiameter: 1000 -- nm --]], NEW[CDLayerRec _ [source: %CMos.pwelCont, deltaDiameter: 1000 -- nm --]], NEW[CDLayerRec _ [source: %CMos.nwelCont, deltaDiameter: 1000 -- nm --]], NEW[ScribeRec _ [dieEdgeToLineCenter: 0, lineWidth: 110000 -- nm --]]]]>> <<>> Enlarge: TYPE = REF EnlargeRec _ NIL; EnlargeRec: TYPE = RECORD [ basis: CoverSpec, deltaDiameter: Nm _ 0 ]; CDLayer: TYPE = REF CDLayerRec _ NIL; CDLayerRec: TYPE = RECORD [ source: CD.Layer, deltaDiameter: Nm _ 0 -- + means mask feature is bigger than layer feature ]; Scribe: TYPE = REF ScribeRec _ NIL; ScribeRec: TYPE = RECORD [ dieEdgeToLineCenter, lineWidth: Nm _ 0 ]; <> stripeHeight: INT = 256; -- in EBES units maxStripes: INT = 255; maskHeight: INT = maxStripes*stripeHeight; maskWidth: INT = 32768; StartDrawing: TYPE = MACHINE DEPENDENT RECORD [ nFields (0: 0..7): [0..256) _ 2, addressCode (0: 8..15): AddressCode _ Nm500, cx (1): CARDINAL[0..maskWidth], -- 0 is illegal cy (2): CARDINAL[0..maskHeight], -- 0 is illegal moDayYr (3): Date, field1Size (6): CARDINAL _ 6, patternFileName (7): FileName, field2Size (13): CARDINAL _ 2, maskInfo (14): PACKED ARRAY [0..4) OF CHAR _ ALL[' ] ]; AddressCode: TYPE = MACHINE DEPENDENT {Nm1000(0), Nm500(3), Nm250(6)}; Date: TYPE = PACKED ARRAY [0..6) OF CHAR _ ALL[' ]; <> FileName: TYPE = PACKED ARRAY [0..12) OF CHAR _ ALL[' ]; <<[9] must be '. , [10] is column ['A..'Z], [11] is row ['A..'Z]>> DrawRectangle: TYPE = MACHINE DEPENDENT RECORD [ h (0: 0..9): [1..stripeHeight], -- Mesa biases subrange so 1 is represented as 0 commandCode (0: 10..15): [0..64) _ 16, w (1): CARDINAL[0..maskWidth], -- 0 is illegal x (2): CARDINAL[0..maskWidth), unused (3: 0..7): [0..256) _ 0, y (3: 8..15): [0..stripeHeight)]; StartStripe: TYPE = MACHINE DEPENDENT RECORD [ stripeNumber (0: 0..7): [0..maxStripes] _ 0, -- 0 is illegal commandCode (0: 8..15): [0..256) _ 7]; BasicCommand: TYPE = MACHINE DEPENDENT RECORD [commandCode (0): NAT _]; endStripe: BasicCommand = [commandCode: 8]; endRecord: BasicCommand = [commandCode: 9]; endDrawing: BasicCommand = [commandCode: 4]; <> nmPerEBESPixel: INT _ 250; stripesPerClump: INT _ 10; wDir: ROPE _ "///"; Init: PROC ~ { Atom.PutProp[$EBESOpProcs, $RestrictNImplant, NEW[CoverProc _ RestrictNImplant]]; CDSequencer.ImplementCommand[a~$EBESMask , p~StartEBESMask, queue~doQueue]; CDMenus.CreateEntry[menu~$ProgramMenu, entry~"EBES mask generation", key~$EBESMask]; TerminalIO.WriteRope["ChipNDale EBES mask generator loaded\n"]; }; <<>> abortFlag: REF BOOL _ NEW[BOOL]; StartEBESMask: PROC [comm: CDSequencer.Command] = TRUSTED BEGIN TerminalIO.WriteRope[" EBES-mask generation\n"]; TerminalIO.WriteRope[" not yet debugged\n"]; TerminalIO.WriteRope["Releases lock of design, but design MUST NOT be changed\n"]; abortFlag^ _ FALSE; [] _ CDCommandOps.CallWithResource[proc: EBESMask, comm: comm, resource: $EBESMask, abortFlag: abortFlag]; END; EBESMask: PROC [ comm: CDSequencer.Command ] = BEGIN NotePunt: PROC = {TerminalIO.WriteRope[IO.PutFR["\n*** EBES mask generation aborted at %g\n", IO.time[]]]}; BEGIN ENABLE BEGIN ABORTED => GOTO Punt; TerminalIO.UserAbort => GOTO Punt; UNWIND => NotePunt[]; END; MakeMask[comm: comm, streamGen: SimpleStreamGen]; IF abortFlag^ THEN NotePunt[]; EXITS Punt => NotePunt[]; END; END; SimpleStreamGen: PROC [ ms: MaskState ] RETURNS [ dest: IO.STREAM ] = BEGIN dest _ FS.StreamOpen[ fileName: IO.PutFR[format: "%g%g/%g", v1: IO.rope[wDir], v2: IO.rope[ms.maskSetName], v3: IO.rope[ms.patternFileName] ], accessOptions: create ]; END; MakeMask: PROC [comm: CDSequencer.Command, streamGen: PROC [ ms: MaskState ] RETURNS [ dest: IO.STREAM ], data: REF _ NIL ] = BEGIN Prop: PROC [prop: REF, default: REF _ NIL, nilOK: BOOL _ FALSE] RETURNS [value: REF] = BEGIN value _ CDProperties.GetPropFromDesign[ms.design, prop]; IF value = NIL THEN value _ CDProperties.GetPropFromTechnology[ms.design.technology, prop]; IF value = NIL THEN value _ CDProperties.GetPropFromAtom[$EBESMask, prop]; IF value = NIL THEN value _ default; IF value = NIL AND NOT nilOK THEN BEGIN TerminalIO.WriteRope[IO.PutFR[" .. no value for property %g.. ", IO.rope[ToRope[prop]]]]; ERROR TerminalIO.UserAbort; END; END; NumericProp: PROC [prop: REF, default: REF _ NIL] RETURNS [value: INT] = {value _ NARROW[Prop[prop], REF INT]^}; ms: MaskState = NEW[ MaskStateRec _ [ design: comm.design, drawCommand: NEW[DrawRectangle], data: data]]; dr: CD.DrawRef; ebesSize: CD.Position; ebesActiveToScribeCenter: EBESPixels; maxBloat: EBESPixels _ NumericProp[$CDxEBESNmMaxBloat, NEW[Nm _ 10000]]/nmPerEBESPixel; TRUSTED {Process.SetPriority[Process.priorityBackground]}; TerminalIO.WriteRope[IO.PutFR["\nEBES Mask Generation\nPreliminary analysis begun at %g.\n", IO.time[]]]; nmPerEBESPixel _ NumericProp[$CDxEBESNmPerEBESPixel]; ms.nmPerLambda _ NumericProp[$CDxEBESNmPerLambda]; ms.maskSetName _ ToRope[Prop[$CDxEBESMaskSetName]]; ms.maskSetSpec _ NARROW[Prop[$CDxEBESMaskSetSpec]]; ms.scale _ ReduceRational[[num: ms.nmPerLambda, denom: CD.lambda*nmPerEBESPixel]]; ebesSize.x _ NumericProp[$CDxEBESXNmPerDie]/nmPerEBESPixel; ebesSize.y _ NumericProp[$CDxEBESYNmPerDie]/nmPerEBESPixel; ebesActiveToScribeCenter _ NumericProp[$CDxEBESActiveToScribeCenter]/nmPerEBESPixel; dr _ CD.CreateDrawRef[ms.design]; dr.minimalSize _ 0; dr.interestClip _ CDBasics.universe; dr.stopFlag _ abortFlag; dr.drawRect _ dr.saveRect _ NoteLayer; dr.devicePrivate _ ms; CDOps.DrawDesign[ms.design, dr]; -- measure design IF NOT abortFlag^ THEN BEGIN ENABLE -- for ERRORs BEGIN UNWIND => ms.s _ AbortFile[ms.s]; END; ComputeReticleClip: PROC RETURNS [c: EBESRect] = BEGIN AdjustReticleSize: PROC [coord: ROPE, z1, z2, zSize: EBESPixels] RETURNS [newZ1, newZ2: EBESPixels] = BEGIN IF z2-z1 > zSize THEN {TerminalIO.WriteRope[IO.PutFR[" .. design %g size of %d EBES units is larger than allowed die size of %d EBES units ..", IO.rope[coord], IO.int[c.x2-c.x1+1], IO.int[zSize]]]; ERROR TerminalIO.UserAbort}; newZ1 _ (z1+z2-zSize)/2; newZ2 _ newZ1+zSize; END; c _ CDBasics.Extend[Bloat[ScaleCDToEBES[ms, ms.designClip^], maxBloat], ebesActiveToScribeCenter]; [c.x1, c.x2] _ AdjustReticleSize["x", c.x1, c.x2, ebesSize.x]; [c.y1, c.y2] _ AdjustReticleSize["y", c.y1, c.y2, ebesSize.y]; END; today: Date = Today[]; reticleClip: EBESRect _ ms.reticleClip _ ComputeReticleClip[]; nRows: NAT = Ceiling[[num: reticleClip.y2-reticleClip.y1, denom: maskHeight]]; nCols: NAT = Ceiling[[num: reticleClip.x2-reticleClip.x1, denom: maskWidth]]; maskCount: INT; TRUSTED {maskCount _ List.Length[LOOPHOLE[ms.maskSetSpec]]}; TerminalIO.WriteRope[IO.PutFR["Preliminary analysis finished at %g. Making %d masks at %d (x) x %d (y) EBES pixels.\n", IO.time[], IO.int[maskCount], IO.int[reticleClip.x2-reticleClip.x1], IO.int[reticleClip.y2-reticleClip.y1]]]; WriteTapeDirectory[streamGen, ms, nRows, nCols, today]; FOR m: LIST OF REF ANY _ ms.maskSetSpec, m.rest WHILE m#NIL DO maskSpec: MaskSpec = NARROW[m.first]; FOR col: NAT IN [0..nCols) DO FOR row: NAT IN [0..nRows) DO ms.patternFileName _ PatternFileName[maskSetName: ms.maskSetName, maskName: maskSpec.name, row: row, col: col]; ms.s _ EBESOpen[streamGen[ms]]; TerminalIO.WriteRope[IO.PutFR["\nStarting mask %g at %g ", IO.rope[ms.patternFileName], IO.time[]]]; SendCommand[s: ms.s, comm: NEW[StartDrawing _ [ patternFileName: RopeToFileName[ms.patternFileName], cx: MIN[maskWidth, reticleClip.x2-reticleClip.x1-col*maskWidth], cy: MIN[maskHeight, reticleClip.y2-reticleClip.y1-row*maskHeight], moDayYr: today, addressCode: (SELECT nmPerEBESPixel FROM 1000 => Nm1000, 500 => Nm500, 250 => Nm250, ENDCASE => Nm500)]]]; FOR stripeBase: INT -- [0..maxStripes) -- _0, stripeBase+stripesPerClump WHILE stripeBase < MIN[maxStripes, Ceiling[[num: reticleClip.y2-reticleClip.y1-maskHeight*row, denom: stripeHeight]]] DO rects: Tesselation _ NIL; IF abortFlag^ THEN GOTO AbortMask; ms.designStripeClip _ ScaleEBESToCD[ms, [ x1: ms.reticleClip.x1+col*maskWidth-1, y1: ms.reticleClip.y1+row*maskHeight+stripeBase*stripeHeight-1, x2: ms.reticleClip.x1+(col+1)*maskWidth+1, y2: ms.reticleClip.y1+row*maskHeight+(stripeBase+stripesPerClump)*stripeHeight+1 ]]; CDViewer.ShowArrow[ design: ms.design, pos: CDBasics.Center[ms.designStripeClip]]; <<.. keep user happy>> rects _ GenerateCover[ms, maskSpec.cover]; FOR stripe: INT -- [0..maxStripes) -- IN [stripeBase..MIN[stripeBase+stripesPerClump, maxStripes, Ceiling[[num: reticleClip.y2-reticleClip.y1-maskHeight*row, denom: stripeHeight]]]) DO ms.stripeClip _ CDBasics.Intersection[ms.reticleClip, [ x1: ms.reticleClip.x1+col*maskWidth, y1: ms.reticleClip.y1+row*maskHeight+stripe*stripeHeight, x2: ms.reticleClip.x1+(col+1)*maskWidth, y2: ms.reticleClip.y1+row*maskHeight+(stripe+1)*stripeHeight ]]; ms.stripeRectCount _ 0; SendCommand[s: ms.s, comm: NEW[StartStripe _ [stripeNumber: stripe+1]]]; [] _ rects.EnumerateArea[rect: ms.stripeClip, perTile: OutputTile, data: ms]; SendCommand[s: ms.s, comm: NEW[BasicCommand _ endStripe]]; TerminalIO.WriteRope[IO.PutFR[".%d", IO.int[ms.stripeRectCount]]]; -- end of stripe ENDLOOP; rects _ DisposeTesselation[rects]; ENDLOOP; SendCommand[s: ms.s, comm: NEW[BasicCommand _ endDrawing]]; ms.s.Close[]; ms.s _ NIL; ENDLOOP; ENDLOOP; ENDLOOP; TerminalIO.WriteRope[IO.PutFR["\nEBES mask generation finished at %g\n", IO.time[]]]; EXITS AbortMask => {ms.s _ AbortFile[ms.s]}; END; END; NoteLayer: PROC [ r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef ] = BEGIN ms: MaskState = NARROW[pr.devicePrivate]; IF abortFlag^ THEN ERROR TerminalIO.UserAbort; IF ms.designClip=NIL THEN ms.designClip _ NEW[CD.DesignRect _ r]; ms.designClip^ _ CDBasics.Surround[ms.designClip^, r]; END; NewTesselation: PROC [ initValue: REF _ NIL ] RETURNS [ tess: Tesselation ] = BEGIN tess _ CornerStitching.NewTesselation[]; tess.ChangeRect[CDBasics.universe, initValue]; END; DisposeTesselation: PROC [ tess: Tesselation ] RETURNS [ Tesselation ] = BEGIN CornerStitching.FreeTesselation[plane: tess, freeCache: FALSE]; RETURN[NIL]; END; CoverProc: TYPE = PROC [ ms: MaskState, spec: LIST OF REF ANY, extInfluenceDiameter: Nm _ 0 ] RETURNS [ result: Tesselation ]; GenerateCover: PROC [ ms: MaskState, spec: CoverSpec, extInfluenceDiameter: Nm _ 0 ] RETURNS [ rects: Tesselation ] = BEGIN WITH spec SELECT FROM list: LIST OF REF ANY => BEGIN atom: ATOM = NARROW[list.first]; SELECT atom FROM $NOT => BEGIN ComplementTile: PROC [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = {rects.ChangeRect[CDBasics.Intersection[CDBasics.universe, tile.Area], $covered]}; basis: Tesselation _ GenerateCover[ms, list.rest.first, extInfluenceDiameter]; rects _ NewTesselation[NIL]; [] _ basis.EnumerateArea[rect: CDBasics.universe, perTile: ComplementTile, backgroundValue: $covered]; basis _ DisposeTesselation[basis]; END; $AND => BEGIN NilTile: PROC [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = {rects.ChangeRect[tile.Area, NIL]}; rects _ GenerateCover[ms, list.rest.first, extInfluenceDiameter]; FOR rest: LIST OF REF ANY _ list.rest.rest, rest.rest WHILE rest # NIL DO term: Tesselation _ GenerateCover[ms, rest.first, extInfluenceDiameter]; [] _ term.EnumerateArea[rect: CDBasics.universe, perTile: NilTile, backgroundValue: $covered]; term _ DisposeTesselation[term]; ENDLOOP; END; $OR => BEGIN CoverTile: PROC [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = {rects.ChangeRect[tile.Area, $covered]}; rects _ GenerateCover[ms, list.rest.first, extInfluenceDiameter]; FOR rest: LIST OF REF ANY _ list.rest.rest, rest.rest WHILE rest # NIL DO term: Tesselation _ GenerateCover[ms, rest.first, extInfluenceDiameter]; [] _ term.EnumerateArea[rect: CDBasics.universe, perTile: CoverTile]; term _ DisposeTesselation[term]; ENDLOOP; END; ENDCASE => -- atom has a procedure registered for it BEGIN <<(e.g., LIST[$Bletch, NEW[INT _ 2], NEW[CDLayer _ []], NEW[CDLayer _ []]] )>> ref: REF ANY = Atom.GetProp[$EBESOpProcs, atom]; rects _ NARROW[ref, REF CoverProc]^[ms, list.rest, extInfluenceDiameter]; END; END; enlarge: Enlarge => BEGIN deltaDiameter: EBESPixels = enlarge.deltaDiameter/nmPerEBESPixel; basis: Tesselation _ GenerateCover[ms, enlarge.basis, extInfluenceDiameter+enlarge.deltaDiameter]; SELECT deltaDiameter FROM <0 => ERROR; =0 => rects _ basis; ENDCASE => BEGIN EnlargeTile: PROC [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = {rects.ChangeRect[Bloat[tile.Area, deltaDiameter], tile.Value]}; rects _ NewTesselation[NIL]; [] _ basis.EnumerateArea[rect: CDBasics.universe, perTile: EnlargeTile]; basis _ DisposeTesselation[basis]; END; END; layer: CDLayer => SELECT layer.deltaDiameter FROM >=0 => BEGIN dr: CD.DrawRef; deltaDiameter: EBESPixels = layer.deltaDiameter/nmPerEBESPixel; rects _ NewTesselation[NIL]; dr _ CD.CreateDrawRef[ms.design]; dr.minimalSize _ 0; dr.stopFlag _ abortFlag; dr.interestClip _ Bloat[ms.designStripeClip, MIN[(CD.lambda*(extInfluenceDiameter+layer.deltaDiameter))/ms.nmPerLambda, 0]]; dr.drawRect _ dr.saveRect _ IncludeRectangle; dr.devicePrivate _ NEW[DrawInfoRec _ [layer: layer.source, deltaDiameter: deltaDiameter, rects: rects, ms: ms]]; CDOps.DrawDesign[ms.design, dr]; -- enumerate design rectangles into rects END; ENDCASE => rects _ GenerateCover[ms, LIST[$NOT, NEW[EnlargeRec _ [basis: LIST[$NOT, NEW[CDLayerRec _ [source: layer.source]]], deltaDiameter: -layer.deltaDiameter]]], extInfluenceDiameter]; scribe: Scribe => BEGIN r: CD.Rect = ms.reticleClip; outer: EBESPixels = MAX[scribe.dieEdgeToLineCenter-scribe.lineWidth/2, 0]/nmPerEBESPixel; inner: EBESPixels = (scribe.dieEdgeToLineCenter+scribe.lineWidth/2)/nmPerEBESPixel; rects _ NewTesselation[NIL]; rects.ChangeRect[[x1: r.x1+outer, y1: r.y1+outer, x2: r.x1+inner, y2: r.y2-outer], $covered]; rects.ChangeRect[[x1: r.x2-inner, y1: r.y1+outer, x2: r.x2-outer, y2: r.y2-outer], $covered]; rects.ChangeRect[[x1: r.x1+outer, y1: r.y1+outer, x2: r.x2-outer, y2: r.y1+inner], $covered]; rects.ChangeRect[[x1: r.x1+outer, y1: r.y2-inner, x2: r.x2-outer, y2: r.y2-outer], $covered]; END; ENDCASE => ERROR; END; DrawInfo: TYPE = REF DrawInfoRec; DrawInfoRec: TYPE = RECORD [ layer: CD.Layer, deltaDiameter: EBESPixels, rects: Tesselation, ms: MaskState ]; IncludeRectangle: PROC [ r: CD.DesignRect, l: CD.Layer, pr: CD.DrawRef ] = BEGIN di: DrawInfo = NARROW[pr.devicePrivate]; IF l = di.layer AND CDBasics.NonEmpty[r] THEN BEGIN er: CD.Rect _ ScaleCDToEBES[ms: di.ms, cdr: r]; IF di.deltaDiameter#0 THEN er _ Bloat[er, di.deltaDiameter]; di.rects.ChangeRect[rect: er, newValue: $covered]; END; END; RestrictNImplant: PROC [ ms: MaskState, spec: LIST OF REF ANY, extInfluenceDiameter: Nm _ 0 ] RETURNS [ result: Tesselation ] -- CoverProc -- = BEGIN PlaceNImplant: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = BEGIN InteractWithPImplant: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = BEGIN Relationship: TYPE = {pNn, pEn, pSn, pWn}; pTile: CornerStitching.TilePtr = tile; pTileArea: EBESRect = pTile.Area; bestDir: Relationship; bestGap: EBESPixels _ -1; tGap: EBESPixels; gaps: ARRAY Relationship OF EBESPixels _ ALL[maxRadialExtension]; deInsertedArea: EBESRect; IF (tGap _ nTileArea.x1-pTileArea.x2)>bestGap THEN {bestDir _ $pWn; bestGap _ tGap}; IF (tGap _ pTileArea.x1-nTileArea.x2)>bestGap THEN {bestDir _ $pEn; bestGap _ tGap}; IF (tGap _ nTileArea.y1-pTileArea.y2)>bestGap THEN {bestDir _ $pSn; bestGap _ tGap}; IF (tGap _ pTileArea.y1-nTileArea.y2)>bestGap THEN {bestDir _ $pNn; bestGap _ tGap}; IF bestGap<0 THEN ERROR; -- design rule violation IF NOT anyInteractingPImplant THEN BEGIN anyInteractingPImplant _ TRUE; nImplPieces.ChangeRect[CDBasics.universe, NIL]; nImplPieces.ChangeRect[desiredNImplant, $covered]; END; gaps[bestDir] _ bestGap/2; deInsertedArea _ [x1: pTileArea.x1-gaps[$pEn], y1: pTileArea.y1-gaps[$pNn], x2: pTileArea.x2+gaps[$pWn], y2: pTileArea.y2+gaps[$pSn]]; IF CDBasics.NonEmpty[deInsertedArea] THEN nImplPieces.ChangeRect[deInsertedArea, NIL]; END; CoverNegotiatedPiece: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = {area: EBESRect = tile.Area; result.ChangeRect[area, $covered]}; nTile: CornerStitching.TilePtr = tile; nTileArea: EBESRect = nTile.Area; desiredNImplant: EBESRect = CDBasics.Extend[nTileArea, maxRadialExtension]; anyInteractingPImplant: BOOL _ FALSE; [] _ pDif.EnumerateArea[rect: CDBasics.Extend[nTileArea, 2*maxRadialExtension], perTile: InteractWithPImplant]; IF NOT anyInteractingPImplant THEN result.ChangeRect[desiredNImplant, $covered] ELSE [] _ nImplPieces.EnumerateArea[desiredNImplant, CoverNegotiatedPiece]; END; maxRadialExtension: EBESPixels = NARROW[spec.first, REF INT]^/nmPerEBESPixel; nDif: Tesselation _ GenerateCover[ms, spec.rest.first, extInfluenceDiameter+2*maxRadialExtension]; pDif: Tesselation _ GenerateCover[ms, spec.rest.rest.first, extInfluenceDiameter+2*maxRadialExtension]; nImplPieces: Tesselation _ NewTesselation[]; result _ NewTesselation[]; [] _ nDif.EnumerateArea[rect: CDBasics.universe, perTile: PlaceNImplant]; nDif _ DisposeTesselation[nDif]; pDif _ DisposeTesselation[pDif]; nImplPieces _ DisposeTesselation[nImplPieces]; END; OutputTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = BEGIN -- only called on tiles with non-NIL values DoOutput: PROC = BEGIN ms: MaskState = NARROW[data]; cr: CD.Rect = CDBasics.Intersection[tile.Area, ms.stripeClip]; IF CDBasics.NonEmpty[cr] THEN BEGIN ms.drawCommand^ _ [x: cr.x1-ms.stripeClip.x1, y: cr.y1-ms.stripeClip.y1, w: cr.x2-cr.x1, h: cr.y2-cr.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; PatternFileName: PROC [ maskSetName, maskName: ROPE, row, col: NAT ] RETURNS [ rfn: ROPE ] = BEGIN r: ROPE = IO.PutFR[format: "%s%s.%g%g", v1: IO.rope[Rope.Substr[base: Rope.Cat[maskSetName, "xxxxxxx"], len: 7]], v2: IO.rope[Rope.Substr[base: Rope.Cat[maskName, "xx"], len: 2]], v3: IO.char[LOOPHOLE['A+col]], v4: IO.char[LOOPHOLE['A+row]]]; rfn _ Rope.Translate[base: r, translator: ToUpperCase]; END; ToUpperCase: PROC [old: CHAR] RETURNS [new: CHAR] -- Rope.TranslatorType -- = {new _ Ascii.Upper[old]}; RopeToFileName: PROC [ rfn: ROPE ] RETURNS [ fn: FileName ] = {FOR i: [0..12) IN [0..12) DO fn[i] _ Rope.Fetch[rfn, i] ENDLOOP}; WriteTapeDirectory: PROC [ streamGen: PROC [ms: MaskState] RETURNS [dest: IO.STREAM], ms: MaskState, nRows, nCols: NAT, today: Date] = BEGIN s: IO.STREAM; nMasks: NAT _ 0; FOR m: LIST OF REF ANY _ ms.maskSetSpec, m.rest WHILE m#NIL DO nMasks _ nMasks+1; ENDLOOP; ms.patternFileName _ IO.PutFR["%g.arch", IO.rope[ms.maskSetName]]; s _ EBESOpen[dest: streamGen[ms], eor: FALSE]; SendCommand[s, NEW[CARDINAL _ 0]]; -- marked "reserved" in Varian Figure A-1 SendCommand[s, NEW[CARDINAL _ nRows*nCols*nMasks]]; -- count of files FOR m: LIST OF REF ANY _ ms.maskSetSpec, m.rest WHILE m#NIL DO maskSpec: MaskSpec = NARROW[m.first]; FOR col: NAT IN [0..nCols) DO FOR row: NAT IN [0..nRows) DO s.PutF[format: "%s ", v1: IO.rope[PatternFileName[ms.maskSetName, maskSpec.name, row, col]]]; ENDLOOP; ENDLOOP; ENDLOOP; SendCommand[s, NEW[Date _ today]]; s.Close[]; END; AbortFile: PROC [s: IO.STREAM ] RETURNS [ IO.STREAM ] = {IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]}; SendCommand: PROC [ s: IO.STREAM, comm: REF ] = BEGIN sizeInWords: NAT; WITH comm SELECT FROM c: REF DrawRectangle => sizeInWords _ SIZE[DrawRectangle]; c: REF BasicCommand => sizeInWords _ SIZE[BasicCommand]; c: REF StartStripe => sizeInWords _ SIZE[StartStripe]; c: REF StartDrawing => sizeInWords _ SIZE[StartDrawing]; c: REF Date => sizeInWords _ SIZE[Date]; c: REF FileName => sizeInWords _ SIZE[FileName]; c: REF CARDINAL => sizeInWords _ SIZE[CARDINAL]; ENDCASE => ERROR; TRUSTED {s.UnsafePutBlock[[base: LOOPHOLE[comm], startIndex: 0, count: 2*sizeInWords]]}; END; <> EBESStreamStateRef: TYPE = REF EBESStreamState; EBESStreamState: TYPE = RECORD [ dest: IO.STREAM, eor: BOOL, buf: REF TEXT]; ebesStreamProcs: REF IO.StreamProcs = IO.CreateStreamProcs[ variety: output, class: $EBESOutputStream, putChar: PutEBESChar, unsafePutBlock: PutEBESBlock, flush: FlushEBES, close: CloseEBES ]; EBESOpen: PROC [ dest: IO.STREAM, eor: BOOL _ TRUE ] RETURNS [ self: IO.STREAM ] = BEGIN state: EBESStreamStateRef = NEW[EBESStreamState _ [dest: dest, eor: eor, buf: NEW[TEXT[2048]]]]; state.buf.length _ 0; self _ IO.CreateStream[ streamProcs: ebesStreamProcs, streamData: state ]; END; PutEBESChar: PROC [ self: IO.STREAM, char: CHAR ] = TRUSTED BEGIN state: EBESStreamStateRef = NARROW[self.streamData]; FlushEBESIfNecessary[state, 1]; state.buf[state.buf.length] _ char; state.buf.length _ state.buf.length+1; END; PutEBESBlock: PROC [ self: IO.STREAM, block: IO.UnsafeBlock ] = TRUSTED BEGIN state: EBESStreamStateRef = NARROW[self.streamData]; FlushEBESIfNecessary[state, block.count]; FOR i: INT IN [0..block.count) DO CharArrayPtr: TYPE = LONG POINTER TO PACKED ARRAY [0..0) OF CHAR; state.buf[state.buf.length+i] _ LOOPHOLE[block.base, CharArrayPtr][block.startIndex+i]; ENDLOOP; state.buf.length _ state.buf.length+block.count; END; FlushEBESIfNecessary: PROC [state: EBESStreamStateRef, newBytes: NAT] = INLINE BEGIN IF state.buf.maxLength0 THEN BEGIN IF state.eor THEN BEGIN IF state.buf.length+2<=state.buf.maxLength THEN TRUSTED BEGIN -- append an end-of-record command to the buffer endRec: PACKED ARRAY [0..2) OF CHAR = LOOPHOLE[endRecord]; state.buf[state.buf.length] _ endRec[0]; state.buf[state.buf.length+1] _ endRec[1]; state.buf.length _ state.buf.length+2; END ELSE ERROR; -- can't terminate buffer properly END; FOR i: CARDINAL IN [state.buf.length..state.buf.maxLength) DO state.buf[i] _ 000C; -- pad out with 0's ENDLOOP; state.buf.length _ state.buf.maxLength; state.dest.PutBlock[state.buf]; END; state.buf.length _ 0; END; CloseEBES: PROC [ self: IO.STREAM, abort: BOOL _ FALSE ] = BEGIN state: EBESStreamStateRef = NARROW[self.streamData]; self.Flush[]; state.dest.Close[]; END; <> RopeNeeded: SIGNAL [ ref: REF REF ] = CODE; ToRope: PROC [ ref: REF ] RETURNS [ rope: ROPE ] = BEGIN IF ref = NIL THEN rope _ NIL ELSE WITH ref SELECT FROM r: ROPE => rope _ r; rt: REF TEXT => rope _ Rope.FromRefText[rt]; a: ATOM => rope _ Atom.GetPName[a]; ri: REF INT => rope _ IO.PutFR[format: "%d", v1: IO.int[ri^]]; ENDCASE => BEGIN refRef: REF REF = NEW[REF _ ref]; SIGNAL RopeNeeded[refRef]; rope _ ToRope[refRef^ ! RopeNeeded => GOTO NoHelp]; EXITS NoHelp => ERROR; END; END; ScaleCDToEBES: PROC [ ms: MaskState, cdr: CD.DesignRect ] RETURNS [ ebr: CD.Rect ] = BEGIN ebr _ CDBasics.NormalizeRect[ [x1: RatMul[ms.scale, cdr.x1], y1: RatMul[ms.scale, cdr.y1], x2: RatMul[ms.scale, cdr.x2], y2: RatMul[ms.scale, cdr.y2]]]; END; ScaleEBESToCD: PROC [ ms: MaskState, ebr: CD.Rect ] RETURNS [ cdr: CD.DesignRect ] = BEGIN cdr _ CDBasics.NormalizeRect[ [x1: RatDiv[ms.scale, ebr.x1], y1: RatDiv[ms.scale, ebr.y1], x2: RatDiv[ms.scale, ebr.x2], y2: RatDiv[ms.scale, ebr.y2]]]; END; Bloat: PROC [ r: CD.Rect, deltaDiameter: CD.Number ] RETURNS [ br: CD.Rect ] = BEGIN b0: NAT = deltaDiameter/2; -- split in "half" for radius b1: NAT = deltaDiameter-b0; <> br _ [x1: MAX[FIRST[CD.Number]+b0, r.x1]-b0, y1: MAX[FIRST[CD.Number]+b0, r.y1]-b0, x2: MIN[LAST[CD.Number]-b1, r.x2]+b1, y2: MIN[LAST[CD.Number]-b1, r.y2]+b1]; END; Ceiling: PROC [ r: Rational ] RETURNS [ c: INT ] = BEGIN c _ r.num/r.denom; <> IF ((r.num>0) = (r.denom>0)) AND r.num MOD r.denom # 0 THEN c _ c+1; END; ReduceRational: PROC [ r: Rational ] RETURNS [ Rational ] = BEGIN gcd: INT = IF r.num=0 THEN r.denom ELSE GCD[r.num, r.denom]; RETURN[[num: r.num/gcd, denom: r.denom/gcd]]; END; RatMul: PROC [ mul: Rational, z: INT ] RETURNS [ INT ] = INLINE {RETURN[(mul.num*z)/mul.denom]}; RatDiv: PROC [ div: Rational, z: INT ] RETURNS [ INT ] = INLINE {RETURN[(div.denom*z)/div.num]}; GCD: PROC [ m, n: INT ] RETURNS [ INT ] = BEGIN r: INT; SELECT m FROM <0 => m _ -m; ENDCASE => NULL; SELECT n FROM <0 => n _ -n; >0 => NULL; ENDCASE => RETURN[m]; r _ m MOD n; WHILE r>0 DO m _ n; n _ r; r _ m MOD n; ENDLOOP; RETURN[n]; END; <> <<>> Init[]; END. -- of EBESMaskImpl