From 5649a3b98418e974fdd9d5af7c0be700fd4060c2 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Wed, 27 Jan 2021 11:38:00 +0100 Subject: [PATCH] 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). --- anabatic/CMakeLists.txt | 1 + anabatic/src/AnabaticEngine.cpp | 2 + anabatic/src/AntennaProtect.cpp | 642 +++++++++++++++++++++++++ anabatic/src/CMakeLists.txt | 4 +- anabatic/src/Configuration.cpp | 26 +- anabatic/src/Dijkstra.cpp | 22 +- anabatic/src/GCell.cpp | 16 + anabatic/src/anabatic/AnabaticEngine.h | 4 + anabatic/src/anabatic/Configuration.h | 9 +- anabatic/src/anabatic/Dijkstra.h | 1 + anabatic/src/anabatic/GCell.h | 3 +- etesian/src/EtesianEngine.cpp | 248 +++++----- etesian/src/Placement.cpp | 127 +++-- etesian/src/etesian/EtesianEngine.h | 145 +++++- etesian/src/etesian/Placement.h | 8 +- katana/src/GlobalRoute.cpp | 2 +- 16 files changed, 1065 insertions(+), 195 deletions(-) create mode 100644 anabatic/src/AntennaProtect.cpp diff --git a/anabatic/CMakeLists.txt b/anabatic/CMakeLists.txt index 4d6c97d7..9786c67f 100644 --- a/anabatic/CMakeLists.txt +++ b/anabatic/CMakeLists.txt @@ -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) diff --git a/anabatic/src/AnabaticEngine.cpp b/anabatic/src/AnabaticEngine.cpp index 9f1d4530..c7d6a805 100644 --- a/anabatic/src/AnabaticEngine.cpp +++ b/anabatic/src/AnabaticEngine.cpp @@ -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() ); diff --git a/anabatic/src/AntennaProtect.cpp b/anabatic/src/AntennaProtect.cpp new file mode 100644 index 00000000..2c49ca13 --- /dev/null +++ b/anabatic/src/AntennaProtect.cpp @@ -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 +#include +#include +#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 RPInfos; + typedef map RoutingPadInfos; + typedef set HorizontalSet; + typedef set VerticalSet; + typedef map< DbU::Unit, vector > 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& 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& 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 _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& 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( 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( 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 ; isize() ; ++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()) ).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 ; igetWest(); + 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& 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(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& 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( 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& 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& 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 + ( ToolEngine::get( getCell(), EtesianEngine::staticGetName() )); + + DbU::Unit antennaMaxWL = etesian->getAntennaMaxWL(); + + vector clusters; + set rpsDone; + set segmentsDone; + for ( RoutingPad* rp : net->getRoutingPads() ) { + if (rpsDone.find(rp) != rpsDone.end()) continue; + + DiodeCluster* cluster = new DiodeCluster ( rp, this ); + clusters.push_back( cluster ); + + vector hooksStack; + hooksStack.push_back( rp->getBodyHook() ); + while ( not hooksStack.empty() ) { + Hook* topHook = hooksStack.back(); + RoutingPad* topRp = dynamic_cast( topHook->getComponent() ); + RoutingPad* connexRp = NULL; + hooksStack.pop_back(); + + for ( Hook* hook : topHook->getHooks() ) { + RoutingPad* gcellRp = dynamic_cast( 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( 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(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 ; ineedsDiode()) continue; + + const vector diodes = clusters[i]->createDiodes( etesian->getArea() ); + RoutingPad* rp = clusters[i]->getRefRp(); + if (not diodes.empty()) { + Net* topNet = rp->getNet(); + Plug* sinkPlug = dynamic_cast( 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 + ( 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. diff --git a/anabatic/src/CMakeLists.txt b/anabatic/src/CMakeLists.txt index ae1c93c7..7597035f 100644 --- a/anabatic/src/CMakeLists.txt +++ b/anabatic/src/CMakeLists.txt @@ -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} diff --git a/anabatic/src/Configuration.cpp b/anabatic/src/Configuration.cpp index 21d85d48..c081813f 100644 --- a/anabatic/src/Configuration.cpp +++ b/anabatic/src/Configuration.cpp @@ -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; } diff --git a/anabatic/src/Dijkstra.cpp b/anabatic/src/Dijkstra.cpp index 7a5122c7..bff4ded9 100644 --- a/anabatic/src/Dijkstra.cpp +++ b/anabatic/src/Dijkstra.cpp @@ -1459,6 +1459,10 @@ namespace Anabatic { } + DbU::Unit Dijkstra::getAntennaMaxWL () const + { return _anabatic->getAntennaMaxWL(); } + + Point Dijkstra::_getPonderedPoint() const { vector rps; @@ -1533,12 +1537,13 @@ namespace Anabatic { cdebug_log(112,1) << "Dijkstra::load() " << _net << endl; vector 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 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); } diff --git a/anabatic/src/GCell.cpp b/anabatic/src/GCell.cpp index 83690322..17e5a8f6 100644 --- a/anabatic/src/GCell.cpp +++ b/anabatic/src/GCell.cpp @@ -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) ) { diff --git a/anabatic/src/anabatic/AnabaticEngine.h b/anabatic/src/anabatic/AnabaticEngine.h index ec56fc58..47d1d058 100644 --- a/anabatic/src/anabatic/AnabaticEngine.h +++ b/anabatic/src/anabatic/AnabaticEngine.h @@ -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(); } diff --git a/anabatic/src/anabatic/Configuration.h b/anabatic/src/anabatic/Configuration.h index 32bfbc5b..ad1fc09a 100644 --- a/anabatic/src/anabatic/Configuration.h +++ b/anabatic/src/anabatic/Configuration.h @@ -14,9 +14,7 @@ // +-----------------------------------------------------------------+ -#ifndef ANABATIC_CONFIGURATION_H -#define ANABATIC_CONFIGURATION_H - +#pragma once #include #include @@ -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 diff --git a/anabatic/src/anabatic/Dijkstra.h b/anabatic/src/anabatic/Dijkstra.h index d2a689fa..53377220 100644 --- a/anabatic/src/anabatic/Dijkstra.h +++ b/anabatic/src/anabatic/Dijkstra.h @@ -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 inline DistanceT* setDistance ( DistanceT ); diff --git a/anabatic/src/anabatic/GCell.h b/anabatic/src/anabatic/GCell.h index 91757fb1..2495d6d1 100644 --- a/anabatic/src/anabatic/GCell.h +++ b/anabatic/src/anabatic/GCell.h @@ -213,7 +213,8 @@ namespace Anabatic { bool doGrid (); Contact* getGContact ( Net* ); inline const vector& 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 (); diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index 0454c1e9..487796d9 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -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 emptyCellsToIds; - _cellsToIds.swap( emptyCellsToIds ); + NetsToIds emptyNetsToIds; + _netsToIds.swap( emptyNetsToIds ); + + InstancesToIds emptyInstsToIds; + _instsToIds.swap( emptyInstsToIds ); vector 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( 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()) ); // 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()) ); ++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(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( 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(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(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(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 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( 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 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 > diodeMasters; + DbU::Unit diodeWidth = (_diodeCell) ? _diodeCell->getAbutmentBox().getWidth() : 0; + vector< tuple > 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 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& 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(_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( 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( 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(); } diff --git a/etesian/src/Placement.cpp b/etesian/src/Placement.cpp index ab189df1..b7c0d24a 100644 --- a/etesian/src/Placement.cpp +++ b/etesian/src/Placement.cpp @@ -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( 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 ; islicegetBlockInstance()->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(occurrence.getEntity()); + Instance* instance = static_cast( 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(); diff --git a/etesian/src/etesian/EtesianEngine.h b/etesian/src/etesian/EtesianEngine.h index 5c06c828..88e9f337 100644 --- a/etesian/src/etesian/EtesianEngine.h +++ b/etesian/src/etesian/EtesianEngine.h @@ -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 NetInfos; - typedef std::tuple InstanceInfos; + typedef std::tuple NetInfos; + typedef std::tuple > InstanceInfos; + typedef std::map InstancesToIds; + typedef std::map 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* _surface; - coloquinte::netlist* _circuit; - coloquinte::placement_t* _placementLB; - coloquinte::placement_t* _placementUB; - coloquinte::density_restrictions* _densityLimits; - std::unordered_map _cellsToIds; - std::vector _idsToInsts; - std::vector _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* _surface; + coloquinte::netlist* _circuit; + coloquinte::placement_t* _placementLB; + coloquinte::placement_t* _placementUB; + coloquinte::density_restrictions* _densityLimits; + NetsToIds _netsToIds; + InstancesToIds _instsToIds; + std::vector _idsToInsts; + std::vector _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; diff --git a/etesian/src/etesian/Placement.h b/etesian/src/etesian/Placement.h index 330c896a..f71c566b 100644 --- a/etesian/src/etesian/Placement.h +++ b/etesian/src/etesian/Placement.h @@ -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: diff --git a/katana/src/GlobalRoute.cpp b/katana/src/GlobalRoute.cpp index 808e3c5d..9d7a96f7 100644 --- a/katana/src/GlobalRoute.cpp +++ b/katana/src/GlobalRoute.cpp @@ -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;