// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC/LIP6 2008-2014, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | K a t a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./KatabaticEngine.cpp" | // +-----------------------------------------------------------------+ #include #include #include "hurricane/DebugSession.h" #include "hurricane/Bug.h" #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "hurricane/DataBase.h" #include "hurricane/Technology.h" #include "hurricane/Layer.h" #include "hurricane/BasicLayer.h" #include "hurricane/NetExternalComponents.h" #include "hurricane/Cell.h" #include "crlcore/Utilities.h" #include "crlcore/Catalog.h" #include "crlcore/Measures.h" #include "crlcore/AllianceFramework.h" #include "katabatic/Session.h" #include "katabatic/AutoContact.h" #include "katabatic/AutoSegment.h" #include "katabatic/GCell.h" #include "katabatic/GCellGrid.h" #include "katabatic/KatabaticEngine.h" namespace { using namespace Hurricane; bool isTopAndBottomConnected ( Segment* segment, set& layers ) { ltrace(88) << "* Potential Null Length: " << segment << endl; ltracein(88); Contact* source = dynamic_cast(segment->getSource()); Contact* target = dynamic_cast(segment->getTarget()); layers.clear(); if (source != NULL) { forEach ( Hook*, ihook, source->getBodyHook()->getSlaveHooks() ) { ltrace(88) << "* Slave: " << (*ihook)->getComponent() << endl; if ((*ihook)->getComponent() == segment) continue; layers.insert( (*ihook)->getComponent()->getLayer() ); } } if (target != NULL) { forEach ( Hook*, ihook, target->getBodyHook()->getSlaveHooks() ) { ltrace(88) << "* Slave: " << (*ihook)->getComponent() << endl; if ((*ihook)->getComponent() == segment) continue; layers.insert( (*ihook)->getComponent()->getLayer() ); } } size_t supplemental = (layers.find(segment->getLayer()) == layers.end()) ? 1 : 0; if ( (source->getAnchor() != NULL) or (target->getAnchor() != NULL) ) supplemental++; ltraceout(88); return layers.size()+supplemental > 2; } } // End of anonymous namespace. namespace Katabatic { using namespace std; using Hurricane::tab; using Hurricane::ltracein; using Hurricane::ltraceout; using Hurricane::inltrace; using Hurricane::DebugSession; using Hurricane::ForEachIterator; using Hurricane::Bug; using Hurricane::Error; using Hurricane::Warning; using Hurricane::DataBase; using Hurricane::Technology; using Hurricane::Layer; using Hurricane::BasicLayer; using Hurricane::NetExternalComponents; using CRL::AllianceFramework; using CRL::Catalog; using CRL::CatalogProperty; using CRL::Measures; using CRL::addMeasure; using CRL::getMeasure; // ------------------------------------------------------------------- // Global Variables. const char* missingKTBT = "%s :\n\n" " Cell %s do not have any Katabatic (or not yet created).\n"; const char* badMethod = "%s :\n\n" " No method id %ud (Cell %s).\n"; const char* lookupFailed = "Katabatic::Extension::getDatas(Segment*) :\n\n" " Cannot find AutoSegment associated to %s (internal error).\n"; // ------------------------------------------------------------------- // Class : "Katabatic::KatabaticEngine". Name KatabaticEngine::_toolName = "Katabatic"; KatabaticEngine* KatabaticEngine::get ( const Cell* cell ) { return static_cast(ToolEngine::get(cell,staticGetName())); } const Name& KatabaticEngine::staticGetName () { return _toolName; } const Name& KatabaticEngine::getName () const { return _toolName; } KatabaticEngine::KatabaticEngine ( Cell* cell ) : ToolEngine (cell) , _timer () , _state (EngineCreation) , _flags (EngineDestroyBaseContact) , _configuration (new ConfigurationConcrete()) , _gcellGrid (NULL) , _chipTools (cell) , _routingNets () { addMeasure( cell, "Gates" , AllianceFramework::getInstancesCount(cell,AllianceFramework::IgnoreFeeds |AllianceFramework::Recursive) ); } void KatabaticEngine::_postCreate () { ToolEngine::_postCreate(); } void KatabaticEngine::createDetailedGrid () { _gcellGrid = GCellGrid::create( this ); Session::revalidate(); addMeasure( getCell(), "GCells", _gcellGrid->getGCellVector()->size() ); if (getChipTools().isChip()) { unsigned int columns = _gcellGrid->getColumns(); unsigned int rows = _gcellGrid->getRows(); for ( unsigned int depth=0 ; depth<8 ; ++depth ) { // West. forEach( GCell*, igcell, _gcellGrid->getGCellsColumn(depth,0,rows-1)) { ltrace(89) << "Setting as West Pad:" << (*igcell) << endl; igcell->setUnderIoPad(); } // East. forEach( GCell*, igcell, _gcellGrid->getGCellsColumn(columns-1-depth,0,rows-1)) { ltrace(89) << "Setting as East Pad:" << (*igcell) << endl; igcell->setUnderIoPad(); } // South. forEach( GCell*, igcell, _gcellGrid->getGCellsRow(depth,0,columns-1)) { ltrace(89) << "Setting as South Pad:" << (*igcell) << endl; igcell->setUnderIoPad(); } // North. forEach( GCell*, igcell, _gcellGrid->getGCellsRow(rows-1-depth,0,columns-1)) { ltrace(89) << "Setting as North Pad:" << (*igcell) << endl; igcell->setUnderIoPad(); } } } } KatabaticEngine* KatabaticEngine::create ( Cell* cell ) { ltrace(90) << "KatabaticEngine::create() - " << cell << endl; KatabaticEngine* katabatic = new KatabaticEngine( cell ); katabatic->_postCreate(); return katabatic; } KatabaticEngine::~KatabaticEngine () { delete _configuration; } void KatabaticEngine::_preDestroy () { ltrace(90) << "Katabatic::_preDestroy ()" << endl; ltracein(90); if (getState() < Katabatic::EngineGutted) setState( Katabatic::EnginePreDestroying ); _gutKatabatic(); _state = EngineGutted; ltrace(89) << "About to delete base class ToolEngine." << endl; ToolEngine::_preDestroy(); ltrace(89) << "Exiting Katabatic::_preDestroy()." << endl; ltraceout(90); cmess2 << " - GCells := " << GCell::getAllocateds() << endl; cmess2 << " - AutoContacts := " << AutoContact::getAllocateds() << endl; cmess2 << " - AutoSegments := " << AutoSegment::getAllocateds() << endl; } void KatabaticEngine::_gutKatabatic () { Session::open( this ); unsetFlags( EngineDestroyBaseContact|EngineDestroyBaseSegment ); if (_state == EngineDriving) { ltracein(90); ltrace(90) << "Saving AutoContacts/AutoSegments." << endl; size_t fixedSegments = 0; AutoSegmentLut::const_iterator isegment = _autoSegmentLut.begin(); for ( ; isegment != _autoSegmentLut.end() ; ++isegment ) { if ((*isegment).second->isFixed()) fixedSegments++; } 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; forEach ( Net*, inet, _cell->getNets() ) _saveNet( *inet ); //_autoContactLut.clear (); ltraceout(90); } if (_state < EngineGutted ) { ltrace(90) << "Gutting Katabatic." << endl; _state = EngineGutted; setFlags( EngineDestroyBaseContact ); _destroyAutoSegments(); _destroyAutoContacts(); if (_gcellGrid) { _gcellGrid->destroy(); _gcellGrid = NULL; } } Session::close(); } AutoSegment* KatabaticEngine::_lookup ( Segment* segment ) const { AutoSegmentLut::const_iterator it = _autoSegmentLut.find( segment ); if (it == _autoSegmentLut.end()) return NULL; return (*it).second; } void KatabaticEngine::_link ( AutoSegment* autoSegment ) { if (_state > EngineActive) return; _autoSegmentLut[ autoSegment->base() ] = autoSegment; } void KatabaticEngine::_unlink ( AutoSegment* autoSegment ) { if (_state > EngineDriving) return; AutoSegmentLut::iterator it = _autoSegmentLut.find( autoSegment->base() ); if (it != _autoSegmentLut.end()) _autoSegmentLut.erase( it ); } AutoContact* KatabaticEngine::_lookup ( Contact* contact ) const { AutoContactLut::const_iterator it = _autoContactLut.find( contact ); if (it == _autoContactLut.end()) { return NULL; } return (*it).second; } void KatabaticEngine::_link ( AutoContact* autoContact ) { if (_state > EngineActive) return; _autoContactLut [ autoContact->base() ] = autoContact; } void KatabaticEngine::_unlink ( AutoContact* autoContact ) { if ( _state > EngineActive ) return; AutoContactLut::iterator it = _autoContactLut.find( autoContact->base() ); if (it != _autoContactLut.end()) _autoContactLut.erase( it ); } void KatabaticEngine::xmlWriteGCellGrid ( const string& fileName ) { ofstream file (fileName.c_str()); xmlWriteGCellGrid( file ); file.close (); } void KatabaticEngine::xmlWriteGCellGrid ( ostream& o ) { if (_gcellGrid) _gcellGrid->_xmlWrite( o ); else cerr << Error("Cannot dump GCellGrid: not allocated yet.") << endl; } void KatabaticEngine::startMeasures () { _timer.resetIncrease(); _timer.start(); } void KatabaticEngine::stopMeasures () { _timer.stop(); } void KatabaticEngine::printMeasures ( const string& tag ) const { ostringstream result; result << Timer::getStringTime(_timer.getCombTime()) << ", " << Timer::getStringMemory(_timer.getIncrease()); cmess1 << Dots::asString( " - Done in", result.str() ) << endl; result.str(""); result << _timer.getCombTime() << "s, +" << (_timer.getIncrease()>>10) << "Kb/" << (_timer.getMemorySize()>>10) << "Kb"; cmess2 << Dots::asString( " - Raw measurements", result.str() ) << endl; if (not tag.empty()) { addMeasure( getCell(), tag+"T", _timer.getCombTime () ); addMeasure( getCell(), tag+"S", (_timer.getMemorySize() >> 20) ); } } bool KatabaticEngine::_check ( const char* message ) const { bool coherency = true; if (message) cerr << " o checking Katabatic DB (" << message << ")." << endl; AutoSegmentLut::const_iterator it = _autoSegmentLut.begin(); AutoSegmentLut::const_iterator end = _autoSegmentLut.end (); for ( ; it != end ; it++ ) coherency = coherency && it->second->_check(); vector::const_iterator itGCell = _gcellGrid->getGCellVector()->begin(); vector::const_iterator endGCell = _gcellGrid->getGCellVector()->end(); for ( ; itGCell != endGCell ; itGCell++ ) { vector::const_iterator itAutoContact = (*itGCell)->getContacts().begin(); vector::const_iterator endAutoContact = (*itGCell)->getContacts().end(); for ( ; itAutoContact != endAutoContact ; itAutoContact++ ) { (*itAutoContact)->checkTopology(); } } if (message) cerr << " - completed." << endl; return coherency; } void KatabaticEngine::refresh ( unsigned int flags ) { if (_gcellGrid) _gcellGrid->updateContacts( flags ); } void KatabaticEngine::_destroyAutoSegments () { ltrace(90) << "Katabatic::_destroyAutoSegments ()" << endl; size_t expandeds = 0; AutoSegmentLut::iterator it = _autoSegmentLut.begin(); AutoSegmentLut::iterator end = _autoSegmentLut.end (); for ( ; it != end ; it++ ) { expandeds++; it->second->destroy(); } if (_state == EngineDriving) cerr << " - Expandeds := " << expandeds << endl; _autoSegmentLut.clear(); } void KatabaticEngine::_destroyAutoContacts () { ltrace(90) << "Katabatic::_destroyAutoContacts ()" << endl; AutoContactLut::iterator it = _autoContactLut.begin(); AutoContactLut::iterator end = _autoContactLut.end (); for ( ; it != end ; it++ ) it->second->destroy(); _autoContactLut.clear(); } Configuration* KatabaticEngine::getConfiguration () { return _configuration; } void KatabaticEngine::loadGlobalRouting ( unsigned int method, NetSet& nets ) { if (_state < EngineGlobalLoaded) throw Error ("KatabaticEngine::loadGlobalRouting() : global routing not present yet."); if (_state > EngineGlobalLoaded) throw Error ("KatabaticEngine::loadGlobalRouting() : global routing already loaded."); AllianceFramework* af = AllianceFramework::get(); if (nets.empty()) { forEach ( Net*, net, _cell->getNets() ) { const char* excludedType = NULL; if (net->getType() == Net::Type::POWER ) excludedType = "POWER"; if (net->getType() == Net::Type::GROUND) excludedType = "GROUND"; if (net->getType() == Net::Type::CLOCK ) excludedType = "CLOCK"; if (excludedType) { cparanoid << Warning( "%s is not a routable net (%s,excluded)." , getString(*net).c_str(), excludedType ) << endl; continue; } if (af->isBLOCKAGE(net->getName())) continue; _routingNets.insert ( *net ); } } else { NetSet::iterator it = nets.begin(); for ( ; it != nets.end() ; it++ ) { const char* excludedType = NULL; if ((*it)->getType() == Net::Type::POWER ) excludedType = "POWER"; if ((*it)->getType() == Net::Type::GROUND) excludedType = "GROUND"; if ((*it)->getType() == Net::Type::CLOCK ) excludedType = "CLOCK"; if (af->isBLOCKAGE((*it)->getName())) excludedType = "BLOCKAGE"; if (excludedType) { cparanoid << Warning( "%s is not a routable net (%s), removed from set." , getString(*it).c_str(), excludedType ) << endl; } else _routingNets.insert( *it ); } } switch ( method ) { case EngineLoadGrByNet: _loadGrByNet(); break; case EngineLoadGrByGCell: default: throw Error( badMethod , "Katabatic::loadGlobalRouting()" , method , getString(_cell).c_str() ); } _state = EngineActive; } void KatabaticEngine::finalizeLayout () { ltrace(90) << "Katabatic::finalizeLayout()" << endl; if (_state > EngineDriving) return; _state = EngineDriving; startMeasures(); _gutKatabatic(); stopMeasures (); printMeasures( "fin" ); _state = EngineGutted; } void KatabaticEngine::_alignate ( Net* net ) { DebugSession::open( net, 99 ); ltrace(100) << "Katabatic::_alignate( " << net << " )" << endl; ltracein(99); //cmess2 << " - " << getString(net) << endl; set exploredSegments; vector unexploreds; vector aligneds; forEach ( Component*, icomponent, net->getComponents() ) { Segment* segment = dynamic_cast(*icomponent); 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()) { ltrace(99) << "New chunk from: " << seedSegment << endl; aligneds.push_back( seedSegment ); forEach ( AutoSegment*, collapsed, seedSegment->getAligneds() ) { ltrace(99) << "Aligned: " << *collapsed << endl; aligneds.push_back( *collapsed ); exploredSegments.insert( collapsed->base() ); } ltracein(99); sort( aligneds.begin(), aligneds.end(), AutoSegment::CompareId() ); ltrace(99) << "Seed: " << (void*)aligneds[0]->base() << " " << aligneds[0] << endl; for ( size_t j=1 ; jbase()) << " " << aligneds[j] << endl; } ltrace(159) << "Align on " << aligneds[0] << " " << DbU::getLambda(aligneds[0]->getAxis()) << endl; aligneds[0]->setAxis( aligneds[0]->getAxis(), KbRealignate ); aligneds.clear(); ltraceout(99); } } ltraceout(99); DebugSession::close(); } void KatabaticEngine::updateNetTopology ( Net* net ) { DebugSession::open( net ); ltrace(100) << "Katabatic::updateNetTopology( " << net << " )" << endl; ltracein(99); vector contacts; forEach ( Component*, icomponent, net->getComponents() ) { Contact* contact = dynamic_cast( *icomponent ); if (contact) { AutoContact* autoContact = Session::lookup( contact ); if (autoContact and autoContact->isInvalidatedCache()) contacts.push_back( autoContact ); } } for ( size_t i=0 ; iupdateTopology(); ltraceout(99); DebugSession::close(); } void KatabaticEngine::_computeNetTerminals ( Net* net ) { DebugSession::open( net, 88 ); ltrace(100) << "Katabatic::_computeNetTerminals( " << net << " )" << endl; ltracein(99); vector segments; forEach ( Segment*, segment, net->getSegments() ) { AutoSegment* autoSegment = Session::lookup( *segment ); if (autoSegment == NULL) continue; if (autoSegment->isInvalidated()) autoSegment->computeTerminal(); } ltraceout(99); DebugSession::close(); } void KatabaticEngine::_saveNet ( Net* net ) { DebugSession::open( net, 88 ); ltrace(90) << "Katabatic::_saveNet() " << net << endl; ltracein(90); #if 0 ltrace(90) << "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) { ltrace(90) << "* Not associated to an AutoSegment: " << *segment << endl; continue; } if (not isTopAndBottomConnected(*segment,connectedLayers)) { nullSegments.push_back( *segment ); ltrace(90) << "* 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 ); } ltrace(90) << "Deleting: " << nullSegments[i] << endl; if (isTopAndBottomConnected(nullSegments[i],connectedLayers)) { ltrace(90) << "Deletion cancelled, no longer top or bottom connected." << endl; continue; } ltrace(90) << "* Source: " << (void*)source << " " << source << endl; ltrace(90) << "* Target: " << (void*)target << " " << target << endl; const Layer* layer = DataBase::getDB()->getTechnology() ->getViaBetween( *connectedLayers.begin(), *connectedLayers.rbegin() ); ltrace(90) << *connectedLayers.begin() << " + " << *connectedLayers.rbegin() << endl; ltrace(90) << "* 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() ); ltrace(90) << "* 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 ); } ltrace(90) << (void*)target << " " << target << " setLayer: " << layer << endl; target->setLayer( layer ); } unsetFlags( EngineDestroyBaseSegment ); #endif ltraceout(90); DebugSession::close(); } void KatabaticEngine::_check ( Net* net ) const { ltrace(200) << "Checking " << net << endl; ltracein(200); forEach ( Segment*, isegment, net->getComponents().getSubSet() ) { AutoSegment* autoSegment = _lookup ( *isegment ); ltrace(200) << autoSegment << endl; if ( autoSegment ) { AutoContact* autoContact = autoSegment->getAutoSource(); ltrace(200) << autoContact << endl; if ( autoContact ) autoContact->checkTopology (); autoContact = autoSegment->getAutoTarget(); ltrace(200) << autoContact << endl; if ( autoContact ) autoContact->checkTopology (); } } ltraceout(200); } void KatabaticEngine::_print ( Net* net ) const { cerr << "Order: Components of " << net << endl; vector segments; forEach ( Segment*, isegment, net->getComponents().getSubSet() ) { AutoSegment* autoSegment = _lookup( *isegment ); if (autoSegment) segments.push_back( autoSegment ); } sort ( segments.begin(), segments.end(), AutoSegment::CompareId() ); Interval constraints; for ( size_t i=0 ; igetConstraints( constraints ); cerr << "Order: " << i << " " << segments[i]->isCanonical() << " " << setw(6) << DbU::getValueString(segments[i]->getSourceU()) << " " << setw(6) << DbU::getValueString(segments[i]->getLength()) << " " << segments[i]->isGlobal() << " " << segments[i]->isStrongTerminal() << " " << segments[i]->isHorizontal() << " " << setw(6) << DbU::getValueString(segments[i]->getAxis()) << " " << segments[i]->isFixed() << " [" << DbU::getValueString(constraints.getVMin()) << ":" << DbU::getValueString(constraints.getVMax()) << "] " << segments[i] << endl; } } void KatabaticEngine::_print () const { vector nets; forEach ( Net*, inet, getCell()->getNets() ) { nets.push_back( *inet ); } sort ( nets.begin(), nets.end(), NetCompareByName() ); } string KatabaticEngine::_getTypeName () const { return "Katabatic"; } string KatabaticEngine::_getString () const { ostringstream os; os << "<" << "Katabatic " << _cell->getName () << " " << _configuration->getRoutingGauge()->getName() << ">"; return ( os.str() ); } Record* KatabaticEngine::_getRecord () const { Record* record = ToolEngine::_getRecord (); record->add( getSlot( "_flags" , _flags ) ); record->add( getSlot( "_state" , _state ) ); record->add( getSlot( "_configuration" , _configuration ) ); record->add( getSlot( "_gcellGrid" , _gcellGrid ) ); record->add( getSlot( "_chipTools" , _chipTools ) ); record->add( getSlot( "_routingNets" , &_routingNets ) ); record->add( getSlot( "_autoContactLut" , &_autoContactLut ) ); record->add( getSlot( "_autoSegmentLut" , &_autoSegmentLut ) ); return record; } } // End of Katabatic namespace.