diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 7c5e399b3..04e58dcf2 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -3749,14 +3749,16 @@ NetlistComparer::join_symmetric_nodes (db::Circuit *circuit) } std::list > symmetry_groups; - std::set considered_nodes; + std::set visited; 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 ()) { + if (visited.find (node_id) != visited.end ()) { continue; } + + std::set considered_nodes; considered_nodes.insert (node_id); std::set symmetry_group; @@ -3764,16 +3766,8 @@ NetlistComparer::join_symmetric_nodes (db::Circuit *circuit) derive_symmetry_groups (graph, identical_nodes, considered_nodes, symmetry_group, symmetry_groups); - } + visited.insert (considered_nodes.begin (), considered_nodes.end ()); - // join the nets - - for (std::list >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) { - for (std::set::const_iterator i = g->begin (); i != g->end (); ++i) { - if (i != g->begin ()) { - circuit->join_nets (const_cast (graph.net_by_node_index (*g->begin ())), const_cast (graph.net_by_node_index (*i))); - } - } } if (! symmetry_groups.empty () && tl::verbosity () >= 30) { @@ -3789,6 +3783,15 @@ NetlistComparer::join_symmetric_nodes (db::Circuit *circuit) } } + // join the nets + + for (std::list >::const_iterator g = symmetry_groups.begin (); g != symmetry_groups.end (); ++g) { + for (std::set::const_iterator i = g->begin (); i != g->end (); ++i) { + if (i != g->begin ()) { + circuit->join_nets (const_cast (graph.net_by_node_index (*g->begin ())), const_cast (graph.net_by_node_index (*i))); + } + } + } } } diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index f72de7b75..5c89e8012 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -3704,9 +3704,9 @@ TEST(24_NodesRemovedButConnectedInOther) EXPECT_EQ (good, true); } -TEST(25_SplitGates) +TEST(25_JoinSymmetricNets) { - const char *nls1 = + const char *nls = "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" @@ -3717,8 +3717,29 @@ TEST(25_SplitGates) " 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" + db::Netlist nl; + prep_nl (nl, nls); + + db::NetlistComparer comp; + comp.join_symmetric_nodes (nl.circuit_by_name ("NAND2")); + + // NOTE $1 and $2 are joined because they are symmetric + EXPECT_EQ (nl.to_string (), + "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,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $4 (S=$1,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $6 (S=$1,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + "end;\n" + ) +} + +TEST(26_JoinSymmetricNets) +{ + const char *nls = + "circuit RESCUBE (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" @@ -3733,25 +3754,113 @@ TEST(25_SplitGates) " 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::Netlist nl; + prep_nl (nl, nls); db::NetlistComparer comp; - comp.join_symmetric_nodes (nl1.circuit_by_name ("NAND2")); // @@@ -#if 0 - bool good = comp.compare (&nl1, &nl2); + comp.join_symmetric_nodes (nl.circuit_by_name ("RESCUBE")); - std::string txt = logger.text (); + EXPECT_EQ (nl.to_string (), + "circuit RESCUBE (A=A,B=B);\n" + " device RES $1 (A=A,B=$1) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $2 (A=A,B=$1) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $3 (A=A,B=$1) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $4 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $5 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $6 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $7 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $8 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $9 (A=$1,B=$4) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $10 (A=$4,B=B) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $11 (A=$4,B=B) (R=1000,L=0,W=0,A=0,P=0);\n" + " device RES $12 (A=$4,B=B) (R=1000,L=0,W=0,A=0,P=0);\n" + "end;\n" + ) - printf("@@@\n%s", txt.c_str()); fflush(stdout); // @@@ -#endif + nl.combine_devices (); + EXPECT_EQ (nl.to_string (), + "circuit RESCUBE (A=A,B=B);\n" + " device RES $10 (A=A,B=B) (R=833.333333333,L=0,W=0,A=0,P=0);\n" + "end;\n" + ) } + +TEST(27_DontJoinSymmetricNetsWithPins) +{ + const char *nls = + "circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD,X=$1,Y=$2);\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"; + + db::Netlist nl; + prep_nl (nl, nls); + + db::NetlistComparer comp; + comp.join_symmetric_nodes (nl.circuit_by_name ("NAND2")); + + // NOTE $1 and $2 are NOT joined because they have pins + EXPECT_EQ (nl.to_string (), + "circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VDD=VDD,X=$1,Y=$2);\n" + " device PMOS $1 (S=OUT,G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S=VDD,G=B,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $3 (S=$1,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $6 (S=$2,G=B,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + "end;\n" + ) +} + +TEST(28_NoSymmetryDetectionCases) +{ + { + const char *nls = + "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 cannot be joined because of different W + " 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.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"; + + db::Netlist nl; + prep_nl (nl, nls); + + db::NetlistComparer comp; + std::string sref = nl.to_string (); + comp.join_symmetric_nodes (nl.circuit_by_name ("NAND2")); + + EXPECT_EQ (nl.to_string (), sref); + } + + { + const char *nls = + "circuit NAND2 (A=A,B=B,OUT=OUT,VSS=VSS,VSS2=VSS2,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=1);\n" + " device NMOS $4 (S=$2,G=A,D=OUT) (L=0.25,W=1);\n" + // NOTE: $1 and $2 are separate nets, but cannot be joined because of different D connections + " device NMOS $5 (S=$1,G=B,D=VSS) (L=0.25,W=1);\n" + " device NMOS $6 (S=$2,G=B,D=VSS2) (L=0.25,W=1);\n" + "end;\n"; + + db::Netlist nl; + prep_nl (nl, nls); + + db::NetlistComparer comp; + std::string sref = nl.to_string (); + comp.join_symmetric_nodes (nl.circuit_by_name ("NAND2")); + + EXPECT_EQ (nl.to_string (), sref); + } +} +