<> <> <> <> <<>> <> DIRECTORY CD, CDBasics, CDCells, CDOps, CDProperties, CDRects, CDSymbolicObjects, Convert, Core, CoreGeometry, CoreOps, ExtendCells, HashTable, PWPins, PWRoute, Rope, Route, RouteUtil, RTBasic, SC, SCChanUtil, SCInstUtil, SCNetUtil, SCPrivate, SCRoutePinsUtil, SCRowUtil, SCUtil, Sinix, SinixOps; SCRouteImpl: CEDAR PROGRAM IMPORTS CDBasics, CDCells, CDOps, CDProperties, CDRects, CDSymbolicObjects, Convert, CoreGeometry, CoreOps, ExtendCells, HashTable, PWPins, PWRoute, Rope, RouteUtil, RTBasic, SCChanUtil, SCInstUtil, SCNetUtil, SCRoutePinsUtil, SCRowUtil, SCUtil, Sinix, SinixOps EXPORTS SCPrivate SHARES SC = BEGIN DetailRoute: PUBLIC PROC [handle: SC.Handle, viaTable: HashTable.Table] RETURNS [result: SC.Result] = { lgRows: SCPrivate.LgRows _ NARROW[handle.layoutData, SCPrivate.LayoutData].lgRows; SCInstUtil.AllOffsets[handle]; [lgRows.maxRowWidth, lgRows.numMaxRows] _ SCRowUtil.FindMaxRow[handle]; PrepareLogicRoute[handle]; result _ NEW[SC.ResultRec _ [handle: handle, object: RouteRows[handle, viaTable]]]; SCInstUtil.AsgnChanPos[handle]; [] _ SCUtil.WriteResults["End detailed routing\n", handle, 0]}; 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 { alwaysUse: BOOLEAN _ (chan = 1 OR chan = rowChans.count) AND netPin.net.externNet = externalNet AND SCNetUtil.ExitOnSide[handle, netPin.net, side]; 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.shell, alwaysUse]}}}; 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.shell, TRUE]}}}; InternalPinsInstance: SCRowUtil.EachInstProc = { [] _ SCInstUtil.EnumeratePinsOnInst[instance, AllPins]}; ExternalPinsInstance: SCRowUtil.EachInstProc = { [] _ SCInstUtil.EnumeratePinsOnInst[instance, ExternalPins]}; lgRows: SCPrivate.LgRows _ NARROW[handle.layoutData, SCPrivate.LayoutData].lgRows; rowChans: SCPrivate.RowChans _ NARROW[handle.layoutData, SCPrivate.LayoutData].rowChans; chan: SCPrivate.MaxChanSr _ rowChan.chanNum; side: SC.Side; lgRow: SCPrivate.LgRow; SELECT TRUE FROM chan = 1 AND lgRows.count = 1 => { <> side _ bottom; lgRow _ lgRows.rows[1]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, InternalPinsInstance]}; chan = 1 => { <> side _ bottom; lgRow _ lgRows.rows[1]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, ExternalPinsInstance]}; chan = lgRows.count + 1 => { <> side _ top; lgRow _ lgRows.rows[lgRows.count]; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, ExternalPinsInstance]}; ENDCASE => { <> 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] = { 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}}; cell: CD.Object; [] _ 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[design: NIL, cell: cell, r: rect]; -- set interestRect of cell RTBasic.RepositionCell[cell]}}; trunkWidth: SC.Number _ handle.rules.rowRules.trunkWidth; [] _ SCRowUtil.EnumerateSides[handle, EachSide]}; PrepareLogicRoute: PROC [handle: SC.Handle] = { ForEachRow: SCRowUtil.EachRowProc = { <<[row: SCPrivate.MaxRowSr, lgRow: SCPrivate.LgRow] RETURNS [quit: BOOL _ FALSE]>> ExtendPin: ExtendCells.ExtendSegmentProc = { <> obj: CD.Object _ CDCells.CreateEmptyCell[]; connection: CD.Object _ CDRects.CreateRect[[extension, max-min], layer]; connectionInst: CD.Instance _ RouteUtil.Include[obj, connection]; name: Rope.ROPE _ CoreOps.GetShortWireName[wire]; CDProperties.PutProp[connectionInst, $SignalName, name]; CDProperties.PutProp[connectionInst, $InstanceName, name]; RTBasic.RepositionCell[obj]; RETURN[obj]}; leftObject, rightObject: CD.Object _ NIL; maxRowWidth: CD.Number _ layoutData.lgRows.maxRowWidth; rowLength: SC.Number _ lgRow.size.p; rowOffset: SC.Number _ lgRow.rowOrg.p - layoutData.lgRows.horzRowOrg; IF rowOffset > 0THEN { -- needs filler on left to extend power leftWirePins: LIST OF ExtendCells.WirePin _ BuildWirePins[handle: handle, cellType: lgRow.lgsOnRow[1].object.cellType, objSide: left]; leftObject _ ExtendCells.ExtendObject[wirePins: leftWirePins, size: [rowOffset, lgRow.size.q], side: left, extendProc: ExtendPin]; RTBasic.SetCDCellName[leftObject, Rope.Cat[handle.name, "Left", Convert.RopeFromInt[lgRow.rowNum]]]}; IF rowOffset + rowLength < maxRowWidth THEN { -- needs filler on right to extend power rightWirePins: LIST OF ExtendCells.WirePin _ BuildWirePins[handle: handle, cellType: lgRow.lgsOnRow[lgRow.nLgsOnRow].object.cellType, objSide: right]; rightObject _ ExtendCells.ExtendObject[wirePins: rightWirePins, size: [maxRowWidth - (rowOffset + rowLength), lgRow.size.q], side: right, extendProc: ExtendPin]; RTBasic.SetCDCellName[rightObject, Rope.Cat[handle.name, "Right", Convert.RopeFromInt[lgRow.rowNum]]]}; lgRow.shell _ CDCells.CreateEmptyCell[]; lgRow.cdOb _ ConstructRow[handle, leftObject, lgRow, rightObject]}; ForEachChannel: SCChanUtil.EachRowChanProc = { <> useThisChan: BOOLEAN _ (1 < rowChan.chanNum AND rowChan.chanNum < rowChans.count) OR (rowChan.chanNum = 1 AND rowChans.count = 2); SCRoutePinsUtil.InitGetChanPins[handle]; IF useThisChan THEN CreateExitsForChannel[handle: handle, rowChan: rowChan]; CreatePinsForChannel[handle: handle, rowChan: rowChan]; SCRoutePinsUtil.EnterNetDat[handle, chan, MakeNetPin, MakeExit, NIL]; SCRoutePinsUtil.TermGetChanPins[handle]; IF useThisChan THEN FinishExitsForChannel[handle: handle, rowChan: rowChan]}; MakeExit: SCRoutePinsUtil.ExitProc = { <> pinOb: CD.Object _ CDSymbolicObjects.CreatePin[size: [trunkWidth, exit.net.trunkWidth]]; pinInst: CD.Instance _ RouteUtil.Include[cell: cell, ob: pinOb]; CDSymbolicObjects.SetName[pinInst, exit.net.name]; CDSymbolicObjects.SetLayer[pinInst, exit.layer]}; MakeNetPin: SCRoutePinsUtil.PinProc = { <> <<>> pinOb: CD.Object _ CDSymbolicObjects.CreatePin[CDBasics.SizeOfRect[rect]]; pinInst: CD.Instance _ RouteUtil.Include[cell: cell, ob: pinOb, position: position]; CDSymbolicObjects.SetName[pinInst, netPin.net.name]; CDSymbolicObjects.SetLayer[pinInst, netPin.pin.layer]}; FinishRow: SCRowUtil.EachRowProc = { <<[row: SCPrivate.MaxRowSr, lgRow: SCPrivate.LgRow] RETURNS [quit: BOOL _ FALSE]>> rect: CD.Rect _ [0, 0, layoutData.lgRows.maxRowWidth, lgRow.size.q]; CDCells.SetInterestRect[design: NIL, cell: lgRow.shell, r: rect]; -- set interestRect of cell RTBasic.RepositionCell[lgRow.shell]}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; rowChans: SCPrivate.RowChans _ layoutData.rowChans; [] _ SCRowUtil.EnumerateRows[handle: handle, eachRow: ForEachRow]; [] _ SCChanUtil.EnumerateRowChans[handle: handle, eachRowChan: ForEachChannel]; [] _ SCRowUtil.EnumerateRows[handle: handle, eachRow: FinishRow]}; 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; instOrientation: CD.Orientation _ SCInstUtil.CDOrien[instance]; instPosition: CD.Position _ CDOps.FitObjectI[ob: object, location: [offset, 0], orientation: instOrientation].off; cdInst: CD.Instance _ RouteUtil.Include[cell: row, ob: object, position: instPosition, orientation: instOrientation]; 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 { [] _ RouteUtil.Include[cell: row, ob: leftObject, position: [offset, 0]]; offset _ offset + RTBasic.IRSize[leftObject].x}; [] _ SCRowUtil.EnumerateAllInstsOnRow[handle, lgRow.rowNum, ForEachInstance]; IF rightObject # NIL THEN { [] _ RouteUtil.Include[cell: row, ob: rightObject, position: [offset, 0]]; offset _ offset + RTBasic.IRSize[rightObject].x}; RTBasic.SetCDCellName[row, Rope.Cat[handle.name, "IntRow", Convert.RopeFromInt[lgRow.rowNum]]]; RTBasic.RepositionCell[row]}; RouteRows: PROC [handle: SC.Handle, viaTable: HashTable.Table] RETURNS [obj: CD.Object _ CDCells.CreateEmptyCell[]] ~ { <> IncludeRow: PROC [rowNum: NAT] ~ { <> RowSidePublics: CoreGeometry.EachWirePinProc ~ { <> <> pin: SCPrivate.PublicPin _ MakeSidePin[wire, min, max, side, layer]; IF pin # NIL THEN lgRow.publics _ CONS[pin, lgRow.publics]}; lgRow: SCPrivate.LgRow _ lgRows.rows[rowNum]; row: CD.Object _ lgRow.cdOb; rowInst: CD.Instance _ RouteUtil.Include[cell: obj, ob: row, position: [0, offset]]; [] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, lgRow.lgsOnRow[1].object.cellType, RowSidePublics]; [] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, lgRow.lgsOnRow[1].object.cellType, RowSidePublics]; CDProperties.PutInstanceProp[rowInst, $InstanceName, Rope.Cat["Row", Convert.RopeFromInt[rowNum]]]; IF rowNum = 1 THEN AddTBPublics[handle, lgRow, bottom, 0]; offset _ offset + lgRow.size.q; IF rowNum = lgRows.count THEN AddTBPublics[handle, lgRow, top, offset]}; RouteChannel: PROC [bottomRow, topRow: CD.Object, rowChan: SCPrivate.RowChan] ~ { <> ChanPublics: CoreGeometry.EachWirePinProc ~ { <> <> pin: SCPrivate.PublicPin _ MakeSidePin[wire, min, max, side, layer]; IF pin # NIL THEN rowChan.publics _ CONS[pin, rowChan.publics]}; result: Route.RoutingResult _ PWRoute.DoRoute[bottomRow, topRow, rowChan.exitCells[left], rowChan.exitCells[right], routerParams, FALSE, channel]; channel: CD.Object _ PWRoute.GetRouting[result, NIL, routerParams]; chanInst: CD.Instance _ RouteUtil.Include[cell: obj, ob: channel, position: [0, offset]]; cellType: Core.CellType _ NARROW [Sinix.Extract[channel, mode].result]; [] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, cellType, ChanPublics]; CDProperties.PutInstanceProp[chanInst, $InstanceName, Rope.Cat[handle.name, "Chan", Convert.RopeFromInt[rowChan.chanNum]]]; offset _ offset + RTBasic.IRSize[channel].y; rowChan.routing _ result; rowChan.chanWidth _ RTBasic.IRSize[channel].y}; MakeSidePin: PROC [wire: Core.Wire, min, max: INT, side: CoreGeometry.Side, layer: CD.Layer] RETURNS [pin: SCPrivate.PublicPin _ NIL] ~ { <> IF side = left OR side = right THEN { name: Rope.ROPE _ CoreOps.GetShortWireName[wire]; net: SCPrivate.Net _ SCUtil.FindNet[handle, name]; trunkWidth: SC.Number _ handle.rules.rowRules.trunkWidth; position: CD.Position _ [IF side = left THEN 0 ELSE lgRows.maxRowWidth - trunkWidth, offset + min]; rect: CD.Object _ CDRects.CreateRect[[trunkWidth, max-min], layer]; trans: CD.Transformation _ [position, original]; RETURN[NEW[SCPrivate.PublicPinRec _ [net.wire, rect, trans]]]}}; EachChannel: SCChanUtil.EachRowChanProc ~ { <<[chan: SCPrivate.MaxChanSr, rowChan: SCPrivate.RowChan] RETURNS [quit: BOOL _ FALSE]>> <> IF chan # 1 THEN IncludeRow[chan-1]; IF chan = 1 AND rowChans.count = 2 THEN { <> TransferExits: ExtendCells.ExtendSegmentProc = { <> net: SCPrivate.Net _ SCUtil.FindNetByWire[handle, wire]; xfer: BOOLEAN _ net.externNet = externalNet AND SCNetUtil.ExitOnSide[handle, net, bottom] AND side = bottom; IF xfer THEN { pinInst: CD.Instance; pinSize: CD.Position _ [max - min, handle.rules.rowRules.branchWidth]; object: CD.Object _ CDCells.CreateEmptyCell[]; pinInst _ RouteUtil.Include[cell: object, ob: CDSymbolicObjects.CreatePin[pinSize], position: [0, extension - handle.rules.rowRules.branchWidth]]; CDSymbolicObjects.SetName[pinInst, net.name]; CDSymbolicObjects.SetLayer[pinInst, layer]; RTBasic.RepositionCell[object]; RETURN[object]}}; topRow: CD.Object _ lgRows.rows[chan].shell; wirePins: LIST OF ExtendCells.WirePin _ BuildWirePinsFromObj[handle: handle, template: topRow, objSide: bottom]; bottomRow: CD.Object _ ExtendCells.ExtendObject[wirePins: wirePins, size: RTBasic.IRSize[topRow], side: bottom, extendProc: TransferExits]; RouteChannel[bottomRow, topRow, rowChan]}; IF chan # rowChans.count AND chan # 1 THEN { <> bottomRow: CD.Object _ lgRows.rows[chan-1].shell; topRow: CD.Object _ lgRows.rows[chan].shell; RouteChannel[bottomRow, topRow, rowChan]}}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; rowChans: SCPrivate.RowChans _ layoutData.rowChans; lgRows: SCPrivate.LgRows _ layoutData.lgRows; mode: Sinix.Mode _ SinixOps.GetExtractMode[handle.rules.technology]; table: HashTable.Table _ IF viaTable # NIL THEN viaTable ELSE HashTable.Create[equal: EqualProc, hash: HashProc]; routerParams: PWRoute.RouterParams _ NEW[PWRoute.RouterParamsRec _ [trunkLayer: handle.rules.horizLayer, branchLayer: handle.rules.vertLayer, technologyKey: NARROW[handle.rules.technology, CD.Technology].key, signalBreakAtExit: FALSE, signalSinglePinNets: TRUE, viaTable: table]]; offset: SC.Number _ 0; parms: SCPrivate.Parms _ NARROW[handle.parms]; parms.viaTable _ table; [] _ SCChanUtil.EnumerateRowChans[handle, EachChannel]; RTBasic.SetCDCellName[obj, handle.name]; RTBasic.RepositionCell[obj]}; BuildWirePins: PROC [handle: SC.Handle, cellType: Core.CellType, objSide: CoreGeometry.Side] RETURNS [wirePins: LIST OF ExtendCells.WirePin _ NIL] ~ { <> EachWirePin: CoreGeometry.EachWirePinProc = { IF side=objSide THEN wirePins _ CONS [[wire, min, max, layer], wirePins]}; mode: Sinix.Mode = SinixOps.GetExtractMode[handle.rules.technology]; [] _ CoreGeometry.EnumerateWireSides[mode.decoration, cellType, EachWirePin]}; BuildWirePinsFromObj: PROC [handle: SC.Handle, template: CD.Object, objSide: PWPins.Side] RETURNS [wirePins: LIST OF ExtendCells.WirePin _ NIL] ~ { <> <> EachPin: PWPins.InstanceEnumerator = { IF objSide=PWPins.GetSide[template, inst] THEN { layer: CD.Layer _ CDSymbolicObjects.GetLayer[inst]; net: SCPrivate.Net _ SCUtil.FindNet[handle, CDSymbolicObjects.GetName[inst]]; rect: CD.Rect _ CDSymbolicObjects.Denotes[inst]; min: CD.Number _ IF objSide = top OR objSide = bottom THEN rect.x1 ELSE rect.y1; max: CD.Number _ IF objSide = top OR objSide = bottom THEN rect.x2 ELSE rect.y2; wirePins _ CONS [[net.wire, min, max, layer], wirePins]}}; [] _ PWPins.EnumerateEdgePins[template, EachPin]}; AddTBPublics: PROC[handle: SC.Handle, lgRow: SCPrivate.LgRow, objSide: PWPins.Side, yCord: CD.Number] ~ { <> <> EachPin: PWPins.InstanceEnumerator = { IF objSide=PWPins.GetSide[lgRow.shell, inst] THEN { layer: CD.Layer _ CDSymbolicObjects.GetLayer[inst]; net: SCPrivate.Net _ SCUtil.FindNet[handle, CDSymbolicObjects.GetName[inst]]; trunkWidth: SC.Number _ handle.rules.rowRules.trunkWidth; denote: CD.Rect _ CDSymbolicObjects.Denotes[inst]; public: CD.Object _ CDRects.CreateRect[[denote.x2-denote.x1, trunkWidth], layer]; position: CD.Position _ [denote.x1, IF objSide = bottom THEN yCord ELSE yCord - trunkWidth]; lgRow.publics _ CONS[NEW[SCPrivate.PublicPinRec _ [net.wire, public, [position, original]]], lgRow.publics]}}; [] _ PWPins.EnumerateEdgePins[lgRow.shell, EachPin]}; EqualProc: PROC [k1, k2: HashTable.Key] RETURNS [eq: BOOL] = { p1: Route.Position _ NARROW[k1, REF Route.Position]^; p2: Route.Position _ NARROW[k2, REF Route.Position]^; eq _ p1.x = p2.x AND p1.y = p2.y}; HashProc: PROC [k: HashTable.Key] RETURNS [hash: CARDINAL] = { size: Route.Position _ NARROW[k, REF Route.Position]^; hash _ size.x + size.y}; END.