From 1d150441b641ca1227f461b25e1a4a848fc88a9d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 21 May 2026 23:05:03 +0200 Subject: [PATCH] WIP --- src/db/db/dbDeviceClass.cc | 40 ++++++ src/db/db/dbDeviceClass.h | 60 +++++++++ src/db/db/dbNetlistSpiceReader.cc | 15 ++- src/db/db/dbNetlistSpiceReaderDelegate.cc | 154 +++++++++++++++++----- src/db/db/dbNetlistSpiceReaderDelegate.h | 8 +- src/db/db/dbNetlistSpiceWriter.cc | 3 +- src/db/db/gsiDeclDbNetlist.cc | 36 ++++- 7 files changed, 270 insertions(+), 46 deletions(-) diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index c2bd5eb0b..e923e7255 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -330,6 +330,46 @@ size_t DeviceClass::terminal_id_for_name (const std::string &name) const throw tl::Exception (tl::to_string (tr ("Invalid terminal name")) + ": '" + name + "'"); } +// @@@ GSI bindings for SPICE profile +void DeviceClass::set_spice_profile (const std::string &name, const SpiceProfile &profile) +{ + m_spice_profiles [name] = profile; +} + +bool DeviceClass::has_spice_profile (const std::string &name) const +{ + auto p = m_spice_profiles.find (name); + if (p == m_spice_profiles.end ()) { + p = m_spice_profiles.find ("*"); + } + return p != m_spice_profiles.end (); +} + +const DeviceClass::SpiceProfile &DeviceClass::spice_profile (const std::string &name) const +{ + auto p = m_spice_profiles.find (name); + if (p == m_spice_profiles.end ()) { + p = m_spice_profiles.find ("*"); + } + + if (p != m_spice_profiles.end ()) { + return p->second; + } else { + static DeviceClass::SpiceProfile def_profile; + return def_profile; + } +} + +void DeviceClass::clear_spice_profiles () +{ + m_spice_profiles.clear (); +} + +void DeviceClass::remove_spice_profile (const std::string &name) +{ + m_spice_profiles.erase (name); +} + // The default compare delegate static EqualDeviceParameters default_compare; diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index d92501c44..035f3cc86 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -408,6 +408,17 @@ class DB_PUBLIC DeviceClass : public gsi::ObjectBase, public tl::Object, public tl::UniqueId { public: + /** + * @brief The SPICE profile + * + * See \set_spice_profile for a description + */ + struct SpiceProfile + { + std::string element; + std::vector terminal_order; + }; + typedef size_t terminal_id_type; /** @@ -689,6 +700,45 @@ public: } } + /** + * @brief Sets a SPICE profile + * + * A Spice profile is a declaration, how a device is serialized to SPICE format + * by default. There can be multiple profiles for different flavors of SPICE + * files (e.g. for simulation etc.). + * A profile has a name and is specified in the SPICE reader or writer. + * + * If a device has an entry for a specific profile name, it can specify: + * * The SPICE element (e.g. "X" or "M") + * * The terminal order (a list of terminal names) + * + * Using "*" for the profile name installs a fallback profile which is + * used if no other profile applies. + */ + void set_spice_profile (const std::string &name, const SpiceProfile &profile); + + /** + * @brief Gets a value indicating whether a profile is available for the given name + */ + bool has_spice_profile (const std::string &name) const; + + /** + * @brief Gets a SPICE profile with a given name + */ + const SpiceProfile &spice_profile (const std::string &name) const; + + /** + * @brief Clears the SPICE profiles + */ + void clear_spice_profiles (); + + /** + * @brief Removes a SPICE profile with the given name + * + * The name can be "*" to remove the fallback profile. + */ + void remove_spice_profile (const std::string &name); + /** * @brief Compares the parameters of the devices a and b * @@ -805,6 +855,15 @@ public: db::mem_stat (stat, purpose, cat, m_description, true, (void *) this); db::mem_stat (stat, purpose, cat, m_terminal_definitions, true, (void *) this); db::mem_stat (stat, purpose, cat, m_parameter_definitions, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_spice_profiles, true, (void *) this); + db::mem_stat (stat, purpose, cat, m_equivalent_terminal_ids, true, (void *) this); + + if (mp_pc_delegate.get ()) { + db::mem_stat (stat, purpose, cat, *mp_pc_delegate, true, (void *) this); + } + if (mp_device_combiner.get ()) { + db::mem_stat (stat, purpose, cat, *mp_device_combiner, true, (void *) this); + } } private: @@ -813,6 +872,7 @@ private: std::string m_name, m_description; std::vector m_terminal_definitions; std::vector m_parameter_definitions; + std::map m_spice_profiles; bool m_strict; db::Netlist *mp_netlist; tl::shared_ptr mp_pc_delegate; diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index b759823e9..af9095ea5 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -794,19 +794,19 @@ SpiceCircuitDict::read_options (tl::Extractor &ex) } } else if (n == "defad") { if (v > min_value) { - mp_delegate->options ().defad = v; + mp_delegate->options ().default_values ["M"]["AD"] = v; } } else if (n == "defas") { if (v > min_value) { - mp_delegate->options ().defas = v; + mp_delegate->options ().default_values ["M"]["AS"] = v; } } else if (n == "defl") { if (v > min_value) { - mp_delegate->options ().defl = v; + mp_delegate->options ().default_values ["M"]["L"] = v; } } else if (n == "defw") { if (v > min_value) { - mp_delegate->options ().defw = v; + mp_delegate->options ().default_values ["M"]["W"] = v; } } @@ -1196,9 +1196,10 @@ SpiceNetlistBuilder::process_element (tl::Extractor &ex, const std::string &pref std::vector nn; NetlistSpiceReader::parameters_type pv; std::string model; + std::string element = prefix; double value = 0.0; - mp_delegate->parse_element (ex.skip (), prefix, model, value, nn, pv, m_variables); + mp_delegate->parse_element (ex.skip (), element, model, value, nn, pv, m_variables); model = mp_netlist->normalize_name (model); @@ -1207,7 +1208,7 @@ SpiceNetlistBuilder::process_element (tl::Extractor &ex, const std::string &pref nets.push_back (make_net (mp_delegate->translate_net_name (*i))); } - if (prefix == "X" && ! subcircuit_captured (model)) { + if (element == "X" && ! subcircuit_captured (model)) { const db::SpiceCachedCircuit *cc = mp_dict->cached_circuit (model); if (! cc) { @@ -1251,7 +1252,7 @@ SpiceNetlistBuilder::process_element (tl::Extractor &ex, const std::string &pref return true; } else { - return mp_delegate->element (mp_netlist_circuit, prefix, name, model, value, nets, pv); + return mp_delegate->element (mp_netlist_circuit, element, name, model, value, nets, pv); } } diff --git a/src/db/db/dbNetlistSpiceReaderDelegate.cc b/src/db/db/dbNetlistSpiceReaderDelegate.cc index 81b396efe..df92025d1 100644 --- a/src/db/db/dbNetlistSpiceReaderDelegate.cc +++ b/src/db/db/dbNetlistSpiceReaderDelegate.cc @@ -26,6 +26,7 @@ #include "dbNetlist.h" #include "dbCircuit.h" #include "dbNetlistDeviceClasses.h" +#include "tlLog.h" namespace db { @@ -34,12 +35,14 @@ namespace db NetlistSpiceReaderOptions::NetlistSpiceReaderOptions () { - scale = 1.0; - defad = 0.0; - defas = 0.0; // ngspice defaults: - defw = 100e-6; - defl = 100e-6; + default_values["M"]["AD"] = 0.0; + default_values["M"]["AS"] = 0.0; + default_values["M"]["W"] = 100e-6; + default_values["M"]["L"] = 100e-6; + + scale = 1.0; + all_parameters = false; } // ------------------------------------------------------------------------------------------------------ @@ -63,6 +66,26 @@ void NetlistSpiceReaderDelegate::set_netlist (db::Netlist *netlist) void NetlistSpiceReaderDelegate::do_start () { + // build the element/model to class map + m_spice_profiles.clear (); + + for (auto dc = mp_netlist->begin_device_classes (); dc != mp_netlist->end_device_classes (); ++dc) { + + const db::DeviceClass *dcc = dc.operator-> (); + if (dcc->has_spice_profile (m_options.profile)) { + + const db::DeviceClass::SpiceProfile &pf = dcc->spice_profile (m_options.profile); + if (! pf.element.empty ()) { + if (m_spice_profiles.find (std::make_pair (pf.element, dcc->name ())) != m_spice_profiles.end ()) { + tl::warn << tl::sprintf (tl::to_string (tr ("Duplicate model name %s bound to element %s in profile %s")), dcc->name (), pf.element, m_options.profile); + } + m_spice_profiles.insert (std::make_pair (std::make_pair (pf.element, dcc->name ()), dcc)); + } + + } + + } + start (mp_netlist); } @@ -175,23 +198,64 @@ void NetlistSpiceReaderDelegate::parse_element_components (const std::string &s, void NetlistSpiceReaderDelegate::def_values_per_element (const std::string &element, std::map &pv) { - if (element == "M") { - - pv.insert (std::make_pair ("W", m_options.defw)); - pv.insert (std::make_pair ("L", m_options.defl)); - pv.insert (std::make_pair ("AD", m_options.defad)); - pv.insert (std::make_pair ("AS", m_options.defas)); - + auto d = m_options.default_values.find (element); + if (d != m_options.default_values.end ()) { + for (auto i = d->second.begin (); i != d->second.end (); ++i) { + pv.insert (std::make_pair (i->first, i->second)); + } } } -void NetlistSpiceReaderDelegate::parse_element (const std::string &s, const std::string &element, std::string &model, double &value, std::vector &nn, std::map &pv, const std::map &variables) +void NetlistSpiceReaderDelegate::parse_element (const std::string &s, std::string &element, std::string &model, double &value, std::vector &nn, std::map &pv, const std::map &variables) { def_values_per_element (element, pv); parse_element_components (s, nn, pv, variables); - // interpret the parameters according to the code - if (element == "X") { + auto dp = m_spice_profiles.end (); + + if (! nn.empty ()) { + m_spice_profiles.find (std::make_pair (element, nn.back ())); + } + + if (dp != m_spice_profiles.end ()) { + + // element bound to a SPICE element through the device class + + model = dp->first.second; + nn.pop_back (); + + // indicates that we must not use the element name further + element.clear (); + + const std::vector &to = dp->second->spice_profile (m_options.profile).terminal_order; + + if (nn.size () != to.size ()) { + error (tl::sprintf (tl::to_string (tr ("Element '%s' bound to model '%s' in SPICE profile '%s' requires %d terminals, but got %d")), + element, model, m_options.profile, int (to.size ()), int (nn.size ()))); + } + + // reorder the terminals according to the terminal order + std::vector nn_ordered; + + const std::vector &td = dp->second->terminal_definitions (); + for (auto t = td.begin (); t != td.end (); ++t) { + int ti = -1; + for (auto i = to.begin (); i != to.end () && ti < 0; ++i) { + if (*i == t->name ()) { + ti = int (i - to.begin ()); + } + } + if (ti < 0) { + std::string tos = tl::join (to, ","); + error (tl::sprintf (tl::to_string (tr ("Element '%s' bound to model '%s' in SPICE profile '%s' terminal order (%s) does not provide a binding for terminal '%s'")), + element, model, m_options.profile, tos, t->name ())); + } + nn_ordered.push_back (nn[ti]); + } + + nn.swap (nn_ordered); + + } else if (element == "X") { // subcircuit call: // Xname n1 n2 ... nn circuit [params] @@ -327,11 +391,8 @@ void NetlistSpiceReaderDelegate::parse_element (const std::string &s, const std: } } -bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector &nets, const std::map &pv) +double NetlistSpiceReaderDelegate::get_multiplier (const std::map ¶ms) { - std::map params = pv; - std::vector terminal_order; - double mult = 1.0; auto mp = params.find ("M"); if (mp != params.end ()) { @@ -342,10 +403,23 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin error (tl::sprintf (tl::to_string (tr ("Invalid multiplier value (M=%.12g) - must not be zero or negative")), mult)); } + return mult; +} + +bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector &nets, const std::map &pv) +{ + std::map params = pv; + std::vector terminal_order; + std::string cn = model; db::DeviceClass *cls = circuit->netlist ()->device_class_by_name (cn); - if (element == "R") { + if (element.empty ()) { + + // obtained through SPICE profile. + tl_assert (cls != 0); + + } else if (element == "R") { if (nets.size () == 2) { if (cls) { @@ -374,6 +448,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } // Apply multiplier (divider, according to ngspice manual) + double mult = get_multiplier (params); value /= mult; params["R"] = tl::Variant (value); @@ -404,6 +479,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } // Apply multiplier (divider, according to ngspice manual) + double mult = get_multiplier (params); value /= mult; params["L"] = tl::Variant (value); @@ -436,6 +512,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } // Apply multiplier + double mult = get_multiplier (params); value *= mult; params["C"] = tl::Variant (value); @@ -462,6 +539,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } // Apply multiplier + double mult = get_multiplier (params); static const char *scale_params[] = { "A", "P" }; for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) { auto p = params.find (scale_params [i]); @@ -499,6 +577,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } // Apply multiplier + double mult = get_multiplier (params); static const char *scale_params[] = { "AE", "PE", "AB", "PB", "AC", "PC" }; for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) { auto p = params.find (scale_params [i]); @@ -525,6 +604,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } // Apply multiplier + double mult = get_multiplier (params); static const char *scale_params[] = { "W", "AD", "AS", "PD", "PS" }; for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) { auto p = params.find (scale_params [i]); @@ -539,8 +619,11 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin terminal_order.push_back (DeviceClassMOS4Transistor::terminal_id_S); terminal_order.push_back (DeviceClassMOS4Transistor::terminal_id_B); - } else { + } else if (! cls) { + + // if the element class cannot be deduced from the "X" element name, raise an error error (tl::sprintf (tl::to_string (tr ("Not a known element type: '%s'")), element)); + } const std::vector &td = cls->terminal_definitions (); @@ -561,17 +644,27 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin } } + for (auto p = params.begin (); p != params.end (); ++p) { + + if (cls->has_parameter_with_name (p->first)) { + + device->set_parameter_value (p->first, p->second); + + } else if (m_options.all_parameters) { + + // if requested, create the parameter + if (p->second.is_long () || p->second.is_ulong ()) { + device->set_parameter_value_create (p->first, p->second, false, tl::Variant (long (0))); + } else if (p->second.is_double ()) { + device->set_parameter_value_create (p->first, p->second, false, tl::Variant (0.0)); + } else if (p->second.is_a_string ()) { + device->set_parameter_value_create (p->first, p->second, false, tl::Variant ("")); + } else { + device->set_parameter_value_create (p->first, p->second, false, tl::Variant ()); + } - std::vector &pd = cls->parameter_definitions_non_const (); - for (std::vector::iterator i = pd.begin (); i != pd.end (); ++i) { - auto v = params.find (i->name ()); - double pv = 0.0; - if (v != params.end ()) { - pv = v->second.to_double (); - } else { - continue; } - device->set_parameter_value (i->id (), pv); + } apply_parameter_scaling (device); @@ -588,7 +681,6 @@ NetlistSpiceReaderDelegate::apply_parameter_scaling (db::Device *device) const const std::vector &pd = device->device_class ()->parameter_definitions (); for (auto i = pd.begin (); i != pd.end (); ++i) { const tl::Variant &pv = device->parameter_value (i->id ()); - // @@@ only in case of double??? if (pv.is_double ()) { device->set_parameter_value (i->id (), pv.to_double () / i->si_scaling () * pow (m_options.scale, i->geo_scaling_exponent ())); } diff --git a/src/db/db/dbNetlistSpiceReaderDelegate.h b/src/db/db/dbNetlistSpiceReaderDelegate.h index 2cfbd0301..8711ab785 100644 --- a/src/db/db/dbNetlistSpiceReaderDelegate.h +++ b/src/db/db/dbNetlistSpiceReaderDelegate.h @@ -44,8 +44,10 @@ struct DB_PUBLIC NetlistSpiceReaderOptions { NetlistSpiceReaderOptions (); + std::string profile; // @@@ GSI binding double scale; - double defad, defas, defw, defl; + std::map > default_values; + bool all_parameters; // @@@ GSI binding }; /** @@ -137,7 +139,7 @@ public: * @param nn Out parameter: the net names * @param pv Out parameter: the parameter values (key/value pairs) */ - virtual void parse_element (const std::string &s, const std::string &element, std::string &model, double &value, std::vector &nn, std::map &pv, const std::map ¶ms); + virtual void parse_element (const std::string &s, std::string &element, std::string &model, double &value, std::vector &nn, std::map &pv, const std::map ¶ms); /** * @brief Produces an error with the given message @@ -187,8 +189,10 @@ public: private: db::Netlist *mp_netlist; NetlistSpiceReaderOptions m_options; + std::map, const db::DeviceClass *> m_spice_profiles; void def_values_per_element (const std::string &element, std::map &pv); + double get_multiplier (const std::map &pv); }; } diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc index 0fa1cea19..d724af789 100644 --- a/src/db/db/dbNetlistSpiceWriter.cc +++ b/src/db/db/dbNetlistSpiceWriter.cc @@ -237,7 +237,6 @@ std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, si double sis = i->si_scaling (); // for compatibility - // @@@ TODO: only for double??? if (fabs (sis * 1e6 - 1.0) < db::epsilon) { os << tl::to_string (v) << "U"; } else if (fabs (sis * 1e12 - 1.0) < db::epsilon) { @@ -246,6 +245,8 @@ std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, si os << tl::to_string (v.to_double () * sis); } + } else if (v.is_long () || v.is_ulong ()) { + os << v.to_string (); } else { os << tl::to_word_or_quoted_string (v.to_string ()); } diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index a89c85747..9b7316cd0 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -442,10 +442,17 @@ Class decl_dbDevice (decl_dbNetlistObject, "db", "Device", "@brief Gets the parameter value for the given parameter name.\n" "If the parameter name is not valid, an exception is thrown." ) + - // @@@ set_parameter_create!!! gsi::method ("set_parameter", (void (db::Device::*) (const std::string &, const tl::Variant &)) &db::Device::set_parameter_value, gsi::arg ("param_name"), gsi::arg ("value"), "@brief Sets the parameter value for the given parameter name.\n" "If the parameter name is not valid, an exception is thrown." + ) + + gsi::method ("set_parameter_create", (void (db::Device::*) (const std::string &, const tl::Variant &, bool, const tl::Variant &)) &db::Device::set_parameter_value_create, gsi::arg ("param_name"), gsi::arg ("value"), gsi::arg ("primary", true), gsi::arg ("default_value", tl::Variant (0.0), "none"), + "@brief Sets the parameter value for the given parameter name and creates a new parameter if no parameter is present with this name.\n" + "If no parameter with the given name exists in the device class's parameter table, a new parameter is created. " + "\\primary indicates that this parameter will be a primary one and \\default_value is the default value for this parameter. " + "The default value also implicitly defines the type of the parameter. A float value will create a float-type parameter, a string value for default will create a string-type parameter.\n" + "\n" + "This method has been introduced in version 0.31.0." ), "@brief A device inside a circuit.\n" "Device object represent atomic devices such as resistors, diodes or transistors. " @@ -887,10 +894,12 @@ Class decl_dbDeviceParameterDefinition ("db", "De gsi::method ("si_scaling", &db::DeviceParameterDefinition::si_scaling, "@brief Gets the scaling factor to SI units.\n" "For parameters in micrometers - for example W and L of MOS devices - this factor can be set to 1e-6 to reflect " - "the unit." + "the unit. SI unit scaling is only applied to parameters of the 'float' type. It is not applied to integer-type " + "or string parameters." ) + gsi::method ("si_scaling=", &db::DeviceParameterDefinition::set_si_scaling, gsi::arg ("flag"), "@brief Sets the scaling factor to SI units.\n" + "See \\si_scaling for details.\n" "\n" "This setter has been added in version 0.28.6." ) + @@ -898,6 +907,8 @@ Class decl_dbDeviceParameterDefinition ("db", "De "@brief Gets the geometry scaling exponent.\n" "This value is used when applying '.options scale' in the SPICE reader for example. " "It is zero for 'no scaling', 1.0 for linear scaling and 2.0 for quadratic scaling.\n" + "Geometric scaling is only applied to parameters of the 'float' type. It is not applied to integer-type " + "or string parameters.\n" "\n" "This attribute has been added in version 0.28.6." ) + @@ -2545,6 +2556,9 @@ class ParseElementData public: ParseElementData () : m_value (0.0) { } + const std::string &element_name () const { return m_element; } + std::string &element_name_nc () { return m_element; } + void set_element_name (const std::string &element) { m_element = element; } const std::string &model_name () const { return m_model; } std::string &model_name_nc () { return m_model; } void set_model_name (const std::string &model) { m_model = model; } @@ -2559,7 +2573,7 @@ public: void set_parameters (const db::NetlistSpiceReader::parameters_type ¶meters) { m_parameters = parameters; } private: - std::string m_model; + std::string m_model, m_element; double m_value; std::vector m_net_names; db::NetlistSpiceReader::parameters_type m_parameters; @@ -2702,12 +2716,15 @@ public: ParseElementData parse_element_helper (const std::string &s, const std::string &element) { + // NOTE: this way of treating the element name is compatible with the old way and + // the new way in which the element name can be modified by "parse_element". ParseElementData data; - db::NetlistSpiceReaderDelegate::parse_element (s, element, data.model_name_nc (), data.value_nc (), data.net_names_nc (), data.parameters_nc (), variables ()); + data.set_element_name (element); + db::NetlistSpiceReaderDelegate::parse_element (s, data.element_name_nc (), data.model_name_nc (), data.value_nc (), data.net_names_nc (), data.parameters_nc (), variables ()); return data; } - virtual void parse_element (const std::string &s, const std::string &element, std::string &model, double &value, std::vector &nn, db::NetlistSpiceReader::parameters_type &pv, const db::NetlistSpiceReader::parameters_type &variables) + virtual void parse_element (const std::string &s, std::string &element, std::string &model, double &value, std::vector &nn, db::NetlistSpiceReader::parameters_type &pv, const db::NetlistSpiceReader::parameters_type &variables) { try { @@ -2721,6 +2738,7 @@ public: data = parse_element_helper (s, element); } + element = data.element_name (); model = data.model_name (); value = data.value (); nn = data.net_names (); @@ -2866,6 +2884,14 @@ Class db_ParseElementData ("db", "ParseElementData", gsi::method ("model_name=", &ParseElementData::set_model_name, gsi::arg ("m"), "@brief Sets the model name\n" ) + + gsi::method ("element_name", &ParseElementData::element_name, + "@brief Gets the element name\n" + "This attribute is available since version 0.31.0.\n" + ) + + gsi::method ("element_name=", &ParseElementData::set_element_name, gsi::arg ("e"), + "@brief Sets the element name\n" + "This attribute is available since version 0.31.0.\n" + ) + gsi::method ("net_names", &ParseElementData::net_names, "@brief Gets the net names\n" ) +