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:
Jean-Paul Chaput 2021-03-14 16:16:54 +01:00
parent 7e6250d460
commit dbb16b618f
8 changed files with 373 additions and 112 deletions

View File

@ -228,22 +228,44 @@ namespace Anabatic {
void NetBuilder::getPositions ( Component* anchor, Point& source, Point& target ) void NetBuilder::getPositions ( Component* anchor, Point& source, Point& target )
{ {
Segment* segment = dynamic_cast<Segment*>( anchor ); Segment* segment = dynamic_cast<Segment*>( anchor );
if (segment) { if (segment) {
source = segment->getSourcePosition(); source = segment->getSourcePosition();
target = segment->getTargetPosition(); 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 (source == target) return;
if (rp) { if (source.getX() > target.getX()) swap( source, target );
source = rp->getSourcePosition(); if (source.getY() > target.getY()) swap( source, target );
target = rp->getTargetPosition();
return;
}
source = anchor->getPosition(); if (not Session::getRoutingGauge()->isSymbolic()) {
target = anchor->getPosition(); 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;
}
} }

View File

@ -95,9 +95,6 @@ namespace Anabatic {
getPositions( rp, sourcePosition, targetPosition ); 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* sourceGCell = Session::getAnabatic()->getGCellUnder( sourcePosition );
GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition ); GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition );
@ -111,6 +108,53 @@ namespace Anabatic {
if ( ((rpDepth != 0) or (sourcePosition == targetPosition)) and not (flags & NoProtect) ) { if ( ((rpDepth != 0) or (sourcePosition == targetPosition)) and not (flags & NoProtect) ) {
map<Component*,AutoSegment*>::iterator irp = getRpLookup().find( rp ); map<Component*,AutoSegment*>::iterator irp = getRpLookup().find( rp );
if (irp == getRpLookup().end()) { 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 AutoContact* sourceProtect = AutoContactTerminal::create( sourceGCell
, rp , rp
, rpLayer , rpLayer

View File

@ -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 ) Point Session::_getNearestGridPoint ( Point p, Box constraint )
{ {
Box ab = _anabatic->getCell()->getAbutmentBox(); Box ab = _anabatic->getCell()->getAbutmentBox();

View File

@ -132,6 +132,7 @@ namespace Anabatic {
static inline DbU::Unit getWireWidth ( const Layer* ); static inline DbU::Unit getWireWidth ( const Layer* );
static inline DbU::Unit getViaWidth ( const Layer* ); static inline DbU::Unit getViaWidth ( const Layer* );
static inline DbU::Unit getExtensionCap ( 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 Point getNearestGridPoint ( Point, Box constraints );
static inline size_t getSegmentStackSize (); static inline size_t getSegmentStackSize ();
static inline size_t getContactStackSize (); static inline size_t getContactStackSize ();
@ -173,6 +174,7 @@ namespace Anabatic {
void _revalidateTopology (); void _revalidateTopology ();
virtual size_t _revalidate (); virtual size_t _revalidate ();
DbU::Unit _getPitch ( size_t depth, Flags flags ) const; DbU::Unit _getPitch ( size_t depth, Flags flags ) const;
DbU::Unit _getNearestTrackAxis ( const Layer*, DbU::Unit, uint32_t mode );
Point _getNearestGridPoint ( Point, Box constraints ); Point _getNearestGridPoint ( Point, Box constraints );
Record* _getRecord () const; Record* _getRecord () const;
string _getString () const; string _getString () const;
@ -277,6 +279,7 @@ namespace Anabatic {
inline DbU::Unit Session::getExtensionCap ( const Layer* layer ) { return getConfiguration()->getExtensionCap(layer); } inline DbU::Unit Session::getExtensionCap ( const Layer* layer ) { return getConfiguration()->getExtensionCap(layer); }
inline Flags Session::getDirection ( const Layer* layer ) { return getDirection( getLayerDepth(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 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::_dogleg ( AutoSegment* segment ) { _doglegs.push_back(segment); }
inline void Session::_doglegReset () { _doglegs.clear(); } inline void Session::_doglegReset () { _doglegs.clear(); }

View File

@ -32,6 +32,7 @@ import Anabatic
import Katana import Katana
import plugins.rsave import plugins.rsave
from plugins import getParameter from plugins import getParameter
from alpha.macro.macro import Macro
from alpha.block import timing from alpha.block import timing
from alpha.block.spares import Spares from alpha.block.spares import Spares
from alpha.block.clocktree import ClockTree from alpha.block.clocktree import ClockTree
@ -327,6 +328,34 @@ class Block ( object ):
.format(self.conf.cell.getName()) ) .format(self.conf.cell.getName()) )
Block.LUT[ self.conf.cell ] = self 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 ): def setUnexpandPins ( self, sides ):
""" """
Prevent Pins from the selected sides to be stick out of one pitch. 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.' ) Breakpoint.stop( 100, 'Placement done.' )
self.etesian.clearColoquinte() 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 ): def route ( self ):
routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell
self.katana = Katana.KatanaEngine.create( routedCell ) self.katana = Katana.KatanaEngine.create( routedCell )

View File

@ -70,10 +70,20 @@ class Chip ( Block ):
self.conf.validated = False self.conf.validated = False
return self.conf.validated return self.conf.validated
def doCoronaFloorplan ( self ): def doChipFloorplan ( self ):
self.conf.computeCoronaBorder()
self.conf.chipValidate()
if not self.conf.validated: if not self.conf.validated:
raise ErrorMessage( 1, 'chip.doCoronaFloorplan(): Chip is not valid, aborting.' ) raise ErrorMessage( 1, 'chip.doChipFloorplan(): Chip is not valid, aborting.' )
return 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 minHCorona = self.conf.minHCorona
minVCorona = self.conf.minVCorona minVCorona = self.conf.minVCorona
innerBb = Box( self.conf.coreAb ) innerBb = Box( self.conf.coreAb )
@ -98,6 +108,8 @@ class Chip ( Block ):
y = y - (y % self.conf.sliceHeight) y = y - (y % self.conf.sliceHeight)
self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) ) self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) )
self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED ) self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
self.padsCorona.doPowerLayout()
self.conf.refresh()
def doConnectCore ( self ): def doConnectCore ( self ):
if self.conf.routingGauge.hasPowerSupply(): if self.conf.routingGauge.hasPowerSupply():
@ -119,22 +131,6 @@ class Chip ( Block ):
self.conf.refresh() self.conf.refresh()
def doPnR ( self ): 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() super(Chip,self).doPnR()
self.conf.refresh( self.conf.chip ) self.conf.refresh( self.conf.chip )
return self.conf.validated return self.conf.validated

View File

@ -16,6 +16,7 @@
from __future__ import print_function from __future__ import print_function
import sys import sys
import os.path import os.path
from operator import itemgetter, attrgetter, methodcaller
import Cfg import Cfg
from Hurricane import Breakpoint, DbU, Box, Transformation, Point, \ from Hurricane import Breakpoint, DbU, Box, Transformation, Point, \
Box, Path, Layer, Occurrence, Net, \ Box, Path, Layer, Occurrence, Net, \
@ -43,22 +44,12 @@ class Macro ( object ):
@staticmethod @staticmethod
def lookup ( macroCell ): def lookup ( macroCell ):
if Macro.LUT.has_key(macroCell): return True if Macro.LUT.has_key(macroCell): return Macro.LUT[ macroCell ]
return False return None
@staticmethod @staticmethod
def getPPitch ( rg, metal ): def place ( topCell, instance, transf, status ):
depth = rg.getLayerDepth( metal ) macro = Macro.lookup( instance.getMasterCell() )
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 ):
ab = instance.getMasterCell().getAbutmentBox() ab = instance.getMasterCell().getAbutmentBox()
abShift = Transformation( -ab.getXMin(), -ab.getYMin(), Transformation.Orientation.ID ) abShift = Transformation( -ab.getXMin(), -ab.getYMin(), Transformation.Orientation.ID )
abShift.applyOn( transf ) abShift.applyOn( transf )
@ -68,15 +59,48 @@ class Macro ( object ):
@staticmethod @staticmethod
def wrap ( macroCell, gaugeName, hMargin, vMargin ): def wrap ( macroCell, gaugeName, hMargin, vMargin ):
""" """
Encapsulate the macro cell, if not already done. Returns True Adjust the interface of a macro block cell to better fit a
if the encapsulation actually takes place. 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 macroCell: The macro cell to be encapsulated.
:param gaugeName: The name of the RoutingGauge to use. :param gaugeName: The name of the RoutingGauge to use.
:param xMargin: The horizontal margin, expressed in pitchs of the :param hMargin: The number of pitchs the horizontal terminals
lowest vertical routing metal (usually METAL3). will stick out of the original abutment box.
:param yMargin: The vertical margin, expressed in pitchs of the :param vMargin: The number of pitchs the vertical terminals
lowesthorizontal routing metal (usually METAL2). will stick out of the original abutment box.
The abutment box of the block is enlarged so both it's dimensions 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 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 that are half free and half occluded by the block itself may
cause (stupid) deadlock to appear. cause (stupid) deadlock to appear.
""" """
if Macro.lookup(macroCell): return False self.cell = macroCell
Macro.LUT[ self.cell ] = self
af = CRL.AllianceFramework.get() af = CRL.AllianceFramework.get()
rg = af.getRoutingGauge( gaugeName ) ab = self.cell.getAbutmentBox()
ab = macroCell.getAbutmentBox() self.rg = af.getRoutingGauge( gaugeName )
self.innerAb = ab
sliceHeight = af.getCellGauge( gaugeName ).getSliceHeight() sliceHeight = af.getCellGauge( gaugeName ).getSliceHeight()
westPins = [] westPins = []
eastPins = [] eastPins = []
northPins = [] northPins = []
southPins = [] southPins = []
for net in macroCell.getNets(): for net in self.cell.getNets():
if not net.isExternal() or net.isSupply() or net.isClock(): if not net.isExternal() or net.isSupply() or net.isClock():
continue continue
for component in net.getComponents(): for component in net.getComponents():
@ -111,114 +137,185 @@ class Macro ( object ):
elif ab.getXMin() == bb.getXMin(): westPins.append( component ) elif ab.getXMin() == bb.getXMin(): westPins.append( component )
elif ab.getYMax() == bb.getYMax(): northPins.append( component ) elif ab.getYMax() == bb.getYMax(): northPins.append( component )
elif ab.getYMin() == bb.getYMin(): southPins.append( component ) elif ab.getYMin() == bb.getYMin(): southPins.append( component )
innerAb = ab
xAdjust = 0 xAdjust = 0
yAdjust = 0 yAdjust = 0
if ab.getWidth () % sliceHeight: xAdjust = sliceHeight - ab.getWidth () % sliceHeight if ab.getWidth () % sliceHeight: xAdjust = sliceHeight - ab.getWidth () % sliceHeight
if ab.getHeight() % sliceHeight: yAdjust = sliceHeight - ab.getHeight() % sliceHeight if ab.getHeight() % sliceHeight: yAdjust = sliceHeight - ab.getHeight() % sliceHeight
innerAb.inflate( 0, 0, xAdjust, yAdjust ) self.innerAb.inflate( 0, 0, xAdjust, yAdjust )
outerAb = innerAb self.outerAb = self.innerAb
outerAb.inflate( sliceHeight ) 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(): with UpdateSession():
for component in westPins: for component in westPins:
NetExternalComponents.setInternal( component ) NetExternalComponents.setInternal( component )
pitch = rg.getPitch( component.getLayer() ) pitch = self.rg.getPitch( component.getLayer() )
ppitch = Macro.getPPitch( rg, component.getLayer() ) ppitch = self.getPPitch( component.getLayer() )
wwidth = Macro.getWireWidth( rg, component.getLayer() ) wwidth = self.getWireWidth( component.getLayer() )
bb = component.getBoundingBox() bb = component.getBoundingBox()
yAxis = bb.getYCenter() yAxis = bb.getYCenter()
xMax = bb.getXMin() yOngrid = self.getNearestTrackAxis( component.getLayer(), yAxis )
xMin = xMax - hMargin*ppitch xMax = bb.getXMin()
width = bb.getHeight() 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() horizontal = Horizontal.create( component.getNet()
, component.getLayer() , component.getLayer()
, yAxis , yOngrid
, width , wwidth
, xMin , xMin
, xMax , xMax
) )
horizontal = Horizontal.create( component.getNet() horizontal = Horizontal.create( component.getNet()
, component.getLayer() , component.getLayer()
, yAxis , yOngrid
, pitch + wwidth , wwidth
, xMin , xMin
, xMax - (hMargin-1) * ppitch , xMax - ppitch
) )
NetExternalComponents.setExternal( horizontal ) NetExternalComponents.setExternal( horizontal )
for component in eastPins: for component in eastPins:
NetExternalComponents.setInternal( component ) NetExternalComponents.setInternal( component )
pitch = rg.getPitch( component.getLayer() ) pitch = self.rg.getPitch( component.getLayer() )
ppitch = Macro.getPPitch( rg, component.getLayer() ) ppitch = self.getPPitch( component.getLayer() )
wwidth = Macro.getWireWidth( rg, component.getLayer() ) wwidth = self.getWireWidth( component.getLayer() )
bb = component.getBoundingBox() bb = component.getBoundingBox()
yAxis = bb.getYCenter() yAxis = bb.getYCenter()
xMin = innerAb.getXMax() yOngrid = self.getNearestTrackAxis( component.getLayer(), yAxis )
xMax = xMin + hMargin*ppitch xMin = self.innerAb.getXMax()
width = bb.getHeight() 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() horizontal = Horizontal.create( component.getNet()
, component.getLayer() , component.getLayer()
, yAxis , yOngrid
, width , pitch + wwidth
, xMin , xMin
, xMax , xMax
) )
horizontal = Horizontal.create( component.getNet() horizontal = Horizontal.create( component.getNet()
, component.getLayer() , component.getLayer()
, yAxis , yOngrid
, pitch + wwidth , pitch + wwidth
, xMin + (hMargin-1) * ppitch , xMin + ppitch
, xMax , xMax
) )
NetExternalComponents.setExternal( horizontal ) NetExternalComponents.setExternal( horizontal )
for component in southPins: for component in southPins:
NetExternalComponents.setInternal( component ) NetExternalComponents.setInternal( component )
pitch = rg.getPitch( component.getLayer() ) pitch = self.rg.getPitch( component.getLayer() )
ppitch = Macro.getPPitch( rg, component.getLayer() ) ppitch = self.getPPitch( component.getLayer() )
wwidth = Macro.getWireWidth( rg, component.getLayer() ) wwidth = self.getWireWidth( component.getLayer() )
bb = component.getBoundingBox() bb = component.getBoundingBox()
xAxis = bb.getXCenter() xAxis = bb.getXCenter()
yMax = bb.getYMin() xOngrid = self.getNearestTrackAxis( component.getLayer(), xAxis )
yMin = xMax - vMargin*ppitch yMax = bb.getYMin()
width = bb.getWidth() 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() vertical = Vertical.create( component.getNet()
, component.getLayer() , component.getLayer()
, xAxis , xOngrid
, width , wwidth
, yMin , yMin
, yMax , yMax
) )
vertical = Vertical.create( component.getNet() vertical = Vertical.create( component.getNet()
, component.getLayer() , component.getLayer()
, xAxis , xOngrid
, pitch + wwidth , wwidth
, yMin , yMin
, yMax - (vMargin-1) * ppitch , yMax - ppitch
) )
NetExternalComponents.setExternal( vertical ) NetExternalComponents.setExternal( vertical )
for component in northPins: for component in northPins:
NetExternalComponents.setInternal( component ) NetExternalComponents.setInternal( component )
pitch = rg.getPitch( component.getLayer() ) pitch = self.rg.getPitch( component.getLayer() )
ppitch = Macro.getPPitch( rg, component.getLayer() ) ppitch = self.getPPitch( component.getLayer() )
wwidth = Macro.getWireWidth( rg, component.getLayer() ) wwidth = self.getWireWidth( component.getLayer() )
bb = component.getBoundingBox() bb = component.getBoundingBox()
xAxis = bb.getXCenter() xAxis = bb.getXCenter()
yMin = innerAb.getYMax() xOngrid = self.getNearestTrackAxis( component.getLayer(), xAxis )
yMax = xMin + vMargin*ppitch yMin = self.innerAb.getYMax()
width = bb.getWidth() 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() vertical = Vertical.create( component.getNet()
, component.getLayer() , component.getLayer()
, xAxis , xOngrid
, width , pitch + wwidth
, yMin , yMin
, yMax , yMax
) )
vertical = Vertical.create( component.getNet() vertical = Vertical.create( component.getNet()
, component.getLayer() , component.getLayer()
, xAxis , xOngrid
, pitch + wwidth , pitch + wwidth
, yMin + (vMargin-1) * ppitch , yMin + ppitch
, yMax , yMax
) )
NetExternalComponents.setExternal( vertical ) NetExternalComponents.setExternal( vertical )
macroCell.setAbutmentBox( outerAb ) self.cell.setAbutmentBox( self.outerAb )

View File

@ -183,8 +183,9 @@ namespace {
TrackElement* parallel; TrackElement* parallel;
for( Segment* osegment : rp->getSlaveComponents().getSubSet<Segment*>() ) { for( Segment* osegment : rp->getSlaveComponents().getSubSet<Segment*>() ) {
parallel = Session::lookup( osegment ); 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->isFixed ()) continue;
if (parallel->isGlobal()) continue; if (parallel->isGlobal()) continue;
getPerpandiculars( parallel, source, direction, perpandiculars ); getPerpandiculars( parallel, source, direction, perpandiculars );