<> <> <> <> <> <> <<(parent vis parameter added at Visible:)>> <> <> <> <> <<.. to scale stretches returned by the ID routine to CIF units instead of microns>> DIRECTORY Atom, List, MPCDefs, PartitionDefs, ParserTypeDefs, NStripeDefs, PrincOps, Real, Rope, IntStorageDefs, IntTransDefs, IODefs, PolygonDefs, ParserErrorDefs, OutputDefs, OutputInternalDefs; Output: CEDAR PROGRAM IMPORTS List, PartitionDefs, NStripeDefs, Real, IntTransDefs, IODefs, PolygonDefs, ParserErrorDefs EXPORTS OutputDefs, OutputInternalDefs = BEGIN OPEN OutputDefs; Point: TYPE = ParserTypeDefs.Point; PointList: TYPE = ParserTypeDefs.PointList; Path: TYPE = ParserTypeDefs.Path; one: REAL _ 1.0; half: REAL _ 0.5; small: REAL _ 0.0001; --used relative to 1 mebes unit w: PUBLIC REF MPCDefs.WaferDescriptor; c: PUBLIC REF MPCDefs.ChipDescriptor; p: PUBLIC REF MPCDefs.ProjectDescriptor; InitOutput: PUBLIC PROC [chip: REF MPCDefs.ChipDescriptor] RETURNS [BOOL] = BEGIN PartitionDefs.InitPartitions["Pfile$"]; c _ chip; w _ c.inWafer; NStripeDefs.InitStripe[c.chipSizeX*w.outputUnitsPerMicron, c.chipSizeY*w.outputUnitsPerMicron]; <> FOR pl: Atom.PropList _ w.layerFileList, pl.rest WHILE pl#NIL DO WITH pl.first.val SELECT FROM lfi: MPCDefs.LayerFileItem => TRUSTED { lfi.pFileLayer _ List.Length[LOOPHOLE[pl]] }; ENDCASE => ERROR; ENDLOOP; RETURN[TRUE]; END; InitProject: PUBLIC PROC [project: REF MPCDefs.ProjectDescriptor] RETURNS [BOOL] = BEGIN p _ project; IF p.inChip # c THEN ERROR; <> TRUSTED { cifMap _ NEW[OutputInternalDefs.CIFMap[List.Length[LOOPHOLE[p.layerMap]]+1]] }; cifMap[0] _ NIL; FOR pl: Atom.PropList _ p.layerMap, pl.rest WHILE pl#NIL DO WITH pl.first.val SELECT FROM lg: MPCDefs.LayerGroup => BEGIN TRUSTED {lg.cifIndex _ List.Length[LOOPHOLE[pl]] }; cifMap[lg.cifIndex] _ lg; END; ENDCASE => ERROR; ENDLOOP; RETURN[TRUE]; END; RPoint: TYPE = RECORD [x, y: REAL]; cifMap: PUBLIC REF OutputInternalDefs.CIFMap _ NIL; ID: PROC [n: CARDINAL, index: INTEGER] RETURNS [fileLayer: CARDINAL, stretch: REAL -- diameter, CIF units --, nextindex: INTEGER] = <> <> <> <<"nextindex".>> <> <> BEGIN IF cifMap[n] = NIL THEN {ParserErrorDefs.Report["No Such Layer", Advisory]; RETURN[0, 0, -1]} ELSE BEGIN r: REF ANY; TRUSTED { r _ List.NthTail[LOOPHOLE[cifMap[n].maskLayers], index] }; IF r = NIL THEN RETURN[0, 0, -1] ELSE WITH r SELECT FROM pl: Atom.PropList => WITH pl.first.val SELECT FROM la: MPCDefs.LayerAssoc => RETURN[ fileLayer: la.toLayer.pFileLayer, stretch: 100*la.stretch, -- express stretch in CIF units nextindex: index+1]; ENDCASE => ERROR; ENDCASE => ERROR; END; END; -- of ID OutputWire: PUBLIC PROC [ visible: VisibleType, layerName: CARDINAL, width: LONG CARDINAL, a: Path] = BEGIN ENABLE NStripeDefs.OutOfBoundsNumber => BEGIN ParserErrorDefs.Report["Wire coordinate out of bounds", Fatal]; CONTINUE; END; layer: CARDINAL; stretch, length, Width, halfw, offset: REAL; A, b, c: PointList; ab, bc: Point; lengthab, lengthbc: REAL; aExt, bExt: REAL; inline: REAL; index: INTEGER _ 0; Stepbc: PROC = BEGIN --given old c, compute b, new c, bc, lengthbc <> <> b _ c; UNTIL c = a.last DO c _ c.rest; bc _ Point[c.first.x - b.first.x, c.first.y - b.first.y]; lengthbc _ Real.SqRt[Dot[bc, bc]]; IF lengthbc = 0 THEN b _ c ELSE EXIT; ENDLOOP; END; IF a.length = 0 OR layerName = 100 THEN RETURN; DO --once per definition of this layer [layer, stretch, index] _ ID[layerName, index]; IF index < 0 THEN RETURN; Width _ width + stretch; halfw _ Width*half; c _ a.first; Stepbc[]; IF b = a.last THEN BEGIN OutputFlash[visible, layerName, width, b.first]; RETURN; END; bExt _ halfw; UNTIL b = a.last DO A _ b; aExt _ bExt; ab _ bc; lengthab _ lengthbc; Stepbc[]; IF b = a.last THEN bExt _ halfw ELSE BEGIN IF (inline _ Dot[ab, bc]) < 0 THEN BEGIN bExt _ 0; OutputFlash[visible, layerName, width, b.first]; END ELSE bExt _ halfw*ABS[Dot[[ab.y, -ab.x], bc]]/(inline + lengthab*lengthbc); END; length _ lengthab + aExt + bExt; offset _ (lengthab - aExt + bExt)/2; SELECT TRUE FROM ab.y = 0 => ROutputBox[ layer, length, Width, [ IF ab.x >= 0 THEN A.first.x + offset ELSE A.first.x - offset, A.first.y]]; ab.x = 0 => ROutputBox[ layer, width, length, [ A.first.x, IF ab.y >= 0 THEN A.first.y + offset ELSE A.first.y - offset]]; ENDCASE => BEGIN IntTransDefs.Push[]; IntTransDefs.Translate[Real.Round[offset], 0]; --'A' to origin IntTransDefs.Rotate[ab.x, ab.y]; IntTransDefs.Translate[A.first.x, A.first.y]; --'A' to correct place ROutputBox[layer, length, Width, [0, 0]]; IntTransDefs.Pop[]; END; ENDLOOP; ENDLOOP; --multi-layers loop END; Dot: PROC [p, q: Point] RETURNS [dotProd: REAL] = BEGIN RETURN[Real.Float[p.x]*Real.Float[q.x] + Real.Float[p.y]*Real.Float[q.y]]; END; twoMR2: REAL = 2.0 - Real.SqRt[2]; R2M1: REAL = Real.SqRt[2] - 1.0; OutputFlash: PUBLIC PROC [ visible: VisibleType, layerName: CARDINAL, diameter: LONG CARDINAL, center: Point] = <> BEGIN ENABLE NStripeDefs.OutOfBoundsNumber => BEGIN ParserErrorDefs.Report["Flash coordinate out of bounds", Fatal]; CONTINUE; END; layer: CARDINAL; stretch, h1, h2, cX, cY, Diameter, radius: REAL; index: INTEGER _ 0; IF layerName = 100 THEN RETURN; DO --once per definition of this layer [layer, stretch, index] _ ID[layerName, index]; IF index < 0 THEN RETURN; Diameter _ (diameter + stretch)*w.outputUnitsPerMicron/100; radius _ Diameter/2; h1 _ twoMR2*radius; h2 _ R2M1*radius; [cX, cY] _ IntTransDefs.RTransformPoint[center.x, center.y]; NStripeDefs.WriteTrapezoid[layer, Diameter, h1, cX - radius, cY + h2, 1, -1]; NStripeDefs.WriteRectangle[layer, Diameter, h2 + h2, cX - radius, cY - h2]; NStripeDefs.WriteTrapezoid[layer, h2 + h2, h1, cX - h2, cY - radius, -1, 1]; ENDLOOP; END; OutputPolygon: PUBLIC PROC [ visible: VisibleType, layerName: CARDINAL, a: Path] = BEGIN ENABLE NStripeDefs.OutOfBoundsNumber => BEGIN ParserErrorDefs.Report["Polygon coordinate out of bounds", Fatal]; CONTINUE; END; xT, yT, stretch, R2M1s: REAL; p, prev: PointList; layer: CARDINAL; poly: PolygonDefs.PolygonDescriptor; index: INTEGER _ 0; Angle: TYPE = { lessthan45, between45and90, perp, between90and135, between135and180}; StretchedTrapezoid: PROC [llx, lrx, ly, ulx, urx, uy: REAL] = BEGIN h: REAL = uy - ly; IF h < small THEN RETURN; NStripeDefs.WriteTrapezoid[layer, lrx - llx, h, llx, ly, (ulx - llx)/h, (urx - lrx)/h]; END; UnStretchedTrapezoid: PROC [llx, lrx, ly, ulx, urx, uy: REAL] = BEGIN --Stretch each trapezoid and reconvert it polygon: PolygonDefs.PolygonDescriptor _ PolygonDefs.PolyCreate[]; p, p1, p2, q, q1, q2, r, r1, r2: RPoint; case: Angle; <> <> [case, p1, p, p2, q1, q, q2, r1, r, r2] _ ExtendCorners[ [urx, uy], [lrx, ly], stretch]; IF case = lessthan45 THEN PolygonDefs.PolyVertex[polygon, urx + p.x, uy + p.y] ELSE BEGIN PolygonDefs.PolyVertex[polygon, urx + p1.x, uy + p1.y]; PolygonDefs.PolyVertex[polygon, urx + p2.x, uy + p2.y] END; SELECT case FROM lessthan45 => BEGIN PolygonDefs.PolyVertex[polygon, lrx + q1.x, ly + q1.y]; PolygonDefs.PolyVertex[polygon, lrx + q2.x, ly + q2.y]; END; between45and90 => PolygonDefs.PolyVertex[polygon, lrx + q.x, ly + q.y]; between90and135 => PolygonDefs.PolyVertex[polygon, urx + q.x, uy + q.y]; between135and180 => BEGIN PolygonDefs.PolyVertex[polygon, urx + q1.x, uy + q1.y]; PolygonDefs.PolyVertex[polygon, urx + q2.x, uy + q2.y]; END; ENDCASE; IF case = between135and180 THEN PolygonDefs.PolyVertex[polygon, lrx + r.x, ly + r.y] ELSE BEGIN PolygonDefs.PolyVertex[polygon, lrx + r1.x, ly + r1.y]; PolygonDefs.PolyVertex[polygon, lrx + r2.x, ly + r2.y]; END; <> [case, p1, p, p2, q1, q, q2, r1, r, r2] _ ExtendCorners[ [-llx, -ly], [-ulx, -uy], stretch]; IF case = lessthan45 THEN PolygonDefs.PolyVertex[polygon, llx - p.x, ly - p.y] ELSE BEGIN PolygonDefs.PolyVertex[polygon, llx - p1.x, ly - p1.y]; PolygonDefs.PolyVertex[polygon, llx - p2.x, ly - p2.y] END; SELECT case FROM lessthan45 => BEGIN PolygonDefs.PolyVertex[polygon, ulx - q1.x, uy - q1.y]; PolygonDefs.PolyVertex[polygon, ulx - q2.x, uy - q2.y]; END; between45and90 => PolygonDefs.PolyVertex[polygon, ulx - q.x, uy - q.y]; between90and135 => PolygonDefs.PolyVertex[polygon, llx - q.x, ly - q.y]; between135and180 => BEGIN PolygonDefs.PolyVertex[polygon, llx - q1.x, ly - q1.y]; PolygonDefs.PolyVertex[polygon, llx - q2.x, ly - q2.y]; END; ENDCASE; IF case = between135and180 THEN PolygonDefs.PolyVertex[polygon, ulx - r.x, uy - r.y] ELSE BEGIN PolygonDefs.PolyVertex[polygon, ulx - r1.x, uy - r1.y]; PolygonDefs.PolyVertex[polygon, ulx - r2.x, uy - r2.y]; END; <> PolygonDefs.PolyGenerate[polygon, StretchedTrapezoid]; END; ExtendCorners: PUBLIC PROC [tr, br: RPoint, s: REAL] RETURNS [case: Angle, P1, P, P2, Q1, Q, Q2, R1, R, R2: RPoint] = BEGIN --return case and displacements of extended points for right edge bc: RPoint; upSideDown: BOOL = tr.x > br.x; s _ s/2; -- Halve stretch so get TOTAL compensation, PJM IF upSideDown THEN BEGIN t: REAL = tr.x; tr.x _ br.x; br.x _ t; END; bc _ [br.x - tr.x, br.y - tr.y]; IF bc.x = 0 THEN RETURN[ perp, [R2M1s, s], [s, s], [s, R2M1s], [s, 0], [s, 0], [s, 0], [ s, -R2M1s], [s, -s], [R2M1s, -s]] ELSE BEGIN p1, p, p2, q1, q, q2, r1, r, r2: RPoint; lengthbc: REAL = Real.SqRt[bc.x*bc.x + bc.y*bc.y]; unitbc: RPoint = [bc.x/lengthbc, bc.y/lengthbc]; bcrot: RPoint = [-unitbc.y, unitbc.x]; pdir: RPoint = [bcrot.x, bcrot.y + 1]; qdir: RPoint = [bcrot.x + 1, bcrot.y]; p _ [s*pdir.x/pdir.y, s]; p1 _ [R2M1*p.x, s]; p2 _ [s*bcrot.x - p1.x*unitbc.x, s*bcrot.y - p1.x*unitbc.y]; q _ [s, s*qdir.y/qdir.x]; q2 _ [s, R2M1*q.y]; q1 _ [s*bcrot.x + q2.y*unitbc.x, s*bcrot.y + q2.y*unitbc.y]; r _ [s, -s]; r1 _ [s, -R2M1s]; r2 _ [R2M1s, -s]; IF upSideDown THEN RETURN[ IF bc.x > -bc.y THEN between135and180 ELSE between90and135, [ r2.x, -r2.y], [r.x, -r.y], [r1.x, -r1.y], [q2.x, -q2.y], [ q.x, -q.y], [q1.x, -q1.y], [p2.x, -p2.y], [p.x, -p.y], [ p1.x, -p1.y]] ELSE RETURN[ IF bc.x > -bc.y THEN lessthan45 ELSE between45and90, p1, p, p2, q1, q, q2, r1, r, r2]; END; END; <> IF a.length = 0 OR layerName = 100 THEN RETURN; DO --once per definition of this layer [layer, stretch, index] _ ID[layerName, index]; IF index < 0 THEN RETURN; IF stretch < 0 THEN ParserErrorDefs.Report["Negative polygon stretch", Advisory]; stretch _ stretch*w.outputUnitsPerMicron/100; --stretch in CIF units R2M1s _ R2M1*stretch; poly _ PolygonDefs.PolyCreate[]; prev _ NIL; FOR p _ a.first, p.rest UNTIL prev = a.last DO [xT, yT] _ IntTransDefs.RTransformPoint[p.first.x, p.first.y]; PolygonDefs.PolyVertex[poly, xT, yT]; prev _ p; ENDLOOP; PolygonDefs.PolyGenerate[ poly, IF stretch = 0 THEN StretchedTrapezoid ELSE UnStretchedTrapezoid]; ENDLOOP; END; OutputBox: PUBLIC PROC [ visible: VisibleType, layerName: CARDINAL, length, width: LONG CARDINAL, center: Point, xRotation, yRotation: INT] = BEGIN ENABLE NStripeDefs.OutOfBoundsNumber => BEGIN ParserErrorDefs.Report["Box coordinate out of bounds", Fatal]; CONTINUE; END; layer: CARDINAL; Length, Width, stretch: REAL; centerX: REAL _ center.x; centerY: REAL _ center.y; index: INTEGER _ 0; IF layerName = 100 THEN RETURN; DO --once per definition of this layer [layer, stretch, index] _ ID[layerName, index]; IF index < 0 THEN RETURN; Length _ length + stretch; Width _ width + stretch; SELECT TRUE FROM yRotation = 0 => ROutputBox[layer, Length, Width, [centerX, centerY]]; xRotation = 0 => ROutputBox[layer, Width, Length, [centerX, centerY]]; ENDCASE => BEGIN --do rotation AND translation via transformations IntTransDefs.Push[]; IntTransDefs.Rotate[xRotation, yRotation]; IntTransDefs.Translate[center.x, center.y]; ROutputBox[layer, Length, Width, [0, 0]]; IntTransDefs.Pop[]; END; ENDLOOP; END; ROutputBox: PROC [layer: CARDINAL, length, width: REAL, center: RPoint] = BEGIN <> <> <> <> lenR: REAL _ length*half; widR: REAL _ width*half; lenT, widT: RPoint; --Transformed half Length and Width [lenT.x, lenT.y] _ IntTransDefs.RTransformVector[lenR, 0]; [widT.x, widT.y] _ IntTransDefs.RTransformVector[0, widR]; <> IF widT.x = 0 OR widT.y = 0 THEN BEGIN ax, ay, bx, by: REAL; [ax, ay] _ IntTransDefs.RTransformPoint[center.x - lenR, center.y - widR]; [bx, by] _ IntTransDefs.RTransformPoint[center.x + lenR, center.y + widR]; NStripeDefs.WriteRectangle[layer, ABS[bx - ax], ABS[by - ay], MIN[ax, bx], MIN[ay, by]]; END ELSE BEGIN top, nextA, nextB: RPoint; lenSl, widSl, widTx2, widTy2, cX, cY: REAL; widH: REAL; --horizontal Width <> IF lenT.y < 0 THEN lenT _ [-lenT.x, -lenT.y]; IF widT.y < 0 THEN widT _ [-widT.x, -widT.y]; IF lenT.y < widT.y THEN BEGIN T: RPoint _ lenT; lenT _ widT; widT _ T; END; <> lenSl _ lenT.x/lenT.y; widSl _ widT.x/widT.y; widH _ 2*(widT.x + widT.y/widSl); top _ [lenT.x + widT.x, lenT.y + widT.y]; nextA _ [lenT.x - widT.x, lenT.y - widT.y]; nextB _ [nextA.x + widH, nextA.y]; widTx2 _ widT.x + widT.x; widTy2 _ widT.y + widT.y; [cX, cY] _ IntTransDefs.RTransformPoint[center.x, center.y]; IF lenT.x > 0 THEN BEGIN --L in first quadrant, widT.x & widH negative NStripeDefs.WriteTrapezoid[ layer, -widH, widTy2, cX + nextB.x, cY + nextB.y, lenSl, widSl]; IF nextA.y # 0 THEN NStripeDefs.WriteTrapezoid[ layer, -widH, nextA.y + nextA.y, cX - nextA.x, cY - nextA.y, lenSl, lenSl]; NStripeDefs.WriteTrapezoid[layer, 0, widTy2, cX - top.x, cY - top.y, widSl, lenSl]; END ELSE BEGIN --L in second quadrant, widT.x & widH positive NStripeDefs.WriteTrapezoid[ layer, widH, widTy2, cX + nextA.x, cY + nextA.y, widSl, lenSl]; IF nextA.y # 0 THEN NStripeDefs.WriteTrapezoid[ layer, widH, nextA.y + nextA.y, cX - nextB.x, cY - nextB.y, lenSl, lenSl]; NStripeDefs.WriteTrapezoid[layer, 0, widTy2, cX - top.x, cY - top.y, lenSl, widSl]; END; END; END; OutputUserCommand: PUBLIC PROC [command: [0..9], userText: Rope.ROPE] = BEGIN <> END; OutputUserObject: PUBLIC PROC [visible: VisibleType, layerName: CARDINAL, data: REF ANY] = { NULL }; <> OutputBoundingBox: PUBLIC PROC [left, right, bottom, top: INT] = BEGIN IODefs.WriteLine["OutputBoundingBox Called"]; END; <> Relation: PUBLIC PROC [ left1, right1, bottom1, top1, left2, right2, bottom2, top2: INT] RETURNS [RelationType] = BEGIN <> RETURN[ dontcare <