-- 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]};
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 ← CDPinObjects.GetName[inst];
tabIndex: ROPE ← IF params.makeTabKeyProc=NIL THEN pinName ELSE params.makeTabKeyProc[inst];
[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];
};
MakeChannel:
PUBLIC
PROC[obj1, obj2, bottomOrLeftObj, topOrRightObj:
CD.Object, retrieveRect: RefRect, params: RouterParams, isX:
BOOL, routeType: RouteType]
RETURNS [channel:
CD.Object] = {
tab: SymTab.Ref;
result: Route.RoutingResult;
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, pRight, pTop, pLeft];
routingRect ← [0, 0, pRight.x, pTop.y];
SELECT routeType
FROM
channel => result ← Route.ChannelRoute[routingArea, sideCoords, routingRect, params.opt];
switchBox => result ← Route.SwitchBoxRoute[routingArea, sideCoords, routingRect, params.opt];
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"];
channel ← Route.RetrieveRouting[result, result.routingArea.name, retrieveRect, NIL].object;
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: CDPinObjects.InstanceEnumerator = {
[inst: CD.Instance] RETURNS [quit: BOOL ← FALSE]
IF PWPins.GetSide[template, inst].side=objSide
THEN {
pinLayer: CD.Layer ← CDPinObjects.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;
CDPinObjects.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;
CDPinObjects.SetLayer[pwBug, CDPinObjects.GetLayer[inst]];
wire ← xferPinsProc[technologyKey, pwBug, routingLayer, width];
pinSize ← CDOrient.OrientedSize[pwBug.ob.size, pwBug.orientation];
pinOb ← CDPinObjects.CreatePinOb[pinSize];
obj ← PW.CreateEmptyCell[];
pinInst ← PW.IncludeInCell[obj, pinOb, [width-pinSize.x, 0]];
[] ← PW.IncludeInCell[obj, wire];
CDPinObjects.SetName[pinInst, CDPinObjects.GetName[inst]];
CDPinObjects.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];
};
};
defaultXferPins: PUBLIC XferPinsProc = {
XferPinsProc: TYPE = PROC [technologyKey: ATOM, inst: CD.Instance, routingLayer: CD.Layer, width: INT] RETURNS [cell: PW.Object] --
pinLayer: CD.Layer ← CDPinObjects.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]];
sizeY, sizeX, pinSizeY: INT;
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: PW.Object;
sizeY ← MAX[pContact.size.y, pinSizeY];
wireP ← CDRects.CreateRect[[m1ToM12, pinSizeY], polyLayer];
sizeX ← wireP.size.x + pContact.size.x;
[] ← PW.IncludeInCell[cell, wireP];
[] ← PW.IncludeInCell[cell, StitchVias[pContact, sizeY], [wireP.size.x, -(sizeY-pinSizeY)/2]];
IF routingLayer = metal2Layer
THEN {
mVia: PW.Object ← CDSimpleRules.Contact[metalLayer, metal2Layer];
wireM2: PW.Object;
sizeY ← MAX[mVia.size.y, sizeY];
wireM2 ← CDRects.CreateRect[[m1ToM12, sizeY], metal2Layer];
[] ← PW.IncludeInCell[cell, wireM2, [sizeX, -(mVia.size.y-pinSizeY)/2]];
sizeX ← sizeX + wireM2.size.x;
[] ← PW.IncludeInCell[cell, StitchVias[mVia, sizeY], [sizeX, -(sizeY-pinSizeY)/2]];
sizeX ← sizeX + mVia.size.x};
IF width > sizeX
THEN {
wireRL: PW.Object ← CDRects.CreateRect[[width - sizeX, sizeY], routingLayer];
[] ← PW.IncludeInCell[cell, wireRL, [sizeX, -(sizeY-pinSizeY)/2]];
sizeX ← width};
};
pinLayer = metalLayer => {
IF routingLayer = metal2Layer
THEN {
mVia: PW.Object ← CDSimpleRules.Contact[metalLayer, metal2Layer];
wireM: PW.Object;
sizeY ← MAX[mVia.size.y, pinSizeY];
wireM ← CDRects.CreateRect[[m1ToM12, sizeY], metalLayer];
sizeX ← wireM.size.x + mVia.size.x;
[] ← PW.IncludeInCell[cell, wireM];
[] ← PW.IncludeInCell[cell, StitchVias[mVia, sizeY], [wireM.size.x, -(sizeY-pinSizeY)/2]];
IF width > sizeX
THEN {
wireM2: PW.Object;
sizeY ← MAX[mVia.size.y, pinSizeY];
wireM2 ← CDRects.CreateRect[[width - sizeX, sizeY], metal2Layer];
[] ← PW.IncludeInCell[cell, wireM2, [sizeX, -(sizeY-pinSizeY)/2]];
sizeX ← width}}
ELSE {
pContact: PW.Object ← CDSimpleRules.Contact[polyLayer, metalLayer];
wireM: PW.Object;
sizeY ← MAX[pContact.size.y, pinSizeY];
wireM ← CDRects.CreateRect[[m1ToM12, pinSizeY], metalLayer];
sizeX ← wireM.size.x + pContact.size.x;
[] ← PW.IncludeInCell[cell, wireM];
[] ← PW.IncludeInCell[cell, StitchVias[pContact, sizeY], [wireM.size.x, -(sizeY-pinSizeY)/2]];
IF width > sizeX
THEN {
wireP: PW.Object ← CDRects.CreateRect[[width - sizeX, sizeY], polyLayer];
[] ← PW.IncludeInCell[cell, wireP, [sizeX, -(sizeY-pinSizeY)/2]];
sizeX ← width}};
};
pinLayer = metal2Layer => {
mVia: PW.Object ← CDSimpleRules.Contact[metalLayer, metal2Layer];
wireM2: PW.Object;
sizeY ← MAX[mVia.size.y, pinSizeY];
wireM2 ← CDRects.CreateRect[[m1ToM12, pinSizeY], metal2Layer];
sizeX ← wireM2.size.x + mVia.size.x;
[] ← PW.IncludeInCell[cell, wireM2];
[] ← PW.IncludeInCell[cell, StitchVias[mVia, sizeY], [wireM2.size.x, -(sizeY-pinSizeY)/2]];
IF routingLayer = polyLayer
THEN {
pContact: PW.Object ← CDSimpleRules.Contact[metalLayer, polyLayer];
wireM: PW.Object;
sizeY ← MAX[pContact.size.y, sizeY];
wireM ← CDRects.CreateRect[[m1ToM12, sizeY], metalLayer];
[] ← PW.IncludeInCell[cell, wireM, [sizeX, -(sizeY-pinSizeY)/2]];
sizeX ← sizeX + wireM.size.x;
[] ← PW.IncludeInCell[cell, StitchVias[pContact, sizeY], [sizeX, -(sizeY-pinSizeY)/2]];
sizeX ← sizeX + pContact.size.x};
IF width > sizeX
THEN {
wireRL: PW.Object ← CDRects.CreateRect[[width - sizeX, sizeY], routingLayer];
[] ← PW.IncludeInCell[cell, wireRL, [sizeX, -(sizeY-pinSizeY)/2]];
sizeX ← width};
};
ENDCASE;
CDCells.SetInterestRect[cell, [0, 0, sizeX, pinSizeY]];
[] ← CDCells.RepositionCell[cell, NIL];
};