coriolis/anabatic/src/AutoContact.cpp

696 lines
23 KiB
C++

// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2018, 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)
, _xMin (_gcell->getXMin())
, _xMax (_gcell->getConstraintXMax())
, _yMin (_gcell->getYMin())
, _yMax (_gcell->getConstraintYMax())
{
_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::getValueString(getCBXMin())
<< " " << DbU::getValueString(getCBYMin())
<< " " << DbU::getValueString(getCBXMax())
<< " " << DbU::getValueString(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(), 145, 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;
for ( Component* component : _contact->getSlaveComponents() ) {
message << "\n | " << component;
}
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 ( Flags 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; }
AutoHorizontal* AutoContact::getHorizontal1 () const { return NULL; }
AutoHorizontal* AutoContact::getHorizontal2 () const { return NULL; }
AutoVertical* AutoContact::getVertical1 () const { return NULL; }
AutoVertical* AutoContact::getVertical2 () const { return NULL; }
bool AutoContact::isOnPin () const { return false; }
void AutoContact::getDepthSpan ( size_t& minDepth, size_t& maxDepth ) const
{
minDepth = (size_t)-1;
maxDepth = 0;
Component* anchor = getAnchor ();
if (anchor) {
minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) );
maxDepth = std::max( maxDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) );
}
for ( AutoSegment* segment : const_cast<AutoContact*>(this)->getAutoSegments() ) {
minDepth = std::min( minDepth, Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) );
maxDepth = std::max( maxDepth, Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) );
}
}
void AutoContact::updateLayer ()
{
size_t minDepth = (size_t)-1;
size_t maxDepth = 0;
getDepthSpan( minDepth, maxDepth );
setLayerAndWidth( maxDepth-minDepth, minDepth );
// if (minDepth == maxDepth)
// setLayer( Session::getRoutingGauge()->getRoutingLayer(minDepth) );
// else
// setLayer( Session::getRoutingGauge()->getContactLayer(minDepth) );
}
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();
for ( AutoSegment* segment : getAutoSegments() ) {
bool isSourceHook = (segment->getAutoSource() == this);
if (processeds.find(segment) != processeds.end()) continue;
processeds.insert( segment );
size_t depth = Session::getRoutingGauge()->getLayerDepth(segment->getLayer());
DbU::Unit length;
if (segment->isLocal()) {
length = segment->getLength();
lengths[depth] += length;
DbU::Unit sideLength = (segment->isHorizontal()) ? hSideLength : vSideLength;
if ( not segment->isUnbound() and (abs(length) > sideLength) )
cerr << Error( "AutoContact::getLength(): Suspicious length %s (> %s) of %s.\n"
" (on: %s)"
, DbU::getValueString(length).c_str()
, DbU::getValueString(sideLength).c_str()
, getString(segment).c_str()
, getString(this).c_str()) << endl;
} else {
if (segment->isHorizontal()) {
if (isSourceHook)
lengths[depth] += _gcell->getXMax() - segment->getSourceX();
else
lengths[depth] += segment->getTargetX() - _gcell->getXMin();
} else {
if (isSourceHook)
lengths[depth] += _gcell->getYMax() - segment->getSourceY();
else
lengths[depth] += segment->getTargetY() - _gcell->getYMin();
}
}
}
}
Box AutoContact::getNativeConstraintBox () const
{
if (isUserNativeConstraints()) return getConstraintBox();
if (isFixed()) return Box(_contact->getPosition());
return _gcell->getConstraintBox();
}
Interval AutoContact::getNativeUConstraints ( Flags 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 ( Flags 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 ( Flags flags )
{
if (flags & Flags::Topology ) setFlags( CntInvalidatedCache );
if (not isInvalidated()) {
cdebug_log(145,1) << "AutoContact::invalidate() - " << this << endl;
cdebug_log(145,0) << "flags:" << flags.asString(FlagsFunction) << endl;
setFlags( CntInvalidated );
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() );
_xMin = _gcell->getXMin();
_yMin = _gcell->getYMin();
_xMax = _gcell->getConstraintXMax();
_yMax = _gcell->getConstraintYMax();
if (cdebug.enabled()) {
cdebug_log(145,0) << "* deltas: [" << DbU::getValueString(_xMin)
<< " " << DbU::getValueString(_yMin)
<< " " << DbU::getValueString(_xMax)
<< " " << DbU::getValueString(_yMax)
<< "]" << endl;
}
} else {
cerr << Bug( "NULL GCell for %s.", _getString().c_str() ) << endl;
}
}
void AutoContact::updateSize ()
{
if (isInvalidatedWidth()) {
size_t minDepth = 0;
size_t maxDepth = 0;
getDepthSpan( minDepth, maxDepth );
if (getVertical1() and getVertical1()->isWide()) {
size_t vdepth = (Session::getLayerDepth(getVertical1()->getLayer()) == maxDepth) ? maxDepth : minDepth;
DbU::Unit width = getVertical1()->getWidth();
width += Session::getViaWidth(vdepth) - Session::getWireWidth(vdepth);
setWidth( width );
}
if (getHorizontal1() and getHorizontal1()->isWide()) {
size_t hdepth = (Session::getLayerDepth(getHorizontal1()->getLayer()) == maxDepth) ? maxDepth : minDepth;
DbU::Unit width = getHorizontal1()->getWidth();
width += Session::getViaWidth(hdepth) - Session::getWireWidth(hdepth);
setHeight( width );
}
unsetFlags ( CntInvalidatedWidth );
}
}
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();
for ( Component* component : support->getSlaveComponents() ) {
Horizontal* h = dynamic_cast<Horizontal*>(component);
if (h != NULL) {
if (hcount < size) horizontals[hcount++] = h;
} else {
Vertical* v = dynamic_cast<Vertical*>(component);
if ( (v != NULL) and (vcount < size) ) verticals[vcount++] = v;
}
}
}
void AutoContact::showTopologyError ( const std::string& message, Flags 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;
}
void AutoContact::forceOnGrid ( Point )
{
cerr << Warning( "AutoContact::forcedOnGrid() not implemented for this derived class.\n"
" %s\n"
, getString(this).c_str()
) << endl;
}
bool AutoContact::isTee ( Flags 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;
}
for ( AutoSegment* segment : const_cast<AutoContact*>(this)->getAutoSegments() ) {
if (segment == moved) continue;
size_t depth = rg->getLayerDepth(segment->getLayer());
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()
<< " from:" << box << endl;
cdebug_log(149,0) << "* " << _gcell << endl;
}
bool AutoContact::restrictConstraintBox ( DbU::Unit constraintMin
, DbU::Unit constraintMax
, Flags 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() )
cerr << Error ( "(constraintMin > CBYMax : %s > %s)"
, DbU::getValueString(constraintMin).c_str()
, DbU::getValueString(getCBYMax()).c_str() )
<< endl;
if ( constraintMax < getCBYMin() )
cerr << Error ( "(constraintMax < CBYMin : %s < %s)"
, DbU::getValueString(constraintMax).c_str()
, DbU::getValueString(getCBYMin()).c_str() )
<< 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() )
cerr << Error ( "(constraintMin > CBXMax : %s > %s)"
, DbU::getValueString(constraintMin).c_str()
, DbU::getValueString(getCBXMax()).c_str() )
<< endl;
if ( constraintMax < getCBXMin() )
cerr << Error ( "(constraintMax < CBXMin : %s < %s)"
, DbU::getValueString(constraintMax).c_str()
, DbU::getValueString(getCBXMin()).c_str() )
<< 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 );
}
void AutoContact::setLayerAndWidth ( size_t delta, size_t depth )
{
cdebug_log(145,1) << "AutoContact::setLayerAndWidth() " << this << endl;
cdebug_log(145,0) << "delta:" << delta << " depth:" << depth << endl;
if (delta == 0) {
setLayer( Session::getRoutingLayer(depth) );
if (Session::getDirection(depth) & Flags::Horizontal) {
setSizes( Session::getPWireWidth(depth)
, Session::getWireWidth (depth) );
} else {
setSizes( Session::getWireWidth (depth)
, Session::getPWireWidth(depth) );
}
} else {
setLayer( Session::getContactLayer(depth) );
setSizes( Session::getViaWidth (depth)
, Session::getViaWidth (depth) );
}
cdebug_tabw(145,-1);
}
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, (canDrag ())? "D": "-" );
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.