diff --git a/bootstrap/allianceInstaller.sh b/bootstrap/allianceInstaller.sh index 0c3526ed..03a0cc3c 100755 --- a/bootstrap/allianceInstaller.sh +++ b/bootstrap/allianceInstaller.sh @@ -20,6 +20,7 @@ srcDir=${HOME}${nightly}/coriolis-2.x/src/alliance/alliance/src commonRoot=${HOME}${nightly}/coriolis-2.x/${arch}/Release.Shared + #commonRoot=${HOME}${nightly}/coriolis-2.x/${arch}/Debug.Shared buildDir=${commonRoot}/build installDir=${commonRoot}/install diff --git a/bootstrap/build.conf b/bootstrap/build.conf index 6f3aa465..3537a0ee 100644 --- a/bootstrap/build.conf +++ b/bootstrap/build.conf @@ -24,8 +24,9 @@ projects = [ #, "knik" #, "katabatic" #, "kite" - , "equinox" - , "solstice" + #, "equinox" + #, "solstice" + , "tramontana" , "oroshi" , "bora" , "karakaze" diff --git a/bootstrap/cmake_modules/CMakeLists.txt b/bootstrap/cmake_modules/CMakeLists.txt index b5083345..25e65995 100644 --- a/bootstrap/cmake_modules/CMakeLists.txt +++ b/bootstrap/cmake_modules/CMakeLists.txt @@ -9,6 +9,7 @@ FindQwt.cmake FindSphinx.cmake FindPelican.cmake + FindCOLOQUINTE.cmake GetGitRevisionDescription.cmake GetGitRevisionDescription.cmake.in ) diff --git a/bootstrap/cmake_modules/FindCOLOQUINTE.cmake b/bootstrap/cmake_modules/FindCOLOQUINTE.cmake new file mode 100644 index 00000000..95504862 --- /dev/null +++ b/bootstrap/cmake_modules/FindCOLOQUINTE.cmake @@ -0,0 +1,38 @@ +# - Find the Coloquinte includes and libraries. +# The following variables are set if Coriolis is found. If COLOQUINTE is not +# found, COLOQUINTE_FOUND is set to false. +# COLOQUINTE_FOUND - True when the Coriolis include directory is found. +# COLOQUINTE_INCLUDE_DIR - the path to where the Coriolis include files are. +# COLOQUINTE_LIBRARIES - The path to where the Coriolis library files are. + + +SET(COLOQUINTE_INCLUDE_PATH_DESCRIPTION "directory containing the Coloquinte include files. E.g /usr/local/include/coriolis2 or /asim/coriolis/include/coriolis2") + +SET(COLOQUINTE_DIR_MESSAGE "Set the COLOQUINTE_INCLUDE_DIR cmake cache entry to the ${COLOQUINTE_INCLUDE_PATH_DESCRIPTION}") + +# don't even bother under WIN32 +IF(UNIX) + # + # Look for an installation. + # + FIND_PATH(COLOQUINTE_INCLUDE_PATH NAMES coloquinte/coloquinte.hpp PATHS + # Look in other places. + ${CORIOLIS_DIR_SEARCH} + PATH_SUFFIXES include/coriolis2 + # Help the user find it if we cannot. + DOC "The ${COLOQUINTE_INCLUDE_PATH_DESCRIPTION}" + ) + MESSAGE( "COL ${COLOQUINTE_INCLUDE_PATH}" ) + + FIND_LIBRARY(COLOQUINTE_LIBRARY_PATH + NAMES coloquinte + PATHS ${CORIOLIS_DIR_SEARCH} + PATH_SUFFIXES lib64 lib + # Help the user find it if we cannot. + DOC "The ${COLOQUINTE_INCLUDE_PATH_DESCRIPTION}" + ) + + SET_LIBRARIES_PATH(COLOQUINTE COLOQUINTE) + HURRICANE_CHECK_LIBRARIES(COLOQUINTE) + +ENDIF(UNIX) diff --git a/crlcore/src/ccore/ToolEngine.cpp b/crlcore/src/ccore/ToolEngine.cpp index 45e18ccf..599a0786 100644 --- a/crlcore/src/ccore/ToolEngine.cpp +++ b/crlcore/src/ccore/ToolEngine.cpp @@ -191,8 +191,9 @@ namespace CRL { bool ToolEngine::_inDestroyAll = false; - ToolEngine::ToolEngine ( Cell* cell ) + ToolEngine::ToolEngine ( Cell* cell, bool verbose ) : Super() + , _verbose (verbose) , _cell (cell) , _placementModificationFlag(0) , _routingModificationFlag (0) @@ -219,11 +220,13 @@ namespace CRL { put( enginesRelation ); - cmess1 << " o Creating ToolEngine<" << getName() << "> for Cell <" - << _cell->getName() << ">" << endl; - - cmess1 << Dots::asString( " - Initial memory" - , Timer::getStringMemory(Timer::getMemorySize()) ) << endl; + if (_verbose) { + cmess1 << " o Creating ToolEngine<" << getName() << "> for Cell <" + << _cell->getName() << ">" << endl; + + cmess1 << Dots::asString( " - Initial memory" + , Timer::getStringMemory(Timer::getMemorySize()) ) << endl; + } } diff --git a/crlcore/src/ccore/crlcore/ToolEngine.h b/crlcore/src/ccore/crlcore/ToolEngine.h index 9e521788..4f86b0b4 100644 --- a/crlcore/src/ccore/crlcore/ToolEngine.h +++ b/crlcore/src/ccore/crlcore/ToolEngine.h @@ -81,13 +81,14 @@ namespace CRL { protected: Cell* _cell; private: + bool _verbose; unsigned int _placementModificationFlag; unsigned int _routingModificationFlag; bool _inRelationDestroy; Timer _timer; uint32_t _passNumber; protected: - ToolEngine ( Cell* cell ); + ToolEngine ( Cell* cell, bool verbose=true ); virtual void _postCreate (); virtual void _preDestroy (); protected: diff --git a/cumulus/src/designflow/pnr.py b/cumulus/src/designflow/pnr.py index 8f0a29ae..57690083 100644 --- a/cumulus/src/designflow/pnr.py +++ b/cumulus/src/designflow/pnr.py @@ -64,7 +64,7 @@ class PnR ( FlowTask ): else: print( 'PnR.doTask() run in interactive CGT mode.' ) PnR.textMode = False - from .. import Etesian, Anabatic, Katana, Bora, Tutorial, Viewer, Unicorn + from .. import Etesian, Anabatic, Katana, Bora, Tramontana, Tutorial, Viewer, Unicorn ShellEnv().export() if self.script and not callable(self.script): @@ -80,8 +80,8 @@ class PnR ( FlowTask ): unicorn = Unicorn.UnicornGui.create() unicorn.setApplicationName ( 'cgt') unicorn.registerTool ( Etesian.GraphicEtesianEngine.grab() ) - #unicorn.registerTool ( Kite.GraphicKiteEngine.grab() ) unicorn.registerTool ( Katana.GraphicKatanaEngine.grab() ) + unicorn.registerTool ( Tramontana.GraphicTramontanaEngine.grab() ) unicorn.registerTool ( Bora.GraphicBoraEngine.grab() ) unicorn.registerTool ( Tutorial.GraphicTutorialEngine.grab() ) #unicorn.setAnonNetSelectable(False) diff --git a/cumulus/src/designflow/technos.py b/cumulus/src/designflow/technos.py index 0aac5c7d..2ff7ebdc 100644 --- a/cumulus/src/designflow/technos.py +++ b/cumulus/src/designflow/technos.py @@ -190,6 +190,7 @@ def setupSky130_c4m ( checkToolkit=None, pdkMasterTop=None ): cfg.misc.logMode = True cfg.misc.verboseLevel1 = False cfg.misc.verboseLevel2 = False + cfg.viewer.pixelThreshold = 5 cfg.etesian.graphics = 2 cfg.anabatic.topRoutingLayer = 'm4' cfg.katana.eventsLimit = 4000000 diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index f189715d..3f9c3530 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -1204,8 +1204,8 @@ namespace Etesian { Instance* instance = static_cast(occurrence.getEntity()); string instanceName = occurrence.getCompactString(); // Remove the enclosing brackets... - instanceName.erase( 0, 1 ); - instanceName.erase( instanceName.size()-1 ); + //instanceName.erase( 0, 1 ); + //instanceName.erase( instanceName.size()-1 ); auto iid = _instsToIds.find( instance ); if (iid == _instsToIds.end() ) { diff --git a/hurricane/src/hurricane/Commons.cpp b/hurricane/src/hurricane/Commons.cpp index fed4c301..fb4d0a50 100644 --- a/hurricane/src/hurricane/Commons.cpp +++ b/hurricane/src/hurricane/Commons.cpp @@ -36,7 +36,7 @@ namespace Hurricane { #ifdef HAVE_CXA_DEMANGLE string demangle ( const char* symbol ) -{ +{ int status; size_t length = 4096; char demangled[length]; @@ -49,13 +49,25 @@ string demangle ( const char* symbol ) #else string demangle ( const char* symbol ) -{ - return symbol; -} +{ return symbol; } #endif + string& split ( string& s ) + { + size_t i = s.find( "<" ); + while ( i != string::npos ) { + if (i+3 > s.size()) break; + //if (s[i+2] != '>') { + s.insert( i, "\\n" ); + //} + i = s.find( "<", i+3 ); + } + return s; + } + + } // End of Hurricane namespace. diff --git a/hurricane/src/hurricane/Interval.cpp b/hurricane/src/hurricane/Interval.cpp index cd338d5a..7581b471 100644 --- a/hurricane/src/hurricane/Interval.cpp +++ b/hurricane/src/hurricane/Interval.cpp @@ -111,21 +111,21 @@ bool Interval::intersect(const Interval& interval, bool strict) const if (isEmpty() or interval.isEmpty()) return false; if ( (_vMax < interval._vMin) or (interval._vMax < _vMin) ) return false; - return not strict or ( (_vMax != interval._vMin) and (interval._vMax != _vMin) ); + return not strict or ( (_vMax > interval._vMin) or (interval._vMax > _vMin) ); } bool Interval::inferior(const Interval& interval, bool strict) const // ***************************************************************** { - if (_vMax < interval._vMin) return true; - return not strict and (_vMax == interval._vMin); + if (_vMax == interval._vMin) return not strict; + return (_vMax < interval._vMin); } bool Interval::superior(const Interval& interval, bool strict) const // ***************************************************************** { if (_vMin > interval._vMax) return true; - return !strict && (_vMin == interval._vMax); + return not (strict or (_vMin != interval._vMax)); } bool Interval::isConstrainedBy(const Interval& interval) const diff --git a/hurricane/src/hurricane/Net.cpp b/hurricane/src/hurricane/Net.cpp index 643cb1ac..12315255 100644 --- a/hurricane/src/hurricane/Net.cpp +++ b/hurricane/src/hurricane/Net.cpp @@ -772,15 +772,23 @@ void Net::_preDestroy() cdebug_tabw(18,-1); } +string Net::_getFlagsAsString() const +// ********************************** +{ + string ds; + ds += ((isDeepNet() ) ? "d" : "-"); + ds += ((_isExternal ) ? "e" : "-"); + ds += ((_isGlobal ) ? "g" : "-"); + ds += ((_isAutomatic) ? "a" : "-"); + return ds; +} + string Net::_getString() const // *************************** { string bs = Inherit::_getString(); string ds = "\"" + getString(_name) + "\" "; - ds += ((isDeepNet() ) ? "d" : "-"); - ds += ((_isExternal ) ? "e" : "-"); - ds += ((_isGlobal ) ? "g" : "-"); - ds += ((_isAutomatic) ? "a" : "-"); + ds += _getFlagsAsString(); ds += " "; ds += getString(_type ) + " "; ds += getString(_direction); diff --git a/hurricane/src/hurricane/Occurrence.cpp b/hurricane/src/hurricane/Occurrence.cpp index 49cb3456..1d3e9d63 100644 --- a/hurricane/src/hurricane/Occurrence.cpp +++ b/hurricane/src/hurricane/Occurrence.cpp @@ -96,16 +96,27 @@ bool Occurrence::operator!=(const Occurrence& occurrence) const bool Occurrence::operator<(const Occurrence& occurrence) const // ******************************************************** { - if (not _entity and not occurrence._entity) return false; - if (not _entity) return true; - if (not occurrence._entity) return false; + cdebug_log(0,0) << "Occurrence::operator<()" << endl; + cdebug_log(0,0) << "| lhs=" << *this << endl; + cdebug_log(0,0) << "| rhs=" << occurrence << endl; + if ((not _sharedPath) xor (not occurrence._sharedPath)) return not _sharedPath; + if ((not _entity ) xor (not occurrence._entity )) return not _entity; + if (_entity and (_entity->getId() != occurrence._entity->getId())) + return _entity->getId() < occurrence._entity->getId(); + if (not _sharedPath) return false; - if (_entity->getId() < occurrence._entity->getId()) return true; - if (_entity->getId() > occurrence._entity->getId()) return false; + // if (not _sharedPath) return true; + // if (not occurrence._sharedPath) return false; + // if (not _sharedPath and not occurrence._sharedPath) return false; + // if (not _sharedPath) return true; + // if (not occurrence._sharedPath) return false; - if (not _sharedPath and not occurrence._sharedPath) return false; - if (not _sharedPath) return true; - if (not occurrence._sharedPath) return false; + // if (not _entity and not occurrence._entity) return false; + // if (not _entity) return true; + // if (not occurrence._entity) return false; + + // if (_entity->getId() < occurrence._entity->getId()) return true; + // if (_entity->getId() > occurrence._entity->getId()) return false; return _sharedPath->getHash() < occurrence._sharedPath->getHash(); @@ -274,11 +285,12 @@ string Occurrence::_getString() const string Occurrence::getCompactString() const // **************************************** { - string s = "<"; + string s; if (_entity) { s += getString(getOwnerCell()->getName()); s += ":"; - if (_sharedPath) s += getString(_sharedPath->getName()) + ":"; + if (_sharedPath) s += getString(_sharedPath->getName()); + s += ":"; Instance* instance = dynamic_cast(_entity); if (instance) { s += "I."+getString(instance->getName()); @@ -291,7 +303,6 @@ string Occurrence::getCompactString() const } } } - s += ">"; return s; } diff --git a/hurricane/src/hurricane/Rectilinear.cpp b/hurricane/src/hurricane/Rectilinear.cpp index 2a869db2..825d776a 100644 --- a/hurricane/src/hurricane/Rectilinear.cpp +++ b/hurricane/src/hurricane/Rectilinear.cpp @@ -40,6 +40,284 @@ #include "hurricane/Warning.h" +namespace { + + using namespace std; + using Hurricane::DbU; + using Hurricane::Point; + using Hurricane::Box; + using Hurricane::Interval; + using Hurricane::Rectilinear; + + + class SweepInterval : public Interval { + public: + inline SweepInterval ( DbU::Unit vmin , DbU::Unit vmax, DbU::Unit xmin ); + inline SweepInterval ( Interval&, DbU::Unit xmin ); + inline SweepInterval& inflate ( DbU::Unit dvMin, DbU::Unit dvMax ); + inline SweepInterval& merge ( DbU::Unit v ); + inline DbU::Unit getXMin () const; + inline void setXMin ( DbU::Unit ); + inline string _getString () const; + private: + DbU::Unit _xMin; + }; + + + inline SweepInterval::SweepInterval ( DbU::Unit vmin , DbU::Unit vmax, DbU::Unit xmin ) + : Interval(vmin,vmax) + , _xMin (xmin) + { } + + inline SweepInterval::SweepInterval ( Interval& base, DbU::Unit xmin ) + : Interval(base) + , _xMin (xmin) + { } + + inline SweepInterval& SweepInterval::inflate ( DbU::Unit dvMin, DbU::Unit dvMax ) { Interval::inflate(dvMin,dvMax); return *this; } + inline SweepInterval& SweepInterval::merge ( DbU::Unit v ) { Interval::merge(v); return *this; } + inline DbU::Unit SweepInterval::getXMin () const { return _xMin; } + inline void SweepInterval::setXMin ( DbU::Unit xmin ) { _xMin=xmin; } + + inline string SweepInterval::_getString () const + { + string s; + s += "@" + DbU::getValueString(_xMin); + s += " [" + DbU::getValueString(getVMin()); + s += " " + DbU::getValueString(getVMax()) + "]"; + return s; + } + + +} // Anonymous namespace. + + +GETSTRING_VALUE_SUPPORT(::SweepInterval); + + +namespace { + + + class SweepLine { + public: + SweepLine ( const Rectilinear*, vector& ); + ~SweepLine (); + void addVEdge ( DbU::Unit ymin, DbU::Unit ymax, DbU::Unit x ); + void loadVEdges (); + void process ( Interval ); + void process ( const pair< DbU::Unit, list >& ); + void toBox ( SweepInterval& ); + void asRectangles (); + private: + const Rectilinear* _rectilinear; + vector& _boxes; + list< pair< DbU::Unit, list > > _vedges; + list< SweepInterval > _sweepLine; + DbU::Unit _prevX; + DbU::Unit _currX; + }; + + + SweepLine::SweepLine ( const Rectilinear* r, vector& boxes ) + : _rectilinear(r) + , _boxes (boxes) + , _vedges () + , _sweepLine () + , _prevX (0) + , _currX (0) + { + cdebug_log(17,1) << "SweepLine::SweepLine()" << endl; + } + + + SweepLine::~SweepLine () + { + cdebug_tabw(17,-1); + } + + + void SweepLine::addVEdge ( DbU::Unit ymin, DbU::Unit ymax, DbU::Unit x ) + { + if (ymin > ymax) std::swap( ymin, ymax ); + + cdebug_log(17,1) << "SweepLine::addVEdge() @"<< DbU::getValueString(x) + << " [" << DbU::getValueString(ymin) + << " " << DbU::getValueString(ymax) << "]" << endl; + + bool inserted = false; + for ( auto ix = _vedges.begin() ; ix != _vedges.end() ; ++ix ) { + cdebug_log(17,0) << "| Looking @" << DbU::getValueString(ix->first) + << " size=" << ix->second.size() << endl; + + if (ix->first > x) { + _vedges.insert( ix, make_pair( x, list() )); + cdebug_log(17,0) << "+ add new @" << DbU::getValueString(x) << endl; + --ix; + } + if (ix->first == x) { + for ( auto iintv = ix->second.begin() ; iintv != ix->second.end() ; ++iintv ) { + if (iintv->getVMin() >= ymax) { + ix->second.insert( iintv, Interval(ymin,ymax) ); + inserted = true; + break; + } + } + if (not inserted) { + ix->second.push_back( Interval(ymin,ymax) ); + inserted = true; + } + break; + } + } + if (not inserted) { + cdebug_log(17,0) << "+ add new (back) @" << DbU::getValueString(x) << endl; + _vedges.push_back( make_pair( x, list() )); + _vedges.back().second.push_back( Interval(ymin,ymax) ); + } + + cdebug_tabw(17,-1); + } + + + void SweepLine::loadVEdges () + { + const vector& points = _rectilinear->getPoints(); + for ( size_t i=0 ; igetVMin()) { + _sweepLine.insert( iintv, SweepInterval(v,_currX) ); + done = true; + break; + } + // Extractor p. 9 (f). + if ( (v.getVMin() == iintv->getVMin()) + and (v.getVMax() == iintv->getVMax()) ) { + toBox( *iintv ); + _sweepLine.erase( iintv ); + done = true; + break; + } + // Extractor p. 9 (b). + if (v.getVMax() == iintv->getVMin()) { + toBox( *iintv ); + iintv->merge( v.getVMin() ); + done = true; + break; + } + // Extractor p. 9 (g). + if (v.getVMax() == iintv->getVMax()) { + toBox( *iintv ); + cdebug_log(17,0) << "case (g): carve" << endl; + iintv->inflate( 0, v.getVMin() - iintv->getVMax() ); + cdebug_log(17,0) << "| " << (*iintv) << endl; + done = true; + break; + } + // Extractor p. 9 (h). + if (v.getVMin() == iintv->getVMin()) { + toBox( *iintv ); + iintv->inflate(iintv->getVMin() - v.getVMax(), 0 ); + done = true; + break; + } + // Extractor p. 9 (c). + if ( (v.getVMin() > iintv->getVMin()) + and (v.getVMax() < iintv->getVMax()) ) { + toBox( *iintv ); + cdebug_log(17,0) << "case (c): carve" << endl; + DbU::Unit wholeVMin = iintv->getVMin(); + iintv->inflate( iintv->getVMin() - v.getVMax(), 0 ); + cdebug_log(17,0) << "| " << (*iintv) << endl; + _sweepLine.insert( iintv, SweepInterval( wholeVMin, v.getVMin(), _currX ) ); + cdebug_log(17,0) << "| " << (*(--iintv)) << endl; + done = true; + break; + } + // Extractor p. 9 (d,e). + if (v.getVMin() == iintv->getVMax()) { + auto iintvNext = iintv; + ++iintvNext; + // Extractor p. 9 (d). + if (iintvNext == _sweepLine.end()) { + toBox( *iintv ); + iintv->merge( v.getVMax() ); + } else { + // Extractor p. 9 (d). + if (v.getVMax() < iintvNext->getVMin()) { + toBox( *iintv ); + iintv->merge( v.getVMax() ); + } else { + // Extractor p. 9 (e). + toBox( *iintv ); + toBox( *iintvNext ); + iintv->merge( iintvNext->getVMax() ); + _sweepLine.erase( iintvNext ); + } + } + done = true; + break; + } + } + if (not done) { + _sweepLine.push_back( SweepInterval(v,_currX) ); + } + + cdebug_tabw(17,-1); + } + + + void SweepLine::process ( const pair< DbU::Unit, list >& intervals ) + { + cdebug_log(17,1) << "SweepLine::process() @"<< DbU::getValueString(intervals.first) + << " size=" << intervals.second.size() << endl; + _currX = intervals.first; + for ( const Interval& v : intervals.second ) process( v ); + cdebug_tabw(17,-1); + } + + + void SweepLine::asRectangles () + { + loadVEdges(); + for ( auto intervals : _vedges ) { + process( intervals ); + } + cdebug_log(17,0) << "SweepLine::asRectangles() size=" << _boxes.size() << endl; + for ( const Box& b : _boxes ) + cdebug_log(17,0) << "| " << b << endl; + } + + +} // Anonymous namespace. + + namespace Hurricane { @@ -50,6 +328,7 @@ namespace Hurricane { : Super (net) , _layer (layer) , _points(points) + , _flags (IsRectilinear) { } @@ -58,9 +337,21 @@ namespace Hurricane { if (not layer) throw Error( "Rectilinear::create(): Can't create, NULL layer" ); - if (points.size() > 1000) - throw Error( "Rectilinear::create(): Rectlinear polygons must not exceed 1000 vertexes." ); + if (points.size() < 4) + throw Error( "Rectilinear::create(): Rectilinear polygons must at least contains 3 vertexes." ); + if (points.size() > 1000) + 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 ); for ( size_t i=0 ; i_flags &= ~IsRectilinear; rectilinear->_postCreate(); return rectilinear; @@ -176,6 +470,15 @@ namespace Hurricane { } + bool Rectilinear::getAsRectangles ( std::vector& rectangles ) const + { + rectangles.clear(); + if (not isRectilinear()) return false; + SweepLine( this, rectangles ).asRectangles(); + return true; + } + + void Rectilinear::_toJson ( JsonWriter* writer ) const { Inherit::_toJson( writer ); diff --git a/hurricane/src/hurricane/hurricane/Commons.h b/hurricane/src/hurricane/hurricane/Commons.h index 9f0489ff..8c5ecbe5 100644 --- a/hurricane/src/hurricane/hurricane/Commons.h +++ b/hurricane/src/hurricane/hurricane/Commons.h @@ -146,6 +146,9 @@ namespace Hurricane { } + string& split ( std::string& ); + + } // End of Hurricane namespace. diff --git a/hurricane/src/hurricane/hurricane/Component.h b/hurricane/src/hurricane/hurricane/Component.h index 328e865c..077ce774 100644 --- a/hurricane/src/hurricane/hurricane/Component.h +++ b/hurricane/src/hurricane/hurricane/Component.h @@ -21,6 +21,7 @@ #ifndef HURRICANE_COMPONENT_H #define HURRICANE_COMPONENT_H +#include #include "hurricane/Points.h" #include "hurricane/Go.h" #include "hurricane/Components.h" @@ -170,6 +171,9 @@ namespace Hurricane { }; + typedef std::set ComponentSet; + + } // Hurricane namespace. diff --git a/hurricane/src/hurricane/hurricane/Interval.h b/hurricane/src/hurricane/hurricane/Interval.h index 6a2d66a6..525237c3 100644 --- a/hurricane/src/hurricane/hurricane/Interval.h +++ b/hurricane/src/hurricane/hurricane/Interval.h @@ -1,6 +1,6 @@ // -*- C++ -*- // -// Copyright (c) BULL S.A. 2000-2018, All Rights Reserved +// Copyright (c) BULL S.A. 2000-2023, All Rights Reserved // // This file is part of Hurricane. // @@ -29,9 +29,7 @@ // +-----------------------------------------------------------------+ -#ifndef HURRICANE_INTERVAL_H -#define HURRICANE_INTERVAL_H - +#pragma once #include "hurricane/DbU.h" namespace Hurricane { @@ -48,6 +46,11 @@ namespace Hurricane { inline bool operator() ( const Interval& rhs, const Interval& lhs ) const; inline bool operator() ( const Interval* rhs, const Interval* lhs ) const; }; + class CompareByMinMax { + public: + inline bool operator() ( const Interval& rhs, const Interval& lhs ) const; + inline bool operator() ( const Interval* rhs, const Interval* lhs ) const; + }; public: Interval ( bool makeEmpty=true ); Interval ( const DbU::Unit& ); @@ -124,6 +127,20 @@ namespace Hurricane { { return lhs->getVMin() < rhs->getVMin(); } + inline bool Interval::CompareByMinMax::operator() ( const Interval& lhs, const Interval& rhs ) const + { + if (lhs.getVMin() != rhs.getVMin()) return lhs.getVMin() < rhs.getVMin(); + return lhs.getVMax() < rhs.getVMax(); + } + + + inline bool Interval::CompareByMinMax::operator() ( const Interval* lhs, const Interval* rhs ) const + { + if (lhs->getVMin() != rhs->getVMin()) return lhs->getVMin() < rhs->getVMin(); + return lhs->getVMax() < rhs->getVMax(); + } + + } // Hurricane namespace. @@ -136,7 +153,5 @@ inline void jsonWrite ( JsonWriter* w, const std::string& key, const Hurricane: w->endArray(); } + INSPECTOR_PR_SUPPORT(Hurricane::Interval); - - -#endif // HURRICANE_INTERVAL_H diff --git a/hurricane/src/hurricane/hurricane/IntervalTree.h b/hurricane/src/hurricane/hurricane/IntervalTree.h index 7d4673b2..58f4264d 100644 --- a/hurricane/src/hurricane/hurricane/IntervalTree.h +++ b/hurricane/src/hurricane/hurricane/IntervalTree.h @@ -1,6 +1,6 @@ // -*- C++ -*- // -// Copyright (c) BULL S.A. 2018-2018, All Rights Reserved +// Copyright (c) BULL S.A. 2018-2023, All Rights Reserved // // This file is part of Hurricane. // @@ -34,9 +34,7 @@ // Third edition, MIT press, 2011, p. 348. -#ifndef HURRICANE_INTERVAL_TREE_H -#define HURRICANE_INTERVAL_TREE_H - +#pragma once #include "hurricane/Interval.h" #include "hurricane/RbTree.h" @@ -57,6 +55,7 @@ namespace Hurricane { inline Data& getData () const; inline DbU::Unit getChildsVMax () const; inline DbU::Unit updateChildsVMax ( DbU::Unit lvmax, DbU::Unit rvmax ); + inline bool operator== ( const IntervalData& ) const; string _getString () const; Record* _getRecord () const; private: @@ -64,7 +63,7 @@ namespace Hurricane { Data data_; }; - + template< typename Data > inline IntervalData::IntervalData () : Interval(1,-1) @@ -93,7 +92,17 @@ namespace Hurricane { template< typename Data > inline DbU::Unit IntervalData::updateChildsVMax ( DbU::Unit lvmax, DbU::Unit rvmax ) - { childsVMax_ = std::max( getVMax(), std::max( lvmax, rvmax ) ); return childsVMax_; } + { + cdebug_log(0,0) << "IntervalData::updateChildsVMax() " << DbU::getValueString(lvmax) + << " " << DbU::getValueString(lvmax) + << " " << this << endl; + childsVMax_ = std::max( getVMax(), std::max( lvmax, rvmax ) ); return childsVMax_; + } + + + template< typename Data > + inline bool IntervalData::operator== ( const IntervalData& other ) const + { return Interval::operator==(*this) and (data_ == other.data_); } template< typename Data > @@ -117,14 +126,35 @@ namespace Hurricane { return record; } + +// ------------------------------------------------------------------- +// Class : "Hurricane::IntervalDataCompare". + + template< typename Data, typename DataCompare=std::less > + class IntervalDataCompare { + public: + inline bool operator() ( const IntervalData& lhs, const IntervalData& rhs ) const + { + static Interval::CompareByMinMax compare; + static DataCompare dataCompare; + if ( (lhs.getVMin() == rhs.getVMin()) + and (lhs.getVMax() == rhs.getVMax())) { + cdebug_log(0,0) << "IntervalDataCompare::operator<() - Data fallback." << endl; + cdebug_log(0,0) << "| " << lhs.getData() << endl; + return dataCompare( lhs.getData(), rhs.getData() ); + } + return compare( lhs, rhs ); + } + }; + + // ------------------------------------------------------------------- // Class : "Hurricane::IntervalTree". - - template< typename Data > - class IntervalTree : public RbTree< IntervalData, Interval::CompareByMin > { + template< typename Data, typename DataCompare=std::less > + class IntervalTree : public RbTree< IntervalData, IntervalDataCompare > { public: - typedef RbTree< IntervalData, Interval::CompareByMin > Super; + typedef RbTree< IntervalData, IntervalDataCompare > Super; public: class overlap_iterator : public Super::iterator { public: @@ -171,31 +201,39 @@ namespace Hurricane { size_t getThickness () const; overlap_iterator beginOverlaps ( const Interval& ) const; inline OverlapElements getOverlaps ( const Interval& ) const; + void checkVMax () const; + void checkVMax ( typename Super::Node* node ) const; private: inline void updateChildsVMax ( typename Super::Node* ); }; - template< typename Data > - IntervalTree::overlap_iterator::overlap_iterator ( const typename Super::Node* node, const Interval& overlap ) + template< typename Data, typename DataCompare > + IntervalTree::overlap_iterator::overlap_iterator ( const typename Super::Node* node, const Interval& overlap ) : Super::iterator(node) , overlap_(overlap) - { } - - - template< typename Data > - typename IntervalTree::overlap_iterator& IntervalTree::overlap_iterator::operator++ () { - while (this->isValid()) { + cdebug_log(0,0) << "IntervalTree::overlap_iterator CTOR " + << (node ? ::getString(node->getValue()) : "node=NULL") + << " " << overlap << endl; + } + + + template< typename Data, typename DataCompare > + typename IntervalTree::overlap_iterator& + IntervalTree::overlap_iterator::operator++ () + { + cdebug_log(0,0) << "IntervalTree::overlap_iterator::operator++()" << endl; + while ( true ) { Super::iterator::operator++(); + if (not this->isValid()) break; - cdebug_log(0,0) << "IntervalTree::overlap_iterator::operator++() " - << ::getString(this->getNode()) << std::endl; + cdebug_log(0,0) << " ==> " << ::getString(this->getNode()->getValue()) << std::endl; - if (this->getNode()->getValue().intersect(overlap_,true)) break; - cdebug_log(0,0) << "NO intersections" << endl; - if (overlap_.inferior(this->getNode()->getValue(),true)) { - cdebug_log(0,0) << "Node is inferior, stop here." << endl; + if (this->getNode()->getValue().intersect(overlap_,false)) break; + cdebug_log(0,0) << " NO intersections" << endl; + if (overlap_.inferior(this->getNode()->getValue(),false)) { + cdebug_log(0,0) << " Node is inferior, stop here." << endl; this->setNode( NULL ); break; } @@ -208,44 +246,45 @@ namespace Hurricane { // Class : "Hurricane::IntervalTree::OverlapOverlapElements" (implementation) - template< typename Data > - inline IntervalTree::OverlapElements::Locator::Locator ( const Locator &locator ) + template< typename Data, typename DataCompare > + inline IntervalTree::OverlapElements::Locator::Locator ( const Locator &locator ) : Hurricane::Locator< IntervalData >() , iterator_(locator.iterator_) { } - template< typename Data > - IntervalTree::OverlapElements::Locator::Locator ( const IntervalTree& tree, const Interval& span ) + template< typename Data, typename DataCompare > + IntervalTree::OverlapElements::Locator::Locator ( const IntervalTree& tree, const Interval& span ) : Hurricane::Locator< IntervalData >() , iterator_(tree.beginOverlaps(span)) { } - template< typename Data > - typename IntervalTree::OverlapElements::Locator* IntervalTree::OverlapElements::Locator::getClone () const + template< typename Data, typename DataCompare > + typename IntervalTree::OverlapElements::Locator* + IntervalTree::OverlapElements::Locator::getClone () const { return new Locator(*this); } - template< typename Data > - IntervalData IntervalTree::OverlapElements::Locator::getElement () const + template< typename Data, typename DataCompare > + IntervalData IntervalTree::OverlapElements::Locator::getElement () const { return (*iterator_); } - template< typename Data > - bool IntervalTree::OverlapElements::Locator::isValid () const + template< typename Data, typename DataCompare > + bool IntervalTree::OverlapElements::Locator::isValid () const { return iterator_.isValid(); } - template< typename Data > - void IntervalTree::OverlapElements::Locator::progress () + template< typename Data, typename DataCompare > + void IntervalTree::OverlapElements::Locator::progress () { if (isValid()) ++iterator_; } - template< typename Data > - std::string IntervalTree::OverlapElements::Locator::_getString () const + template< typename Data, typename DataCompare > + std::string IntervalTree::OverlapElements::Locator::_getString () const { std::string s = "<" + _TName("OverlapElements::Locator") + ">"; @@ -253,34 +292,34 @@ namespace Hurricane { } - template< typename Data > - inline IntervalTree::OverlapElements::OverlapElements ( const IntervalTree& tree, const Interval& span ) + template< typename Data, typename DataCompare > + inline IntervalTree::OverlapElements::OverlapElements ( const IntervalTree& tree, const Interval& span ) : Collection< IntervalData >() , tree_(tree) , span_(span) { } - template< typename Data > - inline IntervalTree::OverlapElements::OverlapElements ( const OverlapElements& elements ) + template< typename Data, typename DataCompare > + inline IntervalTree::OverlapElements::OverlapElements ( const OverlapElements& elements ) : Collection< IntervalData >() , tree_(elements.tree_) , span_(elements.span_) { } - template< typename Data > - Collection< IntervalData >* IntervalTree::OverlapElements::getClone () const + template< typename Data, typename DataCompare > + Collection< IntervalData >* IntervalTree::OverlapElements::getClone () const { return new OverlapElements(*this); } - template< typename Data > - typename IntervalTree::OverlapElements::Locator* IntervalTree::OverlapElements::getLocator () const + template< typename Data, typename DataCompare > + typename IntervalTree::OverlapElements::Locator* IntervalTree::OverlapElements::getLocator () const { return new Locator( tree_, span_ ); } - template< typename Data > - std::string IntervalTree::OverlapElements::_getString () const + template< typename Data, typename DataCompare > + std::string IntervalTree::OverlapElements::_getString () const { std::string s = "<" + _TName("OverlapElements") + " " + getString(tree_) @@ -293,39 +332,45 @@ namespace Hurricane { // Class : "Hurricane::IntervalTree" (implementation). - template< typename Data > - inline void IntervalTree::updateChildsVMax ( typename Super::Node* node ) + template< typename Data, typename DataCompare > + inline void IntervalTree::updateChildsVMax ( typename Super::Node* node ) { + cdebug_log(0,1) << "IntervalTree::updateChildsVMax() " << node->getValue() << endl; DbU::Unit lchildVMax = (node->getLeft ()) ? node->getLeft ()->getValue().getChildsVMax() : node->getValue().getVMax(); DbU::Unit rchildVMax = (node->getRight()) ? node->getRight()->getValue().getChildsVMax() : node->getValue().getVMax(); const_cast< IntervalData& >( node->getValue() ).updateChildsVMax( lchildVMax, rchildVMax ); + cdebug_tabw(0,-1); } - template< typename Data > - void IntervalTree::postRotateLeft ( typename Super::Node* node ) + template< typename Data, typename DataCompare > + void IntervalTree::postRotateLeft ( typename Super::Node* node ) { + cdebug_log(0,1) << "IntervalTree::postRotateLeft() " << node->getValue() << endl; + updateChildsVMax( node ); + if (node->getParent()) updateChildsVMax( node->getParent() ); + cdebug_tabw(0,-1); + } + + + template< typename Data, typename DataCompare > + void IntervalTree::postRotateRight ( typename Super::Node* node ) + { + cdebug_log(0,0) << "IntervalTree::postRotateRight() " << node->getValue() << endl; updateChildsVMax( node ); if (node->getParent()) updateChildsVMax( node->getParent() ); } - template< typename Data > - void IntervalTree::postRotateRight ( typename Super::Node* node ) + template< typename Data, typename DataCompare > + void IntervalTree::postInsert ( typename Super::Node* node ) { - updateChildsVMax( node ); - if (node->getParent()) updateChildsVMax( node->getParent() ); - } - - - template< typename Data > - void IntervalTree::postInsert ( typename Super::Node* node ) - { - cdebug_log(0,1) << "IntervalTree::postInsert() " << node << std::endl; + cdebug_log(0,1) << "IntervalTree::postInsert() " + << ((node) ? ::getString(node->getValue()) : "node=NULL") << std::endl; while ( node ) { - cdebug_log(0,0) << "| " << node << std::endl; + cdebug_log(0,0) << "| " << node->getValue() << std::endl; updateChildsVMax( node ); node = node->getParent(); @@ -335,26 +380,38 @@ namespace Hurricane { } - template< typename Data > - void IntervalTree::postRemove ( typename Super::Node* node ) + template< typename Data, typename DataCompare > + void IntervalTree::postRemove ( typename Super::Node* node ) { + cdebug_log(0,1) << "IntervalTree::postRemove() " + << ((node) ? ::getString(node->getValue()) : "node=NULL") << std::endl; + + if (not node) { + cdebug_tabw(0,-1); + return; + } + typename Super::Node* parent = node->getParent(); if (parent) { - typename Super::Node* child = NULL; + DbU::Unit childsVMax = parent->getValue().getVMax(); + typename Super::Node* child1 = parent->getLeft (); + typename Super::Node* child2 = parent->getRight(); + if (child1 == node) std::swap( child1, child2 ); + if (child1) childsVMax = std::max( childsVMax, child1->getValue().getChildsVMax() ); + if (child2->getLeft ()) childsVMax = std::max( childsVMax, child2->getLeft ()->getValue().getChildsVMax() ); + if (child2->getRight()) childsVMax = std::max( childsVMax, child2->getRight()->getValue().getChildsVMax() ); - if (parent->hasLeftChild(node)) child = parent->getRight(); - else child = parent->getLeft (); - - DbU::Unit childVMax = (child) ? child->getValue().getChildsVMax() : parent->getValue().getVMax(); - const_cast< IntervalData& >( parent->getValue() ).updateChildsVMax( childVMax, childVMax ); + const_cast< IntervalData& >( parent->getValue() ).updateChildsVMax( childsVMax, childsVMax ); postInsert( parent->getParent() ); } + + cdebug_tabw(0,-1); } - template< typename Data > - size_t IntervalTree::getThickness () const + template< typename Data, typename DataCompare > + size_t IntervalTree::getThickness () const { cdebug_log(0,0) << "IntervalTree::getThickness() " << std::endl; @@ -382,36 +439,70 @@ namespace Hurricane { } - template< typename Data > - typename IntervalTree::overlap_iterator IntervalTree::beginOverlaps ( const Interval& overlap ) const + template< typename Data, typename DataCompare > + typename IntervalTree::overlap_iterator + IntervalTree::beginOverlaps ( const Interval& overlap ) const { cdebug_log(0,0) << "IntervalTree::beginOverlaps() " << overlap << std::endl; const typename Super::Node* current = this->getRoot(); - const typename Super::Node* leftMost = NULL; + const typename Super::Node* leftMost = nullptr; while ( current ) { - cdebug_log(0,0) << "| " << ::getString(current) << endl; + cdebug_log(0,0) << "| " << ::getString(current->getValue()) << endl; - if (current->getValue().intersect(overlap)) leftMost = current; + if (current->getValue().intersect(overlap,false)) { + cdebug_log(0,0) << "* Leftmost candidate." << endl; + leftMost = current; + } if ( current->getLeft() - and (overlap.getVMin() < current->getLeft()->getValue().getChildsVMax()) ) - current = current->getLeft(); - else - current = current->getRight(); + and (overlap.getVMin() < current->getLeft()->getValue().getChildsVMax()) ) { + current = current->getLeft(); + leftMost = nullptr; + } else { + if (not leftMost) + current = current->getRight(); + else + current = nullptr; + } } return overlap_iterator( leftMost, overlap ); } - template< typename Data > - typename IntervalTree::OverlapElements IntervalTree::getOverlaps ( const Interval& overlap ) const + template< typename Data, typename DataCompare > + typename IntervalTree::OverlapElements + IntervalTree::getOverlaps ( const Interval& overlap ) const { cdebug_log(0,0) << "IntervalTree::getOverlaps() " << overlap << std::endl; return OverlapElements( *this, overlap ); } + + template< typename Data, typename DataCompare > + void IntervalTree::checkVMax () const + { + checkVMax( this->getRoot() ); + } + + + template< typename Data, typename DataCompare > + void IntervalTree::checkVMax ( typename Super::Node* node ) const + { + if (not node) return; + + DbU::Unit lchildVMax = (node->getLeft ()) ? node->getLeft ()->getValue().getChildsVMax() : node->getValue().getVMax(); + DbU::Unit rchildVMax = (node->getRight()) ? node->getRight()->getValue().getChildsVMax() : node->getValue().getVMax(); + DbU::Unit childsVMax = std::max( lchildVMax, rchildVMax ); + childsVMax = std::max( childsVMax, node->getValue().getVMax() ); + + if (node->getValue().getChildsVMax() != childsVMax) { + cerr << "ChildVMax discrepency on vmax=" << DbU::getValueString(childsVMax) + << " " << ::getString(node->getValue()) << endl; + } + + checkVMax( node->getLeft() ); + checkVMax( node->getRight() ); + } } // HUrricane namespace. - -#endif // HURRICANE_INTERVAL_TREE_H diff --git a/hurricane/src/hurricane/hurricane/Net.h b/hurricane/src/hurricane/hurricane/Net.h index a239352f..545e58e0 100644 --- a/hurricane/src/hurricane/hurricane/Net.h +++ b/hurricane/src/hurricane/hurricane/Net.h @@ -17,9 +17,7 @@ // not, see . // **************************************************************************************************** -#ifndef HURRICANE_NET -#define HURRICANE_NET - +#pragma once #include #include "hurricane/Entity.h" #include "hurricane/Nets.h" @@ -253,6 +251,7 @@ class Net : public Entity { public: virtual void _toJsonSignature(JsonWriter*) const; public: virtual void _toJsonCollections(JsonWriter*) const; public: virtual string _getTypeName() const {return _TName("Net");}; + public: string _getFlagsAsString() const; public: virtual string _getString() const; public: virtual Record* _getRecord() const; public: NetMainName& _getMainName() { return _mainName; } @@ -445,9 +444,10 @@ namespace Hurricane { // Because sometimes it didn't happens (?). const SlotTemplate dummyNetSlot ( string("dummyNetSlot"), NULL ); -} -#endif // HURRICANE_NET + typedef std::set NetSet; + +} // **************************************************************************************************** diff --git a/hurricane/src/hurricane/hurricane/Occurrence.h b/hurricane/src/hurricane/hurricane/Occurrence.h index b022016a..1becac05 100644 --- a/hurricane/src/hurricane/hurricane/Occurrence.h +++ b/hurricane/src/hurricane/hurricane/Occurrence.h @@ -121,6 +121,10 @@ class JsonOccurrence : public JsonObject { public: virtual void toData(JsonStack&); }; + + typedef std::set OccurrenceSet; + + } // End of Hurricane namespace. diff --git a/hurricane/src/hurricane/hurricane/RbTree.h b/hurricane/src/hurricane/hurricane/RbTree.h index ef9d3cc2..1c1b57da 100644 --- a/hurricane/src/hurricane/hurricane/RbTree.h +++ b/hurricane/src/hurricane/hurricane/RbTree.h @@ -34,9 +34,7 @@ // Third edition, MIT press, 2011, p. 308. -#ifndef HURRICANE_RBTREE_H -#define HURRICANE_RBTREE_H - +#pragma once #include #include #include @@ -90,7 +88,7 @@ namespace Hurricane { inline void copyColor ( Node* ); void updateEdge ( Node* oldChild, Node* newChild ); void clear (); - inline void copy ( const Node* ); + inline void swap ( Node* ); virtual std::string _getString () const; virtual Record* _getRecord () const; private: @@ -284,8 +282,15 @@ namespace Hurricane { template< typename Data, typename Compare > - inline void RbTree::Node::copy ( const Node* other ) - { value_ = other->value_; } + inline void RbTree::Node::swap ( Node* other ) + { + cdebug_log(0,0) << "Node::swap()" << endl; + cdebug_log(0,0) << "| " << value_ << endl; + cdebug_log(0,0) << "| " << other->value_ << endl; + Data tmp = value_; value_ = other->value_; other->value_ = tmp; + cdebug_log(0,0) << "| " << value_ << endl; + cdebug_log(0,0) << "| " << other->value_ << endl; + } template< typename Data, typename Compare > @@ -515,7 +520,7 @@ namespace Hurricane { template< typename Data, typename Compare > void RbTree::rotateLeft ( typename RbTree::Node* node ) { - cdebug_log(0,0) << "RbTree::rotateLeft() " << node << std::endl; + cdebug_log(0,0) << "RbTree::rotateLeft() " << node->getValue() << std::endl; Node* rchild = node->getRight(); @@ -534,7 +539,7 @@ namespace Hurricane { template< typename Data, typename Compare > void RbTree::rotateRight ( typename RbTree::Node* node ) { - cdebug_log(0,0) << "RbTree::rotateRight() " << node << std::endl; + cdebug_log(0,0) << "RbTree::rotateRight() " << node->getValue() << std::endl; Node* lchild = node->getLeft(); @@ -557,15 +562,21 @@ namespace Hurricane { Node* current = root_; while ( current ) { - cdebug_log(0,0) << "| " << current << std::endl; + cdebug_log(0,0) << "| " << current->getValue() << std::endl; if (current->getValue() == value) { - cdebug_log(0,-1) << "> Value found: " << current < Value found: " << current->getValue() << std::endl; return iterator(current); } - if (compare_(value,current->getValue())) current = current->getLeft (); - else current = current->getRight(); + if (compare_(value,current->getValue())) { + current = current->getLeft (); + cdebug_log(0,0) << "| Go left " << ((current) ? ::getString(current->getValue()) : "NULL") << std::endl; + } + else { + current = current->getRight(); + cdebug_log(0,0) << "| Go right " << ((current) ? ::getString(current->getValue()) : "NULL") << std::endl; + } } cdebug_log(0,-1) << "Value not found." << std::endl; @@ -630,21 +641,22 @@ namespace Hurricane { Node* rmNode = const_cast( find( value ).getNode() ); if (not rmNode) { - cdebug_log(0,1) << "No node of value=" << value << std::endl; + cdebug_log(0,-1) << "No node of value=" << value << std::endl; return; } + Node* rmLeaf = nullptr; if (rmNode->getLeft() and rmNode->getRight()) { - Node* rmLeaf = rmNode->getLeft(); - Node* rmMax = rmLeaf->getMax(); + rmLeaf = rmNode->getLeft(); + Node* rmMax = rmLeaf->getMax(); if (rmMax) rmLeaf = rmMax; - rmNode->copy( rmLeaf ); - rmNode = rmLeaf; + rmNode->swap( rmLeaf ); + std::swap( rmNode, rmLeaf ); } - - postRemove ( rmNode ); + removeRepair( rmNode, 0 ); + postRemove ( rmNode ); Node* parent = rmNode->getParent(); Node* child = (rmNode->getLeft()) ? rmNode->getLeft() : rmNode->getRight(); @@ -660,8 +672,9 @@ namespace Hurricane { } } - cdebug_log(0,0) << "delete " << rmNode << std::endl; + cdebug_log(0,0) << "delete " << rmNode->getValue() << std::endl; delete rmNode; + --count_; cdebug_tabw(0,-1); @@ -671,8 +684,13 @@ namespace Hurricane { template< typename Data, typename Compare > void RbTree::removeRepair ( typename RbTree::Node* rmNode, size_t depth ) { - cdebug_log(0,1) << "RbTree::removeRepair() rmNode:" << rmNode + cdebug_log(0,1) << "RbTree::removeRepair() rmNode:" << rmNode->getValue() << " depth:" << depth << std::endl; + + if (not rmNode) { + cdebug_tabw(0,-1); + return ; + } if (rmNode->isBlack()) { Node* parent = rmNode->getParent(); @@ -979,6 +997,7 @@ namespace Hurricane { void RbTreeToDot::write ( std::ostream& o ) const { o << "digraph RbTree {\n"; + o << " ratio=\"1.0\";\n"; toDot( o, tree_->getRoot() ); o << "}"; } @@ -989,8 +1008,9 @@ namespace Hurricane { { if (not node) return; + string svalue = ::getString( node->getValue() ); o << " id_" << getId(node) << " " - << "[label=\"id:" << getId(node) << "\\n" << ::getString(node->getValue()) + << "[label=\"id:" << getId(node) << "\\n" << split( svalue ) << "\"" << ",color=" << (node->isRed() ? "red" : "black") << ",fontcolor=" << (node->isRed() ? "red" : "black") @@ -1031,6 +1051,3 @@ namespace Hurricane { } // Hurricane namespace. - - -#endif // HURRICANE_RBTREE_H diff --git a/hurricane/src/hurricane/hurricane/Rectilinear.h b/hurricane/src/hurricane/hurricane/Rectilinear.h index 1df05c38..5f08876a 100644 --- a/hurricane/src/hurricane/hurricane/Rectilinear.h +++ b/hurricane/src/hurricane/hurricane/Rectilinear.h @@ -1,6 +1,6 @@ // -*- C++ -*- // -// Copyright (c) BULL S.A. 2018-2018, All Rights Reserved +// Copyright (c) BULL S.A. 2018-2023, All Rights Reserved // // This file is part of Hurricane. // @@ -28,10 +28,7 @@ // | C++ Header : "./hurricane/Rectilinear.h" | // +-----------------------------------------------------------------+ - -#ifndef HURRICANE_RECTILINEAR_H -#define HURRICANE_RECTILINEAR_H - +#pragma once #include "hurricane/Component.h" @@ -46,11 +43,13 @@ namespace Hurricane { class Rectilinear : public Component { public: typedef Component Super; + static const uint32_t IsRectilinear = (1<<0); public: static Rectilinear* create ( Net*, const Layer*, const vector& ); // Accessors. virtual bool isNonRectangle () const; + inline bool isRectilinear () const; virtual DbU::Unit getX () const; virtual DbU::Unit getY () const; virtual Box getBoundingBox () const; @@ -59,6 +58,7 @@ namespace Hurricane { virtual Point getPoint ( size_t i ) const; virtual const Layer* getLayer () const; inline Points getContour () const; + bool getAsRectangles ( std::vector& ) const; inline const vector& getPoints () const; // Mutators. void setLayer ( const Layer* ); @@ -75,11 +75,13 @@ namespace Hurricane { private: const Layer* _layer; vector _points; + uint32_t _flags; }; - inline Points Rectilinear::getContour () const { return new VectorCollection(_points); } - inline const vector& Rectilinear::getPoints () const { return _points; } + inline bool Rectilinear::isRectilinear () const { return _flags & IsRectilinear; } + inline Points Rectilinear::getContour () const { return new VectorCollection(_points); } + inline const vector& Rectilinear::getPoints () const { return _points; } // ------------------------------------------------------------------- @@ -99,5 +101,3 @@ namespace Hurricane { INSPECTOR_P_SUPPORT(Hurricane::Rectilinear); - -#endif // HURRICANE_RECTILINEAR_H diff --git a/hurricane/src/isobar/PyRectilinear.cpp b/hurricane/src/isobar/PyRectilinear.cpp index 0f837ff9..ca0e371b 100644 --- a/hurricane/src/isobar/PyRectilinear.cpp +++ b/hurricane/src/isobar/PyRectilinear.cpp @@ -45,6 +45,24 @@ namespace Isobar { } + PyObject* VectorToList ( const std::vector& v ) + { + PyObject* pyList = PyList_New( v.size() ); + + for ( size_t i=0 ; i_object = new Box ( v[i] ); + HCATCH + PyList_SetItem( pyList, i, (PyObject*)pyBox ); + } + + return pyList; + } + + extern "C" { @@ -168,20 +186,54 @@ extern "C" { } + static PyObject* PyRectilinear_getAsRectangles ( PyRectilinear *self, PyObject* args ) + { + cdebug_log(20,0) << "Rectilinear.getAsRectangles()" << endl; + + HTRY + METHOD_HEAD( "Rectilinear.getAsRectangles()" ) + + PyObject* pyList = NULL; + if (not PyArg_ParseTuple( args, "O:Rectilinear.getAsRectangles", &pyList )) { + PyErr_SetString( ConstructorError, "Rectilinear.getAsRectangles(): Must have exactly one parameter." ); + return NULL; + } + if (not PyList_Check(pyList)) { + PyErr_SetString( ConstructorError, "Rectilinear.getAsRectangles(): Argument must be a list." ); + return NULL; + } + + PyList_SetSlice( pyList, 0, PyList_Size(pyList), NULL ); + vector boxes; + rectilinear->getAsRectangles( boxes ); + for ( size_t i=0 ; i_object = new Box ( boxes[i] ); + PyList_Append( pyList, (PyObject*)pyBox ); + } + HCATCH + + Py_RETURN_NONE; + } + + // --------------------------------------------------------------- // PyRectilinear Attribute Method table. PyMethodDef PyRectilinear_Methods[] = - { { "create" , (PyCFunction)PyRectilinear_create , METH_VARARGS|METH_STATIC - , "Create a new Rectilinear polygon." } - , { "isNonRectangle", (PyCFunction)PyRectilinear_isNonRectangle, METH_NOARGS , "Tells if the shape is not a rectangle." } - , { "getX" , (PyCFunction)PyRectilinear_getX , METH_NOARGS , "Return the Rectilinear X value." } - , { "getY" , (PyCFunction)PyRectilinear_getY , METH_NOARGS , "Return the Rectilinear Y value." } - , { "getBoundingBox", (PyCFunction)PyRectilinear_getBoundingBox, METH_NOARGS , "Return the Rectilinear Bounding Box." } - , { "setPoints" , (PyCFunction)PyRectilinear_setPoints , METH_VARARGS, "Sets the Rectilinear Bounding Box." } - , { "translate" , (PyCFunction)PyRectilinear_translate , METH_VARARGS, "Translates the Rectilinear of dx and dy." } - , { "destroy" , (PyCFunction)PyRectilinear_destroy , METH_NOARGS - , "Destroy associated hurricane object, the python object remains." } + { { "create" , (PyCFunction)PyRectilinear_create , METH_VARARGS|METH_STATIC + , "Create a new Rectilinear polygon." } + , { "isNonRectangle" , (PyCFunction)PyRectilinear_isNonRectangle , METH_NOARGS , "Tells if the shape is not a rectangle." } + , { "getX" , (PyCFunction)PyRectilinear_getX , METH_NOARGS , "Return the Rectilinear X value." } + , { "getY" , (PyCFunction)PyRectilinear_getY , METH_NOARGS , "Return the Rectilinear Y value." } + , { "getBoundingBox" , (PyCFunction)PyRectilinear_getBoundingBox , METH_NOARGS , "Return the Rectilinear Bounding Box." } + , { "setPoints" , (PyCFunction)PyRectilinear_setPoints , METH_VARARGS, "Sets the Rectilinear Bounding Box." } + , { "translate" , (PyCFunction)PyRectilinear_translate , METH_VARARGS, "Translates the Rectilinear of dx and dy." } + , { "getAsRectangles", (PyCFunction)PyRectilinear_getAsRectangles, METH_VARARGS, "Return the rectangle coverage." } + , { "destroy" , (PyCFunction)PyRectilinear_destroy , METH_NOARGS + , "Destroy associated hurricane object, the python object remains." } , {NULL, NULL, 0, NULL} /* sentinel */ }; diff --git a/hurricane/src/isobar/hurricane/isobar/PyHurricane.h b/hurricane/src/isobar/hurricane/isobar/PyHurricane.h index ef985fe7..c1b65258 100644 --- a/hurricane/src/isobar/hurricane/isobar/PyHurricane.h +++ b/hurricane/src/isobar/hurricane/isobar/PyHurricane.h @@ -1625,31 +1625,31 @@ extern "C" { catch ( const Warning& w ) { \ std::string message = getString(w); \ PyErr_Warn ( HurricaneWarning, const_cast(message.c_str()) ); \ - std::cerr << message << std::endl; \ + std::cerr << message << std::endl; \ } \ catch ( const Error& e ) { \ std::string message = getString(e); \ if (not e.where().empty()) message += "\n" + e.where(); \ PyErr_SetString ( HurricaneError, message.c_str() ); \ - std::cerr << message << std::endl; \ + std::cerr << message << std::endl; \ return NULL; \ } \ catch ( const Bug& e ) { \ std::string message = getString(e); \ PyErr_SetString ( HurricaneError, message.c_str() ); \ - std::cerr << message << std::endl; \ + std::cerr << message << std::endl; \ return NULL; \ } \ catch ( const Exception& e ) { \ std::string message = "Unknown Hurricane::Exception"; \ PyErr_SetString ( HurricaneError, message.c_str() ); \ - std::cerr << message << std::endl; \ + std::cerr << message << std::endl; \ return NULL; \ } \ catch ( const std::exception& e ) { \ std::string message = std::string(e.what()); \ PyErr_SetString ( HurricaneError, message.c_str() ); \ - std::cerr << message << std::endl; \ + std::cerr << message << std::endl; \ return NULL; \ } \ catch ( ... ) { \ @@ -1657,7 +1657,7 @@ extern "C" { "Unmanaged exception, neither a Hurricane::Error nor" \ " a std::exception."; \ PyErr_SetString ( HurricaneError, message.c_str() ); \ - std::cerr << message << std::endl; \ + std::cerr << message << std::endl; \ return NULL; \ } \ diff --git a/hurricane/src/viewer/CellImage.cpp b/hurricane/src/viewer/CellImage.cpp index 07c0ecab..367adafa 100644 --- a/hurricane/src/viewer/CellImage.cpp +++ b/hurricane/src/viewer/CellImage.cpp @@ -157,8 +157,9 @@ namespace Hurricane { //int scale = 80 * Cfg::getParamEnumerate("viewer.printer.mode")->asInt(); int scale = (Graphics::isHighDpi()) ? 4 : 2; - _drawingWidth = _cellWidget->width () * scale; - _drawingHeight = _cellWidget->height() * scale; + _drawingWidth = _screenCellWidget->geometry().width () * scale; + _drawingHeight = _screenCellWidget->geometry().height() * scale; + _cellWidget->resize( _drawingWidth, _drawingHeight ); _image = new QImage( _drawingWidth , _drawingHeight + ((_flags&ShowScale) ? 60 : 0) @@ -188,7 +189,7 @@ namespace Hurricane { setFitOnAbutmentBox( true ); _cellWidget->fitToContents(); } else { - //_cellWidget->reframe( _screenCellWidget->getVisibleArea() ); + _cellWidget->reframe( _screenCellWidget->getVisibleArea() ); } cerr << " After resize CellWidget: " << _cellWidget->geometry().width() << "x" << _cellWidget->geometry().height() << endl; diff --git a/hurricane/src/viewer/CellViewer.cpp b/hurricane/src/viewer/CellViewer.cpp index 0ab78a19..9ab51b2f 100644 --- a/hurricane/src/viewer/CellViewer.cpp +++ b/hurricane/src/viewer/CellViewer.cpp @@ -584,7 +584,7 @@ namespace Hurricane { void CellViewer::refreshTitle () { - QString cellName = "None"; + QString cellName = "empty"; if ( getCell() ) cellName = getString(getCell()->getName()).c_str(); diff --git a/hurricane/src/viewer/CellWidget.cpp b/hurricane/src/viewer/CellWidget.cpp index 1540e8c6..8cd3c6f8 100644 --- a/hurricane/src/viewer/CellWidget.cpp +++ b/hurricane/src/viewer/CellWidget.cpp @@ -2683,7 +2683,86 @@ namespace Hurricane { } else selected = false; - if ( (--_delaySelectionChanged == 0) and selected ) emit selectionChanged( _selectors ); + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); + } + + + void CellWidget::selectSet ( const ComponentSet& components ) + { + if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) { + openRefreshSession(); + unselectAll(); + closeRefreshSession(); + } + + bool selected = true; + // SelectorCriterion* criterion = _state->getSelection().add ( selectArea ); + // if ( criterion and (not criterion->isEnabled()) ) { + // criterion->enable(); + + for ( Component* component : components ) { + if (component->getCell() == getCell()) { + select( Occurrence( component )); + } + } + // } else + // selected = false; + + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); + } + + + void CellWidget::selectSet ( const OccurrenceSet& occurrences ) + { + if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) { + openRefreshSession(); + unselectAll(); + closeRefreshSession(); + } + + bool selected = true; + // SelectorCriterion* criterion = _state->getSelection().add ( selectArea ); + // if ( criterion and (not criterion->isEnabled()) ) { + // criterion->enable(); + + for ( const Occurrence& occurrence : occurrences ) { + if (occurrence.getOwnerCell() == getCell()) { + select( occurrence ); + } + } + // } else + // selected = false; + + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); + } + + + void CellWidget::select ( Occurrences occurrences ) + { + if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) { + openRefreshSession(); + unselectAll(); + closeRefreshSession(); + } + + bool selected = true; + // SelectorCriterion* criterion = _state->getSelection().add ( selectArea ); + // if ( criterion and (not criterion->isEnabled()) ) { + // criterion->enable(); + + for ( const Occurrence& occurrence : occurrences ) { + if (occurrence.getOwnerCell() == getCell()) { + select( occurrence ); + } + } + // } else + // selected = false; + + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); } @@ -2744,7 +2823,7 @@ namespace Hurricane { if ( (--_delaySelectionChanged == 0) and selected ) { if ( _state->showSelection() ) _redrawManager.refresh (); - emit selectionChanged(_selectors); + emit selectionChanged(_selectors); } } @@ -2782,7 +2861,47 @@ namespace Hurricane { } _selectionHasChanged = true; - if ( (_delaySelectionChanged == 0) and unselected ) emit selectionChanged( _selectors ); + if ( (_delaySelectionChanged == 0) and unselected ) + emit selectionChanged( _selectors ); + } + + + void CellWidget::unselectSet ( const ComponentSet& components ) + { + ++_delaySelectionChanged; + for ( Component* component : components ) { + if (component->getCell() == getCell()) { + unselect( Occurrence( component )); + } + } + if ( --_delaySelectionChanged == 0 ) + emit selectionChanged( _selectors ); + } + + + void CellWidget::unselectSet ( const OccurrenceSet& occurrences ) + { + ++_delaySelectionChanged; + for ( const Occurrence& occurrence : occurrences ) { + if (occurrence.getOwnerCell() == getCell()) { + unselect( occurrence ); + } + } + if ( --_delaySelectionChanged == 0 ) + emit selectionChanged( _selectors ); + } + + + void CellWidget::unselect ( Occurrences occurrences ) + { + ++_delaySelectionChanged; + for ( const Occurrence& occurrence : occurrences ) { + if (occurrence.getOwnerCell() == getCell()) { + unselect( occurrence ); + } + } + if ( --_delaySelectionChanged == 0 ) + emit selectionChanged( _selectors ); } @@ -2793,7 +2912,8 @@ namespace Hurricane { _state->getSelection().clear (); _unselectAll (); - if ( --_delaySelectionChanged == 0 ) emit selectionChanged(_selectors); + if ( --_delaySelectionChanged == 0 ) + emit selectionChanged(_selectors); } diff --git a/hurricane/src/viewer/ControllerWidget.cpp b/hurricane/src/viewer/ControllerWidget.cpp index bdab568d..4b425f10 100644 --- a/hurricane/src/viewer/ControllerWidget.cpp +++ b/hurricane/src/viewer/ControllerWidget.cpp @@ -658,6 +658,19 @@ namespace Hurricane { } + void ControllerWidget::insertTabAfter ( const QString& ref, QWidget* tab, const QString& label ) + { + for ( int itab=0 ; true; ++itab ) { + QWidget* refTab = widget( itab ); + if (not refTab) break; + if (refTab->objectName() != ref) continue; + insertTab( itab, tab, label ); + return; + } + addTab( tab, label ); + } + + // ------------------------------------------------------------------- // Class : "ControllerWidget::GraphicsObserver". diff --git a/hurricane/src/viewer/NetInformations.cpp b/hurricane/src/viewer/NetInformations.cpp index 1064cd65..87dc620b 100644 --- a/hurricane/src/viewer/NetInformations.cpp +++ b/hurricane/src/viewer/NetInformations.cpp @@ -63,7 +63,7 @@ namespace Hurricane { int SimpleNetInformations::getColumnCount () - { return 3; } + { return 6; } QVariant SimpleNetInformations::getColumnName ( int column ) @@ -71,7 +71,10 @@ namespace Hurricane { switch ( column ) { case 0: return QVariant(QObject::tr("Net")); case 1: return QVariant(QObject::tr("Plugs")); - case 2: return QVariant(QObject::tr("RoutingPads")); + case 2: return QVariant(QObject::tr("RPs")); + case 3: return QVariant(QObject::tr("Flags")); + case 4: return QVariant(QObject::tr("Type")); + case 5: return QVariant(QObject::tr("Direction")); } return QVariant(QObject::tr("Column Out of Bound")); } @@ -84,11 +87,15 @@ namespace Hurricane { case 1: return (unsigned int)_plugsCount; case 2: if (_net->isGlobal()) { - if (not _rpsCount) return "N/A (global)"; - string s = getString(_rpsCount) + " (global)"; + if (not _rpsCount) return "N/A"; + string s = getString(_rpsCount); return s.c_str(); } return (unsigned int)_rpsCount; + case 3: return QString::fromStdString( getString( _net->_getFlagsAsString() )); + case 4: return QString::fromStdString( getString( _net->getType() )); + case 5: return QString::fromStdString( getString( _net->getDirection() )); + } return QVariant(QObject::tr("Column Out of Bound")); } diff --git a/hurricane/src/viewer/NetlistWidget.cpp b/hurricane/src/viewer/NetlistWidget.cpp index b0bc2994..8902993a 100644 --- a/hurricane/src/viewer/NetlistWidget.cpp +++ b/hurricane/src/viewer/NetlistWidget.cpp @@ -70,7 +70,7 @@ namespace Hurricane { QHeaderView* horizontalHeader = _view->horizontalHeader(); horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter ); - horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 300 : 150 ); + horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 150 : 75 ); horizontalHeader->setStretchLastSection( true ); QHeaderView* verticalHeader = _view->verticalHeader(); @@ -151,24 +151,18 @@ namespace Hurricane { _forceReselect = false; } - SelectedNetSet::iterator remove; - SelectedNetSet::iterator isel = _selecteds.begin (); + SelectedNetSet::iterator isel = _selecteds.begin (); while ( isel != _selecteds.end() ) { - switch ( isel->getAccesses() ) { - case 1: break; - case 64: - emit netSelected ( Occurrence(isel->getNet()) ); - break; - case 0: - emit netUnselected ( Occurrence(isel->getNet()) ); - remove = isel; - ++isel; - _selecteds.erase ( remove ); - continue; - default: - cerr << Bug("NetlistWidget::updateSelecteds(): invalid code %d" - ,isel->getAccesses()) << endl; + SelectedNetSet::iterator remove = isel++; + if ( remove->getAccesses() == 0 ) { + emit netUnselected ( Occurrence(remove->getNet()) ); + _selecteds.erase ( remove ); } + } + isel = _selecteds.begin (); + while ( isel != _selecteds.end() ) { + if ( isel->getAccesses() == 64 ) + emit netSelected ( Occurrence(isel->getNet()) ); ++isel; } diff --git a/hurricane/src/viewer/PyCellViewer.cpp b/hurricane/src/viewer/PyCellViewer.cpp index 5eff9c79..e5e62ed8 100644 --- a/hurricane/src/viewer/PyCellViewer.cpp +++ b/hurricane/src/viewer/PyCellViewer.cpp @@ -219,6 +219,7 @@ extern "C" { } cw->setApplicationName ( name ); + cw->refreshTitle (); HCATCH Py_RETURN_NONE; diff --git a/hurricane/src/viewer/SelectionModel.cpp b/hurricane/src/viewer/SelectionModel.cpp index cc5dafbe..91646922 100644 --- a/hurricane/src/viewer/SelectionModel.cpp +++ b/hurricane/src/viewer/SelectionModel.cpp @@ -91,8 +91,8 @@ namespace Hurricane { { if (not _cellWidget) return; + if (not isCumulative()) clear (); beginResetModel(); - if (not isCumulative()) _selection.clear (); for ( Selector* selector : selection ) { if (not selector->isInModel(_cellWidget)) { diff --git a/hurricane/src/viewer/hurricane/viewer/CellViewer.h b/hurricane/src/viewer/hurricane/viewer/CellViewer.h index 9e129d14..55946f90 100644 --- a/hurricane/src/viewer/hurricane/viewer/CellViewer.h +++ b/hurricane/src/viewer/hurricane/viewer/CellViewer.h @@ -87,6 +87,7 @@ namespace Hurricane { CellViewer ( QWidget* parent=NULL ); virtual ~CellViewer (); inline bool isToolInterrupted () const; + void refreshTitle (); QMenu* createDebugMenu (); bool hasMenu ( const QString& path ) const; bool hasMenuAction ( const QString& path ) const; @@ -166,7 +167,6 @@ namespace Hurricane { void cellPostModificated (); protected: void createMenus (); - void refreshTitle (); void refreshHistory (); void rebuildHistory (); private: diff --git a/hurricane/src/viewer/hurricane/viewer/CellWidget.h b/hurricane/src/viewer/hurricane/viewer/CellWidget.h index 60997001..3abd74f1 100644 --- a/hurricane/src/viewer/hurricane/viewer/CellWidget.h +++ b/hurricane/src/viewer/hurricane/viewer/CellWidget.h @@ -265,10 +265,16 @@ namespace Hurricane { inline DrawingPlanes& getDrawingPlanes (); // void select ( const Net* ); void select ( Occurrence ); + void select ( Occurrences ); + void selectSet ( const OccurrenceSet& ); + void selectSet ( const ComponentSet& ); bool isSelected ( Occurrence ); void selectOccurrencesUnder ( Box selectArea ); // void unselect ( const Net* ); void unselect ( Occurrence ); + void unselect ( Occurrences ); + void unselectSet ( const ComponentSet& ); + void unselectSet ( const OccurrenceSet& ); void unselectAll (); void toggleSelection ( Occurrence ); void setShowSelection ( bool state ); diff --git a/hurricane/src/viewer/hurricane/viewer/ControllerWidget.h b/hurricane/src/viewer/hurricane/viewer/ControllerWidget.h index e3811f06..a74f2713 100644 --- a/hurricane/src/viewer/hurricane/viewer/ControllerWidget.h +++ b/hurricane/src/viewer/hurricane/viewer/ControllerWidget.h @@ -312,6 +312,7 @@ namespace Hurricane { inline TabSettings* getSettings (); void setCellWidget ( CellWidget* ); //inline int addSetting ( QWidget* page, const QString& label ); + void insertTabAfter ( const QString& ref, QWidget*, const QString& label ); public slots: void graphicsUpdated (); void cellPreModificate (); diff --git a/tramontana/CMakeLists.txt b/tramontana/CMakeLists.txt new file mode 100644 index 00000000..6af613ef --- /dev/null +++ b/tramontana/CMakeLists.txt @@ -0,0 +1,29 @@ +# -*- explicit-buffer-name: "CMakeLists.txt" -*- + + set(CMAKE_LEGACY_CYGWIN_WIN32 0) + project(TRAMONTANA) + + set(ignoreVariables "${BUILD_DOC} ${CMAKE_INSTALL_DIR}") + + option(BUILD_DOC "Build the documentation (doxygen)" OFF) + option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF) + + cmake_minimum_required(VERSION 3.16) + + list(INSERT CMAKE_MODULE_PATH 0 "${DESTDIR}$ENV{CORIOLIS_TOP}/share/cmake/Modules/") + find_package(Bootstrap REQUIRED) + setup_project_paths(CORIOLIS) + + set_cmake_policies() + setup_boost() + setup_qt() + + find_package(Python 3 REQUIRED COMPONENTS Interpreter Development) + find_package(PythonSitePackages REQUIRED) + find_package(HURRICANE REQUIRED) + find_package(CORIOLIS REQUIRED) + find_package(Doxygen) + + add_subdirectory(src) +#add_subdirectory(cmake_modules) +#add_subdirectory(doc) diff --git a/tramontana/src/CMakeLists.txt b/tramontana/src/CMakeLists.txt new file mode 100644 index 00000000..c0c81af1 --- /dev/null +++ b/tramontana/src/CMakeLists.txt @@ -0,0 +1,78 @@ +# -*- explicit-buffer-name: "CMakeLists.txt" -*- + +# include( ${QT_USE_FILE} ) + include_directories( ${TRAMONTANA_SOURCE_DIR}/src + ${CORIOLIS_INCLUDE_DIR} + ${HURRICANE_INCLUDE_DIR} + ${CONFIGURATION_INCLUDE_DIR} + ${QtX_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${Python_INCLUDE_DIRS} + ) + set( includes tramontana/Tile.h + tramontana/QueryTiles.h + tramontana/SweepLine.h + tramontana/Equipotential.h + tramontana/EquipotentialRelation.h + tramontana/EquipotentialComponents.h + tramontana/TramontanaEngine.h + tramontana/GraphicTramontanaEngine.h + ) + set( pyIncludes tramontana/PyTramontanaEngine.h + tramontana/PyGraphicTramontanaEngine.h + ) + set( mocIncludes tramontana/GraphicTramontanaEngine.h + tramontana/EquipotentialsModel.h + tramontana/EquipotentialsWidget.h + tramontana/TabEquipotentials.h + ) + set( cpps Tile.cpp + QueryTiles.cpp + SweepLine.cpp + Equipotential.cpp + EquipotentialRelation.cpp + EquipotentialComponents.cpp + TramontanaEngine.cpp + GraphicTramontanaEngine.cpp + EquipotentialsModel.cpp + EquipotentialsWidget.cpp + TabEquipotentials.cpp + ) + set( pyCpps PyTramontana.cpp + PyTramontanaEngine.cpp + PyGraphicTramontanaEngine.cpp + ) + qtX_wrap_cpp( mocCpps ${mocIncludes} ) + + set( depLibs ${CORIOLIS_PYTHON_LIBRARIES} + ${CORIOLIS_LIBRARIES} + ${HURRICANE_PYTHON_LIBRARIES} + ${HURRICANE_GRAPHICAL_LIBRARIES} + ${HURRICANE_LIBRARIES} + ${CONFIGURATION_LIBRARY} + ${UTILITIES_LIBRARY} + ${LEFDEF_LIBRARIES} + ${QtX_LIBRARIES} + ${Boost_LIBRARIES} + ${Python3_LIBRARIES} + -lutil + ${LIBEXECINFO_LIBRARIES} + ) + + add_library( tramontana ${cpps} ${mocCpps} ${pyCpps} ) + set_target_properties( tramontana PROPERTIES VERSION 1.0 SOVERSION 1 ) + target_link_libraries( tramontana ${depLibs} ) + + add_python_module( "${pyCpps}" + "${pyIncludes}" + "Do_not_generate_C_library" + Tramontana + "tramontana;${depLibs}" + include/coriolis2/tramontana + ) + + install( TARGETS tramontana DESTINATION lib${LIB_SUFFIX} ) + install( FILES ${includes} + ${mocIncludes} DESTINATION include/coriolis2/tramontana ) + + diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp new file mode 100644 index 00000000..e4a25b02 --- /dev/null +++ b/tramontana/src/Equipotential.cpp @@ -0,0 +1,533 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./Equipotential.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include "hurricane/utilities/Path.h" +#include "hurricane/DebugSession.h" +#include "hurricane/UpdateSession.h" +#include "hurricane/Bug.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/Breakpoint.h" +#include "hurricane/Timer.h" +#include "hurricane/Layer.h" +#include "hurricane/Net.h" +#include "hurricane/Pad.h" +#include "hurricane/Contact.h" +#include "hurricane/Plug.h" +#include "hurricane/Cell.h" +#include "hurricane/Instance.h" +#include "hurricane/Vertical.h" +#include "hurricane/Horizontal.h" +#include "hurricane/RoutingPad.h" +#include "crlcore/Utilities.h" +#include "tramontana/Equipotential.h" +#include "tramontana/EquipotentialRelation.h" +#include "tramontana/EquipotentialComponents.h" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + + using std::cout; + using std::cerr; + using std::endl; + using std::dec; + using std::setw; + using std::setfill; + using std::left; + using std::string; + using std::ostream; + using std::ofstream; + using std::ostringstream; + using std::setprecision; + using std::vector; + using std::set; + using std::make_pair; + using Hurricane::dbo_ptr; + using Hurricane::UpdateSession; + using Hurricane::DebugSession; + using Hurricane::tab; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Breakpoint; + using Hurricane::Box; + using Hurricane::Layer; + using Hurricane::Entity; + using Hurricane::Net; + using Hurricane::Plug; + using Hurricane::Contact; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::RoutingPad; + using Hurricane::Cell; + using Hurricane::Instance; + using Hurricane::Path; + + + bool NetCompareByName::operator() ( const Net* lhs, const Net* rhs ) const + { + if (lhs->isFused () != rhs->isFused ()) return rhs->isFused(); + if (lhs->isAutomatic() != rhs->isAutomatic()) return rhs->isAutomatic(); + if (lhs->isGlobal () != rhs->isGlobal ()) return rhs->isGlobal(); + + if (lhs->getName().size() != rhs->getName().size()) + return lhs->getName().size() < rhs->getName().size(); + return lhs->getName() < rhs->getName(); + } + + + bool OccNetCompareByName::operator() ( const Occurrence& lhs, const Occurrence& rhs ) const + { + static NetCompareByName compareByName; + + size_t lhsLength = lhs.getPath().getInstances().getSize(); + size_t rhsLength = rhs.getPath().getInstances().getSize(); + + if (lhsLength != rhsLength) return lhsLength < rhsLength; + return compareByName( static_cast(lhs.getEntity()), static_cast(rhs.getEntity()) ); + } + + +// ------------------------------------------------------------------- +// Class : "Tramontana::Equipotential". + + + Equipotential* Equipotential::get ( Component* component ) + { + EquipotentialRelation* relation = dynamic_cast( + component->getNet()->getProperty( EquipotentialRelation::staticGetName() )); + if (not relation) { + relation = dynamic_cast( + component->getProperty( EquipotentialRelation::staticGetName() )); + } + if (not relation) return nullptr; + return dynamic_cast( relation->getMasterOwner() ); + } + + + Equipotential* Equipotential::get ( Occurrence occurrence ) + { + EquipotentialRelation* relation = dynamic_cast( + occurrence.getProperty( EquipotentialRelation::staticGetName() )); + if (not relation) return nullptr; + return dynamic_cast( relation->getMasterOwner() ); + } + + + Occurrence Equipotential::getChildEqui ( Occurrence flatOccurrence ) + { + Component* component = dynamic_cast( flatOccurrence.getEntity() ); + if (not component) { + cerr << Error( "Equipotential::getChildEqui(): Occurrence must be over a Component.\n" + " (on:%s)" + , getString(flatOccurrence).c_str() + ) << endl; + return Occurrence(); + } + + Equipotential* equi = Equipotential::get( component ); + if (not equi) { + cerr << Error( "Equipotential::getChildEqui(): Component not associated to an Equipotential.\n" + " (on:%s)" + , getString(flatOccurrence).c_str() + ) << endl; + return Occurrence(); + } + + if (flatOccurrence.getPath().isEmpty()) return flatOccurrence; + + // cerr << "childEqui:" << flatOccurrence << endl; + // cerr << " " << equi << endl; + Instance* tailInst = flatOccurrence.getPath().getTailInstance(); + Path headPath = flatOccurrence.getPath().getHeadPath(); + Occurrence tailOccurrence; + while ( tailInst ) { + tailOccurrence = Occurrence( equi, tailInst ); + equi = Equipotential::get( tailOccurrence ); + tailInst = headPath.getTailInstance(); + headPath = headPath.getHeadPath(); + } + + // cerr << " ==> " << tailOccurrence << endl; + // cerr << " " << equi << endl; + return tailOccurrence; + } + + + Equipotential::Equipotential ( Cell* owner ) + : _owner (owner) + , _boundingBox () + , _components () + , _childs () + , _name () + , _type (Net::Type::UNDEFINED) + , _direction (Net::Direction::DirUndefined) + , _netCount (0) + , _isBuried (false) + , _isExternal (false) + , _isGlobal (false) + , _isAutomatic (false) + , _hasFused (false) + , _shortCircuits() + { + _name = "Unnamed_" + getString( getId() ); + } + + + void Equipotential::_postCreate () + { + Super::_postCreate(); + TramontanaEngine* tramontana = TramontanaEngine::get( _owner ); + tramontana->add( this ); + } + + + Equipotential* Equipotential::create ( Cell* owner ) + { + Equipotential* equi = new Equipotential ( owner ); + equi->_postCreate(); + return equi; + } + + + void Equipotential::_preDestroy () + { + Super::_preDestroy(); + } + + + Equipotential::~Equipotential () + { + for ( ShortCircuit* shortCircuit : _shortCircuits ) delete shortCircuit; + } + + + Cell* Equipotential::getCell () const + { return _owner; } + + + Box Equipotential::getBoundingBox () const + { return _boundingBox; } + + + Occurrences Equipotential::getFlatComponents () const + { return EquipotentialComponents( this ); } + + + void Equipotential::add ( Occurrence occ, const Box& boundingBox ) + { + if(occ.getPath().isEmpty()) { + Contact* contact = dynamic_cast( occ.getEntity() ); + if ((_components.find(occ) != _components.end())) { + if (not contact) + cdebug_log(160,0) << "Equipotential::add(): Duplicated " << occ.getCompactString() << endl; + return; + } + Component* comp = dynamic_cast( occ.getEntity() ); + if (not comp) { + cerr << Error( "Equipotential::add(): Occurrences with null Path must be Components.\n" + " (on:%s)" + , getString(occ).c_str() + ) << endl; + return; + } + cdebug_log(160,0) << "Equipotential::add(): " << occ << endl; + _components.insert( occ ); + NetMap::iterator inet = _nets.find( comp->getNet() ); + if (inet != _nets.end()) { + inet->second.first++; + if (inet->second.first > inet->second.second) { + cerr << Error( "Equipotential::add(): Doubly counted component of %s.\n" + " (on:%s)" + , getString(inet->first).c_str() + , getString(occ).c_str() + ) << endl; + } + return; + } + uint32_t compCount = 0; + for ( Component* component : comp->getNet()->getComponents() ) { + if (dynamic_cast(component)) continue; + ++compCount; + } + _nets.insert( make_pair( comp->getNet(), make_pair(1,compCount) )); + if (comp->getNet()->isFused()) { + _hasFused = true; + return; + } + if (_nets.size() <= 1 + ((_hasFused) ? 1 : 0)) + return; + Net* netA = nullptr; + for ( auto item : _nets ) { + if (not item.first->isFused() and (item.first != comp->getNet())) { + netA = item.first; + break; + } + } + _shortCircuits.push_back( new ShortCircuit( netA, comp->getNet(), comp )); + } else { + Equipotential* equi = dynamic_cast( occ.getEntity() ); + if (not equi) { + cerr << Error( "Equipotential::add(): Occurrence is not an Equipotential.\n" + " (on:%s)" + , getString(occ).c_str() + ) << endl; + return; + } + if (not occ.getPath().getTailPath().isEmpty()) { + cerr << Error( "Equipotential::add(): Occurrence is more than one instances deep.\n" + " (on:%s)" + , getString(occ).c_str() + ) << endl; + return; + } + _childs.insert( occ ); + } + _boundingBox.merge( boundingBox ); + } + + void Equipotential::merge ( Equipotential* other ) + { + if (this == other) { + cerr << Warning( "Equipotential::merge(): Attempt to merge itself (ignored).\n" + " (on: %s)" + , getString(this).c_str() + ) << endl; + return; + } + + for ( auto otherNetData : other->_nets ) { + NetMap::iterator inet = _nets.find( otherNetData.first ); + if (inet != _nets.end()) { + //inet->second.first += otherNetData.second.first; + continue; + } + + if (otherNetData.first->isFused()) _hasFused = true; + _nets.insert( make_pair( otherNetData.first, make_pair(0,otherNetData.second.second) )); + + if (_nets.size() > 1 + ((_hasFused) ? 1 : 0)) { + cdebug_log(169,0) << "Short by merging equis." << _nets.size() << endl; + for ( auto inet : _nets ) { + cdebug_log(169,0) << "this | " << inet.first << endl; + } + for ( auto inet : other->_nets ) { + cdebug_log(169,0) << "other | " << inet.first << endl; + } + } + } + + //cerr << "Equipotential::merge() " << this << endl; + //cerr << " " << other << endl; + for ( const Occurrence& component : other->getComponents () ) add( component ); + for ( const Occurrence& child : other->getChilds () ) add( child ); + for ( ShortCircuit* shortCircuit : other->getShortCircuits () ) add( shortCircuit ); + _boundingBox.merge( other->_boundingBox ); + //cerr << "Equipotential::merge() done" << endl; + other->clear(); + } + + + void Equipotential::consolidate () + { + EquipotentialRelation* relation = EquipotentialRelation::create( this ); + + + for ( const Occurrence& occurrence : getComponents() ) { + Component* component = dynamic_cast( occurrence.getEntity() ); + if (not component) continue; + if (not occurrence.getPath().isEmpty()) { + //cerr << "Occurrence from a DeepNet " << occurrence << endl; + continue; + } + component->put( relation ); + } + + if (not _nets.empty()) { + _name = getString( (*_nets.begin()).first->getName() ); + } + + for ( auto netData : _nets ) { + Net* net = netData.first; + if (net->isFused()) continue; + if (net->isExternal ()) _isExternal = true; + if (net->isGlobal ()) _isGlobal = true; + if (net->isAutomatic()) _isAutomatic = true; + _type = net->getType(); + _direction |= net->getDirection(); + + if (netData.second.first >= netData.second.second) { + for ( Component* component : net->getComponents() ) { + if (dynamic_cast(component)) continue; + component->remove( relation ); + } + net->put( relation ); + } + cdebug_log(169,0) << netData.first << " [" << netData.second.first + << " / " << netData.second.second << "]" << endl; + } + + for ( Occurrence childEqui : _childs ) { + childEqui.put( relation ); + } + if (_components.empty() and _nets.empty()) _isBuried = true; + +#if FIRST_IMPLEMENTATION + EquipotentialRelation* relation = EquipotentialRelation::create( this ); + map nets; + set deepNets; + for ( const Occurrence& occurrence : getComponents() ) { + Component* component = dynamic_cast( occurrence.getEntity() ); + if (not component) continue; + if (not occurrence.getPath().isEmpty()) { + deepNets.insert( Occurrence( component->getNet(), occurrence.getPath() )); + continue; + } + component->put( relation ); + Net* net = component->getNet(); + 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(); + } + uint32_t accounted = (dynamic_cast(component)) ? 0 : 1; + auto inet = nets.find( component->getNet() ); + if (inet != nets.end()) + inet->second += accounted; + else + nets.insert( make_pair( component->getNet(), accounted ) ); + } + if (not nets.empty()) { + _name = getString( (*nets.begin()).first->getName() ); + } else { + if (not deepNets.empty()) { + _name = (*deepNets.begin()).getCompactString(); + } + } + _netCount = nets.size(); + + for ( auto item : nets ) { + Net* net = item.first; + uint32_t count = 0; + for ( Component* component : net->getComponents() ) { + count += (dynamic_cast(component)) ? 0 : 1; + } + if (count > item.second) continue; + if (count < item.second) { + cerr << Error( "Equipotential::consolidate(): On %s, found more components of %s than existing (%d > %d)." + , getString(this).c_str() + , getString(net).c_str() + , item.second + , count ) << endl; + } + for ( Component* component : net->getComponents() ) { + if (dynamic_cast(component)) continue; + component->remove( relation ); + } + net->put( relation ); + //_nets.insert( net ); + } + for ( Occurrence childEqui : _childs ) { + childEqui.put( relation ); + } + if (_components.empty() and _nets.empty()) _isBuried = true; + + // if (_name == "abc_11873_auto_rtlil_cc_2560_muxgate_11612") + // show(); +#endif + } + + + void Equipotential::clear () + { + _components .clear(); + _childs .clear(); + _nets .clear(); + _shortCircuits.clear(); + } + + + void Equipotential::show () const + { + cerr << this << endl; + cerr << "+ Components:" << endl; + for ( const Occurrence& component : _components ) { + cerr << "| " << component << endl; + } + cerr << "+ Occurrences:" << endl; + for ( Occurrence occ : _childs ) { + cerr << "| " << occ << endl; + } + } + + + string Equipotential::getFlagsAsString () const + { + string sflags; + sflags += ((_isExternal ) ? "e" : "-"); + sflags += ((_isGlobal ) ? "g" : "-"); + sflags += ((_isAutomatic) ? "a" : "-"); + sflags += ((_isBuried ) ? "B" : "-"); + sflags += " [N:" + getString( _nets.size() - ((_hasFused) ? 1 : 0) ); + sflags += "+E:" + getString( _childs.size() ); + if (_hasFused) + sflags += "+fused"; + sflags += "] "; + return sflags; + } + + + string Equipotential::_getTypeName () const + { return "Tramontana::Equipotential"; } + + + string Equipotential::_getString () const + { + ostringstream os; + os << ""; + return os.str(); + } + + + Record* Equipotential::_getRecord () const + { + Record* record = Super::_getRecord(); + if (record) { + record->add( getSlot( "_name" , &_name ) ); + record->add( getSlot( "_boundingBox", &_boundingBox ) ); + //record->add( getSlot( "_nets" , &_nets ) ); + record->add( getSlot( "_components" , &_components ) ); + record->add( getSlot( "_childs" , &_childs ) ); + } + return record; + } + + +} // Tramontana namespace. diff --git a/tramontana/src/EquipotentialComponents.cpp b/tramontana/src/EquipotentialComponents.cpp new file mode 100644 index 00000000..2b5fb566 --- /dev/null +++ b/tramontana/src/EquipotentialComponents.cpp @@ -0,0 +1,245 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./EquipotentialComponents.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/Error.h" +#include "tramontana/EquipotentialComponents.h" +#include "tramontana/Equipotential.h" + + +namespace Tramontana { + + using namespace std; + using Hurricane::tab; + using Hurricane::Error; + using Hurricane::Path; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::EquipotentialComponents". + + EquipotentialComponents::EquipotentialComponents () + : Super() + , _equipotential(nullptr) + { } + + + EquipotentialComponents::EquipotentialComponents ( const Equipotential* equi ) + : Super() + , _equipotential(equi) + { } + + + EquipotentialComponents::EquipotentialComponents ( const EquipotentialComponents& other ) + : Super() + , _equipotential(other._equipotential) + { } + + + EquipotentialComponents& EquipotentialComponents::operator= ( const EquipotentialComponents& other ) + { + _equipotential = other._equipotential; + return *this; + } + + + Collection* EquipotentialComponents::getClone () const + { return new EquipotentialComponents( *this ); } + + + Locator* EquipotentialComponents::getLocator () const + { return new Locator ( _equipotential ); } + + + string EquipotentialComponents::_getString () const + { + string s = "getComponents().end()) + , _netsIterator (equi->getNets().end()) + , _childsIterator (equi->getChilds().end()) + , _childCompsLocator (nullptr) + , _componentsLocator (nullptr) + { + progress(); + } + + + EquipotentialComponents::Locator::Locator ( const Locator& other ) + : Super() + , _equipotential (other._equipotential) + , _state (other._state) + , _componentsIterator(other._componentsIterator) + , _netsIterator (other._netsIterator) + , _childsIterator (other._childsIterator) + , _childCompsLocator (nullptr) + , _componentsLocator (nullptr) + { + if (other._childCompsLocator) _childCompsLocator = other._childCompsLocator->getClone(); + if (other._componentsLocator) _componentsLocator = other._componentsLocator->getClone(); + } + + + EquipotentialComponents::Locator& EquipotentialComponents::Locator::operator= ( const Locator& other ) + { + _equipotential = other._equipotential; + _state = other._state; + _componentsIterator= other._componentsIterator; + _netsIterator = other._netsIterator; + _childsIterator = other._childsIterator; + _componentsLocator = (other._componentsLocator) ? other._componentsLocator->getClone() : nullptr; + _childCompsLocator = (other._childCompsLocator) ? other._childCompsLocator->getClone() : nullptr; + return *this; + } + + + Occurrence EquipotentialComponents::Locator::getElement () const + { + if (not _equipotential or (_state >= Finished)) return Occurrence(); + switch ( _state ) { + case InComponents: return (*_componentsIterator); + case InNets: return Occurrence( _componentsLocator->getElement() ); + case InChildEquis: { + Path compPath = (*_childsIterator).getPath(); + Path tailPath = _childCompsLocator->getElement().getPath(); + while ( not tailPath.isEmpty() ) { + compPath = Path( compPath, tailPath.getHeadInstance() ); + tailPath = tailPath.getTailPath(); + } + return Occurrence( _childCompsLocator->getElement().getEntity(), compPath ); + } + default: + break; + } + return Occurrence(); + } + + + Locator* EquipotentialComponents::Locator::getClone () const + { return new Locator( *this ); } + + + bool EquipotentialComponents::Locator::isValid () const + { return (_equipotential) and (_state < Finished); } + + + void EquipotentialComponents::Locator::progress () + { + while ( isValid() ) { + switch ( _state ) { + case Constructed: { + _state = InComponents; + _componentsIterator = _equipotential->getComponents().begin(); + if (_componentsIterator != _equipotential->getComponents().end()) return; + } + case InComponents: { + if (_componentsIterator != _equipotential->getComponents().end()) { + ++_componentsIterator; + if (_componentsIterator != _equipotential->getComponents().end()) return; + } + _state = InNets; + _netsIterator = _equipotential->getNets().begin(); + } + case InNets: { + if (_netsIterator != _equipotential->getNets().end()) { + if ( not _netsIterator->first->isFused() + and _netsIterator->first->getProperty(EquipotentialRelation::staticGetName())) { + if (not _componentsLocator) { + _componentsLocator = _netsIterator->first->getComponents().getLocator()->getClone(); + if (_componentsLocator->isValid()) return; + } else { + _componentsLocator->progress(); + if (_componentsLocator->isValid()) return; + } + } + + _componentsLocator = nullptr; + ++_netsIterator; + if (_netsIterator != _equipotential->getNets().end()) + continue; + } + _state = InChildEquis; + _childsIterator = _equipotential->getChilds().begin(); + } + case InChildEquis: { + if (_childsIterator != _equipotential->getChilds().end()) { + if (not _childCompsLocator) { + Equipotential* child = dynamic_cast( (*_childsIterator).getEntity() ); + _childCompsLocator = child->getFlatComponents().getLocator()->getClone(); + if (_childCompsLocator->isValid()) return; + } else { + _childCompsLocator->progress(); + if (_childCompsLocator->isValid()) return; + } + + _childCompsLocator = nullptr; + ++_childsIterator; + if (_childsIterator != _equipotential->getChilds().end()) + continue; + } + _state = Finished; + } + case Finished: + break; + } + } + } + + + string EquipotentialComponents::Locator::_getString () const + { + string s = "_postCreate(); + return relation; + } + + + void EquipotentialRelation::_preDestroy () + { Super::_preDestroy(); } + + + Name EquipotentialRelation::staticGetName () + { return EquipotentialRelationName; } + + + Name EquipotentialRelation::getName () const + { return EquipotentialRelationName; } + + + string EquipotentialRelation::_getTypeName () const + { return "EquipotentialRelation"; } + + + Record* EquipotentialRelation::_getRecord () const + { + Record* record = Super::_getRecord(); + return record; + } + + + EquipotentialRelation* EquipotentialRelation::get ( const Component* component ) + { + if (not component) return nullptr; + + Property* property = component->getProperty( EquipotentialRelationName ); + if (not property) return nullptr; + + EquipotentialRelation* relation = dynamic_cast( property ); + if (not relation) return nullptr; + return relation; + } + + + +} // Tramontana namespace. + diff --git a/tramontana/src/EquipotentialsModel.cpp b/tramontana/src/EquipotentialsModel.cpp new file mode 100644 index 00000000..6f83171e --- /dev/null +++ b/tramontana/src/EquipotentialsModel.cpp @@ -0,0 +1,122 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./EquipotentialsModel.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Name.h" +#include "hurricane/Net.h" +#include "hurricane/Cell.h" +#include "hurricane/viewer/Graphics.h" +#include "tramontana/EquipotentialsModel.h" + + +namespace Tramontana { + + using Hurricane::Graphics; + + + EquipotentialsModel::EquipotentialsModel ( QObject* parent ) + : QAbstractTableModel(parent) + , _cell (nullptr) + , _equipotentials () + { } + + + QVariant EquipotentialsModel::data ( const QModelIndex& index, int role ) const + { + static QFont nameFont = Graphics::getFixedFont ( QFont::Bold ); + static QFont valueFont = Graphics::getFixedFont ( QFont::Normal, true ); + + if (role == Qt::FontRole) { + switch (index.column()) { + case 0: return nameFont; + default: return valueFont; + } + return QVariant(); + } + + if (not index.isValid()) return QVariant (); + + if (role == Qt::DisplayRole) { + 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(); + } + + + QVariant EquipotentialsModel::headerData ( int section + , Qt::Orientation orientation + , int role ) const + { + if (orientation == Qt::Vertical) return QVariant(); + + static QFont headerFont = Graphics::getFixedFont( QFont::Bold, false, false, +0 ); + + if (role == Qt::FontRole ) return headerFont; + if (role != Qt::DisplayRole) return QVariant(); + 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(); } + + + int EquipotentialsModel::columnCount ( const QModelIndex& parent ) const + { return 4; } + + + const Equipotential* EquipotentialsModel::getEqui ( int row ) + { + if (row >= (int)_equipotentials.size()) return nullptr; + return _equipotentials[ row ]; + } + + + void EquipotentialsModel::setCell ( Cell* cell ) + { + if (_cell != cell) { + emit layoutAboutToBeChanged (); + + if (_cell) _equipotentials.clear(); + _cell = cell; + + if (_cell) { + TramontanaEngine* tramontana = TramontanaEngine::get( _cell ); + if (tramontana) { + for ( Equipotential* equi : tramontana->getEquipotentials() ) + _equipotentials.push_back( equi ); + } + } + + emit layoutChanged (); + } + } + + +} // Tramontana namespace. diff --git a/tramontana/src/EquipotentialsWidget.cpp b/tramontana/src/EquipotentialsWidget.cpp new file mode 100644 index 00000000..216b472f --- /dev/null +++ b/tramontana/src/EquipotentialsWidget.cpp @@ -0,0 +1,269 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./EquipotentialsWidget.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hurricane/Commons.h" +#include "hurricane/viewer/Graphics.h" +#include "tramontana/EquipotentialsModel.h" +#include "tramontana/EquipotentialsWidget.h" + + +namespace Tramontana { + + using std::cerr; + using std::endl; + using Hurricane::Bug; + using Hurricane::Graphics; + + +// ------------------------------------------------------------------- +// Class : "BuriedFilterProxymodel". + + + EquiFilterProxyModel::EquiFilterProxyModel ( QObject* parent ) + : Super (parent) + , _filter(NoFilter) + { } + + + void EquiFilterProxyModel::setFilter ( uint32_t filter ) + { _filter = filter; invalidateFilter(); } + + + bool EquiFilterProxyModel::filterAcceptsRow ( int row, const QModelIndex& index ) const + { + EquipotentialsModel* model = dynamic_cast( sourceModel() ); + if (not model) return true; + + const Equipotential* equi = model->getEqui( row ); + if (not (_filter & ShowBuried) and equi->isBuried()) return false; + return true; + } + + +// ------------------------------------------------------------------- +// Class : "EquipotentialsWidget". + + + EquipotentialsWidget::EquipotentialsWidget ( QWidget* parent ) + : QWidget (parent) + , _cellWidget (NULL) + , _cell (NULL) + , _baseModel (new EquipotentialsModel(this)) + , _sortModel (new QSortFilterProxyModel(this)) + , _filterModel (new EquiFilterProxyModel(this)) + , _view (new QTableView(this)) + , _rowHeight (20) + , _selecteds () + , _forceReselect(false) + { + setAttribute( Qt::WA_DeleteOnClose ); + setAttribute( Qt::WA_QuitOnClose, false ); + setContextMenuPolicy( Qt::ActionsContextMenu ); + + _rowHeight = QFontMetrics( Graphics::getFixedFont() ).height() + 4; + + _filterModel->setSourceModel ( _baseModel ); + //_filterModel->setFilter ( EquiFilterProxyModel::ShowBuried ); + _sortModel->setSourceModel ( _filterModel ); + _sortModel->setDynamicSortFilter( true ); + _sortModel->setFilterKeyColumn ( 0 ); + + _view->setShowGrid ( false ); + _view->setAlternatingRowColors( true ); + _view->setSelectionBehavior ( QAbstractItemView::SelectRows ); + _view->setSortingEnabled ( true ); + _view->setModel ( _sortModel ); + + QHeaderView* horizontalHeader = _view->horizontalHeader(); + horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter ); + horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 150 : 75 ); + horizontalHeader->setStretchLastSection( true ); + + QHeaderView* verticalHeader = _view->verticalHeader(); + verticalHeader->setVisible( false ); + verticalHeader->setDefaultSectionSize( _rowHeight ); + + // verticalHeader->setStyleSheet( "QHeaderView::section {" + // "padding-bottom: 0px;" + // "padding-top: 0px;" + // "padding-left: 0px;" + // "padding-right: 1px;" + // "margin: 0px;" + // "}" + // ); + + _filterPatternLineEdit = new QLineEdit( this ); + QLabel* filterPatternLabel = new QLabel( tr("&Filter pattern:"), this ); + filterPatternLabel->setBuddy( _filterPatternLineEdit ); + + QGridLayout* gLayout = new QGridLayout(); + gLayout->addWidget( _view , 1, 0, 1, 2 ); + gLayout->addWidget( filterPatternLabel , 2, 0 ); + gLayout->addWidget( _filterPatternLineEdit, 2, 1 ); + + setLayout( gLayout ); + + QAction* fitAction = new QAction( tr("&Fit to Equi"), this ); + fitAction->setShortcut ( QKeySequence(tr("CTRL+F")) ); + fitAction->setStatusTip( tr("Fit the view to the Equipotentials's bounding box") ); + addAction( fitAction ); + + connect( _filterPatternLineEdit , SIGNAL(textChanged(const QString &)) + , this , SLOT (textFilterChanged()) ); + connect( _view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)) + , this , SLOT (updateSelecteds (const QItemSelection&,const QItemSelection&)) ); + connect( fitAction, SIGNAL(triggered()), this, SLOT(fitToEqui()) ); + + resize( 300, 300 ); + } + + + QModelIndex EquipotentialsWidget::mapToSource ( QModelIndex viewIndex ) const + { return _filterModel->mapToSource( _sortModel->mapToSource( viewIndex )); } + + + void EquipotentialsWidget::setShowBuried ( bool state ) + { + _filterModel->setFilter( (state) ? EquiFilterProxyModel::ShowBuried + : EquiFilterProxyModel::NoFilter ); + } + + + void EquipotentialsWidget::goTo ( int delta ) + { + if ( delta == 0 ) return; + + QModelIndex newIndex = _sortModel->index( _view->currentIndex().row()+delta, 0, QModelIndex() ); + if (newIndex.isValid()) + _view->selectRow( newIndex.row() ); + } + + + void EquipotentialsWidget::updateSelecteds () + { + _forceReselect = true; + + QItemSelection dummy; + updateSelecteds( dummy, dummy ); + } + + + void EquipotentialsWidget::updateSelecteds ( const QItemSelection& , const QItemSelection& ) + { + if (_cellWidget) _cellWidget->openRefreshSession (); + + _selecteds.resetAccesses (); + + const Equipotential* equi = nullptr; + QModelIndexList iList = _view->selectionModel()->selectedRows(); + for ( int i=0 ; igetEqui( mapToSource(iList[i]).row() ); + if ( equi ) + _selecteds.insert( equi ); + } + + if (_forceReselect) { + _selecteds.forceInserteds(); + _forceReselect = false; + } + + SelectedEquiSet::iterator isel = _selecteds.begin (); + while ( isel != _selecteds.end() ) { + SelectedEquiSet::iterator remove = isel++; + if (remove->getAccesses() == 0) { + emit equipotentialUnselect ( remove->getEqui()->getFlatComponents() ); + _selecteds.erase( remove ); + } + } + isel = _selecteds.begin (); + while ( isel != _selecteds.end() ) { + if (isel->getAccesses() == 64) { + emit equipotentialSelect ( isel->getEqui()->getFlatComponents() ); + } + ++isel; + } + isel = _selecteds.begin (); + + if (_cellWidget) _cellWidget->closeRefreshSession (); + } + + + void EquipotentialsWidget::textFilterChanged () + { + _sortModel->setFilterRegExp( _filterPatternLineEdit->text() ); + //updateSelecteds (); + } + + + void EquipotentialsWidget::fitToEqui () + { + const Equipotential* equi = _baseModel->getEqui( mapToSource(_view->currentIndex()).row() ); + if (equi) emit reframe ( equi->getBoundingBox() ); + } + + + void EquipotentialsWidget::setCellWidget ( CellWidget* cw ) + { + if (_cellWidget) { + disconnect( this, 0, _cellWidget, 0 ); + } + + _cellWidget = cw; + if (_cellWidget) { + setCell( _cellWidget->getCell() ); + connect( this, SIGNAL( reframe(const Box&) ), _cellWidget, SLOT( reframe(const Box&) )); + } else + setCell( nullptr ); + } + + + void EquipotentialsWidget::setCell ( Cell* cell ) + { + _cell = cell; + _view->setVisible( false ); + _view->selectionModel()->clear(); + _baseModel->setCell( cell ); + + string windowTitle = "Equis" + getString(cell); + setWindowTitle( tr(windowTitle.c_str()) ); + + QHeaderView* header = _view->horizontalHeader(); + + _view->selectRow( 0 ); + for ( int i=0 ; i<_baseModel->columnCount() ; ++i ) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + header->setSectionResizeMode( i, QHeaderView::Interactive ); +#else + header->setResizeMode( i, QHeaderView::Interactive ); +#endif + _view->resizeColumnToContents( i ); + } + _view->setVisible( true ); + } + + +} diff --git a/tramontana/src/GraphicTramontanaEngine.cpp b/tramontana/src/GraphicTramontanaEngine.cpp new file mode 100644 index 00000000..b3380a7d --- /dev/null +++ b/tramontana/src/GraphicTramontanaEngine.cpp @@ -0,0 +1,258 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./GraphicTramontanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace Tramontana { + + using namespace std; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Exception; + using Hurricane::Breakpoint; + using Hurricane::DebugSession; + using Hurricane::Point; + using Hurricane::Entity; + using Hurricane::Net; + using Hurricane::Graphics; + using Hurricane::ColorScale; + using Hurricane::DisplayStyle; + using Hurricane::ControllerWidget; + using Hurricane::ExceptionWidget; + using CRL::Catalog; + using CRL::AllianceFramework; + + + size_t GraphicTramontanaEngine::_references = 0; + GraphicTramontanaEngine* GraphicTramontanaEngine::_singleton = NULL; + + +#if THIS_IS_DISABLED + void GraphicTramontanaEngine::initGCell ( CellWidget* widget ) + { + widget->getDrawingPlanes().setPen( Qt::NoPen ); + TramontanaEngine* tramontana = TramontanaEngine::get( widget->getCell() ); + if (tramontana) tramontana->setDensityMode( GCell::MaxDensity ); + } + + + void GraphicTramontanaEngine::drawGCell ( CellWidget* widget + , const Go* go + , const BasicLayer* basicLayer + , const Box& box + , const Transformation& transformation + ) + { + const GCell* gcell = static_cast(go); + + QPainter& painter = widget->getPainter(); + QPen pen = Graphics::getPen ("Anabatic::GCell",widget->getDarkening()); + Box bb = gcell->getBoundingBox(); + QRect pixelBb = widget->dbuToScreenRect(bb); + + if (GCell::getDisplayMode() == GCell::Density) { + uint32_t density = (unsigned int)( 255.0 * gcell->getDensity() ); + if (density > 255) density = 255; + + painter.setBrush( Graphics::getColorScale( ColorScale::Fire ).getBrush( density, widget->getDarkening() ) ); + painter.drawRect( pixelBb ); + } else { + int fontScale = 0; + int halfHeight = 20; + int halfWidth = 80; + if (widget->isPrinter()) { + fontScale = -5; + halfHeight = 9; + halfWidth = 39; + } + + painter.setPen ( pen ); + painter.setBrush( Graphics::getBrush("Anabatic::GCell",widget->getDarkening()) ); + painter.drawRect( pixelBb ); + + if ( (pixelBb.width() > 2*halfWidth) and (pixelBb.height() > 2*halfHeight) ) { + QString text = QString("%1").arg(gcell->getId()); + QFont font = Graphics::getFixedFont( QFont::Normal, false, false, fontScale ); + painter.setFont(font); + + pen.setWidth( 1 ); + painter.setPen( pen ); + + painter.save (); + painter.translate( widget->dbuToScreenPoint(bb.getCenter().getX(), bb.getCenter().getY()) ); + painter.drawRect ( QRect( -halfWidth, -halfHeight, 2*halfWidth, 2*halfHeight ) ); + painter.drawText ( QRect( -halfWidth, -halfHeight, 2*halfWidth, 2*halfHeight ) + , text + , QTextOption(Qt::AlignCenter) + ); + painter.restore (); + } + } + } +#endif + + + TramontanaEngine* GraphicTramontanaEngine::createEngine () + { + Cell* cell = getCell (); + + TramontanaEngine* tramontana = TramontanaEngine::get( cell ); + if (not tramontana) { + tramontana = TramontanaEngine::create( cell ); + tramontana->setViewer( _viewer ); + } else + cerr << Warning( "%s already has a Tramontana engine.", getString(cell).c_str() ) << endl; + + return tramontana; + } + + + TramontanaEngine* GraphicTramontanaEngine::getForFramework ( uint32_t flags ) + { + // Currently, only one framework is avalaible: Alliance. + + TramontanaEngine* tramontana = TramontanaEngine::get( getCell() ); + if (tramontana) return tramontana; + + if (flags & CreateEngine) { + tramontana = createEngine(); + if (not tramontana) + throw Error( "Failed to create Tramontana engine on %s.", getString(getCell()).c_str() ); + } else { + throw Error( "TramontanaEngine not created yet, run the global router first." ); + } + + return tramontana; + } + + + void GraphicTramontanaEngine::_extract () + { + TramontanaEngine* tramontana = getForFramework( CreateEngine ); + tramontana->extract(); + + //Breakpoint::stop( 0, "GraphicTramontanaEngine::_extract() done." ); + } + + + void GraphicTramontanaEngine::addToMenu ( CellViewer* viewer ) + { + assert(_viewer == NULL); + + _viewer = viewer; + + if (_viewer->hasMenuAction("tools.extract")) { + cerr << Warning( "GraphicTramontanaEngine::addToMenu() - Tramontana extractor already hooked in." ) << endl; + return; + } + + _viewer->addToMenu( "tools.extract" + , "E&xtract . . . . . [Tramontana]" + , "Run the extractor" + , std::bind(&GraphicTramontanaEngine::_extract,this) + ); + + ControllerWidget* controller = viewer->getControllerWidget(); + if (controller) { + TabEquipotentials* tabEqui = new TabEquipotentials (); + tabEqui->setObjectName( "controller.tabEquipotentials" ); + tabEqui->setCellWidget( viewer->getCellWidget() ); + controller->insertTabAfter( "controller.tabNetlist", tabEqui, "Equipotentials" ); + } + } + + + const Name& GraphicTramontanaEngine::getName () const + { return TramontanaEngine::staticGetName(); } + + + Cell* GraphicTramontanaEngine::getCell () + { + if (not _viewer) { + throw Error( "Tramontana: GraphicTramontanaEngine not bound to any Viewer." ); + return NULL; + } + if (not _viewer->getCell()) { + throw Error( "Tramontana: No Cell is loaded into the Viewer." ); + return NULL; + } + + return _viewer->getCell(); + } + + + GraphicTramontanaEngine* GraphicTramontanaEngine::grab () + { + if (not _references) { + _singleton = new GraphicTramontanaEngine (); + } + _references++; + + return _singleton; + } + + + size_t GraphicTramontanaEngine::release () + { + --_references; + if (not _references) { + delete _singleton; + _singleton = NULL; + } + return _references; + } + + + GraphicTramontanaEngine::GraphicTramontanaEngine () + : GraphicTool() + , _viewer (NULL) + { +#if THIS_IS_DISABLED + addDrawGo( "Anabatic::GCell", initGCell, drawGCell ); + addDrawGo( "Anabatic::Edge" , initEdge , drawEdge ); +#endif + } + + + GraphicTramontanaEngine::~GraphicTramontanaEngine () + { } + + +} // Tramontana namespace. diff --git a/tramontana/src/PyGraphicTramontanaEngine.cpp b/tramontana/src/PyGraphicTramontanaEngine.cpp new file mode 100644 index 00000000..cb2198c4 --- /dev/null +++ b/tramontana/src/PyGraphicTramontanaEngine.cpp @@ -0,0 +1,113 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./PyGraphicTramontanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#include "tramontana/PyGraphicTramontanaEngine.h" +#include "hurricane/isobar/PyCell.h" +#include "hurricane/Cell.h" + + +#undef ACCESS_OBJECT +#undef ACCESS_CLASS +#define ACCESS_OBJECT _baseObject._object +#define ACCESS_CLASS(_pyObject) &(_pyObject->_baseObject) +#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(GraphicTramontanaEngine,gtool,function) + + +namespace Tramontana { + +using namespace Hurricane; +using namespace Isobar; + +extern "C" { + + +// +=================================================================+ +// | "PyGraphicTramontanaEngine" Python Module Code Part | +// +=================================================================+ + +#if defined(__PYTHON_MODULE__) + + + static PyObject* PyGraphicTramontanaEngine_grab ( PyObject* ) + { + cdebug_log(40,0) << "PyGraphicTramontanaEngine_grab()" << endl; + PyGraphicTramontanaEngine* pyGraphicTramontanaEngine = NULL; + HTRY + pyGraphicTramontanaEngine = PyObject_NEW ( PyGraphicTramontanaEngine, &PyTypeGraphicTramontanaEngine ); + if ( pyGraphicTramontanaEngine == NULL ) return NULL; + pyGraphicTramontanaEngine->ACCESS_OBJECT = GraphicTramontanaEngine::grab(); + HCATCH + return (PyObject*)pyGraphicTramontanaEngine; + } + + + static PyObject* PyGraphicTramontanaEngine_getCell ( PyGraphicTramontanaEngine* self ) + { + cdebug_log(40,0) << "PyGraphicTramontanaEngine_getCell ()" << endl; + Cell* cell = NULL; + HTRY + METHOD_HEAD("GraphicTramontanaEngine.getCell()") + cell = gtool->getCell (); + HCATCH + if (cell == NULL) Py_RETURN_NONE; + return PyCell_Link(cell); + } + + + GetNameMethod(GraphicTramontanaEngine, gtool) + + // Standart destroy (Attribute). + + + PyMethodDef PyGraphicTramontanaEngine_Methods[] = + { { "grab" , (PyCFunction)PyGraphicTramontanaEngine_grab , METH_NOARGS|METH_STATIC + , "Returns the GraphicTramontanaEngine singleton." } + , { "getName" , (PyCFunction)PyGraphicTramontanaEngine_getName , METH_NOARGS + , "Returns the name of the GraphicTramontanaEngine (class attribute)." } + , { "getCell" , (PyCFunction)PyGraphicTramontanaEngine_getCell , METH_NOARGS + , "Returns the Cell on which this GraphicTramontanaEngine is attached." } + , {NULL, NULL, 0, NULL} /* sentinel */ + }; + + + // --------------------------------------------------------------- + // PyGraphicTramontanaEngine Type Methods. + + + PythonOnlyDeleteMethod(GraphicTramontanaEngine) + PyTypeObjectLinkPyType(GraphicTramontanaEngine) + + +#else // End of Python Module Code Part. + + +// +=================================================================+ +// | "PyGraphicTramontanaEngine" Shared Library Code Part | +// +=================================================================+ + + // Link/Creation Method. + LinkCreateMethod(GraphicTramontanaEngine) + + PyTypeInheritedObjectDefinitions(GraphicTramontanaEngine,GraphicTool) + + +#endif // End of Shared Library Code Part. + +} // extern "C". + +} // CRL namespace. diff --git a/tramontana/src/PyTramontana.cpp b/tramontana/src/PyTramontana.cpp new file mode 100644 index 00000000..4336d068 --- /dev/null +++ b/tramontana/src/PyTramontana.cpp @@ -0,0 +1,107 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./PyTramontana.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/isobar/PyHurricane.h" +#include "hurricane/isobar/PyCell.h" +#include "tramontana/PyTramontanaEngine.h" +#include "tramontana/PyGraphicTramontanaEngine.h" + + +namespace Tramontana { + + using std::cerr; + using std::endl; + using Hurricane::tab; + using Isobar::getPyHash; + using Isobar::__cs; + using CRL::PyTypeToolEngine; + using CRL::PyTypeGraphicTool; + + +#if !defined(__PYTHON_MODULE__) + +// +=================================================================+ +// | "PyTramontana" Shared Library Code Part | +// +=================================================================+ + + +# else // End of PyHurricane Shared Library Code Part. + + +// +=================================================================+ +// | "PyTramontana" Python Module Code Part | +// +=================================================================+ + + +extern "C" { + + + static PyMethodDef PyTramontana_Methods[] = + { {NULL, NULL, 0, NULL} /* sentinel */ + }; + + + static PyModuleDef PyTramontana_ModuleDef = + { PyModuleDef_HEAD_INIT + , .m_name = "Tramontana" + , .m_doc = "Layout extractor & LVX." + , .m_size = -1 + , .m_methods = PyTramontana_Methods + }; + + + + + // --------------------------------------------------------------- + // Module Initialization : "PyInit_Tramontana ()" + + PyMODINIT_FUNC PyInit_Tramontana ( void ) + { + cdebug_log(40,0) << "PyInit_Tramontana()" << endl; + + PyTramontanaEngine_LinkPyType(); + PyGraphicTramontanaEngine_LinkPyType(); + + PYTYPE_READY_SUB( TramontanaEngine , ToolEngine ); + PYTYPE_READY_SUB( GraphicTramontanaEngine, GraphicTool ); + + + PyObject* module = PyModule_Create( &PyTramontana_ModuleDef ); + if (module == NULL) { + cerr << "[ERROR]\n" + << " Failed to initialize Tramontana module." << endl; + return NULL; + } + + Py_INCREF( &PyTypeTramontanaEngine ); + PyModule_AddObject( module, "TramontanaEngine", (PyObject*)&PyTypeTramontanaEngine ); + Py_INCREF( &PyTypeGraphicTramontanaEngine ); + PyModule_AddObject( module, "GraphicTramontanaEngine", (PyObject*)&PyTypeGraphicTramontanaEngine ); + + //PyTramontanaEngine_postModuleInit(); + return module; + } + + +} // End of extern "C". + + +#endif // End of Python Module Code Part. + + +} // End of Tramontana namespace. diff --git a/tramontana/src/PyTramontanaEngine.cpp b/tramontana/src/PyTramontanaEngine.cpp new file mode 100644 index 00000000..11f5a8c8 --- /dev/null +++ b/tramontana/src/PyTramontanaEngine.cpp @@ -0,0 +1,216 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./PyTramontanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/isobar/PyNet.h" +#include "hurricane/isobar/PyCell.h" +#include "hurricane/viewer/PyCellViewer.h" +#include "hurricane/viewer/ExceptionWidget.h" +#include "hurricane/Cell.h" +#include "crlcore/Utilities.h" +#include "tramontana/PyTramontanaEngine.h" +#include + +# undef ACCESS_OBJECT +# undef ACCESS_CLASS +# define ACCESS_OBJECT _baseObject._object +# define ACCESS_CLASS(_pyObject) &(_pyObject->_baseObject) +#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(TramontanaEngine,tramontana,function) + + +namespace Tramontana { + + using std::cerr; + using std::endl; + using std::hex; + using std::ostringstream; + using Hurricane::tab; + using Hurricane::Exception; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::ExceptionWidget; + using Isobar::__cs; + using Isobar::Converter; + using Isobar::ProxyProperty; + using Isobar::ProxyError; + using Isobar::ConstructorError; + using Isobar::HurricaneError; + using Isobar::HurricaneWarning; + using Isobar::getPyHash; + using Isobar::ParseOneArg; + using Isobar::ParseTwoArg; + using Isobar::PyNet; + using Isobar::PyCell; + using Isobar::PyCell_Link; + using Isobar::PyCellViewer; + using Isobar::PyTypeCellViewer; + using CRL::PyToolEngine; + + +extern "C" { + +#if defined(__PYTHON_MODULE__) + + +#define DirectVoidToolMethod(SELF_TYPE, SELF_OBJECT, FUNC_NAME) \ + static PyObject* Py##SELF_TYPE##_##FUNC_NAME(Py##SELF_TYPE* self) \ + { \ + cdebug_log(40,0) << "Py" #SELF_TYPE "_" #FUNC_NAME "()" << endl; \ + HTRY \ + METHOD_HEAD(#SELF_TYPE "." #FUNC_NAME "()") \ + if (SELF_OBJECT->getViewer()) { \ + if (ExceptionWidget::catchAllWrapper( std::bind(&TramontanaEngine::FUNC_NAME,SELF_OBJECT) )) { \ + PyErr_SetString( HurricaneError, #FUNC_NAME "() has thrown an exception (C++)." ); \ + return NULL; \ + } \ + } else { \ + SELF_OBJECT->FUNC_NAME(); \ + } \ + HCATCH \ + Py_RETURN_NONE; \ + } + + +// +=================================================================+ +// | "PyTramontanaEngine" Python Module Code Part | +// +=================================================================+ + + + static PyObject* PyTramontanaEngine_get ( PyObject*, PyObject* args ) + { + cdebug_log(40,0) << "PyTramontanaEngine_get()" << endl; + TramontanaEngine* tramontana = NULL; + HTRY + PyObject* arg0; + if (not ParseOneArg("Tramontana.get", args, CELL_ARG, &arg0)) return NULL; + tramontana = TramontanaEngine::get(PYCELL_O(arg0)); + HCATCH + return PyTramontanaEngine_Link(tramontana); + } + + + static PyObject* PyTramontanaEngine_create ( PyObject*, PyObject* args ) + { + cdebug_log(40,0) << "PyTramontanaEngine_create()" << endl; + TramontanaEngine* tramontana = NULL; + HTRY + PyObject* arg0; + if (not ParseOneArg("Tramontana.get", args, CELL_ARG, &arg0)) return NULL; + Cell* cell = PYCELL_O(arg0); + tramontana = TramontanaEngine::get(cell); + if (tramontana == NULL) { + tramontana = TramontanaEngine::create(cell); + } else + cerr << Warning("%s already has a Tramontana engine.",getString(cell).c_str()) << endl; + HCATCH + return PyTramontanaEngine_Link(tramontana); + } + + + static PyObject* PyTramontanaEngine_setViewer ( PyTramontanaEngine* self, PyObject* args ) + { + cdebug_log(40,0) << "PyTramontanaEngine_setViewer ()" << endl; + HTRY + METHOD_HEAD( "TramontanaEngine.setViewer()" ) + PyObject* pyViewer = NULL; + if (not PyArg_ParseTuple(args,"O:TramontanaEngine.setViewer()",&pyViewer)) { + PyErr_SetString( ConstructorError, "Bad parameters given to TramontanaEngine.setViewer()." ); + return NULL; + } + if (IsPyCellViewer(pyViewer)) { + tramontana->setViewer( PYCELLVIEWER_O(pyViewer) ); + } + HCATCH + Py_RETURN_NONE; + } + + + static PyObject* PyTramontanaEngine_extract ( PyTramontanaEngine* self ) + { + cdebug_log(40,0) << "PyTramontanaEngine_extract()" << endl; + HTRY + METHOD_HEAD("TramontanaEngine.extract()") + if (tramontana->getViewer()) { + if (ExceptionWidget::catchAllWrapper( std::bind(&TramontanaEngine::extract,tramontana) )) { + PyErr_SetString( HurricaneError, "TramontanaEngine::extract() has thrown an exception (C++)." ); + return NULL; + } + } else { + tramontana->extract(); + } + HCATCH + Py_RETURN_NONE; + } + + + // Standart Accessors (Attributes). + + // Standart Destroy (Attribute). + DBoDestroyAttribute(PyTramontanaEngine_destroy,PyTramontanaEngine) + + + PyMethodDef PyTramontanaEngine_Methods[] = + { { "get" , (PyCFunction)PyTramontanaEngine_get , METH_VARARGS|METH_STATIC + , "Returns the Tramontana engine attached to the Cell, None if there isnt't." } + , { "create" , (PyCFunction)PyTramontanaEngine_create , METH_VARARGS|METH_STATIC + , "Create a Tramontana engine on this cell." } + , { "destroy" , (PyCFunction)PyTramontanaEngine_destroy , METH_NOARGS + , "Destroy a Tramontana engine." } + , { "setViewer" , (PyCFunction)PyTramontanaEngine_setViewer , METH_VARARGS + , "Associate a Viewer to this TramontanaEngine." } + , { "extract" , (PyCFunction)PyTramontanaEngine_extract , METH_NOARGS + , "Perform the layout extraction." } + , {NULL, NULL, 0, NULL} /* sentinel */ + }; + + + DBoDeleteMethod(TramontanaEngine) + PyTypeObjectLinkPyType(TramontanaEngine) + + +#else // End of Python Module Code Part. + + +// +=================================================================+ +// | "PyTramontanaEngine" Shared Library Code Part | +// +=================================================================+ + + + // Link/Creation Method. + PyTypeInheritedObjectDefinitions(TramontanaEngine,PyToolEngine) + DBoLinkCreateMethod(TramontanaEngine) + + + // extern void PyTramontanaEngine_postModuleInit () + // { + // PyTramontanaFlags_postModuleInit(); + + // PyDict_SetItemString( PyTypeTramontanaEngine.tp_dict, "Flags", (PyObject*)&PyTypeTramontanaFlags ); + + // PyObject* constant = NULL; + // LoadObjectConstant( PyTypeTramontanaEngine.tp_dict, TramontanaEngine::GlobalRoutingSuccess , "GlobalRoutingSuccess" ) + // LoadObjectConstant( PyTypeTramontanaEngine.tp_dict, TramontanaEngine::DetailedRoutingSuccess, "DetailedRoutingSuccess" ) + // } + + +#endif // Shared Library Code Part. + +} // extern "C". + +} // Tramontana namespace. + diff --git a/tramontana/src/QueryTiles.cpp b/tramontana/src/QueryTiles.cpp new file mode 100644 index 00000000..0a72edfe --- /dev/null +++ b/tramontana/src/QueryTiles.cpp @@ -0,0 +1,105 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./QueryTiles.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "tramontana/QueryTiles.h" +#include "tramontana/SweepLine.h" + + +namespace Tramontana { + + using std::cerr; + using std::endl; + using std::vector; + + + QueryTiles::QueryTiles ( SweepLine* sweepLine ) + : Query () + , _sweepLine (sweepLine) + , _goMatchCount (0) + , _processedLayers(0) + { + setCell ( sweepLine->getCell() ); + setArea ( sweepLine->getCell()->getBoundingBox() ); + setFilter( Query::DoComponents|Query::DoTerminalCells ); + } + + + void QueryTiles::setBasicLayer ( const BasicLayer* basicLayer ) + { + _processedLayers |= basicLayer->getMask(); + Query::setBasicLayer ( basicLayer ); + } + + + bool QueryTiles::isProcessed ( Component* component ) const + { + Layer::Mask fullyProcesseds = _processedLayers & ~getBasicLayer()->getMask(); + return component->getLayer()->getMask().intersect( fullyProcesseds ); + } + + + void QueryTiles::masterCellCallback () + { } + + + void QueryTiles::rubberCallback ( Rubber* ) + { } + + + void QueryTiles::extensionGoCallback ( Go* ) + { } + + + bool QueryTiles::hasGoCallback () const + { return true; } + + + void QueryTiles::goCallback ( Go* go ) + { + 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; + 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++; + } + + +} // Tramontana namespace. diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp new file mode 100644 index 00000000..317e4b23 --- /dev/null +++ b/tramontana/src/SweepLine.cpp @@ -0,0 +1,370 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./SweepLine.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "hurricane/utilities/Path.h" +#include "hurricane/DebugSession.h" +#include "hurricane/UpdateSession.h" +#include "hurricane/Bug.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/Breakpoint.h" +#include "hurricane/Timer.h" +#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" +#include "hurricane/Cell.h" +#include "hurricane/Instance.h" +#include "hurricane/Vertical.h" +#include "hurricane/Horizontal.h" +#include "hurricane/RoutingPad.h" +#include "crlcore/Utilities.h" +#include "tramontana/SweepLine.h" +#include "tramontana/QueryTiles.h" + + +namespace Tramontana { + + using std::cout; + using std::cerr; + using std::endl; + using std::dec; + using std::setw; + using std::setfill; + using std::left; + using std::right; + using std::string; + using std::ostream; + using std::ofstream; + using std::ostringstream; + using std::setprecision; + using std::vector; + using std::make_pair; + using Hurricane::dbo_ptr; + using Hurricane::UpdateSession; + using Hurricane::DebugSession; + using Hurricane::tab; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Breakpoint; + using Hurricane::Interval; + using Hurricane::Box; + using Hurricane::DataBase; + using Hurricane::Technology; + using Hurricane::Layer; + using Hurricane::ViaLayer; + using Hurricane::Entity; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::RoutingPad; + using Hurricane::Cell; + using Hurricane::Instance; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::SweepLine". + + + SweepLine::SweepLine ( TramontanaEngine* tramontana ) + : _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::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" )); + // _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" )); + } + + + SweepLine::~SweepLine () + { } + + + 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; + 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; + // } + // if (not debugOn and (element.getX() == DbU::fromLambda(1724.0))) { + // debugOn = true; + // DebugSession::open( 0, 169 ); + // } + // if (debugOn and (element.getX() > DbU::fromLambda(1726.0))) { + // debugOn = false; + // DebugSession::close(); + // } + cdebug_log(160,1) << "X@ + " << 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; + cdebug_tabw(160,-1); + continue; + } + if (element.isLeftEdge()) { + // 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; + // if (elt.getData()->getBoundingBox().getXMax() < tile->getLeftEdge()) + // cdebug_log(160,0) << " * Should have been removed !" << endl; + // } + // } + for ( const TileIntv& overlap : intvTree->second.getOverlaps( + Interval(tile->getYMin(), tile->getYMax() ))) { + cdebug_log(160,0) << " | intersect " << overlap.getData() << endl; + tile->merge( overlap.getData() ); + } + cdebug_log(160,0) << " | insert tile" << endl; + // if (tile->getId() == 60117) { + // cerr << " | insert in " << element.getMask() << endl; + // cerr << " | " << tile << endl; + // } + // if (tile->getId() == 46373) { + // cerr << " | insert " << tile << endl; + // } + intvTree->second.insert( tileIntv ); + 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 ); + // } + // cdebug_log(160,0) << " | remove tile from " << element.getMask() << endl; + // cdebug_log(160,0) << " | " << tile << endl; + // if ((tile->getId() == 289) and not written) { + // cerr << "(before) written is " << written << endl; + // DebugSession::open( 0, 169 ); + // intvTree->second.write( "tree-before.gv" ); + // //DebugSession::close(); + // for ( auto elt : intvTree->second.getElements() ) { + // cerr << " | in tree:" << elt << endl; + // } + // } + cdebug_log(160,0) << " | remove tile" << endl; + intvTree->second.remove( tileIntv ); + // DebugSession::open( 0, 169 ); + // intvTree->second.checkVMax(); + // DebugSession::close(); + // if ((tile->getId() == 289) and not written) { + // //DebugSession::open( 0, 169 ); + // written = true; + // cerr << "(after) written is " << written << endl; + // intvTree->second.write( "tree-after.gv" ); + // DebugSession::close(); + // } + // if (intvTree->second.find( tileIntv ) != intvTree->second.end()) { + // cerr << "NOT Removed " << tileIntv << endl; + // } + // if (tile->getId() == 289) { + // cerr << " | removed " << tile << endl; + // intvTree->second.write( "tree.gv" ); + // for ( auto elt : intvTree->second.getElements() ) { + // cerr << " | in tree:" << elt << endl; + // } + // DebugSession::close(); + // } + // if (tile->getId() == 46055) { + // intvTree->second.write( "we_at_remove.gv" ); + // for ( auto tile : intvTree->second.getElements() ) { + // cerr << "| in tree:" << tile << endl; + // } + // } + } + //intvTree->second.checkVMax(); + // cdebug_tabw(160,-1); + // if (tile->getOccurrence().getEntity()->getId() == 3348) { + // DebugSession::close(); + // } + cdebug_tabw(160,-1); + } + //if (debugOn) DebugSession::close(); + cdebug_tabw(160,-1); + //DebugSession::close(); + mergeEquipotentials(); + deleteTiles(); + } + + + void SweepLine::loadTiles () + { + //cerr << "SweepLine::loadTiles()" << endl; + + for ( const BasicLayer* layer : _extracteds ) { + _intervalTrees.insert( make_pair( layer->getMask(), TileIntvTree() )); + } + + QueryTiles query ( this ); + for ( const BasicLayer* layer : _extracteds ) { + query.setBasicLayer( layer ); + query.doQuery(); + } + cmess2 << " - Loaded " << query.getGoMatchCount() << " tiles." << endl; + + // for ( Occurrence occurrence : getCell()->getOccurrencesUnder( getCell()->getBoundingBox() ) ) { + // vector tiles; + // Component* component = dynamic_cast( occurrence.getEntity() ); + // if (occurrence.getPath().getInstances().getSize() > 0) { + // cerr << occurrence << endl; + // } + // if (not component) continue; + // 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() ); + } + + + void SweepLine::deleteTiles () + { + Tile::deleteAllTiles(); + } + + + void SweepLine::mergeEquipotentials () + { + //DebugSession::open( 160, 169 ); + cdebug_log(160,1) << "SweepLine::mergeEquipotentials()" << endl; + //cerr << "SweepLine::mergeEquipotentials()" << endl; + Tile::timeTick(); + for ( Tile* tile : Tile::getAllTiles() ) { + tile->getRoot( Tile::MergeEqui|Tile::MakeLeafEqui ); + } + cdebug_tabw(160,-1); + //DebugSession::close(); + } + + + string SweepLine::_getTypeName () const + { return "Tramontana::SweepLine"; } + + + string SweepLine::_getString () const + { + ostringstream os; + os << "getCell()->getName() << "\">"; + return os.str(); + } + + + Record* SweepLine::_getRecord () const + { + Record* record = new Record ( _getString() ); + if (record) { + record->add( getSlot( "_tramontana" , &_tramontana ) ); + record->add( getSlot( "_tiles" , &_tiles ) ); + } + return record; + } + + +} // Tramontana namespace. diff --git a/tramontana/src/TabEquipotentials.cpp b/tramontana/src/TabEquipotentials.cpp new file mode 100644 index 00000000..9d052537 --- /dev/null +++ b/tramontana/src/TabEquipotentials.cpp @@ -0,0 +1,161 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./TabEquipotentials.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include +#include +#include "tramontana/TabEquipotentials.h" + + +namespace Tramontana { + + using std::cerr; + using std::endl; + using Hurricane::Graphics; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TabEquipotentials". + + + TabEquipotentials::TabEquipotentials ( QWidget* parent ) + : ControllerTab (parent) + , _browser (new EquipotentialsWidget()) + , _syncEquipotentials (new QCheckBox()) + , _syncSelection (new QCheckBox()) + , _showBuried (new QCheckBox()) + , _cwCumulativeSelection(false) + { + _browser->setObjectName ( "controller.tabEquipotentials.browser" ); + + QVBoxLayout* wLayout = new QVBoxLayout (); + wLayout->setContentsMargins( 10, 0, 10, 0 ); + wLayout->setSpacing( 0 ); + + _syncEquipotentials->setText ( tr("Sync Equipotentials") ); + _syncEquipotentials->setChecked( false ); + _syncEquipotentials->setFont ( Graphics::getFixedFont(QFont::Bold,false,false) ); + connect( _syncEquipotentials, SIGNAL(toggled(bool)), this, SLOT(setSyncEquipotentials(bool)) ); + + _syncSelection->setText ( tr("Sync Selection") ); + _syncSelection->setChecked( false ); + _syncSelection->setFont ( Graphics::getFixedFont(QFont::Bold,false,false) ); + connect( _syncSelection, SIGNAL(toggled(bool)), this, SLOT(setSyncSelection(bool)) ); + + _showBuried->setText ( tr("Show Buried") ); + _showBuried->setChecked( false ); + _showBuried->setFont ( Graphics::getFixedFont(QFont::Bold,false,false) ); + connect( _showBuried, SIGNAL(toggled(bool)), this, SLOT(setShowBuried(bool)) ); + + QHBoxLayout* commands = new QHBoxLayout (); + commands->setContentsMargins( 0, 0, 0, 0 ); + commands->addStretch(); + commands->addWidget ( _syncEquipotentials ); + commands->addStretch(); + commands->addWidget ( _showBuried ); + commands->addStretch(); + commands->addWidget ( _syncSelection ); + commands->addStretch(); + wLayout->addLayout ( commands ); + + QFrame* separator = new QFrame (); + separator->setFrameShape ( QFrame::HLine ); + separator->setFrameShadow( QFrame::Sunken ); + wLayout->addWidget( separator ); + wLayout->addWidget( _browser ); + + setLayout( wLayout ); + } + + + void TabEquipotentials::setSyncEquipotentials ( bool state ) + { + if (state and getCellWidget()) { + _browser->setCell( getCellWidget()->getCell() ); + } else { + _browser->setCell( nullptr ); + } + } + + + void TabEquipotentials::setSyncSelection ( bool state ) + { + if (state and getCellWidget() and _syncEquipotentials->isChecked()) { + _cwCumulativeSelection = getCellWidget()->cumulativeSelection(); + if (not _cwCumulativeSelection) { + getCellWidget()->openRefreshSession (); + getCellWidget()->unselectAll (); + getCellWidget()->closeRefreshSession (); + } + getCellWidget()->setShowSelection( true ); + connect( _browser, SIGNAL(equipotentialSelect (Occurrences)), getCellWidget(), SLOT(select (Occurrences)) ); + connect( _browser, SIGNAL(equipotentialUnselect(Occurrences)), getCellWidget(), SLOT(unselect(Occurrences)) ); + _browser->updateSelecteds(); + } else { + getCellWidget()->setShowSelection( false ); + getCellWidget()->setCumulativeSelection( _cwCumulativeSelection ); + _browser->disconnect( getCellWidget(), SLOT(select (Occurrences)) ); + _browser->disconnect( getCellWidget(), SLOT(unselect(Occurrences)) ); + } + } + + + void TabEquipotentials::setShowBuried ( bool state ) + { + if (not getCellWidget()) return; + _browser->setShowBuried( state ); + } + + + void TabEquipotentials::setCell ( Cell* cell ) + { + setSyncEquipotentials( _syncEquipotentials->isChecked() ); + } + + + void TabEquipotentials::setCellWidget ( CellWidget* cellWidget ) + { + if (getCellWidget() != cellWidget) { + ControllerTab::setCellWidget( cellWidget ); + _browser->setCellWidget( cellWidget ); + if (getCellWidget()) { + connect( getCellWidget(), SIGNAL(cellChanged(Cell*)), this, SLOT(setCell(Cell*)) ); + } + setSyncEquipotentials( _syncEquipotentials->isChecked() ); + } + } + + + void TabEquipotentials::cellPreModificate () + { + _browser->setCell( nullptr ); + } + + + void TabEquipotentials::cellPostModificate () + { + setSyncEquipotentials( _syncEquipotentials->isChecked() ); + } + + + + +} diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp new file mode 100644 index 00000000..e6863ae4 --- /dev/null +++ b/tramontana/src/Tile.cpp @@ -0,0 +1,362 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./Tile.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "hurricane/utilities/Path.h" +#include "hurricane/DebugSession.h" +#include "hurricane/UpdateSession.h" +#include "hurricane/Bug.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/Breakpoint.h" +#include "hurricane/Timer.h" +#include "hurricane/Layer.h" +#include "hurricane/Net.h" +#include "hurricane/Pad.h" +#include "hurricane/Plug.h" +#include "hurricane/Cell.h" +#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 { + + using std::cout; + using std::cerr; + using std::endl; + using std::dec; + using std::setw; + using std::setfill; + using std::left; + using std::string; + using std::ostream; + using std::ofstream; + using std::ostringstream; + using std::setprecision; + using std::vector; + using std::make_pair; + using Hurricane::dbo_ptr; + using Hurricane::UpdateSession; + using Hurricane::DebugSession; + using Hurricane::tab; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Breakpoint; + using Hurricane::Box; + using Hurricane::Layer; + using Hurricane::Entity; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::Vertical; + using Hurricane::Diagonal; + using Hurricane::Rectilinear; + using Hurricane::Polygon; + using Hurricane::Cell; + using Hurricane::Instance; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::Tile". + + + uint32_t Tile::_idCounter = 0; + uint32_t Tile::_time = 0; + vector Tile::_allocateds; + + + 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 (parent) + , _rank (0) + , _timeStamp (0) + { + cdebug_log(160,0) << "Tile::Tile() " << this << endl; + _allocateds.push_back( this ); + if (occurrence.getPath().isEmpty() and not occurrence.getEntity()) + cerr << "Tile with empty occurrence!!" << endl; + } + + + Tile* Tile::create ( Occurrence occurrence + , const BasicLayer* layer + , Tile* rootTile + , SweepLine* sweepLine + , uint32_t flags ) + { + Component* component = dynamic_cast( occurrence.getEntity() ); + if (not component) { + cerr << Error( "Tile::create(): Must be build over an occurrence of *Component*.\n" + " (%s)" + , getString(occurrence).c_str() + ) << endl; + return nullptr; + } + 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(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 ); + + Tile* tile = new Tile ( childEqui, layer, bb, rootTile ); + sweepLine->add( tile ); + return tile; + } + + + void Tile::destroy () + { + cdebug_log(160,1) << "Tile::destroy() " << this << endl; + cdebug_tabw(160,-1); + } + + + Tile::~Tile () + { } + + + void Tile::deleteAllTiles () + { + for ( Tile* tile : _allocateds) delete tile; + _allocateds.clear(); + _idCounter = 0; + } + + // Net* Tile::getNet () const + // { return dynamic_cast( _occurrence.getEntity() )->getNet(); } + + + Tile* Tile::getRoot ( uint32_t flags ) + { + cdebug_log(160,1) << "Tile::getRoot() tid=" << getId() << " " << getOccurrence() << endl; + cdebug_log(160,0) << "+ " << (getEquipotential() ? getString(getEquipotential()) : "equi=NULL") << endl; + if (not getParent()) { + if ((flags & MakeLeafEqui) and not getEquipotential()) { + newEquipotential(); + } + cdebug_tabw(160,-1); + return this; + } + + Tile* root = this; + while ( root->getParent() ) { + // if (flags & MergeEqui) { + // if (not root->getParent()->getEquipotential() and root->getEquipotential()) { + // cdebug_log(160,0) << "| tile has no equi, immediate merge" << endl; + // root->getParent()->setEquipotential( root->getEquipotential() ); + // root->getEquipotential()->add( root->getParent()->getOccurrence () + // , root->getParent()->getBoundingBox() ); + // root->getParent()->setOccMerged( true ); + // } + // } + root = root->getParent(); + cdebug_log(160,0) << "| parent tid=" << root->getId() << " " << root->getOccurrence() << endl; + } + cdebug_log(160,0) << "> root tid=" << root->getId() << " " + << (root->getEquipotential() ? getString(root->getEquipotential()) : "equi=NULL") << endl; + + + if (flags & MergeEqui) { + Equipotential* rootEqui = root->getEquipotential(); + if (not rootEqui) { + rootEqui = root->newEquipotential(); + } + + Tile* current = this; + while ((current != root) and current) { + if (current->isUpToDate()) { + cdebug_log(160,0) << "> Up to date current: tid=" << current->getId() << endl; + break; + } + if (not current->isOccMerged()) { + if (current->getEquipotential()) { + if (current->getEquipotential() != rootEqui) { + cdebug_log(160,0) << "| merge tid=" << current->getId() << " => tid=" << root->getId() << endl; + cdebug_log(160,0) << "| tid=" << current->getEquipotential() << endl; + rootEqui->merge( current->getEquipotential() ); + } + } else { + cdebug_log(160,0) << "| add " << current->getOccurrence() << endl; + rootEqui->add( current->getOccurrence(), _boundingBox ); + } + current->setOccMerged( true ); + current->syncTime(); + cdebug_log(160,0) << "| current up to date: time=" << current->_timeStamp + << " " << current->isUpToDate() << endl; + } + current = current->getParent(); + } + } + + if (flags & Compress) { + Tile* current = this; + while ( current != root ) { + Tile* curParent = current->getParent(); + current->setParent( root ); + current = curParent; + } + } + + cdebug_tabw(160,-1); + return root; + } + + + Tile* Tile::merge ( Tile* other ) + { + cdebug_log(160,1) << "Tile::merge() this->tid:" << getId() + << " + other->tid:" << other->getId() << endl; + Tile* root1 = getRoot( Compress|MergeEqui ); + Tile* root2 = other->getRoot( Compress|MergeEqui ); + if (root1 and (root1 == root2)) { + cdebug_log(160,0) << "Already have same root tid:" << root1->getId() << endl; + cdebug_tabw(160,-1); + return root1; + } + + if (root1->getRank() < root2->getRank()) + std::swap( root1, root2 ); + if (root1->getRank() == root2->getRank()) + root1->incRank(); + root2->setParent( root1 ); + cdebug_log(160,0) << "New root tid:" << root1->getId() + << " child tid:" << root2->getId() << endl; + // Fuse root2 into root1 here! + + cdebug_tabw(160,-1); + return root1; + } + + + Equipotential* Tile::newEquipotential () + { + if (_equipotential) { + cerr << Error( "Tile::newEquipotential(): Equipotential already created (ignoring).\n" + " (on: %s)" + , getString(this).c_str() + ) << endl; + return _equipotential; + } + + _equipotential = Equipotential::create( _occurrence.getOwnerCell() ); + _equipotential->add( _occurrence, _boundingBox ); + cdebug_log(160,0) << "new " << _equipotential << endl; + cdebug_log(160,0) << "| " << _occurrence << endl; + return _equipotential; + } + + + string Tile::_getTypeName () const + { return "Tramontana::Tile"; } + + + string Tile::_getString () const + { + ostringstream os; + os << "getName() << " " << _occurrence << ">"; + return os.str(); + } + + + Record* Tile::_getRecord () const + { + Record* record = new Record ( _getString() ); + if (record) { + record->add( getSlot( "_occurrence" , &_occurrence ) ); + record->add( getSlot( "_layer" , _layer ) ); + record->add( getSlot( "_boundingBox", &_boundingBox ) ); + record->add( getSlot( "_flags" , &_flags ) ); + } + return record; + } + + +} // Tramontana namespace. diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp new file mode 100644 index 00000000..8b028520 --- /dev/null +++ b/tramontana/src/TramontanaEngine.cpp @@ -0,0 +1,245 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./TramontanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include "hurricane/utilities/Path.h" +#include "hurricane/DebugSession.h" +#include "hurricane/UpdateSession.h" +#include "hurricane/Bug.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/Breakpoint.h" +#include "hurricane/Timer.h" +#include "hurricane/Layer.h" +#include "hurricane/Net.h" +#include "hurricane/Pad.h" +#include "hurricane/Plug.h" +#include "hurricane/Cell.h" +#include "hurricane/Instance.h" +#include "hurricane/Vertical.h" +#include "hurricane/Horizontal.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/viewer/Script.h" +#include "crlcore/Measures.h" +#include "crlcore/Utilities.h" +#include "crlcore/AllianceFramework.h" +#include "tramontana/SweepLine.h" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + + using std::cout; + using std::cerr; + using std::endl; + using std::dec; + using std::setw; + using std::setfill; + using std::left; + using std::string; + using std::ostream; + using std::ofstream; + using std::ostringstream; + using std::setprecision; + using std::vector; + using std::make_pair; + using Hurricane::dbo_ptr; + using Hurricane::UpdateSession; + using Hurricane::DebugSession; + using Hurricane::tab; + using Hurricane::ForEachIterator; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Breakpoint; + using Hurricane::Timer; + using Hurricane::Box; + using Hurricane::Layer; + using Hurricane::Entity; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::RoutingPad; + using Hurricane::Cell; + using Hurricane::Instance; + using CRL::Catalog; + using CRL::AllianceFramework; + using CRL::addMeasure; + using CRL::Measures; + using CRL::MeasuresSet; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TramontanaEngine". + + Name TramontanaEngine::_toolName = "Tramontana"; + + + const Name& TramontanaEngine::staticGetName () + { return _toolName; } + + + TramontanaEngine* TramontanaEngine::get ( const Cell* cell ) + { return static_cast(ToolEngine::get(cell,staticGetName())); } + + + TramontanaEngine::TramontanaEngine ( Cell* cell, uint32_t depth ) + : Super (cell, (depth==0)) + , _viewer (NULL) + , _depth (depth) + , _equipotentials() + { } + + + void TramontanaEngine::_postCreate () + { + Super::_postCreate(); + } + + + TramontanaEngine* TramontanaEngine::create ( Cell* cell, uint32_t depth ) + { + TramontanaEngine* tramontana = new TramontanaEngine ( cell, depth ); + + tramontana->_postCreate(); + + return tramontana; + } + + + void TramontanaEngine::_preDestroy () + { + cdebug_log(160,1) << "TramontanaEngine::_preDestroy()" << endl; + + cmess1 << " o Deleting ToolEngine<" << getName() << "> from Cell <" + << _cell->getName() << ">" << endl; + Super::_preDestroy(); + + cdebug_tabw(160,-1); + } + + + TramontanaEngine::~TramontanaEngine () + { } + + + const Name& TramontanaEngine::getName () const + { return _toolName; } + + + void TramontanaEngine::extract () + { + if (getDepth() == 0) { + cmess1 << " o Extracting " << getCell() << endl; + startMeasures(); + } + + cdebug_log(160,0) << "EXTRACTING " << getCell() << endl; + for ( Instance* instance : getCell()->getInstances() ) { + Cell* master = instance->getMasterCell(); + TramontanaEngine* extractor = TramontanaEngine::get( master ); + if (not extractor) { + extractor = TramontanaEngine::create( master, getDepth()+1 ); + extractor->extract(); + } + } + _extract(); + + if (getDepth() == 0) { + stopMeasures(); + printMeasures(); + } + } + + + void TramontanaEngine::_extract () + { + if (getDepth()) { + startMeasures(); + } + + SweepLine sweepLine ( this ); + sweepLine.run(); + consolidate(); + //showEquipotentials(); + + if (getDepth()) { + stopMeasures(); + + ostringstream header; + ostringstream result; + + header << " "; + for ( size_t i=0 ; igetName() ); + result << Timer::getStringTime (getTimer().getCombTime()) + << ", " << Timer::getStringMemory(getTimer().getIncrease()); + cmess1 << Dots::asString( header.str(), result.str() ) << endl; + } + } + + + void TramontanaEngine::showEquipotentials () const + { + cerr << "Equipotentials:" << endl; + for ( Equipotential* equi : _equipotentials ) { + equi->show(); + } + } + + + void TramontanaEngine::consolidate () + { + //cerr << "Tramontana::consolidate()" << endl; + for ( Equipotential* equi : _equipotentials ) + equi->consolidate(); + } + + + void TramontanaEngine::add ( Equipotential* equi ) + { + _equipotentials.insert( equi ); + } + + + string TramontanaEngine::_getTypeName () const + { return "Tramontana::TramontanaEngine"; } + + + string TramontanaEngine::_getString () const + { + ostringstream os; + os << "getName () << ">"; + return os.str(); + } + + + Record* TramontanaEngine::_getRecord () const + { + Record* record = Super::_getRecord (); + + if (record) { + record->add( getSlot( "_equipotentials", &_equipotentials ) ); + } + return record; + } + + +} // Tramontana namespace. diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h new file mode 100644 index 00000000..1f699663 --- /dev/null +++ b/tramontana/src/tramontana/Equipotential.h @@ -0,0 +1,175 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/Equipotential.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include "hurricane/Net.h" +#include "hurricane/Component.h" +#include "hurricane/Occurrence.h" +#include "hurricane/Occurrences.h" +#include "tramontana/EquipotentialRelation.h" + + +namespace Tramontana { + + using Hurricane::Record; + using Hurricane::Box; + using Hurricane::DbU; + using Hurricane::DBo; + using Hurricane::Entity; + using Hurricane::Layer; + using Hurricane::BasicLayer; + using Hurricane::Net; + using Hurricane::NetSet; + using Hurricane::Cell; + using Hurricane::Component; + using Hurricane::OccurrenceSet; + using Hurricane::Occurrence; + using Hurricane::Occurrences; + + + class NetCompareByName { + public: + bool operator() ( const Net* lhs, const Net* rhs ) const; + }; + + + class OccNetCompareByName { + public: + bool operator() ( const Occurrence& lhs, const Occurrence& rhs ) const; + }; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::ShortCircuit". + + class ShortCircuit { + public: + inline ShortCircuit ( Net*, Net*, Component* ); + private: + Net* _netA; + Net* _netB; + Component* _shortCircuit; + }; + + + inline ShortCircuit::ShortCircuit ( Net* a, Net* b, Component* shortCircuit ) + : _netA (a) + , _netB (b) + , _shortCircuit(shortCircuit) + { } + + +// ------------------------------------------------------------------- +// Class : "Tramontana::Equipotential". + + class Equipotential : public Entity { + public: + typedef Entity Super; + typedef std::map< Net*, std::pair, NetCompareByName > NetMap; + public: + static Equipotential* get ( Component* ); + static Equipotential* get ( Occurrence ); + static Occurrence getChildEqui ( Occurrence ); + public: + static Equipotential* create ( Cell* ); + inline bool isEmpty () const; + inline bool isBuried () 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; + void show () const; + inline bool hasComponent ( Component* ) const; + void add ( Occurrence, const Box& boundingBox=Box() ); + void merge ( Equipotential* ); + inline void add ( ShortCircuit* ); + void consolidate (); + void clear (); + inline const OccurrenceSet& getComponents () const; + inline const OccurrenceSet& getChilds () const; + inline const NetMap& getNets () const; + Occurrences getFlatComponents () const; + inline const std::vector& + getShortCircuits () 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; + NetMap _nets; + OccurrenceSet _components; + OccurrenceSet _childs; + std::string _name; + Net::Type _type; + Net::Direction _direction; + uint32_t _netCount; + bool _isBuried; + bool _isExternal; + bool _isGlobal; + bool _isAutomatic; + bool _hasFused; + std::vector _shortCircuits; + }; + + + + inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } + inline bool Equipotential::isBuried () const { return _isBuried; } + inline const OccurrenceSet& Equipotential::getComponents () const { return _components; } + inline const OccurrenceSet& Equipotential::getChilds () const { return _childs; } + inline const Equipotential::NetMap& + Equipotential::getNets () const { return _nets; } + 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& + Equipotential::getShortCircuits () const { return _shortCircuits; } + inline void Equipotential::add ( ShortCircuit* s ) { _shortCircuits.push_back( s ); } + + inline bool Equipotential::hasComponent ( Component* component ) const + { + if (component->getCell() != getCell()) return false; + EquipotentialRelation* relation = dynamic_cast( + component->getNet()->getProperty( EquipotentialRelation::staticGetName() )); + if (not relation) { + relation = dynamic_cast( + component->getProperty( EquipotentialRelation::staticGetName() )); + } + if (not relation) return false; + return (relation->getMasterOwner() == this); + } + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::Equipotential); diff --git a/tramontana/src/tramontana/EquipotentialComponents.h b/tramontana/src/tramontana/EquipotentialComponents.h new file mode 100644 index 00000000..ae502891 --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialComponents.h @@ -0,0 +1,110 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/EquipotentialComponents.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include +#include +#include +#include "hurricane/Collection.h" +#include "hurricane/DbU.h" +#include "hurricane/Box.h" +#include "hurricane/Net.h" +#include "hurricane/Occurrence.h" +#include "tramontana/Equipotential.h" + + +namespace Tramontana { + + using std::string; + using std::pair; + using std::list; + using std::vector; + using std::map; + using Hurricane::Record; + using Hurricane::DbU; + using Hurricane::Box; + using Hurricane::Entity; + using Hurricane::Component; + using Hurricane::Net; + using Hurricane::NetSet; + using Hurricane::Occurrence; + using Hurricane::OccurrenceSet; + using Hurricane::Filter; + using Hurricane::Locator; + using Hurricane::Collection; + using Hurricane::GenericFilter; + using Hurricane::GenericLocator; + using Hurricane::GenericCollection; + + typedef Hurricane::Locator ComponentsLocator; + typedef Hurricane::Locator OccurrencesLocator; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::EquipotentialComponents". + + class EquipotentialComponents : public Collection { + public: + typedef Collection Super; + static const uint16_t Constructed = (1<<0); + static const uint16_t InComponents = (1<<1); + static const uint16_t InNets = (1<<2); + static const uint16_t InChildEquis = (1<<3); + static const uint16_t Finished = (1<<4); + public: + class Locator : public Hurricane::Locator { + public: + typedef Hurricane::Locator Super; + public: + Locator (); + Locator ( const Equipotential* ); + Locator ( const Locator& ); + Locator& operator= ( const Locator& ); + virtual Occurrence getElement () const; + virtual Hurricane::Locator* + getClone () const; + virtual bool isValid () const; + virtual void progress (); + virtual std::string _getString () const; + private: + const Equipotential* _equipotential; + uint16_t _state; + OccurrenceSet::iterator _componentsIterator; + Equipotential::NetMap::const_iterator _netsIterator; + OccurrenceSet::iterator _childsIterator; + OccurrencesLocator* _childCompsLocator; + ComponentsLocator* _componentsLocator; + }; + + public: + EquipotentialComponents (); + EquipotentialComponents ( const Equipotential* ); + EquipotentialComponents ( const EquipotentialComponents& ); + EquipotentialComponents& operator= ( const EquipotentialComponents& ); + virtual Collection* getClone () const; + virtual Hurricane::Locator* getLocator () const; + virtual std::string _getString () const; + private: + const Equipotential* _equipotential; + }; + + + +} // Tramontana namespace. diff --git a/tramontana/src/tramontana/EquipotentialRelation.h b/tramontana/src/tramontana/EquipotentialRelation.h new file mode 100644 index 00000000..63f8031b --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialRelation.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/EquipotentialRelation.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include "hurricane/Relation.h" + + +namespace Tramontana { + + using Hurricane::Name; + using Hurricane::Record; + using Hurricane::Relation; + using Hurricane::Component; + class Equipotential; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::EquipotentialRelation". + + class EquipotentialRelation : public Relation { + public: + typedef Relation Super; + public: + static EquipotentialRelation* get ( const Component* ); + static EquipotentialRelation* create ( Equipotential* ); + static Name staticGetName (); + public: + virtual Name getName () const; + virtual std::string _getTypeName () const; + virtual Record* _getRecord () const; + private: + EquipotentialRelation ( Equipotential* ); + protected: + virtual void _preDestroy (); + }; + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::EquipotentialRelation); diff --git a/tramontana/src/tramontana/EquipotentialsModel.h b/tramontana/src/tramontana/EquipotentialsModel.h new file mode 100644 index 00000000..0a277e11 --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialsModel.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/EquipotentialsModel.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include +#include +#include "hurricane/Commons.h" +#include "hurricane/Name.h" +#include "hurricane/Net.h" +#include "hurricane/Cell.h" +#include "hurricane/viewer/Graphics.h" +#include "tramontana/Equipotential.h" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + + using Hurricane::Cell; + + + class EquipotentialsModel : public QAbstractTableModel { + Q_OBJECT; + + public: + EquipotentialsModel ( QObject* parent=NULL ); + void setCell ( Cell* cell ); + int rowCount ( const QModelIndex& parent=QModelIndex() ) const; + int columnCount ( const QModelIndex& parent=QModelIndex() ) const; + QVariant data ( const QModelIndex& index, int role=Qt::DisplayRole ) const; + QVariant headerData ( int section, Qt::Orientation orientation, int role=Qt::DisplayRole ) const; + inline Cell* getCell (); + const Equipotential* getEqui ( int row ); + + private: + Cell* _cell; + std::vector _equipotentials; + }; + + +// Inline Functions. + + inline Cell* EquipotentialsModel::getCell () { return _cell; } + + +} // Hurricane namespace. diff --git a/tramontana/src/tramontana/EquipotentialsWidget.h b/tramontana/src/tramontana/EquipotentialsWidget.h new file mode 100644 index 00000000..6df29cad --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialsWidget.h @@ -0,0 +1,186 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/EquipotentialsWidget.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include +#include +#include +#include +#include "hurricane/Commons.h" +#include "hurricane/Bug.h" +#include "hurricane/viewer/CellWidget.h" +#include "hurricane/viewer/CellWidget.h" +#include "tramontana/EquipotentialsModel.h" + + +class QSortFilterProxyModel; +class QModelIndex; +class QTableView; +class QLineEdit; +class QComboBox; +class QHeaderView; + + +namespace Tramontana { + + using std::string; + using std::set; + using Hurricane::Cell; + using Hurricane::CellWidget; + using Hurricane::OccurrenceSet; + + +// ------------------------------------------------------------------- +// Class : EquiFilterProxyModel". + + + class EquiFilterProxyModel : public QSortFilterProxyModel { + Q_OBJECT; + public: + typedef QSortFilterProxyModel Super; + static const uint32_t NoFilter = 0; + static const uint32_t ShowBuried = (1<<0); + public: + EquiFilterProxyModel ( QObject* ); + void setFilter ( uint32_t ); + virtual bool filterAcceptsRow ( int row, const QModelIndex& ) const; + private: + uint32_t _filter; + }; + + +// ------------------------------------------------------------------- +// Class : "SelectedEqui". + + + class SelectedEqui { + public: + inline SelectedEqui (); + inline SelectedEqui ( const Equipotential*, size_t access=0 ); + inline const Equipotential* getEqui () const; + inline size_t getAccesses () const; + inline void incAccesses () const; + inline void setInserted () const; + inline void resetAccesses () const; + private: + const Equipotential* _equi; + mutable size_t _accesses; + }; + + + inline SelectedEqui::SelectedEqui () : _equi(nullptr), _accesses(0) { } + inline SelectedEqui::SelectedEqui ( const Equipotential* equi, size_t accesses ) : _equi(equi), _accesses(accesses) { } + inline const Equipotential* SelectedEqui::getEqui () const { return _equi; } + inline void SelectedEqui::setInserted () const { _accesses = 64; } + inline size_t SelectedEqui::getAccesses () const { return _accesses; } + inline void SelectedEqui::incAccesses () const { ++_accesses; } + inline void SelectedEqui::resetAccesses () const { _accesses = 0; } + + + struct SelectedEquiCompare { + inline bool operator() ( const SelectedEqui& lhs, const SelectedEqui& rhs ) const; + }; + + + inline bool SelectedEquiCompare::operator() ( const SelectedEqui& lhs, const SelectedEqui& rhs ) const + { + return lhs.getEqui()->getId() < rhs.getEqui()->getId(); + } + + +// ------------------------------------------------------------------- +// Class : "SelectedEquiSet". + + + class SelectedEquiSet : public set{ + public: + void insert ( const Equipotential* ); + void forceInserteds (); + void resetAccesses (); + }; + + + inline void SelectedEquiSet::insert ( const Equipotential* equi ) + { + iterator iselected = find(SelectedEqui(equi)); + if (iselected != end()) + iselected->incAccesses(); + else + set::insert( SelectedEqui(equi,64) ); + } + + + inline void SelectedEquiSet::forceInserteds () + { + for ( iterator iselected=begin() ; iselected != end() ; ++iselected ) + iselected->setInserted(); + } + + + inline void SelectedEquiSet::resetAccesses () + { + for ( iterator iselected=begin() ; iselected != end() ; ++iselected ) + iselected->resetAccesses(); + } + + +// ------------------------------------------------------------------- +// Class : "EquipotentialsWidget". + + + class EquipotentialsWidget : public QWidget { + Q_OBJECT; + + public: + EquipotentialsWidget ( QWidget* parent=nullptr ); + inline Cell* getCell (); + void setShowBuried ( bool ); + void setCellWidget ( CellWidget* ); + void setCell ( Cell* ); + void goTo ( int ); + void updateSelecteds (); + QModelIndex mapToSource ( QModelIndex ) const; + signals: + void equipotentialSelect ( Occurrences ); + void equipotentialUnselect ( Occurrences ); + void reframe ( const Box& ); + private slots: + void textFilterChanged (); + void updateSelecteds ( const QItemSelection& , const QItemSelection& ); + void fitToEqui (); + + private: + CellWidget* _cellWidget; + Cell* _cell; + EquipotentialsModel* _baseModel; + QSortFilterProxyModel* _sortModel; + EquiFilterProxyModel* _filterModel; + QTableView* _view; + QLineEdit* _filterPatternLineEdit; + int _rowHeight; + SelectedEquiSet _selecteds; + bool _forceReselect; + }; + + + inline Cell* EquipotentialsWidget::getCell () { return _cell; } + + +} // Hurricane namespace. diff --git a/tramontana/src/tramontana/GraphicTramontanaEngine.h b/tramontana/src/tramontana/GraphicTramontanaEngine.h new file mode 100644 index 00000000..c16588f4 --- /dev/null +++ b/tramontana/src/tramontana/GraphicTramontanaEngine.h @@ -0,0 +1,83 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/GraphicTramontanaEngine.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include + +namespace Hurricane { + class Go; + class BasicLayer; + class Transformation; + class CellWidget; + class CellViewer; +} + +#include "crlcore/GraphicToolEngine.h" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + + using Hurricane::Go; + using Hurricane::Box; + using Hurricane::BasicLayer; + using Hurricane::Transformation; + using Hurricane::CellWidget; + using Hurricane::CellViewer; + using CRL::GraphicTool; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::GraphicTramontanaEngine". + + class GraphicTramontanaEngine : public GraphicTool { + Q_OBJECT; + + public: + enum FunctionFlags { NoFlags=0x0000, CreateEngine=0x0001 }; + public: +#if THIS_IS_DISABLED + static void initGCell ( CellWidget* ); + static void drawGCell ( CellWidget* + , const Go* + , const BasicLayer* + , const Box& + , const Transformation& + ); +#endif + TramontanaEngine* createEngine (); + TramontanaEngine* getForFramework ( uint32_t flags ); + static GraphicTramontanaEngine* grab (); + virtual const Name& getName () const; + Cell* getCell (); + virtual size_t release (); + virtual void addToMenu ( CellViewer* ); + void postEvent (); + protected: + static size_t _references; + static GraphicTramontanaEngine* _singleton; + CellViewer* _viewer; + protected: + GraphicTramontanaEngine (); + virtual ~GraphicTramontanaEngine (); + void _extract (); + }; + + +} // Tramontana namespace. diff --git a/tramontana/src/tramontana/PyGraphicTramontanaEngine.h b/tramontana/src/tramontana/PyGraphicTramontanaEngine.h new file mode 100644 index 00000000..bc78e334 --- /dev/null +++ b/tramontana/src/tramontana/PyGraphicTramontanaEngine.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/PyGraphicTramontanaEngine.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include "crlcore/PyGraphicToolEngine.h" +#include "tramontana/GraphicTramontanaEngine.h" + + +namespace Tramontana { + +extern "C" { + + +// ------------------------------------------------------------------- +// Python Object : "PyGraphicTramontanaEngine". + + typedef struct { + CRL::PyGraphicTool _baseObject; + } PyGraphicTramontanaEngine; + + +// ------------------------------------------------------------------- +// Functions & Types exported to "PyTramontana.ccp". + + extern PyTypeObject PyTypeGraphicTramontanaEngine; + extern PyMethodDef PyGraphicTramontanaEngine_Methods[]; + + extern void PyGraphicTramontanaEngine_LinkPyType (); + + +#define IsPyGraphicTramontanaEngine(v) ( (v)->ob_type == &PyTypeGraphicTramontanaEngine ) +#define PY_GRAPHIC_TRAMONTANA_ENGINE(v) ( (PyGraphicTramontanaEngine*)(v) ) +#define PY_GRAPHIC_TRAMONTANA_ENGINE_O(v) ( PY_GRAPHIC_TRAMONTANA_ENGINE(v)->_baseObject._object ) + + +} // extern "C". + +} // Tramontana namespace. diff --git a/tramontana/src/tramontana/PyTramontanaEngine.h b/tramontana/src/tramontana/PyTramontanaEngine.h new file mode 100644 index 00000000..5dfec18f --- /dev/null +++ b/tramontana/src/tramontana/PyTramontanaEngine.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/PyTramontanaEngine.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include "hurricane/isobar/PyHurricane.h" +#include "crlcore/PyToolEngine.h" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + +extern "C" { + + +// ------------------------------------------------------------------- +// Python Object : "PyTramontanaEngine". + + typedef struct { + CRL::PyToolEngine _baseObject; + } PyTramontanaEngine; + + +// ------------------------------------------------------------------- +// Functions & Types exported to "PyTramontana.ccp". + + extern PyTypeObject PyTypeTramontanaEngine; + extern PyMethodDef PyTramontanaEngine_Methods[]; + + extern PyObject* PyTramontanaEngine_Link ( Tramontana::TramontanaEngine* ); + extern void PyTramontanaEngine_LinkPyType (); +//extern void PyTramontanaEngine_postModuleInit (); + + +#define IsPyTramontanaEngine(v) ( (v)->ob_type == &PyTypeTramontanaEngine ) +#define PYTRAMONTANAENGINE(v) ( (PyTramontanaEngine*)(v) ) +#define PYTRAMONTANAENGINE_O(v) ( PYTRAMONTANAENGINE(v)->_baseObject._object ) + + +} // extern "C". + +} // Tramontana namespace. diff --git a/tramontana/src/tramontana/QueryTiles.h b/tramontana/src/tramontana/QueryTiles.h new file mode 100644 index 00000000..b1742013 --- /dev/null +++ b/tramontana/src/tramontana/QueryTiles.h @@ -0,0 +1,60 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/QueryTiles.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include "hurricane/Query.h" + + +namespace Tramontana { + + using Hurricane::Box; + using Hurricane::DbU; + using Hurricane::Layer; + using Hurricane::BasicLayer; + using Hurricane::Go; + using Hurricane::Component; + using Hurricane::Rubber; + using Hurricane::Query; + class SweepLine; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::QueryTiles". + + class QueryTiles : public Query { + public: + QueryTiles ( SweepLine* ); + bool isProcessed ( Component* ) const; + virtual void setBasicLayer ( const BasicLayer* ); + virtual bool hasGoCallback () const; + virtual void goCallback ( Go* ); + virtual void rubberCallback ( Rubber* ); + virtual void extensionGoCallback ( Go* ); + virtual void masterCellCallback (); + inline uint32_t getGoMatchCount () const; + private: + SweepLine* _sweepLine; + uint32_t _goMatchCount; + Layer::Mask _processedLayers; + }; + + + inline uint32_t QueryTiles::getGoMatchCount () const { return _goMatchCount; } + + +} // Tramontana namespace. diff --git a/tramontana/src/tramontana/SweepLine.h b/tramontana/src/tramontana/SweepLine.h new file mode 100644 index 00000000..4ab04e98 --- /dev/null +++ b/tramontana/src/tramontana/SweepLine.h @@ -0,0 +1,137 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/SweepLine.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include +#include +#include "hurricane/BasicLayer.h" +namespace Hurricane { + class Net; +} +#include "tramontana/Tile.h" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + + using Hurricane::Record; + using Hurricane::Box; + using Hurricane::DbU; + using Hurricane::DBo; + using Hurricane::Cell; + using Hurricane::Layer; + using Hurricane::BasicLayer; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::SweepLine". + + class SweepLine { + private: + typedef std::map IntervalTrees; + public: + typedef std::set LayerSet; + typedef std::map ConnexityMap; + private: + class Element { + public: + inline Element ( Tile*, uint32_t flags ); + inline bool operator< ( const Element& ) const; + 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; + }; + public: + SweepLine ( TramontanaEngine* ); + ~SweepLine (); + inline Cell* getCell (); + inline const std::vector& + getExtracteds () const; + inline Layer::Mask getExtractedMask () const; + const LayerSet& getCutConnexLayers ( const BasicLayer* ) const; + void run (); + void loadTiles (); + void deleteTiles (); + inline void add ( Tile* ); + void mergeEquipotentials (); + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + 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; + }; + + +// 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 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 (isLeftEdge() xor rhs.isLeftEdge()) return isLeftEdge(); + if (getY() != rhs.getY()) return (getY() < rhs.getY()); + if (getMask() != rhs.getMask()) return (getMask() < rhs.getMask()); + return TileCompare() ( getTile(), rhs.getTile() ); + } + + + inline bool SweepLine::Element::operator== ( const Element& rhs ) const + { return getTile() == rhs.getTile(); } + + +// SweepLine. + inline Cell* SweepLine::getCell () { return _tramontana->getCell(); } + inline const std::vector& SweepLine::getExtracteds () const { return _extracteds; } + inline Layer::Mask SweepLine::getExtractedMask () const { return _extractedsMask; } + + inline void SweepLine::add ( Tile* tile ) + { + _tiles.push_back( Element( tile, Tile::LeftEdge ) ); + _tiles.push_back( Element( tile, Tile::RightEdge ) ); + } + + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::SweepLine); diff --git a/tramontana/src/tramontana/TabEquipotentials.h b/tramontana/src/tramontana/TabEquipotentials.h new file mode 100644 index 00000000..8945c2f7 --- /dev/null +++ b/tramontana/src/tramontana/TabEquipotentials.h @@ -0,0 +1,60 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/TabEquipotentials.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include "hurricane/viewer/ControllerWidget.h" +#include "tramontana/EquipotentialsWidget.h" + + +namespace Tramontana { + + using Hurricane::ControllerTab; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TabEquipotentials". + + + class TabEquipotentials : public ControllerTab { + Q_OBJECT; + + public: + TabEquipotentials ( QWidget* parent=NULL ); + inline EquipotentialsWidget* getBrowser (); + virtual void cellPreModificate (); + virtual void cellPostModificate (); + public slots: + virtual void setCell ( Cell* ); + virtual void setCellWidget ( CellWidget* ); + virtual void setSyncEquipotentials ( bool ); + virtual void setSyncSelection ( bool ); + virtual void setShowBuried ( bool ); + + protected: + EquipotentialsWidget* _browser; + QCheckBox* _syncEquipotentials; + QCheckBox* _syncSelection; + QCheckBox* _showBuried; + bool _cwCumulativeSelection; + }; + + + inline EquipotentialsWidget* TabEquipotentials::getBrowser () { return _browser; } + + +} diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h new file mode 100644 index 00000000..6414719e --- /dev/null +++ b/tramontana/src/tramontana/Tile.h @@ -0,0 +1,173 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/Tile.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include "hurricane/Box.h" +#include "hurricane/BasicLayer.h" +#include "hurricane/Component.h" +#include "hurricane/Occurrence.h" +#include "hurricane/IntervalTree.h" +namespace Hurricane { + class Net; +} + + +namespace Tramontana { + + using Hurricane::Record; + using Hurricane::Box; + using Hurricane::DbU; + using Hurricane::Layer; + using Hurricane::BasicLayer; + using Hurricane::Net; + using Hurricane::Cell; + using Hurricane::Component; + using Hurricane::Occurrence; + using Hurricane::RbTree; + using Hurricane::IntervalData; + using Hurricane::IntervalTree; + class Equipotential; + class SweepLine; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::Tile". + + 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 MakeLeafEqui = (1<<4); + static const uint32_t ForceLayer = (1<<5); + static const uint32_t OccMerged = (1<<6); + public: + static inline const std::vector getAllTiles (); + static void deleteAllTiles (); + static inline void timeTick (); + static Tile* create ( Occurrence + , const BasicLayer* + , Tile* rootTile + , SweepLine* + , uint32_t flags=NoFlags ); + void destroy (); + inline bool isUpToDate () const; + inline bool isOccMerged () const; + inline unsigned int getId () const; + inline uint32_t getRank () const; + inline Tile* getParent () const; + Tile* getRoot ( uint32_t flags=Compress ); + //inline Component* getComponent () const; + inline Occurrence getOccurrence () const; + // Net* getNet () 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; + inline DbU::Unit getRightEdge () const; + inline DbU::Unit getYMin () const; + inline DbU::Unit getYMax () const; + inline uint32_t getFlags () const; + inline void incRank (); + inline void syncTime (); + inline void setParent ( Tile* ); + Tile* merge ( Tile* ); + inline void setOccMerged ( bool state ); + inline void setEquipotential ( Equipotential* ); + Equipotential* newEquipotential (); + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + private: + Tile ( Occurrence, const BasicLayer*, const Box&, Tile* parent ); + ~Tile (); + private: + Tile ( const Tile& ) = delete; + Tile& operator= ( const Tile& ) = delete; + private: + static uint32_t _idCounter; + static uint32_t _time; + static std::vector _allocateds; + uint32_t _id; + Occurrence _occurrence; + const BasicLayer* _layer; + Box _boundingBox; + Equipotential* _equipotential; + uint32_t _flags; + Tile* _parent; + uint32_t _rank; + uint32_t _timeStamp; + }; + + inline const std::vector Tile::getAllTiles () { return _allocateds; } + inline void Tile::timeTick () { _time++; } + inline bool Tile::isUpToDate () const { return _timeStamp >= _time; } + inline bool Tile::isOccMerged () const { return _flags & OccMerged; } + inline unsigned int Tile::getId () const { return _id; } +//inline Component* Tile::getComponent () const { return dynamic_cast( _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; } + inline DbU::Unit Tile::getLeftEdge () const { return _boundingBox.getXMin(); } + inline DbU::Unit Tile::getRightEdge () const { return _boundingBox.getXMax(); } + inline DbU::Unit Tile::getYMin () const { return _boundingBox.getYMin(); } + inline DbU::Unit Tile::getYMax () const { return _boundingBox.getYMax(); } + inline uint32_t Tile::getFlags () const { return _flags; } + inline uint32_t Tile::getRank () const { return _rank; } + inline Tile* Tile::getParent () const { return _parent; } + inline void Tile::incRank () { _rank++; } + inline void Tile::syncTime () { _timeStamp=_time; } + inline void Tile::setParent ( Tile* parent ) { _parent=parent; } + inline void Tile::setEquipotential ( Equipotential* equi ) { _equipotential=equi; } + + inline void Tile::setOccMerged ( bool state ) + { if (state) _flags |= OccMerged; + else _flags &= ~OccMerged; } + + + class TileCompare { + public: + inline bool operator() ( const Tile* lhs, const Tile* rhs ) const + { + cdebug_log(0,0) << "TileCompare::operator()" << std::endl; + return lhs->getId() < rhs->getId(); + } + }; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TileIntvTree". + + + typedef IntervalData TileIntv; + typedef IntervalTree TileIntvTree; + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::Tile); +INSPECTOR_PR_SUPPORT(Tramontana::TileIntv); +INSPECTOR_PR_SUPPORT(Tramontana::TileIntvTree); diff --git a/tramontana/src/tramontana/TramontanaEngine.h b/tramontana/src/tramontana/TramontanaEngine.h new file mode 100644 index 00000000..d5beae81 --- /dev/null +++ b/tramontana/src/tramontana/TramontanaEngine.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/TramontanaEngine.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include + +#include "hurricane/Name.h" +namespace Hurricane { + class Layer; + class Net; + class Cell; + class CellViewer; +} +#include "crlcore/ToolEngine.h" +#include "tramontana/Equipotential.h" + + +namespace Tramontana { + + using Hurricane::Record; + using Hurricane::Name; + using Hurricane::Layer; + using Hurricane::Net; + using Hurricane::Cell; + using Hurricane::CellViewer; + using CRL::ToolEngine; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TramontanaEngine". + + class TramontanaEngine : public ToolEngine { + public: + typedef ToolEngine Super; + public: + static const Name& staticGetName (); + static TramontanaEngine* create ( Cell*, uint32_t depth=0 ); + static TramontanaEngine* get ( const Cell* ); + public: + const Name& getName () const; + inline uint32_t getDepth () const; + inline const std::set + getEquipotentials () const; + inline void setViewer ( CellViewer* ); + inline CellViewer* getViewer (); + void extract (); + void _extract (); + void consolidate (); + void showEquipotentials () const; + void add ( Equipotential* ); + virtual Record* _getRecord () const; + virtual std::string _getString () const; + virtual std::string _getTypeName () const; + private: + // Attributes. + static Name _toolName; + private: + CellViewer* _viewer; + uint32_t _depth; + std::set _equipotentials; + protected: + // Constructors & Destructors. + TramontanaEngine ( Cell*, uint32_t depth ); + virtual ~TramontanaEngine (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + TramontanaEngine ( const TramontanaEngine& ) = delete; + TramontanaEngine& operator= ( const TramontanaEngine& ) = delete; + }; + + + inline void TramontanaEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } + inline CellViewer* TramontanaEngine::getViewer () { return _viewer; } + inline uint32_t TramontanaEngine::getDepth () const { return _depth; } + inline const std::set + TramontanaEngine::getEquipotentials () const { return _equipotentials; } + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::TramontanaEngine); diff --git a/unicorn/CMakeLists.txt b/unicorn/CMakeLists.txt index 8c407065..119cb23e 100644 --- a/unicorn/CMakeLists.txt +++ b/unicorn/CMakeLists.txt @@ -38,8 +38,8 @@ #find_package(KNIK REQUIRED) #find_package(KATABATIC REQUIRED) #find_package(KITE REQUIRED) - find_package(EQUINOX REQUIRED) - find_package(SOLSTICE REQUIRED) + #find_package(EQUINOX REQUIRED) + #find_package(SOLSTICE REQUIRED) #find_package(TUTORIAL REQUIRED) # FIXME: make FindTUTORIAL.cmake find_package(Doxygen) diff --git a/unicorn/src/CgtMain.cpp b/unicorn/src/CgtMain.cpp index b9249dbe..deb9c28c 100644 --- a/unicorn/src/CgtMain.cpp +++ b/unicorn/src/CgtMain.cpp @@ -58,8 +58,8 @@ using namespace CRL; #include "katana/GraphicKatanaEngine.h" #include "etesian/GraphicEtesianEngine.h" #include "katana/GraphicKatanaEngine.h" -#include "equinox/GraphicEquinoxEngine.h" -#include "solstice/GraphicSolsticeEngine.h" +//#include "equinox/GraphicEquinoxEngine.h" +//#include "solstice/GraphicSolsticeEngine.h" #include "unicorn/UnicornGui.h" using namespace Unicorn; diff --git a/unicorn/src/cgt.py b/unicorn/src/cgt.py index 3c7b22f0..85fc9936 100755 --- a/unicorn/src/cgt.py +++ b/unicorn/src/cgt.py @@ -20,7 +20,7 @@ try: from coriolis import helpers helpers.loadUserSettings() from coriolis import Cfg, Hurricane, Viewer, CRL, Etesian, Anabatic, \ - Katana, Bora, Tutorial, Unicorn + Katana, Tramontana, Bora, Tutorial, Unicorn except Exception as e: helpers.io.showPythonTrace( sys.argv[0], e ) sys.exit(2) @@ -179,8 +179,8 @@ if __name__ == '__main__': unicorn = Unicorn.UnicornGui.create() unicorn.setApplicationName ('cgt') unicorn.registerTool (Etesian.GraphicEtesianEngine.grab()) - #unicorn.registerTool (Kite.GraphicKiteEngine.grab()) unicorn.registerTool (Katana.GraphicKatanaEngine.grab()) + unicorn.registerTool (Tramontana.GraphicTramontanaEngine.grab()) unicorn.registerTool (Bora.GraphicBoraEngine.grab()) unicorn.registerTool (Tutorial.GraphicTutorialEngine.grab()) #unicorn.setAnonNetSelectable(False) diff --git a/unittests/python/test_rectilinear.py b/unittests/python/test_rectilinear.py new file mode 100644 index 00000000..447dce17 --- /dev/null +++ b/unittests/python/test_rectilinear.py @@ -0,0 +1,168 @@ +#!/usr/bin/python + +import sys +from coriolis.Hurricane import DataBase, Net, \ + DbU, Point, Box, Pad, Rectilinear +from coriolis import Cfg +from coriolis.CRL import AllianceFramework, Catalog, Gds +from coriolis.helpers import l, u +from coriolis.helpers.overlay import CfgCache, UpdateSession + + +def testRectilinear ( editor ): + """Check Hurricane.Rectilinear class.""" + with CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg: + cfg.misc.minTraceLevel = 17000 + cfg.misc.maxTraceLevel = 18000 + with UpdateSession(): + cell = AllianceFramework.get().createCell( 'Rectilinear' ) + cell.setTerminalNetlist( True ) + cell.setAbutmentBox( Box( l(-5.0), l(-5.0), l(400.0), l(200.0) ) ) + #cell.setAbutmentBox( Box( l(-5.0), l(-5.0), l(21.0), l(35.0) ) ) + if editor: + editor.setCell( cell ) + editor.fit() + + technology = DataBase.getDB().getTechnology() + metal1 = technology.getLayer( "METAL1" ) + metal2 = technology.getLayer( "METAL2" ) + metal3 = technology.getLayer( "METAL3" ) + metal4 = technology.getLayer( "METAL4" ) + poly = technology.getLayer( "POLY" ) + ptrans = technology.getLayer( "PTRANS" ) + ntrans = technology.getLayer( "NTRANS" ) + pdif = technology.getLayer( "PDIF" ) + ndif = technology.getLayer( "NDIF" ) + contdifn = technology.getLayer( "CONT_DIF_N" ) + contdifp = technology.getLayer( "CONT_DIF_P" ) + nwell = technology.getLayer( "NWELL" ) + contpoly = technology.getLayer( "CONT_POLY" ) + ntie = technology.getLayer( "NTIE" ) + + with UpdateSession(): + net = Net.create( cell, 'my_net' ) + net.setExternal( True ) + + points = [ Point( l( 0.0), l( 0.0) ) + , Point( l( 0.0), l( 10.0) ) + , 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( 0.0), l( 0.0) ) ] + r = Rectilinear.create( net, metal2, points ) + + #print( 'Normalized and manhattanized contour:' ) + #i = 0 + #for point in p.getMContour(): + # print( '| %d '%i, point, '[%fum %fum]' % ( u(point.getX()), u(point.getY()) )) + # i += 1 + + #points = [ Point( l( 0.0), l( 40.0) ) # 0 + # , Point( l( 30.0), l( 40.0) ) # 1 + # , Point( l( 30.0), l( 60.0) ) # 2 + # , Point( l( 50.0), l( 60.0) ) # 3 + # , Point( l( 50.0), l( 80.0) ) # 4 + # , Point( l( 90.0), l( 80.0) ) # 5 + # , Point( l( 90.0), l( 50.0) ) # 6 + # , Point( l( 60.0), l( 50.0) ) # 7 + # , Point( l( 60.0), l( 30.0) ) # 8 + # , Point( l( 70.0), l( 30.0) ) # 9 + # , Point( l( 70.0), l( 20.0) ) # 10 + # , Point( l( 90.0), l( 20.0) ) # 11 + # , 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( 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 + , Point( l( 10.0), l( 30.0) ) # 3 + , Point( l( 20.0), l( 30.0) ) # 4 + , Point( l( 20.0), l( 40.0) ) # 5 + , Point( l( 40.0), l( 40.0) ) # 6 + , 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 + , Point( l( 0.0), l(120.0) ) # 13 + , Point( l( 10.0), l(120.0) ) # 14 + , Point( l( 10.0), l(110.0) ) # 15 + , Point( l( 20.0), l(110.0) ) # 16 + , 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 + , Point( l( 10.0), l(160.0) ) # 23 + , Point( l( 0.0), l(160.0) ) # 24 + , Point( l( 0.0), l(180.0) ) # 25 + , Point( l( 40.0), l(180.0) ) # 26 + , 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 + , Point( l(130.0), l(140.0) ) # 33 + , Point( l(120.0), l(140.0) ) # 34 + , Point( l(120.0), l(130.0) ) # 35 + , Point( l(110.0), l(130.0) ) # 36 + , 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 + , Point( l(150.0), l( 80.0) ) # 43 + , Point( l(120.0), l( 80.0) ) # 44 + , Point( l(120.0), l( 70.0) ) # 45 + , Point( l(110.0), l( 70.0) ) # 46 + , 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 + , Point( l(150.0), l( 20.0) ) # 53 + , 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( 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 = [] + r.getAsRectangles( boxes ) + #print( 'boxes={}'.format( boxes )) + for box in boxes: + box.translate( l(180.0), l(0.0) ) + Pad.create( net, metal3, box ) + + Gds.save( cell ) + + +def scriptMain ( **kw ): + """The mandatory function to be called by Coriolis CGT/Unicorn.""" + editor = None + if 'editor' in kw and kw['editor']: + editor = kw['editor'] + testRectilinear( editor ) + return True diff --git a/unittests/src/unittests.cpp b/unittests/src/unittests.cpp index 232a2d0c..93cf2282 100644 --- a/unittests/src/unittests.cpp +++ b/unittests/src/unittests.cpp @@ -65,6 +65,7 @@ namespace { cerr << endl << endl; } + rb.remove( Interval( l(3), l(4) )); rb.write( "finalRbTree.gv" ); for ( Interval intv : rb.getElements() ) { @@ -100,6 +101,7 @@ namespace { cerr << endl << endl; } + itree.remove( IntvString( "a", l(3), l(4) )); itree.write( "finalIntervalTree.gv" ); for ( IntervalData intv : itree.getElements() ) {