<> <> <> <> <<>> 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, SCChanUtil, SCInstUtil, SCNetUtil, SCRoutePinsUtil, SCRowUtil, SCUtil EXPORTS SCPrivate SHARES SC = BEGIN CreatePinsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan] = { 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 { rowOffset: SC.Number _ lgRow.rowOrg.p - lgRows.horzRowOrg; rect: CD.Rect _ SCInstUtil.RotateRect[instance, netPin.pin.rect]; position: CD.Position _ SCUtil.PQToXY[handle, [p: rowOffset + instance.offset + rect.x1, q: rect.y1]]; SCRoutePinsUtil.EnterPin[rect, position, netPin, RTBasic.OtherSide[side], lgRow.cdOb]}}}; 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 SCNetUtil.ExitOnSide[handle, netPin.net, side] THEN { rowOffset: SC.Number _ lgRow.rowOrg.p - lgRows.horzRowOrg; rect: CD.Rect _ SCInstUtil.RotateRect[instance, netPin.pin.rect]; position: CD.Position _ SCUtil.PQToXY[handle, [p: rowOffset + instance.offset + rect.x1, q: rect.y1]]; SCRoutePinsUtil.EnterPin[rect, position, netPin, RTBasic.OtherSide[side], lgRow.cdOb]}}}; 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; lgRow: SCPrivate.LgRow; IF chan = 1 THEN { side _ bottom; lgRow _ lgRows.rows[1]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, ExternalPinsInstance]} ELSE IF chan = lgRows.count + 1 THEN { side _ top; lgRow _ lgRows.rows[lgRows.count]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, ExternalPinsInstance]} ELSE { side _ top; lgRow _ lgRows.rows[chan - 1]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, InternalPinsInstance]; side _ bottom; lgRow _ lgRows.rows[chan]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, InternalPinsInstance]}}; CreateExitsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan] = { cell: CD.Object; ExitPins: SCChanUtil.EachExitProc = {SCRoutePinsUtil.EnterExit[exit, lrSide, cell]}; EachSide: SCRowUtil.EachSideProc ~ { <<[side: SC.Side, bpRow: SCPrivate.BpRow] RETURNS [quit: BOOL _ FALSE]>> IF side = left OR side = right THEN { cell _ CDCells.CreateEmptyCell[]; [] _ SCChanUtil.EnumerateExits[handle, rowChan, side, ExitPins]; rowChan.exitCells[side] _ cell}}; [] _ SCRowUtil.EnumerateSides[handle, EachSide]}; FinishExitsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan] = { EachSide: SCRowUtil.EachSideProc ~ { <<[side: SC.Side, bpRow: SCPrivate.BpRow] RETURNS [quit: BOOL _ FALSE]>> IF side = left OR side = right THEN { rect: CD.Rect; cell: CD.Object _ rowChan.exitCells[side]; 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 RTBasic.RepositionCell[cell]}}; trunkWidth: SC.Number _ handle.rules.rowRules.trunkWidth; [] _ SCRowUtil.EnumerateSides[handle, EachSide]}; CreateWireAndContact: PROC [handle: SC.Handle, pin: CD.Instance, size: Route.Position, length: CD.Number, trunkLayer: CD.Layer, cdLambda: Route.Number] RETURNS [obj: CD.Object] = { branchLayer: CD.Layer _ CDSymbolicObjects.GetLayer[pin]; obj _ CDCells.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]; RTBasic.RepositionCell[obj]}; CreateWireFromPin: PROC [handle: SC.Handle, pin: CD.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: CD.Instance, extLen: CD.Number, side: SC.Side] RETURNS [obj: CD.Object _ NIL] = { <> IF CDSymbolicObjects.IsSymbolicOb[inst.ob] THEN { pinInst, wireInst: CD.Instance; name: Rope.ROPE _ CDSymbolicObjects.GetName[inst]; wire: CD.Object _ CreateWireFromPin[handle, inst, extLen]; pinOb: CD.Object _ CDSymbolicObjects.CreateSegment[inst.ob.size.y]; obj _ CDCells.CreateEmptyCell[]; pinInst _ PW.IncludeInCell[obj, pinOb, [extLen-pinOb.size.x, 0], CDSymbolicObjects.OrientFromDirection[east]]; wireInst _ PW.IncludeInCell[obj, wire]; CDProperties.PutProp[wireInst, $SignalName, name]; CDSymbolicObjects.SetName[pinInst, name]; CDSymbolicObjects.SetLayer[pinInst, CDSymbolicObjects.GetLayer[inst]]; RTBasic.SetCDCellName[obj, Rope.Cat[name, IF side = right THEN "Right" ELSE "Left", name]]; RTBasic.RepositionCell[obj]}}; LogicRoute: PROC [handle: SC.Handle] RETURNS [logicOb: CD.Object] = { ForEachRow: SCRowUtil.EachRowProc = { <<[row: SCPrivate.MaxRowSr, lgRow: SCPrivate.LgRow] RETURNS [quit: BOOL _ FALSE]>> ExtendPin: PW.ForEachPinProc = { IF Rope.Equal[CDSymbolicObjects.GetName[inst], layoutData.powerBuses[side].name] THEN obj _ AlwaysExtendPin[handle, inst, extLen, side]}; extLen: CD.Number; side: SCPrivate.LRSide; leftObject, rightObject: CD.Object; leftTemplate: CD.Object _ lgRow.lgsOnRow[1].object.cdOb; rightTemplate: CD.Object _ lgRow.lgsOnRow[lgRow.nLgsOnRow].object.cdOb; lgRows: SCPrivate.LgRows _ layoutData.lgRows; maxRowWidth: CD.Number _ lgRows.maxRowWidth; rowLength: SC.Number _ lgRow.size.p; rowOffset: SC.Number _ lgRow.rowOrg.p - lgRows.horzRowOrg; IF rowOffset > 0 AND rowLength < maxRowWidth THEN { -- needs filler on left and right side _ left; extLen _ rowOffset; leftObject _ TransferCell[template: leftTemplate, objSide: left, width: extLen, objProc: ExtendPin, stopEnumerateDeepPins: FALSE]; RTBasic.SetCDCellName[leftObject, Rope.Cat[handle.name, "LeftRow",Convert.RopeFromInt[lgRow.rowNum]]]; side _ right; extLen _ maxRowWidth - (rowOffset + rowLength); rightObject _ TransferCell[template: rightTemplate, objSide: right, width: extLen, objProc: ExtendPin, stopEnumerateDeepPins: FALSE]; RTBasic.SetCDCellName[rightObject, Rope.Cat[handle.name, "RightRow",Convert.RopeFromInt[lgRow.rowNum]]]} ELSE IF rowLength < maxRowWidth THEN { -- rowOffset = 0, no filler on left side _ right; extLen _ maxRowWidth - rowLength; rightObject _ TransferCell[template: rightTemplate, objSide: right, width: extLen, objProc: ExtendPin, stopEnumerateDeepPins: FALSE]; RTBasic.SetCDCellName[rightObject, Rope.Cat[handle.name, "RightRow",Convert.RopeFromInt[lgRow.rowNum]]]; leftObject _ NIL} ELSE -- no filler needed {leftObject _ NIL; rightObject _ NIL}; lgRow.cdOb _ ConstructRow[handle, leftObject, lgRow, rightObject]}; ForEachChannel: SCChanUtil.EachRowChanProc = { rowChans: SCPrivate.RowChans _ layoutData.rowChans; SCRoutePinsUtil.InitGetChanPins[handle]; IF 1 < rowChan.chanNum AND rowChan.chanNum < rowChans.count THEN CreateExitsForChannel[handle: handle, rowChan: rowChan]; CreatePinsForChannel[handle: handle, rowChan: rowChan]; 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]}; 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]}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; parms: SCPrivate.Parms _ NARROW[handle.parms]; technologyKey: ATOM _ NARROW[handle.rules.technology, CD.Technology].key; routerParams: PWRoute.RouterParams _ NEW[PWRoute.RouterParamsRec _ [trunkLayer: handle.rules.horizLayer, branchLayer: handle.rules.vertLayer, technologyKey: technologyKey, signalBreakAtExit: FALSE, signalSinglePinNets: TRUE]]; [] _ SCRowUtil.EnumerateRows[handle: handle, eachRow: ForEachRow]; [] _ SCChanUtil.EnumerateRowChans[handle: handle, eachRowChan: ForEachChannel]; logicOb _ RouteRows[handle, routerParams]; }; IncludeTrunkPin: PROC [handle: SC.Handle, cell: CD.Object, name: Rope.ROPE, tbSide: SCPrivate.TBSide, trunkSize, trunkPos: SCPrivate.PQPos, layer: CD.Layer] = { pin: CD.Object _ CDSymbolicObjects.CreateSegment[trunkSize.p]; pinPos: SCPrivate.PQPos _ [trunkPos.p, IF tbSide = top THEN trunkPos.q + trunkSize.q - pin.size.x ELSE trunkPos.q]; pos: CD.Position _ SCUtil.PQToXY[handle, pinPos]; pinInst: CD.Instance _ PW.IncludeInCell[cell, pin, pos, CDSymbolicObjects.OrientFromDirection[IF tbSide = top THEN north ELSE south]]; CDSymbolicObjects.SetName[pinInst, name]; CDSymbolicObjects.SetLayer[pinInst, layer]}; PowerRoute: PROC [handle: SC.Handle, pwOb: CD.Object] RETURNS [obj: CD.Object] = { <> <<>> EachSide: SCRowUtil.EachSideProc ~ { <<[side: SC.Side, bpRow: SCPrivate.BpRow] RETURNS [quit: BOOL _ FALSE]>> IF side = left OR side = right THEN { ExtendPin: PW.ForEachPinProc = { name: Rope.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, side]}; pBus: SCPrivate.PowerBus _ layoutData.powerBuses[side]; width: SC.Number _ MAX[pBus.width, rules.trunkToTrunk]; trunkWidth: SC.Number _ width - rules.trunkSpacing; extLen: SC.Number _ rules.trunkSpacing; trunkSize: SCPrivate.PQPos _ [p: trunkWidth, q: RTBasic.IRSize[pwOb].y]; trunkPos: SCPrivate.PQPos _ [IF side = right THEN extLen ELSE 0, 0]; pwSide: PWPins.Side _ SELECT side FROM right => right, left => left, ENDCASE => ERROR; trunk: CD.Object _ CDRects.CreateRect[SCUtil.PQToXY[handle, trunkSize], trunkLayer]; ext[side] _ TransferCell[template: pwOb, objSide: pwSide, width: width, objProc: ExtendPin, stopEnumerateDeepPins: FALSE]; RTBasic.SetCDCellName[ext[side], Rope.Cat[handle.name, IF side = right THEN "RightPower" ELSE "LeftPower"]]; [] _ PW.IncludeInCell[ext[side], trunk, SCUtil.PQToXY[handle, trunkPos]]; IncludeTrunkPin[handle, ext[side], pBus.name, top, trunkSize, trunkPos , trunkLayer]; IncludeTrunkPin[handle, ext[side], pBus.name, bottom, trunkSize, trunkPos, trunkLayer]}}; ext: ARRAY SCPrivate.LRSide OF CD.Object; rules: Route.DesignRules _ handle.rules.sideRules; trunkLayer: CD.Layer _ rules.trunkLayer; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; [] _ SCRowUtil.EnumerateSides[handle, EachSide]; obj _ ConstructLayout[o1: ext[left], o2: pwOb, o3: ext[right], name: handle.name]}; DetailRoute: PUBLIC PROC [handle: SC.Handle] RETURNS [result: SC.Result] = { centerObj, fullObj: CD.Object; lgRows: SCPrivate.LgRows _ NARROW[handle.layoutData, SCPrivate.LayoutData].lgRows; SCInstUtil.AllOffsets[handle]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; centerObj _ LogicRoute[handle]; fullObj _ PowerRoute[handle, centerObj]; result _ NEW[SC.ResultRec _ [handle: handle, object: fullObj]]}; TransferCell: PROC [template: PW.Object, objSide: PWPins.Side, width: INT, objProc: PW.ForEachPinProc, stopEnumerateDeepPins: BOOLEAN _ TRUE] RETURNS [cell: CD.Object _ CDCells.CreateEmptyCell[]] = { KeepPinOnEdge: PWPins.InstanceEnumerator = { newObj: CD.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]]}}; iRect: CD.Rect; <<-- Start with an empty cell of appropriate interestRect (origin in 0,0)>> IF objSide=none THEN ERROR; 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]; RTBasic.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: CD.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}; ConstructRow: PROC [handle: SC.Handle, leftObject: CD.Object, lgRow: SCPrivate.LgRow, rightObject: CD.Object] RETURNS [row: CD.Object _ CDCells.CreateEmptyCell[]] ~ { ForEachInstance: SCRowUtil.EachInstProc = { <<[pos: NAT, instance: SCPrivate.Instance] RETURNS [quit: BOOL _ FALSE]>> object: CD.Object _ instance.object.cdOb; cdInst: CD.Instance _ PW.IncludeInCell[cell: row, obj: object, position: [offset, 0], orientation: SCInstUtil.CDOrien[instance]]; CDProperties.PutInstanceProp[cdInst, $InstanceName, instance.name]; CDProperties.PutProp[cdInst, $StopEnumerateDeepPins, $StopEnumerateDeepPins]; offset _ offset + RTBasic.IRSize[object].x}; offset: SC.Number _ 0; IF leftObject # NIL THEN { [] _ PW.IncludeInCell[cell: row, obj: leftObject, position: [offset, 0], orientation: 0]; offset _ offset + RTBasic.IRSize[leftObject].x}; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, ForEachInstance]; IF rightObject # NIL THEN { [] _ PW.IncludeInCell[cell: row, obj: rightObject, position: [offset, 0], orientation: 0]; offset _ offset + RTBasic.IRSize[rightObject].x}; RTBasic.RepositionCell[row]; RTBasic.SetCDCellName[row, Rope.Cat[handle.name, "Row",Convert.RopeFromInt[lgRow.rowNum]]]}; ConstructLayout: PROC [o1, o2, o3, o4, o5: CD.Object _ NIL, name: Rope.ROPE] RETURNS [obj: CD.Object _ CDCells.CreateEmptyCell[]] ~ { offset: SC.Number _ 0; IF o1 # NIL THEN { [] _ PW.IncludeInCell[cell: obj, obj: o1, position: [offset, 0], orientation: 0]; offset _ offset + RTBasic.IRSize[o1].x}; IF o2 # NIL THEN { [] _ PW.IncludeInCell[cell: obj, obj: o2, position: [offset, 0], orientation: 0]; offset _ offset + RTBasic.IRSize[o2].x}; IF o3 # NIL THEN { [] _ PW.IncludeInCell[cell: obj, obj: o3, position: [offset, 0], orientation: 0]; offset _ offset + RTBasic.IRSize[o3].x}; IF o4 # NIL THEN { [] _ PW.IncludeInCell[cell: obj, obj: o4, position: [offset, 0], orientation: 0]; offset _ offset + RTBasic.IRSize[o4].x}; IF o5 # NIL THEN { [] _ PW.IncludeInCell[cell: obj, obj: o5, position: [offset, 0], orientation: 0]; offset _ offset + RTBasic.IRSize[o5].x}; RTBasic.RepositionCell[obj]; RTBasic.SetCDCellName[obj, name]}; RouteRows: PROC [handle: SC.Handle, routerParams: PWRoute.RouterParams] RETURNS [obj: CD.Object _ CDCells.CreateEmptyCell[]] ~ { <> EachChannel: SCChanUtil.EachRowChanProc ~ { <<[chan: SCPrivate.MaxChanSr, rowChan: SCPrivate.RowChan] RETURNS [quit: BOOL _ FALSE]>> <> IF chan # 1 THEN { bottomRow: CD.Object _ lgRows.rows[rowChan.chanNum-1].cdOb; rowInst: CD.Instance _ PW.IncludeInCell[cell: obj, obj: bottomRow, position: [0, offset], orientation: 0]; CDProperties.PutInstanceProp[rowInst, $InstanceName, Rope.Cat["Row", Convert.RopeFromInt[rowChan.chanNum]]]; offset _ offset + RTBasic.IRSize[ bottomRow].y; IF chan # rowChans.count THEN { topRow: CD.Object _ lgRows.rows[rowChan.chanNum].cdOb; result: Route.RoutingResult _ PWRoute.DoRoute[bottomRow, topRow, rowChan.exitCells[left], rowChan.exitCells[right], routerParams, FALSE, channel]; channel: CD.Object _ PWRoute.GetRouting[result, NIL]; chanInst: CD.Instance _ PW.IncludeInCell[cell: obj, obj: channel, position: [0, offset], orientation: 0]; RTBasic.SetCDCellName[channel, Rope.Cat[handle.name, "Channel", Convert.RopeFromInt[rowChan.chanNum]]]; CDProperties.PutInstanceProp[chanInst, $InstanceName, Rope.Cat["Channel", Convert.RopeFromInt[rowChan.chanNum]]]; offset _ offset + RTBasic.IRSize[channel].y; rowChans.chans[chan].routing _ result}}}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; rowChans: SCPrivate.RowChans _ layoutData.rowChans; lgRows: SCPrivate.LgRows _ layoutData.lgRows; offset: SC.Number _ 0; [] _ SCChanUtil.EnumerateRowChans[handle, EachChannel]; RTBasic.RepositionCell[obj]; RTBasic.SetCDCellName[obj, Rope.Cat[handle.name, "Center"]]}; END.