From 0c5293410076307f99859b9c83296f6f160a47f5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 26 May 2024 15:17:58 +0200 Subject: [PATCH 01/13] Trying a solution for issue #1719, part 2 The solution is to drop clusters that have no area and not connections downward. This implies, we cannot connect from upward to such clusters - i.e. we cannot force a pin inside a subcircuit with a plain text. We need some polygon at least. This is not a problem as texts were not enough so far anyway. --- src/db/db/dbHierNetworkProcessor.cc | 21 ++++++ src/lvs/unit_tests/lvsSimpleTests.cc | 12 ++++ testdata/lvs/stray_texts.gds | Bin 0 -> 1742 bytes testdata/lvs/stray_texts1.cir | 12 ++++ testdata/lvs/stray_texts1.l2n | 98 +++++++++++++++++++++++++++ testdata/lvs/stray_texts1.lvs | 28 ++++++++ testdata/lvs/stray_texts2.cir | 12 ++++ testdata/lvs/stray_texts2.l2n | 96 ++++++++++++++++++++++++++ testdata/lvs/stray_texts2.lvs | 25 +++++++ 9 files changed, 304 insertions(+) create mode 100644 testdata/lvs/stray_texts.gds create mode 100644 testdata/lvs/stray_texts1.cir create mode 100644 testdata/lvs/stray_texts1.l2n create mode 100644 testdata/lvs/stray_texts1.lvs create mode 100644 testdata/lvs/stray_texts2.cir create mode 100644 testdata/lvs/stray_texts2.l2n create mode 100644 testdata/lvs/stray_texts2.lvs diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index bd7dbd903..4c868b8fa 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -2903,11 +2903,32 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c } bs2.process (*rec, 1 /*touching*/, local_cluster_box_convert (), cibc); + } // join local clusters which got connected by child clusters rec->finish_cluster_to_instance_interactions (); + { + // remove empty or point-like clusters which do not make a downward connection - i.e. from stray texts. + // This implies, we cannot connect from upward down to such nets too. In other words: to force a pin, + // inside a cell we need more than a text. + // (issue #1719, part 2) + std::vector::id_type> to_delete; + for (typename connected_clusters::const_iterator c = local.begin (); c != local.end (); ++c) { + box_type bbox = c->bbox (); + if ((bbox.empty () || (bbox.width () == 0 && bbox.height () == 0)) && local.connections_for_cluster (c->id ()).empty ()) { + to_delete.push_back (c->id ()); + } + } + for (auto i = to_delete.begin (); i != to_delete.end (); ++i) { + local.remove_cluster (*i); + } + if (tl::verbosity () >= m_base_verbosity + 20) { + tl::info << "Removed " << to_delete.size () << " clusters because they are point-like or empty and do not have connections downward (stray texts)"; + } + } + if (tl::verbosity () >= m_base_verbosity + 20) { tl::info << "Cluster build cache statistics (instance to shape cache): size=" << rec->cluster_cache_size () << ", hits=" << rec->cluster_cache_hits () << ", misses=" << rec->cluster_cache_misses (); } diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 1f06fefcf..050f039eb 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -338,3 +338,15 @@ TEST(55_SoftConnectionSecondLevel) { run_test (_this, "soft_connect6", "soft_connect6.gds", true, false /*no LVS*/); } + +// Issue #1719, part 2 +TEST(60_StrayTextsDoNotMakeNets) +{ + run_test (_this, "stray_texts1", "stray_texts.gds", true, false /*no LVS*/); +} + +// Issue #1719, part 2 +TEST(61_StrayTextsDoNotMakeNets) +{ + run_test (_this, "stray_texts2", "stray_texts.gds", true, false /*no LVS*/); +} diff --git a/testdata/lvs/stray_texts.gds b/testdata/lvs/stray_texts.gds new file mode 100644 index 0000000000000000000000000000000000000000..d97c2a0da4043fb3b5b83577beed7bfb781acf79 GIT binary patch literal 1742 zcma)+ze^lZ5XZm!ZtvZCcLs9_5#>q=K_o&NNs54a1`p34g@ss%Sc;?yVqsycbt==O z2uYX9!aqPHMT(H(2q{wq5wVxM^*j4^yd$~i?ZNUnX6HNeW@hKX!k9Hw15@~mJVsGO z1a$vLWNf2813b>Aqnx|2>&`D!JL$;}3~(gDv7^}{FD1XD+DWgzv_U=l zCp64iu6C$)?O*wBeoth6b~xZyQkE&k&l%+ccEnDzl`<>8Z|es$Jk8?E9B;G6Wz6^V zZA)CX>+PzL-_IXDzy4*vDGqG% zB;RE+bLmOa8^(0sFgIY_ZO)NhG;8UGCRDr7 Date: Sun, 26 May 2024 17:08:34 +0200 Subject: [PATCH 02/13] Updating unit tests - stray text nets are gone. --- src/db/db/dbHierNetworkProcessor.cc | 2 +- testdata/lvs/bbdevices1.cir | 4 ---- testdata/lvs/bbdevices1.lvsdb | 12 ------------ testdata/lvs/bbdevices2.cir | 4 ---- testdata/lvs/bbdevices2.lvsdb | 12 ------------ testdata/lvs/bbdevices3.cir | 4 ---- testdata/lvs/bbdevices3.lvsdb | 12 ------------ testdata/lvs/bbdevices4.cir | 4 ---- testdata/lvs/bbdevices4.lvsdb | 12 ------------ testdata/lvs/bbdevices5.cir | 4 ---- testdata/lvs/bbdevices5.lvsdb | 12 ------------ testdata/lvs/bbdevices6.cir | 4 ---- testdata/lvs/bbdevices6.lvsdb | 12 ------------ 13 files changed, 1 insertion(+), 97 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 4c868b8fa..4c5c089ea 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -2917,7 +2917,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c std::vector::id_type> to_delete; for (typename connected_clusters::const_iterator c = local.begin (); c != local.end (); ++c) { box_type bbox = c->bbox (); - if ((bbox.empty () || (bbox.width () == 0 && bbox.height () == 0)) && local.connections_for_cluster (c->id ()).empty ()) { + if ((bbox.empty () || (bbox.width () == 0 && bbox.height () == 0)) && c->get_global_nets ().empty () && local.connections_for_cluster (c->id ()).empty ()) { to_delete.push_back (c->id ()); } } diff --git a/testdata/lvs/bbdevices1.cir b/testdata/lvs/bbdevices1.cir index 80ce62dca..2738f6c53 100644 --- a/testdata/lvs/bbdevices1.cir +++ b/testdata/lvs/bbdevices1.cir @@ -47,7 +47,6 @@ X$14 4 BBGATEST .SUBCKT BBGATEST 2 * net 1 B * net 2 A -* net 3 BBGATEST .ENDS BBGATEST * cell FBGATEST @@ -55,7 +54,6 @@ X$14 4 BBGATEST .SUBCKT FBGATEST 1 * net 1 B * net 2 A -* net 3 FBGATEST .ENDS FBGATEST * cell FWBTEST @@ -63,7 +61,6 @@ X$14 4 BBGATEST .SUBCKT FWBTEST 2 * net 1 B * net 2 A -* net 3 FWBTEST .ENDS FWBTEST * cell BWBTEST @@ -71,5 +68,4 @@ X$14 4 BBGATEST .SUBCKT BWBTEST 2 * net 1 B * net 2 A -* net 3 BWBTEST .ENDS BWBTEST diff --git a/testdata/lvs/bbdevices1.lvsdb b/testdata/lvs/bbdevices1.lvsdb index 27cd08e35..482fe39a9 100644 --- a/testdata/lvs/bbdevices1.lvsdb +++ b/testdata/lvs/bbdevices1.lvsdb @@ -60,9 +60,6 @@ layout( rect(l15 (576500 -249000) (105500 81500)) rect(l15 (-52750 -40750) (0 0)) ) - net(3 name(BWBTEST) - rect(l15 (754500 -114000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -82,9 +79,6 @@ layout( rect(l3 (572500 432500) (74500 73500)) rect(l3 (-37250 -36750) (0 0)) ) - net(3 name(FWBTEST) - rect(l3 (798000 565500) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -104,9 +98,6 @@ layout( rect(l3 (-449500 422500) (146000 144500)) rect(l3 (-71000 -71250) (0 0)) ) - net(3 name(FBGATEST) - rect(l3 (-417000 610500) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -126,9 +117,6 @@ layout( rect(l15 (-218500 -290000) (193000 203000)) rect(l15 (-94000 -101500) (0 0)) ) - net(3 name(BBGATEST) - rect(l15 (-422000 -313000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) diff --git a/testdata/lvs/bbdevices2.cir b/testdata/lvs/bbdevices2.cir index bac395789..cad12158b 100644 --- a/testdata/lvs/bbdevices2.cir +++ b/testdata/lvs/bbdevices2.cir @@ -48,7 +48,6 @@ X$14 7 6 BBGATEST .SUBCKT BBGATEST 1 2 * net 1 B * net 2 A -* net 3 BBGATEST .ENDS BBGATEST * cell FBGATEST @@ -57,7 +56,6 @@ X$14 7 6 BBGATEST .SUBCKT FBGATEST 1 2 * net 1 B * net 2 A -* net 3 FBGATEST .ENDS FBGATEST * cell FWBTEST @@ -66,7 +64,6 @@ X$14 7 6 BBGATEST .SUBCKT FWBTEST 1 2 * net 1 B * net 2 A -* net 3 FWBTEST .ENDS FWBTEST * cell BWBTEST @@ -75,5 +72,4 @@ X$14 7 6 BBGATEST .SUBCKT BWBTEST 1 2 * net 1 B * net 2 A -* net 3 BWBTEST .ENDS BWBTEST diff --git a/testdata/lvs/bbdevices2.lvsdb b/testdata/lvs/bbdevices2.lvsdb index c9372a16f..49b82b677 100644 --- a/testdata/lvs/bbdevices2.lvsdb +++ b/testdata/lvs/bbdevices2.lvsdb @@ -60,9 +60,6 @@ layout( rect(l15 (576500 -249000) (105500 81500)) rect(l15 (-52750 -40750) (0 0)) ) - net(3 name(BWBTEST) - rect(l15 (754500 -114000) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -83,9 +80,6 @@ layout( rect(l3 (572500 432500) (74500 73500)) rect(l3 (-37250 -36750) (0 0)) ) - net(3 name(FWBTEST) - rect(l3 (798000 565500) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -106,9 +100,6 @@ layout( rect(l3 (-449500 422500) (146000 144500)) rect(l3 (-71000 -71250) (0 0)) ) - net(3 name(FBGATEST) - rect(l3 (-417000 610500) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -129,9 +120,6 @@ layout( rect(l15 (-218500 -290000) (193000 203000)) rect(l15 (-94000 -101500) (0 0)) ) - net(3 name(BBGATEST) - rect(l15 (-422000 -313000) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) diff --git a/testdata/lvs/bbdevices3.cir b/testdata/lvs/bbdevices3.cir index 82abe4cee..675240f7b 100644 --- a/testdata/lvs/bbdevices3.cir +++ b/testdata/lvs/bbdevices3.cir @@ -47,7 +47,6 @@ X$14 4 BBGATEST .SUBCKT BBGATEST 2 * net 1 B * net 2 A -* net 3 BBGATEST .ENDS BBGATEST * cell FBGATEST @@ -55,7 +54,6 @@ X$14 4 BBGATEST .SUBCKT FBGATEST 1 * net 1 B * net 2 A -* net 3 FBGATEST .ENDS FBGATEST * cell FWBTEST @@ -63,7 +61,6 @@ X$14 4 BBGATEST .SUBCKT FWBTEST 2 * net 1 B * net 2 A -* net 3 FWBTEST .ENDS FWBTEST * cell BWBTEST @@ -71,5 +68,4 @@ X$14 4 BBGATEST .SUBCKT BWBTEST 1 * net 1 B * net 2 A -* net 3 BWBTEST .ENDS BWBTEST diff --git a/testdata/lvs/bbdevices3.lvsdb b/testdata/lvs/bbdevices3.lvsdb index 819e2dbe9..1f7335c95 100644 --- a/testdata/lvs/bbdevices3.lvsdb +++ b/testdata/lvs/bbdevices3.lvsdb @@ -60,9 +60,6 @@ layout( rect(l15 (830000 -249000) (105500 81500)) rect(l15 (-52750 -40750) (0 0)) ) - net(3 name(BWBTEST) - rect(l15 (757500 -114000) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -82,9 +79,6 @@ layout( rect(l3 (572500 432500) (74500 73500)) rect(l3 (-37250 -36750) (0 0)) ) - net(3 name(FWBTEST) - rect(l3 (798000 565500) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -104,9 +98,6 @@ layout( rect(l3 (-449500 422500) (146000 144500)) rect(l3 (-71000 -71250) (0 0)) ) - net(3 name(FBGATEST) - rect(l3 (-417000 610500) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -126,9 +117,6 @@ layout( rect(l15 (-218500 -290000) (193000 203000)) rect(l15 (-94000 -101500) (0 0)) ) - net(3 name(BBGATEST) - rect(l15 (-422000 -313000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) diff --git a/testdata/lvs/bbdevices4.cir b/testdata/lvs/bbdevices4.cir index 61fcf18da..4a99dee30 100644 --- a/testdata/lvs/bbdevices4.cir +++ b/testdata/lvs/bbdevices4.cir @@ -20,7 +20,6 @@ X$13 4 BBGATEST .SUBCKT BWBTEST * net 1 B * net 2 A -* net 3 BWBTEST .ENDS BWBTEST * cell FDPTEST @@ -52,7 +51,6 @@ X$13 4 BBGATEST .SUBCKT BBGATEST 2 * net 1 B * net 2 A -* net 3 BBGATEST .ENDS BBGATEST * cell FBGATEST @@ -60,7 +58,6 @@ X$13 4 BBGATEST .SUBCKT FBGATEST 1 * net 1 B * net 2 A -* net 3 FBGATEST .ENDS FBGATEST * cell FWBTEST @@ -68,5 +65,4 @@ X$13 4 BBGATEST .SUBCKT FWBTEST 2 * net 1 B * net 2 A -* net 3 FWBTEST .ENDS FWBTEST diff --git a/testdata/lvs/bbdevices4.lvsdb b/testdata/lvs/bbdevices4.lvsdb index 5a9aa2c04..fe5d26b4a 100644 --- a/testdata/lvs/bbdevices4.lvsdb +++ b/testdata/lvs/bbdevices4.lvsdb @@ -60,9 +60,6 @@ layout( rect(l3 (572500 432500) (74500 73500)) rect(l3 (-37250 -36750) (0 0)) ) - net(3 name(FWBTEST) - rect(l3 (798000 565500) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -82,9 +79,6 @@ layout( rect(l3 (-449500 422500) (146000 144500)) rect(l3 (-71000 -71250) (0 0)) ) - net(3 name(FBGATEST) - rect(l3 (-417000 610500) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -104,9 +98,6 @@ layout( rect(l15 (-218500 -290000) (193000 203000)) rect(l15 (-94000 -101500) (0 0)) ) - net(3 name(BBGATEST) - rect(l15 (-422000 -313000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -186,9 +177,6 @@ layout( rect(l15 (576500 -249000) (105500 81500)) rect(l15 (-52750 -40750) (0 0)) ) - net(3 name(BWBTEST) - rect(l15 (754500 -114000) (0 0)) - ) ) circuit(testall diff --git a/testdata/lvs/bbdevices5.cir b/testdata/lvs/bbdevices5.cir index de64bad72..5b4ecfb20 100644 --- a/testdata/lvs/bbdevices5.cir +++ b/testdata/lvs/bbdevices5.cir @@ -47,7 +47,6 @@ X$14 5 BWBTEST .SUBCKT BBGATEST 2 * net 1 B * net 2 A -* net 3 BBGATEST .ENDS BBGATEST * cell FBGATEST @@ -55,7 +54,6 @@ X$14 5 BWBTEST .SUBCKT FBGATEST 1 * net 1 B * net 2 A -* net 3 FBGATEST .ENDS FBGATEST * cell FWBTEST @@ -63,7 +61,6 @@ X$14 5 BWBTEST .SUBCKT FWBTEST 2 * net 1 B * net 2 A -* net 3 FWBTEST .ENDS FWBTEST * cell BWBTEST @@ -71,5 +68,4 @@ X$14 5 BWBTEST .SUBCKT BWBTEST 2 * net 1 B * net 2 A -* net 3 BWBTEST .ENDS BWBTEST diff --git a/testdata/lvs/bbdevices5.lvsdb b/testdata/lvs/bbdevices5.lvsdb index 56183ddcd..42cef8ab3 100644 --- a/testdata/lvs/bbdevices5.lvsdb +++ b/testdata/lvs/bbdevices5.lvsdb @@ -60,9 +60,6 @@ layout( rect(l15 (576500 -249000) (105500 81500)) rect(l15 (-52750 -40750) (0 0)) ) - net(3 name(BWBTEST) - rect(l15 (754500 -114000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -82,9 +79,6 @@ layout( rect(l3 (572500 432500) (74500 73500)) rect(l3 (-37250 -36750) (0 0)) ) - net(3 name(FWBTEST) - rect(l3 (798000 565500) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -104,9 +98,6 @@ layout( rect(l3 (-449500 422500) (146000 144500)) rect(l3 (-71000 -71250) (0 0)) ) - net(3 name(FBGATEST) - rect(l3 (-417000 610500) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -126,9 +117,6 @@ layout( rect(l15 (-218500 -290000) (193000 203000)) rect(l15 (-94000 -101500) (0 0)) ) - net(3 name(BBGATEST) - rect(l15 (-422000 -313000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) diff --git a/testdata/lvs/bbdevices6.cir b/testdata/lvs/bbdevices6.cir index 39fba7dc1..22cc76a10 100644 --- a/testdata/lvs/bbdevices6.cir +++ b/testdata/lvs/bbdevices6.cir @@ -47,7 +47,6 @@ X$14 3 FBGATEST .SUBCKT BBGATEST 2 * net 1 B * net 2 A -* net 3 BBGATEST .ENDS BBGATEST * cell FBGATEST @@ -55,7 +54,6 @@ X$14 3 FBGATEST .SUBCKT FBGATEST 1 * net 1 B * net 2 A -* net 3 FBGATEST .ENDS FBGATEST * cell FWBTEST @@ -63,7 +61,6 @@ X$14 3 FBGATEST .SUBCKT FWBTEST 2 * net 1 B * net 2 A -* net 3 FWBTEST .ENDS FWBTEST * cell BWBTEST @@ -71,5 +68,4 @@ X$14 3 FBGATEST .SUBCKT BWBTEST 2 * net 1 B * net 2 A -* net 3 BWBTEST .ENDS BWBTEST diff --git a/testdata/lvs/bbdevices6.lvsdb b/testdata/lvs/bbdevices6.lvsdb index d15a89969..b0264ad49 100644 --- a/testdata/lvs/bbdevices6.lvsdb +++ b/testdata/lvs/bbdevices6.lvsdb @@ -60,9 +60,6 @@ layout( rect(l15 (576500 -249000) (105500 81500)) rect(l15 (-52750 -40750) (0 0)) ) - net(3 name(BWBTEST) - rect(l15 (754500 -114000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -82,9 +79,6 @@ layout( rect(l3 (572500 432500) (74500 73500)) rect(l3 (-37250 -36750) (0 0)) ) - net(3 name(FWBTEST) - rect(l3 (798000 565500) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) @@ -104,9 +98,6 @@ layout( rect(l3 (-449500 422500) (146000 144500)) rect(l3 (-71000 -71250) (0 0)) ) - net(3 name(FBGATEST) - rect(l3 (-417000 610500) (0 0)) - ) # Outgoing pins and their connections to nets pin(1 name(B)) @@ -126,9 +117,6 @@ layout( rect(l15 (-218500 -290000) (193000 203000)) rect(l15 (-94000 -101500) (0 0)) ) - net(3 name(BBGATEST) - rect(l15 (-422000 -313000) (0 0)) - ) # Outgoing pins and their connections to nets pin(2 name(A)) From 994b23abf6fed97e7a23833d97ebf4e3a02b4be4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 26 May 2024 17:23:50 +0200 Subject: [PATCH 03/13] Refining solution of issue #1719, part 2 --- src/db/db/dbHierNetworkProcessor.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 4c5c089ea..7f2acce95 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -2817,6 +2817,18 @@ private: std::map m_global_net_to_entries; }; +template +struct is_for_nets +{ + static bool value () { return false; } +}; + +template <> +struct is_for_nets +{ + static bool value () { return true; } +}; + } template @@ -2909,7 +2921,8 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // join local clusters which got connected by child clusters rec->finish_cluster_to_instance_interactions (); - { + if (is_for_nets::value ()) { + // remove empty or point-like clusters which do not make a downward connection - i.e. from stray texts. // This implies, we cannot connect from upward down to such nets too. In other words: to force a pin, // inside a cell we need more than a text. @@ -2927,6 +2940,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c if (tl::verbosity () >= m_base_verbosity + 20) { tl::info << "Removed " << to_delete.size () << " clusters because they are point-like or empty and do not have connections downward (stray texts)"; } + } if (tl::verbosity () >= m_base_verbosity + 20) { From 14b1fddcc54ea9ae9dcc5ea4767a4dca0f70c728 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 26 May 2024 19:32:15 +0200 Subject: [PATCH 04/13] Trying to improve must-connect error messages * Avoid repetitions * Include geometry for nets if possible * Better wording * All joined nets tested together - leaner code --- src/db/db/dbLayoutToNetlist.cc | 194 ++++++++++++++---- src/db/db/dbLayoutToNetlist.h | 4 +- src/lvs/unit_tests/lvsTests.cc | 2 +- testdata/lvs/double_height2.lvsdb | 6 +- testdata/lvs/double_height2_texts.lvsdb | 6 +- testdata/lvs/must_connect1.lvsdb | 2 +- testdata/lvs/must_connect1_tl.lvsdb | 2 +- testdata/lvs/must_connect2.lvsdb | 6 +- .../ringo_simple_implicit_connections.lvsdb.1 | 2 +- .../ringo_simple_implicit_connections.lvsdb.2 | 2 +- testdata/lvs/test_22a.lvsdb.1 | 2 +- testdata/lvs/test_22a.lvsdb.2 | 2 +- testdata/lvs/test_22b.lvsdb.1 | 2 +- testdata/lvs/test_22b.lvsdb.2 | 2 +- testdata/lvs/test_22c.lvsdb.1 | 2 +- testdata/lvs/test_22c.lvsdb.2 | 2 +- testdata/lvs/test_22d.lvsdb.1 | 2 +- testdata/lvs/test_22d.lvsdb.2 | 2 +- testdata/lvs/test_22d.lvsdb.3 | 2 +- 19 files changed, 176 insertions(+), 68 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index bc865bdc5..9275b442f 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -508,12 +508,37 @@ void LayoutToNetlist::do_join_nets (db::Circuit &c, const std::vector return; } + check_must_connect (c, nets); + for (auto n = nets.begin () + 1; n != nets.end (); ++n) { - check_must_connect (c, *nets [0], **n); c.join_nets (nets [0], *n); } } +void LayoutToNetlist::check_must_connect (const db::Circuit &c, const std::vector &nets) +{ + std::vector unique_nets; + unique_nets.reserve (nets.size ()); + std::set seen; + for (auto n = nets.begin (); n != nets.end (); ++n) { + if (seen.find (*n) == seen.end ()) { + seen.insert (*n); + unique_nets.push_back (*n); + } + } + if (unique_nets.size () < size_t (2)) { + return; + } + + bool same_names = true; + for (auto n = unique_nets.begin () + 1; n != unique_nets.end () && same_names; ++n) { + same_names = (unique_nets.front ()->expanded_name () == (*n)->expanded_name ()); + } + + std::vector path; + check_must_connect_impl (c, unique_nets, c, unique_nets, path, same_names); +} + static std::string subcircuit_to_string (const db::SubCircuit &sc) { if (! sc.name ().empty ()) { @@ -533,14 +558,31 @@ static db::DPolygon subcircuit_geometry (const db::SubCircuit &sc, const db::Lay return db::DPolygon (sc.trans () * dbox); } -void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b) +static db::DBox net_geometry_box (const db::Circuit &c, const db::Net *net, const db::Layout *layout, const db::hier_clusters &net_clusters) { - if (&a == &b) { - return; + if (! layout || ! net) { + return db::DBox (); } - std::vector path; - check_must_connect_impl (c, a, b, c, a, b, path); + auto nc = net_clusters.clusters_per_cell (c.cell_index ()); + auto lc = nc.cluster_by_id (net->cluster_id ()); + + return db::CplxTrans (layout->dbu ()) * lc.bbox (); +} + +static db::DPolygon net_geometry (const db::Circuit &c, const db::Net *net, const db::Layout *layout, const db::hier_clusters &net_clusters) +{ + auto box = net_geometry_box (c, net, layout, net_clusters); + return box.empty () ? db::DPolygon () : db::DPolygon (box); +} + +static db::DPolygon net_geometry (const db::Circuit &c, const std::vector &nets, const db::Layout *layout, const db::hier_clusters &net_clusters) +{ + db::DBox box; + for (auto n = nets.begin (); n != nets.end (); ++n) { + box += net_geometry_box (c, *n, layout, net_clusters); + } + return box.empty () ? db::DPolygon () : db::DPolygon (box); } static std::string path_msg (const std::vector &path) @@ -562,46 +604,98 @@ static std::string path_msg (const std::vector &path) return msg; } -void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::Net &a, const db::Net &b, const db::Circuit &c_org, const db::Net &a_org, const db::Net &b_org, std::vector &path) +static bool all_nets_are_same (const std::vector &nets) +{ + for (auto n = nets.begin () + 1; n != nets.end (); ++n) { + if (*n != nets.front ()) { + return false; + } + } + return true; +} + +static bool no_pins_on_any_net (const std::vector &nets) +{ + for (auto n = nets.begin (); n != nets.end (); ++n) { + if ((*n)->begin_pins () == (*n)->end_pins ()) { + return true; + } + } + return false; +} + +static std::string net_names_msg (const std::vector &nets) +{ + std::set names; + for (auto n = nets.begin (); n != nets.end (); ++n) { + names.insert ((*n)->expanded_name ()); + } + + std::string msg; + size_t num = names.size (); + size_t i = 0; + for (auto n = names.begin (); n != names.end (); ++n, ++i) { + if (i > 0) { + if (i + 1 < num) { + msg += ", "; + } else { + msg += tl::to_string (tr (" and ")); + } + } + msg += *n; + } + + return msg; +} + +void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const std::vector &nets, const db::Circuit &c_org, const std::vector &nets_org, std::vector &path, bool same_names) { if (c.begin_refs () != c.end_refs () && path.empty ()) { - if (a.begin_pins () == a.end_pins ()) { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected to outside")), a_org.expanded_name ())); - error.set_cell_name (c.name ()); - error.set_category_name ("must-connect"); - log_entry (error); - } - if (b.begin_pins () == b.end_pins ()) { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected to outside")), a_org.expanded_name ())); - error.set_cell_name (c.name ()); - error.set_category_name ("must-connect"); - log_entry (error); + for (auto n = nets.begin (); n != nets.end (); ++n) { + + if ((*n)->begin_pins () == (*n)->end_pins ()) { + std::string msg; + if (same_names) { + msg = tl::sprintf (tl::to_string (tr ("Must-connect subnet of %s does not have any pin at all")), (*n)->expanded_name ()); + } else { + msg = tl::sprintf (tl::to_string (tr ("Must-connect net %s does not have any pin at all")), (*n)->expanded_name ()); + } + db::LogEntryData error (db::Error, msg); + error.set_cell_name (c.name ()); + error.set_geometry (net_geometry (c, *n, internal_layout (), net_clusters ())); + error.set_category_name ("must-connect"); + log_entry (error); + } + } - } else if (c.begin_refs () == c.end_refs () || a.begin_pins () == a.end_pins () || b.begin_pins () == b.end_pins ()) { + } else if (c.begin_refs () == c.end_refs () || no_pins_on_any_net (nets)) { - if (a_org.expanded_name () == b_org.expanded_name ()) { + if (same_names) { if (path.empty ()) { - db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name ()) + path_msg (path)); + db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect subnets of %s must be connected further up in the hierarchy - this is an error at chip top level")), nets_org.front ()->expanded_name ()) + path_msg (path)); warn.set_cell_name (c.name ()); + warn.set_geometry (net_geometry (c, nets, internal_layout (), net_clusters ())); warn.set_category_name ("must-connect"); log_entry (warn); } else { - db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), c_org.name ()) + path_msg (path)); + db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect subnets of %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), nets_org.front ()->expanded_name (), c_org.name ()) + path_msg (path)); warn.set_cell_name (c.name ()); warn.set_geometry (subcircuit_geometry (*path.back (), internal_layout ())); warn.set_category_name ("must-connect"); log_entry (warn); } } else { + std::string net_names = net_names_msg (nets_org); if (path.empty ()) { - db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), b_org.expanded_name ()) + path_msg (path)); + db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at chip top level")), net_names) + path_msg (path)); warn.set_cell_name (c.name ()); + warn.set_geometry (net_geometry (c, nets, internal_layout (), net_clusters ())); warn.set_category_name ("must-connect"); log_entry (warn); } else { - db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), a_org.expanded_name (), b_org.expanded_name (), c_org.name ()) + path_msg (path)); + db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s of circuit %s must be connected further up in the hierarchy - this is an error at chip top level")), net_names, c_org.name ()) + path_msg (path)); warn.set_cell_name (c.name ()); warn.set_geometry (subcircuit_geometry (*path.back (), internal_layout ())); warn.set_category_name ("must-connect"); @@ -611,35 +705,49 @@ void LayoutToNetlist::check_must_connect_impl (const db::Circuit &c, const db::N } - if (a.begin_pins () != a.end_pins () && b.begin_pins () != b.end_pins ()) { + if (! no_pins_on_any_net (nets)) { for (auto ref = c.begin_refs (); ref != c.end_refs (); ++ref) { const db::SubCircuit &sc = *ref; // TODO: consider the case of multiple pins on a net (rare) - const db::Net *net_a = sc.net_for_pin (a.begin_pins ()->pin_id ()); - const db::Net *net_b = sc.net_for_pin (b.begin_pins ()->pin_id ()); + std::vector new_nets; + new_nets.reserve (nets.size ()); + + bool failed = false; + std::set seen; + size_t i = 0; + for (auto n = nets.begin (); n != nets.end (); ++n, ++i) { + + if (seen.find (*n) != seen.end ()) { + continue; + } + seen.insert (*n); + + const db::Net *new_net = sc.net_for_pin ((*n)->begin_pins ()->pin_id ()); + new_nets.push_back (new_net); + + if (new_net == 0) { + failed = true; + std::string msg; + if (same_names) { + msg = tl::sprintf (tl::to_string (tr ("Must-connect subnet of %s of circuit %s has no outside connection at all%s")), nets_org[i]->expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path); + } else { + msg = tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s has no outside connection at all%s")), nets_org[i]->expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path); + } + db::LogEntryData error (db::Error, msg); + error.set_cell_name (sc.circuit ()->name ()); + error.set_geometry (subcircuit_geometry (sc, internal_layout ())); + error.set_category_name ("must-connect"); + log_entry (error); + } - if (net_a == 0) { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), a_org.expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path)); - error.set_cell_name (sc.circuit ()->name ()); - error.set_geometry (subcircuit_geometry (sc, internal_layout ())); - error.set_category_name ("must-connect"); - log_entry (error); } - if (net_b == 0) { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), b_org.expanded_name (), c_org.name (), subcircuit_to_string (sc)) + path_msg (path)); - error.set_cell_name (sc.circuit ()->name ()); - error.set_geometry (subcircuit_geometry (sc, internal_layout ())); - error.set_category_name ("must-connect"); - log_entry (error); - } - - if (net_a && net_b && net_a != net_b) { + if (! failed && ! all_nets_are_same (new_nets)) { path.push_back (&sc); - check_must_connect_impl (*sc.circuit (), *net_a, *net_b, c_org, a_org, b_org, path); + check_must_connect_impl (*sc.circuit (), new_nets, c_org, nets_org, path, same_names); path.pop_back (); } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 812ee5d7b..e8c78d217 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -1109,8 +1109,8 @@ private: void do_soft_connections (); void join_nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p); void join_nets_from_pattern (db::Circuit &c, const std::set &p); - void check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b); - void check_must_connect_impl (const db::Circuit &c, const db::Net &a, const db::Net &b, const db::Circuit &c_org, const db::Net &a_org, const db::Net &b_org, std::vector &path); + void check_must_connect (const db::Circuit &c, const std::vector &nets); + void check_must_connect_impl (const db::Circuit &c, const std::vector &nets, const db::Circuit &c_org, const std::vector &nets_org, std::vector &path, bool same_names); // for debugging and testing void place_soft_connection_diodes (); diff --git a/src/lvs/unit_tests/lvsTests.cc b/src/lvs/unit_tests/lvsTests.cc index a21008c38..001df63da 100644 --- a/src/lvs/unit_tests/lvsTests.cc +++ b/src/lvs/unit_tests/lvsTests.cc @@ -171,7 +171,7 @@ TEST(20_private) TEST(21_private) { - run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_4.lvsdb"); + run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_5.lvsdb"); } // issue #1021 diff --git a/testdata/lvs/double_height2.lvsdb b/testdata/lvs/double_height2.lvsdb index 3c2330e64..ff5e4200a 100644 --- a/testdata/lvs/double_height2.lvsdb +++ b/testdata/lvs/double_height2.lvsdb @@ -27,9 +27,9 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) - H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) - H(W B('Must-connect nets R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$1') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) + H(W B('Must-connect subnets of GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect') Q('(0.27,0.8;0.27,8.4;0.32,8.4;0.32,0.8)')) + H(W B('Must-connect subnets of R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect') Q('(1.48,2.37;1.48,7.46;2.61,7.46;2.61,2.37)')) + H(W B('Must-connect subnets of R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$1') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/double_height2_texts.lvsdb b/testdata/lvs/double_height2_texts.lvsdb index 6dc2a6872..c5b5b94bf 100644 --- a/testdata/lvs/double_height2_texts.lvsdb +++ b/testdata/lvs/double_height2_texts.lvsdb @@ -27,9 +27,9 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) - H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) - H(W B('Must-connect nets R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$1') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) + H(W B('Must-connect subnets of GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect') Q('(0.27,0.8;0.27,8.4;0.32,8.4;0.32,0.8)')) + H(W B('Must-connect subnets of R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect') Q('(1.48,2.37;1.48,7.46;2.61,7.46;2.61,2.37)')) + H(W B('Must-connect subnets of R of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$1') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/must_connect1.lvsdb b/testdata/lvs/must_connect1.lvsdb index 6d86052d3..1d91c7e7e 100644 --- a/testdata/lvs/must_connect1.lvsdb +++ b/testdata/lvs/must_connect1.lvsdb @@ -27,7 +27,7 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) + H(W B('Must-connect subnets of VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect') Q('(3.61,0.7;3.61,8.89;11.365,8.89;11.365,0.7)')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/must_connect1_tl.lvsdb b/testdata/lvs/must_connect1_tl.lvsdb index 0bd8468c4..fa05c7401 100644 --- a/testdata/lvs/must_connect1_tl.lvsdb +++ b/testdata/lvs/must_connect1_tl.lvsdb @@ -27,7 +27,7 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(E B('Must-connect nets VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) + H(E B('Must-connect subnets of VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect') Q('(3.61,0.7;3.61,8.89;11.365,8.89;11.365,0.7)')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/must_connect2.lvsdb b/testdata/lvs/must_connect2.lvsdb index 8a9daf6e2..9357d2c35 100644 --- a/testdata/lvs/must_connect2.lvsdb +++ b/testdata/lvs/must_connect2.lvsdb @@ -27,9 +27,9 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) - H(W B('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) - H(W B('Must-connect nets VSS of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$2') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) + H(W B('Must-connect subnets of VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect') Q('(3.61,0.7;3.61,8.89;11.365,8.89;11.365,0.7)')) + H(W B('Must-connect subnets of VDD must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect') Q('(2.595,4.725;2.595,4.805;11.865,4.805;11.865,4.725)')) + H(W B('Must-connect subnets of VSS of circuit INV2 must be connected further up in the hierarchy - this is an error at chip top level.\nInstance path: INVCHAIN/INV2[r0 0,0]:$2') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 index 576801b98..90d11e8b4 100644 --- a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 +++ b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 @@ -39,7 +39,7 @@ layout( global(l10 SUBSTRATE) # Log entries - message(warning description('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at chip top level') cell(RINGO) cat('must-connect')) + message(warning description('Must-connect subnets of VDD must be connected further up in the hierarchy - this is an error at chip top level') cell(RINGO) cat('must-connect') polygon('(2.95,7.25;2.95,7.4;25.1,7.4;25.1,7.25)')) # Device class section class(PMOS MOS4) diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 index 86c5148b8..145f3cd6a 100644 --- a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 +++ b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 @@ -39,7 +39,7 @@ layout( global(l10 SUBSTRATE) # Log entries - message(warning description('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at chip top level') cell(RINGO) cat('must-connect')) + message(warning description('Must-connect subnets of VDD must be connected further up in the hierarchy - this is an error at chip top level') cell(RINGO) cat('must-connect') polygon('(2.95,7.25;2.95,7.4;25.1,7.4;25.1,7.25)')) # Device class section class(PMOS MOS4) diff --git a/testdata/lvs/test_22a.lvsdb.1 b/testdata/lvs/test_22a.lvsdb.1 index ed14452f3..3b1267688 100644 --- a/testdata/lvs/test_22a.lvsdb.1 +++ b/testdata/lvs/test_22a.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.385,-0.305;-0.385,5.855;9.105,5.855;9.105,-0.305)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22a.lvsdb.2 b/testdata/lvs/test_22a.lvsdb.2 index 653bea80f..bd5c980af 100644 --- a/testdata/lvs/test_22a.lvsdb.2 +++ b/testdata/lvs/test_22a.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.385,-0.305;-0.385,5.855;9.105,5.855;9.105,-0.305)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.1 b/testdata/lvs/test_22b.lvsdb.1 index 37f240e44..bac531746 100644 --- a/testdata/lvs/test_22b.lvsdb.1 +++ b/testdata/lvs/test_22b.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.385,-0.305;-0.385,5.855;9.105,5.855;9.105,-0.305)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.2 b/testdata/lvs/test_22b.lvsdb.2 index 806634244..cac410e2b 100644 --- a/testdata/lvs/test_22b.lvsdb.2 +++ b/testdata/lvs/test_22b.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.385,-0.305;-0.385,5.855;9.105,5.855;9.105,-0.305)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.1 b/testdata/lvs/test_22c.lvsdb.1 index f61eaa9e9..029afa97f 100644 --- a/testdata/lvs/test_22c.lvsdb.1 +++ b/testdata/lvs/test_22c.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.16,-0.13;-0.16,5.68;8.88,5.68;8.88,-0.13)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.2 b/testdata/lvs/test_22c.lvsdb.2 index c85f87ba1..7a023acbf 100644 --- a/testdata/lvs/test_22c.lvsdb.2 +++ b/testdata/lvs/test_22c.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.16,-0.13;-0.16,5.68;8.88,5.68;8.88,-0.13)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.1 b/testdata/lvs/test_22d.lvsdb.1 index 45e3e88fc..bb827e1c7 100644 --- a/testdata/lvs/test_22d.lvsdb.1 +++ b/testdata/lvs/test_22d.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.16,-0.13;-0.16,5.68;8.88,5.68;8.88,-0.13)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.2 b/testdata/lvs/test_22d.lvsdb.2 index 22c7b9fa6..7b32708a2 100644 --- a/testdata/lvs/test_22d.lvsdb.2 +++ b/testdata/lvs/test_22d.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.16,-0.13;-0.16,5.68;8.88,5.68;8.88,-0.13)')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.3 b/testdata/lvs/test_22d.lvsdb.3 index 5c772a9c5..d1f5b2a20 100644 --- a/testdata/lvs/test_22d.lvsdb.3 +++ b/testdata/lvs/test_22d.lvsdb.3 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.16,-0.13;-0.16,5.68;8.88,5.68;8.88,-0.13)')) # Device class section class(active_res RES) From 3edb193562df21e4e3e32c0aea3149e88e84f517 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 26 May 2024 22:55:37 +0200 Subject: [PATCH 05/13] A proposal for fixing issue #1719, part 1 --- src/db/db/dbNetlistCompare.cc | 61 ++++++++++++++++++---- src/db/db/dbNetlistCompare.h | 1 + src/db/db/gsiDeclDbNetlist.cc | 4 +- src/lvs/lvs/built-in-macros/_lvs_netter.rb | 31 ++++++++++- 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 6040ba4a8..038fb9e7c 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -86,14 +86,17 @@ NetlistComparer::exclude_resistors (double threshold) void NetlistComparer::same_nets (const db::Net *na, const db::Net *nb, bool must_match) { - 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)); + if (na || nb) { + 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)); + if (na || nb) { + m_same_nets [std::make_pair (ca, cb)].push_back (std::make_pair (std::make_pair (na, nb), must_match)); + } } void @@ -207,6 +210,49 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const return res; } +/** + * @brief Returns a consolidated list of identical nets for a circuit pair (aka "same_nets") + * + * The list is reduced by duplicates of the first net such, that the + * last "same_nets" entry wins. + * + * The return value is a list of net pairs and a flag indicating "must_match" mode. + * The second net can be null if "must_match" is true, indicating that no schematic + * net with the same name was found - hence a mismatch exists. + */ +std::vector, bool> > +NetlistComparer::get_net_identity (const db::Circuit *ca, const db::Circuit *cb) const +{ + std::vector, bool> > net_identity; + + std::map, std::vector, bool> > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb)); + if (sn != m_same_nets.end ()) { + + const std::vector, bool> > &ni = sn->second; + + // take last definition for a given first net + net_identity.reserve (ni.size ()); + std::set seen; + for (auto i = ni.end (); i != ni.begin (); ) { + --i; + const Net *main_net = i->first.first ? i->first.first : i->first.second; + const Net *other_net = i->first.first ? i->first.second : i->first.first; + if (seen.find (main_net) == seen.end () && (! other_net || seen.find (other_net) == seen.end ())) { + net_identity.push_back (*i); + seen.insert (main_net); + if (other_net) { + seen.insert (other_net); + } + } + } + + std::reverse (net_identity.begin (), net_identity.end ()); + + } + + return net_identity; +} + bool NetlistComparer::compare_impl (const db::Netlist *a, const db::Netlist *b) const { @@ -344,13 +390,6 @@ NetlistComparer::compare_impl (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, bool> > empty; - const std::vector, bool> > *net_identity = ∅ - std::map, std::vector, bool> > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb)); - if (sn != m_same_nets.end ()) { - net_identity = &sn->second; - } - if (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) { if (db::NetlistCompareGlobalOptions::options ()->debug_netcompare) { @@ -362,7 +401,7 @@ NetlistComparer::compare_impl (const db::Netlist *a, const db::Netlist *b) const } bool pin_mismatch = false; - bool g = compare_circuits (ca, cb, device_categorizer, circuit_categorizer, circuit_pin_mapper, *net_identity, pin_mismatch, c12_pin_mapping, c22_pin_mapping); + bool g = compare_circuits (ca, cb, device_categorizer, circuit_categorizer, circuit_pin_mapper, get_net_identity (ca, cb), pin_mismatch, c12_pin_mapping, c22_pin_mapping); if (! g) { good = false; } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index 0dff2e059..18ff5288d 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -387,6 +387,7 @@ protected: void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const; void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinCategorizer &circuit_pin_mapper, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, db::SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const; 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; + std::vector, bool> > get_net_identity (const db::Circuit *ca, const db::Circuit *cb) const; mutable NetlistCompareLogger *mp_logger; bool m_with_log; diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index a1163ae29..f84294c9f 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1451,7 +1451,7 @@ nets_by_name_const (const db::Circuit *circuit, const std::string &name_pattern) } 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 ())) { + if (!net->name ().empty () && glob.match (net->name ())) { res.push_back (net); } } @@ -1480,7 +1480,7 @@ nets_by_name_const_from_netlist (const db::Netlist *netlist, const std::string & for (auto n = c->begin_nets (); n != c->end_nets (); ++n) { const db::Net *net = n.operator-> (); // NOTE: we only pick root nets (pin_count == 0 or in top cell) - if ((is_top || net->pin_count () == 0) && glob.match (net->name ())) { + if ((is_top || net->pin_count () == 0) && !net->name ().empty () && glob.match (net->name ())) { res.push_back (net); } } diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb index 9eb5b5541..4b3a44f7c 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb @@ -552,6 +552,9 @@ CODE # same_nets("INV*", "A*") # @/code # + # A plain "*" for the net pattern forces all (named) nets to be equivalent between layout and schematic. + # Unnamed nets from the extracted netlist are not considered - i.e. nets without a label. + # # 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 # resolve otherwise. @@ -560,6 +563,16 @@ CODE # Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists. # # Use this method andwhere in the script before the \compare call. + # + # Multiple calls of "same_nets" can be used. The calls are effective in the order + # the are given. For example, the following sequence specifies equivalence of all + # equally named nets, with the exception of "A" and "B" which are equivalent to each other + # inside cell "ND2", despite their different name: + # + # @code + # same_nets("*", "*") + # same_nets("ND2", "A", "B") + # @/code def same_nets(*args) _same_nets_impl(false, *args) @@ -573,6 +586,22 @@ CODE # @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. + # + # For example, this global specification requires all named nets from the + # layout to have an equivalent net in the schematic and those nets need to be + # identical for all circuits: + # + # @code + # same_nets!("*", "*") + # @/code + # + # The following specification requires "A" and "B" to be identical in + # circuit "ND2". It is not an error if either "A" does not exist in the + # layout or "B" does not exist in the schematic: + # + # @code + # same_nets!("ND2", "A", "B") + # @/code def same_nets!(*args) _same_nets_impl(true, *args) @@ -655,7 +684,7 @@ CODE nets = [] n2n.keys.sort.each do |n| - if force || (n2n[n][0] && n2n[n][1]) + if n2n[n][0] && (force || n2n[n][1]) nets << n2n[n] end end From f01d8d46b586359f7bb01144fb68f094cda331a3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 27 May 2024 00:43:36 +0200 Subject: [PATCH 06/13] Improving reports for errors in 'same_nets' cases --- src/db/db/dbNetlistCompare.cc | 24 ++++++++++++++++++++---- src/db/db/dbNetlistCompareUtils.cc | 2 +- src/db/db/dbNetlistCompareUtils.h | 1 + testdata/lvs/blackbox3.lvsdb | 7 ++++--- testdata/lvs/blackbox4.lvsdb | 5 ++--- testdata/lvs/blackbox5.lvsdb | 8 ++------ 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 038fb9e7c..6d0e3128c 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -938,8 +938,16 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (mp_logger) { if (p->second && ! exact_match) { if (m_with_log) { - mp_logger->log_entry (db::Error, - tl::sprintf (tl::to_string (tr ("Nets %s are paired explicitly, but are not identical topologically")), nets2string (p->first))); + if (! p->first.first) { + mp_logger->log_entry (db::Error, + tl::sprintf (tl::to_string (tr ("Right-side net %s is paired explicitly with a left-side one, but no net is present there")), expanded_name (p->first.second))); + } else if (! p->first.second) { + mp_logger->log_entry (db::Error, + tl::sprintf (tl::to_string (tr ("Left-side net %s is paired explicitly with a right-side one, but no net is present there")), expanded_name (p->first.first))); + } else { + mp_logger->log_entry (db::Error, + tl::sprintf (tl::to_string (tr ("Nets %s are paired explicitly, but are not identical topologically")), nets2string (p->first))); + } } mp_logger->net_mismatch (p->first.first, p->first.second); } else { @@ -950,7 +958,11 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } else if (p->second && g1.has_node_index_for_net (p->first.first)) { if (mp_logger) { - mp_logger->net_mismatch (p->first.first, 0); + mp_logger->net_mismatch (p->first.first, p->first.second); + if (m_with_log && p->first.second) { + mp_logger->log_entry (db::Error, + tl::sprintf (tl::to_string (tr ("Nets %s are paired explicitly, but are not identical topologically")), nets2string (p->first))); + } } size_t ni1 = g1.node_index_for_net (p->first.first); @@ -959,7 +971,11 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, } else if (p->second && g2.has_node_index_for_net (p->first.second)) { if (mp_logger) { - mp_logger->net_mismatch (0, p->first.second); + mp_logger->net_mismatch (p->first.first, p->first.second); + if (m_with_log && p->first.first) { + mp_logger->log_entry (db::Error, + tl::sprintf (tl::to_string (tr ("Nets %s are paired explicitly, but are not identical topologically")), nets2string (p->first))); + } } size_t ni2 = g2.node_index_for_net (p->first.second); diff --git a/src/db/db/dbNetlistCompareUtils.cc b/src/db/db/dbNetlistCompareUtils.cc index 97951ca25..0e7be811a 100644 --- a/src/db/db/dbNetlistCompareUtils.cc +++ b/src/db/db/dbNetlistCompareUtils.cc @@ -73,7 +73,7 @@ nl_compare_debug_indent (size_t depth) const std::string var_sep = tl::to_string (tr (" vs. ")); -static std::string +std::string expanded_name (const db::Net *a) { if (a == 0) { diff --git a/src/db/db/dbNetlistCompareUtils.h b/src/db/db/dbNetlistCompareUtils.h index 55614577a..f84c30ab0 100644 --- a/src/db/db/dbNetlistCompareUtils.h +++ b/src/db/db/dbNetlistCompareUtils.h @@ -83,6 +83,7 @@ const size_t unknown_id = std::numeric_limits::max () - 1; // Some utilities std::string nl_compare_debug_indent (size_t depth); +std::string expanded_name (const db::Net *a); std::string nets2string (const db::Net *a, const db::Net *b); std::string nets2string (const std::pair &np); diff --git a/testdata/lvs/blackbox3.lvsdb b/testdata/lvs/blackbox3.lvsdb index f95a64186..0ea7fb1e5 100644 --- a/testdata/lvs/blackbox3.lvsdb +++ b/testdata/lvs/blackbox3.lvsdb @@ -185,10 +185,9 @@ xref( ) circuit(TOP TOP nomatch log( - entry(error description('Nets $1 vs. (not connected) are paired explicitly, but are not identical topologically')) + entry(error description('Nets 7 are paired explicitly, but are not identical topologically')) ) xref( - net(() 7 mismatch) net(1 () mismatch) net(5 1 match) net(4 2 match) @@ -196,8 +195,10 @@ xref( net(3 4 match) net(7 5 match) net(8 6 match) + net(9 7 mismatch) net(6 8 match) - circuit(1 1 mismatch) + circuit(() 1 mismatch) + circuit(1 () mismatch) ) ) ) diff --git a/testdata/lvs/blackbox4.lvsdb b/testdata/lvs/blackbox4.lvsdb index a54819f42..5e782006a 100644 --- a/testdata/lvs/blackbox4.lvsdb +++ b/testdata/lvs/blackbox4.lvsdb @@ -181,9 +181,8 @@ xref( ) circuit(TOP TOP nomatch log( - entry(error description('Nets (not connected) vs. 5 are paired explicitly, but are not identical topologically')) - entry(error description('Nets 5,7 vs. (not connected) are paired explicitly, but are not identical topologically')) - entry(error description('Nets (not connected) vs. 7 are paired explicitly, but are not identical topologically')) + entry(error description('Left-side net 5,7 is paired explicitly with a right-side one, but no net is present there')) + entry(error description('Net 5,7 is not matching any net from reference netlist')) ) xref( net(() 5 mismatch) diff --git a/testdata/lvs/blackbox5.lvsdb b/testdata/lvs/blackbox5.lvsdb index 391475a66..6d8f88e0a 100644 --- a/testdata/lvs/blackbox5.lvsdb +++ b/testdata/lvs/blackbox5.lvsdb @@ -184,15 +184,11 @@ xref( ) circuit(TOP TOP nomatch log( - entry(error description('Nets $1 vs. (not connected) are paired explicitly, but are not identical topologically')) - entry(error description('Nets (not connected) vs. 5 are paired explicitly, but are not identical topologically')) - entry(error description('Nets 5,7 vs. (not connected) are paired explicitly, but are not identical topologically')) - entry(error description('Nets (not connected) vs. 7 are paired explicitly, but are not identical topologically')) + entry(error description('Left-side net 5,7 is paired explicitly with a right-side one, but no net is present there')) ) xref( net(() 5 mismatch) - net(() 7 mismatch) - net(1 () mismatch) + net(1 7 match) net(5 1 match) net(4 2 match) net(2 3 match) From 45e77ce40ca2fcfb4e32425c87426ce2c5b0cbd1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 27 May 2024 19:02:38 +0200 Subject: [PATCH 07/13] Fixed a typo --- src/db/db/dbLayoutToNetlist.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 9275b442f..86b7d50ab 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1018,7 +1018,7 @@ void LayoutToNetlist::register_layer (const ShapeCollection &collection, const s throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n_in); } - // Caution: this make create names which clash with future explicit names. Hopefully, the generated names are unique enough. + // Caution: this may create names which clash with future explicit names. Hopefully, the generated names are unique enough. std::string n = n_in.empty () ? make_new_name () : n_in; db::DeepLayer dl; From dc526132c0be6149b6a252942003368c70ad7120 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 27 May 2024 19:02:53 +0200 Subject: [PATCH 08/13] Part 3 of issue #1719 New LVS/DRC functions: "name" and "name_prefix" to control what layer names are used. "name" needs to be used explicitly and before a layer is used (and gets auto-assigned a name). --- src/drc/drc/built-in-macros/_drc_engine.rb | 14 ++++ src/drc/drc/built-in-macros/_drc_netter.rb | 91 +++++++++++++++++++--- 2 files changed, 94 insertions(+), 11 deletions(-) diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 14a384a1a..765fc4215 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -2394,6 +2394,18 @@ CODE # @synopsis extract_devices(extractor_class, name, layer_hash) # See \Netter#extract_devices for a description of that function. + # %DRC% + # @name name + # @brief Assigns a name to a layer for reference in the LVS database + # @synopsis name(layer, name) + # See \Netter#name for a description of that function. + + # %DRC% + # @name name_prefix + # @brief Specifies the layer name prefix for auto-generated layer names + # @synopsis name_prefix(prefix) + # See \Netter#name_prefix for a description of that function. + # %DRC% # @name netlist # @brief Obtains the extracted netlist from the default \Netter @@ -2408,6 +2420,8 @@ CODE connect_global soft_connect soft_connect_global + name_prefix + name connect_implicit connect_explicit device_scaling diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 627dd85a9..4a3b023f9 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -68,6 +68,7 @@ module DRC @post_extract_config = [] @l2n = nil @lnum = 0 + @name_prefix = "l" @device_scaling = 1.0 @ignore_extraction_errors = false @top_level = false @@ -106,8 +107,8 @@ module DRC a.requires_texts_or_region b.requires_texts_or_region - register_layer(a.data) - register_layer(b.data) + _register_layer(a.data, "connect") + _register_layer(b.data, "connect") a.data.is_a?(RBA::Region) && @l2n.connect(a.data) b.data.is_a?(RBA::Region) && @l2n.connect(b.data) @l2n.connect(a.data, b.data) @@ -150,8 +151,8 @@ module DRC a.requires_texts_or_region b.requires_texts_or_region - register_layer(a.data) - register_layer(b.data) + _register_layer(a.data, "soft_connect") + _register_layer(b.data, "soft_connect") # soft connections imply hard intra-layer connections a.data.is_a?(RBA::Region) && @l2n.connect(a.data) b.data.is_a?(RBA::Region) && @l2n.connect(b.data) @@ -177,7 +178,7 @@ module DRC l.is_a?(DRC::DRCLayer) || raise("Layer argument must be a layer") l.requires_texts_or_region - register_layer(l.data) + _register_layer(l.data, "connect_global") l.data.is_a?(RBA::Region) && @l2n.connect(l.data) @l2n.connect_global(l.data, name) @@ -204,7 +205,7 @@ module DRC l.is_a?(DRC::DRCLayer) || raise("Layer argument must be a layer") l.requires_texts_or_region - register_layer(l.data) + _register_layer(l.data, "soft_connect_global") l.data.is_a?(RBA::Region) && @l2n.connect(l.data) @l2n.soft_connect_global(l.data, name) @@ -282,7 +283,7 @@ module DRC layer_selection.keys.sort.each do |n| l = layer_selection[n] l.requires_texts_or_region - register_layer(l.data) + _register_layer(l.data, "extract_devices") ls[n.to_s] = l.data end @@ -294,6 +295,70 @@ module DRC end + # %DRC% + # @name name + # @brief Assigns a name to a layer + # @synopsis name(layer, name) + # Layer names are listed in the LayoutToNetlist (L2N) or LVS database. They + # are used to identify the layers, the net or device terminal geometries are + # on. It is usual to have computed layers, so it is necessary to indicate the + # purpose of the layer for later reuse of the geometries. + # + # It is a good practice to assign names to computed and original layers, + # for example: + # + # @code + # poly = input(...) + # poly_resistor = input(...) + # + # poly_wiring = poly - poly_resistor + # name(poly_wiring, "poly_wiring") + # @/code + # + # Names must be assigned before the layers are used for the first time + # in \connect, \soft_connect, \connect_global, \soft_connect_global and + # extract_devices statements. + # + # If layers are not named, they will be given a name made from the + # \name_prefix and an incremental number when the layer is used for the + # first time. + # + # \name can only be used once on a layer and the layer names must be + # unique (not taken by another layer). + + # %DRC% + # @name name_prefix + # @brief Specifies the name prefix for auto-generated layer names + # @synopsis name_prefix(prefix) + # See \\name for details. The default prefix is "l". + + def name(l, name) + + @engine._context("name") do + + l.is_a?(DRC::DRCLayer) || raise("First argument must be a layer") + (name.is_a?(String) && name != "") || raise("Second argument must be a non-empty string") + + id = l.data.data_id + + if @layers && @layers[id] + # already registered + if @layers[id][1] != name + raise("Layer already registered with name #{@layers[id][1]} in context: #{@layers[id][2]}") + end + return + end + + self._register_layer(l.data, "name", name) + + end + + end + + def name_prefix(prefix) + @name_prefix = prefix.to_s + end + # %DRC% # @name device_scaling # @brief Specifies a dimension scale factor for the geometrical device properties @@ -792,7 +857,7 @@ module DRC end - def register_layer(data) + def _register_layer(data, context, name = nil) id = data.data_id ensure_data @@ -802,11 +867,15 @@ module DRC return end - @layers[id] = data - @lnum += 1 + if !name + @lnum += 1 + name = @name_prefix + @lnum.to_s + end + + @layers[id] = [ data, name, context ] # every layer gets registered and intra-layer connections are made - @l2n.register(data, "l" + @lnum.to_s) + @l2n.register(data, name) end From 2360eb41fdcd0459120e7b682408fc2fd8a6b933 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 27 May 2024 19:04:06 +0200 Subject: [PATCH 09/13] Generated documentation --- src/doc/doc/about/drc_ref_global.xml | 18 ++++++++++++ src/doc/doc/about/drc_ref_netter.xml | 43 ++++++++++++++++++++++++++++ src/doc/doc/about/lvs_ref_netter.xml | 29 +++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/doc/doc/about/drc_ref_global.xml b/src/doc/doc/about/drc_ref_global.xml index 45b725686..7fe05da4a 100644 --- a/src/doc/doc/about/drc_ref_global.xml +++ b/src/doc/doc/about/drc_ref_global.xml @@ -1175,6 +1175,24 @@ four-terminal MOS transistor. See DeviceExtractorMOS4Transistor for more details about this extractor (non-strict mode applies for 'mos4').

