Add Rectilinear & "cut" support to the extractor.

Note about the managment of VIA & cuts: Components using a layer which
  is a ViaLayer, that is one containing more than one BasicLayer,
  multiple tiles are created in QueryTiles::goCallback().
    Components that have a single BasicLayer of "cut" material will
  also have their multiples tiles created in QueryTiles::goCallback().
    Rectilinear components will have their multiples tiles created
  in Tile::create(). Tile::create() return not all the tiles but the
  one used as root (for the union find).

* New: In SweepLine::_buildCutConnexMap(), when using a "cut" layer
    in a standalone way, and not as part of a ViaLayer, we do not
    automatically know to which layer above & below they are connected.
      We build a table for each cut layer, based on the ViaLayer,
    to know all tops & belows layers they connect (this is cumulative,
    in the case of "cut" towards the substrate).
      Then in Tile::create(), we not only create the tile for the "cut"
    but also in thoses connected layers (and link them in the union
    find).
* New: In Tile::create(), when we encounter a Rectilinear, break it
    into rectangles and make as many tiles. All tiles linked to the
    same root in the union find.
* Bug: In Hurricane::Rectilinear, ambiguous specification of the set
    of points defining the shape. I did suppose that the start and and
    point where not the same the last edge being between them.
      But if FlexLib, it uses the GDSII inspired convention where the
    first and last point must be the same, to indicate a closed contour.
      This difference was not causing any difference with the drawing,
    but it was a problem for getAsRectangle(). This was creating a
    "false" extra vertical edge leading to a bigger rectangle.
    And this, in turn, was making "false" intersections in the
    tiling/sweepline of the extractor.
      Add a more thorough checking of the points vector.
This commit is contained in:
Jean-Paul Chaput 2023-05-05 16:22:51 +02:00
parent 52fd1c1c40
commit c53fc01cb2
7 changed files with 225 additions and 51 deletions

View File

