-- 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:
REF ←
NIL]
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:
REF ←
NIL]
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:
REF ←
NIL]
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]};
-- 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;
-- 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;
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;
-- 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;