mirror of https://github.com/KLayout/klayout.git
WIP
This commit is contained in:
parent
1d150441b6
commit
2e91220e8c
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ¬_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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue