From a90e14b692acef7efa79d42fa506737256a4b986 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 27 Jul 2021 23:08:34 +0200 Subject: [PATCH] Some tests added. --- src/db/db/dbDeviceClass.h | 2 +- src/db/unit_tests/dbNetlistCompareTests.cc | 186 +++++++++++++++++++++ src/lvs/lvs/built-in-macros/_lvs_engine.rb | 22 ++- src/lvs/lvs/built-in-macros/_lvs_netter.rb | 77 +++++++++ 4 files changed, 285 insertions(+), 2 deletions(-) diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 2ab2fbd2f..69fe5aaa6 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -310,7 +310,7 @@ class DB_PUBLIC EqualDeviceParameters public: EqualDeviceParameters (); EqualDeviceParameters (size_t parameter_id, bool ignore = false); - EqualDeviceParameters (size_t parameter_id, double relative, double absolute); + EqualDeviceParameters (size_t parameter_id, double absolute, double relative); virtual bool less (const db::Device &a, const db::Device &b) const; diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 7ef82e780..f2d394e9a 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -4712,3 +4712,189 @@ TEST(29_EmptySubCircuitsFromSPICE) EXPECT_EQ (comp.compare (&a, &b), true); EXPECT_EQ (comp.compare (&a, &c), false); } + +TEST(30_ComparePrimaryAndOtherParameters) +{ + db::Netlist nl1, nl2; + db::DeviceClass *dc1, *dc2; + db::Circuit *circuit; + db::Device *d; + db::Net *n; + std::string txt; + bool good; + + dc1 = new db::DeviceClassResistor (); + dc1->set_name ("RES"); + nl1.add_device_class (dc1); + circuit = new db::Circuit (); + circuit->set_name ("X"); + d = new db::Device (); + d->set_device_class (dc1); + d->set_name ("D"); + d->set_parameter_value (db::DeviceClassResistor::param_id_L, 1.0); + d->set_parameter_value (db::DeviceClassResistor::param_id_R, 10.0); + d->set_parameter_value (db::DeviceClassResistor::param_id_W, 0.25); + circuit->add_device (d); + n = new db::Net (); + circuit->add_net (n); + n->set_name ("1"); + d->connect_terminal (db::DeviceClassResistor::terminal_id_A, n); + n->add_pin (db::NetPinRef (circuit->add_pin ("1").id ())); + n = new db::Net (); + circuit->add_net (n); + n->set_name ("2"); + d->connect_terminal (db::DeviceClassResistor::terminal_id_B, n); + n->add_pin (db::NetPinRef (circuit->add_pin ("2").id ())); + nl1.add_circuit (circuit); + + dc2 = new db::DeviceClassResistor (); + dc2->set_name ("RES"); + nl2.add_device_class (dc2); + circuit = new db::Circuit (); + circuit->set_name ("X"); + d = new db::Device (); + d->set_device_class (dc2); + d->set_name ("D"); + d->set_parameter_value (db::DeviceClassResistor::param_id_L, 1.1); // differs + d->set_parameter_value (db::DeviceClassResistor::param_id_R, 10.0); + d->set_parameter_value (db::DeviceClassResistor::param_id_W, 0.20); // differs + circuit->add_device (d); + n = new db::Net (); + circuit->add_net (n); + n->set_name ("1"); + d->connect_terminal (db::DeviceClassResistor::terminal_id_A, n); + n->add_pin (db::NetPinRef (circuit->add_pin ("1").id ())); + n = new db::Net (); + circuit->add_net (n); + n->set_name ("2"); + d->connect_terminal (db::DeviceClassResistor::terminal_id_B, n); + n->add_pin (db::NetPinRef (circuit->add_pin ("2").id ())); + nl2.add_circuit (circuit); + + NetlistCompareTestLogger logger; + db::NetlistComparer comp (&logger); + comp.set_dont_consider_net_names (true); + + good = comp.compare (&nl1, &nl2); + + txt = logger.text (); + + // we did not enable L and W, hence that works + EXPECT_EQ (good, true); + + EXPECT_EQ (txt, + "begin_circuit X X\n" + "match_ambiguous_nets 1 1\n" + "match_ambiguous_nets 2 2\n" + "match_pins 1 1\n" + "match_pins 2 2\n" + "match_devices D D\n" + "end_circuit X X MATCH" + ); + + // changing R will make the compare fail + + d->set_parameter_value (db::DeviceClassResistor::param_id_R, 12.0); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, false); + + // if we install a delegate which introduces a tolerance (absolute 1) it will still not match + + dc1->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassResistor::param_id_R, 1.0, 0.0)); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, false); + + // if we install a delegate which introduces a tolerance (absolute 2.0) it will match + + dc1->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassResistor::param_id_R, 2.0, 0.0)); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, true); + + // removing the comparer will make it non-matching + + dc1->set_parameter_compare_delegate (0); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, false); + + // disabling the parameter will make it match too + + dc1->parameter_definition_non_const (db::DeviceClassResistor::param_id_R)->set_is_primary (false); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, true); + + // enabling the parameter again will make it mismatch again + + dc1->parameter_definition_non_const (db::DeviceClassResistor::param_id_R)->set_is_primary (true); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, false); + + // disabling the parameter in the second netlist will make it match too + + dc2->parameter_definition_non_const (db::DeviceClassResistor::param_id_R)->set_is_primary (false); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, true); + + // enabling the parameter again will make it mismatch again + + dc2->parameter_definition_non_const (db::DeviceClassResistor::param_id_R)->set_is_primary (true); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, false); + + // we can install an ignore handler to make it match again + + dc1->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassResistor::param_id_R, true)); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, true); + + // if we enable the L parameter we'll get a mismatch again (but we have to enable it in both netlists) + + dc1->parameter_definition_non_const (db::DeviceClassResistor::param_id_L)->set_is_primary (true); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, true); + + dc2->parameter_definition_non_const (db::DeviceClassResistor::param_id_L)->set_is_primary (true); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, false); + + // until we install another tolerance + + *dynamic_cast (dc1->parameter_compare_delegate ()) += db::EqualDeviceParameters (db::DeviceClassResistor::param_id_L, 0.11, 0.0); + + logger.clear (); + good = comp.compare (&nl1, &nl2); + + EXPECT_EQ (good, true); +} diff --git a/src/lvs/lvs/built-in-macros/_lvs_engine.rb b/src/lvs/lvs/built-in-macros/_lvs_engine.rb index 3a0506516..5d7b3f8df 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_engine.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_engine.rb @@ -183,7 +183,27 @@ 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_nets! same_circuits same_device_classes equivalent_pins min_caps max_res max_depth max_branch_complexity consider_net_names).each do |f| + # %LVS% + # @name ignore_parameter + # @brief Specifies whether to ignore a parameter from a given device class for the compare + # @synopsis ignore_parameter(device_class_name, parameter_name) + # See \Netter#ignore_parameter for a description of that function. + + # %LVS% + # @name enable_parameter + # @brief Specifies whether to enable a parameter from a given device class for the netlisting and default compare + # @synopsis enable_parameter(device_class_name, parameter_name) + # See \Netter#enable_parameter for a description of that function. + + # %LVS% + # @name disable_parameter + # @brief Specifies whether to disable a parameter from a given device class for the netlisting and default compare + # @synopsis disable_parameter(device_class_name, parameter_name) + # See \Netter#disable_parameter for a description of that function. + + %w(schematic compare join_symmetric_nets tolerance ignore_parameter enable_parameter disable_parameter + 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 5c34685a3..f316c61b8 100644 --- a/src/lvs/lvs/built-in-macros/_lvs_netter.rb +++ b/src/lvs/lvs/built-in-macros/_lvs_netter.rb @@ -164,6 +164,83 @@ module LVS end + # %LVS% + # @name ignore_parameter + # @brief Indicates whether not to compare a specific parameter for a given device class name + # @synopsis ignore_parameter(device_class_name, parameter_name) + + def ignore_parameter(device_class_name, parameter_name) + + device_class_name.is_a?(String) || raise("Device class argument of 'ignore_parameter' must be a string") + parameter_name.is_a?(String) || raise("Parameter name argument of 'ignore_parameter' must be a string") + + if self._l2n_data + # already extracted + self._ignore_parameter(self._l2n_data, device_class_name, parameter_name) + else + @post_extract_config << lambda { |l2n| self._ignore_parameter(l2n, device_class_name, parameter_name) } + end + + end + + def _ignore_parameter(l2n, device_class_name, parameter_name) + + dc = l2n.netlist.device_class_by_name(device_class_name) + if dc && dc.has_parameter?(parameter_name) + ep = RBA::EqualDeviceParameters::ignore(dc.parameter_id(parameter_name)) + if dc.equal_parameters == nil + dc.equal_parameters = ep + else + dc.equal_parameters += ep + end + end + + end + + # %LVS% + # @name enable_parameter + # @brief Indicates whether to enable a specific parameter for a given device + # @synopsis enable_parameter(device_class_name, parameter_name) + # Enabling a parameter has two effects: first the parameter is netlisted and second + # the parameter is compared in the netlist compare - provided it is given in the schematic. + # Setting a tolerance or using a custom device comparer will override the last rule. + + # %LVS% + # @name disable_parameter + # @brief Indicates whether to disable a specific parameter for a given device + # @synopsis disable_parameter(device_class_name, parameter_name) + # Disabling a parameter has two effects: first the parameter is not netlisted and second + # the parameter is compared in the netlist compare - provided it is given in the schematic. + # Setting a tolerance or using a custom device comparer will override the last rule. + # To disable a parameter for compare only, \ignore_parameter can be used. + + [ :enable_parameter, :disable_parameter ].each do |mn| + eval <<"CODE" + def #{mn}(device_class_name, parameter_name) + + device_class_name.is_a?(String) || raise("Device class argument of '#{mn}' must be a string") + parameter_name.is_a?(String) || raise("Parameter name argument of '#{mn}' must be a string") + + if self._l2n_data + # already extracted + self._enable_parameter(self._l2n_data, device_class_name, parameter_name, :#{mn} == :enable_parameter) + else + @post_extract_config << lambda { |l2n| self._enable_parameter(l2n, device_class_name, parameter_name, :#{mn} == :enable_parameter) } + end + + end +CODE + end + + def _enable_parameter(l2n, device_class_name, parameter_name, enable) + + dc = l2n.netlist.device_class_by_name(device_class_name) + if dc && dc.has_parameter?(parameter_name) + dc.enable_parameter(parameter_name, enable) + end + + end + # %LVS% # @name align # @brief Aligns the extracted netlist vs. the schematic