From 090c13663ec6f082c3b0d0e7d4283982e14e1265 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 16 Mar 2023 15:06:11 +0100 Subject: [PATCH 01/28] Create stub for Tramontana, reimplementation of the extractor/LVX. --- bootstrap/build.conf | 5 +- cumulus/src/designflow/pnr.py | 4 +- tramontana/CMakeLists.txt | 29 ++ tramontana/src/CMakeLists.txt | 59 +++++ tramontana/src/GraphicTramontanaEngine.cpp | 250 ++++++++++++++++++ tramontana/src/PyGraphicTramontanaEngine.cpp | 113 ++++++++ tramontana/src/PyTramontana.cpp | 107 ++++++++ tramontana/src/PyTramontanaEngine.cpp | 194 ++++++++++++++ tramontana/src/TramontanaEngine.cpp | 173 ++++++++++++ .../src/tramontana/GraphicTramontanaEngine.h | 83 ++++++ .../tramontana/PyGraphicTramontanaEngine.h | 53 ++++ .../src/tramontana/PyTramontanaEngine.h | 56 ++++ tramontana/src/tramontana/TramontanaEngine.h | 83 ++++++ unicorn/src/cgt.py | 4 +- 14 files changed, 1207 insertions(+), 6 deletions(-) create mode 100644 tramontana/CMakeLists.txt create mode 100644 tramontana/src/CMakeLists.txt create mode 100644 tramontana/src/GraphicTramontanaEngine.cpp create mode 100644 tramontana/src/PyGraphicTramontanaEngine.cpp create mode 100644 tramontana/src/PyTramontana.cpp create mode 100644 tramontana/src/PyTramontanaEngine.cpp create mode 100644 tramontana/src/TramontanaEngine.cpp create mode 100644 tramontana/src/tramontana/GraphicTramontanaEngine.h create mode 100644 tramontana/src/tramontana/PyGraphicTramontanaEngine.h create mode 100644 tramontana/src/tramontana/PyTramontanaEngine.h create mode 100644 tramontana/src/tramontana/TramontanaEngine.h 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/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/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..373178f4 --- /dev/null +++ b/tramontana/src/CMakeLists.txt @@ -0,0 +1,59 @@ +# -*- 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/TramontanaEngine.h + tramontana/GraphicTramontanaEngine.h + ) + set( pyIncludes tramontana/PyTramontanaEngine.h + tramontana/PyGraphicTramontanaEngine.h + ) + set( mocIncludes tramontana/GraphicTramontanaEngine.h ) + set( cpps TramontanaEngine.cpp + GraphicTramontanaEngine.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/GraphicTramontanaEngine.cpp b/tramontana/src/GraphicTramontanaEngine.cpp new file mode 100644 index 00000000..093b7be5 --- /dev/null +++ b/tramontana/src/GraphicTramontanaEngine.cpp @@ -0,0 +1,250 @@ +// -*- 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 + + +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("placeAndRoute.extract")) { + cerr << Warning( "GraphicTramontanaEngine::addToMenu() - Tramontana extractor already hooked in." ) << endl; + return; + } + + _viewer->addToMenu( "placeAndRoute.extract" + , "E&xtract . . . . . [Tramontana]" + , "Run the extractor" + , std::bind(&GraphicTramontanaEngine::_extract,this) + ); + } + + + 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..900eed41 --- /dev/null +++ b/tramontana/src/PyTramontanaEngine.cpp @@ -0,0 +1,194 @@ +// -*- 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; + } + + + // 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." } + , { "setViewer" , (PyCFunction)PyTramontanaEngine_setViewer , METH_VARARGS + , "Associate a Viewer to this TramontanaEngine." } + , {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/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp new file mode 100644 index 00000000..3d09d1a0 --- /dev/null +++ b/tramontana/src/TramontanaEngine.cpp @@ -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++ 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/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 ) + : Super (cell) + , _viewer (NULL) + { } + + + void TramontanaEngine::_postCreate () + { + Super::_postCreate(); + } + + + TramontanaEngine* TramontanaEngine::create ( Cell* cell ) + { + TramontanaEngine* tramontana = new TramontanaEngine ( cell ); + + 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 () + { + cerr << "TramontanaEngine::extract() called on " << getCell() << endl; + } + + + 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( "_blocks" , &_blocks ) ); + } + return record; + } + + +} // Tramontana 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/TramontanaEngine.h b/tramontana/src/tramontana/TramontanaEngine.h new file mode 100644 index 00000000..a0dc3642 --- /dev/null +++ b/tramontana/src/tramontana/TramontanaEngine.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/TramontanaEngine.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include + +#include "hurricane/Name.h" +namespace Hurricane { + class Layer; + class Net; + class Cell; + class CellViewer; +} +#include "crlcore/ToolEngine.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* ); + static TramontanaEngine* get ( const Cell* ); + public: + const Name& getName () const; + inline void setViewer ( CellViewer* ); + void extract (); + virtual Record* _getRecord () const; + virtual std::string _getString () const; + virtual std::string _getTypeName () const; + private: + // Attributes. + static Name _toolName; + protected: + CellViewer* _viewer; + protected: + // Constructors & Destructors. + TramontanaEngine ( Cell* ); + 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; } + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::TramontanaEngine); diff --git a/unicorn/src/cgt.py b/unicorn/src/cgt.py index 337386cb..bfad2270 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) @@ -182,8 +182,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) From 1f4b9450e5aa140335ef789d9356bea5557bac53 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sat, 18 Mar 2023 18:11:03 +0100 Subject: [PATCH 02/28] Fix, IntervalTree::overlap_iterator was progressing one step too far. --- hurricane/src/hurricane/hurricane/IntervalTree.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hurricane/src/hurricane/hurricane/IntervalTree.h b/hurricane/src/hurricane/hurricane/IntervalTree.h index 7d4673b2..f479651c 100644 --- a/hurricane/src/hurricane/hurricane/IntervalTree.h +++ b/hurricane/src/hurricane/hurricane/IntervalTree.h @@ -186,8 +186,9 @@ namespace Hurricane { template< typename Data > typename IntervalTree::overlap_iterator& IntervalTree::overlap_iterator::operator++ () { - while (this->isValid()) { + while ( true ) { Super::iterator::operator++(); + if (not this->isValid()) break; cdebug_log(0,0) << "IntervalTree::overlap_iterator::operator++() " << ::getString(this->getNode()) << std::endl; From 5879a5b581f2cd532480b8f5c3cd053823cebc08 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sat, 18 Mar 2023 18:12:24 +0100 Subject: [PATCH 03/28] Removing Solstice & Equinox from Unicorn (forgotten bits). --- unicorn/CMakeLists.txt | 4 ++-- unicorn/src/CgtMain.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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; From 8f387620cbeeea2a0182c8a16c5bcb3ad80dc7ec Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sat, 18 Mar 2023 18:17:23 +0100 Subject: [PATCH 04/28] One Layer, one Cell extraction implementation in Tramontana. * New: Tramontana::Equipotential, implemented. * Change: Tramontana::Tile, add UnionFind capabilities and Equipotential attribute. * New: Tramontana::SweepLine, build upon Hurricane::IntervalTree, can now perform a "one layer only" extraction (checked with "metal1"). --- tramontana/src/CMakeLists.txt | 10 +- tramontana/src/Equipotential.cpp | 189 +++++++++++++++ tramontana/src/PyTramontanaEngine.cpp | 22 ++ tramontana/src/SweepLine.cpp | 166 +++++++++++++ tramontana/src/Tile.cpp | 239 +++++++++++++++++++ tramontana/src/TramontanaEngine.cpp | 26 +- tramontana/src/tramontana/Equipotential.h | 95 ++++++++ tramontana/src/tramontana/SweepLine.h | 100 ++++++++ tramontana/src/tramontana/Tile.h | 142 +++++++++++ tramontana/src/tramontana/TramontanaEngine.h | 10 +- 10 files changed, 993 insertions(+), 6 deletions(-) create mode 100644 tramontana/src/Equipotential.cpp create mode 100644 tramontana/src/SweepLine.cpp create mode 100644 tramontana/src/Tile.cpp create mode 100644 tramontana/src/tramontana/Equipotential.h create mode 100644 tramontana/src/tramontana/SweepLine.h create mode 100644 tramontana/src/tramontana/Tile.h diff --git a/tramontana/src/CMakeLists.txt b/tramontana/src/CMakeLists.txt index 373178f4..abc8f8c5 100644 --- a/tramontana/src/CMakeLists.txt +++ b/tramontana/src/CMakeLists.txt @@ -9,14 +9,20 @@ ${Boost_INCLUDE_DIRS} ${Python_INCLUDE_DIRS} ) - set( includes tramontana/TramontanaEngine.h + set( includes tramontana/Tile.h + tramontana/SweepLine.h + tramontana/Equipotential.h + tramontana/TramontanaEngine.h tramontana/GraphicTramontanaEngine.h ) set( pyIncludes tramontana/PyTramontanaEngine.h tramontana/PyGraphicTramontanaEngine.h ) set( mocIncludes tramontana/GraphicTramontanaEngine.h ) - set( cpps TramontanaEngine.cpp + set( cpps Tile.cpp + SweepLine.cpp + Equipotential.cpp + TramontanaEngine.cpp GraphicTramontanaEngine.cpp ) set( pyCpps PyTramontana.cpp diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp new file mode 100644 index 00000000..8a1df31c --- /dev/null +++ b/tramontana/src/Equipotential.cpp @@ -0,0 +1,189 @@ +// -*- 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 "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 "crlcore/Utilities.h" +#include "tramontana/Equipotential.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::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::RoutingPad; + using Hurricane::Cell; + using Hurricane::Instance; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::Equipotential". + + + Equipotential::Equipotential ( Cell* owner ) + : _owner (owner) + , _boundingBox() + , _components () + , _childs () + { } + + + 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 () + { } + + + Cell* Equipotential::getCell () const + { return _owner; } + + + Box Equipotential::getBoundingBox () const + { return _boundingBox; } + + + void Equipotential::add ( Component* component ) + { + _components.insert( component ); + } + + + void Equipotential::add ( Occurrence child ) + { + if (child.getPath().isEmpty()) + add( dynamic_cast( child.getEntity() )); + else + _childs.push_back( child ); + } + + + 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 ( Component* component : other->getComponents() ) { + add( component ); + } + for ( Occurrence child : other->getChilds() ) { + add( child ); + } + other->clear(); + } + + + void Equipotential::clear () + { + _components.clear(); + _childs .clear(); + } + + + string Equipotential::_getTypeName () const + { return "Tramontana::Equipotential"; } + + + string Equipotential::_getString () const + { + ostringstream os; + os << "getName() << ">"; + return os.str(); + } + + + Record* Equipotential::_getRecord () const + { + Record* record = new Record ( _getString() ); + if (record) { + record->add( getSlot( "_owner" , &_owner ) ); + record->add( getSlot( "_boundingBox", &_boundingBox ) ); + record->add( getSlot( "_components" , &_components ) ); + record->add( getSlot( "_childs" , &_childs ) ); + } + return record; + } + + +} // Tramontana namespace. diff --git a/tramontana/src/PyTramontanaEngine.cpp b/tramontana/src/PyTramontanaEngine.cpp index 900eed41..11f5a8c8 100644 --- a/tramontana/src/PyTramontanaEngine.cpp +++ b/tramontana/src/PyTramontanaEngine.cpp @@ -140,6 +140,24 @@ extern "C" { } + 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). @@ -151,8 +169,12 @@ extern "C" { , "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 */ }; diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp new file mode 100644 index 00000000..8ee8ba09 --- /dev/null +++ b/tramontana/src/SweepLine.cpp @@ -0,0 +1,166 @@ +// -*- 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/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" + + +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::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) + , _tiles () + , _intervalTree() + { } + + + SweepLine::~SweepLine () + { } + + + void SweepLine::run () + { + BasicLayer* layer = DataBase::getDB()->getTechnology()->getBasicLayer( "metal1" ); + loadTiles( layer ); + for ( Element& element : _tiles ) { + Tile* tile = element.getTile(); + TileIntv tileIntv ( tile, tile->getYMin(), tile->getYMax() ); + cerr << right << setw(10) << DbU::getValueString(element.getX()) << " > " << tile << endl; + if (element.isLeftEdge()) { + for ( const TileIntv& overlap : _intervalTree.getOverlaps( + Interval(tile->getYMin(), tile->getYMax() ))) { + cerr << " | intersect " << overlap.getData() << endl; + tile->merge( overlap.getData() ); + } + _intervalTree.insert( tileIntv ); + } else { + _intervalTree.remove( tileIntv ); + } + } + mergeEquipotentials(); + } + + + void SweepLine::loadTiles ( const BasicLayer* layer ) + { + cerr << "SweepLine::run()" << endl; + for ( Occurrence occurrence : getCell()->getOccurrencesUnder( getCell()->getBoundingBox() ) ) { + Component* component = dynamic_cast( occurrence.getEntity() ); + if (not component) continue; + if (not component->getLayer()->contains(layer)) continue; + Tile* tile = Tile::create( occurrence, layer ); + _tiles.push_back( Element( tile, Tile::LeftEdge ) ); + _tiles.push_back( Element( tile, Tile::RightEdge ) ); + } + sort( _tiles.begin(), _tiles.end() ); + } + + + void SweepLine::mergeEquipotentials () + { + Tile::timeTick(); + for ( Tile* tile : Tile::getAllTiles() ) { + tile->getRoot( Tile::MergeEqui ); + } + } + + + 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/Tile.cpp b/tramontana/src/Tile.cpp new file mode 100644 index 00000000..e28e8725 --- /dev/null +++ b/tramontana/src/Tile.cpp @@ -0,0 +1,239 @@ +// -*- 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/RoutingPad.h" +#include "crlcore/Utilities.h" +#include "tramontana/Tile.h" +#include "tramontana/Equipotential.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::RoutingPad; + using Hurricane::Cell; + using Hurricane::Instance; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::Tile". + + + uint32_t Tile::_time = 0; + vector Tile::_allocateds; + + + Tile::Tile ( Occurrence occurrence, const BasicLayer* layer, const Box& boundingBox ) + : _occurrence (occurrence) + , _layer (layer) + , _boundingBox (boundingBox) + , _equipotential(nullptr) + , _flags (0) + , _parent (nullptr) + , _rank (0) + , _timeStamp (0) + { + _allocateds.push_back( this ); + } + + + Tile* Tile::create ( Occurrence occurrence, const BasicLayer* layer ) + { + 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 component->getLayer()->contains(layer)) { + cerr << Error( "Tile::create(): Component layer does not contains \"%s\".\n" + " (%s)" + , getString(layer->getName()).c_str() + , getString(occurrence).c_str() + ) << endl; + return nullptr; + } + + Box bb = component->getBoundingBox( layer ); + occurrence.getPath().getTransformation().applyOn( bb ); + Tile* tile = new Tile ( occurrence, layer, bb ); + + return tile; + } + + + void Tile::destroy () + { + cdebug_log(160,1) << "Tile::destroy() " << this << endl; + cdebug_tabw(160,-1); + } + + + Tile::~Tile () + { } + + + Tile* Tile::getRoot ( uint32_t flags ) + { + if (not getParent() and (not (flags & MergeEqui))) return this; + + Tile* root = this; + while ( root->getParent() ) { + if (flags & MergeEqui) { + if (not root->getParent()->getEquipotential() and root->getEquipotential()) + root->getParent()->setEquipotential( root->getEquipotential() ); + } + root = root->getParent(); + } + + if (flags & Compress) { + Tile* current = this; + while ( current != root ) { + Tile* curParent = current->getParent(); + current->setParent( root ); + current = curParent; + } + } + + if (flags & MergeEqui) { + Equipotential* rootEqui = root->getEquipotential(); + if (not rootEqui) + rootEqui = root->newEquipotential(); + + Tile* current = this; + while ( current ) { + if (current->isUpToDate()) break; + if (current->getEquipotential()) { + if (current->getEquipotential() != rootEqui) + rootEqui->merge( current->getEquipotential() ); + } else { + rootEqui->add( current->getOccurrence() ); + } + current->syncTime(); + current = current->getParent(); + } + } + + return root; + } + + + Tile* Tile::merge ( Tile* other ) + { + Tile* root1 = getRoot(); + Tile* root2 = other->getRoot(); + if (root1 and (root1 == root2)) return root1; + + if (root1->getRank() < root2->getRank()) + std::swap( root1, root2 ); + if (root1->getRank() == root2->getRank()) + root1->incRank(); + root2->setParent( root1 ); + // Fuse root2 into root1 here! + + 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 ); + 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 index 3d09d1a0..629ec10c 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -41,6 +41,7 @@ #include "crlcore/Measures.h" #include "crlcore/Utilities.h" #include "crlcore/AllianceFramework.h" +#include "tramontana/SweepLine.h" #include "tramontana/TramontanaEngine.h" @@ -100,8 +101,9 @@ namespace Tramontana { TramontanaEngine::TramontanaEngine ( Cell* cell ) - : Super (cell) - , _viewer (NULL) + : Super (cell) + , _viewer (NULL) + , _equipotentials() { } @@ -144,9 +146,29 @@ namespace Tramontana { void TramontanaEngine::extract () { cerr << "TramontanaEngine::extract() called on " << getCell() << endl; + SweepLine sweepLine ( this ); + sweepLine.run(); + showEquipotentials(); } + void TramontanaEngine::showEquipotentials () const + { + cerr << "Equipotentials:" << endl; + for ( Equipotential* equi : _equipotentials ) { + cerr << equi << endl; + for ( Component* component : equi->getComponents() ) { + cerr << "| " << component << endl; + } + } + } + + void TramontanaEngine::add ( Equipotential* equi ) + { + _equipotentials.insert( equi ); + } + + string TramontanaEngine::_getTypeName () const { return "Tramontana::TramontanaEngine"; } diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h new file mode 100644 index 00000000..672fc866 --- /dev/null +++ b/tramontana/src/tramontana/Equipotential.h @@ -0,0 +1,95 @@ +// -*- 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/Component.h" +#include "hurricane/Occurrence.h" +namespace Hurricane { + class Net; +} + + +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::Cell; + using Hurricane::Component; + using Hurricane::Occurrence; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::Equipotential". + + class Equipotential : public Entity { + public: + typedef Entity Super; + typedef std::set ComponentSet; + public: + static Equipotential* create ( Cell* ); + inline bool isEmpty () const; + virtual Cell* getCell () const; + virtual Box getBoundingBox () const; + inline bool hasComponent ( Component* ) const; + void add ( Component* ); + void add ( Occurrence ); + void merge ( Equipotential* ); + void clear (); + inline const ComponentSet& getComponents () const; + inline const std::vector& getChilds () const; + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + protected: + virtual void _postCreate (); + virtual void _preDestroy (); + private: + Equipotential ( Cell* ); + ~Equipotential (); + private: + Equipotential ( const Equipotential& ) = delete; + Equipotential& operator= ( const Equipotential& ) = delete; + private: + Cell* _owner; + Box _boundingBox; + ComponentSet _components; + std::vector _childs; + }; + + + + inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } + inline const Equipotential::ComponentSet& Equipotential::getComponents () const { return _components; } + inline const std::vector& Equipotential::getChilds () const { return _childs; } + + inline bool Equipotential::hasComponent ( Component* component ) const + { return _components.find( component ) != _components.end(); } + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::Equipotential); diff --git a/tramontana/src/tramontana/SweepLine.h b/tramontana/src/tramontana/SweepLine.h new file mode 100644 index 00000000..1e3b441d --- /dev/null +++ b/tramontana/src/tramontana/SweepLine.h @@ -0,0 +1,100 @@ +// -*- 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 "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::Cell; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::SweepLine". + + class SweepLine { + private: + class Element { + public: + inline Element ( Tile*, uint32_t flags ); + inline bool operator< ( const Element& ) const; + inline bool isLeftEdge () const; + inline Tile* getTile () const; + inline DbU::Unit getX () const; + inline DbU::Unit getY () const; + inline DbU::Unit getId () const; + private: + Tile* _tile; + uint32_t _flags; + }; + public: + SweepLine ( TramontanaEngine* ); + ~SweepLine (); + inline Cell* getCell (); + void run (); + void loadTiles ( const BasicLayer* ); + void mergeEquipotentials (); + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + private: + SweepLine ( const SweepLine& ) = delete; + SweepLine& operator= ( const SweepLine& ) = delete; + private: + TramontanaEngine* _tramontana; + std::vector _tiles; + TileIntvTree _intervalTree; + }; + + +// 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 bool SweepLine::Element::operator< ( const Element& rhs ) const + { + if (getX() != rhs.getX()) return (getX() < rhs.getX()); + if (getY() != rhs.getY()) return (getY() < rhs.getY()); + return getId() < rhs.getId(); + } + + +// SweepLine. + inline Cell* SweepLine::getCell () { return _tramontana->getCell(); } + + + +} // Tramontana namespace. + + +INSPECTOR_P_SUPPORT(Tramontana::SweepLine); diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h new file mode 100644 index 00000000..652d346a --- /dev/null +++ b/tramontana/src/tramontana/Tile.h @@ -0,0 +1,142 @@ +// -*- 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 : "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); + public: + static inline const std::vector getAllTiles (); + static inline void timeTick (); + static Tile* create ( Occurrence, const BasicLayer* ); + void destroy (); + inline bool isUpToDate () 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; + 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 setEquipotential ( Equipotential* ); + Equipotential* newEquipotential (); + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + private: + Tile ( Occurrence, const BasicLayer*, const Box& ); + ~Tile (); + private: + Tile ( const Tile& ) = delete; + Tile& operator= ( const Tile& ) = delete; + private: + static uint32_t _time; + static std::vector _allocateds; + 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 unsigned int Tile::getId () const { return getComponent()->getId(); } + inline Component* Tile::getComponent () const { return dynamic_cast( _occurrence.getEntity() ); } + inline Occurrence Tile::getOccurrence () const { return _occurrence; } + 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; } + + +// ------------------------------------------------------------------- +// 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 index a0dc3642..46212665 100644 --- a/tramontana/src/tramontana/TramontanaEngine.h +++ b/tramontana/src/tramontana/TramontanaEngine.h @@ -27,6 +27,7 @@ namespace Hurricane { class CellViewer; } #include "crlcore/ToolEngine.h" +#include "tramontana/Equipotential.h" namespace Tramontana { @@ -53,15 +54,19 @@ namespace Tramontana { public: const Name& getName () const; inline void setViewer ( CellViewer* ); + inline CellViewer* getViewer (); void extract (); + 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; - protected: + private: CellViewer* _viewer; + std::set _equipotentials; protected: // Constructors & Destructors. TramontanaEngine ( Cell* ); @@ -74,7 +79,8 @@ namespace Tramontana { }; - inline void TramontanaEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } + inline void TramontanaEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } + inline CellViewer* TramontanaEngine::getViewer () { return _viewer; } } // Tramontana namespace. From 50a9036d287465ee6ea30f1b767c884d0f260b25 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 26 Mar 2023 21:08:58 +0200 Subject: [PATCH 05/28] Add support for selection by ComponentSet in CellWidget. * New: In Component, typedef ComponentSet (set sorted on Ids). * New: CellWidget::selectSet() & CellWidget::unselectSet() select/unselect a whole set of component. --- hurricane/src/hurricane/hurricane/Component.h | 4 ++ .../src/isobar/hurricane/isobar/PyHurricane.h | 12 +++--- hurricane/src/viewer/CellWidget.cpp | 37 +++++++++++++++++++ .../src/viewer/hurricane/viewer/CellWidget.h | 2 + 4 files changed, 49 insertions(+), 6 deletions(-) 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/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/CellWidget.cpp b/hurricane/src/viewer/CellWidget.cpp index 1540e8c6..02edb928 100644 --- a/hurricane/src/viewer/CellWidget.cpp +++ b/hurricane/src/viewer/CellWidget.cpp @@ -2687,6 +2687,31 @@ namespace Hurricane { } + 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::select ( Occurrence occurrence ) { if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) { @@ -2786,6 +2811,18 @@ namespace Hurricane { } + 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::unselectAll () { ++_delaySelectionChanged; diff --git a/hurricane/src/viewer/hurricane/viewer/CellWidget.h b/hurricane/src/viewer/hurricane/viewer/CellWidget.h index 60997001..5b277e3f 100644 --- a/hurricane/src/viewer/hurricane/viewer/CellWidget.h +++ b/hurricane/src/viewer/hurricane/viewer/CellWidget.h @@ -265,10 +265,12 @@ namespace Hurricane { inline DrawingPlanes& getDrawingPlanes (); // void select ( const Net* ); void select ( Occurrence ); + void selectSet ( const ComponentSet& ); bool isSelected ( Occurrence ); void selectOccurrencesUnder ( Box selectArea ); // void unselect ( const Net* ); void unselect ( Occurrence ); + void unselectSet ( const ComponentSet& ); void unselectAll (); void toggleSelection ( Occurrence ); void setShowSelection ( bool state ); From 7ed41613def11a4c01bfb8c1da5239a68bd341dd Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 26 Mar 2023 21:12:14 +0200 Subject: [PATCH 06/28] Add ControllerWidget::insertAfterTab() to put a new tab where we want. --- hurricane/src/viewer/ControllerWidget.cpp | 13 +++++++++++++ .../src/viewer/hurricane/viewer/ControllerWidget.h | 1 + 2 files changed, 14 insertions(+) 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/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 (); From e5d9c8808bef2d8ad042b193fefb9488b74d6293 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 26 Mar 2023 21:12:49 +0200 Subject: [PATCH 07/28] Reduce the default pixel threshold to 5. --- cumulus/src/designflow/technos.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cumulus/src/designflow/technos.py b/cumulus/src/designflow/technos.py index 0d69724a..2e80b51e 100644 --- a/cumulus/src/designflow/technos.py +++ b/cumulus/src/designflow/technos.py @@ -189,6 +189,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 From a0911be50a2d564b295d805e4f163c04148aa5a3 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 26 Mar 2023 21:15:15 +0200 Subject: [PATCH 08/28] Add complete support for Equipotential selection in the Controller. --- tramontana/src/CMakeLists.txt | 9 +- tramontana/src/Equipotential.cpp | 71 +++++- tramontana/src/EquipotentialsModel.cpp | 124 ++++++++++ tramontana/src/EquipotentialsWidget.cpp | 230 ++++++++++++++++++ tramontana/src/GraphicTramontanaEngine.cpp | 10 +- tramontana/src/SweepLine.cpp | 1 + tramontana/src/TabEquipotentials.cpp | 144 +++++++++++ tramontana/src/Tile.cpp | 6 +- tramontana/src/TramontanaEngine.cpp | 10 + tramontana/src/tramontana/Equipotential.h | 17 +- .../src/tramontana/EquipotentialsModel.h | 62 +++++ .../src/tramontana/EquipotentialsWidget.h | 163 +++++++++++++ tramontana/src/tramontana/TabEquipotentials.h | 62 +++++ tramontana/src/tramontana/TramontanaEngine.h | 5 + 14 files changed, 905 insertions(+), 9 deletions(-) create mode 100644 tramontana/src/EquipotentialsModel.cpp create mode 100644 tramontana/src/EquipotentialsWidget.cpp create mode 100644 tramontana/src/TabEquipotentials.cpp create mode 100644 tramontana/src/tramontana/EquipotentialsModel.h create mode 100644 tramontana/src/tramontana/EquipotentialsWidget.h create mode 100644 tramontana/src/tramontana/TabEquipotentials.h diff --git a/tramontana/src/CMakeLists.txt b/tramontana/src/CMakeLists.txt index abc8f8c5..b916b224 100644 --- a/tramontana/src/CMakeLists.txt +++ b/tramontana/src/CMakeLists.txt @@ -18,12 +18,19 @@ set( pyIncludes tramontana/PyTramontanaEngine.h tramontana/PyGraphicTramontanaEngine.h ) - set( mocIncludes tramontana/GraphicTramontanaEngine.h ) + set( mocIncludes tramontana/GraphicTramontanaEngine.h + tramontana/EquipotentialsModel.h + tramontana/EquipotentialsWidget.h + tramontana/TabEquipotentials.h + ) set( cpps Tile.cpp SweepLine.cpp Equipotential.cpp TramontanaEngine.cpp GraphicTramontanaEngine.cpp + EquipotentialsModel.cpp + EquipotentialsWidget.cpp + TabEquipotentials.cpp ) set( pyCpps PyTramontana.cpp PyTramontanaEngine.cpp diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp index 8a1df31c..b2c5141e 100644 --- a/tramontana/src/Equipotential.cpp +++ b/tramontana/src/Equipotential.cpp @@ -17,6 +17,7 @@ #include +#include #include "hurricane/utilities/Path.h" #include "hurricane/DebugSession.h" #include "hurricane/UpdateSession.h" @@ -39,6 +40,32 @@ #include "tramontana/TramontanaEngine.h" +namespace { + + using Hurricane::Net; + + + class NetCompareByName { + public: + bool operator() ( const Net* lhs, const Net* rhs ) const; + }; + + + 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(); + } + + +} // Anonymous namespace. + + namespace Tramontana { using std::cout; @@ -54,6 +81,7 @@ namespace Tramontana { using std::ostringstream; using std::setprecision; using std::vector; + using std::set; using std::make_pair; using Hurricane::dbo_ptr; using Hurricane::UpdateSession; @@ -66,6 +94,7 @@ namespace Tramontana { using Hurricane::Box; using Hurricane::Layer; using Hurricane::Entity; + using Hurricane::Net; using Hurricane::Horizontal; using Hurricane::Vertical; using Hurricane::RoutingPad; @@ -77,11 +106,20 @@ namespace Tramontana { // Class : "Tramontana::Equipotential". + const char* defaultName = "Unamed (please call consolidate())"; + + Equipotential::Equipotential ( Cell* owner ) : _owner (owner) , _boundingBox() , _components () , _childs () + , _name (defaultName) + , _type (Net::Type::UNDEFINED) + , _direction (Net::Direction::DirUndefined) + , _isExternal (false) + , _isGlobal (false) + , _isAutomatic(false) { } @@ -154,6 +192,34 @@ namespace Tramontana { } + void Equipotential::consolidate () + { + int containsFused = 0; + set nets; + for ( Component* component : getComponents() ) { + Net* net = component->getNet(); + if (net->isFused ()) containsFused = 1; + if (net->isExternal ()) _isExternal = true; + if (net->isGlobal ()) _isGlobal = true; + if (net->isAutomatic()) _isAutomatic = true; + _type = net->getType(); + _direction |= net->getDirection(); + nets.insert( component->getNet() ); + } + _name = getString( (*nets.begin())->getName() ); + _name += " [" + getString(nets.size() - containsFused); + if (containsFused) + _name += "+fused"; + _name += "] "; + _name += ((_isExternal ) ? "e" : "-"); + _name += ((_isGlobal ) ? "g" : "-"); + _name += ((_isAutomatic) ? "a" : "-"); + _name += " "; + _name += getString(_type ) + " "; + _name += getString(_direction); + } + + void Equipotential::clear () { _components.clear(); @@ -168,7 +234,9 @@ namespace Tramontana { string Equipotential::_getString () const { ostringstream os; - os << "getName() << ">"; + os << "getName() << ">"; return os.str(); } @@ -181,6 +249,7 @@ namespace Tramontana { record->add( getSlot( "_boundingBox", &_boundingBox ) ); record->add( getSlot( "_components" , &_components ) ); record->add( getSlot( "_childs" , &_childs ) ); + //record->add( getSlot( "_name" , &_name ) ); } return record; } diff --git a/tramontana/src/EquipotentialsModel.cpp b/tramontana/src/EquipotentialsModel.cpp new file mode 100644 index 00000000..b27817ab --- /dev/null +++ b/tramontana/src/EquipotentialsModel.cpp @@ -0,0 +1,124 @@ +// -*- 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) { + if (index.row() == 0) return QVariant(); + switch (index.column()) { + case 0: return nameFont; + default: return valueFont; + } + return QVariant(); + } + + if (not index.isValid()) return QVariant (); + + if (role == Qt::DisplayRole) { + int row = index.row (); + return QString::fromStdString( _equipotentials[row]->getName() ); + } + 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("Equipotential"); + // if (section < _equipotentials->getColumnCount()) + // return _equipotentials->getColumnName( section ); + + return QVariant(); + } + + + int EquipotentialsModel::rowCount ( const QModelIndex& parent ) const + { + return _equipotentials.size(); + } + + + int EquipotentialsModel::columnCount ( const QModelIndex& parent ) const + { + return 1; + //return (_equipotentials) ? _equipotentials->getColumnCount() : 1; + } + + + 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..f6ec7a57 --- /dev/null +++ b/tramontana/src/EquipotentialsWidget.cpp @@ -0,0 +1,230 @@ +// -*- 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; + + + EquipotentialsWidget::EquipotentialsWidget ( QWidget* parent ) + : QWidget (parent) + , _cellWidget (NULL) + , _cell (NULL) + , _baseModel (new EquipotentialsModel(this)) + , _sortModel (new QSortFilterProxyModel(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; + + _sortModel->setSourceModel ( _baseModel ); + _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()) ? 300 : 150 ); + 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 ); + } + + + 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( _sortModel->mapToSource(iList[i]).row() ); + if ( equi ) + _selecteds.insert( equi ); + } + + if (_forceReselect) { + _selecteds.forceInserteds(); + _forceReselect = false; + } + + SelectedEquiSet::iterator remove; + SelectedEquiSet::iterator isel = _selecteds.begin (); + while ( isel != _selecteds.end() ) { + switch ( isel->getAccesses() ) { + case 1: break; + case 64: + emit equipotentialSelect ( isel->getEqui()->getComponents() ); + break; + case 0: + emit equipotentialUnselect ( isel->getEqui()->getComponents() ); + remove = isel; + ++isel; + _selecteds.erase( remove ); + continue; + default: + cerr << Bug( "EquipotentialsWidget::updateSelecteds(): invalid code %d" + , isel->getAccesses()) << endl; + } + ++isel; + } + + if (_cellWidget) _cellWidget->closeRefreshSession (); + } + + + void EquipotentialsWidget::textFilterChanged () + { + _sortModel->setFilterRegExp( _filterPatternLineEdit->text() ); + //updateSelecteds (); + } + + + // void EquipotentialsWidget::fitToNet () + // { + // const Equipotential* equi = _baseModel->getEqui( _sortModel->mapToSource(_view->currentIndex()).row() ); + // if (equi) emit netFitted ( equi ); + // } + + + void EquipotentialsWidget::setCellWidget ( CellWidget* cw ) + { + if (_cellWidget) { + disconnect( this, 0, _cellWidget, 0 ); + } + + _cellWidget = cw; + if (_cellWidget) { + setCell( _cellWidget->getCell() ); + //connect( this, SIGNAL(netFitted(const Equi*)), _cellWidget, SLOT(fitToEqui (const Equi*)) ); + } 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 index 093b7be5..05bedb8f 100644 --- a/tramontana/src/GraphicTramontanaEngine.cpp +++ b/tramontana/src/GraphicTramontanaEngine.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -100,7 +101,6 @@ namespace Tramontana { fontScale = -5; halfHeight = 9; halfWidth = 39; - } painter.setPen ( pen ); @@ -188,6 +188,14 @@ namespace 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" ); + } } diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index 8ee8ba09..45011625 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -133,6 +133,7 @@ namespace Tramontana { void SweepLine::mergeEquipotentials () { + cerr << "Tramontana::mergeEquipotentials()" << endl; Tile::timeTick(); for ( Tile* tile : Tile::getAllTiles() ) { tile->getRoot( Tile::MergeEqui ); diff --git a/tramontana/src/TabEquipotentials.cpp b/tramontana/src/TabEquipotentials.cpp new file mode 100644 index 00000000..78829b4f --- /dev/null +++ b/tramontana/src/TabEquipotentials.cpp @@ -0,0 +1,144 @@ +// -*- 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 Hurricane::Graphics; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TabEquipotentials". + + + TabEquipotentials::TabEquipotentials ( QWidget* parent ) + : ControllerTab (parent) + , _browser (new EquipotentialsWidget()) + , _syncEquipotentials (new QCheckBox()) + , _syncSelection (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)) ); + + QHBoxLayout* commands = new QHBoxLayout (); + commands->setContentsMargins( 0, 0, 0, 0 ); + commands->addStretch(); + commands->addWidget ( _syncEquipotentials ); + 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 (const ComponentSet&)), getCellWidget(), SLOT(selectSet (const ComponentSet&)) ); + connect( _browser, SIGNAL(equipotentialUnselect(const ComponentSet&)), getCellWidget(), SLOT(unselectSet(const ComponentSet&)) ); + _browser->updateSelecteds(); + } else { + getCellWidget()->setShowSelection( false ); + getCellWidget()->setCumulativeSelection( _cwCumulativeSelection ); + _browser->disconnect( getCellWidget(), SLOT(selectSet (const ComponentSet&)) ); + _browser->disconnect( getCellWidget(), SLOT(unselectSet(const ComponentSet&)) ); + } + } + + + 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 index e28e8725..4cf692e6 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -157,15 +157,17 @@ namespace Tramontana { if (flags & MergeEqui) { Equipotential* rootEqui = root->getEquipotential(); - if (not rootEqui) + if (not rootEqui) { rootEqui = root->newEquipotential(); + } Tile* current = this; while ( current ) { if (current->isUpToDate()) break; if (current->getEquipotential()) { - if (current->getEquipotential() != rootEqui) + if (current->getEquipotential() != rootEqui) { rootEqui->merge( current->getEquipotential() ); + } } else { rootEqui->add( current->getOccurrence() ); } diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp index 629ec10c..852f8d62 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -148,6 +148,7 @@ namespace Tramontana { cerr << "TramontanaEngine::extract() called on " << getCell() << endl; SweepLine sweepLine ( this ); sweepLine.run(); + consolidate(); showEquipotentials(); } @@ -163,6 +164,15 @@ namespace Tramontana { } } + + void TramontanaEngine::consolidate () + { + cerr << "Tramontana::consolidate()" << endl; + for ( Equipotential* equi : _equipotentials ) + equi->consolidate(); + } + + void TramontanaEngine::add ( Equipotential* equi ) { _equipotentials.insert( equi ); diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h index 672fc866..57c95500 100644 --- a/tramontana/src/tramontana/Equipotential.h +++ b/tramontana/src/tramontana/Equipotential.h @@ -38,6 +38,7 @@ namespace Tramontana { using Hurricane::Net; using Hurricane::Cell; using Hurricane::Component; + using Hurricane::ComponentSet; using Hurricane::Occurrence; @@ -47,16 +48,17 @@ namespace Tramontana { class Equipotential : public Entity { public: typedef Entity Super; - typedef std::set ComponentSet; public: static Equipotential* create ( Cell* ); inline bool isEmpty () const; virtual Cell* getCell () const; virtual Box getBoundingBox () const; + inline std::string getName () const; inline bool hasComponent ( Component* ) const; void add ( Component* ); void add ( Occurrence ); void merge ( Equipotential* ); + void consolidate (); void clear (); inline const ComponentSet& getComponents () const; inline const std::vector& getChilds () const; @@ -77,13 +79,20 @@ namespace Tramontana { Box _boundingBox; ComponentSet _components; std::vector _childs; + std::string _name; + Net::Type _type; + Net::Direction _direction; + bool _isExternal; + bool _isGlobal; + bool _isAutomatic; }; - inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } - inline const Equipotential::ComponentSet& Equipotential::getComponents () const { return _components; } - inline const std::vector& Equipotential::getChilds () const { return _childs; } + inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } + inline const ComponentSet& Equipotential::getComponents () const { return _components; } + inline std::string Equipotential::getName () const { return _name; } + inline const std::vector& Equipotential::getChilds () const { return _childs; } inline bool Equipotential::hasComponent ( Component* component ) const { return _components.find( component ) != _components.end(); } 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..4ebdcb04 --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialsWidget.h @@ -0,0 +1,163 @@ +// -*- 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; + + +// ------------------------------------------------------------------- +// 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 setCellWidget ( CellWidget* ); + void setCell ( Cell* ); + void goTo ( int ); + void updateSelecteds (); + signals: + void equipotentialSelect ( const ComponentSet& ); + void equipotentialUnselect ( const ComponentSet& ); + void netFitted ( const Equipotential* ); + private slots: + void textFilterChanged (); + void updateSelecteds ( const QItemSelection& , const QItemSelection& ); + // void fitToEqui (); + + private: + CellWidget* _cellWidget; + Cell* _cell; + EquipotentialsModel* _baseModel; + QSortFilterProxyModel* _sortModel; + QTableView* _view; + QLineEdit* _filterPatternLineEdit; + int _rowHeight; + SelectedEquiSet _selecteds; + bool _forceReselect; + }; + + + inline Cell* EquipotentialsWidget::getCell () { return _cell; } + + +} // Hurricane namespace. diff --git a/tramontana/src/tramontana/TabEquipotentials.h b/tramontana/src/tramontana/TabEquipotentials.h new file mode 100644 index 00000000..075a2783 --- /dev/null +++ b/tramontana/src/tramontana/TabEquipotentials.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/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 QCheckBox* getSyncEquipotentials (); + inline QCheckBox* getSyncSelection (); + 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 ); + + protected: + EquipotentialsWidget* _browser; + QCheckBox* _syncEquipotentials; + QCheckBox* _syncSelection; + bool _cwCumulativeSelection; + }; + + + inline EquipotentialsWidget* TabEquipotentials::getBrowser () { return _browser; } + inline QCheckBox* TabEquipotentials::getSyncEquipotentials () { return _syncEquipotentials; } + inline QCheckBox* TabEquipotentials::getSyncSelection () { return _syncSelection; } + + +} diff --git a/tramontana/src/tramontana/TramontanaEngine.h b/tramontana/src/tramontana/TramontanaEngine.h index 46212665..95c07e68 100644 --- a/tramontana/src/tramontana/TramontanaEngine.h +++ b/tramontana/src/tramontana/TramontanaEngine.h @@ -53,9 +53,12 @@ namespace Tramontana { static TramontanaEngine* get ( const Cell* ); public: const Name& getName () const; + inline const std::set + getEquipotentials () const; inline void setViewer ( CellViewer* ); inline CellViewer* getViewer (); void extract (); + void consolidate (); void showEquipotentials () const; void add ( Equipotential* ); virtual Record* _getRecord () const; @@ -81,6 +84,8 @@ namespace Tramontana { inline void TramontanaEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } inline CellViewer* TramontanaEngine::getViewer () { return _viewer; } + inline const std::set + TramontanaEngine::getEquipotentials () const { return _equipotentials; } } // Tramontana namespace. From e22e7f7476cfee629d0d4de2f0777b6495dbd27c Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 28 Mar 2023 14:52:23 +0200 Subject: [PATCH 09/28] IntervalTree is now support multiple intervals with same lower bound. * New: Interval::CompareByMinMax, lexicographical comparison of Intervals, first compare the lower bound (VMin) then the upper bound (VMax). Needed for IntervalTree. * Change: In IntervalTree, the key comparison was only based on the lower bound (VMin). That means that the tree would accept only one interval for a given VMin. You couldn't store both [1:4] and [1:5]. Now use CompareByMinMax that allows it. --- hurricane/src/hurricane/hurricane/Interval.h | 29 ++++++++++++++----- .../src/hurricane/hurricane/IntervalTree.h | 14 ++++----- hurricane/src/hurricane/hurricane/RbTree.h | 4 +-- 3 files changed, 29 insertions(+), 18 deletions(-) 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 f479651c..20c55536 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" @@ -117,14 +115,14 @@ namespace Hurricane { return record; } + // ------------------------------------------------------------------- // Class : "Hurricane::IntervalTree". - template< typename Data > - class IntervalTree : public RbTree< IntervalData, Interval::CompareByMin > { + class IntervalTree : public RbTree< IntervalData, Interval::CompareByMinMax > { public: - typedef RbTree< IntervalData, Interval::CompareByMin > Super; + typedef RbTree< IntervalData, Interval::CompareByMinMax > Super; public: class overlap_iterator : public Super::iterator { public: @@ -414,5 +412,3 @@ namespace Hurricane { } // HUrricane namespace. - -#endif // HURRICANE_INTERVAL_TREE_H diff --git a/hurricane/src/hurricane/hurricane/RbTree.h b/hurricane/src/hurricane/hurricane/RbTree.h index ef9d3cc2..d441540d 100644 --- a/hurricane/src/hurricane/hurricane/RbTree.h +++ b/hurricane/src/hurricane/hurricane/RbTree.h @@ -557,10 +557,10 @@ 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() < Date: Tue, 28 Mar 2023 15:12:31 +0200 Subject: [PATCH 10/28] Added deletion tests for RbTree & IntervalTree in unittests. --- unittests/src/unittests.cpp | 2 ++ 1 file changed, 2 insertions(+) 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() ) { From 23c0c24c0f9af46349027c6a9ea9183e3c483cd7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 28 Mar 2023 15:13:02 +0200 Subject: [PATCH 11/28] Non-hierarchical, metal only, rectangle only, extractor is now working. * New: In Tramontana, * Multi-layer support for the swap line. Split VIAs into their various metal plates and link the two relevant tiles, ensuring connexity between layers. * Improved Equipotential information rebuild. Try to rebuild more closely the Net characteristics. Improved tab widgets. --- tramontana/src/Equipotential.cpp | 51 +++++++++------ tramontana/src/EquipotentialsModel.cpp | 28 ++++----- tramontana/src/SweepLine.cpp | 76 ++++++++++++++++++----- tramontana/src/Tile.cpp | 2 +- tramontana/src/TramontanaEngine.cpp | 9 ++- tramontana/src/tramontana/Equipotential.h | 57 +++++++++-------- tramontana/src/tramontana/SweepLine.h | 38 +++++++----- tramontana/src/tramontana/Tile.h | 4 +- 8 files changed, 168 insertions(+), 97 deletions(-) diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp index b2c5141e..6a7f6574 100644 --- a/tramontana/src/Equipotential.cpp +++ b/tramontana/src/Equipotential.cpp @@ -117,9 +117,11 @@ namespace Tramontana { , _name (defaultName) , _type (Net::Type::UNDEFINED) , _direction (Net::Direction::DirUndefined) + , _netCount (0) , _isExternal (false) , _isGlobal (false) , _isAutomatic(false) + , _hasFused (false) { } @@ -194,29 +196,21 @@ namespace Tramontana { void Equipotential::consolidate () { - int containsFused = 0; set nets; for ( Component* component : getComponents() ) { Net* net = component->getNet(); - if (net->isFused ()) containsFused = 1; - if (net->isExternal ()) _isExternal = true; - if (net->isGlobal ()) _isGlobal = true; - if (net->isAutomatic()) _isAutomatic = true; - _type = net->getType(); - _direction |= net->getDirection(); + if (net->isFused()) _hasFused = true; + else { + if (net->isExternal ()) _isExternal = true; + if (net->isGlobal ()) _isGlobal = true; + if (net->isAutomatic()) _isAutomatic = true; + _type = net->getType(); + _direction |= net->getDirection(); + } nets.insert( component->getNet() ); } _name = getString( (*nets.begin())->getName() ); - _name += " [" + getString(nets.size() - containsFused); - if (containsFused) - _name += "+fused"; - _name += "] "; - _name += ((_isExternal ) ? "e" : "-"); - _name += ((_isGlobal ) ? "g" : "-"); - _name += ((_isAutomatic) ? "a" : "-"); - _name += " "; - _name += getString(_type ) + " "; - _name += getString(_direction); + _netCount = nets.size(); } @@ -227,6 +221,20 @@ namespace Tramontana { } + string Equipotential::getFlagsAsString () const + { + string sflags; + sflags += ((_isExternal ) ? "e" : "-"); + sflags += ((_isGlobal ) ? "g" : "-"); + sflags += ((_isAutomatic) ? "a" : "-"); + sflags += " [" + getString( _netCount - ((_hasFused) ? 1 : 0) ); + if (_hasFused) + sflags += "+fused"; + sflags += "] "; + return sflags; + } + + string Equipotential::_getTypeName () const { return "Tramontana::Equipotential"; } @@ -234,9 +242,12 @@ namespace Tramontana { string Equipotential::_getString () const { ostringstream os; - os << "getName() << ">"; + os << ""; return os.str(); } diff --git a/tramontana/src/EquipotentialsModel.cpp b/tramontana/src/EquipotentialsModel.cpp index b27817ab..6f83171e 100644 --- a/tramontana/src/EquipotentialsModel.cpp +++ b/tramontana/src/EquipotentialsModel.cpp @@ -43,7 +43,6 @@ namespace Tramontana { static QFont valueFont = Graphics::getFixedFont ( QFont::Normal, true ); if (role == Qt::FontRole) { - if (index.row() == 0) return QVariant(); switch (index.column()) { case 0: return nameFont; default: return valueFont; @@ -54,8 +53,13 @@ namespace Tramontana { if (not index.isValid()) return QVariant (); if (role == Qt::DisplayRole) { - int row = index.row (); - return QString::fromStdString( _equipotentials[row]->getName() ); + Equipotential* equi = _equipotentials[ index.row() ]; + switch ( index.column() ) { + case 0: return QString::fromStdString( equi->getName() ); + case 1: return QString::fromStdString( equi->getFlagsAsString() ); + case 2: return QString::fromStdString( getString( equi->getType() )); + case 3: return QString::fromStdString( getString( equi->getDirection() )); + } } return QVariant(); } @@ -71,26 +75,20 @@ namespace Tramontana { if (role == Qt::FontRole ) return headerFont; if (role != Qt::DisplayRole) return QVariant(); - - if (section == 0) return QVariant("Equipotential"); - // if (section < _equipotentials->getColumnCount()) - // return _equipotentials->getColumnName( section ); - + if (section == 0) return QVariant( "Name" ); + if (section == 1) return QVariant( "Flags" ); + if (section == 2) return QVariant( "Type" ); + if (section == 3) return QVariant( "Direction" ); return QVariant(); } int EquipotentialsModel::rowCount ( const QModelIndex& parent ) const - { - return _equipotentials.size(); - } + { return _equipotentials.size(); } int EquipotentialsModel::columnCount ( const QModelIndex& parent ) const - { - return 1; - //return (_equipotentials) ? _equipotentials->getColumnCount() : 1; - } + { return 4; } const Equipotential* EquipotentialsModel::getEqui ( int row ) diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index 45011625..c40715a1 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -83,9 +83,9 @@ namespace Tramontana { SweepLine::SweepLine ( TramontanaEngine* tramontana ) - : _tramontana (tramontana) - , _tiles () - , _intervalTree() + : _tramontana (tramontana) + , _tiles () + , _intervalTrees() { } @@ -95,37 +95,79 @@ namespace Tramontana { void SweepLine::run () { - BasicLayer* layer = DataBase::getDB()->getTechnology()->getBasicLayer( "metal1" ); - loadTiles( layer ); + //cerr << "SweepLine::run()" << endl; + //DebugSession::open( 0, 2 ); + loadTiles(); for ( Element& element : _tiles ) { Tile* tile = element.getTile(); TileIntv tileIntv ( tile, tile->getYMin(), tile->getYMax() ); - cerr << right << setw(10) << DbU::getValueString(element.getX()) << " > " << tile << endl; + //cerr << right << setw(10) << DbU::getValueString(element.getX()) << " > " << tile << endl; + auto intvTree = _intervalTrees.find( element.getMask() ); + if (intvTree == _intervalTrees.end()) { + cerr << Error( "SweepLine::run(): Missing interval tree for layer(mask) %s." + " (for tile: %s)" + , getString(element.getMask()).c_str() + , getString(element.getTile()).c_str() + ) << endl; + continue; + } if (element.isLeftEdge()) { - for ( const TileIntv& overlap : _intervalTree.getOverlaps( + for ( const TileIntv& overlap : intvTree->second.getOverlaps( Interval(tile->getYMin(), tile->getYMax() ))) { - cerr << " | intersect " << overlap.getData() << endl; + //cerr << " | intersect " << overlap.getData() << endl; tile->merge( overlap.getData() ); } - _intervalTree.insert( tileIntv ); + //cerr << " | insert tile" << endl; + intvTree->second.insert( tileIntv ); } else { - _intervalTree.remove( tileIntv ); + //cerr << " | remove tile" << endl; + intvTree->second.remove( tileIntv ); + // if (tile->getId() == 46055) { + // intvTree->second.write( "we_at_remove.gv" ); + // for ( auto tile : intvTree->second.getElements() ) { + // cerr << "| in tree:" << tile << endl; + // } + // } } } + //DebugSession::close(); mergeEquipotentials(); } - void SweepLine::loadTiles ( const BasicLayer* layer ) + void SweepLine::loadTiles () { - cerr << "SweepLine::run()" << endl; + //cerr << "SweepLine::loadTiles()" << endl; + vector extracteds; + for ( const BasicLayer* bl : DataBase::getDB()->getTechnology()->getBasicLayers() ) { + if (bl->getMaterial() == BasicLayer::Material::metal) + extracteds.push_back( bl ); + } + + // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal5" )); + // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal4" )); + // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal3" )); + // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal2" )); + // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal1" )); + // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "poly" )); + + for ( const BasicLayer* layer : extracteds ) { + _intervalTrees.insert( make_pair( layer->getMask(), TileIntvTree() )); + } + for ( Occurrence occurrence : getCell()->getOccurrencesUnder( getCell()->getBoundingBox() ) ) { + vector tiles; Component* component = dynamic_cast( occurrence.getEntity() ); if (not component) continue; - if (not component->getLayer()->contains(layer)) continue; - Tile* tile = Tile::create( occurrence, layer ); - _tiles.push_back( Element( tile, Tile::LeftEdge ) ); - _tiles.push_back( Element( tile, Tile::RightEdge ) ); + for ( const BasicLayer* layer : extracteds ) { + if (not component->getLayer()->getMask().intersect(layer->getMask())) continue; + tiles.push_back( Tile::create( occurrence, layer )); + _tiles.push_back( Element( tiles.back(), Tile::LeftEdge ) ); + _tiles.push_back( Element( tiles.back(), Tile::RightEdge ) ); + if (tiles.size() > 1) + tiles.back()->setParent( tiles[0] ); + } + tiles.clear(); } sort( _tiles.begin(), _tiles.end() ); } @@ -133,7 +175,7 @@ namespace Tramontana { void SweepLine::mergeEquipotentials () { - cerr << "Tramontana::mergeEquipotentials()" << endl; + //cerr << "SweepLine::mergeEquipotentials()" << endl; Tile::timeTick(); for ( Tile* tile : Tile::getAllTiles() ) { tile->getRoot( Tile::MergeEqui ); diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp index 4cf692e6..550778cb 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -108,7 +108,7 @@ namespace Tramontana { if (not component->getLayer()->contains(layer)) { cerr << Error( "Tile::create(): Component layer does not contains \"%s\".\n" " (%s)" - , getString(layer->getName()).c_str() + , getString(layer).c_str() , getString(occurrence).c_str() ) << endl; return nullptr; diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp index 852f8d62..bf5c8490 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -145,11 +145,14 @@ namespace Tramontana { void TramontanaEngine::extract () { - cerr << "TramontanaEngine::extract() called on " << getCell() << endl; + cmess1 << " o Extracting " << getCell() << endl; + startMeasures(); SweepLine sweepLine ( this ); sweepLine.run(); consolidate(); - showEquipotentials(); + //showEquipotentials(); + stopMeasures(); + printMeasures(); } @@ -167,7 +170,7 @@ namespace Tramontana { void TramontanaEngine::consolidate () { - cerr << "Tramontana::consolidate()" << endl; + //cerr << "Tramontana::consolidate()" << endl; for ( Equipotential* equi : _equipotentials ) equi->consolidate(); } diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h index 57c95500..f8f9bb5b 100644 --- a/tramontana/src/tramontana/Equipotential.h +++ b/tramontana/src/tramontana/Equipotential.h @@ -49,31 +49,34 @@ namespace Tramontana { public: typedef Entity Super; public: - static Equipotential* create ( Cell* ); - inline bool isEmpty () const; - virtual Cell* getCell () const; - virtual Box getBoundingBox () const; - inline std::string getName () const; - inline bool hasComponent ( Component* ) const; - void add ( Component* ); - void add ( Occurrence ); - void merge ( Equipotential* ); - void consolidate (); - void clear (); - inline const ComponentSet& getComponents () const; - inline const std::vector& getChilds () const; - Record* _getRecord () const; - std::string _getString () const; - std::string _getTypeName () const; - protected: - virtual void _postCreate (); - virtual void _preDestroy (); - private: - Equipotential ( Cell* ); - ~Equipotential (); - private: - Equipotential ( const Equipotential& ) = delete; - Equipotential& operator= ( const Equipotential& ) = delete; + static Equipotential* create ( Cell* ); + inline bool isEmpty () const; + virtual Cell* getCell () const; + virtual Box getBoundingBox () const; + inline std::string getName () const; + std::string getFlagsAsString () const; + inline Net::Type getType () const; + inline Net::Direction getDirection () const; + inline bool hasComponent ( Component* ) const; + void add ( Component* ); + void add ( Occurrence ); + void merge ( Equipotential* ); + void consolidate (); + void clear (); + inline const ComponentSet& getComponents () const; + inline const std::vector& getChilds () const; + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + protected: + virtual void _postCreate (); + virtual void _preDestroy (); + private: + Equipotential ( Cell* ); + ~Equipotential (); + private: + Equipotential ( const Equipotential& ) = delete; + Equipotential& operator= ( const Equipotential& ) = delete; private: Cell* _owner; Box _boundingBox; @@ -82,9 +85,11 @@ namespace Tramontana { std::string _name; Net::Type _type; Net::Direction _direction; + uint32_t _netCount; bool _isExternal; bool _isGlobal; bool _isAutomatic; + bool _hasFused; }; @@ -92,6 +97,8 @@ namespace Tramontana { inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } inline const ComponentSet& Equipotential::getComponents () const { return _components; } inline std::string Equipotential::getName () const { return _name; } + inline Net::Type Equipotential::getType () const { return _type; } + inline Net::Direction Equipotential::getDirection () const { return _direction; } inline const std::vector& Equipotential::getChilds () const { return _childs; } inline bool Equipotential::hasComponent ( Component* component ) const diff --git a/tramontana/src/tramontana/SweepLine.h b/tramontana/src/tramontana/SweepLine.h index 1e3b441d..0fb6d0eb 100644 --- a/tramontana/src/tramontana/SweepLine.h +++ b/tramontana/src/tramontana/SweepLine.h @@ -19,6 +19,7 @@ #pragma once #include #include +#include #include "hurricane/BasicLayer.h" namespace Hurricane { class Net; @@ -33,22 +34,27 @@ namespace Tramontana { using Hurricane::Box; using Hurricane::DbU; using Hurricane::Cell; + using Hurricane::Layer; + using Hurricane::BasicLayer; // ------------------------------------------------------------------- // Class : "Tramontana::SweepLine". class SweepLine { + private: + typedef std::map IntervalTrees; private: class Element { public: - inline Element ( Tile*, uint32_t flags ); - inline bool operator< ( const Element& ) const; - inline bool isLeftEdge () const; - inline Tile* getTile () const; - inline DbU::Unit getX () const; - inline DbU::Unit getY () const; - inline DbU::Unit getId () const; + inline Element ( Tile*, uint32_t flags ); + inline bool operator< ( const Element& ) const; + inline bool isLeftEdge () const; + inline Tile* getTile () const; + inline DbU::Unit getX () const; + inline DbU::Unit getY () const; + inline DbU::Unit getId () const; + inline Layer::Mask getMask () const; private: Tile* _tile; uint32_t _flags; @@ -58,7 +64,7 @@ namespace Tramontana { ~SweepLine (); inline Cell* getCell (); void run (); - void loadTiles ( const BasicLayer* ); + void loadTiles (); void mergeEquipotentials (); Record* _getRecord () const; std::string _getString () const; @@ -69,22 +75,24 @@ namespace Tramontana { private: TramontanaEngine* _tramontana; std::vector _tiles; - TileIntvTree _intervalTree; + IntervalTrees _intervalTrees; }; // SweepLine::Element. - inline SweepLine::Element::Element ( Tile* tile, uint32_t flags ) : _tile(tile), _flags(flags) { } - inline bool SweepLine::Element::isLeftEdge () const { return _flags & Tile::LeftEdge; } - inline Tile* SweepLine::Element::getTile () const { return _tile; } - inline DbU::Unit SweepLine::Element::getX () const { return isLeftEdge() ? _tile->getLeftEdge() : _tile->getRightEdge(); } - inline DbU::Unit SweepLine::Element::getY () const { return _tile->getBoundingBox().getYMin(); } - inline DbU::Unit SweepLine::Element::getId () const { return _tile->getId(); } + inline SweepLine::Element::Element ( Tile* tile, uint32_t flags ) : _tile(tile), _flags(flags) { } + inline bool SweepLine::Element::isLeftEdge () const { return _flags & Tile::LeftEdge; } + inline Tile* SweepLine::Element::getTile () const { return _tile; } + inline DbU::Unit SweepLine::Element::getX () const { return isLeftEdge() ? _tile->getLeftEdge() : _tile->getRightEdge(); } + inline DbU::Unit SweepLine::Element::getY () const { return _tile->getBoundingBox().getYMin(); } + inline DbU::Unit SweepLine::Element::getId () const { return _tile->getId(); } + inline Layer::Mask SweepLine::Element::getMask () const { return _tile->getMask(); } inline bool SweepLine::Element::operator< ( const Element& rhs ) const { if (getX() != rhs.getX()) return (getX() < rhs.getX()); if (getY() != rhs.getY()) return (getY() < rhs.getY()); + if (getMask() != rhs.getMask()) return (getMask() < rhs.getMask()); return getId() < rhs.getId(); } diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h index 652d346a..a8bf7db9 100644 --- a/tramontana/src/tramontana/Tile.h +++ b/tramontana/src/tramontana/Tile.h @@ -68,7 +68,8 @@ namespace Tramontana { Tile* getRoot ( uint32_t flags=Compress ); inline Component* getComponent () const; inline Occurrence getOccurrence () const; - inline const BasicLayer* getLayer () const; + inline Layer::Mask getMask () const; + inline const BasicLayer* getLayer () const; inline const Box& getBoundingBox () const; inline Equipotential* getEquipotential () const; inline DbU::Unit getLeftEdge () const; @@ -110,6 +111,7 @@ namespace Tramontana { inline unsigned int Tile::getId () const { return getComponent()->getId(); } inline Component* Tile::getComponent () const { return dynamic_cast( _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; } From 5afb4cabe944f22171f8d00f0e1f708072f1a4bc Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 28 Mar 2023 16:06:49 +0200 Subject: [PATCH 12/28] Add a verbose option to ToolEngine, don't always display infos. --- crlcore/src/ccore/ToolEngine.cpp | 15 +++++++++------ crlcore/src/ccore/crlcore/ToolEngine.h | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) 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: From e968a5088f95d474390dc5df32bbf7f4b6036206 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 28 Mar 2023 16:08:11 +0200 Subject: [PATCH 13/28] Added recursive extraction of all instances models in Tramontana. --- tramontana/src/TramontanaEngine.cpp | 55 +++++++++++++++++--- tramontana/src/tramontana/TramontanaEngine.h | 8 ++- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp index bf5c8490..e31252f2 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -100,9 +100,10 @@ namespace Tramontana { { return static_cast(ToolEngine::get(cell,staticGetName())); } - TramontanaEngine::TramontanaEngine ( Cell* cell ) - : Super (cell) + TramontanaEngine::TramontanaEngine ( Cell* cell, uint32_t depth ) + : Super (cell, (depth==0)) , _viewer (NULL) + , _depth (depth) , _equipotentials() { } @@ -113,9 +114,9 @@ namespace Tramontana { } - TramontanaEngine* TramontanaEngine::create ( Cell* cell ) + TramontanaEngine* TramontanaEngine::create ( Cell* cell, uint32_t depth ) { - TramontanaEngine* tramontana = new TramontanaEngine ( cell ); + TramontanaEngine* tramontana = new TramontanaEngine ( cell, depth ); tramontana->_postCreate(); @@ -145,14 +146,52 @@ namespace Tramontana { void TramontanaEngine::extract () { - cmess1 << " o Extracting " << getCell() << endl; - startMeasures(); + if (getDepth() == 0) { + cmess1 << " o Extracting " << getCell() << endl; + startMeasures(); + } + + 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(); - stopMeasures(); - printMeasures(); + + 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; + } } diff --git a/tramontana/src/tramontana/TramontanaEngine.h b/tramontana/src/tramontana/TramontanaEngine.h index 95c07e68..d5beae81 100644 --- a/tramontana/src/tramontana/TramontanaEngine.h +++ b/tramontana/src/tramontana/TramontanaEngine.h @@ -49,15 +49,17 @@ namespace Tramontana { typedef ToolEngine Super; public: static const Name& staticGetName (); - static TramontanaEngine* create ( Cell* ); + 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* ); @@ -69,10 +71,11 @@ namespace Tramontana { static Name _toolName; private: CellViewer* _viewer; + uint32_t _depth; std::set _equipotentials; protected: // Constructors & Destructors. - TramontanaEngine ( Cell* ); + TramontanaEngine ( Cell*, uint32_t depth ); virtual ~TramontanaEngine (); virtual void _postCreate (); virtual void _preDestroy (); @@ -84,6 +87,7 @@ namespace Tramontana { 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; } From 6361ad4ca0c4a94a160ebe1135d5cb93c370f5e7 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 28 Mar 2023 16:09:00 +0200 Subject: [PATCH 14/28] Move the Tramontana menu from P&R to Tools. --- tramontana/src/GraphicTramontanaEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tramontana/src/GraphicTramontanaEngine.cpp b/tramontana/src/GraphicTramontanaEngine.cpp index 05bedb8f..b3380a7d 100644 --- a/tramontana/src/GraphicTramontanaEngine.cpp +++ b/tramontana/src/GraphicTramontanaEngine.cpp @@ -178,12 +178,12 @@ namespace Tramontana { _viewer = viewer; - if (_viewer->hasMenuAction("placeAndRoute.extract")) { + if (_viewer->hasMenuAction("tools.extract")) { cerr << Warning( "GraphicTramontanaEngine::addToMenu() - Tramontana extractor already hooked in." ) << endl; return; } - _viewer->addToMenu( "placeAndRoute.extract" + _viewer->addToMenu( "tools.extract" , "E&xtract . . . . . [Tramontana]" , "Run the extractor" , std::bind(&GraphicTramontanaEngine::_extract,this) From 518a376c01d03d4521ada01fccad15734f873d16 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 2 Apr 2023 23:02:46 +0200 Subject: [PATCH 15/28] Transhierarchical/flat extraction work, no netlist rebuild yet. * Bug: In Interval::intersect(), bad condition check in strict mode. * Change: In Occurrence::operator<(), change the sorting criterions so that the ones with no paths are "lower", then the one with no entities, then compare entities Id then Path hashes. * Change: In Occurrence::getCompactString(), to be more readable, suppress leading and ending "<>". * Change: In IntervalTree, now use an IntervalDataCompare to control the ordering of the nodes inside the tree. This may be needed when IntervalData is build upon a pointer, we don't want to sort on pointer values (non deterministic) . * Bug: In IntervalTree::postRemove(), there was an incorrect computation of the updated childsVMax. * Bug: In IntervalTree::beginOverlaps(), miscalculated leftmost interval overlapping. * Bug: In RbTree::remove(), when exchanging the removed node for a leaf, fully swap the nodes contents, was incompletly copied before. * New: In CellWidget, add new slots selectSet(OccurrenceSet&) and unselectSet(OccurrenceSet&), to be able to select/unselected sets of Occurrence (for use by TabEquipotentials). * Change: In EtesianEngine, no more need to remove leading/ending "<>". * New: In Tramontana, use a Query to find all the Occurrence under an area. Previously we were using Cell::getOccurrencesUnder() which *do not* return the components in instances, so we would have been unable to find trans-hierarchical shorts circuits. * New: In tramontana, now use a Relation to tag all the components belonging to an Equipotential. * Change: In Equipotential, store everything under the form of Occurrence, instead of Components. Due to the way the Occurrences are sorted, the one holding Components should be firts. --- etesian/src/EtesianEngine.cpp | 8 +- hurricane/src/hurricane/Commons.cpp | 20 +- hurricane/src/hurricane/Interval.cpp | 8 +- hurricane/src/hurricane/Occurrence.cpp | 30 ++- hurricane/src/hurricane/hurricane/Commons.h | 3 + .../src/hurricane/hurricane/IntervalTree.h | 252 ++++++++++++------ .../src/hurricane/hurricane/Occurrence.h | 4 + hurricane/src/hurricane/hurricane/RbTree.h | 65 +++-- hurricane/src/viewer/CellWidget.cpp | 37 +++ .../src/viewer/hurricane/viewer/CellWidget.h | 2 + tramontana/src/CMakeLists.txt | 4 + tramontana/src/Equipotential.cpp | 81 ++++-- tramontana/src/EquipotentialRelation.cpp | 81 ++++++ tramontana/src/EquipotentialsWidget.cpp | 14 +- tramontana/src/QueryTiles.cpp | 91 +++++++ tramontana/src/SweepLine.cpp | 155 ++++++++--- tramontana/src/TabEquipotentials.cpp | 8 +- tramontana/src/Tile.cpp | 14 +- tramontana/src/TramontanaEngine.cpp | 5 +- tramontana/src/tramontana/Equipotential.h | 102 ++++--- .../src/tramontana/EquipotentialRelation.h | 54 ++++ .../src/tramontana/EquipotentialsWidget.h | 9 +- tramontana/src/tramontana/QueryTiles.h | 60 +++++ tramontana/src/tramontana/SweepLine.h | 25 +- tramontana/src/tramontana/Tile.h | 17 +- 25 files changed, 891 insertions(+), 258 deletions(-) create mode 100644 tramontana/src/EquipotentialRelation.cpp create mode 100644 tramontana/src/QueryTiles.cpp create mode 100644 tramontana/src/tramontana/EquipotentialRelation.h create mode 100644 tramontana/src/tramontana/QueryTiles.h diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index 267fd03d..274636f0 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -883,8 +883,8 @@ namespace Etesian { Cell* masterCell = instance->getMasterCell(); 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 ); if (CatalogExtension::isFeed(masterCell)) { string feedName = getString( instance->getName() ); @@ -1557,8 +1557,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/Occurrence.cpp b/hurricane/src/hurricane/Occurrence.cpp index 49cb3456..67e3750f 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,7 +285,7 @@ string Occurrence::_getString() const string Occurrence::getCompactString() const // **************************************** { - string s = "<"; + string s; if (_entity) { s += getString(getOwnerCell()->getName()); s += ":"; @@ -291,7 +302,6 @@ string Occurrence::getCompactString() const } } } - s += ">"; return s; } 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/IntervalTree.h b/hurricane/src/hurricane/hurricane/IntervalTree.h index 20c55536..d104d117 100644 --- a/hurricane/src/hurricane/hurricane/IntervalTree.h +++ b/hurricane/src/hurricane/hurricane/IntervalTree.h @@ -55,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: @@ -62,7 +63,7 @@ namespace Hurricane { Data data_; }; - + template< typename Data > inline IntervalData::IntervalData () : Interval(1,-1) @@ -91,9 +92,19 @@ 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 > std::string IntervalData::_getString () const { @@ -116,13 +127,34 @@ namespace Hurricane { } +// ------------------------------------------------------------------- +// 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::CompareByMinMax > { + template< typename Data, typename DataCompare=std::less > + class IntervalTree : public RbTree< IntervalData, IntervalDataCompare > { public: - typedef RbTree< IntervalData, Interval::CompareByMinMax > Super; + typedef RbTree< IntervalData, IntervalDataCompare > Super; public: class overlap_iterator : public Super::iterator { public: @@ -169,32 +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++ () { + 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; } @@ -207,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") + ">"; @@ -252,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_) @@ -292,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(); @@ -334,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; @@ -381,34 +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. 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 d441540d..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(); @@ -560,12 +565,18 @@ namespace Hurricane { cdebug_log(0,0) << "| " << current->getValue() << std::endl; if (current->getValue() == value) { - cdebug_log(0,-1) << "> Value found: " << current->getValue() < 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/viewer/CellWidget.cpp b/hurricane/src/viewer/CellWidget.cpp index 02edb928..573dea8e 100644 --- a/hurricane/src/viewer/CellWidget.cpp +++ b/hurricane/src/viewer/CellWidget.cpp @@ -2712,6 +2712,31 @@ namespace Hurricane { } + 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 ( Occurrence occurrence ) { if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) { @@ -2823,6 +2848,18 @@ namespace Hurricane { } + 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::unselectAll () { ++_delaySelectionChanged; diff --git a/hurricane/src/viewer/hurricane/viewer/CellWidget.h b/hurricane/src/viewer/hurricane/viewer/CellWidget.h index 5b277e3f..51abdff6 100644 --- a/hurricane/src/viewer/hurricane/viewer/CellWidget.h +++ b/hurricane/src/viewer/hurricane/viewer/CellWidget.h @@ -265,12 +265,14 @@ namespace Hurricane { inline DrawingPlanes& getDrawingPlanes (); // void select ( const Net* ); void select ( Occurrence ); + void selectSet ( const OccurrenceSet& ); void selectSet ( const ComponentSet& ); bool isSelected ( Occurrence ); void selectOccurrencesUnder ( Box selectArea ); // void unselect ( const Net* ); void unselect ( Occurrence ); void unselectSet ( const ComponentSet& ); + void unselectSet ( const OccurrenceSet& ); void unselectAll (); void toggleSelection ( Occurrence ); void setShowSelection ( bool state ); diff --git a/tramontana/src/CMakeLists.txt b/tramontana/src/CMakeLists.txt index b916b224..56692952 100644 --- a/tramontana/src/CMakeLists.txt +++ b/tramontana/src/CMakeLists.txt @@ -10,8 +10,10 @@ ${Python_INCLUDE_DIRS} ) set( includes tramontana/Tile.h + tramontana/QueryTiles.h tramontana/SweepLine.h tramontana/Equipotential.h + tramontana/EquipotentialRelation.h tramontana/TramontanaEngine.h tramontana/GraphicTramontanaEngine.h ) @@ -24,8 +26,10 @@ tramontana/TabEquipotentials.h ) set( cpps Tile.cpp + QueryTiles.cpp SweepLine.cpp Equipotential.cpp + EquipotentialRelation.cpp TramontanaEngine.cpp GraphicTramontanaEngine.cpp EquipotentialsModel.cpp diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp index 6a7f6574..c5092f00 100644 --- a/tramontana/src/Equipotential.cpp +++ b/tramontana/src/Equipotential.cpp @@ -37,12 +37,14 @@ #include "hurricane/RoutingPad.h" #include "crlcore/Utilities.h" #include "tramontana/Equipotential.h" +#include "tramontana/EquipotentialRelation.h" #include "tramontana/TramontanaEngine.h" namespace { using Hurricane::Net; + using Hurricane::Occurrence; class NetCompareByName { @@ -63,6 +65,24 @@ namespace { } + class OccNetCompareByName { + public: + bool operator() ( const Occurrence& lhs, const Occurrence& rhs ) const; + }; + + + 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()) ); + } + + } // Anonymous namespace. @@ -158,19 +178,11 @@ namespace Tramontana { Box Equipotential::getBoundingBox () const { return _boundingBox; } - - void Equipotential::add ( Component* component ) + + void Equipotential::add ( Occurrence component, const Box& boundingBox ) { _components.insert( component ); - } - - - void Equipotential::add ( Occurrence child ) - { - if (child.getPath().isEmpty()) - add( dynamic_cast( child.getEntity() )); - else - _childs.push_back( child ); + _boundingBox.merge( boundingBox ); } @@ -184,20 +196,26 @@ namespace Tramontana { return; } - for ( Component* component : other->getComponents() ) { - add( component ); - } - for ( Occurrence child : other->getChilds() ) { - add( child ); - } + for ( const Occurrence& component : other->getComponents() ) add( component ); + for ( const Occurrence& child : other->getChilds () ) add( child ); + _boundingBox.merge( other->_boundingBox ); other->clear(); } void Equipotential::consolidate () { - set nets; - for ( Component* component : getComponents() ) { + EquipotentialRelation* relation = EquipotentialRelation::create( this ); + set 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 { @@ -209,8 +227,17 @@ namespace Tramontana { } nets.insert( component->getNet() ); } - _name = getString( (*nets.begin())->getName() ); + if (not nets.empty()) { + _name = getString( (*nets.begin())->getName() ); + } else { + if (not deepNets.empty()) { + _name = (*deepNets.begin()).getCompactString(); + } + } _netCount = nets.size(); + + // if (_name == "abc_11873_auto_rtlil_cc_2560_muxgate_11612") + // show(); } @@ -221,6 +248,20 @@ namespace Tramontana { } + 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; diff --git a/tramontana/src/EquipotentialRelation.cpp b/tramontana/src/EquipotentialRelation.cpp new file mode 100644 index 00000000..bcd9af95 --- /dev/null +++ b/tramontana/src/EquipotentialRelation.cpp @@ -0,0 +1,81 @@ +// -*- 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 : "./EquipotentialRelation.cpp" | +// +-----------------------------------------------------------------+ + + +#include "tramontana/EquipotentialRelation.h" + + +namespace Tramontana { + + using std::string; + using Hurricane::Property; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::EquipotentialRelation". + + const Name EquipotentialRelationName = "EquipotentialRelation"; + + + EquipotentialRelation::EquipotentialRelation ( Equipotential* owner ) + : Super(owner) + { } + + + EquipotentialRelation* EquipotentialRelation::create ( Equipotential* owner ) + { + EquipotentialRelation* relation = new EquipotentialRelation ( owner ); + relation->_postCreate(); + return relation; + } + + + void EquipotentialRelation::_preDestroy () + { Super::_preDestroy(); } + + + 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/EquipotentialsWidget.cpp b/tramontana/src/EquipotentialsWidget.cpp index f6ec7a57..f4f39bf8 100644 --- a/tramontana/src/EquipotentialsWidget.cpp +++ b/tramontana/src/EquipotentialsWidget.cpp @@ -104,7 +104,7 @@ namespace Tramontana { , 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()) ); + connect( fitAction, SIGNAL(triggered()), this, SLOT(fitToEqui()) ); resize( 300, 300 ); } @@ -180,11 +180,11 @@ namespace Tramontana { } - // void EquipotentialsWidget::fitToNet () - // { - // const Equipotential* equi = _baseModel->getEqui( _sortModel->mapToSource(_view->currentIndex()).row() ); - // if (equi) emit netFitted ( equi ); - // } + void EquipotentialsWidget::fitToEqui () + { + const Equipotential* equi = _baseModel->getEqui( _sortModel->mapToSource(_view->currentIndex()).row() ); + if (equi) emit reframe ( equi->getBoundingBox() ); + } void EquipotentialsWidget::setCellWidget ( CellWidget* cw ) @@ -196,7 +196,7 @@ namespace Tramontana { _cellWidget = cw; if (_cellWidget) { setCell( _cellWidget->getCell() ); - //connect( this, SIGNAL(netFitted(const Equi*)), _cellWidget, SLOT(fitToEqui (const Equi*)) ); + connect( this, SIGNAL( reframe(const Box&) ), _cellWidget, SLOT( reframe(const Box&) )); } else setCell( nullptr ); } diff --git a/tramontana/src/QueryTiles.cpp b/tramontana/src/QueryTiles.cpp new file mode 100644 index 00000000..eb3f4833 --- /dev/null +++ b/tramontana/src/QueryTiles.cpp @@ -0,0 +1,91 @@ +// -*- 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 ) + { + vector tiles; + Component* component = dynamic_cast( go ); + if (not component) return; + if (isProcessed(component)) return; + Occurrence occurrence = Occurrence( go, getPath() ); + for ( const BasicLayer* layer : _sweepLine->getExtracteds() ) { + if (not component->getLayer()->getMask().intersect(layer->getMask())) continue; + tiles.push_back( Tile::create( occurrence, layer )); + _sweepLine->add( tiles.back() ); + if (tiles.size() > 1) + tiles.back()->setParent( tiles[0] ); + } + _goMatchCount++; + } + + +} // Tramontana namespace. diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index c40715a1..cced774e 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -38,6 +38,7 @@ #include "hurricane/RoutingPad.h" #include "crlcore/Utilities.h" #include "tramontana/SweepLine.h" +#include "tramontana/QueryTiles.h" namespace Tramontana { @@ -84,9 +85,24 @@ namespace Tramontana { SweepLine::SweepLine ( TramontanaEngine* tramontana ) : _tramontana (tramontana) + , _extracteds () , _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) + _extracteds.push_back( bl ); + } + + // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal5" )); + // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal4" )); + // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal3" )); + // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal2" )); + // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal1" )); + // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "poly" )); + } SweepLine::~SweepLine () @@ -95,13 +111,26 @@ namespace Tramontana { void SweepLine::run () { - //cerr << "SweepLine::run()" << endl; - //DebugSession::open( 0, 2 ); + //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() ); - //cerr << right << setw(10) << DbU::getValueString(element.getX()) << " > " << tile << endl; + // 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." @@ -109,19 +138,77 @@ namespace Tramontana { , getString(element.getMask()).c_str() , getString(element.getTile()).c_str() ) << endl; + cdebug_tabw(160,-1); continue; } if (element.isLeftEdge()) { + // if (tile->getId() == 60117) { + // DebugSession::open( 0, 169 ); + // 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() ))) { - //cerr << " | intersect " << overlap.getData() << endl; + cdebug_log(160,0) << " | intersect " << overlap.getData() << endl; tile->merge( overlap.getData() ); } - //cerr << " | insert tile" << endl; + 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->getId() == 60117) { + // if (not written) intvTree->second.write( "tree-after.gv" ); + // written = true; + // DebugSession::close(); + // } } else { - //cerr << " | remove tile" << endl; + // 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() ) { @@ -129,7 +216,11 @@ namespace Tramontana { // } // } } + intvTree->second.checkVMax(); + cdebug_tabw(160,-1); } + //if (debugOn) DebugSession::close(); + cdebug_tabw(160,-1); //DebugSession::close(); mergeEquipotentials(); } @@ -138,37 +229,35 @@ namespace Tramontana { void SweepLine::loadTiles () { //cerr << "SweepLine::loadTiles()" << endl; - vector extracteds; - for ( const BasicLayer* bl : DataBase::getDB()->getTechnology()->getBasicLayers() ) { - if (bl->getMaterial() == BasicLayer::Material::metal) - extracteds.push_back( bl ); - } - - // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal5" )); - // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal4" )); - // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal3" )); - // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal2" )); - // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal1" )); - // extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "poly" )); - for ( const BasicLayer* layer : extracteds ) { + for ( const BasicLayer* layer : _extracteds ) { _intervalTrees.insert( make_pair( layer->getMask(), TileIntvTree() )); } - for ( Occurrence occurrence : getCell()->getOccurrencesUnder( getCell()->getBoundingBox() ) ) { - vector tiles; - Component* component = dynamic_cast( occurrence.getEntity() ); - 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(); + 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() ); } diff --git a/tramontana/src/TabEquipotentials.cpp b/tramontana/src/TabEquipotentials.cpp index 78829b4f..0c4ecac2 100644 --- a/tramontana/src/TabEquipotentials.cpp +++ b/tramontana/src/TabEquipotentials.cpp @@ -96,14 +96,14 @@ namespace Tramontana { getCellWidget()->closeRefreshSession (); } getCellWidget()->setShowSelection( true ); - connect( _browser, SIGNAL(equipotentialSelect (const ComponentSet&)), getCellWidget(), SLOT(selectSet (const ComponentSet&)) ); - connect( _browser, SIGNAL(equipotentialUnselect(const ComponentSet&)), getCellWidget(), SLOT(unselectSet(const ComponentSet&)) ); + connect( _browser, SIGNAL(equipotentialSelect (const OccurrenceSet&)), getCellWidget(), SLOT(selectSet (const OccurrenceSet&)) ); + connect( _browser, SIGNAL(equipotentialUnselect(const OccurrenceSet&)), getCellWidget(), SLOT(unselectSet(const OccurrenceSet&)) ); _browser->updateSelecteds(); } else { getCellWidget()->setShowSelection( false ); getCellWidget()->setCumulativeSelection( _cwCumulativeSelection ); - _browser->disconnect( getCellWidget(), SLOT(selectSet (const ComponentSet&)) ); - _browser->disconnect( getCellWidget(), SLOT(unselectSet(const ComponentSet&)) ); + _browser->disconnect( getCellWidget(), SLOT(selectSet (const OccurrenceSet&)) ); + _browser->disconnect( getCellWidget(), SLOT(unselectSet(const OccurrenceSet&)) ); } } diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp index 550778cb..8c2eefa8 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -133,9 +133,14 @@ namespace Tramontana { { } + Net* Tile::getNet () const + { return dynamic_cast( _occurrence.getEntity() )->getNet(); } + + Tile* Tile::getRoot ( uint32_t flags ) { if (not getParent() and (not (flags & MergeEqui))) return this; + cdebug_log(160,1) << "Tile::getRoot()" << endl; Tile* root = this; while ( root->getParent() ) { @@ -145,6 +150,7 @@ namespace Tramontana { } root = root->getParent(); } + cdebug_log(160,0) << "> root " << root->getId() << endl; if (flags & Compress) { Tile* current = this; @@ -166,16 +172,18 @@ namespace Tramontana { if (current->isUpToDate()) break; if (current->getEquipotential()) { if (current->getEquipotential() != rootEqui) { + cdebug_log(160,0) << "| merge " << current->getId() << " => " << root->getId() << endl; rootEqui->merge( current->getEquipotential() ); } } else { - rootEqui->add( current->getOccurrence() ); + rootEqui->add( current->getOccurrence(), _boundingBox ); } current->syncTime(); current = current->getParent(); } } + cdebug_tabw(160,-1); return root; } @@ -208,7 +216,9 @@ namespace Tramontana { } _equipotential = Equipotential::create( _occurrence.getOwnerCell() ); - _equipotential->add( _occurrence ); + _equipotential->add( _occurrence, _boundingBox ); + //cerr << "new " << _equipotential << endl; + //cerr << "| " << _occurrence << endl; return _equipotential; } diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp index e31252f2..6631b0df 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -199,10 +199,7 @@ namespace Tramontana { { cerr << "Equipotentials:" << endl; for ( Equipotential* equi : _equipotentials ) { - cerr << equi << endl; - for ( Component* component : equi->getComponents() ) { - cerr << "| " << component << endl; - } + equi->show(); } } diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h index f8f9bb5b..0c9ceb90 100644 --- a/tramontana/src/tramontana/Equipotential.h +++ b/tramontana/src/tramontana/Equipotential.h @@ -18,12 +18,10 @@ #pragma once #include -#include +#include +#include "hurricane/Net.h" #include "hurricane/Component.h" #include "hurricane/Occurrence.h" -namespace Hurricane { - class Net; -} namespace Tramontana { @@ -38,7 +36,7 @@ namespace Tramontana { using Hurricane::Net; using Hurricane::Cell; using Hurricane::Component; - using Hurricane::ComponentSet; + using Hurricane::OccurrenceSet; using Hurricane::Occurrence; @@ -49,60 +47,60 @@ namespace Tramontana { public: typedef Entity Super; public: - static Equipotential* create ( Cell* ); - inline bool isEmpty () const; - virtual Cell* getCell () const; - virtual Box getBoundingBox () const; - inline std::string getName () const; - std::string getFlagsAsString () const; - inline Net::Type getType () const; - inline Net::Direction getDirection () const; - inline bool hasComponent ( Component* ) const; - void add ( Component* ); - void add ( Occurrence ); - void merge ( Equipotential* ); - void consolidate (); - void clear (); - inline const ComponentSet& getComponents () const; - inline const std::vector& getChilds () const; - Record* _getRecord () const; - std::string _getString () const; - std::string _getTypeName () const; - protected: - virtual void _postCreate (); - virtual void _preDestroy (); - private: - Equipotential ( Cell* ); - ~Equipotential (); - private: - Equipotential ( const Equipotential& ) = delete; - Equipotential& operator= ( const Equipotential& ) = delete; + static Equipotential* create ( Cell* ); + inline bool isEmpty () const; + virtual Cell* getCell () const; + virtual Box getBoundingBox () const; + inline std::string getName () const; + std::string getFlagsAsString () const; + inline Net::Type getType () const; + inline Net::Direction getDirection () const; + void show () const; + inline bool hasComponent ( Component* ) const; + void add ( Occurrence, const Box& boundingBox=Box() ); + void merge ( Equipotential* ); + void consolidate (); + void clear (); + inline const OccurrenceSet& getComponents () const; + inline const OccurrenceSet& getChilds () const; + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + protected: + virtual void _postCreate (); + virtual void _preDestroy (); + private: + Equipotential ( Cell* ); + ~Equipotential (); + private: + Equipotential ( const Equipotential& ) = delete; + Equipotential& operator= ( const Equipotential& ) = delete; private: - Cell* _owner; - Box _boundingBox; - ComponentSet _components; - std::vector _childs; - std::string _name; - Net::Type _type; - Net::Direction _direction; - uint32_t _netCount; - bool _isExternal; - bool _isGlobal; - bool _isAutomatic; - bool _hasFused; + Cell* _owner; + Box _boundingBox; + OccurrenceSet _components; + OccurrenceSet _childs; + std::string _name; + Net::Type _type; + Net::Direction _direction; + uint32_t _netCount; + bool _isExternal; + bool _isGlobal; + bool _isAutomatic; + bool _hasFused; }; - inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } - inline const ComponentSet& Equipotential::getComponents () const { return _components; } - inline std::string Equipotential::getName () const { return _name; } - inline Net::Type Equipotential::getType () const { return _type; } - inline Net::Direction Equipotential::getDirection () const { return _direction; } - inline const std::vector& Equipotential::getChilds () const { return _childs; } + inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } + inline const OccurrenceSet& Equipotential::getComponents () const { return _components; } + inline const OccurrenceSet& Equipotential::getChilds () const { return _childs; } + 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 bool Equipotential::hasComponent ( Component* component ) const - { return _components.find( component ) != _components.end(); } + { return _components.find( Occurrence(component) ) != _components.end(); } } // Tramontana namespace. diff --git a/tramontana/src/tramontana/EquipotentialRelation.h b/tramontana/src/tramontana/EquipotentialRelation.h new file mode 100644 index 00000000..0102c267 --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialRelation.h @@ -0,0 +1,54 @@ +// -*- 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" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + + using Hurricane::Name; + using Hurricane::Record; + using Hurricane::Relation; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::EquipotentialRelation". + + class EquipotentialRelation : public Relation { + public: + typedef Relation Super; + public: + static EquipotentialRelation* get ( const Component* ); + static EquipotentialRelation* create ( Equipotential* ); + 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/EquipotentialsWidget.h b/tramontana/src/tramontana/EquipotentialsWidget.h index 4ebdcb04..ec48d62f 100644 --- a/tramontana/src/tramontana/EquipotentialsWidget.h +++ b/tramontana/src/tramontana/EquipotentialsWidget.h @@ -44,6 +44,7 @@ namespace Tramontana { using std::set; using Hurricane::Cell; using Hurricane::CellWidget; + using Hurricane::OccurrenceSet; // ------------------------------------------------------------------- @@ -136,13 +137,13 @@ namespace Tramontana { void goTo ( int ); void updateSelecteds (); signals: - void equipotentialSelect ( const ComponentSet& ); - void equipotentialUnselect ( const ComponentSet& ); - void netFitted ( const Equipotential* ); + void equipotentialSelect ( const OccurrenceSet& ); + void equipotentialUnselect ( const OccurrenceSet& ); + void reframe ( const Box& ); private slots: void textFilterChanged (); void updateSelecteds ( const QItemSelection& , const QItemSelection& ); - // void fitToEqui (); + void fitToEqui (); private: CellWidget* _cellWidget; 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 index 0fb6d0eb..b7f8be26 100644 --- a/tramontana/src/tramontana/SweepLine.h +++ b/tramontana/src/tramontana/SweepLine.h @@ -49,6 +49,7 @@ namespace Tramontana { 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; @@ -63,8 +64,11 @@ namespace Tramontana { SweepLine ( TramontanaEngine* ); ~SweepLine (); inline Cell* getCell (); + inline const std::vector& + getExtracteds () const; void run (); void loadTiles (); + inline void add ( Tile* ); void mergeEquipotentials (); Record* _getRecord () const; std::string _getString () const; @@ -73,9 +77,10 @@ namespace Tramontana { SweepLine ( const SweepLine& ) = delete; SweepLine& operator= ( const SweepLine& ) = delete; private: - TramontanaEngine* _tramontana; - std::vector _tiles; - IntervalTrees _intervalTrees; + TramontanaEngine* _tramontana; + std::vector _extracteds; + std::vector _tiles; + IntervalTrees _intervalTrees; }; @@ -91,14 +96,26 @@ namespace Tramontana { 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 getId() < rhs.getId(); + 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 void SweepLine::add ( Tile* tile ) + { + _tiles.push_back( Element( tile, Tile::LeftEdge ) ); + _tiles.push_back( Element( tile, Tile::RightEdge ) ); + } diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h index a8bf7db9..f73f1242 100644 --- a/tramontana/src/tramontana/Tile.h +++ b/tramontana/src/tramontana/Tile.h @@ -68,8 +68,9 @@ namespace Tramontana { 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 BasicLayer* getLayer () const; inline const Box& getBoundingBox () const; inline Equipotential* getEquipotential () const; inline DbU::Unit getLeftEdge () const; @@ -128,12 +129,22 @@ namespace Tramontana { inline void Tile::setEquipotential ( Equipotential* equi ) { _equipotential=equi; } + class TileCompare { + public: + inline bool operator() ( const Tile* lhs, const Tile* rhs ) const + { + cdebug_log(0,0) << "TileCompare::operator()" << std::endl; + return lhs->getOccurrence() < rhs->getOccurrence(); + } + }; + + // ------------------------------------------------------------------- // Class : "Tramontana::TileIntvTree". - typedef IntervalData TileIntv; - typedef IntervalTree TileIntvTree; + typedef IntervalData TileIntv; + typedef IntervalTree TileIntvTree; } // Tramontana namespace. From b9862ecd5e82b8fcc4bdfdb2eab2fb3a2fbe8cf6 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 13 Apr 2023 00:14:12 +0200 Subject: [PATCH 16/28] Fix scaling in CellImage::toImage(), compute size from *screen widget*. --- hurricane/src/viewer/CellImage.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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; From 31b0c4daf14a1597430998ae9a84b3ce9f73457b Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 13 Apr 2023 00:15:38 +0200 Subject: [PATCH 17/28] Add selection/unselection by Occurrence collection in CellWidget. --- hurricane/src/viewer/CellWidget.cpp | 37 +++++++++++++++++++ .../src/viewer/hurricane/viewer/CellWidget.h | 2 + 2 files changed, 39 insertions(+) diff --git a/hurricane/src/viewer/CellWidget.cpp b/hurricane/src/viewer/CellWidget.cpp index 573dea8e..cffabcde 100644 --- a/hurricane/src/viewer/CellWidget.cpp +++ b/hurricane/src/viewer/CellWidget.cpp @@ -2737,6 +2737,31 @@ namespace Hurricane { } + 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 ); + } + + void CellWidget::select ( Occurrence occurrence ) { if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) { @@ -2860,6 +2885,18 @@ namespace Hurricane { } + void CellWidget::unselect ( Occurrences occurrences ) + { + ++_delaySelectionChanged; + for ( const Occurrence& occurrence : occurrences ) { + if (occurrence.getOwnerCell() == getCell()) { + unselect( occurrence ); + } + } + if ( --_delaySelectionChanged == 0 ) emit selectionChanged( _selectors ); + } + + void CellWidget::unselectAll () { ++_delaySelectionChanged; diff --git a/hurricane/src/viewer/hurricane/viewer/CellWidget.h b/hurricane/src/viewer/hurricane/viewer/CellWidget.h index 51abdff6..3abd74f1 100644 --- a/hurricane/src/viewer/hurricane/viewer/CellWidget.h +++ b/hurricane/src/viewer/hurricane/viewer/CellWidget.h @@ -265,12 +265,14 @@ 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 (); From 57bab117b453070e0342532ce3143d4b63854532 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 13 Apr 2023 00:18:10 +0200 Subject: [PATCH 18/28] Add typedef NetSet, for set of Net* sorted by Ids. --- hurricane/src/hurricane/hurricane/IntervalTree.h | 2 +- hurricane/src/hurricane/hurricane/Net.h | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hurricane/src/hurricane/hurricane/IntervalTree.h b/hurricane/src/hurricane/hurricane/IntervalTree.h index d104d117..58f4264d 100644 --- a/hurricane/src/hurricane/hurricane/IntervalTree.h +++ b/hurricane/src/hurricane/hurricane/IntervalTree.h @@ -99,12 +99,12 @@ namespace Hurricane { 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 > std::string IntervalData::_getString () const { diff --git a/hurricane/src/hurricane/hurricane/Net.h b/hurricane/src/hurricane/hurricane/Net.h index a239352f..5f598133 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" @@ -445,9 +443,10 @@ namespace Hurricane { // Because sometimes it didn't happens (?). const SlotTemplate dummyNetSlot ( string("dummyNetSlot"), NULL ); -} -#endif // HURRICANE_NET + typedef std::set NetSet; + +} // **************************************************************************************************** From c3bed612578f20196acb859b56e155e190900b18 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 13 Apr 2023 14:00:50 +0200 Subject: [PATCH 19/28] Full transhierarchical implementation done. * New: Equipotential elements includes now: 1. Components at the top level (the cell owning the Equi). 2. Nets at the top level. If an equi include all the components of a Net, own the Net, not all it's individual components. 3. Other equipotentials from the Instances immediatey below. Thoses equis should be equivalents to the Plug of the Net. They are stored in the form of Occurrences , the relation is stored on that Occurrence. * New: Equipotential::getFlatComponents(), a collection to recursively get all the *component* occurrences of the equi. Transhierarchically. Go through components, nets components, and recursively through the child equis. * New: EquipotentialRelation, the master of this relation is the Equipotential and the slaves, all its elements. * Change: In Tile, in case the tile is build on a deep component, we trace up the Equipotential it belongs to in the Instance level immediately belonging to the Cell under extraction. They must exists as we extract from bottom to top all the master cells. So we have, for that tile an Occurrence that we can store in the current Equi level. * Change/Bug: In Tile, add an Id to be reliably sort the tiles in the IntervalTree. As we replaced the tile component occurrence by a we were having multiple tiles with the same equi. This was causing havoc again in the IntervalTree. Should add a check in the RbTree for elements with the exact same key, but that would imply passing a new template parameter for the "equal" function. --- tramontana/src/CMakeLists.txt | 2 + tramontana/src/Equipotential.cpp | 145 ++++++++++- tramontana/src/EquipotentialComponents.cpp | 242 ++++++++++++++++++ tramontana/src/EquipotentialRelation.cpp | 5 + tramontana/src/EquipotentialsWidget.cpp | 4 +- tramontana/src/SweepLine.cpp | 19 +- tramontana/src/TabEquipotentials.cpp | 8 +- tramontana/src/Tile.cpp | 22 +- tramontana/src/TramontanaEngine.cpp | 2 +- tramontana/src/tramontana/Equipotential.h | 80 +++--- .../src/tramontana/EquipotentialComponents.h | 110 ++++++++ .../src/tramontana/EquipotentialRelation.h | 4 +- .../src/tramontana/EquipotentialsWidget.h | 4 +- tramontana/src/tramontana/Tile.h | 12 +- 14 files changed, 589 insertions(+), 70 deletions(-) create mode 100644 tramontana/src/EquipotentialComponents.cpp create mode 100644 tramontana/src/tramontana/EquipotentialComponents.h diff --git a/tramontana/src/CMakeLists.txt b/tramontana/src/CMakeLists.txt index 56692952..c0c81af1 100644 --- a/tramontana/src/CMakeLists.txt +++ b/tramontana/src/CMakeLists.txt @@ -14,6 +14,7 @@ tramontana/SweepLine.h tramontana/Equipotential.h tramontana/EquipotentialRelation.h + tramontana/EquipotentialComponents.h tramontana/TramontanaEngine.h tramontana/GraphicTramontanaEngine.h ) @@ -30,6 +31,7 @@ SweepLine.cpp Equipotential.cpp EquipotentialRelation.cpp + EquipotentialComponents.cpp TramontanaEngine.cpp GraphicTramontanaEngine.cpp EquipotentialsModel.cpp diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp index c5092f00..e92466a2 100644 --- a/tramontana/src/Equipotential.cpp +++ b/tramontana/src/Equipotential.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "hurricane/utilities/Path.h" #include "hurricane/DebugSession.h" #include "hurricane/UpdateSession.h" @@ -38,12 +39,15 @@ #include "crlcore/Utilities.h" #include "tramontana/Equipotential.h" #include "tramontana/EquipotentialRelation.h" +#include "tramontana/EquipotentialComponents.h" #include "tramontana/TramontanaEngine.h" namespace { + using std::map; using Hurricane::Net; + using Hurricane::Plug; using Hurricane::Occurrence; @@ -120,13 +124,73 @@ namespace Tramontana { using Hurricane::RoutingPad; using Hurricane::Cell; using Hurricane::Instance; + using Hurricane::Path; // ------------------------------------------------------------------- // Class : "Tramontana::Equipotential". - const char* defaultName = "Unamed (please call consolidate())"; + 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 ) @@ -134,7 +198,7 @@ namespace Tramontana { , _boundingBox() , _components () , _childs () - , _name (defaultName) + , _name () , _type (Net::Type::UNDEFINED) , _direction (Net::Direction::DirUndefined) , _netCount (0) @@ -142,7 +206,9 @@ namespace Tramontana { , _isGlobal (false) , _isAutomatic(false) , _hasFused (false) - { } + { + _name = "Unnamed_" + getString( getId() ); + } void Equipotential::_postCreate () @@ -178,10 +244,33 @@ namespace Tramontana { Box Equipotential::getBoundingBox () const { return _boundingBox; } + + Occurrences Equipotential::getFlatComponents () const + { return EquipotentialComponents( this ); } + - void Equipotential::add ( Occurrence component, const Box& boundingBox ) + void Equipotential::add ( Occurrence occ, const Box& boundingBox ) { - _components.insert( component ); + if(occ.getPath().isEmpty()) { + _components.insert( occ ); + } 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 ); } @@ -206,7 +295,7 @@ namespace Tramontana { void Equipotential::consolidate () { EquipotentialRelation* relation = EquipotentialRelation::create( this ); - set nets; + map nets; set deepNets; for ( const Occurrence& occurrence : getComponents() ) { Component* component = dynamic_cast( occurrence.getEntity() ); @@ -225,10 +314,15 @@ namespace Tramontana { _type = net->getType(); _direction |= net->getDirection(); } - nets.insert( component->getNet() ); + 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())->getName() ); + _name = getString( (*nets.begin()).first->getName() ); } else { if (not deepNets.empty()) { _name = (*deepNets.begin()).getCompactString(); @@ -236,6 +330,31 @@ namespace Tramontana { } _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 (_name == "abc_11873_auto_rtlil_cc_2560_muxgate_11612") // show(); } @@ -245,6 +364,7 @@ namespace Tramontana { { _components.clear(); _childs .clear(); + _nets .clear(); } @@ -268,7 +388,8 @@ namespace Tramontana { sflags += ((_isExternal ) ? "e" : "-"); sflags += ((_isGlobal ) ? "g" : "-"); sflags += ((_isAutomatic) ? "a" : "-"); - sflags += " [" + getString( _netCount - ((_hasFused) ? 1 : 0) ); + sflags += " [N:" + getString( _netCount - ((_hasFused) ? 1 : 0) ); + sflags += "+E:" + getString( _childs.size() ); if (_hasFused) sflags += "+fused"; sflags += "] "; @@ -295,13 +416,13 @@ namespace Tramontana { Record* Equipotential::_getRecord () const { - Record* record = new Record ( _getString() ); + Record* record = Super::_getRecord(); if (record) { - record->add( getSlot( "_owner" , &_owner ) ); + 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 ) ); - //record->add( getSlot( "_name" , &_name ) ); } return record; } diff --git a/tramontana/src/EquipotentialComponents.cpp b/tramontana/src/EquipotentialComponents.cpp new file mode 100644 index 00000000..6c4470b9 --- /dev/null +++ b/tramontana/src/EquipotentialComponents.cpp @@ -0,0 +1,242 @@ +// -*- 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 _componentsLocator) { + _componentsLocator = (*_netsIterator)->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 = "getAccesses() ) { case 1: break; case 64: - emit equipotentialSelect ( isel->getEqui()->getComponents() ); + emit equipotentialSelect ( isel->getEqui()->getFlatComponents() ); break; case 0: - emit equipotentialUnselect ( isel->getEqui()->getComponents() ); + emit equipotentialUnselect ( isel->getEqui()->getFlatComponents() ); remove = isel; ++isel; _selecteds.erase( remove ); diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index cced774e..5850683f 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -92,7 +92,8 @@ namespace Tramontana { 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) + if ( (bl->getMaterial() == BasicLayer::Material::metal) + or (bl->getMaterial() == BasicLayer::Material::poly)) _extracteds.push_back( bl ); } @@ -142,7 +143,7 @@ namespace Tramontana { continue; } if (element.isLeftEdge()) { - // if (tile->getId() == 60117) { + // if (tile->getId() == 46055) { // DebugSession::open( 0, 169 ); // if (not written) intvTree->second.write( "tree-before.gv" ); // cdebug_log(160,0) << " Interval tree *before* insertion." << endl; @@ -166,7 +167,7 @@ namespace Tramontana { // cerr << " | insert " << tile << endl; // } intvTree->second.insert( tileIntv ); - // if (tile->getId() == 60117) { + // if (tile->getId() == 46055) { // if (not written) intvTree->second.write( "tree-after.gv" ); // written = true; // DebugSession::close(); @@ -188,9 +189,9 @@ namespace Tramontana { // } cdebug_log(160,0) << " | remove tile" << endl; intvTree->second.remove( tileIntv ); - //DebugSession::open( 0, 169 ); - intvTree->second.checkVMax(); - //DebugSession::close(); + // DebugSession::open( 0, 169 ); + // intvTree->second.checkVMax(); + // DebugSession::close(); // if ((tile->getId() == 289) and not written) { // //DebugSession::open( 0, 169 ); // written = true; @@ -216,7 +217,7 @@ namespace Tramontana { // } // } } - intvTree->second.checkVMax(); + //intvTree->second.checkVMax(); cdebug_tabw(160,-1); } //if (debugOn) DebugSession::close(); @@ -264,11 +265,15 @@ namespace Tramontana { 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 ); } + cdebug_tabw(160,-1); + //DebugSession::close(); } diff --git a/tramontana/src/TabEquipotentials.cpp b/tramontana/src/TabEquipotentials.cpp index 0c4ecac2..13112101 100644 --- a/tramontana/src/TabEquipotentials.cpp +++ b/tramontana/src/TabEquipotentials.cpp @@ -96,14 +96,14 @@ namespace Tramontana { getCellWidget()->closeRefreshSession (); } getCellWidget()->setShowSelection( true ); - connect( _browser, SIGNAL(equipotentialSelect (const OccurrenceSet&)), getCellWidget(), SLOT(selectSet (const OccurrenceSet&)) ); - connect( _browser, SIGNAL(equipotentialUnselect(const OccurrenceSet&)), getCellWidget(), SLOT(unselectSet(const OccurrenceSet&)) ); + 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(selectSet (const OccurrenceSet&)) ); - _browser->disconnect( getCellWidget(), SLOT(unselectSet(const OccurrenceSet&)) ); + _browser->disconnect( getCellWidget(), SLOT(select (Occurrences)) ); + _browser->disconnect( getCellWidget(), SLOT(unselect(Occurrences)) ); } } diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp index 8c2eefa8..648e882b 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -77,12 +77,14 @@ namespace Tramontana { // Class : "Tramontana::Tile". - uint32_t Tile::_time = 0; + uint32_t Tile::_idCounter = 0; + uint32_t Tile::_time = 0; vector Tile::_allocateds; Tile::Tile ( Occurrence occurrence, const BasicLayer* layer, const Box& boundingBox ) - : _occurrence (occurrence) + : _id (_idCounter++) + , _occurrence (occurrence) , _layer (layer) , _boundingBox (boundingBox) , _equipotential(nullptr) @@ -116,6 +118,9 @@ namespace Tramontana { Box bb = component->getBoundingBox( layer ); occurrence.getPath().getTransformation().applyOn( bb ); + + if (not occurrence.getPath().isEmpty()) + occurrence = Equipotential::getChildEqui( occurrence ); Tile* tile = new Tile ( occurrence, layer, bb ); return tile; @@ -133,8 +138,8 @@ namespace Tramontana { { } - Net* Tile::getNet () const - { return dynamic_cast( _occurrence.getEntity() )->getNet(); } + // Net* Tile::getNet () const + // { return dynamic_cast( _occurrence.getEntity() )->getNet(); } Tile* Tile::getRoot ( uint32_t flags ) @@ -150,7 +155,8 @@ namespace Tramontana { } root = root->getParent(); } - cdebug_log(160,0) << "> root " << root->getId() << endl; + cdebug_log(160,0) << "> root " << root->getId() << " " + << (root->getEquipotential() ? getString(root->getEquipotential()) : "equi=NULL") << endl; if (flags & Compress) { Tile* current = this; @@ -173,9 +179,11 @@ namespace Tramontana { if (current->getEquipotential()) { if (current->getEquipotential() != rootEqui) { cdebug_log(160,0) << "| merge " << current->getId() << " => " << root->getId() << endl; + cdebug_log(160,0) << "| " << current->getEquipotential() << endl; rootEqui->merge( current->getEquipotential() ); } } else { + cdebug_log(160,0) << "| add " << current->getOccurrence() << endl; rootEqui->add( current->getOccurrence(), _boundingBox ); } current->syncTime(); @@ -217,8 +225,8 @@ namespace Tramontana { _equipotential = Equipotential::create( _occurrence.getOwnerCell() ); _equipotential->add( _occurrence, _boundingBox ); - //cerr << "new " << _equipotential << endl; - //cerr << "| " << _occurrence << endl; + cdebug_log(160,0) << "new " << _equipotential << endl; + cdebug_log(160,0) << "| " << _occurrence << endl; return _equipotential; } diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp index 6631b0df..2786e232 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -235,7 +235,7 @@ namespace Tramontana { Record* record = Super::_getRecord (); if (record) { - //record->add( getSlot( "_blocks" , &_blocks ) ); + record->add( getSlot( "_equipotentials", &_equipotentials ) ); } return record; } diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h index 0c9ceb90..e5ced07a 100644 --- a/tramontana/src/tramontana/Equipotential.h +++ b/tramontana/src/tramontana/Equipotential.h @@ -22,6 +22,8 @@ #include "hurricane/Net.h" #include "hurricane/Component.h" #include "hurricane/Occurrence.h" +#include "hurricane/Occurrences.h" +#include "tramontana/EquipotentialRelation.h" namespace Tramontana { @@ -34,10 +36,12 @@ namespace Tramontana { 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; // ------------------------------------------------------------------- @@ -47,37 +51,44 @@ namespace Tramontana { public: typedef Entity Super; public: - static Equipotential* create ( Cell* ); - inline bool isEmpty () const; - virtual Cell* getCell () const; - virtual Box getBoundingBox () const; - inline std::string getName () const; - 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* ); - void consolidate (); - void clear (); - inline const OccurrenceSet& getComponents () const; - inline const OccurrenceSet& getChilds () const; - Record* _getRecord () const; - std::string _getString () const; - std::string _getTypeName () const; - protected: - virtual void _postCreate (); - virtual void _preDestroy (); - private: - Equipotential ( Cell* ); - ~Equipotential (); - private: - Equipotential ( const Equipotential& ) = delete; - Equipotential& operator= ( const Equipotential& ) = delete; + static Equipotential* get ( Component* ); + static Equipotential* get ( Occurrence ); + static Occurrence getChildEqui ( Occurrence ); + public: + static Equipotential* create ( Cell* ); + inline bool isEmpty () const; + virtual Cell* getCell () const; + virtual Box getBoundingBox () const; + inline std::string getName () const; + std::string getFlagsAsString () const; + inline Net::Type getType () const; + inline Net::Direction getDirection () const; + void show () const; + inline bool hasComponent ( Component* ) const; + void add ( Occurrence, const Box& boundingBox=Box() ); + void merge ( Equipotential* ); + void consolidate (); + void clear (); + inline const OccurrenceSet& getComponents () const; + inline const OccurrenceSet& getChilds () const; + inline const NetSet& getNets () const; + Occurrences getFlatComponents () 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; + NetSet _nets; OccurrenceSet _components; OccurrenceSet _childs; std::string _name; @@ -95,12 +106,23 @@ namespace Tramontana { inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } inline const OccurrenceSet& Equipotential::getComponents () const { return _components; } inline const OccurrenceSet& Equipotential::getChilds () const { return _childs; } + inline const NetSet& 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 bool Equipotential::hasComponent ( Component* component ) const - { return _components.find( Occurrence(component) ) != _components.end(); } + { + 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. diff --git a/tramontana/src/tramontana/EquipotentialComponents.h b/tramontana/src/tramontana/EquipotentialComponents.h new file mode 100644 index 00000000..70967612 --- /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" + + +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; + class Equipotential; + + 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; + NetSet::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 index 0102c267..63f8031b 100644 --- a/tramontana/src/tramontana/EquipotentialRelation.h +++ b/tramontana/src/tramontana/EquipotentialRelation.h @@ -18,7 +18,6 @@ #pragma once #include "hurricane/Relation.h" -#include "tramontana/TramontanaEngine.h" namespace Tramontana { @@ -26,6 +25,8 @@ namespace Tramontana { using Hurricane::Name; using Hurricane::Record; using Hurricane::Relation; + using Hurricane::Component; + class Equipotential; // ------------------------------------------------------------------- @@ -37,6 +38,7 @@ namespace Tramontana { public: static EquipotentialRelation* get ( const Component* ); static EquipotentialRelation* create ( Equipotential* ); + static Name staticGetName (); public: virtual Name getName () const; virtual std::string _getTypeName () const; diff --git a/tramontana/src/tramontana/EquipotentialsWidget.h b/tramontana/src/tramontana/EquipotentialsWidget.h index ec48d62f..71e0837a 100644 --- a/tramontana/src/tramontana/EquipotentialsWidget.h +++ b/tramontana/src/tramontana/EquipotentialsWidget.h @@ -137,8 +137,8 @@ namespace Tramontana { void goTo ( int ); void updateSelecteds (); signals: - void equipotentialSelect ( const OccurrenceSet& ); - void equipotentialUnselect ( const OccurrenceSet& ); + void equipotentialSelect ( Occurrences ); + void equipotentialUnselect ( Occurrences ); void reframe ( const Box& ); private slots: void textFilterChanged (); diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h index f73f1242..e316b0f5 100644 --- a/tramontana/src/tramontana/Tile.h +++ b/tramontana/src/tramontana/Tile.h @@ -66,9 +66,9 @@ namespace Tramontana { inline uint32_t getRank () const; inline Tile* getParent () const; Tile* getRoot ( uint32_t flags=Compress ); - inline Component* getComponent () const; + //inline Component* getComponent () const; inline Occurrence getOccurrence () const; - Net* getNet () const; + // Net* getNet () const; inline Layer::Mask getMask () const; inline const BasicLayer* getLayer () const; inline const Box& getBoundingBox () const; @@ -94,8 +94,10 @@ namespace Tramontana { 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; @@ -109,8 +111,8 @@ namespace Tramontana { inline const std::vector Tile::getAllTiles () { return _allocateds; } inline void Tile::timeTick () { _time++; } inline bool Tile::isUpToDate () const { return _timeStamp >= _time; } - inline unsigned int Tile::getId () const { return getComponent()->getId(); } - inline Component* Tile::getComponent () const { return dynamic_cast( _occurrence.getEntity() ); } + 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; } @@ -134,7 +136,7 @@ namespace Tramontana { inline bool operator() ( const Tile* lhs, const Tile* rhs ) const { cdebug_log(0,0) << "TileCompare::operator()" << std::endl; - return lhs->getOccurrence() < rhs->getOccurrence(); + return lhs->getId() < rhs->getId(); } }; From 4c7cf227bec3323576babe303781afada675c674 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Fri, 14 Apr 2023 01:07:40 +0200 Subject: [PATCH 20/28] Add ability to "filter out" buried net in TabEquipotentials. Definition: A buried net is a net that has no components at the top Cell level. Typically example is a wire internal to a standard cell. Those nets, while part of the complete design (flat) are not part of the top netlist, and we may want not to see it. A buried net is slighly different from a deep net. While a deepnet is also not reaching the top level cell, we created it at top level to be processed by the router (virtual flatten). --- tramontana/src/Equipotential.cpp | 3 + tramontana/src/EquipotentialsWidget.cpp | 49 +++++++++++++- tramontana/src/TabEquipotentials.cpp | 17 +++++ tramontana/src/tramontana/Equipotential.h | 5 +- .../src/tramontana/EquipotentialsWidget.h | 64 +++++++++++++------ tramontana/src/tramontana/TabEquipotentials.h | 8 +-- 6 files changed, 116 insertions(+), 30 deletions(-) diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp index e92466a2..d5a49b65 100644 --- a/tramontana/src/Equipotential.cpp +++ b/tramontana/src/Equipotential.cpp @@ -202,6 +202,7 @@ namespace Tramontana { , _type (Net::Type::UNDEFINED) , _direction (Net::Direction::DirUndefined) , _netCount (0) + , _isBuried (false) , _isExternal (false) , _isGlobal (false) , _isAutomatic(false) @@ -354,6 +355,7 @@ namespace Tramontana { 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(); @@ -388,6 +390,7 @@ namespace Tramontana { sflags += ((_isExternal ) ? "e" : "-"); sflags += ((_isGlobal ) ? "g" : "-"); sflags += ((_isAutomatic) ? "a" : "-"); + sflags += ((_isBuried ) ? "B" : "-"); sflags += " [N:" + getString( _netCount - ((_hasFused) ? 1 : 0) ); sflags += "+E:" + getString( _childs.size() ); if (_hasFused) diff --git a/tramontana/src/EquipotentialsWidget.cpp b/tramontana/src/EquipotentialsWidget.cpp index 80910baf..5d7ef6b6 100644 --- a/tramontana/src/EquipotentialsWidget.cpp +++ b/tramontana/src/EquipotentialsWidget.cpp @@ -39,12 +39,42 @@ namespace Tramontana { 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 () @@ -56,7 +86,9 @@ namespace Tramontana { _rowHeight = QFontMetrics( Graphics::getFixedFont() ).height() + 4; - _sortModel->setSourceModel ( _baseModel ); + _filterModel->setSourceModel ( _baseModel ); + //_filterModel->setFilter ( EquiFilterProxyModel::ShowBuried ); + _sortModel->setSourceModel ( _filterModel ); _sortModel->setDynamicSortFilter( true ); _sortModel->setFilterKeyColumn ( 0 ); @@ -110,6 +142,17 @@ namespace Tramontana { } + 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; @@ -138,7 +181,7 @@ namespace Tramontana { const Equipotential* equi = nullptr; QModelIndexList iList = _view->selectionModel()->selectedRows(); for ( int i=0 ; igetEqui( _sortModel->mapToSource(iList[i]).row() ); + equi = _baseModel->getEqui( mapToSource(iList[i]).row() ); if ( equi ) _selecteds.insert( equi ); } @@ -182,7 +225,7 @@ namespace Tramontana { void EquipotentialsWidget::fitToEqui () { - const Equipotential* equi = _baseModel->getEqui( _sortModel->mapToSource(_view->currentIndex()).row() ); + const Equipotential* equi = _baseModel->getEqui( mapToSource(_view->currentIndex()).row() ); if (equi) emit reframe ( equi->getBoundingBox() ); } diff --git a/tramontana/src/TabEquipotentials.cpp b/tramontana/src/TabEquipotentials.cpp index 13112101..9d052537 100644 --- a/tramontana/src/TabEquipotentials.cpp +++ b/tramontana/src/TabEquipotentials.cpp @@ -27,6 +27,8 @@ namespace Tramontana { + using std::cerr; + using std::endl; using Hurricane::Graphics; @@ -39,6 +41,7 @@ namespace Tramontana { , _browser (new EquipotentialsWidget()) , _syncEquipotentials (new QCheckBox()) , _syncSelection (new QCheckBox()) + , _showBuried (new QCheckBox()) , _cwCumulativeSelection(false) { _browser->setObjectName ( "controller.tabEquipotentials.browser" ); @@ -57,11 +60,18 @@ namespace Tramontana { _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 ); @@ -108,6 +118,13 @@ namespace Tramontana { } + void TabEquipotentials::setShowBuried ( bool state ) + { + if (not getCellWidget()) return; + _browser->setShowBuried( state ); + } + + void TabEquipotentials::setCell ( Cell* cell ) { setSyncEquipotentials( _syncEquipotentials->isChecked() ); diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h index e5ced07a..fefecd6b 100644 --- a/tramontana/src/tramontana/Equipotential.h +++ b/tramontana/src/tramontana/Equipotential.h @@ -57,6 +57,7 @@ namespace Tramontana { 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; @@ -95,6 +96,7 @@ namespace Tramontana { Net::Type _type; Net::Direction _direction; uint32_t _netCount; + bool _isBuried; bool _isExternal; bool _isGlobal; bool _isAutomatic; @@ -103,7 +105,8 @@ namespace Tramontana { - inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } + 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 NetSet& Equipotential::getNets () const { return _nets; } diff --git a/tramontana/src/tramontana/EquipotentialsWidget.h b/tramontana/src/tramontana/EquipotentialsWidget.h index 71e0837a..6df29cad 100644 --- a/tramontana/src/tramontana/EquipotentialsWidget.h +++ b/tramontana/src/tramontana/EquipotentialsWidget.h @@ -47,6 +47,25 @@ namespace Tramontana { 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". @@ -130,31 +149,34 @@ namespace Tramontana { Q_OBJECT; public: - EquipotentialsWidget ( QWidget* parent=nullptr ); - inline Cell* getCell (); - void setCellWidget ( CellWidget* ); - void setCell ( Cell* ); - void goTo ( int ); - void updateSelecteds (); + 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& ); + void equipotentialSelect ( Occurrences ); + void equipotentialUnselect ( Occurrences ); + void reframe ( const Box& ); private slots: - void textFilterChanged (); - void updateSelecteds ( const QItemSelection& , const QItemSelection& ); - void fitToEqui (); + void textFilterChanged (); + void updateSelecteds ( const QItemSelection& , const QItemSelection& ); + void fitToEqui (); private: - CellWidget* _cellWidget; - Cell* _cell; - EquipotentialsModel* _baseModel; - QSortFilterProxyModel* _sortModel; - QTableView* _view; - QLineEdit* _filterPatternLineEdit; - int _rowHeight; - SelectedEquiSet _selecteds; - bool _forceReselect; + CellWidget* _cellWidget; + Cell* _cell; + EquipotentialsModel* _baseModel; + QSortFilterProxyModel* _sortModel; + EquiFilterProxyModel* _filterModel; + QTableView* _view; + QLineEdit* _filterPatternLineEdit; + int _rowHeight; + SelectedEquiSet _selecteds; + bool _forceReselect; }; diff --git a/tramontana/src/tramontana/TabEquipotentials.h b/tramontana/src/tramontana/TabEquipotentials.h index 075a2783..8945c2f7 100644 --- a/tramontana/src/tramontana/TabEquipotentials.h +++ b/tramontana/src/tramontana/TabEquipotentials.h @@ -35,8 +35,6 @@ namespace Tramontana { public: TabEquipotentials ( QWidget* parent=NULL ); - inline QCheckBox* getSyncEquipotentials (); - inline QCheckBox* getSyncSelection (); inline EquipotentialsWidget* getBrowser (); virtual void cellPreModificate (); virtual void cellPostModificate (); @@ -45,18 +43,18 @@ namespace Tramontana { 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; } - inline QCheckBox* TabEquipotentials::getSyncEquipotentials () { return _syncEquipotentials; } - inline QCheckBox* TabEquipotentials::getSyncSelection () { return _syncSelection; } + inline EquipotentialsWidget* TabEquipotentials::getBrowser () { return _browser; } } From 52fd1c1c4079dca17c5ee67288ad918a20dc4bcf Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Wed, 3 May 2023 17:08:57 +0200 Subject: [PATCH 21/28] Add vertical rectangles partionning to Rectilinear. * New: Rectilinear::asRectangles(), decompose the Rectilinear into a set of non-overlapping rectangles sliced vertically. This not a mathematical minimum set. But should be speedier. Done using a sweepline processing the vertical edges. Specially suited for use in the extractor which basically manage only rectangles. Simple algorithm described in pp. 9-11 of Extractor notebook. Tests done with unitests/python/test_rectilinear.py, the Rectilinear here should cover all the sweepline cases. --- hurricane/src/hurricane/Rectilinear.cpp | 300 +++++++++++++++++- .../src/hurricane/hurricane/Rectilinear.h | 18 +- hurricane/src/isobar/PyRectilinear.cpp | 72 ++++- unittests/python/test_rectilinear.py | 157 +++++++++ 4 files changed, 524 insertions(+), 23 deletions(-) create mode 100644 unittests/python/test_rectilinear.py diff --git a/hurricane/src/hurricane/Rectilinear.cpp b/hurricane/src/hurricane/Rectilinear.cpp index 2a869db2..42bc911b 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) { } @@ -61,6 +340,7 @@ namespace Hurricane { if (points.size() > 1000) throw Error( "Rectilinear::create(): Rectlinear polygons must not exceed 1000 vertexes." ); + bool isRect = true; DbU::Unit oneGrid = DbU::fromGrid( 1.0 ); for ( size_t i=0 ; i_flags &= ~IsRectilinear; rectilinear->_postCreate(); return rectilinear; @@ -176,6 +459,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/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/unittests/python/test_rectilinear.py b/unittests/python/test_rectilinear.py new file mode 100644 index 00000000..10b1db34 --- /dev/null +++ b/unittests/python/test_rectilinear.py @@ -0,0 +1,157 @@ +#!/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) ) ] + 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 + 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 + 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 From c53fc01cb2e990fe699d397ca1a7dcf785907950 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Fri, 5 May 2023 16:22:51 +0200 Subject: [PATCH 22/28] Add Rectilinear & "cut" support to the extractor. Note about the managment of VIA & cuts: Components using a layer which is a ViaLayer, that is one containing more than one BasicLayer, multiple tiles are created in QueryTiles::goCallback(). Components that have a single BasicLayer of "cut" material will also have their multiples tiles created in QueryTiles::goCallback(). Rectilinear components will have their multiples tiles created in Tile::create(). Tile::create() return not all the tiles but the one used as root (for the union find). * New: In SweepLine::_buildCutConnexMap(), when using a "cut" layer in a standalone way, and not as part of a ViaLayer, we do not automatically know to which layer above & below they are connected. We build a table for each cut layer, based on the ViaLayer, to know all tops & belows layers they connect (this is cumulative, in the case of "cut" towards the substrate). Then in Tile::create(), we not only create the tile for the "cut" but also in thoses connected layers (and link them in the union find). * New: In Tile::create(), when we encounter a Rectilinear, break it into rectangles and make as many tiles. All tiles linked to the same root in the union find. * Bug: In Hurricane::Rectilinear, ambiguous specification of the set of points defining the shape. I did suppose that the start and and point where not the same the last edge being between them. But if FlexLib, it uses the GDSII inspired convention where the first and last point must be the same, to indicate a closed contour. This difference was not causing any difference with the drawing, but it was a problem for getAsRectangle(). This was creating a "false" extra vertical edge leading to a bigger rectangle. And this, in turn, was making "false" intersections in the tiling/sweepline of the extractor. Add a more thorough checking of the points vector. --- hurricane/src/hurricane/Rectilinear.cpp | 15 ++++- tramontana/src/QueryTiles.cpp | 24 +++++-- tramontana/src/SweepLine.cpp | 89 ++++++++++++++++++++----- tramontana/src/Tile.cpp | 86 ++++++++++++++++++++---- tramontana/src/tramontana/SweepLine.h | 15 ++++- tramontana/src/tramontana/Tile.h | 20 ++++-- unittests/python/test_rectilinear.py | 27 +++++--- 7 files changed, 225 insertions(+), 51 deletions(-) diff --git a/hurricane/src/hurricane/Rectilinear.cpp b/hurricane/src/hurricane/Rectilinear.cpp index 42bc911b..825d776a 100644 --- a/hurricane/src/hurricane/Rectilinear.cpp +++ b/hurricane/src/hurricane/Rectilinear.cpp @@ -182,7 +182,7 @@ namespace { void SweepLine::loadVEdges () { const vector& points = _rectilinear->getPoints(); - for ( size_t i=0 ; i 1000) - throw Error( "Rectilinear::create(): Rectlinear polygons must not exceed 1000 vertexes." ); + throw Error( "Rectilinear::create(): Rectilinear polygons must not exceed 1000 vertexes." ); + + if (points[0] != points[points.size()-1]) + throw Error( "Rectilinear::create(): First and last point must be the same.\n" + "0:%s %d:%s" + , getString(points[0]).c_str() + , points.size()-1 + , getString(points[points.size()-1]).c_str() + ); bool isRect = true; DbU::Unit oneGrid = DbU::fromGrid( 1.0 ); diff --git a/tramontana/src/QueryTiles.cpp b/tramontana/src/QueryTiles.cpp index eb3f4833..0a72edfe 100644 --- a/tramontana/src/QueryTiles.cpp +++ b/tramontana/src/QueryTiles.cpp @@ -72,18 +72,32 @@ namespace Tramontana { void QueryTiles::goCallback ( Go* go ) { - vector tiles; + Tile* rootTile = nullptr; Component* component = dynamic_cast( go ); if (not component) return; if (isProcessed(component)) return; Occurrence occurrence = Occurrence( go, getPath() ); for ( const BasicLayer* layer : _sweepLine->getExtracteds() ) { if (not component->getLayer()->getMask().intersect(layer->getMask())) continue; - tiles.push_back( Tile::create( occurrence, layer )); - _sweepLine->add( tiles.back() ); - if (tiles.size() > 1) - tiles.back()->setParent( tiles[0] ); + Tile* tile = Tile::create( occurrence + , layer + , rootTile + , _sweepLine ); + if (not rootTile) rootTile = tile; } + + BasicLayer* cutLayer = component->getLayer()->getBasicLayers().getFirst(); + if (cutLayer->getMaterial() == BasicLayer::Material::cut) { + const SweepLine::LayerSet& connexSet = _sweepLine->getCutConnexLayers( cutLayer ); + for ( const BasicLayer* connexLayer : connexSet ) { + Tile::create( occurrence + , connexLayer + , rootTile + , _sweepLine + , Tile::ForceLayer ); + } + } + _goMatchCount++; } diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index 5850683f..5a6f51f3 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -28,6 +28,7 @@ #include "hurricane/DataBase.h" #include "hurricane/Technology.h" #include "hurricane/Layer.h" +#include "hurricane/ViaLayer.h" #include "hurricane/Net.h" #include "hurricane/Pad.h" #include "hurricane/Plug.h" @@ -71,6 +72,7 @@ namespace Tramontana { using Hurricane::DataBase; using Hurricane::Technology; using Hurricane::Layer; + using Hurricane::ViaLayer; using Hurricane::Entity; using Hurricane::Horizontal; using Hurricane::Vertical; @@ -84,18 +86,24 @@ namespace Tramontana { SweepLine::SweepLine ( TramontanaEngine* tramontana ) - : _tramontana (tramontana) - , _extracteds () - , _tiles () - , _intervalTrees() + : _tramontana (tramontana) + , _extracteds () + , _extractedsMask() + , _connexityMap () + , _tiles () + , _intervalTrees () { for ( const BasicLayer* bl : DataBase::getDB()->getTechnology()->getBasicLayers() ) { // HARDCODED. Should read the gauge. if (getString(bl->getName()).substr(0,6) == "gmetal") continue; if ( (bl->getMaterial() == BasicLayer::Material::metal) - or (bl->getMaterial() == BasicLayer::Material::poly)) + or (bl->getMaterial() == BasicLayer::Material::poly) + or (bl->getMaterial() == BasicLayer::Material::cut)) { _extracteds.push_back( bl ); + _extractedsMask |= bl->getMask(); + } } + _buildCutConnexMap(); // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal5" )); // _extracteds.push_back( DataBase::getDB()->getTechnology()->getBasicLayer( "metal4" )); @@ -110,16 +118,66 @@ namespace Tramontana { { } + void SweepLine::_buildCutConnexMap () + { + for ( const ViaLayer* viaLayer : DataBase::getDB()->getTechnology()->getViaLayers() ) { + const BasicLayer* cutLayer = nullptr; + for ( const BasicLayer* layer : viaLayer->getBasicLayers() ) { + if (layer->getMaterial() == BasicLayer::Material::cut) { + cutLayer = layer; + break; + } + } + if (not cutLayer) { + cerr << Error( "SweepLine::_buildConnexityMap(): ViaLayer \"%s\" does not contains any *cut* (ignored)." + , getString(viaLayer->getName()).c_str() + ) << endl; + continue; + } + auto iCutMap = _connexityMap.find( cutLayer ); + if (iCutMap == _connexityMap.end()) { + _connexityMap.insert( make_pair( cutLayer, LayerSet() )); + iCutMap = _connexityMap.find( cutLayer ); + } + for ( const BasicLayer* layer : viaLayer->getBasicLayers() ) { + if ( (layer->getMaterial() != BasicLayer::Material::cut) + and (_extractedsMask.intersect(layer->getMask())) ) { + iCutMap->second.insert( layer ); + } + } + } + // for ( auto item : _connexityMap ) { + // cerr << "BasicLayers connex to cut: " << item.first << endl; + // for ( const BasicLayer* bl : item.second ) { + // cerr << "| " << bl << endl; + // } + // } + } + + + const SweepLine::LayerSet& SweepLine::getCutConnexLayers ( const BasicLayer* cutLayer ) const + { + static LayerSet emptySet; + auto iCutMap = _connexityMap.find( cutLayer ); + if (iCutMap == _connexityMap.end()) + return emptySet; + return iCutMap->second; + } + + void SweepLine::run () { //DebugSession::open( 160, 169 ); cdebug_log(160,1) << "SweepLine::run()" << endl; loadTiles(); //bool debugOn = false; - bool written = false; + //bool written = false; for ( Element& element : _tiles ) { Tile* tile = element.getTile(); TileIntv tileIntv ( tile, tile->getYMin(), tile->getYMax() ); + // if (tile->getOccurrence().getEntity()->getId() == 3348) { + // DebugSession::open( 160, 169 ); + // } // if (getString(tile->getNet()->getName()) == "a(13)") { // cerr << tile << endl; // } @@ -143,9 +201,8 @@ namespace Tramontana { continue; } if (element.isLeftEdge()) { - // if (tile->getId() == 46055) { - // DebugSession::open( 0, 169 ); - // if (not written) intvTree->second.write( "tree-before.gv" ); + // if (tile->getOccurrence().getEntity()->getId() == 3348) { + // //if (not written) intvTree->second.write( "tree-before.gv" ); // cdebug_log(160,0) << " Interval tree *before* insertion." << endl; // for ( auto elt : intvTree->second.getElements() ) { // cdebug_log(160,0) << " | in tree:" << elt << endl; @@ -167,11 +224,10 @@ namespace Tramontana { // cerr << " | insert " << tile << endl; // } intvTree->second.insert( tileIntv ); - // if (tile->getId() == 46055) { - // if (not written) intvTree->second.write( "tree-after.gv" ); - // written = true; - // DebugSession::close(); - // } + if (tile->getOccurrence().getEntity()->getId() == 3348) { + //if (not written) intvTree->second.write( "tree-after.gv" ); + //written = true; + } } else { // if (tile->getId() == 289) { // DebugSession::open( 0, 169 ); @@ -218,7 +274,10 @@ namespace Tramontana { // } } //intvTree->second.checkVMax(); - cdebug_tabw(160,-1); + // cdebug_tabw(160,-1); + // if (tile->getOccurrence().getEntity()->getId() == 3348) { + // DebugSession::close(); + // } } //if (debugOn) DebugSession::close(); cdebug_tabw(160,-1); diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp index 648e882b..45e0d5a2 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -33,10 +33,14 @@ #include "hurricane/Instance.h" #include "hurricane/Vertical.h" #include "hurricane/Horizontal.h" +#include "hurricane/Diagonal.h" +#include "hurricane/Rectilinear.h" +#include "hurricane/Polygon.h" #include "hurricane/RoutingPad.h" #include "crlcore/Utilities.h" #include "tramontana/Tile.h" #include "tramontana/Equipotential.h" +#include "tramontana/SweepLine.h" namespace Tramontana { @@ -68,7 +72,10 @@ namespace Tramontana { using Hurricane::Entity; using Hurricane::Horizontal; using Hurricane::Vertical; - using Hurricane::RoutingPad; + using Hurricane::Vertical; + using Hurricane::Diagonal; + using Hurricane::Rectilinear; + using Hurricane::Polygon; using Hurricane::Cell; using Hurricane::Instance; @@ -82,14 +89,14 @@ namespace Tramontana { vector Tile::_allocateds; - Tile::Tile ( Occurrence occurrence, const BasicLayer* layer, const Box& boundingBox ) + Tile::Tile ( Occurrence occurrence, const BasicLayer* layer, const Box& boundingBox, Tile* parent ) : _id (_idCounter++) , _occurrence (occurrence) , _layer (layer) , _boundingBox (boundingBox) , _equipotential(nullptr) , _flags (0) - , _parent (nullptr) + , _parent (parent) , _rank (0) , _timeStamp (0) { @@ -97,7 +104,11 @@ namespace Tramontana { } - Tile* Tile::create ( Occurrence occurrence, const BasicLayer* layer ) + Tile* Tile::create ( Occurrence occurrence + , const BasicLayer* layer + , Tile* rootTile + , SweepLine* sweepLine + , uint32_t flags ) { Component* component = dynamic_cast( occurrence.getEntity() ); if (not component) { @@ -107,22 +118,72 @@ namespace Tramontana { ) << endl; return nullptr; } - if (not component->getLayer()->contains(layer)) { - cerr << Error( "Tile::create(): Component layer does not contains \"%s\".\n" + if (not (flags & ForceLayer) and not component->getLayer()->contains(layer)) { + cerr << "Intersect:" << component->getLayer()->getMask().intersect(layer->getMask()) << endl; + cerr << Error( "Tile::create(): Component layer \"%s\" does not contains \"%s\".\n" + " (%s)\n" + " component :%s\n" + " basicLayer:%s" + , getString(component->getLayer()->getName()).c_str() + , getString(layer->getName()).c_str() + , getString(occurrence).c_str() + , getString(component->getLayer()->getMask()).c_str() + , getString(layer->getMask()).c_str() + ) << endl; + return nullptr; + } + if (dynamic_cast(component)) { + cerr << Error( "Tile::create(): Polygon are not supported for extraction.\n" + " (%s)" + , getString(occurrence).c_str() + ) << endl; + return nullptr; + } + if (dynamic_cast(component)) { + cerr << Error( "Tile::create(): Diagonal are not supported for extraction.\n" " (%s)" - , getString(layer).c_str() , getString(occurrence).c_str() ) << endl; return nullptr; } + Occurrence childEqui = occurrence; + if (not childEqui.getPath().isEmpty()) + childEqui = Equipotential::getChildEqui( occurrence ); + + Rectilinear* rectilinear = dynamic_cast( component ); + if (rectilinear) { + if (not rectilinear->isRectilinear()) { + cerr << Error( "Tile::create(): Rectilinear with 45/135 edges are not supported for extraction.\n" + " (%s)" + , getString(occurrence).c_str() + ) << endl; + return nullptr; + } + if (rectilinear->getId() == 3367) { + DebugSession::open( 160, 169 ); + cdebug_log(160,0) << "Tiling: " << rectilinear << endl; + } + vector boxes; + rectilinear->getAsRectangles( boxes ); + for ( Box bb : boxes ) { + occurrence.getPath().getTransformation().applyOn( bb ); + Tile* tile = new Tile ( childEqui, layer, bb, rootTile ); + sweepLine->add( tile ); + cdebug_log(160,0) << "| " << tile << endl; + if (not rootTile) rootTile = tile; + } + if (rectilinear->getId() == 3367) { + DebugSession::close(); + } + return rootTile; + } + Box bb = component->getBoundingBox( layer ); occurrence.getPath().getTransformation().applyOn( bb ); - if (not occurrence.getPath().isEmpty()) - occurrence = Equipotential::getChildEqui( occurrence ); - Tile* tile = new Tile ( occurrence, layer, bb ); - + Tile* tile = new Tile ( childEqui, layer, bb, rootTile ); + sweepLine->add( tile ); return tile; } @@ -238,7 +299,8 @@ namespace Tramontana { string Tile::_getString () const { ostringstream os; - os << "getName() << " " << _occurrence << ">"; + os << "getName() << " " << _occurrence << ">"; return os.str(); } diff --git a/tramontana/src/tramontana/SweepLine.h b/tramontana/src/tramontana/SweepLine.h index b7f8be26..a7a4aec9 100644 --- a/tramontana/src/tramontana/SweepLine.h +++ b/tramontana/src/tramontana/SweepLine.h @@ -19,6 +19,7 @@ #pragma once #include #include +#include #include #include "hurricane/BasicLayer.h" namespace Hurricane { @@ -33,6 +34,7 @@ namespace Tramontana { using Hurricane::Record; using Hurricane::Box; using Hurricane::DbU; + using Hurricane::DBo; using Hurricane::Cell; using Hurricane::Layer; using Hurricane::BasicLayer; @@ -43,7 +45,10 @@ namespace Tramontana { class SweepLine { private: - typedef std::map IntervalTrees; + typedef std::map IntervalTrees; + public: + typedef std::set LayerSet; + typedef std::map ConnexityMap; private: class Element { public: @@ -66,6 +71,8 @@ namespace Tramontana { inline Cell* getCell (); inline const std::vector& getExtracteds () const; + inline Layer::Mask getExtractedMask () const; + const LayerSet& getCutConnexLayers ( const BasicLayer* ) const; void run (); void loadTiles (); inline void add ( Tile* ); @@ -76,9 +83,12 @@ namespace Tramontana { private: SweepLine ( const SweepLine& ) = delete; SweepLine& operator= ( const SweepLine& ) = delete; + void _buildCutConnexMap (); private: TramontanaEngine* _tramontana; std::vector _extracteds; + Layer::Mask _extractedsMask; + ConnexityMap _connexityMap; std::vector _tiles; IntervalTrees _intervalTrees; }; @@ -109,7 +119,8 @@ namespace Tramontana { // SweepLine. inline Cell* SweepLine::getCell () { return _tramontana->getCell(); } - inline const std::vector& SweepLine::getExtracteds () const { return _extracteds; } + inline const std::vector& SweepLine::getExtracteds () const { return _extracteds; } + inline Layer::Mask SweepLine::getExtractedMask () const { return _extractedsMask; } inline void SweepLine::add ( Tile* tile ) { diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h index e316b0f5..2d2a3e20 100644 --- a/tramontana/src/tramontana/Tile.h +++ b/tramontana/src/tramontana/Tile.h @@ -44,6 +44,7 @@ namespace Tramontana { using Hurricane::IntervalData; using Hurricane::IntervalTree; class Equipotential; + class SweepLine; // ------------------------------------------------------------------- @@ -51,15 +52,20 @@ namespace Tramontana { class Tile { public: - static const uint32_t NoFlags = 0; - static const uint32_t LeftEdge = (1<<0); - static const uint32_t RightEdge = (1<<1); - static const uint32_t Compress = (1<<2); - static const uint32_t MergeEqui = (1<<3); + static const uint32_t NoFlags = 0; + static const uint32_t LeftEdge = (1<<0); + static const uint32_t RightEdge = (1<<1); + static const uint32_t Compress = (1<<2); + static const uint32_t MergeEqui = (1<<3); + static const uint32_t ForceLayer = (1<<4); public: static inline const std::vector getAllTiles (); static inline void timeTick (); - static Tile* create ( Occurrence, const BasicLayer* ); + static Tile* create ( Occurrence + , const BasicLayer* + , Tile* rootTile + , SweepLine* + , uint32_t flags=NoFlags ); void destroy (); inline bool isUpToDate () const; inline unsigned int getId () const; @@ -88,7 +94,7 @@ namespace Tramontana { std::string _getString () const; std::string _getTypeName () const; private: - Tile ( Occurrence, const BasicLayer*, const Box& ); + Tile ( Occurrence, const BasicLayer*, const Box&, Tile* parent ); ~Tile (); private: Tile ( const Tile& ) = delete; diff --git a/unittests/python/test_rectilinear.py b/unittests/python/test_rectilinear.py index 10b1db34..447dce17 100644 --- a/unittests/python/test_rectilinear.py +++ b/unittests/python/test_rectilinear.py @@ -48,7 +48,8 @@ def testRectilinear ( editor ): , Point( l( 20.0), l( 30.0) ) , Point( l( 30.0), l( 30.0) ) , Point( l( 30.0), l( 20.0) ) - , Point( l( 10.0), l( 0.0) ) ] + , Point( l( 10.0), l( 0.0) ) + , Point( l( 0.0), l( 0.0) ) ] r = Rectilinear.create( net, metal2, points ) #print( 'Normalized and manhattanized contour:' ) @@ -72,7 +73,9 @@ def testRectilinear ( editor ): # , Point( l( 90.0), l( 0.0) ) # 12 # , Point( l( 20.0), l( 0.0) ) # 13 # , Point( l( 20.0), l( 20.0) ) # 14 - # , Point( l( 0.0), l( 20.0) ) ] # 15 + # , Point( l( 0.0), l( 20.0) ) # 15 + # , Point( l( 0.0), l( 40.0) ) ] # 16 + # Super-test rectilinear. points = [ Point( l( 0.0), l( 0.0) ) # 0 , Point( l( 0.0), l( 20.0) ) # 1 , Point( l( 10.0), l( 20.0) ) # 2 @@ -83,7 +86,7 @@ def testRectilinear ( editor ): , Point( l( 40.0), l( 80.0) ) # 7 , Point( l( 20.0), l( 80.0) ) # 8 , Point( l( 20.0), l( 70.0) ) # 9 - + , Point( l( 10.0), l( 70.0) ) # 10 , Point( l( 10.0), l( 60.0) ) # 11 , Point( l( 0.0), l( 60.0) ) # 12 @@ -94,7 +97,7 @@ def testRectilinear ( editor ): , Point( l( 20.0), l(100.0) ) # 17 , Point( l( 40.0), l(100.0) ) # 18 , Point( l( 40.0), l(140.0) ) # 19 - + , Point( l( 20.0), l(140.0) ) # 20 , Point( l( 20.0), l(150.0) ) # 21 , Point( l( 10.0), l(150.0) ) # 22 @@ -105,7 +108,7 @@ def testRectilinear ( editor ): , Point( l( 40.0), l(170.0) ) # 27 , Point( l( 50.0), l(170.0) ) # 28 , Point( l( 50.0), l(160.0) ) # 29 - + , Point( l(150.0), l(160.0) ) # 30 , Point( l(150.0), l(150.0) ) # 31 , Point( l(130.0), l(150.0) ) # 32 @@ -116,7 +119,7 @@ def testRectilinear ( editor ): , Point( l(110.0), l(110.0) ) # 37 , Point( l(120.0), l(110.0) ) # 38 , Point( l(120.0), l(100.0) ) # 39 - + , Point( l(130.0), l(100.0) ) # 40 , Point( l(130.0), l( 90.0) ) # 41 , Point( l(150.0), l( 90.0) ) # 42 @@ -127,7 +130,7 @@ def testRectilinear ( editor ): , Point( l(110.0), l( 50.0) ) # 47 , Point( l(120.0), l( 50.0) ) # 48 , Point( l(120.0), l( 40.0) ) # 49 - + , Point( l(130.0), l( 40.0) ) # 50 , Point( l(130.0), l( 30.0) ) # 51 , Point( l(150.0), l( 30.0) ) # 52 @@ -135,7 +138,15 @@ def testRectilinear ( editor ): , Point( l( 50.0), l( 20.0) ) # 54 , Point( l( 50.0), l( 10.0) ) # 55 , Point( l( 40.0), l( 10.0) ) # 56 - , Point( l( 40.0), l( 0.0) ) ] # 57 + , Point( l( 40.0), l( 0.0) ) # 57 + , Point( l( 0.0), l( 0.0) ) ] # 57 + #points = [ Point( l( 0.0), l( 0.0) ) # 0 + # , Point( l( 0.0), l( 80.0) ) # 1 + # , Point( l( 40.0), l( 80.0) ) # 2 + # , Point( l( 40.0), l( 60.0) ) # 3 + # , Point( l( 20.0), l( 60.0) ) # 4 + # , Point( l( 20.0), l( 0.0) ) # 5 + # , Point( l( 0.0), l( 0.0) ) ] # 6 r = Rectilinear.create( net, metal2, points ) boxes = [] From 96e6c9dd06e80bf945aaa196dfac373859774d08 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sat, 6 May 2023 18:13:39 +0200 Subject: [PATCH 23/28] Fix a sync problem between the EquiWidget and the SelectionWidget. --- hurricane/src/viewer/CellWidget.cpp | 29 ++++++++++++++++--------- hurricane/src/viewer/SelectionModel.cpp | 2 +- tramontana/src/EquipotentialsWidget.cpp | 28 ++++++++++-------------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/hurricane/src/viewer/CellWidget.cpp b/hurricane/src/viewer/CellWidget.cpp index cffabcde..8cd3c6f8 100644 --- a/hurricane/src/viewer/CellWidget.cpp +++ b/hurricane/src/viewer/CellWidget.cpp @@ -2683,7 +2683,8 @@ namespace Hurricane { } else selected = false; - if ( (--_delaySelectionChanged == 0) and selected ) emit selectionChanged( _selectors ); + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); } @@ -2708,7 +2709,8 @@ namespace Hurricane { // } else // selected = false; - if ( (--_delaySelectionChanged == 0) and selected ) emit selectionChanged( _selectors ); + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); } @@ -2733,7 +2735,8 @@ namespace Hurricane { // } else // selected = false; - if ( (--_delaySelectionChanged == 0) and selected ) emit selectionChanged( _selectors ); + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); } @@ -2758,7 +2761,8 @@ namespace Hurricane { // } else // selected = false; - if ( (--_delaySelectionChanged == 0) and selected ) emit selectionChanged( _selectors ); + if ( (--_delaySelectionChanged == 0) and selected ) + emit selectionChanged( _selectors ); } @@ -2819,7 +2823,7 @@ namespace Hurricane { if ( (--_delaySelectionChanged == 0) and selected ) { if ( _state->showSelection() ) _redrawManager.refresh (); - emit selectionChanged(_selectors); + emit selectionChanged(_selectors); } } @@ -2857,7 +2861,8 @@ namespace Hurricane { } _selectionHasChanged = true; - if ( (_delaySelectionChanged == 0) and unselected ) emit selectionChanged( _selectors ); + if ( (_delaySelectionChanged == 0) and unselected ) + emit selectionChanged( _selectors ); } @@ -2869,7 +2874,8 @@ namespace Hurricane { unselect( Occurrence( component )); } } - if ( --_delaySelectionChanged == 0 ) emit selectionChanged( _selectors ); + if ( --_delaySelectionChanged == 0 ) + emit selectionChanged( _selectors ); } @@ -2881,7 +2887,8 @@ namespace Hurricane { unselect( occurrence ); } } - if ( --_delaySelectionChanged == 0 ) emit selectionChanged( _selectors ); + if ( --_delaySelectionChanged == 0 ) + emit selectionChanged( _selectors ); } @@ -2893,7 +2900,8 @@ namespace Hurricane { unselect( occurrence ); } } - if ( --_delaySelectionChanged == 0 ) emit selectionChanged( _selectors ); + if ( --_delaySelectionChanged == 0 ) + emit selectionChanged( _selectors ); } @@ -2904,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/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/tramontana/src/EquipotentialsWidget.cpp b/tramontana/src/EquipotentialsWidget.cpp index 5d7ef6b6..0f08d8ff 100644 --- a/tramontana/src/EquipotentialsWidget.cpp +++ b/tramontana/src/EquipotentialsWidget.cpp @@ -191,26 +191,22 @@ namespace Tramontana { _forceReselect = false; } - SelectedEquiSet::iterator remove; - SelectedEquiSet::iterator isel = _selecteds.begin (); + SelectedEquiSet::iterator isel = _selecteds.begin (); while ( isel != _selecteds.end() ) { - switch ( isel->getAccesses() ) { - case 1: break; - case 64: - emit equipotentialSelect ( isel->getEqui()->getFlatComponents() ); - break; - case 0: - emit equipotentialUnselect ( isel->getEqui()->getFlatComponents() ); - remove = isel; - ++isel; - _selecteds.erase( remove ); - continue; - default: - cerr << Bug( "EquipotentialsWidget::updateSelecteds(): invalid code %d" - , isel->getAccesses()) << endl; + 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 (); } From abee13d669c7d4337a9332044fd195a75b545750 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 7 May 2023 11:54:04 +0200 Subject: [PATCH 24/28] Small improvement to the NetlistWidget (more fields). --- hurricane/src/hurricane/Net.cpp | 16 ++++++++++---- hurricane/src/hurricane/hurricane/Net.h | 1 + hurricane/src/viewer/NetInformations.cpp | 15 +++++++++---- hurricane/src/viewer/NetlistWidget.cpp | 28 ++++++++++-------------- tramontana/src/EquipotentialsWidget.cpp | 2 +- 5 files changed, 36 insertions(+), 26 deletions(-) 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/hurricane/Net.h b/hurricane/src/hurricane/hurricane/Net.h index 5f598133..545e58e0 100644 --- a/hurricane/src/hurricane/hurricane/Net.h +++ b/hurricane/src/hurricane/hurricane/Net.h @@ -251,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; } 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/tramontana/src/EquipotentialsWidget.cpp b/tramontana/src/EquipotentialsWidget.cpp index 0f08d8ff..216b472f 100644 --- a/tramontana/src/EquipotentialsWidget.cpp +++ b/tramontana/src/EquipotentialsWidget.cpp @@ -100,7 +100,7 @@ namespace Tramontana { 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(); From 56883db08e6f0cfe08f7db3daf24d5d96314ae27 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 7 May 2023 12:16:18 +0200 Subject: [PATCH 25/28] Display a window title when the viewer starts empty. --- hurricane/src/viewer/CellViewer.cpp | 2 +- hurricane/src/viewer/PyCellViewer.cpp | 1 + hurricane/src/viewer/hurricane/viewer/CellViewer.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) 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/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/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: From 46c685a7f8efe7d2828b4ceb88e5ec446d62f031 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 25 May 2023 23:10:49 +0200 Subject: [PATCH 26/28] Install Alliance in Release.Shared, not Debug.Shared. --- bootstrap/allianceInstaller.sh | 1 + 1 file changed, 1 insertion(+) 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 From 5233d860f489ee47c960ad4106202426f4a50445 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Fri, 16 Jun 2023 13:33:50 +0200 Subject: [PATCH 27/28] Slight change in Occurrence::getCompactString() formatting. * Change: In Occurrence::getCompactString(), when the path is void, still display a double colon (::) instead of just one so we know for sure that the it is void. --- hurricane/src/hurricane/Occurrence.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hurricane/src/hurricane/Occurrence.cpp b/hurricane/src/hurricane/Occurrence.cpp index 67e3750f..1d3e9d63 100644 --- a/hurricane/src/hurricane/Occurrence.cpp +++ b/hurricane/src/hurricane/Occurrence.cpp @@ -289,7 +289,8 @@ string Occurrence::getCompactString() const 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()); From 9b87b92eec154a1d4877e242d513c191932f0795 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Fri, 16 Jun 2023 13:34:36 +0200 Subject: [PATCH 28/28] Groudwork for short localization in Tramontana. In order to accurately find the rectangles (Components) causing a short circuit, we need to aggregate the equipotentials as soon as we starts to merge the tiles. Because tiles being a union set, the tree compression forbid to know which tile overlap which one afterwards. So the equipotentials are created early on the fly. We also add an accounting of all the net's components (Plug excluded) to know if it is fully included in the equipotential. If not, we have an open. This is an impacting change from the previous version in which we build the equipotentials *after* aggregating the tiles only. The added cost comes from the number of equipotential merging that we have to perform when we merge tiles. Almost two times slower. May need to have a deep look on how to optimize it later (efficient merge or keeping the order tiles where merged). --- tramontana/src/Equipotential.cpp | 241 ++++++++++++------ tramontana/src/EquipotentialComponents.cpp | 15 +- tramontana/src/SweepLine.cpp | 10 +- tramontana/src/Tile.cpp | 109 +++++--- tramontana/src/TramontanaEngine.cpp | 1 + tramontana/src/tramontana/Equipotential.h | 87 +++++-- .../src/tramontana/EquipotentialComponents.h | 16 +- tramontana/src/tramontana/SweepLine.h | 1 + tramontana/src/tramontana/Tile.h | 22 +- 9 files changed, 353 insertions(+), 149 deletions(-) diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp index d5a49b65..e4a25b02 100644 --- a/tramontana/src/Equipotential.cpp +++ b/tramontana/src/Equipotential.cpp @@ -30,6 +30,7 @@ #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" @@ -43,53 +44,6 @@ #include "tramontana/TramontanaEngine.h" -namespace { - - using std::map; - using Hurricane::Net; - using Hurricane::Plug; - using Hurricane::Occurrence; - - - class NetCompareByName { - public: - bool operator() ( const Net* lhs, const Net* rhs ) const; - }; - - - 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(); - } - - - class OccNetCompareByName { - public: - bool operator() ( const Occurrence& lhs, const Occurrence& rhs ) const; - }; - - - 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()) ); - } - - -} // Anonymous namespace. - - namespace Tramontana { using std::cout; @@ -119,6 +73,8 @@ namespace Tramontana { using Hurricane::Layer; using Hurricane::Entity; using Hurricane::Net; + using Hurricane::Plug; + using Hurricane::Contact; using Hurricane::Horizontal; using Hurricane::Vertical; using Hurricane::RoutingPad; @@ -127,6 +83,30 @@ namespace Tramontana { 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". @@ -194,19 +174,20 @@ namespace Tramontana { 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) + : _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() ); } @@ -235,7 +216,9 @@ namespace Tramontana { Equipotential::~Equipotential () - { } + { + for ( ShortCircuit* shortCircuit : _shortCircuits ) delete shortCircuit; + } Cell* Equipotential::getCell () const @@ -253,7 +236,54 @@ namespace Tramontana { 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) { @@ -274,8 +304,7 @@ namespace Tramontana { } _boundingBox.merge( boundingBox ); } - - + void Equipotential::merge ( Equipotential* other ) { if (this == other) { @@ -285,16 +314,84 @@ namespace Tramontana { ) << 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; + } + } + } - for ( const Occurrence& component : other->getComponents() ) add( component ); - for ( const Occurrence& child : other->getChilds () ) add( child ); + //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; @@ -350,7 +447,7 @@ namespace Tramontana { component->remove( relation ); } net->put( relation ); - _nets.insert( net ); + //_nets.insert( net ); } for ( Occurrence childEqui : _childs ) { childEqui.put( relation ); @@ -359,14 +456,16 @@ namespace Tramontana { // if (_name == "abc_11873_auto_rtlil_cc_2560_muxgate_11612") // show(); +#endif } void Equipotential::clear () { - _components.clear(); - _childs .clear(); - _nets .clear(); + _components .clear(); + _childs .clear(); + _nets .clear(); + _shortCircuits.clear(); } @@ -391,7 +490,7 @@ namespace Tramontana { sflags += ((_isGlobal ) ? "g" : "-"); sflags += ((_isAutomatic) ? "a" : "-"); sflags += ((_isBuried ) ? "B" : "-"); - sflags += " [N:" + getString( _netCount - ((_hasFused) ? 1 : 0) ); + sflags += " [N:" + getString( _nets.size() - ((_hasFused) ? 1 : 0) ); sflags += "+E:" + getString( _childs.size() ); if (_hasFused) sflags += "+fused"; @@ -423,7 +522,7 @@ namespace Tramontana { if (record) { record->add( getSlot( "_name" , &_name ) ); record->add( getSlot( "_boundingBox", &_boundingBox ) ); - record->add( getSlot( "_nets" , &_nets ) ); + //record->add( getSlot( "_nets" , &_nets ) ); record->add( getSlot( "_components" , &_components ) ); record->add( getSlot( "_childs" , &_childs ) ); } diff --git a/tramontana/src/EquipotentialComponents.cpp b/tramontana/src/EquipotentialComponents.cpp index 6c4470b9..2b5fb566 100644 --- a/tramontana/src/EquipotentialComponents.cpp +++ b/tramontana/src/EquipotentialComponents.cpp @@ -185,12 +185,15 @@ namespace Tramontana { } case InNets: { if (_netsIterator != _equipotential->getNets().end()) { - if (not _componentsLocator) { - _componentsLocator = (*_netsIterator)->getComponents().getLocator()->getClone(); - if (_componentsLocator->isValid()) return; - } else { - _componentsLocator->progress(); - if (_componentsLocator->isValid()) return; + 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; diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index 5a6f51f3..317e4b23 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -278,11 +278,13 @@ namespace Tramontana { // if (tile->getOccurrence().getEntity()->getId() == 3348) { // DebugSession::close(); // } + cdebug_tabw(160,-1); } //if (debugOn) DebugSession::close(); cdebug_tabw(160,-1); //DebugSession::close(); mergeEquipotentials(); + deleteTiles(); } @@ -322,6 +324,12 @@ namespace Tramontana { } + void SweepLine::deleteTiles () + { + Tile::deleteAllTiles(); + } + + void SweepLine::mergeEquipotentials () { //DebugSession::open( 160, 169 ); @@ -329,7 +337,7 @@ namespace Tramontana { //cerr << "SweepLine::mergeEquipotentials()" << endl; Tile::timeTick(); for ( Tile* tile : Tile::getAllTiles() ) { - tile->getRoot( Tile::MergeEqui ); + tile->getRoot( Tile::MergeEqui|Tile::MakeLeafEqui ); } cdebug_tabw(160,-1); //DebugSession::close(); diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp index 45e0d5a2..e6863ae4 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -100,7 +100,10 @@ namespace Tramontana { , _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; } @@ -199,26 +202,79 @@ namespace Tramontana { { } + 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 ) { - if (not getParent() and (not (flags & MergeEqui))) return this; - cdebug_log(160,1) << "Tile::getRoot()" << endl; + 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()) - root->getParent()->setEquipotential( root->getEquipotential() ); - } + // 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 " << root->getId() << " " + 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 ) { @@ -228,30 +284,6 @@ namespace Tramontana { } } - if (flags & MergeEqui) { - Equipotential* rootEqui = root->getEquipotential(); - if (not rootEqui) { - rootEqui = root->newEquipotential(); - } - - Tile* current = this; - while ( current ) { - if (current->isUpToDate()) break; - if (current->getEquipotential()) { - if (current->getEquipotential() != rootEqui) { - cdebug_log(160,0) << "| merge " << current->getId() << " => " << root->getId() << endl; - cdebug_log(160,0) << "| " << current->getEquipotential() << endl; - rootEqui->merge( current->getEquipotential() ); - } - } else { - cdebug_log(160,0) << "| add " << current->getOccurrence() << endl; - rootEqui->add( current->getOccurrence(), _boundingBox ); - } - current->syncTime(); - current = current->getParent(); - } - } - cdebug_tabw(160,-1); return root; } @@ -259,17 +291,26 @@ namespace Tramontana { Tile* Tile::merge ( Tile* other ) { - Tile* root1 = getRoot(); - Tile* root2 = other->getRoot(); - if (root1 and (root1 == root2)) return root1; + 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; } diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp index 2786e232..8b028520 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -151,6 +151,7 @@ namespace Tramontana { startMeasures(); } + cdebug_log(160,0) << "EXTRACTING " << getCell() << endl; for ( Instance* instance : getCell()->getInstances() ) { Cell* master = instance->getMasterCell(); TramontanaEngine* extractor = TramontanaEngine::get( master ); diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h index fefecd6b..1f699663 100644 --- a/tramontana/src/tramontana/Equipotential.h +++ b/tramontana/src/tramontana/Equipotential.h @@ -44,12 +44,45 @@ namespace Tramontana { 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 ); @@ -68,12 +101,15 @@ namespace Tramontana { 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 NetSet& getNets () 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; @@ -87,32 +123,37 @@ namespace Tramontana { Equipotential ( const Equipotential& ) = delete; Equipotential& operator= ( const Equipotential& ) = delete; private: - Cell* _owner; - Box _boundingBox; - NetSet _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; + 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 NetSet& 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 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 { diff --git a/tramontana/src/tramontana/EquipotentialComponents.h b/tramontana/src/tramontana/EquipotentialComponents.h index 70967612..ae502891 100644 --- a/tramontana/src/tramontana/EquipotentialComponents.h +++ b/tramontana/src/tramontana/EquipotentialComponents.h @@ -27,6 +27,7 @@ #include "hurricane/Box.h" #include "hurricane/Net.h" #include "hurricane/Occurrence.h" +#include "tramontana/Equipotential.h" namespace Tramontana { @@ -51,7 +52,6 @@ namespace Tramontana { using Hurricane::GenericFilter; using Hurricane::GenericLocator; using Hurricane::GenericCollection; - class Equipotential; typedef Hurricane::Locator ComponentsLocator; typedef Hurricane::Locator OccurrencesLocator; @@ -84,13 +84,13 @@ namespace Tramontana { virtual void progress (); virtual std::string _getString () const; private: - const Equipotential* _equipotential; - uint16_t _state; - OccurrenceSet::iterator _componentsIterator; - NetSet::iterator _netsIterator; - OccurrenceSet::iterator _childsIterator; - OccurrencesLocator* _childCompsLocator; - ComponentsLocator* _componentsLocator; + const Equipotential* _equipotential; + uint16_t _state; + OccurrenceSet::iterator _componentsIterator; + Equipotential::NetMap::const_iterator _netsIterator; + OccurrenceSet::iterator _childsIterator; + OccurrencesLocator* _childCompsLocator; + ComponentsLocator* _componentsLocator; }; public: diff --git a/tramontana/src/tramontana/SweepLine.h b/tramontana/src/tramontana/SweepLine.h index a7a4aec9..4ab04e98 100644 --- a/tramontana/src/tramontana/SweepLine.h +++ b/tramontana/src/tramontana/SweepLine.h @@ -75,6 +75,7 @@ namespace Tramontana { const LayerSet& getCutConnexLayers ( const BasicLayer* ) const; void run (); void loadTiles (); + void deleteTiles (); inline void add ( Tile* ); void mergeEquipotentials (); Record* _getRecord () const; diff --git a/tramontana/src/tramontana/Tile.h b/tramontana/src/tramontana/Tile.h index 2d2a3e20..6414719e 100644 --- a/tramontana/src/tramontana/Tile.h +++ b/tramontana/src/tramontana/Tile.h @@ -52,14 +52,17 @@ namespace Tramontana { class Tile { public: - static const uint32_t NoFlags = 0; - static const uint32_t LeftEdge = (1<<0); - static const uint32_t RightEdge = (1<<1); - static const uint32_t Compress = (1<<2); - static const uint32_t MergeEqui = (1<<3); - static const uint32_t ForceLayer = (1<<4); + 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* @@ -68,6 +71,7 @@ namespace Tramontana { , 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; @@ -88,6 +92,7 @@ namespace Tramontana { inline void syncTime (); inline void setParent ( Tile* ); Tile* merge ( Tile* ); + inline void setOccMerged ( bool state ); inline void setEquipotential ( Equipotential* ); Equipotential* newEquipotential (); Record* _getRecord () const; @@ -117,6 +122,7 @@ namespace Tramontana { 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; } @@ -136,6 +142,10 @@ namespace Tramontana { 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: