Second version of the antenna effect protection.
* Change: In EtesianEngine::globalPlace(), disable the call to antennaProtect(). First reason is that, after all, Coloquinte do not handle so well the resizing of the cells "on the fly", it overspill the boundaries sometimes. Second reason is that as we cannot know the routing tree at this stage, we will not be able to choose the correct points for diode insertions. We only have a Steiner tree wich may not be the same as a density driven Dijkstra. * Change: In Etesian::Area, the Occurrence to the Instances where not stored in a uniform way. Some where starting from the placed sub-block, some where starting from the top level (corona), making their processing (and remembering it) tricky. Now, they are all expressed from the top cell (corona). The coordinate system is now systematically the one of the top block (*not* the block). Create various overloaded functions EtesianEngine::toCell() and EtesianEngine::toBlock() to ease Occurrence & coordinate translations. * New: In Etesian::Slice::createDiodeUnder(), add a X position hint. Search is done by going through the whole slice range and minimizing the distance to the hint. If it starts to be too slow, we may optimize. * Bug: In EtesianEngine::toColoquinte(), the placement of the top level external pins was not taken into account (this at last explain their weird positioning). * New: AnabaticEngine::antennaProtect(), new algorithm to avoid antenna effect. This step must be done *after* global routing and *before* detailed routing. This way we have access to the real routing and can mend it (along with the netlist) to insert diodes at the rigth points. From the global routing we build clusters (DiodeCluster) of RoutingPads connected through a set of wire whose total length is below the antenna effect threshold. Long wires connecting the clusters are also tagged because we need to put a diode between them and the first RoutingPad of the cluster. This is to avoid a long METAL2 wire connecting to the RoutingPad before the diode is connected through METAL3 (in case of misalignment). This protection is not even enough. For *very long* wires, we needs to put *more* than one diode (this is to be implemented).
This commit is contained in:
parent
b926e02d92
commit
5649a3b984
|
@ -24,6 +24,7 @@
|
||||||
find_package(VLSISAPD REQUIRED)
|
find_package(VLSISAPD REQUIRED)
|
||||||
find_package(HURRICANE REQUIRED)
|
find_package(HURRICANE REQUIRED)
|
||||||
find_package(CORIOLIS REQUIRED)
|
find_package(CORIOLIS REQUIRED)
|
||||||
|
find_package(ETESIAN REQUIRED)
|
||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
|
@ -1004,6 +1004,8 @@ namespace Anabatic {
|
||||||
if (_state > EngineGlobalLoaded)
|
if (_state > EngineGlobalLoaded)
|
||||||
throw Error ("AnabaticEngine::loadGlobalRouting() : global routing already loaded.");
|
throw Error ("AnabaticEngine::loadGlobalRouting() : global routing already loaded.");
|
||||||
|
|
||||||
|
antennaProtect();
|
||||||
|
|
||||||
if (method == EngineLoadGrByNet ) { _loadGrByNet(); }
|
if (method == EngineLoadGrByNet ) { _loadGrByNet(); }
|
||||||
else {
|
else {
|
||||||
throw Error( badMethod, "Anabatic::loadGlobalRouting()", method, getString(_cell).c_str() );
|
throw Error( badMethod, "Anabatic::loadGlobalRouting()", method, getString(_cell).c_str() );
|
||||||
|
|
|
@ -0,0 +1,642 @@
|
||||||
|
// -*- C++ -*-
|
||||||
|
//
|
||||||
|
// This file is part of the Coriolis Software.
|
||||||
|
// Copyright (c) UPMC 2021-2021, 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 : "./AntennaProtect.cpp" |
|
||||||
|
// +-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <sstream>
|
||||||
|
#include <tuple>
|
||||||
|
#include "hurricane/Bug.h"
|
||||||
|
#include "hurricane/Warning.h"
|
||||||
|
#include "hurricane/DebugSession.h"
|
||||||
|
#include "hurricane/Breakpoint.h"
|
||||||
|
#include "hurricane/Net.h"
|
||||||
|
#include "hurricane/NetExternalComponents.h"
|
||||||
|
#include "hurricane/NetRoutingProperty.h"
|
||||||
|
#include "hurricane/Layer.h"
|
||||||
|
#include "hurricane/RoutingPad.h"
|
||||||
|
#include "hurricane/Pad.h"
|
||||||
|
#include "hurricane/Plug.h"
|
||||||
|
#include "hurricane/Instance.h"
|
||||||
|
#include "hurricane/Vertical.h"
|
||||||
|
#include "hurricane/Horizontal.h"
|
||||||
|
#include "hurricane/Cell.h"
|
||||||
|
#include "crlcore/RoutingGauge.h"
|
||||||
|
#include "etesian/EtesianEngine.h"
|
||||||
|
#include "anabatic/AutoContactTerminal.h"
|
||||||
|
#include "anabatic/AutoSegment.h"
|
||||||
|
#include "anabatic/AnabaticEngine.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace CRL;
|
||||||
|
using namespace Hurricane;
|
||||||
|
using namespace Anabatic;
|
||||||
|
using Etesian::EtesianEngine;
|
||||||
|
|
||||||
|
|
||||||
|
class CompareGCellByXMin {
|
||||||
|
public:
|
||||||
|
inline bool operator () ( const GCell* lhs, const GCell* rhs ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline bool CompareGCellByXMin::operator () ( const GCell* lhs, const GCell* rhs ) const
|
||||||
|
{ return lhs->getXMin() < rhs->getXMin(); }
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
// Class : "::DiodeCluster".
|
||||||
|
|
||||||
|
class DiodeCluster {
|
||||||
|
public:
|
||||||
|
static const uint32_t IsDriver;
|
||||||
|
static const uint32_t IsSink;
|
||||||
|
static const uint32_t HasDiode;
|
||||||
|
static const uint32_t IsSegSource;
|
||||||
|
static string toStr ( uint32_t );
|
||||||
|
public:
|
||||||
|
typedef tuple<uint32_t,Segment*> RPInfos;
|
||||||
|
typedef map<RoutingPad*,RPInfos,DBo::CompareById> RoutingPadInfos;
|
||||||
|
typedef set<Horizontal*,DBo::CompareById> HorizontalSet;
|
||||||
|
typedef set<Vertical* ,DBo::CompareById> VerticalSet;
|
||||||
|
typedef map< DbU::Unit, vector<GCell*> > GCellArea;
|
||||||
|
public:
|
||||||
|
DiodeCluster ( RoutingPad*, AnabaticEngine* );
|
||||||
|
inline bool hasRp ( RoutingPad* ) const;
|
||||||
|
bool hasGCell ( GCell* ) const;
|
||||||
|
inline Net* getTopNet () const;
|
||||||
|
inline RoutingPad* getRefRp () const;
|
||||||
|
inline const RoutingPadInfos& getRoutingPads () const;
|
||||||
|
inline const vector<Instance*>& getDiodes () const;
|
||||||
|
inline DbU::Unit getWL () const;
|
||||||
|
bool needsDiode () const;
|
||||||
|
Box getBoundingBox () const;
|
||||||
|
void merge ( GCell* );
|
||||||
|
void merge ( RoutingPad* );
|
||||||
|
void merge ( Segment* );
|
||||||
|
void mergeHalo ( Segment* );
|
||||||
|
void forceDiodeOn ( RoutingPad*, Segment*, Flags );
|
||||||
|
Instance* createDiode ( Etesian::Area*, GCell*, Flags side, uint32_t distance=1 );
|
||||||
|
const vector<Instance*>& createDiodes ( Etesian::Area* );
|
||||||
|
private:
|
||||||
|
void _consolidate ();
|
||||||
|
private:
|
||||||
|
AnabaticEngine* _anabatic;
|
||||||
|
bool _sortArea;
|
||||||
|
DbU::Unit _WL;
|
||||||
|
RoutingPadInfos _routingPads;
|
||||||
|
HorizontalSet _horizontals;
|
||||||
|
VerticalSet _verticals;
|
||||||
|
HorizontalSet _horizontalHalo;
|
||||||
|
VerticalSet _verticalHalo;
|
||||||
|
GCellArea _area;
|
||||||
|
vector<Instance*> _diodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const uint32_t DiodeCluster::IsDriver = (1 << 0);
|
||||||
|
const uint32_t DiodeCluster::IsSink = (1 << 1);
|
||||||
|
const uint32_t DiodeCluster::HasDiode = (1 << 2);
|
||||||
|
const uint32_t DiodeCluster::IsSegSource = (1 << 3);
|
||||||
|
|
||||||
|
|
||||||
|
string DiodeCluster::toStr ( uint32_t flags )
|
||||||
|
{
|
||||||
|
string s;
|
||||||
|
s += (flags & IsDriver ) ? 'd' : '-';
|
||||||
|
s += (flags & IsSink ) ? 's' : '-';
|
||||||
|
s += (flags & HasDiode ) ? 'D' : '-';
|
||||||
|
s += (flags & IsSegSource) ? 'S' : '-';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DiodeCluster::DiodeCluster ( RoutingPad* rp, AnabaticEngine* anabatic )
|
||||||
|
: _anabatic(anabatic)
|
||||||
|
, _sortArea(true)
|
||||||
|
, _WL(0)
|
||||||
|
, _routingPads()
|
||||||
|
, _horizontals()
|
||||||
|
, _verticals()
|
||||||
|
, _horizontalHalo()
|
||||||
|
, _verticalHalo()
|
||||||
|
, _area()
|
||||||
|
, _diodes()
|
||||||
|
{
|
||||||
|
merge( rp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Net* DiodeCluster::getTopNet () const { return getRefRp()->getNet(); }
|
||||||
|
inline DbU::Unit DiodeCluster::getWL () const { return _WL; }
|
||||||
|
inline const DiodeCluster::RoutingPadInfos& DiodeCluster::getRoutingPads () const { return _routingPads; }
|
||||||
|
inline const vector<Instance*>& DiodeCluster::getDiodes () const { return _diodes; }
|
||||||
|
|
||||||
|
bool DiodeCluster::needsDiode () const
|
||||||
|
{
|
||||||
|
for ( auto& item : _routingPads ) {
|
||||||
|
if (std::get<0>(item.second) & IsSink) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool DiodeCluster::hasRp ( RoutingPad* rp ) const
|
||||||
|
{ return (_routingPads.find(rp) != _routingPads.end()); }
|
||||||
|
|
||||||
|
|
||||||
|
inline bool DiodeCluster::hasGCell ( GCell* gcell ) const
|
||||||
|
{
|
||||||
|
if (not gcell) return false;
|
||||||
|
auto islice = _area.find( gcell->getYMin());
|
||||||
|
if (islice == _area.end()) return false;
|
||||||
|
for ( const GCell* igcell : (*islice).second )
|
||||||
|
if (igcell == gcell) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline RoutingPad* DiodeCluster::getRefRp () const
|
||||||
|
{
|
||||||
|
if (not _routingPads.empty()) return (*_routingPads.begin()).first;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeCluster::merge ( RoutingPad* rp )
|
||||||
|
{
|
||||||
|
Plug* rpPlug = dynamic_cast<Plug*>( rp->getPlugOccurrence().getEntity() );
|
||||||
|
if (rpPlug) {
|
||||||
|
merge( _anabatic->getGCellUnder( rp->getPosition() ));
|
||||||
|
if (rpPlug->getMasterNet()->getDirection() & Net::Direction::DirIn) {
|
||||||
|
_routingPads.insert( make_pair(rp,make_tuple(IsSink,(Segment*)NULL)) );
|
||||||
|
} else {
|
||||||
|
_routingPads.insert( make_pair(rp,make_tuple(IsDriver,(Segment*)NULL)) );
|
||||||
|
cdebug_log(147,0) << "| Driver " << rp << endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Pin* rpPin = dynamic_cast<Pin*>( rp->getPlugOccurrence().getEntity() );
|
||||||
|
if (rpPin) {
|
||||||
|
_routingPads.insert( make_pair(rp,make_tuple(IsDriver,(Segment*)NULL)) );
|
||||||
|
cdebug_log(147,0) << "| Pin (considered driver) " << rp << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeCluster::merge ( Segment* segment )
|
||||||
|
{
|
||||||
|
_WL += segment->getLength();
|
||||||
|
GCellsUnder gcells = _anabatic->getGCellsUnder( segment );
|
||||||
|
if (not gcells->empty()) {
|
||||||
|
_sortArea = true;
|
||||||
|
for ( size_t i=0 ; i<gcells->size() ; ++i ) {
|
||||||
|
merge( gcells->gcellAt(i) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeCluster::merge ( GCell* gcell )
|
||||||
|
{
|
||||||
|
if (not gcell) return;
|
||||||
|
auto islice = _area.find( gcell->getYMin());
|
||||||
|
if (islice == _area.end())
|
||||||
|
islice = _area.insert( make_pair(gcell->getYMin(),vector<GCell*>()) ).first;
|
||||||
|
for ( const GCell* igcell : (*islice).second ) {
|
||||||
|
if (igcell == gcell) return;
|
||||||
|
}
|
||||||
|
(*islice).second.push_back( gcell );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Box DiodeCluster::getBoundingBox () const
|
||||||
|
{
|
||||||
|
Box bb;
|
||||||
|
for ( auto& item : _routingPads ) bb.merge( item.first->getPosition() );
|
||||||
|
return bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeCluster::forceDiodeOn ( RoutingPad* rp, Segment* segment, Flags flags )
|
||||||
|
{
|
||||||
|
cdebug_log(147,0) << "DiodeCluster::forceDiodeOn(): " << endl;
|
||||||
|
cdebug_log(147,0) << " rp=" << rp << endl;
|
||||||
|
cdebug_log(147,0) << " seg=" << segment << endl;
|
||||||
|
if (not rp or not segment) return;
|
||||||
|
for ( auto& item : _routingPads ) {
|
||||||
|
if (item.first == rp) {
|
||||||
|
std::get<0>(item.second) |= HasDiode;
|
||||||
|
if (flags & Flags::Source) std::get<0>(item.second) |= IsSegSource;
|
||||||
|
std::get<1>(item.second) = segment;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cdebug_log(147,0) << "DiodeCluster::forceDiodeOn(): No RP registered." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Instance* DiodeCluster::createDiode ( Etesian::Area* area, GCell* gcell, Flags side, uint32_t distance )
|
||||||
|
{
|
||||||
|
cdebug_log(147,0) << "DiodeCluster::createDiode(): from=" << gcell
|
||||||
|
<< " distance=" << distance << endl;
|
||||||
|
|
||||||
|
GCell* neighbor = gcell;
|
||||||
|
for ( uint32_t i=0 ; i<distance and neighbor ; ++i ) {
|
||||||
|
if (side.contains(Flags::WestSide )) neighbor = neighbor->getWest();
|
||||||
|
else if (side.contains(Flags::EastSide )) neighbor = neighbor->getEast();
|
||||||
|
else if (side.contains(Flags::NorthSide)) neighbor = neighbor->getNorth();
|
||||||
|
else if (side.contains(Flags::SouthSide)) neighbor = neighbor->getSouth();
|
||||||
|
}
|
||||||
|
if (not neighbor) return NULL;
|
||||||
|
|
||||||
|
DbU::Unit xHint = 0;
|
||||||
|
if (side.contains(Flags::WestSide )) xHint = neighbor->getBoundingBox().getXMax();
|
||||||
|
else if (side.contains(Flags::EastSide )) xHint = neighbor->getBoundingBox().getXMin();
|
||||||
|
else if (side.contains(Flags::NorthSide)) xHint = neighbor->getBoundingBox().getXCenter();
|
||||||
|
else if (side.contains(Flags::SouthSide)) xHint = neighbor->getBoundingBox().getXCenter();
|
||||||
|
|
||||||
|
Box bb = neighbor->getBoundingBox();
|
||||||
|
Instance* diode = area->createDiodeUnder( getRefRp(), bb, xHint );
|
||||||
|
if (diode) {
|
||||||
|
_diodes.push_back( diode );
|
||||||
|
cdebug_log(147,0) << "> GCell area (neighbor): " << bb << endl;
|
||||||
|
Contact* sourceContact = gcell->breakGoThrough( getTopNet() );
|
||||||
|
Contact* targetContact = neighbor->hasGContact( getTopNet() );
|
||||||
|
|
||||||
|
if (not targetContact) {
|
||||||
|
bool hasGoThrough = (neighbor->hasGoThrough(getTopNet()) != NULL);
|
||||||
|
targetContact = neighbor->breakGoThrough( getTopNet() );
|
||||||
|
|
||||||
|
if (not hasGoThrough) {
|
||||||
|
if (side & Flags::Horizontal) {
|
||||||
|
if (sourceContact->getX() > targetContact->getX())
|
||||||
|
std::swap( sourceContact, targetContact );
|
||||||
|
|
||||||
|
Horizontal::create( sourceContact
|
||||||
|
, targetContact
|
||||||
|
, _anabatic->getConfiguration()->getGHorizontalLayer()
|
||||||
|
, bb.getCenter().getY()
|
||||||
|
, _anabatic->getConfiguration()->getGHorizontalPitch()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (sourceContact->getY() > targetContact->getY())
|
||||||
|
std::swap( sourceContact, targetContact );
|
||||||
|
|
||||||
|
Vertical::create( sourceContact
|
||||||
|
, targetContact
|
||||||
|
, _anabatic->getConfiguration()->getGVerticalLayer()
|
||||||
|
, bb.getCenter().getX()
|
||||||
|
, _anabatic->getConfiguration()->getGVerticalPitch()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return diode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const vector<Instance*>& DiodeCluster::createDiodes ( Etesian::Area* area )
|
||||||
|
{
|
||||||
|
if (not needsDiode()) return _diodes;
|
||||||
|
_consolidate();
|
||||||
|
|
||||||
|
Instance* diode = NULL;
|
||||||
|
|
||||||
|
for ( auto& item : _routingPads ) {
|
||||||
|
if (not (std::get<0>(item.second) & HasDiode)) continue;
|
||||||
|
|
||||||
|
diode = NULL;
|
||||||
|
GCell* gcell = _anabatic->getGCellUnder( item.first->getPosition() );
|
||||||
|
|
||||||
|
Horizontal* h = dynamic_cast<Horizontal*>(std::get<1>(item.second));
|
||||||
|
if (h) {
|
||||||
|
cdebug_log(147,0) << "> Long segment (forced diode) h=" << h << endl;
|
||||||
|
diode = area->createDiodeUnder( getRefRp()
|
||||||
|
, h->getBoundingBox()
|
||||||
|
, item.first->getPosition().getX() );
|
||||||
|
if (diode) {
|
||||||
|
_diodes.push_back( diode );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto islice = _area.find( gcell->getYMin());
|
||||||
|
if (islice != _area.end()) {
|
||||||
|
Box gcellsBb;
|
||||||
|
bool containsRp = false;
|
||||||
|
vector<GCell*>& slice = (*islice).second;
|
||||||
|
for ( size_t i=0 ; i < slice.size() ; ++i ) {
|
||||||
|
if (slice[i] == gcell) containsRp = true;
|
||||||
|
if ((i > 0) and (slice[i-1]->getXMax() < slice[i]->getXMin())) {
|
||||||
|
cdebug_log(147,0) << "> GCell area (forced diode): " << gcellsBb << endl;
|
||||||
|
if (containsRp) {
|
||||||
|
diode = area->createDiodeUnder( getRefRp(), gcellsBb, item.first->getPosition().getX() );
|
||||||
|
if (diode) {
|
||||||
|
_diodes.push_back( diode );
|
||||||
|
containsRp = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gcellsBb.makeEmpty();
|
||||||
|
}
|
||||||
|
gcellsBb.merge( slice[i]->getBoundingBox() );
|
||||||
|
}
|
||||||
|
if (diode) continue;
|
||||||
|
if (containsRp and not gcellsBb.isEmpty()) {
|
||||||
|
cdebug_log(147,0) << "> GCell area (forced diode, end): " << gcellsBb << endl;
|
||||||
|
diode = area->createDiodeUnder( getRefRp(), gcellsBb, item.first->getPosition().getX() );
|
||||||
|
if (diode) {
|
||||||
|
_diodes.push_back( diode );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cdebug_log(147,0) << "> Try along connecting segment" << endl;
|
||||||
|
Horizontal* h = dynamic_cast<Horizontal*>( std::get<1>(item.second) );
|
||||||
|
if (h) {
|
||||||
|
if (std::get<0>(item.second) & IsSegSource) {
|
||||||
|
for ( uint32_t i=0 ; i<3 ; ++i ) {
|
||||||
|
if ((diode = createDiode(area,gcell,Flags::EastSide,i))) break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ( uint32_t i=0 ; i<3 ; ++i ) {
|
||||||
|
if ((diode = createDiode(area,gcell,Flags::WestSide,i))) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (std::get<0>(item.second) & IsSegSource) {
|
||||||
|
for ( uint32_t i=0 ; i<3 ; ++i ) {
|
||||||
|
if ((diode = createDiode(area,gcell,Flags::NorthSide,i))) break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for ( uint32_t i=0 ; i<3 ; ++i ) {
|
||||||
|
if ((diode = createDiode(area,gcell,Flags::SouthSide,i))) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (diode) return _diodes;
|
||||||
|
|
||||||
|
for ( auto& item : _area ) {
|
||||||
|
cdebug_log(147,0) << "+ Slice @" << DbU::getValueString(item.first) << endl;
|
||||||
|
Box gcellsBb;
|
||||||
|
vector<GCell*>& slice = item.second;
|
||||||
|
for ( size_t i=0 ; (i < slice.size()) and not diode ; ++i ) {
|
||||||
|
if ((i > 0) and (slice[i-1]->getXMax() < slice[i]->getXMin())) {
|
||||||
|
cdebug_log(147,0) << "> GCell area: " << gcellsBb << endl;
|
||||||
|
diode = area->createDiodeUnder( getRefRp(), gcellsBb, gcellsBb.getXCenter() );
|
||||||
|
if (diode) {
|
||||||
|
_diodes.push_back( diode );
|
||||||
|
return _diodes;
|
||||||
|
}
|
||||||
|
gcellsBb.makeEmpty();
|
||||||
|
}
|
||||||
|
cdebug_log(147,0) << "| Agglomerate [" << i << "]: " << slice[i] << endl;
|
||||||
|
gcellsBb.merge( slice[i]->getBoundingBox() );
|
||||||
|
}
|
||||||
|
if (not gcellsBb.isEmpty()) {
|
||||||
|
cdebug_log(147,0) << "> GCell area (end): " << gcellsBb << endl;
|
||||||
|
diode = area->createDiodeUnder( getRefRp(), gcellsBb, gcellsBb.getXCenter() );
|
||||||
|
if (diode) {
|
||||||
|
_diodes.push_back( diode );
|
||||||
|
return _diodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto& item : _area ) {
|
||||||
|
vector<GCell*>& slice = item.second;
|
||||||
|
if (createDiode(area,slice[0 ],Flags::WestSide)) return _diodes;
|
||||||
|
if (createDiode(area,slice[slice.size()-1],Flags::EastSide)) return _diodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto& item : _routingPads ) {
|
||||||
|
GCell* gcell = _anabatic->getGCellUnder( item.first->getPosition() );
|
||||||
|
if (createDiode(area,gcell,Flags::NorthSide)) return _diodes;
|
||||||
|
if (createDiode(area,gcell,Flags::SouthSide)) return _diodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _diodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeCluster::_consolidate ()
|
||||||
|
{
|
||||||
|
if (not _sortArea) return;
|
||||||
|
for ( auto& item : _area ) {
|
||||||
|
std::sort( item.second.begin(), item.second.end(), CompareGCellByXMin() );
|
||||||
|
}
|
||||||
|
_sortArea = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // Anonymous namespace.
|
||||||
|
|
||||||
|
|
||||||
|
namespace Anabatic {
|
||||||
|
|
||||||
|
using namespace Hurricane;
|
||||||
|
using CRL::ToolEngine;
|
||||||
|
using Etesian::EtesianEngine;
|
||||||
|
|
||||||
|
|
||||||
|
void AnabaticEngine::antennaProtect ( Net* net, uint32_t& failed, uint32_t& total )
|
||||||
|
{
|
||||||
|
DebugSession::open( net, 145, 150 );
|
||||||
|
cdebug_log(147,1) << "Net \"" << net->getName() << endl;
|
||||||
|
|
||||||
|
EtesianEngine* etesian = static_cast<EtesianEngine*>
|
||||||
|
( ToolEngine::get( getCell(), EtesianEngine::staticGetName() ));
|
||||||
|
|
||||||
|
DbU::Unit antennaMaxWL = etesian->getAntennaMaxWL();
|
||||||
|
|
||||||
|
vector<DiodeCluster*> clusters;
|
||||||
|
set<RoutingPad*,DBo::CompareById> rpsDone;
|
||||||
|
set<Segment* ,DBo::CompareById> segmentsDone;
|
||||||
|
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
||||||
|
if (rpsDone.find(rp) != rpsDone.end()) continue;
|
||||||
|
|
||||||
|
DiodeCluster* cluster = new DiodeCluster ( rp, this );
|
||||||
|
clusters.push_back( cluster );
|
||||||
|
|
||||||
|
vector<Hook*> hooksStack;
|
||||||
|
hooksStack.push_back( rp->getBodyHook() );
|
||||||
|
while ( not hooksStack.empty() ) {
|
||||||
|
Hook* topHook = hooksStack.back();
|
||||||
|
RoutingPad* topRp = dynamic_cast<RoutingPad*>( topHook->getComponent() );
|
||||||
|
RoutingPad* connexRp = NULL;
|
||||||
|
hooksStack.pop_back();
|
||||||
|
|
||||||
|
for ( Hook* hook : topHook->getHooks() ) {
|
||||||
|
RoutingPad* gcellRp = dynamic_cast<RoutingPad*>( hook->getComponent() );
|
||||||
|
if (gcellRp) {
|
||||||
|
if (not connexRp) connexRp = gcellRp;
|
||||||
|
if (rpsDone.find(gcellRp) == rpsDone.end())
|
||||||
|
cluster->merge( gcellRp );
|
||||||
|
rpsDone.insert( gcellRp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( Hook* hook : topHook->getHooks() ) {
|
||||||
|
Segment* segment = dynamic_cast<Segment*>( hook->getComponent() );
|
||||||
|
if (segment) {
|
||||||
|
cdebug_log(147,0) << "| " << DbU::getValueString(segment->getLength())
|
||||||
|
<< " " << segment << endl;
|
||||||
|
if (segmentsDone.find(segment) != segmentsDone.end()) continue;
|
||||||
|
segmentsDone.insert( segment );
|
||||||
|
if (segment->getLength() > antennaMaxWL/2) {
|
||||||
|
Flags flags = (segment->getSourceHook() == hook) ? Flags::Source : Flags::Target;
|
||||||
|
if (not connexRp) connexRp = topRp;
|
||||||
|
cluster->forceDiodeOn( connexRp, segment, flags );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cluster->merge( segment );
|
||||||
|
if (dynamic_cast<Segment::SourceHook*>(hook)) {
|
||||||
|
hooksStack.push_back( segment->getTargetHook() );
|
||||||
|
} else {
|
||||||
|
hooksStack.push_back( segment->getSourceHook() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell* diodeCell = etesian->getDiodeCell();
|
||||||
|
Net* diodeOutput = NULL;
|
||||||
|
for ( Net* net : diodeCell->getNets() ) {
|
||||||
|
if (net->isSupply() or not net->isExternal()) continue;
|
||||||
|
diodeOutput = net;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clusters.size() > 1) {
|
||||||
|
total += clusters.size();
|
||||||
|
cdebug_log(147,1) << "Net \"" << net->getName() << " has " << clusters.size() << " diode clusters." << endl;
|
||||||
|
for ( size_t i=0 ; i<clusters.size() ; ++i ) {
|
||||||
|
cdebug_log(147,0) << "Cluster [" << i << "] needsDiode=" << clusters[i]->needsDiode()
|
||||||
|
<< " bb=" << clusters[i]->getBoundingBox() << endl;
|
||||||
|
for ( auto& item : clusters[i]->getRoutingPads() ) {
|
||||||
|
cdebug_log(147,0) << "| flags=" << DiodeCluster::toStr(std::get<0>(item.second))
|
||||||
|
<< " " << item.first << endl;
|
||||||
|
}
|
||||||
|
if (not clusters[i]->needsDiode()) continue;
|
||||||
|
|
||||||
|
const vector<Instance*> diodes = clusters[i]->createDiodes( etesian->getArea() );
|
||||||
|
RoutingPad* rp = clusters[i]->getRefRp();
|
||||||
|
if (not diodes.empty()) {
|
||||||
|
Net* topNet = rp->getNet();
|
||||||
|
Plug* sinkPlug = dynamic_cast<Plug*>( rp->getPlugOccurrence().getEntity() );
|
||||||
|
Path path = rp->getOccurrence().getPath().getHeadPath();
|
||||||
|
if (sinkPlug) {
|
||||||
|
for ( Instance* diode : diodes ) {
|
||||||
|
cdebug_log(147,0) << " Bind diode input:" << endl;
|
||||||
|
cdebug_log(147,0) << " " << diode << " @" << diode ->getTransformation() << endl;
|
||||||
|
cdebug_log(147,0) << " topNet->getCell():" << topNet->getCell() << endl;
|
||||||
|
cdebug_log(147,0) << " " << rp->getOccurrence().getPath() << endl;
|
||||||
|
//Path path = rp->getOccurrence().getPath().getHeadPath();
|
||||||
|
Plug* diodePlug = diode->getPlug( diodeOutput );
|
||||||
|
diodePlug->setNet( sinkPlug->getNet() );
|
||||||
|
RoutingPad* diodeRp = RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea );
|
||||||
|
|
||||||
|
GCell* gcell = getGCellUnder( diodeRp->getPosition() );
|
||||||
|
if (gcell) {
|
||||||
|
Contact* contact = gcell->breakGoThrough( topNet );
|
||||||
|
contact->getBodyHook()->merge( diodeRp->getBodyHook() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cerr << Error( "EtesianEngine::antennaProtect(): For %s (rps:%u, clusters:%u)\n"
|
||||||
|
" Cannot get a Plug from %s (?)."
|
||||||
|
, getString(net).c_str()
|
||||||
|
, rpsDone.size()
|
||||||
|
, clusters.size()
|
||||||
|
, getString(clusters[i]->getRefRp()).c_str()
|
||||||
|
) << endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cerr << Error( "EtesianEngine::antennaProtect(): For %s (rps:%u, clusters:%u)\n"
|
||||||
|
" Cannot find a diode nearby %s."
|
||||||
|
, getString(net).c_str()
|
||||||
|
, rpsDone.size()
|
||||||
|
, clusters.size()
|
||||||
|
, getString(clusters[i]->getRefRp()).c_str()
|
||||||
|
) << endl;
|
||||||
|
failed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cdebug_tabw(147,-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( DiodeCluster* cluster : clusters ) delete cluster;
|
||||||
|
|
||||||
|
cdebug_tabw(147,-1);
|
||||||
|
DebugSession::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AnabaticEngine::antennaProtect ()
|
||||||
|
{
|
||||||
|
//DebugSession::open( 145, 150 );
|
||||||
|
|
||||||
|
if (not ToolEngine::get( getCell(), EtesianEngine::staticGetName() )) {
|
||||||
|
cerr << Warning( "AnabaticEngine::antennaProtect(): No EtesianEngine found, skipped." ) << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EtesianEngine* etesian = static_cast<EtesianEngine*>
|
||||||
|
( ToolEngine::get( getCell(), EtesianEngine::staticGetName() ));
|
||||||
|
DbU::Unit segmentMaxWL = etesian->getAntennaMaxWL() / 2;
|
||||||
|
|
||||||
|
if (not etesian->getDiodeCell()) {
|
||||||
|
cerr << Warning( "AnabaticEngine::antennaProtect(): No diode cell found, skipped." ) << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startMeasures();
|
||||||
|
openSession();
|
||||||
|
|
||||||
|
uint32_t failed = 0;
|
||||||
|
uint32_t total = 0;
|
||||||
|
for ( Net* net : getCell()->getNets() ) {
|
||||||
|
if (net->isSupply()) continue;
|
||||||
|
if (net->isClock ()) continue;
|
||||||
|
antennaProtect( net, failed, total );
|
||||||
|
}
|
||||||
|
cmess2 << Dots::asString ( " - Antenna maximum WL" , DbU::getValueString(etesian->getAntennaMaxWL()) ) << endl;
|
||||||
|
cmess2 << Dots::asString ( " - Segment maximum WL" , DbU::getValueString(segmentMaxWL) ) << endl;
|
||||||
|
cmess2 << Dots::asInt ( " - Total needed diodes", total ) << endl;
|
||||||
|
cmess2 << Dots::asInt ( " - Failed to allocate" , failed ) << endl;
|
||||||
|
cmess2 << Dots::asPercentage( " - Success ratio" , (float)(total-failed)/(float)total ) << endl;
|
||||||
|
|
||||||
|
stopMeasures();
|
||||||
|
printMeasures( "antennas" );
|
||||||
|
|
||||||
|
// cmess2 << " - Total segments : " << total << endl;
|
||||||
|
// cmess2 << " - Global segments : " << global << endl;
|
||||||
|
// cmess2 << " - Ratio : "
|
||||||
|
// << ((float)global/(float)total)*100.0 << "%." << endl;
|
||||||
|
|
||||||
|
Session::close();
|
||||||
|
//DebugSession::close();
|
||||||
|
Breakpoint::stop( 99, "After diodes insertions." );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // Anabatic namespace.
|
|
@ -63,13 +63,15 @@ endif ( CHECK_DETERMINISM )
|
||||||
NetBuilderVH.cpp
|
NetBuilderVH.cpp
|
||||||
ChipTools.cpp
|
ChipTools.cpp
|
||||||
LayerAssign.cpp
|
LayerAssign.cpp
|
||||||
|
AntennaProtect.cpp
|
||||||
PreRouteds.cpp
|
PreRouteds.cpp
|
||||||
AnabaticEngine.cpp
|
AnabaticEngine.cpp
|
||||||
)
|
)
|
||||||
set( pyCpps PyAnabatic.cpp
|
set( pyCpps PyAnabatic.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set( depLibs ${CORIOLIS_PYTHON_LIBRARIES}
|
set( depLibs ${ETESIAN_LIBRARIES}
|
||||||
|
${CORIOLIS_PYTHON_LIBRARIES}
|
||||||
${CORIOLIS_LIBRARIES}
|
${CORIOLIS_LIBRARIES}
|
||||||
${HURRICANE_PYTHON_LIBRARIES}
|
${HURRICANE_PYTHON_LIBRARIES}
|
||||||
${HURRICANE_GRAPHICAL_LIBRARIES}
|
${HURRICANE_GRAPHICAL_LIBRARIES}
|
||||||
|
|
|
@ -90,6 +90,7 @@ namespace Anabatic {
|
||||||
, _edgeHInc (Cfg::getParamDouble("anabatic.edgeHInc" , 1.5)->asDouble())
|
, _edgeHInc (Cfg::getParamDouble("anabatic.edgeHInc" , 1.5)->asDouble())
|
||||||
, _edgeHScaling (Cfg::getParamDouble("anabatic.edgeHScaling" , 1.0)->asDouble())
|
, _edgeHScaling (Cfg::getParamDouble("anabatic.edgeHScaling" , 1.0)->asDouble())
|
||||||
, _globalIterations(Cfg::getParamInt ("anabatic.globalIterations", 10 )->asInt())
|
, _globalIterations(Cfg::getParamInt ("anabatic.globalIterations", 10 )->asInt())
|
||||||
|
, _antennaMaxWL (Cfg::getParamInt ("etesian.antennaMaxWL" , 0 )->asInt())
|
||||||
{
|
{
|
||||||
GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() );
|
GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() );
|
||||||
|
|
||||||
|
@ -180,6 +181,7 @@ namespace Anabatic {
|
||||||
, _edgeHInc (other._edgeHInc)
|
, _edgeHInc (other._edgeHInc)
|
||||||
, _edgeHScaling (other._edgeHScaling)
|
, _edgeHScaling (other._edgeHScaling)
|
||||||
, _globalIterations(other._globalIterations)
|
, _globalIterations(other._globalIterations)
|
||||||
|
, _antennaMaxWL (other._antennaMaxWL)
|
||||||
{
|
{
|
||||||
GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() );
|
GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() );
|
||||||
|
|
||||||
|
@ -585,8 +587,12 @@ namespace Anabatic {
|
||||||
record->add( getSlot( "_allowedDepth" , _allowedDepth ) );
|
record->add( getSlot( "_allowedDepth" , _allowedDepth ) );
|
||||||
record->add( getSlot( "_edgeCostH" , _edgeCostH ) );
|
record->add( getSlot( "_edgeCostH" , _edgeCostH ) );
|
||||||
record->add( getSlot( "_edgeCostK" , _edgeCostK ) );
|
record->add( getSlot( "_edgeCostK" , _edgeCostK ) );
|
||||||
|
record->add( getSlot( "_edgeHInc" , _edgeHInc ) );
|
||||||
|
record->add( getSlot( "_edgeHScaling" , _edgeHScaling ) );
|
||||||
|
record->add( getSlot( "_globalIterations", _globalIterations ) );
|
||||||
|
record->add( DbU::getValueSlot( "_antennaMaxWL", &_antennaMaxWL ) );
|
||||||
|
|
||||||
return ( record );
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1459,6 +1459,10 @@ namespace Anabatic {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DbU::Unit Dijkstra::getAntennaMaxWL () const
|
||||||
|
{ return _anabatic->getAntennaMaxWL(); }
|
||||||
|
|
||||||
|
|
||||||
Point Dijkstra::_getPonderedPoint() const
|
Point Dijkstra::_getPonderedPoint() const
|
||||||
{
|
{
|
||||||
vector<RoutingPad*> rps;
|
vector<RoutingPad*> rps;
|
||||||
|
@ -1539,6 +1543,7 @@ namespace Anabatic {
|
||||||
if (state->isSelfSym()) {
|
if (state->isSelfSym()) {
|
||||||
cdebug_log(112,0) << "Dijkstra::SELF SYMMETRY CASE " << DbU::getValueString(state->getSymAxis()) << endl;
|
cdebug_log(112,0) << "Dijkstra::SELF SYMMETRY CASE " << DbU::getValueString(state->getSymAxis()) << endl;
|
||||||
}
|
}
|
||||||
|
state->unsetFlags( NetRoutingState::HasAntenna );
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( Component* component : _net->getComponents() ) {
|
for ( Component* component : _net->getComponents() ) {
|
||||||
|
@ -2196,6 +2201,7 @@ namespace Anabatic {
|
||||||
|
|
||||||
if (_sources.size() < 2) { cdebug_tabw(112,-1); return; }
|
if (_sources.size() < 2) { cdebug_tabw(112,-1); return; }
|
||||||
|
|
||||||
|
DbU::Unit gWL = 0;
|
||||||
NetRoutingState* state = NetRoutingExtension::get( _net );
|
NetRoutingState* state = NetRoutingExtension::get( _net );
|
||||||
//cerr << "state: " << state << endl;
|
//cerr << "state: " << state << endl;
|
||||||
|
|
||||||
|
@ -2286,6 +2292,7 @@ namespace Anabatic {
|
||||||
, constraint.getCenter()
|
, constraint.getCenter()
|
||||||
, width
|
, width
|
||||||
);
|
);
|
||||||
|
gWL += segment->getLength();
|
||||||
cdebug_log(112,0) << "| ref: " << segment << endl;
|
cdebug_log(112,0) << "| ref: " << segment << endl;
|
||||||
|
|
||||||
for ( Edge* through : aligneds ) through->add( segment );
|
for ( Edge* through : aligneds ) through->add( segment );
|
||||||
|
@ -2305,6 +2312,7 @@ namespace Anabatic {
|
||||||
, constraint.getCenter()
|
, constraint.getCenter()
|
||||||
, width
|
, width
|
||||||
);
|
);
|
||||||
|
gWL += segment->getLength();
|
||||||
cdebug_log(112,0) << "| ref: " << segment << endl;
|
cdebug_log(112,0) << "| ref: " << segment << endl;
|
||||||
|
|
||||||
for ( Edge* through : aligneds ) through->add( segment );
|
for ( Edge* through : aligneds ) through->add( segment );
|
||||||
|
@ -2322,6 +2330,14 @@ namespace Anabatic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gWL > getAntennaMaxWL()) {
|
||||||
|
cdebug_log(113,0) << "| \"" << _net->getName() << "\" may have antenna effect, "
|
||||||
|
<< DbU::getValueString(gWL)
|
||||||
|
<< endl;
|
||||||
|
if (state)
|
||||||
|
state->setFlags( NetRoutingState::HasAntenna );
|
||||||
|
}
|
||||||
|
|
||||||
cdebug_tabw(112,-1);
|
cdebug_tabw(112,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -508,6 +508,22 @@ namespace Anabatic {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Segment* GCell::hasGoThrough ( Net* net ) const
|
||||||
|
{
|
||||||
|
for ( Edge* edge : _eastEdges ) {
|
||||||
|
for ( Segment* segment : edge->getSegments() ) {
|
||||||
|
if (segment->getNet() == net) return segment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ( Edge* edge : _northEdges ) {
|
||||||
|
for ( Segment* segment : edge->getSegments() ) {
|
||||||
|
if (segment->getNet() == net) return segment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Edge* GCell::getEdgeTo ( GCell* neighbor, Flags sideHint ) const
|
Edge* GCell::getEdgeTo ( GCell* neighbor, Flags sideHint ) const
|
||||||
{
|
{
|
||||||
for ( Edge* edge : getEdges(sideHint) ) {
|
for ( Edge* edge : getEdges(sideHint) ) {
|
||||||
|
|
|
@ -245,6 +245,7 @@ namespace Anabatic {
|
||||||
inline bool doDestroyBaseContact () const;
|
inline bool doDestroyBaseContact () const;
|
||||||
inline bool doDestroyBaseSegment () const;
|
inline bool doDestroyBaseSegment () const;
|
||||||
inline bool doDestroyTool () const;
|
inline bool doDestroyTool () const;
|
||||||
|
inline DbU::Unit getAntennaMaxWL () const;
|
||||||
inline DbU::Unit getGlobalThreshold () const;
|
inline DbU::Unit getGlobalThreshold () const;
|
||||||
inline float getSaturateRatio () const;
|
inline float getSaturateRatio () const;
|
||||||
inline size_t getSaturateRp () const;
|
inline size_t getSaturateRp () const;
|
||||||
|
@ -261,6 +262,8 @@ namespace Anabatic {
|
||||||
inline void setBlockageNet ( Net* );
|
inline void setBlockageNet ( Net* );
|
||||||
void chipPrep ();
|
void chipPrep ();
|
||||||
void computeEdgeCapacities ( int maxHCap, int maxVCap, int termSatThreshold, int maxTermSat );
|
void computeEdgeCapacities ( int maxHCap, int maxVCap, int termSatThreshold, int maxTermSat );
|
||||||
|
void antennaProtect ( Net*, uint32_t& failed, uint32_t& total );
|
||||||
|
void antennaProtect ();
|
||||||
void setupSpecialNets ();
|
void setupSpecialNets ();
|
||||||
size_t setupPreRouteds ();
|
size_t setupPreRouteds ();
|
||||||
void loadGlobalRouting ( uint32_t method );
|
void loadGlobalRouting ( uint32_t method );
|
||||||
|
@ -367,6 +370,7 @@ namespace Anabatic {
|
||||||
inline bool AnabaticEngine::doWarnOnGCellOverload () const { return _flags & Flags::WarnOnGCellOverload; }
|
inline bool AnabaticEngine::doWarnOnGCellOverload () const { return _flags & Flags::WarnOnGCellOverload; }
|
||||||
inline bool AnabaticEngine::isInDemoMode () const { return _flags & Flags::DemoMode; }
|
inline bool AnabaticEngine::isInDemoMode () const { return _flags & Flags::DemoMode; }
|
||||||
inline bool AnabaticEngine::isChip () const { return _chipTools.isChip(); }
|
inline bool AnabaticEngine::isChip () const { return _chipTools.isChip(); }
|
||||||
|
inline DbU::Unit AnabaticEngine::getAntennaMaxWL () const { return getConfiguration()->getAntennaMaxWL(); }
|
||||||
inline DbU::Unit AnabaticEngine::getGlobalThreshold () const { return _configuration->getGlobalThreshold(); }
|
inline DbU::Unit AnabaticEngine::getGlobalThreshold () const { return _configuration->getGlobalThreshold(); }
|
||||||
inline float AnabaticEngine::getSaturateRatio () const { return _configuration->getSaturateRatio(); }
|
inline float AnabaticEngine::getSaturateRatio () const { return _configuration->getSaturateRatio(); }
|
||||||
inline size_t AnabaticEngine::getSaturateRp () const { return _configuration->getSaturateRp(); }
|
inline size_t AnabaticEngine::getSaturateRp () const { return _configuration->getSaturateRp(); }
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
// +-----------------------------------------------------------------+
|
// +-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
#ifndef ANABATIC_CONFIGURATION_H
|
#pragma once
|
||||||
#define ANABATIC_CONFIGURATION_H
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -117,6 +115,7 @@ namespace Anabatic {
|
||||||
Flags getDirection ( const Layer* ) const;
|
Flags getDirection ( const Layer* ) const;
|
||||||
float getSaturateRatio () const;
|
float getSaturateRatio () const;
|
||||||
size_t getSaturateRp () const;
|
size_t getSaturateRp () const;
|
||||||
|
inline DbU::Unit getAntennaMaxWL () const;
|
||||||
DbU::Unit getGlobalThreshold () const;
|
DbU::Unit getGlobalThreshold () const;
|
||||||
void setAllowedDepth ( size_t );
|
void setAllowedDepth ( size_t );
|
||||||
void setSaturateRatio ( float );
|
void setSaturateRatio ( float );
|
||||||
|
@ -159,6 +158,7 @@ namespace Anabatic {
|
||||||
float _edgeHInc;
|
float _edgeHInc;
|
||||||
float _edgeHScaling;
|
float _edgeHScaling;
|
||||||
int _globalIterations;
|
int _globalIterations;
|
||||||
|
DbU::Unit _antennaMaxWL;
|
||||||
private:
|
private:
|
||||||
Configuration& operator= ( const Configuration& ) = delete;
|
Configuration& operator= ( const Configuration& ) = delete;
|
||||||
void _setTopRoutingLayer ( Name name );
|
void _setTopRoutingLayer ( Name name );
|
||||||
|
@ -186,11 +186,10 @@ namespace Anabatic {
|
||||||
inline const Layer* Configuration::getDContactLayer () const { return getContactLayer( getDContactDepth() ); }
|
inline const Layer* Configuration::getDContactLayer () const { return getContactLayer( getDContactDepth() ); }
|
||||||
inline DbU::Unit Configuration::getDContactWidth () const { return getWireWidth ( getDContactDepth() ); }
|
inline DbU::Unit Configuration::getDContactWidth () const { return getWireWidth ( getDContactDepth() ); }
|
||||||
inline DbU::Unit Configuration::getDContactPitch () const { return getPitch ( getDContactDepth(), Flags::NoFlags ); }
|
inline DbU::Unit Configuration::getDContactPitch () const { return getPitch ( getDContactDepth(), Flags::NoFlags ); }
|
||||||
|
inline DbU::Unit Configuration::getAntennaMaxWL () const { return _antennaMaxWL; }
|
||||||
|
|
||||||
|
|
||||||
} // Anabatic namespace.
|
} // Anabatic namespace.
|
||||||
|
|
||||||
|
|
||||||
INSPECTOR_P_SUPPORT(Anabatic::Configuration);
|
INSPECTOR_P_SUPPORT(Anabatic::Configuration);
|
||||||
|
|
||||||
#endif // ANABATIC_CONFIGURATION_H
|
|
||||||
|
|
|
@ -522,6 +522,7 @@ namespace Anabatic {
|
||||||
inline bool isSourceVertex ( Vertex* ) const;
|
inline bool isSourceVertex ( Vertex* ) const;
|
||||||
inline Net* getNet () const;
|
inline Net* getNet () const;
|
||||||
inline bool isTargetVertex ( Vertex* ) const;
|
inline bool isTargetVertex ( Vertex* ) const;
|
||||||
|
DbU::Unit getAntennaMaxWL () const;
|
||||||
inline DbU::Unit getSearchAreaHalo () const;
|
inline DbU::Unit getSearchAreaHalo () const;
|
||||||
template<typename DistanceT>
|
template<typename DistanceT>
|
||||||
inline DistanceT* setDistance ( DistanceT );
|
inline DistanceT* setDistance ( DistanceT );
|
||||||
|
|
|
@ -213,7 +213,8 @@ namespace Anabatic {
|
||||||
bool doGrid ();
|
bool doGrid ();
|
||||||
Contact* getGContact ( Net* );
|
Contact* getGContact ( Net* );
|
||||||
inline const vector<Contact*>& getGContacts () const;
|
inline const vector<Contact*>& getGContacts () const;
|
||||||
Contact* breakGoThrough ( Net* net );
|
Segment* hasGoThrough ( Net* ) const;
|
||||||
|
Contact* breakGoThrough ( Net* );
|
||||||
bool unrefContact ( Contact* );
|
bool unrefContact ( Contact* );
|
||||||
void setSouthWestCorner ( DbU::Unit x, DbU::Unit y );
|
void setSouthWestCorner ( DbU::Unit x, DbU::Unit y );
|
||||||
void cleanupGlobal ();
|
void cleanupGlobal ();
|
||||||
|
|
|
@ -72,6 +72,12 @@ namespace {
|
||||||
//unsigned const NonConvexOpt = 0x0200;
|
//unsigned const NonConvexOpt = 0x0200;
|
||||||
|
|
||||||
|
|
||||||
|
Instance* extractInstance ( const RoutingPad* rp )
|
||||||
|
{
|
||||||
|
return rp->getOccurrence().getPath().getTailInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
string extractInstanceName ( const RoutingPad* rp )
|
string extractInstanceName ( const RoutingPad* rp )
|
||||||
{
|
{
|
||||||
ostringstream name;
|
ostringstream name;
|
||||||
|
@ -300,7 +306,8 @@ namespace Etesian {
|
||||||
, _placementLB (NULL)
|
, _placementLB (NULL)
|
||||||
, _placementUB (NULL)
|
, _placementUB (NULL)
|
||||||
, _densityLimits(NULL)
|
, _densityLimits(NULL)
|
||||||
, _cellsToIds ()
|
, _netsToIds ()
|
||||||
|
, _instsToIds ()
|
||||||
, _idsToInsts ()
|
, _idsToInsts ()
|
||||||
, _idsToNets ()
|
, _idsToNets ()
|
||||||
, _viewer (NULL)
|
, _viewer (NULL)
|
||||||
|
@ -410,8 +417,11 @@ namespace Etesian {
|
||||||
delete _placementUB;
|
delete _placementUB;
|
||||||
delete _densityLimits;
|
delete _densityLimits;
|
||||||
|
|
||||||
unordered_map<string,unsigned int> emptyCellsToIds;
|
NetsToIds emptyNetsToIds;
|
||||||
_cellsToIds.swap( emptyCellsToIds );
|
_netsToIds.swap( emptyNetsToIds );
|
||||||
|
|
||||||
|
InstancesToIds emptyInstsToIds;
|
||||||
|
_instsToIds.swap( emptyInstsToIds );
|
||||||
|
|
||||||
vector<InstanceInfos> emptyIdsToInsts;
|
vector<InstanceInfos> emptyIdsToInsts;
|
||||||
_idsToInsts.swap( emptyIdsToInsts );
|
_idsToInsts.swap( emptyIdsToInsts );
|
||||||
|
@ -701,8 +711,8 @@ namespace Etesian {
|
||||||
|
|
||||||
cmess1 << " - Building RoutingPads (transhierarchical) ..." << endl;
|
cmess1 << " - Building RoutingPads (transhierarchical) ..." << endl;
|
||||||
//getCell()->flattenNets( Cell::Flags::BuildRings|Cell::Flags::NoClockFlatten );
|
//getCell()->flattenNets( Cell::Flags::BuildRings|Cell::Flags::NoClockFlatten );
|
||||||
getCell()->flattenNets( getBlockInstance(), Cell::Flags::NoClockFlatten );
|
//getCell()->flattenNets( getBlockInstance(), Cell::Flags::NoClockFlatten );
|
||||||
|
getCell()->flattenNets( NULL, Cell::Flags::NoClockFlatten );
|
||||||
|
|
||||||
bool tooManyInstances = false;
|
bool tooManyInstances = false;
|
||||||
index_t instanceId = 0;
|
index_t instanceId = 0;
|
||||||
|
@ -725,8 +735,8 @@ namespace Etesian {
|
||||||
positions[instanceId] = point<int_t>( xpos, ypos );
|
positions[instanceId] = point<int_t>( xpos, ypos );
|
||||||
instances[instanceId].attributes = 0;
|
instances[instanceId].attributes = 0;
|
||||||
|
|
||||||
_cellsToIds.insert( make_pair(getString(instance->getName()),instanceId) );
|
_instsToIds.insert( make_pair(instance,instanceId) );
|
||||||
_idsToInsts.push_back( make_tuple(instance,0,0) );
|
_idsToInsts.push_back( make_tuple(instance,vector<RoutingPad*>()) );
|
||||||
// cerr << "FIXED id=" << instanceId
|
// cerr << "FIXED id=" << instanceId
|
||||||
// << " " << instance << " size:(" << xsize << " " << ysize
|
// << " " << instance << " size:(" << xsize << " " << ysize
|
||||||
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
|
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
|
||||||
|
@ -799,8 +809,8 @@ namespace Etesian {
|
||||||
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
|
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cellsToIds.insert( make_pair(instanceName,instanceId) );
|
_instsToIds.insert( make_pair(instance,instanceId) );
|
||||||
_idsToInsts.push_back( make_tuple(instance,0,0) );
|
_idsToInsts.push_back( make_tuple(instance,vector<RoutingPad*>()) );
|
||||||
++instanceId;
|
++instanceId;
|
||||||
dots.dot();
|
dots.dot();
|
||||||
}
|
}
|
||||||
|
@ -862,45 +872,56 @@ namespace Etesian {
|
||||||
|
|
||||||
dots.dot();
|
dots.dot();
|
||||||
|
|
||||||
|
_netsToIds.insert( make_pair(net,netId) );
|
||||||
|
_idsToNets[netId] = make_tuple( net, _instsToIds.size(), 0 );
|
||||||
nets[netId] = temporary_net( netId, 1 );
|
nets[netId] = temporary_net( netId, 1 );
|
||||||
_idsToNets[netId] = make_tuple( net, _cellsToIds.size(), 0 );
|
|
||||||
|
|
||||||
//cerr << "+ " << net << endl;
|
//cerr << "+ " << net << endl;
|
||||||
|
|
||||||
for ( Pin* pin : net->getPins() ) {
|
|
||||||
// For Gabriel Gouvine : the position of this pin should be added as a fixed
|
|
||||||
// attractor in Coloquinte. May be outside the placement area.
|
|
||||||
Point pt = pin->getPosition();
|
|
||||||
topTransformation.applyOn(pt);
|
|
||||||
int_t xpin = pt.getX() / vpitch;
|
|
||||||
int_t ypin = pt.getY() / hpitch;
|
|
||||||
// Dummy last instance
|
|
||||||
pins.push_back( temporary_pin( point<int_t>(xpin,ypin), instanceId, netId ) );
|
|
||||||
//cerr << "Outside Pin: " << pin << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
string topCellInstancePin = getString(getCell()->getName()) + ":C";
|
string topCellInstancePin = getString(getCell()->getName()) + ":C";
|
||||||
|
|
||||||
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
||||||
if (getBlockInstance() and (rp->getOccurrence().getPath().getHeadInstance() != getBlockInstance())) {
|
Path path = rp->getOccurrence().getPath();
|
||||||
|
Pin* pin = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
|
||||||
|
if (pin) {
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
Point pt = rp->getCenter();
|
||||||
|
int_t xpin = pt.getX() / vpitch;
|
||||||
|
int_t ypin = pt.getY() / hpitch;
|
||||||
|
// Dummy last instance
|
||||||
|
pins.push_back( temporary_pin( point<int_t>(xpin,ypin), instanceId, netId ) );
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getBlockInstance()) {
|
||||||
// For Gabriel Gouvine : if there are multiple blocks (i.e. we have a true
|
// For Gabriel Gouvine : if there are multiple blocks (i.e. we have a true
|
||||||
// floorplan, there may be RoutingPad that are elsewhere. We should check
|
// floorplan, there may be RoutingPad that are elsewhere. We should check
|
||||||
// that the RP is placed or is inside a define area (the abutment box of
|
// that the RP is placed or is inside a define area (the abutment box of
|
||||||
// it's own block). No example yet of that case, though.
|
// it's own block). No example yet of that case, though.
|
||||||
cerr << Warning("Net %s has a routing pad that is not rooted at the placed instance.", getString(net).c_str()) << endl;
|
if (path.getHeadInstance() != getBlockInstance()) {
|
||||||
|
cerr << Warning( "EtesianEngine::toColoquinte(): Net %s has a RoutingPad that is not rooted at the placed instance.\n"
|
||||||
|
" * Placed instance: %s\n"
|
||||||
|
" * RoutingPad: %s"
|
||||||
|
, getString(net).c_str()
|
||||||
|
, getString(getBlockInstance()).c_str()
|
||||||
|
, getString(rp->getOccurrence()).c_str()
|
||||||
|
) << endl;
|
||||||
//cerr << "Outside RP: " << rp << endl;
|
//cerr << "Outside RP: " << rp << endl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Instance* instance = extractInstance ( rp );
|
||||||
string insName = extractInstanceName( rp );
|
string insName = extractInstanceName( rp );
|
||||||
Point offset = extractRpOffset ( rp );
|
Point offset = extractRpOffset ( rp );
|
||||||
|
|
||||||
int_t xpin = offset.getX() / vpitch;
|
int_t xpin = offset.getX() / vpitch;
|
||||||
int_t ypin = offset.getY() / hpitch;
|
int_t ypin = offset.getY() / hpitch;
|
||||||
|
|
||||||
auto iid = _cellsToIds.find( insName );
|
auto iid = _instsToIds.find( instance );
|
||||||
if (iid == _cellsToIds.end()) {
|
if (iid == _instsToIds.end()) {
|
||||||
if (insName != topCellInstancePin) {
|
if (not instance) {
|
||||||
cerr << Error( "Unable to lookup instance \"%s\".", insName.c_str() ) << endl;
|
cerr << Error( "Unable to lookup instance \"%s\".", insName.c_str() ) << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -914,8 +935,6 @@ namespace Etesian {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//cerr << "| " << rp << " pos:(" << xpin << " " << ypin << ")" << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
netId++;
|
netId++;
|
||||||
|
@ -1052,7 +1071,7 @@ namespace Etesian {
|
||||||
ostringstream label;
|
ostringstream label;
|
||||||
label.str("");
|
label.str("");
|
||||||
label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "] "
|
label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "] "
|
||||||
<< setw(5) << setprecision(4) << linearDisruption << "% Bipart.";
|
<< setw(7) << fixed << setprecision(1) << linearDisruption << "% Bipart.";
|
||||||
_progressReport1(label.str() );
|
_progressReport1(label.str() );
|
||||||
|
|
||||||
upperWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementUB));
|
upperWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementUB));
|
||||||
|
@ -1103,7 +1122,7 @@ namespace Etesian {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if ((linearDisruption < getAntennaInsertThreshold()*100.0) and not antennaDone) {
|
if ((linearDisruption < getAntennaInsertThreshold()*100.0) and not antennaDone) {
|
||||||
antennaProtect();
|
//antennaProtect();
|
||||||
antennaDone = true;
|
antennaDone = true;
|
||||||
}
|
}
|
||||||
// First way to exit the loop: UB and LB difference is <10%
|
// First way to exit the loop: UB and LB difference is <10%
|
||||||
|
@ -1188,32 +1207,34 @@ namespace Etesian {
|
||||||
|
|
||||||
for ( coloquinte::index_t inet=0 ; inet < _circuit->net_cnt() ; ++inet ) {
|
for ( coloquinte::index_t inet=0 ; inet < _circuit->net_cnt() ; ++inet ) {
|
||||||
DbU::Unit rsmt = toDbU( coloquinte::get_RSMT_length( *_circuit, *_placementUB, inet ) );
|
DbU::Unit rsmt = toDbU( coloquinte::get_RSMT_length( *_circuit, *_placementUB, inet ) );
|
||||||
size_t idriver = std::get<1>( _idsToNets[inet] );
|
|
||||||
if (idriver >= _cellsToIds.size()) continue;
|
|
||||||
|
|
||||||
Instance* instance = std::get<0>( _idsToInsts[idriver] );
|
|
||||||
string masterName = getString( instance->getMasterCell()->getName() );
|
|
||||||
uint32_t drivePower = 1;
|
|
||||||
if (masterName.substr(masterName.size()-3,2) == "_x") {
|
|
||||||
drivePower = std::stoi( masterName.substr(masterName.size()-1) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rsmt > drivePower*maxWL) {
|
|
||||||
Net* net = std::get<0>( _idsToNets[inet] );
|
Net* net = std::get<0>( _idsToNets[inet] );
|
||||||
|
|
||||||
|
if ((rsmt > maxWL) or net->isExternal()) {
|
||||||
cdebug_log(122,0) << "| Net [" << inet << "] \"" << net->getName() << "\" may have antenna effect, "
|
cdebug_log(122,0) << "| Net [" << inet << "] \"" << net->getName() << "\" may have antenna effect, "
|
||||||
<< DbU::getValueString(rsmt)
|
<< DbU::getValueString(rsmt)
|
||||||
<< " drive=" << drivePower
|
|
||||||
<< " \"" << masterName << "\""
|
|
||||||
<< endl;
|
<< endl;
|
||||||
std::get<2>( _idsToNets[inet] ) |= NeedsDiode;
|
std::get<2>( _idsToNets[inet] ) |= NeedsDiode;
|
||||||
std::get<2>( _idsToInsts[idriver] ) |= NeedsDiode;
|
|
||||||
std::get<1>( _idsToInsts[idriver] ) = inet;
|
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
||||||
coloquinte::point<int_t> cell_size = _circuit->get_cell_size(idriver);
|
Segment* segment = dynamic_cast<Segment*>( rp->getOccurrence().getEntity() );
|
||||||
cell_size.x += diodeWidth;
|
if (not segment) continue;
|
||||||
_circuit->set_cell_size( idriver, cell_size );
|
if (segment->getNet()->getDirection() & Net::Direction::DirOut) continue;
|
||||||
|
|
||||||
|
Instance* instance = extractInstance( rp );
|
||||||
|
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto iinst = _instsToIds.find( instance );
|
||||||
|
if (iinst == _instsToIds.end()) continue;
|
||||||
|
|
||||||
|
std::get<1>( _idsToInsts[ (*iinst).second ] ).push_back( rp );
|
||||||
|
coloquinte::point<int_t> cell_size = _circuit->get_cell_size( (*iinst).second );
|
||||||
|
cell_size.x += 2*diodeWidth;
|
||||||
|
_circuit->set_cell_size( (*iinst).second, cell_size );
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
cmess1 << ::Dots::asInt( " - Inserted diodes", count ) << endl;
|
cmess1 << ::Dots::asInt( " - Inserted diodes", count ) << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1383,7 +1404,8 @@ namespace Etesian {
|
||||||
if (getBlockInstance()) topTransformation = getBlockInstance()->getTransformation();
|
if (getBlockInstance()) topTransformation = getBlockInstance()->getTransformation();
|
||||||
topTransformation.invert();
|
topTransformation.invert();
|
||||||
|
|
||||||
vector< tuple<Occurrence,size_t,Transformation> > diodeMasters;
|
DbU::Unit diodeWidth = (_diodeCell) ? _diodeCell->getAbutmentBox().getWidth() : 0;
|
||||||
|
vector< tuple<RoutingPad*,Transformation> > diodeInsts;
|
||||||
|
|
||||||
for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences(getBlockInstance()) )
|
for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences(getBlockInstance()) )
|
||||||
{
|
{
|
||||||
|
@ -1396,14 +1418,14 @@ namespace Etesian {
|
||||||
instanceName.erase( 0, 1 );
|
instanceName.erase( 0, 1 );
|
||||||
instanceName.erase( instanceName.size()-1 );
|
instanceName.erase( instanceName.size()-1 );
|
||||||
|
|
||||||
auto iid = _cellsToIds.find( instanceName );
|
auto iid = _instsToIds.find( instance );
|
||||||
if (iid == _cellsToIds.end() ) {
|
if (iid == _instsToIds.end() ) {
|
||||||
cerr << Error( "Unable to lookup instance <%s>.", instanceName.c_str() ) << endl;
|
cerr << Error( "Unable to lookup instance <%s>.", instanceName.c_str() ) << endl;
|
||||||
} else {
|
} else {
|
||||||
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED)
|
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32_t outputSide = getOutputSide( instance->getMasterCell() );
|
//uint32_t outputSide = getOutputSide( instance->getMasterCell() );
|
||||||
point<int_t> position = placement->positions_[(*iid).second];
|
point<int_t> position = placement->positions_[(*iid).second];
|
||||||
Transformation cellTrans = toTransformation( position
|
Transformation cellTrans = toTransformation( position
|
||||||
, placement->orientations_[(*iid).second]
|
, placement->orientations_[(*iid).second]
|
||||||
|
@ -1412,33 +1434,28 @@ namespace Etesian {
|
||||||
, vpitch
|
, vpitch
|
||||||
);
|
);
|
||||||
topTransformation.applyOn( cellTrans );
|
topTransformation.applyOn( cellTrans );
|
||||||
//cerr << "Setting <" << instanceName << " @" << instancePosition << endl;
|
//if (flags & FinalStage)
|
||||||
|
// cerr << "Raw position of <" << instanceName << " @" << cellTrans << endl;
|
||||||
|
|
||||||
if ((flags & FinalStage) and (std::get<2>(_idsToInsts[(*iid).second]) & NeedsDiode)) {
|
const vector<RoutingPad*>& rps = std::get<1>( _idsToInsts[(*iid).second] );
|
||||||
Transformation diodeTrans;
|
if ((flags & FinalStage) and not rps.empty()) {
|
||||||
|
DbU::Unit sign = 1;
|
||||||
if (outputSide & RightSide) {
|
DbU::Unit cellWidth = instance->getMasterCell()->getAbutmentBox().getWidth();
|
||||||
DbU::Unit dx = instance ->getMasterCell()->getAbutmentBox().getWidth();
|
cdebug_log(122,0) << "cellWidth=" << DbU::getValueString(cellWidth) << endl;
|
||||||
|
cdebug_log(122,0) << "diodeWidth=" << DbU::getValueString(diodeWidth) << endl;
|
||||||
if ( (cellTrans.getOrientation() == Transformation::Orientation::R2)
|
if ( (cellTrans.getOrientation() == Transformation::Orientation::R2)
|
||||||
or (cellTrans.getOrientation() == Transformation::Orientation::MX))
|
or (cellTrans.getOrientation() == Transformation::Orientation::MX)) {
|
||||||
dx = -dx;
|
sign = -1;
|
||||||
diodeTrans = Transformation( cellTrans.getTx() + dx
|
}
|
||||||
, cellTrans.getTy()
|
for ( size_t i=0 ; i<rps.size() ; ++i ) {
|
||||||
, cellTrans.getOrientation() );
|
cdebug_log(122,0) << "diode position [" << i << "] " << DbU::getValueString((DbU::Unit)(cellTrans.getTx() + cellWidth + i*diodeWidth)) << endl;
|
||||||
} else {
|
diodeInsts.push_back
|
||||||
DbU::Unit dx = _diodeCell->getAbutmentBox().getWidth();
|
( make_tuple( rps[i]
|
||||||
if ( (cellTrans.getOrientation() == Transformation::Orientation::R2)
|
, Transformation( cellTrans.getTx() + sign * (cellWidth + i*diodeWidth)
|
||||||
or (cellTrans.getOrientation() == Transformation::Orientation::MX))
|
, cellTrans.getTy()
|
||||||
dx = -dx;
|
, cellTrans.getOrientation() ))
|
||||||
diodeTrans = cellTrans;
|
);
|
||||||
cellTrans = Transformation( diodeTrans.getTx() + dx
|
|
||||||
, diodeTrans.getTy()
|
|
||||||
, diodeTrans.getOrientation() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diodeMasters.push_back( make_tuple( occurrence
|
|
||||||
, std::get<1>(_idsToInsts[(*iid).second])
|
|
||||||
, diodeTrans ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is temporary as it's not trans-hierarchic: we ignore the positions
|
// This is temporary as it's not trans-hierarchic: we ignore the positions
|
||||||
|
@ -1456,35 +1473,28 @@ namespace Etesian {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto diodeInfos : diodeMasters ) {
|
for ( auto diodeInfos : diodeInsts ) {
|
||||||
Net* topNet = std::get<0>( _idsToNets[ std::get<1>(diodeInfos) ] );
|
RoutingPad* rp = std::get<0>( diodeInfos );
|
||||||
Instance* instance = static_cast<Instance*>( std::get<0>(diodeInfos).getEntity() );
|
Net* topNet = rp->getNet();
|
||||||
|
Instance* instance = extractInstance( rp );
|
||||||
Cell* ownerCell = instance->getCell();
|
Cell* ownerCell = instance->getCell();
|
||||||
Instance* diode = _createDiode( ownerCell );
|
Instance* diode = _createDiode( ownerCell );
|
||||||
diode->setTransformation( std::get<2>( diodeInfos ));
|
diode->setTransformation ( std::get<1>( diodeInfos ));
|
||||||
diode->setPlacementStatus( Instance::PlacementStatus::PLACED );
|
diode->setPlacementStatus( Instance::PlacementStatus::PLACED );
|
||||||
|
|
||||||
Net* driverOutput = NULL;
|
|
||||||
for ( Net* net : instance->getMasterCell()->getNets() ) {
|
|
||||||
if (net->isSupply() or not net->isExternal()) continue;
|
|
||||||
if (net->getDirection() & Net::Direction::DirOut) {
|
|
||||||
driverOutput = net;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diodeOutput and driverOutput) {
|
|
||||||
cdebug_log(122,0) << "Bind:" << endl;
|
|
||||||
Plug* diodePlug = diode ->getPlug( diodeOutput );
|
|
||||||
Plug* driverPlug = instance->getPlug( driverOutput );
|
|
||||||
diodePlug->setNet( driverPlug->getNet() );
|
|
||||||
|
|
||||||
cdebug_log(122,0) << "Driver net=" << topNet << endl;
|
cdebug_log(122,0) << "Driver net=" << topNet << endl;
|
||||||
cdebug_log(122,0) << " " << instance << " @" << instance->getTransformation() << endl;
|
cdebug_log(122,0) << " " << instance << " @" << instance->getTransformation() << endl;
|
||||||
|
|
||||||
|
Plug* sinkPlug = dynamic_cast<Plug*>( rp->getPlugOccurrence().getEntity() );
|
||||||
|
if (sinkPlug) {
|
||||||
|
cdebug_log(122,0) << " Bind diode input:" << endl;
|
||||||
|
Plug* diodePlug = diode->getPlug( diodeOutput );
|
||||||
|
diodePlug->setNet( sinkPlug->getNet() );
|
||||||
|
|
||||||
cdebug_log(122,0) << " " << diode << " @" << diode ->getTransformation() << endl;
|
cdebug_log(122,0) << " " << diode << " @" << diode ->getTransformation() << endl;
|
||||||
cdebug_log(122,0) << " topNet->getCell():" << topNet->getCell() << endl;
|
cdebug_log(122,0) << " topNet->getCell():" << topNet->getCell() << endl;
|
||||||
cdebug_log(122,0) << " " << std::get<0>(diodeInfos).getPath() << endl;
|
cdebug_log(122,0) << " " << rp->getOccurrence().getPath() << endl;
|
||||||
Path path = std::get<0>(diodeInfos).getPath();
|
Path path = rp->getOccurrence().getPath().getHeadPath();
|
||||||
RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea );
|
RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1499,7 +1509,15 @@ namespace Etesian {
|
||||||
Instance* EtesianEngine::_createDiode ( Cell* owner )
|
Instance* EtesianEngine::_createDiode ( Cell* owner )
|
||||||
{
|
{
|
||||||
if (not _diodeCell) return NULL;
|
if (not _diodeCell) return NULL;
|
||||||
return Instance::create( owner, string("diode_")+getString(_getNewDiodeId()), _diodeCell );
|
return Instance::create( owner, getUniqueDiodeName(), _diodeCell );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string EtesianEngine::getUniqueDiodeName ()
|
||||||
|
{
|
||||||
|
ostringstream os;
|
||||||
|
os << "diode_" << _getNewDiodeId();
|
||||||
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
#include "hurricane/Warning.h"
|
#include "hurricane/Warning.h"
|
||||||
#include "hurricane/DataBase.h"
|
#include "hurricane/DataBase.h"
|
||||||
#include "hurricane/UpdateSession.h"
|
#include "hurricane/UpdateSession.h"
|
||||||
|
#include "hurricane/DeepNet.h"
|
||||||
#include "hurricane/Plug.h"
|
#include "hurricane/Plug.h"
|
||||||
|
#include "hurricane/RoutingPad.h"
|
||||||
#include "hurricane/Path.h"
|
#include "hurricane/Path.h"
|
||||||
#include "hurricane/Library.h"
|
#include "hurricane/Library.h"
|
||||||
#include "hurricane/viewer/CellWidget.h"
|
#include "hurricane/viewer/CellWidget.h"
|
||||||
|
@ -38,6 +40,9 @@ namespace Etesian {
|
||||||
using Hurricane::Transformation;
|
using Hurricane::Transformation;
|
||||||
using Hurricane::DataBase;
|
using Hurricane::DataBase;
|
||||||
using Hurricane::Library;
|
using Hurricane::Library;
|
||||||
|
using Hurricane::DeepNet;
|
||||||
|
using Hurricane::Plug;
|
||||||
|
using Hurricane::RoutingPad;
|
||||||
using Hurricane::UpdateSession;
|
using Hurricane::UpdateSession;
|
||||||
using CRL::AllianceFramework;
|
using CRL::AllianceFramework;
|
||||||
using CRL::CatalogExtension;
|
using CRL::CatalogExtension;
|
||||||
|
@ -238,26 +243,29 @@ namespace Etesian {
|
||||||
if (feed == NULL) break;
|
if (feed == NULL) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Point blockPoint = getEtesian()->toBlock( Point(xtie,_ybottom) );
|
||||||
Instance* instance = Instance::create
|
Instance* instance = Instance::create
|
||||||
( getEtesian()->getBlockCell()
|
( getEtesian()->getBlockCell()
|
||||||
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
|
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
|
||||||
, feed
|
, feed
|
||||||
, getTransformation( feed->getAbutmentBox()
|
, getTransformation( feed->getAbutmentBox()
|
||||||
, xtie
|
, blockPoint.getX()
|
||||||
, _ybottom
|
, blockPoint.getY()
|
||||||
, (yspin) ? Transformation::Orientation::MY
|
, (yspin) ? Transformation::Orientation::MY
|
||||||
: Transformation::Orientation::ID
|
: Transformation::Orientation::ID
|
||||||
)
|
)
|
||||||
, Instance::PlacementStatus::PLACED
|
, Instance::PlacementStatus::PLACED
|
||||||
);
|
);
|
||||||
_tiles.insert( before
|
_tiles.insert( before
|
||||||
, Tile( xtie, feed->getAbutmentBox().getWidth(), Occurrence(instance) ));
|
, Tile( xtie
|
||||||
|
, feed->getAbutmentBox().getWidth()
|
||||||
|
, getEtesian()->toCell( Occurrence(instance) )));
|
||||||
xtie += feedWidth;
|
xtie += feedWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Instance* Slice::createDiodeUnder ( const Box& diodeArea )
|
Instance* Slice::createDiodeUnder ( RoutingPad* rp, const Box& diodeArea, DbU::Unit xHint )
|
||||||
{
|
{
|
||||||
Cell* diode = getEtesian()->getDiodeCell();
|
Cell* diode = getEtesian()->getDiodeCell();
|
||||||
if (diode == NULL) {
|
if (diode == NULL) {
|
||||||
|
@ -270,15 +278,61 @@ namespace Etesian {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cdebug_log(147,0) << "Slice::createDiodeUnder(): xHint=" << DbU::getValueString(xHint) << endl;
|
||||||
|
cdebug_log(147,0) << " rp=" << rp << endl;
|
||||||
|
cdebug_log(147,0) << " diodeArea=" << diodeArea << endl;
|
||||||
|
|
||||||
|
Instance* blockInst = getEtesian()->getBlockInstance();
|
||||||
Instance* diodeInst = NULL;
|
Instance* diodeInst = NULL;
|
||||||
|
bool foundCandidate = false;
|
||||||
|
auto iCandidate = _tiles.begin();
|
||||||
|
DbU::Unit dCandidate = 0;
|
||||||
for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) {
|
for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) {
|
||||||
if ((*iTile).getXMax() < diodeArea.getXMin()) continue;
|
if ((*iTile).getXMax() <= diodeArea.getXMin()) continue;
|
||||||
if ((*iTile).getXMax() >= diodeArea.getXMax()) break;
|
if ((*iTile).getXMin() >= diodeArea.getXMax()) break;
|
||||||
if ((*iTile).getMasterCell() != feed) continue;
|
if ((*iTile).getMasterCell() != feed) continue;
|
||||||
diodeInst = (*iTile).getInstance();
|
if (blockInst) {
|
||||||
diodeInst->setMasterCell( diode );
|
if ((*iTile).getOccurrence().getPath().getHeadInstance() != blockInst)
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
DbU::Unit distance = std::abs( (*iTile).getXMin() - xHint );
|
||||||
|
if (not foundCandidate or (distance < dCandidate)) {
|
||||||
|
foundCandidate = true;
|
||||||
|
iCandidate = iTile;
|
||||||
|
dCandidate = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not foundCandidate) return NULL;
|
||||||
|
|
||||||
|
auto before = iCandidate;
|
||||||
|
before++;
|
||||||
|
|
||||||
|
DbU::Unit xmin = (*iCandidate).getXMin();
|
||||||
|
DbU::Unit width = (*iCandidate).getWidth();
|
||||||
|
diodeInst = (*iCandidate).getInstance();
|
||||||
|
Transformation transf = diodeInst->getTransformation();
|
||||||
|
diodeInst->destroy();
|
||||||
|
_tiles.erase( iCandidate );
|
||||||
|
|
||||||
|
Occurrence rpOccurrence = rp->getPlugOccurrence();
|
||||||
|
Path instancePath = rpOccurrence.getPath();
|
||||||
|
if (instancePath.isEmpty())
|
||||||
|
transf = getEtesian()->toCell( transf );
|
||||||
|
// transf = getEtesian()->toBlock( transf );
|
||||||
|
// if (instancePath.isEmpty() and blockInst) {
|
||||||
|
// Transformation blockTransf = blockInst->getTransformation();
|
||||||
|
// blockTransf.applyOn( transf );
|
||||||
|
// }
|
||||||
|
Plug* plug = static_cast<Plug*>( rpOccurrence.getEntity() );
|
||||||
|
diodeInst = Instance::create( plug->getCell()
|
||||||
|
, getEtesian()->getUniqueDiodeName()
|
||||||
|
, diode
|
||||||
|
, transf
|
||||||
|
, Instance::PlacementStatus::FIXED );
|
||||||
|
_tiles.insert( before, Tile(xmin,width,Occurrence(diodeInst,instancePath)) );
|
||||||
|
cdebug_log(147,0) << " " << diodeInst << " @" << transf << endl;
|
||||||
|
|
||||||
return diodeInst;
|
return diodeInst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,10 +355,13 @@ namespace Etesian {
|
||||||
Area::Area ( EtesianEngine* etesian )
|
Area::Area ( EtesianEngine* etesian )
|
||||||
: _etesian (etesian)
|
: _etesian (etesian)
|
||||||
, _tieLut ()
|
, _tieLut ()
|
||||||
, _cellAb (etesian->getBlockCell()->getAbutmentBox())
|
, _cellAb (etesian->getCell()->getAbutmentBox())
|
||||||
, _sliceHeight(_etesian->getSliceHeight())
|
, _sliceHeight(_etesian->getSliceHeight())
|
||||||
, _slices ()
|
, _slices ()
|
||||||
{
|
{
|
||||||
|
if (etesian->getBlockInstance())
|
||||||
|
_cellAb = etesian->getBlockInstance()->getAbutmentBox();
|
||||||
|
|
||||||
size_t slicesNb = _cellAb.getHeight() / _sliceHeight;
|
size_t slicesNb = _cellAb.getHeight() / _sliceHeight;
|
||||||
for ( size_t islice=0 ; islice<slicesNb ; ++islice )
|
for ( size_t islice=0 ; islice<slicesNb ; ++islice )
|
||||||
_slices.push_back( new Slice( this, _cellAb.getYMin()+islice*_sliceHeight ) );
|
_slices.push_back( new Slice( this, _cellAb.getYMin()+islice*_sliceHeight ) );
|
||||||
|
@ -569,15 +626,21 @@ namespace Etesian {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Instance* Area::createDiodeUnder ( const Box& diodeArea )
|
Instance* Area::createDiodeUnder ( RoutingPad* rp, const Box& diodeArea, DbU::Unit xHint )
|
||||||
{
|
{
|
||||||
DbU::Unit y = diodeArea.getYCenter();
|
//Transformation toBlockTransf = getEtesian()->getBlockInstance()->getTransformation();
|
||||||
|
//toBlockTransf.invert();
|
||||||
|
Box blockDiodeArea ( diodeArea );
|
||||||
|
//toBlockTransf.applyOn( blockDiodeArea );
|
||||||
|
//xHint += toBlockTransf.getTx();
|
||||||
|
|
||||||
|
DbU::Unit y = blockDiodeArea.getYCenter();
|
||||||
|
|
||||||
if ((y < _cellAb.getYMin()) or (y >= _cellAb.getYMax())) return NULL;
|
if ((y < _cellAb.getYMin()) or (y >= _cellAb.getYMax())) return NULL;
|
||||||
if (not diodeArea.intersect(_cellAb)) return NULL;
|
if (not blockDiodeArea.intersect(_cellAb)) return NULL;
|
||||||
|
|
||||||
size_t islice = (y - _cellAb.getYMin()) / _sliceHeight;
|
size_t islice = (y - _cellAb.getYMin()) / _sliceHeight;
|
||||||
return _slices[islice]->createDiodeUnder( diodeArea );
|
return _slices[islice]->createDiodeUnder( rp, blockDiodeArea, xHint );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -595,18 +658,16 @@ namespace Etesian {
|
||||||
|
|
||||||
if (_area) delete _area;
|
if (_area) delete _area;
|
||||||
_area = new Area ( this );
|
_area = new Area ( this );
|
||||||
Box topCellAb = getBlockCell()->getAbutmentBox();
|
Box topCellAb = getCell()->getAbutmentBox();
|
||||||
|
|
||||||
_area->setSpinSlice0( _yspinSlice0 );
|
_area->setSpinSlice0( _yspinSlice0 );
|
||||||
|
|
||||||
if (getBlockInstance()) {
|
if (getBlockInstance()) {
|
||||||
Transformation toBlockTransf = getBlockInstance()->getTransformation();
|
topCellAb = getBlockInstance()->getAbutmentBox();
|
||||||
toBlockTransf.invert();
|
|
||||||
for ( Instance* instance : getCell()->getInstances() ) {
|
for ( Instance* instance : getCell()->getInstances() ) {
|
||||||
if (instance == getBlockInstance()) continue;
|
if (instance == getBlockInstance()) continue;
|
||||||
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) {
|
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) {
|
||||||
Box overlapAb = instance->getAbutmentBox();
|
Box overlapAb = instance->getAbutmentBox();
|
||||||
toBlockTransf.applyOn( overlapAb );
|
|
||||||
overlapAb = topCellAb.getIntersection( overlapAb );
|
overlapAb = topCellAb.getIntersection( overlapAb );
|
||||||
if (not overlapAb.isEmpty()) {
|
if (not overlapAb.isEmpty()) {
|
||||||
_area->merge( Occurrence(instance), overlapAb );
|
_area->merge( Occurrence(instance), overlapAb );
|
||||||
|
@ -625,19 +686,23 @@ namespace Etesian {
|
||||||
, getString(instance->getName()).c_str() ) << endl;
|
, getString(instance->getName()).c_str() ) << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
Box instanceAb = masterCell->getAbutmentBox();
|
Box instanceAb = instance->getAbutmentBox();
|
||||||
|
Occurrence cellOccurrence = toCell( occurrence );
|
||||||
Transformation instanceTransf = instance->getTransformation();
|
cellOccurrence.getPath().getTransformation().applyOn( instanceAb );
|
||||||
occurrence.getPath().getTransformation().applyOn( instanceTransf );
|
|
||||||
instanceTransf.applyOn( instanceAb );
|
|
||||||
|
|
||||||
if (not topCellAb.contains(instanceAb)) {
|
if (not topCellAb.contains(instanceAb)) {
|
||||||
cerr << Warning( "EtesianEngine::readSlices(): Instance %s is not fully enclosed in the top cell."
|
cerr << Warning( "EtesianEngine::readSlices(): Instance %s is not fully enclosed in the top cell.\n"
|
||||||
, getString(instance->getName()).c_str() ) << endl;
|
" * topCellAb=%s\n"
|
||||||
|
" * instanceAb=%s cell=%s"
|
||||||
|
, getString(instance->getName()).c_str()
|
||||||
|
, getString(topCellAb).c_str()
|
||||||
|
, getString(instanceAb).c_str()
|
||||||
|
, getString(instance->getCell()).c_str()
|
||||||
|
) << endl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_area->merge( occurrence, instanceAb );
|
_area->merge( cellOccurrence, instanceAb );
|
||||||
}
|
}
|
||||||
|
|
||||||
_area->buildSubSlices();
|
_area->buildSubSlices();
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
namespace Hurricane {
|
namespace Hurricane {
|
||||||
class Layer;
|
class Layer;
|
||||||
class Net;
|
class Net;
|
||||||
|
class RoutingPad;
|
||||||
class Cell;
|
class Cell;
|
||||||
class CellWidget;
|
class CellWidget;
|
||||||
class CellViewer;
|
class CellViewer;
|
||||||
|
@ -43,10 +44,15 @@ namespace Etesian {
|
||||||
using Hurricane::Timer;
|
using Hurricane::Timer;
|
||||||
using Hurricane::Name;
|
using Hurricane::Name;
|
||||||
using Hurricane::Layer;
|
using Hurricane::Layer;
|
||||||
|
using Hurricane::DBo;
|
||||||
using Hurricane::Net;
|
using Hurricane::Net;
|
||||||
|
using Hurricane::RoutingPad;
|
||||||
using Hurricane::Cell;
|
using Hurricane::Cell;
|
||||||
using Hurricane::Record;
|
using Hurricane::Record;
|
||||||
using Hurricane::Instance;
|
using Hurricane::Instance;
|
||||||
|
using Hurricane::Point;
|
||||||
|
using Hurricane::Path;
|
||||||
|
using Hurricane::Transformation;
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -61,7 +67,9 @@ namespace Etesian {
|
||||||
public:
|
public:
|
||||||
typedef ToolEngine Super;
|
typedef ToolEngine Super;
|
||||||
typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
|
typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
|
||||||
typedef std::tuple<Instance*,int32_t,uint32_t> InstanceInfos;
|
typedef std::tuple<Instance*, std::vector<RoutingPad*> > InstanceInfos;
|
||||||
|
typedef std::map<Instance*,size_t,DBo::CompareById> InstancesToIds;
|
||||||
|
typedef std::map<Net*,size_t,DBo::CompareById> NetsToIds;
|
||||||
public:
|
public:
|
||||||
static const Name& staticGetName ();
|
static const Name& staticGetName ();
|
||||||
static EtesianEngine* create ( Cell* );
|
static EtesianEngine* create ( Cell* );
|
||||||
|
@ -88,6 +96,8 @@ namespace Etesian {
|
||||||
inline DbU::Unit getLatchUpDistance () const;
|
inline DbU::Unit getLatchUpDistance () const;
|
||||||
inline const FeedCells& getFeedCells () const;
|
inline const FeedCells& getFeedCells () const;
|
||||||
inline Cell* getDiodeCell () const;
|
inline Cell* getDiodeCell () const;
|
||||||
|
std::string getUniqueDiodeName ();
|
||||||
|
inline Area* getArea () const;
|
||||||
inline Hurricane::CellViewer* getViewer () const;
|
inline Hurricane::CellViewer* getViewer () const;
|
||||||
inline void setViewer ( Hurricane::CellViewer* );
|
inline void setViewer ( Hurricane::CellViewer* );
|
||||||
inline Cell* getBlockCell () const;
|
inline Cell* getBlockCell () const;
|
||||||
|
@ -103,6 +113,13 @@ namespace Etesian {
|
||||||
void clearColoquinte ();
|
void clearColoquinte ();
|
||||||
void loadLeafCellLayouts ();
|
void loadLeafCellLayouts ();
|
||||||
inline DbU::Unit toDbU ( int64_t ) const;
|
inline DbU::Unit toDbU ( int64_t ) const;
|
||||||
|
inline Occurrence toCell ( Occurrence ) const;
|
||||||
|
inline Point toCell ( const Point& ) const;
|
||||||
|
inline Transformation toCell ( Transformation ) const;
|
||||||
|
inline Path toBlock ( Path ) const;
|
||||||
|
inline Occurrence toBlock ( Occurrence ) const;
|
||||||
|
inline Point toBlock ( const Point& ) const;
|
||||||
|
inline Transformation toBlock ( const Transformation& ) const;
|
||||||
size_t toColoquinte ();
|
size_t toColoquinte ();
|
||||||
void preplace ();
|
void preplace ();
|
||||||
void roughLegalize ( float minDisruption, unsigned options );
|
void roughLegalize ( float minDisruption, unsigned options );
|
||||||
|
@ -132,7 +149,8 @@ namespace Etesian {
|
||||||
coloquinte::placement_t* _placementLB;
|
coloquinte::placement_t* _placementLB;
|
||||||
coloquinte::placement_t* _placementUB;
|
coloquinte::placement_t* _placementUB;
|
||||||
coloquinte::density_restrictions* _densityLimits;
|
coloquinte::density_restrictions* _densityLimits;
|
||||||
std::unordered_map<string,unsigned int> _cellsToIds;
|
NetsToIds _netsToIds;
|
||||||
|
InstancesToIds _instsToIds;
|
||||||
std::vector<InstanceInfos> _idsToInsts;
|
std::vector<InstanceInfos> _idsToInsts;
|
||||||
std::vector<NetInfos> _idsToNets;
|
std::vector<NetInfos> _idsToNets;
|
||||||
Hurricane::CellViewer* _viewer;
|
Hurricane::CellViewer* _viewer;
|
||||||
|
@ -197,6 +215,81 @@ namespace Etesian {
|
||||||
inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); }
|
inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); }
|
||||||
inline DbU::Unit EtesianEngine::toDbU ( int64_t v ) const { return v*getSliceStep(); }
|
inline DbU::Unit EtesianEngine::toDbU ( int64_t v ) const { return v*getSliceStep(); }
|
||||||
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
|
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
|
||||||
|
inline Area* EtesianEngine::getArea () const { return _area; }
|
||||||
|
|
||||||
|
|
||||||
|
inline Occurrence EtesianEngine::toCell ( Occurrence blockOccurrence ) const
|
||||||
|
{
|
||||||
|
if (not _block) return blockOccurrence;
|
||||||
|
if (blockOccurrence.getOwnerCell() != getBlockCell()) {
|
||||||
|
std::cerr << Error( "EtesianEngine::toCell(Occurrence): %s"
|
||||||
|
"\n Is *not* rooted to the block %s but to %s."
|
||||||
|
, getString(blockOccurrence).c_str()
|
||||||
|
, getString(getBlockCell()).c_str()
|
||||||
|
, getString(blockOccurrence.getOwnerCell()).c_str()
|
||||||
|
) << std::endl;
|
||||||
|
return blockOccurrence;
|
||||||
|
}
|
||||||
|
return Occurrence( blockOccurrence.getEntity(), Path(_block,blockOccurrence.getPath()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Point EtesianEngine::toCell ( const Point& blockPoint ) const
|
||||||
|
{
|
||||||
|
if (not _block) return blockPoint;
|
||||||
|
Point cellPoint = blockPoint;
|
||||||
|
_block->getTransformation().applyOn( cellPoint );
|
||||||
|
return cellPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Transformation EtesianEngine::toCell ( Transformation blockTransf ) const
|
||||||
|
{
|
||||||
|
if (not _block) return blockTransf;
|
||||||
|
return _block->getTransformation().getTransformation( blockTransf );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Path EtesianEngine::toBlock ( Path cellPath ) const
|
||||||
|
{
|
||||||
|
if (not _block) return cellPath;
|
||||||
|
if (cellPath.getHeadInstance() != getBlockInstance()) {
|
||||||
|
std::cerr << Error( "EtesianEngine::toBlock(Path): %s"
|
||||||
|
"\n Do *not* go through the block %s but through %s."
|
||||||
|
, getString(cellPath).c_str()
|
||||||
|
, getString(getBlockInstance()).c_str()
|
||||||
|
, getString(cellPath.getHeadInstance()).c_str()
|
||||||
|
) << std::endl;
|
||||||
|
return cellPath;
|
||||||
|
}
|
||||||
|
return cellPath.getTailPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Occurrence EtesianEngine::toBlock ( Occurrence cellOccurrence ) const
|
||||||
|
{
|
||||||
|
if (not _block) return cellOccurrence;
|
||||||
|
return Occurrence( cellOccurrence.getEntity(), toBlock(cellOccurrence.getPath()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Point EtesianEngine::toBlock ( const Point& cellPoint ) const
|
||||||
|
{
|
||||||
|
if (not _block) return cellPoint;
|
||||||
|
Point blockPoint = cellPoint;
|
||||||
|
Transformation blockTransf = _block->getTransformation();
|
||||||
|
blockTransf.invert().applyOn( blockPoint );
|
||||||
|
return blockPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline Transformation EtesianEngine::toBlock ( const Transformation& cellTransf ) const
|
||||||
|
{
|
||||||
|
if (not _block) return cellTransf;
|
||||||
|
Transformation blockTransf = _block->getTransformation();
|
||||||
|
return blockTransf.invert().getTransformation( cellTransf );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Variables.
|
// Variables.
|
||||||
extern const char* missingEtesian;
|
extern const char* missingEtesian;
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#include "hurricane/Interval.h"
|
#include "hurricane/Interval.h"
|
||||||
#include "hurricane/Instance.h"
|
#include "hurricane/Instance.h"
|
||||||
#include "hurricane/Occurrence.h"
|
#include "hurricane/Occurrence.h"
|
||||||
|
namespace Hurricane {
|
||||||
|
class RoutingPad;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace Etesian {
|
namespace Etesian {
|
||||||
|
@ -32,6 +35,7 @@ namespace Etesian {
|
||||||
using Hurricane::Interval;
|
using Hurricane::Interval;
|
||||||
using Hurricane::DBo;
|
using Hurricane::DBo;
|
||||||
using Hurricane::Cell;
|
using Hurricane::Cell;
|
||||||
|
using Hurricane::RoutingPad;
|
||||||
using Hurricane::Instance;
|
using Hurricane::Instance;
|
||||||
using Hurricane::Transformation;
|
using Hurricane::Transformation;
|
||||||
using Hurricane::Occurrence;
|
using Hurricane::Occurrence;
|
||||||
|
@ -232,7 +236,7 @@ namespace Etesian {
|
||||||
void buildSubSlices ();
|
void buildSubSlices ();
|
||||||
void showSubSlices ();
|
void showSubSlices ();
|
||||||
void insertTies ( DbU::Unit latchUpMax );
|
void insertTies ( DbU::Unit latchUpMax );
|
||||||
Instance* createDiodeUnder ( const Box& );
|
Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint );
|
||||||
inline std::string _getString () const;
|
inline std::string _getString () const;
|
||||||
Record* _getRecord () const;
|
Record* _getRecord () const;
|
||||||
private:
|
private:
|
||||||
|
@ -270,7 +274,7 @@ namespace Etesian {
|
||||||
void buildSubSlices ();
|
void buildSubSlices ();
|
||||||
void showSubSlices ();
|
void showSubSlices ();
|
||||||
void insertTies ( DbU::Unit latchUpMax );
|
void insertTies ( DbU::Unit latchUpMax );
|
||||||
Instance* createDiodeUnder ( const Box& );
|
Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint );
|
||||||
inline std::string _getString () const;
|
inline std::string _getString () const;
|
||||||
Record* _getRecord () const;
|
Record* _getRecord () const;
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -494,7 +494,7 @@ namespace Katana {
|
||||||
throw Error ("KatanaEngine::runGlobalRouter(): Global routing already done or loaded.");
|
throw Error ("KatanaEngine::runGlobalRouter(): Global routing already done or loaded.");
|
||||||
|
|
||||||
if (flags & Flags::ShowBloatedInstances) selectBloatedInstances( this );
|
if (flags & Flags::ShowBloatedInstances) selectBloatedInstances( this );
|
||||||
Breakpoint::stop( 1, "Bloated cells from previous placement iteration." );
|
Breakpoint::stop( 100, "Bloated cells from previous placement iteration." );
|
||||||
|
|
||||||
startMeasures();
|
startMeasures();
|
||||||
cmess1 << " o Running global routing." << endl;
|
cmess1 << " o Running global routing." << endl;
|
||||||
|
|
Loading…
Reference in New Issue