Non-hierarchical, metal only, rectangle only, extractor is now working.

* New: In Tramontana,
  * Multi-layer support for the swap line. Split VIAs into their
    various metal plates and link the two relevant tiles, ensuring
    connexity between layers.
  * Improved Equipotential information rebuild. Try to rebuild more
    closely the Net characteristics. Improved tab widgets.
This commit is contained in:
Jean-Paul Chaput 2023-03-28 15:13:02 +02:00
parent 2568a1a496
commit 23c0c24c0f
8 changed files with 168 additions and 97 deletions

View File

@ -117,9 +117,11 @@ namespace Tramontana {
, _name (defaultName)
, _type (Net::Type::UNDEFINED)
, _direction (Net::Direction::DirUndefined)
, _netCount (0)
, _isExternal (false)
, _isGlobal (false)
, _isAutomatic(false)
, _hasFused (false)
{ }
@ -194,29 +196,21 @@ namespace Tramontana {
void Equipotential::consolidate ()
{
int containsFused = 0;
set<Net*,NetCompareByName> nets;
for ( Component* component : getComponents() ) {
Net* net = component->getNet();
if (net->isFused ()) containsFused = 1;
if (net->isExternal ()) _isExternal = true;
if (net->isGlobal ()) _isGlobal = true;
if (net->isAutomatic()) _isAutomatic = true;
_type = net->getType();
_direction |= net->getDirection();
if (net->isFused()) _hasFused = true;
else {
if (net->isExternal ()) _isExternal = true;
if (net->isGlobal ()) _isGlobal = true;
if (net->isAutomatic()) _isAutomatic = true;
_type = net->getType();
_direction |= net->getDirection();
}
nets.insert( component->getNet() );
}
_name = getString( (*nets.begin())->getName() );
_name += " [" + getString(nets.size() - containsFused);
if (containsFused)
_name += "+fused";
_name += "] ";
_name += ((_isExternal ) ? "e" : "-");
_name += ((_isGlobal ) ? "g" : "-");
_name += ((_isAutomatic) ? "a" : "-");
_name += " ";
_name += getString(_type ) + " ";
_name += getString(_direction);
_netCount = nets.size();
}
@ -227,6 +221,20 @@ namespace Tramontana {
}
string Equipotential::getFlagsAsString () const
{
string sflags;
sflags += ((_isExternal ) ? "e" : "-");
sflags += ((_isGlobal ) ? "g" : "-");
sflags += ((_isAutomatic) ? "a" : "-");
sflags += " [" + getString( _netCount - ((_hasFused) ? 1 : 0) );
if (_hasFused)
sflags += "+fused";
sflags += "] ";
return sflags;
}
string Equipotential::_getTypeName () const
{ return "Tramontana::Equipotential"; }
@ -234,9 +242,12 @@ namespace Tramontana {
string Equipotential::_getString () const
{
ostringstream os;
os << "<Equipotential id:" << getId()
//<< " " << getName()
<< " " << _owner->getName() << ">";
os << "<Equipotential id:" << getId() << " "
<< getFlagsAsString()
<< " " << getName()
<< " " << getType()
<< " " << getDirection()
<< ">";
return os.str();
}

View File

@ -43,7 +43,6 @@ namespace Tramontana {
static QFont valueFont = Graphics::getFixedFont ( QFont::Normal, true );
if (role == Qt::FontRole) {
if (index.row() == 0) return QVariant();
switch (index.column()) {
case 0: return nameFont;
default: return valueFont;
@ -54,8 +53,13 @@ namespace Tramontana {
if (not index.isValid()) return QVariant ();
if (role == Qt::DisplayRole) {
int row = index.row ();
return QString::fromStdString( _equipotentials[row]->getName() );
Equipotential* equi = _equipotentials[ index.row() ];
switch ( index.column() ) {
case 0: return QString::fromStdString( equi->getName() );
case 1: return QString::fromStdString( equi->getFlagsAsString() );
case 2: return QString::fromStdString( getString( equi->getType() ));
case 3: return QString::fromStdString( getString( equi->getDirection() ));
}
}
return QVariant();
}
@ -71,26 +75,20 @@ namespace Tramontana {
if (role == Qt::FontRole ) return headerFont;
if (role != Qt::DisplayRole) return QVariant();
if (section == 0) return QVariant("Equipotential");
// if (section < _equipotentials->getColumnCount())
// return _equipotentials->getColumnName( section );
if (section == 0) return QVariant( "Name" );
if (section == 1) return QVariant( "Flags" );
if (section == 2) return QVariant( "Type" );
if (section == 3) return QVariant( "Direction" );
return QVariant();
}
int EquipotentialsModel::rowCount ( const QModelIndex& parent ) const
{
return _equipotentials.size();
}
{ return _equipotentials.size(); }
int EquipotentialsModel::columnCount ( const QModelIndex& parent ) const
{
return 1;
//return (_equipotentials) ? _equipotentials->getColumnCount() : 1;
}
{ return 4; }
const Equipotential* EquipotentialsModel::getEqui ( int row )

View File

@ -83,9 +83,9 @@ namespace Tramontana {
SweepLine::SweepLine ( TramontanaEngine* tramontana )
: _tramontana (tramontana)
, _tiles ()
, _intervalTree()
: _tramontana (tramontana)
, _tiles ()
, _intervalTrees()
{ }
@ -95,37 +95,79 @@ namespace Tramontana {
void SweepLine::run ()
{
BasicLayer* layer = DataBase::getDB()->getTechnology()->getBasicLayer( "metal1" );
loadTiles( layer );
//cerr << "SweepLine::run()" << endl;
//DebugSession::open( 0, 2 );
loadTiles();
for ( Element& element : _tiles ) {
Tile* tile = element.getTile();
TileIntv tileIntv ( tile, tile->getYMin(), tile->getYMax() );
cerr << right << setw(10) << DbU::getValueString(element.getX()) << " > " << tile << endl;
//cerr << right << setw(10) << DbU::getValueString(element.getX()) << " > " << tile << endl;
auto intvTree = _intervalTrees.find( element.getMask() );
if (intvTree == _intervalTrees.end()) {
cerr << Error( "SweepLine::run(): Missing interval tree for layer(mask) %s."
" (for tile: %s)"
, getString(element.getMask()).c_str()
, getString(element.getTile()).c_str()
) << endl;
continue;
}
if (element.isLeftEdge()) {
for ( const TileIntv& overlap : _intervalTree.getOverlaps(
for ( const TileIntv& overlap : intvTree->second.getOverlaps(
Interval(tile->getYMin(), tile->getYMax() ))) {
cerr << " | intersect " << overlap.getData() << endl;
//cerr << " | intersect " << overlap.getData() << endl;
tile->merge( overlap.getData() );
}
_intervalTree.insert( tileIntv );
//cerr << " | insert tile" << endl;
intvTree->second.insert( tileIntv );
} else {
_intervalTree.remove( tileIntv );
//cerr << " | remove tile" << endl;
intvTree->second.remove( tileIntv );
// if (tile->getId() == 46055) {
// intvTree->second.write( "we_at_remove.gv" );
// for ( auto tile : intvTree->second.getElements() ) {
// cerr << "| in tree:" << tile << endl;
// }
// }
}
}
//DebugSession::close();
mergeEquipotentials();
}
void SweepLine::loadTiles ( const BasicLayer* layer )
void SweepLine::loadTiles ()
{
cerr << "SweepLine::run()" << endl;
//cerr << "SweepLine::loadTiles()" << endl;
vector<const BasicLayer*> extracteds;
for ( const BasicLayer* bl : DataBase::getDB()->getTechnology()->getBasicLayers() ) {
if (bl->getMaterial() == BasicLayer::Material::metal)
extracteds.push_back( bl );
}
// extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal5" ));
// extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal4" ));
// extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal3" ));
// extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal2" ));
// extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal1" ));
// extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "poly" ));
for ( const BasicLayer* layer : extracteds ) {
_intervalTrees.insert( make_pair( layer->getMask(), TileIntvTree() ));
}
for ( Occurrence occurrence : getCell()->getOccurrencesUnder( getCell()->getBoundingBox() ) ) {
vector<Tile*> tiles;
Component* component = dynamic_cast<Component*>( occurrence.getEntity() );
if (not component) continue;
if (not component->getLayer()->contains(layer)) continue;
Tile* tile = Tile::create( occurrence, layer );
_tiles.push_back( Element( tile, Tile::LeftEdge ) );
_tiles.push_back( Element( tile, Tile::RightEdge ) );
for ( const BasicLayer* layer : extracteds ) {
if (not component->getLayer()->getMask().intersect(layer->getMask())) continue;
tiles.push_back( Tile::create( occurrence, layer ));
_tiles.push_back( Element( tiles.back(), Tile::LeftEdge ) );
_tiles.push_back( Element( tiles.back(), Tile::RightEdge ) );
if (tiles.size() > 1)
tiles.back()->setParent( tiles[0] );
}
tiles.clear();
}
sort( _tiles.begin(), _tiles.end() );
}
@ -133,7 +175,7 @@ namespace Tramontana {
void SweepLine::mergeEquipotentials ()
{
cerr << "Tramontana::mergeEquipotentials()" << endl;
//cerr << "SweepLine::mergeEquipotentials()" << endl;
Tile::timeTick();
for ( Tile* tile : Tile::getAllTiles() ) {
tile->getRoot( Tile::MergeEqui );

View File

@ -108,7 +108,7 @@ namespace Tramontana {
if (not component->getLayer()->contains(layer)) {
cerr << Error( "Tile::create(): Component layer does not contains \"%s\".\n"
" (%s)"
, getString(layer->getName()).c_str()
, getString(layer).c_str()
, getString(occurrence).c_str()
) << endl;
return nullptr;

View File

@ -145,11 +145,14 @@ namespace Tramontana {
void TramontanaEngine::extract ()
{
cerr << "TramontanaEngine::extract() called on " << getCell() << endl;
cmess1 << " o Extracting " << getCell() << endl;
startMeasures();
SweepLine sweepLine ( this );
sweepLine.run();
consolidate();
showEquipotentials();
//showEquipotentials();
stopMeasures();
printMeasures();
}
@ -167,7 +170,7 @@ namespace Tramontana {
void TramontanaEngine::consolidate ()
{
cerr << "Tramontana::consolidate()" << endl;
//cerr << "Tramontana::consolidate()" << endl;
for ( Equipotential* equi : _equipotentials )
equi->consolidate();
}

View File

@ -49,31 +49,34 @@ namespace Tramontana {
public:
typedef Entity Super;
public:
static Equipotential* create ( Cell* );
inline bool isEmpty () const;
virtual Cell* getCell () const;
virtual Box getBoundingBox () const;
inline std::string getName () const;
inline bool hasComponent ( Component* ) const;
void add ( Component* );
void add ( Occurrence );
void merge ( Equipotential* );
void consolidate ();
void clear ();
inline const ComponentSet& getComponents () const;
inline const std::vector<Occurrence>& getChilds () const;
Record* _getRecord () const;
std::string _getString () const;
std::string _getTypeName () const;
protected:
virtual void _postCreate ();
virtual void _preDestroy ();
private:
Equipotential ( Cell* );
~Equipotential ();
private:
Equipotential ( const Equipotential& ) = delete;
Equipotential& operator= ( const Equipotential& ) = delete;
static Equipotential* create ( Cell* );
inline bool isEmpty () const;
virtual Cell* getCell () const;
virtual Box getBoundingBox () const;
inline std::string getName () const;
std::string getFlagsAsString () const;
inline Net::Type getType () const;
inline Net::Direction getDirection () const;
inline bool hasComponent ( Component* ) const;
void add ( Component* );
void add ( Occurrence );
void merge ( Equipotential* );
void consolidate ();
void clear ();
inline const ComponentSet& getComponents () const;
inline const std::vector<Occurrence>& getChilds () const;
Record* _getRecord () const;
std::string _getString () const;
std::string _getTypeName () const;
protected:
virtual void _postCreate ();
virtual void _preDestroy ();
private:
Equipotential ( Cell* );
~Equipotential ();
private:
Equipotential ( const Equipotential& ) = delete;
Equipotential& operator= ( const Equipotential& ) = delete;
private:
Cell* _owner;
Box _boundingBox;
@ -82,9 +85,11 @@ namespace Tramontana {
std::string _name;
Net::Type _type;
Net::Direction _direction;
uint32_t _netCount;
bool _isExternal;
bool _isGlobal;
bool _isAutomatic;
bool _hasFused;
};
@ -92,6 +97,8 @@ namespace Tramontana {
inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); }
inline const ComponentSet& Equipotential::getComponents () const { return _components; }
inline std::string Equipotential::getName () const { return _name; }
inline Net::Type Equipotential::getType () const { return _type; }
inline Net::Direction Equipotential::getDirection () const { return _direction; }
inline const std::vector<Occurrence>& Equipotential::getChilds () const { return _childs; }
inline bool Equipotential::hasComponent ( Component* component ) const

View File

@ -19,6 +19,7 @@
#pragma once
#include <iostream>
#include <vector>
#include <map>
#include "hurricane/BasicLayer.h"
namespace Hurricane {
class Net;
@ -33,22 +34,27 @@ namespace Tramontana {
using Hurricane::Box;
using Hurricane::DbU;
using Hurricane::Cell;
using Hurricane::Layer;
using Hurricane::BasicLayer;
// -------------------------------------------------------------------
// Class : "Tramontana::SweepLine".
class SweepLine {
private:
typedef std::map<Layer::Mask,TileIntvTree> IntervalTrees;
private:
class Element {
public:
inline Element ( Tile*, uint32_t flags );
inline bool operator< ( const Element& ) const;
inline bool isLeftEdge () const;
inline Tile* getTile () const;
inline DbU::Unit getX () const;
inline DbU::Unit getY () const;
inline DbU::Unit getId () const;
inline Element ( Tile*, uint32_t flags );
inline bool operator< ( const Element& ) const;
inline bool isLeftEdge () const;
inline Tile* getTile () const;
inline DbU::Unit getX () const;
inline DbU::Unit getY () const;
inline DbU::Unit getId () const;
inline Layer::Mask getMask () const;
private:
Tile* _tile;
uint32_t _flags;
@ -58,7 +64,7 @@ namespace Tramontana {
~SweepLine ();
inline Cell* getCell ();
void run ();
void loadTiles ( const BasicLayer* );
void loadTiles ();
void mergeEquipotentials ();
Record* _getRecord () const;
std::string _getString () const;
@ -69,22 +75,24 @@ namespace Tramontana {
private:
TramontanaEngine* _tramontana;
std::vector<Element> _tiles;
TileIntvTree _intervalTree;
IntervalTrees _intervalTrees;
};
// SweepLine::Element.
inline SweepLine::Element::Element ( Tile* tile, uint32_t flags ) : _tile(tile), _flags(flags) { }
inline bool SweepLine::Element::isLeftEdge () const { return _flags & Tile::LeftEdge; }
inline Tile* SweepLine::Element::getTile () const { return _tile; }
inline DbU::Unit SweepLine::Element::getX () const { return isLeftEdge() ? _tile->getLeftEdge() : _tile->getRightEdge(); }
inline DbU::Unit SweepLine::Element::getY () const { return _tile->getBoundingBox().getYMin(); }
inline DbU::Unit SweepLine::Element::getId () const { return _tile->getId(); }
inline SweepLine::Element::Element ( Tile* tile, uint32_t flags ) : _tile(tile), _flags(flags) { }
inline bool SweepLine::Element::isLeftEdge () const { return _flags & Tile::LeftEdge; }
inline Tile* SweepLine::Element::getTile () const { return _tile; }
inline DbU::Unit SweepLine::Element::getX () const { return isLeftEdge() ? _tile->getLeftEdge() : _tile->getRightEdge(); }
inline DbU::Unit SweepLine::Element::getY () const { return _tile->getBoundingBox().getYMin(); }
inline DbU::Unit SweepLine::Element::getId () const { return _tile->getId(); }
inline Layer::Mask SweepLine::Element::getMask () const { return _tile->getMask(); }
inline bool SweepLine::Element::operator< ( const Element& rhs ) const
{
if (getX() != rhs.getX()) return (getX() < rhs.getX());
if (getY() != rhs.getY()) return (getY() < rhs.getY());
if (getMask() != rhs.getMask()) return (getMask() < rhs.getMask());
return getId() < rhs.getId();
}

View File

@ -68,7 +68,8 @@ namespace Tramontana {
Tile* getRoot ( uint32_t flags=Compress );
inline Component* getComponent () const;
inline Occurrence getOccurrence () const;
inline const BasicLayer* getLayer () const;
inline Layer::Mask getMask () const;
inline const BasicLayer* getLayer () const;
inline const Box& getBoundingBox () const;
inline Equipotential* getEquipotential () const;
inline DbU::Unit getLeftEdge () const;
@ -110,6 +111,7 @@ namespace Tramontana {
inline unsigned int Tile::getId () const { return getComponent()->getId(); }
inline Component* Tile::getComponent () const { return dynamic_cast<Component*>( _occurrence.getEntity() ); }
inline Occurrence Tile::getOccurrence () const { return _occurrence; }
inline Layer::Mask Tile::getMask () const { return _layer->getMask(); }
inline const BasicLayer* Tile::getLayer () const { return _layer; }
inline const Box& Tile::getBoundingBox () const { return _boundingBox; }
inline Equipotential* Tile::getEquipotential () const { return _equipotential; }