SCRouteImpl.mesa: Implementation of SC.DetailedRoute
Frank Bowers February 15, 1986 12:40:54 pm PST
Preas December 6, 1985 5:35:17 pm PST : PowerBus width, and transfercell call in PowerRoute
Bryan Preas March 24, 1986 12:12:38 pm PST
DIRECTORY
CD,
CDBasics,
CDCells,
CDOrient,
CDPinObjects,
CDProperties,
CDRects,
CDSymbolicObjects,
Convert,
PW,
PWPins,
PWRoute,
Rope,
Route,
RouteUtil,
RTBasic,
SC,
SCChanUtil,
SCInstUtil,
SCPrivate,
SCRowUtil,
SCUtil;
SCRouteImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDPinObjects, CDProperties, CDRects, CDSymbolicObjects, Convert, PW, PWPins, PWRoute, Rope, RouteUtil, RTBasic, SCChanUtil, SCInstUtil, SCRowUtil, SCUtil
EXPORTS SCPrivate
SHARES SC = BEGIN
RowCellArray: TYPE = ARRAY [1..SCPrivate.maxLgRows] OF PW.Object;
RowCells: TYPE = REF RowCellArray;
NumSeqRec: TYPE = RECORD [
c: SEQUENCE size: NAT OF REF SC.Number];
NumSeq: TYPE = REF NumSeqRec;
EachPinProc: TYPE = PROC [instance: SCPrivate.Instance, netPin: SCPrivate.PinNet, side: SC.Side];
LRSide: TYPE = SCPrivate.LRSide;
TBSide: TYPE = SCPrivate.TBSide;
LayoutData: TYPE = SCPrivate.LayoutData;
ROPE: TYPE = Rope.ROPE;
PQPos: TYPE = RTBasic.PQPos;
SideObjs: TYPE = REF SideObjsRec;
SideObjsRec: TYPE = ARRAY LRSide OF PW.ListOb;
IRSize: PROC [obj: PW.Object] RETURNS [size: CD.Position] =
{size ← CDBasics.SizeOfRect[CD.InterestRect[obj]]};
CreatePinsForChannel: PROC [handle: SC.Handle, chan: NAT, rowCells: RowCells] =
BEGIN
side: SC.Side;
row: NAT;
externOnly: BOOLEAN;
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
lgRows: SCPrivate.LgRows ← layoutData.lgRows;
MakeNetPin: SCInstUtil.EachPinProc = {
[instance: SCPrivate.Instance, pin: NAT, netPin: SCPrivate.PinNet]
IF netPin.net #NIL AND
(~externOnly OR (externOnly AND netPin.net.externNet = externalNet)) THEN {
IF side = SCInstUtil.PosOf[instance, netPin.pin].sideOn THEN {
rect: CD.Rect ← SCInstUtil.RotateRect[instance, netPin.pin.rect];
pinOb: CD.Object ← CDPinObjects.CreatePinOb[CDBasics.SizeOfRect[rect]];
position: CD.Position ← SCUtil.PQToXY[handle, [p: instance.offset + rect.x1, q: rect.y1]];
pinInst: CD.Instance;
IF ~externOnly AND netPin.net.pinsOnChan <= 1 THEN RETURN;
pinInst ← PW.IncludeInCell[cell: rowCells[row], obj: pinOb, position: position];
CDPinObjects.SetName[pinInst, netPin.net.name];
CDPinObjects.SetLayer[pinInst, netPin.pin.layer]}};
};
ResetInstCount: EachPinProc = {
IF netPin.net # NIL AND side = SCInstUtil.PosOf[instance, netPin.pin].sideOn THEN netPin.net.pinsOnChan ← 0;
};
CountInsts: EachPinProc = {
IF netPin.net # NIL AND side = SCInstUtil.PosOf[instance, netPin.pin].sideOn THEN netPin.net.pinsOnChan ← netPin.net.pinsOnChan + 1;
};
ForEachExtInstance: SCRowUtil.EachInstProc = {
externOnly ← TRUE;
[] ← SCInstUtil.EnumeratePinsOnInst[instance, MakeNetPin]};
ForEachIntInstance: SCRowUtil.EachInstProc = {
externOnly ← FALSE;
[] ← SCInstUtil.EnumeratePinsOnInst[instance, MakeNetPin]};
IF chan = 1 THEN {
side ← bottom; row ← 1;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachExtInstance]}
ELSE IF chan = lgRows.count + 1 THEN {
side ← top; row ← lgRows.count;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachExtInstance]}
ELSE {
EnumeratePinsOnChan[handle, chan, CountInsts];
side ← top; row ← chan - 1;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachIntInstance];
side ← bottom; row ← chan;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachIntInstance];
EnumeratePinsOnChan[handle, chan, ResetInstCount];
};
END;
EnumeratePinsOnChan: PROC [handle: SC.Handle, chan: NAT, action: EachPinProc] = {
side: SC.Side;
row: NAT;
ForEachPin: SCInstUtil.EachPinProc = {
action[instance, netPin, side]};
ForEachIntInstance: SCRowUtil.EachInstProc = {
[] ← SCInstUtil.EnumeratePinsOnInst[instance, ForEachPin]};
side ← top; row ← chan - 1;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachIntInstance];
side ← bottom; row ← chan;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachIntInstance];
};
CreateExitsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan, exitCells: SideObjs] =
BEGIN
cell: CD.Object;
trunkWidth: SC.Number ← handle.rules.rowRules.trunkWidth;
CreateNewExit: SCChanUtil.EachExitProc = {
pinOb: CD.Object ← CDPinObjects.CreatePinOb[size: [trunkWidth, trunkWidth]];
pinInst: CD.Instance ← PW.IncludeInCell[cell: cell, obj: pinOb];
CDPinObjects.SetName[pinInst, exit.net.name];
CDPinObjects.SetLayer[pinInst, exit.layer];
exit.net.pinsOnChan ← exit.net.pinsOnChan + 1;
};
FOR side: LRSide IN LRSide DO
rect: CD.Rect;
cell ← PW.CreateEmptyCell[];
[] ← SCChanUtil.EnumerateExits[handle, rowChan, side, CreateNewExit];
SELECT side FROM -- pw needs a better way of finding sides
left => rect ← [-trunkWidth, -trunkWidth, trunkWidth, 2*trunkWidth];
right => rect ← [0, -trunkWidth, 2*trunkWidth, 2*trunkWidth];
ENDCASE;
CDCells.SetInterestRect[cell, rect]; -- set interestRect of cell
PW.RepositionCell[cell];
exitCells[side] ← CONS[cell, exitCells[side]];
ENDLOOP;
END;
CreateWireAndContact: PROC [handle: SC.Handle, pin: PW.Instance, size: Route.Position, length: CD.Number, trunkLayer: CD.Layer]
RETURNS [obj: CD.Object] = {
branchLayer: CD.Layer ← CDPinObjects.GetLayer[pin];
obj ← PW.CreateEmptyCell[];
[] ← PW.IncludeInCell[obj, CreateWireFromPin[handle, pin, length]];
RouteUtil.AddVia[obj, CDPinObjects.GetName[pin], [length-size.x/2, size.y/2], size, trunkLayer, branchLayer];
PW.RepositionCell[obj];
};
CreateWireFromPin: PROC [handle: SC.Handle, pin: PW.Instance, length: CD.Number]
RETURNS [wire: CD.Object] =
BEGIN
wx: CD.Number ← length;
wy: CD.Number ← pin.ob.size.y;
wSize: CD.Position ← SCUtil.PQToXY[handle, [wx, wy]];
layer: CD.Layer ← CDPinObjects.GetLayer[pin];
wire ← CDRects.CreateRect[wSize, layer];
END;
AlwaysExtendPin: PROC [handle: SC.Handle, inst: PW.Instance, extLen: CD.Number]
RETURNS [obj: CD.Object ← NIL] =
BEGIN
create wire and copy pin to end of wire
IF CDSymbolicObjects.IsPin[inst.ob] THEN {
pinInst: CD.Instance;
pinSize: CD.Position ← SCUtil.PQToXY[handle, [inst.ob.size.x, inst.ob.size.y]];
wire: CD.Object ← CreateWireFromPin[handle, inst, extLen];
pinOb: CD.Object ← CDPinObjects.CreatePinOb[pinSize];
obj ← PW.CreateEmptyCell[];
pinInst ← PW.IncludeInCell[obj, pinOb, [extLen-inst.ob.size.x, 0]];
[] ← PW.IncludeInCell[obj, wire];
CDPinObjects.SetName[pinInst, CDPinObjects.GetName[inst]];
CDPinObjects.SetLayer[pinInst, CDPinObjects.GetLayer[inst]];
PW.RepositionCell[obj]};
END;
ExtendPowerBuses: PROC [handle: SC.Handle, rowList: PW.ListOb]
RETURNS [rows: PW.ListOb ← NIL] =
BEGIN
extend power buses to length of longest row
extLen: CD.Number;
side: LRSide;
rl: PW.ListOb ← NIL;
abutOb: PW.Object;
pwSide: PWPins.Side;
rowNum: NAT ← 0;
layout: LayoutData ← NARROW[handle.layoutData];
maxRowLength: CD.Number ← SCRowUtil.FindMaxRow[handle].maxRowWidth;
ExtendPin: PW.ForEachPinProc = {
IF Rope.Equal[CDPinObjects.GetName[inst], layout.powerBuses[side].name] THEN
obj ← AlwaysExtendPin[handle, inst, extLen]};
FOR rl ← rowList, rl.rest UNTIL rl = NIL DO
rowLength: CD.Number ← IRSize[rl.first].x;
rowNum ← rowNum + 1;
IF rowLength < maxRowLength THEN {
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
FOR side IN LRSide DO
extLen ← SELECT side FROM
left => (maxRowLength - rowLength)/2,
right => maxRowLength - rowLength - (maxRowLength - rowLength)/2,
ENDCASE => ERROR;
pwSide ← SELECT side FROM right => right, left => left, ENDCASE => ERROR;
ext[side] ← TransferCell[template: rl.first, objSide: pwSide, width: extLen, objProc: ExtendPin, stopEnumerateDeepPins: FALSE];
ENDLOOP;
abutOb ← PW.AbutListX[LIST[ext[left], rl.first, ext[right]]]}
ELSE abutOb ← rl.first;
rows ← CONS[IncludeCell[abutOb, Rope.Cat["Row",Convert.RopeFromInt[rowNum]], FALSE], rows];
ENDLOOP;
END;
CreateRowCell: PROC [handle: SC.Handle, row: NAT, rowList: PW.ListOb, rowCells: RowCells]
RETURNS [PW.ListOb] =
BEGIN
rowOb: PW.Object ← NIL;
listOb: PW.ListOb ← NIL;
rCell: CD.Object ← NIL; -- cell obtained from rowOb
ForEachInstance: SCRowUtil.EachInstProc = {
thisObj: CD.Object ← instance.object.cdOb;
listOb ← CONS[thisObj, listOb]};
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachInstance];
listOb ← PW.Reverse[listOb];
rowOb ← PW.AbutListX[listOb];
rCell ← IncludeCell[rowOb, Rope.Cat["Row", Convert.RopeFromInt[row]], TRUE];
rowList ← CONS[rCell, rowList];
rowCells[row] ← rCell;
RETURN[rowList];
END;
LogicRoute: PROC [handle: SC.Handle] RETURNS [logicOb: PW.Object] =
BEGIN
exitCells: SideObjs ← NEW[SideObjsRec ← ALL[NIL]];
rowList: PW.ListOb ← NIL;
rowCells: RowCells ← NEW[RowCellArray];
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
rowChans: SCPrivate.RowChans ← layoutData.rowChans;
parms: SCPrivate.Parms ← NARROW[handle.parms];
routerParams: PWRoute.RouterParams ← NEW[ PWRoute.RouterParamsRec ← [handle.rules.horizLayer, handle.rules.vertLayer, parms.cdDesign.technology.key]];
abutOb: PW.Object;
ForEachRow: SCRowUtil.EachRowProc = {
rowList ← CreateRowCell[handle, row, rowList, rowCells];
};
ForEachChannel: SCChanUtil.EachRowChanProc = {
IF 1 < rowChan.chanNum AND rowChan.chanNum < rowChans.count THEN
CreateExitsForChannel[handle: handle, rowChan: rowChan, exitCells: exitCells];
CreatePinsForChannel[handle: handle, chan: chan, rowCells: rowCells];
};
SCInstUtil.AllOffsets[handle];
[] ← SCRowUtil.EnumerateRows[handle: handle, eachRow: ForEachRow];
[] ← SCChanUtil.EnumerateRowChans[handle: handle, eachRowChan: ForEachChannel];
rowList ← ExtendPowerBuses[handle, rowList];
exitCells[left] ← PW.Reverse[exitCells[left]];
exitCells[right] ← PW.Reverse[exitCells[right]];
abutOb ← PWRoute.AbutChRouteListY[
listOb: rowList, leftListOb: exitCells[left], rightListOb: exitCells[right],
params: routerParams
-- ! Route.Signal => RESUME -- ];
logicOb ← IncludeCell[abutOb, Rope.Cat[handle.name, "Logic"], FALSE];
END;
IncludeTrunkPin: PROC [handle: SC.Handle, cell: CD.Object, name: ROPE, tbSide: TBSide, trunkSize, trunkPos: PQPos, layer: CD.Layer] =
BEGIN
pin: CD.Object ← CDPinObjects.CreatePinOb[[trunkSize.p, trunkSize.p]];
pos: CD.Position;
pinInst: CD.Instance;
trunkPos.q ← trunkPos.q + (IF tbSide = top THEN trunkSize.q - trunkSize.p ELSE 0);
pos ← SCUtil.PQToXY[handle, trunkPos];
pinInst ← PW.IncludeInCell[cell, pin, pos];
CDPinObjects.SetName[pinInst, name];
CDPinObjects.SetLayer[pinInst, layer];
END;
PowerRoute: PROC [handle: SC.Handle, pwOb: PW.Object]
RETURNS [ob: PW.Object] =
BEGIN
ext end power pins on edges and put in power rails
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
trunkLayer: CD.Layer ← handle.rules.sideRules.trunkLayer;
pwSide: PWPins.Side;
pBus: SCPrivate.PowerBus;
side: LRSide;
trunk, abutOb: CD.Object;
trunkSize, trunkPos: PQPos;
extLen, width, trunkWidth: SC.Number;
layout: LayoutData ← NARROW[handle.layoutData];
ExtendPin: PW.ForEachPinProc = {
name: ROPE ← CDPinObjects.GetName[inst];
otherPBus: SCPrivate.PowerBus = layout.powerBuses[RTBasic.OtherSide[side]];
SELECT TRUE FROM
Rope.Equal[name, pBus.name] =>
obj ← CreateWireAndContact[handle, inst, [trunkWidth, IRSize[inst.ob].y], width, trunkLayer];
Rope.Equal[name, otherPBus.name] => NULL;
ENDCASE => obj ← AlwaysExtendPin[handle, inst, width]};
FOR side IN LRSide DO
pBus ← layout.powerBuses[side];
width ← pBus.width;
trunkWidth ← pBus.net.trunkWidth;
extLen ← width - trunkWidth;
trunkSize ← [p: trunkWidth, q: IRSize[pwOb].y];
trunkPos ← [IF side = right THEN extLen ELSE 0, 0];
pwSide ← SELECT side FROM right => right, left => left, ENDCASE => ERROR;
ext[side] ← TransferCell[template: pwOb, objSide: pwSide, width: width, objProc: ExtendPin, name: IF side = right THEN "RPower" ELSE "LPower", stopEnumerateDeepPins: FALSE];
trunk ← MakeTrunk[handle: handle, trunkSize: trunkSize, lev: trunkLayer];
[] ← PW.IncludeInCell[ext[side], trunk, SCUtil.PQToXY[handle, trunkPos]];
FOR tbSide: TBSide IN TBSide DO
IncludeTrunkPin[handle, ext[side], pBus.name, tbSide, trunkSize, trunkPos , trunkLayer];
ENDLOOP;
ENDLOOP;
abutOb ← PW.AbutListX[LIST [ext[left], pwOb, ext[right]]];
ob ← IncludeCell[abutOb, Rope.Cat[handle.name, "WPower"], FALSE];
END;
MakeTrunk: PROC [handle: SC.Handle, trunkSize: PQPos, lev: CD.Layer]
RETURNS [obj: CD.Object] =
BEGIN
obj ← CDRects.CreateRect[SCUtil.PQToXY[handle, trunkSize], lev];
END;
AcBusForName: PROC [handle: SC.Handle, side: LRSide, name: ROPE] RETURNS [acBus: SCPrivate.AcBus ← NIL, i: NAT] =
BEGIN
layout: LayoutData ← NARROW[handle.layoutData];
sigs: SCPrivate.AcBusSigs ← layout.acBuses[side].sigs;
FOR i IN [0..sigs.size) DO
IF Rope.Equal[name, sigs[i].name] THEN RETURN [sigs[i], i];
ENDLOOP;
END;
ComputeTrunkEnd: PROC [trunkEnd: NumSeq, q: SC.Number, index: NAT, fromTB: TBSide] =
BEGIN
prev: REF SC.Number ← trunkEnd[index];
trunkEnd[index] ← NEW[SC.Number];
trunkEnd[index]^ ← IF prev = NIL THEN q ELSE SELECT fromTB FROM
top => MIN[q, prev^],
bottom => MAX[q, prev^],
ENDCASE => ERROR;
END;
CreateAcTrunks: PROC [handle: SC.Handle, cell: CD.Object, acBusSide: SCPrivate.AcBusSides, trunkEnd: NumSeq, layer: CD.Layer] =
BEGIN
side: LRSide;
trunk: CD.Object;
trunkSize, trunkPos: PQPos;
bus: SCPrivate.AcBus;
FOR i: NAT IN [0..acBusSide.sigs.size) DO
bus ← acBusSide.sigs[i];
side ← bus.onSide;
trunkPos.p ← SELECT side FROM
left => IRSize[cell].x - bus.depth, right => bus.depth, ENDCASE => ERROR;
trunkPos.q ← SELECT bus.fromTB FROM
bottom => 0, top => trunkEnd[i]^, ENDCASE => ERROR;
trunkSize.p ← bus.net.trunkWidth;
trunkSize.q ← SELECT bus.fromTB FROM
bottom => trunkEnd[i]^, top => IRSize[cell].y - trunkEnd[i]^, ENDCASE => ERROR;
trunk ← MakeTrunk[handle: handle, trunkSize: trunkSize, lev: layer];
[] ← PW.IncludeInCell[cell, trunk, SCUtil.PQToXY[handle, trunkPos]];
IncludeTrunkPin[handle, cell, bus.name, bus.fromTB, trunkSize, trunkPos, layer];
ENDLOOP;
END;
ClockRoute: PROC [handle: SC.Handle, pwOb: PW.Object]
RETURNS [ob: PW.Object] =
BEGIN
trunkEnd: NumSeq; -- "q" coordinate of trunk end point
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
trunkLayer: CD.Layer ← handle.rules.sideRules.trunkLayer;
side: LRSide;
abutOb: CD.Object;
width: SC.Number;
layout: LayoutData ← NARROW[handle.layoutData];
ExtendPin: PW.ForEachPinProc = {
[inst: Instance] RETURNS [obj: Object];
pinName: ROPE ← CDPinObjects.GetName[inst];
acBus: SCPrivate.AcBus;
sigIndex: NAT;
[acBus, sigIndex] ← AcBusForName[handle, side, pinName];
IF acBus = NIL THEN obj ← AlwaysExtendPin[handle, inst, width]
ELSE {
ComputeTrunkEnd[trunkEnd: trunkEnd, q: inst.location.y, index: sigIndex, fromTB: acBus.fromTB];
obj ← CreateWireAndContact[handle, inst, [acBus.net.trunkWidth, acBus.net.branchWidth], acBus.depth, trunkLayer]}};
FOR side IN LRSide DO
pwSide: PWPins.Side;
acBusSide: SCPrivate.AcBusSides ← layout.acBuses[side];
IF acBusSide = NIL OR acBusSide.sigs = NIL THEN LOOP;
trunkEnd ← NEW[NumSeqRec[acBusSide.sigs.size]];
FOR i: NAT IN [0..trunkEnd.size) DO trunkEnd[i] ← NIL; ENDLOOP;
pwSide ← SELECT side FROM right => right, left => left, ENDCASE => ERROR;
width ← acBusSide.width;
ext[side] ← TransferCell[template: pwOb, objSide: pwSide, width: width, objProc: ExtendPin, stopEnumerateDeepPins: FALSE];
CreateAcTrunks[handle, ext[side], acBusSide, trunkEnd, trunkLayer];
ENDLOOP;
abutOb ← PW.AbutListX[LIST [ext[left], pwOb, ext[right]]];
ob ← IncludeCell[abutOb, Rope.Cat[handle.name, "WClocks"], FALSE];
END;
IORoute: PROC [handle: SC.Handle, pwOb: PW.Object]
RETURNS [ob: PW.Object] =
BEGIN
layout: LayoutData ← NARROW[handle.layoutData];
bpRows: SCPrivate.BpRows ← layout.bpRows;
FOR side: SC.Side IN SC.Side DO
IF bpRows[side].fnlBpFxd THEN {
expand bprow to length of corresponding cell's side.
PWRoute.AbutRoute to pwOb
SCInstutil.BpPos
right side => position in bp
bottom => origin lower left hand side
top => lower right hand side origin
left => upper left side
};
ENDLOOP;
handle: for each side for which side.fnlBpFxd invoke PWRoute.AbutRoute else
extend exit pins to edge of cell
END;
DetailRoute: PUBLIC PROC [handle: SC.Handle] RETURNS [result: SC.Result] =
BEGIN
pwOb: PW.Object ← NIL;
pwOb ← LogicRoute[handle];
pwOb ← PowerRoute[handle, pwOb];
pwOb ← ClockRoute[handle, pwOb];
result ← NEW[SC.ResultRec ← []];
result.object ← pwOb;
result.handle ← handle;
pwOb ← IORoute[handle, pwOb];
END;
IncludeCell: PROC [rowOb: PW.Object, name: Rope.ROPENIL, StopEnumerateDeepPins: BOOLEANTRUE] RETURNS [rCell: CD.Object] =
BEGIN
rCellPtr: CD.CellPtr;
inst: CD.Instance;
rCell ← PW.CreateEmptyCell[];
rCellPtr ← NARROW [rCell.specificRef];
inst ← NEW [CD.InstanceRep ← [ob: rowOb]];
IF StopEnumerateDeepPins THEN
CDProperties.PutPropOnInstance[inst, $StopEnumerateDeepPins, $StopEnumerateDeepPins];
rCellPtr.contents ← CONS [inst, rCellPtr.contents];
CDCells.SetInterestRect[rCell, CD.InterestRect[rowOb]];
[] ← PW.RepositionCell[rCell];
END;
TransferCell: PROC [template: PW.Object, objSide: PWPins.Side, width: INT, objProc: PW.ForEachPinProc, name: Rope.ROPE ← "Transfer", stopEnumerateDeepPins: BOOLEANTRUE] RETURNS [cell: PW.Object] =
BEGIN
KeepPinOnEdge: PWPins.InstanceEnumerator =
BEGIN
newObj: PW.Object;
side: PWPins.Side ← PWPins.GetSide[template, inst].side;
IF side=objSide THEN {
newObj ← objProc[inst]; IF newObj=NIL THEN RETURN;
[] ← PW.IncludeInCell[cell, newObj, Position[inst, template, objSide], SideToOrient[objSide]];
};
END;
iRect: CD.Rect;
-- Start with an empty cell of appropriate interestRect (origin in 0,0)
IF objSide=none THEN ERROR;
cell ← PW.CreateEmptyCell[];
iRect ← CD.InterestRect[template];   -- copy interestRect of obj
CDCells.SetInterestRect[cell, IRect[iRect, width, objSide]]; -- set interestRect of cell
-- Parse the pins
[] ← PWPins.EnumerateEdgePins[template, KeepPinOnEdge, stopEnumerateDeepPins];
PW.RepositionCell[cell];
END;
IRect: PROC [templateRect: CD.Rect, otherDim: INT, side: PWPins.Side] RETURNS [iRect: CD.Rect] =
BEGIN
iRect ← SELECT side FROM
top, bottom => [0, 0, templateRect.x2-templateRect.x1, otherDim],
left, right => [0, 0, otherDim, templateRect.y2-templateRect.y1],
ENDCASE => ERROR;
END;
SideToOrient: PROC [side: PWPins.Side] RETURNS [orient: CD.Orientation] ~ {
orient ← SELECT side FROM
bottom => CDOrient.rotate270,
right => CDOrient.original,
top => CDOrient.rotate90,
left => CDOrient.rotate180,
ENDCASE => ERROR;
};
Position: PROC [inst: CD.Instance, template: PW.Object, side: PWPins.Side] RETURNS [position: CD.Position] =
BEGIN
position ← PW.GetLocation[inst, template];
SELECT side FROM
top, bottom => position.y ← 0;
left, right => position.x ← 0;
ENDCASE => ERROR;
END;
END.