DIRECTORY Ascii, Atom, CD, CDViewer, CDInline, CDOps, CDSequencer, CDProperties, CornerStitching, FS, IO, PriorityQueue, Process, Rope, TerminalIO, BasicTime; EBESMaskImpl: CEDAR MONITOR IMPORTS Ascii, Atom, CD, CDViewer, CDInline, CDOps, CDSequencer, CDProperties, CornerStitching, FS, IO, PriorityQueue, Process, Rope, --TapeStream,-- TerminalIO, BasicTime EXPORTS = BEGIN Rational: TYPE = RECORD [num, denom: INT _ 1]; MaskStateRef: TYPE = REF MaskState; MaskState: TYPE = RECORD [ s: IO.STREAM, -- EBES stream where rectangles are to be drawn scale: Rational, offset: CD.Position _ [0,0], -- in EBES co-ordinates drawCommand: REF DrawRectangle, level: CD.Level _ CD.combined, bloat: CD.Number _ 0, -- of this level in EBES pixels, half per side areas, unbloated: REF CornerStitching.Tesselation _ NIL, -- in offset EBES space stripeClip: CD.Rect _ [0,0,0,0] -- in offset EBES space ]; DesignDataRef: TYPE = REF DesignData; DesignData: TYPE = RECORD [ bbox: REF CD.DesignRect, used: REF PACKED ARRAY CD.Level OF BOOL ]; MaskDescriptionRef: TYPE = REF MaskDescription; MaskDescription: TYPE = RECORD [ lev: CD.Level, name: Rope.ROPE ]; 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[' ]; 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]; Init: ENTRY PROC ~ { CDSequencer.ImplementCommand[a~$EBESMask , p~ForkEBESMask]; TerminalIO.WriteRope["ChipNDale EBES mask generator loaded\n"]; }; ForkEBESMask: PROC [ c: CDSequencer.Command ] = TRUSTED BEGIN TerminalIO.WriteRope[" not yet debugged\n"]; TerminalIO.WriteRope["Releases lock of design, but design MUST NOT be changed\n"]; Process.Detach[FORK EBESMask[c]] END; EBESMask: ENTRY PROC [ c: CDSequencer.Command ] = BEGIN ENABLE BEGIN ABORTED => {TerminalIO.WriteRope[" mask generation aborted\n"]; GOTO Exit}; RopeNeeded => BEGIN explanation: Rope.ROPE = IO.PutFR[format: "Please enter a string corresponding to the value %g: ", v1: IO.refAny[ref^]]; ref^ _ TerminalIO.RequestRope[explanation]; RESUME; END; UNWIND => NULL; END; fileNoRef: REF INT = NEW[INT _ 0]; SELECT TerminalIO.RequestSelection[label: "Destination", choice: LIST[" Local files", " Tape 0", " Tape 1"] ] FROM 1 => MakeMask[c: c, StreamGen: SimpleStreamGen, data: fileNoRef, tapeDirectory: FS.Open[fileName: "Directory.ebes", accessOptions: overwrite]]; 2 => TerminalIO.WriteRope["not impl\n"]; --MakeTapeMasks[c: c, drive: 0]; 3 => TerminalIO.WriteRope["not impl\n"]; --MakeTapeMasks[c: c, drive: 1]; ENDCASE => RETURN; EXITS Exit => NULL; END; SimpleStreamGen: PROC [ name: Rope.ROPE, data: REF ] RETURNS [ dest: IO.STREAM ] = BEGIN fileNoRef: REF INT = NARROW[data]; dest _ FS.Open[fileName: IO.PutFR[format: "%g%d.EBES", v1: IO.rope[name], v2: IO.int[fileNoRef^]], accessOptions: overwrite]; fileNoRef^ _ fileNoRef^+1; END; unloadAfterward: BOOL _ TRUE; abortMask: BOOL _ FALSE; MakeMask: INTERNAL PROC [ c: CDSequencer.Command, StreamGen: PROC [ name: Rope.ROPE, data: REF ] RETURNS [ dest: IO.STREAM ], data: REF, maskSetName: Rope.ROPE _ NIL, tapeDirectory: IO.STREAM _ NIL ] = BEGIN nmPerLambda, nmPerEBESPixel: INT; ms: MaskStateRef = NEW[ MaskState _ [ areas: CornerStitching.NewTesselation[], unbloated: CornerStitching.NewTesselation[], drawCommand: NEW[DrawRectangle], offset: [0, 0]]]; design: CD.Design = c.design; dr: CD.DrawRef = CD.NewNullDeviceDrawRef[design]; dd: DesignDataRef = NEW[DesignData _ [bbox: NIL, used: NEW[PACKED ARRAY CD.Level OF BOOL _ ALL[FALSE]]]]; designClip: CD.DesignRect; SELECT TerminalIO.RequestSelection[label: "Microns per lambda", choice: LIST[" 2.0", " 1.5", " 1.0"] ] FROM 1 => nmPerLambda _ 2000; 2 => nmPerLambda _ 1500; 3 => nmPerLambda _ 1000; ENDCASE => nmPerLambda _ TerminalIO.RequestInt["OK, wise guy, how many nanometers per lambda? "]; SELECT TerminalIO.RequestSelection[label: "Microns per EBES pixel", choice: LIST[" 1.0", " 0.5", " 0.25"] ] FROM 1 => nmPerEBESPixel _ 1000; 2 => nmPerEBESPixel _ 500; 3 => nmPerEBESPixel _ 250; ENDCASE => RETURN; -- nothing else is legal abortMask _ FALSE; TRUSTED {Process.SetPriority[Process.priorityBackground]}; TerminalIO.WriteRope["Analyzing design "]; dr.minimalSize _ 0; dr.drawRect _ dr.saveRect _ NoteLevel; dr.devicePrivate _ dd; dr.worldClip _ CDInline.ToRect[c.pos, c.sPos]; CDOps.DrawDesign[design, dr]; -- mark used levels and measure design designClip _ CDInline.Intersection[CDInline.ToRect[c.pos, c.sPos], dd.bbox^]; BEGIN ENABLE -- for ERRORs BEGIN UNWIND => ms.s _ AbortFile[ms.s]; END; today: Date = Today[]; scale: Rational = ReduceRational[[num: nmPerLambda, denom: CD.lambda*nmPerEBESPixel]]; ebesClip: CD.Rect; nRows, nCols: NAT; maskCount: NAT _ 0; masks: LIST OF MaskDescriptionRef _ NIL; maxBloat: CD.Number _ 0; -- EBES pixels FOR lev: CD.Level IN CD.Level DO levKey: ATOM = CD.LevelKey[lev]; IF dd.used[lev] THEN BEGIN IF CDProperties.GetPropFromLevel[from: lev, prop: $EBESMakeMask]#NIL THEN dd.used[lev] _ NARROW[CDProperties.GetPropFromLevel[from: lev, prop: $EBESMakeMask], REF BOOL]^; END; IF dd.used[lev] THEN BEGIN maskCount _ maskCount+1; masks _ CONS[first: NEW[MaskDescription _ [lev: lev, name: MaskName[lev]]], rest: masks]; maxBloat _ MAX[maxBloat, (IF CDProperties.GetPropFromLevel[from: lev, prop: $EBESBloatActive]#NIL THEN NARROW[CDProperties.GetPropFromLevel[from: lev, prop: $EBESBloatActive], REF INT]^ ELSE 0)/nmPerEBESPixel]; END; ENDLOOP; IF maskSetName = NIL THEN maskSetName _ ToRope[CDProperties.GetPropFromDesign[from: design, prop: $EBESMaskSetName]]; IF maskSetName = NIL THEN maskSetName _ ToRope[Atom.GetProp[atom: $EBESMask, prop: $MaskSetName]]; IF maskSetName = NIL THEN maskSetName _ design.name; ms.scale _ ReduceRational[[num: nmPerLambda, denom: CD.lambda*nmPerEBESPixel]]; ebesClip _ Bloat[ScaleCDToEBES[ms, designClip], maxBloat]; nRows _ Ceiling[[num: ebesClip.y2-ebesClip.y1, denom: maskHeight]]; nCols _ Ceiling[[num: ebesClip.x2-ebesClip.x1, denom: maskWidth]]; TerminalIO.WriteRope[IO.PutFR[format: "..making %d masks at %d (x) x %d (y) EBES pixels..", v1: IO.int[maskCount], v2: IO.int[ebesClip.x2-ebesClip.x1], v3: IO.int[ebesClip.y2-ebesClip.y1]]]; masks _ SortMasks[masks]; IF tapeDirectory#NIL THEN WriteTapeDirectory[tapeDirectory, maskSetName, nRows, nCols, masks, today]; dr.drawRect _ dr.saveRect _ NoteRectangle; dr.devicePrivate _ ms; FOR m: LIST OF MaskDescriptionRef _ masks, m.rest WHILE m#NIL DO mask: MaskDescription = m.first^; ms.level _ mask.lev; ms.bloat _ (IF CDProperties.GetPropFromLevel[from: mask.lev, prop: $EBESBloatActive]#NIL THEN NARROW[CDProperties.GetPropFromLevel[from: mask.lev, prop: $EBESBloatActive], REF INT]^ ELSE 0)/nmPerEBESPixel; FOR col: NAT IN [0..nCols) DO FOR row: NAT IN [0..nRows) DO patternFileName: Rope.ROPE = PatternFileName[maskSetName: maskSetName, maskName: mask.name, row: row, col: col]; ms.s _ EBESOpen[StreamGen[name: patternFileName, data: data]]; TerminalIO.WriteRope[patternFileName]; SendCommand[s: ms.s, comm: NEW[StartDrawing _ [ patternFileName: RopeToFileName[patternFileName], cx: MIN[maskWidth, ebesClip.x2-ebesClip.x1-col*maskWidth], cy: MIN[maskHeight, ebesClip.y2-ebesClip.y1-row*maskHeight], moDayYr: today, addressCode: (SELECT nmPerEBESPixel FROM 1000 => Nm1000, 500 => Nm500, 250 => Nm250, ENDCASE => Nm500)]]]; FOR stripe: [0..256) IN [0..MIN[maxStripes, Ceiling[[num: ebesClip.y2-ebesClip.y1-maskHeight*row, denom: stripeHeight]]]) DO IF abortMask THEN GOTO AbortMask; ms.areas.ChangeRect[rect: CDInline.universe, newvalue: NIL, checkOldvalue: FALSE]; ms.offset _ [x: -maskWidth*col-ebesClip.x1, y: -maskHeight*row-stripeHeight*stripe-ebesClip.y1]; ms.stripeClip _ [x1: 0, y1: 0, x2: MIN[maskWidth, ebesClip.x2-ebesClip.x1-maskWidth*col], y2: MIN[stripeHeight, ebesClip.y2-ebesClip.y1-maskHeight*row-stripeHeight*stripe]]; dr.worldClip _ ScaleEBESToCD[ms, [x1: ms.stripeClip.x1-1-ABS[ms.bloat], y1: ms.stripeClip.y1-1-ABS[ms.bloat], x2: ms.stripeClip.x2+1+ABS[ms.bloat], y2: ms.stripeClip.y2+1+ABS[ms.bloat]]]; CDViewer.ShowArrow[design: design, pos: [x: (dr.worldClip.x1+dr.worldClip.x2)/2, y: (dr.worldClip.y1+dr.worldClip.y2)/2]]; -- keep user happy CDOps.DrawDesign[design, dr]; -- build tesselation of the relevant design rectangle AnalyzeTesselation[stripe, ms]; -- sends the stripe to s ENDLOOP; SendCommand[s: ms.s, comm: NEW[BasicCommand _ endDrawing]]; ms.s.Close[]; ms.s _ NIL; ENDLOOP; ENDLOOP; ENDLOOP; TerminalIO.WriteRope["finished\n"]; EXITS AbortMask => {ms.s _ AbortFile[ms.s]; TerminalIO.WriteRope["aborted\n"]}; END; END; NoteLevel: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] = BEGIN dd: DesignDataRef = NARROW[pr.devicePrivate]; IF dd.bbox=NIL THEN dd.bbox _ NEW[CD.DesignRect _ r]; dd.bbox^ _ CDInline.Surround[dd.bbox^, r]; dd.used[l] _ TRUE; END; NoteRectangle: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] = BEGIN ms: MaskStateRef = NARROW[pr.devicePrivate]; IF l=ms.level AND CDInline.NonEmpty[r] THEN ms.areas.ChangeRect[rect: ScaleCDToEBES[ms: ms, cdr: r], newvalue: $covered, checkOldvalue: FALSE]; END; ScaleCDToEBES: PROC [ ms: MaskStateRef, cdr: CD.DesignRect ] RETURNS [ ebr: CD.Rect ] = BEGIN -- scales and offsets ebr _ CDInline.NormalizeRect[CDInline.MoveRect[ [x1: RatMul[ms.scale, cdr.x1], y1: RatMul[ms.scale, cdr.y1], x2: RatMul[ms.scale, cdr.x2], y2: RatMul[ms.scale, cdr.y2]], ms.offset]]; END; ScaleEBESToCD: PROC [ ms: MaskStateRef, ebr: CD.Rect ] RETURNS [ cdr: CD.DesignRect ] = BEGIN -- scales and offsets r: CD.Rect = CDInline.MoveRect[ebr, CDInline.NegOffset[ms.offset]]; cdr _ CDInline.NormalizeRect[ [x1: RatDiv[ms.scale, r.x1], y1: RatDiv[ms.scale, r.y1], x2: RatDiv[ms.scale, r.x2], y2: RatDiv[ms.scale, r.y2]]]; END; AnalyzeTesselation: PROC [ stripe: [0..255), ms: MaskStateRef ] = BEGIN active: CD.Rect = ms.areas.ContentsBound[rect: CDInline.universe]; IF CDInline.NonEmpty[active] THEN BEGIN SendCommand[s: ms.s, comm: NEW[StartStripe _ [stripeNumber: stripe+1]]]; IF ms.bloat#0 THEN BEGIN t: REF CornerStitching.Tesselation = ms.unbloated; ms.unbloated _ ms.areas; ms.areas _ t; ms.areas.ChangeRect[rect: CDInline.universe, newvalue: NIL, checkOldvalue: FALSE]; IF ms.bloat>0 THEN [] _ ms.unbloated.EnumerateArea[rect: CDInline.universe, perTile: BloatTile, data: ms] ELSE BEGIN ms.areas.ChangeRect[rect: active, newvalue: $covered, checkOldvalue: FALSE]; [] _ ms.unbloated.EnumerateArea[rect: CDInline.universe, perTile: BloatTile, data: ms, backgroundValue: $covered]; END; END; [] _ ms.areas.EnumerateArea[rect: CDInline.universe, perTile: OutputTile, data: ms, backgroundValue: NIL]; SendCommand[s: ms.s, comm: NEW[BasicCommand _ endStripe]]; TerminalIO.WriteRope["."]; -- end of stripe END; END; BloatTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- CornerStitching.PerTileProc -- = BEGIN ms: MaskStateRef = NARROW[data]; cr: CD.Rect = CDInline.Intersection[CDInline.universe, Bloat[tile.Area, ABS[ms.bloat]]]; IF CDInline.NonEmpty[cr] THEN ms.areas.ChangeRect[rect: cr, newvalue: tile.Value, checkOldvalue: FALSE]; RETURN[ms]; END; OutputTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- CornerStitching.PerTileProc -- = BEGIN -- only called on tiles with non-NIL values ms: MaskStateRef = NARROW[data]; cr: CD.Rect = CDInline.Intersection[tile.Area, ms.stripeClip]; IF CDInline.NonEmpty[cr] THEN BEGIN ms.drawCommand^ _ [x: cr.x1, y: cr.y1, w: cr.x2-cr.x1, h: cr.y2-cr.y1]; SendCommand[s: ms.s, comm: ms.drawCommand]; END; RETURN[ms]; END; Today: PROC RETURNS [ d: Date ] = TRUSTED BEGIN time: BasicTime.Unpacked = BasicTime.Unpack[BasicTime.Now[]]; moDayYr: Rope.ROPE = IO.PutFR[format: "%02d%02d%02d", v1: IO.int[time.month+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.ROPE, row, col: NAT ] RETURNS [ rfn: Rope.ROPE ] = BEGIN r: Rope.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: ]; END; ToUpperCase: PROC [old: CHAR] RETURNS [new: CHAR] -- Rope.TranslatorType -- = {new _ Ascii.Upper[old]}; MaskName: PROC [ lev: CD.Level ] RETURNS [ name: Rope.ROPE ] = BEGIN defaultLevName: Rope.ROPE = ToRope[CDProperties.GetPropFromLevel[from: lev, prop: $CDxCIFName]]; name _ IF CDProperties.GetPropFromLevel[from: lev, prop: $EBESMaskName]#NIL THEN ToRope[CDProperties.GetPropFromLevel[from: lev, prop: $EBESMaskName]] ELSE Rope.Substr[base: defaultLevName, start: 1, len: Rope.Length[defaultLevName]-1]; END; RopeToFileName: PROC [ rfn: Rope.ROPE ] RETURNS [ fn: FileName ] = {FOR i: [0..12) IN [0..12) DO fn[i] _ Rope.Fetch[rfn, i] ENDLOOP}; SortMasks: PROC [ in: LIST OF MaskDescriptionRef ] RETURNS [ out: LIST OF MaskDescriptionRef ] = BEGIN q: PriorityQueue.Ref = PriorityQueue.Create[pred: CompareMaskNames]; FOR m: LIST OF MaskDescriptionRef _ in, m.rest WHILE m#NIL DO q.Insert[m.first]; ENDLOOP; out _ NIL; WHILE NOT q.Empty[] DO out _ CONS[NARROW[q.Remove[], MaskDescriptionRef], out]; ENDLOOP; END; CompareMaskNames: PROC [ x, y: PriorityQueue.Item, data: REF _ NIL ] RETURNS [ BOOL ] -- PriorityQueue.SortPred -- = BEGIN xm: MaskDescriptionRef = NARROW[x]; ym: MaskDescriptionRef = NARROW[y]; RETURN[Rope.Compare[s1: xm.name, s2: ym.name, case: FALSE]=greater]; END; WriteTapeDirectory: PROC [ dest: IO.STREAM, maskSetName: Rope.ROPE, nRows, nCols: NAT, masks: LIST OF MaskDescriptionRef, today: Date] = BEGIN s: IO.STREAM = EBESOpen[dest: dest, eor: FALSE]; nMasks: NAT _ 0; FOR m: LIST OF MaskDescriptionRef _ masks, m.rest WHILE m#NIL DO nMasks _ nMasks+1; ENDLOOP; 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 MaskDescriptionRef _ masks, m.rest WHILE m#NIL DO FOR col: NAT IN [0..nCols) DO FOR row: NAT IN [0..nRows) DO s.PutF[format: "%s ", v1: IO.rope[PatternFileName[maskSetName, m.first.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, stopIndexPlusOne: 2*sizeInWords]]}; END; EBESStreamStateRef: TYPE = REF EBESStreamState; EBESStreamState: TYPE = RECORD [ dest: IO.STREAM, eor: BOOL, buf: REF TEXT]; 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.CreateProcsStream[streamProcs: IO.CreateRefStreamProcs[ putChar: PutEBESChar, unsafePutBlock: PutEBESBlock, flush: FlushEBES, close: CloseEBES], 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.stopIndexPlusOne-block.startIndex]; FOR i: CARDINAL IN [0..block.stopIndexPlusOne-block.startIndex) 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.stopIndexPlusOne-block.startIndex; 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; PutTapeSubStreamBlock: PROC [ self: IO.STREAM, block: REF READONLY TEXT, startIndex: NAT, stopIndexPlusOne: NAT ] = TRUSTED BEGIN dest: IO.STREAM = NARROW[self.streamData]; dest.PutBlock[block: block, startIndex: startIndex, stopIndexPlusOne: stopIndexPlusOne]; END; RopeNeeded: SIGNAL [ ref: REF REF ] = CODE; ToRope: PROC [ ref: REF ] RETURNS [ rope: Rope.ROPE ] = BEGIN IF ref = NIL THEN rope _ NIL ELSE WITH ref SELECT FROM r: Rope.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; Bloat: PROC [ r: CD.Rect, delta: CD.Number ] RETURNS [ br: CD.Rect ] = INLINE BEGIN b0: NAT = delta/2; -- bloat must be >=0, split in "half" b1: NAT = delta-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*r.denom>0 AND r.num MOD r.denom # 0 THEN c _ c+1; END; Floor: PROC [ r: Rational ] RETURNS [ f: INT ] = BEGIN f _ r.num/r.denom; IF r.num*r.denom<0 AND r.num MOD r.denom # 0 THEN f _ f-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; >0 => NULL; ENDCASE => ERROR; SELECT n FROM <0 => n _ -n; >0 => NULL; ENDCASE => ERROR; r _ m MOD n; WHILE r>0 DO m _ n; n _ r; r _ m MOD n; ENDLOOP; RETURN[n]; END; Init[]; END. -- of EBESMaskImpl ฺEBESMaskImpl.mesa A package to output a ChipnDale design in EBES format for a Varian Lithographic System. The format produced herein is described in the proprietary document "Pattern Data Formats for Varian Lithography Systems", dated May, 1982, and available from Varian/Semiconductor Equipment Group Lithography Products Division Blackburn Industrial Park Gloucester, Mass. 01930 written by E. McCreight, November 2, 1983 6:03 pm Last Edited by: Mccreight, November 23, 1983 5:46 pm TapeStream, The EBES command formats: month [01..12], day [01..31], year [00..99] [9] must be '. , [10] is column ['A..'Z], [11] is row ['A..'Z] MakeTapeMasks: INTERNAL PROC [c: CDSequencer.Command, drive: [0..4]] = BEGIN tape: IO.STREAM _ NIL; BEGIN ENABLE UNWIND => IF tape#NIL THEN {tape.Close[]; tape _ NIL}; tape _ TapeStream.Create[drive: drive, density: NRZI800]; TapeStream.Rewind[tape]; MakeMask[c: c, StreamGen: TapeSubStreamGen, data: tape, tapeDirectory: TapeSubStreamGen[name: "", data: tape]]; TapeStream.Rewind[tape]; IF unloadAfterward THEN TapeStream.Unload[tape] ELSE tape.Close[]; tape _ NIL; END; END; TapeSubStreamGen: PROC [ name: Rope.ROPE, data: REF ] RETURNS [ dest: IO.STREAM ] = BEGIN dest _ IO.CreateProcsStream[streamProcs: IO.CreateRefStreamProcs[ putBlock: PutTapeSubStreamBlock, close: CloseTapeSubStream], streamData: data]; END; CloseTapeSubStream: PROC [ self: IO.STREAM, abort: BOOL _ FALSE ] = BEGIN dest: IO.STREAM = NARROW[self.streamData]; TapeStream.WriteFileMark[dest]; END; Be careful not to exceed the limits of a CD.Number, even temporarily c = SGN[r.num]*SGN[r.denom]*FLOOR[ABS[r.num]/ABS[r.denom]] if r.denom#0 f = SGN[r.num]*SGN[r.denom]*FLOOR[ABS[r.num]/ABS[r.denom]] if r.denom#0 Module START code... สI˜Jšœ™J˜šœ๘™๘Jšœ$™$Jšœ™Jšœ™Jšœ™—J˜Jšœ1™1J™4J˜šฯk ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ™ Jšœ ˜ Jšœ ˜ J˜—šฯb œœ˜JšœœMœE˜ซJšœ˜ Jš˜J˜Jšœ œœœ˜.Jšœœœ ˜#šœ œœ˜Jšœœœฯc/˜=Jšœ˜JšœœŸ˜4Jšœ œ˜Jšœœ œ ˜Jšœœ Ÿ.˜DJšœœœŸ˜PJšœ œŸ˜7Jšœ˜—Jšœœœ ˜%šœ œœ˜Jšœœœ ˜Jš œœœœœœ˜'Jšœ˜—Jšœœœ˜/Jš œœœœœ˜BJ˜šœ™J˜JšœœŸ˜)Jšœ œ˜Jšœ œ˜*Jšœ œ ˜J˜š œœœ œœ˜/J˜ J˜,JšœœŸ˜/JšœœŸ˜0Jšœ˜Jšœœ˜Jšœ˜Jšœœ˜Jš œœœœœœ˜4J˜—Jšœ œœ œ!˜Fš œœœœœœœ˜3Jšœ+™+—š œ œœœ œœœ˜8Jšœ>™>—š œœœ œœ˜0Jšœ Ÿ0˜PJ˜&JšœœŸ˜.Jšœœ˜Jšœ˜Jšœ!˜!—š œ œœ œœ˜.Jšœ-Ÿ˜˜>Jšœ&˜&šœœ˜/Jšœ1˜1Jšœœ3˜:Jšœœ5˜˜Cšœ˜Jšœr˜r—Jšœ˜J˜J˜—š œœ)˜AJš˜Jšœœ8˜Bšœ˜!Jš˜Jšœœ*˜Hšœ ˜Jš˜Jšœœ,˜2Jšœ˜Jšœ ˜ Jšœ7œœ˜Ršœ ˜JšœV˜V—š˜Jš˜JšœEœ˜LJšœr˜rJšœ˜—Jšœ˜—J˜Jšœeœ˜jJšœœ˜:JšœŸ˜+Jšœ˜—Jšœ˜J˜J˜—š  œ œ'œœœœœŸ!œ˜yJš˜Jšœœ˜ JšœœBœ ˜Xšœ˜JšœCœ˜J—Jšœ˜ Jšœ˜J˜J˜—š  œ œ'œœœœœŸ!œ˜zJšœŸ+˜1Jšœœ˜ Jšœœ8˜>šœ˜Jš˜JšœG˜GJšœ+˜+Jšœ˜—Jšœ˜ Jšœ˜J˜—J˜š œœœ˜!Jšœ˜ Jšœ=˜=Jš œœœ#œœœœ˜…Jšœ œœœ˜AJšœ˜J˜J˜—š  œœœ œœ œ˜fJš˜Jšœœœ œHœ@œœœœ ˜๗Jšœ,˜,Jšœ˜J˜J˜—š   œœœœœŸœ˜MJšœ˜J˜J˜—š  œœœ œœ˜>Jš˜JšœœG˜`Jš œœ?œœGœQ˜์Jšœ˜J˜J˜—š œœ œœ˜BJš œœ œ œœ˜BJ˜J˜—š  œœœœœœœ˜`Jš˜JšœD˜Dš œœœ!œœ˜=Jšœ˜Jšœ˜—Jšœœ˜ šœœ ˜Jšœœœ'˜8Jšœ˜—Jšœ˜J˜J˜—š œœ#œœœœŸœ˜tJš˜Jšœœ˜#Jšœœ˜#Jšœ.œ ˜DJšœ˜J˜J˜—š œœ œœœœ œœ#˜ˆJš˜Jšœœœœ˜0Jšœœ˜š œœœ$œœ˜@Jšœ˜Jšœ˜J˜—JšœœœŸ)˜LJšœœœŸ˜Eš œœœ$œœ˜@šœœœ ˜šœœœ ˜Jšœœ=˜\Jšœ˜—Jšœ˜—Jšœ˜—Jšœœ˜"Jšœ ˜ Jšœ˜J˜J˜—š  œœœœœœœ˜7Jš œœœœœœœ˜2J˜J˜—š   œœœœœ˜/Jš˜Jšœ œ˜šœœ˜Jšœœ œ˜:Jšœœœ˜8Jšœœœ˜6Jšœœœ˜8Jšœœœ˜(Jšœœœ ˜0Jš œœœœœ˜0Jšœœ˜—Jšœœ:˜cJšœ˜J˜J˜—Jšœœœ˜/šœœœ˜ Jšœœœ˜Jšœœ˜ Jšœœœ˜—J˜š œœ œœœœœ œœ˜RJš˜Jšœœ/œœ ˜`Jšœ˜Jšœœ œƒ˜ฎJšœ˜J˜J˜—š   œœ œœœ˜3Jšœ˜ Jšœœ˜4Jšœ˜Jšœ#˜#Jšœ&˜&Jšœ˜J˜J˜—š   œœ œœ œ˜?Jšœ˜ Jšœœ˜4JšœE˜Ešœœœ.˜BJšœœœœœœœœœ˜AJšœ œ/˜WJšœ˜—JšœL˜LJšœ˜J˜J˜—š œœ'œ˜NJš˜š œ1œ œœŸœœ˜~Jšœ˜—Jšœ˜J˜J˜—š   œœ œœœ˜MJ˜J˜—š  œœ ˜1Jš˜šœ˜Jš˜šœ ˜Jš˜šœ)˜/JšœœŸ0˜>Jš œœœœœœ ˜:Jšœ(˜(Jšœ*˜*Jšœ&˜&Jš˜—JšœœŸ"˜.Jšœ˜—šœœœ)˜=JšœŸ˜(Jšœ˜—Jšœ'˜'Jšœ˜Jšœ˜—Jšœ˜Jšœ˜J˜J˜—š   œœ œœ œœ˜:Jš˜Jšœœ˜4Jšœ ˜ Jšœ˜Jšœ˜J˜J˜—š œœ œœ œœœœœ˜sJšœ˜ Jšœœœœ˜*JšœX˜XJšœ˜J˜J˜—š  œœ œœ œœ™CJš™Jšœœœœ™*Jšœ™Jšœ™J™J™—Jš œ œœœœ˜+J˜š  œœœœœ˜7Jš˜Jšœœœ˜šœœœ˜Jšœœ ˜Jšœœœ ˜,Jšœœ˜#Jš œœœ œœ ˜>šœ˜ Jš˜Jš œœœœœ˜!Jšœ˜Jšœ&œ ˜3š˜Jšœ œ˜—Jšœ˜——Jšœ˜J˜J˜—š  œœœœ œœ ˜MJš˜Jšœœ Ÿ%˜8Jšœœ ˜JšœD™DJšœ œœœœœœœœœœœœ˜ Jšœ˜J˜J˜—š œœœœ˜2Jš˜šœ˜JšœG™G—Jšœœœ œ ˜:Jšœ˜J˜—š œœœœ˜1Jš˜šœ˜JšœG™G—Jšœœœ œ ˜:Jšœ˜J˜—š œœœ˜;Jš˜Jš œœœ œ œœ˜