+

"name" - Assigns a name to a layer for reference in the LVS database

+ +

Usage:

+
    +
  • name(layer, name)
  • +
+

+See Netter#name for a description of that function. +

+

"name_prefix" - Specifies the layer name prefix for auto-generated layer names

+ +

Usage:

+
    +
  • name_prefix(prefix)
  • +
+

+See Netter#name_prefix for a description of that function. +

"netlist" - Obtains the extracted netlist from the default Netter

diff --git a/src/doc/doc/about/drc_ref_netter.xml b/src/doc/doc/about/drc_ref_netter.xml index bd82b4fbd..4ffc860eb 100644 --- a/src/doc/doc/about/drc_ref_netter.xml +++ b/src/doc/doc/about/drc_ref_netter.xml @@ -422,6 +422,49 @@ but no error is raised. The LayoutToNetlist object provides access to the internal details of the netter object.

+

"name" - Assigns a name to a layer

+ +

Usage:

+
    +
  • name(layer, name)
  • +
+

+Layer names are listed in the LayoutToNetlist (L2N) or LVS database. They +are used to identify the layers, the net or device terminal geometries are +on. It is usual to have computed layers, so it is necessary to indicate the +purpose of the layer for later reuse of the geometries. +

+It is a good practice to assign names to computed and original layers, +for example: +

