coriolis/katana/src/Block.cpp

363 lines
11 KiB
C++

// -*- mode: C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2017-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | K i t e - D e t a i l e d R o u t e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./Block.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/Breakpoint.h"
#include "hurricane/DebugSession.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/Cell.h"
#include "anabatic/Edge.h"
#include "katana/Block.h"
#include "katana/KatanaEngine.h"
namespace Katana {
using std::cerr;
using std::endl;
using std::make_pair;
using std::ostringstream;
using std::setw;
using Hurricane::Error;
using Hurricane::Warning;
using Hurricane::Breakpoint;
using Hurricane::DebugSession;
using Hurricane::SubTypeCollection;
using Hurricane::Transformation;
using Hurricane::RoutingPad;
using Hurricane::Instance;
using Hurricane::Path;
using Anabatic::Edge;
// -------------------------------------------------------------------
// Class : "Katana::Row".
void Row::add ( DbU::Unit x, Occurrence occurrence )
{
auto iocc = _occurrences.find( x );
if (iocc != _occurrences.end()) {
cerr << Error( "Row::add() In row @%s, two elements at the same X position %s:\n"
" %s\n"
" %s"
, DbU::getValueString(_y).c_str()
, DbU::getValueString(x).c_str()
, getString((*iocc).second).c_str()
, getString(occurrence).c_str()
) << endl;
return;
}
_occurrences.insert( make_pair(x,occurrence) );
}
void Row::setY ( DbU::Unit y )
{
for ( auto iocc : _occurrences ) {
Instance* instance = dynamic_cast<Instance*>( iocc.second.getEntity() );
if (not instance) continue;
Transformation itransf = instance->getTransformation();
Transformation dtransf ( itransf.getTx(), itransf.getTy() - _y + y, itransf.getOrientation() );
instance->setTransformation( dtransf );
}
_y = y;
DbU::Unit sliceHeight = Session::getSliceHeight() + Session::getPitch( (size_t)0 );
if (getSouthWest()) {
GCell* gcellRow = getSouthWest();
GCell* gcellChannel = gcellRow->getNorth();
while ( gcellRow ) {
gcellRow->setSouthWestCorner( gcellRow->getXMin(), _y );
gcellRow = gcellRow->getEast();
if (gcellChannel) {
gcellChannel->setSouthWestCorner( gcellChannel->getXMin(), _y+sliceHeight );
gcellChannel = gcellChannel->getEast();
}
}
}
}
GCell* Row::createChannel ( GCell* southWest, DbU::Unit channelHeight )
{
if (not southWest)
throw Error( "Row::createChannel(): NULL southWest GCell." );
if (_occurrences.empty())
throw Error( "Row::createChannel(): No instances in row." );
if (southWest->getXMin() != (*_occurrences.begin()).first)
throw Error( "Row::createChannel(): South-west GCell XMin and Row X min differs." );
if (southWest->getYMin() != _y)
throw Error( "Row::createChannel(): South-west GCell YMIn and Row Y min differs (%s vs. %s)."
, DbU::getValueString(southWest->getYMin()).c_str()
, DbU::getValueString(_y).c_str()
);
DbU::Unit ypitch = Session::getPitch( (size_t)0 );
DbU::Unit sliceHeight = Session::getSliceHeight() + ypitch;
bool northRow = (_y + sliceHeight >= getCell()->getAbutmentBox().getYMax());
_southWest = southWest;
GCell* channel = _southWest->hcut( _southWest->getYMin() + sliceHeight );
GCell* nextSW = NULL;
if (not northRow) {
nextSW = channel->hcut( _southWest->getYMin() + sliceHeight + channelHeight );
if (not nextSW) {
throw Error( "Row::createChannel(): Cannot h-cut %s @%s."
, getString(channel).c_str()
, DbU::getValueString(_southWest->getYMin() + sliceHeight + channelHeight).c_str()
);
}
}
southWest->setType( Anabatic::Flags::StdCellRow );
if (channel) channel->setType( Anabatic::Flags::ChannelRow );
DbU::Unit xmax = getCell()->getAbutmentBox().getXMax() - sliceHeight;
DbU::Unit xcut = _southWest->getXMin() + sliceHeight;
for ( ; xcut < xmax ; xcut += sliceHeight ) {
southWest = southWest->vcut( xcut );
southWest->setType( Anabatic::Flags::StdCellRow );
if (channel) {
channel = channel->vcut( xcut );
channel->setType( Anabatic::Flags::ChannelRow );
channel->getWestEdge()->setFlags( Flags::InfiniteCapacity );
}
}
return nextSW;
}
void Row::routingPadsSubBreak ()
{
if (not _southWest)
throw Error( "Row::routingPadsSubBreak(): NULL southWest GCell." );
set<Net*> nets;
map<DbU::Unit, RoutingPad*> rps;
GCell* southWest = _southWest;
while ( southWest ) {
bool gcellSplitted = false;
for ( RoutingPad* rp : SubTypeCollection<Component*,RoutingPad*>( getCell()->getComponentsUnder(southWest->getBoundingBox() ) ) ) {
if ( (rp->getX() >= southWest->getXMax())
or (rp->getX() < southWest->getXMin()) ) continue;
rps.insert( make_pair(rp->getX(),rp) );
}
for ( auto irp : rps ) {
auto inet = nets.find( irp.second->getNet() );
if (inet == nets.end()) {
nets.insert( irp.second->getNet() );
} else {
southWest = southWest->vcut( irp.second->getX() );
southWest->setType( Anabatic::Flags::StdCellRow );
gcellSplitted = true;
break;
}
}
rps .clear();
nets.clear();
if (not gcellSplitted) {
southWest = southWest->getEast();
}
}
}
uint32_t Row::computeChannelHeight ()
{
_channelHeight = 2;
GCell* gcell = getSouthWest()->getNorth();
while ( gcell ) {
_channelHeight = std::max( _channelHeight, (uint32_t)gcell->getNetCount() );
// Edge* east = gcell->getEastEdge();
// if (east)
// _channelHeight = std::max( _channelHeight, east->getRealOccupancy() );
gcell = gcell->getEast();
}
return _channelHeight;
}
string Row::_getString () const
{ return "<Row @" + DbU::getValueString(_y) + " instances:" + getString(_occurrences.size()) + ">"; }
Record* Row::_getRecord () const
{
Record* record = new Record ( _getString() );
record->add( DbU::getValueSlot( "_y", &_y ) );
record->add( getSlot( "_occurrences", &_occurrences ) );
return record;
}
// -------------------------------------------------------------------
// Class : "Katana::Block".
Block::Block ( KatanaEngine* katana, Cell* cell )
: _katana(katana)
, _cell (cell)
, _rows ()
{
for ( Occurrence occurrence : _cell->getLeafInstanceOccurrences() ) {
add( occurrence );
}
_katana->addBlock( this );
}
Block::~Block ()
{
for ( Row* row : _rows ) delete row;
}
Row* Block::getAt ( DbU::Unit y ) const
{
for ( size_t i=0 ; i<_rows.size() ; ++i ) {
if (_rows[i]->getY() == y) return _rows[i];
}
return NULL;
}
void Block::add ( Occurrence occurrence )
{
Instance* instance = dynamic_cast<Instance*>(occurrence.getEntity());
if (not instance) {
cerr << Warning( "Block::add(): Not an Instance occurrence, %s."
,getString(occurrence).c_str() ) << endl;
return;
}
Transformation transf = occurrence.getPath().getTransformation( instance->getTransformation() );
Box bbInstance = transf.getBox( instance->getMasterCell()->getAbutmentBox() );
Row* row = getAt( bbInstance.getYMin() );
if (not row) {
row = new Row ( this, bbInstance.getYMin() );
auto irow = _rows.begin();
for ( ; irow != _rows.end() ; ++irow ) {
if ((*irow)->getY() >= row->getY()) break;
}
_rows.insert( irow, row );
}
row->add( bbInstance.getXMin(), occurrence );
}
void Block::createChannels ()
{
bool sessionReUse = Session::isOpen();
if (not sessionReUse) _katana->openSession();
DbU::Unit ypitch = Session::getPitch( (size_t)0 );
DbU::Unit sliceHeight = Session::getSliceHeight() + ypitch;
for ( size_t i=0 ; i<_rows.size() ; ++i )
_rows[i]->setY( i*ypitch + i*sliceHeight );
Box ab ( _cell->getAbutmentBox() );
if (not _rows.empty()) {
_cell->setAbutmentBox( ab.inflate( 0, 0, 0, ypitch*(2*_rows.size()-1) ) );
_katana->_resizeMatrix();
}
//GCell* southWest = _katana->getGCellUnder( ab.getXMin(), ab.getYMin() );
GCell* southWest = _katana->getSouthWestGCell();
if (southWest != _katana->getSouthWestGCell())
throw Error( "Block::createChannels(): Only block are supported for now..." );
for ( Row* row : _rows )
southWest = row->createChannel( southWest, ypitch );
_katana->invalidateRoutingPads();
Session::close();
_katana->openSession();
for ( Row* row : _rows ) row->routingPadsSubBreak();
if (not sessionReUse) Session::close();
}
void Block::resizeChannels ()
{
cmess1 << " o Sizing routing channels." << endl;
bool sessionReUse = Session::isOpen();
if (not sessionReUse) _katana->openSession();
DbU::Unit ypitch = Session::getPitch( (size_t)0 );
DbU::Unit sliceHeight = Session::getSliceHeight() + ypitch;
uint32_t channelSum = 0;
for ( Row* row : _rows ) channelSum += row->computeChannelHeight();
Box ab = _cell->getAbutmentBox();
_cell->setAbutmentBox( ab.inflate( 0, 0, 0, ypitch*(channelSum - _rows.size() + 1) ) );
_katana->_resizeMatrix();
channelSum = 0;
for ( size_t irow=0 ; irow < _rows.size() ; ++irow ) {
_rows[irow]->setY( ab.getYMin() + sliceHeight*irow + ypitch*channelSum );
channelSum += _rows[irow]->getChannelHeight();
ostringstream rowName;
rowName << " - [" << setw(2) << irow << "]";
rowName << " @" << DbU::getValueString(_rows[irow]->getY() + sliceHeight);
ostringstream rowTracks;
rowTracks << _rows[irow]->getChannelHeight() << " tracks.";
cmess2 << Dots::asString( rowName.str(), rowTracks.str() ) << endl;
}
_katana->_updateGContacts( Flags::Vertical );
_katana->invalidateRoutingPads();
if (not sessionReUse) Session::close();
}
string Block::_getString () const
{ return "<Block rows:" + getString(_rows.size()) + ">"; }
Record* Block::_getRecord () const
{
Record* record = new Record ( _getString() );
record->add( getSlot( "_katana", _katana ) );
record->add( getSlot( "_rows" , &_rows ) );
return record;
}
} // Katana namespace.