// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2016-2018, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | A n a b a t i c - Global Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./AnabaticEngine.cpp" | // +-----------------------------------------------------------------+ #include #include #include "hurricane/Bug.h" #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "hurricane/Breakpoint.h" #include "hurricane/RegularLayer.h" #include "hurricane/Horizontal.h" #include "hurricane/RoutingPad.h" #include "hurricane/Vertical.h" #include "hurricane/Cell.h" #include "hurricane/DebugSession.h" #include "hurricane/UpdateSession.h" #include "crlcore/RoutingGauge.h" #include "crlcore/Measures.h" #include "crlcore/Histogram.h" #include "anabatic/GCell.h" #include "anabatic/AutoContactTerminal.h" #include "anabatic/NetBuilderM2.h" #include "anabatic/NetBuilderHV.h" #include "anabatic/NetBuilderVH.h" #include "anabatic/AnabaticEngine.h" namespace { using namespace Hurricane; using namespace Anabatic; class SortAcByXY { public: inline bool operator() ( AutoContactTerminal* contact1, AutoContactTerminal* contact2 ); }; inline bool SortAcByXY::operator() ( AutoContactTerminal* contact1, AutoContactTerminal* contact2 ) { DbU::Unit x1 = contact1->getX(); DbU::Unit x2 = contact2->getX(); if (x1 == x2) { DbU::Unit y1 = contact1->getY(); DbU::Unit y2 = contact2->getY(); if (y1 == y2) return false; return (y1 < y2); } return (x1 < x2); } void shear ( AutoSegment* segment ) { AutoContact* source = segment->getAutoSource(); AutoContact* target = segment->getAutoTarget(); bool useSource = true; if (segment->isHorizontal()) { if (not source->isTurn() and target->isTurn()) useSource = false; } else { if (not source->isTurn() and target->isTurn()) useSource = false; } segment->makeDogleg( (useSource ? source->getGCell() : target->getGCell()) ); Session::getDoglegs()[ Session::getDoglegs().size()-2 ]->unsetFlags( AutoSegment::SegAxisSet ); #if BAD_RESULTS AutoContact* source = segment->getAutoSource(); AutoContact* target = segment->getAutoTarget(); AutoSegment* perpandicular = NULL; bool useSource = true; if (segment->isHorizontal()) { if (source->isTurn()) perpandicular = source->getPerpandicular( segment ); else { if (target->isTurn()) { perpandicular = target->getPerpandicular( segment ); useSource = false; } else { if (source->isHTee()) perpandicular = source->getPerpandicular( segment ); else { if (target->isHTee()) { perpandicular = target->getPerpandicular( segment ); useSource = false; } else perpandicular = segment; } } } } else { if (source->isTurn()) perpandicular = source->getPerpandicular( segment ); else { if (target->isTurn()) { perpandicular = target->getPerpandicular( segment ); useSource = false; } else { if (source->isVTee()) perpandicular = source->getPerpandicular( segment ); else { if (target->isVTee()) { perpandicular = target->getPerpandicular( segment ); useSource = false; } else perpandicular = segment; } } } } perpandicular->makeDogleg( (useSource ? source->getGCell() : target->getGCell()) ); #endif } } // Anonymous namespace. namespace Anabatic { using std::cerr; using std::cout; using std::endl; using std::multiset; using std::ostringstream; using Hurricane::Bug; using Hurricane::Error; using Hurricane::Warning; using Hurricane::Breakpoint; using Hurricane::RegularLayer; using Hurricane::Component; using Hurricane::Horizontal; using Hurricane::Vertical; using Hurricane::NetRoutingExtension; using Hurricane::Cell; using Hurricane::DebugSession; using Hurricane::UpdateSession; using CRL::RoutingGauge; using CRL::RoutingLayerGauge; using CRL::addMeasure; using CRL::getMeasure; using CRL::Histogram; // ------------------------------------------------------------------- // Error messages. const char* missingAnbt = "%s :\n\n" " Cell %s do not have any Anabatic (or not yet created).\n"; const char* badMethod = "%s :\n\n" " No method id %ud (Cell %s).\n"; const char* lookupFailed = "Anabatic::Extension::getDatas(Segment*) :\n\n" " Cannot find AutoSegment associated to %s (internal error).\n"; // ------------------------------------------------------------------- // Class : "Anabatic::RawGCellsUnder". RawGCellsUnder::RawGCellsUnder ( const AnabaticEngine* engine, Segment* segment ) { cdebug_log(112,1) << "RawGCellsUnder::RawGCellsUnder(Segment*): " << segment << endl; commonCtor( engine, segment->getSourcePosition(), segment->getTargetPosition() ); cdebug_tabw(112,-1); } RawGCellsUnder::RawGCellsUnder ( const AnabaticEngine* engine, Point source, Point target ) { cdebug_log(112,1) << "RawGCellsUnder::RawGCellsUnder(Point,Point): s:" << source << " t:" << target << endl; commonCtor( engine, source, target ); cdebug_tabw(112,-1); } void RawGCellsUnder::commonCtor ( const AnabaticEngine* engine, Point source, Point target ) { cdebug_log(112,1) << "RawGCellsUnder::commontCtor(): s:" << source << " t:" << target << endl; Box gcellsArea = engine->getCell()->getAbutmentBox(); DbU::Unit axis = 0; Flags side = Flags::NoFlags; if (source.getY() == target.getY()) { side = Flags::EastSide; axis = source.getY(); if (source.getX() > target.getX()) std::swap( source, target ); } if (source.getX() == target.getX()) { side = Flags::NorthSide; axis = source.getX(); if (source.getY() > target.getY()) std::swap( source, target ); } if (side == Flags::NoFlags) { cerr << Error( "RawGCellsUnder::commonCtor(): Points are neither horizontally nor vertically aligneds (ignored)." ) << endl; cdebug_tabw(112,-1); DebugSession::close(); return; } if ( (source.getX() > gcellsArea.getXMax()) or (source.getY() > gcellsArea.getYMax()) or (target.getX() <= gcellsArea.getXMin()) or (target.getY() <= gcellsArea.getYMin()) ) { cerr << Error( "RawGCellsUnder::commonCtor(): Area is completly outside the GCells area (ignored)." ) << endl; cdebug_tabw(112,-1); DebugSession::close(); return; } DbU::Unit xsource = std::max( source.getX(), gcellsArea.getXMin() ); DbU::Unit ysource = std::max( source.getY(), gcellsArea.getYMin() ); DbU::Unit xtarget = std::min( target.getX(), gcellsArea.getXMax() ); DbU::Unit ytarget = std::min( target.getY(), gcellsArea.getYMax() ); if (xtarget == gcellsArea.getXMax()) --xtarget; if (ytarget == gcellsArea.getYMax()) --ytarget; GCell* gsource = engine->getGCellUnder( xsource, ysource ); GCell* gtarget = engine->getGCellUnder( xtarget, ytarget ); if (not gsource) { cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): Source not under a GCell (ignored)." ) << endl; cdebug_tabw(112,-1); DebugSession::close(); return; } if (not gtarget) { cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): Target not under a GCell (ignored)." ) << endl; cdebug_tabw(112,-1); DebugSession::close(); return; } if (gsource == gtarget) { _elements.push_back( Element(gsource,NULL) ); cdebug_tabw(112,-1); DebugSession::close(); return; } cdebug_log(112,0) << "flags:" << side << " axis:" << DbU::getValueString(axis) << endl; Edge* edge = gsource->getEdgeAt( side, axis ); while ( edge ) { _elements.push_back( Element(edge->getSource(),edge) ); cdebug_log(112,0) << "| push:" << edge->getSource() << " from " << edge << endl; if (edge->getTarget() == gtarget) break; edge = edge->getTarget()->getEdgeAt( side, axis ); } _elements.push_back( Element(gtarget,NULL) ); cdebug_log(112,0) << "| push:" << gtarget << " last/target" << endl; cdebug_tabw(112,-1); } // ------------------------------------------------------------------- // Class : "Anabatic::NetData". NetData::NetData ( Net* net ) : _net (net) , _state (NetRoutingExtension::get(net)) , _searchArea() , _rpCount (0) , _sparsity (0) , _flags () { if (_state and _state->isMixedPreRoute()) return; for ( RoutingPad* rp : _net->getRoutingPads() ) { _searchArea.merge( rp->getBoundingBox() ); ++_rpCount; } _update(); } // ------------------------------------------------------------------- // Class : "Anabatic::AnabaticEngine". Name AnabaticEngine::_toolName = "Anabatic"; AnabaticEngine* AnabaticEngine::get ( const Cell* cell ) { return static_cast(ToolEngine::get(cell,staticGetName())); } const Name& AnabaticEngine::staticGetName () { return _toolName; } const Name& AnabaticEngine::getName () const { return _toolName; } AnabaticEngine::AnabaticEngine ( Cell* cell ) : Super(cell) , _configuration (new Configuration()) , _chipTools (cell) , _state (EngineCreation) , _matrix () , _gcells () , _ovEdges () , _netOrdering () , _netDatas () , _viewer (NULL) , _flags (Flags::DestroyBaseContact) , _stamp (-1) , _densityMode (MaxDensity) , _autoSegmentLut () , _autoContactLut () , _edgeCapacitiesLut() , _blockageNet (cell->getNet("blockagenet")) { _matrix.setCell( cell, _configuration->getSliceHeight() ); Edge::unity = _configuration->getSliceHeight(); if (not _blockageNet) _blockageNet = Net::create( cell, "blockagenet" ); } void AnabaticEngine::_postCreate () { Super::_postCreate(); UpdateSession::open(); GCell::create( this ); UpdateSession::close(); } AnabaticEngine* AnabaticEngine::create ( Cell* cell ) { if (not cell) throw Error( "AnabaticEngine::create(): NULL cell argument." ); if (cell->getAbutmentBox().isEmpty()) throw Error( "AnabaticEngine::create(): %s has no abutment box." , getString(cell).c_str() ); AnabaticEngine* engine = new AnabaticEngine ( cell ); engine->_postCreate(); return engine; } AnabaticEngine::~AnabaticEngine () { delete _configuration; for ( pair data : _netDatas ) delete data.second; } void AnabaticEngine::_preDestroy () { cdebug_log(145,1) << "Anabatic::_preDestroy ()" << endl; if (getState() < EngineGutted) setState( EnginePreDestroying ); _gutAnabatic(); _state = EngineGutted; cdebug_log(145,0) << "About to delete base class ToolEngine." << endl; Super::_preDestroy(); //cmess2 << " - GCells := " << GCell::getAllocateds() << endl; cmess2 << " - AutoContacts := " << AutoContact::getAllocateds() << endl; cmess2 << " - AutoSegments := " << AutoSegment::getAllocateds() << endl; cdebug_log(145,0) << "Exiting Anabatic::_preDestroy()." << endl; cdebug_tabw(145,-1); } void AnabaticEngine::_gutAnabatic () { openSession(); _flags.reset( Flags::DestroyBaseContact|Flags::DestroyBaseSegment ); if (_state == EngineDriving) { cdebug_log(145,1) << "Saving AutoContacts/AutoSegments." << endl; size_t fixedSegments = 0; size_t sameLayerDoglegs = 0; for ( auto isegment : _autoSegmentLut ) { if (isegment.second->isFixed()) ++fixedSegments; if (isegment.second->reduceDoglegLayer()) ++sameLayerDoglegs; } cmess1 << " o Driving Hurricane data-base." << endl; cmess1 << Dots::asSizet(" - Active AutoSegments",AutoSegment::getAllocateds()-fixedSegments) << endl; cmess1 << Dots::asSizet(" - Active AutoContacts",AutoContact::getAllocateds()-fixedSegments*2) << endl; cmess1 << Dots::asSizet(" - AutoSegments" ,AutoSegment::getAllocateds()) << endl; cmess1 << Dots::asSizet(" - AutoContacts" ,AutoContact::getAllocateds()) << endl; cmess1 << Dots::asSizet(" - Same Layer doglegs" ,sameLayerDoglegs) << endl; //for ( Net* net : _cell->getNets() ) _saveNet( net ); cdebug_tabw(145,-1); } if (_state < EngineGutted ) { cdebug_log(145,0) << "Gutting Anabatic." << endl; _state = EngineGutted; _flags |= Flags::DestroyBaseContact; _destroyAutoSegments(); _destroyAutoContacts(); _flags |= Flags::DestroyGCell; for ( GCell* gcell : _gcells ) gcell->_destroyEdges(); for ( GCell* gcell : _gcells ) gcell->destroy(); _gcells.clear(); _ovEdges.clear(); } Session::close(); } Configuration* AnabaticEngine::getConfiguration () { return _configuration; } Interval AnabaticEngine::getUSide ( Flags direction ) const { Interval side; Box bBox ( getCell()->getBoundingBox() ); if (direction & Flags::Horizontal) side = Interval( bBox.getXMin(), bBox.getXMax() ); else if (direction & Flags::Vertical ) side = Interval( bBox.getYMin(), bBox.getYMax() ); else { cerr << Error( "AnabaticEngine::getUSide(): Unknown direction flag \"%i\"" , getString(direction).c_str() ) << endl; } return side; } int AnabaticEngine::getCapacity ( Interval span, Flags flags ) const { int capacity = 0; Box ab = getCell()->getAbutmentBox(); RoutingGauge* rg = _configuration->getRoutingGauge(); span.inflate( 0, -1 ); if (span.isEmpty()) return 0; const vector& layerGauges = rg->getLayerGauges(); for ( size_t depth=0 ; depth <= _configuration->getAllowedDepth() ; ++depth ) { if (layerGauges[depth]->getType() != Constant::Default) continue; if (flags & Flags::Horizontal) { if (layerGauges[depth]->getDirection() != Constant::Horizontal) continue; capacity += layerGauges[depth]->getTrackNumber( span.getVMin() - ab.getYMin() , span.getVMax() - ab.getYMin() ); //cdebug_log(110,0) << "Horizontal edge capacity:" << capacity << endl; } if (flags & Flags::Vertical) { if (layerGauges[depth]->getDirection() != Constant::Vertical) continue; capacity += layerGauges[depth]->getTrackNumber( span.getVMin() - ab.getXMin() , span.getVMax() - ab.getXMin() ); //cdebug_log(110,0) << "Vertical edge capacity:" << capacity << endl; } } return capacity; } void AnabaticEngine::openSession () { Session::_open(this); } void AnabaticEngine::reset () { _gutAnabatic(); _flags.reset( Flags::DestroyMask ); _state = EngineCreation; UpdateSession::open(); GCell::create( this ); UpdateSession::close(); } void AnabaticEngine::setupNetDatas () { Histogram netHistogram ( 0.0, 1.0, 1 ); netHistogram.setTitle ( "RoutingPads", 0 ); netHistogram.setColor ( "green" , 0 ); netHistogram.setIndent( " " , 0 ); size_t oindex = _netOrdering.size(); for ( Net* net : _cell->getNets() ) { if (_netDatas.find(net->getId()) != _netDatas.end()) continue; NetData* data = new NetData( net ); _netOrdering.push_back( data ); netHistogram.addSample( (float)data->getRpCount(), 0 ); } for ( ; oindex < _netOrdering.size() ; ++oindex ) { _netDatas.insert( make_pair( _netOrdering[oindex]->getNet()->getId() , _netOrdering[oindex] ) ); } sort( _netOrdering.begin(), _netOrdering.end(), SparsityOrder() ); cmess2 << " o Nets Histogram." << endl; cmess2 << netHistogram.toString(0) << endl; } void AnabaticEngine::exclude ( const Name& netName ) { Net* net = _cell->getNet( netName ); if (not net) return; exclude( net ); } void AnabaticEngine::exclude ( Net* net ) { NetDatas::iterator inet =_netDatas.find( net->getId() ); if (inet == _netDatas.end()) return; (*inet).second->setExcluded( true ); } void AnabaticEngine::updateMatrix() { _matrix.setCell( getCell(), Session::getSliceHeight() ); for ( GCell* gcell : _gcells ) _updateLookup( gcell ); } size_t AnabaticEngine::getNetsFromEdge ( const Edge* edge, NetSet& nets ) { size_t count = 0; GCell* source = edge->getSource(); GCell* target = edge->getTarget(); const vector& contacts = source->getGContacts(); for ( Contact* contact : contacts ) { for ( Component* component : contact->getSlaveComponents() ) { if (edge->isHorizontal()) { Horizontal* horizontal = dynamic_cast( component ); if (horizontal and (horizontal->getSource() == contact) and (target->hasGContact(dynamic_cast(horizontal->getTarget())))) { nets.insert( horizontal->getNet() ); ++count; } } if (edge->isVertical()) { Vertical* vertical = dynamic_cast( component ); if (vertical and (vertical->getSource() == contact) and (target->hasGContact(dynamic_cast(vertical->getTarget())))) { nets.insert( vertical->getNet() ); ++count; } } } } return count; } NetData* AnabaticEngine::getNetData ( Net* net, Flags flags ) { NetData* data = NULL; NetDatas::iterator idata = _netDatas.find( net->getId() ); if (idata == _netDatas.end()) { data = new NetData( net ); _netDatas.insert( make_pair(net->getId(),data) ); _netOrdering.push_back( data ); // cerr << Bug( "AnabaticEngine::getNetData() - %s is missing in NetDatas table." // , getString(net->getName()).c_str() // ) << endl; // return NULL; } else data = idata->second; if ((flags & Flags::Create) and not data->getNetRoutingState()) { data->setNetRoutingState( NetRoutingExtension::create(net) ); } return data; } Contact* AnabaticEngine::breakAt ( Segment* segment, GCell* breakGCell ) { size_t i = 0; GCellsUnder gcells ( new RawGCellsUnder(this,segment) ); for ( ; isize() ; ++i ) { if (gcells->gcellAt(i) == breakGCell) break; } Contact* breakContact = breakGCell->getGContact( segment->getNet() ); if (i == gcells->size()) { cerr << Error( "AnabaticEngine::breakAt(): %s is *not* over %s." , getString(segment).c_str() , getString(breakGCell).c_str() ) << endl; return breakContact; } Component* targetContact = segment->getTarget(); segment->getTargetHook()->detach(); segment->getTargetHook()->attach( breakContact->getBodyHook() ); Segment* splitted = NULL; Horizontal* horizontal = dynamic_cast(segment); if (horizontal) { splitted = Horizontal::create( breakContact , targetContact , getConfiguration()->getGHorizontalLayer() , horizontal->getY() , DbU::fromLambda(2.0) ); } else { Vertical* vertical = dynamic_cast(segment); if (vertical) { splitted = Vertical::create( breakContact , targetContact , getConfiguration()->getGVerticalLayer() , vertical->getX() , DbU::fromLambda(2.0) ); } else return breakContact; } for ( ; isize()-1 ; ++i ) gcells->edgeAt(i)->replace( segment, splitted ); return breakContact; } bool AnabaticEngine::unify ( Contact* contact ) { size_t hCount = 0; size_t vCount = 0; Horizontal* horizontals[2]; Vertical* verticals [2]; cdebug_log(112,1) << "AnabaticEngine::unify(): " << (void*)contact << endl; cdebug_log(112,0) << contact << endl; for ( Hook* hook : contact->getBodyHook()->getHooks() ) { RoutingPad* rp = dynamic_cast( hook->getComponent() ); if (rp) { cdebug_log(112,0) << "Cannot unify, there is a RoutingPad in this GCell." << endl; cdebug_tabw(112,-1); return false; } } for ( Component* slave : contact->getSlaveComponents() ) { Horizontal* h = dynamic_cast( slave ); if (h) { if (vCount or (hCount > 1)) return false; horizontals[hCount++] = h; } else { Vertical* v = dynamic_cast( slave ); if (v) { if (hCount or (vCount > 1)) return false; verticals[vCount++] = v; } else { // Something else depends on this contact. cdebug_log(112,0) << "Cannot unify, still have slave components." << endl; cdebug_tabw(112,-1); return false; } } } if (hCount == 2) { if (horizontals[0]->getTarget() != contact) std::swap( horizontals[0], horizontals[1] ); Interval constraints ( false ); GCellsUnder gcells0 = getGCellsUnder( horizontals[0] ); if (not gcells0->empty()) { for ( size_t i=0 ; isize() ; ++i ) constraints.intersection( gcells0->gcellAt(i)->getSide(Flags::Vertical) ); } GCellsUnder gcells1 = getGCellsUnder( horizontals[1] ); if (not gcells1->empty()) { for ( size_t i=0 ; isize() ; ++i ) { constraints.intersection( gcells1->gcellAt(i)->getSide(Flags::Vertical) ); if (constraints.isEmpty()) { cdebug_tabw(112,-1); return false; } } } if (not gcells1->empty()) { for ( size_t i=0 ; isize()-1 ; ++i ) gcells1->edgeAt(i)->replace( horizontals[1], horizontals[0] ); } Component* target = horizontals[1]->getTarget(); horizontals[1]->destroy(); horizontals[0]->getTargetHook()->detach(); horizontals[0]->getTargetHook()->attach( target->getBodyHook() ); horizontals[0]->setY( constraints.getCenter() ); } if (vCount == 2) { cdebug_log(112,0) << "Vertical unify of: " << contact << endl; if (verticals[0]->getTarget() != contact) std::swap( verticals[0], verticals[1] ); Interval constraints ( false ); GCellsUnder gcells0 = getGCellsUnder( verticals[0] ); if (not gcells0->empty()) { for ( size_t i=0 ; isize() ; ++i ) constraints.intersection( gcells0->gcellAt(i)->getSide(Flags::Horizontal) ); } GCellsUnder gcells1 = getGCellsUnder( verticals[1] ); if (not gcells1->empty()) { for ( size_t i=0 ; isize() ; ++i ) { constraints.intersection( gcells1->gcellAt(i)->getSide(Flags::Horizontal) ); if (constraints.isEmpty()) { cdebug_log(112,0) << "Cannot unify, shearing constraints." << endl; cdebug_tabw(112,-1); return false; } } } if (not gcells1->empty()) { for ( size_t i=0 ; isize()-1 ; ++i ) gcells1->edgeAt(i)->replace( verticals[1], verticals[0] ); } Component* target = verticals[1]->getTarget(); verticals[1]->destroy(); verticals[0]->getTargetHook()->detach(); verticals[0]->getTargetHook()->attach( target->getBodyHook() ); verticals[0]->setX( constraints.getCenter() ); } getGCellUnder( contact->getPosition() )->unrefContact( contact ); cdebug_tabw(112,-1); return true; } void AnabaticEngine::ripup ( Segment* seed, Flags flags ) { Net* net = seed->getNet(); DebugSession::open( net, 112, 120 ); cdebug_log(112,1) << "AnabaticEngine::ripup(): " << seed << endl; Contact* end0 = NULL; Contact* end1 = NULL; set ripups; ripups.insert( seed ); vector< pair > stack; if (flags & Flags::Propagate) { stack.push_back( make_pair(seed,seed->getSource()) ); stack.push_back( make_pair(seed,seed->getTarget()) ); } while ( not stack.empty() ) { Contact* contact = dynamic_cast( stack.back().second ); Segment* from = stack.back().first; stack.pop_back(); if (not contact) continue; Segment* connected = NULL; size_t slaveCount = 0; for ( Hook* hook : contact->getBodyHook()->getHooks() ) { Component* linked = hook->getComponent(); if ((linked == contact) or (linked == from)) continue; if (dynamic_cast(linked)) { ++slaveCount; continue; } connected = dynamic_cast( linked ); if (connected) ++slaveCount; } if ((slaveCount == 1) and (connected)) { if (not ripups.count(connected)) { stack .push_back( make_pair(connected,connected->getOppositeAnchor(contact)) ); ripups.insert( connected ); } } else { if (not end0) { end0 = contact; cdebug_log(112,0) << "end0:" << contact << endl; } else { if (contact != end0) { end1 = contact; cdebug_log(112,0) << "end1:" << contact << endl; } } } } for ( Segment* segment : ripups ) { cdebug_log(112,1) << "| Destroy:" << segment << endl; GCellsUnder gcells = getGCellsUnder( segment ); if (not gcells->empty()) { for ( size_t i=0 ; isize()-1 ; ++i ) { cdebug_log(112,0) << "| " << gcells->gcellAt(i) << endl; cdebug_log(112,0) << "| " << gcells->edgeAt(i) << endl; gcells->edgeAt(i)->remove( segment ); } } else { cdebug_log(112,0) << "No GCells under segment." << endl; } Contact* source = dynamic_cast( segment->getSource() ); Contact* target = dynamic_cast( segment->getTarget() ); segment->getSourceHook()->detach(); segment->getTargetHook()->detach(); segment->destroy(); bool deletedSource = gcells->gcellAt( 0 )->unrefContact( source ); bool deletedTarget = gcells->gcellAt( gcells->size()-1 )->unrefContact( target ); if (deletedSource) { if (source == end0) end0 = NULL; if (source == end1) end1 = NULL; } if (deletedTarget) { if (target == end0) end0 = NULL; if (target == end1) end1 = NULL; } cdebug_tabw(112,-1); } if (end0) unify( end0 ); if (end1) unify( end1 ); getNetData( net )->setGlobalRouted( false ); cdebug_tabw(112,-1); DebugSession::close(); } void AnabaticEngine::cleanupGlobal () { UpdateSession::open(); for ( GCell* gcell : _gcells ) gcell->cleanupGlobal(); UpdateSession::close(); } void AnabaticEngine::loadGlobalRouting ( uint32_t method ) { if (_state < EngineGlobalLoaded) throw Error ("AnabaticEngine::loadGlobalRouting() : global routing not present yet."); if (_state > EngineGlobalLoaded) throw Error ("AnabaticEngine::loadGlobalRouting() : global routing already loaded."); if (method == EngineLoadGrByNet ) { _loadGrByNet(); } else { throw Error( badMethod, "Anabatic::loadGlobalRouting()", method, getString(_cell).c_str() ); } cleanupGlobal(); if (not getConfiguration()->isTwoMetals()) relaxOverConstraineds(); _state = EngineActive; } void AnabaticEngine::relaxOverConstraineds () { openSession(); DbU::Unit pitch3 = Session::getPitch( 2 ); AutoSegment::IdSet constraineds; AutoSegment::IdSet processeds; for ( GCell* gcell : _gcells ) { multiset acTerminals; for ( AutoContact* contact : gcell->getContacts() ) { if (contact->isTerminal() and (Session::getViaDepth(contact->getLayer()) == 0) ) acTerminals.insert( dynamic_cast(contact) ); } AutoContactTerminal* south = NULL; for ( AutoContactTerminal* north : acTerminals ) { if (south) { if ( south->canDrag() and north->canDrag() and (south->getNet() != north->getNet()) and (south->getX () == north->getX ()) ) { Interval constraints ( gcell->getYMin(), north->getCBYMin() /*- pitch3*/ ); AutoSegment* terminal = south->getSegment(); AutoContact* opposite = terminal->getOppositeAnchor( south ); for ( AutoSegment* segment : AutoSegments_OnContact(terminal,opposite->base()) ) { segment->mergeUserConstraints( constraints ); constraineds.insert( segment ); } constraints = Interval( south->getCBYMax() /*+ pitch3*/, gcell->getYMax() ); terminal = north->getSegment(); opposite = terminal->getOppositeAnchor( north ); for ( AutoSegment* segment : AutoSegments_OnContact(terminal,opposite->base()) ) { segment->mergeUserConstraints( constraints ); constraineds.insert( segment ); } } } south = north; } } Session::revalidate(); for ( AutoSegment* constrained : constraineds ) { if (processeds.find(constrained) != processeds.end()) continue; processeds.insert( constrained ); Interval userConstraints ( false ); vector aligneds; aligneds.push_back( constrained ); for ( AutoSegment* aligned : constrained->getAligneds() ) { aligneds.push_back( aligned ); processeds.insert( aligned ); } sort( aligneds.begin(), aligneds.end(), AutoSegment::CompareBySourceU() ); //AutoSegment* previous = NULL; for ( AutoSegment* aligned : aligneds ) { Interval constraints = userConstraints.getIntersection( aligned->getUserConstraints() ); if (constraints.getSize() < Session::getPitch(1)) { //if (not previous) { // cerr << Warning( "protectAlignedAccesses(): Shearing constraints between S/T on\n" // " %s\n" // " S:%s\n" // " T:%s\n" // " Combined user constraints are too tight [%s : %s]." // , getString(aligned ).c_str() // , getString(aligned->getAutoSource()->getConstraintBox()).c_str() // , getString(aligned->getAutoTarget()->getConstraintBox()).c_str() // , DbU::getValueString(constraints.getVMin()).c_str() // , DbU::getValueString(constraints.getVMax()).c_str() // ) << endl; //} else { // cerr << Warning( "protectAlignedAccesses(): Shearing constraints between\n" // " %s\n" // " %s\n" // " Combined user constraints are too tight [%s : %s]." // , getString(previous).c_str() // , getString(aligned ).c_str() // , DbU::getValueString(constraints.getVMin()).c_str() // , DbU::getValueString(constraints.getVMax()).c_str() // ) << endl; //} //if (previous) { // if (previous->getAutoTarget() == aligned->getAutoSource()) { // cerr << "Found a shared contact: " << aligned->getAutoSource() << endl; shear( aligned ); // } //} userConstraints = aligned->getUserConstraints(); } else { userConstraints = constraints; } //previous = aligned; } } Session::close(); } void AnabaticEngine::_loadGrByNet () { cmess1 << " o Building detailed routing from global. " << endl; size_t shortNets = 0; startMeasures(); openSession(); int gaugeKind = 3; if (getConfiguration()->isTwoMetals()) gaugeKind = 0; if (getConfiguration()->isHV ()) gaugeKind = 1; if (getConfiguration()->isVH ()) gaugeKind = 2; if (gaugeKind < 3) { for ( Net* net : getCell()->getNets() ) { if (NetRoutingExtension::isShortNet(net)) { //AutoSegment::setShortNetMode( true ); ++shortNets; } if (NetRoutingExtension::isAutomaticGlobalRoute(net)) { DebugSession::open( net, 145, 150 ); AutoSegment::setAnalogMode( NetRoutingExtension::isAnalog(net) ); switch ( gaugeKind ) { case 0: NetBuilder::load( this, net ); break; case 1: NetBuilder::load( this, net ); break; case 2: NetBuilder::load( this, net ); break; } Session::revalidate(); DebugSession::close(); } AutoSegment::setAnalogMode ( false ); AutoSegment::setShortNetMode( false ); } } #if defined(CHECK_DATABASE) _check ( "after Anabatic loading" ); #endif Session::close(); stopMeasures(); cmess2 << Dots::asSizet(" - Short nets",shortNets) << endl; if (gaugeKind > 2) { throw Error( "AnabaticEngine::_loadGrByNet(): Unsupported kind of routing gauge \"%s\"." , getString(getConfiguration()->getRoutingGauge()->getName()).c_str() ); } printMeasures( "load" ); addMeasure( getCell(), "Globals", AutoSegment::getGlobalsCount() ); addMeasure( getCell(), "Edges" , AutoSegment::getAllocateds() ); } void AnabaticEngine::updateNetTopology ( Net* net ) { DebugSession::open( net, 145, 150 ); cdebug_log(149,0) << "Anabatic::updateNetTopology( " << net << " )" << endl; cdebug_tabw(145,1); vector contacts; for ( Component* component : net->getComponents() ) { Contact* contact = dynamic_cast( component ); if (contact) { AutoContact* autoContact = Session::lookup( contact ); if (autoContact and autoContact->isInvalidatedCache()) contacts.push_back( autoContact ); } } for ( size_t i=0 ; iupdateTopology(); cdebug_tabw(145,-1); DebugSession::close(); } void AnabaticEngine::finalizeLayout () { cdebug_log(145,0) << "Anabatic::finalizeLayout()" << endl; if (_state > EngineDriving) return; _state = EngineDriving; startMeasures(); _gutAnabatic(); stopMeasures (); printMeasures( "fin" ); _state = EngineGutted; } void AnabaticEngine::_alignate ( Net* net ) { DebugSession::open( net, 145, 150 ); cdebug_log(149,0) << "Anabatic::_alignate( " << net << " )" << endl; cdebug_tabw(145,1); //cmess2 << " - " << getString(net) << endl; set exploredSegments; vector unexploreds; vector aligneds; for ( Component* component : net->getComponents() ) { Segment* segment = dynamic_cast(component); if (segment) { AutoSegment* seedSegment = Session::lookup( segment ); if (seedSegment) unexploreds.push_back( seedSegment ); } } sort( unexploreds.begin(), unexploreds.end(), AutoSegment::CompareId() ); for ( size_t i=0 ; ibase()) == exploredSegments.end()) { cdebug_log(145,0) << "New chunk from: " << seedSegment << endl; aligneds.push_back( seedSegment ); for ( AutoSegment* collapsed : seedSegment->getAligneds() ) { cdebug_log(145,0) << "Aligned: " << collapsed << endl; aligneds.push_back( collapsed ); exploredSegments.insert( collapsed->base() ); } cdebug_tabw(145,1); sort( aligneds.begin(), aligneds.end(), AutoSegment::CompareId() ); cdebug_log(145,0) << "Seed: " << (void*)aligneds[0]->base() << " " << aligneds[0] << endl; for ( size_t j=1 ; jbase()) << " " << aligneds[j] << endl; } cdebug_log(149,0) << "Align on " << aligneds[0] << " " << DbU::getValueString(aligneds[0]->getAxis()) << endl; aligneds[0]->setAxis( aligneds[0]->getAxis(), Flags::Realignate ); aligneds.clear(); cdebug_tabw(145,-1); } } cdebug_tabw(145,-1); DebugSession::close(); } void AnabaticEngine::_computeNetTerminals ( Net* net ) { DebugSession::open( net, 145, 150 ); cdebug_log(149,0) << "Anabatic::_computeNetTerminals( " << net << " )" << endl; cdebug_tabw(145,1); for ( Segment* segment : net->getSegments() ) { AutoSegment* autoSegment = Session::lookup( segment ); if (autoSegment == NULL) continue; if (autoSegment->isInvalidated()) autoSegment->computeTerminal(); } cdebug_tabw(145,-1); DebugSession::close(); } void AnabaticEngine::_saveNet ( Net* net ) { DebugSession::open( net, 145, 150 ); cdebug_log(145,0) << "Anabatic::_saveNet() " << net << endl; cdebug_tabw(145,1); #if 0 cdebug_log(145,0) << "Deleting zero-length segments." << endl; vector nullSegments; set connectedLayers; forEach ( Segment*, segment, net->getSegments() ) { if (segment->getLength()) { if (net->isExternal()) { NetExternalComponents::setExternal( *segment ); } continue; } if (Session::lookup(*segment) == NULL) { cdebug_log(145,0) << "* Not associated to an AutoSegment: " << *segment << endl; continue; } if (not isTopAndBottomConnected(*segment,connectedLayers)) { nullSegments.push_back( *segment ); cdebug_log(145,0) << "* Null Length: " << *segment << endl; } } setFlags( EngineDestroyBaseSegment ); for ( size_t i = 0 ; i < nullSegments.size() ; i++ ) { Contact* source = dynamic_cast(nullSegments[i]->getSource()); Contact* target = dynamic_cast(nullSegments[i]->getTarget()); if ( (source == NULL) or (target == NULL) ) { cerr << Error("Unconnected source/target on %s.",getString(nullSegments[i]).c_str()) << endl; continue; } if (source->getAnchor()) { if (target->getAnchor()) { continue; //cerr << Bug("Both source & target are anchored while deleting zero-length segment:\n" // " %s.",getString(nullSegments[i]).c_str()) << endl; } else swap( source, target ); } cdebug_log(145,0) << "Deleting: " << nullSegments[i] << endl; if (isTopAndBottomConnected(nullSegments[i],connectedLayers)) { cdebug_log(145,0) << "Deletion cancelled, no longer top or bottom connected." << endl; continue; } cdebug_log(145,0) << "* Source: " << (void*)source << " " << source << endl; cdebug_log(145,0) << "* Target: " << (void*)target << " " << target << endl; const Layer* layer = DataBase::getDB()->getTechnology() ->getViaBetween( *connectedLayers.begin(), *connectedLayers.rbegin() ); cdebug_log(145,0) << *connectedLayers.begin() << " + " << *connectedLayers.rbegin() << endl; cdebug_log(145,0) << "* Shrink layer: " << layer << endl; if ( !layer ) { cerr << Error("NULL contact layer while deleting %s." ,getString(nullSegments[i]).c_str()) << endl; continue; } Session::lookup( nullSegments[i] )->destroy (); vector slaveHooks; Hook* masterHook = source->getBodyHook()->getPreviousMasterHook(); while ( masterHook->getNextHook() != source->getBodyHook() ) { slaveHooks.push_back( masterHook->getNextHook() ); cdebug_log(145,0) << "* detach: " << (void*)masterHook->getNextHook()->getComponent() << " " << masterHook->getNextHook()->getComponent() << endl; masterHook->getNextHook()->detach(); } source->destroy(); masterHook = target->getBodyHook(); for ( size_t j=0 ; j < slaveHooks.size() ; j++ ) { slaveHooks[j]->attach( masterHook ); } cdebug_log(145,0) << (void*)target << " " << target << " setLayer: " << layer << endl; target->setLayer( layer ); } unsetFlags( EngineDestroyBaseSegment ); #endif cdebug_tabw(145,-1); DebugSession::close(); } void AnabaticEngine::invalidateRoutingPads () { // This a flaw in the Hurricane Session update mechanism // and needs to be fixed in the future. for ( Net* net : getCell()->getNets() ) { for ( RoutingPad* rp : net->getRoutingPads() ) { rp->invalidate( false ); } } } void AnabaticEngine::updateDensity () { for ( GCell* gcell : _gcells ) gcell->updateDensity(); } size_t AnabaticEngine::checkGCellDensities () { size_t saturateds = 0; for ( GCell* gcell : _gcells ) saturateds += gcell->checkDensity(); return saturateds; } AutoSegment* AnabaticEngine::_lookup ( Segment* segment ) const { AutoSegmentLut::const_iterator it = _autoSegmentLut.find( segment ); if (it == _autoSegmentLut.end()) return NULL; return (*it).second; } void AnabaticEngine::_link ( AutoSegment* autoSegment ) { if (_state > EngineActive) return; _autoSegmentLut[ autoSegment->base() ] = autoSegment; } void AnabaticEngine::_unlink ( AutoSegment* autoSegment ) { if (_state > EngineDriving) return; AutoSegmentLut::iterator it = _autoSegmentLut.find( autoSegment->base() ); if (it != _autoSegmentLut.end()) _autoSegmentLut.erase( it ); } AutoContact* AnabaticEngine::_lookup ( Contact* contact ) const { AutoContactLut::const_iterator it = _autoContactLut.find( contact ); if (it == _autoContactLut.end()) { return NULL; } return (*it).second; } void AnabaticEngine::_link ( AutoContact* autoContact ) { if (_state > EngineActive) return; _autoContactLut [ autoContact->base() ] = autoContact; } void AnabaticEngine::_unlink ( AutoContact* autoContact ) { if ( _state > EngineActive ) return; AutoContactLut::iterator it = _autoContactLut.find( autoContact->base() ); if (it != _autoContactLut.end()) _autoContactLut.erase( it ); } void AnabaticEngine::_destroyAutoSegments () { cdebug_log(145,0) << "Anabatic::_destroyAutoSegments ()" << endl; size_t expandeds = 0; for ( auto sasp : _autoSegmentLut ) { expandeds++; sasp.second->destroy(); } if (_state == EngineDriving) cmess2 << " - Expandeds := " << expandeds << endl; _autoSegmentLut.clear(); } void AnabaticEngine::_destroyAutoContacts () { cdebug_log(145,0) << "Anabatic::_destroyAutoContacts ()" << endl; for ( auto cacp : _autoContactLut ) cacp.second->destroy(); _autoContactLut.clear(); } EdgeCapacity* AnabaticEngine::_createCapacity ( Flags flags, Interval span ) { size_t depth = getConfiguration()->getAllowedDepth(); EdgeCapacity* edgeCapacity = NULL; flags &= Flags::EdgeCapacityMask; EdgeCapacity key ( this, flags, span, depth ); auto icap = _edgeCapacitiesLut.find( &key ); if (icap != _edgeCapacitiesLut.end()) { edgeCapacity = *icap; } else { edgeCapacity = new EdgeCapacity ( this, flags, span, depth ); _edgeCapacitiesLut.insert( edgeCapacity ); } edgeCapacity->incref(); return edgeCapacity; } size_t AnabaticEngine::_unrefCapacity ( EdgeCapacity* capacity ) { if (capacity->getref() < 2) _edgeCapacitiesLut.erase( capacity ); return capacity->decref(); } void AnabaticEngine::computeEdgeCapacities ( int maxHCap, int maxVCap, int termSatThreshold, int maxTermSat ) { vector rps; vector saturateds; const vector& netDatas = getNetOrdering(); for ( NetData* netData : netDatas ) { for ( Component* component : netData->getNet()->getComponents() ) { RoutingPad* rp = dynamic_cast( component ); if (rp) rps.push_back( rp ); } } UpdateSession::open(); for ( auto rp : rps ) { if (not getConfiguration()->selectRpComponent(rp)) cerr << Warning( "AnabaticEngine::computeEdgeCapacities(): %s has no components on grid.", getString(rp).c_str() ) << endl; Point center = rp->getBoundingBox().getCenter(); GCell* gcell = getGCellUnder( center ); if (not gcell) { cerr << Error( "AnabaticEngine::computeEdgeCapacities(): %s\n" " @%s of %s is not under any GCell.\n" " It will be ignored so the edge capacity estimate may be wrong." , getString(rp).c_str() , getString(center).c_str() , getString(rp->getNet()).c_str() ) << endl; continue; } gcell->incRpCount( 1 ); if (gcell->getRpCount() == termSatThreshold) saturateds.push_back( gcell ); } for ( GCell* gcell : getGCells() ) { if (not gcell->isMatrix()) continue; for ( Edge* edge : gcell->getEdges(Flags::EastSide|Flags::NorthSide) ) { GCell* opposite = edge->getOpposite( gcell ); int maxReserved = maxHCap; int reserved = std::max( gcell->getRpCount(), opposite->getRpCount() ); if (edge->isVertical()) maxReserved = maxVCap; edge->reserveCapacity( std::min( maxReserved, reserved ) ); } } for ( GCell* gcell : saturateds ) { GCell* neighbor = gcell; for ( size_t i=0 ; i<2; ++i ) { Edge* edge = neighbor->getWestEdge(); if (not edge) break; if (edge->getReservedCapacity() < maxTermSat) edge->reserveCapacity( maxTermSat - edge->getReservedCapacity() ); neighbor = neighbor->getWest(); } neighbor = gcell; for ( size_t i=0 ; i<2; ++i ) { Edge* edge = neighbor->getEastEdge(); if (not edge) break; if (edge->getReservedCapacity() < maxTermSat) edge->reserveCapacity( maxTermSat - edge->getReservedCapacity() ); neighbor = neighbor->getEast(); } } UpdateSession::close(); //Breakpoint::stop( 1, "Edge capacities computeds." ); } void AnabaticEngine::_check ( Net* net ) const { cdebug_log(149,1) << "Checking " << net << endl; for ( Segment* segment : net->getComponents().getSubSet() ) { AutoSegment* autoSegment = _lookup( segment ); cdebug_log(149,0) << autoSegment << endl; if (autoSegment) { AutoContact* autoContact = autoSegment->getAutoSource(); cdebug_log(149,0) << autoContact << endl; if (autoContact) autoContact->checkTopology(); autoContact = autoSegment->getAutoTarget(); cdebug_log(149,0) << autoContact << endl; if (autoContact) autoContact->checkTopology(); } } cdebug_tabw(149,-1); } bool AnabaticEngine::_check ( const char* message ) const { bool coherency = true; if (message) cerr << " o checking Anabatic DB (" << message << ")." << endl; for ( auto element : _autoSegmentLut ) coherency = element.second->_check() and coherency; for ( GCell* gcell : _gcells ) { for ( AutoContact* contact : gcell->getContacts() ) contact->checkTopology(); } if (message) cerr << " - completed." << endl; return coherency; } void AnabaticEngine::printMeasures ( const string& tag ) const { Super::printMeasures(); // if (not tag.empty()) { // addMeasure( getCell(), tag+"T", getTimer().getCombTime () ); // addMeasure( getCell(), tag+"S", (getTimer().getMemorySize() >> 20) ); // } } string AnabaticEngine::_getTypeName () const { return getString(_toolName); } string AnabaticEngine::_getString () const { ostringstream os; os << "<" << _toolName << " " << _cell->getName() << ">"; return os.str(); } Record* AnabaticEngine::_getRecord () const { Record* record = Super::_getRecord(); record->add( getSlot("_configuration" , _configuration ) ); record->add( getSlot("_gcells" , &_gcells ) ); record->add( getSlot("_matrix" , &_matrix ) ); record->add( getSlot("_flags" , &_flags ) ); record->add( getSlot("_autoSegmentLut" , &_autoSegmentLut ) ); record->add( getSlot("_autoContactLut" , &_autoContactLut ) ); record->add( getSlot("_edgeCapacitiesLut", &_edgeCapacitiesLut ) ); return record; } } // Anabatic namespace.