+

+poly = input(...)
+poly_resistor = input(...)
+
+poly_wiring = poly - poly_resistor
+name(poly_wiring, "poly_wiring")
+
+

+Names must be assigned before the layers are used for the first time +in connect, soft_connect, connect_global, soft_connect_global and +extract_devices statements. +

+If layers are not named, they will be given a name made from the +name_prefix and an incremental number when the layer is used for the +first time. +

+name can only be used once on a layer and the layer names must be +unique (not taken by another layer). +

+

"name_prefix" - Specifies the name prefix for auto-generated layer names

+ +

Usage:

+
    +
  • name_prefix(prefix)
  • +
+

+See for details. The default prefix is "l". +

"netlist" - Gets the extracted netlist or triggers extraction if not done yet

Usage:

diff --git a/src/doc/doc/about/lvs_ref_netter.xml b/src/doc/doc/about/lvs_ref_netter.xml index 9feef786f..c983b88f0 100644 --- a/src/doc/doc/about/lvs_ref_netter.xml +++ b/src/doc/doc/about/lvs_ref_netter.xml @@ -396,6 +396,9 @@ the schematic netlist for all circuits starting with "INV": same_nets("INV*", "A*")

+A plain "*" for the net pattern forces all (named) nets to be equivalent between layout and schematic. +Unnamed nets from the extracted netlist are not considered - i.e. nets without a label. +

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 resolve otherwise. @@ -404,6 +407,16 @@ circuit_a and net_a are for the layout netlist, circuit_b and net_b for the sche Names are case sensitive for layout-derived netlists and case-insensitive for SPICE schematic netlists.

