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:
Jean-Paul Chaput 2021-01-27 11:38:00 +01:00
parent b926e02d92
commit 5649a3b984
16 changed files with 1065 additions and 195 deletions

View File

@ -24,6 +24,7 @@
find_package(VLSISAPD REQUIRED)
find_package(HURRICANE REQUIRED)
find_package(CORIOLIS REQUIRED)
find_package(ETESIAN REQUIRED)
find_package(Doxygen)
add_subdirectory(src)

View File

@ -1004,6 +1004,8 @@ namespace Anabatic {
if (_state > EngineGlobalLoaded)
throw Error ("AnabaticEngine::loadGlobalRouting() : global routing already loaded.");
antennaProtect();
if (method == EngineLoadGrByNet ) { _loadGrByNet(); }
else {
throw Error( badMethod, "Anabatic::loadGlobalRouting()", method, getString(_cell).c_str() );

View File

@ -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.

View File

@ -63,13 +63,15 @@ endif ( CHECK_DETERMINISM )
NetBuilderVH.cpp
ChipTools.cpp
LayerAssign.cpp
AntennaProtect.cpp
PreRouteds.cpp
AnabaticEngine.cpp
)
set( pyCpps PyAnabatic.cpp
)
set( depLibs ${CORIOLIS_PYTHON_LIBRARIES}
set( depLibs ${ETESIAN_LIBRARIES}
${CORIOLIS_PYTHON_LIBRARIES}
${CORIOLIS_LIBRARIES}
${HURRICANE_PYTHON_LIBRARIES}
${HURRICANE_GRAPHICAL_LIBRARIES}

View File

@ -90,6 +90,7 @@ namespace Anabatic {
, _edgeHInc (Cfg::getParamDouble("anabatic.edgeHInc" , 1.5)->asDouble())
, _edgeHScaling (Cfg::getParamDouble("anabatic.edgeHScaling" , 1.0)->asDouble())
, _globalIterations(Cfg::getParamInt ("anabatic.globalIterations", 10 )->asInt())
, _antennaMaxWL (Cfg::getParamInt ("etesian.antennaMaxWL" , 0 )->asInt())
{
GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() );
@ -180,6 +181,7 @@ namespace Anabatic {
, _edgeHInc (other._edgeHInc)
, _edgeHScaling (other._edgeHScaling)
, _globalIterations(other._globalIterations)
, _antennaMaxWL (other._antennaMaxWL)
{
GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() );
@ -576,17 +578,21 @@ namespace Anabatic {
Record* Configuration::_getRecord () const
{
Record* record = new Record ( _getString() );
record->add ( getSlot( "_gdepthh" , _gdepthh ) );
record->add ( getSlot( "_gdepthv" , _gdepthv ) );
record->add ( getSlot( "_rg" , _rg ) );
record->add ( getSlot( "_gmetalh" , _gmetalh ) );
record->add ( getSlot( "_gmetalv" , _gmetalv ) );
record->add ( getSlot( "_gcontact" , _gcontact ) );
record->add ( getSlot( "_allowedDepth", _allowedDepth ) );
record->add ( getSlot( "_edgeCostH" , _edgeCostH ) );
record->add ( getSlot( "_edgeCostK" , _edgeCostK ) );
record->add( getSlot( "_gdepthh" , _gdepthh ) );
record->add( getSlot( "_gdepthv" , _gdepthv ) );
record->add( getSlot( "_rg" , _rg ) );
record->add( getSlot( "_gmetalh" , _gmetalh ) );
record->add( getSlot( "_gmetalv" , _gmetalv ) );
record->add( getSlot( "_gcontact" , _gcontact ) );
record->add( getSlot( "_allowedDepth" , _allowedDepth ) );
record->add( getSlot( "_edgeCostH" , _edgeCostH ) );
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;
}

View File

@ -1459,6 +1459,10 @@ namespace Anabatic {
}
DbU::Unit Dijkstra::getAntennaMaxWL () const
{ return _anabatic->getAntennaMaxWL(); }
Point Dijkstra::_getPonderedPoint() const
{
vector<RoutingPad*> rps;
@ -1533,12 +1537,13 @@ namespace Anabatic {
cdebug_log(112,1) << "Dijkstra::load() " << _net << endl;
vector<RoutingPad*> rps;
NetRoutingState* state = NetRoutingExtension::get( _net );
NetRoutingState* state = NetRoutingExtension::get( _net );
if (state) {
if (state->isSelfSym()) {
cdebug_log(112,0) << "Dijkstra::SELF SYMMETRY CASE " << DbU::getValueString(state->getSymAxis()) << endl;
}
state->unsetFlags( NetRoutingState::HasAntenna );
}
for ( Component* component : _net->getComponents() ) {
@ -2196,6 +2201,7 @@ namespace Anabatic {
if (_sources.size() < 2) { cdebug_tabw(112,-1); return; }
DbU::Unit gWL = 0;
NetRoutingState* state = NetRoutingExtension::get( _net );
//cerr << "state: " << state << endl;
@ -2226,8 +2232,8 @@ namespace Anabatic {
vector<Edge*> aligneds;
aligneds.push_back( from );
Vertex* target = source->getPredecessor();
Interval constraint = from->getSide();
Vertex* target = source->getPredecessor();
Interval constraint = from->getSide();
source->setFrom( NULL );
cdebug_log(112,0) << "| " << target << endl;
@ -2286,6 +2292,7 @@ namespace Anabatic {
, constraint.getCenter()
, width
);
gWL += segment->getLength();
cdebug_log(112,0) << "| ref: " << segment << endl;
for ( Edge* through : aligneds ) through->add( segment );
@ -2305,6 +2312,7 @@ namespace Anabatic {
, constraint.getCenter()
, width
);
gWL += segment->getLength();
cdebug_log(112,0) << "| ref: " << segment << endl;
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);
}

View File

@ -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
{
for ( Edge* edge : getEdges(sideHint) ) {

View File

@ -245,6 +245,7 @@ namespace Anabatic {
inline bool doDestroyBaseContact () const;
inline bool doDestroyBaseSegment () const;
inline bool doDestroyTool () const;
inline DbU::Unit getAntennaMaxWL () const;
inline DbU::Unit getGlobalThreshold () const;
inline float getSaturateRatio () const;
inline size_t getSaturateRp () const;
@ -261,6 +262,8 @@ namespace Anabatic {
inline void setBlockageNet ( Net* );
void chipPrep ();
void computeEdgeCapacities ( int maxHCap, int maxVCap, int termSatThreshold, int maxTermSat );
void antennaProtect ( Net*, uint32_t& failed, uint32_t& total );
void antennaProtect ();
void setupSpecialNets ();
size_t setupPreRouteds ();
void loadGlobalRouting ( uint32_t method );
@ -367,6 +370,7 @@ namespace Anabatic {
inline bool AnabaticEngine::doWarnOnGCellOverload () const { return _flags & Flags::WarnOnGCellOverload; }
inline bool AnabaticEngine::isInDemoMode () const { return _flags & Flags::DemoMode; }
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 float AnabaticEngine::getSaturateRatio () const { return _configuration->getSaturateRatio(); }
inline size_t AnabaticEngine::getSaturateRp () const { return _configuration->getSaturateRp(); }

View File

@ -14,9 +14,7 @@
// +-----------------------------------------------------------------+
#ifndef ANABATIC_CONFIGURATION_H
#define ANABATIC_CONFIGURATION_H
#pragma once
#include <string>
#include <vector>
@ -117,6 +115,7 @@ namespace Anabatic {
Flags getDirection ( const Layer* ) const;
float getSaturateRatio () const;
size_t getSaturateRp () const;
inline DbU::Unit getAntennaMaxWL () const;
DbU::Unit getGlobalThreshold () const;
void setAllowedDepth ( size_t );
void setSaturateRatio ( float );
@ -159,6 +158,7 @@ namespace Anabatic {
float _edgeHInc;
float _edgeHScaling;
int _globalIterations;
DbU::Unit _antennaMaxWL;
private:
Configuration& operator= ( const Configuration& ) = delete;
void _setTopRoutingLayer ( Name name );
@ -186,11 +186,10 @@ namespace Anabatic {
inline const Layer* Configuration::getDContactLayer () const { return getContactLayer( 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::getAntennaMaxWL () const { return _antennaMaxWL; }
} // Anabatic namespace.
INSPECTOR_P_SUPPORT(Anabatic::Configuration);
#endif // ANABATIC_CONFIGURATION_H

View File

@ -522,6 +522,7 @@ namespace Anabatic {
inline bool isSourceVertex ( Vertex* ) const;
inline Net* getNet () const;
inline bool isTargetVertex ( Vertex* ) const;
DbU::Unit getAntennaMaxWL () const;
inline DbU::Unit getSearchAreaHalo () const;
template<typename DistanceT>
inline DistanceT* setDistance ( DistanceT );

View File

@ -213,7 +213,8 @@ namespace Anabatic {
bool doGrid ();
Contact* getGContact ( Net* );
inline const vector<Contact*>& getGContacts () const;
Contact* breakGoThrough ( Net* net );
Segment* hasGoThrough ( Net* ) const;
Contact* breakGoThrough ( Net* );
bool unrefContact ( Contact* );
void setSouthWestCorner ( DbU::Unit x, DbU::Unit y );
void cleanupGlobal ();

View File

@ -72,6 +72,12 @@ namespace {
//unsigned const NonConvexOpt = 0x0200;
Instance* extractInstance ( const RoutingPad* rp )
{
return rp->getOccurrence().getPath().getTailInstance();
}
string extractInstanceName ( const RoutingPad* rp )
{
ostringstream name;
@ -300,7 +306,8 @@ namespace Etesian {
, _placementLB (NULL)
, _placementUB (NULL)
, _densityLimits(NULL)
, _cellsToIds ()
, _netsToIds ()
, _instsToIds ()
, _idsToInsts ()
, _idsToNets ()
, _viewer (NULL)
@ -410,8 +417,11 @@ namespace Etesian {
delete _placementUB;
delete _densityLimits;
unordered_map<string,unsigned int> emptyCellsToIds;
_cellsToIds.swap( emptyCellsToIds );
NetsToIds emptyNetsToIds;
_netsToIds.swap( emptyNetsToIds );
InstancesToIds emptyInstsToIds;
_instsToIds.swap( emptyInstsToIds );
vector<InstanceInfos> emptyIdsToInsts;
_idsToInsts.swap( emptyIdsToInsts );
@ -701,8 +711,8 @@ namespace Etesian {
cmess1 << " - Building RoutingPads (transhierarchical) ..." << endl;
//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;
index_t instanceId = 0;
@ -725,8 +735,8 @@ namespace Etesian {
positions[instanceId] = point<int_t>( xpos, ypos );
instances[instanceId].attributes = 0;
_cellsToIds.insert( make_pair(getString(instance->getName()),instanceId) );
_idsToInsts.push_back( make_tuple(instance,0,0) );
_instsToIds.insert( make_pair(instance,instanceId) );
_idsToInsts.push_back( make_tuple(instance,vector<RoutingPad*>()) );
// cerr << "FIXED id=" << instanceId
// << " " << instance << " size:(" << xsize << " " << ysize
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
@ -799,8 +809,8 @@ namespace Etesian {
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
}
_cellsToIds.insert( make_pair(instanceName,instanceId) );
_idsToInsts.push_back( make_tuple(instance,0,0) );
_instsToIds.insert( make_pair(instance,instanceId) );
_idsToInsts.push_back( make_tuple(instance,vector<RoutingPad*>()) );
++instanceId;
dots.dot();
}
@ -862,45 +872,56 @@ namespace Etesian {
dots.dot();
_netsToIds.insert( make_pair(net,netId) );
_idsToNets[netId] = make_tuple( net, _instsToIds.size(), 0 );
nets[netId] = temporary_net( netId, 1 );
_idsToNets[netId] = make_tuple( net, _cellsToIds.size(), 0 );
//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";
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
// 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
// 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;
//cerr << "Outside RP: " << rp << endl;
continue;
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;
continue;
}
}
string insName = extractInstanceName( rp );
Point offset = extractRpOffset ( rp );
Instance* instance = extractInstance ( rp );
string insName = extractInstanceName( rp );
Point offset = extractRpOffset ( rp );
int_t xpin = offset.getX() / vpitch;
int_t ypin = offset.getY() / hpitch;
auto iid = _cellsToIds.find( insName );
if (iid == _cellsToIds.end()) {
if (insName != topCellInstancePin) {
auto iid = _instsToIds.find( instance );
if (iid == _instsToIds.end()) {
if (not instance) {
cerr << Error( "Unable to lookup instance \"%s\".", insName.c_str() ) << endl;
}
} else {
@ -914,8 +935,6 @@ namespace Etesian {
}
}
}
//cerr << "| " << rp << " pos:(" << xpin << " " << ypin << ")" << endl;
}
netId++;
@ -1052,7 +1071,7 @@ namespace Etesian {
ostringstream label;
label.str("");
label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "] "
<< setw(5) << setprecision(4) << linearDisruption << "% Bipart.";
<< setw(7) << fixed << setprecision(1) << linearDisruption << "% Bipart.";
_progressReport1(label.str() );
upperWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementUB));
@ -1070,7 +1089,7 @@ namespace Etesian {
, pullingForce
, 2.0f * linearDisruption);
solve_linear_system( *_circuit, *_placementLB, solv, 200 ); // 200 iterations
_progressReport2(" Linear." );
_progressReport2(" Linear." );
if(options & UpdateLB)
_updatePlacement( _placementUB );
@ -1078,7 +1097,7 @@ namespace Etesian {
// Optimize orientation sometimes
if (i%5 == 0) {
optimize_exact_orientations( *_circuit, *_placementLB );
_progressReport2(" Orient." );
_progressReport2(" Orient." );
}
lowerWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementLB));
@ -1093,8 +1112,8 @@ namespace Etesian {
penaltyIncrease = std::min(maxInc, std::max(minInc,
penaltyIncrease * std::sqrt( targetImprovement / (optRatio - prevOptRatio) )
) );
cparanoid << " L/U ratio: " << 100*optRatio << "% (previous: " << 100*prevOptRatio << "%)\n"
<< " Pulling force: " << pullingForce << " Increase: " << penaltyIncrease << endl;
cparanoid << " L/U ratio: " << 100*optRatio << "% (previous: " << 100*prevOptRatio << "%)\n"
<< " Pulling force: " << pullingForce << " Increase: " << penaltyIncrease << endl;
pullingForce += penaltyIncrease;
prevOptRatio = optRatio;
@ -1103,7 +1122,7 @@ namespace Etesian {
++i;
if ((linearDisruption < getAntennaInsertThreshold()*100.0) and not antennaDone) {
antennaProtect();
//antennaProtect();
antennaDone = true;
}
// First way to exit the loop: UB and LB difference is <10%
@ -1187,31 +1206,33 @@ namespace Etesian {
cdebug_log(122,0) << "diodeWidth=" << diodeWidth << "p" << endl;
for ( coloquinte::index_t inet=0 ; inet < _circuit->net_cnt() ; ++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;
DbU::Unit rsmt = toDbU( coloquinte::get_RSMT_length( *_circuit, *_placementUB, inet ) );
Net* net = std::get<0>( _idsToNets[inet] );
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] );
if ((rsmt > maxWL) or net->isExternal()) {
cdebug_log(122,0) << "| Net [" << inet << "] \"" << net->getName() << "\" may have antenna effect, "
<< DbU::getValueString(rsmt)
<< " drive=" << drivePower
<< " \"" << masterName << "\""
<< endl;
std::get<2>( _idsToNets [inet ] ) |= NeedsDiode;
std::get<2>( _idsToInsts[idriver] ) |= NeedsDiode;
std::get<1>( _idsToInsts[idriver] ) = inet;
coloquinte::point<int_t> cell_size = _circuit->get_cell_size(idriver);
cell_size.x += diodeWidth;
_circuit->set_cell_size( idriver, cell_size );
++count;
std::get<2>( _idsToNets[inet] ) |= NeedsDiode;
for ( RoutingPad* rp : net->getRoutingPads() ) {
Segment* segment = dynamic_cast<Segment*>( rp->getOccurrence().getEntity() );
if (not segment) continue;
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;
}
}
}
cmess1 << ::Dots::asInt( " - Inserted diodes", count ) << endl;
@ -1383,7 +1404,8 @@ namespace Etesian {
if (getBlockInstance()) topTransformation = getBlockInstance()->getTransformation();
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()) )
{
@ -1396,14 +1418,14 @@ namespace Etesian {
instanceName.erase( 0, 1 );
instanceName.erase( instanceName.size()-1 );
auto iid = _cellsToIds.find( instanceName );
if (iid == _cellsToIds.end() ) {
auto iid = _instsToIds.find( instance );
if (iid == _instsToIds.end() ) {
cerr << Error( "Unable to lookup instance <%s>.", instanceName.c_str() ) << endl;
} else {
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED)
continue;
uint32_t outputSide = getOutputSide( instance->getMasterCell() );
//uint32_t outputSide = getOutputSide( instance->getMasterCell() );
point<int_t> position = placement->positions_[(*iid).second];
Transformation cellTrans = toTransformation( position
, placement->orientations_[(*iid).second]
@ -1412,33 +1434,28 @@ namespace Etesian {
, vpitch
);
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)) {
Transformation diodeTrans;
if (outputSide & RightSide) {
DbU::Unit dx = instance ->getMasterCell()->getAbutmentBox().getWidth();
if ( (cellTrans.getOrientation() == Transformation::Orientation::R2)
or (cellTrans.getOrientation() == Transformation::Orientation::MX))
dx = -dx;
diodeTrans = Transformation( cellTrans.getTx() + dx
, cellTrans.getTy()
, cellTrans.getOrientation() );
} else {
DbU::Unit dx = _diodeCell->getAbutmentBox().getWidth();
if ( (cellTrans.getOrientation() == Transformation::Orientation::R2)
or (cellTrans.getOrientation() == Transformation::Orientation::MX))
dx = -dx;
diodeTrans = cellTrans;
cellTrans = Transformation( diodeTrans.getTx() + dx
, diodeTrans.getTy()
, diodeTrans.getOrientation() );
const vector<RoutingPad*>& rps = std::get<1>( _idsToInsts[(*iid).second] );
if ((flags & FinalStage) and not rps.empty()) {
DbU::Unit sign = 1;
DbU::Unit cellWidth = 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)
or (cellTrans.getOrientation() == Transformation::Orientation::MX)) {
sign = -1;
}
for ( size_t i=0 ; i<rps.size() ; ++i ) {
cdebug_log(122,0) << "diode position [" << i << "] " << DbU::getValueString((DbU::Unit)(cellTrans.getTx() + cellWidth + i*diodeWidth)) << endl;
diodeInsts.push_back
( make_tuple( rps[i]
, Transformation( cellTrans.getTx() + sign * (cellWidth + i*diodeWidth)
, cellTrans.getTy()
, cellTrans.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
@ -1456,35 +1473,28 @@ namespace Etesian {
break;
}
for ( auto diodeInfos : diodeMasters ) {
Net* topNet = std::get<0>( _idsToNets[ std::get<1>(diodeInfos) ] );
Instance* instance = static_cast<Instance*>( std::get<0>(diodeInfos).getEntity() );
Cell* ownerCell = instance->getCell();
Instance* diode = _createDiode( ownerCell );
diode->setTransformation( std::get<2>( diodeInfos ));
for ( auto diodeInfos : diodeInsts ) {
RoutingPad* rp = std::get<0>( diodeInfos );
Net* topNet = rp->getNet();
Instance* instance = extractInstance( rp );
Cell* ownerCell = instance->getCell();
Instance* diode = _createDiode( ownerCell );
diode->setTransformation ( std::get<1>( diodeInfos ));
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;
}
}
cdebug_log(122,0) << "Driver net=" << topNet << endl;
cdebug_log(122,0) << " " << instance << " @" << instance->getTransformation() << endl;
if (diodeOutput and driverOutput) {
cdebug_log(122,0) << "Bind:" << endl;
Plug* diodePlug = diode ->getPlug( diodeOutput );
Plug* driverPlug = instance->getPlug( driverOutput );
diodePlug->setNet( driverPlug->getNet() );
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) << " Driver net=" << topNet << endl;
cdebug_log(122,0) << " " << instance << " @" << instance->getTransformation() << endl;
cdebug_log(122,0) << " " << diode << " @" << diode ->getTransformation() << endl;
cdebug_log(122,0) << " topNet->getCell():" << topNet->getCell() << endl;
cdebug_log(122,0) << " " << std::get<0>(diodeInfos).getPath() << endl;
Path path = std::get<0>(diodeInfos).getPath();
cdebug_log(122,0) << " " << diode << " @" << diode ->getTransformation() << endl;
cdebug_log(122,0) << " topNet->getCell():" << topNet->getCell() << endl;
cdebug_log(122,0) << " " << rp->getOccurrence().getPath() << endl;
Path path = rp->getOccurrence().getPath().getHeadPath();
RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea );
}
}
@ -1499,7 +1509,15 @@ namespace Etesian {
Instance* EtesianEngine::_createDiode ( Cell* owner )
{
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();
}

View File

@ -18,7 +18,9 @@
#include "hurricane/Warning.h"
#include "hurricane/DataBase.h"
#include "hurricane/UpdateSession.h"
#include "hurricane/DeepNet.h"
#include "hurricane/Plug.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/Path.h"
#include "hurricane/Library.h"
#include "hurricane/viewer/CellWidget.h"
@ -38,6 +40,9 @@ namespace Etesian {
using Hurricane::Transformation;
using Hurricane::DataBase;
using Hurricane::Library;
using Hurricane::DeepNet;
using Hurricane::Plug;
using Hurricane::RoutingPad;
using Hurricane::UpdateSession;
using CRL::AllianceFramework;
using CRL::CatalogExtension;
@ -238,26 +243,29 @@ namespace Etesian {
if (feed == NULL) break;
}
Instance* instance = Instance::create
Point blockPoint = getEtesian()->toBlock( Point(xtie,_ybottom) );
Instance* instance = Instance::create
( getEtesian()->getBlockCell()
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
, feed
, getTransformation( feed->getAbutmentBox()
, xtie
, _ybottom
, (yspin)?Transformation::Orientation::MY
:Transformation::Orientation::ID
, blockPoint.getX()
, blockPoint.getY()
, (yspin) ? Transformation::Orientation::MY
: Transformation::Orientation::ID
)
, Instance::PlacementStatus::PLACED
);
_tiles.insert( before
, Tile( xtie, feed->getAbutmentBox().getWidth(), Occurrence(instance) ));
, Tile( xtie
, feed->getAbutmentBox().getWidth()
, getEtesian()->toCell( Occurrence(instance) )));
xtie += feedWidth;
}
}
Instance* Slice::createDiodeUnder ( const Box& diodeArea )
Instance* Slice::createDiodeUnder ( RoutingPad* rp, const Box& diodeArea, DbU::Unit xHint )
{
Cell* diode = getEtesian()->getDiodeCell();
if (diode == NULL) {
@ -270,15 +278,61 @@ namespace Etesian {
return NULL;
}
Instance* diodeInst = 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;
bool foundCandidate = false;
auto iCandidate = _tiles.begin();
DbU::Unit dCandidate = 0;
for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) {
if ((*iTile).getXMax() < diodeArea.getXMin()) continue;
if ((*iTile).getXMax() >= diodeArea.getXMax()) break;
if ((*iTile).getXMax() <= diodeArea.getXMin()) continue;
if ((*iTile).getXMin() >= diodeArea.getXMax()) break;
if ((*iTile).getMasterCell() != feed) continue;
diodeInst = (*iTile).getInstance();
diodeInst->setMasterCell( diode );
break;
if (blockInst) {
if ((*iTile).getOccurrence().getPath().getHeadInstance() != blockInst)
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;
}
@ -301,10 +355,13 @@ namespace Etesian {
Area::Area ( EtesianEngine* etesian )
: _etesian (etesian)
, _tieLut ()
, _cellAb (etesian->getBlockCell()->getAbutmentBox())
, _cellAb (etesian->getCell()->getAbutmentBox())
, _sliceHeight(_etesian->getSliceHeight())
, _slices ()
{
if (etesian->getBlockInstance())
_cellAb = etesian->getBlockInstance()->getAbutmentBox();
size_t slicesNb = _cellAb.getHeight() / _sliceHeight;
for ( size_t islice=0 ; islice<slicesNb ; ++islice )
_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 (not diodeArea.intersect(_cellAb)) return NULL;
if (not blockDiodeArea.intersect(_cellAb)) return NULL;
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;
_area = new Area ( this );
Box topCellAb = getBlockCell()->getAbutmentBox();
Box topCellAb = getCell()->getAbutmentBox();
_area->setSpinSlice0( _yspinSlice0 );
if (getBlockInstance()) {
Transformation toBlockTransf = getBlockInstance()->getTransformation();
toBlockTransf.invert();
topCellAb = getBlockInstance()->getAbutmentBox();
for ( Instance* instance : getCell()->getInstances() ) {
if (instance == getBlockInstance()) continue;
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) {
Box overlapAb = instance->getAbutmentBox();
toBlockTransf.applyOn( overlapAb );
overlapAb = topCellAb.getIntersection( overlapAb );
if (not overlapAb.isEmpty()) {
_area->merge( Occurrence(instance), overlapAb );
@ -617,7 +678,7 @@ namespace Etesian {
for ( Occurrence occurrence : getBlockCell()->getTerminalNetlistInstanceOccurrences() )
{
Instance* instance = static_cast<Instance*>(occurrence.getEntity());
Instance* instance = static_cast<Instance*>( occurrence.getEntity() );
Cell* masterCell = instance->getMasterCell();
if (CatalogExtension::isFeed(masterCell)) {
@ -625,19 +686,23 @@ namespace Etesian {
, getString(instance->getName()).c_str() ) << endl;
}
Box instanceAb = masterCell->getAbutmentBox();
Transformation instanceTransf = instance->getTransformation();
occurrence.getPath().getTransformation().applyOn( instanceTransf );
instanceTransf.applyOn( instanceAb );
Box instanceAb = instance->getAbutmentBox();
Occurrence cellOccurrence = toCell( occurrence );
cellOccurrence.getPath().getTransformation().applyOn( instanceAb );
if (not topCellAb.contains(instanceAb)) {
cerr << Warning( "EtesianEngine::readSlices(): Instance %s is not fully enclosed in the top cell."
, getString(instance->getName()).c_str() ) << endl;
cerr << Warning( "EtesianEngine::readSlices(): Instance %s is not fully enclosed in the top cell.\n"
" * 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;
}
_area->merge( occurrence, instanceAb );
_area->merge( cellOccurrence, instanceAb );
}
_area->buildSubSlices();

View File

@ -25,6 +25,7 @@
namespace Hurricane {
class Layer;
class Net;
class RoutingPad;
class Cell;
class CellWidget;
class CellViewer;
@ -43,10 +44,15 @@ namespace Etesian {
using Hurricane::Timer;
using Hurricane::Name;
using Hurricane::Layer;
using Hurricane::DBo;
using Hurricane::Net;
using Hurricane::RoutingPad;
using Hurricane::Cell;
using Hurricane::Record;
using Hurricane::Instance;
using Hurricane::Point;
using Hurricane::Path;
using Hurricane::Transformation;
// -------------------------------------------------------------------
@ -60,8 +66,10 @@ namespace Etesian {
static const uint32_t LeftSide = (1<<3);
public:
typedef ToolEngine Super;
typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
typedef std::tuple<Instance*,int32_t,uint32_t> InstanceInfos;
typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
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:
static const Name& staticGetName ();
static EtesianEngine* create ( Cell* );
@ -88,6 +96,8 @@ namespace Etesian {
inline DbU::Unit getLatchUpDistance () const;
inline const FeedCells& getFeedCells () const;
inline Cell* getDiodeCell () const;
std::string getUniqueDiodeName ();
inline Area* getArea () const;
inline Hurricane::CellViewer* getViewer () const;
inline void setViewer ( Hurricane::CellViewer* );
inline Cell* getBlockCell () const;
@ -103,6 +113,13 @@ namespace Etesian {
void clearColoquinte ();
void loadLeafCellLayouts ();
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 ();
void preplace ();
void roughLegalize ( float minDisruption, unsigned options );
@ -120,31 +137,32 @@ namespace Etesian {
virtual std::string _getTypeName () const;
private:
// Attributes.
static Name _toolName;
static Name _toolName;
protected:
Configuration* _configuration;
Instance* _block;
bool _placed;
bool _ySpinSet;
bool _flatDesign;
coloquinte::box<coloquinte::int_t>* _surface;
coloquinte::netlist* _circuit;
coloquinte::placement_t* _placementLB;
coloquinte::placement_t* _placementUB;
coloquinte::density_restrictions* _densityLimits;
std::unordered_map<string,unsigned int> _cellsToIds;
std::vector<InstanceInfos> _idsToInsts;
std::vector<NetInfos> _idsToNets;
Hurricane::CellViewer* _viewer;
Cell* _diodeCell;
FeedCells _feedCells;
BloatCells _bloatCells;
Area* _area;
size_t _yspinSlice0;
DbU::Unit _sliceHeight;
DbU::Unit _fixedAbHeight;
DbU::Unit _fixedAbWidth;
uint32_t _diodeCount;
Configuration* _configuration;
Instance* _block;
bool _placed;
bool _ySpinSet;
bool _flatDesign;
coloquinte::box<coloquinte::int_t>* _surface;
coloquinte::netlist* _circuit;
coloquinte::placement_t* _placementLB;
coloquinte::placement_t* _placementUB;
coloquinte::density_restrictions* _densityLimits;
NetsToIds _netsToIds;
InstancesToIds _instsToIds;
std::vector<InstanceInfos> _idsToInsts;
std::vector<NetInfos> _idsToNets;
Hurricane::CellViewer* _viewer;
Cell* _diodeCell;
FeedCells _feedCells;
BloatCells _bloatCells;
Area* _area;
size_t _yspinSlice0;
DbU::Unit _sliceHeight;
DbU::Unit _fixedAbHeight;
DbU::Unit _fixedAbWidth;
uint32_t _diodeCount;
protected:
// Constructors & Destructors.
@ -197,6 +215,81 @@ namespace Etesian {
inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); }
inline DbU::Unit EtesianEngine::toDbU ( int64_t v ) const { return v*getSliceStep(); }
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.
extern const char* missingEtesian;

View File

@ -21,6 +21,9 @@
#include "hurricane/Interval.h"
#include "hurricane/Instance.h"
#include "hurricane/Occurrence.h"
namespace Hurricane {
class RoutingPad;
}
namespace Etesian {
@ -32,6 +35,7 @@ namespace Etesian {
using Hurricane::Interval;
using Hurricane::DBo;
using Hurricane::Cell;
using Hurricane::RoutingPad;
using Hurricane::Instance;
using Hurricane::Transformation;
using Hurricane::Occurrence;
@ -232,7 +236,7 @@ namespace Etesian {
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( const Box& );
Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint );
inline std::string _getString () const;
Record* _getRecord () const;
private:
@ -270,7 +274,7 @@ namespace Etesian {
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( const Box& );
Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint );
inline std::string _getString () const;
Record* _getRecord () const;
private:

View File

@ -494,7 +494,7 @@ namespace Katana {
throw Error ("KatanaEngine::runGlobalRouter(): Global routing already done or loaded.");
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();
cmess1 << " o Running global routing." << endl;