SCRouteImpl.mesa: Implementation of SC.DetailedRoute
Copyright © 1986 by Xerox Corporation. All rights reserved.
Frank Bowers June 3, 1986 10:58:48 am PDT
Bryan Preas April 3, 1986 5:34:51 pm PST
DIRECTORY
CD,
CDBasics,
CDCells,
CDOrient,
CDProperties,
CDRects,
CDSymbolicObjects,
Convert,
PW,
PWPins,
PWRoute,
Rope,
Route,
RouteUtil,
RTBasic,
SC,
SCChanUtil,
SCInstUtil,
SCNetUtil,
SCPrivate,
SCRoutePinsUtil,
SCRowUtil,
SCUtil;
SCRouteImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDProperties, CDRects, CDSymbolicObjects, Convert, PW, PWPins, PWRoute, Rope, RouteUtil, RTBasic, SC, SCChanUtil, SCInstUtil, SCNetUtil, SCRoutePinsUtil, SCRowUtil, SCUtil
EXPORTS SCPrivate
SHARES SC = BEGIN
RowCellsRec: TYPE = ARRAY SCPrivate.MaxRowSr OF PW.Object;
RowCells: TYPE = REF RowCellsRec;
ExitCellsSideRec: TYPE = ARRAY SCPrivate.MaxChanSr OF PW.Object;
ExitCellsSide: TYPE = REF ExitCellsSideRec;
ExitCellsRec: TYPE = ARRAY LRSide OF ExitCellsSide;
ExitCells: TYPE = REF ExitCellsRec;
NumSeqRec: TYPE = RECORD [
c: SEQUENCE size: NAT OF REF SC.Number];
NumSeq: TYPE = REF NumSeqRec;
LRSide: TYPE = SCPrivate.LRSide;
TBSide: TYPE = SCPrivate.TBSide;
LayoutData: TYPE = SCPrivate.LayoutData;
ROPE: TYPE = Rope.ROPE;
PQPos: TYPE = SCPrivate.PQPos;
CreatePinsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan, rowCells: RowCells] = {
AllPins: SCInstUtil.EachPinProc = {
[instance: SCPrivate.Instance, pin: NAT, netPin: SCPrivate.PinNet]
IF netPin.net #NIL THEN {
IF side = SCInstUtil.PosOf[instance, netPin.pin].sideOn THEN {
rect: CD.Rect ← SCInstUtil.RotateRect[instance, netPin.pin.rect];
position: CD.Position ← SCUtil.PQToXY[handle, [p: instance.offset + rect.x1, q: rect.y1]];
SCRoutePinsUtil.EnterPin[rect, position, netPin, RTBasic.OtherSide[side], rowCells[row]]}}};
ExternalPins: SCInstUtil.EachPinProc = {
[instance: SCPrivate.Instance, pin: NAT, netPin: SCPrivate.PinNet]
IF netPin.net #NIL AND netPin.net.externNet = externalNet THEN {
IF side = SCInstUtil.PosOf[instance, netPin.pin].sideOn AND ExitOnSide[handle, netPin.net, side] THEN {
rect: CD.Rect ← SCInstUtil.RotateRect[instance, netPin.pin.rect];
position: CD.Position ← SCUtil.PQToXY[handle, [p: instance.offset + rect.x1, q: rect.y1]];
SCRoutePinsUtil.EnterPin[rect, position, netPin, RTBasic.OtherSide[side], rowCells[row]]}}};
InternalPinsInstance: SCRowUtil.EachInstProc = {
[] ← SCInstUtil.EnumeratePinsOnInst[instance, AllPins]};
ExternalPinsInstance: SCRowUtil.EachInstProc = {
[] ← SCInstUtil.EnumeratePinsOnInst[instance, ExternalPins]};
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
lgRows: SCPrivate.LgRows ← layoutData.lgRows;
chan: SCPrivate.MaxChanSr ← rowChan.chanNum;
side: SC.Side;
row: SCPrivate.MaxRowSr;
IF chan = 1 THEN {
side ← bottom; row ← 1;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ExternalPinsInstance]}
ELSE IF chan = lgRows.count + 1 THEN {
side ← top; row ← lgRows.count;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ExternalPinsInstance]}
ELSE {
side ← top; row ← chan - 1;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, InternalPinsInstance];
side ← bottom; row ← chan;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, InternalPinsInstance]}};
CreateExitsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan, exitCells: ExitCells] = {
cell: CD.Object;
ExitPins: SCChanUtil.EachExitProc = {SCRoutePinsUtil.EnterExit[exit, lrSide, cell]};
FOR side: LRSide IN LRSide DO
cell ← PW.CreateEmptyCell[];
[] ← SCChanUtil.EnumerateExits[handle, rowChan, side, ExitPins];
exitCells[side][rowChan.chanNum] ← cell;
ENDLOOP};
FinishExitsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan, exitCells: ExitCells] = {
trunkWidth: SC.Number ← handle.rules.rowRules.trunkWidth;
FOR side: LRSide IN LRSide DO
rect: CD.Rect;
cell: CD.Object ← exitCells[side][rowChan.chanNum];
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];
ENDLOOP};
CreateWireAndContact: PROC [handle: SC.Handle, pin: PW.Instance, size: Route.Position, length: CD.Number, trunkLayer: CD.Layer, cdLambda: Route.Number]
RETURNS [obj: CD.Object] = {
branchLayer: CD.Layer ← CDSymbolicObjects.GetLayer[pin];
obj ← PW.CreateEmptyCell[];
[] ← PW.IncludeInCell[obj, CreateWireFromPin[handle, pin, length]];
RouteUtil.AddVia[obj, CDSymbolicObjects.GetName[pin], [length-size.x/2, size.y/2], size, trunkLayer, branchLayer, cdLambda];
PW.RepositionCell[obj]};
CreateWireFromPin: PROC [handle: SC.Handle, pin: PW.Instance, length: CD.Number]
RETURNS [wire: CD.Object] = {
wx: CD.Number ← length;
wy: CD.Number ← pin.ob.size.y;
wSize: CD.Position ← SCUtil.PQToXY[handle, [wx, wy]];
layer: CD.Layer ← CDSymbolicObjects.GetLayer[pin];
wire ← CDRects.CreateRect[wSize, layer]};
AlwaysExtendPin: PROC [handle: SC.Handle, inst: PW.Instance, extLen: CD.Number]
RETURNS [obj: CD.Object ← NIL] = {
create wire and copy pin to end of wire
IF CDSymbolicObjects.IsSymbolicOb[inst.ob] THEN {
pinInst: CD.Instance;
wire: CD.Object ← CreateWireFromPin[handle, inst, extLen];
pinOb: CD.Object ← CDSymbolicObjects.CreateSegment[inst.ob.size.y];
obj ← PW.CreateEmptyCell[];
pinInst ← PW.IncludeInCell[obj, pinOb, [extLen-pinOb.size.x, 0], CDSymbolicObjects.OrientFromDirection[east]];
[] ← PW.IncludeInCell[obj, wire];
CDSymbolicObjects.SetName[pinInst, CDSymbolicObjects.GetName[inst]];
CDSymbolicObjects.SetLayer[pinInst, CDSymbolicObjects.GetLayer[inst]];
PW.RepositionCell[obj]}};
ExtendPowerBuses: PROC [handle: SC.Handle, rowCells: RowCells] = {
extend power buses to length of longest row
extLen: CD.Number;
side: LRSide;
abutOb: PW.Object;
layoutData: LayoutData ← NARROW[handle.layoutData];
lgRows: SCPrivate.LgRows ← layoutData.lgRows;
maxRowWidth: CD.Number ← lgRows.maxRowWidth;
ExtendPin: PW.ForEachPinProc = {
IF Rope.Equal[CDSymbolicObjects.GetName[inst], layoutData.powerBuses[side].name] THEN
obj ← AlwaysExtendPin[handle, inst, extLen]};
FOR rowNum: SCPrivate.MaxRowSr IN [1 .. lgRows.count] DO
row: SCPrivate.LgRow ← lgRows.rows[rowNum];
rowLength: SC.Number ← row.size.p;
rowOffset: SC.Number ← row.rowOrg.p - lgRows.horzRowOrg;
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
IF rowOffset > 0 AND rowLength < maxRowWidth THEN { -- needs filler on left and right
side ← left; extLen ← rowOffset;
ext[left] ← TransferCell[template: rowCells[rowNum], objSide: left, width: extLen, objProc: ExtendPin, stopEnumerateDeepPins: FALSE];
side ← right; extLen ← maxRowWidth - (rowOffset + rowLength);
ext[right] ← TransferCell[template: rowCells[rowNum], objSide: right, width: extLen, objProc: ExtendPin, stopEnumerateDeepPins: FALSE];
abutOb ← PW.AbutListX[LIST[ext[left], rowCells[rowNum], ext[right]]]}
ELSE IF rowLength < maxRowWidth THEN { -- rowOffset = 0, no filler on left
side ← right; extLen ← maxRowWidth - rowLength;
ext[right] ← TransferCell[template: rowCells[rowNum], objSide: right, width: extLen, objProc: ExtendPin, stopEnumerateDeepPins: FALSE];
abutOb ← PW.AbutListX[LIST[rowCells[rowNum], ext[right]]]}
ELSE -- no filler needed
abutOb ← rowCells[rowNum];
rowCells[rowNum] ← IncludeCell[abutOb, Rope.Cat["Row",Convert.RopeFromInt[rowNum]], FALSE];
ENDLOOP};
CreateRowCell: PROC [handle: SC.Handle, row: SCPrivate.MaxRowSr, rowCells: RowCells] = {
ForEachInstance: SCRowUtil.EachInstProc = {
thisObj: CD.Object;
IF instance.curOrien = 1 THEN thisObj ← instance.object.cdOb
ELSE thisObj ← PW.ChangeOrientation[instance.object.cdOb, SCInstUtil.CDOrien[instance]];
listOb ← CONS[thisObj, listOb]};
rowOb: PW.Object ← NIL;
listOb: PW.ListOb ← NIL;
rCell: CD.Object ← NIL; -- cell obtained from rowOb
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachInstance];
listOb ← PW.Reverse[listOb];
rowOb ← PW.AbutListX[listOb];
rCell ← IncludeCell[rowOb, Rope.Cat["Row", Convert.RopeFromInt[row]], TRUE];
rowCells[row] ← rCell};
-- AbutRoute: uses a channel router to connect adjacent objects
AbutRouteList: PROC [listOb, bottomOrLeftListOb, topOrRightListOb: PW.ListOb, params: PWRoute.RouterParams, rowChans: SCPrivate.RowChans]
RETURNS [obj: PW.Object] =
BEGIN
newListObj: PW.ListOb ← NIL;
obj1, obj2, topOrRightObj, bottomOrLeftObj, channel: PW.Object;
result: Route.RoutingResult;
chan: SCPrivate.MaxChanSr ← 1;
IF listOb = NIL THEN RETURN[NIL];
obj1 ← listOb.first; listOb ← listOb.rest;
newListObj ← CONS[obj1, NIL];
FOR l: PW.ListOb ← listOb, l.rest WHILE l # NIL DO
obj2 ← l.first;
IF topOrRightListOb = NIL THEN topOrRightObj ← NIL
ELSE {topOrRightObj ← topOrRightListOb.first;
topOrRightListOb ← topOrRightListOb.rest};
IF bottomOrLeftListOb = NIL THEN bottomOrLeftObj ← NIL
ELSE {bottomOrLeftObj ← bottomOrLeftListOb.first;
bottomOrLeftListOb ← bottomOrLeftListOb.rest};
result ← PWRoute.DoRoute[obj1, obj2, bottomOrLeftObj, topOrRightObj, params, FALSE, channel];
rowChans.chans[chan].routing ← result;
channel ← PWRoute.GetRouting[result, NIL];
newListObj ← CONS[obj2, CONS[channel, newListObj]];
obj1 ← obj2; -- just before looping
chan ← chan + 1;
ENDLOOP;
newListObj ← PW.Reverse[newListObj];
obj ← PW.AbutListY[newListObj];
END;
LogicRoute: PROC [handle: SC.Handle] RETURNS [logicOb: PW.Object] = {
ForEachRow: SCRowUtil.EachRowProc = {
CreateRowCell[handle, row, rowCells]};
ForEachChannel: SCChanUtil.EachRowChanProc = {
SCRoutePinsUtil.InitGetChanPins[handle];
IF 1 < rowChan.chanNum AND rowChan.chanNum < rowChans.count THEN
CreateExitsForChannel[handle: handle, rowChan: rowChan, exitCells: exitCells];
CreatePinsForChannel[handle: handle, rowChan: rowChan, rowCells: rowCells];
SCRoutePinsUtil.EnterNetDat[handle, chan, MakeNetPin, MakeExit, NIL];
SCRoutePinsUtil.TermGetChanPins[handle];
IF 1 < rowChan.chanNum AND rowChan.chanNum < rowChans.count THEN
FinishExitsForChannel[handle: handle, rowChan: rowChan, exitCells: exitCells]};
MakeExit: SCRoutePinsUtil.ExitProc = {
pinOb: CD.Object ← CDSymbolicObjects.CreatePin[size: [trunkWidth, exit.net.trunkWidth]];
pinInst: CD.Instance ← PW.IncludeInCell[cell: cell, obj: pinOb];
CDSymbolicObjects.SetName[pinInst, exit.net.name];
CDSymbolicObjects.SetLayer[pinInst, exit.layer]};
MakeNetPin: SCRoutePinsUtil.PinProc = {
[rect: SC.Rect, position: CD.Position, netPin: SCPrivate.PinNet, cell: CD.Object]
pinOb: CD.Object ← CDSymbolicObjects.CreatePin[CDBasics.SizeOfRect[rect]];
pinInst: CD.Instance ← PW.IncludeInCell[cell: cell, obj: pinOb, position: position];
CDSymbolicObjects.SetName[pinInst, netPin.net.name];
CDSymbolicObjects.SetLayer[pinInst, netPin.pin.layer]};
exitCells: ExitCells ← NEW[ExitCellsRec];
rowCells: RowCells ← NEW[RowCellsRec ← ALL[NIL]];
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
rowChans: SCPrivate.RowChans ← layoutData.rowChans;
parms: SCPrivate.Parms ← NARROW[handle.parms];
routerParams: PWRoute.RouterParams ← NEW[PWRoute.RouterParamsRec ← [trunkLayer: handle.rules.horizLayer, branchLayer: handle.rules.vertLayer, technologyKey: parms.cdDesign.technology.key, signalBreakAtExit: FALSE, signalSinglePinNets: TRUE]];
abutOb: PW.Object;
exitCells[left] ← NEW[ExitCellsSideRec ← ALL[NIL]];
exitCells[right] ← NEW[ExitCellsSideRec ← ALL[NIL]];
SCInstUtil.AllOffsets[handle];
[] ← SCRowUtil.EnumerateRows[handle: handle, eachRow: ForEachRow];
[] ← SCChanUtil.EnumerateRowChans[handle: handle, eachRowChan: ForEachChannel];
ExtendPowerBuses[handle, rowCells];
abutOb ← AbutRouteList[
listOb: RowListConvert[handle, rowCells], bottomOrLeftListOb: ChanListConvert[handle, exitCells[left]], topOrRightListOb: ChanListConvert[handle, exitCells[right]], rowChans: rowChans,
params: routerParams];
logicOb ← IncludeCell[abutOb, Rope.Cat[handle.name, "Logic"], FALSE]};
IncludeTrunkPin: PROC [handle: SC.Handle, cell: CD.Object, name: ROPE, tbSide: TBSide, trunkSize, trunkPos: PQPos, layer: CD.Layer] = {
height: INT ← handle.rules.rowRules.trunkWidth;
pin: CD.Object ← CDSymbolicObjects.CreatePin[[trunkSize.p, height]];
pinPos: PQPos ← [trunkPos.p, IF tbSide = top THEN trunkPos.q + trunkSize.q - height ELSE trunkPos.q];
pos: CD.Position ← SCUtil.PQToXY[handle, pinPos];
pinInst: CD.Instance ← PW.IncludeInCell[cell, pin, pos];
CDSymbolicObjects.SetName[pinInst, name];
CDSymbolicObjects.SetLayer[pinInst, layer]};
PowerRoute: PROC [handle: SC.Handle, pwOb: PW.Object]
RETURNS [ob: PW.Object] = {
ext end power pins on edges and put in power rails
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
rules: Route.DesignRules ← handle.rules.sideRules;
trunkLayer: CD.Layer ← rules.trunkLayer;
pwSide: PWPins.Side;
pBus: SCPrivate.PowerBus;
side: LRSide;
trunk, abutOb: CD.Object;
trunkSize, trunkPos: PQPos;
extLen, width, trunkWidth: SC.Number;
layoutData: LayoutData ← NARROW[handle.layoutData];
ExtendPin: PW.ForEachPinProc = {
name: ROPE ← CDSymbolicObjects.GetName[inst];
otherPBus: SCPrivate.PowerBus = layoutData.powerBuses[RTBasic.OtherSide[side]];
SELECT TRUE FROM
Rope.Equal[name, pBus.name] =>
obj ← CreateWireAndContact[handle, inst, [trunkWidth, RTBasic.IRSize[inst.ob].y], width, trunkLayer, handle.rules.sideRules.CDLambda];
Rope.Equal[name, otherPBus.name] => NULL;
ENDCASE => obj ← AlwaysExtendPin[handle, inst, width]};
FOR side IN LRSide DO
pBus ← layoutData.powerBuses[side];
width ← MAX[pBus.width, rules.trunkToTrunk];
trunkWidth ← width - rules.trunkSpacing;
extLen ← rules.trunkSpacing;
trunkSize ← [p: trunkWidth, q: RTBasic.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]];
IF Rope.Equal[pBus.name, "Vdd"] THEN
IncludeTrunkPin[handle, ext[side], pBus.name, top, trunkSize, trunkPos , trunkLayer];
IF Rope.Equal[pBus.name, "Gnd"] THEN
IncludeTrunkPin[handle, ext[side], pBus.name, bottom, trunkSize, trunkPos , trunkLayer];
ENDLOOP;
abutOb ← PW.AbutListX[LIST [ext[left], pwOb, ext[right]]];
ob ← IncludeCell[abutOb, Rope.Cat[handle.name, "WPower"], FALSE]};
MakeTrunk: PROC [handle: SC.Handle, trunkSize: PQPos, lev: CD.Layer]
RETURNS [obj: CD.Object] = {
obj ← CDRects.CreateRect[SCUtil.PQToXY[handle, trunkSize], lev]};
AcBusForName: PROC [handle: SC.Handle, side: LRSide, name: ROPE] RETURNS [acBus: SCPrivate.AcBus ← NIL, i: NAT] = {
layoutData: LayoutData ← NARROW[handle.layoutData];
sigs: SCPrivate.AcBusSigs ← layoutData.acBuses[side].sigs;
FOR i IN [0..sigs.size) DO
IF Rope.Equal[name, sigs[i].name] THEN RETURN [sigs[i], i];
ENDLOOP};
ComputeTrunkEnd: PROC [trunkEnd: NumSeq, q: SC.Number, index: NAT, fromTB: TBSide] = {
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};
CreateAcTrunks: PROC [handle: SC.Handle, cell: CD.Object, acBusSide: SCPrivate.AcBusSides, trunkEnd: NumSeq, layer: CD.Layer] = {
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 => RTBasic.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 => RTBasic.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};
ClockRoute: PROC [handle: SC.Handle, pwOb: PW.Object]
RETURNS [ob: PW.Object] = {
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;
layoutData: LayoutData ← NARROW[handle.layoutData];
ExtendPin: PW.ForEachPinProc = {
[inst: Instance] RETURNS [obj: Object];
pinName: ROPE ← CDSymbolicObjects.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, handle.rules.sideRules.CDLambda]}};
FOR side IN LRSide DO
pwSide: PWPins.Side;
acBusSide: SCPrivate.AcBusSides ← layoutData.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]};
DetailRoute: PUBLIC PROC [handle: SC.Handle] RETURNS [result: SC.Result] = {
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;
CheckExports[result]};
IncludeCell: PROC [rowOb: PW.Object, name: Rope.ROPENIL, stopEnumerateDeepPins: BOOLEANTRUE] RETURNS [rCell: CD.Object] = {
rCellPtr: CD.CellPtr;
inst: CD.Instance;
rCell ← PW.CreateEmptyCell[];
rCellPtr ← NARROW [rCell.specificRef];
inst ← NEW [CD.InstanceRep ← [ob: rowOb]];
CDProperties.PutInstanceProp[inst, $InstanceName, name];
IF stopEnumerateDeepPins THEN
CDProperties.PutProp[inst, $StopEnumerateDeepPins, $StopEnumerateDeepPins];
rCellPtr.contents ← CONS [inst, rCellPtr.contents];
CDCells.SetInterestRect[rCell, CD.InterestRect[rowOb]];
[] ← PW.RepositionCell[rCell]};
TransferCell: PROC [template: PW.Object, objSide: PWPins.Side, width: INT, objProc: PW.ForEachPinProc, name: Rope.ROPE ← "Transfer", stopEnumerateDeepPins: BOOLEANTRUE] RETURNS [cell: PW.Object] = {
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]};
IRect: PROC [templateRect: CD.Rect, otherDim: INT, side: PWPins.Side] RETURNS [iRect: CD.Rect] = {
iRect ← SELECT side FROM
top, bottom => [0, 0, templateRect.x2-templateRect.x1, otherDim],
left, right => [0, 0, otherDim, templateRect.y2-templateRect.y1],
ENDCASE => ERROR};
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] = {
position ← PW.GetLocation[inst, template];
SELECT side FROM
top, bottom => position.y ← 0;
left, right => position.x ← 0;
ENDCASE => ERROR};
RowListConvert: PROC [handle: SC.Handle, rowCells: RowCells] RETURNS [listOb: PW.ListObNIL] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
FOR rowNum: SCPrivate.MaxRowSr DECREASING IN [1 .. layoutData.lgRows.count] DO
listOb ← CONS[rowCells[rowNum], listOb];
ENDLOOP};
ChanListConvert: PROC [handle: SC.Handle, exitCells: ExitCellsSide] RETURNS [listOb: PW.ListObNIL] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
FOR chanNum: SCPrivate.MaxChanSr DECREASING IN [2 .. layoutData.rowChans.count-1] DO
listOb ← CONS[exitCells[chanNum], listOb];
ENDLOOP};
ExitOnSide: PROC [handle: SC.Handle, net: SCPrivate.Net, side: SC.Side] RETURNS [onThisSide: BOOLEAN] ~ {
EachInstance: SCRowUtil.EachInstProc ~ {
CheckPin: SCInstUtil.EachPinProc = {
[instance: SCPrivate.Instance, pin: NAT, netPin: SCPrivate.PinNet]
IF netPin.net = net THEN quit ← TRUE};
quit ← SCInstUtil.EnumeratePinsOnInst[instance, CheckPin]};
onThisSide ← SCRowUtil.EnumerateAllInstsOnSide[handle, side, EachInstance]};
CheckExports: PROC [result: SC.Result] ~ {
check to insure all exports are correct:
pins representing exported wires and only exported wires are present on boundry
KeepPinOnEdge: PWPins.InstanceEnumerator = {
name: Rope.ROPE ← CDSymbolicObjects.GetName[inst];
IF ~Memb[name, exportsList] THEN exportsList ← CONS[name, exportsList]};
CheckNet: SCNetUtil.EachNetProc ~ {
memb: BOOLEAN ← Memb[net.name, exportsList];
IF ~memb AND net.externNet = externalNet THEN
SC.Signal[programmingError, Rope.Cat["Public net not exported: ", net.name]]};
exportsList: LIST OF Rope.ROPENIL;
[] ← PWPins.EnumerateEdgePins[result.object, KeepPinOnEdge, TRUE];
[] ← SCNetUtil.EnumerateNets[result.handle, CheckNet]};
Memb: PROC [rope: Rope.ROPE, list: LIST OF Rope.ROPE] RETURNS [BOOL] = {
UNTIL list = NIL DO
IF Rope.Equal[list.first, rope] THEN RETURN[TRUE];
list ← list.rest;
ENDLOOP;
RETURN[FALSE];
};
END.