@ -182,7 +182,7 @@ namespace {
void SweepLine::loadVEdges ()
{
const vector<Point>& points = _rectilinear->getPoints();
for ( size_t i=0 ; i<points.size() ; ++i ) {
for ( size_t i=0 ; i<points.size()-1 ; ++i ) {
const Point& source = points[ i ];
const Point& target = points[ (i+1) % points.size() ];
DbU::Unit dx = target.getX() - source.getX();
@ -337,8 +337,19 @@ namespace Hurricane {
if (not layer)
throw Error( "Rectilinear::create(): Can't create, NULL layer" );
if (points.size() < 4)
throw Error( "Rectilinear::create(): Rectilinear polygons must at least contains 3 vertexes." );
if (points.size() > 1000)
throw Error( "Rectilinear::create(): Rectlinear polygons must not exceed 1000 vertexes." );
throw Error( "Rectilinear::create(): Rectilinear polygons must not exceed 1000 vertexes." );
if (points[0] != points[points.size()-1])
throw Error( "Rectilinear::create(): First and last point must be the same.\n"
"0:%s %d:%s"
, getString(points[0]).c_str()
, points.size()-1
, getString(points[points.size()-1]).c_str()
);
bool isRect = true;
DbU::Unit oneGrid = DbU::fromGrid( 1.0 );

View File

@ -72,18 +72,32 @@ namespace Tramontana {
void QueryTiles::goCallback ( Go* go )
{
vector<Tile*> tiles;
Tile* rootTile = nullptr;
Component* component = dynamic_cast<Component*>( go );
if (not component) return;
if (isProcessed(component)) return;
Occurrence occurrence = Occurrence( go, getPath() );
for ( const BasicLayer* layer : _sweepLine->getExtracteds() ) {
if (not component->getLayer()->getMask().intersect(layer->getMask())) continue;
tiles.push_back( Tile::create( occurrence, layer ));
_sweepLine->add( tiles.back() );
if (tiles.size() > 1)
tiles.back()->setParent( tiles[0] );
Tile* tile = Tile::create( occurrence
, layer
, rootTile
, _sweepLine );
if (not rootTile) rootTile = tile;
}
BasicLayer* cutLayer = component->getLayer()->getBasicLayers().getFirst();
if (cutLayer->getMaterial() == BasicLayer::Material::cut) {
const SweepLine::LayerSet& connexSet = _sweepLine->getCutConnexLayers( cutLayer );
for ( const BasicLayer* connexLayer : connexSet ) {
Tile::create( occurrence
, connexLayer
, rootTile
, _sweepLine
, Tile::ForceLayer );
}
}
_goMatchCount++;
}

View File

@ -28,6 +28,7 @@
#include "hurricane/DataBase.h"
#include "hurricane/Technology.h"
#include "hurricane/Layer.h"
#include "hurricane/ViaLayer.h"
#include "hurricane/Net.h"
#include "hurricane/Pad.h"
#include "hurricane/Plug.h"
@ -71,6 +72,7 @@ namespace Tramontana {
using Hurricane::DataBase;
using Hurricane::Technology;
using Hurricane::Layer;
using Hurricane::ViaLayer;
using Hurricane::Entity;
using Hurricane::Horizontal;
using Hurricane::Vertical;
@ -84,18 +86,24 @@ namespace Tramontana {
SweepLine::SweepLine ( TramontanaEngine* tramontana )
: _tramontana (tramontana)
, _extracteds ()
, _tiles ()
, _intervalTrees()
: _tramontana (tramontana)
, _extracteds ()
, _extractedsMask()
, _connexityMap ()
, _tiles ()
, _intervalTrees ()
{
for ( const BasicLayer* bl : DataBase::getDB()->getTechnology()->getBasicLayers() ) {
// HARDCODED. Should read the gauge.
if (getString(bl->getName()).substr(0,6) == "gmetal") continue;
if ( (bl->getMaterial() == BasicLayer::Material::metal)
or (bl->getMaterial() == BasicLayer::Material::poly))
or (bl->getMaterial() == BasicLayer::Material::poly)
or (bl->getMaterial() == BasicLayer::Material::cut)) {
_extracteds.push_back( bl );
_extractedsMask |= bl->getMask();
}
}
_buildCutConnexMap();
// _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal5" ));
// _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal4" ));
@ -110,16 +118,66 @@ namespace Tramontana {
{ }
void SweepLine::_buildCutConnexMap ()
{
for ( const ViaLayer* viaLayer : DataBase::getDB()->getTechnology()->getViaLayers() ) {
const BasicLayer* cutLayer = nullptr;
for ( const BasicLayer* layer : viaLayer->getBasicLayers() ) {
if (layer->getMaterial() == BasicLayer::Material::cut) {
cutLayer = layer;
break;
}
}
if (not cutLayer) {
cerr << Error( "SweepLine::_buildConnexityMap(): ViaLayer \"%s\" does not contains any *cut* (ignored)."
, getString(viaLayer->getName()).c_str()
) << endl;
continue;
}
auto iCutMap = _connexityMap.find( cutLayer );
if (iCutMap == _connexityMap.end()) {
_connexityMap.insert( make_pair( cutLayer, LayerSet() ));
iCutMap = _connexityMap.find( cutLayer );
}
for ( const BasicLayer* layer : viaLayer->getBasicLayers() ) {
if ( (layer->getMaterial() != BasicLayer::Material::cut)
and (_extractedsMask.intersect(layer->getMask())) ) {
iCutMap->second.insert( layer );
}
}
}
// for ( auto item : _connexityMap ) {
// cerr << "BasicLayers connex to cut: " << item.first << endl;
// for ( const BasicLayer* bl : item.second ) {
// cerr << "| " << bl << endl;
// }
// }
}
const SweepLine::LayerSet& SweepLine::getCutConnexLayers ( const BasicLayer* cutLayer ) const
{
static LayerSet emptySet;
auto iCutMap = _connexityMap.find( cutLayer );
if (iCutMap == _connexityMap.end())
return emptySet;
return iCutMap->second;
}
void SweepLine::run ()
{
//DebugSession::open( 160, 169 );
cdebug_log(160,1) << "SweepLine::run()" << endl;
loadTiles();
//bool debugOn = false;
bool written = false;
//bool written = false;
for ( Element& element : _tiles ) {
Tile* tile = element.getTile();
TileIntv tileIntv ( tile, tile->getYMin(), tile->getYMax() );
// if (tile->getOccurrence().getEntity()->getId() == 3348) {
// DebugSession::open( 160, 169 );
// }
// if (getString(tile->getNet()->getName()) == "a(13)") {
// cerr << tile << endl;
// }
@ -143,9 +201,8 @@ namespace Tramontana {
continue;
}
if (element.isLeftEdge()) {
// if (tile->getId() == 46055) {
// DebugSession::open( 0, 169 );
// if (not written) intvTree->second.write( "tree-before.gv" );
// if (tile->getOccurrence().getEntity()->getId() == 3348) {
// //if (not written) intvTree->second.write( "tree-before.gv" );
// cdebug_log(160,0) << " Interval tree *before* insertion." << endl;
// for ( auto elt : intvTree->second.getElements() ) {
// cdebug_log(160,0) << " | in tree:" << elt << endl;
@ -167,11 +224,10 @@ namespace Tramontana {
// cerr << " | insert " << tile << endl;
// }
intvTree->second.insert( tileIntv );
// if (tile->getId() == 46055) {
// if (not written) intvTree->second.write( "tree-after.gv" );
// written = true;
// DebugSession::close();
// }
if (tile->getOccurrence().getEntity()->getId() == 3348) {
//if (not written) intvTree->second.write( "tree-after.gv" );
//written = true;
}
} else {
// if (tile->getId() == 289) {
// DebugSession::open( 0, 169 );
@ -218,7 +274,10 @@ namespace Tramontana {
// }
}
//intvTree->second.checkVMax();
cdebug_tabw(160,-1);
// cdebug_tabw(160,-1);
// if (tile->getOccurrence().getEntity()->getId() == 3348) {
// DebugSession::close();
// }
}
//if (debugOn) DebugSession::close();
cdebug_tabw(160,-1);

View File

@ -33,10 +33,14 @@
#include "hurricane/Instance.h"
#include "hurricane/Vertical.h"
#include "hurricane/Horizontal.h"
#include "hurricane/Diagonal.h"
#include "hurricane/Rectilinear.h"
#include "hurricane/Polygon.h"
#include "hurricane/RoutingPad.h"
#include "crlcore/Utilities.h"
#include "tramontana/Tile.h"
#include "tramontana/Equipotential.h"
#include "tramontana/SweepLine.h"
namespace Tramontana {
@ -68,7 +72,10 @@ namespace Tramontana {
using Hurricane::Entity;
using Hurricane::Horizontal;
using Hurricane::Vertical;
using Hurricane::RoutingPad;
using Hurricane::Vertical;
using Hurricane::Diagonal;
using Hurricane::Rectilinear;
using Hurricane::Polygon;
using Hurricane::Cell;
using Hurricane::Instance;
@ -82,14 +89,14 @@ namespace Tramontana {
vector<Tile*> Tile::_allocateds;
Tile::Tile ( Occurrence occurrence, const BasicLayer* layer, const Box& boundingBox )
Tile::Tile ( Occurrence occurrence, const BasicLayer* layer, const Box& boundingBox, Tile* parent )
: _id (_idCounter++)
, _occurrence (occurrence)
, _layer (layer)
, _boundingBox (boundingBox)
, _equipotential(nullptr)
, _flags (0)
, _parent (nullptr)
, _parent (parent)
, _rank (0)
, _timeStamp (0)
{
@ -97,7 +104,11 @@ namespace Tramontana {
}
Tile* Tile::create ( Occurrence occurrence, const BasicLayer* layer )
Tile* Tile::create ( Occurrence occurrence
, const BasicLayer* layer
, Tile* rootTile
, SweepLine* sweepLine
, uint32_t flags )
{
Component* component = dynamic_cast<Component*>( occurrence.getEntity() );
if (not component) {
@ -107,22 +118,72 @@ namespace Tramontana {
) << endl;
return nullptr;
}
if (not component->getLayer()->contains(layer)) {
cerr << Error( "Tile::create(): Component layer does not contains \"%s\".\n"
if (not (flags & ForceLayer) and not component->getLayer()->contains(layer)) {
cerr << "Intersect:" << component->getLayer()->getMask().intersect(layer->getMask()) << endl;
cerr << Error( "Tile::create(): Component layer \"%s\" does not contains \"%s\".\n"
" (%s)\n"
" component :%s\n"
" basicLayer:%s"
, getString(component->getLayer()->getName()).c_str()
, getString(layer->getName()).c_str()
, getString(occurrence).c_str()
, getString(component->getLayer()->getMask()).c_str()
, getString(layer->getMask()).c_str()
) << endl;
return nullptr;
}
if (dynamic_cast<Polygon*>(component)) {
cerr << Error( "Tile::create(): Polygon are not supported for extraction.\n"
" (%s)"
, getString(occurrence).c_str()
) << endl;
return nullptr;
}
if (dynamic_cast<Diagonal*>(component)) {
cerr << Error( "Tile::create(): Diagonal are not supported for extraction.\n"
" (%s)"
, getString(layer).c_str()
, getString(occurrence).c_str()
) << endl;
return nullptr;
}
Occurrence childEqui = occurrence;
if (not childEqui.getPath().isEmpty())
childEqui = Equipotential::getChildEqui( occurrence );
Rectilinear* rectilinear = dynamic_cast<Rectilinear*>( component );
if (rectilinear) {
if (not rectilinear->isRectilinear()) {
cerr << Error( "Tile::create(): Rectilinear with 45/135 edges are not supported for extraction.\n"
" (%s)"
, getString(occurrence).c_str()
) << endl;
return nullptr;
}
if (rectilinear->getId() == 3367) {
DebugSession::open( 160, 169 );
cdebug_log(160,0) << "Tiling: " << rectilinear << endl;
}
vector<Box> boxes;
rectilinear->getAsRectangles( boxes );
for ( Box bb : boxes ) {
occurrence.getPath().getTransformation().applyOn( bb );
Tile* tile = new Tile ( childEqui, layer, bb, rootTile );
sweepLine->add( tile );
cdebug_log(160,0) << "| " << tile << endl;
if (not rootTile) rootTile = tile;
}
if (rectilinear->getId() == 3367) {
DebugSession::close();
}
return rootTile;
}
Box bb = component->getBoundingBox( layer );
occurrence.getPath().getTransformation().applyOn( bb );
if (not occurrence.getPath().isEmpty())
occurrence = Equipotential::getChildEqui( occurrence );
Tile* tile = new Tile ( occurrence, layer, bb );
Tile* tile = new Tile ( childEqui, layer, bb, rootTile );
sweepLine->add( tile );
return tile;
}
@ -238,7 +299,8 @@ namespace Tramontana {
string Tile::_getString () const
{
ostringstream os;
os << "<Tile " << _boundingBox << " " << _layer->getName() << " " << _occurrence << ">";
os << "<Tile tid:" << _id
<< " " << _boundingBox << " " << _layer->getName() << " " << _occurrence << ">";
return os.str();
}

View File

@ -19,6 +19,7 @@
#pragma once
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include "hurricane/BasicLayer.h"
namespace Hurricane {
@ -33,6 +34,7 @@ namespace Tramontana {
using Hurricane::Record;
using Hurricane::Box;
using Hurricane::DbU;
using Hurricane::DBo;
using Hurricane::Cell;
using Hurricane::Layer;
using Hurricane::BasicLayer;
@ -43,7 +45,10 @@ namespace Tramontana {
class SweepLine {
private:
typedef std::map<Layer::Mask,TileIntvTree> IntervalTrees;
typedef std::map<Layer::Mask, TileIntvTree> IntervalTrees;
public:
typedef std::set<const BasicLayer*, DBo::CompareById> LayerSet;
typedef std::map<const BasicLayer*, LayerSet, DBo::CompareById> ConnexityMap;
private:
class Element {
public:
@ -66,6 +71,8 @@ namespace Tramontana {
inline Cell* getCell ();
inline const std::vector<const BasicLayer*>&
getExtracteds () const;
inline Layer::Mask getExtractedMask () const;
const LayerSet& getCutConnexLayers ( const BasicLayer* ) const;
void run ();
void loadTiles ();
inline void add ( Tile* );
@ -76,9 +83,12 @@ namespace Tramontana {
private:
SweepLine ( const SweepLine& ) = delete;
SweepLine& operator= ( const SweepLine& ) = delete;
void _buildCutConnexMap ();
private:
TramontanaEngine* _tramontana;
std::vector<const BasicLayer*> _extracteds;
Layer::Mask _extractedsMask;
ConnexityMap _connexityMap;
std::vector<Element> _tiles;
IntervalTrees _intervalTrees;
};
@ -109,7 +119,8 @@ namespace Tramontana {
// SweepLine.
inline Cell* SweepLine::getCell () { return _tramontana->getCell(); }
inline const std::vector<const BasicLayer*>& SweepLine::getExtracteds () const { return _extracteds; }
inline const std::vector<const BasicLayer*>& SweepLine::getExtracteds () const { return _extracteds; }
inline Layer::Mask SweepLine::getExtractedMask () const { return _extractedsMask; }
inline void SweepLine::add ( Tile* tile )
{

View File

@ -44,6 +44,7 @@ namespace Tramontana {
using Hurricane::IntervalData;
using Hurricane::IntervalTree;
class Equipotential;
class SweepLine;
// -------------------------------------------------------------------
@ -51,15 +52,20 @@ namespace Tramontana {
class Tile {
public:
static const uint32_t NoFlags = 0;
static const uint32_t LeftEdge = (1<<0);
static const uint32_t RightEdge = (1<<1);
static const uint32_t Compress = (1<<2);
static const uint32_t MergeEqui = (1<<3);
static const uint32_t NoFlags = 0;
static const uint32_t LeftEdge = (1<<0);
static const uint32_t RightEdge = (1<<1);
static const uint32_t Compress = (1<<2);
static const uint32_t MergeEqui = (1<<3);
static const uint32_t ForceLayer = (1<<4);
public:
static inline const std::vector<Tile*> getAllTiles ();
static inline void timeTick ();
static Tile* create ( Occurrence, const BasicLayer* );
static Tile* create ( Occurrence
, const BasicLayer*
, Tile* rootTile
, SweepLine*
, uint32_t flags=NoFlags );
void destroy ();
inline bool isUpToDate () const;
inline unsigned int getId () const;
@ -88,7 +94,7 @@ namespace Tramontana {
std::string _getString () const;
std::string _getTypeName () const;
private:
Tile ( Occurrence, const BasicLayer*, const Box& );
Tile ( Occurrence, const BasicLayer*, const Box&, Tile* parent );
~Tile ();
private:
Tile ( const Tile& ) = delete;

View File

@ -48,7 +48,8 @@ def testRectilinear ( editor ):
, Point( l( 20.0), l( 30.0) )
, Point( l( 30.0), l( 30.0) )
, Point( l( 30.0), l( 20.0) )
, Point( l( 10.0), l( 0.0) ) ]
, Point( l( 10.0), l( 0.0) )
, Point( l( 0.0), l( 0.0) ) ]
r = Rectilinear.create( net, metal2, points )
#print( 'Normalized and manhattanized contour:' )
@ -72,7 +73,9 @@ def testRectilinear ( editor ):
# , Point( l( 90.0), l( 0.0) ) # 12
# , Point( l( 20.0), l( 0.0) ) # 13
# , Point( l( 20.0), l( 20.0) ) # 14
# , Point( l( 0.0), l( 20.0) ) ] # 15
# , Point( l( 0.0), l( 20.0) ) # 15
# , Point( l( 0.0), l( 40.0) ) ] # 16
# Super-test rectilinear.
points = [ Point( l( 0.0), l( 0.0) ) # 0
, Point( l( 0.0), l( 20.0) ) # 1
, Point( l( 10.0), l( 20.0) ) # 2
@ -83,7 +86,7 @@ def testRectilinear ( editor ):
, Point( l( 40.0), l( 80.0) ) # 7
, Point( l( 20.0), l( 80.0) ) # 8
, Point( l( 20.0), l( 70.0) ) # 9
, Point( l( 10.0), l( 70.0) ) # 10
, Point( l( 10.0), l( 60.0) ) # 11
, Point( l( 0.0), l( 60.0) ) # 12
@ -94,7 +97,7 @@ def testRectilinear ( editor ):
, Point( l( 20.0), l(100.0) ) # 17
, Point( l( 40.0), l(100.0) ) # 18
, Point( l( 40.0), l(140.0) ) # 19
, Point( l( 20.0), l(140.0) ) # 20
, Point( l( 20.0), l(150.0) ) # 21
, Point( l( 10.0), l(150.0) ) # 22
@ -105,7 +108,7 @@ def testRectilinear ( editor ):
, Point( l( 40.0), l(170.0) ) # 27
, Point( l( 50.0), l(170.0) ) # 28
, Point( l( 50.0), l(160.0) ) # 29
, Point( l(150.0), l(160.0) ) # 30
, Point( l(150.0), l(150.0) ) # 31
, Point( l(130.0), l(150.0) ) # 32
@ -116,7 +119,7 @@ def testRectilinear ( editor ):
, Point( l(110.0), l(110.0) ) # 37
, Point( l(120.0), l(110.0) ) # 38
, Point( l(120.0), l(100.0) ) # 39
, Point( l(130.0), l(100.0) ) # 40
, Point( l(130.0), l( 90.0) ) # 41
, Point( l(150.0), l( 90.0) ) # 42
@ -127,7 +130,7 @@ def testRectilinear ( editor ):
, Point( l(110.0), l( 50.0) ) # 47
, Point( l(120.0), l( 50.0) ) # 48
, Point( l(120.0), l( 40.0) ) # 49
, Point( l(130.0), l( 40.0) ) # 50
, Point( l(130.0), l( 30.0) ) # 51
, Point( l(150.0), l( 30.0) ) # 52
@ -135,7 +138,15 @@ def testRectilinear ( editor ):
, Point( l( 50.0), l( 20.0) ) # 54
, Point( l( 50.0), l( 10.0) ) # 55
, Point( l( 40.0), l( 10.0) ) # 56
, Point( l( 40.0), l( 0.0) ) ] # 57
, Point( l( 40.0), l( 0.0) ) # 57
, Point( l( 0.0), l( 0.0) ) ] # 57
#points = [ Point( l( 0.0), l( 0.0) ) # 0
# , Point( l( 0.0), l( 80.0) ) # 1
# , Point( l( 40.0), l( 80.0) ) # 2
# , Point( l( 40.0), l( 60.0) ) # 3
# , Point( l( 20.0), l( 60.0) ) # 4
# , Point( l( 20.0), l( 0.0) ) # 5
# , Point( l( 0.0), l( 0.0) ) ] # 6
r = Rectilinear.create( net, metal2, points )
boxes = []