PWStretchImpl.mesa
Copyright © 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
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;
-- Constants
worldSegment: PUBLIC Segment = NEW [SegmentRec ← [pos: [min: FIRST [CD.Number], max: LAST [CD.Number]]]];
worldSortedSegments: PUBLIC SortedSegments = LIST [worldSegment];
-- Operations on those data structures
-- Operations on PosRange
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]]};
-- Predicate telling if 2 PosRanges Intersects
IntersectPos: PUBLIC PROC [pos1, pos2: PosRange] RETURNS [intersect: BOOL] =
{RETURN [MAX [pos1.min, pos2.min] < MIN [pos1.max, pos2.max]]};
-- Tells whether some position is in a range
InPos: PROC [x: CD.Number, pos: PosRange] RETURNS [BOOL] =
INLINE {RETURN [x>= pos.min AND x<pos.max]};
-- Offsets a PosRange by an INT amount
OffsetPosRange: PUBLIC PROC [pos: PosRange, offset: INT] RETURNS [posrange: PosRange] =
{RETURN [[pos.min+offset, pos.max+offset]]};
-- Intersects 2 PosRange
IntersectPosRange: PUBLIC PROC [pos1, pos2: PosRange] RETURNS [posrange: PosRange] =
{RETURN [[MAX [pos1.min, pos2.min], MIN [pos1.max, pos2.max]]]};
-- Union of 2 PosRange
UnionPosRange: PUBLIC PROC [pos1, pos2: PosRange] RETURNS [posrange: PosRange] =
{RETURN [[MIN [pos1.min, pos2.min], MAX [pos1.max, pos2.max]]]};
-- Operations on Segment
-- Creates a new Segment
MakeNewSegment: PUBLIC PROC [pos: PosRange, info: REFNIL] RETURNS [seg: Segment] =
{IF pos.min>= pos.max THEN ERROR;
RETURN [NEW [SegmentRec ← [pos: pos, info: info]]]};
-- Tells whether 2 segments do intersect
IntersectSeg: PUBLIC PROC [s1, s2: Segment] RETURNS [intersect: BOOL] =
{RETURN [IntersectPos[s1.pos, s2.pos]]};
-- Creates a new Segment at the intersection of 2
IntersectSegment: PUBLIC PROC [s1, s2: Segment, info: REFNIL] RETURNS [seg: Segment] =
{RETURN [MakeNewSegment[IntersectPosRange[s1.pos, s2.pos], info]]};
-- Creates a new Segment at the reunion of 2
UnionSegment: PUBLIC PROC [s1, s2: Segment, info: REFNIL]
RETURNS [Segment] =
{RETURN [MakeNewSegment[UnionPosRange[s1.pos, s2.pos], info]]};
-- Copies a segment with displacing it
CopySegment: PUBLIC PROC [s: Segment, offset: INT ← 0] RETURNS [seg: Segment] =
{RETURN [MakeNewSegment[OffsetPosRange[s.pos, offset], s.info]]};
-- Splits a Segment in two at position x. Both new segments share the same info.
SplitSegmentInTwo: PUBLIC PROC [s: Segment, x: INT] RETURNS [s1, s2: Segment] =
{RETURN [MakeNewSegment[[s.pos.min, x], s.info],
MakeNewSegment[[x, s.pos.max], s.info]]};
-- Operations on SortedSegments
-- Returns the sorted list of all segments which intersect some given PosRange
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]];
};
-- Appends a SortedSegments to an existing one, with copying and displacing the Segments. With only first argument, returns a top-layer copy of it.
Append: PUBLIC PROC [s1: SortedSegments, s2: SortedSegments ← NIL, offset: INT ← 0] RETURNS [SortedSegments] =
{RETURN [IF s1#NIL
THEN CONS [CopySegment[s1.first, 0], Append[s1.rest, s2, offset]]
ELSE IF s2#NIL
THEN CONS [CopySegment[s2.first, offset], Append[NIL, s2.rest, offset]]
ELSE NIL]};
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 a SortedSegments, as Lisp's reverse!
Reverse: PUBLIC PROC [list: SortedSegments] RETURNS [new: SortedSegments] =
{WHILE list#NIL DO new ← CONS [list.first, new]; list ← list.rest ENDLOOP};
-- Makes a new SortedSegments with all segments that appear in both lists
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]]};
-- Makes a new SortedSegments with all segments that appear in either lists
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]]]};
-- Inserts a new Segment
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]]]};
-- Makes a list with all segments in range that are excluded by list
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<list.first.pos.min
THEN new ← CONS [MakeNewSegment[[range.min, list.first.pos.min]], new];
range.min ← list.first.pos.max;
list ← list.rest;
ENDLOOP;
RETURN [Reverse[new]]
END;
-- Removes all segments which are within some range
Difference: PUBLIC PROC [list: SortedSegments, pos: PosRange] RETURNS [SortedSegments] =
BEGIN
inter: PosRange;
IF list=NIL THEN RETURN [NIL];
inter ← IntersectPosRange[list.first.pos, pos];
RETURN [IF inter.min <= inter.max THEN CONS [MakeNewSegment[inter, list.first.info], Difference[list.rest, pos]] ELSE Difference[list.rest, pos]]
END;
-- Splits a SortedSegments in two at position x
SplitIListInTwo: PUBLIC PROC [list: SortedSegments, x: INT] RETURNS [list1, list2: SortedSegments] =
BEGIN
IF list=NIL THEN RETURN [NIL, NIL];
[list1, list2] ← SplitIListInTwo[list.rest, x];
SELECT TRUE FROM
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
GetStretchValue: PUBLIC PROC [s: StretchSegment] RETURNS [CD.Number] =
{RETURN [NARROW [s.info, StretchInfo].value]};
InsertStretchSegment: PUBLIC PROC [pos: PosRange, value: CD.Number, s: SortedStretchSegments] RETURNS [SortedStretchSegments] =
BEGIN
SELECT TRUE FROM
value=0          => 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;
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
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]]]};
-- Uses the stretch quantities for determining the new position of a point after stretch
ComposePositionStretches: PROC [point: CD.Position, hor, ver: SortedSegments] RETURNS [CD.Position] =
{RETURN [[AbcissAfterStretch[point.x, hor], AbcissAfterStretch[point.y, ver]]]};
-- Uses the stretch quantity for determining the new abciss of a point after stretch
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;
-- When we have choice, where are we going to stretch?
-- It is completely heuristic, and there is something wrong about that.
WhereToStretch: PROC [s: Segment] RETURNS [CD.Number] =
{RETURN [(s.pos.min + s.pos.max) /2]};
-- Private operations
-- Procs specific to composed cells
Compose: PROC [map: PWBasics.MapRectProc, hor, ver: SortedSegments] RETURNS [newHor, newVer: SortedSegments] =
BEGIN
-- inserts a new segment in either hor or ver (according to bool)
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;
-- Given a composed cell, tells where the stretch areas are.
CellParseStretch: ParseStretchProc =
BEGIN
HorVer allows us to implement a emo facility
HorVer: TYPE = REF HorVerRec;
HorVerRec: TYPE = RECORD [hor, ver: SortedSegments];
horver: HorVer ← NARROW [CDProperties.GetPropFromObject[obj, $ParsedStretch]];
-- 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.
size: CD.Position ← PWBasics.GetISize[obj];
IF horver#NIL THEN RETURN [horver.hor, horver.ver];
Output["Entering CellParseStretch"];
-- a priori, the entire cell is stretchable
hor ← ver ← NIL; -- during the loop, hor and ver and the complement of their final meaning, the areas where stretch is not possible.
-- we parse the cell by parsing the applications
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];
-- union with the global segments to know where not to stretch
hor ← Union[hor, subHor];
ver ← Union[ver, subVer];
ENDLOOP;
hor ← Complement[hor, [0, size.x]];
ver ← Complement[ver, [0, size.y]];
Output["Leaving CellParseStretch"];
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]]};
Using this proc we compute where to stretch in the appl coordinates system
[subHor, subVer] ← Compose[proc, hor, ver];
We restrict where to stretch to the iRect
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;
-- Pin related procs
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;
-- Wire related procs
WireParseStretch: ParseStretchProc =
BEGIN
-- If one dimension is "too large", then no stretch in the other direction is allowed (i.e. no stretch line in the same direction)
maxWireWidth: CD.Number = 4*CD.lambda; -- BIG heuristic
Output["Entering WireParseStretch"];
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;
Output["Leaving WireParseStretch", IF hor#NIL THEN " hor " ELSE "", IF ver#NIL THEN " ver" ELSE ""];
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;
-- CmosTransistors N-type and P-type related procs
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;
enlarging the Poly wire
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;
Enlarging the diff wire
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;
-- Given any obj, tells where the stretch areas are
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;
-- Given obj and wanted stretches, returns a new obj
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;
-- Used for telling that an object is not stretchable
HardObjParseStretch: PUBLIC ParseStretchProc = {RETURN [NIL, NIL]};
-- Main body
-- We register properties
[] ← 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;
-- We register our new properties if they are not already there
IF CDObjectProcs.FetchFurther[CD.FetchObjectProcs[$Cell], $DoStretchProc]=NIL THEN
BEGIN
CDObjectProcs.RegisterFurther[$ParseStretchProc];
CDObjectProcs.RegisterFurther[$DoStretchProc];
END;
-- We register properties for composed cells
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;
We register properties for pins
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;
-- We register properties for wires
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;
-- We register properties for CMosPDifRect which must behave like wires, although they are a different class of objects
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;
-- We register properties for n transistors
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;
-- We register properties for transistors P
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.