Provide 'align' method to auto-align circuit and cell hierarchy in LVS

This commit is contained in:
Matthias Koefferlein 2019-07-23 00:14:43 +02:00
parent 14d9689498
commit aff8212f2f
5 changed files with 129 additions and 2 deletions

View File

@ -2083,6 +2083,49 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b, NetlistCom
return res;
}
void
NetlistComparer::unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector<db::Circuit *> &in_a, std::vector<db::Circuit *> &in_b) const
{
// we need to create a copy because this method is supposed to be const.
db::CircuitCategorizer circuit_categorizer = *mp_circuit_categorizer;
std::map<size_t, std::pair<db::Circuit *, db::Circuit *> > cat2circuits;
for (db::Netlist::circuit_iterator i = a->begin_circuits (); i != a->end_circuits (); ++i) {
size_t cat = circuit_categorizer.cat_for_circuit (i.operator-> ());
if (cat && i->begin_refs () != i->end_refs ()) {
cat2circuits[cat].first = i.operator-> ();
}
}
for (db::Netlist::circuit_iterator i = b->begin_circuits (); i != b->end_circuits (); ++i) {
size_t cat = circuit_categorizer.cat_for_circuit (i.operator-> ());
if (cat && i->begin_refs () != i->end_refs ()) {
cat2circuits[cat].second = i.operator-> ();
}
}
size_t na = 0, nb = 0;
for (std::map<size_t, std::pair<db::Circuit *, db::Circuit *> >::const_iterator i = cat2circuits.begin (); i != cat2circuits.end (); ++i) {
if (! i->second.first) {
++nb;
} else if (! i->second.second) {
++na;
}
}
in_a.reserve (na);
in_b.reserve (nb);
for (std::map<size_t, std::pair<db::Circuit *, db::Circuit *> >::const_iterator i = cat2circuits.begin (); i != cat2circuits.end (); ++i) {
if (! i->second.first) {
in_b.push_back (i->second.second);
} else if (! i->second.second) {
in_a.push_back (i->second.first);
}
}
}
bool
NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
{

View File

@ -266,6 +266,13 @@ public:
return m_max_n_branch;
}
/**
* @brief Gets the list of circuits without matching circuit in the other netlist
* The result can be used to flatten these circuits prior to compare.
* Mismatching top level circuits are not reported because they cannot be flattened.
*/
void unmatched_circuits (db::Netlist *a, db::Netlist *b, std::vector<db::Circuit *> &in_a, std::vector<db::Circuit *> &in_b) const;
/**
* @brief Actually compares the two netlists
*/

View File

@ -452,6 +452,20 @@ static db::NetlistComparer *make_comparer1 (GenericNetlistCompareLogger *logger)
return new db::NetlistComparer (logger);
}
static std::vector<db::Circuit *> unmatched_circuits_a (const db::NetlistComparer *comparer, db::Netlist *a, db::Netlist *b)
{
std::vector<db::Circuit *> res_a, res_b;
comparer->unmatched_circuits (a, b, res_a, res_b);
return res_a;
}
static std::vector<db::Circuit *> unmatched_circuits_b (const db::NetlistComparer *comparer, db::Netlist *a, db::Netlist *b)
{
std::vector<db::Circuit *> res_a, res_b;
comparer->unmatched_circuits (a, b, res_a, res_b);
return res_b;
}
Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
gsi::constructor ("new", &make_comparer0,
"@brief Creates a new comparer object.\n"
@ -524,6 +538,16 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
"@brief Gets the maximum branch complexity\n"
"See \\max_branch_complexity= for details."
) +
gsi::method_ext ("unmatched_circuits_a", &unmatched_circuits_a, gsi::arg ("a"), gsi::arg ("b"),
"@brief Returns a list of circuits in A for which there is not corresponding circuit in B\n"
"This list can be used to flatten these circuits so they do not participate in the compare process.\n"
"Top level circuits are not included as they cannot be flattened.\n"
) +
gsi::method_ext ("unmatched_circuits_b", &unmatched_circuits_b, gsi::arg ("a"), gsi::arg ("b"),
"@brief Returns a list of circuits in B for which there is not corresponding circuit in A\n"
"This list can be used to flatten these circuits so they do not participate in the compare process.\n"
"Top level circuits are not included as they cannot be flattened.\n"
) +
gsi::method ("compare", (bool (db::NetlistComparer::*) (const db::Netlist *, const db::Netlist *) const) &db::NetlistComparer::compare, gsi::arg ("netlist_a"), gsi::arg ("netlist_b"),
"@brief Compares two netlists.\n"
"This method will perform the actual netlist compare. It will return true if both netlists are identical. "

View File

@ -94,6 +94,12 @@ module LVS
# @synopsis compare
# See \Netter#compare for a description of that function.
# %LVS%
# @name align
# @brief Aligns the extracted netlist vs. the schematic by flattening circuits where required
# @synopsis align
# See \Netter#align for a description of that function.
# %LVS%
# @name same_nets
# @brief Establishes an equivalence between the nets
@ -143,7 +149,7 @@ module LVS
# @synopsis max_depth(n)
# See \Netter#max_depth for a description of that function.
%w(schematic compare same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity).each do |f|
%w(schematic compare align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity).each do |f|
eval <<"CODE"
def #{f}(*args)
_netter.#{f}(*args)

View File

@ -91,6 +91,46 @@ module LVS
data
end
# %LVS%
# @name align
# @brief Aligns the extracted netlist vs. the schematic
# @synopsis align
# The align method will modify the netlists in case of missing
# corresponding circuits. It will flatten these circuits, thus
# improving the equivalence between the netlists. Top level circuits
# are not flattened.
#
# This feature is in particular useful to remove structural cells
# like device PCells, reuse blocks etc.
#
# This method will also remove schematic circuits for which there is
# no corresponding layout cell. In the extreme case of flat layout this
# will result in a flat vs. flat compare.
#
# "netlist.flatten_circuit(...)" or "schematic.flatten_circuit(...)"
# are other (explicit) ways to flatten circuits.
#
# Please note that flattening circuits has some side effects such
# as loss of details in the cross reference and net layout.
def align
nl = _ensure_two_netlists
# flatten layout cells for which there is no corresponding schematic circuit
@comparer.unmatched_circuits_a(*nl).each do |c|
@engine.info("Flatten layout cell (no schematic): #{c.name}")
nl[0].flatten_circuit(c)
end
# flatten schematic circuits for which there is no corresponding layout cell
@comparer.unmatched_circuits_b(*nl).each do |c|
@engine.info("Flatten schematic circuit (no layout): #{c.name}")
nl[1].flatten_circuit(c)
end
end
# %LVS%
# @name compare
# @brief Compares the extracted netlist vs. the schematic
@ -99,12 +139,19 @@ module LVS
# The compare can be configured in more details using \same_nets, \same_circuits,
# \same_device_classes and \equivalent_pins.
#
# The compare method will also modify the netlists in case of missing
# corresponding circuits: the unpaired circuit will be flattened then.
#
# This method will return true, if the netlists are equivalent and false
# otherwise.
def compare
lvs_data.reference = _ensure_two_netlists[1]
nl = _ensure_two_netlists
lvs_data.reference = nl[1]
lvs_data.compare(@comparer)
end
def _ensure_two_netlists