diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 2fe29c4ec..8377e3c52 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -879,6 +879,13 @@ local_clusters::insert () return i.operator-> (); } +template +void +local_clusters::make_soft_connection (typename local_cluster::id_type a, typename local_cluster::id_type b) +{ + // @@@ TODO: implement +} + template void local_clusters::ensure_sorted () @@ -942,6 +949,8 @@ struct cluster_building_receiver void generate_clusters (local_clusters &clusters) { + std::map *> in_to_out; + // build the resulting clusters for (typename std::list::const_iterator c = m_clusters.begin (); c != m_clusters.end (); ++c) { @@ -952,6 +961,8 @@ struct cluster_building_receiver cluster->add_attr (s->second.second); } + in_to_out.insert (std::make_pair (c.operator-> (), cluster)); + std::set global_nets = c->second; // Add the global nets we derive from the attribute equivalence (join_nets of labelled vs. @@ -980,6 +991,20 @@ struct cluster_building_receiver cluster->set_global_nets (global_nets); } + + for (auto sc = m_soft_connections.begin (); sc != m_soft_connections.end (); ++sc) { + + if (sc->second >= 0) { + continue; + } + + auto c1 = in_to_out.find (sc->first.first); + auto c2 = in_to_out.find (sc->first.second); + tl_assert (c1 != in_to_out.end () && c2 != in_to_out.end ()); + + clusters.make_soft_connection (c1->second->id (), c2->second->id ()); + + } } void add (const T *s1, std::pair p1, const T *s2, std::pair p2) @@ -1153,6 +1178,7 @@ private: std::map::iterator> m_shape_to_clusters; std::map::iterator> m_global_to_clusters; std::list m_clusters; + std::map, int> m_soft_connections; std::map > m_global_nets_by_attribute_cluster; const tl::equivalence_clusters *mp_attr_equivalence; bool m_separate_attributes; @@ -1170,13 +1196,35 @@ private: } m_clusters.erase (ic2); + + auto i1 = m_soft_connections.find (std::make_pair (ic1.operator-> (), ic2.operator-> ())); + if (i1 != m_soft_connections.end ()) { + i1->second = 0; + } + + auto i2 = m_soft_connections.find (std::make_pair (ic2.operator-> (), ic1.operator-> ())); + if (i2 != m_soft_connections.end ()) { + i2->second = 0; + } } void register_soft_connection (typename std::list::iterator ic1, typename std::list::iterator ic2, int soft) { + auto i1 = m_soft_connections.find (std::make_pair (ic1.operator-> (), ic2.operator-> ())); + auto i2 = m_soft_connections.find (std::make_pair (ic2.operator-> (), ic1.operator-> ())); - // @@@ TODO: implement + if (i1 != m_soft_connections.end () && i1->second != 0 && i1->second != soft) { + i1->second = 0; + } + if (i2 != m_soft_connections.end () && i2->second != 0 && i2->second != -soft) { + i2->second = 0; + } + if (i1 == m_soft_connections.end ()) { + tl_assert (i2 == m_soft_connections.end ()); + m_soft_connections.insert (std::make_pair (std::make_pair (ic1.operator-> (), ic2.operator-> ()), soft)); + m_soft_connections.insert (std::make_pair (std::make_pair (ic2.operator-> (), ic1.operator-> ()), -soft)); + } } }; @@ -1269,6 +1317,7 @@ void local_clusters::apply_attr_equivalences (const tl::equivalence_clusters &attr_equivalence) { // identify the layout clusters joined into one attribute cluster and join them + // NOTE: soft connections are not supported here, but that is a deprecated mechanism anyway. std::map::cluster_id_type, std::set > c2c; @@ -1533,17 +1582,18 @@ public: struct ClusterInstanceInteraction { - ClusterInstanceInteraction (size_t _cluster_id, const ClusterInstance &_other_ci) - : cluster_id (_cluster_id), other_ci (_other_ci) + ClusterInstanceInteraction (size_t _cluster_id, const ClusterInstance &_other_ci, int _soft) + : cluster_id (_cluster_id), other_ci (_other_ci), soft (_soft) { } bool operator== (const ClusterInstanceInteraction &other) const { - return cluster_id == other.cluster_id && other_ci == other.other_ci; + return cluster_id == other.cluster_id && other_ci == other.other_ci && soft == other.soft; } size_t cluster_id; ClusterInstance other_ci; + int soft; }; /** @@ -1597,7 +1647,7 @@ public: { db::ICplxTrans t; - std::list > ic; + std::list ic; consider_instance_pair (box_type::world (), *i1, t, db::CellInstArray::iterator (), *i2, t, db::CellInstArray::iterator (), ic); connect_clusters (ic); @@ -1634,21 +1684,35 @@ public: void finish_cluster_to_instance_interactions () { for (typename std::list::const_iterator ii = m_ci_interactions.begin (); ii != m_ci_interactions.end (); ++ii) { - mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, ii->other_ci, mp_cell->cell_index (), false); + + // NOTE: soft connections make a dummy cluster at the level of our instance. This allows registering a soft connection to it. + mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, ii->other_ci, mp_cell->cell_index (), ii->soft != 0 ? true /*with self*/ : false /*without self*/); + } for (typename std::list::const_iterator ii = m_ci_interactions.begin (); ii != m_ci_interactions.end (); ++ii) { - id_type other = mp_cell_clusters->find_cluster_with_connection (ii->other_ci); - if (other > 0) { + if (ii->soft != 0) { - // we found a child cluster that connects two clusters on our own level: - // we must join them into one, but not now. We're still iterating and - // would invalidate the box trees. So keep this now and combine the clusters later. - mark_to_join (other, ii->cluster_id); + id_type other = mp_cell_clusters->find_cluster_with_connection (ii->other_ci); + tl_assert (other > 0); // because we used "with self" in "propagate_cluster_inst" + + register_soft_connection (ii->cluster_id, other, ii->soft); } else { - mp_cell_clusters->add_connection (ii->cluster_id, ii->other_ci); + + id_type other = mp_cell_clusters->find_cluster_with_connection (ii->other_ci); + if (other > 0) { + + // we found a child cluster that connects two clusters on our own level: + // we must join them into one, but not now. We're still iterating and + // would invalidate the box trees. So keep this now and combine the clusters later. + mark_to_join (other, ii->cluster_id); + + } else { + mp_cell_clusters->add_connection (ii->cluster_id, ii->other_ci); + } + } } @@ -1664,6 +1728,22 @@ public: typename std::set::const_iterator cc = c; for (++cc; cc != sc->end (); ++cc) { mp_cell_clusters->join_cluster_with (*c, *cc); + m_soft_connections.erase (std::make_pair (*c < *cc ? *c : *cc, *c < *cc ? *cc : *c)); + } + + } + + for (auto sc = m_soft_connections.begin (); sc != m_soft_connections.end (); ++sc) { + + if (sc->second == 0) { + // dropped soft connection + continue; + } + + if (sc->second > 0) { + mp_cell_clusters->make_soft_connection (sc->first.second, sc->first.first); + } else { + mp_cell_clusters->make_soft_connection (sc->first.first, sc->first.second); } } @@ -1685,8 +1765,9 @@ private: typedef std::list > join_set_list; std::map m_cm2join_map; join_set_list m_cm2join_sets; + std::map, int> m_soft_connections; std::list m_ci_interactions; - instance_interaction_cache, std::list > > m_interaction_cache_for_clusters; + instance_interaction_cache, std::list > m_interaction_cache_for_clusters; size_t m_cluster_cache_misses, m_cluster_cache_hits; typename hier_clusters::instance_interaction_cache_type *mp_instance_interaction_cache; bool m_separate_attributes; @@ -1762,10 +1843,10 @@ private: interacting_clusters = *cached; for (cluster_instance_pair_list_type::iterator i = interacting_clusters.begin (); i != interacting_clusters.end (); ++i) { // translate the property IDs - i->first.set_inst_prop_id (i1.prop_id ()); - i->first.transform (i1t); - i->second.set_inst_prop_id (i2.prop_id ()); - i->second.transform (i2t); + i->a.set_inst_prop_id (i1.prop_id ()); + i->a.transform (i1t); + i->b.set_inst_prop_id (i2.prop_id ()); + i->b.transform (i2t); } return; @@ -1832,23 +1913,23 @@ private: box_type common12 = ib1 & ib2 & common; if (! common12.empty ()) { - const std::list > &i2i_interactions = compute_instance_interactions (common12, i1.cell_index (), tt1, i2.cell_index (), tt2); + const std::list &i2i_interactions = compute_instance_interactions (common12, i1.cell_index (), tt1, i2.cell_index (), tt2); - for (std::list >::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { - ClusterInstance k1 (ii->first, i1.cell_index (), i1t, i1.prop_id ()); - ClusterInstance k2 (ii->second, i2.cell_index (), i2t, i2.prop_id ()); - interacting_clusters.push_back (std::make_pair (k1, k2)); + for (std::list::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { + ClusterInstance k1 (ii->a, i1.cell_index (), i1t, i1.prop_id ()); + ClusterInstance k2 (ii->b, i2.cell_index (), i2t, i2.prop_id ()); + interacting_clusters.push_back (ClusterInstancePair (k1, k2, ii->soft)); } // dive into cell of ii2 const db::Cell &cell2 = mp_layout->cell (i2.cell_index ()); for (db::Cell::touching_iterator jj2 = cell2.begin_touching (common12.transformed (tt2.inverted ())); ! jj2.at_end (); ++jj2) { - std::list > ii_interactions; + std::list ii_interactions; consider_instance_pair (common12, i1, t1, ii1, *jj2, tt2, db::CellInstArray::iterator (), ii_interactions); - for (std::list >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { - propagate_cluster_inst (i->second, i2.cell_index (), i2t, i2.prop_id ()); + for (std::list::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { + propagate_cluster_inst (i->b, i2.cell_index (), i2t, i2.prop_id ()); } ii_interactions.unique (); @@ -1860,11 +1941,11 @@ private: const db::Cell &cell1 = mp_layout->cell (i1.cell_index ()); for (db::Cell::touching_iterator jj1 = cell1.begin_touching (common12.transformed (tt1.inverted ())); ! jj1.at_end (); ++jj1) { - std::list > ii_interactions; + std::list ii_interactions; consider_instance_pair (common12, *jj1, tt1, db::CellInstArray::iterator (), i2, t2, ii2, ii_interactions); - for (std::list >::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { - propagate_cluster_inst (i->first, i1.cell_index (), i1t, i1.prop_id ()); + for (std::list::iterator i = ii_interactions.begin (); i != ii_interactions.end (); ++i) { + propagate_cluster_inst (i->a, i1.cell_index (), i1t, i1.prop_id ()); } ii_interactions.unique (); @@ -1889,7 +1970,7 @@ private: // remove duplicates (after doing a quick unique before) // NOTE: duplicates may happen due to manifold child/child interactions which boil down to // identical parent cluster interactions. - std::vector > sorted_interactions; + std::vector sorted_interactions; sorted_interactions.reserve (interacting_clusters.size ()); sorted_interactions.insert (sorted_interactions.end (), interacting_clusters.begin (), interacting_clusters.end ()); interacting_clusters.clear (); @@ -1903,9 +1984,9 @@ private: // normalize transformations for cache db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted (); - for (std::vector >::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) { - i->first.transform (i1ti); - i->second.transform (i2ti); + for (std::vector::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) { + i->a.transform (i1ti); + i->b.transform (i2ti); } cluster_instance_pair_list_type &cached = mp_instance_interaction_cache->insert (i1.cell_index (), i2.cell_index (), ii_key); @@ -1917,13 +1998,13 @@ private: /** * @brief Computes a list of interacting clusters for two instances */ - const std::list > & + const std::list & compute_instance_interactions (const box_type &common, db::cell_index_type ci1, const db::ICplxTrans &t1, db::cell_index_type ci2, const db::ICplxTrans &t2) { if (is_breakout_cell (mp_breakout_cells, ci1) || is_breakout_cell (mp_breakout_cells, ci2)) { - static const std::list > empty; + static const std::list empty; return empty; } @@ -1935,7 +2016,7 @@ private: interaction_key_for_clusters ikey (t1i, t21, common2); - const std::list > *ici = m_interaction_cache_for_clusters.find (ci1, ci2, ikey); + const std::list *ici = m_interaction_cache_for_clusters.find (ci1, ci2, ikey); if (ici) { return *ici; @@ -1947,7 +2028,7 @@ private: const db::local_clusters &cl1 = mp_tree->clusters_per_cell (ci1); const db::local_clusters &cl2 = mp_tree->clusters_per_cell (ci2); - std::list > &new_interactions = m_interaction_cache_for_clusters.insert (ci1, ci2, ikey); + std::list &new_interactions = m_interaction_cache_for_clusters.insert (ci1, ci2, ikey); db::ICplxTrans t12 = t2i * t1; for (typename db::local_clusters::touching_iterator i = cl1.begin_touching (common2.transformed (t21)); ! i.at_end (); ++i) { @@ -1962,8 +2043,7 @@ private: int soft = 0; if ((! m_separate_attributes || i->same_attrs (*j)) && i->interacts (*j, t21, *mp_conn, soft)) { - // @@@ soft mode? - new_interactions.push_back (std::make_pair (i->id (), j->id ())); + new_interactions.push_back (ClusterIDPair (i->id (), j->id (), soft)); } } @@ -2015,22 +2095,22 @@ private: cluster_instance_pair_list_type interacting_clusters; box_type common = (ib & ib2); - const std::list > &i2i_interactions = compute_instance_interactions (common, i.cell_index (), tt, i.cell_index (), tt2); - for (std::list >::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { - ClusterInstance k1 (ii->first, i.cell_index (), tt, i.prop_id ()); - ClusterInstance k2 (ii->second, i.cell_index (), tt2, i.prop_id ()); - interacting_clusters.push_back (std::make_pair (k1, k2)); + const std::list &i2i_interactions = compute_instance_interactions (common, i.cell_index (), tt, i.cell_index (), tt2); + for (std::list::const_iterator ii = i2i_interactions.begin (); ii != i2i_interactions.end (); ++ii) { + ClusterInstance k1 (ii->a, i.cell_index (), tt, i.prop_id ()); + ClusterInstance k2 (ii->b, i.cell_index (), tt2, i.prop_id ()); + interacting_clusters.push_back (ClusterInstancePair (k1, k2, ii->soft)); } for (db::Cell::touching_iterator jj2 = cell.begin_touching (common.transformed (tt2.inverted ())); ! jj2.at_end (); ++jj2) { db::ICplxTrans t; - std::list > ii_interactions; + std::list ii_interactions; consider_instance_pair (common, i, t, ii, *jj2, tt2, db::CellInstArray::iterator (), ii_interactions); - for (std::list >::iterator ii = ii_interactions.begin (); ii != ii_interactions.end (); ++ii) { - propagate_cluster_inst (ii->second, i.cell_index (), tt2, i.prop_id ()); + for (std::list::iterator ii = ii_interactions.begin (); ii != ii_interactions.end (); ++ii) { + propagate_cluster_inst (ii->b, i.cell_index (), tt2, i.prop_id ()); } interacting_clusters.splice (interacting_clusters.end (), ii_interactions, ii_interactions.begin (), ii_interactions.end ()); @@ -2051,6 +2131,7 @@ private: } } + } /** @@ -2077,7 +2158,7 @@ private: return; } - std::vector > c2i_interactions; + std::vector c2i_interactions; for (db::CellInstArray::iterator ii2 = i2.begin_touching ((b1 & b2).transformed (t2.inverted ()), mp_layout); ! ii2.at_end (); ++ii2) { @@ -2090,9 +2171,9 @@ private: c2i_interactions.clear (); compute_cluster_instance_interactions (c1, i2.cell_index (), tt2, c2i_interactions); - for (std::vector >::const_iterator ii = c2i_interactions.begin (); ii != c2i_interactions.end (); ++ii) { - ClusterInstance k (ii->second, i2.cell_index (), i2t, i2.prop_id ()); - interactions_out.push_back (ClusterInstanceInteraction (ii->first, k)); + for (std::vector::const_iterator ii = c2i_interactions.begin (); ii != c2i_interactions.end (); ++ii) { + ClusterInstance k (ii->b, i2.cell_index (), i2t, i2.prop_id ()); + interactions_out.push_back (ClusterInstanceInteraction (ii->a, k, ii->soft)); } // dive into cell of ii2 @@ -2124,7 +2205,7 @@ private: void compute_cluster_instance_interactions (const local_cluster &c1, db::cell_index_type ci2, const db::ICplxTrans &t2, - std::vector > &interactions) + std::vector &interactions) { if (is_breakout_cell (mp_breakout_cells, ci2)) { return; @@ -2136,11 +2217,7 @@ private: int soft = 0; if ((! m_separate_attributes || c1.same_attrs (*j)) && c1.interacts (*j, t2, *mp_conn, soft)) { - if (soft != 0) { - // @@@ TODO: soft mode - } else { - interactions.push_back (std::make_pair (c1.id (), j->id ())); - } + interactions.push_back (ClusterIDPair (c1.id (), j->id (), soft)); } } @@ -2243,8 +2320,8 @@ private: { for (cluster_instance_pair_list_type::const_iterator ic = interacting_clusters.begin (); ic != interacting_clusters.end (); ++ic) { - const ClusterInstance &k1 = ic->first; - const ClusterInstance &k2 = ic->second; + const ClusterInstance &k1 = ic->a; + const ClusterInstance &k2 = ic->b; // Note: "with_self" is false as we're going to create a connected cluster anyway id_type x1 = mp_tree->propagate_cluster_inst (*mp_layout, *mp_cell, k1, mp_cell->cell_index (), false); @@ -2254,34 +2331,102 @@ private: if (x2 == 0) { - id_type connector = mp_cell_clusters->insert_dummy (); - mp_cell_clusters->add_connection (connector, k1); - mp_cell_clusters->add_connection (connector, k2); + if (ic->soft != 0) { + + id_type ca = mp_cell_clusters->insert_dummy (); + id_type cb = mp_cell_clusters->insert_dummy (); + mp_cell_clusters->add_connection (ca, k1); + mp_cell_clusters->add_connection (cb, k2); + + register_soft_connection (ca, cb, ic->soft); + + } else { + + id_type connector = mp_cell_clusters->insert_dummy (); + mp_cell_clusters->add_connection (connector, k1); + mp_cell_clusters->add_connection (connector, k2); + + } } else { - mp_cell_clusters->add_connection (x2, k1); + + if (ic->soft != 0) { + + id_type ca = mp_cell_clusters->insert_dummy (); + mp_cell_clusters->add_connection (ca, k1); + + register_soft_connection (ca, x2, ic->soft); + + } else { + + mp_cell_clusters->add_connection (x2, k1); + + } } } else if (x2 == 0) { - mp_cell_clusters->add_connection (x1, k2); + if (ic->soft != 0) { + + id_type cb = mp_cell_clusters->insert_dummy (); + mp_cell_clusters->add_connection (cb, k2); + + register_soft_connection (x1, cb, ic->soft); + + } else { + + mp_cell_clusters->add_connection (x1, k2); + + } } else if (x1 != x2) { + int soft = ic->soft; + // for instance-to-instance interactions the number of connections is more important for the // cost of the join operation: make the one with more connections the target // TODO: this will be SLOW for STL's not providing a fast size() if (mp_cell_clusters->connections_for_cluster (x1).size () < mp_cell_clusters->connections_for_cluster (x2).size ()) { std::swap (x1, x2); + soft = -soft; } - mp_cell_clusters->join_cluster_with (x1, x2); - mp_cell_clusters->remove_cluster (x2); + if (soft != 0) { + + register_soft_connection (x1, x2, soft); + + } else { + + mp_cell_clusters->join_cluster_with (x1, x2); + mp_cell_clusters->remove_cluster (x2); + + } } } } + + /** + * @brief Registers a soft connection for clusters a and b + */ + void register_soft_connection (id_type a, id_type b, int soft) + { + std::pair key (a < b ? a : b, a < b ? b : a); + if (!(a < b)) { + soft = -soft; + } + + auto sc = m_soft_connections.find (key); + if (sc != m_soft_connections.end ()) { + if (sc->second != 0 && sc->second != soft) { + sc->second = 0; // turn into hard connection + mark_to_join (a, b); + } + } else { + m_soft_connections [key] = soft; + } + } }; template diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index e0c51fd53..62b060644 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -622,6 +622,11 @@ public: return id > m_clusters.size (); } + /** + * @brief Makes a soft connection between clusters a and b (a: upper, b: lower) + */ + void make_soft_connection (typename local_cluster::id_type a, typename local_cluster::id_type b); + /** * @brief Gets the number of clusters */ @@ -844,7 +849,61 @@ private: size_t m_id; }; -typedef std::list > cluster_instance_pair_list_type; +struct ClusterInstancePair +{ + ClusterInstancePair (const ClusterInstance &_a, const ClusterInstance &_b, int _soft) + : a (_a), b (_b), soft (_soft) + { } + + bool operator== (const ClusterInstancePair &other) const + { + return a == other.a && b == other.b && soft == other.soft; + } + + bool operator< (const ClusterInstancePair &other) const + { + if (!(a == other.a)) { + return a < other.a; + } + if (!(b == other.b)) { + return b < other.b; + } + return soft < other.soft; + } + + ClusterInstance a, b; + int soft; +}; + +typedef std::list cluster_instance_pair_list_type; + +struct ClusterIDPair +{ + typedef size_t id_type; + + ClusterIDPair (id_type _a, id_type _b, int _soft) + : a (_a), b (_b), soft (_soft) + { } + + bool operator== (const ClusterIDPair &other) const + { + return a == other.a && b == other.b && soft == other.soft; + } + + bool operator< (const ClusterIDPair &other) const + { + if (!(a == other.a)) { + return a < other.a; + } + if (!(b == other.b)) { + return b < other.b; + } + return soft < other.soft; + } + + id_type a, b; + int soft; +}; inline bool equal_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b) { @@ -1156,7 +1215,7 @@ public: * The "with_id" cluster is removed. All connections of "with_id" are transferred to the * first one. All shapes of "with_id" are transferred to "id". */ - void join_cluster_with(typename local_cluster::id_type id, typename local_cluster::id_type with_id); + void join_cluster_with (typename local_cluster::id_type id, typename local_cluster::id_type with_id); /** * @brief An iterator delivering all clusters (even the connectors)