diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index af9095ea5..b4b484729 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -1314,13 +1314,33 @@ NetlistSpiceReader::~NetlistSpiceReader () // .. nothing yet .. } +const std::string &NetlistSpiceReader::profile () const +{ + return m_profile; +} + +void NetlistSpiceReader::set_profile (const std::string &profile) +{ + m_profile = profile; +} + +NetlistSpiceReaderDelegate *NetlistSpiceReader::delegate () +{ + return mp_delegate.get (); +} + +const NetlistSpiceReaderDelegate *NetlistSpiceReader::delegate () const +{ + return mp_delegate.get (); +} + void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist) { tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading netlist ")) + stream.source ()); try { - mp_delegate->set_netlist (&netlist); + mp_delegate->set_netlist (&netlist, profile ()); // SPICE netlists are case insensitive netlist.set_case_sensitive (false); @@ -1338,10 +1358,10 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist) builder.set_strict (m_strict); builder.build (); - mp_delegate->set_netlist (0); + mp_delegate->set_netlist (0, std::string ()); } catch (...) { - mp_delegate->set_netlist (0); + mp_delegate->set_netlist (0, std::string ()); throw; } } diff --git a/src/db/db/dbNetlistSpiceReader.h b/src/db/db/dbNetlistSpiceReader.h index aa9ad187d..343424fa4 100644 --- a/src/db/db/dbNetlistSpiceReader.h +++ b/src/db/db/dbNetlistSpiceReader.h @@ -55,6 +55,29 @@ public: virtual void read (tl::InputStream &stream, db::Netlist &netlist); + /** + * @brief Gets the SPICE profile name + * + * The SPICE profile name is used to collect SPICE reader settings from the + * device classes. + */ + const std::string &profile () const; + + /** + * @brief Sets the SPICE profile name + */ + void set_profile (const std::string &profile); + + /** + * @brief Gets the SPICE reader delegate + */ + NetlistSpiceReaderDelegate *delegate (); + + /** + * @brief Gets the SPICE reader delegate (const version) + */ + const NetlistSpiceReaderDelegate *delegate () const; + /** * @brief Sets or resets strict mode * In strict mode, all subcircuits need to be present in the net list for example. @@ -82,15 +105,11 @@ public: */ static std::string parse_component (tl::Extractor &ex); - /** - * @brief Reads a component name - * Scans over a component name and returns the - */ - private: tl::weak_ptr mp_delegate; std::unique_ptr mp_default_delegate; bool m_strict; + std::string m_profile; }; } diff --git a/src/db/db/dbNetlistSpiceReaderDelegate.cc b/src/db/db/dbNetlistSpiceReaderDelegate.cc index df92025d1..3064d953f 100644 --- a/src/db/db/dbNetlistSpiceReaderDelegate.cc +++ b/src/db/db/dbNetlistSpiceReaderDelegate.cc @@ -42,13 +42,12 @@ NetlistSpiceReaderOptions::NetlistSpiceReaderOptions () default_values["M"]["L"] = 100e-6; scale = 1.0; - all_parameters = false; } // ------------------------------------------------------------------------------------------------------ NetlistSpiceReaderDelegate::NetlistSpiceReaderDelegate () - : mp_netlist (0), m_options () + : mp_netlist (0), m_options (), m_profile (), m_read_all_parameters (true) { // .. nothing yet .. } @@ -58,10 +57,23 @@ NetlistSpiceReaderDelegate::~NetlistSpiceReaderDelegate () // .. nothing yet .. } -void NetlistSpiceReaderDelegate::set_netlist (db::Netlist *netlist) +bool +NetlistSpiceReaderDelegate::read_all_parameters () const +{ + return m_read_all_parameters; +} + +void +NetlistSpiceReaderDelegate::set_read_all_parameters (bool f) +{ + m_read_all_parameters = f; +} + +void NetlistSpiceReaderDelegate::set_netlist (db::Netlist *netlist, const std::string &profile) { m_options = NetlistSpiceReaderOptions (); mp_netlist = netlist; + m_profile = profile; } void NetlistSpiceReaderDelegate::do_start () @@ -72,12 +84,12 @@ void NetlistSpiceReaderDelegate::do_start () 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)) { + if (dcc->has_spice_profile (m_profile)) { - const db::DeviceClass::SpiceProfile &pf = dcc->spice_profile (m_options.profile); + const db::DeviceClass::SpiceProfile &pf = dcc->spice_profile (m_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); + tl::warn << tl::sprintf (tl::to_string (tr ("Duplicate model name %s bound to element %s in profile %s")), dcc->name (), pf.element, m_profile); } m_spice_profiles.insert (std::make_pair (std::make_pair (pf.element, dcc->name ()), dcc)); } @@ -109,9 +121,9 @@ bool NetlistSpiceReaderDelegate::control_statement (const std::string & /*line*/ return false; } -bool NetlistSpiceReaderDelegate::wants_subcircuit (const std::string & /*circuit_name*/) +bool NetlistSpiceReaderDelegate::wants_subcircuit (const std::string &circuit_name) { - return false; + return m_spice_profiles.find (std::make_pair ("X", circuit_name)) != m_spice_profiles.end (); } std::string NetlistSpiceReaderDelegate::translate_net_name (const std::string &nn) @@ -227,11 +239,11 @@ void NetlistSpiceReaderDelegate::parse_element (const std::string &s, std::strin // 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; + const std::vector &to = dp->second->spice_profile (m_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 ()))); + element, model, m_profile, int (to.size ()), int (nn.size ()))); } // reorder the terminals according to the terminal order @@ -248,7 +260,7 @@ void NetlistSpiceReaderDelegate::parse_element (const std::string &s, std::strin 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 ())); + element, model, m_profile, tos, t->name ())); } nn_ordered.push_back (nn[ti]); } @@ -650,7 +662,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin device->set_parameter_value (p->first, p->second); - } else if (m_options.all_parameters) { + } else if (m_read_all_parameters) { // if requested, create the parameter if (p->second.is_long () || p->second.is_ulong ()) { diff --git a/src/db/db/dbNetlistSpiceReaderDelegate.h b/src/db/db/dbNetlistSpiceReaderDelegate.h index 8711ab785..3744d89bf 100644 --- a/src/db/db/dbNetlistSpiceReaderDelegate.h +++ b/src/db/db/dbNetlistSpiceReaderDelegate.h @@ -44,19 +44,26 @@ struct DB_PUBLIC NetlistSpiceReaderOptions { NetlistSpiceReaderOptions (); - std::string profile; // @@@ GSI binding double scale; std::map > default_values; - bool all_parameters; // @@@ GSI binding }; /** * @brief A delegate to handle various forms of devices and translates them * - * The reader delegate can be configured to receive subcircuit elements too. - * In this case, parameters are allowed. + * The default behavior is controlled by the device classes that + * are defined inside the netlist object, before it is passed to the + * "start" method. The device class may define rules which are + * selected by the "SPICE profile" string. These rules include the + * SPICE element that is used for a device and the terminal order. + * + * Instead of using the device profiles, the SPICE reader delegate + * can also be customized by re-implementing methods that control + * the parsing of SPICE lines and creation of devices from them. + * * For receiving subcircuit elements, the delegate needs to indicate - * this by returning true upon "wants_subcircuit". + * this by returning true upon "wants_subcircuit" or by declaring + * device classes with "X" elements in their SPICE profile. */ class DB_PUBLIC NetlistSpiceReaderDelegate : public tl::Object @@ -67,6 +74,9 @@ public: /** * @brief Gets the reader options + * + * The reader options are settings collected during the parsing of the SPICE file, + * such as the scale value etc. */ const NetlistSpiceReaderOptions &options () const { @@ -81,6 +91,21 @@ public: return m_options; } + /** + * @brief Gets a flag indicating whether all parameters shall be read + * + * With this flag set to false (the default), only those parameters which + * are declared in the device classes of the netlist are read. + * Otherwise, additional parameters are added to the device classes + * and their values are stored in the device objects. + */ + bool read_all_parameters () const; + + /** + * @brief Sets a flag indicating whether all parameters shall be read + */ + void set_read_all_parameters (bool f); + /** * @brief Called when the netlist reading starts */ @@ -177,9 +202,9 @@ public: void do_finish (); /** - * @brief Sets the netlist + * @brief Sets the netlist and the SPICE profile to be used */ - void set_netlist (db::Netlist *netlist); + void set_netlist (db::Netlist *netlist, const std::string &profile); /** * @brief Applies SI and geometry scaling to the device parameters @@ -189,6 +214,8 @@ public: private: db::Netlist *mp_netlist; NetlistSpiceReaderOptions m_options; + std::string m_profile; + bool m_read_all_parameters; std::map, const db::DeviceClass *> m_spice_profiles; void def_values_per_element (const std::string &element, std::map &pv); diff --git a/src/db/db/dbNetlistSpiceWriter.cc b/src/db/db/dbNetlistSpiceWriter.cc index d724af789..947a452cf 100644 --- a/src/db/db/dbNetlistSpiceWriter.cc +++ b/src/db/db/dbNetlistSpiceWriter.cc @@ -35,13 +35,16 @@ namespace db { -static const char *allowed_name_chars = "_.:,!+$/&\\#[]<>"; -static const char *not_connect_prefix = "nc_"; +// default allowed name characters +static const char *s_allowed_name_chars = "_.:,!+$/&\\#[]<>"; + +// default prefix for "not connected" terminals +static const char *s_not_connect_prefix = "nc_"; // -------------------------------------------------------------------------------- NetlistSpiceWriterDelegate::NetlistSpiceWriterDelegate () - : mp_writer (0) + : mp_writer (0), mp_netlist (0), m_write_all_parameters (true) { // .. nothing yet .. } @@ -75,9 +78,10 @@ void NetlistSpiceWriterDelegate::emit_comment (const std::string &comment) const mp_writer->emit_comment (comment); } -void NetlistSpiceWriterDelegate::attach_writer (NetlistSpiceWriter *writer) +void NetlistSpiceWriterDelegate::attach_writer (NetlistSpiceWriter *writer, const db::Netlist *netlist) { mp_writer = writer; + mp_netlist = netlist; } void NetlistSpiceWriterDelegate::write_header () const @@ -93,6 +97,36 @@ void NetlistSpiceWriterDelegate::write_device_intro (const db::DeviceClass &) co void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const { const db::DeviceClass *dc = dev.device_class (); + + const db::DeviceClass::SpiceProfile &profile = dc->spice_profile (mp_writer->profile ()); + if (! profile.element.empty ()) { + write_device_profile (dev, profile); + } else { + write_device_default (dev); + } +} + +void NetlistSpiceWriterDelegate::write_device_profile (const db::Device &dev, const db::DeviceClass::SpiceProfile &profile) const +{ + std::ostringstream os; + + os << profile.element; + os << format_name (dev.expanded_name ()); + os << format_terminals_with_order (dev, profile.terminal_order); + os << " "; + if (! dev.device_class ()->name ().empty ()) { + os << " "; + os << format_name (dev.device_class ()->name ()); + } + os << format_params (dev); + + emit_line (os.str ()); +} + +void NetlistSpiceWriterDelegate::write_device_default (const db::Device &dev) const +{ + const db::DeviceClass *dc = dev.device_class (); + const db::DeviceClassCapacitor *cap = dynamic_cast (dc); const db::DeviceClassCapacitor *cap3 = dynamic_cast (dc); const db::DeviceClassInductor *ind = dynamic_cast (dc); @@ -117,7 +151,8 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const os << " "; os << format_name (dev.device_class ()->name ()); } - os << format_params (dev, db::DeviceClassCapacitor::param_id_C, true); + + os << format_params (dev, db::DeviceClassCapacitor::param_id_C); } else if (ind) { @@ -130,7 +165,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const os << " "; os << format_name (dev.device_class ()->name ()); } - os << format_params (dev, db::DeviceClassInductor::param_id_L, true); + os << format_params (dev, db::DeviceClassInductor::param_id_L); } else if (res || res3) { @@ -143,7 +178,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const os << " "; os << format_name (dev.device_class ()->name ()); } - os << format_params (dev, db::DeviceClassResistor::param_id_R, true); + os << format_params (dev, db::DeviceClassResistor::param_id_R); } else if (diode) { @@ -168,7 +203,7 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const os << net_to_string (dev.net_for_terminal (db::DeviceClassMOS3Transistor::terminal_id_G)); os << " "; os << net_to_string (dev.net_for_terminal (db::DeviceClassMOS3Transistor::terminal_id_S)); - os << " "; + os << " "; if (! mos4) { // we assume for the MOS3 type the bulk is connected to Source @@ -221,10 +256,25 @@ std::string NetlistSpiceWriterDelegate::format_terminals (const db::Device &dev, return os.str (); } -std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, size_t without_id, bool only_primary) const +std::string NetlistSpiceWriterDelegate::format_terminals_with_order (const db::Device &dev, const std::vector &terminal_order) const { std::ostringstream os; + for (auto t = terminal_order.begin (); t != terminal_order.end (); ++t) { + if (! dev.device_class ()->has_terminal_with_name (*t)) { + throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid terminal name '%s' for device of class '%s' in SPICE profile '%s")), *t, dev.device_class ()->name (), mp_writer->profile ())); + } + os << " " << net_to_string (dev.net_for_terminal (dev.device_class ()->terminal_id_for_name (*t))); + } + + return os.str (); +} + +std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, size_t without_id) const +{ + bool only_primary = ! m_write_all_parameters; + std::ostringstream os; + const std::vector &pd = dev.device_class ()->parameter_definitions (); for (std::vector::const_iterator i = pd.begin (); i != pd.end (); ++i) { @@ -263,6 +313,9 @@ std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, si NetlistSpiceWriter::NetlistSpiceWriter (NetlistSpiceWriterDelegate *delegate) : mp_netlist (0), mp_stream (0), mp_delegate (delegate), m_next_net_id (0), m_use_net_names (false), m_with_comments (true) { + m_allowed_name_chars = s_allowed_name_chars; + m_not_connect_prefix = s_not_connect_prefix; + static NetlistSpiceWriterDelegate std_delegate; if (! delegate) { mp_delegate.reset (&std_delegate); @@ -274,6 +327,21 @@ NetlistSpiceWriter::~NetlistSpiceWriter () // .. nothing yet .. } +void NetlistSpiceWriter::set_profile (const std::string &profile) +{ + m_profile = profile; +} + +void NetlistSpiceWriter::set_allowed_name_chars (const std::string &a) +{ + m_allowed_name_chars = a; +} + +void NetlistSpiceWriter::set_not_connect_prefix (const std::string &p) +{ + m_not_connect_prefix = p; +} + void NetlistSpiceWriter::set_use_net_names (bool use_net_names) { m_use_net_names = use_net_names; @@ -290,7 +358,7 @@ void NetlistSpiceWriter::write (tl::OutputStream &stream, const db::Netlist &net mp_stream = &stream; mp_netlist = &netlist; - mp_delegate->attach_writer (this); + mp_delegate->attach_writer (this, &netlist); try { @@ -298,13 +366,13 @@ void NetlistSpiceWriter::write (tl::OutputStream &stream, const db::Netlist &net mp_stream = 0; mp_netlist = 0; - mp_delegate->attach_writer (0); + mp_delegate->attach_writer (0, 0); } catch (...) { mp_stream = 0; mp_netlist = 0; - mp_delegate->attach_writer (0); + mp_delegate->attach_writer (0, 0); throw; } @@ -316,7 +384,7 @@ std::string NetlistSpiceWriter::net_to_string (const db::Net *net) const if (! net) { - return std::string (not_connect_prefix) + tl::to_string (++m_next_net_id); + return std::string (m_not_connect_prefix) + tl::to_string (++m_next_net_id); } else { @@ -334,7 +402,7 @@ std::string NetlistSpiceWriter::net_to_string (const db::Net *net) const nn += "\\"; } for (const char *cp = n.c_str (); *cp; ++cp) { - if (! isalnum (*cp) && strchr (allowed_name_chars, *cp) == 0) { + if (! isalnum (*cp) && strchr (m_allowed_name_chars.c_str (), *cp) == 0) { nn += tl::sprintf ("\\x%02x", (unsigned char) *cp); } else if (*cp == ',') { nn += "|"; @@ -459,10 +527,10 @@ void NetlistSpiceWriter::do_write (const std::string &description) // determine the next net id for non-connected nets such that there is no clash with // existing names - size_t prefix_len = strlen (not_connect_prefix); + size_t prefix_len = m_not_connect_prefix.size (); for (std::set::const_iterator n = names.begin (); n != names.end (); ++n) { - if (n->find (not_connect_prefix) == 0 && n->size () > prefix_len) { + if (n->find (m_not_connect_prefix) == 0 && n->size () > prefix_len) { size_t num = 0; tl::from_string (n->c_str () + prefix_len, num); m_next_net_id = std::max (m_next_net_id, num); diff --git a/src/db/db/dbNetlistSpiceWriter.h b/src/db/db/dbNetlistSpiceWriter.h index a30614743..1577a9a18 100644 --- a/src/db/db/dbNetlistSpiceWriter.h +++ b/src/db/db/dbNetlistSpiceWriter.h @@ -25,6 +25,7 @@ #include "dbCommon.h" #include "dbNetlistWriter.h" +#include "dbDeviceClass.h" #include "tlObject.h" #include @@ -34,7 +35,6 @@ namespace db { -class DeviceClass; class Device; class Net; class NetlistSpiceWriter; @@ -54,6 +54,9 @@ public: NetlistSpiceWriterDelegate (); virtual ~NetlistSpiceWriterDelegate (); + bool write_all_parameters () const { return m_write_all_parameters; } + void set_write_all_parameters (bool f) { m_write_all_parameters = f; } + virtual void write_header () const; virtual void write_device_intro (const db::DeviceClass &cls) const; virtual void write_device (const db::Device &dev) const; @@ -63,14 +66,19 @@ public: void emit_comment (const std::string &comment) const; std::string format_name (const std::string &s) const; std::string format_terminals (const db::Device &dev, size_t max_terminals = std::numeric_limits::max ()) const; - std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits::max (), bool only_primary = false) const; + std::string format_terminals_with_order (const db::Device &dev, const std::vector &terminal_order) const; + std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits::max ()) const; private: friend class NetlistSpiceWriter; NetlistSpiceWriter *mp_writer; + const Netlist *mp_netlist; + bool m_write_all_parameters; - void attach_writer (NetlistSpiceWriter *writer); + void attach_writer (NetlistSpiceWriter *writer, const Netlist *netlist); + void write_device_default (const db::Device &dev) const; + void write_device_profile (const db::Device &dev, const db::DeviceClass::SpiceProfile &profile) const; }; /** @@ -87,13 +95,69 @@ public: virtual void write (tl::OutputStream &stream, const db::Netlist &netlist, const std::string &description); + /** + * @brief Sets the SPICE profile name + */ + void set_profile (const std::string &profile); + + /** + * @brief Gets the SPICE profile name + * + * The SPICE profile name is used to collect SPICE reader settings from the + * device classes. + */ + const std::string &profile () const + { + return m_profile; + } + + /** + * @brief Sets a string listing the allowed characters in names (beside alphanumeric) + */ + void set_allowed_name_chars (const std::string &a); + + /** + * @brief Gets a string listing the allowed characters in names + */ + const std::string &allowed_name_chars () const + { + return m_allowed_name_chars; + } + + /** + * @brief Sets the prefix for "not connected" nets + */ + void set_not_connect_prefix (const std::string &p); + + /** + * @brief Gets the prefix for "not connected" nets + */ + const std::string ¬_connect_prefix () const + { + return m_not_connect_prefix; + } + + /** + * @brief Sets a value indicating whether to use net names + */ void set_use_net_names (bool use_net_names); + + /** + * @brief Gets a value indicating whether to use net names + */ bool use_net_names () const { return m_use_net_names; } + /** + * @brief Sets a value indicating whether to use comments + */ void set_with_comments (bool f); + + /** + * @brief Gets a value indicating whether to use comments + */ bool with_comments () const { return m_with_comments; @@ -110,6 +174,10 @@ private: mutable size_t m_next_net_id; bool m_use_net_names; bool m_with_comments; + std::string m_profile; + std::string m_allowed_name_chars; + std::string m_not_connect_prefix; + void do_write (const std::string &description); diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 9b7316cd0..556686e51 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -2437,14 +2437,18 @@ private: } -db::NetlistSpiceWriter *new_spice_writer () +db::NetlistSpiceWriter *new_spice_writer (const std::string &profile) { - return new db::NetlistSpiceWriter (); + auto *writer = new db::NetlistSpiceWriter (); + writer->set_profile (profile); + return writer; } -db::NetlistSpiceWriter *new_spice_writer2 (NetlistSpiceWriterDelegateImpl *delegate) +db::NetlistSpiceWriter *new_spice_writer2 (NetlistSpiceWriterDelegateImpl *delegate, const std::string &profile) { - return new NetlistSpiceWriterWithOwnership (delegate); + auto *writer = new NetlistSpiceWriterWithOwnership (delegate); + writer->set_profile (profile); + return writer; } Class db_NetlistWriter ("db", "NetlistWriter", @@ -2456,11 +2460,45 @@ Class db_NetlistWriter ("db", "NetlistWriter", ); Class db_NetlistSpiceWriter (db_NetlistWriter, "db", "NetlistSpiceWriter", - gsi::constructor ("new", &new_spice_writer, + gsi::constructor ("new", &new_spice_writer, gsi::arg ("profile", std::string ()), "@brief Creates a new writer without delegate.\n" + "The profile string gives the name of the SPICE profile to use, when taking the SPICE representation " + "from the device classes in the netlist.\n" + "\n" + "The profile argument has been added in version 0.31.0." ) + - gsi::constructor ("new", &new_spice_writer2, gsi::arg ("delegate"), + gsi::constructor ("new", &new_spice_writer2, gsi::arg ("delegate"), gsi::arg ("profile", std::string ()), "@brief Creates a new writer with a delegate.\n" + "The profile string gives the name of the SPICE profile to use, when taking the SPICE representation " + "from the device classes in the netlist.\n" + "\n" + "The profile argument has been added in version 0.31.0." + ) + + gsi::method ("not_connect_prefix", &db::NetlistSpiceWriter::not_connect_prefix, + "@brief Gets the prefix used for terminals or pins which are not connected.\n" + "See \\not_connect_prefix= for details.\n" + "\n" + "This attribute has been introduced in version 0.31.0." + ) + + gsi::method ("not_connect_prefix=", &db::NetlistSpiceWriter::set_not_connect_prefix, gsi::arg ("s"), + "@brief Sets the prefix used for terminals or pins which are not connected.\n" + "By default, the prefix is 'nc_'." + "\n" + "This attribute has been introduced in version 0.31.0." + ) + + gsi::method ("allowed_name_characters", &db::NetlistSpiceWriter::allowed_name_chars, + "@brief Gets a string listing the allowed characters for names (beside alphanumeric).\n" + "See \\allowed_name_characters= for details.\n" + "\n" + "This attribute has been introduced in version 0.31.0." + ) + + gsi::method ("allowed_name_characters=", &db::NetlistSpiceWriter::set_allowed_name_chars, gsi::arg ("s"), + "@brief Sets a string listing the allowed characters for names (beside alphanumeric).\n" + "\n" + "This attribute has been introduced in version 0.31.0." + ) + + gsi::method ("use_net_names?", &db::NetlistSpiceWriter::use_net_names, + "@brief Gets a value indicating whether to use net names (true) or net numbers (false).\n" ) + gsi::method ("use_net_names=", &db::NetlistSpiceWriter::set_use_net_names, gsi::arg ("f"), "@brief Sets a value indicating whether to use net names (true) or net numbers (false).\n" @@ -2537,7 +2575,8 @@ Class db_NetlistSpiceWriter (db_NetlistWriter, "db", "Ne "netlist.write(path, writer)\n" "@/code\n" "\n" - "This class has been introduced in version 0.26." + "This class has been introduced in version 0.26. " + "SPICE profiles have been added to device classes in version 0.31.0." ); Class db_NetlistReader ("db", "NetlistReader", @@ -3041,7 +3080,7 @@ Class db_NetlistSpiceReaderDelegate ("db", "Netl "\n" "See \\NetlistSpiceReader for more details.\n" "\n" - "This class has been introduced in version 0.26." + "This class has been introduced in version 0.26. Profiles have been added to the device classes in version 0.31.0." ); namespace { @@ -3064,22 +3103,65 @@ private: } -db::NetlistSpiceReader *new_spice_reader () +db::NetlistSpiceReader *new_spice_reader (const std::string &profile) { - return new db::NetlistSpiceReader (); + auto *reader = new db::NetlistSpiceReader (); + reader->set_profile (profile); + return reader; } -db::NetlistSpiceReader *new_spice_reader2 (NetlistSpiceReaderDelegateImpl *delegate) +db::NetlistSpiceReader *new_spice_reader2 (NetlistSpiceReaderDelegateImpl *delegate, const std::string &profile) { - return new NetlistSpiceReaderWithOwnership (delegate); + auto *reader = new NetlistSpiceReaderWithOwnership (delegate); + reader->set_profile (profile); + return reader; } +static bool read_all_parameters (const db::NetlistSpiceReader *reader) +{ + return reader->delegate () ? reader->delegate ()->read_all_parameters () : false; +} + +static void set_read_all_parameters (db::NetlistSpiceReader *reader, bool f) +{ + if (reader->delegate ()) { + reader->delegate ()->set_read_all_parameters (f); + } +} + + Class db_NetlistSpiceReader (db_NetlistReader, "db", "NetlistSpiceReader", - gsi::constructor ("new", &new_spice_reader, + gsi::constructor ("new", &new_spice_reader, gsi::arg ("profile", std::string ()), "@brief Creates a new reader.\n" + "The profile string defines the SPICE profile to use for picking default SPICE mappings from the " + "device classes declared in the netlist to read.\n" + "\n" + "The profile string argument has been added in version 0.31.0." ) + - gsi::constructor ("new", &new_spice_reader2, gsi::arg ("delegate"), + gsi::constructor ("new", &new_spice_reader2, gsi::arg ("delegate"), gsi::arg ("profile", std::string ()), "@brief Creates a new reader with a delegate.\n" + "The profile string defines the SPICE profile to use for picking default SPICE mappings from the " + "device classes declared in the netlist to read.\n" + "\n" + "The profile string argument has been added in version 0.31.0." + ) + + gsi::method_ext ("read_all_parameters", &read_all_parameters, + "@brief Gets a flag indicating whether all parameters shall be read\n" + "\n" + "With this flag set to false, only those parameters which\n" + "are declared in the device classes of the netlist are read.\n" + "If set to true (the default), additional parameters are added to the device classes\n" + "and their values are stored in the device objects.\n" + "Note that this behavior can be changed in reimplementations of the\n" + "SPICE reader delegate class.\n" + "\n" + "This attribute has been introduced in version 0.31.0." + ) + + gsi::method_ext ("read_all_parameters=", &set_read_all_parameters, gsi::arg ("f"), + "@brief Sets a flag indicating whether all parameters shall be read\n" + "See \\read_all_parameters for details.\n" + "\n" + "This attribute has been introduced in version 0.31.0." ), "@brief Implements a netlist Reader for the SPICE format.\n" "Use the SPICE reader like this:\n" @@ -3090,8 +3172,9 @@ Class db_NetlistSpiceReader (db_NetlistReader, "db", "Ne "netlist.read(path, reader)\n" "@/code\n" "\n" - "The translation of SPICE elements can be tailored by providing a \\NetlistSpiceReaderDelegate class. " - "This allows translating of device parameters and mapping of some subcircuits to devices.\n" + "The translation of SPICE elements can be tailored by providing a \\NetlistSpiceReaderDelegate class or by " + "supplying device classes in the netlist that declare their SPICe representation in a SPICE profile.\n" + // @@@ TODO: example for profiles in device classes "\n" "The following example is a delegate that turns subcircuits called HVNMOS and HVPMOS into " "MOS4 devices with the parameters scaled by 1.5:\n" @@ -3162,7 +3245,8 @@ Class db_NetlistSpiceReader (db_NetlistReader, "db", "Ne "end\n" "@/code\n" "\n" - "This class has been introduced in version 0.26. It has been extended in version 0.27.1." + "This class has been introduced in version 0.26. It has been extended in version 0.27.1. " + "Profiles have been added to the device classes in version 0.31.0." ); }