From 08af8d85c4de03da7f9af92a4be4c1722c0ba661 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 26 Feb 2020 00:20:18 +0100 Subject: [PATCH] WIP: first algorithm - is capable of deriving the 'resistor cube' symmetry. --- src/db/db/dbNetlistCompare.cc | 132 +++++++++++++++++++++ src/db/db/dbNetlistCompare.h | 3 + src/db/unit_tests/dbNetlistCompareTests.cc | 54 +++++++++ 3 files changed, 189 insertions(+) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 4ac53a39a..d2309665f 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -3626,4 +3626,136 @@ NetlistComparer::do_subcircuit_assignment (const db::Circuit *c1, const db::NetG } } +// @@@ + +bool derive_symmetry_groups (const db::NetGraph &graph, const tl::equivalence_clusters &identical_nodes, std::set &considered_nodes, const std::set &symmetry_group, std::list > &symmetry_groups) +{ + std::set cids; + std::set new_symmetry_group; + NetGraphNode::edge_type::first_type edge; + + bool has_candidate = true; + + for (std::set::const_iterator g = symmetry_group.begin (); g != symmetry_group.end (); ++g) { + + const NetGraphNode &n = graph.node (*g); + for (NetGraphNode::edge_iterator e = n.begin (); e != n.end () && has_candidate; ++e) { + + if (considered_nodes.find (e->second.first) != considered_nodes.end ()) { + continue; + } + + const NetGraphNode *other = &graph.node (e->second.first); + if (identical_nodes.has_attribute (other)) { + + if (cids.empty ()) { + edge = e->first; + } else if (edge != e->first) { + has_candidate = false; + } + + if (has_candidate) { + cids.insert (identical_nodes.cluster_id (other)); + if (cids.size () > 1) { + has_candidate = false; + } else { + new_symmetry_group.insert (e->second.first); + } + } + + } + + } + + } + + if (has_candidate && ! cids.empty () && new_symmetry_group.size () > 1) { + + considered_nodes.insert (new_symmetry_group.begin (), new_symmetry_group.end ()); + + if (derive_symmetry_groups (graph, identical_nodes, considered_nodes, new_symmetry_group, symmetry_groups)) { + + symmetry_groups.push_back (new_symmetry_group); + + } else { + + std::set cn; + std::set_difference (considered_nodes.begin (), considered_nodes.end (), new_symmetry_group.begin (), new_symmetry_group.end (), std::inserter (cn, cn.begin ())); + considered_nodes.swap (cn); + + has_candidate = false; + + } + + } + + return has_candidate; +} + +void join_symmetric_nodes (db::Circuit *circuit) +{ + db::CircuitCategorizer circuit_categorizer; + db::DeviceCategorizer device_categorizer; + db::CircuitPinMapper circuit_pin_mapper; + db::DeviceFilter device_filter (0.0, 0.0); + std::map circuit_and_pin_mapping; + + db::NetGraph graph; + graph.build (circuit, device_categorizer, circuit_categorizer, device_filter, &circuit_and_pin_mapping, &circuit_pin_mapper); + + // sort the nodes so we can easily identify the identical ones (in terms of topology) + // nodes are identical if the attached devices and circuits are of the same kind and with the same parameters + // and connect to other nodes in identical configurations. + + std::vector nodes; + + nodes.reserve (graph.end () - graph.begin ()); + for (db::NetGraph::node_iterator i = graph.begin (); i != graph.end (); ++i) { + if (! i->has_other () && i->net ()) { + nodes.push_back (i.operator-> ()); + } + } + + std::sort (nodes.begin (), nodes.end (), CompareNodePtr ()); + + // Identical nodes leading to the same nodes on the other side are candidates for symmetry. + + tl::equivalence_clusters identical_nodes; + + for (std::vector::const_iterator np = nodes.begin (); np + 1 != nodes.end (); ++np) { + if (*np[0] == *np[1]) { + identical_nodes.same (np[0], np[1]); + } + } + + std::list > symmetry_groups; + std::set considered_nodes; + + for (std::vector::const_iterator np = nodes.begin (); np != nodes.end (); ++np) { + + size_t node_id = graph.node_index_for_net (np[0]->net ()); + if (considered_nodes.find (node_id) != considered_nodes.end ()) { + continue; + } + considered_nodes.insert (node_id); + + std::set symmetry_group; + symmetry_group.insert (node_id); + + derive_symmetry_groups (graph, identical_nodes, considered_nodes, symmetry_group, symmetry_groups); + + } + + printf("@@@ symmetry groups:\n"); + for (std::list >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) { + printf("@@@ group:\n"); + for (std::set::const_iterator i = g->begin (); i != g->end (); ++i) { + printf("@@@ %s\n", graph.node (*i).net () ? graph.node (*i).net ()->expanded_name ().c_str () : "(null)"); + } + } + fflush(stdout); + +} +// @@@ + } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index 0ba957017..1fee52fff 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -328,6 +328,9 @@ protected: bool m_dont_consider_net_names; }; +// @@@ +void DB_PUBLIC join_symmetric_nodes (db::Circuit *circuit); + } namespace tl diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index db3f02048..9be38bace 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -3703,3 +3703,57 @@ TEST(24_NodesRemovedButConnectedInOther) ); EXPECT_EQ (good, true); } + +TEST(25_SplitGates) +{ + const char *nls1 = + "circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n" + " device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n" + " device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n" + // NOTE: $1 and $2 are separate nets, but can be joined due to symmetry + " device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1);\n" + " device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1);\n" + " device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1);\n" + " device NMOS $6 (S=$2,G=B,D=VSS) (L=0.25,W=1);\n" + "end;\n"; + + nls1 = + "circuit NAND2 (A=A,B=B);\n" + " device RES $1 (A=A,B=$1) (R=1000);\n" + " device RES $2 (A=A,B=$2) (R=1000);\n" + " device RES $3 (A=A,B=$3) (R=1000);\n" + " device RES $4 (A=$1,B=$4) (R=1000);\n" + " device RES $5 (A=$2,B=$4) (R=1000);\n" + " device RES $6 (A=$2,B=$5) (R=1000);\n" + " device RES $7 (A=$3,B=$5) (R=1000);\n" + " device RES $8 (A=$3,B=$6) (R=1000);\n" + " device RES $9 (A=$1,B=$6) (R=1000);\n" + " device RES $9 (A=$4,B=B) (R=1000);\n" + " device RES $10 (A=$5,B=B) (R=1000);\n" + " device RES $11 (A=$6,B=B) (R=1000);\n" + "end;\n"; + + const char *nls2 = + "circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD);\n" + " device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1);\n" + " device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1);\n" + " device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=2);\n" + " device NMOS $4 (S=$1,G=B,D=VSS) (L=0.25,W=2);\n" + "end;\n"; + + db::Netlist nl1, nl2; + prep_nl (nl1, nls1); + prep_nl (nl2, nls2); + + db::join_symmetric_nodes (nl1.circuit_by_name ("NAND2")); // @@@ +#if 0 + NetlistCompareTestLogger logger; + db::NetlistComparer comp (&logger); + + bool good = comp.compare (&nl1, &nl2); + + std::string txt = logger.text (); + + printf("@@@\n%s", txt.c_str()); fflush(stdout); // @@@ +#endif +}