2016-07-18 07:48:37 -05:00
|
|
|
// -*- C++ -*-
|
|
|
|
//
|
|
|
|
// This file is part of the Coriolis Software.
|
|
|
|
// Copyright (c) UPMC 2008-2016, All Rights Reserved
|
|
|
|
//
|
|
|
|
// +-----------------------------------------------------------------+
|
|
|
|
// | C O R I O L I S |
|
|
|
|
// | A n a b a t i c - Routing Toolbox |
|
|
|
|
// | |
|
|
|
|
// | Author : Jean-Paul CHAPUT |
|
|
|
|
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
|
|
|
// | =============================================================== |
|
|
|
|
// | C++ Module : "./AutoContact.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 "anabatic/AutoContact.h"
|
|
|
|
#include "anabatic/AutoContactTerminal.h"
|
|
|
|
#include "anabatic/AutoContactTurn.h"
|
|
|
|
#include "anabatic/AutoContactHTee.h"
|
|
|
|
#include "anabatic/AutoContactVTee.h"
|
|
|
|
#include "anabatic/AutoVertical.h"
|
|
|
|
#include "anabatic/AutoHorizontal.h"
|
|
|
|
#include "anabatic/AnabaticEngine.h"
|
|
|
|
#include "anabatic/Session.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace Anabatic {
|
|
|
|
|
|
|
|
using std::ostringstream;
|
|
|
|
using Hurricane::Bug;
|
|
|
|
using Hurricane::Error;
|
|
|
|
using Hurricane::Warning;
|
|
|
|
using Hurricane::DebugSession;
|
|
|
|
using Hurricane::ForEachIterator;
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
// Class : "Anabatic::AutoContact".
|
|
|
|
|
|
|
|
|
|
|
|
size_t AutoContact::_maxId = 0;
|
|
|
|
size_t AutoContact::_allocateds = 0;
|
|
|
|
const Name AutoContact::_goName = "Anabatic::AutoContact";
|
|
|
|
|
|
|
|
|
|
|
|
AutoContact::AutoContact ( GCell* gcell, Contact* contact )
|
|
|
|
: _id (contact->getId())
|
|
|
|
, _contact (contact)
|
|
|
|
, _gcell (gcell)
|
|
|
|
, _flags (CntInvalidatedCache|CntInCreationStage)
|
2016-09-22 07:16:53 -05:00
|
|
|
, _xMin (_gcell->getXMin())
|
|
|
|
, _xMax (_gcell->getConstraintXMax())
|
|
|
|
, _yMin (_gcell->getYMin())
|
|
|
|
, _yMax (_gcell->getConstraintYMax())
|
2016-07-18 07:48:37 -05:00
|
|
|
{
|
|
|
|
_allocateds++;
|
|
|
|
_gcell->addContact ( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::_preCreate ( GCell* gcell, Net* net, const Layer* layer )
|
|
|
|
{
|
|
|
|
if (not gcell) throw Error("AutoContact::_preCreate(): GCell* parameter must not be NULL.");
|
|
|
|
if (not net ) throw Error("AutoContact::_preCreate(): Net* parameter must not be NULL.");
|
|
|
|
if (not layer) throw Error("AutoContact::_preCreate(): const Layer* parameter must not be NULL.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::_postCreate ()
|
|
|
|
{
|
|
|
|
restoreNativeConstraintBox();
|
|
|
|
|
|
|
|
cdebug_log(145,0) << "Native CBox: " << this
|
|
|
|
<< " <" << DbU::toLambda(getCBXMin())
|
|
|
|
<< " " << DbU::toLambda(getCBYMin())
|
|
|
|
<< " " << DbU::toLambda(getCBXMax())
|
|
|
|
<< " " << DbU::toLambda(getCBYMax()) << ">" << endl;
|
|
|
|
|
|
|
|
Session::link( this );
|
|
|
|
invalidate( Flags::Topology );
|
|
|
|
|
|
|
|
cdebug_log(145,0) << "AutoContact::_postCreate() - " << this << " in " << _gcell << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::destroy ()
|
|
|
|
{
|
|
|
|
_preDestroy ();
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::_preDestroy ()
|
|
|
|
{
|
|
|
|
DebugSession::open( _contact->getNet(), 140, 150 );
|
|
|
|
|
|
|
|
cdebug_log(145,0) << "AutoContact::_preDestroy() - <AutoContact id:" << _id << ">" << endl;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
bool canDestroyBase = true;
|
|
|
|
|
|
|
|
if (not _contact->getSlaveComponents().isEmpty()) {
|
|
|
|
ostringstream message;
|
|
|
|
message << "Base contact still have slaves components, cancelled.\n"
|
|
|
|
<< " on: " << this;
|
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
for ( Component* component : _contact->getSlaveComponents() ) {
|
|
|
|
message << "\n | " << component;
|
2016-07-18 07:48:37 -05:00
|
|
|
}
|
|
|
|
cerr << Error( message.str() ) << endl;
|
|
|
|
|
|
|
|
canDestroyBase = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (not Session::doDestroyTool()) {
|
|
|
|
_gcell->removeContact( this );
|
|
|
|
Session::unlink( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (Session::doDestroyBaseContact() and canDestroyBase)
|
|
|
|
_contact->destroy();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DebugSession::close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoContact::~AutoContact ()
|
|
|
|
{ _allocateds--; }
|
|
|
|
|
|
|
|
|
|
|
|
size_t AutoContact::getAllocateds ()
|
|
|
|
{ return _allocateds; }
|
|
|
|
|
|
|
|
|
|
|
|
const Name& AutoContact::getStaticName ()
|
|
|
|
{ return _goName; }
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoContact::canDestroy ( unsigned int flags ) const
|
|
|
|
{
|
|
|
|
if (not _contact->getSlaveComponents().isEmpty()) {
|
|
|
|
if (flags & Flags::WarnOnError) {
|
|
|
|
cerr << Error("Base contact still have slaves components, cancelled.\n"
|
|
|
|
" (%s)"
|
|
|
|
,_getString().c_str()) << endl;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const Name& AutoContact::getName () const
|
|
|
|
{ return _goName; }
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegments AutoContact::getAutoSegments ()
|
|
|
|
{ return new AutoSegments_CachedOnContact(this); }
|
|
|
|
|
|
|
|
|
|
|
|
AutoSegment* AutoContact::getPerpandicular ( const AutoSegment* ) const
|
|
|
|
{ return NULL; }
|
|
|
|
|
|
|
|
|
Forgot to perform Track re-order after removing zero-length segments.
* Change: In Anabatic::Autocontact, replace getMinDepth() and
getMaxDepth() by getDepthSpan().
* New: In Anabatic::AutoSegment::canMoveUp(), add an optional check of
low up density (Flags::CheckLowUpDensity). Allows to move up a
segment if the up density is (very) low, and in this case it's more
efficient than breaking it to fit in the lower layer.
canMoveUp() is now able to perform the same work as canPivotUp()
if *not* supplied the flag Flags::IgnoreContacts.
* New: In Katana, in GlobalRouting::DigitalDistance() now take into
account the cost of a VIA (currently set to 2.5). Need to known the
Net currently routed in the DigitalDistance object itself.
* Change: In Katana::Track::Element::canPivotUp(), now also takes a flag
parameter.
* Change: In Katana::Manipulator, new flag IgnoreContacts to mirror the
one of Anabatic.
* Change: In Katana::SegmentFsm, allocate once a Manipulator object instead
of many times on the fly.
In SegmentFsm::_slackenGlobal(), in the slacken state, if the up
density is (very) low, bypass to move up instead of slackening.
This solve better the routing of the control part of the register file.
The register file having a pathological case of terminal placement:
many punctual terminals aligneds in METAL2 *and* a grid of METAL2 and
METAL3 blockages near below...
* Bug: In Katana::Session::_revalidate(), after removing the zero-length
segments, forgot to re-order the track, leading to many stranges effects
as the indexes where no longer coherent in the Track.
2016-09-20 04:30:45 -05:00
|
|
|
void AutoContact::getDepthSpan ( size_t& minDepth, size_t& maxDepth ) const
|
2016-07-18 07:48:37 -05:00
|
|
|
{
|
Forgot to perform Track re-order after removing zero-length segments.
* Change: In Anabatic::Autocontact, replace getMinDepth() and
getMaxDepth() by getDepthSpan().
* New: In Anabatic::AutoSegment::canMoveUp(), add an optional check of
low up density (Flags::CheckLowUpDensity). Allows to move up a
segment if the up density is (very) low, and in this case it's more
efficient than breaking it to fit in the lower layer.
canMoveUp() is now able to perform the same work as canPivotUp()
if *not* supplied the flag Flags::IgnoreContacts.
* New: In Katana, in GlobalRouting::DigitalDistance() now take into
account the cost of a VIA (currently set to 2.5). Need to known the
Net currently routed in the DigitalDistance object itself.
* Change: In Katana::Track::Element::canPivotUp(), now also takes a flag
parameter.
* Change: In Katana::Manipulator, new flag IgnoreContacts to mirror the
one of Anabatic.
* Change: In Katana::SegmentFsm, allocate once a Manipulator object instead
of many times on the fly.
In SegmentFsm::_slackenGlobal(), in the slacken state, if the up
density is (very) low, bypass to move up instead of slackening.
This solve better the routing of the control part of the register file.
The register file having a pathological case of terminal placement:
many punctual terminals aligneds in METAL2 *and* a grid of METAL2 and
METAL3 blockages near below...
* Bug: In Katana::Session::_revalidate(), after removing the zero-length
segments, forgot to re-order the track, leading to many stranges effects
as the indexes where no longer coherent in the Track.
2016-09-20 04:30:45 -05:00
|
|
|
minDepth = (size_t)-1;
|
|
|
|
maxDepth = 0;
|
|
|
|
|
2016-07-18 07:48:37 -05:00
|
|
|
Component* anchor = getAnchor ();
|
|
|
|
if (anchor) {
|
|
|
|
minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) );
|
Forgot to perform Track re-order after removing zero-length segments.
* Change: In Anabatic::Autocontact, replace getMinDepth() and
getMaxDepth() by getDepthSpan().
* New: In Anabatic::AutoSegment::canMoveUp(), add an optional check of
low up density (Flags::CheckLowUpDensity). Allows to move up a
segment if the up density is (very) low, and in this case it's more
efficient than breaking it to fit in the lower layer.
canMoveUp() is now able to perform the same work as canPivotUp()
if *not* supplied the flag Flags::IgnoreContacts.
* New: In Katana, in GlobalRouting::DigitalDistance() now take into
account the cost of a VIA (currently set to 2.5). Need to known the
Net currently routed in the DigitalDistance object itself.
* Change: In Katana::Track::Element::canPivotUp(), now also takes a flag
parameter.
* Change: In Katana::Manipulator, new flag IgnoreContacts to mirror the
one of Anabatic.
* Change: In Katana::SegmentFsm, allocate once a Manipulator object instead
of many times on the fly.
In SegmentFsm::_slackenGlobal(), in the slacken state, if the up
density is (very) low, bypass to move up instead of slackening.
This solve better the routing of the control part of the register file.
The register file having a pathological case of terminal placement:
many punctual terminals aligneds in METAL2 *and* a grid of METAL2 and
METAL3 blockages near below...
* Bug: In Katana::Session::_revalidate(), after removing the zero-length
segments, forgot to re-order the track, leading to many stranges effects
as the indexes where no longer coherent in the Track.
2016-09-20 04:30:45 -05:00
|
|
|
maxDepth = std::max( maxDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) );
|
2016-07-18 07:48:37 -05:00
|
|
|
}
|
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
for ( AutoSegment* segment : const_cast<AutoContact*>(this)->getAutoSegments() ) {
|
|
|
|
minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) );
|
Forgot to perform Track re-order after removing zero-length segments.
* Change: In Anabatic::Autocontact, replace getMinDepth() and
getMaxDepth() by getDepthSpan().
* New: In Anabatic::AutoSegment::canMoveUp(), add an optional check of
low up density (Flags::CheckLowUpDensity). Allows to move up a
segment if the up density is (very) low, and in this case it's more
efficient than breaking it to fit in the lower layer.
canMoveUp() is now able to perform the same work as canPivotUp()
if *not* supplied the flag Flags::IgnoreContacts.
* New: In Katana, in GlobalRouting::DigitalDistance() now take into
account the cost of a VIA (currently set to 2.5). Need to known the
Net currently routed in the DigitalDistance object itself.
* Change: In Katana::Track::Element::canPivotUp(), now also takes a flag
parameter.
* Change: In Katana::Manipulator, new flag IgnoreContacts to mirror the
one of Anabatic.
* Change: In Katana::SegmentFsm, allocate once a Manipulator object instead
of many times on the fly.
In SegmentFsm::_slackenGlobal(), in the slacken state, if the up
density is (very) low, bypass to move up instead of slackening.
This solve better the routing of the control part of the register file.
The register file having a pathological case of terminal placement:
many punctual terminals aligneds in METAL2 *and* a grid of METAL2 and
METAL3 blockages near below...
* Bug: In Katana::Session::_revalidate(), after removing the zero-length
segments, forgot to re-order the track, leading to many stranges effects
as the indexes where no longer coherent in the Track.
2016-09-20 04:30:45 -05:00
|
|
|
maxDepth = std::max( maxDepth, Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) );
|
2016-07-18 07:48:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::getLengths ( DbU::Unit* lengths, AutoSegment::DepthLengthSet& processeds )
|
|
|
|
{
|
|
|
|
DbU::Unit hSideLength = getGCell()->getSide( Flags::Horizontal ).getSize();
|
|
|
|
DbU::Unit vSideLength = getGCell()->getSide( Flags::Vertical ).getSize();
|
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
for ( AutoSegment* segment : getAutoSegments() ) {
|
|
|
|
bool isSourceHook = (segment->getAutoSource() == this);
|
2016-07-18 07:48:37 -05:00
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
if (processeds.find(segment) != processeds.end()) continue;
|
|
|
|
processeds.insert( segment );
|
2016-07-18 07:48:37 -05:00
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
size_t depth = Session::getRoutingGauge()->getLayerDepth(segment->getLayer());
|
2016-07-18 07:48:37 -05:00
|
|
|
DbU::Unit length;
|
2016-07-30 05:15:49 -05:00
|
|
|
if (segment->isLocal()) {
|
|
|
|
length = segment->getLength();
|
2016-07-18 07:48:37 -05:00
|
|
|
lengths[depth] += length;
|
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
DbU::Unit sideLength = (segment->isHorizontal()) ? hSideLength : vSideLength;
|
|
|
|
if ( not segment->isUnbound() and (abs(length) > sideLength) )
|
2016-07-18 07:48:37 -05:00
|
|
|
cerr << Error("Suspicious length:%.2f of %s."
|
2016-07-30 05:15:49 -05:00
|
|
|
,DbU::toLambda(length),getString(segment).c_str()) << endl;
|
2016-07-18 07:48:37 -05:00
|
|
|
} else {
|
2016-07-30 05:15:49 -05:00
|
|
|
if (segment->isHorizontal()) {
|
2016-07-18 07:48:37 -05:00
|
|
|
if (isSourceHook)
|
2016-07-30 05:15:49 -05:00
|
|
|
lengths[depth] += _gcell->getXMax() - segment->getSourceX();
|
2016-07-18 07:48:37 -05:00
|
|
|
else
|
2016-07-30 05:15:49 -05:00
|
|
|
lengths[depth] += segment->getTargetX() - _gcell->getXMin();
|
2016-07-18 07:48:37 -05:00
|
|
|
} else {
|
|
|
|
if (isSourceHook)
|
2016-07-30 05:15:49 -05:00
|
|
|
lengths[depth] += _gcell->getYMax() - segment->getSourceY();
|
2016-07-18 07:48:37 -05:00
|
|
|
else
|
2016-07-30 05:15:49 -05:00
|
|
|
lengths[depth] += segment->getTargetY() - _gcell->getYMin();
|
2016-07-18 07:48:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Box AutoContact::getNativeConstraintBox () const
|
|
|
|
{
|
|
|
|
if (isUserNativeConstraints()) return getConstraintBox();
|
|
|
|
if (isFixed()) return Box(_contact->getPosition());
|
2016-08-27 08:59:12 -05:00
|
|
|
return _gcell->getConstraintBox();
|
2016-07-18 07:48:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Interval AutoContact::getNativeUConstraints ( unsigned int direction ) const
|
|
|
|
{
|
|
|
|
Box nativeConstraints = getNativeConstraintBox();
|
|
|
|
Interval constraint;
|
|
|
|
if (direction & Flags::Horizontal) {
|
|
|
|
constraint = Interval( nativeConstraints.getXMin(), nativeConstraints.getXMax() );
|
|
|
|
} else {
|
|
|
|
constraint = Interval( nativeConstraints.getYMin(), nativeConstraints.getYMax() );
|
|
|
|
}
|
|
|
|
//if (direction & Flags::NoGCellShrink) constraint.inflate( 0, GCell::getTopRightShrink() );
|
|
|
|
return constraint;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Interval AutoContact::getUConstraints ( unsigned int direction ) const
|
|
|
|
{
|
|
|
|
Interval constraint;
|
|
|
|
if (direction & Flags::Horizontal) {
|
|
|
|
constraint = Interval( getCBXMin(), getCBXMax() );
|
|
|
|
} else {
|
|
|
|
constraint = Interval( getCBYMin(), getCBYMax() );
|
|
|
|
}
|
|
|
|
//if (direction & Flags::NoGCellShrink) constraint.inflate( 0, GCell::getTopRightShrink() );
|
|
|
|
return constraint;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::invalidate ( unsigned int flags )
|
|
|
|
{
|
|
|
|
if (not isInvalidated()) {
|
|
|
|
cdebug_log(145,1) << "AutoContact::invalidate() - " << this << endl;
|
|
|
|
setFlags( CntInvalidated );
|
|
|
|
if (flags & Flags::Topology ) setFlags( CntInvalidatedCache );
|
|
|
|
Session::invalidate( this );
|
|
|
|
|
|
|
|
_invalidate( flags );
|
|
|
|
|
|
|
|
getGCell()->invalidate();
|
|
|
|
cdebug_tabw(145,-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::setGCell ( GCell* gcell )
|
|
|
|
{
|
|
|
|
invalidate();
|
|
|
|
if (_gcell) _gcell->removeContact( this );
|
|
|
|
|
|
|
|
_gcell = gcell;
|
|
|
|
if (_gcell) {
|
|
|
|
cdebug_log(145,0) << "AutoContact::setGCell() " << gcell << endl;
|
|
|
|
_gcell->addContact( this );
|
|
|
|
_contact->setPosition( _gcell->getCenter() );
|
2016-09-22 07:16:53 -05:00
|
|
|
_xMin = _gcell->getXMin();
|
|
|
|
_yMin = _gcell->getYMin();
|
|
|
|
_xMax = _gcell->getConstraintXMax();
|
|
|
|
_yMax = _gcell->getConstraintYMax();
|
Solve the template lookup problem in tstream.
* Bug: In Hurricane, in tstream (Commons.h), in the *template* overload of
operator<<(), do not use the operator<<() of ostream as it will be
looked up in "stage 1" (template definition) and so will miss all the
overloads added later and built over getString<>(). Instead, make use
of getString<>(), which, as another template will be looked up in
"stage 2" (template instanciation) and at that point will have all the
needed template specialisation of getString<>().
We also need to define new stream manipulators to be able to create
a matching template overload not dependant from the implementation.
To avoid name clashes, we prefix a 't'. For now, only 'tsetw()' is
refined.
As a side effect, we cannot directly print bit-fields into the stream,
we must go through an intermediate variable (happens once in AutoContact).
2016-07-19 09:02:55 -05:00
|
|
|
if (cdebug.enabled()) {
|
2016-09-22 07:16:53 -05:00
|
|
|
cdebug_log(145,0) << "* deltas: [" << DbU::getValueString(_xMin)
|
|
|
|
<< " " << DbU::getValueString(_yMin)
|
|
|
|
<< " " << DbU::getValueString(_xMax)
|
|
|
|
<< " " << DbU::getValueString(_yMax)
|
|
|
|
<< "]" << endl;
|
Solve the template lookup problem in tstream.
* Bug: In Hurricane, in tstream (Commons.h), in the *template* overload of
operator<<(), do not use the operator<<() of ostream as it will be
looked up in "stage 1" (template definition) and so will miss all the
overloads added later and built over getString<>(). Instead, make use
of getString<>(), which, as another template will be looked up in
"stage 2" (template instanciation) and at that point will have all the
needed template specialisation of getString<>().
We also need to define new stream manipulators to be able to create
a matching template overload not dependant from the implementation.
To avoid name clashes, we prefix a 't'. For now, only 'tsetw()' is
refined.
As a side effect, we cannot directly print bit-fields into the stream,
we must go through an intermediate variable (happens once in AutoContact).
2016-07-19 09:02:55 -05:00
|
|
|
}
|
2016-07-18 07:48:37 -05:00
|
|
|
} else {
|
|
|
|
cerr << Bug( "NULL GCell for %s.", _getString().c_str() ) << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::_getTopology ( Contact* support, Component*& anchor, Horizontal**& horizontals, Vertical**& verticals, size_t size )
|
|
|
|
{
|
|
|
|
size_t hcount = 0;
|
|
|
|
size_t vcount = 0;
|
|
|
|
|
|
|
|
for ( size_t i=0 ; i<size ; ++i ) {
|
|
|
|
horizontals[i] = NULL;
|
|
|
|
verticals [i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
anchor = support->getAnchor();
|
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
for ( Component* component : support->getSlaveComponents() ) {
|
|
|
|
Horizontal* h = dynamic_cast<Horizontal*>(component);
|
2016-07-18 07:48:37 -05:00
|
|
|
if (h != NULL) {
|
|
|
|
if (hcount < size) horizontals[hcount++] = h;
|
|
|
|
} else {
|
2016-07-30 05:15:49 -05:00
|
|
|
Vertical* v = dynamic_cast<Vertical*>(component);
|
2016-07-18 07:48:37 -05:00
|
|
|
if ( (v != NULL) and (vcount < size) ) verticals[vcount++] = v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::showTopologyError ( const std::string& message, unsigned int flags )
|
|
|
|
{
|
|
|
|
Component* anchor = NULL;
|
|
|
|
Horizontal** horizontals = new Horizontal* [10];
|
|
|
|
Vertical** verticals = new Vertical* [10];
|
|
|
|
|
|
|
|
if (not (flags & Flags::CParanoid)) cparanoid.setStreamMask( mstream::PassThrough );
|
|
|
|
|
|
|
|
_getTopology ( base(), anchor, horizontals, verticals, 10 );
|
|
|
|
|
|
|
|
cparanoid << Error("In topology of %s",getString(this).c_str()) << endl;
|
|
|
|
if (anchor) cparanoid << " A: " << anchor << endl;
|
|
|
|
|
|
|
|
for ( size_t i=0 ; (i<10) and (horizontals[i] != NULL); ++i ) {
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( horizontals[i] );
|
|
|
|
if (autoSegment != NULL)
|
|
|
|
cparanoid << " " << (autoSegment->isGlobal()?'G':'L') << ": " << autoSegment << endl;
|
|
|
|
else
|
|
|
|
cparanoid << " ?: " << horizontals[i] << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( size_t i=0 ; (i<10) and (verticals[i] != NULL); ++i ) {
|
|
|
|
AutoSegment* autoSegment = Session::lookup ( verticals[i] );
|
|
|
|
if (autoSegment != NULL)
|
|
|
|
cparanoid << " " << (autoSegment->isGlobal()?'G':'L') << ": " << autoSegment << endl;
|
|
|
|
else
|
|
|
|
cparanoid << " ?: " << verticals[i] << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
cparanoid << " " << message << endl;
|
|
|
|
if (not (flags & Flags::CParanoid)) cparanoid.unsetStreamMask( mstream::PassThrough );
|
|
|
|
|
|
|
|
delete [] horizontals;
|
|
|
|
delete [] verticals;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::checkTopology ()
|
|
|
|
{
|
|
|
|
//cdebug_log(145,0) << "checkTopology() NOT RE-IMPLEMENTED YET " << this << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoContact::isTee ( unsigned int direction ) const
|
|
|
|
{
|
|
|
|
return (isHTee() and (direction & Flags::Horizontal))
|
|
|
|
or (isVTee() and (direction & Flags::Vertical ));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoContact::canMoveUp ( const AutoSegment* moved ) const
|
|
|
|
{
|
|
|
|
cdebug_log(149,0) << "AutoContact::canMoveUp() " << this << endl;
|
|
|
|
size_t viaDepth = 100;
|
|
|
|
|
|
|
|
RoutingGauge* rg = Session::getRoutingGauge();
|
|
|
|
size_t movedDepth = rg->getLayerDepth(moved->getLayer());
|
|
|
|
|
|
|
|
Component* anchor = getAnchor();
|
|
|
|
if (anchor) {
|
|
|
|
viaDepth = rg->getLayerDepth( anchor->getLayer() );
|
|
|
|
cdebug_log(149,0) << "| Anchor depth: " << viaDepth << endl;
|
|
|
|
}
|
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
for ( AutoSegment* segment : const_cast<AutoContact*>(this)->getAutoSegments() ) {
|
|
|
|
if (segment == moved) continue;
|
2016-07-18 07:48:37 -05:00
|
|
|
|
2016-07-30 05:15:49 -05:00
|
|
|
size_t depth = rg->getLayerDepth(segment->getLayer());
|
2016-07-18 07:48:37 -05:00
|
|
|
if (viaDepth == 100) viaDepth = depth;
|
|
|
|
else
|
|
|
|
if (viaDepth != depth) return false;
|
|
|
|
|
|
|
|
cdebug_log(149,0) << "| Segment depth: " << depth << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (movedDepth+1 == viaDepth);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::setConstraintBox ( const Box& box )
|
|
|
|
{
|
|
|
|
setCBXMin ( box.getXMin() );
|
|
|
|
setCBXMax ( box.getXMax() );
|
|
|
|
setCBYMin ( box.getYMin() );
|
|
|
|
setCBYMax ( box.getYMax() );
|
|
|
|
cdebug_log(149,0) << "setConstraintBox() - " << this << " " << getConstraintBox() << endl;
|
|
|
|
cdebug_log(149,0) << "* " << _gcell << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool AutoContact::restrictConstraintBox ( DbU::Unit constraintMin
|
|
|
|
, DbU::Unit constraintMax
|
|
|
|
, unsigned int flags
|
|
|
|
)
|
|
|
|
{
|
|
|
|
cdebug_log(149,0) << "restrictConstraintBox() - " << this << " " << getConstraintBox() << endl;
|
|
|
|
if (flags & Flags::Horizontal) {
|
|
|
|
if ( (constraintMin > getCBYMax()) or (constraintMax < getCBYMin()) ) {
|
|
|
|
if ( Session::isInDemoMode() or not (flags & Flags::WarnOnError) ) return false;
|
|
|
|
|
|
|
|
cerr << Error ( "Incompatible DY restriction on %s", _getString().c_str() ) << endl;
|
|
|
|
if ( constraintMin > getCBYMax() )
|
2016-09-22 07:16:53 -05:00
|
|
|
cerr << Error ( "(constraintMin > CBYMax : %s > %s)"
|
|
|
|
, DbU::getValueString(constraintMin).c_str()
|
|
|
|
, DbU::getValueString(getCBYMax()).c_str() )
|
2016-07-18 07:48:37 -05:00
|
|
|
<< endl;
|
|
|
|
if ( constraintMax < getCBYMin() )
|
2016-09-22 07:16:53 -05:00
|
|
|
cerr << Error ( "(constraintMax < CBYMin : %s < %s)"
|
|
|
|
, DbU::getValueString(constraintMax).c_str()
|
|
|
|
, DbU::getValueString(getCBYMin()).c_str() )
|
2016-07-18 07:48:37 -05:00
|
|
|
<< endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
setCBYMin ( std::max(getCBYMin(),constraintMin) );
|
|
|
|
setCBYMax ( std::min(getCBYMax(),constraintMax) );
|
|
|
|
} else if (flags & Flags::Vertical) {
|
|
|
|
if ( (constraintMin > getCBXMax()) || (constraintMax < getCBXMin()) ) {
|
|
|
|
if ( Session::isInDemoMode() or not (flags & Flags::WarnOnError) ) return false;
|
|
|
|
|
|
|
|
cerr << Error ( "Incompatible DX restriction on %s", _getString().c_str() ) << endl;
|
|
|
|
if ( constraintMin > getCBXMax() )
|
2016-09-22 07:16:53 -05:00
|
|
|
cerr << Error ( "(constraintMin > CBXMax : %s > %s)"
|
|
|
|
, DbU::getValueString(constraintMin).c_str()
|
|
|
|
, DbU::getValueString(getCBXMax()).c_str() )
|
2016-07-18 07:48:37 -05:00
|
|
|
<< endl;
|
|
|
|
if ( constraintMax < getCBXMin() )
|
2016-09-22 07:16:53 -05:00
|
|
|
cerr << Error ( "(constraintMax < CBXMin : %s < %s)"
|
|
|
|
, DbU::getValueString(constraintMax).c_str()
|
|
|
|
, DbU::getValueString(getCBXMin()).c_str() )
|
2016-07-18 07:48:37 -05:00
|
|
|
<< endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
setCBXMin ( std::max(getCBXMin(),constraintMin) );
|
|
|
|
setCBXMax ( std::min(getCBXMax(),constraintMax) );
|
|
|
|
}
|
|
|
|
cdebug_log(149,0) << "restrictConstraintBox() - " << this << " " << getConstraintBox() << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::restoreNativeConstraintBox ()
|
|
|
|
{ setConstraintBox ( getNativeConstraintBox() ); }
|
|
|
|
|
|
|
|
|
|
|
|
Box& AutoContact::intersectConstraintBox ( Box& box ) const
|
|
|
|
{ return box = box.getIntersection ( getConstraintBox() ); }
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::migrateConstraintBox ( AutoContact* other )
|
|
|
|
{
|
|
|
|
if (_gcell != other->_gcell) {
|
|
|
|
cerr << Error( "AutoContact::migrateConstraintBox(): AutoContacts do not belongs to the same GCell:\n"
|
|
|
|
" from: %s\n"
|
|
|
|
" to: %s"
|
|
|
|
, getString(other).c_str()
|
|
|
|
, getString(this ).c_str()
|
|
|
|
) << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
setConstraintBox( other->getConstraintBox() );
|
|
|
|
other->restoreNativeConstraintBox();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Box AutoContact::getBoundingBox () const
|
|
|
|
{ return _gcell->getBoundingBox (); }
|
|
|
|
|
|
|
|
|
|
|
|
void AutoContact::translate ( const DbU::Unit& tx, const DbU::Unit& ty )
|
|
|
|
{
|
|
|
|
cerr << Warning("Calling AutoContact::translate() is likely a bug.") << endl;
|
|
|
|
_contact->translate ( tx, ty );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AutoContact* AutoContact::createFrom ( Contact* hurricaneContact )
|
|
|
|
{
|
|
|
|
AutoContact* autoContact = NULL;
|
|
|
|
Component* anchor;
|
|
|
|
size_t hSize = 0;
|
|
|
|
size_t vSize = 0;
|
|
|
|
Horizontal** horizontals = new Horizontal* [4];
|
|
|
|
Vertical** verticals = new Vertical* [4];
|
|
|
|
GCell* gcell = Session::getAnabatic()->getGCellUnder( hurricaneContact->getCenter() );
|
|
|
|
|
|
|
|
if (not gcell) {
|
|
|
|
throw Error("AutoContact::createFrom( %s ):\n"
|
|
|
|
" Contact is *not* under a GCell (outside routed area?)"
|
|
|
|
, getString(hurricaneContact).c_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_getTopology ( hurricaneContact, anchor, horizontals, verticals, 4 );
|
|
|
|
|
|
|
|
for ( size_t i=0 ; i<4 ; ++i ) {
|
|
|
|
hSize += (horizontals[i] != NULL) ? 1 : 0;
|
|
|
|
vSize += (verticals [i] != NULL) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (anchor) {
|
|
|
|
if (hSize+vSize == 1) {
|
|
|
|
autoContact = new AutoContactTerminal( gcell, hurricaneContact );
|
|
|
|
autoContact->_postCreate();
|
|
|
|
autoContact->unsetFlags( CntInCreationStage );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((hSize == 1) and (vSize == 1)) {
|
|
|
|
autoContact = new AutoContactTurn ( gcell, hurricaneContact );
|
|
|
|
autoContact->_postCreate();
|
|
|
|
autoContact->unsetFlags( CntInCreationStage );
|
|
|
|
} else if ((hSize == 2) and (vSize == 1)) {
|
|
|
|
autoContact = new AutoContactHTee ( gcell, hurricaneContact );
|
|
|
|
autoContact->_postCreate();
|
|
|
|
autoContact->unsetFlags( CntInCreationStage );
|
|
|
|
} else if ((hSize == 1) and (vSize == 2)) {
|
|
|
|
autoContact = new AutoContactVTee ( gcell, hurricaneContact );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not autoContact) {
|
|
|
|
throw Error("AutoContact::createFrom( %s ):\n"
|
|
|
|
" Contact do not have a manageable topology (a:%u, h:%u, v:%u)"
|
|
|
|
, getString(hurricaneContact).c_str()
|
|
|
|
, ((anchor) ? 1 : 0)
|
|
|
|
, hSize
|
|
|
|
, vSize
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
autoContact->_postCreate();
|
|
|
|
autoContact->unsetFlags( CntInCreationStage );
|
|
|
|
|
|
|
|
return autoContact;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string AutoContact::_getTypeName () const
|
|
|
|
{ return "AutoContact"; }
|
|
|
|
|
|
|
|
|
|
|
|
string AutoContact::_getString () const
|
|
|
|
{
|
|
|
|
string s = _contact->_getString();
|
|
|
|
size_t i = s.find(' ');
|
|
|
|
if (i != string::npos) {
|
|
|
|
s.erase ( i+1, 7 );
|
|
|
|
s.insert( i+1, _getTypeName() );
|
|
|
|
}
|
|
|
|
//s.insert( 1, "id: " );
|
|
|
|
//s.insert( 4, getString(_id) );
|
|
|
|
s.insert( s.size()-1, (isFixed ())?" F":" -" );
|
|
|
|
s.insert( s.size()-1, (isTerminal ())? "T": "-" );
|
|
|
|
s.insert( s.size()-1, (isHTee ())? "h": "-" );
|
|
|
|
s.insert( s.size()-1, (isVTee ())? "v": "-" );
|
|
|
|
s.insert( s.size()-1, (isInvalidated ())? "i": "-" );
|
|
|
|
s.insert( s.size()-1, (isInvalidatedCache())? "c": "-" );
|
|
|
|
|
|
|
|
//s.insert( s.size()-1, getString(getConstraintBox()));
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Record* AutoContact::_getRecord () const
|
|
|
|
{
|
|
|
|
Record* record = _contact->_getRecord ();
|
|
|
|
record->add ( getSlot ( "_gcell" , _gcell ) );
|
|
|
|
record->add ( getSlot ( "_constraintBox", getConstraintBox() ) );
|
|
|
|
record->add ( getSlot ( "_flags" , _flags ) );
|
|
|
|
return record;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // Anabatic namespace.
|