2013-12-03 18:58:58 -06:00
|
|
|
// -*- C++ -*-
|
|
|
|
//
|
|
|
|
// This file is part of the Coriolis Software.
|
Support of RoutingGauge, part 2.
In Katabatic & Kite, remove all hard-coded values related to track pitches.
* New: In <Session>, add more convenience function to access RoutingGauge
characteristics.
* New: In <AutoSegment>, <AutoContact>, add support for the "depth spin",
that is, if the source/target contacts are going "top" or "down".
Used to compute the perpandicular pitch. Need a small modification
of the revalidation mechanism. The observers of <AutoSegment> are
notified when the spin changes.
* New: In <AutoSegment>, the getPPitch() method allow to compute the
"perpandicular pitch". For now it is simply the greatest from the
source perpandicular pitch and the target perpandicular pitch.
Make uses of the "depth spin".
* New: In <TrackElement>, <TrackSegment>, cache the perpandicular pitch.
Updated through the notification from the observable.
2014-05-19 10:58:38 -05:00
|
|
|
// Copyright (c) UPMC 2012-2014, All Rights Reserved
|
2013-12-03 18:58:58 -06:00
|
|
|
//
|
|
|
|
// +-----------------------------------------------------------------+
|
|
|
|
// | C O R I O L I S |
|
|
|
|
// | K a t a b a t i c - Routing Toolbox |
|
|
|
|
// | |
|
|
|
|
// | Author : Jean-Paul CHAPUT |
|
|
|
|
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
|
|
|
// | =============================================================== |
|
|
|
|
// | C++ Module : "./AutoContactTerminal.cpp" |
|
|
|
|
// +-----------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <climits>
|
|
|
|
#include <sstream>
|
|
|
|
#include "hurricane/Bug.h"
|
|
|
|
#include "hurricane/Error.h"
|
|
|
|
#include "hurricane/Warning.h"
|
|
|
|
#include "hurricane/Layer.h"
|
|
|
|
#include "hurricane/ViaLayer.h"
|
|
|
|
#include "hurricane/BasicLayer.h"
|
|
|
|
#include "hurricane/Technology.h"
|
|
|
|
#include "hurricane/Net.h"
|
|
|
|
#include "hurricane/Plug.h"
|
|
|
|
#include "hurricane/RoutingPad.h"
|
|
|
|
#include "hurricane/Vertical.h"
|
|
|
|
#include "hurricane/Horizontal.h"
|
|
|
|
#include "hurricane/DebugSession.h"
|
|
|
|
#include "crlcore/RoutingGauge.h"
|
|
|
|
#include "katabatic/AutoContactTerminal.h"
|
|
|
|
#include "katabatic/AutoContactTurn.h"
|
|
|
|
#include "katabatic/AutoVertical.h"
|
|
|
|
#include "katabatic/AutoHorizontal.h"
|
|
|
|
#include "katabatic/Session.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace Katabatic {
|
|
|
|
|
|
|
|
using std::ostringstream;
|
|
|
|
using Hurricane::Bug;
|
|
|
|
using Hurricane::Error;
|
|
|
|
using Hurricane::DebugSession;
|
|
|
|
using Hurricane::ltracein;
|
|
|
|
using Hurricane::ltraceout;
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
// Class : "Katabatic::AutoContactTerminal".
|
|
|
|
|
|
|
|
|
|
|
|
AutoContactTerminal* AutoContactTerminal::create ( GCell* gcell
|
|
|
|
, Component* anchor
|
|
|
|
, const Layer* layer
|
|
|
|
, Point point
|
|
|
|
, DbU::Unit width
|
|
|
|
, DbU::Unit height
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ltrace(90) << "AutoContactTerminal::create(... Point ...)" << endl;
|
|
|
|
ltracein(90);
|
|
|
|
ltrace(90) << "@" << point << endl;
|
|
|
|
|
|
|
|
anchor->getBodyHook()->detach();
|
|
|
|
|
|
|
|
AutoContactTerminal* autoContact = AutoContactTerminal::create( gcell
|
|
|
|
, anchor
|
|
|
|
, layer
|
|
|
|
, point.getX(), point.getY()
|
|
|
|
, width, height
|
|
|
|
);
|
|
|
|
ltraceout(90);
|
|
|
|
return autoContact;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoContactTerminal* AutoContactTerminal::create ( GCell* gcell
|
|
|
|
, Component* anchor
|
|
|
|
, const Layer* layer
|
|
|
|
, const DbU::Unit x
|
|
|
|
, const DbU::Unit y
|
|
|
|
, const DbU::Unit width
|
|
|
|
, const DbU::Unit height
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ltrace(90) << "AutoContactTerminal::create(... x, y ...)" << endl;
|
|
|
|
ltrace(90) << "@ x:" << DbU::getValueString(x) << " y:" << DbU::getValueString(y) << endl;
|
|
|
|
|
|
|
|
Point anchorPosition = anchor->getPosition();
|
|
|
|
|
|
|
|
Contact* contact = Contact::create( anchor
|
|
|
|
, layer
|
|
|
|
, x - anchorPosition.getX()
|
|
|
|
, y - anchorPosition.getY()
|
|
|
|
, width
|
|
|
|
, height
|
|
|
|
);
|
|
|
|
AutoContactTerminal* autoContact = new AutoContactTerminal( gcell, contact );
|
|
|
|
|
|
|
|
autoContact->_postCreate();
|
|
|
|
autoContact->unsetFlags( CntInCreationStage );
|
|
|
|
|
|
|
|
ltrace(90) << "create(Component*) " << autoContact << endl;
|
|
|
|
return autoContact;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoContactTerminal::AutoContactTerminal ( GCell* gcell, Contact* contact )
|
|
|
|
: AutoContact(gcell,contact)
|
|
|
|
, _segment (NULL)
|
|
|
|
{
|
|
|
|
setFlags( CntTerminal );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoContactTerminal::~AutoContactTerminal ()
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment* AutoContactTerminal::getOpposite ( const AutoSegment* ) const
|
|
|
|
{ return NULL; }
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment* AutoContactTerminal::getSegment ( unsigned int index ) const
|
|
|
|
{
|
|
|
|
if (_segment) {
|
|
|
|
switch ( index ) {
|
|
|
|
case 0: return (_segment->isHorizontal()) ? _segment : NULL;
|
|
|
|
case 2: return (_segment->isVertical ()) ? _segment : NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Box AutoContactTerminal::getNativeConstraintBox () const
|
|
|
|
{
|
|
|
|
Component* component = getAnchor();
|
|
|
|
if (component == NULL) {
|
|
|
|
cerr << Error( "%s is not anchored.", getString(this).c_str() ) << endl;
|
|
|
|
return _gcell->getBoundingBox ();
|
|
|
|
}
|
|
|
|
|
|
|
|
DbU::Unit xMin;
|
|
|
|
DbU::Unit xMax;
|
|
|
|
DbU::Unit yMin;
|
|
|
|
DbU::Unit yMax;
|
|
|
|
Vertical* vertical;
|
|
|
|
Horizontal* horizontal;
|
|
|
|
RoutingPad* routingPad;
|
|
|
|
|
|
|
|
if ( (horizontal = dynamic_cast<Horizontal*>(component)) ) {
|
|
|
|
xMin = horizontal->getSourcePosition().getX();
|
|
|
|
xMax = horizontal->getTargetPosition().getX();
|
|
|
|
yMin = yMax
|
|
|
|
= horizontal->getTargetPosition().getY();
|
|
|
|
} else if ( (vertical = dynamic_cast<Vertical*>(component)) ) {
|
|
|
|
yMin = vertical->getSourcePosition().getY();
|
|
|
|
yMax = vertical->getTargetPosition().getY();
|
|
|
|
xMin = xMax
|
|
|
|
= vertical->getTargetPosition().getX();
|
|
|
|
} else if ( (routingPad = dynamic_cast<RoutingPad*>(component)) ) {
|
|
|
|
Entity* entity = routingPad->getOccurrence().getEntity();
|
|
|
|
|
|
|
|
// Assumes there is no rotation in the Transformation.
|
|
|
|
if ( dynamic_cast<Horizontal*>(entity) ) {
|
|
|
|
xMin = routingPad->getSourcePosition().getX();
|
|
|
|
xMax = routingPad->getTargetPosition().getX();
|
|
|
|
yMin = yMax
|
|
|
|
= routingPad->getTargetPosition().getY();
|
|
|
|
} else if ( dynamic_cast<Vertical*>(entity) ) {
|
|
|
|
yMin = routingPad->getSourcePosition().getY();
|
|
|
|
yMax = routingPad->getTargetPosition().getY();
|
|
|
|
xMin = xMax
|
|
|
|
= routingPad->getTargetPosition().getX();
|
|
|
|
} else {
|
|
|
|
xMin = xMax = routingPad->getPosition().getX();
|
|
|
|
yMin = yMax = routingPad->getPosition().getY();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
xMin = xMax = component->getPosition().getX();
|
|
|
|
yMin = yMax = component->getPosition().getY();
|
|
|
|
}
|
|
|
|
|
|
|
|
order( xMin, xMax );
|
|
|
|
order( yMin, yMax );
|
|
|
|
|
|
|
|
return Box( xMin, yMin, xMax, yMax );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContactTerminal::_invalidate ( unsigned int flags )
|
|
|
|
{
|
|
|
|
if (_segment) _segment->invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContactTerminal::cacheDetach ( AutoSegment* segment )
|
|
|
|
{
|
|
|
|
if (_segment == segment) {
|
|
|
|
_segment = NULL;
|
|
|
|
setFlags( CntInvalidatedCache );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContactTerminal::cacheAttach ( AutoSegment* segment )
|
|
|
|
{
|
|
|
|
if (_segment) {
|
|
|
|
cerr << Bug( "%s::cacheAttach() On %s,\n"
|
|
|
|
" cache has not been cleared first, cancelled."
|
|
|
|
, _getTypeName().c_str(), getString(this).c_str()
|
|
|
|
) << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_segment = segment;
|
|
|
|
unsetFlags( CntInvalidatedCache );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContactTerminal::updateCache ()
|
|
|
|
{
|
|
|
|
DebugSession::open( getNet(), 80 );
|
|
|
|
|
|
|
|
ltrace(110) << _getTypeName() << "::updateCache() " << this << endl;
|
|
|
|
ltracein(110);
|
|
|
|
|
|
|
|
Component* anchor;
|
|
|
|
Horizontal** horizontals = new Horizontal* [2];
|
|
|
|
Vertical** verticals = new Vertical* [2];
|
|
|
|
|
|
|
|
_getTopology( anchor, horizontals, verticals, 2 );
|
|
|
|
|
|
|
|
if (anchor == NULL)
|
|
|
|
showTopologyError( "Terminal is missing an anchor (RoutingPad or Component)." );
|
|
|
|
|
|
|
|
size_t count = 0;
|
|
|
|
if (horizontals[0] != NULL) ++count;
|
|
|
|
if (horizontals[1] != NULL) ++count;
|
|
|
|
if (verticals [0] != NULL) ++count;
|
|
|
|
if (verticals [1] != NULL) ++count;
|
|
|
|
if (count > 1) {
|
|
|
|
showTopologyError( "Terminal has more than one segment." );
|
|
|
|
}
|
|
|
|
if (horizontals[0] != NULL ) {
|
|
|
|
_segment = Session::lookup( horizontals[0] );
|
|
|
|
} else {
|
|
|
|
_segment = Session::lookup( verticals[0] );
|
|
|
|
}
|
|
|
|
if (_segment == NULL) {
|
|
|
|
ostringstream os;
|
|
|
|
os << this << ", AutoSegment lookup failed for:"
|
|
|
|
<< "\n h1: " << horizontals[0]
|
|
|
|
<< "\n v1: " << verticals[0];
|
|
|
|
|
|
|
|
delete [] horizontals;
|
|
|
|
delete [] verticals;
|
|
|
|
|
|
|
|
showTopologyError( os.str() );
|
|
|
|
throw Error( os.str() );
|
|
|
|
}
|
|
|
|
unsetFlags( CntInvalidatedCache );
|
|
|
|
ltrace(110) << "seg:" << _segment << endl;
|
|
|
|
|
|
|
|
delete [] horizontals;
|
|
|
|
delete [] verticals;
|
|
|
|
|
|
|
|
ltraceout(110);
|
|
|
|
DebugSession::close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContactTerminal::updateGeometry ()
|
|
|
|
{
|
|
|
|
DebugSession::open( getNet(), 80 );
|
|
|
|
|
|
|
|
ltrace(110) << _getTypeName() << "::updateGeometry() " << this << endl;
|
|
|
|
ltracein(110);
|
|
|
|
|
|
|
|
if (isInvalidatedCache()) updateCache();
|
|
|
|
if (isInvalidatedCache()) {
|
|
|
|
cerr << Error( "%s::updateGeometry() %s: Unable to restore cache."
|
|
|
|
, _getTypeName().c_str(), getString(this).c_str() ) << endl;
|
|
|
|
ltraceout(110);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
base()->invalidate( false );
|
|
|
|
unsetFlags( CntInvalidated );
|
|
|
|
|
|
|
|
ostringstream message;
|
|
|
|
if (not hasBadTopology()) {
|
|
|
|
if (_segment->isHorizontal()) {
|
|
|
|
if (not getUConstraints(KbVertical).contains(_segment->getY())) {
|
|
|
|
ltrace(110) << "Cached: " << _segment << endl;
|
|
|
|
message << "Terminal horizontal segment Y " << DbU::getValueString(_segment->getY())
|
|
|
|
<< " axis is outside RoutingPad " << getUConstraints(KbVertical) << ".";
|
ExtensionCap support and source/target terminal flags in Katabatic & Kite.
Placement management:
* Change: In <metis>, always disable the hMetis support regardless of
it being detected or not as the placer is still unable manage the
final bin contents.
Routing gauge management:
* Bug: In CRL Core, <vsclib/alliance.conf>, set the correct pitches and
size for the routing layers and the cell gauge.
* Change: In Katabatic & Kite, extract the correct extension cap for each
routing layer from the layers characteristics (cache then in
Katabatic::Configuration).
* Change: In Katabatic, <AutoSegment>, create segment with the wire width
defined in the gauge. For AutoSegment created on already existing
Segment from the global routing, adjust the width.
* Change: In Katabatic, <AutoSegment>, more accurate information about how
a segment is connected to terminal via source and/or target.
The flag SegStrongTerminal is splitted into SegSourceTerminal and
SegSourceTarget (but still used as a mask). So now we can know by
which end an AutoSegment is connected to a terminal.
* Change: In Katabatic, ::doRp_Access(), create constraint freeing segments
not only when HSmall but also when VSmall (more critical for <vsclib>).
Otherwise we may see AutoSegments with incompatible source/target
constraints.
* Change: In Kite, BuildPowerRails, do not create blockage on PinOnly
layers *but* still create power rails planes. This is a temporary
workaround for <vsclib> where the METAL1 blockages overlaps the
terminals (it was fine for Nero, but they shouldn't for Kite).
* Change: In Kite, <RoutingEvent>, if a TrackSegment is overconstrained,
directly bybass it's slackening state to DataNegociate::Slacken.
Also rename the flag "_canHandleConstraints" to "_overConstrained",
seems clearer to me.
Miscellaneous:
* Change: In CRL Core, <Utilities>, add a "pass-though" capability on the
mstream to temporarily make them print everything.
2014-05-25 08:00:35 -05:00
|
|
|
|
|
|
|
unsigned int flags = 0;
|
|
|
|
if (_segment->isCreated()) flags |= KbCParanoid;
|
|
|
|
showTopologyError( message.str(), flags );
|
2013-12-03 18:58:58 -06:00
|
|
|
} else
|
|
|
|
setY( _segment->getY() );
|
|
|
|
} else {
|
|
|
|
if (not getUConstraints(KbHorizontal).contains(_segment->getX())) {
|
|
|
|
ltrace(110) << "Cached: " << _segment << endl;
|
|
|
|
message << "Terminal vertical segment X" << DbU::getValueString(_segment->getX())
|
|
|
|
<< " axis is outside RoutingPad " << getUConstraints(KbHorizontal) << ".";
|
ExtensionCap support and source/target terminal flags in Katabatic & Kite.
Placement management:
* Change: In <metis>, always disable the hMetis support regardless of
it being detected or not as the placer is still unable manage the
final bin contents.
Routing gauge management:
* Bug: In CRL Core, <vsclib/alliance.conf>, set the correct pitches and
size for the routing layers and the cell gauge.
* Change: In Katabatic & Kite, extract the correct extension cap for each
routing layer from the layers characteristics (cache then in
Katabatic::Configuration).
* Change: In Katabatic, <AutoSegment>, create segment with the wire width
defined in the gauge. For AutoSegment created on already existing
Segment from the global routing, adjust the width.
* Change: In Katabatic, <AutoSegment>, more accurate information about how
a segment is connected to terminal via source and/or target.
The flag SegStrongTerminal is splitted into SegSourceTerminal and
SegSourceTarget (but still used as a mask). So now we can know by
which end an AutoSegment is connected to a terminal.
* Change: In Katabatic, ::doRp_Access(), create constraint freeing segments
not only when HSmall but also when VSmall (more critical for <vsclib>).
Otherwise we may see AutoSegments with incompatible source/target
constraints.
* Change: In Kite, BuildPowerRails, do not create blockage on PinOnly
layers *but* still create power rails planes. This is a temporary
workaround for <vsclib> where the METAL1 blockages overlaps the
terminals (it was fine for Nero, but they shouldn't for Kite).
* Change: In Kite, <RoutingEvent>, if a TrackSegment is overconstrained,
directly bybass it's slackening state to DataNegociate::Slacken.
Also rename the flag "_canHandleConstraints" to "_overConstrained",
seems clearer to me.
Miscellaneous:
* Change: In CRL Core, <Utilities>, add a "pass-though" capability on the
mstream to temporarily make them print everything.
2014-05-25 08:00:35 -05:00
|
|
|
|
|
|
|
unsigned int flags = 0;
|
|
|
|
if (_segment->isCreated()) flags |= KbCParanoid;
|
|
|
|
showTopologyError( message.str(), flags );
|
2013-12-03 18:58:58 -06:00
|
|
|
} else
|
|
|
|
setX( _segment->getX() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ltraceout(110);
|
|
|
|
DebugSession::close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContactTerminal::updateTopology ()
|
|
|
|
{
|
|
|
|
DebugSession::open( getNet(), 80 );
|
|
|
|
|
|
|
|
ltrace(110) << _getTypeName() << "::updateTopology() " << this << endl;
|
|
|
|
ltracein(110);
|
|
|
|
|
|
|
|
if (isInvalidatedCache()) updateCache();
|
|
|
|
if (isInvalidatedCache()) {
|
|
|
|
cerr << Error( "%s::updateGeometry() %s: Unable to restore cache."
|
|
|
|
, _getTypeName().c_str(), getString(this).c_str() ) << endl;
|
|
|
|
ltraceout(110);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RoutingGauge* rg = Session::getRoutingGauge();
|
|
|
|
size_t anchorDepth = rg->getLayerDepth( (_flags & CntIgnoreAnchor) ? getLayer()
|
|
|
|
: getAnchor()->getLayer() );
|
|
|
|
size_t segmentDepth = rg->getLayerDepth( _segment->getLayer() );
|
|
|
|
size_t delta = abssub( anchorDepth, segmentDepth );
|
|
|
|
|
|
|
|
if (delta > 3) {
|
|
|
|
showTopologyError( "Sheared Terminal, layer delta exceed 3." );
|
|
|
|
setFlags( CntBadTopology );
|
|
|
|
} else {
|
|
|
|
if (delta > 1) {
|
|
|
|
//_segment = _segment->makeDogleg( this );
|
|
|
|
_segment->makeDogleg( this );
|
|
|
|
ltrace(110) << "Update seg: " << _segment << endl;
|
|
|
|
delta = abssub( anchorDepth, rg->getLayerDepth( _segment->getLayer() ) );
|
|
|
|
}
|
|
|
|
else if (delta == 0) setLayer( rg->getRoutingLayer(anchorDepth) );
|
|
|
|
else if (delta == 1) setLayer( rg->getContactLayer(std::min(anchorDepth,segmentDepth)) );
|
|
|
|
}
|
Support of RoutingGauge, part 2.
In Katabatic & Kite, remove all hard-coded values related to track pitches.
* New: In <Session>, add more convenience function to access RoutingGauge
characteristics.
* New: In <AutoSegment>, <AutoContact>, add support for the "depth spin",
that is, if the source/target contacts are going "top" or "down".
Used to compute the perpandicular pitch. Need a small modification
of the revalidation mechanism. The observers of <AutoSegment> are
notified when the spin changes.
* New: In <AutoSegment>, the getPPitch() method allow to compute the
"perpandicular pitch". For now it is simply the greatest from the
source perpandicular pitch and the target perpandicular pitch.
Make uses of the "depth spin".
* New: In <TrackElement>, <TrackSegment>, cache the perpandicular pitch.
Updated through the notification from the observable.
2014-05-19 10:58:38 -05:00
|
|
|
_segment->invalidate( this );
|
2013-12-03 18:58:58 -06:00
|
|
|
|
|
|
|
ltraceout(110);
|
|
|
|
DebugSession::close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string AutoContactTerminal::_getTypeName () const
|
|
|
|
{ return "ContactTerminal"; }
|
|
|
|
|
|
|
|
|
|
|
|
} // Katabatic namespace.
|