mirror of https://github.com/KLayout/klayout.git
Reworking parameter scaling
This commit is contained in:
parent
48078b79e3
commit
e337706634
|
|
@ -373,6 +373,15 @@ void NetlistSpiceReaderDelegate::parse_element (const std::string &s, std::strin
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant si_unscale (const tl::Variant &value, double sis)
|
||||
{
|
||||
if (value.is_double () && sis != 0 && sis != 1.0) {
|
||||
return tl::Variant (value.to_double () / sis);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class SPICEParameterEval
|
||||
|
|
@ -393,22 +402,27 @@ protected:
|
|||
return;
|
||||
}
|
||||
|
||||
auto p = m_params.find (name == "_" ? m_name : name);
|
||||
if (p != m_params.end ()) {
|
||||
value = &p->second;
|
||||
return;
|
||||
}
|
||||
std::string n = name == "_" ? m_name : name;
|
||||
auto h = m_heap.find (n);
|
||||
if (h != m_heap.end ()) {
|
||||
|
||||
auto pp = m_all_params.find (name == "_" ? m_name : name);
|
||||
if (pp != m_all_params.end ()) {
|
||||
if (pp->second) {
|
||||
value = &pp->second->default_value ();
|
||||
return;
|
||||
value = &h->second;
|
||||
|
||||
} else {
|
||||
|
||||
auto p = m_params.find (n);
|
||||
auto pp = m_all_params.find (n);
|
||||
|
||||
tl::Variant v;
|
||||
if (pp != m_all_params.end () && pp->second) {
|
||||
v = si_unscale (p == m_params.end () ? pp->second->default_value () : p->second, pp->second->si_scaling ());
|
||||
} else if (p != m_params.end ()) {
|
||||
v = p->second;
|
||||
}
|
||||
}
|
||||
|
||||
static tl::Variant nil;
|
||||
value = &nil;
|
||||
value = &m_heap.insert (std::make_pair (n, v)).first->second;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -416,6 +430,7 @@ private:
|
|||
const std::map<std::string, tl::Variant> &m_params;
|
||||
const std::map<std::string, const db::DeviceParameterDefinition *> &m_all_params;
|
||||
tl::Variant m_value;
|
||||
std::map<std::string, tl::Variant> m_heap;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -431,7 +446,13 @@ eval_parameter_expression (const std::string &name, const std::string &expr, con
|
|||
} else if (expr == "_") {
|
||||
|
||||
auto p = params.find (name);
|
||||
return p != params.end () ? p->second : tl::Variant ();
|
||||
auto pp = all_params.find (name);
|
||||
|
||||
if (p != params.end () && pp != all_params.end () && pp->second) {
|
||||
return si_unscale (p->second, pp->second->si_scaling ());
|
||||
} else {
|
||||
return p != params.end () ? p->second : tl::Variant ();
|
||||
}
|
||||
|
||||
} else if (expr == "$") {
|
||||
|
||||
|
|
@ -659,7 +680,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
tl_assert (pp != params.end ());
|
||||
|
||||
if (p->second) {
|
||||
device->set_parameter_value (p->second->id (), pp->second);
|
||||
device->set_parameter_value (p->second->id (), si_unscale (pp->second, p->second->si_scaling ()));
|
||||
} else {
|
||||
device->set_parameter_value_create (p->first, pp->second, false, default_from_value (pp->second));
|
||||
}
|
||||
|
|
@ -684,7 +705,7 @@ NetlistSpiceReaderDelegate::apply_parameter_scaling (db::Device *device) const
|
|||
for (auto i = pd.begin (); i != pd.end (); ++i) {
|
||||
const tl::Variant &pv = device->parameter_value (i->id ());
|
||||
if (pv.is_double ()) {
|
||||
device->set_parameter_value (i->id (), pv.to_double () / i->si_scaling () * pow (m_options.scale, i->geo_scaling_exponent ()));
|
||||
device->set_parameter_value (i->id (), pv.to_double () * pow (m_options.scale, i->geo_scaling_exponent ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,13 +113,36 @@ write_parameter_value (std::ostringstream &os, const tl::Variant &v, double sis)
|
|||
{
|
||||
if (v.is_double ()) {
|
||||
|
||||
double d = v.to_double () * sis;
|
||||
double da = fabs (d);
|
||||
|
||||
// for compatibility
|
||||
if (fabs (sis * 1e6 - 1.0) < db::epsilon) {
|
||||
os << tl::to_string (v.to_double ()) << "U";
|
||||
} else if (fabs (sis * 1e12 - 1.0) < db::epsilon) {
|
||||
os << tl::to_string (v.to_double ()) << "P";
|
||||
} else {
|
||||
os << tl::to_string (v.to_double () * sis);
|
||||
if (da > 1e15) {
|
||||
os << tl::to_string (d);
|
||||
} else if (da > 1e11 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e-12) << "T";
|
||||
} else if (da > 1e8 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e-9) << "G";
|
||||
} else if (da > 1e5 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e-6) << "MEG";
|
||||
} else if (da > 1e2 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e-3) << "K";
|
||||
} else if (da > 0.1 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d);
|
||||
} else if (da > 1e-4 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e3) << "M";
|
||||
} else if (da > 1e-7 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e6) << "U";
|
||||
} else if (da > 1e-10 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e9) << "N";
|
||||
} else if (da > 1e-13 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e12) << "P";
|
||||
} else if (da > 1e-16 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e15) << "F";
|
||||
} else if (da > 1e-19 * (1.0 - db::epsilon)) {
|
||||
os << tl::to_string (d * 1e18) << "A";
|
||||
} else if (da < 1e-21) {
|
||||
os << tl::to_string (d);
|
||||
}
|
||||
|
||||
} else if (v.is_long () || v.is_ulong ()) {
|
||||
|
|
@ -129,6 +152,15 @@ write_parameter_value (std::ostringstream &os, const tl::Variant &v, double sis)
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant si_scaling (const tl::Variant &value, double sis)
|
||||
{
|
||||
if (sis == 1.0 || ! value.is_double ()) {
|
||||
return value;
|
||||
} else {
|
||||
return tl::Variant (sis * value.to_double ());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class SPICEParameterEval
|
||||
|
|
@ -145,18 +177,32 @@ protected:
|
|||
virtual void resolve_name (const std::string &name, const tl::EvalFunction *& /*function*/, const tl::Variant *&value, tl::Variant *& /*var*/)
|
||||
{
|
||||
std::string n = (name == "_" ? m_name : name);
|
||||
if (mp_dev->device_class ()->has_parameter_with_name (n)) {
|
||||
value = &mp_dev->parameter_value (mp_dev->device_class ()->parameter_id_for_name (n));
|
||||
return;
|
||||
}
|
||||
|
||||
static tl::Variant nil;
|
||||
value = &nil;
|
||||
const auto *cls = mp_dev->device_class ();
|
||||
if (cls->has_parameter_with_name (n)) {
|
||||
|
||||
size_t id = cls->parameter_id_for_name (n);
|
||||
|
||||
auto h = m_heap.find (id);
|
||||
if (h != m_heap.end ()) {
|
||||
value = &h->second;
|
||||
} else {
|
||||
tl::Variant v = si_scaling (mp_dev->parameter_value (id), cls->parameter_definition (id)->si_scaling ());
|
||||
value = &m_heap.insert (std::make_pair (id, v)).first->second;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
static tl::Variant nil;
|
||||
value = &nil;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string m_name;
|
||||
const db::Device *mp_dev;
|
||||
std::map<size_t, tl::Variant> m_heap;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -171,9 +217,10 @@ eval_parameter_expression (const std::string &name, const std::string &expr, con
|
|||
|
||||
} else if (expr == "_") {
|
||||
|
||||
if (dev.device_class ()->has_parameter_with_name (name)) {
|
||||
auto id = dev.device_class ()->parameter_id_for_name (name);
|
||||
return dev.parameter_value (id);
|
||||
const auto *cls = dev.device_class ();
|
||||
if (cls->has_parameter_with_name (name)) {
|
||||
auto id = cls->parameter_id_for_name (name);
|
||||
return si_scaling (dev.parameter_value (id), cls->parameter_definition (id)->si_scaling ());
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
|
@ -200,7 +247,7 @@ void NetlistSpiceWriterDelegate::write_device_profile (const db::Device &dev, co
|
|||
const std::map<std::string, std::string> &dict = profile.outgoing_parameters;
|
||||
|
||||
std::vector<std::pair<std::string, const db::DeviceParameterDefinition *> > all_params;
|
||||
std::vector<std::pair<std::string, std::pair<tl::Variant, const db::DeviceParameterDefinition *> > > param_values;
|
||||
std::vector<std::pair<std::string, tl::Variant> > param_values;
|
||||
|
||||
const db::DeviceClass *cls = dev.device_class ();
|
||||
tl_assert (cls != 0);
|
||||
|
|
@ -233,14 +280,14 @@ void NetlistSpiceWriterDelegate::write_device_profile (const db::Device &dev, co
|
|||
if (id != dict.end ()) {
|
||||
pv = eval_parameter_expression (p->first, id->second, dev);
|
||||
} else if (p->second) {
|
||||
pv = dev.parameter_value (p->second->id ());
|
||||
pv = si_scaling (dev.parameter_value (p->second->id ()), p->second->si_scaling ());
|
||||
}
|
||||
|
||||
if (! pv.is_nil ()) {
|
||||
if (p->first == "$") {
|
||||
direct_value = pv;
|
||||
} else {
|
||||
param_values.push_back (std::make_pair (p->first, std::make_pair (pv, p->second)));
|
||||
param_values.push_back (std::make_pair (p->first, pv));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +307,7 @@ void NetlistSpiceWriterDelegate::write_device_profile (const db::Device &dev, co
|
|||
|
||||
for (auto p = param_values.begin (); p != param_values.end (); ++p) {
|
||||
os << " " << p->first << "=";
|
||||
write_parameter_value (os, p->second.first, p->second.second ? p->second.second->si_scaling () : 1.0);
|
||||
write_parameter_value (os, p->second, 1.0);
|
||||
}
|
||||
|
||||
emit_line (os.str ());
|
||||
|
|
|
|||
|
|
@ -339,9 +339,9 @@ static void set_outgoing_parameters (db::DeviceClass::SpiceProfile *profile, con
|
|||
Class<db::DeviceClass::SpiceProfile> decl_dbDeviceClassSpiceProfile ("db", "DeviceClassSpiceProfile",
|
||||
gsi::method_ext ("element", &get_element,
|
||||
"@brief Gets the SPICE element to use for this device.\n"
|
||||
"The element is the SPICE code for the element - i.e. 'X', 'M', 'R' etc.\n"
|
||||
"The element is the single-character SPICE code for the element - i.e. 'X', 'M', 'R' etc.\n"
|
||||
) +
|
||||
gsi::method_ext ("element=", &set_element,
|
||||
gsi::method_ext ("element=", &set_element, gsi::arg ("e"),
|
||||
"@brief Sets the SPICE element to use for this device.\n"
|
||||
"See \\element for a description of this attribute.\n"
|
||||
) +
|
||||
|
|
@ -376,7 +376,7 @@ Class<db::DeviceClass::SpiceProfile> decl_dbDeviceClassSpiceProfile ("db", "Devi
|
|||
"So, the forth element mimics the bulk pin of a MOS4 device. It is optional on reading (the net is ignored)\n"
|
||||
"and upon writing it is connected to 'S'.\n"
|
||||
) +
|
||||
gsi::method_ext ("terminal_order=", &set_terminal_order,
|
||||
gsi::method_ext ("terminal_order=", &set_terminal_order, gsi::arg ("to"),
|
||||
"@brief Sets the terminal order to use for this device.\n"
|
||||
"See \\terminal_order for a description of this attribute.\n"
|
||||
) +
|
||||
|
|
@ -430,7 +430,7 @@ Class<db::DeviceClass::SpiceProfile> decl_dbDeviceClassSpiceProfile ("db", "Devi
|
|||
"cls.set_spice_profile(sp)\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
gsi::method_ext ("incoming_parameters=", &set_incoming_parameters,
|
||||
gsi::method_ext ("incoming_parameters=", &set_incoming_parameters, gsi::arg ("par"),
|
||||
"@brief Sets the mapping of incoming parameters from SPICE files\n"
|
||||
"See \\incoming_parameters for a description of this attribute.\n"
|
||||
) +
|
||||
|
|
@ -468,7 +468,7 @@ Class<db::DeviceClass::SpiceProfile> decl_dbDeviceClassSpiceProfile ("db", "Devi
|
|||
"cls.set_spice_profile(sp)\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
gsi::method_ext ("outgoing_parameters=", &set_outgoing_parameters,
|
||||
gsi::method_ext ("outgoing_parameters=", &set_outgoing_parameters, gsi::arg ("par"),
|
||||
"@brief Sets the mapping tables for outgoing parameters\n"
|
||||
"See \\outgoing_parameters for a description of this attribute.\n"
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1502,7 +1502,7 @@ TEST(15_SpiceProfiles)
|
|||
EXPECT_EQ (std::string (om.data (), om.size ()),
|
||||
"* written by unit test\n\n"
|
||||
".SUBCKT TOP 1 2 3\n"
|
||||
"X1 3 2 1 1 NMOS L=1U WW=5 X=42\n"
|
||||
"X1 3 2 1 1 NMOS L=1U WW=5U X=42\n"
|
||||
".ENDS TOP\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -1522,8 +1522,7 @@ TEST(15_SpiceProfiles)
|
|||
EXPECT_EQ (std::string (om.data (), om.size ()),
|
||||
"* written by unit test\n\n"
|
||||
".SUBCKT TOP 1 2 3\n"
|
||||
// @@@ not "5U"?
|
||||
"X1 3 2 1 1 NMOS L=1U AS=0P AD=1.25P PS=0U PD=0U WW=5 X=42\n"
|
||||
"X1 3 2 1 1 NMOS L=1U AS=0 AD=1.25P PS=0 PD=0 WW=5U X=42\n"
|
||||
".ENDS TOP\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -1567,7 +1566,7 @@ TEST(15_SpiceProfiles)
|
|||
EXPECT_EQ (std::string (om.data (), om.size ()),
|
||||
"* written by unit test\n\n"
|
||||
".SUBCKT TOP 1 2 3\n"
|
||||
"X1 3 2 1 1 NMOS L=1U AS=0P AD=1.25P PS=0U PD=0U\n"
|
||||
"X1 3 2 1 1 NMOS L=1U AS=0 AD=1.25P PS=0 PD=0\n"
|
||||
".ENDS TOP\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -1589,7 +1588,7 @@ TEST(15_SpiceProfiles)
|
|||
EXPECT_EQ (std::string (om.data (), om.size ()),
|
||||
"* written by unit test\n\n"
|
||||
".SUBCKT TOP 1 2 3\n"
|
||||
"X1 3 2 1 1 NMOS L=1U W=2.5U AS=0P AD=1.25P PS=0U PD=0U\n"
|
||||
"X1 3 2 1 1 NMOS L=1U W=2.5U AS=0 AD=1.25P PS=0 PD=0\n"
|
||||
".ENDS TOP\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
* net 2 n2
|
||||
* net 3 n3
|
||||
* device instance $1 r0 *1 0,0 DCLS
|
||||
D$1 1 3 DCLS A=1.7P P=0U
|
||||
D$1 1 3 DCLS A=1.7P P=0
|
||||
* device instance $2 r0 *1 0,0 DCLS
|
||||
D$2 3 2 DCLS A=0.42P P=0U
|
||||
D$2 3 2 DCLS A=0.42P P=0
|
||||
.ENDS C1
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
* cell Res2
|
||||
.SUBCKT Res2
|
||||
* device instance $1 r0 *1 110.14,51.795 RPP1
|
||||
R$1 1 2 95 RPP1 L=420U W=2.21052631579U
|
||||
R$1 1 2 95 RPP1 L=0.42M W=2.21052631579U
|
||||
.ENDS Res2
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
* cell Res2
|
||||
.SUBCKT Res2
|
||||
* device instance $6 r0 *1 110.14,51.795 RPP1
|
||||
R$6 1 2 95 RPP1 L=420U W=2.21052631579U
|
||||
R$6 1 2 95 RPP1 L=0.42M W=2.21052631579U
|
||||
.ENDS Res2
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
* cell Res2
|
||||
.SUBCKT Res2
|
||||
* device instance $1 r0 *1 110.14,51.795 RPP1
|
||||
R$1 2 1 95 RPP1 L=420U W=2.21052631579U
|
||||
R$1 2 1 95 RPP1 L=0.42M W=2.21052631579U
|
||||
.ENDS Res2
|
||||
|
|
|
|||
Loading…
Reference in New Issue