mirror of https://github.com/KLayout/klayout.git
832 lines
27 KiB
C++
832 lines
27 KiB
C++
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
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 <memory>
|
||
|
|
#include <map>
|
||
|
|
#include <set>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
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<db::ICplxTrans, db::trans_less_func<db::ICplxTrans> > 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<db::cell_index_type>::max ()),
|
||
|
|
m_repr_set (false)
|
||
|
|
{
|
||
|
|
// ..
|
||
|
|
}
|
||
|
|
|
||
|
|
bool compare (db::cell_index_type cell_a, const std::set<db::cell_index_type> &selection_cone_a, db::cell_index_type cell_b, const std::set<db::cell_index_type> &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<db::cell_index_type> 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<db::cell_index_type, db::ICplxTrans>::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<db::cell_index_type> m_callers_a;
|
||
|
|
trans_set_t m_trans;
|
||
|
|
std::map<db::cell_index_type, db::ICplxTrans> 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<db::cell_index_type> &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<db::cell_index_type>::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<db::cell_index_type> &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<db::cell_index_type>::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<db::cell_index_type> called_b;
|
||
|
|
layout_b.cell (cell_index_b).collect_called_cells (called_b);
|
||
|
|
|
||
|
|
map (cell_index_b, cell_index_a);
|
||
|
|
|
||
|
|
for (std::set<db::cell_index_type>::const_iterator b = called_b.begin (); b != called_b.end (); ++b) {
|
||
|
|
std::pair<bool, db::cell_index_type> ac = layout_a.cell_by_name (layout_b.cell_name (*b));
|
||
|
|
if (ac.first) {
|
||
|
|
map (*b, ac.second);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<db::cell_index_type>
|
||
|
|
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<db::cell_index_type> new_cells;
|
||
|
|
std::vector<db::cell_index_type> new_cells_b;
|
||
|
|
|
||
|
|
std::set<db::cell_index_type> called_b;
|
||
|
|
layout_b.cell (cell_index_b).collect_called_cells (called_b);
|
||
|
|
called_b.insert (cell_index_b);
|
||
|
|
|
||
|
|
for (std::set<db::cell_index_type>::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<size_t, db::cell_index_type> 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<size_t, db::cell_index_type> 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 <db::cell_index_type, std::vector<db::cell_index_type> > candidates; // key = index(a), value = indices(b)
|
||
|
|
|
||
|
|
InstanceSetCompareFunction cmp (layout_a, cell_index_a, layout_b, cell_index_b);
|
||
|
|
|
||
|
|
std::multimap<size_t, db::cell_index_type>::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<db::cell_index_type> ()));
|
||
|
|
++a;
|
||
|
|
} else {
|
||
|
|
|
||
|
|
if (tl::verbosity () >= 30) {
|
||
|
|
size_t na = 0, nb = 0;
|
||
|
|
for (std::multimap<size_t, db::cell_index_type>::const_iterator aa = a; aa != cm_a.end () && aa->first == w; ++aa) {
|
||
|
|
++na;
|
||
|
|
}
|
||
|
|
for (std::multimap<size_t, db::cell_index_type>::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 <unsigned int, std::vector <db::cell_index_type> > b_group;
|
||
|
|
std::map <db::cell_index_type, unsigned int> b_group_of_cell;
|
||
|
|
|
||
|
|
while (a != cm_a.end () && a->first == w) {
|
||
|
|
|
||
|
|
candidates.insert (std::make_pair (a->second, std::vector <db::cell_index_type> ()));
|
||
|
|
|
||
|
|
std::set <unsigned int> groups_taken;
|
||
|
|
|
||
|
|
std::multimap<size_t, db::cell_index_type>::const_iterator bb = b;
|
||
|
|
while (bb != cm_b.end () && bb->first == w) {
|
||
|
|
|
||
|
|
std::map <db::cell_index_type, unsigned int>::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 <db::cell_index_type> ())).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<db::cell_index_type> ()));
|
||
|
|
++a;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (tl::verbosity () >= 40) {
|
||
|
|
tl::info << "Mapping candidates:";
|
||
|
|
dump_mapping (candidates, layout_a, layout_b);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (std::map <db::cell_index_type, std::vector<db::cell_index_type> >::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 <db::cell_index_type, std::pair<db::cell_index_type, int> > unique_candidates;
|
||
|
|
|
||
|
|
std::vector<db::cell_index_type> refined_cand;
|
||
|
|
|
||
|
|
for (std::map <db::cell_index_type, std::vector<db::cell_index_type> >::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<db::cell_index_type> callers;
|
||
|
|
layout_a.cell (cand->first).collect_caller_cells (callers, cc_a.selection (), -1);
|
||
|
|
|
||
|
|
for (std::set<db::cell_index_type>::const_iterator c = callers.begin (); c != callers.end () && refined_cand.size () > 0; ++c) {
|
||
|
|
|
||
|
|
if (*c != cell_index_a) {
|
||
|
|
|
||
|
|
const std::vector<db::cell_index_type> &others = candidates.find (*c)->second;
|
||
|
|
if (others.size () == 1) {
|
||
|
|
|
||
|
|
std::set<db::cell_index_type> cross_cone_b;
|
||
|
|
layout_b.cell (others.front ()).collect_called_cells (cross_cone_b);
|
||
|
|
|
||
|
|
std::vector<db::cell_index_type>::iterator cout = refined_cand.begin ();
|
||
|
|
for (std::vector<db::cell_index_type>::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<db::cell_index_type> called;
|
||
|
|
layout_a.cell (cand->first).collect_called_cells (called);
|
||
|
|
|
||
|
|
for (std::set<db::cell_index_type>::const_iterator c = called.begin (); c != called.end () && refined_cand.size () > 0; ++c) {
|
||
|
|
|
||
|
|
const std::vector<db::cell_index_type> &others = candidates.find (*c)->second;
|
||
|
|
if (others.size () == 1) {
|
||
|
|
|
||
|
|
std::set<db::cell_index_type> cross_cone_b;
|
||
|
|
layout_b.cell (others.front ()).collect_caller_cells (cross_cone_b, cc_b.selection (), -1);
|
||
|
|
|
||
|
|
std::vector<db::cell_index_type>::iterator cout = refined_cand.begin ();
|
||
|
|
for (std::vector<db::cell_index_type>::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 <db::cell_index_type, std::pair<db::cell_index_type, int> >::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 <db::cell_index_type, std::pair<db::cell_index_type, int> >::const_iterator uc = unique_candidates.begin (); uc != unique_candidates.end (); ++uc) {
|
||
|
|
|
||
|
|
std::map <db::cell_index_type, std::vector<db::cell_index_type> >::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 <db::cell_index_type, std::vector<db::cell_index_type> >::iterator cand = candidates.begin (); cand != candidates.end (); ++cand) {
|
||
|
|
|
||
|
|
if (cand->second.size () > 1) {
|
||
|
|
|
||
|
|
std::vector<db::cell_index_type> refined_cand;
|
||
|
|
for (std::vector<db::cell_index_type>::const_iterator c = cand->second.begin (); c != cand->second.end (); ++c) {
|
||
|
|
std::map<db::cell_index_type, db::cell_index_type>::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 <db::cell_index_type, std::vector<db::cell_index_type> >::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 <db::cell_index_type, std::vector<db::cell_index_type> >::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<int>::max ();
|
||
|
|
db::cell_index_type min_ed_ci;
|
||
|
|
|
||
|
|
for (std::vector<db::cell_index_type>::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<int>::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 <db::cell_index_type, std::vector<db::cell_index_type> >::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 <db::cell_index_type, std::vector<db::cell_index_type> >::const_iterator cand,
|
||
|
|
std::map<db::cell_index_type, db::cell_index_type> &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<db::cell_index_type>::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 <db::cell_index_type, std::vector<db::cell_index_type> > &candidates,
|
||
|
|
const db::Layout &layout_a, const db::Layout &layout_b)
|
||
|
|
{
|
||
|
|
for (std::map <db::cell_index_type, std::vector<db::cell_index_type> >::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<db::cell_index_type>::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<bool, db::cell_index_type>
|
||
|
|
CellMapping::cell_mapping_pair (db::cell_index_type cell_index_b) const
|
||
|
|
{
|
||
|
|
std::map <db::cell_index_type, db::cell_index_type>::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 <db::cell_index_type, db::cell_index_type>::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 <db::cell_index_type, db::cell_index_type>::const_iterator m = m_b2a_mapping.find (cell_index_b);
|
||
|
|
tl_assert (m != m_b2a_mapping.end ());
|
||
|
|
return m->second;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|