diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 6e4bc6ae2..00cbe62a5 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -287,19 +287,37 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry); if (ec == extractor_cache.end ()) { + log_entry_list log_entries; + m_log_entries.swap (log_entries); + // do the actual device extraction extract_devices (layer_geometry); // push the new devices to the layout push_new_devices (disp); - ExtractorCacheValueType &ecv = extractor_cache [layer_geometry]; - ecv.disp = disp; + if (m_log_entries.empty ()) { + + // cache unless log entries are produced + ExtractorCacheValueType &ecv = extractor_cache [layer_geometry]; + ecv.disp = disp; + + for (std::map >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) { + ecv.devices.push_back (d->second.first); + } + + } else { + + // transform the marker geometries from the log entries to match the device + db::DVector disp_dbu = db::CplxTrans (dbu ()) * disp; + for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) { + l->set_geometry (l->geometry ().moved (disp_dbu)); + } - for (std::map >::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) { - ecv.devices.push_back (d->second.first); } + m_log_entries.splice (m_log_entries.begin (), log_entries); + m_new_devices.clear (); } else { diff --git a/src/layui/layui/layBrowser.cc b/src/layui/layui/layBrowser.cc index e47e56525..edfbf4a26 100644 --- a/src/layui/layui/layBrowser.cc +++ b/src/layui/layui/layBrowser.cc @@ -95,6 +95,16 @@ Browser::accept () } } +void +Browser::reject () +{ + if (active ()) { + m_active = false; + deactivated (); + QDialog::reject (); + } +} + } #endif diff --git a/src/layui/layui/layBrowser.h b/src/layui/layui/layBrowser.h index 03416ce20..30edb4199 100644 --- a/src/layui/layui/layBrowser.h +++ b/src/layui/layui/layBrowser.h @@ -138,6 +138,7 @@ private: void closeEvent (QCloseEvent *); void accept (); + void reject (); }; } diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index cde9e8f7f..d82d5d56d 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -28,7 +28,7 @@ #include "lymMacro.h" #include "tlFileUtils.h" -void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, const std::string &top = std::string (), bool change_case = false) +void run_test (tl::TestBase *_this, const std::string &suffix, const std::string &layout, bool with_l2n = false, bool with_lvs = true, const std::string &top = std::string (), bool change_case = false) { std::string rs = tl::testdata (); rs += "/lvs/" + suffix + ".lvs"; @@ -70,7 +70,9 @@ void run_test (tl::TestBase *_this, const std::string &suffix, const std::string lvs.load_from (rs); EXPECT_EQ (lvs.run (), 0); - _this->compare_text_files (output_lvsdb, au_lvsdb); + if (with_lvs) { + _this->compare_text_files (output_lvsdb, au_lvsdb); + } _this->compare_text_files (output_cir, au_cir); if (with_l2n) { _this->compare_text_files (output_l2n, au_l2n); @@ -121,14 +123,14 @@ TEST(6_simple_pin_swapping) { run_test (_this, "ringo_simple_pin_swapping", "ringo.gds"); // change case - run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, std::string (), true); + run_test (_this, "ringo_simple_pin_swapping", "ringo.gds", false, true, std::string (), true); } TEST(7_net_and_circuit_equivalence) { run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds"); // change case - run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, std::string (), true); + run_test (_this, "ringo_simple_net_and_circuit_equivalence", "ringo_renamed.gds", false, true, std::string (), true); } TEST(8_simplification) @@ -166,7 +168,7 @@ TEST(13_simple_ringo_device_subcircuits) { run_test (_this, "ringo_device_subcircuits", "ringo.gds"); // change case - run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, std::string (), true); + run_test (_this, "ringo_device_subcircuits", "ringo.gds", false, true, std::string (), true); } TEST(14_simple_ringo_mixed_hierarchy) @@ -181,7 +183,7 @@ TEST(15_simple_dummy_device) TEST(16_floating) { - run_test (_this, "floating", "floating.gds", false, "TOP"); + run_test (_this, "floating", "floating.gds", false, true, "TOP"); } TEST(17_layout_variants) @@ -287,3 +289,9 @@ TEST(31_MustConnect2) run_test (_this, "must_connect2", "must_connect2.gds"); } +// issue 1609 +TEST(40_DeviceExtractorErrors) +{ + run_test (_this, "custom_resistors", "custom_resistors.gds", true, false /*no LVS*/); +} + diff --git a/src/lvs/unit_tests/lvsTests.cc b/src/lvs/unit_tests/lvsTests.cc index 40de5d859..616b561e2 100644 --- a/src/lvs/unit_tests/lvsTests.cc +++ b/src/lvs/unit_tests/lvsTests.cc @@ -165,7 +165,7 @@ TEST(20_private) TEST(21_private) { - run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_3.lvsdb"); + run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_4.lvsdb"); } // issue #1021 diff --git a/testdata/lvs/custom_resistors.cir b/testdata/lvs/custom_resistors.cir new file mode 100644 index 000000000..f49736e76 --- /dev/null +++ b/testdata/lvs/custom_resistors.cir @@ -0,0 +1,18 @@ + +* cell TOP +.SUBCKT TOP +* cell instance $1 r180 *1 2,2.6 +X$1 6 1 A +* cell instance $2 r0 *1 2.2,1 +X$2 6 5 A +* device instance $1 r0 *1 0.8,0.75 RPP1 +R$1 2 1 0.555555555556 RPP1 +.ENDS TOP + +* cell A +* pin +* pin +.SUBCKT A 1 2 +* device instance $1 r0 *1 -0.2,0.4 RPP1 +R$1 1 2 1.25 RPP1 +.ENDS A diff --git a/testdata/lvs/custom_resistors.gds b/testdata/lvs/custom_resistors.gds new file mode 100644 index 000000000..df4b2d400 Binary files /dev/null and b/testdata/lvs/custom_resistors.gds differ diff --git a/testdata/lvs/custom_resistors.l2n.1 b/testdata/lvs/custom_resistors.l2n.1 new file mode 100644 index 000000000..1047b4c0a --- /dev/null +++ b/testdata/lvs/custom_resistors.l2n.1 @@ -0,0 +1,103 @@ +#%l2n-klayout +W(TOP) +U(0.001) +L(l4 '15/0') +L(l3 '16/0') +L(l1) +C(l4 l4 l3 l1) +C(l3 l4 l3) +C(l1 l4 l1) +H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)')) +H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)')) +H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)')) +K(RPP1 RES) +D(D$RPP1 RPP1 + T(A + R(l1 (0 400) (200 300)) + ) + T(B + R(l1 (0 1200) (200 250)) + ) +) +D(D$RPP1$1 RPP1 + T(A + R(l1 (0 0) (250 200)) + ) + T(B + R(l1 (750 0) (250 200)) + ) +) +X(A + R((-200 -450) (1750 1350)) + N(1 + R(l4 (-150 450) (100 100)) + R(l3 (-150 -150) (200 500)) + R(l1 (-200 -500) (250 200)) + ) + N(2 + R(l4 (650 450) (100 100)) + R(l4 (-100 -900) (100 100)) + R(l3 (-150 200) (200 650)) + R(l3 (-200 -1000) (200 500)) + R(l1 (-250 300) (250 200)) + R(l1 (-200 -1000) (250 200)) + ) + N(3 + R(l4 (1450 -350) (100 100)) + ) + P(1) + P(2) + D(1 D$RPP1$1 + Y(-200 400) + E(R 1.25) + E(L 0.5) + E(W 0.2) + E(A 0.1) + E(P 1.4) + T(A 1) + T(B 2) + ) +) +X(TOP + R((-50 450) (3800 2600)) + N(1 + R(l4 (850 2050) (100 100)) + R(l3 (-150 -150) (500 200)) + R(l1 (-500 -250) (200 250)) + ) + N(2 + R(l4 (850 1250) (100 100)) + R(l4 (-100 -100) (100 100)) + R(l4 (-900 -100) (100 100)) + R(l3 (200 -150) (650 200)) + R(l3 (-1000 -200) (500 200)) + R(l1 (300 -250) (200 300)) + R(l1 (-1000 -300) (200 250)) + ) + N(3 + R(l4 (50 450) (100 100)) + ) + N(4 + R(l4 (850 450) (100 100)) + ) + N(5) + N(6) + D(1 D$RPP1 + Y(800 750) + E(R 0.555555555556) + E(L 0.333333333333) + E(W 0.3) + E(A 0.1) + E(P 1.26666666667) + T(A 2) + T(B 1) + ) + X(1 A O(180) Y(2000 2600) + P(0 6) + P(1 1) + ) + X(2 A Y(2200 1000) + P(0 6) + P(1 5) + ) +) diff --git a/testdata/lvs/custom_resistors.l2n.2 b/testdata/lvs/custom_resistors.l2n.2 new file mode 100644 index 000000000..17deb7617 --- /dev/null +++ b/testdata/lvs/custom_resistors.l2n.2 @@ -0,0 +1,103 @@ +#%l2n-klayout +W(TOP) +U(0.001) +L(l4 '15/0') +L(l3 '16/0') +L(l1) +C(l4 l4 l3 l1) +C(l3 l4 l3) +C(l1 l4 l1) +H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0,0.75;0,1.15;0.2,1.15;0.2,0.75)')) +H(E B('Resistor shape does not touch marker border in exactly two places') C(TOP) X('device-extract') Q('(0.8,0.75;0.8,1.15;1,1.15;1,0.75)')) +H(E B('Resistor shape does not touch marker border in exactly two places') C(A) X('device-extract') Q('(0.85,-0.4;0.85,-0.2;1.25,-0.2;1.25,-0.4)')) +K(RPP1 RES) +D(D$RPP1 RPP1 + T(A + R(l1 (0 400) (200 300)) + ) + T(B + R(l1 (0 1200) (200 250)) + ) +) +D(D$RPP1$1 RPP1 + T(A + R(l1 (0 0) (250 200)) + ) + T(B + R(l1 (750 0) (250 200)) + ) +) +X(A + R((-200 -450) (1750 1350)) + N(1 + R(l4 (-150 450) (100 100)) + R(l3 (-150 -150) (200 500)) + R(l1 (-200 -500) (250 200)) + ) + N(2 + R(l4 (650 450) (100 100)) + R(l4 (-100 -900) (100 100)) + R(l3 (-150 200) (200 650)) + R(l3 (-200 -1000) (200 500)) + R(l1 (-250 300) (250 200)) + R(l1 (-200 -1000) (250 200)) + ) + N(3 + R(l4 (1450 -350) (100 100)) + ) + P(1) + P(2) + D(1 D$RPP1$1 + Y(-200 400) + E(R 1.25) + E(L 0.5) + E(W 0.2) + E(A 0.1) + E(P 1.4) + T(A 1) + T(B 2) + ) +) +X(TOP + R((-50 450) (3800 2600)) + N(1 + R(l4 (850 2050) (100 100)) + R(l3 (-150 -150) (500 200)) + R(l1 (-500 -250) (200 250)) + ) + N(2 + R(l4 (850 1250) (100 100)) + R(l4 (-100 -100) (100 100)) + R(l4 (-900 -100) (100 100)) + R(l3 (200 -150) (650 200)) + R(l3 (-1000 -200) (500 200)) + R(l1 (300 -250) (200 300)) + R(l1 (-1000 -300) (200 250)) + ) + N(3 + R(l4 (50 450) (100 100)) + ) + N(4 + R(l4 (850 450) (100 100)) + ) + N(5) + N(6) + D(1 D$RPP1 + Y(800 750) + E(R 0.555555555556) + E(L 0.333333333333) + E(W 0.3) + E(A 0.1) + E(P 1.26666666667) + T(A 2) + T(B 1) + ) + X(1 A O(180) Y(2000 2600) + P(0 6) + P(1 1) + ) + X(2 A Y(2200 1000) + P(0 6) + P(1 5) + ) +) diff --git a/testdata/lvs/custom_resistors.lvs b/testdata/lvs/custom_resistors.lvs new file mode 100644 index 000000000..78072f645 --- /dev/null +++ b/testdata/lvs/custom_resistors.lvs @@ -0,0 +1,86 @@ + +source($lvs_test_source, "TOP") + +report_netlist($lvs_test_target_l2n) +target_netlist($lvs_test_target_cir) + +deep + +# ------------------------------------------------------------------- +# Layers + +poly_dg = input(13, 0) +cont = input(15, 0) +met1_dg = input(16, 0) +sblk = input(34, 0) +rp_1 = sblk & poly_dg +p1trm = poly_dg - rp_1 + +class ResistorExtractor < RBA::GenericDeviceExtractor + + def initialize(name, sheet_rho) + self.name = name + @sheet_rho = sheet_rho + end + + def setup + define_layer("C", "Conductor") + define_layer("R", "Resistor") + register_device_class(RBA::DeviceClassResistor::new) + end + + def get_connectivity(layout, layers) + # this "connectivity" forms the shape clusters that make up the device + conn = RBA::Connectivity::new + conn.connect(layers[0], layers[1]) # collect touching contacts + conn.connect(layers[1], layers[1]) # combine resistor shapes into one area + conn + end + + def extract_devices(layer_geometry) + # layer_geometry provides the input layers in the order they are defined with "define_layer" + conductor = layer_geometry[0] + resistor = layer_geometry[1] + + resistor_regions = resistor.merged + + resistor_regions.each do |r| + terminals = conductor.interacting(RBA::Region::new(r)) + if terminals.size != 2 + error("Resistor shape does not touch marker border in exactly two places", r) + else + double_width = 0 + (terminals.edges & resistor.edges).merged.each do |e| + double_width += e.length + end + # A = L*W + # -> L = A/W + a = r.area*dbu*dbu + w = (double_width / 2.0)*dbu + l = a / w + + device = create_device + device.set_parameter(RBA::DeviceClassResistor::PARAM_R, @sheet_rho * l / w); + + device.set_parameter(RBA::DeviceClassResistor::PARAM_A, a) + device.set_parameter(RBA::DeviceClassResistor::PARAM_L, l) + device.set_parameter(RBA::DeviceClassResistor::PARAM_P, 2*l+2*w) + device.set_parameter(RBA::DeviceClassResistor::PARAM_W, w) + define_terminal(device, "A", "C", terminals[0]); + define_terminal(device, "B", "C", terminals[1]); + end + end + end +end + +extract_devices(ResistorExtractor::new("RPP1", 0.5), # intentionally wrong: 1565.15/5 + { "C" => p1trm, "R" => rp_1 }) + +connect(met1_dg, cont) +connect(p1trm, cont) + +begin + netlist +rescue => ex +end +