855 lines
26 KiB
C++
855 lines
26 KiB
C++
// -*- 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 <iostream>
|
|
#include <fstream>
|
|
#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<const Layer*>& layers )
|
|
{
|
|
ltrace(88) << "* Potential Null Length: " << segment << endl;
|
|
ltracein(88);
|
|
|
|
Contact* source = dynamic_cast<Contact*>(segment->getSource());
|
|
Contact* target = dynamic_cast<Contact*>(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<KatabaticEngine*>(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)
|
|
, _autoSegmentLut ()
|
|
, _autoContactLut ()
|
|
, _netRoutingStates ()
|
|
{
|
|
addMeasure<size_t>( cell, "Gates"
|
|
, AllianceFramework::getInstancesCount(cell,AllianceFramework::IgnoreFeeds
|
|
|AllianceFramework::Recursive) );
|
|
}
|
|
|
|
|
|
void KatabaticEngine::_postCreate ()
|
|
{ ToolEngine::_postCreate(); }
|
|
|
|
|
|
void KatabaticEngine::createDetailedGrid ()
|
|
{
|
|
_gcellGrid = GCellGrid::create( this );
|
|
Session::revalidate();
|
|
|
|
addMeasure<size_t>( 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<double>( getCell(), tag+"T", _timer.getCombTime () );
|
|
addMeasure<size_t>( 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 = it->second->_check() and coherency;
|
|
|
|
vector<GCell*>::const_iterator itGCell = _gcellGrid->getGCellVector()->begin();
|
|
vector<GCell*>::const_iterator endGCell = _gcellGrid->getGCellVector()->end();
|
|
for ( ; itGCell != endGCell ; itGCell++ ) {
|
|
vector<AutoContact*>::const_iterator itAutoContact = (*itGCell)->getContacts().begin();
|
|
vector<AutoContact*>::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::findSpecialNets ()
|
|
{
|
|
AllianceFramework* af = AllianceFramework::get();
|
|
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;
|
|
}
|
|
if (af->isBLOCKAGE(net->getName())) excludedType = "BLOCKAGE";
|
|
if (excludedType) {
|
|
NetRoutingState* state = getRoutingState( *net, KbCreate );
|
|
state->setFlags( NetRoutingState::Fixed );
|
|
}
|
|
} // forEach( Net* )
|
|
}
|
|
|
|
|
|
NetRoutingState* KatabaticEngine::getRoutingState ( Net* net, unsigned int flags )
|
|
{
|
|
NetRoutingState* state = NetRoutingExtension::get( net );
|
|
|
|
if (state) {
|
|
NetRoutingStates::iterator istate = _netRoutingStates.find( net->getName() );
|
|
if (istate != _netRoutingStates.end()) {
|
|
if (istate->second != state) {
|
|
cerr << Error( "KatabaticEngine::updateRoutingStates() - %s incoherency between property and LUT:\n"
|
|
" Property:%x vs. LUT:%x, re-init LUT from property."
|
|
, getString(net->getName()).c_str()
|
|
, (void*)state
|
|
, (void*)(istate->second)) << endl;
|
|
_netRoutingStates.insert( make_pair(net->getName(), state) );
|
|
}
|
|
return state;
|
|
}
|
|
} else {
|
|
if (not (flags & KbCreate)) return NULL;
|
|
|
|
state = NetRoutingExtension::create( net );
|
|
}
|
|
|
|
_netRoutingStates.insert( make_pair(net->getName(), state) );
|
|
return state;
|
|
}
|
|
|
|
|
|
void KatabaticEngine::loadGlobalRouting ( unsigned int method )
|
|
{
|
|
if (_state < EngineGlobalLoaded)
|
|
throw Error ("KatabaticEngine::loadGlobalRouting() : global routing not present yet.");
|
|
|
|
if (_state > EngineGlobalLoaded)
|
|
throw Error ("KatabaticEngine::loadGlobalRouting() : global routing already loaded.");
|
|
|
|
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<Segment*> exploredSegments;
|
|
vector<AutoSegment*> unexploreds;
|
|
vector<AutoSegment*> aligneds;
|
|
|
|
forEach ( Component*, icomponent, net->getComponents() ) {
|
|
Segment* segment = dynamic_cast<Segment*>(*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 ; i<unexploreds.size() ; i++ ) {
|
|
AutoSegment* seedSegment = unexploreds[i];
|
|
|
|
if (exploredSegments.find(seedSegment->base()) == 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 ; j<aligneds.size() ; j++ ) {
|
|
ltrace(99) << "Secondary: " << (void*)(aligneds[j]->base()) << " " << aligneds[j] << endl;
|
|
}
|
|
|
|
ltrace(159) << "Align on " << aligneds[0]
|
|
<< " " << DbU::toLambda(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<AutoContact*> contacts;
|
|
forEach ( Component*, icomponent, net->getComponents() ) {
|
|
Contact* contact = dynamic_cast<Contact*>( *icomponent );
|
|
if (contact) {
|
|
AutoContact* autoContact = Session::lookup( contact );
|
|
if (autoContact and autoContact->isInvalidatedCache())
|
|
contacts.push_back( autoContact );
|
|
}
|
|
}
|
|
|
|
for ( size_t i=0 ; i<contacts.size() ; ++i )
|
|
contacts[i]->updateTopology();
|
|
|
|
ltraceout(99);
|
|
DebugSession::close();
|
|
}
|
|
|
|
|
|
void KatabaticEngine::_computeNetTerminals ( Net* net )
|
|
{
|
|
DebugSession::open( net, 88 );
|
|
|
|
ltrace(100) << "Katabatic::_computeNetTerminals( " << net << " )" << endl;
|
|
ltracein(99);
|
|
|
|
vector<AutoSegment*> 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<Segment*> nullSegments;
|
|
set<const Layer*> 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<Contact*>(nullSegments[i]->getSource());
|
|
Contact* target = dynamic_cast<Contact*>(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<Hook*> 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<Segment*>() ) {
|
|
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<AutoSegment*> segments;
|
|
forEach ( Segment*, isegment, net->getComponents().getSubSet<Segment*>() ) {
|
|
AutoSegment* autoSegment = _lookup( *isegment );
|
|
if (autoSegment)
|
|
segments.push_back( autoSegment );
|
|
}
|
|
|
|
sort ( segments.begin(), segments.end(), AutoSegment::CompareId() );
|
|
|
|
Interval constraints;
|
|
for ( size_t i=0 ; i<segments.size() ; i++ ) {
|
|
segments[i]->getConstraints( 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<Net*> 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( "_autoContactLut" , &_autoContactLut ) );
|
|
record->add( getSlot( "_autoSegmentLut" , &_autoSegmentLut ) );
|
|
record->add( getSlot( "_netRoutingStates", &_netRoutingStates) );
|
|
|
|
return record;
|
|
}
|
|
|
|
|
|
} // End of Katabatic namespace.
|