/* 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 */ #ifndef HDR_dbNetTracer #define HDR_dbNetTracer #include "dbCommon.h" #include "dbShapes.h" #include "dbShape.h" #include "dbEdgeProcessor.h" #include "tlProgress.h" #include "tlFixedVector.h" #include #include #include namespace db { class RecursiveShapeIterator; class NetTracerLayerElement; class NetTracerData; /** * @brief A shape heap where intermediate shapes can be placed into * * This heap is intended to hold flat, top level shapes and uses a cache. First, the cache compresses * the data and second, this guarantees that the Shape references delivered point to the same object * for identical shapes. */ class DB_PUBLIC NetTracerShapeHeap { public: /** * @brief Constructor */ NetTracerShapeHeap (); /** * @brief Get a shape object for a polygon */ db::Shape insert (const db::Polygon &p); /** * @brief Clear the heap */ void clear (); private: db::Shapes m_container; std::map m_cache; }; /** * @brief A shape abstraction for the net tracer, used for storing the net information * * This class describes a shape in the hierarchy by the transformation into the top cell, the shape reference, the cell * index and the layer the shape resides on. */ class DB_PUBLIC NetTracerShape { public: /** * @brief Creates an invalid shape */ NetTracerShape () : m_trans (), m_shape (), m_pseudo (true), m_layer (0), m_cell_index (0) { // .. nothing yet .. } /** * @brief Create a shape from the given transformation, shape, layer, cell index and pseudo flag */ NetTracerShape (const db::ICplxTrans &t, const db::Shape &s, unsigned int l, db::cell_index_type c, bool pseudo = false) : m_trans (t), m_shape (s), m_pseudo (pseudo), m_layer (l), m_cell_index (c) { m_bbox = m_trans * m_shape.bbox (); } /** * @brief Returns true if the shape is valid */ bool is_valid () const { return !m_shape.is_null (); } /** * @brief Gets the bounding box of the cell in the top cell */ const db::Box &bbox () const { return m_bbox; } /** * @brief Gets the transformation * * This is the transformation of the shape relative to the top cell */ const db::ICplxTrans &trans () const { return m_trans; } /** * @brief Gets the shape */ const db::Shape &shape () const { return m_shape; } /** * @brief Sets the shape */ void shape (const db::Shape &s) { m_shape = s; m_bbox = m_trans * m_shape.bbox (); } /** * @brief Gets the pseudo flag * * The pseudo flag is set when the shape is not a part of the incremental net * detection process but rather an endpoint. That way, start and stop shapes can * be made part of the net with a special marking. */ bool is_pseudo () const { return m_pseudo; } /** * @brief Sets the pseudo flag */ void set_pseudo (bool p) { m_pseudo = p; } /** * @brief Gets the layer where the shape is located */ unsigned int layer () const { return m_layer; } /** * @brief Gets the cell index where the shape is located */ db::cell_index_type cell_index () const { return m_cell_index; } /** * @brief equal operator */ bool operator== (const NetTracerShape &other) const { // Note: the pseudo flag is not part of the comparison. That way, the shape can be // marked "already found" by a pseudo-type shape. if (m_layer != other.m_layer) { return false; } if (m_bbox != other.m_bbox) { return false; } if (m_cell_index != other.m_cell_index) { return false; } if (m_shape != other.m_shape) { return false; } return m_trans.equal (other.m_trans); } /** * @brief less operator */ bool operator< (const NetTracerShape &other) const { // Note: the pseudo flag is not part of the comparison. That way, the shape can be // marked "already found" by a pseudo-type shape. if (m_layer != other.m_layer) { return m_layer < other.m_layer; } if (m_bbox != other.m_bbox) { return m_bbox < other.m_bbox; } if (m_cell_index != other.m_cell_index) { return m_cell_index < other.m_cell_index; } if (m_shape != other.m_shape) { return m_shape < other.m_shape; } return m_trans.less (other.m_trans); } private: db::ICplxTrans m_trans; db::Shape m_shape; bool m_pseudo : 1; unsigned int m_layer : 31; db::cell_index_type m_cell_index; db::Box m_bbox; }; /** * @brief A box converter for the NetTracerShape which is used to build a quad tree for them */ struct HitTestDataBoxConverter { db::Box operator() (const NetTracerShape *d) const { return d->bbox (); } typedef db::simple_bbox_tag complexity; }; typedef db::box_tree HitTestDataBoxTree; /** * @brief Describes a boolean expression for computed layers */ class DB_PUBLIC NetTracerLayerExpression { public: /** * @brief The operator */ enum Operator { OPNone, OPOr, OPNot, OPAnd, OPXor }; /** * @brief Default Constructor */ NetTracerLayerExpression (); /** * @brief Default Constructor with the given layer as the "a" argument and OPNone * * The argument must be an original layer. */ NetTracerLayerExpression (int l); /** * @brief Copy Constructor */ NetTracerLayerExpression (const NetTracerLayerExpression &other); /** * @brief Assignment */ NetTracerLayerExpression &operator= (const NetTracerLayerExpression &other); /** * @brief Destructor */ ~NetTracerLayerExpression (); /** * @brief Returns true, if the given original layer is a positive contribution to the formula */ bool is_positive (unsigned int ol) const { if (m_op == OPOr || m_op == OPNone) { if (mp_a) { if (mp_a->is_positive (ol)) { return true; } } else if (int (ol) == m_a) { return true; } } if (m_op == OPOr) { if (mp_b) { if (mp_b->is_positive (ol)) { return true; } } else if (int (ol) == m_b) { return true; } } return false; } /** * @brief Returns a representative (first) layer */ int representative_layer () const { return mp_a ? mp_a->representative_layer () : m_a; } /** * @brief Returns true, if the expression is an alias for the given layer a */ bool is_alias_for (int a) const { return m_op == OPNone && mp_a == 0 && m_a == a; } /** * @brief Returns true, if the expression is a simple alias */ bool is_alias () const { return m_op == OPNone && mp_a == 0; } /** * @brief Returns the layer, if the expression is an alias for it or -1 if the expression is not an alias at all */ int alias_for () const { if (m_op == OPNone && mp_a == 0) { return m_a; } else { return -1; } } /** * @brief Merge the given expression as the "b" argument with the given operator * * This becomes owner of b. */ void merge (Operator op, NetTracerLayerExpression *a); /** * @brief Obtains the list of original layers involved in this operation */ std::set original_layers () const { std::set l; collect_original_layers (l); return l; } /** * @brief Compute the results * * This function takes the shapes from the input set holding all related shapes. It will perform the booleans in this * expression on the input shapes and verify them against the seeds. If a boolean result interacts with one of these * new seeds, it is stored in the output set using the seed as the adjacent shape. * "mask" is used as a mask for the output if not null. */ void compute_results (unsigned int layer, db::cell_index_type cell_index, const std::vector *mask, const std::set > &input, const HitTestDataBoxTree *seeds, NetTracerShapeHeap &shape_heap, std::set > &output, const NetTracerData &data, db::EdgeProcessor &ep) const; /** * @brief Dump for debugging purposes */ std::string to_string () const; private: int m_a, m_b; NetTracerLayerExpression *mp_a, *mp_b; Operator m_op; void collect_original_layers (std::set &l) const; }; /** * @brief Describes one connection between two conductive layers * * This class has three members: the index of the first conductive layer, the * index of the via layer and the index of the second conductive layer. */ class DB_PUBLIC NetTracerConnection { public: /** * @brief Creates a connection between layer la and lb without an intermediate via layer * * A connection described by this constructor defines a connection at all places where la overlaps lb. */ NetTracerConnection (int la, int lb) : m_layer_a (la), m_via_layer (-1), m_has_via_layer (false), m_layer_b (lb) { // .. nothing yet .. } /** * @brief Creates a connection between layer la and lb with a via layer * * A connection described by this constructor defines a connection at all places where la overlaps the via * shape and the same via shape overlaps lb. */ NetTracerConnection (int la, int via, int lb) : m_layer_a (la), m_via_layer (via), m_has_via_layer (true), m_layer_b (lb) { // .. nothing yet .. } /** * @brief Gets the index of the first conductive layer * * Returns a negative value if the via layer is not present (and should be considered * empty). */ int layer_a () const { return m_layer_a; } /** * @brief Gets the index of the second conductive layer * * Returns a negative value if the via layer is not present (and should be considered * empty). */ int layer_b () const { return m_layer_b; } /** * @brief Returns true if this connection has a via layer */ bool has_via_layer () const { return m_has_via_layer; } /** * @brief Returns the index of the via layer. * * Returns a negative value if the via layer is not present (and should be considered * empty). */ int via_layer () const { return m_via_layer; } private: int m_layer_a; int m_via_layer; bool m_has_via_layer; int m_layer_b; }; /** * @brief Wraps the data for a net tracing */ class DB_PUBLIC NetTracerData { public: /** * @brief Default constructor */ NetTracerData (); /** * @brief Destructor */ ~NetTracerData (); /** * @brief Register a logical layer * * @param expr The expression by which the new layer is computed (can be 0 to set an alias) * @param symbol The symbol under which to register the expression or 0 for anonymous * @return The ID of the logical layer * * The NetTracerData object becomes the owner of the expr object. */ unsigned int register_logical_layer (NetTracerLayerExpression *expr, const char *symbol); /** * @brief Find the logical layer for a symbol */ int find_symbol (const std::string &symbol) const; /** * @brief Returns the expression for a given logical layer * * If no explicit expression was registered, this method returns a alias expression. */ const NetTracerLayerExpression &expression (unsigned int l) const; /** * @brief Add a connection to the connection graph * * The layers in the connect are logical layers. Hence, logical layer must be specified before * add_connection can be used. */ void add_connection (const NetTracerConnection &connection); /** * @brief Returns all connections starting or ending at the given layer. * * 'from_layer' is a logical layer while the returned values are all original layers * involved in the composition of connected layers or the input layer. */ const std::set &connections (unsigned int from_layer) const; /** * @brief Returns all logical layers connected to the given logical layer */ const std::set &log_connections (unsigned int from_layer) const; /** * @brief Returns the connected original layers split into the ones requiring booleans and the ones which don't * The result pair will contain the ones which do not require booleans in the first element, and the ones which * do in the second. */ const std::pair , std::set > &requires_booleans (unsigned int from_layer) const; /** * @brief Find the logical layers that the given original layer participates in * * Returns an empty set if the original layer does not participate in any connection */ std::set log_layers_for (unsigned int original_layer) const; /** * @brief returns the symbol list */ const std::map &symbols () const { return m_symbols; } /** * @brief Returns true, if no connection is defined. */ bool is_empty () const { return m_connections.empty (); } private: unsigned int m_next_log_layer; std::vector m_connections; std::map > m_original_layers; std::map > m_connection_graph; std::map > m_log_connection_graph; mutable std::map m_log_layers; mutable std::map , std::set > > m_requires_booleans; std::map m_symbols; void add_layer_pair (unsigned int a, unsigned int b); void add_layers (unsigned int a, unsigned int b); }; /** * @brief The net tracer * * This object will provide a net tracing on a given cell view. * Net tracing can be performed with a given seed point and given tracing data. * The tracing is initiated with the "trace" method. */ class DB_PUBLIC NetTracer { public: typedef std::set ::const_iterator iterator; /** * @brief Construct a net tracer on the given cellview. */ NetTracer (); /** * @brief Trace the net starting from the given seed with the given data. */ void trace (const db::Layout &layout, const db::Cell &cell, const NetTracerShape &start, const NetTracerData &data); /** * @brief Trace the net starting from the given point/layer seed with the given data. */ void trace (const db::Layout &layout, const db::Cell &cell, const db::Point &pt_start, unsigned int l_start, const NetTracerData &data); /** * @brief Trace the path starting from the given seed and ending at the given shape with the given data. */ void trace (const db::Layout &layout, const db::Cell &cell, const NetTracerShape &start, const NetTracerShape &stop, const NetTracerData &data); /** * @brief Trace the net starting from the given point/layer seed with the given data. */ void trace (const db::Layout &layout, const db::Cell &cell, const db::Point &pt_start, unsigned int l_start, const db::Point &pt_stop, unsigned int l_stop, const NetTracerData &data); /** * @brief Begin operator for the shapes found */ iterator begin () const { return m_shapes_found.begin (); } /** * @brief End operator for the shapes found */ iterator end () const { return m_shapes_found.end (); } /** * @brief Returns the number of shapes found */ size_t size () const { return m_shapes_found.size (); } /** * @brief Returns true, if the net is incomplete * * This flag is true if the extractor was aborted * for example by the user. * The shapes do not fully cover the net. */ bool incomplete () const { return m_incomplete; } /** * @brief Clear the data found so far. */ void clear (); /** * @brief Get a name for the net * * The name can be empty if not specific net name could be determined (i.e. from a label or property) */ std::string name () const; /** * @brief Set a name for the net */ void set_name (const std::string &n); /** * @brief Get the layout from which this net was taken */ const db::Layout &layout () const { return *mp_layout; } /** * @brief Get the cell from which this net was taken */ const db::Cell &cell () const { return *mp_cell; } private: const db::Layout *mp_layout; const db::Cell *mp_cell; std::set m_shapes_found; NetTracerShapeHeap m_shape_heap; std::map > m_shapes_graph; tl::AbsoluteProgress *mp_progress; std::set > m_hit_test_queue; std::string m_name; int m_name_hier_depth; bool m_incomplete; NetTracerShape m_stop_shape; NetTracerShape m_start_shape; db::EdgeProcessor m_ep; void determine_interactions (const db::Box &seed, const NetTracerShape *shape, const std::set &layers, std::set > &delivery); void determine_interactions (const db::Polygon &seed, const NetTracerShape *shape, const std::set &layers, std::set > &delivery); void determine_interactions (const std::vector &seeds, const db::Box &combined_box, const std::set &layers, std::set > &delivery, bool do_seed_assignment = true); void evaluate_text (const db::RecursiveShapeIterator &iter); const NetTracerShape *deliver_shape (const NetTracerShape &shape, const NetTracerShape *adjacent); void compute_results_for_next_iteration (const std::vector &new_seeds, unsigned int seed_layer, const std::set &output_layers, std::set > ¤t, std::set > &output, const NetTracerData &data); }; } #endif