544 lines
20 KiB
C++
544 lines
20 KiB
C++
// -*- 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<Device*>( model );
|
|
|
|
if (device) {
|
|
unique_ptr<LayoutGenerator> layoutGenerator ( new LayoutGenerator() );
|
|
|
|
TransistorFamily* tf = dynamic_cast<TransistorFamily*>( device );
|
|
if (tf) {
|
|
StepParameterRange* stepRange = dynamic_cast<StepParameterRange*>( 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<MultiCapacitor *>( device );
|
|
MatrixParameterRange* matrixRange = dynamic_cast<MatrixParameterRange*>( 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<MatrixParameter*>(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<Device*>(_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<Device*>( model1 );
|
|
Device* device2 = dynamic_cast<Device*>( model2 );
|
|
|
|
if (device1 and device2) {
|
|
CommonSourcePair* csp1 = dynamic_cast<CommonSourcePair*>( model1 );
|
|
DifferentialPair* dp1 = dynamic_cast<DifferentialPair*>( model1 );
|
|
Transistor* ts1 = dynamic_cast<Transistor* >( model1 );
|
|
|
|
CommonSourcePair* csp2 = dynamic_cast<CommonSourcePair*>( model2 );
|
|
DifferentialPair* dp2 = dynamic_cast<DifferentialPair*>( model2 );
|
|
Transistor* ts2 = dynamic_cast<Transistor* >( 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<Device*>(_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.
|