406 lines
13 KiB
C++
406 lines
13 KiB
C++
// -*- C++ -*-
|
|
//
|
|
// This file is part of the Coriolis Software.
|
|
// Copyright (c) UPMC 2014-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@asim.lip6.fr |
|
|
// | =============================================================== |
|
|
// | C++ Module : "./SymmetricRoute.cpp" |
|
|
// +-----------------------------------------------------------------+
|
|
|
|
|
|
#include <map>
|
|
#include <list>
|
|
#include "hurricane/Error.h"
|
|
#include "hurricane/Warning.h"
|
|
#include "hurricane/DebugSession.h"
|
|
#include "hurricane/NetRoutingProperty.h"
|
|
#include "hurricane/RoutingPad.h"
|
|
#include "anabatic/AutoContactTerminal.h"
|
|
#include "katana/RoutingPlane.h"
|
|
#include "katana/TrackFixedSegment.h"
|
|
#include "katana/Track.h"
|
|
#include "katana/KatanaEngine.h"
|
|
|
|
|
|
namespace {
|
|
|
|
using namespace std;
|
|
using Hurricane::Error;
|
|
using Hurricane::DebugSession;
|
|
using Hurricane::DbU;
|
|
using Hurricane::Point;
|
|
using Hurricane::Net;
|
|
using Hurricane::NetRoutingState;
|
|
using Hurricane::NetRoutingExtension;
|
|
using Hurricane::Component;
|
|
using Hurricane::Contact;
|
|
using Hurricane::Segment;
|
|
using Hurricane::Horizontal;
|
|
using Hurricane::Vertical;
|
|
using Hurricane::RoutingPad;
|
|
using Anabatic::Flags;
|
|
using Anabatic::GCell;
|
|
using Anabatic::AutoContact;
|
|
using Anabatic::AutoContactTerminal;
|
|
using Anabatic::AutoSegment;
|
|
using Katana::TrackElement;
|
|
using Katana::DataSymmetric;
|
|
using Katana::KatanaEngine;
|
|
using Katana::Session;
|
|
|
|
|
|
class Message {
|
|
public:
|
|
inline Message ( size_t, string header="" );
|
|
inline size_t size () const;
|
|
inline ostringstream& newline ();
|
|
inline ostringstream& line ();
|
|
inline void setHeader ( string );
|
|
void print ( ostream& );
|
|
private:
|
|
size_t _indent;
|
|
string _header;
|
|
vector<string> _lines;
|
|
ostringstream _current;
|
|
};
|
|
|
|
|
|
inline Message::Message ( size_t indent, string header )
|
|
: _indent (indent)
|
|
, _header (header)
|
|
, _lines ()
|
|
, _current()
|
|
{ }
|
|
|
|
inline size_t Message::size () const { return _lines.size(); }
|
|
inline void Message::setHeader ( string header ) { _header = header; }
|
|
inline ostringstream& Message::line () { return _current; }
|
|
|
|
inline ostringstream& Message::newline ()
|
|
{
|
|
if (_current.str().size())
|
|
_lines.push_back(_current.str());
|
|
_current.str("");
|
|
return _current;
|
|
}
|
|
|
|
void Message::print ( ostream& o )
|
|
{
|
|
if (not _header.empty()) _indent = _header.size()+1;
|
|
|
|
string head ( _indent, ' ' );
|
|
for ( size_t i=0 ; i<_lines.size() ; ++i ) {
|
|
if ((i == 0) and not _header.empty()) o << _header << " ";
|
|
else o << head;
|
|
o << _lines[i] << endl;
|
|
}
|
|
}
|
|
|
|
|
|
class TopologicalPairing {
|
|
public:
|
|
TopologicalPairing ( KatanaEngine*, Net* );
|
|
bool doPairing ();
|
|
void _doSelfPairing ();
|
|
void _doDualPairing ();
|
|
AutoContactTerminal* _getSymmetricTerminal ( AutoContactTerminal* masterContact );
|
|
Component* _findMiddleComponent ();
|
|
void _associate ();
|
|
private:
|
|
KatanaEngine* _katana;
|
|
AutoSegment* _seed;
|
|
DataSymmetric* _data;
|
|
};
|
|
|
|
|
|
TopologicalPairing::TopologicalPairing ( KatanaEngine* katana, Net* net )
|
|
: _katana (katana)
|
|
, _seed (NULL)
|
|
, _data (NULL)
|
|
{
|
|
_data = _katana->getDataSymmetric( net );
|
|
if (not _data)
|
|
_data = _katana->addDataSymmetric( net );
|
|
|
|
if (_data and (_data->getNet() != net) ) _data = NULL;
|
|
}
|
|
|
|
|
|
bool TopologicalPairing::doPairing ()
|
|
{
|
|
if (not _data) return false;
|
|
if (not _data->isValid()) return _data->isValid();
|
|
|
|
DebugSession::open( _data->getNet(), 145, 146 );
|
|
|
|
// Temporary.
|
|
//_data->setSymAxis( _katana->getCell()->getAbutmentBox().getCenter().getX() );
|
|
_data->setSymAxis( NetRoutingExtension::getSymAxis(_data->getNet()) );
|
|
|
|
cmess2 << " - Net: \"" << _data->getNet()->getName() << "\" ";
|
|
cmess2 << "@" << DbU::getValueString(_data->getSymAxis()) << " ";
|
|
cmess2 << (_data->isSymVertical() ? "Vertical" : "Horizontal") << " ";
|
|
if (_data->getSymNet()) cmess2 << "(paired: \"" << _data->getSymNet()->getName() << "\")";
|
|
else cmess2 << "(self symmetric)";
|
|
cmess2 << endl;
|
|
|
|
if (_data->getSymNet()) _doDualPairing();
|
|
else _doSelfPairing();
|
|
|
|
if (_data->isValid()) _data->checkPairing();
|
|
_associate();
|
|
|
|
DebugSession::close();
|
|
|
|
return _data->isValid();
|
|
}
|
|
|
|
|
|
void TopologicalPairing::_doSelfPairing ()
|
|
{
|
|
Component* middle = _findMiddleComponent();
|
|
|
|
AutoSegment* _seed = Session::base()->lookup( dynamic_cast<Segment*>( middle ) );
|
|
if (_seed) {
|
|
for ( AutoSegment* segment : _seed->getConnecteds(Flags::Source) )
|
|
_data->addReference( segment );
|
|
|
|
for ( AutoSegment* segment : _seed->getConnecteds(Flags::Target) )
|
|
_data->addSymmetrical( segment );
|
|
}
|
|
}
|
|
|
|
|
|
void TopologicalPairing::_doDualPairing ()
|
|
{
|
|
for ( Contact* terminal : _data->getNet()->getContacts() ) {
|
|
AutoContactTerminal* autoTerminal = dynamic_cast<AutoContactTerminal*>(Session::lookup( terminal ));
|
|
if (autoTerminal) {
|
|
if (not autoTerminal->isEndPoint()) continue;
|
|
|
|
_seed = autoTerminal->getSegment();
|
|
Flags flags = (_seed->getAutoSource() == autoTerminal) ? Flags::Target : Flags::Source;
|
|
for ( AutoSegment* segment : _seed->getConnecteds(flags) )
|
|
_data->addReference( segment );
|
|
|
|
AutoContactTerminal* symTerminal = _getSymmetricTerminal( autoTerminal );
|
|
if (not symTerminal) { _data->setValid( false ); break; }
|
|
|
|
AutoSegment* symSeed = symTerminal->getSegment();
|
|
if (not symSeed) { _data->setValid( false ); break; }
|
|
|
|
flags = (symSeed->getAutoSource() == symTerminal) ? Flags::Target : Flags::Source;
|
|
for ( AutoSegment* segment : symSeed->getConnecteds(flags) ) {
|
|
_data->addSymmetrical( segment );
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
AutoContactTerminal* TopologicalPairing::_getSymmetricTerminal ( AutoContactTerminal* masterContact )
|
|
{
|
|
Point mirror = _data->getSymmetrical( masterContact->getCenter() );
|
|
GCell* mirrorGCell = _katana->getGCellUnder( mirror );
|
|
if (not mirrorGCell) {
|
|
cerr << Error( "getSymmetricTerminal() No GCell under symmetric position (%s,%s)."
|
|
, DbU::getValueString(mirror.getX()).c_str()
|
|
, DbU::getValueString(mirror.getY()).c_str()
|
|
) << endl;
|
|
_data->setValid( false );
|
|
return NULL;
|
|
}
|
|
|
|
for ( AutoContact* mirrorContact : mirrorGCell->getContacts() ) {
|
|
if (mirrorContact->getNet() == _data->getSymNet()) {
|
|
AutoContactTerminal* symContact = dynamic_cast<AutoContactTerminal*>( mirrorContact );
|
|
if (symContact) return symContact;
|
|
}
|
|
}
|
|
|
|
cerr << Error( "getSymmetricTerminal() Missing terminal contact in symmetric GCell.\n"
|
|
" master:%s\n"
|
|
" mirror:%s"
|
|
, getString(masterContact).c_str(), getString(mirrorGCell).c_str()
|
|
) << endl;
|
|
|
|
_data->setValid( false );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
Component* TopologicalPairing::_findMiddleComponent ()
|
|
{
|
|
DbU::Unit axis = _data->getSymAxis();
|
|
Component* middle = NULL;
|
|
|
|
if (_data->isSymVertical()) {
|
|
for ( Component* component : _data->getNet()->getComponents() ) {
|
|
Horizontal* horizontal = dynamic_cast<Horizontal*>(component);
|
|
if (horizontal) {
|
|
if ( (horizontal->getSourceX() < axis) and (axis < horizontal->getTargetX()) ) {
|
|
if (not middle) middle = horizontal;
|
|
else {
|
|
cerr << Error( "::findMiddleComponent(): Multiple middle Horizontal candidates on \"%s\"\n"
|
|
" %s\n"
|
|
" %s"
|
|
, getString(_data->getNet()->getName()).c_str()
|
|
, getString(middle).c_str()
|
|
, getString(horizontal).c_str()
|
|
) << endl;
|
|
_data->setValid( false );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Vertical* vertical = dynamic_cast<Vertical*>(component);
|
|
if (vertical) {
|
|
if (vertical->getSourceX() == axis) {
|
|
if (not middle) middle = vertical;
|
|
else {
|
|
cerr << Error( "::findMiddleComponent(): Multiple middle Vertical candidates on \"%s\"\n"
|
|
" %s\n"
|
|
" %s"
|
|
, getString(_data->getNet()->getName()).c_str()
|
|
, getString(middle).c_str()
|
|
, getString(vertical).c_str()
|
|
) << endl;
|
|
_data->setValid( false );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RoutingPad* rp = dynamic_cast<RoutingPad*>(component);
|
|
if (rp) {
|
|
if ( (rp->getSourcePosition().getX() < axis) and (axis < rp->getTargetPosition().getX()) ) {
|
|
if (not middle) middle = rp;
|
|
else {
|
|
cerr << Error( "::findMiddleComponent(): Multiple middle Horizontal candidates on \"%s\"\n"
|
|
" %s\n"
|
|
" %s"
|
|
, getString(_data->getNet()->getName()).c_str()
|
|
, getString(middle).c_str()
|
|
, getString(rp).c_str()
|
|
) << endl;
|
|
_data->setValid( false );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for ( Component* component : _data->getNet()->getComponents() ) {
|
|
Vertical* vertical = dynamic_cast<Vertical*>(component);
|
|
if (vertical) {
|
|
if ( (vertical->getSourceY() < axis) and (axis > vertical->getTargetY()) ) {
|
|
if (not middle) middle = vertical;
|
|
else {
|
|
cerr << Error( "::findMiddleComponent(): Multiple middle Vertical candidates on \"%s\"\n"
|
|
" %s\n"
|
|
" %s"
|
|
, getString(_data->getNet()->getName()).c_str()
|
|
, getString(middle).c_str()
|
|
, getString(vertical).c_str()
|
|
) << endl;
|
|
_data->setValid( false );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Horizontal* horizontal = dynamic_cast<Horizontal*>(component);
|
|
if (horizontal) {
|
|
if (horizontal->getSourceY() == axis) {
|
|
if (not middle) middle = horizontal;
|
|
else {
|
|
cerr << Error( "::findMiddleComponent(): Multiple middle Horizontal candidates on \"%s\"\n"
|
|
" %s\n"
|
|
" %s"
|
|
, getString(_data->getNet()->getName()).c_str()
|
|
, getString(middle).c_str()
|
|
, getString(horizontal).c_str()
|
|
) << endl;
|
|
_data->setValid( false );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RoutingPad* rp = dynamic_cast<RoutingPad*>(component);
|
|
if (rp) {
|
|
if ( (rp->getSourcePosition().getY() < axis) and (axis > rp->getTargetPosition().getY()) ) {
|
|
if (not middle) middle = rp;
|
|
else {
|
|
cerr << Error( "::findMiddleComponent(): Multiple middle Horizontal candidates on \"%s\"\n"
|
|
" %s\n"
|
|
" %s"
|
|
, getString(_data->getNet()->getName()).c_str()
|
|
, getString(middle).c_str()
|
|
, getString(rp).c_str()
|
|
) << endl;
|
|
_data->setValid( false );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return middle;
|
|
}
|
|
|
|
|
|
void TopologicalPairing::_associate ()
|
|
{
|
|
cdebug_log(144,1) << "TopologicalPairing::_associate()" << endl;
|
|
|
|
//cmess1 << " - Associating symmetrics." << endl;
|
|
|
|
if (not _data->isValid()) return;
|
|
|
|
const DataSymmetric::Paireds& paireds = _data->getPaireds();
|
|
for ( auto sympair : paireds ) {
|
|
if (not sympair[0]->isCanonical() or not sympair[1]->isCanonical()) continue;
|
|
|
|
TrackElement* trackSegment0 = Session::lookup( sympair[0] );
|
|
TrackElement* trackSegment1 = Session::lookup( sympair[1] );
|
|
|
|
if (not trackSegment0 or not trackSegment1) continue;
|
|
|
|
trackSegment0->setSymmetric( trackSegment1 );
|
|
trackSegment1->setSymmetric( trackSegment0 );
|
|
}
|
|
|
|
cdebug_tabw(144,-1);
|
|
}
|
|
|
|
} // Anonymous namespace.
|
|
|
|
|
|
namespace Katana {
|
|
|
|
using namespace std;
|
|
|
|
|
|
void KatanaEngine::pairSymmetrics ()
|
|
{
|
|
for ( Net* net : getCell()->getNets() ) {
|
|
if (not NetRoutingExtension::isSymmetric(net)) continue;
|
|
TopologicalPairing(this,net).doPairing();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // Katana namespace.
|