// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2015-2018, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | B o r a - A n a l o g S l i c i n g T r e e | // | | // | Authors : Eric LAO | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./VSlicingNode.cpp" | // +-----------------------------------------------------------------+ #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "crlcore/RoutingGauge.h" #include "bora/HVSetState.h" #include "bora/VSlicingNode.h" #include "bora/RVSlicingNode.h" namespace Bora { using namespace std; using Hurricane::Error; using Hurricane::Warning; // ------------------------------------------------------------------- // Class : "Bora::VSlicingNode". int VSlicingNode::_count = 0; int VSlicingNode::_countAll = 0; VSlicingNode::VSlicingNode ( unsigned int type, unsigned int alignment ) : HVSlicingNode(type,alignment) { ++_count; } VSlicingNode::~VSlicingNode () { --_count; } VSlicingNode* VSlicingNode::create ( unsigned int alignment ) { ++_countAll; return new VSlicingNode( VerticalSNode, alignment ); } void VSlicingNode::createRouting ( DbU::Unit space ) { push_back( RVSlicingNode::create( space ) ); resetSlicingTree(); } void VSlicingNode::print () const { cerr << "- Print from Slicing Node - " << endl; cerr << "SlicingType: Vertical Node" << endl; if (isAlignBottom()) cerr << "Alignment : Bottom" << endl; else if (isAlignCenter()) cerr << "Alignment : Middle" << endl; else if (isAlignTop ()) cerr << "Alignment : Top" << endl; else cerr << "Alignment : Unknown" << endl; cerr << "Tolerances : RatioH: " << DbU::getPhysical(_toleranceRatioH,DbU::Micro) << ", RatioW: " << DbU::getPhysical(_toleranceRatioW,DbU::Micro) << ", BandH: " << DbU::getPhysical(_toleranceBandH,DbU::Micro) << ", BandW: " << DbU::getPhysical(_toleranceBandW,DbU::Micro) << endl; HVSlicingNode::print(); } VSlicingNode* VSlicingNode::clone ( unsigned int tr ) { VSlicingNode* node = VSlicingNode::create( this->getAlignment() ); node->setTolerances( getToleranceRatioH() , getToleranceRatioW() , getToleranceBandH() , getToleranceBandW() ); node->setBoxSet ( getBoxSet() ); node->setNodeSets ( _nodeSets->clone() ); node->setPreset ( getPreset() ); node->setSet ( getSet() ); node->setPlaced ( getPlaced() ); node->setSymmetries( getSymmetries() ); for ( SlicingNode* child : _children ) { if (tr == MX) node->push_front( child->clone(tr) ); else node->push_back ( child->clone(tr) ); } return node; } void VSlicingNode::place ( DbU::Unit x, DbU::Unit y ) { if (recursiveCheckSet()) { if (not _slicingRouting.empty()) { destroySlicingRouting(); resetSlicingRouting(); } _place(x,y); if (_slicingRouting.empty()) createSlicingRouting(); updateCellAbutmentBox(); } else cerr << Error( "VSlicingNode::place(DbU::Unit x, DbU::Unit y): The SlicingTree is not completely set." ) << endl; } void VSlicingNode::replace ( DbU::Unit x, DbU::Unit y ) { // WARNING: This will change GCell edges. if (recursiveCheckSet()) { _place( x, y, true ); updateCellAbutmentBox(); updateGCellPosition(); updateGContacts(); } else { cerr << Error( "HVlicingNode::place(DbU::Unit,DbU::Unit): The SlicingTree is not completely set." ) << endl; } } void VSlicingNode::_place ( DbU::Unit x, DbU::Unit y, bool replace ) { cdebug_log(536,1) << "VSlicingNode::_place(DbU::Unit,DbU::Unit,bool)" << endl; vector::iterator itspace = _slicingRouting.begin(); DbU::Unit xref = x; DbU::Unit yref = y; if (isRoutingEstimated()){ (*itspace)->_place( xref, yref, replace ); xref += (*itspace)->getWidth(); itspace++; } for ( SlicingNode* child : _children ) { if ( child->isHorizontal() or child->isVertical() ) { if (child->isAlignBottom()) { child->setX( xref ); child->setY( yref ); } else if (child->isAlignCenter()) { child->setX( xref ); child->setY( yref + (getHeight() - child->getHeight()) / 2 ); } else if (child->isAlignTop()) { child->setX( xref ); child->setY( yref + getHeight() - child->getHeight() ); } } if (child->isAlignBottom()) child->_place( xref, yref , replace ); else if (child->isAlignCenter()) child->_place( xref, yref + (getHeight() - child->getHeight())/2, replace ); else if (child->isAlignTop ()) child->_place( xref, yref + getHeight() - child->getHeight() , replace ); else if (child->isRouting ()) child->_place( xref, yref , replace ); else { cerr << Error( "VSlicingNode::place(DbU::Unit,DbU::Unit): Unknown Alignment in SlicingTree." ) << endl ; child->print(); } xref += child->getWidth(); yref = y; if (isRoutingEstimated()) { (*itspace)->_place( xref, yref, replace ); xref += (*itspace)->getWidth(); itspace++; } } setPlaced( Placed ); cdebug_tabw(536,-1); } void VSlicingNode::updateGlobalSize () { cdebug_log(535,1) << "VSlicingNode::updateGlobalsize() - " << this << endl; for ( SlicingNode* child : _children ) child->updateGlobalSize(); if (not getMaster()) { if (getNbChild() == 1) { _nodeSets->clear(); NodeSets* node = _children[0]->getNodeSets(); for ( BoxSet* bs : node->getBoxSets() ) { vector bss; bss.push_back( bs ); _nodeSets->push_back( bss, bs->getHeight(), bs->getWidth(), VerticalSNode ); } } else if ( not hasEmptyChildrenNodeSets() and _nodeSets->empty() ) { VSetState state = VSetState( this ); while ( not state.end() ) state.next(); _nodeSets = state.getNodeSets(); } if (_nodeSets->empty()) cerr << Error( "VSlicingNode::updateGlobalSize(): No solution has been found. Try to set larger tolerances.\n" " - Width tolerance ratio: %s\n" " - Height tolerance ratio: %s\n" " - Width band: %s\n" " - Height band: %s" , DbU::getValueString(getToleranceRatioW()).c_str() , DbU::getValueString(getToleranceRatioH()).c_str() , DbU::getValueString(getToleranceBandW ()).c_str() , DbU::getValueString(getToleranceBandH ()).c_str() ) << endl; } else { _nodeSets = _master->getNodeSets(); } cdebug_log(535,0) << "Computed " << _nodeSets->size() << " choices" << endl; cdebug_tabw(535,-1); } void VSlicingNode::preDestroy () { HVSlicingNode::preDestroy(); } void VSlicingNode::destroy () { VSlicingNode::preDestroy(); delete this; } void VSlicingNode::preRecursiveDestroy () { HVSlicingNode::preRecursiveDestroy(); } void VSlicingNode::recursiveDestroy () { VSlicingNode::preRecursiveDestroy(); delete this; } void VSlicingNode::createSlicingRouting () { if (not isPlaced()) { cerr << Warning( "VSlicingNode::createSlicingRouting(): SlicingTree needs to be placed first." ) << endl; return; } size_t childrenCount = getNbChild(); size_t ichild = 0; DbU::Unit x = getX(); DbU::Unit y = getY(); DbU::Unit widthValue = 0; if (_parent) { if ( _parent->getType() == HorizontalSNode) { if ( (getAlignment() == AlignLeft) or (getAlignment() == AlignRight) ) { widthValue = _parent->getWidth() - getWidth(); } else if (getAlignment() == AlignCenter) { widthValue = (_parent->getWidth() - getWidth())/2; } } } DbU::Unit vpitch = _rg->getVerticalPitch(); if (widthValue % vpitch) cerr << Warning( "VSlicingNode::createSlicingRouting(): On %s, width is not pitched (%s, pitch:%s)." , getString(this).c_str() , DbU::getValueString(widthValue).c_str() , DbU::getValueString(vpitch).c_str() ) << endl; for ( size_t inode = 0; inodesetParent( this ); if (inode == 0) { if (getAlignment() == AlignLeft) node->place( x, y ); else if ( (getAlignment() == AlignCenter) or (getAlignment() == AlignRight) ) node->place( x-widthValue, y ); } else node->place( x, y ); _slicingRouting.push_back( node ); if (inode < childrenCount) x += getChild( ichild++ )->getWidth(); } if (_master) { if (isVSymmetry()) { for ( size_t i=0; i<_slicingRouting.size(); ++i ) { getSlicingRouting( i )->setMaster( _master->getSlicingRouting( _slicingRouting.size()-1-i ) ); } } else { for ( size_t i=0; i<_slicingRouting.size(); ++i ) { getSlicingRouting( i )->setMaster( _master->getSlicingRouting( i ) ); } } } else if ( not _symmetries.empty() and isAlignCenter()) { for ( size_t i=0; i<(_slicingRouting.size()/2); ++i ) { getSlicingRouting( _slicingRouting.size()-1-i )->setMaster( getSlicingRouting( i ) ); } } for ( SlicingNode* child : _children ) { if ( child->isHorizontal() or child->isVertical() ) child->createSlicingRouting(); } setRoutingCreated(RoutingCreated); } DbU::Unit VSlicingNode::getWidth () const { DbU::Unit vpitch = _rg->getVerticalPitch(); DbU::Unit width = 0; if (isRoutingEstimated()) { for ( SlicingNode* node : _children ) width += node->getWidth(); for ( RHVSlicingNode* node : _slicingRouting ) width += node->getWidth(); } else { if (_boxSet) width = _boxSet->getWidth(); } if (width % vpitch) cerr << Warning( "VSlicingNode::getWidth(): On %s, width is not pitched (%s, pitch:%s)." , getString(this).c_str() , DbU::getValueString(width).c_str() , DbU::getValueString(vpitch).c_str() ) << endl; return width; } DbU::Unit VSlicingNode::getHeight () const { DbU::Unit hpitch = _rg->getHorizontalPitch(); DbU::Unit height = 0; if (isRoutingEstimated()) { SlicingNode* m = NULL; for ( SlicingNode* node : _children ) { if ( (node->getType() != RoutingSNode) and (node->getHeight() > height) ) { height = node->getHeight(); m = node; } } if (m->isDevice()) height += hpitch*2; } else { if (_boxSet) height = _boxSet->getHeight(); } if (height % hpitch) cerr << Warning( "VSlicingNode::getHeight(): On %s, height is not pitched (%s, pitch:%s)." , getString(this).c_str() , DbU::getValueString(height).c_str() , DbU::getValueString(hpitch).c_str() ) << endl; return height; } void VSlicingNode::setGCell ( Anabatic::GCell* gcell ) { cdebug_log(535,1) << "VSlicingNode::setGCell(Anabatic::GCell*) " << gcell << endl; Anabatic::GCell* childGCell = gcell; Anabatic::GCell* remainGCell = NULL; DbU::Unit x = _slicingRouting[0]->getX(); for ( size_t ichild=0 ; ichild<_children.size() ; ++ichild ) { // Setting up the GCell for the channel *before* the current child. cdebug_log(535,0) << "node[" << ichild << "] width:" << DbU::getValueString(_slicingRouting[ ichild ]->getWidth()) << endl; x += _slicingRouting[ ichild ]->getWidth(); remainGCell = childGCell->vcut( x ); _slicingRouting[ ichild ]->setGCell( childGCell ); childGCell = remainGCell; // Setting up the GCell for the current child. cdebug_log(535,0) << "children[" << ichild << "] width:" << DbU::getValueString(_slicingRouting[ ichild ]->getWidth()) << endl; x += _children[ ichild ]->getWidth(); remainGCell = childGCell->vcut( x ); _children[ ichild ]->setGCell( childGCell ); childGCell = remainGCell; } // Setting up the GCell for the channel *after* the last child. _slicingRouting.back()->setGCell( childGCell ); cdebug_tabw(535,-1); } void VSlicingNode::adjustBorderChannels () { if (_parent) { DbU::Unit space = _parent->getWidth() - getWidth(); if (getAlignment() == AlignRight) { RHVSlicingNode* node = _slicingRouting.front(); node->setWidth( node->getWidth() + space ); } else if (getAlignment() == AlignCenter) { RHVSlicingNode* first = _slicingRouting.front(); RHVSlicingNode* last = _slicingRouting.back (); first->setWidth( first->getWidth() + space/2 ); last ->setWidth( last ->getWidth() + space/2 ); } else if (getAlignment() == AlignLeft) { RHVSlicingNode* node = _slicingRouting.back(); node->setWidth( node->getWidth() + space ); } } for ( SlicingNode* child : _children ) child->adjustBorderChannels(); } string VSlicingNode::_getString () const { string s = Super::_getString(); return s; } string VSlicingNode::_getTypeName () const { return "VSlicingNode"; } } // Bora namespace.