Use this method andwhere in the script before the compare call. +

+Multiple calls of "same_nets" can be used. The calls are effective in the order +the are given. For example, the following sequence specifies equivalence of all +equally named nets, with the exception of "A" and "B" which are equivalent to each other +inside cell "ND2", despite their different name: +

+

+same_nets("*", "*")
+same_nets("ND2", "A", "B")
+

"same_nets!" - Establishes an equivalence between the nets with matching requirement

@@ -416,6 +429,22 @@ Use this method andwhere in the script before the
compare

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. +

+For example, this global specification requires all named nets from the +layout to have an equivalent net in the schematic and those nets need to be +identical for all circuits: +

+

+same_nets!("*", "*")
+
+

+The following specification requires "A" and "B" to be identical in +circuit "ND2". It is not an error if either "A" does not exist in the +layout or "B" does not exist in the schematic: +

+

+same_nets!("ND2", "A", "B")
+

"schematic" - Gets, sets or reads the reference netlist

From f1d3597b2e22cb2db24e585dbd38acefb171324e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 27 May 2024 19:06:56 +0200 Subject: [PATCH 10/13] Small doc update --- src/doc/doc/about/drc_ref_netter.xml | 2 +- src/drc/drc/built-in-macros/_drc_netter.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/doc/about/drc_ref_netter.xml b/src/doc/doc/about/drc_ref_netter.xml index 4ffc860eb..e299ae380 100644 --- a/src/doc/doc/about/drc_ref_netter.xml +++ b/src/doc/doc/about/drc_ref_netter.xml @@ -447,7 +447,7 @@ name(poly_wiring, "poly_wiring")

