335 lines
8.8 KiB
C++
335 lines
8.8 KiB
C++
#include "Seabreeze/Seabreeze.h"
|
|
#include "hurricane/Net.h"
|
|
#include "hurricane/Segment.h"
|
|
#include "hurricane/DebugSession.h"
|
|
|
|
namespace Seabreeze {
|
|
|
|
using namespace std;
|
|
using Hurricane::DBo;
|
|
using Hurricane::DbU;
|
|
using Hurricane::Net;
|
|
using Hurricane::Cell;
|
|
using Hurricane::Instance;
|
|
using Hurricane::PrivateProperty;
|
|
using Hurricane::Component;
|
|
using Hurricane::Segment;
|
|
using Hurricane::DebugSession;
|
|
|
|
//---------------------------------------------------------
|
|
// Class : "Elmore"
|
|
|
|
Elmore::Elmore ( Net* net )
|
|
: _config (new Configuration())
|
|
, _conts ()
|
|
, checker ()
|
|
, _tree (new Tree())
|
|
{}
|
|
|
|
Elmore::~Elmore ()
|
|
{
|
|
delete _tree;
|
|
}
|
|
|
|
void Elmore::contFromNet ( Net* net ) {
|
|
for ( RoutingPad* rp : net->getRoutingPads() ) {
|
|
for ( Component* comp : rp->getSlaveComponents() ) {
|
|
Contact* ct = dynamic_cast<Contact*>(comp);
|
|
if ( not ct ) continue;
|
|
_conts.insert(ct);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Elmore::buildTree ( RoutingPad* rp )
|
|
{
|
|
if ( rp == nullptr ) {
|
|
cerr << "Input RoutingPad is NULL. Please select a RoutingPad !" << endl;
|
|
cerr << "Cannot build tree" << endl;
|
|
return;
|
|
}
|
|
|
|
Contact* ct = nullptr;
|
|
for ( Component* c : rp->getSlaveComponents() ) {
|
|
Contact* cont = dynamic_cast<Contact*>(c);
|
|
|
|
if ( cont ) {
|
|
ct = cont;
|
|
break;
|
|
}
|
|
}
|
|
if ( ct == nullptr ) {
|
|
cerr << "No contact found" << endl;
|
|
cerr << "Cannot build tree" << endl;
|
|
return;
|
|
}
|
|
|
|
cerr << "Root contact : " << ct->getId() << endl;
|
|
cerr << "Start building tree..." << endl;
|
|
|
|
checker.insert(ct);
|
|
Node* s = new Node(nullptr, ct);
|
|
//---------------------------------------------------------
|
|
double R = 0;
|
|
double C = 0;
|
|
Set_RC(&R, &C, ct, nullptr);
|
|
s->R = R;
|
|
if ( C == 0 )
|
|
s->C = 0;
|
|
else
|
|
s->C = 1/C;
|
|
//---------------------------------------------------------
|
|
Segment* seg = nullptr;
|
|
int c = 0;
|
|
for ( Component* comp : ct->getSlaveComponents() ) {
|
|
seg = dynamic_cast<Segment*>(comp);
|
|
if ( not seg ) continue;
|
|
c++;
|
|
}
|
|
if ( c != 1 ) {
|
|
cerr << "Not begin with a RoutingPad ? Something doesn't seem right : " << c << " linked segments" << endl;
|
|
cerr << "Tree build failed" << endl;
|
|
return;
|
|
}
|
|
build_from_Node(s, seg);
|
|
cerr << endl << "Finished building tree !" << endl << endl;
|
|
_tree->print(cerr);
|
|
}
|
|
|
|
void Elmore::build_from_Node ( Node* s, Segment* seg )
|
|
{
|
|
if ( s->_contact == nullptr ) {
|
|
cerr << "No contact found" << s->_contact << endl;
|
|
return;
|
|
}
|
|
_tree->add_node(s);
|
|
|
|
cdebug_log(199,0) << endl
|
|
<< endl
|
|
<< "Build from contact : " << s->_contact->getId() << endl
|
|
<< "With segment : " << seg->getId() << endl;
|
|
|
|
Contact* ccont = dynamic_cast<Contact*>(seg->getOppositeAnchor(s->_contact));
|
|
if ( not ccont || (s->Np && ccont == (s->Np)->_contact) )
|
|
return;
|
|
|
|
cdebug_log(199,0) << "Target contact : " << ccont->getId() << endl;
|
|
//-----------------------------------------------------------------------
|
|
double Rb = 0;
|
|
double Cb = 0;
|
|
//-----------------------------------------------------------------------
|
|
ccont = build_branch(&Rb, &Cb, ccont);
|
|
|
|
cdebug_log(199, 0) << "Found a node : " << ccont->getId() << endl;
|
|
|
|
if ( not ccont ) {
|
|
cerr << "This branch leads to a NULL contact ?" << endl;
|
|
return;
|
|
}
|
|
|
|
Node* node = new Node(s, ccont);
|
|
//-----------------------------------------------------------------------
|
|
node->R = Rb;
|
|
if ( Cb == 0 )
|
|
node->C = 0;
|
|
else
|
|
node->C = 1/Cb;
|
|
|
|
cdebug_log(199,0) << "R = " << Rb << "; C = " << Cb << endl;
|
|
//-----------------------------------------------------------------------
|
|
int count = 0;
|
|
for ( Component* comp : ccont->getSlaveComponents() ) {
|
|
count += (dynamic_cast<Segment*>(comp)) ? 1 : 0;
|
|
}
|
|
|
|
cdebug_log(199,0) << "This node's contact has : " << count << " segments" << endl;
|
|
|
|
if ( count == 1 ){
|
|
_tree->add_node(node);
|
|
}
|
|
else if ( count > 2 ) {
|
|
for ( Component* comp : ccont->getSlaveComponents() ) {
|
|
Segment* segmt = dynamic_cast<Segment*>(comp);
|
|
if ( not segmt )
|
|
continue;
|
|
|
|
cdebug_log(199,1) << "Segment : " << segmt->getId() << endl;
|
|
cdebug_tabw(199,-1);
|
|
|
|
Contact* target = dynamic_cast<Contact*>(segmt->getOppositeAnchor(ccont));
|
|
if ( not target ) {
|
|
cerr << "Wait... How can this happen ?" << endl;
|
|
continue;
|
|
}
|
|
|
|
cdebug_log(199,0) << "Target is : " << target->getId() << endl;
|
|
cdebug_tabw(199,-1);
|
|
|
|
if ( checker.count(target) == 0 ){
|
|
build_from_Node(node, segmt);
|
|
cdebug_log(199,0) << endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Contact* Elmore::build_branch ( double* R, double* C, Contact* ct )
|
|
{
|
|
Contact* tmp = ct;
|
|
|
|
cdebug_log(199,1) << endl << "Start building branch with contact : " << ct->getId() << endl;
|
|
|
|
int count;
|
|
do {
|
|
checker.insert(tmp);
|
|
count = 0;
|
|
Segment* sm = nullptr;
|
|
for ( Component* cp : tmp->getSlaveComponents() ) {
|
|
sm = dynamic_cast<Segment*>(cp);
|
|
if ( not sm )
|
|
continue;
|
|
|
|
Contact* tar = dynamic_cast<Contact*>(sm->getOppositeAnchor(tmp));
|
|
if ( tar && checker.count(tar) != 0 ) {
|
|
Set_RC(R, C, tmp, sm);
|
|
cdebug_log(199,0) << "RC from build_branch :" << endl;
|
|
cdebug_log(199,0) << "tmp = " << tmp->getId() << "; sm = " << sm->getId() << "; R = " << *R << "; C = " << *C << endl;
|
|
}
|
|
count += 1;
|
|
}
|
|
if ( count == 0 ) {
|
|
cerr << "Something is not right here : Contact " << tmp << " is isolated ?" << endl;
|
|
break;
|
|
}
|
|
else if ( count != 2 ) {
|
|
break;
|
|
}
|
|
else {
|
|
Contact* cct = nullptr;
|
|
for ( Component* cp : tmp->getSlaveComponents() ) {
|
|
sm = dynamic_cast<Segment*>(cp);
|
|
if ( not sm )
|
|
continue;
|
|
|
|
cdebug_log(199,1) << "Sm : " << sm->getId() << endl;
|
|
cdebug_tabw(199,-1);
|
|
|
|
Contact* tar = dynamic_cast<Contact*>(sm->getOppositeAnchor(tmp));
|
|
|
|
cdebug_log(199,0) << "tar : " << tar->getId() << endl << endl;
|
|
|
|
if ( tar && checker.count(tar) == 0 )
|
|
cct = tar;
|
|
}
|
|
|
|
cdebug_tabw(199,-1);
|
|
cdebug_log(199,0) << "cct : " << cct->getId() << endl;
|
|
|
|
if ( not cct || checker.count(cct) != 0 ) {
|
|
cerr << "This branch leads to no where ?" << endl;
|
|
tmp = nullptr;
|
|
break;
|
|
}
|
|
else
|
|
tmp = cct;
|
|
}
|
|
} while ( count == 2 );
|
|
|
|
cdebug_tabw(199,-1);
|
|
cdebug_log(199,0) << "Branch done !" << endl;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
void Elmore::Set_RC ( double* R, double* C, Contact* ct, Segment* sm ) {
|
|
double Rct = getConfig()->getRct();
|
|
//double h_ct = DbU::toPhysical(ct->getHeight(), DbU::UnitPower::Nano);
|
|
double w_ct = DbU::toPhysical(ct->getWidth(), DbU::UnitPower::Nano);
|
|
|
|
double S_ct = w_ct*w_ct;
|
|
(*R) += Rct*S_ct;
|
|
|
|
if ( sm == nullptr ) {
|
|
*C = 0;
|
|
}
|
|
else {
|
|
double Rsm = getConfig()->getRsm();
|
|
double Csm = getConfig()->getCsm();
|
|
double l_sm = DbU::toPhysical(sm->getLength(), DbU::UnitPower::Nano);
|
|
double w_sm = DbU::toPhysical(sm->getWidth(), DbU::UnitPower::Nano);
|
|
double S_sm = l_sm*w_sm;
|
|
//---------------------------------------------------------------------------------------
|
|
cdebug_log(199,0) << "sm = " << sm->getId() << "; l_sm = " << l_sm << "; w_sm = " << w_sm << "; S_sm = " << S_sm << endl;
|
|
//---------------------------------------------------------------------------------------
|
|
(*R) += Rsm*S_sm;
|
|
if ( S_sm == 0 )
|
|
(*C) += 0;
|
|
else
|
|
(*C) += 1/(Csm*S_sm);
|
|
}
|
|
}
|
|
|
|
void Elmore::clearTree ()
|
|
{
|
|
_tree->clear();
|
|
checker.clear();
|
|
}
|
|
|
|
Tree* Elmore::getTree ()
|
|
{
|
|
return _tree;
|
|
}
|
|
|
|
int Elmore::delayElmore ( RoutingPad* rp )
|
|
{
|
|
return _tree->Delay_Elmore(rp);
|
|
}
|
|
|
|
void Elmore::toTREE ( ostream& out ) const
|
|
{
|
|
_tree->print( out );
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Class : "ElmoreProperty"
|
|
|
|
Name ElmoreProperty::_name = "Seabreeze::Elmore";
|
|
|
|
ElmoreProperty* ElmoreProperty::create ( Net* net )
|
|
{
|
|
ElmoreProperty* property = new ElmoreProperty(net);
|
|
//ElmoreProperty* property(net);
|
|
|
|
property->_postCreate();
|
|
return property;
|
|
}
|
|
|
|
Name ElmoreProperty::getName () const
|
|
{
|
|
return _name;
|
|
}
|
|
|
|
string ElmoreProperty::_getTypeName () const
|
|
{
|
|
return "ElmoreProperty";
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Class : "ElmoreExtension"
|
|
|
|
Elmore* ElmoreExtension::create ( Net* net )
|
|
{
|
|
return ElmoreProperty::create(net)->getElmore();
|
|
}
|
|
|
|
void ElmoreExtension::destroyAll ()
|
|
{
|
|
|
|
}
|
|
|
|
void ElmoreExtension::destroy ( Net* net )
|
|
{
|
|
|
|
}
|
|
}
|