<> <> <> <> <> <<>> DIRECTORY CD, CDBasics, CDCells, CDOrient, CDSymbolicObjects, CDRects, CDSimpleRules, PW, PWPins, PWRoute, Route, RouteUtil, SymTab; 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 = { <> 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.