363 lines
11 KiB
C++
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.
|