Names must be assigned before the layers are used for the first time in connect, soft_connect, connect_global, soft_connect_global and -extract_devices statements. +extract_devices statements.

If layers are not named, they will be given a name made from the name_prefix and an incremental number when the layer is used for the diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 4a3b023f9..2e5be7906 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -317,7 +317,7 @@ module DRC # # Names must be assigned before the layers are used for the first time # in \connect, \soft_connect, \connect_global, \soft_connect_global and - # extract_devices statements. + # \extract_devices statements. # # If layers are not named, they will be given a name made from the # \name_prefix and an incremental number when the layer is used for the From 496818f0a83d569cd28a5d83580317d4c06a3911 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 28 May 2024 23:21:58 +0200 Subject: [PATCH 11/13] Added testdata for #1719, part 3 --- src/lvs/unit_tests/lvsSimpleTests.cc | 11 +- testdata/lvs/layer_names.cir | 50 +++ testdata/lvs/layer_names.gds | Bin 0 -> 5258 bytes testdata/lvs/layer_names.lvs | 105 +++++++ testdata/lvs/layer_names.lvsdb | 434 +++++++++++++++++++++++++++ 5 files changed, 598 insertions(+), 2 deletions(-) create mode 100644 testdata/lvs/layer_names.cir create mode 100644 testdata/lvs/layer_names.gds create mode 100644 testdata/lvs/layer_names.lvs create mode 100644 testdata/lvs/layer_names.lvsdb diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 050f039eb..6ed065c3d 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -339,14 +339,21 @@ TEST(55_SoftConnectionSecondLevel) run_test (_this, "soft_connect6", "soft_connect6.gds", true, false /*no LVS*/); } -// Issue #1719, part 2 +// Issue #1719, part 2 (ignore stray texts) TEST(60_StrayTextsDoNotMakeNets) { run_test (_this, "stray_texts1", "stray_texts.gds", true, false /*no LVS*/); } -// Issue #1719, part 2 +// Issue #1719, part 2 (ignore stray texts) TEST(61_StrayTextsDoNotMakeNets) { run_test (_this, "stray_texts2", "stray_texts.gds", true, false /*no LVS*/); } + +// Issue #1719, part 3 (layer naming) +TEST(62_LayerNames) +{ + run_test (_this, "layer_names", "layer_names.gds", false, true, "TOP"); +} + diff --git a/testdata/lvs/layer_names.cir b/testdata/lvs/layer_names.cir new file mode 100644 index 000000000..9acc99ffe --- /dev/null +++ b/testdata/lvs/layer_names.cir @@ -0,0 +1,50 @@ +* Extracted by KLayout + +* cell TOP +* pin A +* pin C +* pin SUBSTRATE +.SUBCKT TOP 2 3 4 +* net 2 A +* net 3 C +* net 4 SUBSTRATE +* cell instance $1 r0 *1 0,0 +X$1 2 3 1 6 4 DINV +* cell instance $2 r0 *1 3.6,0 +X$2 5 6 1 4 INVX1 +.ENDS TOP + +* cell DINV +* pin A<1> +* pin A<2> +* pin B<2> +* pin VDD +* pin VSS +.SUBCKT DINV 1 2 3 5 6 +* net 1 A<1> +* net 2 A<2> +* net 3 B<2> +* net 4 B<1> +* net 5 VDD +* net 6 VSS +* cell instance $1 r0 *1 0,0 +X$1 4 5 1 6 INVX1 +* cell instance $2 r0 *1 1.8,0 +X$2 3 5 2 6 INVX1 +.ENDS DINV + +* cell INVX1 +* pin OUT +* pin VDD +* pin IN +* pin VSS +.SUBCKT INVX1 1 2 3 4 +* net 1 OUT +* net 2 VDD +* net 3 IN +* net 4 VSS +* device instance $1 r0 *1 0.85,5.8 PMOS +M$1 1 3 2 2 PMOS L=0.25U W=1.5U AS=0.6375P AD=0.6375P PS=3.85U PD=3.85U +* device instance $2 r0 *1 0.85,2.135 NMOS +M$2 1 3 4 4 NMOS L=0.25U W=0.95U AS=0.40375P AD=0.40375P PS=2.75U PD=2.75U +.ENDS INVX1 diff --git a/testdata/lvs/layer_names.gds b/testdata/lvs/layer_names.gds new file mode 100644 index 0000000000000000000000000000000000000000..3329c14d1b9eb2f7b126d6fda2935ac9377839f0 GIT binary patch literal 5258 zcmcJT&1+m$7{=eZcjjg?ndY-3CYks}DMf;kRuG|-BnB~FCH8v)XrY zk)4e7h%fg43EFoBzOTeZcCw%!F6jH{|B&?>sm;qIx5uHu6jKwdr@ymK2oR?J?TyO-+(?a`V{-WQ_#PP zzTZGiFntdGAI&K{SgEI$h1$5t4wmZE$AWLr`Tjj8_2GM^p8aG!_CJMQl)c!0tLO1! zZhusP?heN9O;L8z_rG_hZ6nhzppoNi5>Z8&mi=lj(>&q9WuRjeX?doeOdqdl_`8dd z4w>5c!e^=|dok0Bde%{)ju|S-UesG@rZ#@_nJS`XJ#qa1QIGlT?n!7K*~E-+Sv5eW zGsBco$}my(Vx}GUPv0!@D&f2AU=)8*e?L}A{TpOA;%J}`Tq&aLV5xuhk@ZOG*l$tx zqTW*Lj(=e_!Hl-B(mV^_od4b{ZGCfZe+iAW%vzH=3)|x<=4jun-SKhwuVMdpUu%o- z`bPXUtl93@slpf(*I@FC*$7%7C%?rQ{*+U8(8Vz9&gJeJ${tBDcFi&Lu=b9fW>5Jv z-!mJ+b^-RGLVQl8I8Wwl?9i*gK737`@hY$n)%0gx1v*vO5eq9ixo$R(*&-KkZZRW7 z*}+OZXPbJgm1ytwSwK6!$NDHEL!GmpJhyrNi%GD9u|7IGyly_!TR`8b7i9-yeRNAg z9=vb%z-ykf=g{7!nJ7D0sh@_1?aUy%s261iOZD|VTs+~|5j%3Dg}+7F&z0-xmwHF& z=%0E=*(>z)%Q#8KP5+|oRq<2DI7!A$y(oLH__M#fe&{2w7i9-a$B%Kd9!VYJ7G}k5~Jrp8lz$|1M>((7O}uwm%Wl*ZqkgCczGt#!vlxsMiU4QFbua zN4I>p{c$gJ57!R&K~Z+FQa=~;3qdc+4wmX`SIwsW#`uA=*D!w9bIJ~u>bX~BU!u<- z^^Iq9$_|$5>6h`6EsO&Fi?V~2ditfF@lr3!4wmY9BbAU|twCuBA?0zWfYq=hGrVq^~ zZg@J~D`ukX6NO)HHk#|<;Rj^@8PB;z%-{jCCs1~s`Jw;E^t`{boz^|C7i9;LuySw{Jh_&;4W7QUi@N)eUC57>i%a4E zQ2NQQ;g{U~*6Gg=pdY!V{9L^_h(6En)q(oY@$2~2*AB?}4&|eP>s`_pA(%n;|!_b3GH(7} ex +end +ok || raise("nwell layer is already named - this is an error") + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +pgate = pactive & poly +psd = pactive - pgate +ntie = active_in_nwell & nplus + +active_outside_nwell = active - nwell +nactive = active_outside_nwell & nplus +ngate = nactive & poly +nsd = nactive - ngate +ptie = active_outside_nwell & pplus + +# Layer names for all other layers + +%w(bulk pactive pgate psd ntie nactive ngate nsd poly contact metal1 via1 metal2).each do |v| + name(eval(v), v) +end + +# Device extraction + +# PMOS transistor device extraction +extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell, + "tS" => psd, "tD" => psd, "tG" => poly, "tW" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk, + "tS" => nsd, "tD" => nsd, "tG" => poly, "tW" => bulk }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, contact) +connect(nsd, contact) +connect(poly, contact) +connect(ntie, contact) +connect(nwell, ntie) +connect(ptie, contact) +connect(contact, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# Global +connect_global(bulk, "SUBSTRATE") +connect_global(ptie, "SUBSTRATE") + +ok = true +begin + name(ptie, "ptie") + ok = false +rescue => ex +end +ok || raise("ptie layer already used - this is an error") + +# Compare section + +netlist.simplify +align + +consider_net_names(false) + +compare + diff --git a/testdata/lvs/layer_names.lvsdb b/testdata/lvs/layer_names.lvsdb new file mode 100644 index 000000000..1a9df5bf6 --- /dev/null +++ b/testdata/lvs/layer_names.lvsdb @@ -0,0 +1,434 @@ +#%lvsdb-klayout + +# Layout +layout( + top(TOP) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(nwell '1/0') + layer(poly '5/0') + layer(contact '8/0') + layer(metal1 '9/0') + layer(via1) + layer(metal2) + layer(bulk) + layer(psd) + layer(ntie) + layer(nsd) + layer(l1) + + # Mask layer connectivity + connect(nwell nwell ntie) + connect(poly poly contact) + connect(contact poly contact metal1 psd ntie nsd l1) + connect(metal1 contact metal1 via1) + connect(via1 metal1 via1 metal2) + connect(metal2 via1 metal2) + connect(bulk bulk) + connect(psd contact psd) + connect(ntie nwell contact ntie) + connect(nsd contact nsd) + connect(l1 contact l1) + + # Global nets and connectivity + global(bulk SUBSTRATE) + global(l1 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(psd (-550 -750) (425 1500)) + ) + terminal(G + rect(poly (-125 -750) (250 1500)) + ) + terminal(D + rect(psd (125 -750) (425 1500)) + ) + terminal(B + rect(nwell (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(nsd (-550 -475) (425 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(nsd (125 -475) (425 950)) + ) + terminal(B + rect(bulk (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(OUT) + rect(contact (1110 5160) (180 180)) + rect(contact (-180 920) (180 180)) + rect(contact (-180 -730) (180 180)) + rect(contact (-180 -4120) (180 180)) + rect(contact (-180 370) (180 180)) + rect(metal1 (-240 -790) (300 4790)) + rect(metal1 (-150 -2500) (0 0)) + rect(psd (-225 1050) (425 1500)) + rect(nsd (-425 -4890) (425 950)) + ) + net(2 name(VDD) + rect(nwell (-100 4500) (2000 3500)) + rect(contact (-1090 -890) (180 180)) + rect(contact (-580 -1030) (180 180)) + rect(contact (-180 -730) (180 180)) + rect(contact (-180 -730) (180 180)) + rect(metal1 (-590 1460) (1800 800)) + rect(metal1 (-1050 -550) (300 300)) + rect(metal1 (-700 -850) (300 300)) + rect(metal1 (300 500) (0 0)) + rect(metal1 (-600 -2200) (300 1400)) + rect(psd (-350 -1450) (425 1500)) + rect(ntie (-75 450) (500 500)) + ) + net(3 name(IN) + rect(poly (725 2860) (250 1940)) + rect(poly (-525 -1850) (300 300)) + rect(poly (-25 -1840) (250 1450)) + rect(poly (-250 1940) (250 2000)) + rect(poly (-250 -2000) (250 2000)) + rect(contact (-465 -3790) (180 180)) + rect(metal1 (-90 -90) (0 0)) + rect(metal1 (-150 -150) (300 300)) + ) + net(4 name(VSS) + rect(contact (810 710) (180 180)) + rect(contact (-580 880) (180 180)) + rect(contact (-180 370) (180 180)) + rect(metal1 (-590 -2100) (1800 800)) + rect(metal1 (-1050 -550) (300 300)) + rect(metal1 (-100 -150) (0 0)) + rect(metal1 (-600 400) (300 1360)) + rect(nsd (-350 -900) (425 950)) + rect(l1 (-75 -2010) (500 400)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(OUT)) + pin(2 name(VDD)) + pin(3 name(IN)) + pin(4 name(VSS)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 2) + terminal(G 3) + terminal(D 1) + terminal(B 2) + ) + device(2 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 4) + terminal(G 3) + terminal(D 1) + terminal(B 4) + ) + + ) + circuit(DINV + + # Circuit boundary + rect((-100 400) (3800 7600)) + + # Nets with their geometries + net(1 name('A<1>') + rect(metal1 (600 3100) (0 0)) + ) + net(2 name('A<2>') + rect(metal1 (2400 3100) (0 0)) + ) + net(3 name('B<2>') + rect(metal1 (3000 4000) (0 0)) + ) + net(4 name('B<1>') + rect(metal1 (1200 4000) (0 0)) + ) + net(5 name(VDD) + rect(metal1 (1800 7200) (0 0)) + ) + net(6 name(VSS) + rect(metal1 (1800 800) (0 0)) + ) + + # Outgoing pins and their connections to nets + pin(1 name('A<1>')) + pin(2 name('A<2>')) + pin(3 name('B<2>')) + pin(5 name(VDD)) + pin(6 name(VSS)) + + # Subcircuits and their connections + circuit(1 INVX1 location(0 0) + pin(0 4) + pin(1 5) + pin(2 1) + pin(3 6) + ) + circuit(2 INVX1 location(1800 0) + pin(0 3) + pin(1 5) + pin(2 2) + pin(3 6) + ) + + ) + circuit(TOP + + # Circuit boundary + rect((-100 400) (5600 7600)) + + # Nets with their geometries + net(1 + rect(metal1 (3100 2950) (950 300)) + ) + net(2 name(A) + rect(metal1 (600 3100) (0 0)) + ) + net(3 name(C) + rect(metal1 (2400 3100) (0 0)) + ) + net(4 name(SUBSTRATE)) + net(5) + net(6) + + # Outgoing pins and their connections to nets + pin(2 name(A)) + pin(3 name(C)) + pin(4 name(SUBSTRATE)) + + # Subcircuits and their connections + circuit(1 DINV location(0 0) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 6) + pin(4 4) + ) + circuit(2 INVX1 location(3600 0) + pin(0 5) + pin(1 6) + pin(2 1) + pin(3 4) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(NMOS MOS4) + class(PMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(INVX1 + + # Nets + net(1 name(A)) + net(2 name(Z)) + net(3 name(VSS)) + net(4 name(VDD)) + + # Outgoing pins and their connections to nets + pin(1 name(A)) + pin(2 name(Z)) + pin(4 name(VDD)) + pin(3 name(VSS)) + + # Devices and their connections + device(1 NMOS + name('0') + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 1) + terminal(D 2) + terminal(B 3) + ) + device(2 PMOS + name('1') + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 4) + terminal(G 1) + terminal(D 2) + terminal(B 4) + ) + + ) + circuit(DINV + + # Nets + net(1 name('A<1>')) + net(2 name('A<2>')) + net(3 name('B<1>')) + net(4 name('B<2>')) + net(5 name(VDD)) + net(6 name(VSS)) + + # Outgoing pins and their connections to nets + pin(1 name('A<1>')) + pin(2 name('A<2>')) + pin(3 name('B<1>')) + pin(4 name('B<2>')) + pin(5 name(VDD)) + pin(6 name(VSS)) + + # Subcircuits and their connections + circuit(1 INVX1 name(A) + pin(0 1) + pin(1 3) + pin(2 5) + pin(3 6) + ) + circuit(2 INVX1 name(B) + pin(0 2) + pin(1 4) + pin(2 5) + pin(3 6) + ) + + ) + circuit(TOP + + # Nets + net(1 name(A)) + net(2 name(C)) + net(3 name(D)) + net(4 name(B)) + net(5 name(E)) + net(6 name(VDD)) + net(7 name(VSS)) + + # Outgoing pins and their connections to nets + pin(1 name(A)) + pin(2 name(C)) + pin(3 name(D)) + pin(6 name(VDD)) + pin(7 name(VSS)) + + # Subcircuits and their connections + circuit(1 DINV name('0') + pin(0 1) + pin(1 2) + pin(2 4) + pin(3 5) + pin(4 6) + pin(5 7) + ) + circuit(2 INVX1 name('1') + pin(0 5) + pin(1 3) + pin(2 6) + pin(3 7) + ) + + ) +) + +# Cross reference +xref( + circuit(DINV DINV match + log( + entry(warning description('Matching nets B<1> from an ambiguous group of nets')) + entry(warning description('Matching nets B<2> from an ambiguous group of nets')) + entry(info description('Matching nets A<1> following an ambiguous match')) + entry(info description('Matching nets A<2> following an ambiguous match')) + ) + xref( + net(1 1 match) + net(2 2 match) + net(4 3 warning) + net(3 4 warning) + net(5 5 match) + net(6 6 match) + pin(() 2 match) + pin(0 0 match) + pin(1 1 match) + pin(2 3 match) + pin(3 4 match) + pin(4 5 match) + circuit(1 1 match) + circuit(2 2 match) + ) + ) + circuit(INVX1 INVX1 match + xref( + net(3 1 match) + net(1 2 match) + net(2 4 match) + net(4 3 match) + pin(2 0 match) + pin(0 1 match) + pin(1 2 match) + pin(3 3 match) + device(2 1 match) + device(1 2 match) + ) + ) + circuit(TOP TOP match + xref( + net(5 3 match) + net(1 5 match) + net(6 6 match) + net(2 1 match) + net(3 2 match) + net(4 7 match) + pin(() 2 match) + pin(() 3 match) + pin(0 0 match) + pin(1 1 match) + pin(2 4 match) + circuit(1 1 match) + circuit(2 2 match) + ) + ) +) From da9dc8929c5ba30a261fa37e209a60c61b616c65 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 31 May 2024 16:03:48 +0200 Subject: [PATCH 12/13] Updating one golden test data file --- testdata/lvs/test_22c.lvsdb.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testdata/lvs/test_22c.lvsdb.3 b/testdata/lvs/test_22c.lvsdb.3 index 2fbe22102..3f52d22f2 100644 --- a/testdata/lvs/test_22c.lvsdb.3 +++ b/testdata/lvs/test_22c.lvsdb.3 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) + message(warning description('Must-connect subnets of vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect') polygon('(-0.16,-0.13;-0.16,5.68;8.88,5.68;8.88,-0.13)')) # Device class section class(active_res RES) From 56035abd9ff7fe1d6ae00c1c14b61817ee68e533 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 31 May 2024 16:29:54 +0200 Subject: [PATCH 13/13] Adjusting DRC/LVS code for Ruby 2.0.0 (protected vs. private methods) --- src/drc/drc/built-in-macros/_drc_netter.rb | 62 +++++++++++----------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 2e5be7906..3e12ac838 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -826,36 +826,7 @@ module DRC @l2n.make_soft_connection_diodes = f end - private - - def cleanup - @l2n && @l2n.is_extracted? && clear_connections - end - - def ensure_data - if !@l2n - @layers = {} - _make_data - @l2n.device_scaling = @device_scaling - @l2n.top_level_mode = @top_level - end - end - - def _make_data - - if @engine._dss - @engine._dss.is_singular? || raise("The DRC script features more than one or no layout source - network extraction cannot be performed in such configurations") - @l2n = RBA::LayoutToNetlist::new(@engine._dss) - else - layout = @engine.source.layout - cell_name = @engine.source.cell_name - @l2n = RBA::LayoutToNetlist::new(cell_name, layout.dbu) - end - - @l2n.name = "DRC" - @l2n.generator = @engine._generator - - end + protected def _register_layer(data, context, name = nil) @@ -879,6 +850,37 @@ module DRC end + def _make_data + + if @engine._dss + @engine._dss.is_singular? || raise("The DRC script features more than one or no layout source - network extraction cannot be performed in such configurations") + @l2n = RBA::LayoutToNetlist::new(@engine._dss) + else + layout = @engine.source.layout + cell_name = @engine.source.cell_name + @l2n = RBA::LayoutToNetlist::new(cell_name, layout.dbu) + end + + @l2n.name = "DRC" + @l2n.generator = @engine._generator + + end + + private + + def cleanup + @l2n && @l2n.is_extracted? && clear_connections + end + + def ensure_data + if !@l2n + @layers = {} + _make_data + @l2n.device_scaling = @device_scaling + @l2n.top_level_mode = @top_level + end + end + end end