mirror of https://github.com/KLayout/klayout.git
WIP: better matching of subcircuits - attempt to map them even if not identical. This hopefully makes solving subcircuit connection problems easier.
This commit is contained in:
parent
3310d34cf3
commit
910a36b83d
|
|
@ -1942,6 +1942,89 @@ compute_subcircuit_key (const db::SubCircuit &subcircuit, const db::NetGraph &g,
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
inline double size_dist (size_t a, size_t b)
|
||||||
|
{
|
||||||
|
double d = a - b;
|
||||||
|
return d * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KeyDistance
|
||||||
|
{
|
||||||
|
typedef std::pair<std::vector<std::pair<size_t, size_t> >, const db::SubCircuit *> value_type;
|
||||||
|
|
||||||
|
double operator() (const value_type &a, const value_type &b) const
|
||||||
|
{
|
||||||
|
tl_assert (a.first.size () == b.first.size ());
|
||||||
|
double d = 0.0;
|
||||||
|
for (std::vector<std::pair<size_t, size_t> >::const_iterator i = a.first.begin (), j = b.first.begin (); i != a.first.end (); ++i, ++j) {
|
||||||
|
d += size_dist (i->first, j->first) + size_dist (i->second, j->second);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeySize
|
||||||
|
{
|
||||||
|
typedef std::pair<std::vector<std::pair<size_t, size_t> >, const db::SubCircuit *> value_type;
|
||||||
|
|
||||||
|
bool operator() (const value_type &a, const value_type &b) const
|
||||||
|
{
|
||||||
|
return (a.first.size () < b.first.size ());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Iter, class Distance>
|
||||||
|
void align (Iter i1, Iter i2, Iter j1, Iter j2, Distance distance)
|
||||||
|
{
|
||||||
|
// TODO: this can probably be done more efficiently
|
||||||
|
|
||||||
|
std::vector<Iter> vi, vj;
|
||||||
|
vi.reserve (std::max (i2 - i1, j2 - j1));
|
||||||
|
vj.reserve (std::max (i2 - i1, j2 - j1));
|
||||||
|
|
||||||
|
for (Iter i = i1; i != i2; ++i) {
|
||||||
|
vi.push_back (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iter j = j1; j != j2; ++j) {
|
||||||
|
vj.push_back (j);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (vi.size () < vj.size ()) {
|
||||||
|
vi.push_back (Iter ());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (vj.size () < vi.size ()) {
|
||||||
|
vj.push_back (Iter ());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vi.size () <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caution: this is an O(2) algorithm ...
|
||||||
|
bool any_swapped = true;
|
||||||
|
for (size_t n = 0; n < vi.size () - 1 && any_swapped; ++n) {
|
||||||
|
|
||||||
|
any_swapped = false;
|
||||||
|
|
||||||
|
for (size_t m = n + 1; m < vj.size () - 1; ++m) {
|
||||||
|
if (vi [n] == Iter () || vi [m] == Iter () || vj [n] == Iter () || vj [m] == Iter ()) {
|
||||||
|
continue;
|
||||||
|
} else if (distance (*vi [n], *vj [m]) + distance (*vi [m], *vj [n]) < distance (*vi [n], *vj [n]) + distance (*vi [m], *vj [m])) {
|
||||||
|
// this will reduce the overall distance:
|
||||||
|
std::swap (vj [n], vj [m]);
|
||||||
|
any_swapped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping) const
|
NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping) const
|
||||||
{
|
{
|
||||||
|
|
@ -2325,6 +2408,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef std::vector<std::pair<std::vector<std::pair<size_t, size_t> >, const db::SubCircuit *> > unmatched_list;
|
||||||
|
unmatched_list unmatched_a, unmatched_b;
|
||||||
|
|
||||||
for (db::Circuit::const_subcircuit_iterator sc = c2->begin_subcircuits (); sc != c2->end_subcircuits (); ++sc) {
|
for (db::Circuit::const_subcircuit_iterator sc = c2->begin_subcircuits (); sc != c2->end_subcircuits (); ++sc) {
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t> > k = compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper);
|
std::vector<std::pair<size_t, size_t> > k = compute_subcircuit_key (*sc, g2, &c22_circuit_and_pin_mapping, &circuit_pin_mapper);
|
||||||
|
|
@ -2345,7 +2431,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
||||||
if (! mapped || scm == subcircuit_map.end ()) {
|
if (! mapped || scm == subcircuit_map.end ()) {
|
||||||
|
|
||||||
if (mp_logger) {
|
if (mp_logger) {
|
||||||
mp_logger->subcircuit_mismatch (0, sc.operator-> ());
|
unmatched_b.push_back (std::make_pair (k, sc.operator-> ()));
|
||||||
}
|
}
|
||||||
good = false;
|
good = false;
|
||||||
|
|
||||||
|
|
@ -2373,11 +2459,81 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
|
||||||
|
|
||||||
for (std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::SubCircuit *, size_t> >::const_iterator scm = subcircuit_map.begin (); scm != subcircuit_map.end (); ++scm) {
|
for (std::multimap<std::vector<std::pair<size_t, size_t> >, std::pair<const db::SubCircuit *, size_t> >::const_iterator scm = subcircuit_map.begin (); scm != subcircuit_map.end (); ++scm) {
|
||||||
if (mp_logger) {
|
if (mp_logger) {
|
||||||
mp_logger->subcircuit_mismatch (scm->second.first, 0);
|
unmatched_a.push_back (std::make_pair (scm->first, scm->second.first));
|
||||||
}
|
}
|
||||||
good = false;
|
good = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try to do some pairing between the mismatching subcircuits - even though we will still report them as
|
||||||
|
// mismatches it will give some better hint about what needs to be fixed
|
||||||
|
|
||||||
|
if (mp_logger) {
|
||||||
|
|
||||||
|
size_t max_analysis_set = 1000;
|
||||||
|
if (unmatched_a.size () + unmatched_b.size () > max_analysis_set) {
|
||||||
|
|
||||||
|
// don't try too much analysis - this may be a waste of time
|
||||||
|
for (unmatched_list::const_iterator i = unmatched_a.begin (); i != unmatched_a.end (); ++i) {
|
||||||
|
mp_logger->subcircuit_mismatch (i->second, 0);
|
||||||
|
}
|
||||||
|
for (unmatched_list::const_iterator i = unmatched_b.begin (); i != unmatched_b.end (); ++i) {
|
||||||
|
mp_logger->subcircuit_mismatch (0, i->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
std::sort (unmatched_a.begin (), unmatched_a.end (), KeySize ());
|
||||||
|
std::sort (unmatched_b.begin (), unmatched_b.end (), KeySize ());
|
||||||
|
|
||||||
|
for (unmatched_list::iterator i = unmatched_a.begin (), j = unmatched_b.begin (); i != unmatched_a.end () || j != unmatched_b.end (); ) {
|
||||||
|
|
||||||
|
while (j != unmatched_b.end () && (i == unmatched_a.end () || j->first.size () < i->first.size ())) {
|
||||||
|
mp_logger->subcircuit_mismatch (0, j->second);
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i != unmatched_a.end () && (j == unmatched_b.end () || i->first.size () < j->first.size ())) {
|
||||||
|
mp_logger->subcircuit_mismatch (i->second, 0);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == unmatched_a.end () && j == unmatched_b.end ()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unmatched_list::iterator ii = i, jj = j;
|
||||||
|
++i, ++j;
|
||||||
|
size_t n = ii->first.size ();
|
||||||
|
tl_assert (n == jj->first.size ());
|
||||||
|
|
||||||
|
while (i != unmatched_a.end () && i->first.size () == n) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (j != unmatched_b.end () && j->first.size () == n) {
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
|
||||||
|
align (ii, i, jj, j, KeyDistance ());
|
||||||
|
|
||||||
|
for ( ; ii != i && jj != j; ++ii, ++jj) {
|
||||||
|
mp_logger->subcircuit_mismatch (ii->second, jj->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; jj != j; ++jj) {
|
||||||
|
mp_logger->subcircuit_mismatch (0, jj->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; ii != i; ++ii) {
|
||||||
|
mp_logger->subcircuit_mismatch (ii->second, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return good;
|
return good;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -830,6 +830,11 @@ std::string devices_string (const std::pair<const db::Device *, const db::Device
|
||||||
|
|
||||||
static QString build_url (void *id, const std::string &tag, const std::string &title)
|
static QString build_url (void *id, const std::string &tag, const std::string &title)
|
||||||
{
|
{
|
||||||
|
if (id == 0) {
|
||||||
|
// no link
|
||||||
|
return tl::to_qstring (tl::escaped_to_html (title));
|
||||||
|
}
|
||||||
|
|
||||||
std::string s = std::string ("<a href='int:");
|
std::string s = std::string ("<a href='int:");
|
||||||
s += tag;
|
s += tag;
|
||||||
s += "?id=";
|
s += "?id=";
|
||||||
|
|
@ -849,7 +854,15 @@ NetlistBrowserModel::make_link_to (const std::pair<const db::Net *, const db::Ne
|
||||||
if ((! nets.first || column == m_second_column) && (! nets.second || column == m_first_column)) {
|
if ((! nets.first || column == m_second_column) && (! nets.second || column == m_first_column)) {
|
||||||
return QString ();
|
return QString ();
|
||||||
} else {
|
} else {
|
||||||
void *id = make_id_circuit_net (mp_indexer->circuit_index (mp_indexer->parent_of (nets)), mp_indexer->net_index (nets));
|
|
||||||
|
IndexedNetlistModel::circuit_pair circuits = mp_indexer->parent_of (nets);
|
||||||
|
void *id = 0;
|
||||||
|
// NOTE: the nets may not be a valid net pair. In this case, circuits is (0, 0) and
|
||||||
|
// no link is generated
|
||||||
|
if (circuits.first || circuits.second) {
|
||||||
|
id = make_id_circuit_net (mp_indexer->circuit_index (circuits), mp_indexer->net_index (nets));
|
||||||
|
}
|
||||||
|
|
||||||
if (mp_indexer->is_single () || column == m_first_column) {
|
if (mp_indexer->is_single () || column == m_first_column) {
|
||||||
return build_url (id, "net", str_from_expanded_name (nets.first));
|
return build_url (id, "net", str_from_expanded_name (nets.first));
|
||||||
} else if (column == m_second_column) {
|
} else if (column == m_second_column) {
|
||||||
|
|
@ -857,6 +870,7 @@ NetlistBrowserModel::make_link_to (const std::pair<const db::Net *, const db::Ne
|
||||||
} else {
|
} else {
|
||||||
return build_url (id, "net", str_from_expanded_names (nets, mp_indexer->is_single ()));
|
return build_url (id, "net", str_from_expanded_names (nets, mp_indexer->is_single ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -866,7 +880,15 @@ NetlistBrowserModel::make_link_to (const std::pair<const db::Device *, const db:
|
||||||
if ((! devices.first || column == m_second_column) && (! devices.second || column == m_first_column)) {
|
if ((! devices.first || column == m_second_column) && (! devices.second || column == m_first_column)) {
|
||||||
return QString ();
|
return QString ();
|
||||||
} else {
|
} else {
|
||||||
void *id = make_id_circuit_device (mp_indexer->circuit_index (mp_indexer->parent_of (devices)), mp_indexer->device_index (devices));
|
|
||||||
|
IndexedNetlistModel::circuit_pair circuits = mp_indexer->parent_of (devices);
|
||||||
|
void *id = 0;
|
||||||
|
// NOTE: the devices may not be a valid device pair. In this case, circuits is (0, 0) and
|
||||||
|
// no link is generated
|
||||||
|
if (circuits.first || circuits.second) {
|
||||||
|
id = make_id_circuit_device (mp_indexer->circuit_index (circuits), mp_indexer->device_index (devices));
|
||||||
|
}
|
||||||
|
|
||||||
if (mp_indexer->is_single () || column == m_first_column) {
|
if (mp_indexer->is_single () || column == m_first_column) {
|
||||||
return build_url (id, "device", str_from_expanded_name (devices.first));
|
return build_url (id, "device", str_from_expanded_name (devices.first));
|
||||||
} else if (column == m_second_column) {
|
} else if (column == m_second_column) {
|
||||||
|
|
@ -874,6 +896,7 @@ NetlistBrowserModel::make_link_to (const std::pair<const db::Device *, const db:
|
||||||
} else {
|
} else {
|
||||||
return build_url (id, "device", str_from_expanded_names (devices, mp_indexer->is_single ()));
|
return build_url (id, "device", str_from_expanded_names (devices, mp_indexer->is_single ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -917,7 +940,15 @@ NetlistBrowserModel::make_link_to (const std::pair<const db::SubCircuit *, const
|
||||||
if ((! subcircuits.first || column == m_second_column) && (! subcircuits.second || column == m_first_column)) {
|
if ((! subcircuits.first || column == m_second_column) && (! subcircuits.second || column == m_first_column)) {
|
||||||
return QString ();
|
return QString ();
|
||||||
} else {
|
} else {
|
||||||
void *id = make_id_circuit_subcircuit (mp_indexer->circuit_index (mp_indexer->parent_of (subcircuits)), mp_indexer->subcircuit_index (subcircuits));
|
|
||||||
|
IndexedNetlistModel::circuit_pair circuits = mp_indexer->parent_of (subcircuits);
|
||||||
|
void *id = 0;
|
||||||
|
// NOTE: the subcircuits may not be a valid subcircuit pair. In this case, circuits is (0, 0) and
|
||||||
|
// no link is generated
|
||||||
|
if (circuits.first || circuits.second) {
|
||||||
|
id = make_id_circuit_subcircuit (mp_indexer->circuit_index (circuits), mp_indexer->subcircuit_index (subcircuits));
|
||||||
|
}
|
||||||
|
|
||||||
if (mp_indexer->is_single () || column == m_first_column) {
|
if (mp_indexer->is_single () || column == m_first_column) {
|
||||||
return build_url (id, "subcircuit", str_from_expanded_name (subcircuits.first));
|
return build_url (id, "subcircuit", str_from_expanded_name (subcircuits.first));
|
||||||
} else if (column == m_second_column) {
|
} else if (column == m_second_column) {
|
||||||
|
|
@ -925,6 +956,7 @@ NetlistBrowserModel::make_link_to (const std::pair<const db::SubCircuit *, const
|
||||||
} else {
|
} else {
|
||||||
return build_url (id, "subcircuit", str_from_expanded_names (subcircuits, mp_indexer->is_single ()));
|
return build_url (id, "subcircuit", str_from_expanded_names (subcircuits, mp_indexer->is_single ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1313,6 +1345,13 @@ static std::string search_string_from_names (const std::pair<const Obj *, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetlistBrowserModel::is_valid_net_pair (const std::pair<const db::Net *, const db::Net *> &nets) const
|
||||||
|
{
|
||||||
|
IndexedNetlistModel::circuit_pair net_parent = mp_indexer->parent_of (nets);
|
||||||
|
return (net_parent.first != 0 || net_parent.second != 0);
|
||||||
|
}
|
||||||
|
|
||||||
db::NetlistCrossReference::Status
|
db::NetlistCrossReference::Status
|
||||||
NetlistBrowserModel::status (const QModelIndex &index) const
|
NetlistBrowserModel::status (const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
|
|
@ -1347,7 +1386,17 @@ NetlistBrowserModel::status (const QModelIndex &index) const
|
||||||
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
|
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
|
||||||
IndexedNetlistModel::pin_pair pins = pins_from_id (id);
|
IndexedNetlistModel::pin_pair pins = pins_from_id (id);
|
||||||
|
|
||||||
return mp_indexer->pin_from_index (circuit_refs, mp_indexer->pin_index (pins, circuit_refs)).second;
|
db::NetlistCrossReference::Status status = mp_indexer->pin_from_index (circuit_refs, mp_indexer->pin_index (pins, circuit_refs)).second;
|
||||||
|
if (status == db::NetlistCrossReference::Mismatch || status == db::NetlistCrossReference::NoMatch) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another test here is to check whether the pins may be attached to an invalid net pair
|
||||||
|
if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) {
|
||||||
|
// This indicates a wrong connection: the nets are associated in a way which is a not
|
||||||
|
// corresponding to a mapped net pair. Report Mismatch here.
|
||||||
|
return db::NetlistCrossReference::Mismatch;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (is_id_circuit_net (id)) {
|
} else if (is_id_circuit_net (id)) {
|
||||||
|
|
||||||
|
|
@ -1371,11 +1420,31 @@ NetlistBrowserModel::status (const QModelIndex &index) const
|
||||||
|
|
||||||
return mp_indexer->subcircuit_from_index (circuits, mp_indexer->subcircuit_index (subcircuits)).second;
|
return mp_indexer->subcircuit_from_index (circuits, mp_indexer->subcircuit_index (subcircuits)).second;
|
||||||
|
|
||||||
|
} else if (is_id_circuit_net_subcircuit_pin_others (id)) {
|
||||||
|
|
||||||
|
IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id);
|
||||||
|
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs);
|
||||||
|
size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id);
|
||||||
|
|
||||||
|
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
|
||||||
|
IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first;
|
||||||
|
|
||||||
|
if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) {
|
||||||
|
// This indicates a wrong connection: the nets are associated in a way which is a not
|
||||||
|
// corresponding to a mapped net pair. Report Mismatch here.
|
||||||
|
return db::NetlistCrossReference::Mismatch;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return db::NetlistCrossReference::None;
|
return db::NetlistCrossReference::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string rewire_subcircuit_pins_status_hint ()
|
||||||
|
{
|
||||||
|
return tl::to_string (tr ("The nets attached to the pins are not equivalent.\nRewire the circuit or use 'equivalent_pins' in the LVS script to fix this issue."));
|
||||||
|
}
|
||||||
|
|
||||||
QVariant
|
QVariant
|
||||||
NetlistBrowserModel::tooltip (const QModelIndex &index) const
|
NetlistBrowserModel::tooltip (const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
|
|
@ -1412,6 +1481,14 @@ NetlistBrowserModel::tooltip (const QModelIndex &index) const
|
||||||
IndexedNetlistModel::pin_pair pins = pins_from_id (id);
|
IndexedNetlistModel::pin_pair pins = pins_from_id (id);
|
||||||
|
|
||||||
hint = mp_indexer->pin_status_hint (circuit_refs, mp_indexer->pin_index (pins, circuit_refs));
|
hint = mp_indexer->pin_status_hint (circuit_refs, mp_indexer->pin_index (pins, circuit_refs));
|
||||||
|
if (hint.empty ()) {
|
||||||
|
|
||||||
|
// Another test here is to check whether the pins may be attached to an invalid net pair
|
||||||
|
if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) {
|
||||||
|
hint = rewire_subcircuit_pins_status_hint ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} else if (is_id_circuit_net (id)) {
|
} else if (is_id_circuit_net (id)) {
|
||||||
|
|
||||||
|
|
@ -1435,6 +1512,21 @@ NetlistBrowserModel::tooltip (const QModelIndex &index) const
|
||||||
|
|
||||||
hint = mp_indexer->subcircuit_status_hint (circuits, mp_indexer->subcircuit_index (subcircuits));
|
hint = mp_indexer->subcircuit_status_hint (circuits, mp_indexer->subcircuit_index (subcircuits));
|
||||||
|
|
||||||
|
} else if (is_id_circuit_net_subcircuit_pin_others (id)) {
|
||||||
|
|
||||||
|
IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id);
|
||||||
|
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs);
|
||||||
|
size_t other_index = circuit_net_subcircuit_pin_other_index_from_id (id);
|
||||||
|
|
||||||
|
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
|
||||||
|
IndexedNetlistModel::pin_pair pins = mp_indexer->pin_from_index (circuit_refs, other_index).first;
|
||||||
|
|
||||||
|
if (! is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, pins))) {
|
||||||
|
// This indicates a wrong connection: the nets are associated in a way which is a not
|
||||||
|
// corresponding to a mapped net pair. Report Mismatch here.
|
||||||
|
hint = rewire_subcircuit_pins_status_hint ();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hint.empty ()) {
|
if (hint.empty ()) {
|
||||||
|
|
@ -1773,7 +1865,7 @@ NetlistBrowserModel::icon (const QModelIndex &index) const
|
||||||
|
|
||||||
} else if (is_id_circuit_subcircuit (id)) {
|
} else if (is_id_circuit_subcircuit (id)) {
|
||||||
return icon_for_circuit ();
|
return icon_for_circuit ();
|
||||||
} else if (is_id_circuit_subcircuit_pin (id) || is_id_circuit_net_pin (id) || is_id_circuit_net_subcircuit_pin_others (id)) {
|
} else if (is_id_circuit_subcircuit_pin (id) || is_id_circuit_net_pin (id)) {
|
||||||
return icon_for_pin ();
|
return icon_for_pin ();
|
||||||
} else if (is_id_circuit_net_subcircuit_pin (id)) {
|
} else if (is_id_circuit_net_subcircuit_pin (id)) {
|
||||||
return icon_for_circuit ();
|
return icon_for_circuit ();
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,8 @@ private:
|
||||||
return std::pair<const db::Netlist *, const db::Netlist *> (mp_l2ndb->netlist (), (const db::Netlist *)0);
|
return std::pair<const db::Netlist *, const db::Netlist *> (mp_l2ndb->netlist (), (const db::Netlist *)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_valid_net_pair (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||||
|
|
||||||
QIcon icon_for_nets (const std::pair<const db::Net *, const db::Net *> &net) const;
|
QIcon icon_for_nets (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||||
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
|
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,10 +238,14 @@ static IndexedNetlistModel::circuit_pair get_parent_of (const Pair &pair, const
|
||||||
}
|
}
|
||||||
|
|
||||||
i = cache.find (pair);
|
i = cache.find (pair);
|
||||||
tl_assert (i != cache.end ());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return i->second;
|
|
||||||
|
if (i == cache.end ()) {
|
||||||
|
return IndexedNetlistModel::circuit_pair ((const db::Circuit *) 0, (const db::Circuit *) 0);
|
||||||
|
} else {
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexedNetlistModel::circuit_pair NetlistCrossReferenceModel::parent_of (const IndexedNetlistModel::net_pair &net_pair) const
|
IndexedNetlistModel::circuit_pair NetlistCrossReferenceModel::parent_of (const IndexedNetlistModel::net_pair &net_pair) const
|
||||||
|
|
@ -436,19 +440,19 @@ std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pai
|
||||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||||
if (! cps.first.first || ! cps.first.second) {
|
if (! cps.first.first || ! cps.first.second) {
|
||||||
return tl::to_string (tr ("No matching circuit found in the other netlist.\n"
|
return tl::to_string (tr ("No matching circuit found in the other netlist.\n"
|
||||||
"By default, circuits are identified by their name. "
|
"By default, circuits are identified by their name.\n"
|
||||||
"A missing circuit probably means there is no circuit in the other netlist with this name.\n"
|
"A missing circuit probably means there is no circuit in the other netlist with this name.\n"
|
||||||
"If circuits with different names need to be associated, use 'same_circuits' in the "
|
"If circuits with different names need to be associated, use 'same_circuits' in the\n"
|
||||||
"LVS script to establish such an association."));
|
"LVS script to establish such an association."));
|
||||||
} else {
|
} else {
|
||||||
return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n"
|
return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n"
|
||||||
"Browse the circuit's component list to identify the mismatching elements."));
|
"Browse the circuit's component list to identify the mismatching elements."));
|
||||||
}
|
}
|
||||||
} else if (cps.second == db::NetlistCrossReference::Skipped) {
|
} else if (cps.second == db::NetlistCrossReference::Skipped) {
|
||||||
return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a pin-to-pin "
|
return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n"
|
||||||
"correspondence could be established for each child circuit.\n"
|
"pin-to-pin correspondence could be established for each child circuit.\n"
|
||||||
"This is not the case here. Browse the child circuits to identify the blockers.\n"
|
"This is not the case here. Browse the child circuits to identify the blockers.\n"
|
||||||
"Potential blockers are subcircuits without a corresponding other circuit or circuits "
|
"Potential blockers are subcircuits without a corresponding other circuit or circuits\n"
|
||||||
"where some pins could not be mapped to pins from the corresponding other circuit."));
|
"where some pins could not be mapped to pins from the corresponding other circuit."));
|
||||||
}
|
}
|
||||||
return std::string ();
|
return std::string ();
|
||||||
|
|
@ -469,15 +473,15 @@ std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit
|
||||||
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> cps = child_circuit_from_index (circuits, index);
|
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> cps = child_circuit_from_index (circuits, index);
|
||||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||||
if (!cps.first.first || !cps.first.second) {
|
if (!cps.first.first || !cps.first.second) {
|
||||||
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment "
|
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n"
|
||||||
"could not be derived from the nets connected to the pins.\n"
|
"assignment could not be derived from the nets connected to the pins.\n"
|
||||||
"Check, if the pins are attached properly. If pins need to be swappable, consider using 'equivalent_pins' "
|
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
|
||||||
"in the LVS script."));
|
"'equivalent_pins' in the LVS script."));
|
||||||
} else {
|
} else {
|
||||||
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not "
|
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n"
|
||||||
"originating from equivalent circuits.\n"
|
"originating from equivalent circuits.\n"
|
||||||
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script "
|
"If the circuits behind the subcircuits are identical, using 'same_circuits'\n"
|
||||||
"helps to associate them."));
|
"in the LVS script will associate them."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::string ();
|
return std::string ();
|
||||||
|
|
@ -487,9 +491,9 @@ std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &cir
|
||||||
{
|
{
|
||||||
std::pair<IndexedNetlistModel::net_pair, NetlistCrossReferenceModel::Status> cps = net_from_index (circuits, index);
|
std::pair<IndexedNetlistModel::net_pair, NetlistCrossReferenceModel::Status> cps = net_from_index (circuits, index);
|
||||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||||
return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a counterpart in "
|
return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n"
|
||||||
"the other netlist (component-wise and pin/terminal-wise).\n"
|
"counterpart in the other netlist (component-wise and pin/terminal-wise).\n"
|
||||||
"If there already is a net candidate from the other netlist, scan the net members for "
|
"If there already is a net candidate from the other netlist, scan the net members for\n"
|
||||||
"mismatching items (with errors or warnings) and fix these issues.\n"
|
"mismatching items (with errors or warnings) and fix these issues.\n"
|
||||||
"Otherwise, look for the corresponding other net.\n"
|
"Otherwise, look for the corresponding other net.\n"
|
||||||
"Net items not found in the reference netlist indicate additional connections.\n"
|
"Net items not found in the reference netlist indicate additional connections.\n"
|
||||||
|
|
@ -504,15 +508,15 @@ std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair &
|
||||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||||
if (!cps.first.first || !cps.first.second) {
|
if (!cps.first.first || !cps.first.second) {
|
||||||
return tl::to_string (tr ("No matching device was found in the other netlist.\n"
|
return tl::to_string (tr ("No matching device was found in the other netlist.\n"
|
||||||
"Devices are identified by the nets they are attached to. Unmatched devices mean that "
|
"Devices are identified by the nets they are attached to. Unmatched devices mean that\n"
|
||||||
"at least one terminal net isn't matched with a corresponding net from the other netlist.\n"
|
"at least one terminal net isn't matched with a corresponding net from the other netlist.\n"
|
||||||
"Make all terminal nets match and the devices will match too."));
|
"Make all terminal nets match and the devices will match too."));
|
||||||
}
|
}
|
||||||
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) {
|
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) {
|
||||||
return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the "
|
return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n"
|
||||||
"device classes don't match.\n"
|
"device classes don't match.\n"
|
||||||
"If the device class is different but should be considered the same, "
|
"If the device class is different but should be considered the same, using\n"
|
||||||
"using 'same_device_class' in the LVS script will solve this issue."));
|
"'same_device_classed' in the LVS script will solve this issue."));
|
||||||
}
|
}
|
||||||
return std::string ();
|
return std::string ();
|
||||||
}
|
}
|
||||||
|
|
@ -523,8 +527,8 @@ std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &cir
|
||||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||||
if (!cps.first.first || !cps.first.second) {
|
if (!cps.first.first || !cps.first.second) {
|
||||||
return tl::to_string (tr ("No matching pin was found in the other netlist.\n"
|
return tl::to_string (tr ("No matching pin was found in the other netlist.\n"
|
||||||
"Pins are identified by the nets they are attached to - pins on equivalent nets are also equivalent.\n"
|
"Pins are identified by the nets they are attached to - pins on equivalent nets are also\n"
|
||||||
"Making the nets match will make the pins match too."));
|
"equivalent. Making the nets match will make the pins match too."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::string ();
|
return std::string ();
|
||||||
|
|
@ -535,15 +539,15 @@ std::string NetlistCrossReferenceModel::subcircuit_status_hint (const circuit_pa
|
||||||
std::pair<IndexedNetlistModel::subcircuit_pair, NetlistCrossReferenceModel::Status> cps = subcircuit_from_index (circuits, index);
|
std::pair<IndexedNetlistModel::subcircuit_pair, NetlistCrossReferenceModel::Status> cps = subcircuit_from_index (circuits, index);
|
||||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||||
if (!cps.first.first || !cps.first.second) {
|
if (!cps.first.first || !cps.first.second) {
|
||||||
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment "
|
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n"
|
||||||
"could not be derived from the nets connected to the pins.\n"
|
"could not be derived from the nets connected to the pins.\n"
|
||||||
"Check, if the pins are attached properly. If pins need to be swappable, consider using 'equivalent_pins' "
|
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
|
||||||
"in the LVS script."));
|
"'equivalent_pins' in the LVS script."));
|
||||||
} else {
|
} else {
|
||||||
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not "
|
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n"
|
||||||
"originating from equivalent circuits.\n"
|
"equivalent circuits.\n"
|
||||||
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script "
|
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n"
|
||||||
"helps to associate them."));
|
"will associate them."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::string ();
|
return std::string ();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue