mirror of https://github.com/KLayout/klayout.git
Provide 'align' method to auto-align circuit and cell hierarchy in LVS
This commit is contained in:
parent
14d9689498
commit
aff8212f2f
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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. "
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue