Create clusters for wire only chunks and add diodes if they are too long.
Protecting clusters of sinks is not enough. There can be very long wires that far exceed the protection capacity of one diode. Instead of putting a bunch of diodes near the sinks, we choose to put them regularly along the interconncting wires. With this approach we are down to 7 antenna violations on LibreSOC LS180 test chip. This will get less good results on arlet6502 & ao6800 because of the core being a long way from the I/O pads. Should create jumpers on thoses, but it is for later.
This commit is contained in:
parent
7ad26f1a37
commit
c80e99c0a1
anabatic/src
|
@ -48,6 +48,32 @@ namespace {
|
||||||
using namespace Anabatic;
|
using namespace Anabatic;
|
||||||
using Etesian::EtesianEngine;
|
using Etesian::EtesianEngine;
|
||||||
|
|
||||||
|
class CompareByLength {
|
||||||
|
public:
|
||||||
|
inline bool operator() ( const Segment* lhs, const Segment* rhs )
|
||||||
|
{
|
||||||
|
DbU::Unit delta = lhs->getLength() - rhs->getLength();
|
||||||
|
if (delta < 0) return false;
|
||||||
|
if (delta > 0) return true;
|
||||||
|
return lhs->getId() < rhs->getId();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompareBySegmentBox {
|
||||||
|
public:
|
||||||
|
inline bool operator() ( const Box& lhs, const Box& rhs )
|
||||||
|
{
|
||||||
|
bool lhsH = (lhs.getWidth() >= lhs.getHeight());
|
||||||
|
bool rhsH = (rhs.getWidth() >= rhs.getHeight());
|
||||||
|
if (lhsH xor rhsH) return lhsH;
|
||||||
|
|
||||||
|
DbU::Unit lhsLength = (lhsH) ? lhs.getWidth() : lhs.getHeight();
|
||||||
|
DbU::Unit rhsLength = (rhsH) ? rhs.getWidth() : rhs.getHeight();
|
||||||
|
return lhsLength > rhsLength;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef tuple<RoutingPad*,uint32_t> RPInfosItem;
|
typedef tuple<RoutingPad*,uint32_t> RPInfosItem;
|
||||||
|
|
||||||
class CompareRPInfos {
|
class CompareRPInfos {
|
||||||
|
@ -62,7 +88,9 @@ namespace {
|
||||||
|
|
||||||
typedef tuple<GCell*,uint32_t,GCell*> GCellInfosItem;
|
typedef tuple<GCell*,uint32_t,GCell*> GCellInfosItem;
|
||||||
|
|
||||||
inline uint32_t& flags ( GCellInfosItem& item ) { return std::get<1>(item); }
|
inline const uint32_t& elemFlags ( const GCellInfosItem& item ) { return std::get<1>(item); }
|
||||||
|
inline uint32_t& elemFlags ( GCellInfosItem& item ) { return std::get<1>(item); }
|
||||||
|
inline GCell* elemGCell ( const GCellInfosItem& item ) { return std::get<0>(item); }
|
||||||
|
|
||||||
class CompareGCellInfos {
|
class CompareGCellInfos {
|
||||||
public:
|
public:
|
||||||
|
@ -92,27 +120,35 @@ namespace {
|
||||||
static const uint32_t InCluster;
|
static const uint32_t InCluster;
|
||||||
static string toStr ( uint32_t );
|
static string toStr ( uint32_t );
|
||||||
public:
|
public:
|
||||||
DiodeCluster ( RoutingPad*, AnabaticEngine* );
|
DiodeCluster ( AnabaticEngine*, RoutingPad* );
|
||||||
inline bool hasRp ( RoutingPad* ) const;
|
virtual ~DiodeCluster ();
|
||||||
bool hasGCell ( GCell* ) const;
|
DbU::Unit getAntennaMaxWL () const;
|
||||||
inline Net* getTopNet () const;
|
inline bool hasRp ( RoutingPad* ) const;
|
||||||
inline RoutingPad* getRefRp () const;
|
bool hasGCell ( GCell* ) const;
|
||||||
inline const RoutingPadInfos& getRoutingPads () const;
|
inline Net* getTopNet () const;
|
||||||
inline const vector<Instance*>& getDiodes () const;
|
inline RoutingPad* getRefRp () const;
|
||||||
inline DbU::Unit getWL () const;
|
inline GCellArea& _getArea ();
|
||||||
void showArea () const;
|
inline AnabaticEngine* _getAnabatic () const;
|
||||||
bool needsDiode () const;
|
inline const RoutingPadInfos& getRoutingPads () const;
|
||||||
Box getBoundingBox () const;
|
inline RoutingPadInfos& _getRoutingPads () ;
|
||||||
void merge ( GCell*, uint32_t distance, GCell* back=NULL );
|
inline const vector<Instance*>& getDiodes () const;
|
||||||
void merge ( RoutingPad* );
|
inline vector<Instance*>& _getDiodes ();
|
||||||
void merge ( Segment* );
|
inline DbU::Unit getWL () const;
|
||||||
void mergeHalo ( Segment*, uint32_t flags );
|
inline DbU::Unit& _getWL ();
|
||||||
void inflateArea ();
|
void showArea () const;
|
||||||
Instance* createDiode ( Etesian::Area*, GCell*, GCell* );
|
virtual bool needsDiode () const = 0;
|
||||||
const vector<Instance*>& createDiodes ( Etesian::Area* );
|
Box getBoundingBox () const;
|
||||||
|
void merge ( GCell*, uint32_t distance, GCell* back=NULL );
|
||||||
|
virtual void merge ( RoutingPad* );
|
||||||
|
virtual void merge ( Segment* ) = 0;
|
||||||
|
virtual void mergeHalo ( Segment*, uint32_t flags );
|
||||||
|
virtual void inflateArea ();
|
||||||
|
Instance* _createDiode ( Etesian::Area*, const Box&, DbU::Unit uHint );
|
||||||
|
Instance* _createDiode ( Etesian::Area*, GCell*, GCell* );
|
||||||
|
virtual const vector<Instance*>& createDiode ( Etesian::Area* );
|
||||||
|
bool connectDiodes ();
|
||||||
private:
|
private:
|
||||||
AnabaticEngine* _anabatic;
|
AnabaticEngine* _anabatic;
|
||||||
bool _sortArea;
|
|
||||||
DbU::Unit _WL;
|
DbU::Unit _WL;
|
||||||
RoutingPadInfos _routingPads;
|
RoutingPadInfos _routingPads;
|
||||||
GCellArea _area;
|
GCellArea _area;
|
||||||
|
@ -139,9 +175,8 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DiodeCluster::DiodeCluster ( RoutingPad* rp, AnabaticEngine* anabatic )
|
DiodeCluster::DiodeCluster ( AnabaticEngine* anabatic, RoutingPad* rp )
|
||||||
: _anabatic(anabatic)
|
: _anabatic(anabatic)
|
||||||
, _sortArea(true)
|
|
||||||
, _WL(0)
|
, _WL(0)
|
||||||
, _routingPads()
|
, _routingPads()
|
||||||
, _area()
|
, _area()
|
||||||
|
@ -151,18 +186,26 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline Net* DiodeCluster::getTopNet () const { return getRefRp()->getNet(); }
|
DiodeCluster::~DiodeCluster ()
|
||||||
inline DbU::Unit DiodeCluster::getWL () const { return _WL; }
|
{ }
|
||||||
inline const RoutingPadInfos& DiodeCluster::getRoutingPads () const { return _routingPads; }
|
|
||||||
inline const vector<Instance*>& DiodeCluster::getDiodes () const { return _diodes; }
|
|
||||||
|
|
||||||
|
|
||||||
bool DiodeCluster::needsDiode () const
|
inline AnabaticEngine* DiodeCluster::_getAnabatic () const { return _anabatic; }
|
||||||
|
inline GCellArea& DiodeCluster::_getArea () { return _area; }
|
||||||
|
inline Net* DiodeCluster::getTopNet () const { return getRefRp()->getNet(); }
|
||||||
|
inline DbU::Unit DiodeCluster::getWL () const { return _WL; }
|
||||||
|
inline DbU::Unit& DiodeCluster::_getWL () { return _WL; }
|
||||||
|
inline const RoutingPadInfos& DiodeCluster::getRoutingPads () const { return _routingPads; }
|
||||||
|
inline RoutingPadInfos& DiodeCluster::_getRoutingPads () { return _routingPads; }
|
||||||
|
inline const vector<Instance*>& DiodeCluster::getDiodes () const { return _diodes; }
|
||||||
|
inline vector<Instance*>& DiodeCluster::_getDiodes () { return _diodes; }
|
||||||
|
|
||||||
|
|
||||||
|
DbU::Unit DiodeCluster::getAntennaMaxWL () const
|
||||||
{
|
{
|
||||||
for ( auto& infos : _routingPads ) {
|
EtesianEngine* etesian = static_cast<EtesianEngine*>
|
||||||
if (std::get<1>(infos) & IsSink) return true;
|
( ToolEngine::get( _getAnabatic()->getCell(), EtesianEngine::staticGetName() ));
|
||||||
}
|
return etesian->getAntennaMaxWL();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,7 +217,7 @@ namespace {
|
||||||
{
|
{
|
||||||
if (not gcell) return false;
|
if (not gcell) return false;
|
||||||
for ( auto& item : _area ) {
|
for ( auto& item : _area ) {
|
||||||
if (std::get<0>(item) == gcell) return true;
|
if (elemGCell(item) == gcell) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -203,37 +246,24 @@ namespace {
|
||||||
{
|
{
|
||||||
Plug* rpPlug = dynamic_cast<Plug*>( rp->getPlugOccurrence().getEntity() );
|
Plug* rpPlug = dynamic_cast<Plug*>( rp->getPlugOccurrence().getEntity() );
|
||||||
if (rpPlug) {
|
if (rpPlug) {
|
||||||
merge( _anabatic->getGCellUnder( rp->getPosition() ), 0 );
|
DiodeCluster::merge( _getAnabatic()->getGCellUnder( rp->getPosition() ), 0 );
|
||||||
if (rpPlug->getMasterNet()->getDirection() & Net::Direction::DirIn) {
|
if (rpPlug->getMasterNet()->getDirection() & Net::Direction::DirIn) {
|
||||||
cdebug_log(147,0) << "| Sink " << rp << endl;
|
cdebug_log(147,0) << "| Sink " << rp << endl;
|
||||||
_routingPads.insert( make_tuple(rp,IsSink) );
|
_getRoutingPads().insert( make_tuple(rp,IsSink) );
|
||||||
} else {
|
} else {
|
||||||
_routingPads.insert( make_tuple(rp,IsDriver) );
|
_getRoutingPads().insert( make_tuple(rp,IsDriver) );
|
||||||
cdebug_log(147,0) << "| Driver " << rp << endl;
|
cdebug_log(147,0) << "| Driver " << rp << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Pin* rpPin = dynamic_cast<Pin*>( rp->getPlugOccurrence().getEntity() );
|
Pin* rpPin = dynamic_cast<Pin*>( rp->getPlugOccurrence().getEntity() );
|
||||||
if (rpPin) {
|
if (rpPin) {
|
||||||
_routingPads.insert( make_tuple(rp,IsDriver) );
|
_getRoutingPads().insert( make_tuple(rp,IsDriver) );
|
||||||
cdebug_log(147,0) << "| Pin (considered driver) " << rp << endl;
|
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), 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DiodeCluster::merge ( GCell* gcell, uint32_t distance, GCell* back )
|
void DiodeCluster::merge ( GCell* gcell, uint32_t distance, GCell* back )
|
||||||
{
|
{
|
||||||
if (not gcell) return;
|
if (not gcell) return;
|
||||||
|
@ -246,69 +276,56 @@ namespace {
|
||||||
Box DiodeCluster::getBoundingBox () const
|
Box DiodeCluster::getBoundingBox () const
|
||||||
{
|
{
|
||||||
Box bb;
|
Box bb;
|
||||||
for ( auto& infos : _routingPads ) bb.merge( std::get<0>(infos)->getPosition() );
|
for ( auto& item : _area ) bb.merge( elemGCell(item)->getBoundingBox() );
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DiodeCluster::mergeHalo ( Segment* segment, uint32_t flags )
|
void DiodeCluster::mergeHalo ( Segment* segment, uint32_t flags )
|
||||||
{
|
{
|
||||||
cdebug_log(147,0) << "DiodeCluster::mergeHalo(): " << segment << endl;
|
cerr << Error( "DiodeCluster::mergeHalo(Segment*): Unimplemented (%s). "
|
||||||
if (not segment) return;
|
, getString(segment).c_str() ) << endl;
|
||||||
|
|
||||||
GCellsUnder gcells = _anabatic->getGCellsUnder( segment );
|
|
||||||
if (not gcells->empty()) {
|
|
||||||
size_t count = std::min( gcells->size(), (size_t)10 );
|
|
||||||
for ( size_t i=0 ; i<count ; ++i ) {
|
|
||||||
size_t igcell = (flags & IsSegSource) ? i : (gcells->size()-1-i);
|
|
||||||
merge( gcells->gcellAt(igcell), i+1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DiodeCluster::inflateArea ()
|
void DiodeCluster::inflateArea ()
|
||||||
{
|
{
|
||||||
vector< tuple<GCell*,GCell*> > border;
|
cerr << Error( "DiodeCluster::inflateArea(): Unimplemented. " ) << endl;
|
||||||
for ( auto& item : _area ) {
|
}
|
||||||
GCell* current = std::get<0>( item );
|
|
||||||
if (std::get<2>(item)) continue;
|
|
||||||
|
|
||||||
|
Instance* DiodeCluster::_createDiode ( Etesian::Area* area, const Box& bb, DbU::Unit uHint )
|
||||||
|
{
|
||||||
|
cdebug_log(147,1) << "DiodeCluster::_createDiode(): under=" << bb
|
||||||
|
<< " uHint=" << DbU::getValueString(uHint) << endl;
|
||||||
|
|
||||||
GCell* neighbor = current->getEast();
|
Instance* diode = area->createDiodeUnder( getRefRp(), bb, uHint );
|
||||||
if (neighbor and not neighbor->hasNet(getTopNet()))
|
if (diode) {
|
||||||
border.push_back( make_tuple(neighbor,current) );
|
cdebug_log(147,0) << "| New diode " << diode << endl;
|
||||||
neighbor = current->getWest();
|
_diodes.push_back( diode );
|
||||||
if (neighbor and not neighbor->hasNet(getTopNet()))
|
GCell* gcell = _anabatic->getGCellUnder( diode->getAbutmentBox().getCenter() );
|
||||||
border.push_back( make_tuple(neighbor,current) );
|
Contact* contact = gcell->hasGContact( getTopNet() );
|
||||||
}
|
if (not contact)
|
||||||
|
contact = gcell->breakGoThrough( getTopNet() );
|
||||||
for ( auto& item : _area ) {
|
cdebug_log(147,0) << "| breakGoThrough(), contact= " << contact << endl;
|
||||||
GCell* current = std::get<0>( item );
|
|
||||||
if (std::get<2>(item)) continue;
|
|
||||||
|
|
||||||
GCell* neighbor = current->getNorth();
|
|
||||||
if (neighbor and not neighbor->hasNet(getTopNet()))
|
|
||||||
border.push_back( make_tuple(neighbor,current) );
|
|
||||||
neighbor = current->getSouth();
|
|
||||||
if (neighbor and not neighbor->hasNet(getTopNet()))
|
|
||||||
border.push_back( make_tuple(neighbor,current) );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( auto& item : border ) {
|
|
||||||
merge( std::get<0>(item), 1, std::get<1>(item) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cdebug_tabw(147,-1);
|
||||||
|
return diode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Instance* DiodeCluster::createDiode ( Etesian::Area* area, GCell* gcell, GCell* backGCell )
|
Instance* DiodeCluster::_createDiode ( Etesian::Area* area, GCell* gcell, GCell* backGCell )
|
||||||
{
|
{
|
||||||
cdebug_log(147,0) << "DiodeCluster::createDiode(): from=" << gcell << endl;
|
cdebug_log(147,1) << "DiodeCluster::_createDiode(): under=" << gcell << endl;
|
||||||
|
|
||||||
Box bb = gcell->getBoundingBox();
|
Box bb = gcell->getBoundingBox();
|
||||||
cdebug_log(147,0) << "> GCell area: " << bb << endl;
|
cdebug_log(147,0) << "> GCell area: " << bb << endl;
|
||||||
|
|
||||||
Instance* diode = area->createDiodeUnder( getRefRp(), bb, 0 );
|
Instance* diode = area->createDiodeUnder( getRefRp(), bb, 0 );
|
||||||
if (diode) {
|
if (diode) {
|
||||||
|
cdebug_log(147,0) << "| New diode " << diode << endl;
|
||||||
_diodes.push_back( diode );
|
_diodes.push_back( diode );
|
||||||
Transformation trans = getRefRp()->getPlugOccurrence().getPath().getTransformation();
|
Transformation trans = getRefRp()->getPlugOccurrence().getPath().getTransformation();
|
||||||
Point center = diode->getAbutmentBox().getCenter();
|
Point center = diode->getAbutmentBox().getCenter();
|
||||||
|
@ -345,7 +362,7 @@ namespace {
|
||||||
, _anabatic->getConfiguration()->getGHorizontalPitch()
|
, _anabatic->getConfiguration()->getGHorizontalPitch()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
cerr << Error( "DiodeCluster::createDiode(): Back GCell not aligned with diode GCell.\n"
|
cerr << Error( "DiodeCluster::_createDiode(): Back GCell not aligned with diode GCell.\n"
|
||||||
" * %s\n"
|
" * %s\n"
|
||||||
" * %s"
|
" * %s"
|
||||||
, getString(gcell).c_str()
|
, getString(gcell).c_str()
|
||||||
|
@ -355,23 +372,35 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cdebug_tabw(147,-1);
|
||||||
return diode;
|
return diode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const vector<Instance*>& DiodeCluster::createDiodes ( Etesian::Area* area )
|
const vector<Instance*>& DiodeCluster::createDiode ( Etesian::Area* area )
|
||||||
{
|
{
|
||||||
if (not needsDiode()) return _diodes;
|
if (not needsDiode()) return _diodes;
|
||||||
|
|
||||||
|
DbU::Unit antennaMaxWL = getAntennaMaxWL();
|
||||||
|
size_t diodeCount = getWL() / antennaMaxWL;
|
||||||
|
if (not diodeCount) diodeCount = 1;
|
||||||
|
|
||||||
showArea();
|
showArea();
|
||||||
|
|
||||||
cdebug_log(147,1) << "DiodeCluster::createDiodes()" << endl;
|
cdebug_log(147,1) << "DiodeCluster::createDiode() count=" << diodeCount << endl;
|
||||||
Instance* diode = NULL;
|
Instance* diode = NULL;
|
||||||
for ( auto& item : _area ) {
|
for ( auto& item : _area ) {
|
||||||
GCell* gcell = std::get<0>( item );
|
GCell* gcell = std::get<0>( item );
|
||||||
GCell* backGCell = std::get<2>( item );
|
GCell* backGCell = std::get<2>( item );
|
||||||
cdebug_log(147,0) << "| d=" << std::get<1>(item) << " " << gcell << endl;
|
cdebug_log(147,0) << "| d=" << std::get<1>(item) << " " << gcell << endl;
|
||||||
diode = createDiode( area, gcell, backGCell );
|
diode = _createDiode( area, gcell, backGCell );
|
||||||
if (diode) break;
|
if (diode) {
|
||||||
|
if (_diodes.size() < diodeCount) {
|
||||||
|
diode = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cdebug_tabw(147,-1);
|
cdebug_tabw(147,-1);
|
||||||
|
|
||||||
|
@ -379,6 +408,231 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DiodeCluster::connectDiodes ()
|
||||||
|
{
|
||||||
|
EtesianEngine* etesian = static_cast<EtesianEngine*>
|
||||||
|
( ToolEngine::get( _anabatic->getCell(), EtesianEngine::staticGetName() ));
|
||||||
|
|
||||||
|
Cell* diodeCell = etesian->getDiodeCell();
|
||||||
|
Net* diodeOutput = NULL;
|
||||||
|
for ( Net* net : diodeCell->getNets() ) {
|
||||||
|
if (net->isSupply() or not net->isExternal()) continue;
|
||||||
|
diodeOutput = net;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Net* topNet = getTopNet();
|
||||||
|
Net* diodeNet = topNet;
|
||||||
|
Plug* sinkPlug = dynamic_cast<Plug*>( getRefRp()->getPlugOccurrence().getEntity() );
|
||||||
|
Path path = Path();
|
||||||
|
|
||||||
|
if (sinkPlug) {
|
||||||
|
diodeNet = sinkPlug->getNet();
|
||||||
|
path = getRefRp()->getOccurrence().getPath().getHeadPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) << " " << getRefRp()->getOccurrence().getPath() << endl;
|
||||||
|
Plug* diodePlug = diode->getPlug( diodeOutput );
|
||||||
|
diodePlug->setNet( diodeNet );
|
||||||
|
RoutingPad* diodeRp = RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea );
|
||||||
|
cdebug_log(147,0) << " " << getRefRp() << endl;
|
||||||
|
|
||||||
|
GCell* gcell = _anabatic->getGCellUnder( diodeRp->getPosition() );
|
||||||
|
if (gcell) {
|
||||||
|
Contact* contact = gcell->breakGoThrough( topNet );
|
||||||
|
contact->getBodyHook()->merge( diodeRp->getBodyHook() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
// Class : "::DiodeRps".
|
||||||
|
|
||||||
|
class DiodeRps : public DiodeCluster {
|
||||||
|
public:
|
||||||
|
DiodeRps ( AnabaticEngine*, RoutingPad* );
|
||||||
|
virtual bool needsDiode () const;
|
||||||
|
virtual void merge ( Segment* );
|
||||||
|
virtual void mergeHalo ( Segment*, uint32_t flags );
|
||||||
|
virtual void inflateArea ();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DiodeRps::DiodeRps ( AnabaticEngine* anabatic, RoutingPad* rp )
|
||||||
|
: DiodeCluster(anabatic,rp)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
bool DiodeRps::needsDiode () const
|
||||||
|
{
|
||||||
|
for ( auto& infos : getRoutingPads() ) {
|
||||||
|
if (std::get<1>(infos) & IsSink) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeRps::merge ( Segment* segment )
|
||||||
|
{
|
||||||
|
_getWL() += segment->getLength();
|
||||||
|
GCellsUnder gcells = _getAnabatic()->getGCellsUnder( segment );
|
||||||
|
if (not gcells->empty()) {
|
||||||
|
for ( size_t i=0 ; i<gcells->size() ; ++i ) {
|
||||||
|
DiodeCluster::merge( gcells->gcellAt(i), 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeRps::mergeHalo ( Segment* segment, uint32_t flags )
|
||||||
|
{
|
||||||
|
cdebug_log(147,0) << "DiodeRps::mergeHalo(): " << segment << endl;
|
||||||
|
if (not segment) return;
|
||||||
|
|
||||||
|
GCellsUnder gcells = _getAnabatic()->getGCellsUnder( segment );
|
||||||
|
if (not gcells->empty()) {
|
||||||
|
size_t count = std::min( gcells->size(), (size_t)10 );
|
||||||
|
for ( size_t i=0 ; i<count ; ++i ) {
|
||||||
|
size_t igcell = (flags & IsSegSource) ? i : (gcells->size()-1-i);
|
||||||
|
DiodeCluster::merge( gcells->gcellAt(igcell), i+1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeRps::inflateArea ()
|
||||||
|
{
|
||||||
|
vector< tuple<GCell*,GCell*> > border;
|
||||||
|
for ( auto& item : _getArea() ) {
|
||||||
|
GCell* current = std::get<0>( item );
|
||||||
|
if (std::get<2>(item)) continue;
|
||||||
|
|
||||||
|
GCell* neighbor = current->getEast();
|
||||||
|
if (neighbor and not neighbor->hasNet(getTopNet()))
|
||||||
|
border.push_back( make_tuple(neighbor,current) );
|
||||||
|
neighbor = current->getWest();
|
||||||
|
if (neighbor and not neighbor->hasNet(getTopNet()))
|
||||||
|
border.push_back( make_tuple(neighbor,current) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto& item : _getArea() ) {
|
||||||
|
GCell* current = std::get<0>( item );
|
||||||
|
if (std::get<2>(item)) continue;
|
||||||
|
|
||||||
|
GCell* neighbor = current->getNorth();
|
||||||
|
if (neighbor and not neighbor->hasNet(getTopNet()))
|
||||||
|
border.push_back( make_tuple(neighbor,current) );
|
||||||
|
neighbor = current->getSouth();
|
||||||
|
if (neighbor and not neighbor->hasNet(getTopNet()))
|
||||||
|
border.push_back( make_tuple(neighbor,current) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto& item : border ) {
|
||||||
|
DiodeCluster::merge( std::get<0>(item), 1, std::get<1>(item) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
// Class : "::DiodeWire".
|
||||||
|
|
||||||
|
class DiodeWire : public DiodeCluster {
|
||||||
|
public:
|
||||||
|
DiodeWire ( AnabaticEngine*, RoutingPad* );
|
||||||
|
virtual bool needsDiode () const;
|
||||||
|
virtual void merge ( Segment* );
|
||||||
|
virtual const vector<Instance*>& createDiode ( Etesian::Area* );
|
||||||
|
private:
|
||||||
|
set<Box,CompareBySegmentBox> _boxes;
|
||||||
|
set<Contact*,Go::CompareById> _contacts;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DiodeWire::DiodeWire ( AnabaticEngine* anabatic, RoutingPad* rp )
|
||||||
|
: DiodeCluster(anabatic,rp)
|
||||||
|
, _boxes()
|
||||||
|
, _contacts()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
bool DiodeWire::needsDiode () const
|
||||||
|
{ return getWL() > getAntennaMaxWL(); }
|
||||||
|
|
||||||
|
|
||||||
|
void DiodeWire::merge ( Segment* segment )
|
||||||
|
{
|
||||||
|
Box bb = segment->getBoundingBox();
|
||||||
|
if (_boxes.find(bb) != _boxes.end()) return;
|
||||||
|
cdebug_log(147,0) << "| merge: " << segment << endl;
|
||||||
|
_boxes.insert( bb );
|
||||||
|
_getWL() += segment->getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const vector<Instance*>& DiodeWire::createDiode ( Etesian::Area* area )
|
||||||
|
{
|
||||||
|
cdebug_log(147,1) << "DiodeWire::createDiode() " << endl;
|
||||||
|
DbU::Unit antennaMaxWL = getAntennaMaxWL();
|
||||||
|
|
||||||
|
size_t diodeCount = getWL() / antennaMaxWL;
|
||||||
|
if (not diodeCount) return _getDiodes();
|
||||||
|
|
||||||
|
for ( const Box& bb : _boxes ) {
|
||||||
|
bool bbH = (bb.getWidth() >= bb.getHeight());
|
||||||
|
DbU::Unit bbLength = (bbH) ? bb.getWidth() : bb.getHeight();
|
||||||
|
size_t segDiodeCount = bbLength / antennaMaxWL;
|
||||||
|
if (not segDiodeCount) ++segDiodeCount;
|
||||||
|
cdebug_log(147,0) << "diodes=" << segDiodeCount << " " << bb << endl;
|
||||||
|
if (bbLength < antennaMaxWL/4) continue;
|
||||||
|
|
||||||
|
if (bbH) {
|
||||||
|
DbU::Unit uHint = bb.getXMin();
|
||||||
|
DbU::Unit uMax = bb.getXMax();
|
||||||
|
while ( uHint < uMax ) {
|
||||||
|
_createDiode( area, bb, uHint );
|
||||||
|
uHint += antennaMaxWL;
|
||||||
|
}
|
||||||
|
if (_getDiodes().size() >= diodeCount) break;
|
||||||
|
} else {
|
||||||
|
GCellsUnder gcells = _getAnabatic()->getGCellsUnder( Point(bb.getXCenter(),bb.getYMin())
|
||||||
|
, Point(bb.getXCenter(),bb.getYMax()) );
|
||||||
|
if (gcells->size()) {
|
||||||
|
size_t gcellPeriod = antennaMaxWL / gcells->gcellAt(0)->getHeight();
|
||||||
|
for ( size_t i=0 ; i<gcells->size() ; ++i ) {
|
||||||
|
Instance* diode = _createDiode( area, gcells->gcellAt(i), NULL );
|
||||||
|
if (diode) {
|
||||||
|
i += gcellPeriod - (i%gcellPeriod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_getDiodes().size() < diodeCount) {
|
||||||
|
cerr << Error( "DiodeWire::createDiode(): On cluster of net \"%s\",\n"
|
||||||
|
" Allocated only %u diodes of %u."
|
||||||
|
, getString(getTopNet()->getName()).c_str()
|
||||||
|
, _getDiodes().size()
|
||||||
|
, diodeCount
|
||||||
|
) << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
cdebug_tabw(147,-1);
|
||||||
|
return _getDiodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
// Local functions.
|
||||||
|
|
||||||
|
|
||||||
} // Anonymous namespace.
|
} // Anonymous namespace.
|
||||||
|
|
||||||
|
|
||||||
|
@ -504,13 +758,14 @@ namespace Anabatic {
|
||||||
|
|
||||||
vector<DiodeCluster*> clusters;
|
vector<DiodeCluster*> clusters;
|
||||||
set<RoutingPad*,DBo::CompareById> rpsDone;
|
set<RoutingPad*,DBo::CompareById> rpsDone;
|
||||||
|
set<Segment*,DBo::CompareById> clusterSegments;
|
||||||
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
||||||
set<Segment*,DBo::CompareById> segmentsDone;
|
set<Segment*,DBo::CompareById> segmentsDone;
|
||||||
|
|
||||||
if (rpsDone.find(rp) != rpsDone.end()) continue;
|
if (rpsDone.find(rp) != rpsDone.end()) continue;
|
||||||
|
|
||||||
cdebug_log(147,0) << "New cluster from " << rp << endl;
|
cdebug_log(147,0) << "New cluster from " << rp << endl;
|
||||||
DiodeCluster* cluster = new DiodeCluster ( rp, this );
|
DiodeCluster* cluster = new DiodeRps ( this, rp );
|
||||||
clusters.push_back( cluster );
|
clusters.push_back( cluster );
|
||||||
rpsDone.insert( rp );
|
rpsDone.insert( rp );
|
||||||
|
|
||||||
|
@ -573,6 +828,7 @@ namespace Anabatic {
|
||||||
else branchWL = 0;
|
else branchWL = 0;
|
||||||
cluster->merge( segment );
|
cluster->merge( segment );
|
||||||
std::get<3>( hooksStack[backIndex] ) |= DiodeCluster::InCluster;
|
std::get<3>( hooksStack[backIndex] ) |= DiodeCluster::InCluster;
|
||||||
|
clusterSegments.insert( segment );
|
||||||
cdebug_log(147,0) << "| back=" << backIndex
|
cdebug_log(147,0) << "| back=" << backIndex
|
||||||
<< " -> " << std::get<2>( hooksStack[backIndex] )
|
<< " -> " << std::get<2>( hooksStack[backIndex] )
|
||||||
<< " " << DbU::getValueString(segment->getLength())
|
<< " " << DbU::getValueString(segment->getLength())
|
||||||
|
@ -626,20 +882,58 @@ namespace Anabatic {
|
||||||
cluster->inflateArea();
|
cluster->inflateArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (clusters.size() > 1) {
|
||||||
|
cdebug_log(147,0) << "Cluster wiring" << endl;
|
||||||
|
for ( Segment* segment : net->getSegments() ) {
|
||||||
|
if (clusterSegments.find(segment) != clusterSegments.end()) continue;
|
||||||
|
|
||||||
|
cdebug_log(147,0) << "New wiring cluster from " << segment << endl;
|
||||||
|
DiodeWire* cluster = new DiodeWire( this, clusters[0]->getRefRp() );
|
||||||
|
cluster->merge( segment );
|
||||||
|
clusters.push_back( cluster );
|
||||||
|
clusterSegments.insert( segment );
|
||||||
|
|
||||||
|
size_t stackTop = 0;
|
||||||
|
vector< StackItem > hooksStack;
|
||||||
|
hooksStack.push_back( make_tuple( segment->getSourceHook()
|
||||||
|
, segment
|
||||||
|
, 0
|
||||||
|
, DiodeCluster::IsSegSource ) );
|
||||||
|
hooksStack.push_back( make_tuple( segment->getTargetHook()
|
||||||
|
, segment
|
||||||
|
, 0
|
||||||
|
, 0 ) );
|
||||||
|
|
||||||
|
while ( stackTop < hooksStack.size() ) {
|
||||||
|
Hook* toHook = std::get<0>( hooksStack[stackTop] );
|
||||||
|
Segment* fromSegment = std::get<1>( hooksStack[stackTop] );
|
||||||
|
|
||||||
|
for ( Hook* hook : toHook->getHooks() ) {
|
||||||
|
Segment* segment = dynamic_cast<Segment*>( hook->getComponent() );
|
||||||
|
if (segment) {
|
||||||
|
if (segment == fromSegment) continue;
|
||||||
|
if (clusterSegments.find(segment) != clusterSegments.end()) continue;
|
||||||
|
clusterSegments.insert( segment );
|
||||||
|
cluster->merge( segment );
|
||||||
|
uint32_t flags = (segment->getSourceHook() == hook) ? DiodeCluster::IsSegSource : 0;
|
||||||
|
if (dynamic_cast<Segment::SourceHook*>(hook)) {
|
||||||
|
hooksStack.push_back( make_tuple( segment->getTargetHook(), segment, stackTop, flags ) );
|
||||||
|
} else {
|
||||||
|
hooksStack.push_back( make_tuple( segment->getSourceHook(), segment, stackTop, flags ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++stackTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
total += clusters.size();
|
total += clusters.size();
|
||||||
cdebug_log(147,1) << "Net \"" << net->getName() << " has " << clusters.size() << " diode clusters." << endl;
|
cdebug_log(147,1) << "Net \"" << net->getName() << " has " << clusters.size() << " diode clusters." << endl;
|
||||||
for ( size_t i=0 ; i<clusters.size() ; ++i ) {
|
for ( size_t i=0 ; i<clusters.size() ; ++i ) {
|
||||||
cdebug_log(147,1) << "Cluster [" << i << "] needsDiode=" << clusters[i]->needsDiode()
|
cdebug_log(147,1) << "Cluster [" << i << "] needsDiode=" << clusters[i]->needsDiode()
|
||||||
<< " bb=" << clusters[i]->getBoundingBox() << endl;
|
<< " bb=" << clusters[i]->getBoundingBox() << endl;
|
||||||
|
cdebug_log(147,0) << " WL=" << DbU::getValueString(clusters[i]->getWL()) << endl;
|
||||||
for ( auto& item : clusters[i]->getRoutingPads() ) {
|
for ( auto& item : clusters[i]->getRoutingPads() ) {
|
||||||
cdebug_log(147,0) << "| flags=" << DiodeCluster::toStr(std::get<1>(item))
|
cdebug_log(147,0) << "| flags=" << DiodeCluster::toStr(std::get<1>(item))
|
||||||
<< " " << std::get<0>(item) << endl;
|
<< " " << std::get<0>(item) << endl;
|
||||||
|
@ -649,39 +943,9 @@ namespace Anabatic {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vector<Instance*> diodes = clusters[i]->createDiodes( etesian->getArea() );
|
const vector<Instance*>& diodes = clusters[i]->createDiode( etesian->getArea() );
|
||||||
RoutingPad* rp = clusters[i]->getRefRp();
|
|
||||||
if (not diodes.empty()) {
|
if (not diodes.empty()) {
|
||||||
Net* topNet = rp->getNet();
|
clusters[i]->connectDiodes();
|
||||||
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 );
|
|
||||||
cdebug_log(147,0) << " " << rp << endl;
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
cerr << Error( "EtesianEngine::antennaProtect(): For %s (rps:%u, clusters:%u)\n"
|
cerr << Error( "EtesianEngine::antennaProtect(): For %s (rps:%u, clusters:%u)\n"
|
||||||
" Cannot find a diode nearby %s."
|
" Cannot find a diode nearby %s."
|
||||||
|
@ -694,9 +958,14 @@ namespace Anabatic {
|
||||||
}
|
}
|
||||||
cdebug_tabw(147,-1);
|
cdebug_tabw(147,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cdebug_tabw(147,-1);
|
cdebug_tabw(147,-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((rpsDone.size() == 2) and (clusters.size() == 2)) {
|
||||||
|
cerr << "Long bipoint " << net << endl;
|
||||||
|
}
|
||||||
|
|
||||||
for ( DiodeCluster* cluster : clusters ) delete cluster;
|
for ( DiodeCluster* cluster : clusters ) delete cluster;
|
||||||
|
|
||||||
cdebug_tabw(147,-1);
|
cdebug_tabw(147,-1);
|
||||||
|
|
Loading…
Reference in New Issue