DIRECTORY SC, SCChanUtil, SCNetUtil, SCPrivate, SCRowUtil, SCWidthUtil, SCInstUtil; SCWidthUtilImpl: CEDAR PROGRAM IMPORTS SC, SCChanUtil, SCNetUtil, SCInstUtil, SCRowUtil EXPORTS SCWidthUtil SHARES SC = BEGIN InitOrTerm: TYPE = {init, term}; InitGetChanWidth: PROCEDURE [handle: SC.Handle, whatToDo: InitOrTerm] = { EachNet: SCNetUtil.EachNetProc = { net.bounds1 _ net.bounds2 _ NIL; net.minPinDist _ LAST[INT]; net.lastEntry _ NIL}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; layoutData.wireSegPins _ NEW[SCPrivate.WireSegPinsRec]; layoutData.wireSegs _ NEW[SCPrivate.WireSegsRec]; [] _ SCNetUtil.EnumerateNets[handle, EachNet]; IF whatToDo = init THEN { layoutData.wireSegs _ NEW[SCPrivate.WireSegsRec]; layoutData.wireSegPins _ NEW[SCPrivate.WireSegPinsRec]} ELSE { layoutData.wireSegs _ NIL; layoutData.wireSegPins _ NIL}}; NewWsEntry: PROCEDURE[handle: SC.Handle, pos: SC.Number, side: SC.Side] RETURNS [wireSeg: SCPrivate.WireSeg] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; wireSegs: SCPrivate.WireSegs _ layoutData.wireSegs; wireSegs.nWireSegsOnCh _ wireSegs.nWireSegsOnCh + 1; wireSeg _ NEW[SCPrivate.WireSegRec _ [pos, side]]; wireSegs.segs[wireSegs.nWireSegsOnCh] _ wireSeg}; EnterNet: PROCEDURE[handle: SC.Handle, net: SCPrivate.Net, pos: SC.Number, side: SCPrivate.TBSide, minMaxRoute: SCPrivate.RouteType] = { SELECT minMaxRoute FROM maxRoute => { IF net.bounds1 = NIL THEN {net.bounds1 _ NewWsEntry[handle, pos, left]; net.bounds2 _ NewWsEntry[handle, pos, right]} ELSE {net.bounds1.pos _ MIN[net.bounds1.pos, pos]; net.bounds2.pos _ MAX[net.bounds2.pos, pos]}}; minRoute => { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; wireSegPins: SCPrivate.WireSegPins _ layoutData.wireSegPins; wireSegPin: SCPrivate.WireSegPin _ NEW[SCPrivate.WireSegPinRec _ [pos, net, side]]; wireSegPins.nPinsOnCh _ wireSegPins.nPinsOnCh +1; wireSegPins.pins[wireSegPins.nPinsOnCh] _ wireSegPin}; ENDCASE}; EnterRowDat: PROCEDURE[handle: SC.Handle, row: SCPrivate.MaxRowSr, side, intrestingSide: SC.Side, minMaxRoute: SCPrivate.RouteType] = { InstProc: SCRowUtil.EachInstProc = { PinProc: SCInstUtil.EachPinProc = { IF netPin.pin # NIL AND netPin.net # NIL THEN { pd: SCInstUtil.PinDescription _ SCInstUtil.PosOf[instance, netPin.pin]; IF pd.sideOn = intrestingSide THEN { net: SCPrivate.Net _ netPin.net; IF net # NIL THEN EnterNet[handle, net, instance.offset + lgRow.rowOrg.p + pd.xPos, intrestingSide, minMaxRoute]}}}; [ ] _ SCInstUtil.EnumeratePinsOnInst[instance, PinProc]}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRow: SCPrivate.LgRow _ layoutData.lgRows.rows[row]; [ ] _ SCRowUtil.EnumerateAllInstsOnRow[handle, row, InstProc]}; EnterSideDat: PROCEDURE[handle: SC.Handle, side, intrestingSide, chanSide: SC.Side, minMaxRoute: SCPrivate.RouteType] = { InstProc: SCRowUtil.EachInstProc = { PinProc: SCInstUtil.EachPinProc = { IF netPin.pin # NIL THEN { pd: SCInstUtil.PinDescription _ SCInstUtil.PosOf[instance, netPin.pin]; IF pd.sideOn = intrestingSide AND netPin.net # NIL THEN { net: SCPrivate.Net _ netPin.net; IF net # NIL THEN { xyPos: SC.Number; SELECT side FROM bottom => xyPos _ bpRow.sideOrg.p + instance.offset + pd.xPos; right => xyPos _ bpRow.sideOrg.q + instance.offset + pd.yPos; top => xyPos _ bpRow.sideOrg.p - instance.offset + pd.xPos; left => xyPos _ bpRow.sideOrg.q - instance.offset + pd.yPos; ENDCASE; EnterNet[handle, net, xyPos, chanSide, minMaxRoute]}}}}; [ ] _ SCInstUtil.EnumeratePinsOnInst[instance, PinProc]}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; bpRow: SCPrivate.BpRow _ layoutData.bpRows[side]; [ ] _ SCRowUtil.EnumerateAllInstsOnSide[handle, side, InstProc]}; EnterExitDat: PROCEDURE[handle: SC.Handle, rowChan: SCPrivate.RowChan, lrSide: SCPrivate.LRSide, side: SC.Side, minMaxRoute: SCPrivate.RouteType] = { ExitProc: SCChanUtil.EachExitProc = { EnterNet[handle, exit.net, sideChan.sideChanPos + MAX[sideChan.sideChanWidth, sideChan.minSideChanWidth]/2, side, minMaxRoute]}; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; sideChan: SCPrivate.SideChan _ layoutData.sideChans[lrSide]; [] _ SCChanUtil.EnumerateExits[handle, rowChan, lrSide, ExitProc]}; EnterMinDat: PROCEDURE [handle: SC.Handle] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; wireSegPins: SCPrivate.WireSegPins _ layoutData.wireSegPins; FOR index: SCPrivate.ZMaxPinsOnChSr IN [1 .. wireSegPins.nPinsOnCh] DO entry: SCPrivate.WireSegPin _ wireSegPins.pins[index]; net: SCPrivate.Net _ entry.net; last: SCPrivate.WireSegPin _ net.lastEntry; IF last # NIL THEN { IF last.side = left OR entry.side = right THEN { [] _ NewWsEntry[handle, last.pos, last.side]; [] _ NewWsEntry[handle, entry.pos, entry.side]} ELSE IF entry.side # last.side THEN { thisDist: SC.Number _ ABS[entry.pos - last.pos]; IF thisDist < net.minPinDist THEN { net.minPinDist _ thisDist; IF net.bounds1 = NIL THEN { net.bounds1 _ NewWsEntry[handle, last.pos, last.side]; net.bounds2 _ NewWsEntry[handle, entry.pos, entry.side]} ELSE { net.bounds1.pos _ last.pos; net.bounds2.pos _ entry.pos}}}}; net.lastEntry _ entry; ENDLOOP}; SortPinDat: PROCEDURE [handle: SC.Handle] = BEGIN layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; wireSegPins: SCPrivate.WireSegPins _ layoutData.wireSegPins; gap: SCPrivate.ZMaxPinsOnChSr _ wireSegPins.nPinsOnCh /2; WHILE gap >0 DO FOR I: SCPrivate.ZMaxPinsOnChSr IN [gap+1 .. wireSegPins.nPinsOnCh] DO J: INTEGER _ I - gap; WHILE J > 0 DO Jg: SCPrivate.MaxPinsOnChSr _ J + gap; jgPtr: SCPrivate.WireSegPin _ wireSegPins.pins[Jg]; jPtr: SCPrivate.WireSegPin _ wireSegPins.pins[J]; IF jgPtr.pos < jPtr.pos THEN { wireSegPins.pins[Jg] _ jPtr; wireSegPins.pins[J] _ jgPtr}; J _ J -gap; ENDLOOP ; ENDLOOP; gap _ gap /2; ENDLOOP ; END; SortLimitDat: PROCEDURE [handle: SC.Handle] = BEGIN layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; wireSegs: SCPrivate.WireSegs _ layoutData.wireSegs; gap: SCPrivate.ZMaxWireSegsSr _ wireSegs.nWireSegsOnCh /2; WHILE gap > 0 DO FOR I: SCPrivate.ZMaxWireSegsSr IN [ gap+1 .. wireSegs.nWireSegsOnCh ] DO J: INTEGER _ I - gap; WHILE J > 0 DO Jg: SCPrivate.MaxWireSegsSr _ J +gap; jgPtr: SCPrivate.WireSeg _ wireSegs.segs[Jg]; jPtr: SCPrivate.WireSeg _ wireSegs.segs[J]; IF jgPtr.pos < jPtr.pos THEN { wireSegs.segs[Jg] _ jPtr; wireSegs.segs[J] _ jgPtr} ELSE IF jgPtr.pos <= jPtr.pos THEN { IF jgPtr.endType = left AND jPtr.endType = right THEN { wireSegs.segs[Jg] _ jPtr; wireSegs.segs[J] _ jgPtr}}; J _ J - gap; ENDLOOP ; ENDLOOP; gap _ gap /2; ENDLOOP ; END; GetChanWl: PUBLIC PROCEDURE [handle: SC.Handle] RETURNS [wireLength: SC.Number _ 0] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; wireSegs: SCPrivate.WireSegs _ layoutData.wireSegs; FOR index: SCPrivate.ZMaxWireSegsSr IN [1 .. wireSegs.nWireSegsOnCh] DO wireSeg: SCPrivate.WireSeg _ wireSegs.segs[index]; IF wireSeg.endType = left THEN wireLength _ wireLength - wireSeg.pos ELSE IF wireSeg.endType = right THEN wireLength _ wireLength + wireSeg.pos; ENDLOOP}; MaxTrackDensity: PROCEDURE[handle: SC.Handle] RETURNS [maxTracks: NAT _ 0] = { nTracks: NAT _ 0; layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; wireSegs: SCPrivate.WireSegs _ layoutData.wireSegs; FOR index: SCPrivate.ZMaxWireSegsSr IN [1 .. wireSegs.nWireSegsOnCh] DO wireSeg: SCPrivate.WireSeg _ wireSegs.segs[index]; SELECT wireSeg.endType FROM left => { nTracks _ nTracks +1; maxTracks _ MAX[maxTracks, nTracks]}; right => { nTracks _ nTracks -1; IF nTracks < 0 THEN SC.Error[programmingError, "Invalid wires in channel"]}; ENDCASE; ENDLOOP}; GetChanWidth: PUBLIC PROCEDURE[handle: SC.Handle, rowChan: SCPrivate.RowChan, fom: SCPrivate.FomType, doWidth: BOOLEAN] RETURNS [chanWidth, wireLength: SC.Number _ 0] = { IF doWidth THEN { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; lgRows: SCPrivate.LgRows _ layoutData.lgRows; rowChans: SCPrivate.RowChans _ layoutData.rowChans; pitch: SC.Number _ handle.rules.rowRules.trunkToTrunk; minMaxRoute: SCPrivate.RouteType _ IF fom = wlFom THEN maxRoute ELSE rowChan.routeType; InitGetChanWidth[handle, init]; IF fom = wlFom THEN minMaxRoute _ maxRoute ELSE minMaxRoute _ rowChan.routeType; IF rowChan.chanNum = 1 THEN { EnterSideDat[handle, bottom, top, bottom, minMaxRoute]; EnterRowDat[handle, 1, bottom, top, minMaxRoute]} ELSE IF rowChan.chanNum = rowChans.count THEN { EnterRowDat[handle, lgRows.count, top, bottom, minMaxRoute]; EnterSideDat[handle, top, bottom, top, minMaxRoute]} ELSE { EnterRowDat[handle, rowChan.chanNum-1, top, bottom, minMaxRoute]; EnterRowDat[handle, rowChan.chanNum, bottom, top, minMaxRoute]}; EnterExitDat[handle, rowChan, left, left, minMaxRoute]; EnterExitDat[handle, rowChan, right, right, minMaxRoute]; wireLength _ GetChanWl[handle]; IF fom = wlFom THEN chanWidth _ wireLength * pitch * horzWireToAreaFact / lgRows.maxRowWidth ELSE { IF minMaxRoute = minRoute THEN { SortPinDat[handle]; EnterMinDat[handle]}; SortLimitDat[handle]; chanWidth _ MAX[1, MaxTrackDensity[handle]] * pitch}; InitGetChanWidth[handle, term]; }}; EnterCntdDat: PROCEDURE [handle: SC.Handle, lrSide: SCPrivate.LRSide, side, chanSide: SC.Side] = { ChansProc: SCChanUtil.EachRowChanProc = { ExitsProc: SCChanUtil.EachExitProc = { EnterNet[handle, exit.net, rowChan.chanPos + MAX[rowChan.chanWidth, rowChan.minChanWidth]/2, chanSide, maxRoute]}; [] _ SCChanUtil.EnumerateExits[handle, rowChan, lrSide, ExitsProc]}; [] _ SCChanUtil.EnumerateRowChans[handle, ChansProc]}; GetSideWidth: PUBLIC PROCEDURE[handle: SC.Handle, lRSide: SCPrivate.LRSide, fom: SCPrivate.FomType] RETURNS [chanWidth, wireLength: SC.Number] = { layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; acBuses: SCPrivate.AcBuses _ layoutData.acBuses; powerBuses: SCPrivate.PowerBuses _ layoutData.powerBuses; rules: SC.DesignRules _ NARROW[handle.rules]; pitch: SC.Number _ rules.sideRules.trunkToTrunk; chanWidth _ acBuses[lRSide].width + powerBuses[lRSide].width; InitGetChanWidth[handle, init]; SELECT lRSide FROM right => { EnterSideDat[handle, right, left, bottom, maxRoute]; EnterCntdDat[handle, right, right, top]}; left => { EnterSideDat[handle, left, right, top, maxRoute]; EnterCntdDat[handle, left, left, bottom]}; ENDCASE; wireLength _ GetChanWl[handle]; IF fom = wlFom THEN { chanWidth _ chanWidth + wireLength*pitch*vertWireToAreaFact/layoutData.totHeight} ELSE { SortLimitDat[handle]; chanWidth _ chanWidth + MAX[1, MaxTrackDensity[handle]]*pitch}; InitGetChanWidth[handle, term]}; AllChanWidths: PUBLIC PROCEDURE[handle: SC.Handle, fom: SCPrivate.FomType] = BEGIN layoutData: SCPrivate.LayoutData _ NARROW[handle.layoutData]; SideChan: SCChanUtil.EachSideChanProc = { [sideChan.sideChanWidth, sideChan.wireLength] _ GetSideWidth[handle, lrSide, fom]}; RowChan: SCChanUtil.EachRowChanProc = { [rowChan.chanWidth, rowChan.wireLength] _ GetChanWidth[handle, rowChan, fom, TRUE]}; [] _ SCChanUtil.EnumerateSideChans[handle, SideChan]; [] _ SCChanUtil.EnumerateRowChans[handle, RowChan]; END; vertWireToAreaFact: SC.Number _ 3; horzWireToAreaFact: SC.Number _ 3; END. îfile ///StdCell/SCWidthUtilImpl.mesa placement utility routines -- InitGetChanWidth - initialize for determining the width of a channel -- NewWsEntry - get a new wire segment entry and insert pos, return location -- EnterNet - enter a net on a channel into data base -- EnterRowDat - enter routing data for one side of one row into data base -- EnterSideDat - enter routing data for one side of one side into data base -- EnterExitDat - enter exit data for a channel into routing data base -- EnterMinDat - minmium route channels need special processing to include the minimun number of wire segments of minimum length -- SortPinDat - sort the pin data -- SortLimitDat - sort the data representing the extremes of each net on each channel -- GetChanWl - find wirelength for this channel -- MaxTrackDensity - find maximum track density on a channel -- GetChanWidth - get width of channel specified -- EnterCntdDat - enter data for connections between horiz and vert channels -- GetSideWidth - get width of channel on side -- AllChanWidths - find widths of all channels initialize for determining the width of a channel get a new wire segment entry and insert pos, return location enter a net on a channel into data base the type of route on this channel determines how the data is stored enter routing data for one side of one row into data base enter routing data for one side of one side into data base enter exit data for a channel into routing data base minmium route channels need special processing to include the minimun number of wire segments of minimum length check to see if a pin for this net has been seen before see if an exit entry needs to be processed two pins on different sides of chan, see if min dist sort the pin data this uses a shell sort, see software tools by kernigan and pluager test and exchange if necessary sort the data representing the extremes of each net on each channel this uses a shell sort, see software tools by kernigan and pluager test and exchange if necessary positions are equal, test end types find wirelength for this channel find maximum track density on a channel use figure of merit type to set flag assemble data for pins on this channel compute or estimate chwidth based on fom type a minimum route channel requires special processing next sort the wireseg entries and find max track density enter data for connections between horiz and vert channels get width of channel on side compute or estimate channel width based on fom find widths of all channels Ê ‰˜Jšœ$™$J˜Jšœ™JšœÏnœ4™GJšœ œ?™LJšœœ*™5Jšœ œ<™JJšœ œ=™LJšœ œ7™Fšœ œ4™BJšœ=™=—Jšœ œ™!Jšœ œF™UJšœ œ#™/Jšœœ*™˜>Jšœ=˜=Jšœ;˜;Jšœ<˜™>Jš œž œ žœ ˜.˜Jšœ#žœ˜=Jšœ<˜<šžœ!žœžœ˜GJšœ6˜6Jšœ˜Jšœ+˜+J˜Jšœ8™8šžœžœžœ˜J˜Jšœ+™+šžœžœžœ˜0Jšœ-˜-Jšœ/˜/J˜—šžœžœžœ˜%J˜Jšœ5™5Jšœ žœ žœ˜0šžœžœ˜#Jšœ˜šžœžœžœ˜Jšœ6˜6Jšœ8˜8—šžœ˜Jšœ˜Jšœ ˜ ————Jšœ˜Jšžœ˜ ——Jšœ™JšœC™Cš œž œ žœ ˜,J˜Jšž˜Jšœ#žœ˜=Jšœ<˜