Date: Mon, 28 Jun 2021 19:51:57 +0200
Subject: [PATCH 07/15] Enhanced documentation for blank_circuit, consilidated
'blank_circuit' method provided which can be used anywhere
---
src/lay/lay/doc/about/drc_ref_layer.xml | 10 +-
src/lay/lay/doc/about/lvs_ref_global.xml | 9 +
src/lay/lay/doc/about/lvs_ref_netter.xml | 28 +
src/lay/lay/doc/manual/lvs_tweaks.xml | 31 +-
src/lvs/lvs/built-in-macros/_lvs_engine.rb | 8 +-
src/lvs/lvs/built-in-macros/_lvs_netter.rb | 49 ++
src/lvs/unit_tests/lvsSimpleTests.cc | 5 +
.../lvs/ringo_simple_blackboxing_netter.cir | 70 +++
.../lvs/ringo_simple_blackboxing_netter.lvs | 87 +++
.../lvs/ringo_simple_blackboxing_netter.lvsdb | 540 ++++++++++++++++++
10 files changed, 821 insertions(+), 16 deletions(-)
create mode 100644 testdata/lvs/ringo_simple_blackboxing_netter.cir
create mode 100644 testdata/lvs/ringo_simple_blackboxing_netter.lvs
create mode 100644 testdata/lvs/ringo_simple_blackboxing_netter.lvsdb
diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml
index 9c2e565dc..d41750cfc 100644
--- a/src/lay/lay/doc/about/drc_ref_layer.xml
+++ b/src/lay/lay/doc/about/drc_ref_layer.xml
@@ -3334,7 +3334,7 @@ The tile size must be specified with the "tile_size" option:
# reports areas where layer 1/0 density is below 10% on 20x20 um tiles
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um))
Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)".
@@ -3348,7 +3348,7 @@ in increments of the tile step:
# reports areas where layer 1/0 density is below 10% on 30x30 um tiles
# with a tile step of 20x20 um:
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
For "tile_step", anisotropic values can be given as well by using two values: the first for the
@@ -3366,7 +3366,7 @@ drawn boundary layer. To specify a separate, additional layer included in the bo
# reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
# layer 0/0:
cell_frame = input(0, 0)
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box.
@@ -3378,7 +3378,7 @@ direction. With the "tile_origin" option this allows full control over the area
# reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
# (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
The "padding mode" indicates how the area outside the layout's bounding box is considered.
@@ -3392,7 +3392,7 @@ There are two modes:
Example:
-low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), padding_ignore)
+low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), padding_ignore)
The complementary version of "with_density" is without_density.
diff --git a/src/lay/lay/doc/about/lvs_ref_global.xml b/src/lay/lay/doc/about/lvs_ref_global.xml
index f854e06e6..927ba0496 100644
--- a/src/lay/lay/doc/about/lvs_ref_global.xml
+++ b/src/lay/lay/doc/about/lvs_ref_global.xml
@@ -28,6 +28,15 @@ For more details about the DRC functions see
See Netter#align for a description of that function.
+"blank_circuit" - Removes the content from the given circuits (blackboxing)
+
+Usage:
+
+- blank_circuit(circuit_filter)
+
+
+See Netter#blank_circuit for a description of that function.
+
"compare" - Compares the extracted netlist vs. the schematic
Usage:
diff --git a/src/lay/lay/doc/about/lvs_ref_netter.xml b/src/lay/lay/doc/about/lvs_ref_netter.xml
index 04244ff71..d68a49a96 100644
--- a/src/lay/lay/doc/about/lvs_ref_netter.xml
+++ b/src/lay/lay/doc/about/lvs_ref_netter.xml
@@ -68,6 +68,34 @@ are other (explicit) ways to flatten circuits.
Please note that flattening circuits has some side effects such
as loss of details in the cross reference and net layout.
+"blank_circuit" - Removes the content from the given circuits (blackboxing)
+
+Usage:
+
+- blank_circuit(circuit_filter)
+
+
+This method will erase all content from the circuits matching the filter.
+The filter is a glob expression.
+
+This has the following effects:
+
+
+- The circuits are no longer compared against each other
+- Named pins are required to match (use labels on the nets to name pins in the layout)
+- Unnamed pins are treated as equivalent and can be swapped
+- The selected circuits will not be purged on netlist simplification
+
+
+Using this method can be useful to reduce the verification overhead for
+blocks which are already verifified by other ways or for which no schematic
+is available - e.g. hard macros.
+
+
+# skips all MEMORY* circuits from compare
+blank_circuit("MEMORY*")
+
+
"compare" - Compares the extracted netlist vs. the schematic
Usage:
diff --git a/src/lay/lay/doc/manual/lvs_tweaks.xml b/src/lay/lay/doc/manual/lvs_tweaks.xml
index 12e4b0bf5..6a8d505f9 100644
--- a/src/lay/lay/doc/manual/lvs_tweaks.xml
+++ b/src/lay/lay/doc/manual/lvs_tweaks.xml
@@ -153,10 +153,11 @@
A useful method in this context is the "blank_circuit" method. It clears
- a circuit's innards and leaves only the pins. You can use this method to
- ensure abstracts in both the layout netlist and the schematic. After this,
+ a circuit's innards from a netlist. After this,
the compare algorithm will identify both circuits as identical, provided
- they feature the same number of pins.
+ they feature the same number of pins. Named pins are required to match exactly
+ unless declared equivalent. Unnamed pins are treated as equivalent. To name
+ pins use labels on the pin's nets inside the circuit's layout.
@@ -166,14 +167,20 @@
netlist.blank_circuit("CIRCUIT_NAME")
schematic.blank_circuit("CIRCUIT_NAME")
+ NOTE: In this version, use "blank_circuit" before "purge" or "simplify" (see below). "blank_circuit"
+ sets a flag () which prevents purging of abstract circuits.
+
- The argument to "blank_circuit" is a glob pattern (shell-like).
- For example, "MEMORY*" will blank out all circuits starting with "MEMORY".
+ There is a short form for this too (blank_circuit).
+ In contrast to netlist-based "blank_circuit", this method can be used anywhere in the LVS script:
- NOTE: Use "blank_circuit" before "purge" or "simplify" (see below). This method
- sets a flag () which prevents purging of abstract
- circuits.
+ blank_circuit("CIRCUIT_NAME")
+
+
+ The argument to "blank_circuit" in both cases is a glob pattern (shell-like).
+ For example, "MEMORY*" will blank out all circuits starting with the word "MEMORY".
+
Joining of symmetric nodes
@@ -201,8 +208,8 @@ schematic.blank_circuit("CIRCUIT_NAME")
- KLayout provides a feature which will add such connections after extraction
- of the netlist:
+ KLayout provides a feature (join_symmetric_nets)
+ which will add such connections after extraction of the netlist:
join_symmetric_nets("NAND2")
@@ -221,6 +228,10 @@ schematic.blank_circuit("CIRCUIT_NAME")
need it.
+
+ "join_symmetric_nets" can be used anywhere in the LVS script.
+
+
Purging (elimination of redundancy)
diff --git a/src/lvs/lvs/built-in-macros/_lvs_engine.rb b/src/lvs/lvs/built-in-macros/_lvs_engine.rb
index f53bfcc72..bb24407e3 100644
--- a/src/lvs/lvs/built-in-macros/_lvs_engine.rb
+++ b/src/lvs/lvs/built-in-macros/_lvs_engine.rb
@@ -100,6 +100,12 @@ module LVS
# @synopsis join_symmetric_nets(circuit_filter)
# See \Netter#join_symmetric_nets for a description of that function.
+ # %LVS%
+ # @name blank_circuit
+ # @brief Removes the content from the given circuits (blackboxing)
+ # @synopsis blank_circuit(circuit_filter)
+ # See \Netter#blank_circuit for a description of that function.
+
# %LVS%
# @name align
# @brief Aligns the extracted netlist vs. the schematic by flattening circuits where required
@@ -168,7 +174,7 @@ module LVS
# @synopsis tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance])
# See \Netter#tolerance for a description of that function.
- %w(schematic compare join_symmetric_nets tolerance align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
+ %w(schematic compare join_symmetric_nets tolerance blank_circuit align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
eval <<"CODE"
def #{f}(*args)
_netter.#{f}(*args)
diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
index 5ab83b83d..8e5aa1d63 100644
--- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb
+++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
@@ -283,6 +283,55 @@ module LVS
end
+ # %LVS%
+ # @name blank_circuit
+ # @brief Removes the content from the given circuits (blackboxing)
+ # @synopsis blank_circuit(circuit_filter)
+ # This method will erase all content from the circuits matching the filter.
+ # The filter is a glob expression.
+ #
+ # This has the following effects:
+ #
+ # @ul
+ # @li The circuits are no longer compared (netlist vs. schematic) @/li
+ # @li Named pins are required to match (use labels on the nets to name pins in the layout) @/li
+ # @li Unnamed pins are treated as equivalent and can be swapped @/li
+ # @li The selected circuits will not be purged on netlist simplification @/li
+ # @/ul
+ #
+ # Using this method can be useful to reduce the verification overhead for
+ # blocks which are already verifified by other ways or for which no schematic
+ # is available - e.g. hard macros.
+ #
+ # Example:
+ #
+ # @code
+ # # skips all MEMORY* circuits from compare
+ # blank_circuit("MEMORY*")
+ # @/code
+
+ def blank_circuit(circuit_pattern)
+
+ circuit_pattern.is_a?(String) || raise("Circuit pattern argument of 'blank_circuit' must be a string")
+
+ if self._l2n_data
+ # already extracted
+ self._blank_circuit(self._l2n_data, circuit_pattern)
+ else
+ @post_extract_config << lambda { |l2n| self._blank_circuit(l2n, circuit_pattern) }
+ end
+
+ end
+
+ def _blank_circuit(l2n, circuit_pattern)
+
+ (n, s) = _ensure_two_netlists
+
+ n.blank_circuit(circuit_pattern)
+ s.blank_circuit(circuit_pattern)
+
+ end
+
def _comparer
comparer = RBA::NetlistComparer::new
diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc
index 2bb188c46..cfc49eb8f 100644
--- a/src/lvs/unit_tests/lvsSimpleTests.cc
+++ b/src/lvs/unit_tests/lvsSimpleTests.cc
@@ -135,6 +135,11 @@ TEST(9_blackboxing)
run_test (_this, "ringo_simple_blackboxing", "ringo_for_blackboxing.gds");
}
+TEST(9b_blackboxing_netter)
+{
+ run_test (_this, "ringo_simple_blackboxing_netter", "ringo_for_blackboxing.gds");
+}
+
TEST(10_simplification_with_align)
{
run_test (_this, "ringo_simple_simplification_with_align", "ringo_for_simplification.gds");
diff --git a/testdata/lvs/ringo_simple_blackboxing_netter.cir b/testdata/lvs/ringo_simple_blackboxing_netter.cir
new file mode 100644
index 000000000..e6a7e5bcc
--- /dev/null
+++ b/testdata/lvs/ringo_simple_blackboxing_netter.cir
@@ -0,0 +1,70 @@
+* Extracted by KLayout
+
+* cell RINGO
+* pin FB
+* pin VDD
+* pin OUT
+* pin ENABLE
+* pin VSS
+.SUBCKT RINGO 5 6 7 8 9
+* net 5 FB
+* net 6 VDD
+* net 7 OUT
+* net 8 ENABLE
+* net 9 VSS
+* cell instance $1 r0 *1 1.8,0
+X$1 6 1 9 6 5 8 9 ND2X1
+* cell instance $2 r0 *1 4.2,0
+X$2 6 2 9 6 1 9 INVX1
+* cell instance $3 r0 *1 6,0
+X$3 6 10 9 6 2 9 INVX1
+* cell instance $4 r0 *1 16.8,0
+X$4 6 3 9 6 11 9 INVX1
+* cell instance $5 r0 *1 18.6,0
+X$5 6 4 9 6 3 9 INVX1
+* cell instance $6 r0 *1 20.4,0
+X$6 6 5 9 6 4 9 INVX1
+* cell instance $7 r0 *1 22.2,0
+X$7 5 6 7 9 6 9 INVX2
+* cell instance $17 r0 *1 7.8,0
+X$17 6 12 9 6 10 9 INVX1
+* cell instance $18 r0 *1 9.6,0
+X$18 6 13 9 6 12 9 INVX1
+* cell instance $19 r0 *1 11.4,0
+X$19 6 14 9 6 13 9 INVX1
+* cell instance $20 r0 *1 13.2,0
+X$20 6 15 9 6 14 9 INVX1
+* cell instance $21 r0 *1 15,0
+X$21 6 11 9 6 15 9 INVX1
+.ENDS RINGO
+
+* cell INVX2
+* pin IN
+* pin VDD
+* pin OUT
+* pin VSS
+* pin
+* pin BULK
+.SUBCKT INVX2 1 2 3 4 5 6
+.ENDS INVX2
+
+* cell INVX1
+* pin VDD
+* pin OUT
+* pin VSS
+* pin
+* pin IN
+* pin BULK
+.SUBCKT INVX1 1 2 3 4 5 6
+.ENDS INVX1
+
+* cell ND2X1
+* pin VDD
+* pin OUT
+* pin VSS
+* pin
+* pin B
+* pin A
+* pin BULK
+.SUBCKT ND2X1 1 2 3 4 5 6 7
+.ENDS ND2X1
diff --git a/testdata/lvs/ringo_simple_blackboxing_netter.lvs b/testdata/lvs/ringo_simple_blackboxing_netter.lvs
new file mode 100644
index 000000000..4cbbc0591
--- /dev/null
+++ b/testdata/lvs/ringo_simple_blackboxing_netter.lvs
@@ -0,0 +1,87 @@
+
+source($lvs_test_source, "RINGO")
+
+report_lvs($lvs_test_target_lvsdb, true)
+
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("ringo_for_blackboxing.cir")
+
+blank_circuit("INVX1")
+blank_circuit("INVX2")
+blank_circuit("ND2X1")
+
+deep
+
+# Drawing layers
+
+nwell = input(1, 0)
+active = input(2, 0)
+pplus = input(3, 0)
+nplus = input(4, 0)
+poly = input(5, 0)
+contact = input(8, 0)
+metal1 = input(9, 0)
+via1 = input(10, 0)
+metal2 = input(11, 0)
+
+# Bulk layer for terminal provisioning
+# and to provide the BULK labels for
+# the abstracts
+
+bulk = labels(13, 0)
+
+# 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
+
+# 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")
+
+# Compare section
+
+netlist.flatten_circuit("INVCHAIN")
+
+netlist.make_top_level_pins
+netlist.purge
+netlist.combine_devices
+netlist.purge_nets
+
+consider_net_names(false)
+
+compare
+
diff --git a/testdata/lvs/ringo_simple_blackboxing_netter.lvsdb b/testdata/lvs/ringo_simple_blackboxing_netter.lvsdb
new file mode 100644
index 000000000..ac20fdda6
--- /dev/null
+++ b/testdata/lvs/ringo_simple_blackboxing_netter.lvsdb
@@ -0,0 +1,540 @@
+#%lvsdb-klayout
+
+# Layout
+layout(
+ top(RINGO)
+ unit(0.001)
+
+ # Layer section
+ # This section lists the mask layers (drawing or derived) and their connections.
+
+ # Mask layers
+ layer(l3 '1/0')
+ layer(l4 '5/0')
+ layer(l8 '8/0')
+ layer(l11 '9/0')
+ layer(l12 '10/0')
+ layer(l13 '11/0')
+ layer(l7 '13/0')
+ layer(l2)
+ layer(l9)
+ layer(l6)
+ layer(l10)
+
+ # Mask layer connectivity
+ connect(l3 l3 l9)
+ connect(l4 l4 l8)
+ connect(l8 l4 l8 l11 l2 l9 l6 l10)
+ connect(l11 l8 l11 l12)
+ connect(l12 l11 l12 l13)
+ connect(l13 l12 l13)
+ connect(l2 l8 l2)
+ connect(l9 l3 l8 l9)
+ connect(l6 l8 l6)
+ connect(l10 l8 l10)
+
+ # Global nets and connectivity
+ global(l7 SUBSTRATE)
+ global(l10 SUBSTRATE)
+
+ # Device class section
+ class(PMOS MOS4)
+ class(NMOS MOS4)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(ND2X1
+
+ # Circuit boundary
+ rect((-100 250) (2600 7750))
+
+ # Outgoing pins and their connections to nets
+ pin(name(VDD))
+ pin(name(OUT))
+ pin(name(VSS))
+ pin()
+ pin(name(B))
+ pin(name(A))
+ pin(name(BULK))
+
+ )
+ circuit(INVX1
+
+ # Circuit boundary
+ rect((-100 250) (2000 7750))
+
+ # Outgoing pins and their connections to nets
+ pin(name(VDD))
+ pin(name(OUT))
+ pin(name(VSS))
+ pin()
+ pin(name(IN))
+ pin(name(BULK))
+
+ )
+ circuit(INVX2
+
+ # Circuit boundary
+ rect((-100 250) (2600 7750))
+
+ # Outgoing pins and their connections to nets
+ pin(name(IN))
+ pin(name(VDD))
+ pin(name(OUT))
+ pin(name(VSS))
+ pin()
+ pin(name(BULK))
+
+ )
+ circuit(RINGO
+
+ # Circuit boundary
+ rect((600 250) (25800 7750))
+
+ # Nets with their geometries
+ net(1
+ rect(l11 (4040 2950) (610 300))
+ )
+ net(2
+ rect(l11 (5550 2950) (900 300))
+ )
+ net(3
+ rect(l11 (18150 2950) (900 300))
+ )
+ net(4
+ rect(l11 (19950 2950) (900 300))
+ )
+ net(5 name(FB)
+ rect(l11 (21750 2950) (900 300))
+ rect(l11 (-19530 590) (320 320))
+ rect(l11 (17820 -320) (320 320))
+ rect(l12 (-18400 -260) (200 200))
+ rect(l12 (17940 -200) (200 200))
+ rect(l13 (-18040 -300) (17740 400))
+ rect(l13 (-17921 -201) (2 2))
+ rect(l13 (-221 -201) (400 400))
+ rect(l13 (17740 -400) (400 400))
+ )
+ net(6 name(VDD)
+ rect(l3 (1100 4500) (1400 3500))
+ rect(l3 (-1900 -3500) (600 3500))
+ rect(l3 (23300 -3500) (1400 3500))
+ rect(l3 (-100 -3500) (600 3500))
+ rect(l8 (-24690 -1240) (180 180))
+ rect(l8 (-180 370) (180 180))
+ rect(l8 (-180 -1280) (180 180))
+ rect(l8 (23220 370) (180 180))
+ rect(l8 (-180 370) (180 180))
+ rect(l8 (-180 -1280) (180 180))
+ rect(l11 (-22341 859) (2 2))
+ rect(l11 (-1751 -451) (1200 800))
+ rect(l11 (-750 -1450) (300 1400))
+ rect(l11 (-101 -351) (2 2))
+ rect(l11 (-1251 -401) (600 800))
+ rect(l11 (23400 -800) (1200 800))
+ rect(l11 (-750 -1450) (300 1400))
+ rect(l11 (-101 -351) (2 2))
+ rect(l11 (549 -401) (600 800))
+ rect(l9 (-24850 -1500) (500 1500))
+ rect(l9 (22900 -1500) (500 1500))
+ )
+ net(7 name(OUT)
+ rect(l11 (23440 3840) (320 320))
+ rect(l12 (-260 -260) (200 200))
+ rect(l13 (-101 -101) (2 2))
+ rect(l13 (-201 -201) (400 400))
+ )
+ net(8 name(ENABLE)
+ rect(l11 (2440 2940) (320 320))
+ rect(l12 (-260 -260) (200 200))
+ rect(l13 (-101 -101) (2 2))
+ rect(l13 (-201 -201) (400 400))
+ )
+ net(9 name(VSS)
+ rect(l8 (1710 1610) (180 180))
+ rect(l8 (-180 -1280) (180 180))
+ rect(l8 (-180 370) (180 180))
+ rect(l8 (23220 370) (180 180))
+ rect(l8 (-180 -1280) (180 180))
+ rect(l8 (-180 370) (180 180))
+ rect(l11 (-22341 -391) (2 2))
+ rect(l11 (-1301 -401) (300 1400))
+ rect(l11 (-750 -1450) (1200 800))
+ rect(l11 (-551 -401) (2 2))
+ rect(l11 (-1251 -401) (600 800))
+ rect(l11 (23850 -750) (300 1400))
+ rect(l11 (-750 -1450) (1200 800))
+ rect(l11 (-551 -401) (2 2))
+ rect(l11 (549 -401) (600 800))
+ rect(l10 (-24850 -800) (500 1500))
+ rect(l10 (22900 -1500) (500 1500))
+ )
+ net(10
+ rect(l11 (7350 2950) (900 300))
+ )
+ net(11
+ rect(l11 (16350 2950) (900 300))
+ )
+ net(12
+ rect(l11 (9150 2950) (900 300))
+ )
+ net(13
+ rect(l11 (10950 2950) (900 300))
+ )
+ net(14
+ rect(l11 (12750 2950) (900 300))
+ )
+ net(15
+ rect(l11 (14550 2950) (900 300))
+ )
+
+ # Outgoing pins and their connections to nets
+ pin(5 name(FB))
+ pin(6 name(VDD))
+ pin(7 name(OUT))
+ pin(8 name(ENABLE))
+ pin(9 name(VSS))
+
+ # Subcircuits and their connections
+ circuit(1 ND2X1 location(1800 0)
+ pin(0 6)
+ pin(1 1)
+ pin(2 9)
+ pin(3 6)
+ pin(4 5)
+ pin(5 8)
+ pin(6 9)
+ )
+ circuit(2 INVX1 location(4200 0)
+ pin(0 6)
+ pin(1 2)
+ pin(2 9)
+ pin(3 6)
+ pin(4 1)
+ pin(5 9)
+ )
+ circuit(3 INVX1 location(6000 0)
+ pin(0 6)
+ pin(1 10)
+ pin(2 9)
+ pin(3 6)
+ pin(4 2)
+ pin(5 9)
+ )
+ circuit(4 INVX1 location(16800 0)
+ pin(0 6)
+ pin(1 3)
+ pin(2 9)
+ pin(3 6)
+ pin(4 11)
+ pin(5 9)
+ )
+ circuit(5 INVX1 location(18600 0)
+ pin(0 6)
+ pin(1 4)
+ pin(2 9)
+ pin(3 6)
+ pin(4 3)
+ pin(5 9)
+ )
+ circuit(6 INVX1 location(20400 0)
+ pin(0 6)
+ pin(1 5)
+ pin(2 9)
+ pin(3 6)
+ pin(4 4)
+ pin(5 9)
+ )
+ circuit(7 INVX2 location(22200 0)
+ pin(0 5)
+ pin(1 6)
+ pin(2 7)
+ pin(3 9)
+ pin(4 6)
+ pin(5 9)
+ )
+ circuit(17 INVX1 location(7800 0)
+ pin(0 6)
+ pin(1 12)
+ pin(2 9)
+ pin(3 6)
+ pin(4 10)
+ pin(5 9)
+ )
+ circuit(18 INVX1 location(9600 0)
+ pin(0 6)
+ pin(1 13)
+ pin(2 9)
+ pin(3 6)
+ pin(4 12)
+ pin(5 9)
+ )
+ circuit(19 INVX1 location(11400 0)
+ pin(0 6)
+ pin(1 14)
+ pin(2 9)
+ pin(3 6)
+ pin(4 13)
+ pin(5 9)
+ )
+ circuit(20 INVX1 location(13200 0)
+ pin(0 6)
+ pin(1 15)
+ pin(2 9)
+ pin(3 6)
+ pin(4 14)
+ pin(5 9)
+ )
+ circuit(21 INVX1 location(15000 0)
+ pin(0 6)
+ pin(1 11)
+ pin(2 9)
+ pin(3 6)
+ pin(4 15)
+ pin(5 9)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Device class section
+ class(PMOS MOS4)
+ class(NMOS MOS4)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(ND2X1
+
+ # Outgoing pins and their connections to nets
+ pin(name(VDD))
+ pin(name(OUT))
+ pin(name(VSS))
+ pin(name(NWELL))
+ pin(name(B))
+ pin(name(A))
+ pin(name(BULK))
+
+ )
+ circuit(INVX1
+
+ # Outgoing pins and their connections to nets
+ pin(name(VDD))
+ pin(name(OUT))
+ pin(name(VSS))
+ pin(name(NWELL))
+ pin(name(IN))
+ pin(name(BULK))
+
+ )
+ circuit(INVX2
+
+ # Outgoing pins and their connections to nets
+ pin(name(VDD))
+ pin(name(OUT))
+ pin(name(VSS))
+ pin(name(NWELL))
+ pin(name(IN))
+ pin(name(BULK))
+
+ )
+ circuit(RINGO
+
+ # Nets
+ net(1 name(VSS))
+ net(2 name(VDD))
+ net(3 name(FB))
+ net(4 name(ENABLE))
+ net(5 name(OUT))
+ net(6 name('1'))
+ net(7 name('2'))
+ net(8 name('3'))
+ net(9 name('4'))
+ net(10 name('5'))
+ net(11 name('6'))
+ net(12 name('7'))
+ net(13 name('8'))
+ net(14 name('9'))
+ net(15 name('10'))
+
+ # Outgoing pins and their connections to nets
+ pin(1 name(VSS))
+ pin(2 name(VDD))
+ pin(3 name(FB))
+ pin(4 name(ENABLE))
+ pin(5 name(OUT))
+
+ # Subcircuits and their connections
+ circuit(1 ND2X1 name($1)
+ pin(0 2)
+ pin(1 6)
+ pin(2 1)
+ pin(3 2)
+ pin(4 3)
+ pin(5 4)
+ pin(6 1)
+ )
+ circuit(2 INVX1 name($2)
+ pin(0 2)
+ pin(1 7)
+ pin(2 1)
+ pin(3 2)
+ pin(4 6)
+ pin(5 1)
+ )
+ circuit(3 INVX1 name($3)
+ pin(0 2)
+ pin(1 8)
+ pin(2 1)
+ pin(3 2)
+ pin(4 7)
+ pin(5 1)
+ )
+ circuit(4 INVX1 name($4)
+ pin(0 2)
+ pin(1 9)
+ pin(2 1)
+ pin(3 2)
+ pin(4 8)
+ pin(5 1)
+ )
+ circuit(5 INVX1 name($5)
+ pin(0 2)
+ pin(1 10)
+ pin(2 1)
+ pin(3 2)
+ pin(4 9)
+ pin(5 1)
+ )
+ circuit(6 INVX1 name($6)
+ pin(0 2)
+ pin(1 11)
+ pin(2 1)
+ pin(3 2)
+ pin(4 10)
+ pin(5 1)
+ )
+ circuit(7 INVX1 name($7)
+ pin(0 2)
+ pin(1 12)
+ pin(2 1)
+ pin(3 2)
+ pin(4 11)
+ pin(5 1)
+ )
+ circuit(8 INVX1 name($8)
+ pin(0 2)
+ pin(1 13)
+ pin(2 1)
+ pin(3 2)
+ pin(4 12)
+ pin(5 1)
+ )
+ circuit(9 INVX1 name($9)
+ pin(0 2)
+ pin(1 14)
+ pin(2 1)
+ pin(3 2)
+ pin(4 13)
+ pin(5 1)
+ )
+ circuit(10 INVX1 name($10)
+ pin(0 2)
+ pin(1 15)
+ pin(2 1)
+ pin(3 2)
+ pin(4 14)
+ pin(5 1)
+ )
+ circuit(11 INVX1 name($11)
+ pin(0 2)
+ pin(1 3)
+ pin(2 1)
+ pin(3 2)
+ pin(4 15)
+ pin(5 1)
+ )
+ circuit(12 INVX2 name($12)
+ pin(0 2)
+ pin(1 5)
+ pin(2 1)
+ pin(3 2)
+ pin(4 3)
+ pin(5 1)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(INVX1 INVX1 match
+ xref(
+ pin(3 3 match)
+ pin(5 5 match)
+ pin(4 4 match)
+ pin(1 1 match)
+ pin(0 0 match)
+ pin(2 2 match)
+ )
+ )
+ circuit(INVX2 INVX2 match
+ xref(
+ pin(4 3 match)
+ pin(5 5 match)
+ pin(0 4 match)
+ pin(2 1 match)
+ pin(1 0 match)
+ pin(3 2 match)
+ )
+ )
+ circuit(ND2X1 ND2X1 match
+ xref(
+ pin(3 3 match)
+ pin(5 5 match)
+ pin(4 4 match)
+ pin(6 6 match)
+ pin(1 1 match)
+ pin(0 0 match)
+ pin(2 2 match)
+ )
+ )
+ circuit(RINGO RINGO match
+ xref(
+ net(1 6 match)
+ net(4 15 match)
+ net(2 7 match)
+ net(10 8 match)
+ net(12 9 match)
+ net(13 10 match)
+ net(14 11 match)
+ net(15 12 match)
+ net(11 13 match)
+ net(3 14 match)
+ net(8 4 match)
+ net(5 3 match)
+ net(7 5 match)
+ net(6 2 match)
+ net(9 1 match)
+ pin(3 3 match)
+ pin(0 2 match)
+ pin(2 4 match)
+ pin(1 1 match)
+ pin(4 0 match)
+ circuit(2 2 match)
+ circuit(3 3 match)
+ circuit(17 4 match)
+ circuit(18 5 match)
+ circuit(19 6 match)
+ circuit(20 7 match)
+ circuit(21 8 match)
+ circuit(4 9 match)
+ circuit(5 10 match)
+ circuit(6 11 match)
+ circuit(7 12 match)
+ circuit(1 1 match)
+ )
+ )
+)
From 72dc94197e68a2ccc95f7fa037fce7d9b27d688b Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 28 Jun 2021 20:29:40 +0200
Subject: [PATCH 08/15] New method: Circuit#nets_by_name
---
src/db/db/gsiDeclDbNetlist.cc | 44 +++++++++++++++++++++++++++++++++++
testdata/ruby/dbNetlist.rb | 3 +++
2 files changed, 47 insertions(+)
diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc
index f2b0bdcd3..4461534e1 100644
--- a/src/db/db/gsiDeclDbNetlist.cc
+++ b/src/db/db/gsiDeclDbNetlist.cc
@@ -1234,6 +1234,38 @@ static db::Pin *create_pin (db::Circuit *circuit, const std::string &name)
return & circuit->add_pin (name);
}
+static std::vector
+nets_by_name (db::Circuit *circuit, const std::string &name_pattern)
+{
+ std::vector res;
+
+ tl::GlobPattern glob (name_pattern);
+ for (db::Circuit::net_iterator n = circuit->begin_nets (); n != circuit->end_nets (); ++n) {
+ db::Net *net = n.operator-> ();
+ if (glob.match (net->name ())) {
+ res.push_back (net);
+ }
+ }
+
+ return res;
+}
+
+static std::vector
+nets_by_name_const (const db::Circuit *circuit, const std::string &name_pattern)
+{
+ std::vector res;
+
+ tl::GlobPattern glob (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 ())) {
+ res.push_back (net);
+ }
+ }
+
+ return res;
+}
+
Class decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
gsi::method_ext ("create_pin", &create_pin, gsi::arg ("name"),
"@brief Creates a new \\Pin object inside the circuit\n"
@@ -1347,6 +1379,18 @@ Class decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
"\n\n"
"This constness variant has been introduced in version 0.26.8"
) +
+ gsi::method_ext ("nets_by_name", &nets_by_name, gsi::arg ("name_pattern"),
+ "@brief Gets the net objects for a given name filter.\n"
+ "The name filter is a glob pattern. This method will return all \\Net objects matching the glob pattern.\n"
+ "\n"
+ "This method has been introduced in version 0.27.3.\n"
+ ) +
+ gsi::method_ext ("nets_by_name", &nets_by_name_const, gsi::arg ("name_pattern"),
+ "@brief Gets the net objects for a given name filter (const version).\n"
+ "The name filter is a glob pattern. This method will return all \\Net objects matching the glob pattern.\n"
+ "\n\n"
+ "This constness variant has been introduced in version 0.27.3"
+ ) +
gsi::method ("pin_by_id", (db::Pin *(db::Circuit::*) (size_t)) &db::Circuit::pin_by_id, gsi::arg ("id"),
"@brief Gets the \\Pin object corresponding to a specific ID\n"
"If the ID is not a valid pin ID, nil is returned."
diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb
index bb1d34570..7e5670fd0 100644
--- a/testdata/ruby/dbNetlist.rb
+++ b/testdata/ruby/dbNetlist.rb
@@ -698,7 +698,9 @@ class DBNetlist_TestClass < TestBase
assert_equal(c.net_by_cluster_id(17).name, "NET1")
assert_equal(c.net_by_cluster_id(42).inspect, "nil")
assert_equal(c.net_by_name("NET1").name, "NET1")
+ assert_equal(c.nets_by_name("NET*").collect(&:name), ["NET1"])
assert_equal(c.net_by_name("DOESNOTEXIST").inspect, "nil")
+ assert_equal(c.nets_by_name("DOESNOTEXIST").collect(&:name), [])
net2 = c.create_net
net2.name = "NET2"
@@ -706,6 +708,7 @@ class DBNetlist_TestClass < TestBase
names = []
c.each_net { |n| names << n.name }
assert_equal(names, [ "NET1", "NET2" ])
+ assert_equal(c.nets_by_name("NET*").collect(&:name), ["NET1", "NET2"])
assert_equal(net1.pin_count, 0)
c.connect_pin(pina1, net1)
From ab70c42c681dcb1651ca3394459749db2a943ef2 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 28 Jun 2021 22:33:46 +0200
Subject: [PATCH 09/15] Some enhancements for strong matching of nets
* same_nets! method for strong matching
* same_nets and same_nets! except glob pattern to circuits and nets
* both observe case sensitivity
* helper functions for case sensitivity Netlist#is_case_sensitive?, Netlist#case_sensitive=
* Netlist#nets_by_name to get nets from pattern
---
src/db/db/dbNetlistCompare.cc | 65 +++++--
src/db/db/dbNetlistCompare.h | 16 +-
src/db/db/gsiDeclDbNetlist.cc | 30 +++
src/db/db/gsiDeclDbNetlistCompare.cc | 23 ++-
src/lay/lay/doc/about/lvs_ref_netter.xml | 30 ++-
src/lvs/lvs/built-in-macros/_lvs_engine.rb | 13 +-
src/lvs/lvs/built-in-macros/_lvs_netter.rb | 138 ++++++++++----
...simple_net_and_circuit_equivalence.lvsdb.1 | 1 +
...simple_net_and_circuit_equivalence.lvsdb.2 | 1 +
testdata/ruby/dbNetlist.rb | 22 +++
testdata/ruby/dbNetlistCompare.rb | 174 +++++++++++++++++-
11 files changed, 455 insertions(+), 58 deletions(-)
diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc
index cfd4db9c2..1d146713d 100644
--- a/src/db/db/dbNetlistCompare.cc
+++ b/src/db/db/dbNetlistCompare.cc
@@ -1013,6 +1013,14 @@ public:
return j->second;
}
+ /**
+ * @brief Gets a value indicating whether there is a node for the given net
+ */
+ bool has_node_index_for_net (const db::Net *net) const
+ {
+ return m_net_index.find (net) != m_net_index.end ();
+ }
+
/**
* @brief Gets the node for a given node index
*/
@@ -2880,9 +2888,16 @@ NetlistComparer::exclude_resistors (double threshold)
}
void
-NetlistComparer::same_nets (const db::Net *na, const db::Net *nb)
+NetlistComparer::same_nets (const db::Net *na, const db::Net *nb, bool must_match)
{
- m_same_nets [std::make_pair (na->circuit (), nb->circuit ())].push_back (std::make_pair (na, nb));
+ 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));
+}
+
+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));
}
void
@@ -3114,9 +3129,9 @@ NetlistComparer::compare (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 > empty;
- const std::vector > *net_identity = ∅
- std::map, std::vector > >::const_iterator sn = m_same_nets.find (std::make_pair (ca, cb));
+ 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;
}
@@ -3525,7 +3540,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
db::DeviceCategorizer &device_categorizer,
db::CircuitCategorizer &circuit_categorizer,
db::CircuitPinMapper &circuit_pin_mapper,
- const std::vector > &net_identity,
+ const std::vector, bool> > &net_identity,
bool &pin_mismatch,
std::map &c12_circuit_and_pin_mapping,
std::map &c22_circuit_and_pin_mapping) const
@@ -3551,11 +3566,39 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2,
g1.identify (0, 0);
g2.identify (0, 0);
- for (std::vector >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) {
- size_t ni1 = g1.node_index_for_net (p->first);
- size_t ni2 = g2.node_index_for_net (p->second);
- g1.identify (ni1, ni2);
- g2.identify (ni2, ni1);
+ for (std::vector, bool> >::const_iterator p = net_identity.begin (); p != net_identity.end (); ++p) {
+
+ // NOTE: nets may vanish, hence there
+ if (g1.has_node_index_for_net (p->first.first) && g2.has_node_index_for_net (p->first.second)) {
+
+ size_t ni1 = g1.node_index_for_net (p->first.first);
+ size_t ni2 = g2.node_index_for_net (p->first.second);
+ g1.identify (ni1, ni2);
+ g2.identify (ni2, ni1);
+
+ // in must_match mode, check if the nets are identical
+ if (p->second && ! (g1.node(ni1) == g2.node(ni2))) {
+ mp_logger->net_mismatch (p->first.first, p->first.second);
+ } else {
+ mp_logger->match_nets (p->first.first, p->first.second);
+ }
+
+ } else if (p->second && g1.has_node_index_for_net (p->first.first)) {
+
+ mp_logger->net_mismatch (p->first.first, 0);
+
+ size_t ni1 = g1.node_index_for_net (p->first.first);
+ g1.identify (ni1, 0);
+
+ } else if (p->second && g2.has_node_index_for_net (p->first.second)) {
+
+ mp_logger->net_mismatch (0, p->first.second);
+
+ size_t ni2 = g2.node_index_for_net (p->first.second);
+ g2.identify (ni2, 0);
+
+ }
+
}
int iter = 0;
diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h
index 2d4e81506..197d5ef6c 100644
--- a/src/db/db/dbNetlistCompare.h
+++ b/src/db/db/dbNetlistCompare.h
@@ -181,7 +181,17 @@ public:
* net nb in netlist b.
* By default nets are not identical expect through their topology.
*/
- void same_nets (const db::Net *na, const db::Net *nb);
+ void same_nets (const db::Net *na, const db::Net *nb, bool must_match = false);
+
+ /**
+ * @brief Mark two nets as identical
+ *
+ * This makes a net na in netlist a identical to the corresponding
+ * net nb in netlist b.
+ * By default nets are not identical expect through their topology.
+ * This version allows mapping one net to a null net because the circuits are explicitly specified.
+ */
+ void same_nets (const db::Circuit *ca, const db::Circuit *cb, const db::Net *na, const db::Net *nb, bool must_match);
/**
* @brief Mark two pins as equivalent (i.e. can be swapped)
@@ -344,7 +354,7 @@ private:
NetlistComparer &operator= (const NetlistComparer &);
protected:
- bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector > &net_identity, bool &pin_mismatch, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping) const;
+ bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector, bool> > &net_identity, bool &pin_mismatch, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping) const;
bool all_subcircuits_verified (const db::Circuit *c, const std::set &verified_circuits) const;
std::string generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set &verified_circuits_a, const db::Circuit *cb, const std::set &verified_circuits_b) const;
static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper);
@@ -354,7 +364,7 @@ protected:
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;
mutable NetlistCompareLogger *mp_logger;
- std::map, std::vector > > m_same_nets;
+ std::map, std::vector, bool> > > m_same_nets;
std::unique_ptr mp_circuit_pin_mapper;
std::unique_ptr mp_device_categorizer;
std::unique_ptr mp_circuit_categorizer;
diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc
index 4461534e1..19bfd3a5e 100644
--- a/src/db/db/gsiDeclDbNetlist.cc
+++ b/src/db/db/gsiDeclDbNetlist.cc
@@ -1238,8 +1238,14 @@ static std::vector
nets_by_name (db::Circuit *circuit, const std::string &name_pattern)
{
std::vector res;
+ if (! circuit) {
+ return res;
+ }
tl::GlobPattern glob (name_pattern);
+ if (circuit->netlist ()) {
+ glob.set_case_sensitive (circuit->netlist ()->is_case_sensitive ());
+ }
for (db::Circuit::net_iterator n = circuit->begin_nets (); n != circuit->end_nets (); ++n) {
db::Net *net = n.operator-> ();
if (glob.match (net->name ())) {
@@ -1254,8 +1260,14 @@ static std::vector
nets_by_name_const (const db::Circuit *circuit, const std::string &name_pattern)
{
std::vector res;
+ if (! circuit) {
+ return res;
+ }
tl::GlobPattern glob (name_pattern);
+ if (circuit->netlist ()) {
+ glob.set_case_sensitive (circuit->netlist ()->is_case_sensitive ());
+ }
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 ())) {
@@ -1681,8 +1693,13 @@ static std::vector
circuits_by_name (db::Netlist *netlist, const std::string &name_pattern)
{
std::vector res;
+ if (! netlist) {
+ return res;
+ }
tl::GlobPattern glob (name_pattern);
+ glob.set_case_sensitive (netlist->is_case_sensitive ());
+
for (db::Netlist::circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
db::Circuit *circuit = c.operator-> ();
if (glob.match (circuit->name ())) {
@@ -1697,8 +1714,13 @@ static std::vector
circuits_by_name_const (const db::Netlist *netlist, const std::string &name_pattern)
{
std::vector res;
+ if (! netlist) {
+ return res;
+ }
tl::GlobPattern glob (name_pattern);
+ glob.set_case_sensitive (netlist->is_case_sensitive ());
+
for (db::Netlist::const_circuit_iterator c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
const db::Circuit *circuit = c.operator-> ();
if (glob.match (circuit->name ())) {
@@ -1710,6 +1732,14 @@ circuits_by_name_const (const db::Netlist *netlist, const std::string &name_patt
}
Class decl_dbNetlist ("db", "Netlist",
+ gsi::method ("is_case_sensitive?", &db::Netlist::is_case_sensitive,
+ "@brief Returns a value indicating whether the netlist names are case sensitive\n"
+ "This method has been added in version 0.27.3.\n"
+ ) +
+ gsi::method ("case_sensitive=", &db::Netlist::set_case_sensitive, gsi::arg ("cs"),
+ "@brief Sets a value indicating whether the netlist names are case sensitive\n"
+ "This method has been added in version 0.27.3.\n"
+ ) +
gsi::method_ext ("add", &gsi::add_circuit, gsi::arg ("circuit"),
"@brief Adds the circuit to the netlist\n"
"This method will add the given circuit object to the netlist. "
diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc
index 815790559..5a0696ee6 100644
--- a/src/db/db/gsiDeclDbNetlistCompare.cc
+++ b/src/db/db/gsiDeclDbNetlistCompare.cc
@@ -476,13 +476,32 @@ Class decl_dbNetlistComparer ("db", "NetlistComparer",
"The logger is a delegate or event receiver which the comparer will send compare events to. "
"See the class description for more details."
) +
- gsi::method ("same_nets", &db::NetlistComparer::same_nets, gsi::arg ("net_a"), gsi::arg ("net_b"),
+ gsi::method ("same_nets", (void (db::NetlistComparer::*) (const db::Net *, const db::Net *, bool)) &db::NetlistComparer::same_nets, gsi::arg ("net_a"), gsi::arg ("net_b"), gsi::arg ("must_match", false),
"@brief Marks two nets as identical.\n"
"This makes a net net_a in netlist a identical to the corresponding\n"
"net net_b in netlist b (see \\compare).\n"
"Otherwise, the algorithm will try to identify nets according to their topology. "
"This method can be used to supply hints to the compare algorithm. It will use "
- "these hints to derive further identities."
+ "these hints to derive further identities.\n"
+ "\n"
+ "If 'must_match' is true, the nets are required to match. If they don't, an error is reported.\n"
+ "\n"
+ "The 'must_match' optional argument has been added in version 0.27.3.\n"
+ ) +
+ gsi::method ("same_nets", (void (db::NetlistComparer::*) (const db::Circuit *, const db::Circuit *, const db::Net *, const db::Net *, bool)) &db::NetlistComparer::same_nets, gsi::arg ("circuit_a"), gsi::arg ("circuit_b"), gsi::arg ("net_a"), gsi::arg ("net_b"), gsi::arg ("must_match", false),
+ "@brief Marks two nets as identical.\n"
+ "This makes a net net_a in netlist a identical to the corresponding\n"
+ "net net_b in netlist b (see \\compare).\n"
+ "Otherwise, the algorithm will try to identify nets according to their topology. "
+ "This method can be used to supply hints to the compare algorithm. It will use "
+ "these hints to derive further identities.\n"
+ "\n"
+ "If 'must_match' is true, the nets are required to match. If they don't, an error is reported.\n"
+ "\n"
+ "This variant allows specifying nil for the nets indicating the nets are mismatched by definition. "
+ "with 'must_match' this will render a net mismatch error.\n"
+ "\n"
+ "This variant has been added in version 0.27.3.\n"
) +
gsi::method ("equivalent_pins", (void (db::NetlistComparer::*) (const db::Circuit *, size_t, size_t)) &db::NetlistComparer::equivalent_pins, gsi::arg ("circuit_b"), gsi::arg ("pin_id1"), gsi::arg ("pin_id2"),
"@brief Marks two pins of the given circuit as equivalent (i.e. they can be swapped).\n"
diff --git a/src/lay/lay/doc/about/lvs_ref_netter.xml b/src/lay/lay/doc/about/lvs_ref_netter.xml
index d68a49a96..4b33f3fe5 100644
--- a/src/lay/lay/doc/about/lvs_ref_netter.xml
+++ b/src/lay/lay/doc/about/lvs_ref_netter.xml
@@ -81,7 +81,7 @@ The filter is a glob expression.
This has the following effects:
-- The circuits are no longer compared against each other
+- The circuits are no longer compared (netlist vs. schematic)
- Named pins are required to match (use labels on the nets to name pins in the layout)
- Unnamed pins are treated as equivalent and can be swapped
- The selected circuits will not be purged on netlist simplification
@@ -91,6 +91,8 @@ Using this method can be useful to reduce the verification overhead for
blocks which are already verifified by other ways or for which no schematic
is available - e.g. hard macros.
+Example:
+
# skips all MEMORY* circuits from compare
blank_circuit("MEMORY*")
@@ -317,7 +319,8 @@ Use this method andwhere in the script before the compare
Usage:
-- same_nets(circuit, net_a, net_b)
+- same_nets(circuit_pattern, net_pattern)
+- same_nets(circuit_pattern, net_a, net_b)
- same_nets(circuit_a, net_a, circuit_b, net_b)
@@ -325,8 +328,17 @@ This method will force an equivalence between the net_a and net_b from circuit_a
and circuit_b (circuit in the three-argument form is for both circuit_a and circuit_b).
In the four-argument form, the circuits can be either given by name or as Circuit
-objects. In the three-argument form, the circuit has to be given by name.
+objects. In the three-argument form, the circuits have to be given by name pattern.
Nets can be either given by name or as Net objects.
+In the two-argument form, the circuits and nets have to be given as name pattern.
+
+"name pattern" are glob-style pattern - e.g. the following will identify the
+all nets starting with "A" from the extracted netlist with the same net from
+the schematic netlist for all circuits starting with "INV":
+
+
+same_nets("INV*", "A*")
+
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
@@ -337,6 +349,18 @@ Names are case sensitive for layout-derived netlists and case-insensitive for SP
Use this method andwhere in the script before the compare call.
+"same_nets!" - Establishes an equivalence between the nets with matching requirement
+
+Usage:
+
+- same_nets!(circuit_pattern, net_pattern)
+- same_nets!(circuit_pattern, net_a, net_b)
+- 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.
+
"schematic" - Gets, sets or reads the reference netlist
Usage:
diff --git a/src/lvs/lvs/built-in-macros/_lvs_engine.rb b/src/lvs/lvs/built-in-macros/_lvs_engine.rb
index bb24407e3..3a0506516 100644
--- a/src/lvs/lvs/built-in-macros/_lvs_engine.rb
+++ b/src/lvs/lvs/built-in-macros/_lvs_engine.rb
@@ -115,10 +115,19 @@ module LVS
# %LVS%
# @name same_nets
# @brief Establishes an equivalence between the nets
- # @synopsis same_nets(circuit, net_a, net_b)
+ # @synopsis same_nets(circuit_pattern, net_pattern)
+ # @synopsis same_nets(circuit_pattern, net_a, net_b)
# @synopsis same_nets(circuit_a, net_a, circuit_b, net_b)
# See \Netter#same_nets for a description of that function.
+ # %LVS%
+ # @name same_nets!
+ # @brief Establishes an equivalence between the nets (must match)
+ # @synopsis same_nets!(circuit_pattern, net_pattern)
+ # @synopsis same_nets!(circuit_pattern, net_a, net_b)
+ # @synopsis same_nets!(circuit_a, net_a, circuit_b, net_b)
+ # See \Netter#same_nets! for a description of that function.
+
# %LVS%
# @name same_circuits
# @brief Establishes an equivalence between the circuits
@@ -174,7 +183,7 @@ module LVS
# @synopsis tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance])
# See \Netter#tolerance for a description of that function.
- %w(schematic compare join_symmetric_nets tolerance blank_circuit align same_nets same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
+ %w(schematic compare join_symmetric_nets tolerance blank_circuit align same_nets same_nets! same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f|
eval <<"CODE"
def #{f}(*args)
_netter.#{f}(*args)
diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
index 8e5aa1d63..4a25a1093 100644
--- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb
+++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
@@ -370,14 +370,24 @@ module LVS
# %LVS%
# @name same_nets
# @brief Establishes an equivalence between the nets
- # @synopsis same_nets(circuit, net_a, net_b)
+ # @synopsis same_nets(circuit_pattern, net_pattern)
+ # @synopsis same_nets(circuit_pattern, net_a, net_b)
# @synopsis same_nets(circuit_a, net_a, circuit_b, net_b)
# This method will force an equivalence between the net_a and net_b from circuit_a
# and circuit_b (circuit in the three-argument form is for both circuit_a and circuit_b).
- #
+ #
# In the four-argument form, the circuits can be either given by name or as Circuit
- # objects. In the three-argument form, the circuit has to be given by name.
+ # objects. In the three-argument form, the circuits have to be given by name pattern.
# Nets can be either given by name or as Net objects.
+ # In the two-argument form, the circuits and nets have to be given as name pattern.
+ #
+ # "name pattern" are glob-style pattern - e.g. the following will identify the
+ # all nets starting with "A" from the extracted netlist with the same net from
+ # the schematic netlist for all circuits starting with "INV":
+ #
+ # @code
+ # same_nets("INV*", "A*")
+ # @/code
#
# 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
@@ -389,65 +399,125 @@ module LVS
# Use this method andwhere in the script before the \compare call.
def same_nets(*args)
+ _same_nets_impl(false, *args)
+ end
- if args.size < 3
- raise("Too few arguments to 'same_nets' (need at least 3)")
+ # %LVS%
+ # @name same_nets!
+ # @brief Establishes an equivalence between the nets with matching requirement
+ # @synopsis same_nets!(circuit_pattern, net_pattern)
+ # @synopsis same_nets!(circuit_pattern, net_a, net_b)
+ # @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.
+
+ def same_nets!(*args)
+ _same_nets_impl(true, *args)
+ end
+
+ def _same_nets_impl(force, *args)
+
+ if args.size < 2
+ raise("Too few arguments to 'same_nets' (need at least 2)")
end
if args.size > 4
raise("Too many arguments to 'same_nets' (need max 4)")
end
if args.size == 3
- ( ca, a, b ) = args
- cb = ca
+ ( ca, a ) = args
+ cb = nil
ca.is_a?(String) || raise("Circuit argument of 'same_nets' must be a string")
+ b = nil
+ a.is_a?(String) || raise("Net argument of 'same_nets' must be a string")
+ elsif args.size == 3
+ ( ca, a, b ) = args
+ cb = nil
+ ca.is_a?(String) || raise("Circuit argument of 'same_nets' must be a string")
+ [ a, b ].each do |n|
+ n.is_a?(String) || n.is_a?(RBA::Net) || raise("Net arguments of 'same_nets' must be strings or Net objects")
+ end
else
( ca, a, cb, b ) = args
[ ca, cb ].each do |n|
- n.is_a?(String) || n.is_a?(RBA::Net) || raise("Circuit arguments of 'same_nets' must be strings or Net objects")
+ n.is_a?(String) || n.is_a?(RBA::Circuit) || raise("Circuit arguments of 'same_nets' must be strings or Circuit objects")
+ end
+ [ a, b ].each do |n|
+ n.is_a?(String) || n.is_a?(RBA::Net) || raise("Net arguments of 'same_nets' must be strings or Net objects")
end
end
- [ a, b ].each do |n|
- n.is_a?(String) || n.is_a?(RBA::Net) || raise("Net arguments of 'same_nets' must be strings or Net objects")
- end
-
- @comparer_config << lambda { |comparer| self._same_nets(comparer, ca, a, cb, b) }
+ @comparer_config << lambda { |comparer| self._same_nets(comparer, ca, a, cb, b, force) }
end
- def _same_nets(comparer, ca, a, cb, b)
+ def _same_nets(comparer, ca, a, cb, b, force)
( nl_a, nl_b ) = _ensure_two_netlists
- if ca.is_a?(String)
- circuit_a = nl_a.circuit_by_name(ca)
+ cs = !(nl_a.is_case_sensitive? && nl_b.is_case_sensitive?)
+
+ if ca.is_a?(String) && !cb
+
+ n2c = {}
+ nl_a.circuits_by_name(ca).each { |c| name = cs ? c.name.upcase : c.name; n2c[name] ||= [ nil, nil ]; n2c[name][0] = c }
+ nl_b.circuits_by_name(ca).each { |c| name = cs ? c.name.upcase : c.name; n2c[name] ||= [ nil, nil ]; n2c[name][1] = c }
+
+ circuits = []
+ n2c.keys.sort.each do |n|
+ if n2c[n][0] && n2c[n][1]
+ circuits << n2c[n]
+ end
+ end
+
else
- circuit_a = ca
- end
- if cb.is_a?(String)
- circuit_b = nl_b.circuit_by_name(cb)
- else
- circuit_b = cb
- end
+ circuit_a = ca.is_a?(String) ? nl_a.circuit_by_name(ca) : ca
+ circuit_b = cb.is_a?(String) ? nl_b.circuit_by_name(cb) : cb
- if circuit_a && circuit_b
-
- if a.is_a?(String)
- net_a = circuit_a.net_by_name(a) || raise("Not a valid net name in extracted netlist in 'same_nets': #{a} (for circuit #{circuit_a})")
- else
- net_a = a
+ circuits = []
+ if circuit_a && circuit_b
+ circuits << [ circuit_a, circuit_b ]
end
- if b.is_a?(String)
- net_b = circuit_b.net_by_name(b) || raise("Not a valid net name in extracted netlist in 'same_nets': #{b} (for circuit #{circuit_b})")
+ end
+
+ circuits.each do |circuit_a, circuit_b|
+
+ if a.is_a?(String) && !b
+
+ n2n = {}
+ circuit_a.nets_by_name(a).each { |n| name = cs ? n.name.upcase : n.name; n2n[name] ||= [ nil, nil ]; n2n[name][0] = n }
+ circuit_b.nets_by_name(a).each { |n| name = cs ? n.name.upcase : n.name; n2n[name] ||= [ nil, nil ]; n2n[name][1] = n }
+
+ nets = []
+ n2n.keys.sort.each do |n|
+ nets << n2n[n]
+ end
+
else
- net_b = b
+
+ if a.is_a?(String)
+ net_a = circuit_a.net_by_name(a) || raise("Not a valid net name in extracted netlist in 'same_nets': #{a} (for circuit #{circuit_a})")
+ else
+ net_a = a
+ end
+
+ if b.is_a?(String)
+ net_b = circuit_b.net_by_name(b) || raise("Not a valid net name in extracted netlist in 'same_nets': #{b} (for circuit #{circuit_b})")
+ else
+ net_b = b
+ end
+
+ nets = []
+ if net_a && net_b
+ nets << [ net_a, net_b ]
+ end
+
end
- if net_a && net_b
- comparer.same_nets(net_a, net_b)
+ nets.each do |net_a, net_b|
+ comparer.same_nets(circuit_a, circuit_b, net_a, net_b, force)
end
end
diff --git a/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.1 b/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.1
index a43d6f458..638555d57 100644
--- a/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.1
+++ b/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.1
@@ -881,6 +881,7 @@ xref(
net(7 12 match)
net(8 13 match)
net(9 14 match)
+ net(14 4 match)
net(11 3 match)
net(13 5 match)
net(12 2 match)
diff --git a/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.2 b/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.2
index 04e80f7d8..a2b8e370d 100644
--- a/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.2
+++ b/testdata/lvs/ringo_simple_net_and_circuit_equivalence.lvsdb.2
@@ -881,6 +881,7 @@ xref(
net(7 12 match)
net(8 13 match)
net(9 14 match)
+ net(14 4 match)
net(11 3 match)
net(13 5 match)
net(12 2 match)
diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb
index 7e5670fd0..392c9a3e8 100644
--- a/testdata/ruby/dbNetlist.rb
+++ b/testdata/ruby/dbNetlist.rb
@@ -63,6 +63,13 @@ class DBNetlist_TestClass < TestBase
assert_equal(nl.circuit_by_cell_index(17).inspect, "nil")
assert_equal(nl.circuit_by_name("DOESNOTEXIST").inspect, "nil")
+ assert_equal(nl.is_case_sensitive?, true)
+ assert_equal(nl.circuit_by_name("xyz").inspect, "nil")
+ nl.case_sensitive = false
+ assert_equal(nl.is_case_sensitive?, false)
+ assert_equal(nl.circuit_by_name("xyz").name, "XYZ")
+ nl.case_sensitive = true
+
cc = RBA::Circuit::new
assert_equal(cc.dont_purge, false)
cc.dont_purge = true
@@ -103,6 +110,11 @@ class DBNetlist_TestClass < TestBase
assert_equal(names, [ c.name, cc.name ])
assert_equal(nl.circuits_by_name("X*").collect { |x| x.name }, [ "XYZ" ])
+ assert_equal(nl.circuits_by_name("x*").collect { |x| x.name }, [])
+ nl.case_sensitive = false
+ assert_equal(nl.circuits_by_name("X*").collect { |x| x.name }, [ "XYZ" ])
+ assert_equal(nl.circuits_by_name("x*").collect { |x| x.name }, [ "XYZ" ])
+ nl.case_sensitive = true
assert_equal(nl.circuits_by_name("???").collect { |x| x.name }, [ "XYZ", "UVW" ])
assert_equal(nl.circuits_by_name("*").collect { |x| x.name }, [ "XYZ", "UVW" ])
assert_equal(nl.circuits_by_name("P*").collect { |x| x.name }, [])
@@ -702,6 +714,11 @@ class DBNetlist_TestClass < TestBase
assert_equal(c.net_by_name("DOESNOTEXIST").inspect, "nil")
assert_equal(c.nets_by_name("DOESNOTEXIST").collect(&:name), [])
+ assert_equal(c.net_by_name("net1").inspect, "nil")
+ nl.case_sensitive = false
+ assert_equal(c.net_by_name("net1").name, "NET1")
+ nl.case_sensitive = true
+
net2 = c.create_net
net2.name = "NET2"
@@ -709,6 +726,11 @@ class DBNetlist_TestClass < TestBase
c.each_net { |n| names << n.name }
assert_equal(names, [ "NET1", "NET2" ])
assert_equal(c.nets_by_name("NET*").collect(&:name), ["NET1", "NET2"])
+ assert_equal(c.nets_by_name("net*").collect(&:name), [])
+ nl.case_sensitive = false
+ assert_equal(c.nets_by_name("NET*").collect(&:name), ["NET1", "NET2"])
+ assert_equal(c.nets_by_name("net*").collect(&:name), ["NET1", "NET2"])
+ nl.case_sensitive = true
assert_equal(net1.pin_count, 0)
c.connect_pin(pina1, net1)
diff --git a/testdata/ruby/dbNetlistCompare.rb b/testdata/ruby/dbNetlistCompare.rb
index 58b3339ca..9fe3b704d 100644
--- a/testdata/ruby/dbNetlistCompare.rb
+++ b/testdata/ruby/dbNetlistCompare.rb
@@ -333,6 +333,8 @@ END
assert_equal(logger.text(), <<"END")
begin_circuit INV INV
+match_nets VDD VDD
+match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_pins $0 $1
@@ -459,6 +461,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
+match_nets VDD VDD
+match_nets VSS VSS
match_nets OUT OUT
match_nets INT $10
net_mismatch IN IN
@@ -487,6 +491,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
+match_nets VDD VDD
+match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_ambiguous_nets INT $10
@@ -515,6 +521,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
+match_nets VDD VDD
+match_nets VSS VSS
match_nets OUT OUT
match_nets INT $10
net_mismatch IN IN
@@ -545,6 +553,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
+match_nets VDD VDD
+match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_ambiguous_nets INT $10
@@ -574,6 +584,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
+match_nets VDD VDD
+match_nets VSS VSS
match_nets OUT OUT
match_nets IN IN
match_ambiguous_nets INT $10
@@ -636,17 +648,20 @@ END
# NOTE: adding this power hint makes the device class error harder to detect
ca = nl1.circuit_by_name("BUF")
cb = nl2.circuit_by_name("BUF")
- comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"))
- comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"))
+ comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"), false)
+ comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"), false)
+ comp.same_nets(ca.net_by_name("OUT"), cb.net_by_name("OUT"), false)
good = comp.compare(nl1, nl2)
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
+match_nets VDD VDD
+match_nets VSS VSS
+match_nets OUT OUT
match_nets INT $10
match_nets IN IN
net_mismatch INT2 $11
-net_mismatch OUT OUT
match_pins $0 $1
match_pins $1 $3
match_pins $2 $0
@@ -666,6 +681,157 @@ END
end
+ def test_6b
+
+ nls1 = <<"END"
+circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
+ device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOSB $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOSB $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+end;
+END
+
+ nls2 = <<"END"
+circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
+ device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOSB $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+end;
+END
+
+ nl1 = RBA::Netlist::new
+ nl2 = RBA::Netlist::new
+ prep_nl(nl1, nls1)
+ prep_nl(nl2, nls2)
+
+ logger = NetlistCompareTestLogger::new
+ comp = RBA::NetlistComparer::new(logger)
+
+ # NOTE: adding this power hint makes the device class error harder to detect
+ ca = nl1.circuit_by_name("BUF")
+ cb = nl2.circuit_by_name("BUF")
+ comp.same_nets(ca.net_by_name("VDD"), cb.net_by_name("VDD"), true)
+ comp.same_nets(ca.net_by_name("VSS"), cb.net_by_name("VSS"), true)
+ comp.same_nets(ca.net_by_name("OUT"), cb.net_by_name("OUT"), true)
+
+ good = comp.compare(nl1, nl2)
+
+ assert_equal(logger.text, <<"END")
+begin_circuit BUF BUF
+net_mismatch VDD VDD
+match_nets VSS VSS
+net_mismatch OUT OUT
+match_nets INT $10
+match_nets IN IN
+net_mismatch INT2 $11
+match_pins $0 $1
+match_pins $1 $3
+match_pins $2 $0
+match_pins $3 $2
+match_devices $1 $1
+match_devices $3 $2
+match_devices $5 $3
+match_devices_with_different_device_classes $7 $4
+match_devices $2 $5
+match_devices $4 $6
+match_devices $6 $7
+match_devices $8 $8
+end_circuit BUF BUF NOMATCH
+END
+
+ assert_equal(good, false)
+
+ end
+
+ def test_6c
+
+ nls1 = <<"END"
+circuit BUF ($1=IN,$2=OUT,$3=VDD,$4=VSS);
+ device PMOS $1 (S=VDD,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $2 (S=VSS,G=IN,D=INT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $3 (S=VDD,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $4 (S=VSS,G=INT,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $5 (S=VDD,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $6 (S=VSS,G=IN,D=INT2) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOSB $7 (S=VDD,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOSB $8 (S=VSS,G=INT2,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+end;
+END
+
+ nls2 = <<"END"
+circuit BUF ($1=VDD,$2=IN,$3=VSS,$4=OUT);
+ device PMOS $1 (S=VDD,G=IN,D=$10) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $2 (S=VDD,G=$10,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $3 (S=VDD,G=IN,D=$11) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device PMOS $4 (S=VDD,G=$11,D=OUT) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $5 (S=$10,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $6 (S=OUT,G=$10,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOS $7 (S=$11,G=IN,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+ device NMOSB $8 (S=OUT,G=$11,D=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);
+end;
+END
+
+ nl1 = RBA::Netlist::new
+ nl2 = RBA::Netlist::new
+ prep_nl(nl1, nls1)
+ prep_nl(nl2, nls2)
+
+ logger = NetlistCompareTestLogger::new
+ comp = RBA::NetlistComparer::new(logger)
+
+ # NOTE: adding this power hint makes the device class error harder to detect
+ ca = nl1.circuit_by_name("BUF")
+ cb = nl2.circuit_by_name("BUF")
+ comp.same_nets(ca, cb, ca.net_by_name("VDD"), cb.net_by_name("VDD"), true)
+ comp.same_nets(ca, cb, ca.net_by_name("VSS"), nil, false)
+ comp.same_nets(ca, cb, ca.net_by_name("OUT"), nil, true)
+
+ good = comp.compare(nl1, nl2)
+
+ assert_equal(logger.text, <<"END")
+begin_circuit BUF BUF
+net_mismatch VDD VDD
+match_nets VSS (null)
+net_mismatch OUT (null)
+match_nets INT $10
+match_nets IN IN
+net_mismatch INT2 (null)
+net_mismatch (null) VSS
+net_mismatch (null) OUT
+net_mismatch (null) $11
+match_pins $0 $1
+match_pins $2 $0
+match_pins $1 (null)
+match_pins $3 (null)
+match_pins (null) $2
+match_pins (null) $3
+match_devices $1 $1
+device_mismatch $3 $2
+device_mismatch $5 $3
+device_mismatch (null) $4
+device_mismatch $6 $5
+device_mismatch $4 $6
+device_mismatch $2 $7
+device_mismatch (null) $8
+device_mismatch $7 (null)
+device_mismatch $8 (null)
+end_circuit BUF BUF NOMATCH
+END
+
+ assert_equal(good, false)
+
+ end
+
def test_7
nls1 = <<"END"
@@ -713,6 +879,8 @@ END
assert_equal(logger.text, <<"END")
begin_circuit BUF BUF
+match_nets VDD VDD
+match_nets VSS VSS
net_mismatch INT $10
match_nets IN IN
net_mismatch INT2 $11
From 8d45adcebd892f8c901c4b588ebdf82d16ef562b Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 28 Jun 2021 22:53:08 +0200
Subject: [PATCH 10/15] Updated doc.
---
src/lay/lay/doc/about/lvs_ref_global.xml | 14 ++++++++-
src/lay/lay/doc/manual/lvs_compare.xml | 39 +++++++++++++++++++++++-
2 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/src/lay/lay/doc/about/lvs_ref_global.xml b/src/lay/lay/doc/about/lvs_ref_global.xml
index 927ba0496..ab05ff346 100644
--- a/src/lay/lay/doc/about/lvs_ref_global.xml
+++ b/src/lay/lay/doc/about/lvs_ref_global.xml
@@ -161,12 +161,24 @@ See Netter#same_device_c
Usage:
-- same_nets(circuit, net_a, net_b)
+- same_nets(circuit_pattern, net_pattern)
+- same_nets(circuit_pattern, net_a, net_b)
- same_nets(circuit_a, net_a, circuit_b, net_b)
See Netter#same_nets for a description of that function.
+"same_nets!" - Establishes an equivalence between the nets (must match)
+
+Usage:
+
+- same_nets!(circuit_pattern, net_pattern)
+- same_nets!(circuit_pattern, net_a, net_b)
+- same_nets!(circuit_a, net_a, circuit_b, net_b)
+
+
+See Netter#same_nets! for a description of that function.
+
"schematic" - Reads the reference netlist
Usage:
diff --git a/src/lay/lay/doc/manual/lvs_compare.xml b/src/lay/lay/doc/manual/lvs_compare.xml
index d5de64f78..5b3fe3073 100644
--- a/src/lay/lay/doc/manual/lvs_compare.xml
+++ b/src/lay/lay/doc/manual/lvs_compare.xml
@@ -52,7 +52,44 @@
- For more information about "same_nets" see same_nets.
+ "same_nets" can also be used to require a matching between specific nets.
+ This is useful on top level to check for matching nets assigned to specific pads.
+ This allows checking correct pad assignment. For example to check whether the
+ same net is attached to the "VDD" pad, label the net "VDD" in the layout and
+ specify:
+
+
+ same_nets!("CHIP", "VDD", "VDD")
+
+
+ The exclamation-mark version will report a net mismatch if either there is no
+ "VDD" net in either layout or schematic or if these nets to not match.
+ The above specification can be abbreviated as layout and schematic net name are identical:
+
+
+ same_nets!("CHIP", "VDD")
+
+
+ It's also possible to specify pattern for circuit names or net names.
+ This example requires all nets starting with "PAD" to have a counterpart
+ in layout and schematic for circuit "TOP" and each of these pairs has to match:
+
+
+ same_nets!("TOP", "PAD*")
+
+
+ So it is an error if there is a PAD1 net in layout but none in the schematic.
+ It is also an error if a net called PAD2 is there is layout and schematic but they
+ do not match.
+
+
+
+ "same_nets" and "same_nets!" can appear anywhere in the LVS script.
+
+
+
+ For more information about "same_nets" see same_nets and
+ same_nets!.
Circuit equivalence hint
From 2d2cf1130852f831cd8861c94b578bede4ee2997 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Mon, 28 Jun 2021 23:08:02 +0200
Subject: [PATCH 11/15] Added tests for new features.
---
src/lvs/unit_tests/lvsSimpleTests.cc | 9 +
testdata/lvs/blackbox.gds | Bin 0 -> 3186 bytes
testdata/lvs/blackbox1.cir | 27 +++
testdata/lvs/blackbox1.lvs | 22 +++
testdata/lvs/blackbox1.lvsdb | 196 ++++++++++++++++++++++
testdata/lvs/blackbox2.cir | 27 +++
testdata/lvs/blackbox2.lvs | 22 +++
testdata/lvs/blackbox2.lvsdb | 196 ++++++++++++++++++++++
testdata/lvs/blackbox3.cir | 27 +++
testdata/lvs/blackbox3.lvs | 22 +++
testdata/lvs/blackbox3.lvsdb | 200 +++++++++++++++++++++++
testdata/lvs/blackbox4.cir | 26 +++
testdata/lvs/blackbox4.lvs | 22 +++
testdata/lvs/blackbox4.lvsdb | 196 ++++++++++++++++++++++
testdata/lvs/blackbox5.cir | 26 +++
testdata/lvs/blackbox5.lvs | 22 +++
testdata/lvs/blackbox5.lvsdb | 200 +++++++++++++++++++++++
testdata/lvs/blackbox_open.gds | Bin 0 -> 3276 bytes
testdata/lvs/blackbox_schematic.cir | 9 +
testdata/lvs/blackbox_short.gds | Bin 0 -> 3250 bytes
testdata/lvs/blackbox_short_and_open.gds | Bin 0 -> 3340 bytes
testdata/lvs/blackbox_swapped.gds | Bin 0 -> 3186 bytes
22 files changed, 1249 insertions(+)
create mode 100644 testdata/lvs/blackbox.gds
create mode 100644 testdata/lvs/blackbox1.cir
create mode 100644 testdata/lvs/blackbox1.lvs
create mode 100644 testdata/lvs/blackbox1.lvsdb
create mode 100644 testdata/lvs/blackbox2.cir
create mode 100644 testdata/lvs/blackbox2.lvs
create mode 100644 testdata/lvs/blackbox2.lvsdb
create mode 100644 testdata/lvs/blackbox3.cir
create mode 100644 testdata/lvs/blackbox3.lvs
create mode 100644 testdata/lvs/blackbox3.lvsdb
create mode 100644 testdata/lvs/blackbox4.cir
create mode 100644 testdata/lvs/blackbox4.lvs
create mode 100644 testdata/lvs/blackbox4.lvsdb
create mode 100644 testdata/lvs/blackbox5.cir
create mode 100644 testdata/lvs/blackbox5.lvs
create mode 100644 testdata/lvs/blackbox5.lvsdb
create mode 100644 testdata/lvs/blackbox_open.gds
create mode 100644 testdata/lvs/blackbox_schematic.cir
create mode 100644 testdata/lvs/blackbox_short.gds
create mode 100644 testdata/lvs/blackbox_short_and_open.gds
create mode 100644 testdata/lvs/blackbox_swapped.gds
diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc
index cfc49eb8f..d6fdec334 100644
--- a/src/lvs/unit_tests/lvsSimpleTests.cc
+++ b/src/lvs/unit_tests/lvsSimpleTests.cc
@@ -226,3 +226,12 @@ TEST(24_issue806)
{
run_test (_this, "custom_compare", "custom_compare.gds");
}
+
+TEST(25_blackbox)
+{
+ run_test (_this, "blackbox1", "blackbox.gds");
+ run_test (_this, "blackbox2", "blackbox_swapped.gds");
+ run_test (_this, "blackbox3", "blackbox_open.gds");
+ run_test (_this, "blackbox4", "blackbox_short.gds");
+ run_test (_this, "blackbox5", "blackbox_short_and_open.gds");
+}
diff --git a/testdata/lvs/blackbox.gds b/testdata/lvs/blackbox.gds
new file mode 100644
index 0000000000000000000000000000000000000000..27ad3ab86a683d005a77681db05b3cde09b8087a
GIT binary patch
literal 3186
zcmeHJJ!q3r6g~ZteEIt0FQqY<4y6@JDVnxvQXPs`hZYNF2v}THNWrm#Lq`V}!6Cbg
zn`;Nb41$Xao!X%VhYk)3K{^z12t|0_`|i6*)P6s!V3yO~@0|B@-#zy|`0%_n6#BgE
zSNJGk1lNGxzY%!;>dF!@oXRZTcviXn@zv4QTg@vkU)-yqkcrUw{>|l;D$)VqpYkvO
z|Fj2S`fSRWqX#t0uHazPm>m18b;P#TeH%mHEgo)4E)_K%rO$2f
z`gxzcZr*x7ti*&p6!o$@DQA#DxuCh
zA>L&V81w0$<}R>noC7VA3U|L4lSoZj1oCz3U+|vE^@KKiG)lrO+BLX-M5Dh|@>Y}++y~Hgg;99p4cP0^+DwVjiFcm^Y
Tb|Tk9I^Dr_39F`eNji;Rn~Vh2
literal 0
HcmV?d00001
diff --git a/testdata/lvs/blackbox1.cir b/testdata/lvs/blackbox1.cir
new file mode 100644
index 000000000..f8fb8eeb8
--- /dev/null
+++ b/testdata/lvs/blackbox1.cir
@@ -0,0 +1,27 @@
+* Extracted by KLayout
+
+* cell TOP
+.SUBCKT TOP
+* net 1 3
+* net 2 4
+* net 3 2
+* net 4 1
+* net 5 8
+* net 6 7
+* net 7 5
+* net 8 6
+* cell instance $1 r0 *1 0,0
+X$1 1 2 7 3 4 5 8 6 CHIP
+.ENDS TOP
+
+* cell CHIP
+* pin pad3
+* pin pad4
+* pin pad5
+* pin pad2
+* pin pad1
+* pin pad8
+* pin pad6
+* pin pad7
+.SUBCKT CHIP 1 2 3 4 5 6 7 8
+.ENDS CHIP
diff --git a/testdata/lvs/blackbox1.lvs b/testdata/lvs/blackbox1.lvs
new file mode 100644
index 000000000..9b20bc4d6
--- /dev/null
+++ b/testdata/lvs/blackbox1.lvs
@@ -0,0 +1,22 @@
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("blackbox_schematic.cir")
+
+deep
+
+same_nets!("TOP", "*", "*")
+
+m1 = input(1, 0)
+via = input(2, 0)
+m2 = input(3, 0)
+pad = input(10, 0)
+
+connect(m1, pad)
+connect(m1, via)
+connect(via, m2)
+
+blank_circuit("CHIP")
+
+compare
diff --git a/testdata/lvs/blackbox1.lvsdb b/testdata/lvs/blackbox1.lvsdb
new file mode 100644
index 000000000..a9012c999
--- /dev/null
+++ b/testdata/lvs/blackbox1.lvsdb
@@ -0,0 +1,196 @@
+#%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(l1 '1/0')
+ layer(l3 '2/0')
+ layer(l4 '3/0')
+ layer(l2 '10/0')
+
+ # Mask layer connectivity
+ connect(l1 l1 l3 l2)
+ connect(l3 l1 l3 l4)
+ connect(l4 l3 l4)
+ connect(l2 l1 l2)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Circuit boundary
+ rect((-4000 -6000) (11000 9000))
+
+ # Outgoing pins and their connections to nets
+ pin(name(pad3))
+ pin(name(pad4))
+ pin(name(pad5))
+ pin(name(pad2))
+ pin(name(pad1))
+ pin(name(pad8))
+ pin(name(pad6))
+ pin(name(pad7))
+
+ )
+ circuit(TOP
+
+ # Circuit boundary
+ rect((-18500 -14000) (44500 28000))
+
+ # Nets with their geometries
+ net(1 name('3')
+ rect(l1 (-10500 2000) (7500 1000))
+ rect(l1 (-7500 0) (1000 4000))
+ rect(l1 (-6000 0) (6000 1000))
+ rect(l1 (-9000 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -5501) (1000 1000))
+ )
+ net(2 name('4')
+ rect(l1 (1000 2000) (1000 10000))
+ rect(l1 (-17500 0) (17500 1000))
+ rect(l1 (-20500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (17499 -10501) (1000 1000))
+ )
+ net(3 name('2')
+ rect(l1 (-15500 -2000) (12500 1000))
+ rect(l1 (-15500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -501) (1000 1000))
+ )
+ net(4 name('1')
+ rect(l1 (-15500 -13000) (6000 1000))
+ rect(l1 (-1000 0) (1000 6000))
+ rect(l1 (-9000 -8000) (3500 3000))
+ rect(l1 (4500 5000) (7500 1000))
+ rect(l1 (-13501 -7501) (2 2))
+ rect(l2 (12499 6499) (1000 1000))
+ )
+ net(5 name('8')
+ rect(l1 (1000 -13000) (22000 1000))
+ rect(l1 (-22000 0) (1000 7000))
+ rect(l1 (20500 -9000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-23501 6499) (1000 1000))
+ )
+ net(6 name('7')
+ rect(l1 (6000 -6000) (7000 1000))
+ rect(l1 (-1000 0) (1000 12000))
+ rect(l1 (-1000 0) (11000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-18501 -13501) (1000 1000))
+ )
+ net(7 name('5')
+ rect(l1 (6000 2000) (1000 10000))
+ rect(l1 (-1000 0) (17000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-18501 -10501) (1000 1000))
+ )
+ net(8 name('6')
+ rect(l1 (16000 -2000) (7000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l1 (-18501 -501) (3500 1000))
+ rect(l3 (6500 -1000) (1000 1000))
+ rect(l3 (-8500 -1000) (1000 1000))
+ rect(l4 (-1000 -1000) (8500 1000))
+ rect(l2 (-11000 -1000) (1000 1000))
+ )
+
+ # Subcircuits and their connections
+ circuit(1 CHIP location(0 0)
+ pin(0 1)
+ pin(1 2)
+ pin(2 7)
+ pin(3 3)
+ pin(4 4)
+ pin(5 5)
+ pin(6 8)
+ pin(7 6)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Outgoing pins and their connections to nets
+ pin(name(PAD1))
+ pin(name(PAD2))
+ pin(name(PAD3))
+ pin(name(PAD4))
+ pin(name(PAD5))
+ pin(name(PAD6))
+ pin(name(PAD7))
+ pin(name(PAD8))
+
+ )
+ circuit(TOP
+
+ # Nets
+ net(1 name('1'))
+ net(2 name('2'))
+ net(3 name('3'))
+ net(4 name('4'))
+ net(5 name('5'))
+ net(6 name('6'))
+ net(7 name('7'))
+ net(8 name('8'))
+
+ # Subcircuits and their connections
+ circuit(1 CHIP name('1')
+ pin(0 1)
+ pin(1 2)
+ pin(2 3)
+ pin(3 4)
+ pin(4 5)
+ pin(5 6)
+ pin(6 7)
+ pin(7 8)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(CHIP CHIP match
+ xref(
+ pin(4 0 match)
+ pin(3 1 match)
+ pin(0 2 match)
+ pin(1 3 match)
+ pin(2 4 match)
+ pin(6 5 match)
+ pin(7 6 match)
+ pin(5 7 match)
+ )
+ )
+ circuit(TOP TOP match
+ xref(
+ net(4 1 match)
+ net(3 2 match)
+ net(1 3 match)
+ net(2 4 match)
+ net(7 5 match)
+ net(8 6 match)
+ net(6 7 match)
+ net(5 8 match)
+ circuit(1 1 match)
+ )
+ )
+)
diff --git a/testdata/lvs/blackbox2.cir b/testdata/lvs/blackbox2.cir
new file mode 100644
index 000000000..6b3a67d15
--- /dev/null
+++ b/testdata/lvs/blackbox2.cir
@@ -0,0 +1,27 @@
+* Extracted by KLayout
+
+* cell TOP
+.SUBCKT TOP
+* net 1 4
+* net 2 3
+* net 3 2
+* net 4 1
+* net 5 8
+* net 6 7
+* net 7 5
+* net 8 6
+* cell instance $1 r0 *1 0,0
+X$1 1 2 7 3 4 5 8 6 CHIP
+.ENDS TOP
+
+* cell CHIP
+* pin pad3
+* pin pad4
+* pin pad5
+* pin pad2
+* pin pad1
+* pin pad8
+* pin pad6
+* pin pad7
+.SUBCKT CHIP 1 2 3 4 5 6 7 8
+.ENDS CHIP
diff --git a/testdata/lvs/blackbox2.lvs b/testdata/lvs/blackbox2.lvs
new file mode 100644
index 000000000..9b20bc4d6
--- /dev/null
+++ b/testdata/lvs/blackbox2.lvs
@@ -0,0 +1,22 @@
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("blackbox_schematic.cir")
+
+deep
+
+same_nets!("TOP", "*", "*")
+
+m1 = input(1, 0)
+via = input(2, 0)
+m2 = input(3, 0)
+pad = input(10, 0)
+
+connect(m1, pad)
+connect(m1, via)
+connect(via, m2)
+
+blank_circuit("CHIP")
+
+compare
diff --git a/testdata/lvs/blackbox2.lvsdb b/testdata/lvs/blackbox2.lvsdb
new file mode 100644
index 000000000..4fa169913
--- /dev/null
+++ b/testdata/lvs/blackbox2.lvsdb
@@ -0,0 +1,196 @@
+#%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(l1 '1/0')
+ layer(l3 '2/0')
+ layer(l4 '3/0')
+ layer(l2 '10/0')
+
+ # Mask layer connectivity
+ connect(l1 l1 l3 l2)
+ connect(l3 l1 l3 l4)
+ connect(l4 l3 l4)
+ connect(l2 l1 l2)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Circuit boundary
+ rect((-4000 -6000) (11000 9000))
+
+ # Outgoing pins and their connections to nets
+ pin(name(pad3))
+ pin(name(pad4))
+ pin(name(pad5))
+ pin(name(pad2))
+ pin(name(pad1))
+ pin(name(pad8))
+ pin(name(pad6))
+ pin(name(pad7))
+
+ )
+ circuit(TOP
+
+ # Circuit boundary
+ rect((-18500 -14000) (44500 28000))
+
+ # Nets with their geometries
+ net(1 name('4')
+ rect(l1 (-10500 2000) (7500 1000))
+ rect(l1 (-7500 0) (1000 4000))
+ rect(l1 (-6000 0) (6000 1000))
+ rect(l1 (-9000 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -5501) (1000 1000))
+ )
+ net(2 name('3')
+ rect(l1 (1000 2000) (1000 10000))
+ rect(l1 (-17500 0) (17500 1000))
+ rect(l1 (-20500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (17499 -10501) (1000 1000))
+ )
+ net(3 name('2')
+ rect(l1 (-15500 -2000) (12500 1000))
+ rect(l1 (-15500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -501) (1000 1000))
+ )
+ net(4 name('1')
+ rect(l1 (-15500 -13000) (6000 1000))
+ rect(l1 (-1000 0) (1000 6000))
+ rect(l1 (-9000 -8000) (3500 3000))
+ rect(l1 (4500 5000) (7500 1000))
+ rect(l1 (-13501 -7501) (2 2))
+ rect(l2 (12499 6499) (1000 1000))
+ )
+ net(5 name('8')
+ rect(l1 (1000 -13000) (22000 1000))
+ rect(l1 (-22000 0) (1000 7000))
+ rect(l1 (20500 -9000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-23501 6499) (1000 1000))
+ )
+ net(6 name('7')
+ rect(l1 (6000 -6000) (7000 1000))
+ rect(l1 (-1000 0) (1000 12000))
+ rect(l1 (-1000 0) (11000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-18501 -13501) (1000 1000))
+ )
+ net(7 name('5')
+ rect(l1 (6000 2000) (1000 10000))
+ rect(l1 (-1000 0) (17000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-18501 -10501) (1000 1000))
+ )
+ net(8 name('6')
+ rect(l1 (16000 -2000) (7000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l1 (-18501 -501) (3500 1000))
+ rect(l3 (6500 -1000) (1000 1000))
+ rect(l3 (-8500 -1000) (1000 1000))
+ rect(l4 (-1000 -1000) (8500 1000))
+ rect(l2 (-11000 -1000) (1000 1000))
+ )
+
+ # Subcircuits and their connections
+ circuit(1 CHIP location(0 0)
+ pin(0 1)
+ pin(1 2)
+ pin(2 7)
+ pin(3 3)
+ pin(4 4)
+ pin(5 5)
+ pin(6 8)
+ pin(7 6)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Outgoing pins and their connections to nets
+ pin(name(PAD1))
+ pin(name(PAD2))
+ pin(name(PAD3))
+ pin(name(PAD4))
+ pin(name(PAD5))
+ pin(name(PAD6))
+ pin(name(PAD7))
+ pin(name(PAD8))
+
+ )
+ circuit(TOP
+
+ # Nets
+ net(1 name('1'))
+ net(2 name('2'))
+ net(3 name('3'))
+ net(4 name('4'))
+ net(5 name('5'))
+ net(6 name('6'))
+ net(7 name('7'))
+ net(8 name('8'))
+
+ # Subcircuits and their connections
+ circuit(1 CHIP name('1')
+ pin(0 1)
+ pin(1 2)
+ pin(2 3)
+ pin(3 4)
+ pin(4 5)
+ pin(5 6)
+ pin(6 7)
+ pin(7 8)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(CHIP CHIP match
+ xref(
+ pin(4 0 match)
+ pin(3 1 match)
+ pin(0 2 match)
+ pin(1 3 match)
+ pin(2 4 match)
+ pin(6 5 match)
+ pin(7 6 match)
+ pin(5 7 match)
+ )
+ )
+ circuit(TOP TOP nomatch
+ xref(
+ net(4 1 match)
+ net(3 2 match)
+ net(2 3 mismatch)
+ net(1 4 mismatch)
+ net(7 5 match)
+ net(8 6 match)
+ net(6 7 match)
+ net(5 8 match)
+ circuit(1 1 mismatch)
+ )
+ )
+)
diff --git a/testdata/lvs/blackbox3.cir b/testdata/lvs/blackbox3.cir
new file mode 100644
index 000000000..40adb3c28
--- /dev/null
+++ b/testdata/lvs/blackbox3.cir
@@ -0,0 +1,27 @@
+* Extracted by KLayout
+
+* cell TOP
+.SUBCKT TOP
+* net 2 3
+* net 3 4
+* net 4 2
+* net 5 1
+* net 6 8
+* net 7 5
+* net 8 6
+* net 9 7
+* cell instance $1 r0 *1 0,0
+X$1 2 3 7 4 5 6 8 1 CHIP
+.ENDS TOP
+
+* cell CHIP
+* pin pad3
+* pin pad4
+* pin pad5
+* pin pad2
+* pin pad1
+* pin pad8
+* pin pad6
+* pin pad7
+.SUBCKT CHIP 1 2 3 4 5 6 7 8
+.ENDS CHIP
diff --git a/testdata/lvs/blackbox3.lvs b/testdata/lvs/blackbox3.lvs
new file mode 100644
index 000000000..9b20bc4d6
--- /dev/null
+++ b/testdata/lvs/blackbox3.lvs
@@ -0,0 +1,22 @@
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("blackbox_schematic.cir")
+
+deep
+
+same_nets!("TOP", "*", "*")
+
+m1 = input(1, 0)
+via = input(2, 0)
+m2 = input(3, 0)
+pad = input(10, 0)
+
+connect(m1, pad)
+connect(m1, via)
+connect(via, m2)
+
+blank_circuit("CHIP")
+
+compare
diff --git a/testdata/lvs/blackbox3.lvsdb b/testdata/lvs/blackbox3.lvsdb
new file mode 100644
index 000000000..1dd6f3942
--- /dev/null
+++ b/testdata/lvs/blackbox3.lvsdb
@@ -0,0 +1,200 @@
+#%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(l1 '1/0')
+ layer(l3 '2/0')
+ layer(l4 '3/0')
+ layer(l2 '10/0')
+
+ # Mask layer connectivity
+ connect(l1 l1 l3 l2)
+ connect(l3 l1 l3 l4)
+ connect(l4 l3 l4)
+ connect(l2 l1 l2)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Circuit boundary
+ rect((-4000 -6000) (11000 9000))
+
+ # Outgoing pins and their connections to nets
+ pin(name(pad3))
+ pin(name(pad4))
+ pin(name(pad5))
+ pin(name(pad2))
+ pin(name(pad1))
+ pin(name(pad8))
+ pin(name(pad6))
+ pin(name(pad7))
+
+ )
+ circuit(TOP
+
+ # Circuit boundary
+ rect((-18500 -14000) (44500 28000))
+
+ # Nets with their geometries
+ net(1
+ rect(l1 (6000 -6000) (7000 1000))
+ rect(l1 (-1000 0) (1000 12000))
+ rect(l1 (-1000 0) (5160 1000))
+ rect(l2 (-11160 -14000) (1000 1000))
+ )
+ net(2 name('3')
+ rect(l1 (-10500 2000) (7500 1000))
+ rect(l1 (-7500 0) (1000 4000))
+ rect(l1 (-6000 0) (6000 1000))
+ rect(l1 (-9000 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -5501) (1000 1000))
+ )
+ net(3 name('4')
+ rect(l1 (1000 2000) (1000 10000))
+ rect(l1 (-17500 0) (17500 1000))
+ rect(l1 (-20500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (17499 -10501) (1000 1000))
+ )
+ net(4 name('2')
+ rect(l1 (-15500 -2000) (12500 1000))
+ rect(l1 (-15500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -501) (1000 1000))
+ )
+ net(5 name('1')
+ rect(l1 (-15500 -13000) (6000 1000))
+ rect(l1 (-1000 0) (1000 6000))
+ rect(l1 (-9000 -8000) (3500 3000))
+ rect(l1 (4500 5000) (7500 1000))
+ rect(l1 (-13501 -7501) (2 2))
+ rect(l2 (12499 6499) (1000 1000))
+ )
+ net(6 name('8')
+ rect(l1 (1000 -13000) (22000 1000))
+ rect(l1 (-22000 0) (1000 7000))
+ rect(l1 (20500 -9000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-23501 6499) (1000 1000))
+ )
+ net(7 name('5')
+ rect(l1 (6000 2000) (1000 10000))
+ rect(l1 (-1000 0) (17000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-18501 -10501) (1000 1000))
+ )
+ net(8 name('6')
+ rect(l1 (16000 -2000) (7000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l1 (-18501 -501) (3500 1000))
+ rect(l3 (6500 -1000) (1000 1000))
+ rect(l3 (-8500 -1000) (1000 1000))
+ rect(l4 (-1000 -1000) (8500 1000))
+ rect(l2 (-11000 -1000) (1000 1000))
+ )
+ net(9 name('7')
+ rect(l1 (18080 7000) (4920 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ )
+
+ # Subcircuits and their connections
+ circuit(1 CHIP location(0 0)
+ pin(0 2)
+ pin(1 3)
+ pin(2 7)
+ pin(3 4)
+ pin(4 5)
+ pin(5 6)
+ pin(6 8)
+ pin(7 1)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Outgoing pins and their connections to nets
+ pin(name(PAD1))
+ pin(name(PAD2))
+ pin(name(PAD3))
+ pin(name(PAD4))
+ pin(name(PAD5))
+ pin(name(PAD6))
+ pin(name(PAD7))
+ pin(name(PAD8))
+
+ )
+ circuit(TOP
+
+ # Nets
+ net(1 name('1'))
+ net(2 name('2'))
+ net(3 name('3'))
+ net(4 name('4'))
+ net(5 name('5'))
+ net(6 name('6'))
+ net(7 name('7'))
+ net(8 name('8'))
+
+ # Subcircuits and their connections
+ circuit(1 CHIP name('1')
+ pin(0 1)
+ pin(1 2)
+ pin(2 3)
+ pin(3 4)
+ pin(4 5)
+ pin(5 6)
+ pin(6 7)
+ pin(7 8)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(CHIP CHIP match
+ xref(
+ pin(4 0 match)
+ pin(3 1 match)
+ pin(0 2 match)
+ pin(1 3 match)
+ pin(2 4 match)
+ pin(6 5 match)
+ pin(7 6 match)
+ pin(5 7 match)
+ )
+ )
+ circuit(TOP TOP nomatch
+ xref(
+ net(() 7 mismatch)
+ net(1 () mismatch)
+ net(5 1 match)
+ net(4 2 match)
+ net(2 3 match)
+ net(3 4 match)
+ net(7 5 match)
+ net(8 6 match)
+ net(6 8 match)
+ circuit(1 1 mismatch)
+ )
+ )
+)
diff --git a/testdata/lvs/blackbox4.cir b/testdata/lvs/blackbox4.cir
new file mode 100644
index 000000000..84da4c047
--- /dev/null
+++ b/testdata/lvs/blackbox4.cir
@@ -0,0 +1,26 @@
+* Extracted by KLayout
+
+* cell TOP
+.SUBCKT TOP
+* net 1 3
+* net 2 4
+* net 3 2
+* net 4 1
+* net 5 8
+* net 6 5,7
+* net 7 6
+* cell instance $1 r0 *1 0,0
+X$1 1 2 6 3 4 5 7 6 CHIP
+.ENDS TOP
+
+* cell CHIP
+* pin pad3
+* pin pad4
+* pin pad5
+* pin pad2
+* pin pad1
+* pin pad8
+* pin pad6
+* pin pad7
+.SUBCKT CHIP 1 2 3 4 5 6 7 8
+.ENDS CHIP
diff --git a/testdata/lvs/blackbox4.lvs b/testdata/lvs/blackbox4.lvs
new file mode 100644
index 000000000..9b20bc4d6
--- /dev/null
+++ b/testdata/lvs/blackbox4.lvs
@@ -0,0 +1,22 @@
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("blackbox_schematic.cir")
+
+deep
+
+same_nets!("TOP", "*", "*")
+
+m1 = input(1, 0)
+via = input(2, 0)
+m2 = input(3, 0)
+pad = input(10, 0)
+
+connect(m1, pad)
+connect(m1, via)
+connect(via, m2)
+
+blank_circuit("CHIP")
+
+compare
diff --git a/testdata/lvs/blackbox4.lvsdb b/testdata/lvs/blackbox4.lvsdb
new file mode 100644
index 000000000..fb865f98d
--- /dev/null
+++ b/testdata/lvs/blackbox4.lvsdb
@@ -0,0 +1,196 @@
+#%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(l1 '1/0')
+ layer(l3 '2/0')
+ layer(l4 '3/0')
+ layer(l2 '10/0')
+
+ # Mask layer connectivity
+ connect(l1 l1 l3 l2)
+ connect(l3 l1 l3 l4)
+ connect(l4 l3 l4)
+ connect(l2 l1 l2)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Circuit boundary
+ rect((-4000 -6000) (11000 9000))
+
+ # Outgoing pins and their connections to nets
+ pin(name(pad3))
+ pin(name(pad4))
+ pin(name(pad5))
+ pin(name(pad2))
+ pin(name(pad1))
+ pin(name(pad8))
+ pin(name(pad6))
+ pin(name(pad7))
+
+ )
+ circuit(TOP
+
+ # Circuit boundary
+ rect((-18500 -14000) (44500 28000))
+
+ # Nets with their geometries
+ net(1 name('3')
+ rect(l1 (-10500 2000) (7500 1000))
+ rect(l1 (-7500 0) (1000 4000))
+ rect(l1 (-6000 0) (6000 1000))
+ rect(l1 (-9000 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -5501) (1000 1000))
+ )
+ net(2 name('4')
+ rect(l1 (1000 2000) (1000 10000))
+ rect(l1 (-17500 0) (17500 1000))
+ rect(l1 (-20500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (17499 -10501) (1000 1000))
+ )
+ net(3 name('2')
+ rect(l1 (-15500 -2000) (12500 1000))
+ rect(l1 (-15500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -501) (1000 1000))
+ )
+ net(4 name('1')
+ rect(l1 (-15500 -13000) (6000 1000))
+ rect(l1 (-1000 0) (1000 6000))
+ rect(l1 (-9000 -8000) (3500 3000))
+ rect(l1 (4500 5000) (7500 1000))
+ rect(l1 (-13501 -7501) (2 2))
+ rect(l2 (12499 6499) (1000 1000))
+ )
+ net(5 name('8')
+ rect(l1 (1000 -13000) (22000 1000))
+ rect(l1 (-22000 0) (1000 7000))
+ rect(l1 (20500 -9000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-23501 6499) (1000 1000))
+ )
+ net(6 name('5,7')
+ rect(l1 (6000 -6000) (7000 1000))
+ rect(l1 (-1000 0) (1000 12000))
+ rect(l1 (-1000 0) (11000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-12200 -1500) (790 4500))
+ rect(l1 (-8590 -10000) (1000 10000))
+ rect(l1 (-1000 0) (17000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -6501) (2 2))
+ rect(l1 (-2 4998) (2 2))
+ rect(l2 (-18501 -18501) (1000 1000))
+ rect(l2 (-1000 7000) (1000 1000))
+ )
+ net(7 name('6')
+ rect(l1 (16000 -2000) (7000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l1 (-18501 -501) (3500 1000))
+ rect(l3 (6500 -1000) (1000 1000))
+ rect(l3 (-8500 -1000) (1000 1000))
+ rect(l4 (-1000 -1000) (8500 1000))
+ rect(l2 (-11000 -1000) (1000 1000))
+ )
+
+ # Subcircuits and their connections
+ circuit(1 CHIP location(0 0)
+ pin(0 1)
+ pin(1 2)
+ pin(2 6)
+ pin(3 3)
+ pin(4 4)
+ pin(5 5)
+ pin(6 7)
+ pin(7 6)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Outgoing pins and their connections to nets
+ pin(name(PAD1))
+ pin(name(PAD2))
+ pin(name(PAD3))
+ pin(name(PAD4))
+ pin(name(PAD5))
+ pin(name(PAD6))
+ pin(name(PAD7))
+ pin(name(PAD8))
+
+ )
+ circuit(TOP
+
+ # Nets
+ net(1 name('1'))
+ net(2 name('2'))
+ net(3 name('3'))
+ net(4 name('4'))
+ net(5 name('5'))
+ net(6 name('6'))
+ net(7 name('7'))
+ net(8 name('8'))
+
+ # Subcircuits and their connections
+ circuit(1 CHIP name('1')
+ pin(0 1)
+ pin(1 2)
+ pin(2 3)
+ pin(3 4)
+ pin(4 5)
+ pin(5 6)
+ pin(6 7)
+ pin(7 8)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(CHIP CHIP match
+ xref(
+ pin(4 0 match)
+ pin(3 1 match)
+ pin(0 2 match)
+ pin(1 3 match)
+ pin(2 4 match)
+ pin(6 5 match)
+ pin(7 6 match)
+ pin(5 7 match)
+ )
+ )
+ circuit(TOP TOP nomatch
+ xref(
+ net(() 5 mismatch)
+ net(() 7 mismatch)
+ net(4 1 match)
+ net(3 2 match)
+ net(1 3 match)
+ net(2 4 match)
+ net(6 () mismatch)
+ net(7 6 match)
+ net(5 8 match)
+ circuit(1 1 mismatch)
+ )
+ )
+)
diff --git a/testdata/lvs/blackbox5.cir b/testdata/lvs/blackbox5.cir
new file mode 100644
index 000000000..4e2b43ed7
--- /dev/null
+++ b/testdata/lvs/blackbox5.cir
@@ -0,0 +1,26 @@
+* Extracted by KLayout
+
+* cell TOP
+.SUBCKT TOP
+* net 2 3
+* net 3 4
+* net 4 2
+* net 5 1
+* net 6 8
+* net 7 5,7
+* net 8 6
+* cell instance $1 r0 *1 0,0
+X$1 2 3 7 4 5 6 8 1 CHIP
+.ENDS TOP
+
+* cell CHIP
+* pin pad3
+* pin pad4
+* pin pad5
+* pin pad2
+* pin pad1
+* pin pad8
+* pin pad6
+* pin pad7
+.SUBCKT CHIP 1 2 3 4 5 6 7 8
+.ENDS CHIP
diff --git a/testdata/lvs/blackbox5.lvs b/testdata/lvs/blackbox5.lvs
new file mode 100644
index 000000000..9b20bc4d6
--- /dev/null
+++ b/testdata/lvs/blackbox5.lvs
@@ -0,0 +1,22 @@
+source($lvs_test_source)
+report_lvs($lvs_test_target_lvsdb, true)
+target_netlist($lvs_test_target_cir, write_spice, "Extracted by KLayout")
+
+schematic("blackbox_schematic.cir")
+
+deep
+
+same_nets!("TOP", "*", "*")
+
+m1 = input(1, 0)
+via = input(2, 0)
+m2 = input(3, 0)
+pad = input(10, 0)
+
+connect(m1, pad)
+connect(m1, via)
+connect(via, m2)
+
+blank_circuit("CHIP")
+
+compare
diff --git a/testdata/lvs/blackbox5.lvsdb b/testdata/lvs/blackbox5.lvsdb
new file mode 100644
index 000000000..3c2726f5a
--- /dev/null
+++ b/testdata/lvs/blackbox5.lvsdb
@@ -0,0 +1,200 @@
+#%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(l1 '1/0')
+ layer(l3 '2/0')
+ layer(l4 '3/0')
+ layer(l2 '10/0')
+
+ # Mask layer connectivity
+ connect(l1 l1 l3 l2)
+ connect(l3 l1 l3 l4)
+ connect(l4 l3 l4)
+ connect(l2 l1 l2)
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Circuit boundary
+ rect((-4000 -6000) (11000 9000))
+
+ # Outgoing pins and their connections to nets
+ pin(name(pad3))
+ pin(name(pad4))
+ pin(name(pad5))
+ pin(name(pad2))
+ pin(name(pad1))
+ pin(name(pad8))
+ pin(name(pad6))
+ pin(name(pad7))
+
+ )
+ circuit(TOP
+
+ # Circuit boundary
+ rect((-18500 -14000) (44500 28000))
+
+ # Nets with their geometries
+ net(1
+ rect(l1 (6000 -6000) (7000 1000))
+ rect(l1 (-1000 0) (1000 12000))
+ rect(l1 (-1000 0) (4550 1000))
+ rect(l2 (-10550 -14000) (1000 1000))
+ )
+ net(2 name('3')
+ rect(l1 (-10500 2000) (7500 1000))
+ rect(l1 (-7500 0) (1000 4000))
+ rect(l1 (-6000 0) (6000 1000))
+ rect(l1 (-9000 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -5501) (1000 1000))
+ )
+ net(3 name('4')
+ rect(l1 (1000 2000) (1000 10000))
+ rect(l1 (-17500 0) (17500 1000))
+ rect(l1 (-20500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (17499 -10501) (1000 1000))
+ )
+ net(4 name('2')
+ rect(l1 (-15500 -2000) (12500 1000))
+ rect(l1 (-15500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (12499 -501) (1000 1000))
+ )
+ net(5 name('1')
+ rect(l1 (-15500 -13000) (6000 1000))
+ rect(l1 (-1000 0) (1000 6000))
+ rect(l1 (-9000 -8000) (3500 3000))
+ rect(l1 (4500 5000) (7500 1000))
+ rect(l1 (-13501 -7501) (2 2))
+ rect(l2 (12499 6499) (1000 1000))
+ )
+ net(6 name('8')
+ rect(l1 (1000 -13000) (22000 1000))
+ rect(l1 (-22000 0) (1000 7000))
+ rect(l1 (20500 -9000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l2 (-23501 6499) (1000 1000))
+ )
+ net(7 name('5,7')
+ rect(l1 (6000 2000) (1000 10000))
+ rect(l1 (-1000 0) (17000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-6960 -6450) (700 4950))
+ rect(l1 (-2270 -5500) (5530 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l1 (-2 4998) (2 2))
+ rect(l2 (-18501 -10501) (1000 1000))
+ )
+ net(8 name('6')
+ rect(l1 (16000 -2000) (7000 1000))
+ rect(l1 (-500 -2000) (3500 3000))
+ rect(l1 (-1501 -1501) (2 2))
+ rect(l1 (-18501 -501) (3500 1000))
+ rect(l3 (6500 -1000) (1000 1000))
+ rect(l3 (-8500 -1000) (1000 1000))
+ rect(l4 (-1000 -1000) (8500 1000))
+ rect(l2 (-11000 -1000) (1000 1000))
+ )
+
+ # Subcircuits and their connections
+ circuit(1 CHIP location(0 0)
+ pin(0 2)
+ pin(1 3)
+ pin(2 7)
+ pin(3 4)
+ pin(4 5)
+ pin(5 6)
+ pin(6 8)
+ pin(7 1)
+ )
+
+ )
+)
+
+# Reference netlist
+reference(
+
+ # Circuit section
+ # Circuits are the hierarchical building blocks of the netlist.
+ circuit(CHIP
+
+ # Outgoing pins and their connections to nets
+ pin(name(PAD1))
+ pin(name(PAD2))
+ pin(name(PAD3))
+ pin(name(PAD4))
+ pin(name(PAD5))
+ pin(name(PAD6))
+ pin(name(PAD7))
+ pin(name(PAD8))
+
+ )
+ circuit(TOP
+
+ # Nets
+ net(1 name('1'))
+ net(2 name('2'))
+ net(3 name('3'))
+ net(4 name('4'))
+ net(5 name('5'))
+ net(6 name('6'))
+ net(7 name('7'))
+ net(8 name('8'))
+
+ # Subcircuits and their connections
+ circuit(1 CHIP name('1')
+ pin(0 1)
+ pin(1 2)
+ pin(2 3)
+ pin(3 4)
+ pin(4 5)
+ pin(5 6)
+ pin(6 7)
+ pin(7 8)
+ )
+
+ )
+)
+
+# Cross reference
+xref(
+ circuit(CHIP CHIP match
+ xref(
+ pin(4 0 match)
+ pin(3 1 match)
+ pin(0 2 match)
+ pin(1 3 match)
+ pin(2 4 match)
+ pin(6 5 match)
+ pin(7 6 match)
+ pin(5 7 match)
+ )
+ )
+ circuit(TOP TOP nomatch
+ xref(
+ net(() 5 mismatch)
+ net(() 7 mismatch)
+ net(1 () mismatch)
+ net(5 1 match)
+ net(4 2 match)
+ net(2 3 match)
+ net(3 4 match)
+ net(7 () mismatch)
+ net(8 6 match)
+ net(6 8 match)
+ circuit(1 1 mismatch)
+ )
+ )
+)
diff --git a/testdata/lvs/blackbox_open.gds b/testdata/lvs/blackbox_open.gds
new file mode 100644
index 0000000000000000000000000000000000000000..3123ac4da1aced18d0917f5ecfee90035e414102
GIT binary patch
literal 3276
zcmeHJJxE+Z5dM63_wMsP-s*Zb>wZth+WB
zBJ16HgZ(*fW2yzgUspMPV-(e1Ei{T>bcZW~N6VsDRQusdBR%JB46R!{T9&g^RC|;@
zx5V*to*XylAEMeD$1ghGhxNQK>lM|m`?uBVe}(Js=b8|pjc>t^S!2GxM9|?cJzW@-
zY@^vHJ&s+BX9LZj9D6954P^G~*u!z`j)gk*NIct^THK{1?An=(#<4T|btgC`>@4E?
za`r)m`lGvSPX`X&JPR)x>Ve&+W=WPfhm-p^*4DH@;O
z<-tR6fxOU{p+{y5_oy*@$02r>jrsfx=qyW>;=I)6f}IbXC(nt(j(92TB=FL%bMB;v
zRdy02&VYNHGYE03U%YJfC)hjBr|KqzMN;A6S7VZ^-J}B}hp{RCx2Sn^I-)+_d
zq8C&)ooSxrZTvPrn()V1@#%=vJ
zj$d^APGWs`ujm!k-uV1PNA3p{>jJBYX=3AnZch+9g))pHn4z}4Kw9G9*QztO$$jSh4T
z%NvoA--tKzA@Up1t=IR*DgF2h(KE7slBS;`>)pE5yGfjK`=6fYc8<9j0-X*Ht(smu
H=`?-=MGP4v
literal 0
HcmV?d00001
diff --git a/testdata/lvs/blackbox_schematic.cir b/testdata/lvs/blackbox_schematic.cir
new file mode 100644
index 000000000..3dcf769b4
--- /dev/null
+++ b/testdata/lvs/blackbox_schematic.cir
@@ -0,0 +1,9 @@
+
+.subckt chip pad1 pad2 pad3 pad4 pad5 pad6 pad7 pad8
+* This chip is an abstract
+.ends
+
+.subckt TOP
+X1 1 2 3 4 5 6 7 8 chip
+.ends
+
diff --git a/testdata/lvs/blackbox_short.gds b/testdata/lvs/blackbox_short.gds
new file mode 100644
index 0000000000000000000000000000000000000000..ec78d962b0f169df555c1d267288668047387c2c
GIT binary patch
literal 3250
zcmeHJJ!q3r6g~ZteEIt0FU1&4htde86iw46txM7B&|<+11&fOnQgH0x(9yv~aLDfB
z=Gs9pgW#e$;p@V}$kPby0LJ^<$zWZ(xwcpPwnB}zhJLmn}ch7wfK0I#~g+4F)
z1wIPM0VwzWjllDlmllBGRA&Ch)7je}ULIY$)x7%R`MnhsG7&o8zqzm18b;P#TJ0k1
z-S?3BdELgeOM*Wx^7@TY)OfoTwtmsI8iI$LqF2;-s}ZK>eH%mHEgo)4E)_K%rO$2f
z`gxzcZr*1Z~PIp|@}#If`B9(E<3ZA@p~)gnoC7VA3U@ynlSoZj1oCz3U+|vE^@KKiG)lrO+BLX-M5DZZJeo5WiHMDB%P5=50Fwr)KvAQKEtElmbcC?;v8P@X(
zxxN%NPPcW${Bpap9uU2t#u=ma+clownEgPiLs8?~wJ^QZ1AVu7+NZX#-r#WrH6Ewu
z*Abs7|JLc&6}0QNjZ@=Ne?p^N+ybl-dZ^_zbFvFI6D
jzd$`$k@fDo)w`aYI`LMqoy_&1PIqx##;WOElTPCo5lIeF
literal 0
HcmV?d00001
diff --git a/testdata/lvs/blackbox_short_and_open.gds b/testdata/lvs/blackbox_short_and_open.gds
new file mode 100644
index 0000000000000000000000000000000000000000..49e96056c10f754115967dc002781510499ef7e9
GIT binary patch
literal 3340
zcmeHJJ4{qj5IwxzeY<@8hPV=!7y>4Q5L^~mupx*PpljTMM6?kTNGvHVsEmb;i3Pol
zm9`WnQkdANfeH#pC@3g2A%=n&iw!Zk&fK}PZ&BZ;HF2A>nRm|InKz$z;luOhP-yb9
zU*V&GJb>=T|HyfMWo8m+Pi4lhKOepI`OVR_skN)GUf!QYArqnV{TtIWRitx(f67A(
z{L>zJ??0O|=4c+sZV9%o8S`TrP*i(%3+Z$Cn;u9VuwJlrP5vvYJxZTn5)C8kF3knV
zdiOl!e2&|gT2b)lMULMXMYY$8VeyOZU`6n7S@eo(KUfLVbKb_#bBl+|@-7wC9;MGO
zar~So$IbZ%sP^#qMaSo`p3h~yqT2QRwtD?9aQ*#!6LM(dF8Drc%(rLAb@)pU7X~HU
zX!dcBW0&IDK=Vh(9*SlInY{+~a2&g1p@BUT&o-tWcR2~W{!T{Y*qObCH#jEjEaK*J
z_D+@Nss+fMml>sMP-Wy7(eu)0Ji9upivMR;XIg6T=g#}LX4b{u~?V0ZhCOkoRe6UG{2eJ<#b+_{~3k6M(64;WM(od%FR$Klj}BXS3`SjnD7$
z;30R0ywI1SM|KO(s4=@o0d`i5`Sb|rtVosOywvxC-4C26?}_5Jcqwit@Y1e(?zo3l
zb`vDdfM=UC2ynAsylnO-IJ>}a)oloiq{7`V#w1s}O$SEGm(&*HGoZXdDw{95dlTku
zRTGaz#gWq9Y}`j$Z|WCg-n|F38f`Nr(zq^^o;->8P^rIPgAR&<93YH@}A2&z3!&-X5_DgPGfdoF0>wtmCo
z7aiY|Sl`_%dPTK|zdzAYeXPE`Dtbk=hu06dIZu=PM38&)c0qcSQSF4be(qL5{qy@B
zSFtR^uH>z_k-Ze#;5Cb}tfl
zGyzw08*^N0JHF$4!5tsy8kRdIBi}Kv6awTsrhDEvUnlhAPesqj`bpZJimZ3ft=?_&
Ylso_A_rUH!w}YVD#i3QxjVYbRFQ7sn*#H0l
literal 0
HcmV?d00001
diff --git a/testdata/lvs/blackbox_swapped.gds b/testdata/lvs/blackbox_swapped.gds
new file mode 100644
index 0000000000000000000000000000000000000000..555ca2c8df960f715510b46d3db7e7c5401d0815
GIT binary patch
literal 3186
zcmeHJJ!q3r6g~NpeEHhcUy3o94y6@J37Y;TbtzgMS}d5MU~y3)1;-2y9UWW*hwLtH
zt{nt32repgYKImaIyfj4=}^QW6ybUAyYD7Z`~9qfSx$SubKcK=_uTj3!}HcqN_n}j
z@KHhmDdhYAM&S7?%ZtEpI=gV=S?%`6S4Y=wwXeQ>ac>o+Y=qADZ!Rs@kqH3*l!rn1
zr#%4WvuR_F9ss!=!F=18A4`Cu#&bK!oWn_aAbr4k!F*f(R@8WuzR(m6BkL}$^^o=M
zd&vB}ZeuzX!Jij-{l+M2yi*BVzvvEHf`=QTSJe1HD@@P(Hio`iJlv36Dr!7RUug3B
zd7r#)-hU4@9=?9j@jR^Od0DThah-ptd;S;r{QW`-0fx8=zONed?J0ty-+b7ZlHEqL
zkH;N*I-U&-ym#!GXf}}D?_QHei1bU7Y}t0dr0(w;S~d2jfAbcY>=?sX-ISA6)c9m4TFv@G-
zUy2&1+d5)?xm{Tgh+a_RjM4h7I?r#+ULe(>sPV0Om|p6EzS}(QQCnDV@i>ASkJIz(
zh|iRN>vZc1+I8D;!`Cl5e$B9cY(n&k8V}E(=;(Z`zPc%TMUCtExx1Ur|IeHL-E&*d
ze$k($n}=U@(Ojxt;?5-CTDK8*DiN0|mAKO}T;Tp|>mcIJCE!{o5Vx9ut9hs;;OgGy
z9hb_6U(#OhB@K+u%1e%sUvigAJ>-|1``+)5-}DPlM9;|jMe3o7tasn7-u2Y
Date: Tue, 29 Jun 2021 08:43:28 +0200
Subject: [PATCH 12/15] Updated tests, sloppy 'same_nets' in non-must-match
mode
---
src/db/unit_tests/dbNetlistCompareTests.cc | 44 +++++++++++++++++-----
src/lvs/lvs/built-in-macros/_lvs_netter.rb | 4 +-
2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc
index 3c299b221..12106ac5e 100644
--- a/src/db/unit_tests/dbNetlistCompareTests.cc
+++ b/src/db/unit_tests/dbNetlistCompareTests.cc
@@ -766,16 +766,18 @@ TEST(2_SimpleInverterWithForcedNetAssignment)
bool good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
- "begin_circuit INV INV\n"
- "match_nets OUT OUT\n"
- "match_nets IN IN\n"
- "match_pins $0 $1\n"
- "match_pins $1 $3\n"
- "match_pins $2 $0\n"
- "match_pins $3 $2\n"
- "match_devices $2 $1\n"
- "match_devices $1 $2\n"
- "end_circuit INV INV MATCH"
+ "begin_circuit INV INV\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
+ "match_nets OUT OUT\n"
+ "match_nets IN IN\n"
+ "match_pins $0 $1\n"
+ "match_pins $1 $3\n"
+ "match_pins $2 $0\n"
+ "match_pins $3 $2\n"
+ "match_devices $2 $1\n"
+ "match_devices $1 $2\n"
+ "end_circuit INV INV MATCH"
);
EXPECT_EQ (good, true);
}
@@ -933,6 +935,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets INT $10\n"
"net_mismatch IN IN\n"
@@ -959,6 +963,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_ambiguous_nets INT $10\n"
@@ -985,6 +991,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets INT $10\n"
"net_mismatch IN IN\n"
@@ -1011,6 +1019,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets INT $10\n"
"net_mismatch IN IN\n"
@@ -1037,6 +1047,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_ambiguous_nets INT $10\n"
@@ -1064,6 +1076,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets IN IN\n"
"match_ambiguous_nets INT $10\n"
@@ -1091,6 +1105,8 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets OUT OUT\n"
"match_nets INT $10\n"
"net_mismatch IN IN\n"
@@ -1156,6 +1172,8 @@ TEST(5_BufferTwoPathsDifferentDeviceClasses)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"match_nets INT $10\n"
"match_nets IN IN\n"
"net_mismatch INT2 $11\n"
@@ -1222,6 +1240,8 @@ TEST(6_BufferTwoPathsAdditionalResistor)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"net_mismatch INT $10\n"
"match_nets IN IN\n"
"net_mismatch INT2 $11\n"
@@ -1249,6 +1269,8 @@ TEST(6_BufferTwoPathsAdditionalResistor)
EXPECT_EQ (logger.text (),
"begin_circuit BUF BUF\n"
+ "match_nets VDD VDD\n"
+ "match_nets VSS VSS\n"
"net_mismatch INT $10\n"
"match_nets OUT OUT\n"
"net_mismatch INT2 $11\n"
@@ -2704,6 +2726,7 @@ TEST(17_InherentlyAmbiguousDecoder)
"match_devices $4 $4\n"
"end_circuit NAND NAND MATCH\n"
"begin_circuit DECODER DECODER\n"
+ "match_nets A A\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets B B\n"
@@ -2755,6 +2778,7 @@ TEST(17_InherentlyAmbiguousDecoder)
"match_devices $4 $4\n"
"end_circuit NAND NAND MATCH\n"
"begin_circuit DECODER DECODER\n"
+ "match_nets A A\n"
"match_nets VSS VSS\n"
"match_nets VDD VDD\n"
"match_nets NA NA\n"
diff --git a/src/lvs/lvs/built-in-macros/_lvs_netter.rb b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
index 4a25a1093..5c34685a3 100644
--- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb
+++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb
@@ -492,7 +492,9 @@ module LVS
nets = []
n2n.keys.sort.each do |n|
- nets << n2n[n]
+ if force || (n2n[n][0] && n2n[n][1])
+ nets << n2n[n]
+ end
end
else
From cd70bea9a0d686686d21960d08011a2db3fd9675 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Tue, 29 Jun 2021 23:32:36 +0200
Subject: [PATCH 13/15] Basic enabling of Ruby 3
---
src/klayout.pri | 3 +++
src/rba/rba/rbaConvert.cc | 2 +-
testdata/ruby/basic_testcore.rb | 20 ++++++++++++--------
3 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/klayout.pri b/src/klayout.pri
index 550c0cba7..b03d5f7ea 100644
--- a/src/klayout.pri
+++ b/src/klayout.pri
@@ -154,6 +154,9 @@ msvc {
# because we use unordered_map/unordered_set:
QMAKE_CXXFLAGS += -std=c++0x
+ # needed for Ruby 3.0
+ QMAKE_CXXFLAGS += -fdeclspec
+
win32 {
QMAKE_LFLAGS += -Wl,--exclude-all-symbols
} else {
diff --git a/src/rba/rba/rbaConvert.cc b/src/rba/rba/rbaConvert.cc
index 6ac1a7877..17673a91a 100644
--- a/src/rba/rba/rbaConvert.cc
+++ b/src/rba/rba/rbaConvert.cc
@@ -224,7 +224,7 @@ object_to_ruby (void *obj, Proxy *self, const gsi::ClassBase *cls, bool pass_obj
// a Ruby object. If it already has, we simply return a reference to this.
ret = rba_data->self ();
-#if HAVE_RUBY_VERSION_CODE >= 20200
+#if HAVE_RUBY_VERSION_CODE >= 20200 && HAVE_RUBY_VERSION_CODE < 30000
// Mark the returned object - the original one may have been already
// scheduled for sweeping. This happens at least for Ruby 2.3 which
// has a two-phase GC (mark and sweep in separate steps). If by chance
diff --git a/testdata/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb
index 008a064d7..ab32c9156 100644
--- a/testdata/ruby/basic_testcore.rb
+++ b/testdata/ruby/basic_testcore.rb
@@ -894,8 +894,10 @@ class Basic_TestClass < TestBase
end
- # TODO: this class is going to be deprecated
- class X < Data
+ if RUBY_VERSION < "3.0.0"
+ # TODO: this class is going to be deprecated
+ class X < Data
+ end
end
class Y < Object
end
@@ -907,12 +909,14 @@ class Basic_TestClass < TestBase
end
# Test, if this throws an error (object of class X passed to A argument):
- begin
- b = RBA::B.new
- assert_equal( b.b4( X.new ), "b4_result: -6" )
- assert_equal( false, true ) # this must never hit
- rescue
- assert_equal( $!.to_s(), "allocator undefined for Basic_TestClass::X" );
+ if RUBY_VERSION < "3.0.0"
+ begin
+ b = RBA::B.new
+ assert_equal( b.b4( X.new ), "b4_result: -6" )
+ assert_equal( false, true ) # this must never hit
+ rescue
+ assert_equal( $!.to_s(), "allocator undefined for Basic_TestClass::X" );
+ end
end
# Test, if this throws an error (object of class X passed to A argument):
From 2986afc8f9ccab9c484159460b5ffe55f049c009 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Wed, 30 Jun 2021 23:00:38 +0200
Subject: [PATCH 14/15] Fixed #851
---
src/laybasic/laybasic/layNetlistBrowserPage.cc | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc
index 2a74de56c..e628cfcb8 100644
--- a/src/laybasic/laybasic/layNetlistBrowserPage.cc
+++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc
@@ -1192,6 +1192,7 @@ NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_ma
while (! shapes.at_end ()) {
if (shapes->type () != db::NetShape::Polygon) {
+ ++shapes;
continue;
}
From 2d24e36c8917d01123e1f75ec191603eb1e9ed17 Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Thu, 1 Jul 2021 00:07:04 +0200
Subject: [PATCH 15/15] Updated build scripts
---
src/klayout.pri | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/klayout.pri b/src/klayout.pri
index b03d5f7ea..4268df503 100644
--- a/src/klayout.pri
+++ b/src/klayout.pri
@@ -154,11 +154,9 @@ msvc {
# because we use unordered_map/unordered_set:
QMAKE_CXXFLAGS += -std=c++0x
- # needed for Ruby 3.0
- QMAKE_CXXFLAGS += -fdeclspec
-
win32 {
QMAKE_LFLAGS += -Wl,--exclude-all-symbols
+ QMAKE_CXXFLAGS += -fdeclspec
} else {
QMAKE_CXXFLAGS += -fvisibility=hidden
}