Some enhancements for strong matching of nets

* same_nets! method for strong matching
* same_nets and same_nets! except glob pattern to circuits and nets
* both observe case sensitivity
* helper functions for case sensitivity Netlist#is_case_sensitive?, Netlist#case_sensitive=
* Netlist#nets_by_name to get nets from pattern
This commit is contained in:
Matthias Koefferlein 2021-06-28 22:33:46 +02:00
parent 72dc94197e
commit ab70c42c68
11 changed files with 455 additions and 58 deletions

View File

@ -1013,6 +1013,14 @@ public:
return j->second;
}
/**
* @brief Gets a value indicating whether there is a node for the given net
*/
bool has_node_index_for_net (const db::Net *net) const
{
return m_net_index.find (net) != m_net_index.end ();
}
/**
* @brief Gets the node for a given node index
*/
@ -2880,9 +2888,16 @@ NetlistComparer::exclude_resistors (double threshold)
}
void
NetlistComparer::same_nets (const db::Net *na, const db::Net *nb)
NetlistComparer::same_nets (const db::Net *na, const db::Net *nb, bool must_match)
{
m_same_nets [std::make_pair (na->circuit (), nb->circuit ())].push_back (std::make_pair (na, nb));
tl_assert (na && na);
m_same_nets [std::make_pair (na->circuit (), nb->circuit ())].push_back (std::make_pair (std::make_pair (na, nb), must_match));
}
void
NetlistComparer::same_nets (const db::Circuit *ca, const db::Circuit *cb, const db::Net *na, const db::Net *nb, bool must_match)
{
m_same_nets [std::make_pair (ca, cb)].push_back (std::make_pair (std::make_pair (na, nb), must_match));
}
void
@ -3114,9 +3129,9 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
tl_assert (i->second.second.size () == size_t (1));
const db::Circuit *cb = i->second.second.front ();
std::vector<std::pair<const Net *, const Net *> > empty;
const std::vector<std::pair<const Net *, const Net *> > *net_identity = &empty;
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<const Net *, const Net *> > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb));
std::vector<std::pair<std::pair<const Net *, const Net *>, bool> > empty;
const std::vector<std::pair<std::pair<const Net *, const Net *>, bool> > *net_identity = &empty;
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<std::pair<const Net *, const Net *>, bool> > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb));
if (sn != m_same_nets.end ()) {
net_identity = &sn->second;
}
@ -3525,7 +3540,7 @@ 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,
const std::vector<std::pair<std::pair<const Net *, const Net *>, bool> > &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
@ -3551,11 +3566,39 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
g1.identify (0, 0);
g2.identify (0, 0);
for (std::vector<std::pair<const Net *, const Net *> >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) {
size_t ni1 = g1.node_index_for_net (p->first);
size_t ni2 = g2.node_index_for_net (p->second);
g1.identify (ni1, ni2);
g2.identify (ni2, ni1);
for (std::vector<std::pair<std::pair<const Net *, const Net *>, bool> >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) {
// NOTE: nets may vanish, hence there
if (g1.has_node_index_for_net (p->first.first) && g2.has_node_index_for_net (p->first.second)) {
size_t ni1 = g1.node_index_for_net (p->first.first);
size_t ni2 = g2.node_index_for_net (p->first.second);
g1.identify (ni1, ni2);
g2.identify (ni2, ni1);
// in must_match mode, check if the nets are identical
if (p->second && ! (g1.node(ni1) == g2.node(ni2))) {
mp_logger->net_mismatch (p->first.first, p->first.second);
} else {
mp_logger->match_nets (p->first.first, p->first.second);
}
} else if (p->second && g1.has_node_index_for_net (p->first.first)) {
mp_logger->net_mismatch (p->first.first, 0);
size_t ni1 = g1.node_index_for_net (p->first.first);
g1.identify (ni1, 0);
} else if (p->second && g2.has_node_index_for_net (p->first.second)) {
mp_logger->net_mismatch (0, p->first.second);
size_t ni2 = g2.node_index_for_net (p->first.second);
g2.identify (ni2, 0);
}
}
int iter = 0;

View File

@ -181,7 +181,17 @@ public:
* net nb in netlist b.
* By default nets are not identical expect through their topology.
*/
void same_nets (const db::Net *na, const db::Net *nb);
void same_nets (const db::Net *na, const db::Net *nb, bool must_match = false);
/**
* @brief Mark two nets as identical
*
* This makes a net na in netlist a identical to the corresponding
* net nb in netlist b.
* By default nets are not identical expect through their topology.
* This version allows mapping one net to a null net because the circuits are explicitly specified.
*/
void same_nets (const db::Circuit *ca, const db::Circuit *cb, const db::Net *na, const db::Net *nb, bool must_match);
/**
* @brief Mark two pins as equivalent (i.e. can be swapped)
@ -344,7 +354,7 @@ private:
NetlistComparer &operator= (const NetlistComparer &);
protected:
bool 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;
bool 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<std::pair<const Net *, const Net *>, bool> > &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;
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
std::string generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set<const db::Circuit *> &verified_circuits_a, const db::Circuit *cb, const std::set<const db::Circuit *> &verified_circuits_b) const;
static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper);
@ -354,7 +364,7 @@ protected:
bool handle_pin_mismatch (const NetGraph &g1, const db::Circuit *c1, const db::Pin *pin1, const NetGraph &g2, const db::Circuit *c2, const db::Pin *p2) const;
mutable NetlistCompareLogger *mp_logger;
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<const Net *, const Net *> > > m_same_nets;
std::map<std::pair<const db::Circuit *, const db::Circuit *>, std::vector<std::pair<std::pair<const Net *, const Net *>, bool> > > m_same_nets;
std::unique_ptr<CircuitPinMapper> mp_circuit_pin_mapper;
std::unique_ptr<DeviceCategorizer> mp_device_categorizer;
std::unique_ptr<CircuitCategorizer> mp_circuit_categorizer;

View File

@ -1238,8 +1238,14 @@ static std::vector<db::Net *>
nets_by_name (db::Circuit *circuit, const std::string &name_pattern)
{
std::vector<db::Net *> res;
if (! circuit) {
return res;
}
tl::GlobPattern glob (name_pattern);
if (circuit->netlist ()) {
glob.set_case_sensitive (circuit->netlist ()->is_case_sensitive ());
}
for (db::Circuit::net_iterator n = circuit->begin_nets (); n != circuit->end_nets (); ++n) {
db::Net *net = n.operator-> ();
if (glob.match (net->name ())) {
@ -1254,8 +1260,14 @@ static std::vector<const db::Net *>
nets_by_name_const (const db::Circuit *circuit, const std::string &name_pattern)
{
std::vector<const db::Net *> res;
if (! circuit) {
return res;
}
tl::GlobPattern glob (name_pattern);
if (circuit->netlist ()) {
glob.set_case_sensitive (circuit->netlist ()->is_case_sensitive ());
}
for (db::Circuit::const_net_iterator n = circuit->begin_nets (); n != circuit->end_nets (); ++n) {
const db::Net *net = n.operator-> ();
if (glob.match (net->name ())) {
@ -1681,8 +1693,13 @@ static std::vector<db::Circuit *>
circuits_by_name (db::Netlist *netlist, const std::string &name_pattern)
{
std::vector<db::Circuit *> res;
if (! netlist) {
return res;
}
tl::GlobPattern glob (name_pattern);
glob.set_case_sensitive (netlist->is_case_sensitive ());
for (db::Netlist::circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
db::Circuit *circuit = c.operator-> ();
if (glob.match (circuit->name ())) {
@ -1697,8 +1714,13 @@ static std::vector<const db::Circuit *>
circuits_by_name_const (const db::Netlist *netlist, const std::string &name_pattern)
{
std::vector<const db::Circuit *> res;
if (! netlist) {
return res;
}
tl::GlobPattern glob (name_pattern);
glob.set_case_sensitive (netlist->is_case_sensitive ());
for (db::Netlist::const_circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
const db::Circuit *circuit = c.operator-> ();
if (glob.match (circuit->name ())) {
@ -1710,6 +1732,14 @@ circuits_by_name_const (const db::Netlist *netlist, const std::string &name_patt
}
Class<db::Netlist> decl_dbNetlist ("db", "Netlist",
gsi::method ("is_case_sensitive?", &db::Netlist::is_case_sensitive,
"@brief Returns a value indicating whether the netlist names are case sensitive\n"
"This method has been added in version 0.27.3.\n"
) +
gsi::method ("case_sensitive=", &db::Netlist::set_case_sensitive, gsi::arg ("cs"),
"@brief Sets a value indicating whether the netlist names are case sensitive\n"
"This method has been added in version 0.27.3.\n"
) +
gsi::method_ext ("add", &gsi::add_circuit, gsi::arg ("circuit"),
"@brief Adds the circuit to the netlist\n"
"This method will add the given circuit object to the netlist. "

View File

@ -476,13 +476,32 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
"The logger is a delegate or event receiver which the comparer will send compare events to. "
"See the class description for more details."
) +
gsi::method ("same_nets", &db::NetlistComparer::same_nets, gsi::arg ("net_a"), gsi::arg ("net_b"),
gsi::method ("same_nets", (void (db::NetlistComparer::*) (const db::Net *, const db::Net *, bool)) &db::NetlistComparer::same_nets, gsi::arg ("net_a"), gsi::arg ("net_b"), gsi::arg ("must_match", false),
"@brief Marks two nets as identical.\n"
"This makes a net net_a in netlist a identical to the corresponding\n"
"net net_b in netlist b (see \\compare).\n"
"Otherwise, the algorithm will try to identify nets according to their topology. "
"This method can be used to supply hints to the compare algorithm. It will use "
"these hints to derive further identities."
"these hints to derive further identities.\n"
"\n"
"If 'must_match' is true, the nets are required to match. If they don't, an error is reported.\n"
"\n"
"The 'must_match' optional argument has been added in version 0.27.3.\n"
) +
gsi::method ("same_nets", (void (db::NetlistComparer::*) (const db::Circuit *, const db::Circuit *, const db::Net *, const db::Net *, bool)) &db::NetlistComparer::same_nets, gsi::arg ("circuit_a"), gsi::arg ("circuit_b"), gsi::arg ("net_a"), gsi::arg ("net_b"), gsi::arg ("must_match", false),
"@brief Marks two nets as identical.\n"
"This makes a net net_a in netlist a identical to the corresponding\n"
"net net_b in netlist b (see \\compare).\n"
"Otherwise, the algorithm will try to identify nets according to their topology. "
"This method can be used to supply hints to the compare algorithm. It will use "
"these hints to derive further identities.\n"
"\n"
"If 'must_match' is true, the nets are required to match. If they don't, an error is reported.\n"
"\n"
"This variant allows specifying nil for the nets indicating the nets are mismatched by definition. "
"with 'must_match' this will render a net mismatch error.\n"
"\n"
"This variant has been added in version 0.27.3.\n"
) +
gsi::method ("equivalent_pins", (void (db::NetlistComparer::*) (const db::Circuit *, size_t, size_t)) &db::NetlistComparer::equivalent_pins, gsi::arg ("circuit_b"), gsi::arg ("pin_id1"), gsi::arg ("pin_id2"),
"@brief Marks two pins of the given circuit as equivalent (i.e. they can be swapped).\n"

View File

@ -81,7 +81,7 @@ The filter is a glob expression.
This has the following effects:
</p><p>
<ul>
<li>The circuits are no longer compared against each other </li>
<li>The circuits are no longer compared (netlist vs. schematic) </li>
<li>Named pins are required to match (use labels on the nets to name pins in the layout) </li>
<li>Unnamed pins are treated as equivalent and can be swapped </li>
<li>The selected circuits will not be purged on netlist simplification </li>
@ -91,6 +91,8 @@ Using this method can be useful to reduce the verification overhead for
blocks which are already verifified by other ways or for which no schematic
is available - e.g. hard macros.
</p><p>
Example:
</p><p>
<pre>
# skips all MEMORY* circuits from compare
blank_circuit("MEMORY*")
@ -317,7 +319,8 @@ Use this method andwhere in the script before the <a href="#compare">compare</a>
<keyword name="same_nets"/>
<p>Usage:</p>
<ul>
<li><tt>same_nets(circuit, net_a, net_b)</tt></li>
<li><tt>same_nets(circuit_pattern, net_pattern)</tt></li>
<li><tt>same_nets(circuit_pattern, net_a, net_b)</tt></li>
<li><tt>same_nets(circuit_a, net_a, circuit_b, net_b)</tt></li>
</ul>
<p>
@ -325,8 +328,17 @@ This method will force an equivalence between the net_a and net_b from circuit_a
and circuit_b (circuit in the three-argument form is for both circuit_a and circuit_b).
</p><p>
In the four-argument form, the circuits can be either given by name or as Circuit
objects. In the three-argument form, the circuit has to be given by name.
objects. In the three-argument form, the circuits have to be given by name pattern.
Nets can be either given by name or as Net objects.
In the two-argument form, the circuits and nets have to be given as name pattern.
</p><p>
"name pattern" are glob-style pattern - e.g. the following will identify the
all nets starting with "A" from the extracted netlist with the same net from
the schematic netlist for all circuits starting with "INV":
</p><p>
<pre>
same_nets("INV*", "A*")
</pre>
</p><p>
After using this function, the compare algorithm will consider these nets equivalent.
Use this method to provide hints for the comparer in cases which are difficult to
@ -337,6 +349,18 @@ Names are case sensitive for layout-derived netlists and case-insensitive for SP
</p><p>
Use this method andwhere in the script before the <a href="#compare">compare</a> call.
</p>
<a name="same_nets!"/><h2>"same_nets!" - Establishes an equivalence between the nets with matching requirement</h2>
<keyword name="same_nets!"/>
<p>Usage:</p>
<ul>
<li><tt>same_nets!(circuit_pattern, net_pattern)</tt></li>
<li><tt>same_nets!(circuit_pattern, net_a, net_b)</tt></li>
<li><tt>same_nets!(circuit_a, net_a, circuit_b, net_b)</tt></li>
</ul>
<p>
This method is equivalent to <a href="#same_nets">same_nets</a>, but requires identity of the given nets.
If the specified nets do not match, an error is reported.
</p>
<a name="schematic"/><h2>"schematic" - Gets, sets or reads the reference netlist</h2>
<keyword name="schematic"/>
<p>Usage:</p>

View File

@ -115,10 +115,19 @@ module LVS
# %LVS%
# @name same_nets
# @brief Establishes an equivalence between the nets
# @synopsis same_nets(circuit, net_a, net_b)
# @synopsis same_nets(circuit_pattern, net_pattern)
# @synopsis same_nets(circuit_pattern, net_a, net_b)
# @synopsis same_nets(circuit_a, net_a, circuit_b, net_b)
# See \Netter#same_nets for a description of that function.
# %LVS%
# @name same_nets!
# @brief Establishes an equivalence between the nets (must match)
# @synopsis same_nets!(circuit_pattern, net_pattern)
# @synopsis same_nets!(circuit_pattern, net_a, net_b)
# @synopsis same_nets!(circuit_a, net_a, circuit_b, net_b)
# See \Netter#same_nets! for a description of that function.
# %LVS%
# @name same_circuits
# @brief Establishes an equivalence between the circuits
@ -174,7 +183,7 @@ module LVS
# @synopsis tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance])
# See \Netter#tolerance for a description of that function.
%w(schematic compare join_symmetric_nets tolerance blank_circuit align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
%w(schematic compare join_symmetric_nets tolerance blank_circuit align same_nets same_nets! same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
eval <<"CODE"
def #{f}(*args)
_netter.#{f}(*args)

View File

@ -370,14 +370,24 @@ module LVS
# %LVS%
# @name same_nets
# @brief Establishes an equivalence between the nets
# @synopsis same_nets(circuit, net_a, net_b)
# @synopsis same_nets(circuit_pattern, net_pattern)
# @synopsis same_nets(circuit_pattern, net_a, net_b)
# @synopsis same_nets(circuit_a, net_a, circuit_b, net_b)
# This method will force an equivalence between the net_a and net_b from circuit_a
# and circuit_b (circuit in the three-argument form is for both circuit_a and circuit_b).
#
#
# In the four-argument form, the circuits can be either given by name or as Circuit
# objects. In the three-argument form, the circuit has to be given by name.
# objects. In the three-argument form, the circuits have to be given by name pattern.
# Nets can be either given by name or as Net objects.
# In the two-argument form, the circuits and nets have to be given as name pattern.
#
# "name pattern" are glob-style pattern - e.g. the following will identify the
# all nets starting with "A" from the extracted netlist with the same net from
# the schematic netlist for all circuits starting with "INV":
#
# @code
# same_nets("INV*", "A*")
# @/code
#
# After using this function, the compare algorithm will consider these nets equivalent.
# Use this method to provide hints for the comparer in cases which are difficult to
@ -389,65 +399,125 @@ module LVS
# Use this method andwhere in the script before the \compare call.
def same_nets(*args)
_same_nets_impl(false, *args)
end
if args.size < 3
raise("Too few arguments to 'same_nets' (need at least 3)")
# %LVS%
# @name same_nets!
# @brief Establishes an equivalence between the nets with matching requirement
# @synopsis same_nets!(circuit_pattern, net_pattern)
# @synopsis same_nets!(circuit_pattern, net_a, net_b)
# @synopsis same_nets!(circuit_a, net_a, circuit_b, net_b)
# This method is equivalent to \same_nets, but requires identity of the given nets.
# If the specified nets do not match, an error is reported.
def same_nets!(*args)
_same_nets_impl(true, *args)
end
def _same_nets_impl(force, *args)
if args.size < 2
raise("Too few arguments to 'same_nets' (need at least 2)")
end
if args.size > 4
raise("Too many arguments to 'same_nets' (need max 4)")
end
if args.size == 3
( ca, a, b ) = args
cb = ca
( ca, a ) = args
cb = nil
ca.is_a?(String) || raise("Circuit argument of 'same_nets' must be a string")
b = nil
a.is_a?(String) || raise("Net argument of 'same_nets' must be a string")
elsif args.size == 3
( ca, a, b ) = args
cb = nil
ca.is_a?(String) || raise("Circuit argument of 'same_nets' must be a string")
[ a, b ].each do |n|
n.is_a?(String) || n.is_a?(RBA::Net) || raise("Net arguments of 'same_nets' must be strings or Net objects")
end
else
( ca, a, cb, b ) = args
[ ca, cb ].each do |n|
n.is_a?(String) || n.is_a?(RBA::Net) || raise("Circuit arguments of 'same_nets' must be strings or Net objects")
n.is_a?(String) || n.is_a?(RBA::Circuit) || raise("Circuit arguments of 'same_nets' must be strings or Circuit objects")
end
[ a, b ].each do |n|
n.is_a?(String) || n.is_a?(RBA::Net) || raise("Net arguments of 'same_nets' must be strings or Net objects")
end
end
[ a, b ].each do |n|
n.is_a?(String) || n.is_a?(RBA::Net) || raise("Net arguments of 'same_nets' must be strings or Net objects")
end
@comparer_config << lambda { |comparer| self._same_nets(comparer, ca, a, cb, b) }
@comparer_config << lambda { |comparer| self._same_nets(comparer, ca, a, cb, b, force) }
end
def _same_nets(comparer, ca, a, cb, b)
def _same_nets(comparer, ca, a, cb, b, force)
( nl_a, nl_b ) = _ensure_two_netlists
if ca.is_a?(String)
circuit_a = nl_a.circuit_by_name(ca)
cs = !(nl_a.is_case_sensitive? && nl_b.is_case_sensitive?)
if ca.is_a?(String) && !cb
n2c = {}
nl_a.circuits_by_name(ca).each { |c| name = cs ? c.name.upcase : c.name; n2c[name] ||= [ nil, nil ]; n2c[name][0] = c }
nl_b.circuits_by_name(ca).each { |c| name = cs ? c.name.upcase : c.name; n2c[name] ||= [ nil, nil ]; n2c[name][1] = c }
circuits = []
n2c.keys.sort.each do |n|
if n2c[n][0] && n2c[n][1]
circuits << n2c[n]
end
end
else
circuit_a = ca
end
if cb.is_a?(String)
circuit_b = nl_b.circuit_by_name(cb)
else
circuit_b = cb
end
circuit_a = ca.is_a?(String) ? nl_a.circuit_by_name(ca) : ca
circuit_b = cb.is_a?(String) ? nl_b.circuit_by_name(cb) : cb
if circuit_a && circuit_b
if a.is_a?(String)
net_a = circuit_a.net_by_name(a) || raise("Not a valid net name in extracted netlist in 'same_nets': #{a} (for circuit #{circuit_a})")
else
net_a = a
circuits = []
if circuit_a && circuit_b
circuits << [ circuit_a, circuit_b ]
end
if b.is_a?(String)
net_b = circuit_b.net_by_name(b) || raise("Not a valid net name in extracted netlist in 'same_nets': #{b} (for circuit #{circuit_b})")
end
circuits.each do |circuit_a, circuit_b|
if a.is_a?(String) && !b
n2n = {}
circuit_a.nets_by_name(a).each { |n| name = cs ? n.name.upcase : n.name; n2n[name] ||= [ nil, nil ]; n2n[name][0] = n }
circuit_b.nets_by_name(a).each { |n| name = cs ? n.name.upcase : n.name; n2n[name] ||= [ nil, nil ]; n2n[name][1] = n }
nets = []
n2n.keys.sort.each do |n|
nets << n2n[n]
end
else
net_b = b
if a.is_a?(String)
net_a = circuit_a.net_by_name(a) || raise("Not a valid net name in extracted netlist in 'same_nets': #{a} (for circuit #{circuit_a})")
else
net_a = a
end
if b.is_a?(String)
net_b = circuit_b.net_by_name(b) || raise("Not a valid net name in extracted netlist in 'same_nets': #{b} (for circuit #{circuit_b})")
else
net_b = b
end
nets = []
if net_a && net_b
nets << [ net_a, net_b ]
end
end
if net_a && net_b
comparer.same_nets(net_a, net_b)
nets.each do |net_a, net_b|
comparer.same_nets(circuit_a, circuit_b, net_a, net_b, force)
end
end

View File

@ -881,6 +881,7 @@ xref(
net(7 12 match)
net(8 13 match)
net(9 14 match)
net(14 4 match)
net(11 3 match)
net(13 5 match)
net(12 2 match)

View File

@ -881,6 +881,7 @@ xref(
net(7 12 match)
net(8 13 match)
net(9 14 match)
net(14 4 match)
net(11 3 match)
net(13 5 match)
net(12 2 match)

View File

@ -63,6 +63,13 @@ class DBNetlist_TestClass < TestBase
assert_equal(nl.circuit_by_cell_index(17).inspect, "nil")
assert_equal(nl.circuit_by_name("DOESNOTEXIST").inspect, "nil")
assert_equal(nl.is_case_sensitive?, true)
assert_equal(nl.circuit_by_name("xyz").inspect, "nil")
nl.case_sensitive = false
assert_equal(nl.is_case_sensitive?, false)
assert_equal(nl.circuit_by_name("xyz").name, "XYZ")
nl.case_sensitive = true
cc = RBA::Circuit::new
assert_equal(cc.dont_purge, false)
cc.dont_purge = true
@ -103,6 +110,11 @@ class DBNetlist_TestClass < TestBase
assert_equal(names, [ c.name, cc.name ])
assert_equal(nl.circuits_by_name("X*").collect { |x| x.name }, [ "XYZ" ])
assert_equal(nl.circuits_by_name("x*").collect { |x| x.name }, [])
nl.case_sensitive = false
assert_equal(nl.circuits_by_name("X*").collect { |x| x.name }, [ "XYZ" ])
assert_equal(nl.circuits_by_name("x*").collect { |x| x.name }, [ "XYZ" ])
nl.case_sensitive = true
assert_equal(nl.circuits_by_name("???").collect { |x| x.name }, [ "XYZ", "UVW" ])
assert_equal(nl.circuits_by_name("*").collect { |x| x.name }, [ "XYZ", "UVW" ])
assert_equal(nl.circuits_by_name("P*").collect { |x| x.name }, [])
@ -702,6 +714,11 @@ class DBNetlist_TestClass < TestBase
assert_equal(c.net_by_name("DOESNOTEXIST").inspect, "nil")
assert_equal(c.nets_by_name("DOESNOTEXIST").collect(&:name), [])
assert_equal(c.net_by_name("net1").inspect, "nil")
nl.case_sensitive = false
assert_equal(c.net_by_name("net1").name, "NET1")
nl.case_sensitive = true
net2 = c.create_net
net2.name = "NET2"
@ -709,6 +726,11 @@ class DBNetlist_TestClass < TestBase
c.each_net { |n| names << n.name }
assert_equal(names, [ "NET1", "NET2" ])
assert_equal(c.nets_by_name("NET*").collect(&:name), ["NET1", "NET2"])
assert_equal(c.nets_by_name("net*").collect(&:name), [])
nl.case_sensitive = false
assert_equal(c.nets_by_name("NET*").collect(&:name), ["NET1", "NET2"])
assert_equal(c.nets_by_name("net*").collect(&:name), ["NET1", "NET2"])
nl.case_sensitive = true
assert_equal(net1.pin_count, 0)
c.connect_pin(pina1, net1)

View File

@ -333,6 +333,8 @@ END
assert_equal(logger.text(), <<"END")
begin_circuit INV INV
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_pins $0 $1
@ -459,6 +461,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets INT $10
net_mismatch IN IN
@ -487,6 +491,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_ambiguous_nets INT $10
@ -515,6 +521,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets INT $10
net_mismatch IN IN
@ -545,6 +553,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_ambiguous_nets INT $10
@ -574,6 +584,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_ambiguous_nets INT $10
@ -636,17 +648,20 @@ END
# NOTE: adding this power hint makes the device class error harder to detect
ca = nl1.circuit_by_name("BUF")
cb = nl2.circuit_by_name("BUF")
comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"))
comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"))
comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"), false)
comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"), false)
comp.same_nets(ca.net_by_name("OUT"), cb.net_by_name("OUT"), false)
good = comp.compare(nl1, nl2)
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
match_nets VDD VDD
match_nets VSS VSS
match_nets OUT OUT
match_nets INT $10
match_nets IN IN
net_mismatch INT2 $11
net_mismatch OUT OUT
match_pins $0 $1
match_pins $1 $3
match_pins $2 $0
@ -666,6 +681,157 @@ END
end
def test_6b
nls1 = <<"END"
circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOSB $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOSB $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
end;
END
nls2 = <<"END"
circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOSB $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
end;
END
nl1 = RBA::Netlist::new
nl2 = RBA::Netlist::new
prep_nl(nl1, nls1)
prep_nl(nl2, nls2)
logger = NetlistCompareTestLogger::new
comp = RBA::NetlistComparer::new(logger)
# NOTE: adding this power hint makes the device class error harder to detect
ca = nl1.circuit_by_name("BUF")
cb = nl2.circuit_by_name("BUF")
comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"), true)
comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"), true)
comp.same_nets(ca.net_by_name("OUT"), cb.net_by_name("OUT"), true)
good = comp.compare(nl1, nl2)
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
net_mismatch VDD VDD
match_nets VSS VSS
net_mismatch OUT OUT
match_nets INT $10
match_nets IN IN
net_mismatch INT2 $11
match_pins $0 $1
match_pins $1 $3
match_pins $2 $0
match_pins $3 $2
match_devices $1 $1
match_devices $3 $2
match_devices $5 $3
match_devices_with_different_device_classes $7 $4
match_devices $2 $5
match_devices $4 $6
match_devices $6 $7
match_devices $8 $8
end_circuit BUF BUF NOMATCH
END
assert_equal(good, false)
end
def test_6c
nls1 = <<"END"
circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOSB $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOSB $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
end;
END
nls2 = <<"END"
circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
device NMOSB $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
end;
END
nl1 = RBA::Netlist::new
nl2 = RBA::Netlist::new
prep_nl(nl1, nls1)
prep_nl(nl2, nls2)
logger = NetlistCompareTestLogger::new
comp = RBA::NetlistComparer::new(logger)
# NOTE: adding this power hint makes the device class error harder to detect
ca = nl1.circuit_by_name("BUF")
cb = nl2.circuit_by_name("BUF")
comp.same_nets(ca, cb, ca.net_by_name("VDD"), cb.net_by_name("VDD"), true)
comp.same_nets(ca, cb, ca.net_by_name("VSS"), nil, false)
comp.same_nets(ca, cb, ca.net_by_name("OUT"), nil, true)
good = comp.compare(nl1, nl2)
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
net_mismatch VDD VDD
match_nets VSS (null)
net_mismatch OUT (null)
match_nets INT $10
match_nets IN IN
net_mismatch INT2 (null)
net_mismatch (null) VSS
net_mismatch (null) OUT
net_mismatch (null) $11
match_pins $0 $1
match_pins $2 $0
match_pins $1 (null)
match_pins $3 (null)
match_pins (null) $2
match_pins (null) $3
match_devices $1 $1
device_mismatch $3 $2
device_mismatch $5 $3
device_mismatch (null) $4
device_mismatch $6 $5
device_mismatch $4 $6
device_mismatch $2 $7
device_mismatch (null) $8
device_mismatch $7 (null)
device_mismatch $8 (null)
end_circuit BUF BUF NOMATCH
END
assert_equal(good, false)
end
def test_7
nls1 = <<"END"
@ -713,6 +879,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
match_nets VDD VDD
match_nets VSS VSS
net_mismatch INT $10
match_nets IN IN
net_mismatch INT2 $11