This commit is contained in:
Matthias Koefferlein 2026-05-23 19:30:37 +02:00
parent 1d150441b6
commit 2e91220e8c
7 changed files with 361 additions and 63 deletions

View File

@ -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;
}
}

View File

@ -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<NetlistSpiceReaderDelegate> mp_delegate;
std::unique_ptr<NetlistSpiceReaderDelegate> mp_default_delegate;
bool m_strict;
std::string m_profile;
};
}

View File

@ -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<std::string> &to = dp->second->spice_profile (m_options.profile).terminal_order;
const std::vector<std::string> &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 ()) {

View File

@ -44,19 +44,26 @@ struct DB_PUBLIC NetlistSpiceReaderOptions
{
NetlistSpiceReaderOptions ();
std::string profile; // @@@ GSI binding
double scale;
std::map<std::string, std::map<std::string, double> > 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<std::pair<std::string, std::string>, const db::DeviceClass *> m_spice_profiles;
void def_values_per_element (const std::string &element, std::map<std::string, tl::Variant> &pv);

View File

@ -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<const db::DeviceClassCapacitor *> (dc);
const db::DeviceClassCapacitor *cap3 = dynamic_cast<const db::DeviceClassCapacitorWithBulk *> (dc);
const db::DeviceClassInductor *ind = dynamic_cast<const db::DeviceClassInductor *> (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<std::string> &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<db::DeviceParameterDefinition> &pd = dev.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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<std::string>::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);

View File

@ -25,6 +25,7 @@
#include "dbCommon.h"
#include "dbNetlistWriter.h"
#include "dbDeviceClass.h"
#include "tlObject.h"
#include <string>
@ -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<size_t>::max ()) const;
std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits<size_t>::max (), bool only_primary = false) const;
std::string format_terminals_with_order (const db::Device &dev, const std::vector<std::string> &terminal_order) const;
std::string format_params (const db::Device &dev, size_t without_id = std::numeric_limits<size_t>::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 &not_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);

View File

@ -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 ("db", "NetlistWriter",
@ -2456,11 +2460,45 @@ Class<db::NetlistWriter> db_NetlistWriter ("db", "NetlistWriter",
);
Class<db::NetlistSpiceWriter> 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_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 ("db", "NetlistReader",
@ -3041,7 +3080,7 @@ Class<NetlistSpiceReaderDelegateImpl> 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_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_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_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."
);
}