This commit is contained in:
Matthias Koefferlein 2026-05-21 00:05:57 +02:00
parent 6e19b34cb3
commit 19ded2d784
17 changed files with 356 additions and 125 deletions

View File

@ -163,7 +163,7 @@ void Device::connect_terminal (size_t terminal_id, Net *net)
}
}
double Device::parameter_value (size_t param_id) const
const tl::Variant &Device::parameter_value (size_t param_id) const
{
if (m_parameters.size () > param_id) {
return m_parameters [param_id];
@ -173,10 +173,11 @@ double Device::parameter_value (size_t param_id) const
return pd->default_value ();
}
}
return 0.0;
static tl::Variant dummy_value (0.0);
return dummy_value;
}
void Device::set_parameter_value (size_t param_id, double v)
void Device::set_parameter_value (size_t param_id, const tl::Variant &v)
{
if (m_parameters.size () <= param_id) {
@ -198,18 +199,26 @@ void Device::set_parameter_value (size_t param_id, double v)
m_parameters [param_id] = v;
}
double Device::parameter_value (const std::string &name) const
const tl::Variant &Device::parameter_value (const std::string &name) const
{
return device_class () ? parameter_value (device_class ()->parameter_id_for_name (name)) : 0.0;
static tl::Variant dummy_value (0.0);
return device_class () ? parameter_value (device_class ()->parameter_id_for_name (name)) : dummy_value;
}
void Device::set_parameter_value (const std::string &name, double v)
void Device::set_parameter_value (const std::string &name, const tl::Variant &v)
{
if (device_class ()) {
set_parameter_value (device_class ()->parameter_id_for_name (name), v);
}
}
void Device::set_parameter_value_create (const std::string &name, const tl::Variant &v, bool primary, const tl::Variant &def_value)
{
if (device_class ()) {
set_parameter_value (device_class ()->parameter_id_for_name_create (name, primary, def_value), v);
}
}
void Device::add_others_terminals (unsigned int this_terminal, db::Device *other, unsigned int other_terminal)
{
std::vector<DeviceReconnectedTerminal> &terminals = m_reconnected_terminals [this_terminal];

View File

@ -283,24 +283,33 @@ public:
/**
* @brief Gets the value for the parameter with the given ID
*/
double parameter_value (size_t param_id) const;
const tl::Variant &parameter_value (size_t param_id) const;
/**
* @brief Sets the value for the parameter with the given ID
*/
void set_parameter_value (size_t param_id, double v);
void set_parameter_value (size_t param_id, const tl::Variant &v);
/**
* @brief Gets the value for the parameter with the given name
* If the name is not valid, an exception is thrown.
*/
double parameter_value (const std::string &name) const;
const tl::Variant &parameter_value (const std::string &name) const;
/**
* @brief Sets the value for the parameter with the given name
* If the name is not valid, an exception is thrown.
*/
void set_parameter_value (const std::string &name, double v);
void set_parameter_value (const std::string &name, const tl::Variant &v);
/**
* @brief Sets the value for the parameter with the given name
*
* If the name is not valid, the parameter is created with the given primary
* flag and default value. The default value also defines the type of the
* parameter.
*/
void set_parameter_value_create (const std::string &name, const tl::Variant &v, bool primary, const tl::Variant &def_value);
/**
* @brief Used for device combination: join terminals with other device
@ -402,7 +411,7 @@ private:
std::string m_name;
db::DCplxTrans m_trans;
std::vector<Net::terminal_iterator> m_terminal_refs;
std::vector<double> m_parameters;
std::vector<tl::Variant> m_parameters;
size_t m_id;
Circuit *mp_circuit;
std::vector<DeviceAbstractRef> m_other_abstracts;

View File

@ -121,9 +121,17 @@ std::string EqualDeviceParameters::to_string () const
bool EqualDeviceParameters::less (const db::Device &a, const db::Device &b) const
{
for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = m_compare_set.begin (); c != m_compare_set.end (); ++c) {
int cmp = compare_parameters (a.parameter_value (c->first), b.parameter_value (c->first), c->second.first, c->second.second);
if (cmp != 0) {
return cmp < 0;
const tl::Variant &va = a.parameter_value (c->first);
const tl::Variant &vb = b.parameter_value (c->first);
if (va.is_double () && vb.is_double ()) {
int cmp = compare_parameters (va.to_double (), vb.to_double (), c->second.first, c->second.second);
if (cmp != 0) {
return cmp < 0;
}
} else {
if (va != vb) {
return va < vb;
}
}
}
@ -137,9 +145,17 @@ bool EqualDeviceParameters::less (const db::Device &a, const db::Device &b) cons
const std::vector<db::DeviceParameterDefinition> &pd = primary_device_class (a, b)->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
if (p->is_primary () && seen.find (p->id ()) == seen.end ()) {
int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()));
if (cmp != 0) {
return cmp < 0;
const tl::Variant &va = a.parameter_value (p->id ());
const tl::Variant &vb = b.parameter_value (p->id ());
if (va.is_double () && vb.is_double ()) {
int cmp = compare_parameters (va.to_double (), vb.to_double ());
if (cmp != 0) {
return cmp < 0;
}
} else {
if (va != vb) {
return va < vb;
}
}
}
}
@ -168,9 +184,17 @@ bool AllDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b
{
const std::vector<db::DeviceParameterDefinition> &parameters = a.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator c = parameters.begin (); c != parameters.end (); ++c) {
int cmp = compare_parameters (a.parameter_value (c->id ()), b.parameter_value (c->id ()), 0.0, m_relative);
if (cmp != 0) {
return cmp < 0;
const tl::Variant &va = a.parameter_value (c->id ());
const tl::Variant &vb = b.parameter_value (c->id ());
if (va.is_double () && vb.is_double ()) {
int cmp = compare_parameters (va.to_double (), vb.to_double (), 0.0, m_relative);
if (cmp != 0) {
return cmp < 0;
}
} else {
if (va != vb) {
return va < vb;
}
}
}

View File

@ -154,7 +154,7 @@ public:
/**
* @brief Creates a device parameter definition with the given name and description
*/
DeviceParameterDefinition (const std::string &name, const std::string &description, double default_value = 0.0, bool is_primary = true, double si_scaling = 1.0, double geo_scaling = 0.0)
DeviceParameterDefinition (const std::string &name, const std::string &description, tl::Variant default_value = tl::Variant (0.0), bool is_primary = true, double si_scaling = 1.0, double geo_scaling = 0.0)
: m_name (name), m_description (description), m_default_value (default_value), m_id (0), m_is_primary (is_primary), m_si_scaling (si_scaling), m_geo_scaling (geo_scaling)
{
// .. nothing yet ..
@ -234,7 +234,7 @@ public:
/**
* @brief Gets the parameter default value
*/
double default_value () const
const tl::Variant &default_value () const
{
return m_default_value;
}
@ -242,7 +242,7 @@ public:
/**
* @brief Sets the parameter default value
*/
void set_default_value (double d)
void set_default_value (const tl::Variant &d)
{
m_default_value = d;
}
@ -291,7 +291,7 @@ private:
friend class DeviceClass;
std::string m_name, m_description;
double m_default_value;
tl::Variant m_default_value;
size_t m_id;
bool m_is_primary;
double m_si_scaling;
@ -578,6 +578,19 @@ public:
*/
size_t parameter_id_for_name (const std::string &name) const;
/**
* @brief Returns the parameter ID for the parameter with the given name
*
* A new parameter definition is created, if the parameter does not exist yes.
*
* @param name The name of the parameter
* @param primary The primary flag of the new parameter, if it does not exist yet
* @param default_value The default value of the new parameter, if it does not exist yet
*
* The default value also declares the type.
*/
size_t parameter_id_for_name_create (const std::string &name, bool primary, const tl::Variant &default_value) const;
/**
* @brief Returns true, if the device has a terminal with the given name
*/

View File

@ -53,6 +53,10 @@ namespace l2n_std_format
DB_PUBLIC std::string LongKeys::terminal_key ("terminal");
DB_PUBLIC std::string LongKeys::abstract_key ("abstract");
DB_PUBLIC std::string LongKeys::param_key ("param");
DB_PUBLIC std::string LongKeys::param_int_key ("param-int");
DB_PUBLIC std::string LongKeys::param_string_key ("param-string");
DB_PUBLIC std::string LongKeys::param_var_key ("param-var");
DB_PUBLIC std::string LongKeys::param_nil_key ("param-nil");
DB_PUBLIC std::string LongKeys::location_key ("location");
DB_PUBLIC std::string LongKeys::rotation_key ("rotation");
DB_PUBLIC std::string LongKeys::mirror_key ("mirror");
@ -88,6 +92,10 @@ namespace l2n_std_format
DB_PUBLIC std::string ShortKeys::terminal_key ("T");
DB_PUBLIC std::string ShortKeys::abstract_key ("A");
DB_PUBLIC std::string ShortKeys::param_key ("E");
DB_PUBLIC std::string ShortKeys::param_int_key ("EI");
DB_PUBLIC std::string ShortKeys::param_string_key ("ES");
DB_PUBLIC std::string ShortKeys::param_var_key ("EV");
DB_PUBLIC std::string ShortKeys::param_nil_key ("EN");
DB_PUBLIC std::string ShortKeys::location_key ("Y");
DB_PUBLIC std::string ShortKeys::rotation_key ("O");
DB_PUBLIC std::string ShortKeys::mirror_key ("M");

View File

@ -163,6 +163,15 @@ namespace db
* [template-param]:
* param(<name> <primary> <default-value>) - defines a template parameter [short key: E]
* ('primary' is a value: 0 or 1, 'default_value' is a float)
* param-int(<name> <primary> <default-value>) - defines a template parameter [short key: EI]
* ('primary' is a value: 0 or 1, 'default_value' is an int)
* param-string(<name> <primary> <default-value>) - defines a template parameter [short key: ES]
* ('primary' is a value: 0 or 1, 'default_value' is a string)
* param-var(<name> <primary> <default-value>) - defines a template parameter [short key: EV]
* ('primary' is a value: 0 or 1, 'default_value' is a string encoding the default
* value in KLayout variant notation)
* param-nil(<name> <primary>) - defines a template parameter [short key: EN]
* ('primary' is a value: 0 or 1)
*
* [template-terminal]:
* terminal(<name>) - defines a terminal [short key: T]
@ -172,7 +181,11 @@ namespace db
* - specifies the terminal geometry [short key: T]
*
* [param]:
* param(<name> <value>) - defines a parameter [short key: E]
* param(<name> <value>) - defines a parameter with a default value [short key: E]
* param-int(<name> <value>) - defines a parameter with an int value [short key: EI]
* param-nil(<name>) - defines a parameter with a nil value [short key: EN]
* param-string(<name> <value>) - defines a parameter with a string value [short key: ES]
* param-var(<name> <value>) - defines a parameter with a variant value [short key: EV]
*
* [device-terminal]:
* terminal(<terminal-name> <net-id>)
@ -246,6 +259,10 @@ namespace l2n_std_format
static std::string terminal_key;
static std::string abstract_key;
static std::string param_key;
static std::string param_int_key;
static std::string param_string_key;
static std::string param_var_key;
static std::string param_nil_key;
static std::string location_key;
static std::string rotation_key;
static std::string mirror_key;
@ -287,6 +304,10 @@ namespace l2n_std_format
static std::string terminal_key;
static std::string abstract_key;
static std::string param_key;
static std::string param_int_key;
static std::string param_string_key;
static std::string param_var_key;
static std::string param_nil_key;
static std::string location_key;
static std::string rotation_key;
static std::string mirror_key;

View File

@ -104,6 +104,21 @@ LayoutToNetlistStandardReader::try_read_int (int &i)
return m_ex.try_read (i);
}
long
LayoutToNetlistStandardReader::read_long ()
{
long i = 0;
m_ex.read (i);
return i;
}
bool
LayoutToNetlistStandardReader::try_read_long (long &i)
{
i = 0;
return m_ex.try_read (i);
}
db::Coord
LayoutToNetlistStandardReader::read_coord ()
{
@ -322,6 +337,21 @@ static db::Region &layer_by_name (db::LayoutToNetlist *l2n, const std::string &n
return *l;
}
static void make_parameter (db::DeviceClass *dc, const std::string &param_name, bool primary, const tl::Variant &default_value)
{
if (! dc->has_parameter_with_name (param_name)) {
db::DeviceParameterDefinition pd;
pd.set_name (param_name);
pd.set_is_primary (primary);
pd.set_default_value (default_value);
dc->add_parameter_definition (pd);
} else {
db::DeviceParameterDefinition *pd = dc->parameter_definition_non_const (dc->parameter_id_for_name (param_name));
pd->set_default_value (default_value);
pd->set_is_primary (primary);
}
}
void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::LayoutToNetlist *l2n, LayoutToNetlistStandardReader::Brace *nested, std::map<const db::Circuit *, ObjectMap> *map_per_circuit)
{
m_dbu = 0.001;
@ -459,17 +489,62 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
read_word_or_quoted (param_name);
int primary = read_int ();
double default_value = read_double ();
if (! dc->has_parameter_with_name (param_name)) {
db::DeviceParameterDefinition pd;
pd.set_name (param_name);
pd.set_is_primary (primary);
pd.set_default_value (default_value);
dc->add_parameter_definition (pd);
} else {
db::DeviceParameterDefinition *pd = dc->parameter_definition_non_const (dc->parameter_id_for_name (param_name));
pd->set_default_value (default_value);
pd->set_is_primary (primary);
}
make_parameter (dc, param_name, primary, default_value);
br.done ();
} else if (test (skeys::param_int_key) || test (lkeys::param_int_key)) {
Brace br (this);
std::string param_name;
read_word_or_quoted (param_name);
int primary = read_int ();
int default_value = read_int ();
make_parameter (dc, param_name, primary, default_value);
br.done ();
} else if (test (skeys::param_string_key) || test (lkeys::param_string_key)) {
Brace br (this);
std::string param_name;
read_word_or_quoted (param_name);
int primary = read_int ();
std::string default_value;
read_word_or_quoted (default_value);
make_parameter (dc, param_name, primary, default_value);
br.done ();
} else if (test (skeys::param_var_key) || test (lkeys::param_var_key)) {
Brace br (this);
std::string param_name;
read_word_or_quoted (param_name);
int primary = read_int ();
std::string default_value_str;
read_word_or_quoted (default_value_str);
tl::Variant default_value;
tl::Extractor ex (default_value_str.c_str ());
ex.read (default_value);
make_parameter (dc, param_name, primary, default_value);
br.done ();
} else if (test (skeys::param_nil_key) || test (lkeys::param_nil_key)) {
Brace br (this);
std::string param_name;
read_word_or_quoted (param_name);
int primary = read_int ();
make_parameter (dc, param_name, primary, tl::Variant ());
br.done ();
@ -1052,24 +1127,58 @@ LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNe
double value = read_double ();
br2.done ();
size_t pid = std::numeric_limits<size_t>::max ();
const std::vector<db::DeviceParameterDefinition> &pd = dm.second->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
if (p->name () == pname) {
pid = p->id ();
break;
}
}
// if no parameter with this name exists, create one
if (pid == std::numeric_limits<size_t>::max ()) {
// TODO: this should only happen for generic devices
db::DeviceClass *dc = const_cast<db::DeviceClass *> (dm.second);
pid = dc->add_parameter_definition (db::DeviceParameterDefinition (pname, std::string ())).id ();
}
size_t pid = dm.second->parameter_id_for_name_create (pname, false, 0.0);
device->set_parameter_value (pid, value);
} else if (test (skeys::param_int_key) || test (lkeys::param_int_key)) {
Brace br2 (this);
std::string pname;
read_word_or_quoted (pname);
long value = read_long ();
br2.done ();
size_t pid = dm.second->parameter_id_for_name_create (pname, false, long (0));
device->set_parameter_value (pid, value);
} else if (test (skeys::param_string_key) || test (lkeys::param_string_key)) {
Brace br2 (this);
std::string pname;
read_word_or_quoted (pname);
std::string value;
read_word_or_quoted (value);
br2.done ();
size_t pid = dm.second->parameter_id_for_name_create (pname, false, std::string ());
device->set_parameter_value (pid, value);
} else if (test (skeys::param_var_key) || test (lkeys::param_var_key)) {
Brace br2 (this);
std::string pname;
read_word_or_quoted (pname);
std::string value_str;
read_word_or_quoted (value_str);
br2.done ();
tl::Variant value;
tl::Extractor ex (value_str.c_str ());
ex.read (value);
size_t pid = dm.second->parameter_id_for_name_create (pname, false, tl::Variant ());
device->set_parameter_value (pid, value);
} else if (test (skeys::param_nil_key) || test (lkeys::param_nil_key)) {
Brace br2 (this);
std::string pname;
read_word_or_quoted (pname);
br2.done ();
size_t pid = dm.second->parameter_id_for_name_create (pname, false, tl::Variant ());
device->set_parameter_value (pid, tl::Variant ());
} else if (at_end ()) {
throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside device definition (location, scale, mirror, rotation, param or terminal expected)")));
} else {

View File

@ -136,6 +136,8 @@ protected:
void read_word_or_quoted (std::string &s);
int read_int ();
bool try_read_int (int &i);
long read_long ();
bool try_read_long (long &i);
db::Coord read_coord ();
double read_double ();
bool at_end ();

View File

@ -324,7 +324,18 @@ void std_writer_impl<Keys>::write_device_class (TokenizedOutput &stream, const d
if (! any_def) {
out << endl;
}
TokenizedOutput (out, Keys::param_key) << tl::to_word_or_quoted_string (p->name ()) << tl::to_string (p->is_primary () ? 1 : 0) << tl::to_string (p->default_value ());
const tl::Variant &def = p->default_value ();
if (def.is_double ()) {
TokenizedOutput (out, Keys::param_key) << tl::to_word_or_quoted_string (p->name ()) << tl::to_string (p->is_primary () ? 1 : 0) << def.to_string ();
} else if (def.is_long () || def.is_ulong ()) {
TokenizedOutput (out, Keys::param_int_key) << tl::to_word_or_quoted_string (p->name ()) << tl::to_string (p->is_primary () ? 1 : 0) << def.to_string ();
} else if (def.is_a_string ()) {
TokenizedOutput (out, Keys::param_string_key) << tl::to_word_or_quoted_string (p->name ()) << tl::to_string (p->is_primary () ? 1 : 0) << tl::to_quoted_string (def.to_string ());
} else if (def.is_nil ()) {
TokenizedOutput (out, Keys::param_nil_key) << tl::to_word_or_quoted_string (p->name ()) << tl::to_string (p->is_primary () ? 1 : 0);
} else {
TokenizedOutput (out, Keys::param_var_key) << tl::to_word_or_quoted_string (p->name ()) << tl::to_string (p->is_primary () ? 1 : 0) << tl::to_quoted_string (def.to_parsable_string ());
}
any_def = true;
}
}
@ -906,7 +917,19 @@ void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::Device &de
}
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
TokenizedOutput (out, Keys::param_key) << tl::to_word_or_quoted_string (i->name ()) << tl::sprintf ("%.12g", device.parameter_value (i->id ()));
const tl::Variant &value = device.parameter_value (i->id ());
if (value.is_double ()) {
TokenizedOutput (out, Keys::param_key) << tl::to_word_or_quoted_string (i->name ()) << value.to_string ();
} else if (value.is_long () || value.is_ulong ()) {
TokenizedOutput (out, Keys::param_int_key) << tl::to_word_or_quoted_string (i->name ()) << value.to_string ();
} else if (value.is_a_string ()) {
TokenizedOutput (out, Keys::param_string_key) << tl::to_word_or_quoted_string (i->name ()) << tl::to_quoted_string (value.to_string ());
} else if (value.is_nil ()) {
TokenizedOutput (out, Keys::param_nil_key) << tl::to_word_or_quoted_string (i->name ());
} else {
TokenizedOutput (out, Keys::param_var_key) << tl::to_word_or_quoted_string (i->name ()) << tl::to_quoted_string (value.to_parsable_string ());
}
}
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {

View File

@ -326,11 +326,11 @@ DeviceFilter::filter (const db::Device *device) const
const db::DeviceClassCapacitor *cap = dynamic_cast<const db::DeviceClassCapacitor *> (device->device_class ());
if (res) {
if (m_res_threshold > 0.0 && device->parameter_value (db::DeviceClassResistor::param_id_R) > m_res_threshold) {
if (m_res_threshold > 0.0 && device->parameter_value (db::DeviceClassResistor::param_id_R).to_double () > m_res_threshold) {
return false;
}
} else if (cap) {
if (m_cap_threshold > 0.0 && device->parameter_value (db::DeviceClassCapacitor::param_id_C) < m_cap_threshold) {
if (m_cap_threshold > 0.0 && device->parameter_value (db::DeviceClassCapacitor::param_id_C).to_double () < m_cap_threshold) {
return false;
}
}

View File

@ -114,8 +114,8 @@ class ResistorDeviceCombiner
public:
void parallel (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
double va = a->parameter_value (0).to_double ();
double vb = b->parameter_value (0).to_double ();
a->set_parameter_value (0, va + vb < 1e-30 ? 0.0 : va * vb / (va + vb));
// parallel width is sum of both, length is the one that gives the same value of resistance
@ -124,10 +124,10 @@ public:
// R1 = L1/W1
// R2 = L2/W2
// -> L = (L1*L2*(W1+W2))/(L2*W1+L1*W2))
double l1 = a->parameter_value (1);
double w1 = a->parameter_value (2);
double l2 = b->parameter_value (1);
double w2 = b->parameter_value (2);
double l1 = a->parameter_value (1).to_double ();
double w1 = a->parameter_value (2).to_double ();
double l2 = b->parameter_value (1).to_double ();
double w2 = b->parameter_value (2).to_double ();
double dnom = (l2 * w1 + l1 * w2);
if (fabs (dnom) > 1e-15) {
a->set_parameter_value (1, (l1 * l2 * (w1 + w2)) / dnom);
@ -135,20 +135,20 @@ public:
a->set_parameter_value (2, w1 + w2);
// TODO: does this implementation make sense? (area)
double aa = a->parameter_value (3);
double ab = b->parameter_value (3);
double aa = a->parameter_value (3).to_double ();
double ab = b->parameter_value (3).to_double ();
a->set_parameter_value (3, aa + ab);
// TODO: does this implementation make sense? (perimeter)
double pa = a->parameter_value (4);
double pb = b->parameter_value (4);
double pa = a->parameter_value (4).to_double ();
double pb = b->parameter_value (4).to_double ();
a->set_parameter_value (4, pa + pb);
}
void serial (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
double va = a->parameter_value (0).to_double ();
double vb = b->parameter_value (0).to_double ();
a->set_parameter_value (0, va + vb);
// parallel length is sum of both, width is the one that gives the same value of resistance
@ -158,22 +158,22 @@ public:
// R1 = L1/W1
// R2 = L2/W2
// -> W = ((L1+L2)*W1*W2)/(W1*L2+W2*L1)
double l1 = a->parameter_value (1);
double w1 = a->parameter_value (2);
double l2 = b->parameter_value (1);
double w2 = b->parameter_value (2);
double l1 = a->parameter_value (1).to_double ();
double w1 = a->parameter_value (2).to_double ();
double l2 = b->parameter_value (1).to_double ();
double w2 = b->parameter_value (2).to_double ();
a->set_parameter_value (1, l1 + l2);
double dnom = (l2 * w1 + l1 * w2);
if (fabs (dnom) > 1e-15) {
a->set_parameter_value (2, (w1 * w2 * (l1 + l2)) / dnom);
}
double aa = a->parameter_value (3);
double ab = b->parameter_value (3);
double aa = a->parameter_value (3).to_double ();
double ab = b->parameter_value (3).to_double ();
a->set_parameter_value (3, aa + ab);
double pa = a->parameter_value (4);
double pb = b->parameter_value (4);
double pa = a->parameter_value (4).to_double ();
double pb = b->parameter_value (4).to_double ();
a->set_parameter_value (4, pa + pb);
}
};
@ -202,33 +202,33 @@ class CapacitorDeviceCombiner
public:
void serial (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
double va = a->parameter_value (0).to_double ();
double vb = b->parameter_value (0).to_double ();
a->set_parameter_value (0, va + vb < 1e-30 ? 0.0 : va * vb / (va + vb));
// TODO: does this implementation make sense?
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
double aa = a->parameter_value (1).to_double ();
double ab = b->parameter_value (1).to_double ();
a->set_parameter_value (1, aa + ab);
// TODO: does this implementation make sense?
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
double pa = a->parameter_value (2).to_double ();
double pb = b->parameter_value (2).to_double ();
a->set_parameter_value (2, pa + pb);
}
void parallel (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
double va = a->parameter_value (0).to_double ();
double vb = b->parameter_value (0).to_double ();
a->set_parameter_value (0, va + vb);
double aa = a->parameter_value (1);
double ab = b->parameter_value (1);
double aa = a->parameter_value (1).to_double ();
double ab = b->parameter_value (1).to_double ();
a->set_parameter_value (1, aa + ab);
double pa = a->parameter_value (2);
double pb = b->parameter_value (2);
double pa = a->parameter_value (2).to_double ();
double pb = b->parameter_value (2).to_double ();
a->set_parameter_value (2, pa + pb);
}
};
@ -257,15 +257,15 @@ class InductorDeviceCombiner
public:
void parallel (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
double va = a->parameter_value (0).to_double ();
double vb = b->parameter_value (0).to_double ();
a->set_parameter_value (0, va + vb < 1e-30 ? 0.0 : va * vb / (va + vb));
}
void serial (Device *a, Device *b) const
{
double va = a->parameter_value (0);
double vb = b->parameter_value (0);
double va = a->parameter_value (0).to_double ();
double vb = b->parameter_value (0).to_double ();
a->set_parameter_value (0, va + vb);
}
};
@ -284,8 +284,8 @@ public:
// only parallel diodes can be combined and their areas will add
if (na1 == nb1 && na2 == nb2) {
a->set_parameter_value (0, a->parameter_value (0) + b->parameter_value (0));
a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
a->set_parameter_value (0, a->parameter_value (0).to_double () + b->parameter_value (0).to_double ());
a->set_parameter_value (1, a->parameter_value (1).to_double () + b->parameter_value (1).to_double ());
a->join_terminals (0, b, 0);
a->join_terminals (1, b, 1);
@ -340,11 +340,11 @@ public:
void combine_parameters (Device *a, Device *b) const
{
a->set_parameter_value (1, a->parameter_value (1) + b->parameter_value (1));
a->set_parameter_value (2, a->parameter_value (2) + b->parameter_value (2));
a->set_parameter_value (3, a->parameter_value (3) + b->parameter_value (3));
a->set_parameter_value (4, a->parameter_value (4) + b->parameter_value (4));
a->set_parameter_value (5, a->parameter_value (5) + b->parameter_value (5));
a->set_parameter_value (1, a->parameter_value (1).to_double () + b->parameter_value (1).to_double ());
a->set_parameter_value (2, a->parameter_value (2).to_double () + b->parameter_value (2).to_double ());
a->set_parameter_value (3, a->parameter_value (3).to_double () + b->parameter_value (3).to_double ());
a->set_parameter_value (4, a->parameter_value (4).to_double () + b->parameter_value (4).to_double ());
a->set_parameter_value (5, a->parameter_value (5).to_double () + b->parameter_value (5).to_double ());
}
};
@ -423,9 +423,9 @@ public:
void combine_parameters (Device *a, Device *b) const
{
a->set_parameter_value (DeviceClassBJT3Transistor::param_id_AE, a->parameter_value (DeviceClassBJT3Transistor::param_id_AE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_AE));
a->set_parameter_value (DeviceClassBJT3Transistor::param_id_PE, a->parameter_value (DeviceClassBJT3Transistor::param_id_PE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_PE));
a->set_parameter_value (DeviceClassBJT3Transistor::param_id_NE, a->parameter_value (DeviceClassBJT3Transistor::param_id_NE) + b->parameter_value (DeviceClassBJT3Transistor::param_id_NE));
a->set_parameter_value (DeviceClassBJT3Transistor::param_id_AE, a->parameter_value (DeviceClassBJT3Transistor::param_id_AE).to_double () + b->parameter_value (DeviceClassBJT3Transistor::param_id_AE).to_double ());
a->set_parameter_value (DeviceClassBJT3Transistor::param_id_PE, a->parameter_value (DeviceClassBJT3Transistor::param_id_PE).to_double () + b->parameter_value (DeviceClassBJT3Transistor::param_id_PE).to_double ());
a->set_parameter_value (DeviceClassBJT3Transistor::param_id_NE, a->parameter_value (DeviceClassBJT3Transistor::param_id_NE).to_double () + b->parameter_value (DeviceClassBJT3Transistor::param_id_NE).to_double ());
}
};
@ -639,7 +639,7 @@ DeviceClassMOS3Transistor::is_drain_terminal (size_t tid) const
bool
DeviceClassMOS3Transistor::lengths_are_identical (const db::Device *a, const db::Device *b)
{
return (fabs (a->parameter_value (DeviceClassMOS3Transistor::param_id_L) - b->parameter_value (DeviceClassMOS3Transistor::param_id_L)) < 1e-6);
return (fabs (a->parameter_value (DeviceClassMOS3Transistor::param_id_L).to_double () - b->parameter_value (DeviceClassMOS3Transistor::param_id_L).to_double ()) < 1e-6);
}
bool

