PWRouteImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDCells, CDOrient, CDSymbolicObjects, CDRects, CDSimpleRules, PW, PWPins, Route, RouteUtil, SymTab
EXPORTS PWRoute =
BEGIN OPEN PWRoute;
-- AbutRoute: uses a channel router to connect adjacent objects
AbutRouteList:
PROC [listOb, bottomOrLeftListOb, topOrRightListOb:
PW.ListOb, params: RouterParams, isX:
BOOL, routeType: RouteType]
RETURNS [obj: PW.Object] =
BEGIN
newListObj: PW.ListOb ← NIL;
obj1, obj2, topOrRightObj, bottomOrLeftObj, channel: PW.Object;
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};
channel ← MakeChannel[obj1, obj2, bottomOrLeftObj, topOrRightObj, NIL, params, isX, routeType];
newListObj ← CONS[obj2, CONS[channel, newListObj]];
obj1 ← obj2; -- just before looping
ENDLOOP;
newListObj ← PW.Reverse[newListObj];
IF isX THEN obj ← PW.AbutListX[newListObj]
ELSE obj ← PW.AbutListY[newListObj];
END;
AbutChRouteListX:
PUBLIC
PROC [
listOb: PW.ListOb,
bottomListOb: PW.ListOb ← NIL,
topListOb: PW.ListOb ← NIL,
params: RouterParams ← defaultRouterParams]
RETURNS [obj: PW.Object] =
{obj ← AbutRouteList[listOb, bottomListOb, topListOb, params, TRUE, channel]};
AbutChRouteListY:
PUBLIC
PROC [
listOb: PW.ListOb,
leftListOb: PW.ListOb ← NIL,
rightListOb: PW.ListOb ← NIL,
params: RouterParams ← defaultRouterParams]
RETURNS [obj: PW.Object] =
{obj ← AbutRouteList[listOb, leftListOb, rightListOb, params, FALSE, channel]};
AbutSbRoute:
PUBLIC
PROC [
bottomOb, rightOb, topOb, leftOb: PW.Object ← NIL,
trunkDir: HorV ← horizontal,
params: RouterParams ← defaultRouterParams] RETURNS [obj: PW.Object] = {
IF trunkDir = horizontal
THEN
obj ← MakeChannel[bottomOb, topOb, leftOb, rightOb, NIL, params, FALSE, switchBox]
ELSE
obj ← MakeChannel[leftOb, rightOb, bottomOb, topOb, NIL, params, TRUE, switchBox]};
-- Given two cells that we plan to abut, this module parses the corresponding edges, extract the pins, build nets according to the names on the pins, then calls the router to produce a cell containing the channel routing.
Net: TYPE = REF NetRec;
NetRec:
TYPE =
RECORD[
name: ROPE ← NIL, -- net name
pins: Route.PinList ← NIL]; -- the list of pins in the net
defaultRouterParams: PUBLIC RouterParams ← NEW[RouterParamsRec ← ["metal", "poly"]];
-- Gets all the pins on the edge; pack them into nets and put in the SymTab.Ref
ParsePins: PROC[obj: CD.Object, tab: SymTab.Ref, side: PWPins.Side, params: RouterParams] = {
EachPin: CDSymbolicObjects.InstEnumerator = {
[inst: CD.Instance] RETURNS [quit: BOOL ← FALSE]
IF PWPins.GetSide[obj, inst].side=side THEN InsertPin[tab, inst, side, params];
};
IF obj # NIL THEN [] ← PWPins.EnumerateEdgePins[obj, EachPin];
};
FromSideToSide:
PROC [side: PWPins.Side]
RETURNS [routeSide: Route.Side] = {
routeSide ←
SELECT side
FROM
left => left,
right => right,
top => top,
bottom => bottom,
ENDCASE => ERROR;
};
OtherSide:
PROC [side: Route.Side]
RETURNS [opposite: Route.Side] = {
opposite ←
SELECT side
FROM
left => right,
right => left,
top => bottom,
bottom => top,
ENDCASE => ERROR;
};
-- Group pins in net and insert in table
InsertPin:
PROC [tab: SymTab.Ref, inst:
CD.Instance, side: PWPins.Side, params: RouterParams] = {
found: BOOL;
val: REF;
net: Net;
pin: Route.Pin ← Route.CreatePin[inst, OtherSide[FromSideToSide[side]]];
pinName: ROPE ← CDSymbolicObjects.GetName[inst];
tabIndex: ROPE ← IF params.makeTabKeyProc=NIL THEN pinName ELSE params.makeTabKeyProc[inst, params.context];
[found, val] ← SymTab.Fetch[tab, tabIndex];
net ← IF ~found THEN NEW[NetRec ← [pinName]] ELSE NARROW[val];
net.pins ← CONS[pin, net.pins];
[] ← SymTab.Store[tab, tabIndex, net];
};
-- Read the table and ship the nets to the channel router
ShipNets:
PROC [tab: SymTab.Ref, routingArea: Route.RoutingArea, trunkAtom:
ATOM, params: RouterParams] = {
EnterOneNet: SymTab.EachPairAction =
BEGIN
netName: ROPE ← NARROW[key];
net: Net ← NARROW[val];
width: Route.Number ← IF params.wireWidthProc=NIL THEN 0 ELSE params.wireWidthProc[net.name, params.context];
properties: Route.PropList ← RouteUtil.PutNumberProp[NIL, Route.trunkWidthKey, width];
Route.IncludeNet[routingArea, net.name, net.pins, properties];
RETURN[FALSE];
END;
[] ← SymTab.Pairs[tab, EnterOneNet];
};
DoRoute:
PUBLIC
PROC [obj1, obj2, bottomOrLeftObj, topOrRightObj:
CD.Object, params: RouterParams, isX:
BOOL, routeType: RouteType]
RETURNS [result: Route.RoutingResult] = {
tab: SymTab.Ref;
sideCoords: Route.PositionVec; -- the positions of the sides in a "large" coord system
r1, r2, rbl, rtr, routingRect: CD.Rect ← [0, 0, 0, 0];
pBottom, pLeft, pTop, pRight: CD.Position;
trunkAtom: ATOM;
-- Make the design rules for proper spacing in this techno
rules: Route.DesignRules ←
IF isX
THEN
-- abutX
Route.CreateDesignRules[params.technologyKey,
CDSimpleRules.GetLayer[params.technologyKey, params.branchLayer],
CDSimpleRules.GetLayer[params.technologyKey, params.trunkLayer],
vertical]
ELSE
-- abutY
Route.CreateDesignRules[params.technologyKey,
CDSimpleRules.GetLayer[params.technologyKey, params.trunkLayer],
CDSimpleRules.GetLayer[params.technologyKey, params.branchLayer],
horizontal];
-- Initialize the channel: no fancy option for now
routingArea: Route.RoutingArea ← Route.CreateRoutingArea["Channel", rules];
-- In prevision of the use of the IRect coord system, origins are [0, 0]
IF obj1 # NIL THEN r1 ← CD.InterestRect[obj1];
IF obj2 # NIL THEN r2 ← CD.InterestRect[obj2];
IF bottomOrLeftObj # NIL THEN rbl ← CD.InterestRect[bottomOrLeftObj];
IF topOrRightObj # NIL THEN rtr ← CD.InterestRect[topOrRightObj];
IF isX
THEN {
-- AbutX
pBottom ← [0, - rbl.y2 + rbl.y1];
pLeft ← [- r1.x2 + r1.x1, 0];
pTop ← [0, MAX[r1.y2 - r1.y1, r2.y2 - r2.y1]];
pRight ← [MAX[rbl.x2 - rbl.x1, rtr.x2 - rtr.x1], 0];
Route.IncludeRoutingAreaSide[routingArea, left, [r1.x1, r1.y1]];
Route.IncludeRoutingAreaSide[routingArea, right, [r2.x1, r2.y1]];
Route.IncludeRoutingAreaSide[routingArea, bottom, [rbl.x1, rbl.y1]];
Route.IncludeRoutingAreaSide[routingArea, top, [rtr.x1, rtr.y1]];
trunkAtom ← $verticalWidth}
ELSE {
-- AbutY
pBottom ← [0, - r1.y2 + r1.y1];
pLeft ← [- rbl.x2 + rbl.x1, 0];
pTop ← [0, MAX[rbl.y2 - rbl.y1, rtr.y2 - rtr.y1]];
pRight ← [MAX[r1.x2 - r1.x1, r2.x2 - r2.x1], 0];
Route.IncludeRoutingAreaSide[routingArea, bottom, [r1.x1, r1.y1]];
Route.IncludeRoutingAreaSide[routingArea, top, [r2.x1, r2.y1]];
Route.IncludeRoutingAreaSide[routingArea, left, [rbl.x1, rbl.y1]];
Route.IncludeRoutingAreaSide[routingArea, right, [rtr.x1, rtr.y1]];
trunkAtom ← $horizontalWidth};
tab ← SymTab.Create[mod: 17, case: TRUE]; -- the table of all nets
-- Parse the objects, get the pins, make the nets, put in table
ParsePins[obj1, tab, IF isX THEN right ELSE top, params];
ParsePins[obj2, tab, IF isX THEN left ELSE bottom, params];
ParsePins[topOrRightObj, tab, IF isX THEN bottom ELSE left, params];
ParsePins[bottomOrLeftObj, tab, IF isX THEN top ELSE right, params];
-- Read the table and ship the nets to the channel router
ShipNets[tab, routingArea, trunkAtom, params];
-- Now route!
sideCoords ← [pBottom, pTop, pLeft, pRight];
routingRect ← [0, 0, pRight.x, pTop.y];
SELECT routeType
FROM
channel => result ← Route.ChannelRoute[routingArea, sideCoords, routingRect, params.opt, params.signalSinglePinNets, params.signalCoincidentPins];
switchBox => result ← Route.SwitchBoxRoute[routingArea, sideCoords, routingRect, params.opt, params.signalSinglePinNets, params.signalCoincidentPins, params.okToDiddleLLPins, params.okToDiddleURPins];
ENDCASE;
IF result.incompleteNets # NIL AND params.signalIncomplete THEN Route.Signal[noResource, "Incomplete routing of nets"];
IF result.breakAtExitNets # NIL AND params.signalBreakAtExit THEN Route.Signal[noResource, "Nets were divided at channel exit"];
};
GetRouting:
PUBLIC
PROC [result: Route.RoutingResult, retrieveRect: RefRect ←
NIL]
RETURNS [channel:
CD.Object] ~ {
channel ← Route.RetrieveRouting[result, result.routingArea.name, retrieveRect, NIL].object;
Route.Destroy[result.routingArea];
};
MakeChannel:
PUBLIC
PROC [obj1, obj2, bottomOrLeftObj, topOrRightObj:
CD.Object, retrieveRect: RefRect, params: RouterParams, isX:
BOOL, routeType: RouteType]
RETURNS [channel:
CD.Object] = {
result: Route.RoutingResult← DoRoute[obj1, obj2, bottomOrLeftObj, topOrRightObj, params, isX, routeType];
channel ← GetRouting[result, retrieveRect].channel;
Route.Destroy[result.routingArea];
};
XferPins:
PUBLIC
PROC [technologyKey:
ATOM, template:
PW.Object, objSide: PWPins.Side, minWidth:
INT, routingLayerDes:
ROPE, selectNameProc:
PW.SelectNamesProc ←
PW.KeepAll, xferPinsProc: PWRoute.XferPinsProc]
RETURNS [cell:
PW.Object ←
NIL] = {
FindPins: CDSymbolicObjects.InstEnumerator = {
[inst: CD.Instance] RETURNS [quit: BOOL ← FALSE]
IF PWPins.GetSide[template, inst].side=objSide
THEN {
pinLayer: CD.Layer ← CDSymbolicObjects.GetLayer[inst];
IF pinLayer # routingLayer
THEN {
-- when PW is fixed clean this up
pwBug: CD.Instance ← CDCells.IncludeOb[NIL, NIL, inst.ob, [0,0], pwBugOrien].newInst;
xferObj: PW.Object;
CDSymbolicObjects.SetLayer[pwBug, pinLayer];
xferObj ← xferPinsProc[technologyKey, pwBug, routingLayer, 0];
needsXfer ← TRUE;
width ← MAX[width, IRSize[xferObj].x]};
};
};
MapPins:
PW.ForEachPinProc = {
[inst: Instance] RETURNS [obj: Object]
obj ← NIL;
IF PWPins.GetSide[template, inst].side = objSide
THEN {
pinInst: CD.Instance;
pinSize: CD.Position;
pinOb, wire: CD.Object;
-- when PW is fixed clean this up
pwBug: CD.Instance ← CDCells.IncludeOb[NIL, NIL, inst.ob, [0,0], pwBugOrien].newInst;
CDSymbolicObjects.SetLayer[pwBug, CDSymbolicObjects.GetLayer[inst]];
wire ← xferPinsProc[technologyKey, pwBug, routingLayer, width];
pinSize ← CDOrient.OrientedSize[pwBug.ob.size, pwBug.orientation];
pinOb ← CDSymbolicObjects.CreatePin[pinSize];
obj ← PW.CreateEmptyCell[];
pinInst ← PW.IncludeInCell[obj, pinOb, [width-pinSize.x, 0]];
[] ← PW.IncludeInCell[obj, wire];
CDSymbolicObjects.SetName[pinInst, CDSymbolicObjects.GetName[inst]];
CDSymbolicObjects.SetLayer[pinInst, routingLayer];
PW.RepositionCell[obj];
};
};
width: INT ← MAX[minWidth, 0];
needsXfer: BOOLEAN ← width > 0;
routingLayer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, routingLayerDes];
-- when PW is fixed clean this up
pwBugOrien: CDOrient.Orientation ← IF objSide=top OR objSide=bottom THEN CDOrient.rotate90 ELSE CDOrient.original; -- PW problem: inst has wrong orientation!!!
IF template #
NIL
THEN {
[] ← PWPins.EnumerateEdgePins[template, FindPins];
IF needsXfer
THEN
cell ← PW.TransferCell[template, objSide, width, MapPins, selectNameProc];
};
};
IRSize:
PROC [obj:
PW.Object]
RETURNS [size:
CD.Position] =
{size ← CDBasics.SizeOfRect[CD.InterestRect[obj]]};
defaultXferPins:
PUBLIC XferPinsProc = {
XferPinsProc: TYPE = PROC [technologyKey: ATOM, inst: CD.Instance, routingLayer: CD.Layer, width: INT] RETURNS [cell: PW.Object] --
pinLayer: CD.Layer ← CDSymbolicObjects.GetLayer[inst];
polyLayer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, "poly"];
metalLayer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, "metal"];
metal2Layer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, "metal2"];
m1ToM12: INT ← MAX[CDSimpleRules.MinDist[metalLayer, metalLayer], CDSimpleRules.MinDist[metal2Layer, metal2Layer]];
sizeX, pinSizeY: INT;
cdLambda: INT ← CD.LayerTechnology[routingLayer].lambda;
pinSize: CD.Position ← CDOrient.OrientedSize[inst.ob.size, inst.orientation];
pinSizeY ← pinSize.y;
cell ← PW.CreateEmptyCell[];
SELECT
TRUE
FROM
pinLayer = routingLayer => {
sizeX ← width;
IF width > 0
THEN {
[] ← PW.IncludeInCell[cell, CDRects.CreateRect[[sizeX, pinSizeY], pinLayer]]}};
pinLayer = polyLayer => {
pContact: PW.Object ← CDSimpleRules.Contact[polyLayer, metalLayer];
wireP, mPContact: PW.Object;
sizeX ← m1ToM12 + pContact.size.x;
wireP ← CDRects.CreateRect[[sizeX, pinSizeY], polyLayer];
[] ← PW.IncludeInCell[cell, wireP];
mPContact ← StitchVias[[pContact.size.x, pinSizeY], polyLayer, metalLayer, cdLambda];
[] ← PW.IncludeInCell[cell, mPContact, [m1ToM12, (pinSizeY-mPContact.size.y)/2]];
IF routingLayer = metal2Layer
THEN {
mVia: PW.Object ← CDSimpleRules.Contact[metalLayer, metal2Layer];
wireM2: PW.Object ← CDRects.CreateRect[[m1ToM12, pinSizeY], metal2Layer];
m2M1Via: PW.Object;
[] ← PW.IncludeInCell[cell, wireM2, [sizeX, 0]];
sizeX ← sizeX + m1ToM12;
m2M1Via ← StitchVias[[mVia.size.x, pinSizeY], metalLayer, metal2Layer, cdLambda];
[] ← PW.IncludeInCell[cell, m2M1Via, [sizeX, (pinSizeY-m2M1Via.size.y)/2]];
sizeX ← sizeX + mVia.size.x};
IF width > sizeX
THEN {
wireRL: PW.Object ← CDRects.CreateRect[[width - sizeX, pinSizeY], routingLayer];
[] ← PW.IncludeInCell[cell, wireRL, [sizeX, 0]];
sizeX ← width}};
pinLayer = metalLayer => {
IF routingLayer = metal2Layer
THEN {
mVia: PW.Object ← CDSimpleRules.Contact[metalLayer, metal2Layer];
wireM, m2M1Via: PW.Object;
sizeX ← m1ToM12 + mVia.size.x;
wireM ← CDRects.CreateRect[[sizeX, pinSizeY], metalLayer];
[] ← PW.IncludeInCell[cell, wireM];
m2M1Via ← StitchVias[[mVia.size.x, pinSizeY], metalLayer, metal2Layer, cdLambda];
[] ← PW.IncludeInCell[cell, m2M1Via, [m1ToM12, (pinSizeY-m2M1Via.size.y)/2]];
IF width > sizeX
THEN {
wireM2: PW.Object ← CDRects.CreateRect[[width - sizeX, pinSizeY], metal2Layer];
[] ← PW.IncludeInCell[cell, wireM2, [sizeX, 0]];
sizeX ← width}}
ELSE {
pContact: PW.Object ← CDSimpleRules.Contact[polyLayer, metalLayer];
wireM, mPContact: PW.Object;
sizeX ← m1ToM12 + pContact.size.x;
wireM ← CDRects.CreateRect[[sizeX, pinSizeY], metalLayer];
[] ← PW.IncludeInCell[cell, wireM];
mPContact ← StitchVias[[pContact.size.x, pinSizeY], polyLayer, metalLayer, cdLambda];
[] ← PW.IncludeInCell[cell, mPContact, [wireM.size.x, (pinSizeY-mPContact.size.y)/2]];
IF width > sizeX
THEN {
wireP: PW.Object ← CDRects.CreateRect[[width - sizeX, pinSizeY], polyLayer];
[] ← PW.IncludeInCell[cell, wireP, [sizeX, 0]];
sizeX ← width}}};
pinLayer = metal2Layer => {
mVia: PW.Object ← CDSimpleRules.Contact[metalLayer, metal2Layer];
wireM2, m2M1Via: PW.Object;
sizeX ← m1ToM12 + mVia.size.x;
wireM2 ← CDRects.CreateRect[[sizeX, pinSizeY], metal2Layer];
[] ← PW.IncludeInCell[cell, wireM2];
m2M1Via ← StitchVias[[mVia.size.x, pinSizeY], metalLayer, metal2Layer, cdLambda];
[] ← PW.IncludeInCell[cell, m2M1Via, [m1ToM12, (pinSizeY-m2M1Via.size.y)/2]];
IF routingLayer = polyLayer
THEN {
pContact: PW.Object ← CDSimpleRules.Contact[metalLayer, polyLayer];
wireM: PW.Object ← CDRects.CreateRect[[m1ToM12 + pContact.size.x, pinSizeY], metalLayer];
mPContact: PW.Object ← StitchVias[[pContact.size.x, pinSizeY], polyLayer, metalLayer, cdLambda];
[] ← PW.IncludeInCell[cell, wireM, [sizeX, 0]];
sizeX ← sizeX + m1ToM12;
[] ← PW.IncludeInCell[cell, mPContact, [sizeX, (pinSizeY-mPContact.size.y)/2]];
sizeX ← sizeX + pContact.size.x};
IF width > sizeX
THEN {
wireRL: PW.Object ← CDRects.CreateRect[[width - sizeX, pinSizeY], routingLayer];
[] ← PW.IncludeInCell[cell, wireRL, [sizeX, 0]];
sizeX ← width};
};
ENDCASE;
CDCells.SetInterestRect[cell, [0, 0, sizeX, pinSizeY]];
[] ← CDCells.RepositionCell[cell, NIL]};
StitchVias:
PROC [size:
CD.Position, layer1, layer2:
CD.Layer, cdLambda:
INT]
RETURNS [cell:
PW.Object] = {
via: PW.Object ← RouteUtil.GetVia[size, layer1, layer2, cdLambda];
cell ← RouteUtil.StitchVias[via, size, layer1, layer2, cdLambda]};
END.