From b391b4510fc8d085b90399b4468e1c18dc655375 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 31 Mar 2019 09:53:51 +0200 Subject: [PATCH] WIP: can compare empty circuits now Empty circuits play a role as abstracts. They are compared by using the pin names the nets are attached to. The implementation change is: * nodes without device terminals or subcircuit pins are compared through their net properties (count and name of pins attached) * some enhancements of the net string serializer have been made to account for pin name mismatches. --- src/db/db/dbNetlist.cc | 20 +++- src/db/db/dbNetlistCompare.cc | 129 +++++++++++++++++---- src/db/unit_tests/dbNetlistCompareTests.cc | 57 ++++----- 3 files changed, 151 insertions(+), 55 deletions(-) diff --git a/src/db/db/dbNetlist.cc b/src/db/db/dbNetlist.cc index a1fdcab96..4396c8e4d 100644 --- a/src/db/db/dbNetlist.cc +++ b/src/db/db/dbNetlist.cc @@ -606,7 +606,10 @@ static db::Net *read_net (tl::Extractor &ex, db::Circuit *circuit, std::map &n2n) { - size_t npins = circuit->pin_count (); + std::vector org_pins; + for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) { + org_pins.push_back (p->name ()); + } circuit->clear_pins (); @@ -627,6 +630,10 @@ static void read_pins (tl::Extractor &ex, db::Circuit *circuit, std::mappin_count () < org_pins.size () && pn != org_pins [circuit->pin_count ()]) { + ex.error (tl::sprintf (tl::to_string (tr ("Circuit defines different name for pin than subcircuit: %s (circuit) vs. %s (subcircuit)")), pn, org_pins [circuit->pin_count ()])); + } + const db::Pin &pin = circuit->add_pin (pn); if (net) { net->add_pin (db::NetPinRef (pin.id ())); @@ -636,8 +643,10 @@ static void read_pins (tl::Extractor &ex, db::Circuit *circuit, std::mappin_count () < npins) { + if (circuit->pin_count () < org_pins.size ()) { ex.error (tl::to_string (tr ("Circuit defines less pins that subcircuit"))); + } else if (org_pins.size () > 0 && circuit->pin_count () > org_pins.size ()) { + ex.error (tl::to_string (tr ("Circuit defines more pins that subcircuit"))); } } @@ -753,7 +762,12 @@ static void read_subcircuit_pins (tl::Extractor &ex, db::Circuit *circuit, db::S while (! ex.test (")")) { std::string pn; - ex.read_word_or_quoted (pn); + if (ex.test ("$")) { + size_t i; + ex.read (i); + } else { + ex.read_word_or_quoted (pn); + } ex.expect ("="); diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 3905c97f5..0cff104fa 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -287,7 +287,7 @@ static size_t translate_terminal_id (size_t tid, const db::Device *device) return device->device_class () ? device->device_class ()->normalize_terminal_id (tid) : tid; } -class NetDeviceGraphNode +class NetGraphNode { public: struct EdgeDesc { @@ -310,7 +310,11 @@ public: bool operator< (const EdgeDesc &other) const { - if (m_id1 > std::numeric_limits::max () / 2) { + if (is_for_subcircuit () != other.is_for_subcircuit ()) { + return is_for_subcircuit () < other.is_for_subcircuit (); + } + + if (is_for_subcircuit ()) { if ((subcircuit_pair ().first != 0) != (other.subcircuit_pair ().first != 0)) { return (subcircuit_pair ().first != 0) < (other.subcircuit_pair ().first != 0); @@ -346,7 +350,11 @@ public: bool operator== (const EdgeDesc &other) const { - if (m_id1 > std::numeric_limits::max () / 2) { + if (is_for_subcircuit () != other.is_for_subcircuit ()) { + return false; + } + + if (is_for_subcircuit ()) { if ((subcircuit_pair ().first != 0) != (other.subcircuit_pair ().first != 0)) { return false; @@ -381,6 +389,11 @@ public: char m_ref [sizeof (std::pair)]; size_t m_id1, m_id2; + inline bool is_for_subcircuit () const + { + return m_id1 > std::numeric_limits::max () / 2; + } + std::pair &device_pair () { return *reinterpret_cast *> ((void *) &m_ref); @@ -412,7 +425,7 @@ public: typedef std::vector, std::pair > >::const_iterator edge_iterator; - NetDeviceGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const std::map *circuit_map, const CircuitPinMapper *pin_map) + NetGraphNode (const db::Net *net, DeviceCategorizer &device_categorizer, CircuitCategorizer &circuit_categorizer, const std::map *circuit_map, const CircuitPinMapper *pin_map) : mp_net (net), m_other_net_index (std::numeric_limits::max ()) { if (! net) { @@ -544,6 +557,11 @@ public: m_other_net_index = index; } + bool empty () const + { + return m_edges.empty (); + } + void apply_net_index (const std::map &ni) { for (std::vector, std::pair > >::iterator i = m_edges.begin (); i != m_edges.end (); ++i) { @@ -560,7 +578,7 @@ public: std::sort (m_edges.begin (), m_edges.end ()); } - bool operator< (const NetDeviceGraphNode &node) const + bool operator< (const NetGraphNode &node) const { if (m_edges.size () != node.m_edges.size ()) { return m_edges.size () < node.m_edges.size (); @@ -570,10 +588,14 @@ public: return m_edges [i].first < node.m_edges [i].first; } } + if (m_edges.empty ()) { + // do a more detailed analysis on the edges + return edge_less (net (), node.net ()); + } return false; } - bool operator== (const NetDeviceGraphNode &node) const + bool operator== (const NetGraphNode &node) const { if (m_edges.size () != node.m_edges.size ()) { return false; @@ -583,10 +605,14 @@ public: return false; } } + if (m_edges.empty ()) { + // do a more detailed analysis on the edges + return edge_equal (net (), node.net ()); + } return true; } - void swap (NetDeviceGraphNode &other) + void swap (NetGraphNode &other) { std::swap (m_other_net_index, other.m_other_net_index); std::swap (mp_net, other.mp_net); @@ -605,7 +631,7 @@ public: edge_iterator find_edge (const std::vector &edge) const { - edge_iterator res = std::lower_bound (begin (), end (), edge, NetDeviceGraphNode::EdgeToEdgeOnlyCompare ()); + edge_iterator res = std::lower_bound (begin (), end (), edge, NetGraphNode::EdgeToEdgeOnlyCompare ()); if (res == end () || res->first != edge) { return end (); } else { @@ -617,6 +643,59 @@ private: const db::Net *mp_net; size_t m_other_net_index; std::vector, std::pair > > m_edges; + + /** + * @brief Compares edges as "less" + * Edge comparison is based on the pins attached (name of the first pin) or net + * name if no pins are attached on both nets. + */ + static bool edge_less (const db::Net *a, const db::Net *b) + { + if ((a != 0) != (b != 0)) { + return (a != 0) < (b != 0); + } + if (a != 0) { + if (a->pin_count () != b->pin_count ()) { + return a->pin_count () < b->pin_count (); + } + if (a->pin_count () > 0) { + const std::string &pna = a->begin_pins ()->pin ()->name (); + const std::string &pnb = b->begin_pins ()->pin ()->name (); + if (! pna.empty () && ! pnb.empty ()) { + return pna < pnb; + } + } + return a->name () < b->name (); + } else { + return false; + } + } + + /** + * @brief Compares edges as "equal" + * See edge_less for the comparison details. + */ + static bool edge_equal (const db::Net *a, const db::Net *b) + { + if ((a != 0) != (b != 0)) { + return false; + } + if (a != 0) { + if (a->pin_count () != b->pin_count ()) { + return false; + } + if (a->pin_count () > 0) { + const std::string &pna = a->begin_pins ()->pin ()->name (); + const std::string &pnb = b->begin_pins ()->pin ()->name (); + if (! pna.empty () && ! pnb.empty ()) { + return pna == pnb; + } + } + return a->name () == b->name (); + } else { + return true; + } + } }; // -------------------------------------------------------------------------------------------------------------------- @@ -626,7 +705,7 @@ private: namespace std { - void swap (db::NetDeviceGraphNode &a, db::NetDeviceGraphNode &b) + void swap (db::NetGraphNode &a, db::NetGraphNode &b) { a.swap (b); } @@ -638,7 +717,7 @@ namespace db class NetDeviceGraph { public: - typedef std::vector::const_iterator node_iterator; + typedef std::vector::const_iterator node_iterator; NetDeviceGraph () { @@ -653,7 +732,7 @@ public: m_net_index.clear (); // create a dummy node for a null net - m_nodes.push_back (NetDeviceGraphNode (0, device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper)); + m_nodes.push_back (NetGraphNode (0, device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper)); size_t nets = 0; for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { @@ -662,16 +741,16 @@ public: m_nodes.reserve (nets); for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { - NetDeviceGraphNode node (n.operator-> (), device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper); + NetGraphNode node (n.operator-> (), device_categorizer, circuit_categorizer, circuit_and_pin_mapping, circuit_pin_mapper); m_nodes.push_back (node); } std::sort (m_nodes.begin (), m_nodes.end ()); - for (std::vector::const_iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { + for (std::vector::const_iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { m_net_index.insert (std::make_pair (i->net (), i - m_nodes.begin ())); } - for (std::vector::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { + for (std::vector::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { i->apply_net_index (m_net_index); } } @@ -717,15 +796,15 @@ public: for (std::vector::const_iterator index = todo.begin (); index != todo.end (); ++index) { - NetDeviceGraphNode *n = & m_nodes[*index]; - NetDeviceGraphNode *nother = & other.m_nodes[n->other_net_index ()]; + NetGraphNode *n = & m_nodes[*index]; + NetGraphNode *nother = & other.m_nodes[n->other_net_index ()]; // non-ambiguous paths to non-assigned nodes create a node identity on the // end of this path - for (NetDeviceGraphNode::edge_iterator e = n->begin (); e != n->end (); ) { + for (NetGraphNode::edge_iterator e = n->begin (); e != n->end (); ) { - NetDeviceGraphNode::edge_iterator ee = e; + NetGraphNode::edge_iterator ee = e; ++ee; while (ee != n->end () && ee->first == e->first) { @@ -733,8 +812,8 @@ public: } size_t count = 0; - NetDeviceGraphNode::edge_iterator ec; - for (NetDeviceGraphNode::edge_iterator i = e; i != ee; ++i) { + NetGraphNode::edge_iterator ec; + for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { if (! m_nodes[i->second.first].has_other ()) { ec = i; ++count; @@ -747,13 +826,13 @@ public: tl::log << "considering " << n->net ()->expanded_name () << " to " << ec->second.second->expanded_name (); #endif - NetDeviceGraphNode::edge_iterator e_other = nother->find_edge (ec->first); + NetGraphNode::edge_iterator e_other = nother->find_edge (ec->first); if (e_other != nother->end ()) { #if defined(PRINT_DEBUG_NETCOMPARE) tl::log << "candidate accepted"; #endif - NetDeviceGraphNode::edge_iterator ee_other = e_other; + NetGraphNode::edge_iterator ee_other = e_other; ++ee_other; while (ee_other != nother->end () && ee_other->first == e_other->first) { @@ -761,8 +840,8 @@ public: } size_t count_other = 0; - NetDeviceGraphNode::edge_iterator ec_other; - for (NetDeviceGraphNode::edge_iterator i = e_other; i != ee_other; ++i) { + NetGraphNode::edge_iterator ec_other; + for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) { if (! other.m_nodes[i->second.first].has_other ()) { ec_other = i; ++count_other; @@ -807,7 +886,7 @@ public: } private: - std::vector m_nodes; + std::vector m_nodes; std::map m_net_index; }; diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 0def3a631..8406093f5 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -1316,18 +1316,6 @@ TEST(14_Subcircuit2MatchWithSwap) TEST(15_EmptySubCircuitTest) { const char *nls1 = - "circuit RINGO ();\n" - " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" - "end;\n" "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" @@ -1342,22 +1330,10 @@ TEST(15_EmptySubCircuitTest) "end;\n"; const char *nls2 = - "circuit RINGO ();\n" - " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $4 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $5 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $6 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" - " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" - "end;\n" "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" - " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" - " device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $1 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $3 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" " subcircuit TRANS $1 (G=$4,S=$2,D=IN);\n" " subcircuit TRANS $2 (G=$5,S=$2,D=IN);\n" @@ -1378,7 +1354,34 @@ TEST(15_EmptySubCircuitTest) bool good = comp.compare (&nl1, &nl2); EXPECT_EQ (logger.text (), - "..." + "begin_circuit TRANS TRANS\n" + "match_nets $3 $3\n" + "match_nets $2 $1\n" + "match_nets $1 $2\n" + "match_pins D D\n" + "match_pins G G\n" + "match_pins S S\n" + "end_circuit TRANS TRANS MATCH\n" + "begin_circuit INV2 INV2\n" + "match_nets IN IN\n" + "match_nets $5 $5\n" + "match_nets $4 $4\n" + "match_nets OUT OUT\n" + "match_nets $2 $2\n" + "match_pins IN IN\n" + "match_pins $4 $4\n" + "match_pins $3 $3\n" + "match_pins OUT OUT\n" + "match_pins $1 $1\n" + "match_devices $1 $1\n" + "match_devices $3 $2\n" + "match_devices $2 $3\n" + "match_devices $4 $4\n" + "match_subcircuits $1 $1\n" + "match_subcircuits $2 $2\n" + "match_subcircuits $3 $3\n" + "match_subcircuits $4 $4\n" + "end_circuit INV2 INV2 MATCH" ); EXPECT_EQ (good, true);