View File

@ -460,7 +460,7 @@ private:
}
std::map<size_t, std::map<unsigned int, std::set<db::NetShape> > > geometry;
std::map<size_t, double> parameters;
std::map<size_t, tl::Variant> parameters;
};
typedef std::map<unsigned int, std::vector<db::NetShape> > geometry_per_layer_type;

View File

@ -587,8 +587,11 @@ 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) {
double pv = device->parameter_value (i->id ());
device->set_parameter_value (i->id (), pv / i->si_scaling () * pow (m_options.scale, i->geo_scaling_exponent ()));
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 ()));
}
}
}

View File

@ -231,12 +231,13 @@ std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev, si
double sis = i->si_scaling ();
os << " " << i->name () << "=";
// for compatibility
// @@@ other parameter types!!!
if (fabs (sis * 1e6 - 1.0) < 1e-10) {
os << tl::to_string (dev.parameter_value (i->id ())) << "U";
} else if (fabs (sis * 1e12 - 1.0) < 1e-10) {
os << tl::to_string (dev.parameter_value (i->id ())) << "P";
} else {
os << tl::to_string (dev.parameter_value (i->id ()) * sis);
os << tl::to_string (dev.parameter_value (i->id ()).to_double () * sis);
}
}
}

View File

@ -432,17 +432,18 @@ Class<db::Device> decl_dbDevice (decl_dbNetlistObject, "db", "Device",
"@brief Disconnects the given terminal from any net.\n"
"This version accepts a terminal name. If the name is not a valid terminal name, an exception is raised."
) +
gsi::method ("parameter", (double (db::Device::*) (size_t) const) &db::Device::parameter_value, gsi::arg ("param_id"),
gsi::method ("parameter", (const tl::Variant &(db::Device::*) (size_t) const) &db::Device::parameter_value, gsi::arg ("param_id"),
"@brief Gets the parameter value for the given parameter ID."
) +
gsi::method ("set_parameter", (void (db::Device::*) (size_t, double)) &db::Device::set_parameter_value, gsi::arg ("param_id"), gsi::arg ("value"),
gsi::method ("set_parameter", (void (db::Device::*) (size_t, const tl::Variant &)) &db::Device::set_parameter_value, gsi::arg ("param_id"), gsi::arg ("value"),
"@brief Sets the parameter value for the given parameter ID."
) +
gsi::method ("parameter", (double (db::Device::*) (const std::string &) const) &db::Device::parameter_value, gsi::arg ("param_name"),
gsi::method ("parameter", (const tl::Variant &(db::Device::*) (const std::string &) const) &db::Device::parameter_value, gsi::arg ("param_name"),
"@brief Gets the parameter value for the given parameter name.\n"
"If the parameter name is not valid, an exception is thrown."
) +
gsi::method ("set_parameter", (void (db::Device::*) (const std::string &, double)) &db::Device::set_parameter_value, gsi::arg ("param_name"), gsi::arg ("value"),
// @@@ 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."
),

View File

@ -507,20 +507,20 @@ TEST(4_CircuitDevices)
EXPECT_EQ (c->device_by_name (d2a->name ()) == d2a, true);
EXPECT_EQ (c->device_by_name ("doesnt_exist") == 0, true);
EXPECT_EQ (d1->parameter_value (0), 1.0);
EXPECT_EQ (d1->parameter_value (1), 2.0);
EXPECT_EQ (d2a->parameter_value (0), 2.0);
EXPECT_EQ (d2a->parameter_value (1), 1.0);
EXPECT_EQ (d1->parameter_value (0).to_double (), 1.0);
EXPECT_EQ (d1->parameter_value (1).to_double (), 2.0);
EXPECT_EQ (d2a->parameter_value (0).to_double (), 2.0);
EXPECT_EQ (d2a->parameter_value (1).to_double (), 1.0);
d1->set_parameter_value (1, 1.5);
EXPECT_EQ (d1->parameter_value (0), 1.0);
EXPECT_EQ (d1->parameter_value (1), 1.5);
EXPECT_EQ (d1->parameter_value (0).to_double (), 1.0);
EXPECT_EQ (d1->parameter_value (1).to_double (), 1.5);
d1->set_parameter_value (0, 0.5);
EXPECT_EQ (d1->parameter_value (0), 0.5);
EXPECT_EQ (d1->parameter_value (1), 1.5);
EXPECT_EQ (d1->parameter_value (0).to_double (), 0.5);
EXPECT_EQ (d1->parameter_value (1).to_double (), 1.5);
d2a->set_parameter_value (0, -1.0);
EXPECT_EQ (d2a->parameter_value (0), -1.0);
EXPECT_EQ (d2a->parameter_value (1), 1.0);
EXPECT_EQ (d2a->parameter_value (0).to_double (), -1.0);
EXPECT_EQ (d2a->parameter_value (1).to_double (), 1.0);
EXPECT_EQ (netlist2 (*c),
"c:\n"

View File

@ -262,6 +262,16 @@ std::string formatted_value (double v)
}
}
static
std::string formatted_value (const tl::Variant &v)
{
if (v.is_double ()) {
return formatted_value (v.to_double ());
} else {
return v.to_string ();
}
}
static
std::string device_parameter_string (const db::Device *device)
{
@ -277,7 +287,6 @@ std::string device_parameter_string (const db::Device *device)
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
if (p->is_primary ()) {
double v = device->parameter_value (p->id ());
if (first) {
s += " [";
} else {
@ -285,7 +294,7 @@ std::string device_parameter_string (const db::Device *device)
}
s += p->name ();
s += "=";
s += formatted_value (v);
s += formatted_value (device->parameter_value (p->id ()));
term = "]";
first = false;
}
@ -294,8 +303,7 @@ std::string device_parameter_string (const db::Device *device)
bool first_sec = true;
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
double v = device->parameter_value (p->id ());
std::string vs = formatted_value (v);
std::string vs = formatted_value (device->parameter_value (p->id ()));
std::string vs_def = formatted_value (p->default_value ());
if (! p->is_primary () && vs != vs_def) {
if (first) {