DIRECTORY CD USING [ApplicationList, ApplicationPtr, CellPtr, combined, FetchObjectProcs, lambda, Layer, Number, ObjectProcs, ObPtr, Orientation, Position, Rect], CDBasics USING [SizeOfRect, ToRect], CDCells USING [CreateEmptyCell, SetInterestRect], CDObjectProcs USING [FetchFurther, RegisterFurther, StoreFurther], CDOrient USING [DeMapRect, MapRect], CDPinObjects USING [CreatePinOb], CDProperties USING [CopyProps, CopyVal, DontCopy, GetPropFromObject, FetchProcs, PutPropOnObject, RegisterProperty], CDRects USING [CreateRect], CMos USING [cmos, pol], CMosTransistors USING [TransistorPtr], Convert, PWBasics, PWStretch, Rope; PWStretchImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDOrient, CDRects, CDObjectProcs, CDPinObjects, CDProperties, CMos, Convert, PWBasics, Rope EXPORTS PWStretch = BEGIN OPEN PWStretch; worldSegment: PUBLIC Segment = NEW [SegmentRec _ [pos: [min: FIRST [CD.Number], max: LAST [CD.Number]]]]; worldSortedSegments: PUBLIC SortedSegments = LIST [worldSegment]; PosRangeXFromRect: PUBLIC PROC [rect: CD.Rect] RETURNS [posrange: PosRange] = {RETURN [[rect.x1, rect.x2]]}; PosRangeYFromRect: PUBLIC PROC [rect: CD.Rect] RETURNS [posrange: PosRange] = {RETURN [[rect.y1, rect.y2]]}; RectFromPosRangeX: PUBLIC PROC [pos: PosRange, y: CD.Number] RETURNS [rect: CD.Rect] = {RETURN [[x1: pos.min, x2: pos.max, y1: y, y2: y]]}; RectFromPosRangeY: PUBLIC PROC [pos: PosRange, x: CD.Number] RETURNS [rect: CD.Rect] = {RETURN [[y1: pos.min, y2: pos.max, x1: x, x2: x]]}; IntersectPos: PUBLIC PROC [pos1, pos2: PosRange] RETURNS [intersect: BOOL] = {RETURN [MAX [pos1.min, pos2.min] < MIN [pos1.max, pos2.max]]}; OffsetPosRange: PUBLIC PROC [pos: PosRange, offset: INT] RETURNS [posrange: PosRange] = {RETURN [[pos.min+offset, pos.max+offset]]}; IntersectPosRange: PUBLIC PROC [pos1, pos2: PosRange] RETURNS [posrange: PosRange] = {RETURN [[MAX [pos1.min, pos2.min], MIN [pos1.max, pos2.max]]]}; UnionPosRange: PUBLIC PROC [pos1, pos2: PosRange] RETURNS [posrange: PosRange] = {RETURN [[MIN [pos1.min, pos2.min], MAX [pos1.max, pos2.max]]]}; MakeNewSegment: PUBLIC PROC [pos: PosRange, info: REF _ NIL] RETURNS [seg: Segment] = {IF pos.min>= pos.max THEN ERROR; RETURN [NEW [SegmentRec _ [pos: pos, info: info]]]}; IntersectSeg: PUBLIC PROC [s1, s2: Segment] RETURNS [intersect: BOOL] = {RETURN [IntersectPos[s1.pos, s2.pos]]}; IntersectSegment: PUBLIC PROC [s1, s2: Segment, info: REF _ NIL] RETURNS [seg: Segment] = {RETURN [MakeNewSegment[IntersectPosRange[s1.pos, s2.pos], info]]}; UnionSegment: PUBLIC PROC [s1, s2: Segment, info: REF _ NIL] RETURNS [Segment] = {RETURN [MakeNewSegment[UnionPosRange[s1.pos, s2.pos], info]]}; CopySegment: PUBLIC PROC [s: Segment, offset: INT _ 0] RETURNS [seg: Segment] = {RETURN [MakeNewSegment[OffsetPosRange[s.pos, offset], s.info]]}; IntersectPosSegs: PUBLIC PROC [pos: PosRange, segments: SortedSegments] RETURNS [inter: SortedSegments] = { inter _ NIL; WHILE segments#NIL DO IF IntersectPos[pos, segments.first.pos] THEN inter _ CONS [MakeNewSegment[ IntersectPosRange[pos, segments.first.pos], segments.first.info], inter]; segments _ segments.rest; ENDLOOP; RETURN [Reverse[inter]]; }; Append: PUBLIC PROC [s1: SortedSegments, s2: SortedSegments _ NIL, offset: INT _ 0] RETURNS [SortedSegments] = BEGIN res: SortedSegments _ NIL; WHILE s1 # NIL DO res _ CONS[CopySegment[s1.first, 0], res]; s1 _ s1.rest; ENDLOOP; WHILE s2 # NIL DO res _ CONS[CopySegment[s2.first, offset], res]; s2 _ s2.rest; ENDLOOP; RETURN[Reverse[res]]; END; Reverse: PUBLIC PROC [list: SortedSegments] RETURNS [new: SortedSegments] = {WHILE list#NIL DO new _ CONS [list.first, new]; list _ list.rest ENDLOOP}; Intersect: PUBLIC PROC [list1, list2: SortedSegments] RETURNS [list: SortedSegments] = {WHILE list1#NIL AND list2#NIL DO IF IntersectSeg[list1.first, list2.first] THEN BEGIN list _ CONS [IntersectSegment[list1.first, list2.first], list]; IF list1.first.pos.max < list2.first.pos.max THEN list1 _ list1.rest ELSE list2 _ list2.rest; END ELSE IF list1.first.pos.min < list2.first.pos.min THEN list1 _ list1.rest ELSE list2 _ list2.rest; ENDLOOP; RETURN [Reverse[list]]}; Union: PUBLIC PROC [list1, list2: SortedSegments] RETURNS [list: SortedSegments] = {RETURN [SELECT TRUE FROM list1=NIL => list2, list2=NIL => list1, IntersectSeg[list1.first, list2.first] => Union[list1.rest, CONS [UnionSegment[list1.first, list2.first], list2.rest]], list1.first.pos.min < list2.first.pos.min => CONS [list1.first, Union[list1.rest, list2]], ENDCASE => CONS [list2.first, Union[list1, list2.rest]]]}; Insert: PUBLIC PROC [pos: PosRange, info: REF, list: SortedSegments _ NIL] RETURNS [SortedSegments] = {RETURN [IF list=NIL OR list.first.pos.min > pos.min THEN CONS [MakeNewSegment[pos, info], list] ELSE CONS [list.first, Insert[pos, info, list.rest]]]}; Complement: PUBLIC PROC [list: SortedSegments, range: PosRange] RETURNS [SortedSegments] = BEGIN new: SortedSegments _ NIL; DO IF range.min>=range.max THEN EXIT; IF list=NIL THEN {new _ CONS [MakeNewSegment[range], new]; EXIT}; IF range.min RETURN [s]; s=NIL OR s.first.pos.min >= pos.max => RETURN [CONS [MakeNewSegment[pos, NEW [StretchInfoRec _ [value: value]]], s]]; IntersectPos[s.first.pos, pos] => {s.first _ MakeNewSegment[UnionPosRange[s.first.pos, pos], NEW [StretchInfoRec _ [value: GetStretchValue[s.first] + value]]]; RETURN [s]}; ENDCASE => {s.rest _ InsertStretchSegment[pos, value, s.rest]; RETURN [s]}; END; ComposeRectStretches: PUBLIC PROC [rect: CD.Rect, hor, ver: SortedSegments] RETURNS [CD.Rect] = {RETURN [CDBasics.ToRect[ComposePositionStretches[[rect.x1, rect.y1], hor, ver], ComposePositionStretches[[rect.x2, rect.y2], hor, ver]]]}; ComposePositionStretches: PROC [point: CD.Position, hor, ver: SortedSegments] RETURNS [CD.Position] = {RETURN [[AbcissAfterStretch[point.x, hor], AbcissAfterStretch[point.y, ver]]]}; AbcissAfterStretch: PROC [x: CD.Number, s: SortedSegments] RETURNS [newx: CD.Number] = BEGIN newx _ x; WHILE s#NIL AND WhereToStretch[s.first] < x DO newx _ newx + GetStretchValue[s.first]; s _ s.rest ENDLOOP; END; WhereToStretch: PROC [s: Segment] RETURNS [CD.Number] = {RETURN [(s.pos.min + s.pos.max) /2]}; Compose: PROC [map: PWBasics.MapRectProc, hor, ver: SortedSegments] RETURNS [newHor, newVer: SortedSegments] = BEGIN InsertDir: PROC [rect: CD.Rect, info: REF, hor, ver: SortedSegments] RETURNS [SortedSegments, SortedSegments] = BEGIN IF PWBasics.SizeX[rect]=0 THEN RETURN [hor, Insert[PosRangeYFromRect[rect], info, ver]] ELSE RETURN [Insert[PosRangeXFromRect[rect], info, hor], ver]; END; WHILE hor#NIL DO [newHor, newVer] _ InsertDir[ map[RectFromPosRangeX[hor.first.pos, 0]], hor.first.info, newHor, newVer]; hor _ hor.rest; ENDLOOP; WHILE ver#NIL DO [newHor, newVer] _ InsertDir[ map[RectFromPosRangeY[ver.first.pos, 0]], ver.first.info, newHor, newVer]; ver _ ver.rest; ENDLOOP; END; CellParseStretch: ParseStretchProc = BEGIN HorVer: TYPE = REF HorVerRec; HorVerRec: TYPE = RECORD [hor, ver: SortedSegments]; horver: HorVer _ NARROW [CDProperties.GetPropFromObject[obj, $ParsedStretch]]; size: CD.Position _ PWBasics.GetISize[obj]; IF horver#NIL THEN RETURN [horver.hor, horver.ver]; hor _ ver _ NIL; -- during the loop, hor and ver and the complement of their final meaning, the areas where stretch is not possible. FOR appls: CD.ApplicationList _ NARROW [obj.specificRef, CD.CellPtr].contents, appls.rest WHILE appls # NIL DO appl: CD.ApplicationPtr _ appls.first; subSize: CD.Position _ PWBasics.GetISize[appl.ob]; location: CD.Position _ PWBasics.GetLocation[appl, obj]; proc: PWBasics.MapRectProc = {RETURN [CDOrient.MapRect[rect, subSize, appl.orientation, location]]}; subHor, subVer: SortedSegments; [subHor, subVer] _ ParseStretch[design, appl.ob]; subHor _ Complement[subHor, [0, subSize.x]]; subVer _ Complement[subVer, [0, subSize.y]]; [subHor, subVer] _ Compose[proc, subHor, subVer]; hor _ Union[hor, subHor]; ver _ Union[ver, subVer]; ENDLOOP; hor _ Complement[hor, [0, size.x]]; ver _ Complement[ver, [0, size.y]]; CDProperties.PutPropOnObject[obj, $ParsedStretch, NEW [HorVerRec _ [hor, ver]]]; END; CellDoStretch: DoStretchProc = BEGIN SpecifyWhereToStretch: PROC [list: SortedSegments] RETURNS [SortedSegments] = {IF list=NIL THEN RETURN [NIL] ELSE {x: CD.Number _ WhereToStretch[list.first]; RETURN [InsertStretchSegment[[x, x+1], GetStretchValue[list.first], SpecifyWhereToStretch[list.rest]]]}}; Restrict: PROC [list: SortedSegments, pos: PosRange] RETURNS [SortedSegments] = {RETURN [IF list=NIL THEN NIL ELSE IF IntersectPos[list.first.pos, pos] THEN InsertStretchSegment[IntersectPosRange[list.first.pos, pos], GetStretchValue[list.first], Restrict[list.rest, pos]] ELSE Restrict[list.rest, pos]]}; PWBasics.Output["Stretching ", PWBasics.NameFromObj[obj], "\n"]; newObj _ CDCells.CreateEmptyCell[]; hor _ SpecifyWhereToStretch[hor]; ver _ SpecifyWhereToStretch[ver]; FOR appls: CD.ApplicationList _ NARROW [obj.specificRef, CD.CellPtr].contents, appls.rest WHILE appls # NIL DO appl: CD.ApplicationPtr _ appls.first; newappl: CD.ApplicationPtr; subHor, subVer: SortedSegments; subnewcell: CD.ObPtr; subSize: CD.Position _ PWBasics.GetISize[appl.ob]; location: CD.Position _ PWBasics.GetLocation[appl, obj]; proc: PWBasics.MapRectProc = {RETURN [CDOrient.DeMapRect[rect, subSize, appl.orientation, location]]}; [subHor, subVer] _ Compose[proc, hor, ver]; subHor _ Restrict[subHor, [0, subSize.x]]; subVer _ Restrict[subVer, [0, subSize.y]]; [subnewcell, errMsg] _ DoStretch[design, appl.ob, subHor, subVer]; IF errMsg#NIL THEN RETURN [NIL, errMsg]; newappl _ PWBasics.IncludeApplication[newObj, subnewcell, ComposePositionStretches[location, hor, ver], appl.orientation]; newappl.properties _ CDProperties.CopyProps[appl.properties]; ENDLOOP; PWBasics.RepositionCell[design, newObj]; CDCells.SetInterestRect[newObj, ComposeRectStretches[[0, 0, PWBasics.GetISize[obj].x, PWBasics.GetISize[obj].y], hor, ver]]; END; PinParseStretch: ParseStretchProc = BEGIN size: CD.Position _ PWBasics.GetISize[obj]; hor _ Insert[[0, size.x], NIL]; ver _ Insert[[0, size.y], NIL]; END; PinDoStretch: DoStretchProc = BEGIN -- use the design and register size: CD.Position _ PWBasics.GetISize[obj]; newObj _ CDPinObjects.CreatePinOb[CDBasics.SizeOfRect[ComposeRectStretches[[0, 0, size.x, size.y], hor, ver]]]; END; WireParseStretch: ParseStretchProc = BEGIN maxWireWidth: CD.Number = 4*CD.lambda; -- BIG heuristic size: CD.Position _ PWBasics.GetISize[obj]; hor _ Insert[[0, size.x], NIL]; ver _ Insert[[0, size.y], NIL]; IF size.y > maxWireWidth THEN hor _ NIL; IF size.x > maxWireWidth THEN ver _ NIL; END; WireDoStretch: DoStretchProc = BEGIN -- use the design and register size: CD.Position _ PWBasics.GetISize[obj]; newObj _ CDRects.CreateRect[CDBasics.SizeOfRect[ComposeRectStretches[[0, 0, size.x, size.y], hor, ver]], obj.layer]; END; CMosTransistorParseStretch: ParseStretchProc = BEGIN tp: CMosTransistors.TransistorPtr _ NARROW [obj.specificRef]; hor _ Insert[[0, tp.wExt], NIL, Insert[[tp.width+tp.wExt, tp.width+2*tp.wExt], NIL]]; ver _ Insert[[0, tp.lExt], NIL, Insert[[tp.length+tp.lExt, tp.length+2*tp.lExt], NIL]]; END; CMosTransistorDoStretch: DoStretchProc = BEGIN -- use the design and register tp: CMosTransistors.TransistorPtr _ NARROW [obj.specificRef]; wExt: CD.Number = tp.wExt; lExt: CD.Number = tp.lExt; newObj _ obj; WHILE hor#NIL AND hor.first.pos.max <= wExt DO newCell: CD.ObPtr _ CDCells.CreateEmptyCell[]; val: INT _ GetStretchValue[hor.first]; [] _ PWBasics.IncludeApplication[newCell, CDRects.CreateRect[[val, tp.length], CMos.pol], [0, lExt]]; [] _ PWBasics.IncludeApplication[newCell, newObj, [val, 0]]; PWBasics.RepositionCell[design, newCell]; newObj _ newCell; hor _ hor.rest; ENDLOOP; WHILE hor#NIL AND hor.first.pos.min >= tp.width+wExt DO newCell: CD.ObPtr _ CDCells.CreateEmptyCell[]; val: INT _ GetStretchValue[hor.first]; [] _ PWBasics.IncludeApplication[newCell, newObj]; [] _ PWBasics.IncludeApplication[newCell, CDRects.CreateRect[[val, tp.length], CMos.pol], [PWBasics.GetISize[newObj].x, lExt]]; PWBasics.RepositionCell[design, newCell]; newObj _ newCell; hor _ hor.rest; ENDLOOP; IF hor#NIL THEN ERROR; WHILE ver#NIL AND ver.first.pos.max <= lExt DO newCell: CD.ObPtr _ CDCells.CreateEmptyCell[]; val: INT _ GetStretchValue[ver.first]; [] _ PWBasics.IncludeApplication[newCell, CDRects.CreateRect[[tp.width, val], obj.layer], [wExt, 0]]; [] _ PWBasics.IncludeApplication[newCell, newObj, [0, val]]; PWBasics.RepositionCell[design, newCell]; newObj _ newCell; ver _ ver.rest; ENDLOOP; WHILE ver#NIL AND ver.first.pos.min >= tp.length+lExt DO newCell: CD.ObPtr _ CDCells.CreateEmptyCell[]; val: INT _ GetStretchValue[ver.first]; [] _ PWBasics.IncludeApplication[newCell, newObj]; [] _ PWBasics.IncludeApplication[newCell, CDRects.CreateRect[[tp.width, val], obj.layer], [wExt, PWBasics.GetISize[newObj].y]]; PWBasics.RepositionCell[design, newCell]; newObj _ newCell; ver _ ver.rest; ENDLOOP; IF ver#NIL THEN ERROR; END; ParseStretch: PUBLIC ParseStretchProc = BEGIN refProc: REF _ CDProperties.GetPropFromObject[obj, $ParseStretchProc]; IF refProc=NIL THEN refProc _ CDObjectProcs.FetchFurther[obj.p, $ParseStretchProc]; IF refProc=NIL THEN hor _ ver _ NIL ELSE WITH refProc SELECT FROM proc: REF ParseStretchProc => [hor, ver] _ proc[design, obj]; ENDCASE => {PWBasics.Output["Non ParseStretchProc class of proc"]; ERROR}; END; DoStretch: PUBLIC DoStretchProc = BEGIN refProc: REF; IF hor=NIL AND ver=NIL THEN RETURN [obj, NIL]; refProc _ CDProperties.GetPropFromObject[obj, $DoStretchProc]; IF refProc=NIL THEN refProc _ CDObjectProcs.FetchFurther[obj.p, $DoStretchProc]; IF refProc=NIL THEN RETURN [NIL, Rope.Cat["No DoStretchProc Registred for object of class: ", Convert.RopeFromAtom[obj.p.objectType], "."]]; WITH refProc SELECT FROM proc: REF DoStretchProc => { [newObj, errMsg] _ proc[design, obj, hor, ver]; IF errMsg#NIL THEN RETURN [NIL, errMsg]; PWBasics.AppendProps[newObj, obj]; }; ENDCASE => RETURN [NIL, "DoStretchProc registred does not have the proper type"]; END; HardObjParseStretch: PUBLIC ParseStretchProc = {RETURN [NIL, NIL]}; [] _ CDProperties.RegisterProperty[$ParsedStretch, $PW]; [] _ CDProperties.RegisterProperty[$ParseStretchProc, $PW]; [] _ CDProperties.RegisterProperty[$DoStretchProc, $PW]; CDProperties.FetchProcs[$ParsedStretch].makeCopy _ CDProperties.DontCopy; CDProperties.FetchProcs[$ParseStretchProc].makeCopy _ CDProperties.CopyVal; CDProperties.FetchProcs[$DoStretchProc].makeCopy _ CDProperties.CopyVal; IF CDObjectProcs.FetchFurther[CD.FetchObjectProcs[$Cell], $DoStretchProc]=NIL THEN BEGIN CDObjectProcs.RegisterFurther[$ParseStretchProc]; CDObjectProcs.RegisterFurther[$DoStretchProc]; END; IF CD.FetchObjectProcs[$Cell]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$Cell]; PWBasics.Output["PW knows how to stretch Cells\n"]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [ParseStretchProc _ CellParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [DoStretchProc _ CellDoStretch]]; END; IF CD.FetchObjectProcs[$PinOb0]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$PinOb0]; PWBasics.Output["PW knows how to stretch Pins\n"]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [ParseStretchProc _ PinParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [DoStretchProc _ PinDoStretch]]; END; IF CD.FetchObjectProcs[$Rect]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$Rect]; PWBasics.Output["PW knows how to stretch Wires\n"]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [ParseStretchProc _ WireParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [DoStretchProc _ WireDoStretch]]; END; IF CD.FetchObjectProcs[$CMosPDifRect, CMos.cmos]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$CMosPDifRect, CMos.cmos]; PWBasics.Output["PW knows how to stretch CMos PDif Wires\n"]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [ParseStretchProc _ WireParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [DoStretchProc _ WireDoStretch]]; END; IF CD.FetchObjectProcs[$CMosTransistor, CMos.cmos]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$CMosTransistor, CMos.cmos]; PWBasics.Output["PW knows how to stretch CMos N-Type Transistors\n"]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [ParseStretchProc _ CMosTransistorParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [DoStretchProc _ CMosTransistorDoStretch]]; END; IF CD.FetchObjectProcs[$CMosPTypeTransistor, CMos.cmos]#NIL THEN BEGIN p: REF CD.ObjectProcs _ CD.FetchObjectProcs[$CMosPTypeTransistor, CMos.cmos]; PWBasics.Output["PW knows how to stretch CMos P-Type Transistors\n"]; CDObjectProcs.StoreFurther[p, $ParseStretchProc, NEW [ParseStretchProc _ CMosTransistorParseStretch]]; CDObjectProcs.StoreFurther[p, $DoStretchProc, NEW [DoStretchProc _ CMosTransistorDoStretch]]; END; END. ึPWStretchImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reversed. Created by: Bertrand Serlet Last Edited by: Monier, February 21, 1985 9:58:56 pm PST Last Edited by: Serlet, May 3, 1985 6:28:45 pm PDT -- Constants -- Operations on those data structures -- Operations on PosRange -- Predicate telling if 2 PosRanges Intersects -- Tells whether some position is in a range InPos: PROC [x: CD.Number, pos: PosRange] RETURNS [BOOL] = INLINE {RETURN [x>= pos.min AND x list.first.pos.max => list1 _ CONS [list.first, list1]; x < list.first.pos.min => list2 _ CONS [list.first, list2]; ENDCASE => BEGIN s1, s2: Segment; [s1, s2] _ SplitInTwo[list.first, x]; list1 _ CONS [s1, list1]; list2 _ CONS [s2, list2]; END; END; -- Operations on StretchSegment ReSetStretchValue: PUBLIC PROC [s: Segment] = {s.info _ NEW [StretchInfoRec _ [value: 0]]}; SetStretchValue: PUBLIC PROC [s: Segment, value: CD.Number _ 0] = {v: Stretch _ NARROW [s.info]; v.value _ value}; IncrStretchValue: PUBLIC PROC [s: Segment, value: CD.Number] = {SetStretchValue[s, GetStretchValue[s] + value]}; -- could be made more efficient! -- adds all stretch quantities of line AddAllStretches: PUBLIC PROC [line: SortedSegments] RETURNS [CD.Number] = {RETURN [IF line=NIL THEN 0 ELSE GetStretchValue[line.first] + AddAllStretches[line.rest]]}; -- Computes the new location of a Rect once composed with the given SortedStretchSegments -- Uses the stretch quantities for determining the new position of a point after stretch -- Uses the stretch quantity for determining the new abciss of a point after stretch -- When we have choice, where are we going to stretch? -- It is completely heuristic, and there is something wrong about that. -- Private operations -- Procs specific to composed cells -- inserts a new segment in either hor or ver (according to bool) -- Given a composed cell, tells where the stretch areas are. HorVer allows us to implement a emo facility -- parses the cell, notes the projection on both edges of all the non-stretchable objects and produces two sorted lists of strips projections in which a stretchline can be inserted. Output["Entering CellParseStretch"]; -- a priori, the entire cell is stretchable -- we parse the cell by parsing the applications -- union with the global segments to know where not to stretch Output["Leaving CellParseStretch"]; Using this proc we compute where to stretch in the appl coordinates system We restrict where to stretch to the iRect -- Pin related procs -- Wire related procs -- If one dimension is "too large", then no stretch in the other direction is allowed (i.e. no stretch line in the same direction) Output["Entering WireParseStretch"]; Output["Leaving WireParseStretch", IF hor#NIL THEN " hor " ELSE "", IF ver#NIL THEN " ver" ELSE ""]; -- CmosTransistors N-type and P-type related procs enlarging the Poly wire Enlarging the diff wire -- Given any obj, tells where the stretch areas are -- Given obj and wanted stretches, returns a new obj -- Used for telling that an object is not stretchable -- Main body -- We register properties -- We register our new properties if they are not already there -- We register properties for composed cells We register properties for pins -- We register properties for wires -- We register properties for CMosPDifRect which must behave like wires, although they are a different class of objects -- We register properties for n transistors -- We register properties for transistors P ส%˜– "Cedar" stylešœ™Jšœ ฯmœ1™—Jšžœ˜—J˜šžœžœž˜šœ˜Jšœ)˜)Jšœ ˜ —Jšœ˜Jšžœ˜—šžœžœž˜šœ˜Jšœ)˜)Jšœ ˜ —J˜Jšžœ˜—Jšžœ˜—J™J™<šŸœ˜%J–[]šž˜Jšœ,™,Jšœžœžœ ˜Jšœ žœžœ˜4Jšœžœ7˜NJšœk œE™ถJšœžœ#˜+Jšžœžœžœžœ˜3Jšœ$™$J™+Jšœ žœกs˜„J™0šžœžœžœžœ˜ZJšžœ žœž˜Jšœžœ˜&Jšœ žœ'˜2Jšœ žœ,˜8šŸœ˜Jšœžœ@˜G—Jšœ˜Jšœ1˜1Jšœ,˜,Jšœ,˜,Jšœ1˜1Jšกœ;™>Jšœ˜Jšœ˜Jšžœ˜—Jšœ#˜#Jšœ#˜#Jšœ#™#Jšœ2žœ˜PJšžœ˜—J˜šŸ œ˜Jšž˜š œžœžœ˜Mš œžœžœžœžœžœžœ˜$Jšœžœ%˜+Jšžœc˜i——J˜š œžœ'žœ˜OJšœžœžœžœžœžœžœžœ#žœužœ˜แ—J˜Jšœ@˜@Jšœ$˜$Jšœ!˜!Jšœ!˜!šžœžœžœžœ˜ZJšžœ žœž˜Jšœžœ˜&Jšœ žœ˜Jšœ˜Jšœ žœ˜Jšœ žœ'˜2Jšœ žœ,˜8–C -- [rect: PlanarBaseTypes.Rect] RETURNS [PlanarBaseTypes.Rect] -- šŸœะckœ˜JšœžœB˜I—JšœJ™JJšœ+˜+Jšœ)™)Jšœ*˜*Jšœ*˜*JšœB˜BJš žœžœžœžœžœ ˜(Jšœz˜zJšœ=˜=Jšžœ˜—Jšœ(˜(Jšœ|˜|Jšžœ˜——J˜™J™šŸœ˜$Jšž˜Jšœžœ#˜+Jšœžœ˜Jšœžœ˜Jšžœ˜—J˜šŸ œ˜Jšžœก˜$Jšœžœ#˜+Jšœo˜oJšžœ˜——J™™J™šŸœ˜%Jšž˜J™‚Jšœžœ žœ ก˜7JšœŸœ™$Jšœžœ#˜+Jšœžœ˜Jšœžœ˜Jšžœžœžœ˜(Jšžœžœžœ˜(JšœŸœŸžœžœžœ žœžœžœžœžœ™dJšžœ˜—J˜šŸ œ˜Jšžœก˜$Jšœžœ#˜+Jšœt˜tJšžœ˜——J™™2J™šŸœ˜/Jšž˜Jšœ$žœ˜=Jšœžœ1žœ˜UJšœžœ3žœ˜WJšžœ˜—J˜–[]šŸœ˜)Jšžœก˜$Jšœ$žœ˜=Jšœžœ˜Jšœžœ˜J˜ Jšœ™šžœžœžœž˜.Jšœ.˜.Jšœžœ˜&Jšœe˜eJšœ<˜˜>Jšžœ žœžœ=˜PJš žœ žœžœžœžœm˜Œšžœ žœž˜šœžœž˜Jšœ/˜/Jš žœžœžœžœžœ ˜(Jšœ"˜"J˜—Jšžœžœžœ;˜Q—Jšžœ˜—J™J™5Jš Ÿœžœžœžœžœ˜CJ˜™ Jšœ™Jšœ8˜8Jšœ;˜;Jšœ8˜8J˜JšœI˜IJšœK˜KJšœH˜HJ˜J™?šžœžœ*žœž˜RJšž˜Jšœ1˜1Jšœ.˜.Jšžœ˜—J™J™,šžœžœžœž˜&Jšž˜Jšœžœžœžœ˜3J˜3Jšœ1žœ(˜\Jšœ.žœ"˜SJšžœ˜—J˜Jšœ™šžœžœžœž˜(Jšž˜Jšœžœžœžœ˜5J˜2Jšœ1žœ'˜[Jšœ.žœ!˜RJšžœ˜—J™Jšœ#™#šžœžœžœž˜&Jšž˜Jšœžœžœžœ˜3J˜3Jšœ1žœ(˜\Jšœ.žœ"˜SJšžœ˜—J™Jšœw™wšžœžœ,žœž˜9Jšž˜Jšœžœžœžœ,˜FJ˜=Jšœ1žœ(˜\Jšœ.žœ"˜SJšžœ˜—J˜J™+šžœžœ.žœž˜;Jšž˜Jšœžœžœžœ.˜HJ˜EJšœ1žœ2˜fJšœ.žœ,˜]Jšžœ˜—J˜J™+šžœžœ3žœž˜@Jšž˜Jšœžœžœžœ3˜MJ˜EJšœ1žœ2˜fJšœ.žœ,˜]Jšžœ˜——J˜Jšžœ˜—J˜—…—D q