From c53fc01cb2e990fe699d397ca1a7dcf785907950 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Fri, 5 May 2023 16:22:51 +0200 Subject: [PATCH] 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. --- hurricane/src/hurricane/Rectilinear.cpp | 15 ++++- tramontana/src/QueryTiles.cpp | 24 +++++-- tramontana/src/SweepLine.cpp | 89 ++++++++++++++++++++----- tramontana/src/Tile.cpp | 86 ++++++++++++++++++++---- tramontana/src/tramontana/SweepLine.h | 15 ++++- tramontana/src/tramontana/Tile.h | 20 ++++-- unittests/python/test_rectilinear.py | 27 +++++--- 7 files changed, 225 insertions(+), 51 deletions(-) diff --git a/hurricane/src/hurricane/Rectilinear.cpp b/hurricane/src/hurricane/Rectilinear.cpp index 42bc911b..825d776a 100644 --- a/hurricane/src/hurricane/Rectilinear.cpp +++ b/hurricane/src/hurricane/Rectilinear.cpp @@ -182,7 +182,7 @@ namespace { void SweepLine::loadVEdges () { const vector& points = _rectilinear->getPoints(); - for ( size_t i=0 ; i 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 ); diff --git a/tramontana/src/QueryTiles.cpp b/tramontana/src/QueryTiles.cpp index eb3f4833..0a72edfe 100644 --- a/tramontana/src/QueryTiles.cpp +++ b/tramontana/src/QueryTiles.cpp @@ -72,18 +72,32 @@ namespace Tramontana { void QueryTiles::goCallback ( Go* go ) { - vector tiles; + Tile* rootTile = nullptr; Component* component = dynamic_cast( 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++; } diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index 5850683f..5a6f51f3 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -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); diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp index 648e882b..45e0d5a2 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -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::_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( 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(component)) { + cerr << Error( "Tile::create(): Polygon are not supported for extraction.\n" + " (%s)" + , getString(occurrence).c_str() + ) << endl; + return nullptr; + } + if (dynamic_cast(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( 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 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 << "getName() << " " << _occurrence << ">"; + os << "getName() << " " << _occurrence << ">"; return os.str(); } diff --git a/tramontana/src/tramontana/SweepLine.h b/tramontana/src/tramontana/SweepLine.h index b7f8be26..a7a4aec9 100644 --- a/tramontana/src/tramontana/SweepLine.h +++ b/tramontana/src/tramontana/SweepLine.h @@ -19,6 +19,7 @@ #pragma once #include #include +#include #include #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 IntervalTrees; + typedef std::map IntervalTrees; + public: + typedef std::set LayerSet; + typedef std::map ConnexityMap; private: class Element { public: @@ -66,6 +71,8 @@ namespace Tramontana { inline Cell* getCell (); inline const std::vector& 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 _extracteds; + Layer::Mask _extractedsMask; + ConnexityMap _connexityMap; std::vector _tiles; IntervalTrees _intervalTrees; }; @@ -109,7 +119,8 @@ namespace Tramontana { // SweepLine. inline Cell* SweepLine::getCell () { return _tramontana->getCell(); } - inline const std::vector& SweepLine::getExtracteds () const { return _extracteds; } + inline const std::vector& SweepLine::getExtracteds () const { return _extracteds; } + inline Layer::Mask SweepLine::getExtractedMask () const { return _extractedsMask; } inline void SweepLine::add ( Tile* tile ) { diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h index e316b0f5..2d2a3e20 100644 --- a/tramontana/src/tramontana/Tile.h +++ b/tramontana/src/tramontana/Tile.h @@ -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 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; diff --git a/unittests/python/test_rectilinear.py b/unittests/python/test_rectilinear.py index 10b1db34..447dce17 100644 --- a/unittests/python/test_rectilinear.py +++ b/unittests/python/test_rectilinear.py @@ -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 = []