coriolis/anabatic/src/AntennaProtect.cpp

653 lines
24 KiB
C++

// -*- 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;
GCell* current = gcell;
uint32_t i = 0;
while ( i<distance ) {
if (side.contains(Flags::WestSide )) current = current->getWest();
else if (side.contains(Flags::EastSide )) current = current->getEast();
else if (side.contains(Flags::NorthSide)) current = current->getNorth();
else if (side.contains(Flags::SouthSide)) current = current->getSouth();
if (not current) break;
neighbor = current;
++i;
}
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 );
Transformation trans = getRefRp()->getPlugOccurrence().getPath().getTransformation();
Point center = diode->getAbutmentBox().getCenter();
trans.applyOn( center );
neighbor = _anabatic->getGCellUnder( center );
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() );
cdebug_log(147,0) << "| breakGoThrough(), targetContact= " << targetContact << endl;
if (not hasGoThrough) {
cdebug_log(147,0) << "| Target GCell do not have a go-through, connecting. " << endl;
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.