/* KLayout Layout Viewer Copyright (C) 2006-2016 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 "dbLayout.h" #include "dbCellGraphUtils.h" #include "dbCellMapping.h" #include "dbLayoutUtils.h" #include "tlLog.h" #include "tlTimer.h" #include #include #include #include namespace db { // ------------------------------------------------------------------------------------- // Some utility class: an iterator for cell instances delivered sorted by cell index struct SortedCellIndexIterator { typedef db::cell_index_type value_type; typedef size_t difference_type; typedef size_t pointer; typedef size_t reference; typedef std::random_access_iterator_tag iterator_category; SortedCellIndexIterator () : mp_cell (0), m_n (0) { // .. nothing yet .. } SortedCellIndexIterator (const db::Cell &cell, size_t n) : mp_cell (&cell), m_n (n) { // .. nothing yet .. } db::cell_index_type operator*() const { return mp_cell->sorted_inst_ptr (m_n).cell_index (); } size_t operator-(const SortedCellIndexIterator &d) const { return m_n - d.m_n; } SortedCellIndexIterator &operator++() { ++m_n; return *this; } SortedCellIndexIterator &operator+=(size_t n) { m_n += n; return *this; } bool operator==(const SortedCellIndexIterator &d) const { return m_n == d.m_n; } bool operator!=(const SortedCellIndexIterator &d) const { return m_n != d.m_n; } bool operator<(const SortedCellIndexIterator &d) const { return m_n < d.m_n; } db::Instance instance () const { return mp_cell->sorted_inst_ptr (m_n); } private: const db::Cell *mp_cell; size_t m_n; }; // ------------------------------------------------------------------------------------- // Some utility class: a compare function for a instance set of two cells in the context // of two layouts and two initial cells. class InstanceSetCompareFunction { public: typedef std::multiset > trans_set_t; InstanceSetCompareFunction (const db::Layout &layout_a, db::cell_index_type initial_cell_a, const db::Layout &layout_b, db::cell_index_type initial_cell_b) : m_layout_a (layout_a), m_initial_cell_a (initial_cell_a), m_layout_b (layout_b), m_initial_cell_b (initial_cell_b), m_cell_a (std::numeric_limits::max ()), m_repr_set (false) { // .. } bool compare (db::cell_index_type cell_a, const std::set &selection_cone_a, db::cell_index_type cell_b, const std::set &selection_cone_b) { if (cell_a != m_cell_a) { m_cell_a = cell_a; m_callers_a.clear (); m_layout_a.cell (cell_a).collect_caller_cells (m_callers_a, selection_cone_a, -1); m_callers_a.insert (cell_a); m_trans.clear (); insert (m_layout_a, m_initial_cell_a, m_cell_a, m_callers_a, m_trans, db::ICplxTrans ()); } std::set callers_b; m_layout_b.cell (cell_b).collect_caller_cells (callers_b, selection_cone_b, -1); callers_b.insert (cell_b); m_repr_set = false; std::map::const_iterator r = m_repr.find (cell_b); if (r != m_repr.end ()) { m_repr_set = true; if (m_trans.find (r->second) == m_trans.end ()) { return false; } } trans_set_t trans (m_trans); double mag = m_layout_b.dbu () / m_layout_a.dbu (); if (! compare (m_layout_b, m_initial_cell_b, cell_b, callers_b, trans, db::ICplxTrans (mag), db::ICplxTrans (1.0 / mag))) { return false; } return trans.empty (); } private: const db::Layout &m_layout_a; db::cell_index_type m_initial_cell_a; const db::Layout &m_layout_b; db::cell_index_type m_initial_cell_b; db::cell_index_type m_cell_a; std::set m_callers_a; trans_set_t m_trans; std::map m_repr; bool m_repr_set; void insert (const db::Layout &layout, db::cell_index_type current_cell, db::cell_index_type cell, const std::set &cone, trans_set_t &trans, const db::ICplxTrans ¤t_trans) { if (current_cell == cell) { trans.insert (current_trans); } else { const db::Cell &cc = layout.cell (current_cell); size_t instances = cc.cell_instances (); SortedCellIndexIterator begin (cc, 0); SortedCellIndexIterator end (cc, instances); SortedCellIndexIterator i = begin; for (std::set::const_iterator c = cone.begin (); c != cone.end () && i != end; ++c) { if (*i <= *c) { for (i = std::lower_bound (i, end, *c); i != end && *i == *c; ++i) { for (db::CellInstArray::iterator arr = i.instance ().begin (); ! arr.at_end (); ++arr) { insert (layout, *c, cell, cone, trans, current_trans * i.instance ().complex_trans (*arr)); } } } } } } bool compare (const db::Layout &layout, db::cell_index_type current_cell, db::cell_index_type cell, const std::set &cone, trans_set_t &trans, const db::ICplxTrans ¤t_trans, const db::ICplxTrans &local_trans) { if (current_cell == cell) { db::ICplxTrans eff_trans (current_trans * local_trans); if (! m_repr_set) { m_repr_set = true; m_repr.insert (std::make_pair (cell, eff_trans)); } trans_set_t::iterator t = trans.find (eff_trans); if (t == trans.end ()) { return false; } else { trans.erase (t); return true; } } else { const db::Cell &cc = layout.cell (current_cell); size_t instances = cc.cell_instances (); SortedCellIndexIterator begin (cc, 0); SortedCellIndexIterator end (cc, instances); SortedCellIndexIterator i = begin; for (std::set::const_iterator c = cone.begin (); c != cone.end () && i != end; ++c) { if (*i <= *c) { for (i = std::lower_bound (i, end, *c); i != end && *i == *c; ++i) { for (db::CellInstArray::iterator arr = i.instance ().begin (); ! arr.at_end (); ++arr) { if (! compare (layout, *c, cell, cone, trans, current_trans * i.instance ().complex_trans (*arr), local_trans)) { return false; } } } } } return true; } } }; // ------------------------------------------------------------------------------------- // CellMapping implementation CellMapping::CellMapping () { // .. nothing yet .. } void CellMapping::clear () { m_b2a_mapping.clear (); } void CellMapping::create_single_mapping (const db::Layout & /*layout_a*/, db::cell_index_type cell_index_a, const db::Layout & /*layout_b*/, db::cell_index_type cell_index_b) { clear (); map (cell_index_b, cell_index_a); } void CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b) { clear (); std::set called_b; layout_b.cell (cell_index_b).collect_called_cells (called_b); map (cell_index_b, cell_index_a); for (std::set::const_iterator b = called_b.begin (); b != called_b.end (); ++b) { std::pair ac = layout_a.cell_by_name (layout_b.cell_name (*b)); if (ac.first) { map (*b, ac.second); } } } std::vector CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b) { std::vector new_cells; std::vector new_cells_b; std::set called_b; layout_b.cell (cell_index_b).collect_called_cells (called_b); called_b.insert (cell_index_b); for (std::set::const_iterator b = called_b.begin (); b != called_b.end (); ++b) { if (m_b2a_mapping.find (*b) == m_b2a_mapping.end ()) { db::cell_index_type new_cell = layout_a.add_cell (layout_b.cell_name (*b)); new_cells.push_back (new_cell); new_cells_b.push_back (*b); map (*b, new_cell); } } if (! new_cells.empty ()) { db::PropertyMapper pm (layout_a, layout_b); // Note: this avoids frequent cell index table rebuilds if source and target layout are identical layout_a.start_changes (); // Create instances for the new cells in layout A according to their instantiation in layout B double mag = layout_b.dbu () / layout_a.dbu (); for (size_t i = 0; i < new_cells.size (); ++i) { const db::Cell &b = layout_b.cell (new_cells_b [i]); for (db::Cell::parent_inst_iterator pb = b.begin_parent_insts (); ! pb.at_end (); ++pb) { if (called_b.find (pb->parent_cell_index ()) != called_b.end ()) { db::Cell &pa = layout_a.cell (m_b2a_mapping [pb->parent_cell_index ()]); db::Instance bi = pb->child_inst (); db::CellInstArray bci = bi.cell_inst (); bci.object ().cell_index (new_cells [i]); bci.transform_into (db::ICplxTrans (mag)); if (bi.has_prop_id ()) { pa.insert (db::CellInstArrayWithProperties (bci, pm (bi.prop_id ()))); } else { pa.insert (bci); } } } } // Note: must be there because of start_changes layout_a.end_changes (); } return new_cells; } void CellMapping::create_from_geometry (const db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b) { tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Cell mapping"))); if (tl::verbosity () >= 20) { tl::info << "Cell mapping - first step: mapping instance count and instance identity"; } clear (); db::CellCounter cc_a (&layout_a, cell_index_a); db::CellCounter cc_b (&layout_b, cell_index_b); std::multimap cm_b; for (db::CellCounter::selection_iterator c = cc_b.begin (); c != cc_b.end (); ++c) { cm_b.insert (std::make_pair (*c == cell_index_b ? 0 : cc_b.weight (*c), *c)); } std::multimap cm_a; for (db::CellCounter::selection_iterator c = cc_a.begin (); c != cc_a.end (); ++c) { cm_a.insert (std::make_pair (*c == cell_index_a ? 0 : cc_a.weight (*c), *c)); } std::map > candidates; // key = index(a), value = indices(b) InstanceSetCompareFunction cmp (layout_a, cell_index_a, layout_b, cell_index_b); std::multimap::const_iterator a = cm_a.begin (), b = cm_b.begin (); while (a != cm_a.end () && b != cm_b.end ()) { size_t w = a->first; while (b != cm_b.end () && b->first < w) { ++b; } if (b == cm_b.end ()) { break; } else if (b->first > w) { candidates.insert (std::make_pair (a->second, std::vector ())); ++a; } else { if (tl::verbosity () >= 30) { size_t na = 0, nb = 0; for (std::multimap::const_iterator aa = a; aa != cm_a.end () && aa->first == w; ++aa) { ++na; } for (std::multimap::const_iterator bb = b; bb != cm_b.end () && bb->first == w; ++bb) { ++nb; } tl::info << "Multiplity group (" << w << " instances) - " << na << " vs. " << nb << " cells"; } unsigned int g = 0; std::map > b_group; std::map b_group_of_cell; while (a != cm_a.end () && a->first == w) { candidates.insert (std::make_pair (a->second, std::vector ())); std::set groups_taken; std::multimap::const_iterator bb = b; while (bb != cm_b.end () && bb->first == w) { std::map ::const_iterator bg = b_group_of_cell.find (bb->second); if (bg != b_group_of_cell.end ()) { if (groups_taken.find (bg->second) == groups_taken.end ()) { if (cmp.compare (a->second, cc_a.selection (), bb->second, cc_b.selection ())) { candidates [a->second] = b_group [bg->second]; groups_taken.insert (bg->second); } } } else { if (cmp.compare (a->second, cc_a.selection (), bb->second, cc_b.selection ())) { candidates [a->second].push_back (bb->second); b_group_of_cell.insert (std::make_pair (bb->second, g)); b_group.insert (std::make_pair (g, std::vector ())).first->second.push_back (bb->second); } } ++bb; } if (tl::verbosity () >= 40) { tl::info << "Checked cell " << layout_a.cell_name (a->second) << ": " << candidates [a->second].size () << " candidates remaining."; } ++a; ++g; } while (b != cm_b.end () && b->second == w) { ++b; } } } while (a != cm_a.end ()) { candidates.insert (std::make_pair (a->second, std::vector ())); ++a; } if (tl::verbosity () >= 40) { tl::info << "Mapping candidates:"; dump_mapping (candidates, layout_a, layout_b); } for (std::map >::const_iterator cand = candidates.begin (); cand != candidates.end (); ++cand) { extract_unique (cand, m_b2a_mapping, layout_a, layout_b); } int iteration = 0; bool reduction = true; while (reduction) { reduction = false; ++iteration; if (tl::verbosity () >= 20) { tl::info << "Cell mapping - iteration " << iteration << ": cross-instance cone reduction"; } // This map stores that layout_b cells with the corresponding layout_a cell for such cells which // have their mapping reduced to a unique one std::map > unique_candidates; std::vector refined_cand; for (std::map >::iterator cand = candidates.begin (); cand != candidates.end (); ++cand) { if (cand->second.size () > 1) { refined_cand.clear (); refined_cand.insert (refined_cand.end (), cand->second.begin (), cand->second.end ()); if (tl::verbosity () >= 50) { tl::info << "--- Cell: " << layout_a.cell_name (cand->first); tl::info << "Before reduction: " << tl::noendl; for (size_t i = 0; i < refined_cand.size (); ++i) { tl::info << " " << layout_b.cell_name(refined_cand[i]) << tl::noendl; } tl::info << ""; } std::set callers; layout_a.cell (cand->first).collect_caller_cells (callers, cc_a.selection (), -1); for (std::set::const_iterator c = callers.begin (); c != callers.end () && refined_cand.size () > 0; ++c) { if (*c != cell_index_a) { const std::vector &others = candidates.find (*c)->second; if (others.size () == 1) { std::set cross_cone_b; layout_b.cell (others.front ()).collect_called_cells (cross_cone_b); std::vector::iterator cout = refined_cand.begin (); for (std::vector::const_iterator cc = refined_cand.begin (); cc != refined_cand.end (); ++cc) { if (cross_cone_b.find (*cc) != cross_cone_b.end ()) { *cout++ = *cc; } } if (tl::verbosity () >= 50 && cout != refined_cand.end ()) { tl::info << "Reduction because of caller mapping: " << layout_a.cell_name (*c) << " <-> " << layout_b.cell_name (others[0]); tl::info << " -> " << tl::noendl; for (size_t i = 0; i < size_t (cout - refined_cand.begin ()); ++i) { tl::info << " " << layout_b.cell_name(refined_cand[i]) << tl::noendl; } tl::info << ""; } refined_cand.erase (cout, refined_cand.end ()); } } } if (refined_cand.size () > 0) { std::set called; layout_a.cell (cand->first).collect_called_cells (called); for (std::set::const_iterator c = called.begin (); c != called.end () && refined_cand.size () > 0; ++c) { const std::vector &others = candidates.find (*c)->second; if (others.size () == 1) { std::set cross_cone_b; layout_b.cell (others.front ()).collect_caller_cells (cross_cone_b, cc_b.selection (), -1); std::vector::iterator cout = refined_cand.begin (); for (std::vector::const_iterator cc = refined_cand.begin (); cc != refined_cand.end (); ++cc) { if (cross_cone_b.find (*cc) != cross_cone_b.end ()) { *cout++ = *cc; } } if (tl::verbosity () >= 50 && cout != refined_cand.end ()) { tl::info << "Reduction because of callee mapping: " << layout_a.cell_name (*c) << " <-> " << layout_b.cell_name (others[0]); tl::info << " -> " << tl::noendl; for (size_t i = 0; i < size_t (cout - refined_cand.begin ()); ++i) { tl::info << " " << layout_b.cell_name(refined_cand[i]) << tl::noendl; } tl::info << ""; } refined_cand.erase (cout, refined_cand.end ()); } } if (refined_cand.size () == 1) { // The remaining cell is a candidate for layout_b to layout_a mapping db::cell_index_type cb = refined_cand[0]; db::cell_index_type ca = cand->first; std::map >::iterator uc = unique_candidates.find (cb); if (uc != unique_candidates.end ()) { if (uc->second.first != ca) { int ed = tl::edit_distance (layout_a.cell_name (ca), layout_b.cell_name (cb)); if (ed < uc->second.second) { uc->second = std::make_pair (ca, ed); if (tl::verbosity () >= 40) { tl::info << "Choosing " << layout_b.cell_name (cb) << " (layout_b) as new unique mapping for " << layout_a.cell_name (ca) << " (layout_a)"; } } } } else { int ed = tl::edit_distance (layout_a.cell_name (ca), layout_b.cell_name (cb)); unique_candidates.insert (std::make_pair (cb, std::make_pair (ca, ed))); if (tl::verbosity () >= 40) { tl::info << "Choosing " << layout_b.cell_name (cb) << " (layout_b) as unique mapping for " << layout_a.cell_name (ca) << " (layout_a)"; } } } } } } // realize the proposed unique mapping for (std::map >::const_iterator uc = unique_candidates.begin (); uc != unique_candidates.end (); ++uc) { std::map >::iterator cand = candidates.find (uc->second.first); tl_assert (cand != candidates.end ()); cand->second.clear (); cand->second.push_back (uc->first); reduction = true; extract_unique (cand, m_b2a_mapping, layout_a, layout_b); } if (tl::verbosity () >= 40) { tl::info << "Further refined candidates:"; dump_mapping (candidates, layout_a, layout_b); } if (tl::verbosity () >= 20) { tl::info << "Cell mapping - iteration " << iteration << ": removal of uniquely mapped cells on B side"; } for (std::map >::iterator cand = candidates.begin (); cand != candidates.end (); ++cand) { if (cand->second.size () > 1) { std::vector refined_cand; for (std::vector::const_iterator c = cand->second.begin (); c != cand->second.end (); ++c) { std::map::const_iterator um = m_b2a_mapping.find (*c); if (um == m_b2a_mapping.end () || um->second == cand->first) { refined_cand.push_back (*c); } } if (refined_cand.size () < cand->second.size ()) { reduction = true; cand->second.swap (refined_cand); extract_unique (cand, m_b2a_mapping, layout_a, layout_b); } } } if (tl::verbosity () >= 40) { tl::info << "After reduction of mapped cells on b side:"; dump_mapping (candidates, layout_a, layout_b); } } if (tl::verbosity () >= 20) { int total = 0; int not_mapped = 0; int unique = 0; int non_unique = 0; int alternatives = 0; for (std::map >::iterator cand = candidates.begin (); cand != candidates.end (); ++cand) { ++total; if (cand->second.size () == 0) { ++not_mapped; } else if (cand->second.size () == 1) { ++unique; } else { ++non_unique; alternatives += (int) cand->second.size (); } } tl::info << "Geometry mapping statistics:"; tl::info << " Total cells = " << total; tl::info << " Not mapped = " << not_mapped; tl::info << " Unique = " << unique; tl::info << " Non unique = " << non_unique << " (total " << alternatives << " of alternatives)"; } // Resolve mapping according to string match if (tl::verbosity () >= 20) { tl::info << "Cell mapping - string mapping as last resort"; } for (std::map >::iterator cand = candidates.begin (); cand != candidates.end (); ++cand) { if (cand->second.size () > 1) { std::string cn_a (layout_a.cell_name (cand->first)); int min_ed = std::numeric_limits::max (); db::cell_index_type min_ed_ci; for (std::vector::const_iterator c = cand->second.begin (); c != cand->second.end (); ++c) { if (m_b2a_mapping.find (*c) == m_b2a_mapping.end ()) { int ed = tl::edit_distance (cn_a, layout_b.cell_name (*c)); if (ed < min_ed) { min_ed = ed; min_ed_ci = *c; } } } cand->second.clear (); if (min_ed < std::numeric_limits::max ()) { cand->second.push_back (min_ed_ci); extract_unique (cand, m_b2a_mapping, layout_a, layout_b); } } } if (tl::verbosity () >= 20) { int total = 0; int not_mapped = 0; int unique = 0; int non_unique = 0; int alternatives = 0; for (std::map >::iterator cand = candidates.begin (); cand != candidates.end (); ++cand) { ++total; if (cand->second.size () == 0) { if (tl::verbosity () >= 30) { tl::info << "Unmapped cell: " << layout_a.cell_name (cand->first); } ++not_mapped; } else if (cand->second.size () == 1) { ++unique; } else { ++non_unique; alternatives += (int) cand->second.size (); } } tl::info << "Final mapping statistics:"; tl::info << " Total cells = " << total; tl::info << " Not mapped = " << not_mapped; tl::info << " Unique = " << unique; tl::info << " Non unique = " << non_unique << " (total " << alternatives << " of alternatives)"; } } void CellMapping::extract_unique (std::map >::const_iterator cand, std::map &unique_mapping, const db::Layout &layout_a, const db::Layout &layout_b) { if (cand->second.size () == 1) { if (tl::verbosity () >= 20) { tl::info << " (U) " << layout_a.cell_name (cand->first) << " -> " << layout_b.cell_name (cand->second.front ()) << " (" << cand->first << " -> " << cand->second.front () << ")"; } unique_mapping.insert (std::make_pair (cand->second.front (), cand->first)); } else if (tl::verbosity () >= 30) { tl::info << " " << layout_a.cell_name (cand->first) << " ->" << tl::noendl; int n = 5; for (std::vector::const_iterator c = cand->second.begin (); c != cand->second.end () && --n > 0; ++c) { tl::info << " " << layout_b.cell_name (*c) << tl::noendl; } if (n == 0) { tl::info << " .."; } else { tl::info << ""; } } } void CellMapping::dump_mapping (const std::map > &candidates, const db::Layout &layout_a, const db::Layout &layout_b) { for (std::map >::const_iterator cand = candidates.begin (); cand != candidates.end (); ++cand) { tl::info << " " << layout_a.cell_name (cand->first) << " ->" << tl::noendl; int n = 5; for (std::vector::const_iterator c = cand->second.begin (); c != cand->second.end () && --n > 0; ++c) { tl::info << " " << layout_b.cell_name (*c) << tl::noendl; } if (n == 0) { tl::info << " .."; } else { tl::info << ""; } } } std::pair CellMapping::cell_mapping_pair (db::cell_index_type cell_index_b) const { std::map ::const_iterator m = m_b2a_mapping.find (cell_index_b); if (m == m_b2a_mapping.end ()) { return std::make_pair (false, 0); } else { return std::make_pair (true, m->second); } } bool CellMapping::has_mapping (db::cell_index_type cell_index_b) const { std::map ::const_iterator m = m_b2a_mapping.find (cell_index_b); return (m != m_b2a_mapping.end ()); } db::cell_index_type CellMapping::cell_mapping (db::cell_index_type cell_index_b) const { std::map ::const_iterator m = m_b2a_mapping.find (cell_index_b); tl_assert (m != m_b2a_mapping.end ()); return m->second; } }