diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 6bad4c7fb..c33724a66 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -682,8 +682,8 @@ public: /** * @brief Constructor */ - hc_receiver (const db::Layout &layout, db::connected_clusters &cell_clusters, hier_clusters &tree, const cell_clusters_box_converter &cbc, const db::Connectivity &conn) - : mp_layout (&layout), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn) + hc_receiver (const db::Layout &layout, const db::Cell &cell, db::connected_clusters &cell_clusters, hier_clusters &tree, const cell_clusters_box_converter &cbc, const db::Connectivity &conn) + : mp_layout (&layout), mp_cell (&cell), mp_tree (&tree), mp_cbc (&cbc), mp_conn (&conn) { mp_cell_clusters = &cell_clusters; } @@ -739,6 +739,7 @@ public: private: const db::Layout *mp_layout; + const db::Cell *mp_cell; db::connected_clusters *mp_cell_clusters; hier_clusters *mp_tree; const cell_clusters_box_converter *mp_cbc; @@ -930,7 +931,7 @@ private: /** * @brief Handles a local clusters vs. the clusters of a specific child instance * @param c1 The local cluster - * @param ci2 The cell index of the child cell + * @param ci2 The cell index of the cell investigated * @param p2 The instantiation path to the child cell (last element is the instance to ci2) * @param t2 The accumulated transformation of the path */ @@ -1022,10 +1023,40 @@ private: ClusterInstance ci (id, *p); if (p == path.begin ()) { + + // if we're attaching to a child which is root yet, we need to promote the + // cluster to the parent in all places + connected_clusters &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ()); + if (child_cc.is_root (id)) { + + const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ()); + for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + + connected_clusters &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ()); + for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { + + ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); + if (mp_cell->cell_index () != pi->parent_cell_index () || ci != ci2) { + + id_type id_dummy = parent_cc.insert_dummy (); + parent_cc.add_connection (id_dummy, ci2); + + } + + } + + } + + child_cc.reset_root (id); + + } + return ci; + } - connected_clusters &target_cc = mp_tree->clusters_per_cell (p [-1].inst_ptr.cell_index ()); + db::cell_index_type pci = p [-1].inst_ptr.cell_index (); + connected_clusters &target_cc = mp_tree->clusters_per_cell (pci); id_type parent_cluster = target_cc.find_cluster_with_connection (ci); if (parent_cluster > 0) { @@ -1035,13 +1066,43 @@ private: } else { + id_type id_new = 0; + + // if we're attaching to a child which is root yet, we need to promote the + // cluster to the parent in all places + connected_clusters &child_cc = mp_tree->clusters_per_cell (p->inst_ptr.cell_index ()); + if (child_cc.is_root (id)) { + + const db::Cell &child_cell = mp_layout->cell (p->inst_ptr.cell_index ()); + for (db::Cell::parent_inst_iterator pi = child_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + + connected_clusters &parent_cc = mp_tree->clusters_per_cell (pi->parent_cell_index ()); + for (db::CellInstArray::iterator pii = pi->child_inst ().begin (); ! pii.at_end (); ++pii) { + + id_type id_dummy = parent_cc.insert_dummy (); + ClusterInstance ci2 (id, db::InstElement (pi->child_inst (), pii)); + parent_cc.add_connection (id_dummy, ci2); + + if (pci == pi->parent_cell_index () && ci == ci2) { + id_new = id_dummy; + } + + } + + } + + child_cc.reset_root (id); + + } + // no parent -> create vertical connector - id = target_cc.insert_dummy (); - target_cc.add_connection (id, ci); + id = id_new; + tl_assert (id != 0); } } + } }; @@ -1165,7 +1226,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // NOTE: this is a receiver for both the child-to-child and // local to child interactions. - hc_receiver rec (layout, local, *this, cbc, conn); + hc_receiver rec (layout, cell, local, *this, cbc, conn); cell_inst_clusters_box_converter cibc (cbc); // The box scanner needs pointers so we have to first store the instances @@ -1241,70 +1302,131 @@ hier_clusters::clusters_per_cell (db::cell_index_type cell_index) return c->second; } -template -static -void put_or_propagate (const hier_clusters &hc, incoming_cluster_connections &inc, size_t cluster_id, const local_cluster &cluster, db::Layout &layout, db::cell_index_type ci, const std::map &lm, const db::ICplxTrans &trans) +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t); + +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t) { - db::Cell &target_cell = layout.cell (ci); - - if (cluster_id > 0 && inc.has_incoming (ci, cluster_id)) { - - typedef std::pair reference_type; - std::map references; - - for (db::Cell::parent_inst_iterator pi = target_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { - db::Instance i = pi->child_inst (); - for (db::CellInstArray::iterator ii = i.cell_inst ().begin (); ! ii.at_end (); ++ii) { - references.insert (std::make_pair (reference_type ((*pi).parent_cell_index (), db::InstElement (i, ii)), false)); - } - } - - const typename incoming_cluster_connections::incoming_connections &connections = inc.incoming (ci, cluster_id); - for (typename incoming_cluster_connections::incoming_connections::const_iterator x = connections.begin (); x != connections.end (); ++x) { - typename std::map::iterator r = references.find (reference_type (x->parent_cell (), x->inst ())); - if (r != references.end () && ! r->second) { - put_or_propagate (hc, inc, x->parent_cluster_id (), cluster, layout, r->first.first, lm, r->first.second.complex_trans () * trans); - r->second = true; - } - } - - for (typename std::map::const_iterator r = references.begin (); r != references.end (); ++r) { - if (! r->second) { - put_or_propagate (hc, inc, 0, cluster, layout, r->first.first, lm, r->first.second.complex_trans () * trans); - } - } - - } else { - - for (typename std::map::const_iterator m = lm.begin (); m != lm.end (); ++m) { - db::Shapes shapes; - for (typename local_cluster::shape_iterator s = cluster.begin (m->first); ! s.at_end (); ++s) { - shapes.insert (*s); - } - tl::ident_map pm; - target_cell.shapes (m->second).insert_transformed (shapes, trans, pm); - } - + db::Polygon poly = s.obj (); + poly.transform (s.trans ()); + if (! t.is_unity ()) { + poly.transform (t); } + shapes.insert (db::PolygonRef (poly, layout.shape_repository ())); } template void -hier_clusters::return_to_hierarchy (db::Layout &layout, db::Cell &cell, const std::map &lm) const +hier_clusters::return_to_hierarchy (db::Layout &layout, const std::map &lm) const { - incoming_cluster_connections inc (layout, cell, *this); - for (db::Layout::bottom_up_iterator c = layout.begin_bottom_up (); c != layout.end_bottom_up (); ++c) { + const db::connected_clusters &cc = clusters_per_cell (*c); - for (typename db::connected_clusters::const_iterator lc = cc.begin (); lc != cc.end (); ++lc) { - put_or_propagate (*this, inc, lc->id (), *lc, layout, *c, lm, db::ICplxTrans ()); + db::Cell &target_cell = layout.cell (*c); + + for (typename db::connected_clusters::all_iterator lc = cc.begin_all (); ! lc.at_end (); ++lc) { + + if (cc.is_root (*lc)) { + + for (typename std::map::const_iterator m = lm.begin (); m != lm.end (); ++m) { + + db::Shapes &shapes = target_cell.shapes (m->second); + + for (recursive_cluster_shape_iterator si (*this, m->first, *c, *lc); ! si.at_end (); ++si) { + insert_transformed (layout, shapes, *si, si.trans ()); + } + + } + + } + } + } } // explicit instantiations template class DB_PUBLIC hier_clusters; +// ------------------------------------------------------------------------------ +// recursive_cluster_shape_iterator implementation + +template +recursive_cluster_shape_iterator::recursive_cluster_shape_iterator (const hier_clusters &hc, unsigned int layer, db::cell_index_type ci, typename local_cluster::id_type id) + : mp_hc (&hc), m_layer (layer), m_id (id) +{ + down (ci, id, db::ICplxTrans ()); + + while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) { + next_conn (); + } +} + +template +recursive_cluster_shape_iterator &recursive_cluster_shape_iterator::operator++ () +{ + ++m_shape_iter; + + while (m_shape_iter.at_end () && ! m_conn_iter_stack.empty ()) { + next_conn (); + } + + return *this; +} + +template +void recursive_cluster_shape_iterator::next_conn () +{ + if (m_conn_iter_stack.back ().first != m_conn_iter_stack.back ().second) { + + const ClusterInstance &cli = *m_conn_iter_stack.back ().first; + down (cli.inst ().inst_ptr.cell_index (), cli.id (), cli.inst ().complex_trans ()); + + } else { + + while (m_conn_iter_stack.back ().first == m_conn_iter_stack.back ().second) { + + up (); + if (m_conn_iter_stack.empty ()) { + return; + } + + ++m_conn_iter_stack.back ().first; + + } + + } +} + +template +void recursive_cluster_shape_iterator::up () +{ + m_conn_iter_stack.pop_back (); + m_trans_stack.pop_back (); + m_cell_index_stack.pop_back (); +} + +template +void recursive_cluster_shape_iterator::down (db::cell_index_type ci, typename db::local_cluster::id_type id, const db::ICplxTrans &t) +{ + const connected_clusters &clusters = mp_hc->clusters_per_cell (ci); + const typename connected_clusters::connections_type &conn = clusters.connections_for_cluster (id); + + if (! m_trans_stack.empty ()) { + m_trans_stack.push_back (m_trans_stack.back () * t); + } else { + m_trans_stack.push_back (t); + } + + m_cell_index_stack.push_back (ci); + m_conn_iter_stack.push_back (std::make_pair (conn.begin (), conn.end ())); + + const local_cluster &cluster = mp_hc->clusters_per_cell (cell_index ()).cluster_by_id (cluster_id ()); + m_shape_iter = cluster.begin (m_layer); +} + +// explicit instantiations +template class DB_PUBLIC recursive_cluster_shape_iterator; + // ------------------------------------------------------------------------------ // incoming_cluster_connections implementation diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index e102a5d26..2442298cb 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -229,6 +229,7 @@ template class DB_PUBLIC local_clusters { public: + typedef typename local_cluster::id_type id_type; typedef typename local_cluster::box_type box_type; typedef db::box_tree, local_cluster_box_convert > tree_type; typedef typename tree_type::touching_iterator touching_iterator; @@ -372,6 +373,14 @@ public: return m_id == other.m_id && m_inst == other.m_inst; } + /** + * @brief Inequality + */ + bool operator!= (const ClusterInstance &other) const + { + return ! operator== (other); + } + /** * @brief Less operator */ @@ -434,12 +443,20 @@ private: /** * @brief Local clusters with connections to clusters from child cells + * + * Clusters can get connected. There are incoming connections (from above the hierarchy) + * and outgoing connections (down to a child cell). + * + * "root" clusters are some that don't have incoming connections. There are only + * root clusters or clusters which are connected from every parent cell. There are no + * "half connected" clusters. */ template class DB_PUBLIC connected_clusters : public local_clusters { public: + typedef typename local_clusters::id_type id_type; typedef std::list connections_type; typedef typename local_clusters::box_type box_type; typedef connected_clusters_iterator all_iterator; @@ -507,11 +524,29 @@ public: return m_connections.end (); } + /** + * @brief Returns true, if the given cluster ID is a root cluster + */ + bool is_root (id_type id) const + { + return m_connected_clusters.find (id) == m_connected_clusters.end (); + } + + /** + * @brief Resets the root status of a cluster + * CAUTION: don't call this method unless you know what you're doing. + */ + void reset_root (id_type id) + { + m_connected_clusters.insert (id); + } + private: template friend class connected_clusters_iterator; - std::map::id_type, connections_type> m_connections; + std::map m_connections; std::map::id_type> m_rev_connections; + std::set m_connected_clusters; }; template @@ -573,7 +608,7 @@ public: * The backannotation process usually involves propagation of shapes up in the hierarchy * to resolve variants. */ - void return_to_hierarchy (db::Layout &layout, db::Cell &cell, const std::map &lm) const; + void return_to_hierarchy (db::Layout &layout, const std::map &lm) const; /** * @brief Clears this collection @@ -589,6 +624,100 @@ private: std::map > m_per_cell_clusters; }; +/** + * @brief A recursive shape iterator for the shapes of a cluster + * + * This iterator will deliver the shapes of a cluster including the shapes for the + * connected child clusters. + * + * This iterator applies to one layer. + */ +template +class DB_PUBLIC recursive_cluster_shape_iterator +{ +public: + typedef T value_type; + typedef const T &reference; + typedef const T *pointer; + + /** + * @brief Constructor + */ + recursive_cluster_shape_iterator (const hier_clusters &hc, unsigned int layer, db::cell_index_type ci, typename local_cluster::id_type id); + + /** + * @brief Returns a value indicating whether there are any more shapes + */ + bool at_end () const + { + return m_shape_iter.at_end (); + } + + /** + * @brief Returns the shape (untransformed) + */ + reference operator* () const + { + return *m_shape_iter; + } + + /** + * @brief Returns the shape pointer (untransformed) + */ + pointer operator-> () const + { + return m_shape_iter.operator-> (); + } + + /** + * @brief Returns the transformation applicable for transforming the shape to the root cluster + */ + const db::ICplxTrans &trans () const + { + return m_trans_stack.back (); + } + + /** + * @brief Returns the cell index the shape lives in + */ + db::cell_index_type cell_index () const + { + return m_cell_index_stack.back (); + } + + /** + * @brief Returns the id of the current cluster + */ + typename db::local_cluster::id_type cluster_id () const + { + if (m_conn_iter_stack.size () <= 1) { + return m_id; + } else { + return m_conn_iter_stack [m_conn_iter_stack.size () - 2].first->id (); + } + } + + /** + * @brief Increment operator + */ + recursive_cluster_shape_iterator &operator++ (); + +private: + typedef typename db::connected_clusters::connections_type connections_type; + + const hier_clusters *mp_hc; + std::vector m_trans_stack; + std::vector m_cell_index_stack; + std::vector > m_conn_iter_stack; + typename db::local_cluster::shape_iterator m_shape_iter; + unsigned int m_layer; + typename db::local_cluster::id_type m_id; + + void next_conn (); + void up (); + void down (db::cell_index_type ci, typename db::local_cluster::id_type id, const db::ICplxTrans &t); +}; + /** * @brief A connection to a cluster from a parent cluster */ diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index d527e4b7d..90bc2701d 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -515,6 +515,10 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std const db::connected_clusters &clusters = hc.clusters_per_cell (*td); for (db::connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { + if (! clusters.is_root (*c)) { + continue; + } + net_layers.push_back (std::make_pair (0, ly.insert_layer ())); unsigned int lout = net_layers.back ().second; @@ -601,7 +605,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str lm[l1] = ly.insert_layer (db::LayerProperties (101, 0)); lm[l2] = ly.insert_layer (db::LayerProperties (102, 0)); lm[l3] = ly.insert_layer (db::LayerProperties (103, 0)); - hc.return_to_hierarchy (ly, ly.cell (*ly.begin_top_down ()), lm); + hc.return_to_hierarchy (ly, lm); CHECKPOINT(); db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file); diff --git a/testdata/algo/hc_test_au10.gds b/testdata/algo/hc_test_au10.gds index d7c92fb93..66499fd67 100644 Binary files a/testdata/algo/hc_test_au10.gds and b/testdata/algo/hc_test_au10.gds differ diff --git a/testdata/algo/hc_test_au11.gds b/testdata/algo/hc_test_au11.gds index 9552f7549..f24149b23 100644 Binary files a/testdata/algo/hc_test_au11.gds and b/testdata/algo/hc_test_au11.gds differ diff --git a/testdata/algo/hc_test_au2.gds b/testdata/algo/hc_test_au2.gds index 86ba92af2..73576e4f4 100644 Binary files a/testdata/algo/hc_test_au2.gds and b/testdata/algo/hc_test_au2.gds differ diff --git a/testdata/algo/hc_test_au3.gds b/testdata/algo/hc_test_au3.gds index c1998d1e4..54b1e4e95 100644 Binary files a/testdata/algo/hc_test_au3.gds and b/testdata/algo/hc_test_au3.gds differ diff --git a/testdata/algo/hc_test_au4.gds b/testdata/algo/hc_test_au4.gds index 57d1aa7c0..37e140f06 100644 Binary files a/testdata/algo/hc_test_au4.gds and b/testdata/algo/hc_test_au4.gds differ diff --git a/testdata/algo/hc_test_au5.gds b/testdata/algo/hc_test_au5.gds index 9ca93f454..8d3ea6b82 100644 Binary files a/testdata/algo/hc_test_au5.gds and b/testdata/algo/hc_test_au5.gds differ diff --git a/testdata/algo/hc_test_au6.gds b/testdata/algo/hc_test_au6.gds index 520e0bbfd..0828f1104 100644 Binary files a/testdata/algo/hc_test_au6.gds and b/testdata/algo/hc_test_au6.gds differ diff --git a/testdata/algo/hc_test_au7.gds b/testdata/algo/hc_test_au7.gds index d7e070c7d..bbaf147d6 100644 Binary files a/testdata/algo/hc_test_au7.gds and b/testdata/algo/hc_test_au7.gds differ diff --git a/testdata/algo/hc_test_au8.gds b/testdata/algo/hc_test_au8.gds index 4cd9a66a5..587bff467 100644 Binary files a/testdata/algo/hc_test_au8.gds and b/testdata/algo/hc_test_au8.gds differ diff --git a/testdata/algo/hc_test_au9.gds b/testdata/algo/hc_test_au9.gds index 16ac993e5..3bf9b01e0 100644 Binary files a/testdata/algo/hc_test_au9.gds and b/testdata/algo/hc_test_au9.gds differ