coriolis/bora/src/HSlicingNode.cpp

454 lines
14 KiB
C++
Raw Normal View History

Analog integration part II. Analog place & route (slicing tree). * Change: In Hurricane::CellWidget, set the minimal size to 350 pixels to fit my normal DPI secondary screen... * Change: In Hurricane::Error(), reactivate the backtrace generation by default. Seriously slow down the program each time an Error is to be constructed. * Bug: In Analog::Device::preCreate(), check for NULL Technology before attempting to use it. * Change: In Hurricane/Analog, remove all '*Arguments*' classes and their Python interface. It was an obsoleted way of passing devices parameters to the Python layout generators (located in Oroshi). Now we just get them straight from the Device with the getParamter() method. * Change: In CRL::System CTOR, add Python pathes for Oroshi & Karakaze. * Change: In Oroshi/Python/WIP_*.py layout generator scripts, remove all uses of the "Arguments". Directly access the parameters through the device itself. Make the checkCoherency() with identical arguments as of layout(). * New: Bora tool that performs analog place & route. Based on a slicing tree representation. It is the thesis work of Eric Lao. Code beautyfication and some programming cleanup. * New: Karakaze tool, provide the Python base class AnalogDesign used to build an analog design. Create/configure devices and assemble them in a slicing tree. * Change: In Unicorn/cgt.py, display the stack trace in case of an ImportError exception as well as for other exceptions. Add Bora to the set for included tool engines.
2018-10-18 11:10:01 -05:00
// -*- 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 : "./HVSlicingNode.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "crlcore/RoutingGauge.h"
#include "bora/HVSetState.h"
#include "bora/HSlicingNode.h"
#include "bora/RHSlicingNode.h"
namespace Bora {
using namespace std;
using Hurricane::Error;
using Hurricane::Warning;
// -------------------------------------------------------------------
// Class : "Bora::HSlicingNode".
int HSlicingNode::_count = 0;
int HSlicingNode::_countAll = 0;
HSlicingNode::HSlicingNode ( unsigned int type, unsigned int alignment )
: HVSlicingNode(type,alignment)
{ ++_count; }
HSlicingNode::~HSlicingNode ()
{ --_count; }
HSlicingNode* HSlicingNode::create ( unsigned int alignment )
{
--_countAll;
return new HSlicingNode( HorizontalSNode, alignment );
}
void HSlicingNode::createRouting( DbU::Unit space )
{
push_back( RHSlicingNode::create( space ) );
resetSlicingTree();
}
void HSlicingNode::print () const
{
cerr << "- Print from Slicing Node - " << endl;
cerr << "SlicingType: Horizontal Node" << endl;
if (isAlignLeft ()) cerr << "Alignment : Left" << endl;
else if (isAlignCenter()) cerr << "Alignment : Middle" << endl;
else if (isAlignRight ()) cerr << "Alignment : Right" << 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();
}
HSlicingNode* HSlicingNode::clone ( unsigned int tr )
{
HSlicingNode* node = HSlicingNode::create( 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 == MY) node->push_front( child->clone(tr) );
else node->push_back ( child->clone(tr) );
}
return node;
}
void HSlicingNode::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 << Warning( "HSlicingNode::place(): The SlicingTree is not completely set." ) << endl;
}
void HSlicingNode::replace ( DbU::Unit x, DbU::Unit y )
{
// WARNING: This will change GCell edges.
if (recursiveCheckSet()) {
_place( x, y, true );
updateCellAbutmentBox();
updateGCellPosition ();
updateGContacts ();
} else {
cerr << Warning( "HSlicingNode::replace(): The SlicingTree is not completely set." ) << endl;
}
}
void HSlicingNode::_place ( DbU::Unit x, DbU::Unit y, bool replace )
{
cdebug_log(536,1) << "HSlicingNode::_place(DbU::Unit,DbU::Unit,bool)" << endl;
vector<RHVSlicingNode*>::iterator itspace = _slicingRouting.begin();
DbU::Unit xref = x;
DbU::Unit yref = y;
if (isRoutingEstimated()) {
(*itspace)->_place( xref, yref, replace );
yref += (*itspace)->getHeight();
itspace++;
}
for ( SlicingNode* child : _children ) {
if ( (child->isHorizontal()) or (child->isVertical()) ) {
if (child->isAlignLeft()) {
child->setX( xref );
child->setY( yref );
} else if (child->isAlignCenter()) {
child->setX( xref + (getWidth()/2) - (child->getWidth()/2) );
child->setY( yref );
} else if (child->isAlignRight()) {
child->setX( xref + getWidth() - child->getWidth() );
child->setY( yref );
}
}
if (child->isAlignLeft() ) child->_place( xref , yref, replace);
else if (child->isAlignCenter()) child->_place( xref + (getWidth()/2) - (child->getWidth()/2), yref, replace);
else if (child->isAlignRight() ) child->_place( xref + getWidth() - child->getWidth() , yref, replace);
else if (child->isRouting() ) child->_place( xref , yref, replace);
else {
cerr << Warning( "HSlicingNode::_place(): Unknown Alignment in SlicingTree." ) << endl;
child->print();
}
xref = x;
yref += child->getHeight();
if (isRoutingEstimated()) {
(*itspace)->_place( xref, yref, replace );
yref += (*itspace)->getHeight();
itspace++;
}
}
setPlaced( Placed );
cdebug_tabw(536,-1);
}
void HSlicingNode::updateGlobalSize ()
{
cdebug_log(535,1) << "HSlicingNode::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<BoxSet*> bss;
bss.push_back( bs );
_nodeSets->push_back( bss, bs->getHeight(), bs->getWidth(), HorizontalSNode );
}
} else if ( not hasEmptyChildrenNodeSets() and _nodeSets->empty() ) {
HSetState state = HSetState( this );
while ( not state.end() ) state.next();
_nodeSets = state.getNodeSets();
}
if (_nodeSets->empty())
cerr << Warning( "HSlicingNode::updateGlobalSize(): No solution has been found, try to set larger tolerances." ) << endl;
} else {
_nodeSets = _master->getNodeSets();
}
cdebug_log(535,0) << "Found " << _nodeSets->size() << " choices" << endl;
cdebug_tabw(535,-1);
}
void HSlicingNode::preDestroy ()
{
HVSlicingNode::preDestroy();
}
void HSlicingNode::destroy ()
{
HSlicingNode::preDestroy();
delete this;
}
void HSlicingNode::preRecursiveDestroy ()
{
HVSlicingNode::preRecursiveDestroy();
}
void HSlicingNode::recursiveDestroy ()
{
HSlicingNode::preRecursiveDestroy();
delete this;
}
void HSlicingNode::createSlicingRouting ()
{
if (not _boxSet) {
cerr << Warning( "HSlicingNode::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 heightValue = 0;
if (_parent) {
if (_parent->getType() == VerticalSNode) {
if ( (getAlignment() == AlignBottom) or (getAlignment() == AlignTop) ) {
heightValue = _parent->getHeight() - getHeight();
} else if (getAlignment() == AlignCenter) {
heightValue = (_parent->getHeight() - getHeight()) / 2;
}
}
}
DbU::Unit hpitch = _rg->getHorizontalPitch();
if (heightValue % hpitch)
cerr << Warning( "HSlicingNode::createSlicingRouting(): On %s, height is not pitched (%s, pitch:%s)."
, getString(this).c_str()
, DbU::getValueString(heightValue).c_str()
, DbU::getValueString(hpitch).c_str()
) << endl;
for ( size_t inode=0; inode<childrenCount+1; ++inode ) {
RHSlicingNode* node = NULL;
if (inode == 0) {
if ( (getAlignment() == AlignTop )
or (getAlignment() == AlignCenter) ) node = RHSlicingNode::create( heightValue );
else node = RHSlicingNode::create();
} else if (inode == childrenCount) {
if ( (getAlignment() == AlignBottom)
or (getAlignment() == AlignCenter) ) node = RHSlicingNode::create( heightValue );
else node = RHSlicingNode::create();
} else
node = RHSlicingNode::create();
node->setParent( this );
if (inode == 0) {
if (getAlignment() == AlignBottom) node->place( x, y );
else if ( (getAlignment() == AlignCenter)
or (getAlignment() == AlignTop) ) node->place( x, y-heightValue );
} else
node->place( x, y );
if (_master) node->setMaster( _master->getSlicingRouting(inode) );
_slicingRouting.push_back( node );
if (inode < childrenCount) y += getChild( ichild++ )->getHeight();
}
if (_master) {
if (isHSymmetry()) {
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 HSlicingNode::getHeight () const
{
DbU::Unit hpitch = _rg->getHorizontalPitch();
DbU::Unit height = 0;
if (isRoutingEstimated()){
for ( SlicingNode* child : _children ) height += child->getHeight();
for ( RHVSlicingNode* node : _slicingRouting ) height += node ->getHeight();
} else {
if (_boxSet != NULL) height = _boxSet->getHeight();
}
if (height % hpitch)
cerr << Warning( "HSlicingNode::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;
}
DbU::Unit HSlicingNode::getWidth () const
{
cdebug_log(536,0) << "HSlicingNode::getWidth()" << endl;
DbU::Unit vpitch = _rg->getVerticalPitch();
DbU::Unit width = 0;
if (isRoutingEstimated()) {
SlicingNode* m = NULL;
for ( SlicingNode* node : _children ) {
if ( (node->getType() != RoutingSNode) and (node->getWidth() > width) ) {
width = node->getWidth();
m = node;
}
}
if (m->isDevice()) width += vpitch*2;
} else {
if (_boxSet) width = _boxSet->getWidth();
}
if (width % vpitch)
cerr << Warning( "HSlicingNode::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;
}
void HSlicingNode::setGCell ( Anabatic::GCell* gcell )
{
cdebug_log(535,1) << "HSlicingNode::setGCell(), start Y: "
<< _slicingRouting[0]->getY() << ", GCell:" << gcell << endl;
Anabatic::GCell* childGCell = gcell;
Anabatic::GCell* remainGCell = gcell;
DbU::Unit y = _slicingRouting[0]->getY();
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 << "] height:"
<< DbU::getValueString(_slicingRouting[ ichild ]->getHeight()) << endl;
y += _slicingRouting[ ichild ]->getHeight();
remainGCell = childGCell->hcut( y );
_slicingRouting[ ichild ]->setGCell( childGCell );
childGCell = remainGCell;
// Setting up the GCell for the current child.
cdebug_log(535,0) << "children[" << ichild << "] height:"
<< DbU::getValueString(_children[ ichild ]->getHeight()) << endl;
y += _children[ ichild ]->getHeight();
remainGCell = childGCell->hcut( y );
_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 HSlicingNode::adjustBorderChannels ()
{
if (_parent) {
if (_parent->getHeight() > getHeight()) {
DbU::Unit space = _parent->getHeight() - getHeight();
if (getAlignment() == AlignTop) {
RHVSlicingNode* channel = _slicingRouting.front();
channel->setHeight( channel->getHeight() + space );
} else if (getAlignment() == AlignCenter) {
RHVSlicingNode* firstChannel = _slicingRouting.front();
RHVSlicingNode* lastChannel = _slicingRouting.back ();
firstChannel->setHeight( firstChannel->getHeight() + space/2 );
lastChannel ->setHeight( lastChannel ->getHeight() + space/2 );
} else if (getAlignment() == AlignBottom) {
RHVSlicingNode* channel = _slicingRouting.back();
channel->setHeight( channel->getHeight() + space );
}
}
}
for ( SlicingNode* child : _children ) child->adjustBorderChannels();
}
string HSlicingNode::_getString () const
{
string s = Super::_getString();
return s;
}
string HSlicingNode::_getTypeName () const
{ return "HSlicingNode"; }
} // Bora namespace.