// -*- 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 : "./DSlicingNode.cpp" | // +-----------------------------------------------------------------+ #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "hurricane/analog/Device.h" #include "hurricane/analog/FormFactorParameter.h" #include "hurricane/analog/TransistorFamily.h" #include "hurricane/analog/Transistor.h" #include "hurricane/analog/CommonSourcePair.h" #include "hurricane/analog/DifferentialPair.h" #include "hurricane/analog/LayoutGenerator.h" #include "hurricane/analog/MultiCapacitor.h" #include "anabatic/Session.h" #include "bora/DSlicingNode.h" namespace Bora { using namespace std; using Hurricane::Error; using Hurricane::Warning; using Hurricane::Transformation; using Analog::Device; using Analog::FormFactorParameter; using Analog::MatrixParameter; using Analog::TransistorFamily; using Analog::Transistor; using Analog::CommonSourcePair; using Analog::DifferentialPair; using Analog::MultiCapacitor; using Analog::LayoutGenerator; using Anabatic::Session; // ------------------------------------------------------------------- // Class : "Bora::DSlicingNode". int DSlicingNode::_count = 0; int DSlicingNode::_countAll = 0; DSlicingNode::DSlicingNode ( unsigned int type , NodeSets* nodeSets , unsigned int alignment , Instance* instance , BoxSet* boxSet ) : SlicingNode( type, nodeSets, alignment, boxSet ) , _instance(instance) { ++_count; } DSlicingNode::~DSlicingNode () { --_count; } DSlicingNode* DSlicingNode::create ( NodeSets* nodeSets , unsigned int alignment , Instance* instance , BoxSet* boxSet ) { _countAll++; return new DSlicingNode( DeviceSNode, nodeSets, alignment, instance, boxSet ); } void DSlicingNode::print () const { cerr << "- Print from Slicing Node - " << endl; cerr << "SlicingType: Device Node" << endl; if (isAlignLeft ()) cerr << "Alignment : Left" << endl; else if (isAlignCenter()) cerr << "Alignment : Middle" << endl; else if (isAlignRight ()) cerr << "Alignment : Right" << endl; else if (isAlignTop ()) cerr << "Alignment : Top" << endl; else if (isAlignBottom()) cerr << "Alignment : Bottom" << endl; else cerr << "Alignment : Unknown" << endl; cerr << "BoxSetIndex : " << getBoxSetIndex() << endl; if (_instance) cerr << "Instance : " << _instance << endl; else cerr << "Instance : None" << endl; SlicingNode::print(); } DSlicingNode* DSlicingNode::clone ( unsigned int tr ) { DSlicingNode* node = DSlicingNode::create( _nodeSets->clone() , getAlignment() , getInstance() , getBoxSet() ); node->setPreset( getPreset() ); node->setSet ( getSet() ); node->setPlaced( getPlaced() ); return node; } void DSlicingNode::setBoxSetIndex ( size_t index ) { _boxSet = _nodeSets->find( index ); } size_t DSlicingNode::getBoxSetIndex () const { return (_boxSet) ? _boxSet->getIndex() : 0 ; } void DSlicingNode::_place( DbU::Unit x, DbU::Unit y, bool replace ) { cdebug_log(536,1) << "DSlicingNode::_place(DbU::Unit,DbU::Unit,bool replace)" << endl; if (replace) { SlicingNode::place( x, y ); if (_instance) { Cell* model = _instance->getMasterCell(); _instance->setTransformation ( Transformation( _x - model->getAbutmentBox().getXMin() , _y - model->getAbutmentBox().getYMin() ) ); _instance->setPlacementStatus( Instance::PlacementStatus::PLACED ); } } else { if (isSet()) { SlicingNode::place( x, y ); if (_instance) { Cell* model = _instance->getMasterCell(); Device* device = dynamic_cast( model ); if (device) { unique_ptr layoutGenerator ( new LayoutGenerator() ); TransistorFamily* tf = dynamic_cast( device ); if (tf) { StepParameterRange* stepRange = dynamic_cast( getNodeSets()->getRange() ); if (not stepRange) { throw Error( "DSlicingNode::_place(): Device \"%s\" must be associated with a StepParameterRange argument instead of %s." , getString(device->getName()).c_str() , getString(stepRange).c_str() ); } stepRange->setIndex( getBoxSet()->getIndex() ); int nfingers = stepRange->getValue(); tf->setNfing( nfingers ); layoutGenerator->setDevice ( device ); layoutGenerator->drawLayout(); } else { MultiCapacitor* mcapacitor = dynamic_cast( device ); MatrixParameterRange* matrixRange = dynamic_cast( getNodeSets()->getRange() ); if (mcapacitor) { if (not matrixRange) { throw Error( "DSlicingNode::create(): Device \"%s\" must be associated with a MatrixParameterRange argument instead of %s." , getString(mcapacitor->getName()).c_str() , getString(matrixRange).c_str() ); } matrixRange->setIndex( getBoxSet()->getIndex() ); MatrixParameter* mp = NULL; if ( (mp = dynamic_cast(mcapacitor->getParameter("Matrix"))) != NULL ) mp->setMatrix( &matrixRange->getValue() ); layoutGenerator->setDevice( mcapacitor ); layoutGenerator->drawLayout(); } } } _instance->setTransformation ( Transformation( _x - model->getAbutmentBox().getXMin() , _y - model->getAbutmentBox().getYMin() ) ); _instance->setPlacementStatus( Instance::PlacementStatus::PLACED ); } } } cdebug_tabw(536,-1); } void DSlicingNode::place ( DbU::Unit x, DbU::Unit y ) { DSlicingNode::_place(x, y); } void DSlicingNode::preDestroy () { SlicingNode::preDestroy(); } void DSlicingNode::destroy() { DSlicingNode::preDestroy(); delete this; } void DSlicingNode::preRecursiveDestroy () { SlicingNode::preRecursiveDestroy(); } void DSlicingNode::recursiveDestroy () { DSlicingNode::preRecursiveDestroy(); delete this; } bool DSlicingNode::checkInitialPlacement ( int& cpt ) const { // Notes: Initial placement criteria is having at least 2 devices // placed at (x,y) = (0 0) // // jpc: Very suspicious code, have to check how it is called. bool initialPlacement = false; if (cpt < 2) { if ( (_x == 0) and (_y == 0) ) { cpt++; if (cpt < 2) initialPlacement = true; } else initialPlacement = true; } return initialPlacement; } void DSlicingNode::setGCell ( Anabatic::GCell* gcell ) { cdebug_log(535,0) << "DSlicingNode::setGCell(Anabatic::GCell*) " << gcell << endl; if (getParent()) { if (getParent()->getType() == HorizontalSNode) { if (getAlignment() == AlignLeft) { Anabatic::GCell* strut = gcell->vcut( getX() + getWidth() ); _gcell = gcell; strut->setType( Anabatic::Flags::StrutGCell ); } else if (getAlignment() == AlignCenter) { _gcell = gcell->vcut( getX() ); Anabatic::GCell* strut = _gcell->vcut( getX() + getWidth() ); gcell->setType( Anabatic::Flags::StrutGCell ); strut->setType( Anabatic::Flags::StrutGCell ); } else if (getAlignment() == AlignRight ){ _gcell = gcell->vcut( getX() ); gcell->setType( Anabatic::Flags::StrutGCell ); } } else if (getParent()->getType() == VerticalSNode) { if (getAlignment() == AlignBottom){ Anabatic::GCell* strut = gcell->hcut( getY() + getHeight() ); _gcell = gcell; strut->setType( Anabatic::Flags::StrutGCell ); } else if (getAlignment() == AlignCenter) { _gcell = gcell->hcut( getY() ); Anabatic::GCell* strut = _gcell->hcut( getY() + getHeight() ); gcell->setType( Anabatic::Flags::StrutGCell ); strut->setType( Anabatic::Flags::StrutGCell ); } else if (getAlignment() == AlignTop) { _gcell = gcell->hcut( getY() ); gcell->setType( Anabatic::Flags::StrutGCell ); } } else _gcell = gcell; } else _gcell = gcell; if (_gcell) { if (dynamic_cast(_instance->getMasterCell())) { _gcell->setType( Anabatic::Flags::DeviceGCell ); } else { _gcell->setType( Anabatic::Flags::MatrixGCell ); if( (_gcell->getWidth() > Anabatic::Session::getSliceHeight()) and (_gcell->getHeight() > Anabatic::Session::getSliceHeight()) ) { _gcell->doGrid(); } } } cdebug_log(535,0) << "> Device:" << _instance << endl; cdebug_log(535,0) << "> GCell: " << _gcell << endl; } bool DSlicingNode::isSame ( SlicingNode* node, unsigned int flags ) const { bool isSame = _nodeSets->compare( node->getNodeSets(), flags ); if ( not isSame and (flags & ShowDiff) ) cerr << "DSlicingNode::isSame() Check " << this << " vs. " << node << endl; return isSame; } bool DSlicingNode::isSymmetric ( SlicingNode* node, unsigned int symmetryType, unsigned int flags ) const { bool isSame = _nodeSets->compare( node->getNodeSets(), flags ); if (not isSame and (flags & ShowDiff)) cerr << Warning( "DSlicingNode::isSymmetric(): Different nodesets Check %s vs. %s." , getString(this).c_str(), getString(node).c_str() ) << endl; if (_instance) { Cell* model1 = _instance->getMasterCell(); Cell* model2 = node->getInstance()->getMasterCell(); Device* device1 = dynamic_cast( model1 ); Device* device2 = dynamic_cast( model2 ); if (device1 and device2) { CommonSourcePair* csp1 = dynamic_cast( model1 ); DifferentialPair* dp1 = dynamic_cast( model1 ); Transistor* ts1 = dynamic_cast( model1 ); CommonSourcePair* csp2 = dynamic_cast( model2 ); DifferentialPair* dp2 = dynamic_cast( model2 ); Transistor* ts2 = dynamic_cast( model2 ); if (csp1 and csp2) isSame = csp1->isSame( csp2 ); else if (dp1 and dp2 ) isSame = dp1 ->isSame( dp2 ); else if (ts1 and ts2 ) isSame = ts1 ->isSame( ts2 ); else isSame = false; } if (not isSame) cerr << Warning( "DSlicingNode::isSymmetric(): Different devices. Check %s vs. %s." , getString(this).c_str(), getString(node).c_str() ) << endl; } return isSame; } void DSlicingNode::updateMatrixGCellPosition () { DbU::Unit tx = getX() -_gcell->getXMin(); DbU::Unit ty = getY() -_gcell->getYMin(); Anabatic::GCell* ygcell = _gcell; Anabatic::GCell* xgcell = ygcell; while ( ygcell ) { while ( xgcell ) { xgcell->setSouthWestCorner( xgcell->getXMin() + tx, xgcell->getYMin() + ty ); if (xgcell->getEast()->isMatrix()) xgcell = xgcell->getEast(); else xgcell = NULL; } if (ygcell->getNorth()->isMatrix()) ygcell = ygcell->getNorth(); else ygcell = NULL; xgcell = ygcell; } } void DSlicingNode::updateMatrixGContacts () { Anabatic::GCell* ygcell = _gcell; Anabatic::GCell* xgcell = ygcell; while ( ygcell ) { while ( xgcell ) { xgcell->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); if (xgcell->getEast()->isMatrix()) xgcell = xgcell->getEast(); else xgcell = NULL; } if (ygcell->getNorth()->isMatrix()) ygcell = ygcell->getNorth(); else ygcell = NULL; xgcell = ygcell; } } void DSlicingNode::updateGCellPosition () { cdebug_log(535,0) << "DSlicingNode::updateGCellPosition() " << _gcell << endl; if (_gcell) { if (_parent) { if (_parent->getType() == HorizontalSNode) { DbU::Unit hpitch = _rg->getHorizontalPitch(); if (getAlignment() == AlignLeft) { _gcell->getEastNMatrix()->setSouthWestCorner( getX()+getWidth(), getY() ); _gcell->getEastNMatrix()->forceEdgesCapacities( floor((_parent->getWidth()-getWidth())/hpitch) , floor(getHeight()/hpitch) ); } else if (getAlignment() == AlignCenter) { _gcell->getWest()->setSouthWestCorner( _parent->getX(), getY() ); _gcell->getWest()->forceEdgesCapacities( floor((_parent->getWidth()-getWidth())/(2*hpitch)) , floor(getHeight()/(2*hpitch)) ); _gcell->getEastNMatrix()->setSouthWestCorner( getX()+getWidth(), getY() ); _gcell->getEastNMatrix()->forceEdgesCapacities( floor((_parent->getWidth()-getWidth())/(2*hpitch)) , floor(getHeight()/(2*hpitch)) ); } else if (getAlignment() == AlignRight) { _gcell->getWest()->setSouthWestCorner( _parent->getX(), getY() ); _gcell->getWest()->forceEdgesCapacities( floor((_parent->getWidth()-getWidth())/hpitch) , floor(getHeight()/hpitch) ); } } else if (_parent->getType() == VerticalSNode) { DbU::Unit vpitch = _rg->getVerticalPitch(); if (getAlignment() == AlignBottom) { _gcell->getNorthNMatrix()->setSouthWestCorner( getX(), getY()+getHeight() ); _gcell->getNorthNMatrix()->forceEdgesCapacities( floor((_parent->getHeight()-getHeight())/vpitch) , floor(getWidth()/vpitch) ); } else if (getAlignment() == AlignCenter) { _gcell->getSouth()->setSouthWestCorner( getX(), _parent->getY() ); _gcell->getSouth()->forceEdgesCapacities( floor((_parent->getHeight()-getHeight())/(2*vpitch)) , floor(getWidth()/(2*vpitch)) ); _gcell->getNorthNMatrix()->setSouthWestCorner( getX(), getY()+getHeight() ); _gcell->getNorthNMatrix()->forceEdgesCapacities( floor((_parent->getHeight()-getHeight())/(2*vpitch)) , floor(getWidth()/(2*vpitch)) ); } else if (getAlignment() == AlignTop) { _gcell->getSouth()->setSouthWestCorner( getX(), _parent->getY() ); _gcell->getSouth()->forceEdgesCapacities( floor((_parent->getHeight()-getHeight())/vpitch) , floor(getWidth()/vpitch) ); } } } if (_gcell->isMatrix()) updateMatrixGCellPosition(); else _gcell->setSouthWestCorner( getX(), getY() ); cdebug_log(535,0) << "| Updated:" << _gcell << endl; } } void DSlicingNode::updateGContacts () { cdebug_log(535,0) << "DSlicingNode::updateGContacts() " << _gcell << endl; if (_gcell) { if (_parent) { if (_parent->getType() == HorizontalSNode) { if (getAlignment() == AlignLeft) { _gcell->getEastNMatrix()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); } else if (getAlignment() == AlignCenter) { _gcell->getWest()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); _gcell->getEastNMatrix()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); } else if (getAlignment() == AlignRight) { _gcell->getWest()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); } } else if (_parent->getType() == VerticalSNode) { if (getAlignment() == AlignBottom) { _gcell->getNorthNMatrix()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); } else if (getAlignment() == AlignCenter) { _gcell->getSouth()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); _gcell->getNorthNMatrix()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); } else if (getAlignment() == AlignTop) { _gcell->getSouth()->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); } } } if (_gcell->isMatrix()) updateMatrixGContacts(); else _gcell->updateGContacts( Anabatic::Flags::Vertical|Anabatic::Flags::Horizontal ); cdebug_log(535,0) << "| Updated:" << _gcell << endl; } } void DSlicingNode::restrictDevices () { if (_gcell) { Anabatic::Vertex* vertex = _gcell->getObserver< Anabatic::Vertex>( Anabatic::GCell::Observable::Vertex ); vertex->setRestricted(); if (not vertex->hasValidStamp()) { if ( (_gcell->getWidth() > _gcell->getHeight()) or (_gcell->getWidth() == _gcell->getHeight()) ) { vertex->unsetFlags( Anabatic::Vertex::iVertical ); vertex->setFlags ( Anabatic::Vertex::iHorizontal ); } else { vertex->unsetFlags( Anabatic::Vertex::iHorizontal ); vertex->setFlags ( Anabatic::Vertex::iVertical ); } } } } void DSlicingNode::printLine () const { cerr << "Instance: " << _instance << ", "; SlicingNode::printLine(); } string DSlicingNode::_getString () const { string s = Super::_getString(); s.insert( s.size()-1, " "+getString(_instance->getName())); return s; } string DSlicingNode::_getTypeName () const { return "DSlicingNode"; } bool DSlicingNode::isAnalog () const { if (not _instance) return false; return dynamic_cast(_instance->getMasterCell() ); } bool DSlicingNode::isDigital () const { return not isAnalog(); } bool DSlicingNode::checkCellInstances ( Cell* cell ) { if (not _instance) return false; return cell->getInstance(_instance->getName()); } void DSlicingNode::resetWireOccupation () { } } // Bora namespace.