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 )
{
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;
}
}

View File

@ -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

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 )
{
Box ab = _anabatic->getCell()->getAbutmentBox();

View File

@ -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(); }

View File

@ -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 )

View File

@ -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

View File

@ -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 )

View File

@ -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 );