diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 09787dd46..ad7aa001e 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -29,6 +29,23 @@ namespace db { +// ---------------------------------------------------------------------------------------- +// NetlistDeviceExtractorError implementation + +NetlistDeviceExtractorError::NetlistDeviceExtractorError () +{ + // .. nothing yet .. +} + +NetlistDeviceExtractorError::NetlistDeviceExtractorError (const std::string &cell_name, const std::string &msg) + : m_cell_name (cell_name), m_message (msg) +{ + // .. nothing yet .. +} + +// ---------------------------------------------------------------------------------------- +// NetlistDeviceExtractor implementation + NetlistDeviceExtractor::NetlistDeviceExtractor () : mp_layout (0), m_cell_index (0), mp_circuit (0) { @@ -219,4 +236,49 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id define_terminal (device, terminal_id, layer_index, db::Polygon (db::Box (point - dv, point + dv))); } +std::string NetlistDeviceExtractor::cell_name () const +{ + if (layout ()) { + return layout ()->cell_name (cell_index ()); + } else { + return std::string (); + } +} + +void NetlistDeviceExtractor::error (const std::string &msg) +{ + m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); +} + +void NetlistDeviceExtractor::error (const std::string &msg, const db::Polygon &poly) +{ + error (msg); + m_errors.back ().set_geometry (db::Region (poly)); +} + +void NetlistDeviceExtractor::error (const std::string &msg, const db::Region ®ion) +{ + error (msg); + m_errors.back ().set_geometry (region); +} + +void NetlistDeviceExtractor::error (const std::string &category_name, const std::string &category_description, const std::string &msg) +{ + error (msg); + m_errors.back ().set_category_name (category_name); + m_errors.back ().set_category_description (category_description); +} + +void NetlistDeviceExtractor::error (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::Polygon &poly) +{ + error (category_name, category_description, msg); + m_errors.back ().set_geometry (db::Region (poly)); +} + +void NetlistDeviceExtractor::error (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::Region ®ion) +{ + error (category_name, category_description, msg); + m_errors.back ().set_geometry (region); +} + } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index 4f99cc1ba..73430901e 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -28,12 +28,123 @@ #include "dbLayout.h" #include "dbHierNetworkProcessor.h" #include "dbDeepShapeStore.h" +#include "dbRegion.h" #include "gsiObject.h" namespace db { +/** + * @brief An error object for the netlist device extractor + * + * The device extractor will keep errors using objects of this kind. + */ +class DB_PUBLIC NetlistDeviceExtractorError +{ +public: + /** + * @brief Creates an error + */ + NetlistDeviceExtractorError (); + + /** + * @brief Creates an error with a cell name and a message (the minimum information) + */ + NetlistDeviceExtractorError (const std::string &cell_name, const std::string &msg); + + /** + * @brief The category name of the error + * Specifying the category name is optional. If a category is given, it will be used for + * the report. + */ + const std::string &category_name () const + { + return m_category_name; + } + + /** + * @brief Sets the category name + */ + void set_category_name (const std::string &s) + { + m_category_name = s; + } + + /** + * @brief The category description of the error + * Specifying the category description is optional. If a category is given, this attribute will + * be used for the category description. + */ + const std::string &category_description () const + { + return m_category_description; + } + + /** + * @brief Sets the category description + */ + void set_category_description (const std::string &s) + { + m_category_description = s; + } + + /** + * @brief Gets the geometry for this error + * Not all errors may specify a geometry. + */ + const db::Region &geometry () const + { + return m_geometry; + } + + /** + * @brief Sets the geometry + */ + void set_geometry (const db::Region &g) + { + m_geometry = g; + } + + /** + * @brief Gets the message for this error + */ + const std::string &message () const + { + return m_message; + } + + /** + * @brief Sets the message + */ + void set_message (const std::string &n) + { + m_message = n; + } + + /** + * @brief Gets the cell name the error occured in + */ + const std::string &cell_name () const + { + return m_cell_name; + } + + /** + * @brief Sets the cell name + */ + void set_cell_name (const std::string &n) + { + m_cell_name = n; + } + +private: + std::string m_cell_name; + std::string m_message; + db::Region m_geometry; + std::string m_category_name, m_category_description; +}; + /** * @brief Implements the device extraction for a specific setup * @@ -44,6 +155,9 @@ class DB_PUBLIC NetlistDeviceExtractor : public gsi::ObjectBase { public: + typedef std::list error_list; + typedef error_list::const_iterator error_iterator; + /** * @brief Default constructor */ @@ -92,6 +206,30 @@ public: */ void extract (DeepShapeStore &dss, const std::vector &layers, Netlist *netlist); + /** + * @brief Gets the error iterator, begin + */ + error_iterator begin_errors () + { + return m_errors.begin (); + } + + /** + * @brief Gets the error iterator, end + */ + error_iterator end_errors () + { + return m_errors.end (); + } + + /** + * @brief Returns true, if there are errors + */ + bool has_errors () const + { + return ! m_errors.empty (); + } + protected: /** * @brief Creates the device classes @@ -186,6 +324,41 @@ protected: return m_cell_index; } + /** + * @brief Issues an error with the given message + */ + void error (const std::string &msg); + + /** + * @brief Issues an error with the given message and error shape + */ + void error (const std::string &msg, const db::Polygon &poly); + + /** + * @brief Issues an error with the given message and error geometry + */ + void error (const std::string &msg, const db::Region ®ion); + + /** + * @brief Issues an error with the given category name, description and message + */ + void error (const std::string &category_name, const std::string &category_description, const std::string &msg); + + /** + * @brief Issues an error with the given category name, description and message and error shape + */ + void error (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::Polygon &poly); + + /** + * @brief Issues an error with the given category name, description and message and error geometry + */ + void error (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::Region ®ion); + + /** + * @brief Gets the name of the current cell + */ + std::string cell_name () const; + private: tl::weak_ptr m_netlist; db::Layout *mp_layout; @@ -195,6 +368,7 @@ private: std::vector m_device_classes; std::vector m_layers; unsigned int m_device_name_index; + error_list m_errors; /** * @brief Initializes the extractor diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc new file mode 100644 index 000000000..a9eaa5ec8 --- /dev/null +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -0,0 +1,88 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbNetlistDeviceExtractor.h" + +#include "tlUnitTest.h" + +TEST(1_NetlistDeviceExtractorErrorBasic) +{ + db::NetlistDeviceExtractorError error; + + EXPECT_EQ (error.message (), ""); + error.set_message ("x"); + EXPECT_EQ (error.message (), "x"); + error.set_category_name ("cat"); + EXPECT_EQ (error.category_name (), "cat"); + error.set_category_description ("cdesc"); + EXPECT_EQ (error.category_description (), "cdesc"); + error.set_cell_name ("cell"); + EXPECT_EQ (error.cell_name (), "cell"); + error.set_geometry (db::Region (db::Box (0, 1, 2, 3))); + EXPECT_EQ (error.geometry ().to_string (), "(0,1;0,3;2,3;2,1)"); + + error = db::NetlistDeviceExtractorError ("cell2", "msg2"); + EXPECT_EQ (error.cell_name (), "cell2"); + EXPECT_EQ (error.message (), "msg2"); + EXPECT_EQ (error.category_name (), ""); + EXPECT_EQ (error.category_description (), ""); + EXPECT_EQ (error.geometry ().to_string (), ""); +} + +namespace { + class DummyDeviceExtractor + : public db::NetlistDeviceExtractor + { + public: + DummyDeviceExtractor () + { + error ("msg1"); + error ("msg2", db::Box (0, 1, 2, 3)); + error ("msg3", db::Region (db::Box (10, 11, 12, 13))); + error ("cat1", "desc1", "msg1"); + error ("cat1", "desc1", "msg2", db::Box (0, 1, 2, 3)); + error ("cat1", "desc1", "msg3", db::Region (db::Box (10, 11, 12, 13))); + } + }; +} + +static std::string error2string (const db::NetlistDeviceExtractorError &e) +{ + return e.cell_name() + ":" + e.category_name () + ":" + e.category_description () + ":" + + e.geometry ().to_string () + ":" + e.message (); +} + +TEST(2_NetlistDeviceExtractorErrors) +{ + DummyDeviceExtractor dummy_ex; + + EXPECT_EQ (dummy_ex.has_errors (), true); + + std::vector errors (dummy_ex.begin_errors (), dummy_ex.end_errors ()); + EXPECT_EQ (int (errors.size ()), 6); + EXPECT_EQ (error2string (errors [0]), "::::msg1"); + EXPECT_EQ (error2string (errors [1]), ":::(0,1;0,3;2,3;2,1):msg2"); + EXPECT_EQ (error2string (errors [2]), ":::(10,11;10,13;12,13;12,11):msg3"); + EXPECT_EQ (error2string (errors [3]), ":cat1:desc1::msg1"); + EXPECT_EQ (error2string (errors [4]), ":cat1:desc1:(0,1;0,3;2,3;2,1):msg2"); + EXPECT_EQ (error2string (errors [5]), ":cat1:desc1:(10,11;10,13;12,13;12,11):msg3"); +} diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 220e787d9..020d5b3fe 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -161,30 +161,6 @@ public: } } - void error (const std::string &msg) - { - // @@@ TODO: move this to device extractor - tl::error << tr ("Error in cell '") << cell_name () << "': " << msg; - } - - void error (const std::string &msg, const db::Polygon &poly) - { - // @@@ TODO: move this to device extractor - tl::error << tr ("Error in cell '") << cell_name () << "': " << msg << " (" << poly.to_string () << ")"; - } - - void error (const std::string &msg, const db::Region ®ion) - { - // @@@ TODO: move this to device extractor - tl::error << tr ("Error in cell '") << cell_name () << "': " << msg << " (" << region.to_string () << ")"; - } - - std::string cell_name () const - { - // @@@ TODO: move this to device extractor - return layout ()->cell_name (cell_index ()); - } - private: db::Layout *mp_debug_out; unsigned int m_ldiff, m_lgate; @@ -363,7 +339,7 @@ static std::string netlist2string (const db::Netlist &nl) return res; } -TEST(1_DeviceAndNetExtraction) +TEST(2_DeviceAndNetExtraction) { db::Layout ly; db::LayerMap lmap; @@ -535,3 +511,92 @@ TEST(1_DeviceAndNetExtraction) db::compare_layouts (_this, ly, au); } + +#if 0 + +// -------------------------------------------------------------------------------------- +// An attempt to simplify things. + +/* +- layers: use db::Region, or wrapper? +-> use regions, but test whether they are deep regions (?) + +TODO: +- netlist query functions such as net_by_name, device_by_name, circuit_by_name +- terminal geometry (Polygon) for device, combined device geometry (all terminals) +- error interface for device extraction + // gets the device extraction errors + // device_extraction_error_iterator begin_device_extraction_errors () const; + // device_extraction_error_iterator end_device_extraction_errors () const; + // bool has_device_extraction_errors () const; + +- device extractor needs to declare the layers to allow passing them by name +- netlist manipulation methods (i.e. flatten certain cells, purging etc.) +*/ + +#include "tlGlobPattern.h" +#include "dbHierNetworkProcessor.h" + +namespace db +{ + +class DB_PUBLIC LayoutToNetlist +{ +public: + // the iterator provides the hierarchical selection (enabling/disabling cells etc.) + LayoutToNetlist (const db::RecursiveShapeIterator &iter); + + // --- preparation + + // returns a new'd region + db::Region *make_layer (unsigned int layer_index); + db::Region *make_text_layer (unsigned int layer_index); + db::Region *make_polygon_layer (unsigned int layer_index); + + // gets the internal layout and cell + const db::Layout &internal_layout () const; + const db::Cell &internal_top_cell () const; + + // --- device extraction + + // after this, the device extractor will have errors if some occured. + void extract_devices (db::NetlistDeviceExtractor *extractor, const std::map &layers); + + // --- net extraction + + // define connectivity for the netlist extraction + void connect (const db::Region &l); + void connect (const db::Region &a, const db::Region &b); + + // runs the netlist extraction + void extract_netlist (); + + // --- retrieval + + // gets the internal layer index of the given region + unsigned int layer_of (const db::Region ®ion) const; + + // creates a cell mapping for copying the internal hierarchy to the given layout + // CAUTION: may create new cells in "layout". + db::CellMapping cell_mapping_into (db::Layout &layout, db::Cell &cell); + + // creates a cell mapping for copying the internal hierarchy to the given layout + // This version will not create new cells in the target layout. + db::CellMapping const_cell_mapping_into (const db::Layout &layout, const db::Cell &cell); + + // gets the netlist extracted (0 if no extraction happened yet) + db::Netlist *netlist () const; + + // gets the hierarchical clusters of the nets (CAUTION: the layer indexes therein are + // internal layer indexes), same for cell indexes. + // -> NOT GSI + const db::hier_clusters &net_clusters () const; + + // copies the shapes of the given net from a given layer + // (recursive true: include nets from subcircuits) + db::Region shapes_of_net (const db::Net &net, const db::Region &of_layer, bool recursive); +}; + +} + +#endif diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 16e32217c..a6f455bac 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -61,7 +61,8 @@ SOURCES = \ dbHierNetworkProcessorTests.cc \ dbNetlistPropertyTests.cc \ dbNetlistTests.cc \ - dbNetlistExtractorTests.cc + dbNetlistExtractorTests.cc \ + dbNetlistDeviceExtractorTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC