Correct managment of macro block regarding to P&R.
* Change: In NetBuilder::getPositions(), ordering of source/target points is now integrated to this function instead of left to the caller. In case of real (non-symbolic) routing gauge, skrink the ends of half the wire width. * Change: In NetBuilderHV::doRp_AutoContacts(), in case of non-METAL1 RoutingPad, put the axis of the segment on the nearest track. Issue a warning if we have to shift, as it may be a potential source of routing problems. * New: Anabatic::Session::getNearestTrackaAxis(), proxy to compute track positions, knowing the design abutment box. * Bug: In Katana::PreProcess::propagateCagedConstraints(), when looking at all the slave components anchoreds on a RoutingPad, if they do not have an AutoSegment lookup, skip them instead of crashing. * New: In cumulus/plugins.block.Block.placeMacro(), new method to place a macro cell, partly delegating to the Macro block wrapper. Must be called *after* both core and corona abutment boxes have been set. Adjust the macro block position so the METAL2 & METAL3 pins are exactly on pitch regarding the full routing grid. The reference being the corona. A shift, less than one pitch may be applied, leading in some cases of overlapping abutment boxes. But this shouldn't be a problem. The macro to place is designated through a path of instances names, rooted at the *core* (not the corona). Meaning that the head instance must be one of the core. * Change: In cumulus/plugins.chip.Chip, the complete chip I/O pads plus corona and core placement is moved out from doPnR() and put into doChipFloorplan(). It is now mandatory to call this method *before* doPnR(). Those methods are now cleanly separated so we can perform macro block placement or any inner core floorplaning operations between them. * Change: In cumulus/plugins.macro.Macro, instead of creating large pads for the I/O pins so whatever the block position, they will be under a grid point, create a simple dogleg to put them on grid. To ensure that they are "on grid", the block pins must be in METAL2 (horizontal E/W) or METAL3 (vertical N/S) and the block is assumed to be placed so the bottom left corner of it's abutment box is exactly on one grid point for M2/M3. This should be done by Block.placeMacro().
This commit is contained in:
parent
7e6250d460
commit
dbb16b618f
|
@ -228,22 +228,44 @@ namespace Anabatic {
|
|||
|
||||
void NetBuilder::getPositions ( Component* anchor, Point& source, Point& target )
|
||||
{
|
||||
Segment* segment = dynamic_cast<Segment*>( anchor );
|
||||
Segment* segment = dynamic_cast<Segment*>( anchor );
|
||||
if (segment) {
|
||||
source = segment->getSourcePosition();
|
||||
target = segment->getTargetPosition();
|
||||
return;
|
||||
} else {
|
||||
RoutingPad* rp = dynamic_cast<RoutingPad*>( anchor );
|
||||
if (rp) {
|
||||
source = rp->getSourcePosition();
|
||||
target = rp->getTargetPosition();
|
||||
} else {
|
||||
source = anchor->getPosition();
|
||||
target = anchor->getPosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RoutingPad* rp = dynamic_cast<RoutingPad*>( anchor );
|
||||
if (rp) {
|
||||
source = rp->getSourcePosition();
|
||||
target = rp->getTargetPosition();
|
||||
return;
|
||||
}
|
||||
if (source == target) return;
|
||||
if (source.getX() > target.getX()) swap( source, target );
|
||||
if (source.getY() > target.getY()) swap( source, target );
|
||||
|
||||
source = anchor->getPosition();
|
||||
target = anchor->getPosition();
|
||||
if (not Session::getRoutingGauge()->isSymbolic()) {
|
||||
size_t rpDepth = Session::getLayerDepth( anchor->getLayer() );
|
||||
Flags direction = Session::getDirection ( rpDepth );
|
||||
DbU::Unit wwidth = Session::getWireWidth (rpDepth) / 2;
|
||||
cdebug_log(145,0) << "Not a symbolic gauge, shrink positions of " << DbU::getValueString(wwidth) << endl;
|
||||
if (rpDepth == 0) return;
|
||||
if (direction.contains(Flags::Horizontal)) {
|
||||
cdebug_log(145,0) << "H shrink" << endl;
|
||||
source.translate( wwidth, 0 );
|
||||
target.translate( -wwidth, 0 );
|
||||
} else {
|
||||
cdebug_log(145,0) << "V shrink" << endl;
|
||||
source.translate( 0, wwidth );
|
||||
target.translate( 0, -wwidth );
|
||||
}
|
||||
} else {
|
||||
cdebug_log(145,0) << "Symbolic gauge, no shrink" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -95,9 +95,6 @@ namespace Anabatic {
|
|||
|
||||
getPositions( rp, sourcePosition, targetPosition );
|
||||
|
||||
if (sourcePosition.getX() > targetPosition.getX()) swap( sourcePosition, targetPosition );
|
||||
if (sourcePosition.getY() > targetPosition.getY()) swap( sourcePosition, targetPosition );
|
||||
|
||||
GCell* sourceGCell = Session::getAnabatic()->getGCellUnder( sourcePosition );
|
||||
GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition );
|
||||
|
||||
|
@ -111,6 +108,53 @@ namespace Anabatic {
|
|||
if ( ((rpDepth != 0) or (sourcePosition == targetPosition)) and not (flags & NoProtect) ) {
|
||||
map<Component*,AutoSegment*>::iterator irp = getRpLookup().find( rp );
|
||||
if (irp == getRpLookup().end()) {
|
||||
Box rpBb = rp->getBoundingBox();
|
||||
if (rpDepth != 0) {
|
||||
DbU::Unit hborder = 0;
|
||||
DbU::Unit vborder = 0;
|
||||
if (direction.contains(Flags::Horizontal)) {
|
||||
vborder = Session::getWireWidth(rpDepth) / 2;
|
||||
rpBb.inflate( hborder, vborder );
|
||||
if (not rpBb.isEmpty()) {
|
||||
DbU::Unit trackAxis = Session::getNearestTrackAxis( rp->getLayer()
|
||||
, sourcePosition.getY()
|
||||
, Constant::Nearest );
|
||||
if (trackAxis != sourcePosition.getY()) {
|
||||
cerr << Warning( "NetBuilderHV::doRp_AutoContacts(): Adjust Y position to nearest H track of %s\n"
|
||||
" (%s -> %s)"
|
||||
, getString(rp).c_str()
|
||||
, DbU::getValueString(sourcePosition.getY()).c_str()
|
||||
, DbU::getValueString(trackAxis).c_str()
|
||||
) << endl;
|
||||
sourcePosition.setY( trackAxis );
|
||||
targetPosition.setY( trackAxis );
|
||||
}
|
||||
} else {
|
||||
cdebug_log(145,0) << "rpBb is too narrow to adjust: " << rp->getBoundingBox() << endl;
|
||||
}
|
||||
} else {
|
||||
hborder = Session::getWireWidth(rpDepth) / 2;
|
||||
rpBb.inflate( hborder, vborder );
|
||||
if (not rpBb.isEmpty()) {
|
||||
DbU::Unit trackAxis = Session::getNearestTrackAxis( rp->getLayer()
|
||||
, sourcePosition.getX()
|
||||
, Constant::Nearest );
|
||||
if (trackAxis != sourcePosition.getX()) {
|
||||
cerr << Warning( "NetBuilderHV::doRp_AutoContacts(): Adjust X position to nearest V track of %s\n"
|
||||
" (%s -> %s)"
|
||||
, getString(rp).c_str()
|
||||
, DbU::getValueString(sourcePosition.getX()).c_str()
|
||||
, DbU::getValueString(trackAxis).c_str()
|
||||
) << endl;
|
||||
sourcePosition.setX( trackAxis );
|
||||
targetPosition.setX( trackAxis );
|
||||
}
|
||||
} else {
|
||||
cdebug_log(145,0) << "rpBb is too narrow to adjust: " << rp->getBoundingBox() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AutoContact* sourceProtect = AutoContactTerminal::create( sourceGCell
|
||||
, rp
|
||||
, rpLayer
|
||||
|
|
|
@ -360,6 +360,31 @@ namespace Anabatic {
|
|||
}
|
||||
|
||||
|
||||
DbU::Unit Session::_getNearestTrackAxis ( const Layer* layer, DbU::Unit axis, uint32_t mode )
|
||||
{
|
||||
Box ab = _anabatic->getCell()->getAbutmentBox();
|
||||
|
||||
RoutingLayerGauge* lg = _routingGauge->getLayerGauge( layer );
|
||||
if (not lg) return axis;
|
||||
|
||||
DbU::Unit minAxis = 0;
|
||||
DbU::Unit maxAxis = 0;
|
||||
if (lg->getDirection() == Constant::Horizontal) {
|
||||
minAxis = ab.getYMin();
|
||||
maxAxis = ab.getYMax();
|
||||
} else {
|
||||
minAxis = ab.getXMin();
|
||||
maxAxis = ab.getXMax();
|
||||
}
|
||||
DbU::Unit trackAxis = lg->getTrackPosition( minAxis
|
||||
, lg->getTrackIndex( minAxis
|
||||
, maxAxis
|
||||
, axis
|
||||
, mode ) );
|
||||
return trackAxis;
|
||||
}
|
||||
|
||||
|
||||
Point Session::_getNearestGridPoint ( Point p, Box constraint )
|
||||
{
|
||||
Box ab = _anabatic->getCell()->getAbutmentBox();
|
||||
|
|
|
@ -132,6 +132,7 @@ namespace Anabatic {
|
|||
static inline DbU::Unit getWireWidth ( const Layer* );
|
||||
static inline DbU::Unit getViaWidth ( const Layer* );
|
||||
static inline DbU::Unit getExtensionCap ( const Layer* );
|
||||
static inline DbU::Unit getNearestTrackAxis ( const Layer*, DbU::Unit, uint32_t mode );
|
||||
static inline Point getNearestGridPoint ( Point, Box constraints );
|
||||
static inline size_t getSegmentStackSize ();
|
||||
static inline size_t getContactStackSize ();
|
||||
|
@ -173,6 +174,7 @@ namespace Anabatic {
|
|||
void _revalidateTopology ();
|
||||
virtual size_t _revalidate ();
|
||||
DbU::Unit _getPitch ( size_t depth, Flags flags ) const;
|
||||
DbU::Unit _getNearestTrackAxis ( const Layer*, DbU::Unit, uint32_t mode );
|
||||
Point _getNearestGridPoint ( Point, Box constraints );
|
||||
Record* _getRecord () const;
|
||||
string _getString () const;
|
||||
|
@ -277,6 +279,7 @@ namespace Anabatic {
|
|||
inline DbU::Unit Session::getExtensionCap ( const Layer* layer ) { return getConfiguration()->getExtensionCap(layer); }
|
||||
inline Flags Session::getDirection ( const Layer* layer ) { return getDirection( getLayerDepth(layer) ); }
|
||||
inline Point Session::getNearestGridPoint ( Point p, Box b ) { return get("getNearestGridPoint()")->_getNearestGridPoint(p,b); }
|
||||
inline DbU::Unit Session::getNearestTrackAxis ( const Layer* layer, DbU::Unit axis, uint32_t mode ) { return get("getNearestTrackAxis()")->_getNearestTrackAxis(layer,axis,mode); }
|
||||
|
||||
inline void Session::_dogleg ( AutoSegment* segment ) { _doglegs.push_back(segment); }
|
||||
inline void Session::_doglegReset () { _doglegs.clear(); }
|
||||
|
|
|
@ -32,6 +32,7 @@ import Anabatic
|
|||
import Katana
|
||||
import plugins.rsave
|
||||
from plugins import getParameter
|
||||
from alpha.macro.macro import Macro
|
||||
from alpha.block import timing
|
||||
from alpha.block.spares import Spares
|
||||
from alpha.block.clocktree import ClockTree
|
||||
|
@ -327,6 +328,34 @@ class Block ( object ):
|
|||
.format(self.conf.cell.getName()) )
|
||||
Block.LUT[ self.conf.cell ] = self
|
||||
|
||||
@staticmethod
|
||||
def _rgetInstance ( cell, path ):
|
||||
"""
|
||||
Get the instance designated by path (recursively). The path argument can be
|
||||
either a string of instance names separated by dots or directly a list of
|
||||
instances names.
|
||||
"""
|
||||
if isinstance(path,str):
|
||||
path = path.split( '.' )
|
||||
elif not isinstance(path,list):
|
||||
raise ErrorMessage( 1, 'Block._rgetInstance(): "path" argument is neither a string or a list ({})"' \
|
||||
.format(path) )
|
||||
instance = cell.getInstance( path[0] )
|
||||
if instance is None:
|
||||
raise ErrorMessage( 1, 'Block._rgetInstance(): no instance "{}" in cell "{}"' \
|
||||
.format(path[0],cell.getName()) )
|
||||
if len(path) == 1:
|
||||
return instance
|
||||
return Block._rgetInstance( instance.getMasterCell(), path[1:] )
|
||||
|
||||
def rgetCoreInstance ( self, path ):
|
||||
"""
|
||||
Get the instance designated by path (recursively). The path argument can be
|
||||
either a string of instance names separated by dots or directly a list of
|
||||
instances names. The root of the path must be *core* cell.
|
||||
"""
|
||||
return Block._rgetInstance( self.conf.core, path )
|
||||
|
||||
def setUnexpandPins ( self, sides ):
|
||||
"""
|
||||
Prevent Pins from the selected sides to be stick out of one pitch.
|
||||
|
@ -551,6 +580,50 @@ class Block ( object ):
|
|||
Breakpoint.stop( 100, 'Placement done.' )
|
||||
self.etesian.clearColoquinte()
|
||||
|
||||
def placeMacro ( self, ipath, transf ):
|
||||
"""
|
||||
Place the instance refered by ``ipath`` at position ``transformation``.
|
||||
Both parameters are relative to the core cell.
|
||||
"""
|
||||
with UpdateSession():
|
||||
instance = self.rgetCoreInstance( ipath )
|
||||
macro = Macro.wrap( instance.getMasterCell()
|
||||
, self.conf.routingGauge.getName(), 2, 2 )
|
||||
instanceAb = instance.getMasterCell().getAbutmentBox()
|
||||
coreTransf = self.conf.icore.getTransformation()
|
||||
if self.conf.isCoreBlock:
|
||||
pnrAb = self.conf.icorona.getMasterCell().getAbutmentBox()
|
||||
else:
|
||||
pnrAb = self.conf.core.getAbutmentBox()
|
||||
print( 'pnrAb={}'.format(pnrAb) )
|
||||
print( 'coreTransf={}'.format(coreTransf) )
|
||||
macroPosition = transf.getTranslation()
|
||||
coreTransf.applyOn( macroPosition )
|
||||
xoffset = macroPosition.getX() - pnrAb.getXMin()
|
||||
xpitch = self.conf.vDeepRG.getPitch()
|
||||
print( 'Original X offset: {}'.format(DbU.getValueString(xoffset)) )
|
||||
if xoffset % xpitch:
|
||||
xoffset += xpitch - (xoffset % xpitch)
|
||||
print( 'Pitched X offset: {}'.format(DbU.getValueString(xoffset)) )
|
||||
yoffset = macroPosition.getY() - pnrAb.getYMin()
|
||||
ypitch = self.conf.hDeepRG.getPitch()
|
||||
print( 'Original Y offset: {}'.format(DbU.getValueString(yoffset)) )
|
||||
if yoffset % ypitch:
|
||||
yoffset += ypitch - (yoffset % ypitch)
|
||||
print( 'Pitched Y offset: {}'.format(DbU.getValueString(yoffset)) )
|
||||
macroPosition = Point( xoffset, yoffset )
|
||||
print( 'Position in corona={}'.format(macroPosition) )
|
||||
coreTransf.invert()
|
||||
coreTransf.applyOn( macroPosition )
|
||||
print( 'Position in core={}'.format(macroPosition) )
|
||||
print( 'instanceAb={}'.format(instanceAb) )
|
||||
Macro.place( instance.getCell()
|
||||
, instance
|
||||
, Transformation( macroPosition.getX()
|
||||
, macroPosition.getY()
|
||||
, Transformation.Orientation.ID )
|
||||
, Instance.PlacementStatus.FIXED )
|
||||
|
||||
def route ( self ):
|
||||
routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell
|
||||
self.katana = Katana.KatanaEngine.create( routedCell )
|
||||
|
|
|
@ -70,10 +70,20 @@ class Chip ( Block ):
|
|||
self.conf.validated = False
|
||||
return self.conf.validated
|
||||
|
||||
def doCoronaFloorplan ( self ):
|
||||
def doChipFloorplan ( self ):
|
||||
self.conf.computeCoronaBorder()
|
||||
self.conf.chipValidate()
|
||||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'chip.doCoronaFloorplan(): Chip is not valid, aborting.' )
|
||||
return
|
||||
raise ErrorMessage( 1, 'chip.doChipFloorplan(): Chip is not valid, aborting.' )
|
||||
self.conf.chip.setAbutmentBox( self.conf.chipAb )
|
||||
trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) )
|
||||
trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) )
|
||||
self.padsCorona = plugins.alpha.chip.pads.Corona( self.conf )
|
||||
self.conf.validated = self.padsCorona.validate()
|
||||
if not self.conf.validated:
|
||||
return False
|
||||
self.padsCorona.doLayout()
|
||||
self.validate()
|
||||
minHCorona = self.conf.minHCorona
|
||||
minVCorona = self.conf.minVCorona
|
||||
innerBb = Box( self.conf.coreAb )
|
||||
|
@ -98,6 +108,8 @@ class Chip ( Block ):
|
|||
y = y - (y % self.conf.sliceHeight)
|
||||
self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) )
|
||||
self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
self.padsCorona.doPowerLayout()
|
||||
self.conf.refresh()
|
||||
|
||||
def doConnectCore ( self ):
|
||||
if self.conf.routingGauge.hasPowerSupply():
|
||||
|
@ -119,22 +131,6 @@ class Chip ( Block ):
|
|||
self.conf.refresh()
|
||||
|
||||
def doPnR ( self ):
|
||||
self.conf.computeCoronaBorder()
|
||||
self.conf.chipValidate()
|
||||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'chip.doChipPnR(): Chip is not valid, aborting.' )
|
||||
self.conf.chip.setAbutmentBox( self.conf.chipAb )
|
||||
trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) )
|
||||
trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) )
|
||||
self.padsCorona = plugins.alpha.chip.pads.Corona( self.conf )
|
||||
self.conf.validated = self.padsCorona.validate()
|
||||
if not self.conf.validated:
|
||||
return False
|
||||
self.padsCorona.doLayout()
|
||||
self.validate()
|
||||
self.doCoronaFloorplan()
|
||||
self.padsCorona.doPowerLayout()
|
||||
self.conf.refresh()
|
||||
super(Chip,self).doPnR()
|
||||
self.conf.refresh( self.conf.chip )
|
||||
return self.conf.validated
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
from __future__ import print_function
|
||||
import sys
|
||||
import os.path
|
||||
from operator import itemgetter, attrgetter, methodcaller
|
||||
import Cfg
|
||||
from Hurricane import Breakpoint, DbU, Box, Transformation, Point, \
|
||||
Box, Path, Layer, Occurrence, Net, \
|
||||
|
@ -43,22 +44,12 @@ class Macro ( object ):
|
|||
|
||||
@staticmethod
|
||||
def lookup ( macroCell ):
|
||||
if Macro.LUT.has_key(macroCell): return True
|
||||
return False
|
||||
if Macro.LUT.has_key(macroCell): return Macro.LUT[ macroCell ]
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getPPitch ( rg, metal ):
|
||||
depth = rg.getLayerDepth( metal )
|
||||
if depth < rg.getDepth(): pdepth = depth + 1
|
||||
else: pdepth = depth - 1
|
||||
return rg.getLayerPitch( pdepth )
|
||||
|
||||
@staticmethod
|
||||
def getWireWidth ( rg, metal ):
|
||||
return rg.getWireWidth( metal )
|
||||
|
||||
@staticmethod
|
||||
def place ( instance, transf, status ):
|
||||
def place ( topCell, instance, transf, status ):
|
||||
macro = Macro.lookup( instance.getMasterCell() )
|
||||
ab = instance.getMasterCell().getAbutmentBox()
|
||||
abShift = Transformation( -ab.getXMin(), -ab.getYMin(), Transformation.Orientation.ID )
|
||||
abShift.applyOn( transf )
|
||||
|
@ -68,15 +59,48 @@ class Macro ( object ):
|
|||
@staticmethod
|
||||
def wrap ( macroCell, gaugeName, hMargin, vMargin ):
|
||||
"""
|
||||
Encapsulate the macro cell, if not already done. Returns True
|
||||
if the encapsulation actually takes place.
|
||||
Adjust the interface of a macro block cell to better fit a
|
||||
given routing gauge. Keep a table of the already processed
|
||||
blocks (must be run only once for a block).
|
||||
|
||||
For an explanation of the parameters, see Macro.__init__().
|
||||
"""
|
||||
|
||||
macro = Macro.lookup( macroCell )
|
||||
if macro is not None:
|
||||
return macro
|
||||
return Macro( macroCell, gaugeName, hMargin, vMargin )
|
||||
|
||||
def getPPitch ( self, metal ):
|
||||
depth = self.rg.getLayerDepth( metal )
|
||||
if depth < self.rg.getDepth(): pdepth = depth + 1
|
||||
else: pdepth = depth - 1
|
||||
return self.rg.getLayerPitch( pdepth )
|
||||
|
||||
def getWireWidth ( self, metal ):
|
||||
return self.rg.getWireWidth( metal )
|
||||
|
||||
def getNearestTrackAxis ( self, metal, axis ):
|
||||
lg = self.rg.getLayerGauge( metal )
|
||||
if lg.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
axisMin = self.outerAb.getYMin()
|
||||
axisMax = self.outerAb.getYMax()
|
||||
else:
|
||||
axisMin = self.outerAb.getXMin()
|
||||
axisMax = self.outerAb.getXMax()
|
||||
trackIndex = lg.getTrackIndex( axisMin, axisMax, axis, RoutingLayerGauge.Nearest )
|
||||
return axisMin + lg.getOffset() + trackIndex * lg.getPitch()
|
||||
|
||||
def __init__ ( self, macroCell, gaugeName, hMargin, vMargin ):
|
||||
"""
|
||||
Encapsulate a macro cell.to better fit the routing gauge.
|
||||
|
||||
:param macroCell: The macro cell to be encapsulated.
|
||||
:param gaugeName: The name of the RoutingGauge to use.
|
||||
:param xMargin: The horizontal margin, expressed in pitchs of the
|
||||
lowest vertical routing metal (usually METAL3).
|
||||
:param yMargin: The vertical margin, expressed in pitchs of the
|
||||
lowesthorizontal routing metal (usually METAL2).
|
||||
:param hMargin: The number of pitchs the horizontal terminals
|
||||
will stick out of the original abutment box.
|
||||
:param vMargin: The number of pitchs the vertical terminals
|
||||
will stick out of the original abutment box.
|
||||
|
||||
The abutment box of the block is enlarged so both it's dimensions
|
||||
are a multiple of the sliceHeight. It is then enlarged of one more
|
||||
|
@ -88,17 +112,19 @@ class Macro ( object ):
|
|||
that are half free and half occluded by the block itself may
|
||||
cause (stupid) deadlock to appear.
|
||||
"""
|
||||
if Macro.lookup(macroCell): return False
|
||||
self.cell = macroCell
|
||||
Macro.LUT[ self.cell ] = self
|
||||
|
||||
af = CRL.AllianceFramework.get()
|
||||
rg = af.getRoutingGauge( gaugeName )
|
||||
ab = macroCell.getAbutmentBox()
|
||||
ab = self.cell.getAbutmentBox()
|
||||
self.rg = af.getRoutingGauge( gaugeName )
|
||||
self.innerAb = ab
|
||||
sliceHeight = af.getCellGauge( gaugeName ).getSliceHeight()
|
||||
westPins = []
|
||||
eastPins = []
|
||||
northPins = []
|
||||
southPins = []
|
||||
for net in macroCell.getNets():
|
||||
for net in self.cell.getNets():
|
||||
if not net.isExternal() or net.isSupply() or net.isClock():
|
||||
continue
|
||||
for component in net.getComponents():
|
||||
|
@ -111,114 +137,185 @@ class Macro ( object ):
|
|||
elif ab.getXMin() == bb.getXMin(): westPins.append( component )
|
||||
elif ab.getYMax() == bb.getYMax(): northPins.append( component )
|
||||
elif ab.getYMin() == bb.getYMin(): southPins.append( component )
|
||||
innerAb = ab
|
||||
xAdjust = 0
|
||||
yAdjust = 0
|
||||
if ab.getWidth () % sliceHeight: xAdjust = sliceHeight - ab.getWidth () % sliceHeight
|
||||
if ab.getHeight() % sliceHeight: yAdjust = sliceHeight - ab.getHeight() % sliceHeight
|
||||
innerAb.inflate( 0, 0, xAdjust, yAdjust )
|
||||
outerAb = innerAb
|
||||
outerAb.inflate( sliceHeight )
|
||||
self.innerAb.inflate( 0, 0, xAdjust, yAdjust )
|
||||
self.outerAb = self.innerAb
|
||||
self.outerAb.inflate( sliceHeight )
|
||||
westPins .sort( key=lambda k: k.getBoundingBox().getYCenter() )
|
||||
eastPins .sort( key=lambda k: k.getBoundingBox().getYCenter() )
|
||||
northPins.sort( key=lambda k: k.getBoundingBox().getXCenter() )
|
||||
southPins.sort( key=lambda k: k.getBoundingBox().getXCenter() )
|
||||
|
||||
with UpdateSession():
|
||||
for component in westPins:
|
||||
NetExternalComponents.setInternal( component )
|
||||
pitch = rg.getPitch( component.getLayer() )
|
||||
ppitch = Macro.getPPitch( rg, component.getLayer() )
|
||||
wwidth = Macro.getWireWidth( rg, component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
yAxis = bb.getYCenter()
|
||||
xMax = bb.getXMin()
|
||||
xMin = xMax - hMargin*ppitch
|
||||
width = bb.getHeight()
|
||||
pitch = self.rg.getPitch( component.getLayer() )
|
||||
ppitch = self.getPPitch( component.getLayer() )
|
||||
wwidth = self.getWireWidth( component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
yAxis = bb.getYCenter()
|
||||
yOngrid = self.getNearestTrackAxis( component.getLayer(), yAxis )
|
||||
xMax = bb.getXMin()
|
||||
xMin = xMax - hMargin*ppitch
|
||||
width = bb.getHeight()
|
||||
ppYAxis = yAxis
|
||||
ppYOngrid = yOngrid
|
||||
if not self.rg.isSymbolic():
|
||||
if ppYAxis < ppYOngrid:
|
||||
ppYAxis -= width/2
|
||||
ppYOngrid += wwidth/2
|
||||
else:
|
||||
ppYAxis += width/2
|
||||
ppYOngrid -= wwidth/2
|
||||
vertical = Vertical.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, bb.getXMin()
|
||||
, width
|
||||
, ppYAxis
|
||||
, ppYOngrid
|
||||
)
|
||||
horizontal = Horizontal.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, yAxis
|
||||
, width
|
||||
, yOngrid
|
||||
, wwidth
|
||||
, xMin
|
||||
, xMax
|
||||
)
|
||||
horizontal = Horizontal.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, yAxis
|
||||
, pitch + wwidth
|
||||
, yOngrid
|
||||
, wwidth
|
||||
, xMin
|
||||
, xMax - (hMargin-1) * ppitch
|
||||
, xMax - ppitch
|
||||
)
|
||||
NetExternalComponents.setExternal( horizontal )
|
||||
for component in eastPins:
|
||||
NetExternalComponents.setInternal( component )
|
||||
pitch = rg.getPitch( component.getLayer() )
|
||||
ppitch = Macro.getPPitch( rg, component.getLayer() )
|
||||
wwidth = Macro.getWireWidth( rg, component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
yAxis = bb.getYCenter()
|
||||
xMin = innerAb.getXMax()
|
||||
xMax = xMin + hMargin*ppitch
|
||||
width = bb.getHeight()
|
||||
pitch = self.rg.getPitch( component.getLayer() )
|
||||
ppitch = self.getPPitch( component.getLayer() )
|
||||
wwidth = self.getWireWidth( component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
yAxis = bb.getYCenter()
|
||||
yOngrid = self.getNearestTrackAxis( component.getLayer(), yAxis )
|
||||
xMin = self.innerAb.getXMax()
|
||||
xMax = xMin + hMargin*ppitch
|
||||
width = bb.getHeight()
|
||||
ppYAxis = yAxis
|
||||
ppYOngrid = yOngrid
|
||||
if not self.rg.isSymbolic():
|
||||
if ppYAxis < ppYOngrid:
|
||||
ppYAxis -= width/2
|
||||
ppYOngrid += wwidth/2
|
||||
else:
|
||||
ppYAxis += width/2
|
||||
ppYOngrid -= wwidth/2
|
||||
vertical = Vertical.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, bb.getXMax()
|
||||
, width
|
||||
, ppYAxis
|
||||
, ppYOngrid
|
||||
)
|
||||
horizontal = Horizontal.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, yAxis
|
||||
, width
|
||||
, yOngrid
|
||||
, pitch + wwidth
|
||||
, xMin
|
||||
, xMax
|
||||
)
|
||||
horizontal = Horizontal.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, yAxis
|
||||
, yOngrid
|
||||
, pitch + wwidth
|
||||
, xMin + (hMargin-1) * ppitch
|
||||
, xMin + ppitch
|
||||
, xMax
|
||||
)
|
||||
NetExternalComponents.setExternal( horizontal )
|
||||
for component in southPins:
|
||||
NetExternalComponents.setInternal( component )
|
||||
pitch = rg.getPitch( component.getLayer() )
|
||||
ppitch = Macro.getPPitch( rg, component.getLayer() )
|
||||
wwidth = Macro.getWireWidth( rg, component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
xAxis = bb.getXCenter()
|
||||
yMax = bb.getYMin()
|
||||
yMin = xMax - vMargin*ppitch
|
||||
width = bb.getWidth()
|
||||
pitch = self.rg.getPitch( component.getLayer() )
|
||||
ppitch = self.getPPitch( component.getLayer() )
|
||||
wwidth = self.getWireWidth( component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
xAxis = bb.getXCenter()
|
||||
xOngrid = self.getNearestTrackAxis( component.getLayer(), xAxis )
|
||||
yMax = bb.getYMin()
|
||||
yMin = yMax - vMargin*ppitch
|
||||
width = bb.getWidth()
|
||||
ppXAxis = xAxis
|
||||
ppXOngrid = xOngrid
|
||||
if not self.rg.isSymbolic():
|
||||
if ppXAxis < ppXOngrid:
|
||||
ppXAxis -= width/2
|
||||
ppXOngrid += wwidth/2
|
||||
else:
|
||||
ppXAxis += width/2
|
||||
ppXOngrid -= wwidth/2
|
||||
horizontal = Horizontal.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, bb.getYMin()
|
||||
, width
|
||||
, ppXAxis
|
||||
, ppXOngrid
|
||||
)
|
||||
vertical = Vertical.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, xAxis
|
||||
, width
|
||||
, xOngrid
|
||||
, wwidth
|
||||
, yMin
|
||||
, yMax
|
||||
)
|
||||
vertical = Vertical.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, xAxis
|
||||
, pitch + wwidth
|
||||
, xOngrid
|
||||
, wwidth
|
||||
, yMin
|
||||
, yMax - (vMargin-1) * ppitch
|
||||
, yMax - ppitch
|
||||
)
|
||||
NetExternalComponents.setExternal( vertical )
|
||||
for component in northPins:
|
||||
NetExternalComponents.setInternal( component )
|
||||
pitch = rg.getPitch( component.getLayer() )
|
||||
ppitch = Macro.getPPitch( rg, component.getLayer() )
|
||||
wwidth = Macro.getWireWidth( rg, component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
xAxis = bb.getXCenter()
|
||||
yMin = innerAb.getYMax()
|
||||
yMax = xMin + vMargin*ppitch
|
||||
width = bb.getWidth()
|
||||
pitch = self.rg.getPitch( component.getLayer() )
|
||||
ppitch = self.getPPitch( component.getLayer() )
|
||||
wwidth = self.getWireWidth( component.getLayer() )
|
||||
bb = component.getBoundingBox()
|
||||
xAxis = bb.getXCenter()
|
||||
xOngrid = self.getNearestTrackAxis( component.getLayer(), xAxis )
|
||||
yMin = self.innerAb.getYMax()
|
||||
yMax = yMin + vMargin*ppitch
|
||||
width = bb.getWidth()
|
||||
ppXAxis = xAxis
|
||||
ppXOngrid = xOngrid
|
||||
if not self.rg.isSymbolic():
|
||||
if ppXAxis < ppXOngrid:
|
||||
ppXAxis -= width/2
|
||||
ppXOngrid += wwidth/2
|
||||
else:
|
||||
ppXAxis += width/2
|
||||
ppXOngrid -= wwidth/2
|
||||
horizontal = Horizontal.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, bb.getYMax()
|
||||
, width
|
||||
, ppXAxis
|
||||
, ppXOngrid
|
||||
)
|
||||
vertical = Vertical.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, xAxis
|
||||
, width
|
||||
, xOngrid
|
||||
, pitch + wwidth
|
||||
, yMin
|
||||
, yMax
|
||||
)
|
||||
vertical = Vertical.create( component.getNet()
|
||||
, component.getLayer()
|
||||
, xAxis
|
||||
, xOngrid
|
||||
, pitch + wwidth
|
||||
, yMin + (vMargin-1) * ppitch
|
||||
, yMin + ppitch
|
||||
, yMax
|
||||
)
|
||||
NetExternalComponents.setExternal( vertical )
|
||||
macroCell.setAbutmentBox( outerAb )
|
||||
self.cell.setAbutmentBox( self.outerAb )
|
||||
|
|
|
@ -183,8 +183,9 @@ namespace {
|
|||
TrackElement* parallel;
|
||||
for( Segment* osegment : rp->getSlaveComponents().getSubSet<Segment*>() ) {
|
||||
parallel = Session::lookup( osegment );
|
||||
cdebug_log(159,0) << "* " << parallel << endl;
|
||||
if (not parallel) continue;
|
||||
|
||||
cdebug_log(159,0) << "* " << parallel << endl;
|
||||
if (parallel->isFixed ()) continue;
|
||||
if (parallel->isGlobal()) continue;
|
||||
getPerpandiculars( parallel, source, direction, perpandiculars );
|
||||
|
|
Loading…
Reference in New Issue