WIP: enhanced backtracking of netlist compare.

This commit is contained in:
Matthias Koefferlein 2019-04-12 00:15:36 +02:00
parent e03a524fcf
commit 187baf2941
2 changed files with 350 additions and 185 deletions

View File

@ -859,14 +859,9 @@ public:
* If tentative is true, assignments will not be retained and just the
* status is reported.
*/
size_t derive_node_identities (size_t net_index, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative);
size_t derive_node_identities (size_t net_index, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative, bool with_ambiguous);
size_t derive_node_identities_from_node_set (const std::vector<const NetGraphNode *> &nodes, const std::vector<const NetGraphNode *> &other_nodes, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative, bool picky);
size_t derive_node_identities (size_t net_index, NetDeviceGraph &other, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper)
{
return derive_node_identities (net_index, other, 0, 1, logger, circuit_pin_mapper, false);
}
size_t derive_node_identities_from_node_set (const std::vector<const NetGraphNode *> &nodes, const std::vector<const NetGraphNode *> &other_nodes, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative, bool with_ambiguous);
private:
std::vector<NetGraphNode> m_nodes;
@ -915,7 +910,7 @@ NetDeviceGraph::build (const db::Circuit *c, DeviceCategorizer &device_categoriz
}
size_t
NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative)
NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative, bool with_ambiguous)
{
NetGraphNode *n = & m_nodes[net_index];
NetGraphNode *nother = & other.m_nodes[n->other_net_index ()];
@ -984,7 +979,34 @@ NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other,
std::sort (nodes.begin (), nodes.end (), CompareNodePtr ());
std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ());
derive_node_identities_from_node_set (nodes, other_nodes, other, depth, n_branch, logger, circuit_pin_mapper, tentative, true);
// for the purpose of match evaluation we require an exact match of the node structure
if (tentative && (nodes.size () > 1 || other_nodes.size () > 1)) {
if (nodes.size () != other_nodes.size ()) {
return std::numeric_limits<size_t>::max ();
}
for (size_t i = 0; i < nodes.size (); ++i) {
if (! (*nodes[i] == *other_nodes[i]) || nodes[i]->has_other () != other_nodes[i]->has_other ()) {
return std::numeric_limits<size_t>::max ();
}
}
}
// propagate pairing in picky mode: this means we only accept exact a match if the node set
// is exactly identical and no ambiguous nodes are present when ambiguous nodes are forbidden
size_t bt_count = derive_node_identities_from_node_set (nodes, other_nodes, other, depth, n_branch, logger, circuit_pin_mapper, tentative, with_ambiguous);
if (bt_count == std::numeric_limits<size_t>::max ()) {
if (tentative) {
return bt_count;
}
} else {
new_nodes += bt_count;
}
}
@ -993,7 +1015,7 @@ NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other,
}
#if defined(PRINT_DEBUG_NETCOMPARE)
if (! tentative && new_nodes > 0 && new_nodes != std::numeric_limits<size_t>::max ()) {
if (! tentative && new_nodes > 0) {
tl::info << "finished pair deduction: " << n->net ()->expanded_name () << " vs. " << nother->net ()->expanded_name () << " with " << new_nodes << " new pairs";
}
#endif
@ -1001,8 +1023,29 @@ NetDeviceGraph::derive_node_identities (size_t net_index, NetDeviceGraph &other,
return new_nodes;
}
namespace {
struct NodeRange
{
NodeRange (size_t _num, std::vector<const NetGraphNode *>::const_iterator _n1, std::vector<const NetGraphNode *>::const_iterator _nn1, std::vector<const NetGraphNode *>::const_iterator _n2, std::vector<const NetGraphNode *>::const_iterator _nn2)
: num (_num), n1 (_n1), nn1 (_nn1), n2 (_n2), nn2 (_nn2)
{
// .. nothing yet ..
}
bool operator< (const NodeRange &other) const
{
return num < other.num;
}
size_t num;
std::vector<const NetGraphNode *>::const_iterator n1, nn1, n2, nn2;
};
}
size_t
NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const NetGraphNode *> &nodes, const std::vector<const NetGraphNode *> &other_nodes, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative, bool picky)
NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const NetGraphNode *> &nodes, const std::vector<const NetGraphNode *> &other_nodes, NetDeviceGraph &other, size_t depth, size_t n_branch, NetlistCompareLogger *logger, CircuitPinMapper *circuit_pin_mapper, bool tentative, bool with_ambiguous)
{
size_t new_nodes = 0;
@ -1031,7 +1074,7 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
}
// unconditionally continue here.
derive_node_identities (ni, other, depth + 1, n_branch, logger, circuit_pin_mapper, false);
derive_node_identities (ni, other, depth + 1, n_branch, logger, circuit_pin_mapper, tentative, with_ambiguous);
}
@ -1040,19 +1083,9 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
}
if (picky) {
// Determine the range of nodes with same identity
if (nodes.size () != other_nodes.size ()) {
return std::numeric_limits<size_t>::max ();
}
for (size_t i = 0; i < nodes.size (); ++i) {
if (! (*nodes[i] == *other_nodes[i]) || nodes[i]->has_other () != other_nodes[i]->has_other ()) {
return std::numeric_limits<size_t>::max ();
}
}
}
std::vector<NodeRange> node_ranges;
std::vector<const NetGraphNode *>::const_iterator n1 = nodes.begin ();
std::vector<const NetGraphNode *>::const_iterator n2 = other_nodes.begin ();
@ -1094,36 +1127,61 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
}
}
if (num == 1) {
if (num == 1 || with_ambiguous) {
node_ranges.push_back (NodeRange (num, n1, nn1, n2, nn2));
}
// a single candiate: just take this one -> this may render
// inexact matches, but further propagates net pairing
// in tentative mode ambiguous nodes don't make a match without
// with_ambiguous
if (num > 1 && tentative && ! with_ambiguous) {
return std::numeric_limits<size_t>::max ();
}
if (! tentative) {
n1 = nn1;
n2 = nn2;
size_t ni = node_index_for_net ((*n1)->net ());
size_t other_ni = other.node_index_for_net ((*n2)->net ());
}
identify (ni, other_ni);
other.identify (other_ni, ni);
if (with_ambiguous) {
std::stable_sort (node_ranges.begin (), node_ranges.end ());
}
for (std::vector<NodeRange>::const_iterator nr = node_ranges.begin (); nr != node_ranges.end (); ++nr) {
if (nr->num == 1) {
if (! (*nr->n1)->has_other () && ! (*nr->n2)->has_other ()) {
// A single candiate: just take this one -> this may render
// inexact matches, but further propagates net pairing
if (! tentative) {
size_t ni = node_index_for_net ((*nr->n1)->net ());
size_t other_ni = other.node_index_for_net ((*nr->n2)->net ());
identify (ni, other_ni);
other.identify (other_ni, ni);
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << "deduced match (singular): " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name ();
#endif
if (logger) {
logger->match_nets ((*nr->n1)->net (), (*nr->n2)->net ());
}
// unconditionally continue here.
derive_node_identities (ni, other, depth + 1, n_branch, logger, circuit_pin_mapper, tentative, with_ambiguous);
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << "deduced match (singular): " << (*n1)->net ()->expanded_name () << " vs. " << (*n2)->net ()->expanded_name ();
#endif
if (logger) {
logger->match_nets ((*n1)->net (), (*n2)->net ());
}
// unconditionally continue here.
derive_node_identities (ni, other, depth + 1, n_branch, logger, circuit_pin_mapper, false);
new_nodes += 1;
}
new_nodes += 1;
} else {
if (num * n_branch > n_branch_max) {
if (nr->num * n_branch > n_branch_max) {
return std::numeric_limits<size_t>::max ();
}
@ -1131,7 +1189,7 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
tl::equivalence_clusters<const NetGraphNode *> equivalent_other_nodes;
std::set<const NetGraphNode *> seen;
for (std::vector<const NetGraphNode *>::const_iterator i1 = n1; i1 != nn1; ++i1) {
for (std::vector<const NetGraphNode *>::const_iterator i1 = nr->n1; i1 != nr->nn1; ++i1) {
if ((*i1)->has_other ()) {
continue;
@ -1140,7 +1198,7 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
bool any = false;
std::vector<const NetGraphNode *>::const_iterator i2;
for (i2 = n2; i2 != nn2; ++i2) {
for (i2 = nr->n2; i2 != nr->nn2; ++i2) {
if ((*i2)->has_other ()) {
continue;
@ -1156,13 +1214,16 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
identify (ni, other_ni);
other.identify (other_ni, ni);
size_t bt_count = derive_node_identities (ni, other, depth + 1, num * n_branch, logger, circuit_pin_mapper, true /*tentative*/);
// try this candidate in tentative mode
size_t bt_count = derive_node_identities (ni, other, depth + 1, nr->num * n_branch, logger, circuit_pin_mapper, true /*tentative*/, with_ambiguous);
unidentify (ni);
other.unidentify (other_ni);
if (bt_count != std::numeric_limits<size_t>::max ()) {
// we have a match ...
if (any) {
// there is already a known pair, so we can mark *i2 and the previous *i2 as equivalent
@ -1183,7 +1244,7 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
}
if (! any && picky) {
if (! any && tentative) {
// a mismatch - stop here.
return std::numeric_limits<size_t>::max ();
}
@ -1262,7 +1323,7 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
size_t ni = node_index_for_net (p->first->net ());
size_t bt_count = derive_node_identities (ni, other, depth + 1, num * n_branch, logger, circuit_pin_mapper, false /*not tentative*/);
size_t bt_count = derive_node_identities (ni, other, depth + 1, nr->num * n_branch, logger, circuit_pin_mapper, tentative, with_ambiguous);
tl_assert (bt_count != std::numeric_limits<size_t>::max ());
}
@ -1271,9 +1332,6 @@ NetDeviceGraph::derive_node_identities_from_node_set (const std::vector<const Ne
}
n1 = nn1;
n2 = nn2;
}
return new_nodes;
@ -1566,77 +1624,85 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
int iter = 0;
#endif
bool good = true;
while (true) {
// two passes: one without ambiguities, the second one with
#if defined(PRINT_DEBUG_NETCOMPARE)
++iter;
tl::info << "new compare iteration #" << iter;
tl::info << "deducing from present nodes ...";
#endif
bool good;
size_t new_identities = 0;
for (int pass = 0; pass < 2; ++pass) {
for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) {
if (i1->has_other () && i1->net ()) {
size_t ni = g1.derive_node_identities (i1 - g1.begin (), g2, mp_logger, mp_circuit_pin_mapper.get ());
if (ni > 0 && ni != std::numeric_limits<size_t>::max ()) {
new_identities += ni;
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << ni << " new identities.";
#endif
good = true;
while (true) {
#if defined(PRINT_DEBUG_NETCOMPARE)
++iter;
tl::info << "new compare iteration #" << iter;
tl::info << "deducing from present nodes ...";
#endif
size_t new_identities = 0;
for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) {
if (i1->has_other () && i1->net ()) {
size_t ni = g1.derive_node_identities (i1 - g1.begin (), g2, 0, 1, mp_logger, mp_circuit_pin_mapper.get (), false /*not tentative*/, pass > 0 /*with ambiguities*/);
if (ni > 0 && ni != std::numeric_limits<size_t>::max ()) {
new_identities += ni;
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << ni << " new identities.";
#endif
}
}
}
}
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << "checking topological identity ...";
#endif
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << "checking topological identity ...";
#endif
// derive new identities through topology: first collect all nets with the same topological signature
// derive new identities through topology: first collect all nets with the same topological signature
std::vector<const NetGraphNode *> nodes, other_nodes;
std::vector<const NetGraphNode *> nodes, other_nodes;
nodes.reserve (g1.end () - g1.begin ());
for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) {
if (! i1->has_other () && i1->net ()) {
nodes.push_back (i1.operator-> ());
nodes.reserve (g1.end () - g1.begin ());
for (db::NetDeviceGraph::node_iterator i1 = g1.begin (); i1 != g1.end (); ++i1) {
if (! i1->has_other () && i1->net ()) {
nodes.push_back (i1.operator-> ());
}
}
}
other_nodes.reserve (g2.end () - g2.begin ());
for (db::NetDeviceGraph::node_iterator i2 = g2.begin (); i2 != g2.end (); ++i2) {
if (! i2->has_other () && i2->net ()) {
other_nodes.push_back (i2.operator-> ());
other_nodes.reserve (g2.end () - g2.begin ());
for (db::NetDeviceGraph::node_iterator i2 = g2.begin (); i2 != g2.end (); ++i2) {
if (! i2->has_other () && i2->net ()) {
other_nodes.push_back (i2.operator-> ());
}
}
}
if (nodes.empty () || other_nodes.empty ()) {
if (! nodes.empty () || ! other_nodes.empty ()) {
if (nodes.empty () || other_nodes.empty ()) {
if (! nodes.empty () || ! other_nodes.empty ()) {
good = false;
}
// this assumes that we don't gain anything here. Stop now.
break;
}
std::sort (nodes.begin (), nodes.end (), CompareNodePtr ());
std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ());
size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, g2, 0, 1, mp_logger, mp_circuit_pin_mapper.get (), false /*not tentative*/, pass > 0 /*with ambiguities*/);
if (ni > 0 && ni != std::numeric_limits<size_t>::max ()) {
new_identities += ni;
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << ni << " new identities.";
#endif
}
if (new_identities == 0) {
good = false;
break;
}
break;
}
std::sort (nodes.begin (), nodes.end (), CompareNodePtr ());
std::sort (other_nodes.begin (), other_nodes.end (), CompareNodePtr ());
size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, g2, 0, 1, mp_logger, mp_circuit_pin_mapper.get (), false /*not tentative*/, false /*don't require a full match*/);
if (ni > 0 && ni != std::numeric_limits<size_t>::max ()) {
new_identities += ni;
#if defined(PRINT_DEBUG_NETCOMPARE)
tl::info << ni << " new identities.";
#endif
}
if (new_identities == 0) {
good = false;
break;
}
}
// Report missing net assignment
for (db::NetDeviceGraph::node_iterator i = g1.begin (); i != g1.end (); ++i) {

View File

@ -335,9 +335,9 @@ TEST(1_SimpleInverter)
EXPECT_EQ (logger.text (),
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -384,9 +384,9 @@ TEST(1_SimpleInverterMatchedDeviceClasses)
EXPECT_EQ (logger.text (),
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -427,8 +427,8 @@ TEST(1_SimpleInverterSkippedDevices)
EXPECT_EQ (logger.text (),
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets VSS VSS\n"
"match_nets IN IN\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
@ -451,9 +451,9 @@ TEST(1_SimpleInverterSkippedDevices)
EXPECT_EQ (logger.text (),
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -536,11 +536,11 @@ TEST(3_Buffer)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets OUT OUT\n"
"match_nets INT $10\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_nets INT $10\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -591,12 +591,12 @@ TEST(4_BufferTwoPaths)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets IN IN\n"
"match_nets OUT OUT\n"
"match_nets VSS VSS\n"
"match_nets INT $10\n"
"match_nets INT2 $11\n"
"match_nets IN IN\n"
"match_ambiguous_nets INT $10\n"
"match_ambiguous_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -658,9 +658,9 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_ambiguous_nets INT $10\n"
"match_nets INT2 $11\n"
"match_nets INT $10\n"
"match_nets IN IN\n"
"match_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -685,8 +685,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets INT2 $11\n"
"match_nets INT $10\n"
"match_ambiguous_nets INT $10\n"
"match_ambiguous_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -710,9 +710,9 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_ambiguous_nets INT $10\n"
"match_nets INT2 $11\n"
"match_nets INT $10\n"
"match_nets IN IN\n"
"match_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -736,9 +736,9 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_ambiguous_nets INT $10\n"
"match_nets INT2 $11\n"
"match_nets INT $10\n"
"match_nets IN IN\n"
"match_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -763,8 +763,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets INT2 $11\n"
"match_nets INT $10\n"
"match_ambiguous_nets INT $10\n"
"match_ambiguous_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -790,8 +790,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets INT2 $11\n"
"match_nets INT $10\n"
"match_ambiguous_nets INT $10\n"
"match_ambiguous_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -816,9 +816,9 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"match_nets OUT OUT\n"
"match_ambiguous_nets INT $10\n"
"match_nets INT2 $11\n"
"match_nets INT $10\n"
"match_nets IN IN\n"
"match_nets INT2 $11\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1006,11 +1006,11 @@ TEST(6_BufferTwoPathsAdditionalDevices)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
"match_nets INT $11\n"
"match_nets IN IN\n"
"match_nets VDD VDD\n"
"match_nets OUT OUT\n"
"match_nets VSS VSS\n"
"match_nets IN IN\n"
"match_nets INT2 $10\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1057,9 +1057,9 @@ TEST(7_Resistors)
EXPECT_EQ (logger.text (),
"begin_circuit TRIANGLE TRIANGLE\n"
"match_nets P2 P2\n"
"match_nets P1 P1\n"
"match_nets P3 P3\n"
"match_nets P2 P2\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
@ -1223,7 +1223,7 @@ TEST(8_DiodesDontMatchOnSwappedPins)
EXPECT_EQ (logger.text (),
"begin_circuit TRIANGLE TRIANGLE\n"
"match_ambiguous_nets P1 P3\n"
"match_nets P1 P3\n"
"match_nets P2 P1\n"
"match_nets P3 P2\n"
"match_pins $0 $2\n"
@ -1272,9 +1272,9 @@ TEST(10_SimpleSubCircuits)
EXPECT_EQ (logger.text (),
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1284,9 +1284,9 @@ TEST(10_SimpleSubCircuits)
"end_circuit INV INV MATCH\n"
"begin_circuit TOP TOP\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets INT INT\n"
"match_pins $0 $2\n"
"match_pins $1 $0\n"
@ -1339,9 +1339,9 @@ TEST(10_SimpleSubCircuitsMatchedNames)
EXPECT_EQ (logger.text (),
"begin_circuit INV INVB\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1351,9 +1351,9 @@ TEST(10_SimpleSubCircuitsMatchedNames)
"end_circuit INV INVB MATCH\n"
"begin_circuit TOP TOP\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets INT INT\n"
"match_pins $0 $2\n"
"match_pins $1 $0\n"
@ -1404,18 +1404,28 @@ TEST(11_MismatchingSubcircuits)
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"net_mismatch VDD (null)\n"
"net_mismatch (null) VDD\n"
"match_nets VDD VDD\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"pin_mismatch $2 (null)\n"
"match_pins $2 $0\n"
"match_pins $3 $2\n"
"pin_mismatch (null) $0\n"
"device_mismatch $1 (null)\n"
"match_devices $2 $1\n"
"device_mismatch (null) $2\n"
"device_mismatch $1 (null)\n"
"end_circuit INV INV NOMATCH\n"
"circuit_skipped TOP TOP"
"begin_circuit TOP TOP\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"match_pins $0 $2\n"
"match_pins $1 $0\n"
"match_pins $2 $1\n"
"match_pins $3 $3\n"
"match_subcircuits $2 $1\n"
"match_subcircuits $1 $2\n"
"end_circuit TOP TOP MATCH"
);
EXPECT_EQ (good, false);
@ -1456,9 +1466,9 @@ TEST(12_MismatchingSubcircuitsDuplicates)
EXPECT_EQ (logger.text (),
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1471,17 +1481,14 @@ TEST(12_MismatchingSubcircuitsDuplicates)
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"net_mismatch OUT (null)\n"
"net_mismatch (null) OUT\n"
"match_nets OUT OUT\n"
"match_pins $0 $1\n"
"pin_mismatch $1 (null)\n"
"match_pins $1 $0\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"pin_mismatch (null) $0\n"
"subcircuit_mismatch $2 (null)\n"
"subcircuit_mismatch $3 (null)\n"
"subcircuit_mismatch (null) $1\n"
"match_subcircuits $2 $1\n"
"match_subcircuits $1 $2\n"
"subcircuit_mismatch $3 (null)\n"
"end_circuit TOP TOP NOMATCH"
);
@ -1527,9 +1534,9 @@ TEST(13_MismatchingSubcircuitsAdditionalHierarchy)
"circuit_mismatch VIA (null)\n"
"begin_circuit INV INV\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_pins $0 $1\n"
"match_pins $1 $3\n"
"match_pins $2 $0\n"
@ -1539,9 +1546,9 @@ TEST(13_MismatchingSubcircuitsAdditionalHierarchy)
"end_circuit INV INV MATCH\n"
"begin_circuit TOP TOP\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets INT INT\n"
"match_pins $0 $1\n"
"match_pins $1 $0\n"
@ -1594,11 +1601,11 @@ TEST(14_Subcircuit2Nand)
EXPECT_EQ (logger.text (),
"begin_circuit NAND NAND\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets B B\n"
"match_nets OUT OUT\n"
"match_nets A A\n"
"match_nets INT INT\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
@ -1611,11 +1618,11 @@ TEST(14_Subcircuit2Nand)
"end_circuit NAND NAND MATCH\n"
"begin_circuit TOP TOP\n"
"match_nets OUT OUT\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets IN1 IN1\n"
"match_nets INT INT\n"
"match_nets IN2 IN2\n"
"match_nets INT INT\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
@ -1668,11 +1675,11 @@ TEST(14_Subcircuit2NandMismatchNoSwap)
EXPECT_EQ (logger.text (),
"begin_circuit NAND NAND\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets B B\n"
"match_nets OUT OUT\n"
"match_nets A A\n"
"match_nets INT INT\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
@ -1689,18 +1696,16 @@ TEST(14_Subcircuit2NandMismatchNoSwap)
"match_nets INT IN1\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"net_mismatch IN2 (null)\n"
"net_mismatch (null) IN2\n"
"match_nets IN2 IN2\n"
"pin_mismatch $0 (null)\n"
"pin_mismatch $1 (null)\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"match_pins $4 $4\n"
"pin_mismatch (null) $1\n"
"pin_mismatch (null) $0\n"
"subcircuit_mismatch $1 (null)\n"
"match_subcircuits $2 $1\n"
"subcircuit_mismatch (null) $2\n"
"subcircuit_mismatch $1 (null)\n"
"end_circuit TOP TOP NOMATCH"
);
@ -1746,11 +1751,11 @@ TEST(14_Subcircuit2MatchWithSwap)
EXPECT_EQ (logger.text (),
"begin_circuit NAND NAND\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets B B\n"
"match_nets OUT OUT\n"
"match_nets A A\n"
"match_nets INT INT\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
@ -1763,11 +1768,11 @@ TEST(14_Subcircuit2MatchWithSwap)
"end_circuit NAND NAND MATCH\n"
"begin_circuit TOP TOP\n"
"match_nets OUT OUT\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets IN1 IN1\n"
"match_nets INT INT\n"
"match_nets IN2 IN2\n"
"match_nets INT INT\n"
"match_nets VDD VDD\n"
"match_nets VSS VSS\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
@ -1831,11 +1836,11 @@ TEST(15_EmptySubCircuitTest)
"match_pins D D\n"
"end_circuit TRANS TRANS MATCH\n"
"begin_circuit INV2 INV2\n"
"match_nets IN IN\n"
"match_nets OUT OUT\n"
"match_nets $5 $5\n"
"match_nets $4 $4\n"
"match_nets OUT OUT\n"
"match_nets $2 $2\n"
"match_nets IN IN\n"
"match_nets $4 $4\n"
"match_pins IN IN\n"
"match_pins $1 $1\n"
"match_pins OUT OUT\n"
@ -1905,11 +1910,11 @@ TEST(15_EmptySubCircuitWithoutPinNames)
"match_pins $2 $2\n"
"end_circuit TRANS TRANS MATCH\n"
"begin_circuit INV2 INV2\n"
"match_nets $5 $5\n"
"match_nets OUT OUT\n"
"match_nets $2 $2\n"
"match_nets IN IN\n"
"match_nets $4 $4\n"
"match_nets $2 $2\n"
"match_nets $5 $5\n"
"match_pins IN IN\n"
"match_pins $1 $1\n"
"match_pins OUT OUT\n"
@ -1980,12 +1985,12 @@ TEST(16_UniqueSubCircuitMatching)
EXPECT_EQ (logger.text (),
"begin_circuit INV2 INV2\n"
"match_nets VDD VDD\n"
"match_nets OUT OUT\n"
"match_nets $3 $3\n"
"match_nets $1 $1\n"
"match_nets IN IN\n"
"match_nets VSS VSS\n"
"match_nets BULK BULK\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_nets $3 $3\n"
"match_pins $0 $0\n"
"match_pins IN IN\n"
"match_pins $2 $2\n"
@ -2000,14 +2005,14 @@ TEST(16_UniqueSubCircuitMatching)
"end_circuit INV2 INV2 MATCH\n"
"begin_circuit INV2PAIR INV2PAIR\n"
"match_nets $I2 $I2\n"
"match_nets $I3 $I3\n"
"match_nets BULK BULK\n"
"match_nets $I6 $I6\n"
"match_nets $I5 $I5\n"
"match_nets $I4 $I4\n"
"match_nets $I1 $I1\n"
"match_nets $I3 $I3\n"
"match_nets $I7 $I7\n"
"match_nets $I4 $I4\n"
"match_nets $I5 $I5\n"
"match_nets $I8 $I8\n"
"match_nets $I6 $I6\n"
"match_nets BULK BULK\n"
"match_pins BULK BULK\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
@ -2020,17 +2025,17 @@ TEST(16_UniqueSubCircuitMatching)
"end_circuit INV2PAIR INV2PAIR MATCH\n"
"begin_circuit RINGO RINGO\n"
"match_nets OSC OSC\n"
"match_nets FB FB\n"
"match_nets VDD VDD\n"
"match_nets BULK,VSS BULK,VSS\n"
"match_nets FB FB\n"
"match_nets $I22 $I22\n"
"match_nets VDD VDD\n"
"match_nets $I13 $I13\n"
"match_nets $I23 $I23\n"
"match_nets $I5 $I5\n"
"match_nets $I24 $I24\n"
"match_nets $I6 $I6\n"
"match_nets $I25 $I25\n"
"match_nets $I7 $I7\n"
"match_nets $I25 $I25\n"
"match_nets $I6 $I6\n"
"match_nets $I24 $I24\n"
"match_subcircuits $1 $1\n"
"match_subcircuits $4 $2\n"
"match_subcircuits $3 $3\n"
@ -2041,3 +2046,97 @@ TEST(16_UniqueSubCircuitMatching)
EXPECT_EQ (good, true);
}
TEST(17_InherentlyAmbiguousDecoder)
{
const char *nls1 =
"circuit NAND ($0=A,$1=B,$2=OUT,$3=VDD,$4=VSS);\n"
" device PMOS $1 (S=VDD,G=A,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $3 (S=VSS,G=A,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $4 (S=INT,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
"end;\n"
"circuit DECODER ($0=A,$1=B,$2=NQ0,$3=NQ1,$4=NQ2,$5=NQ3,$6=VDD,$7=VSS);\n"
" subcircuit NAND $1 ($0=A,$1=A,$2=NA,$3=VDD,$4=VSS);\n"
" subcircuit NAND $2 ($0=B,$1=B,$2=NB,$3=VDD,$4=VSS);\n"
" subcircuit NAND $3 ($0=NA,$1=NB,$2=NQ0,$3=VDD,$4=VSS);\n"
" subcircuit NAND $4 ($0=A,$1=NB,$2=NQ1,$3=VDD,$4=VSS);\n"
" subcircuit NAND $5 ($0=NA,$1=B,$2=NQ2,$3=VDD,$4=VSS);\n"
" subcircuit NAND $6 ($0=A,$1=B,$2=NQ3,$3=VDD,$4=VSS);\n"
"end;\n";
const char *nls2 =
"circuit NAND ($0=A,$1=B,$2=OUT,$3=VDD,$4=VSS);\n"
" device PMOS $1 (S=VDD,G=A,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $3 (S=VSS,G=A,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
" device NMOS $4 (S=INT,G=B,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n"
"end;\n"
"circuit DECODER ($0=A,$1=B,$2=NQ0,$3=NQ1,$4=NQ2,$5=NQ3,$6=VDD,$7=VSS);\n"
" subcircuit NAND $1 ($0=B,$1=B,$2=NB,$3=VDD,$4=VSS);\n"
" subcircuit NAND $2 ($0=A,$1=NB,$2=NQ1,$3=VDD,$4=VSS);\n"
" subcircuit NAND $3 ($0=A,$1=A,$2=NA,$3=VDD,$4=VSS);\n"
" subcircuit NAND $4 ($0=A,$1=B,$2=NQ3,$3=VDD,$4=VSS);\n"
" subcircuit NAND $5 ($0=NA,$1=NB,$2=NQ0,$3=VDD,$4=VSS);\n"
" subcircuit NAND $6 ($0=NA,$1=B,$2=NQ2,$3=VDD,$4=VSS);\n"
"end;\n";
db::Netlist nl1, nl2;
prep_nl (nl1, nls1);
prep_nl (nl2, nls2);
NetlistCompareTestLogger logger;
db::NetlistComparer comp (&logger);
comp.equivalent_pins (nl2.circuit_by_name ("NAND"), 0, 1);
bool good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
"begin_circuit NAND NAND\n"
"match_nets VSS VSS\n"
"match_nets INT INT\n"
"match_nets OUT OUT\n"
"match_nets VDD VDD\n"
"match_nets B B\n"
"match_nets A A\n"
"match_pins $0 $0\n"
"match_pins $1 $1\n"
"match_pins $2 $2\n"
"match_pins $3 $3\n"
"match_pins $4 $4\n"
"match_devices $1 $1\n"
"match_devices $2 $2\n"
"match_devices $3 $3\n"
"match_devices $4 $4\n"
"end_circuit NAND NAND MATCH\n"
"begin_circuit DECODER DECODER\n"
"match_nets NA NB\n"
"match_nets A B\n"
"match_nets VDD VDD\n"
"match_nets B A\n"
"match_nets NB NA\n"
"match_nets VSS VSS\n"
"match_ambiguous_nets NQ0 NQ0\n"
"match_ambiguous_nets NQ2 NQ1\n"
"match_ambiguous_nets NQ1 NQ2\n"
"match_ambiguous_nets NQ3 NQ3\n"
"match_pins $0 $1\n"
"match_pins $1 $0\n"
"match_pins $2 $2\n"
"match_pins $3 $4\n"
"match_pins $4 $3\n"
"match_pins $5 $5\n"
"match_pins $6 $6\n"
"match_pins $7 $7\n"
"match_subcircuits $1 $1\n"
"match_subcircuits $5 $2\n"
"match_subcircuits $2 $3\n"
"match_subcircuits $6 $4\n"
"match_subcircuits $3 $5\n"
"match_subcircuits $4 $6\n"
"end_circuit DECODER DECODER MATCH"
);
EXPECT_EQ (good, true);
}