mirror of https://github.com/KLayout/klayout.git
WIP
This commit is contained in:
parent
3ef0d593b1
commit
1d150441b6
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<std::string> 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<DeviceTerminalDefinition> m_terminal_definitions;
|
||||
std::vector<DeviceParameterDefinition> m_parameter_definitions;
|
||||
std::map<std::string, SpiceProfile> m_spice_profiles;
|
||||
bool m_strict;
|
||||
db::Netlist *mp_netlist;
|
||||
tl::shared_ptr<db::DeviceParameterCompareDelegate> mp_pc_delegate;
|
||||
|
|
|
|||
|
|
@ -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<std::string> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<std::string, tl::Variant> &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<std::string> &nn, std::map<std::string, tl::Variant> &pv, const std::map<std::string, tl::Variant> &variables)
|
||||
void NetlistSpiceReaderDelegate::parse_element (const std::string &s, std::string &element, std::string &model, double &value, std::vector<std::string> &nn, std::map<std::string, tl::Variant> &pv, const std::map<std::string, tl::Variant> &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<std::string> &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<std::string> nn_ordered;
|
||||
|
||||
const std::vector<db::DeviceTerminalDefinition> &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<db::Net *> &nets, const std::map<std::string, tl::Variant> &pv)
|
||||
double NetlistSpiceReaderDelegate::get_multiplier (const std::map<std::string, tl::Variant> ¶ms)
|
||||
{
|
||||
std::map<std::string, tl::Variant> params = pv;
|
||||
std::vector<size_t> 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<db::Net *> &nets, const std::map<std::string, tl::Variant> &pv)
|
||||
{
|
||||
std::map<std::string, tl::Variant> params = pv;
|
||||
std::vector<size_t> 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<db::DeviceTerminalDefinition> &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<db::DeviceParameterDefinition> &pd = cls->parameter_definitions_non_const ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::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<db::DeviceParameterDefinition> &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 ()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,10 @@ struct DB_PUBLIC NetlistSpiceReaderOptions
|
|||
{
|
||||
NetlistSpiceReaderOptions ();
|
||||
|
||||
std::string profile; // @@@ GSI binding
|
||||
double scale;
|
||||
double defad, defas, defw, defl;
|
||||
std::map<std::string, std::map<std::string, double> > 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<std::string> &nn, std::map<std::string, tl::Variant> &pv, const std::map<std::string, tl::Variant> ¶ms);
|
||||
virtual void parse_element (const std::string &s, std::string &element, std::string &model, double &value, std::vector<std::string> &nn, std::map<std::string, tl::Variant> &pv, const std::map<std::string, tl::Variant> ¶ms);
|
||||
|
||||
/**
|
||||
* @brief Produces an error with the given message
|
||||
|
|
@ -187,8 +189,10 @@ public:
|
|||
private:
|
||||
db::Netlist *mp_netlist;
|
||||
NetlistSpiceReaderOptions m_options;
|
||||
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);
|
||||
double get_multiplier (const std::map<std::string, tl::Variant> &pv);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -442,10 +442,17 @@ Class<db::Device> 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<db::DeviceParameterDefinition> 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<db::DeviceParameterDefinition> 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<std::string> 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<std::string> &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<std::string> &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<ParseElementData> 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"
|
||||
) +
|
||||
|
|
|
|||
Loading…
Reference in New Issue