diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 82c1a89d7..6bad4c7fb 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -1241,7 +1241,148 @@ 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) +{ + 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); + } + + } +} + +template +void +hier_clusters::return_to_hierarchy (db::Layout &layout, db::Cell &cell, 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 ()); + } + } +} + // explicit instantiations template class DB_PUBLIC hier_clusters; +// ------------------------------------------------------------------------------ +// incoming_cluster_connections implementation + +template +incoming_cluster_connections::incoming_cluster_connections (const db::Layout &layout, const db::Cell &cell, const hier_clusters &hc) + : mp_layout (const_cast (&layout)), mp_hc (const_cast *> (&hc)) +{ + cell.collect_called_cells (m_called_cells); + m_called_cells.insert (cell.cell_index ()); +} + +template +bool +incoming_cluster_connections::has_incoming (db::cell_index_type ci, size_t cluster_id) const +{ + std::map >::const_iterator i = m_incoming.find (ci); + if (i == m_incoming.end ()) { + ensure_computed (ci); + i = m_incoming.find (ci); + tl_assert (i != m_incoming.end ()); + } + + tl_assert (i != m_incoming.end ()); + return (i->second.find (cluster_id) != i->second.end ()); +} + +template +const typename incoming_cluster_connections::incoming_connections & +incoming_cluster_connections::incoming (db::cell_index_type ci, size_t cluster_id) const +{ + std::map >::const_iterator i = m_incoming.find (ci); + if (i == m_incoming.end ()) { + ensure_computed (ci); + i = m_incoming.find (ci); + tl_assert (i != m_incoming.end ()); + } + + std::map::const_iterator ii = i->second.find (cluster_id); + if (ii != i->second.end ()) { + return ii->second; + } else { + static incoming_connections empty; + return empty; + } +} + +template +void +incoming_cluster_connections::ensure_computed (db::cell_index_type ci) const +{ + tl_assert (mp_layout.get () != 0); + m_incoming.insert (std::make_pair (ci, std::map ())); + + const db::Cell &cell = mp_layout->cell (ci); + for (db::Cell::parent_cell_iterator pc = cell.begin_parent_cells (); pc != cell.end_parent_cells (); ++pc) { + if (m_called_cells.find (*pc) != m_called_cells.end ()) { + ensure_computed_parent (*pc); + } + } + + m_called_cells.erase (ci); +} + +template +void +incoming_cluster_connections::ensure_computed_parent (db::cell_index_type ci) const +{ + ensure_computed (ci); + + const connected_clusters &cc = ((const hier_clusters *) mp_hc.get ())->clusters_per_cell (ci); + for (typename connected_clusters::connections_iterator x = cc.begin_connections (); x != cc.end_connections (); ++x) { + for (typename connected_clusters::connections_type::const_iterator xx = x->second.begin (); xx != x->second.end (); ++xx) { + m_incoming [xx->inst ().inst_ptr.cell_index ()][xx->id ()].push_back (IncomingClusterInstance (ci, x->first, xx->inst ())); + } + } +} + +// explicit instantiations +template class DB_PUBLIC incoming_cluster_connections; + } diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 108b185e1..e102a5d26 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -443,6 +443,7 @@ public: typedef std::list connections_type; typedef typename local_clusters::box_type box_type; typedef connected_clusters_iterator all_iterator; + typedef typename std::map::id_type, connections_type>::const_iterator connections_iterator; /** * @brief Constructor @@ -488,6 +489,24 @@ public: return connected_clusters_iterator (*this); } + /** + * @brief Begin iterator for the connections + * + * The iterated object is a pair or (cluster id, connections_type). + */ + connections_iterator begin_connections () const + { + return m_connections.begin (); + } + + /** + * @brief Begin iterator for the connections + */ + connections_iterator end_connections () const + { + return m_connections.end (); + } + private: template friend class connected_clusters_iterator; @@ -519,6 +538,7 @@ template class cell_clusters_box_converter; */ template class DB_PUBLIC hier_clusters + : public tl::Object { public: typedef typename local_cluster::box_type box_type; @@ -543,6 +563,18 @@ public: */ connected_clusters &clusters_per_cell (db::cell_index_type cell_index); + /** + * @brief Writes the net shapes back to the original hierarchy + * + * The layout object is supposed to be the original layout or one with identical cell indexes. + * "lm" is a layer mapping table from the connection layer indexes to the target layer + * indexes. + * + * 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; + /** * @brief Clears this collection */ @@ -557,6 +589,103 @@ private: std::map > m_per_cell_clusters; }; +/** + * @brief A connection to a cluster from a parent cluster + */ +class DB_PUBLIC IncomingClusterInstance +{ +public: + IncomingClusterInstance (db::cell_index_type pc, size_t parent_cluster_id, const db::InstElement &inst) + : m_parent_cell (pc), m_parent_cluster_id (parent_cluster_id), m_inst (inst) + { + // .. nothing yet .. + } + + IncomingClusterInstance () + : m_parent_cell (0), m_parent_cluster_id (0), m_inst () + { + // .. nothing yet .. + } + + /** + * @brief Gets the cell index of the parent cell + */ + size_t parent_cell () const + { + return m_parent_cell; + } + + /** + * @brief Gets the cluster ID from which the cluster is connected to + * The parent cluster lives in the parent cell + */ + size_t parent_cluster_id () const + { + return m_parent_cluster_id; + } + + /** + * @brief Gets the instance path + */ + const db::InstElement &inst () const + { + return m_inst; + } + + /** + * @brief Equality + */ + bool operator== (const IncomingClusterInstance &other) const + { + return m_parent_cluster_id == other.m_parent_cluster_id && m_parent_cell == other.m_parent_cell && m_inst == other.m_inst; + } + + /** + * @brief Less operator + */ + bool operator< (const IncomingClusterInstance &other) const + { + if (m_parent_cluster_id != other.m_parent_cluster_id) { + return m_parent_cluster_id < other.m_parent_cluster_id; + } + if (m_parent_cell != other.m_parent_cell) { + return m_parent_cell < other.m_parent_cell; + } + return m_inst < other.m_inst; + } + +private: + db::cell_index_type m_parent_cell; + size_t m_parent_cluster_id; + db::InstElement m_inst; +}; + +/** + * @brief A class holding the parent relationships for clusters of cells + * + * This class can be used to quickly identify the connections made to a specific cluster from a parent cluster. + */ +template +class incoming_cluster_connections +{ +public: + typedef std::list incoming_connections; + + incoming_cluster_connections (const db::Layout &layout, const db::Cell &cell, const hier_clusters &hc); + + bool has_incoming (db::cell_index_type ci, size_t cluster_id) const; + const incoming_connections &incoming (db::cell_index_type ci, size_t cluster_id) const; + +private: + mutable std::set m_called_cells; + mutable std::map > m_incoming; + tl::weak_ptr mp_layout; + tl::weak_ptr > mp_hc; + + void ensure_computed (db::cell_index_type ci) const; + void ensure_computed_parent (db::cell_index_type ci) const; +}; + } #endif diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index fab9c5d49..d527e4b7d 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -546,57 +546,129 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file); } +static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::string &file, const std::string &au_file) +{ + db::Layout ly; + unsigned int l1 = 0, l2 = 0, l3 = 0; + + { + db::LayerProperties p; + db::LayerMap lmap; + + p.layer = 1; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ()); + ly.set_properties (l1, p); + + p.layer = 2; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l2 = ly.insert_layer ()); + ly.set_properties (l2, p); + + p.layer = 3; + p.datatype = 0; + lmap.map (db::LDPair (p.layer, p.datatype), l3 = ly.insert_layer ()); + ly.set_properties (l3, p); + + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/"; + fn += file; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + normalize_layer (ly, l1); + normalize_layer (ly, l2); + normalize_layer (ly, l3); + + // connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3 + db::Connectivity conn; + conn.connect (l1, l1); + conn.connect (l2, l2); + conn.connect (l3, l3); + conn.connect (l1, l2); + conn.connect (l1, l3); + + db::hier_clusters hc; + hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn); + + std::map lm; + 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); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file); +} + TEST(41_HierClusters) { run_hc_test (_this, "hc_test_l1.gds", "hc_test_au1.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l1.gds", "hc_test_au1b.gds"); } TEST(42_HierClusters) { run_hc_test (_this, "hc_test_l2.gds", "hc_test_au2.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l2.gds", "hc_test_au2b.gds"); } TEST(43_HierClusters) { run_hc_test (_this, "hc_test_l3.gds", "hc_test_au3.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l3.gds", "hc_test_au3b.gds"); } TEST(44_HierClusters) { run_hc_test (_this, "hc_test_l4.gds", "hc_test_au4.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds"); } TEST(45_HierClusters) { run_hc_test (_this, "hc_test_l5.gds", "hc_test_au5.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l5.gds", "hc_test_au5b.gds"); } TEST(46_HierClusters) { run_hc_test (_this, "hc_test_l6.gds", "hc_test_au6.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l6.gds", "hc_test_au6b.gds"); } TEST(47_HierClusters) { run_hc_test (_this, "hc_test_l7.gds", "hc_test_au7.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l7.gds", "hc_test_au7b.gds"); } TEST(48_HierClusters) { run_hc_test (_this, "hc_test_l8.gds", "hc_test_au8.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l8.gds", "hc_test_au8b.gds"); } TEST(49_HierClusters) { run_hc_test (_this, "hc_test_l9.gds", "hc_test_au9.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l9.gds", "hc_test_au9b.gds"); } TEST(50_HierClusters) { run_hc_test (_this, "hc_test_l10.gds", "hc_test_au10.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l10.gds", "hc_test_au10b.gds"); } TEST(51_HierClusters) { run_hc_test (_this, "hc_test_l11.gds", "hc_test_au11.gds"); + run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds"); } diff --git a/testdata/algo/hc_test_au10b.gds b/testdata/algo/hc_test_au10b.gds new file mode 100644 index 000000000..56a41f98c Binary files /dev/null and b/testdata/algo/hc_test_au10b.gds differ diff --git a/testdata/algo/hc_test_au1b.gds b/testdata/algo/hc_test_au1b.gds new file mode 100644 index 000000000..e1f2615cf Binary files /dev/null and b/testdata/algo/hc_test_au1b.gds differ diff --git a/testdata/algo/hc_test_au2b.gds b/testdata/algo/hc_test_au2b.gds new file mode 100644 index 000000000..cd520f4de Binary files /dev/null and b/testdata/algo/hc_test_au2b.gds differ diff --git a/testdata/algo/hc_test_au3b.gds b/testdata/algo/hc_test_au3b.gds new file mode 100644 index 000000000..9767fc7a0 Binary files /dev/null and b/testdata/algo/hc_test_au3b.gds differ diff --git a/testdata/algo/hc_test_au4b.gds b/testdata/algo/hc_test_au4b.gds new file mode 100644 index 000000000..1855f963d Binary files /dev/null and b/testdata/algo/hc_test_au4b.gds differ diff --git a/testdata/algo/hc_test_au5b.gds b/testdata/algo/hc_test_au5b.gds new file mode 100644 index 000000000..b33c783ae Binary files /dev/null and b/testdata/algo/hc_test_au5b.gds differ diff --git a/testdata/algo/hc_test_au6b.gds b/testdata/algo/hc_test_au6b.gds new file mode 100644 index 000000000..903d59d5f Binary files /dev/null and b/testdata/algo/hc_test_au6b.gds differ diff --git a/testdata/algo/hc_test_au7b.gds b/testdata/algo/hc_test_au7b.gds new file mode 100644 index 000000000..457f97e87 Binary files /dev/null and b/testdata/algo/hc_test_au7b.gds differ diff --git a/testdata/algo/hc_test_au8b.gds b/testdata/algo/hc_test_au8b.gds new file mode 100644 index 000000000..816bb74d3 Binary files /dev/null and b/testdata/algo/hc_test_au8b.gds differ diff --git a/testdata/algo/hc_test_au9b.gds b/testdata/algo/hc_test_au9b.gds new file mode 100644 index 000000000..3e89d8674 Binary files /dev/null and b/testdata/algo/hc_test_au9b.gds differ