mirror of https://github.com/KLayout/klayout.git
commit
40848be14b
|
|
@ -360,6 +360,7 @@ drop_method "QNoDebug", /QNoDebug::operator<</ # nothing usable (TODO: how to ma
|
|||
|
||||
include "QCoreApplication", [ "<QCoreApplication>", "<QAbstractEventDispatcher>", "<QAbstractNativeEventFilter>", "<QTranslator>" ]
|
||||
include "QThread", [ "<QThread>", "<QAbstractEventDispatcher>" ]
|
||||
include "QByteArrayMatcher", [ "<limits>", "<QByteArrayMatcher>" ]
|
||||
|
||||
rename "QLocale", /QLocale::toString\(int i/, "toString_i"
|
||||
rename "QLocale", /QLocale::toString\(unsigned int/, "toString_ui"
|
||||
|
|
|
|||
|
|
@ -209,9 +209,14 @@ class PropertyStub(Stub):
|
|||
class ClassStub(Stub):
|
||||
indent_docstring: bool = True
|
||||
|
||||
def get_child_classes(c: ktl.Class):
|
||||
child_classes = []
|
||||
for c_child in c.each_child_class():
|
||||
child_classes.append(c_child)
|
||||
return sorted(child_classes, key=lambda cls: cls.name())
|
||||
|
||||
def get_py_child_classes(c: ktl.Class):
|
||||
for c_child in c.each_child_class():
|
||||
for c_child in get_child_classes(c):
|
||||
yield c_child
|
||||
|
||||
|
||||
|
|
@ -390,9 +395,9 @@ def get_py_methods(
|
|||
)
|
||||
)
|
||||
|
||||
boundmethods = sorted(boundmethods)
|
||||
properties = sorted(properties)
|
||||
classmethods = sorted(classmethods)
|
||||
boundmethods = sorted(boundmethods, key=lambda m: m.signature)
|
||||
properties = sorted(properties, key=lambda m: m.signature)
|
||||
classmethods = sorted(classmethods, key=lambda m: m.signature)
|
||||
|
||||
return_list: List[Stub] = properties + classmethods + boundmethods
|
||||
|
||||
|
|
@ -415,7 +420,7 @@ def get_class_stub(
|
|||
signature="class " + full_name + base, docstring=c.doc(), name=full_name
|
||||
)
|
||||
child_attributes = get_py_methods(c)
|
||||
for child_c in c.each_child_class():
|
||||
for child_c in get_child_classes(c):
|
||||
_cstub.child_stubs.append(
|
||||
get_class_stub(
|
||||
child_c,
|
||||
|
|
@ -434,7 +439,7 @@ def get_classes(module: str) -> List[ktl.Class]:
|
|||
if c.module() != module:
|
||||
continue
|
||||
_classes.append(c)
|
||||
return _classes
|
||||
return sorted(_classes, key=lambda cls: cls.name())
|
||||
|
||||
|
||||
def get_module_stubs(module: str) -> List[ClassStub]:
|
||||
|
|
@ -457,7 +462,7 @@ def print_mod(module, dependencies):
|
|||
|
||||
if __name__ == "__main__":
|
||||
if len(argv) < 2:
|
||||
print("Specity module in argument")
|
||||
print("Specify module in argument")
|
||||
exit(1)
|
||||
if len(argv) == 2:
|
||||
print_mod(argv[1], [])
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public:
|
|||
virtual void finish (bool);
|
||||
|
||||
void keep_for_healing (const db::Polygon &poly);
|
||||
void keep_for_healing (const db::Box &box);
|
||||
|
||||
private:
|
||||
size_t *mp_count;
|
||||
|
|
@ -78,6 +79,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void operator() (const db::Box &box)
|
||||
{
|
||||
if (m_healing && ! box.inside (mp_tile->enlarged (db::Vector (-1, -1)))) {
|
||||
mp_receiver->keep_for_healing (box);
|
||||
} else {
|
||||
m_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t count () const
|
||||
{
|
||||
return m_count;
|
||||
|
|
@ -110,6 +120,12 @@ HealingCountingReceiver::keep_for_healing (const db::Polygon &poly)
|
|||
m_for_healing.insert (poly);
|
||||
}
|
||||
|
||||
void
|
||||
HealingCountingReceiver::keep_for_healing (const db::Box &box)
|
||||
{
|
||||
m_for_healing.insert (box);
|
||||
}
|
||||
|
||||
void
|
||||
HealingCountingReceiver::finish (bool)
|
||||
{
|
||||
|
|
@ -132,7 +148,9 @@ public:
|
|||
void finish (bool /*success*/);
|
||||
|
||||
void keep_for_healing (const db::Polygon &poly);
|
||||
void keep_for_healing (const db::Box &box);
|
||||
void output (const db::Polygon &poly);
|
||||
void output (const db::Box &poly);
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
|
|
@ -167,6 +185,23 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void operator() (const db::Box &box)
|
||||
{
|
||||
if (m_healing && ! box.inside (mp_tile->enlarged (db::Vector (-1, -1)))) {
|
||||
if (mp_trans->is_complex ()) {
|
||||
mp_receiver->keep_for_healing (*mp_trans * db::Polygon (box));
|
||||
} else {
|
||||
mp_receiver->keep_for_healing (*mp_trans * box);
|
||||
}
|
||||
} else {
|
||||
if (mp_trans->is_complex ()) {
|
||||
mp_receiver->output (*mp_trans * db::Polygon (box));
|
||||
} else {
|
||||
mp_receiver->output (*mp_trans * box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const db::Box *mp_tile;
|
||||
bool m_healing;
|
||||
|
|
@ -211,12 +246,24 @@ HealingTileLayoutOutputReceiver::keep_for_healing (const db::Polygon &poly)
|
|||
m_for_healing.insert (poly);
|
||||
}
|
||||
|
||||
void
|
||||
HealingTileLayoutOutputReceiver::keep_for_healing (const db::Box &box)
|
||||
{
|
||||
m_for_healing.insert (box);
|
||||
}
|
||||
|
||||
void
|
||||
HealingTileLayoutOutputReceiver::output (const db::Polygon &poly)
|
||||
{
|
||||
mp_cell->shapes (m_layer).insert (poly);
|
||||
}
|
||||
|
||||
void
|
||||
HealingTileLayoutOutputReceiver::output (const db::Box &box)
|
||||
{
|
||||
mp_cell->shapes (m_layer).insert (box);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
struct ResultDescriptor
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ TEST(1A_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
|
|
@ -141,7 +141,7 @@ TEST(1A_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
|
|
@ -321,7 +321,7 @@ TEST(2_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
""
|
||||
);
|
||||
|
|
@ -354,7 +354,7 @@ TEST(2_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
""
|
||||
);
|
||||
|
|
@ -387,7 +387,7 @@ TEST(3_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -453,7 +453,7 @@ TEST(3_FlatHeal)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -520,7 +520,7 @@ TEST(3_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -553,7 +553,7 @@ TEST(4_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -586,7 +586,7 @@ TEST(4_FlatHeal)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -619,7 +619,7 @@ TEST(4_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -652,7 +652,7 @@ TEST(5_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -685,7 +685,7 @@ TEST(5_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -718,7 +718,7 @@ TEST(6_Flat)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
@ -751,7 +751,7 @@ TEST(6_Deep)
|
|||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1146,14 +1146,14 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
check.set_min_projection (options.min_projection);
|
||||
check.set_max_projection (options.max_projection);
|
||||
|
||||
std::vector<generic_shape_iterator<db::Polygon> > others;
|
||||
std::vector<db::RegionIterator> others;
|
||||
std::vector<bool> foreign;
|
||||
bool has_other = false;
|
||||
bool other_is_merged = true;
|
||||
|
||||
if (other == subject_regionptr () || other == foreign_regionptr ()) {
|
||||
foreign.push_back (other == foreign_regionptr ());
|
||||
others.push_back (begin_merged ());
|
||||
others.push_back (polygons);
|
||||
other_is_merged = primary_is_merged;
|
||||
} else {
|
||||
foreign.push_back (false);
|
||||
|
|
|
|||
|
|
@ -376,15 +376,12 @@ private:
|
|||
|
||||
while (cc != current) {
|
||||
rec.finish (cc->first, cc->second);
|
||||
typename std::set<std::pair<const Obj *, const Obj *> >::iterator s;
|
||||
s = seen.lower_bound (std::make_pair (cc->first, (const Obj *)0));
|
||||
auto s = seen.lower_bound (std::make_pair (cc->first, (const Obj *)0));
|
||||
auto s0 = s;
|
||||
while (s != seen.end () && s->first == cc->first) {
|
||||
seen.erase (s++);
|
||||
}
|
||||
s = seen.lower_bound (std::make_pair ((const Obj *)0, cc->first));
|
||||
while (s != seen.end () && s->second == cc->first) {
|
||||
seen.erase (s++);
|
||||
++s;
|
||||
}
|
||||
seen.erase (s0, s);
|
||||
++cc;
|
||||
}
|
||||
|
||||
|
|
@ -429,8 +426,8 @@ private:
|
|||
for (iterator_type i = f0; i != f; ++i) {
|
||||
for (iterator_type j = c; j < i; ++j) {
|
||||
if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) {
|
||||
if (seen.insert (std::make_pair (i->first, j->first)).second) {
|
||||
seen.insert (std::make_pair (j->first, i->first));
|
||||
if (seen.find (std::make_pair (i->first, j->first)) == seen.end () && seen.find (std::make_pair (j->first, i->first)) == seen.end ()) {
|
||||
seen.insert (std::make_pair (i->first, j->first));
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
if (rec.stop ()) {
|
||||
return false;
|
||||
|
|
@ -791,21 +788,23 @@ private:
|
|||
|
||||
while (cc1 != current1) {
|
||||
rec.finish1 (cc1->first, cc1->second);
|
||||
typename std::set<std::pair<const Obj1 *, const Obj2 *> >::iterator s;
|
||||
s = seen1.lower_bound (std::make_pair (cc1->first, (const Obj2 *)0));
|
||||
auto s = seen1.lower_bound (std::make_pair (cc1->first, (const Obj2 *)0));
|
||||
auto s0 = s;
|
||||
while (s != seen1.end () && s->first == cc1->first) {
|
||||
seen1.erase (s++);
|
||||
++s;
|
||||
}
|
||||
seen1.erase (s0, s);
|
||||
++cc1;
|
||||
}
|
||||
|
||||
while (cc2 != current2) {
|
||||
rec.finish2 (cc2->first, cc2->second);
|
||||
typename std::set<std::pair<const Obj2 *, const Obj1 *> >::iterator s;
|
||||
s = seen2.lower_bound (std::make_pair (cc2->first, (const Obj1 *)0));
|
||||
auto s = seen2.lower_bound (std::make_pair (cc2->first, (const Obj1 *)0));
|
||||
auto s0 = s;
|
||||
while (s != seen2.end () && s->first == cc2->first) {
|
||||
seen2.erase (s++);
|
||||
++s;
|
||||
}
|
||||
seen2.erase (s0, s);
|
||||
++cc2;
|
||||
}
|
||||
|
||||
|
|
@ -883,7 +882,7 @@ private:
|
|||
x = xx;
|
||||
|
||||
if (m_report_progress) {
|
||||
progress->set (std::min (f1 - m_pp1.begin (), f2 - m_pp2.begin ()));
|
||||
progress->set ((f1 - m_pp1.begin ()) + (f2 - m_pp2.begin ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -867,7 +867,9 @@ void DeepShapeStore::remove_ref (unsigned int layout, unsigned int layer)
|
|||
unsigned int
|
||||
DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
layout_map_type::iterator l = m_layout_map.find (std::make_pair (si, trans));
|
||||
size_t gen_id = si.layout () ? si.layout ()->hier_generation_id () : 0;
|
||||
|
||||
layout_map_type::iterator l = m_layout_map.find (std::make_pair (si, std::make_pair (gen_id, trans)));
|
||||
if (l == m_layout_map.end () || m_layouts[l->second] == 0) {
|
||||
|
||||
unsigned int layout_index;
|
||||
|
|
@ -886,7 +888,7 @@ DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si, const db:
|
|||
layout.dbu (si.layout ()->dbu () / trans.mag ());
|
||||
}
|
||||
|
||||
m_layout_map[std::make_pair (si, trans)] = layout_index;
|
||||
m_layout_map[std::make_pair (si, std::make_pair (gen_id, trans))] = layout_index;
|
||||
return layout_index;
|
||||
|
||||
} else {
|
||||
|
|
@ -896,7 +898,8 @@ DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si, const db:
|
|||
|
||||
void DeepShapeStore::make_layout (unsigned int layout_index, const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
tl_assert (m_layout_map.find (std::make_pair (si, trans)) == m_layout_map.end ());
|
||||
size_t gen_id = si.layout () ? si.layout ()->hier_generation_id () : 0;
|
||||
tl_assert (m_layout_map.find (std::make_pair (si, std::make_pair (gen_id, trans))) == m_layout_map.end ());
|
||||
|
||||
while (m_layouts.size () <= layout_index) {
|
||||
m_layouts.push_back (0);
|
||||
|
|
@ -909,7 +912,7 @@ void DeepShapeStore::make_layout (unsigned int layout_index, const db::Recursive
|
|||
layout.dbu (si.layout ()->dbu () / trans.mag ());
|
||||
}
|
||||
|
||||
m_layout_map[std::make_pair (si, trans)] = layout_index;
|
||||
m_layout_map[std::make_pair (si, std::make_pair (gen_id, trans))] = layout_index;
|
||||
}
|
||||
|
||||
DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count, const db::ICplxTrans &trans)
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ private:
|
|||
|
||||
struct DB_PUBLIC RecursiveShapeIteratorCompareForTargetHierarchy
|
||||
{
|
||||
bool operator () (const std::pair<db::RecursiveShapeIterator, db::ICplxTrans> &a, const std::pair<db::RecursiveShapeIterator, db::ICplxTrans> &b) const
|
||||
bool operator () (const std::pair<db::RecursiveShapeIterator, std::pair<size_t, db::ICplxTrans> > &a, const std::pair<db::RecursiveShapeIterator, std::pair<size_t, db::ICplxTrans> > &b) const
|
||||
{
|
||||
int cmp_iter = db::compare_iterators_with_respect_to_target_hierarchy (a.first, b.first);
|
||||
if (cmp_iter != 0) {
|
||||
|
|
@ -865,7 +865,7 @@ private:
|
|||
|
||||
void issue_variants (unsigned int layout, const std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > &var_map);
|
||||
|
||||
typedef std::map<std::pair<db::RecursiveShapeIterator, db::ICplxTrans>, unsigned int, RecursiveShapeIteratorCompareForTargetHierarchy> layout_map_type;
|
||||
typedef std::map<std::pair<db::RecursiveShapeIterator, std::pair<size_t, db::ICplxTrans> >, unsigned int, RecursiveShapeIteratorCompareForTargetHierarchy> layout_map_type;
|
||||
|
||||
// no copying
|
||||
DeepShapeStore (const DeepShapeStore &);
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ public:
|
|||
* @brief Creates an empty device parameter definition
|
||||
*/
|
||||
DeviceParameterDefinition ()
|
||||
: m_name (), m_description (), m_default_value (0.0), m_id (0), m_is_primary (true), m_si_scaling (1.0)
|
||||
: m_name (), m_description (), m_default_value (0.0), m_id (0), m_is_primary (true), m_si_scaling (1.0), m_geo_scaling (0.0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -154,8 +154,8 @@ 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)
|
||||
: m_name (name), m_description (description), m_default_value (default_value), m_id (0), m_is_primary (is_primary), m_si_scaling (si_scaling)
|
||||
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)
|
||||
: 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 ..
|
||||
}
|
||||
|
|
@ -192,18 +192,10 @@ public:
|
|||
m_description = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parameter default value
|
||||
*/
|
||||
double default_value () const
|
||||
{
|
||||
return m_default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the SI unit scaling factor
|
||||
*
|
||||
* Some parameters are given in micrometers for example. This
|
||||
* Some parameters are given in micrometers - for example W and L of MOS devices. This
|
||||
* scaling factor gives the translation to SI units (1e-6 for micrometers).
|
||||
*/
|
||||
double si_scaling () const
|
||||
|
|
@ -212,7 +204,43 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the parameter description
|
||||
* @brief Set the SI unit scaling factor
|
||||
*/
|
||||
void set_si_scaling (double s)
|
||||
{
|
||||
m_si_scaling = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the geometry scaling exponent
|
||||
*
|
||||
* The geometry scaling exponent is used for example when applying .option scale
|
||||
* in Spice reading. It is 0 for "no scaling", 1 for linear scaling and 2 for
|
||||
* quadratic scaling.
|
||||
*/
|
||||
double geo_scaling_exponent () const
|
||||
{
|
||||
return m_geo_scaling;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the geometry scaling exponent
|
||||
*/
|
||||
void set_geo_scaling_exponent (double e)
|
||||
{
|
||||
m_geo_scaling = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parameter default value
|
||||
*/
|
||||
double default_value () const
|
||||
{
|
||||
return m_default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the parameter default value
|
||||
*/
|
||||
void set_default_value (double d)
|
||||
{
|
||||
|
|
@ -267,6 +295,7 @@ private:
|
|||
size_t m_id;
|
||||
bool m_is_primary;
|
||||
double m_si_scaling;
|
||||
double m_geo_scaling;
|
||||
|
||||
void set_id (size_t id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -487,10 +487,10 @@ DeviceClassResistor::DeviceClassResistor ()
|
|||
equivalent_terminal_id (terminal_id_A, terminal_id_B);
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("R", "Resistance (Ohm)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Length (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Width (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Length (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Width (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
|
@ -526,8 +526,8 @@ DeviceClassCapacitor::DeviceClassCapacitor ()
|
|||
equivalent_terminal_id (terminal_id_A, terminal_id_B);
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("C", "Capacitance (Farad)", 0.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
|
@ -580,8 +580,8 @@ DeviceClassDiode::DeviceClassDiode ()
|
|||
add_terminal_definition (db::DeviceTerminalDefinition ("A", "Anode"));
|
||||
add_terminal_definition (db::DeviceTerminalDefinition ("C", "Cathode"));
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("A", "Area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("P", "Perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
|
@ -608,12 +608,12 @@ DeviceClassMOS3Transistor::DeviceClassMOS3Transistor ()
|
|||
add_terminal_definition (db::DeviceTerminalDefinition ("D", "Drain"));
|
||||
equivalent_terminal_id (terminal_id_D, terminal_id_S);
|
||||
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0, true, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0, true, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PS", "Source perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("L", "Gate length (micrometer)", 0.0, true, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("W", "Gate width (micrometer)", 0.0, true, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AS", "Source area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AD", "Drain area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PS", "Source perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PD", "Drain perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -886,12 +886,12 @@ DeviceClassBJT3Transistor::DeviceClassBJT3Transistor ()
|
|||
add_terminal_definition (db::DeviceTerminalDefinition ("E", "Emitter"));
|
||||
|
||||
// NOTE: the emitter area and the emitter count are the primary parameters
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AE", "Emitter area (square micrometer)", 0.0, true, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PE", "Emitter perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AB", "Base area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PB", "Base perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AC", "Collector area (square micrometer)", 0.0, false, 1e-12));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PC", "Collector perimeter (micrometer)", 0.0, false, 1e-6));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AE", "Emitter area (square micrometer)", 0.0, true, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PE", "Emitter perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AB", "Base area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PB", "Base perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("AC", "Collector area (square micrometer)", 0.0, false, 1e-12, 2.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("PC", "Collector perimeter (micrometer)", 0.0, false, 1e-6, 1.0));
|
||||
add_parameter_definition (db::DeviceParameterDefinition ("NE", "Emitter count", 1.0, true));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@ private:
|
|||
void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets);
|
||||
void read_circuit (tl::Extractor &ex, const std::string &name);
|
||||
bool read_card ();
|
||||
void read_options (tl::Extractor &ex);
|
||||
void ensure_circuit ();
|
||||
std::string get_line ();
|
||||
void error (const std::string &msg);
|
||||
|
|
@ -614,6 +615,10 @@ SpiceCircuitDict::read_card ()
|
|||
std::string nc = read_name (ex, mp_netlist);
|
||||
read_circuit (ex, nc);
|
||||
|
||||
} else if (ex.test_without_case (".options")) {
|
||||
|
||||
read_options (ex);
|
||||
|
||||
} else if (ex.test_without_case (".ends")) {
|
||||
|
||||
return true;
|
||||
|
|
@ -680,6 +685,56 @@ SpiceCircuitDict::read_card ()
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SpiceCircuitDict::read_options (tl::Extractor &ex)
|
||||
{
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
std::string n;
|
||||
ex.read_word_or_quoted (n, allowed_name_chars);
|
||||
n = tl::to_lower_case (n);
|
||||
|
||||
double v = 0.0;
|
||||
std::string w;
|
||||
if (ex.test ("=")) {
|
||||
if (ex.try_read (v)) {
|
||||
// take value
|
||||
} else {
|
||||
// skip until end or next space
|
||||
ex.skip ();
|
||||
while (! ex.at_end () && ! isspace (*ex)) {
|
||||
++ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: further options?
|
||||
const double min_value = 1e-18;
|
||||
if (n == "scale") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().scale = v;
|
||||
}
|
||||
} else if (n == "defad") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defad = v;
|
||||
}
|
||||
} else if (n == "defas") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defas = v;
|
||||
}
|
||||
} else if (n == "defl") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defl = v;
|
||||
}
|
||||
} else if (n == "defw") {
|
||||
if (v > min_value) {
|
||||
mp_delegate->options ().defw = v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpiceCircuitDict::ensure_circuit ()
|
||||
{
|
||||
|
|
@ -1148,9 +1203,9 @@ SpiceNetlistBuilder::build_global_nets ()
|
|||
NetlistSpiceReader::NetlistSpiceReader (NetlistSpiceReaderDelegate *delegate)
|
||||
: mp_delegate (delegate), m_strict (false)
|
||||
{
|
||||
static NetlistSpiceReaderDelegate std_delegate;
|
||||
if (! delegate) {
|
||||
mp_delegate.reset (&std_delegate);
|
||||
mp_default_delegate.reset (new NetlistSpiceReaderDelegate ());
|
||||
mp_delegate.reset (mp_default_delegate.get ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -64,6 +65,7 @@ public:
|
|||
|
||||
private:
|
||||
tl::weak_ptr<NetlistSpiceReaderDelegate> mp_delegate;
|
||||
std::unique_ptr<NetlistSpiceReaderDelegate> mp_default_delegate;
|
||||
bool m_strict;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -86,8 +86,20 @@ static std::string unescape_name (const std::string &n)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
NetlistSpiceReaderOptions::NetlistSpiceReaderOptions ()
|
||||
{
|
||||
scale = 1.0;
|
||||
defad = 0.0;
|
||||
defas = 0.0;
|
||||
// ngspice defaults:
|
||||
defw = 100e-6;
|
||||
defl = 100e-6;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
NetlistSpiceReaderDelegate::NetlistSpiceReaderDelegate ()
|
||||
: mp_netlist (0)
|
||||
: mp_netlist (0), m_options ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -97,6 +109,22 @@ NetlistSpiceReaderDelegate::~NetlistSpiceReaderDelegate ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::set_netlist (db::Netlist *netlist)
|
||||
{
|
||||
m_options = NetlistSpiceReaderOptions ();
|
||||
mp_netlist = netlist;
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::do_start ()
|
||||
{
|
||||
start (mp_netlist);
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::do_finish ()
|
||||
{
|
||||
finish (mp_netlist);
|
||||
}
|
||||
|
||||
void NetlistSpiceReaderDelegate::start (db::Netlist * /*netlist*/)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -107,7 +135,7 @@ void NetlistSpiceReaderDelegate::finish (db::Netlist * /*netlist*/)
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool NetlistSpiceReaderDelegate::control_statement(const std::string & /*line*/)
|
||||
bool NetlistSpiceReaderDelegate::control_statement (const std::string & /*line*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -196,7 +224,8 @@ void NetlistSpiceReaderDelegate::parse_element_components (const std::string &s,
|
|||
if (ex.try_read_word (n) && ex.test ("=")) {
|
||||
|
||||
// a parameter
|
||||
pv [mp_netlist ? mp_netlist->normalize_name (n) : tl::to_upper_case (n)] = read_value (ex, variables);
|
||||
std::string pn = mp_netlist ? mp_netlist->normalize_name (n) : tl::to_upper_case (n);
|
||||
pv [pn] = read_value (ex, variables);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -231,8 +260,21 @@ 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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
def_values_per_element (element, pv);
|
||||
parse_element_components (s, nn, pv, variables);
|
||||
|
||||
// interpret the parameters according to the code
|
||||
|
|
@ -337,6 +379,8 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
std::map<std::string, tl::Variant> params = pv;
|
||||
std::vector<size_t> terminal_order;
|
||||
|
||||
size_t defp = std::numeric_limits<size_t>::max ();
|
||||
|
||||
double mult = 1.0;
|
||||
auto mp = params.find ("M");
|
||||
if (mp != params.end ()) {
|
||||
|
|
@ -378,9 +422,20 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
error (tl::to_string (tr ("A 'R' element requires two or three nets")));
|
||||
}
|
||||
|
||||
// Apply multiplier
|
||||
// Apply multiplier (divider, according to ngspice manual)
|
||||
value /= mult;
|
||||
|
||||
defp = db::DeviceClassResistor::param_id_R;
|
||||
|
||||
// Apply multiplier to other parameters
|
||||
static const char *scale_params[] = { "A", "P", "W" };
|
||||
for (size_t i = 0; i < sizeof (scale_params) / sizeof (scale_params[0]); ++i) {
|
||||
auto p = params.find (scale_params [i]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "L") {
|
||||
|
||||
if (nets.size () == 2) {
|
||||
|
|
@ -398,9 +453,11 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
error (tl::to_string (tr ("A 'L' element requires two nets")));
|
||||
}
|
||||
|
||||
// Apply multiplier
|
||||
// Apply multiplier (divider, according to ngspice manual)
|
||||
value /= mult;
|
||||
|
||||
defp = db::DeviceClassInductor::param_id_L;
|
||||
|
||||
} else if (element == "C") {
|
||||
|
||||
if (nets.size () == 2) {
|
||||
|
|
@ -432,6 +489,17 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
// Apply multiplier
|
||||
value *= mult;
|
||||
|
||||
defp = db::DeviceClassCapacitor::param_id_C;
|
||||
|
||||
// Apply multiplier to other parameters
|
||||
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]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "D") {
|
||||
|
||||
if (cls) {
|
||||
|
|
@ -445,10 +513,13 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
cls = make_device_class<db::DeviceClassDiode> (circuit, cn);
|
||||
}
|
||||
|
||||
// Apply multiplier to "A"
|
||||
auto p = params.find ("A");
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
// Apply multiplier
|
||||
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]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "Q") {
|
||||
|
|
@ -479,10 +550,13 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
}
|
||||
}
|
||||
|
||||
// Apply multiplier to "AE"
|
||||
auto p = params.find ("AE");
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
// Apply multiplier
|
||||
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]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (element == "M") {
|
||||
|
|
@ -502,10 +576,13 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
}
|
||||
}
|
||||
|
||||
// Apply multiplier to "W"
|
||||
auto p = params.find ("W");
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
// Apply multiplier
|
||||
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]);
|
||||
if (p != params.end ()) {
|
||||
p->second = tl::Variant (p->second.to_double () * mult);
|
||||
}
|
||||
}
|
||||
|
||||
// issue #1304
|
||||
|
|
@ -537,28 +614,38 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
}
|
||||
|
||||
|
||||
size_t defp = std::numeric_limits<size_t>::max ();
|
||||
if (dynamic_cast<db::DeviceClassCapacitor *> (cls)) {
|
||||
defp = db::DeviceClassCapacitor::param_id_C;
|
||||
} else if (dynamic_cast<db::DeviceClassResistor *> (cls)) {
|
||||
defp = db::DeviceClassResistor::param_id_R;
|
||||
} else if (dynamic_cast<db::DeviceClassInductor *> (cls)) {
|
||||
defp = db::DeviceClassInductor::param_id_L;
|
||||
}
|
||||
|
||||
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 ()) {
|
||||
device->set_parameter_value (i->id (), v->second.to_double () / i->si_scaling ());
|
||||
pv = v->second.to_double ();
|
||||
} else if (i->id () == defp) {
|
||||
device->set_parameter_value (i->id (), value / i->si_scaling ());
|
||||
pv = value;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
device->set_parameter_value (i->id (), pv);
|
||||
}
|
||||
|
||||
apply_parameter_scaling (device);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NetlistSpiceReaderDelegate::apply_parameter_scaling (db::Device *device) const
|
||||
{
|
||||
if (! device || ! device->device_class ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 ()));
|
||||
}
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
NetlistSpiceReaderDelegate::read_value (tl::Extractor &ex, const std::map<std::string, tl::Variant> &variables)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,14 @@ class Circuit;
|
|||
class DeviceClass;
|
||||
class Device;
|
||||
|
||||
struct DB_PUBLIC NetlistSpiceReaderOptions
|
||||
{
|
||||
NetlistSpiceReaderOptions ();
|
||||
|
||||
double scale;
|
||||
double defad, defas, defw, defl;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A delegate to handle various forms of devices and translates them
|
||||
*
|
||||
|
|
@ -55,6 +63,22 @@ public:
|
|||
NetlistSpiceReaderDelegate ();
|
||||
virtual ~NetlistSpiceReaderDelegate ();
|
||||
|
||||
/**
|
||||
* @brief Gets the reader options
|
||||
*/
|
||||
const NetlistSpiceReaderOptions &options () const
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the reader options (non-const)
|
||||
*/
|
||||
NetlistSpiceReaderOptions &options ()
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when the netlist reading starts
|
||||
*/
|
||||
|
|
@ -122,7 +146,6 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Reads a set of string components and parameters from the string
|
||||
* A special key "param:" is recognized for starting a parameter list.
|
||||
*/
|
||||
void parse_element_components (const std::string &s, std::vector<std::string> &strings, std::map<std::string, tl::Variant> &pv, const std::map<std::string, tl::Variant> &variables);
|
||||
|
||||
|
|
@ -139,29 +162,28 @@ public:
|
|||
/**
|
||||
* @brief External interface for start
|
||||
*/
|
||||
void do_start ()
|
||||
{
|
||||
start (mp_netlist);
|
||||
}
|
||||
void do_start ();
|
||||
|
||||
/**
|
||||
* @brief External interface for finish
|
||||
*/
|
||||
void do_finish ()
|
||||
{
|
||||
finish (mp_netlist);
|
||||
}
|
||||
void do_finish ();
|
||||
|
||||
/**
|
||||
* @brief Sets the netlist
|
||||
*/
|
||||
void set_netlist (db::Netlist *netlist)
|
||||
{
|
||||
mp_netlist = netlist;
|
||||
}
|
||||
void set_netlist (db::Netlist *netlist);
|
||||
|
||||
/**
|
||||
* @brief Applies SI and geometry scaling to the device parameters
|
||||
*/
|
||||
void apply_parameter_scaling (db::Device *device) const;
|
||||
|
||||
private:
|
||||
db::Netlist *mp_netlist;
|
||||
NetlistSpiceReaderOptions m_options;
|
||||
|
||||
void def_values_per_element (const std::string &element, std::map<std::string, tl::Variant> &pv);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ static bool to_bool (const tl::Variant &v)
|
|||
}
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars)
|
||||
NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale)
|
||||
: m_def_scale (def_scale)
|
||||
{
|
||||
static variables_type empty_variables;
|
||||
mp_variables = vars ? vars : &empty_variables;
|
||||
|
|
@ -202,7 +203,7 @@ NetlistSpiceReaderExpressionParser::read_atomic_value (tl::Extractor &ex, bool *
|
|||
*status = true;
|
||||
}
|
||||
|
||||
double f = 1.0;
|
||||
double f = m_def_scale;
|
||||
if (*ex == 't' || *ex == 'T') {
|
||||
f = 1e12;
|
||||
} else if (*ex == 'g' || *ex == 'G') {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class DB_PUBLIC NetlistSpiceReaderExpressionParser
|
|||
public:
|
||||
typedef std::map<std::string, tl::Variant> variables_type;
|
||||
|
||||
NetlistSpiceReaderExpressionParser (const variables_type *vars);
|
||||
NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale = 1.0);
|
||||
|
||||
tl::Variant read (tl::Extractor &ex) const;
|
||||
tl::Variant read (const std::string &s) const;
|
||||
|
|
@ -54,6 +54,7 @@ public:
|
|||
|
||||
private:
|
||||
const variables_type *mp_variables;
|
||||
double m_def_scale;
|
||||
|
||||
tl::Variant read_atomic_value (tl::Extractor &ex, bool *status) const;
|
||||
tl::Variant read_dot_expr (tl::Extractor &ex, bool *status) const;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,31 @@ public:
|
|||
mp_shapes->insert (t.transformed (m_trans));
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void insert_polygon (const P &p)
|
||||
{
|
||||
if (p.is_box () && ! m_trans.is_complex ()) {
|
||||
mp_shapes->insert (p.box ().transformed (m_trans));
|
||||
} else {
|
||||
if (mp_shapes->cell () && mp_shapes->cell ()->layout ()) {
|
||||
db::polygon_ref<P, db::Disp> pr (p.transformed (m_trans), mp_shapes->cell ()->layout ()->shape_repository ());
|
||||
mp_shapes->insert (pr);
|
||||
} else {
|
||||
mp_shapes->insert (p.transformed (m_trans));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void operator() (const db::Polygon &p)
|
||||
{
|
||||
insert_polygon (p);
|
||||
}
|
||||
|
||||
void operator() (const db::SimplePolygon &p)
|
||||
{
|
||||
insert_polygon (p);
|
||||
}
|
||||
|
||||
void operator() (const db::EdgePair &ep)
|
||||
{
|
||||
mp_shapes->insert (ep.normalized ().to_polygon (m_ep_sizing).transformed (m_trans));
|
||||
|
|
|
|||
|
|
@ -135,6 +135,27 @@ private:
|
|||
TilingProcessor *mp_proc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
* The inserter is an object having an operator() that takes the object.
|
||||
* This function is responsible for preparing (i.e. clipping) and delivering the output.
|
||||
*/
|
||||
template <class X>
|
||||
void insert (X &inserter, const db::Box &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip) {
|
||||
// clipping
|
||||
db::Box oc = o & tile;
|
||||
if (! oc.empty () && oc.width () > 0 && oc.height () > 0) {
|
||||
inserter (oc);
|
||||
}
|
||||
} else {
|
||||
// no clipping
|
||||
inserter (o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
|
|
@ -144,7 +165,10 @@ private:
|
|||
template <class X>
|
||||
void insert (X &inserter, const db::Polygon &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip && ! o.box ().inside (tile)) {
|
||||
if (o.is_box ()) {
|
||||
// simple case: box
|
||||
insert (inserter, o.box (), tile, clip);
|
||||
} else if (clip && ! o.box ().inside (tile)) {
|
||||
// apply clipping
|
||||
if (o.box ().touches (tile)) {
|
||||
std::vector <db::Polygon> clipped_poly;
|
||||
|
|
@ -168,7 +192,10 @@ void insert (X &inserter, const db::Polygon &o, const db::Box &tile, bool clip)
|
|||
template <class X>
|
||||
void insert (X &inserter, const db::SimplePolygon &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip && ! o.box ().inside (tile)) {
|
||||
if (o.is_box ()) {
|
||||
// simple case: box
|
||||
insert (inserter, o.box (), tile, clip);
|
||||
} else if (clip && ! o.box ().inside (tile)) {
|
||||
// apply clipping
|
||||
if (o.box ().touches (tile)) {
|
||||
std::vector <db::SimplePolygon> clipped_poly;
|
||||
|
|
@ -242,27 +269,6 @@ void insert (X &inserter, const db::Text &o, const db::Box &tile, bool clip)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
* The inserter is an object having an operator() that takes the object.
|
||||
* This function is responsible for preparing (i.e. clipping) and delivering the output.
|
||||
*/
|
||||
template <class X>
|
||||
void insert (X &inserter, const db::Box &o, const db::Box &tile, bool clip)
|
||||
{
|
||||
if (clip) {
|
||||
// clipping
|
||||
db::Box oc = o & tile;
|
||||
if (! oc.empty ()) {
|
||||
inserter (oc);
|
||||
}
|
||||
} else {
|
||||
// no clipping
|
||||
inserter (o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
|
|
|
|||
|
|
@ -141,14 +141,14 @@ struct box_defs
|
|||
"box is also an empty box. The width, height, p1 and p2 attributes of an empty box are undefined. "
|
||||
"Use \\empty? to get a value indicating whether the box is empty.\n"
|
||||
) +
|
||||
constructor ("new", &new_sq,
|
||||
constructor ("new", &new_sq, gsi::arg ("w"),
|
||||
"@brief Creates a square with the given dimensions centered around the origin\n"
|
||||
"\n"
|
||||
"Note that for integer-unit boxes, the dimension has to be an even number to avoid rounding.\n"
|
||||
"\n"
|
||||
"This convenience constructor has been introduced in version 0.28."
|
||||
) +
|
||||
constructor ("new", &new_wh,
|
||||
constructor ("new", &new_wh, gsi::arg ("w"), gsi::arg ("h"),
|
||||
"@brief Creates a rectangle with given width and height, centered around the origin\n"
|
||||
"\n"
|
||||
"Note that for integer-unit boxes, the dimensions have to be an even number to avoid rounding.\n"
|
||||
|
|
|
|||
|
|
@ -790,19 +790,20 @@ Class<db::DeviceTerminalDefinition> decl_dbDeviceTerminalDefinition ("db", "Devi
|
|||
"This class has been added in version 0.26."
|
||||
);
|
||||
|
||||
static db::DeviceParameterDefinition *new_parameter_definition (const std::string &name, const std::string &description, double default_value, bool is_primary, double si_scaling)
|
||||
static db::DeviceParameterDefinition *new_parameter_definition (const std::string &name, const std::string &description, double default_value, bool is_primary, double si_scaling, double geo_scaling_exponent)
|
||||
{
|
||||
return new db::DeviceParameterDefinition (name, description, default_value, is_primary, si_scaling);
|
||||
return new db::DeviceParameterDefinition (name, description, default_value, is_primary, si_scaling, geo_scaling_exponent);
|
||||
}
|
||||
|
||||
Class<db::DeviceParameterDefinition> decl_dbDeviceParameterDefinition ("db", "DeviceParameterDefinition",
|
||||
gsi::constructor ("new", &gsi::new_parameter_definition, gsi::arg ("name"), gsi::arg ("description", std::string ()), gsi::arg ("default_value", 0.0), gsi::arg ("is_primary", true), gsi::arg ("si_scaling", 1.0),
|
||||
gsi::constructor ("new", &gsi::new_parameter_definition, gsi::arg ("name"), gsi::arg ("description", std::string ()), gsi::arg ("default_value", 0.0), gsi::arg ("is_primary", true), gsi::arg ("si_scaling", 1.0), gsi::arg ("geo_scaling_exponent", 0.0),
|
||||
"@brief Creates a new parameter definition.\n"
|
||||
"@param name The name of the parameter\n"
|
||||
"@param description The human-readable description\n"
|
||||
"@param default_value The initial value\n"
|
||||
"@param is_primary True, if the parameter is a primary parameter (see \\is_primary=)\n"
|
||||
"@param si_scaling The scaling factor to SI units\n"
|
||||
"@param geo_scaling_exponent Indicates how the parameter scales with geometrical scaling (0: no scaling, 1.0: linear, 2.0: quadratic)\n"
|
||||
) +
|
||||
gsi::method ("name", &db::DeviceParameterDefinition::name,
|
||||
"@brief Gets the name of the parameter."
|
||||
|
|
@ -834,7 +835,26 @@ 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, this factor will be 1e-6."
|
||||
"For parameters in micrometers - for example W and L of MOS devices - this factor can be set to 1e-6 to reflect "
|
||||
"the unit."
|
||||
) +
|
||||
gsi::method ("si_scaling=", &db::DeviceParameterDefinition::set_si_scaling,
|
||||
"@brief Sets the scaling factor to SI units.\n"
|
||||
"\n"
|
||||
"This setter has been added in version 0.28.6."
|
||||
) +
|
||||
gsi::method ("geo_scaling_exponent", &db::DeviceParameterDefinition::geo_scaling_exponent,
|
||||
"@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"
|
||||
"\n"
|
||||
"This attribute has been added in version 0.28.6."
|
||||
) +
|
||||
gsi::method ("geo_scaling_exponent=", &db::DeviceParameterDefinition::set_geo_scaling_exponent,
|
||||
"@brief Sets the geometry scaling exponent.\n"
|
||||
"See \\geo_scaling_exponent for details.\n"
|
||||
"\n"
|
||||
"This attribute has been added in version 0.28.6."
|
||||
) +
|
||||
gsi::method ("id", &db::DeviceParameterDefinition::id,
|
||||
"@brief Gets the ID of the parameter.\n"
|
||||
|
|
@ -2749,6 +2769,16 @@ Class<ParseElementData> db_ParseElementData ("db", "ParseElementData",
|
|||
"This helper class has been introduced in version 0.27.1. Starting with version 0.28.6, named parameters can be string types too.\n"
|
||||
);
|
||||
|
||||
static double get_delegate_scale (const db::NetlistSpiceReaderDelegate *delegate)
|
||||
{
|
||||
return delegate->options ().scale;
|
||||
}
|
||||
|
||||
static void apply_parameter_scaling (const db::NetlistSpiceReaderDelegate *delegate, db::Device *device)
|
||||
{
|
||||
delegate->apply_parameter_scaling (device);
|
||||
}
|
||||
|
||||
Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "NetlistSpiceReaderDelegate",
|
||||
gsi::method_ext ("start", &start_fb, "@hide") +
|
||||
gsi::method_ext ("finish", &finish_fb, "@hide") +
|
||||
|
|
@ -2826,6 +2856,21 @@ Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "Netl
|
|||
"@brief Issues an error with the given message.\n"
|
||||
"Use this method to generate an error."
|
||||
) +
|
||||
gsi::method_ext ("get_scale", &get_delegate_scale,
|
||||
"@brief Gets the scale factor set with '.options scale=...'\n"
|
||||
"This method has been introduced in version 0.28.6."
|
||||
) +
|
||||
gsi::method_ext ("apply_parameter_scaling", &apply_parameter_scaling, gsi::arg ("device"),
|
||||
"@brief Applies parameter scaling to the given device\n"
|
||||
"Applies SI scaling (according to the parameter's si_scaling attribute) and "
|
||||
"geometry scaling (according to the parameter's geo_scale_exponent attribute) to "
|
||||
"the device parameters. Use this method of finish the device when you have created "
|
||||
"a custom device yourself.\n"
|
||||
"\n"
|
||||
"The geometry scale is taken from the '.options scale=...' control statement.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.6."
|
||||
) +
|
||||
gsi::method_ext ("value_from_string", &value_from_string, gsi::arg ("s"), gsi::arg ("variables", db::NetlistSpiceReader::parameters_type (), "{}"),
|
||||
"@brief Translates a string into a value\n"
|
||||
"This function simplifies the implementation of SPICE readers by providing a translation of a unit-annotated string "
|
||||
|
|
|
|||
|
|
@ -704,16 +704,50 @@ TEST(18_XSchemOutput)
|
|||
" subcircuit 'PMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=2.685,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=1.305,AD=0.87,PS=10.74,PD=7.16);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15U,NF=4,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=2.685,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=1.305,AD=0.87,PS=10.74,PD=7.16);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=3.58,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.87,AD=0.435,PS=7.16,PD=3.58);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15U,NF=2,W=1.5U)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=3.58,PD=1.79);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.87,AD=0.435,PS=7.16,PD=3.58);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(19_ngspice_ref)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader19.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit .TOP ();\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=4,W=1.5)' XPMOS (D=Q,G=I,S=VDD,B=VDD);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=4,W=1.5)' XNMOS (D=Q,G=I,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY0 (D=VSS,G=VSS,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY1 (D=VSS,G=VSS,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY2 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15,NF=4,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15,NF=4,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15,NF=2,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15,NF=2,W=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
|
@ -828,3 +862,18 @@ TEST(100_ExpressionParser)
|
|||
EXPECT_EQ (parser.try_read ("\"1+2*(2+1)-1\"", v), true);
|
||||
EXPECT_EQ (v.to_string (), "6");
|
||||
}
|
||||
|
||||
TEST(101_ExpressionParserWithDefScale)
|
||||
{
|
||||
std::map<std::string, tl::Variant> vars;
|
||||
vars["A"] = 17.5;
|
||||
|
||||
tl::Variant v;
|
||||
|
||||
db::NetlistSpiceReaderExpressionParser parser (&vars, 1e-3);
|
||||
|
||||
EXPECT_EQ (parser.read ("1.75").to_string (), "0.00175");
|
||||
EXPECT_EQ (parser.read ("-1.75u").to_string (), "-1.75e-06");
|
||||
EXPECT_EQ (parser.read ("1.75k").to_string (), "1750");
|
||||
EXPECT_EQ (parser.read ("2*A").to_string (), "0.035");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ TEST(2)
|
|||
tp.queue ("_tile && _output(o3, _tile, false)");
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (60,10;60,20;70,20;70,10);polygon (10,10;10,30;30,30;30,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "polygon (50,40;50,70;80,70;80,40)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (60,10;70,20);box (10,10;30,30)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "box (50,40;80,70)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "");
|
||||
|
||||
ly.clear_layer (o1);
|
||||
|
|
@ -164,9 +164,9 @@ TEST(2)
|
|||
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (10,10;10,23;20,23;20,10);polygon (10,23;10,30;20,30;20,23);polygon (20,10;20,23;30,23;30,10);polygon (20,23;20,30;30,30;30,23);polygon (60,10;60,20;70,20;70,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (10,10;20,23);box (10,23;20,30);box (20,10;30,23);box (20,23;30,30);box (60,10;70,20)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "polygon (-5,-2;-5,23;20,23;20,-2);polygon (-5,23;-5,48;20,48;20,23);polygon (-5,48;-5,73;20,73;20,48);polygon (20,-2;20,23;45,23;45,-2);polygon (20,23;20,48;45,48;45,23);polygon (20,48;20,73;45,73;45,48);polygon (45,-2;45,23;70,23;70,-2);polygon (45,23;45,48;70,48;70,23);polygon (45,48;45,73;70,73;70,48);polygon (70,-2;70,23;95,23;95,-2);polygon (70,23;70,48;95,48;95,23);polygon (70,48;70,73;95,73;95,48);polygon (95,-2;95,23;120,23;120,-2);polygon (95,23;95,48;120,48;120,23);polygon (95,48;95,73;120,73;120,48);polygon (120,-2;120,23;145,23;145,-2);polygon (120,23;120,48;145,48;145,23);polygon (120,48;120,73;145,73;145,48)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "box (-5,-2;20,23);box (-5,23;20,48);box (-5,48;20,73);box (20,-2;45,23);box (20,23;45,48);box (20,48;45,73);box (45,-2;70,23);box (45,23;70,48);box (45,48;70,73);box (70,-2;95,23);box (70,23;95,48);box (70,48;95,73);box (95,-2;120,23);box (95,23;120,48);box (95,48;120,73);box (120,-2;145,23);box (120,23;145,48);box (120,48;145,73)");
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -185,8 +185,8 @@ TEST(2)
|
|||
tp.queue ("_output(o3, _tile)");
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (60,10;60,20;70,20;70,10);polygon (10,10;10,30;30,30;30,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "polygon (50,40;50,70;80,70;80,40)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (60,10;70,20);box (10,10;30,30)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "box (50,40;80,70)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "");
|
||||
|
||||
ly.clear_layer (o1);
|
||||
|
|
@ -199,9 +199,9 @@ TEST(2)
|
|||
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (ly, top, o1), "polygon (10,10;10,23;20,23;20,10);polygon (10,23;10,30;20,30;20,23);polygon (20,10;20,23;30,23;30,10);polygon (20,23;20,30;30,30;30,23);polygon (60,10;60,20;70,20;70,10)");
|
||||
EXPECT_EQ (to_s (ly, top, o1), "box (10,10;20,23);box (10,23;20,30);box (20,10;30,23);box (20,23;30,30);box (60,10;70,20)");
|
||||
EXPECT_EQ (to_s (ly, top, o2), "");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "polygon (-5,-2;-5,23;20,23;20,-2);polygon (-5,23;-5,48;20,48;20,23);polygon (-5,48;-5,73;20,73;20,48);polygon (20,-2;20,23;45,23;45,-2);polygon (20,23;20,48;45,48;45,23);polygon (20,48;20,73;45,73;45,48);polygon (45,-2;45,23;70,23;70,-2);polygon (45,23;45,48;70,48;70,23);polygon (45,48;45,73;70,73;70,48);polygon (70,-2;70,23;95,23;95,-2);polygon (70,23;70,48;95,48;95,23);polygon (70,48;70,73;95,73;95,48);polygon (95,-2;95,23;120,23;120,-2);polygon (95,23;95,48;120,48;120,23);polygon (95,48;95,73;120,73;120,48);polygon (120,-2;120,23;145,23;145,-2);polygon (120,23;120,48;145,48;145,23);polygon (120,48;120,73;145,73;145,48)");
|
||||
EXPECT_EQ (to_s (ly, top, o3), "box (-5,-2;20,23);box (-5,23;20,48);box (-5,48;20,73);box (20,-2;45,23);box (20,23;45,48);box (20,48;45,73);box (45,-2;70,23);box (45,23;70,48);box (45,48;70,73);box (70,-2;95,23);box (70,23;95,48);box (70,48;95,73);box (95,-2;120,23);box (95,23;120,48);box (95,48;120,73);box (120,-2;145,23);box (120,23;145,48);box (120,48;145,73)");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -348,8 +348,8 @@ TEST(4)
|
|||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "polygon (1000,2000;1000,4000;3000,4000;3000,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "polygon (1000,2000;1000,4000;3000,4000;3000,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "box (1000,2000;3000,4000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "box (1000,2000;3000,4000)");
|
||||
|
||||
o.clear_layer (l1o);
|
||||
o.clear_layer (l2o);
|
||||
|
|
@ -359,8 +359,8 @@ TEST(4)
|
|||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (3000,2000;3000,4000;1000,4000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "polygon (1000,2000;1000,4000;3000,4000;3000,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "polygon (1000,2000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "box (1000,2000;3000,4000)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "box (1000,2000;3010,4010)");
|
||||
|
||||
o.clear_layer (l1o);
|
||||
o.clear_layer (l2o);
|
||||
|
|
@ -370,7 +370,7 @@ TEST(4)
|
|||
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (1000,4000;1000,4010;1510,4010;1510,4000);polygon (1510,4000;1510,4010;2510,4010;2510,4000);polygon (3000,2000;3000,2510;3010,2510;3010,2000);polygon (3000,2510;3000,3510;3010,3510;3010,2510);polygon (3000,3510;3000,4000;2510,4000;2510,4010;3010,4010;3010,3510)");
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (3000,3510;3000,4000;2510,4000;2510,4010;3010,4010;3010,3510);box (1000,4000;1510,4010);box (1510,4000;2510,4010);box (3000,2000;3010,2510);box (3000,2510;3010,3510)");
|
||||
|
||||
o.clear_layer (l1o);
|
||||
o.clear_layer (l2o);
|
||||
|
|
@ -380,9 +380,9 @@ TEST(4)
|
|||
tp.set_scale_to_dbu (false);
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "polygon (100,200;100,400;300,400;300,200);polygon (1000,2000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "polygon (100,200;100,400;300,400;300,200)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "polygon (1000,2000;1000,4010;3010,4010;3010,2000)");
|
||||
EXPECT_EQ (to_s (o, topo, l1o), "box (100,200;300,400);box (1000,2000;3010,4010)");
|
||||
EXPECT_EQ (to_s (o, topo, l2o), "box (100,200;300,400)");
|
||||
EXPECT_EQ (to_s (o, topo, l3o), "box (1000,2000;3010,4010)");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5148,9 +5148,6 @@ CODE
|
|||
|
||||
m = with_left ? "fill_with_left" : "fill"
|
||||
|
||||
# generation of new cells not tested in deep mode
|
||||
@deep && raise("#{m} command not supported in deep mode currently")
|
||||
|
||||
(@engine._output_layout && @engine._output_cell) || raise("#{m} command needs an output layout and output cell")
|
||||
|
||||
source = @engine.source
|
||||
|
|
|
|||
|
|
@ -1302,6 +1302,16 @@ TEST(47_fillWithOverlappingBoxesTiled)
|
|||
run_test (_this, "47", false);
|
||||
}
|
||||
|
||||
TEST(47b_fillWithUsingOutput)
|
||||
{
|
||||
run_test (_this, "47b", false);
|
||||
}
|
||||
|
||||
TEST(47bd_fillWithUsingOutputDeep)
|
||||
{
|
||||
run_test (_this, "47b", true);
|
||||
}
|
||||
|
||||
TEST(48_drcWithFragments)
|
||||
{
|
||||
run_test (_this, "48", false);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
* This file has been created automatically
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <QByteArrayMatcher>
|
||||
#include "gsiQt.h"
|
||||
#include "gsiQtCoreCommon.h"
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ BEGIN_PROTECTED
|
|||
|
||||
try {
|
||||
|
||||
view ()->manager ()->transaction (tl::to_string (QObject::tr ("Export Markers")));
|
||||
db::Transaction transaction (view ()->is_editable () ? view ()->manager () : 0, tl::to_string (QObject::tr ("Export Markers")));
|
||||
|
||||
std::vector <const Category *> categories;
|
||||
for (rdb::Categories::const_iterator cat = rdb->categories ().begin (); cat != rdb->categories ().end (); ++cat) {
|
||||
|
|
@ -355,11 +355,9 @@ BEGIN_PROTECTED
|
|||
|
||||
}
|
||||
|
||||
view ()->manager ()->commit ();
|
||||
view ()->update_content ();
|
||||
|
||||
} catch (...) {
|
||||
view ()->manager ()->commit ();
|
||||
view ()->update_content ();
|
||||
throw;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -859,6 +859,14 @@ PythonClassClientData::PythonClassClientData (const gsi::ClassBase *_cls, PyType
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PythonClassClientData::~PythonClassClientData ()
|
||||
{
|
||||
// This destructor is called from the exit code. Python may have shut down already.
|
||||
// We must not try to release the objects in that case and simply don't care about them any longer.
|
||||
py_type_object.release ();
|
||||
py_type_object_static.release ();
|
||||
}
|
||||
|
||||
PyTypeObject *
|
||||
PythonClassClientData::py_type (const gsi::ClassBase &cls_decl, bool as_static)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ struct PythonClassClientData
|
|||
: public gsi::PerClassClientSpecificData
|
||||
{
|
||||
PythonClassClientData (const gsi::ClassBase *_cls, PyTypeObject *_py_type, PyTypeObject *_py_type_static, PythonModule *module);
|
||||
~PythonClassClientData ();
|
||||
|
||||
PythonPtr py_type_object;
|
||||
PythonPtr py_type_object_static;
|
||||
|
|
|
|||
|
|
@ -151,6 +151,13 @@ PythonPtr::~PythonPtr ()
|
|||
Py_XDECREF (mp_obj);
|
||||
}
|
||||
|
||||
PyObject *PythonPtr::release ()
|
||||
{
|
||||
PyObject *obj = mp_obj;
|
||||
mp_obj = NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
PythonPtr::operator bool () const
|
||||
{
|
||||
return mp_obj != NULL;
|
||||
|
|
|
|||
|
|
@ -211,6 +211,14 @@ public:
|
|||
return mp_obj < other.mp_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases the object
|
||||
*
|
||||
* This method returns and resets the raw pointer without changing the
|
||||
* reference count.
|
||||
*/
|
||||
PyObject *release ();
|
||||
|
||||
private:
|
||||
PyObject *mp_obj;
|
||||
};
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -2,252 +2,6 @@ from typing import Any, ClassVar, Dict, Sequence, List, Iterator, Optional
|
|||
from typing import overload
|
||||
import klayout.tl as tl
|
||||
import klayout.db as db
|
||||
class RdbReference:
|
||||
r"""
|
||||
@brief A cell reference inside the report database
|
||||
This class describes a cell reference. Such reference object can be attached to cells to describe instantiations of them in parent cells. Not necessarily all instantiations of a cell in the layout database are represented by references and in some cases there might even be no references at all. The references are merely a hint how a marker must be displayed in the context of any other, potentially parent, cell in the layout database.
|
||||
"""
|
||||
parent_cell_id: int
|
||||
r"""
|
||||
Getter:
|
||||
@brief Gets parent cell ID for this reference
|
||||
@return The parent cell ID
|
||||
|
||||
Setter:
|
||||
@brief Sets the parent cell ID for this reference
|
||||
"""
|
||||
trans: db.DCplxTrans
|
||||
r"""
|
||||
Getter:
|
||||
@brief Gets the transformation for this reference
|
||||
The transformation describes the transformation of the child cell into the parent cell. In that sense that is the usual transformation of a cell reference.
|
||||
@return The transformation
|
||||
|
||||
Setter:
|
||||
@brief Sets the transformation for this reference
|
||||
"""
|
||||
@classmethod
|
||||
def new(cls, trans: db.DCplxTrans, parent_cell_id: int) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a reference with a given transformation and parent cell ID
|
||||
"""
|
||||
def __copy__(self) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def __deepcopy__(self) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def __init__(self, trans: db.DCplxTrans, parent_cell_id: int) -> None:
|
||||
r"""
|
||||
@brief Creates a reference with a given transformation and parent cell ID
|
||||
"""
|
||||
def _create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def _destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def _destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def _is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def _manage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as managed by the script side.
|
||||
After calling this method on an object, the script side will be responsible for the management of the object. This method may be called if an object is returned from a C++ function and the object is known not to be owned by any C++ instance. If necessary, the script side may delete the object if the script's reference is no longer required.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def _unmanage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as no longer owned by the script side.
|
||||
Calling this method will make this object no longer owned by the script's memory management. Instead, the object must be managed in some other way. Usually this method may be called if it is known that some C++ object holds and manages this object. Technically speaking, this method will turn the script's reference into a weak reference. After the script engine decides to delete the reference, the object itself will still exist. If the object is not managed otherwise, memory leaks will occur.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def assign(self, other: RdbReference) -> None:
|
||||
r"""
|
||||
@brief Assigns another object to self
|
||||
"""
|
||||
def create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def database(self) -> ReportDatabase:
|
||||
r"""
|
||||
@brief Gets the database object that category is associated with
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
"""
|
||||
def destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def dup(self) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
|
||||
class RdbCell:
|
||||
r"""
|
||||
@brief A cell inside the report database
|
||||
This class represents a cell in the report database. There is not necessarily a 1:1 correspondence of RDB cells and layout database cells. Cells have an ID, a name, optionally a variant name and a set of references which describe at least one example instantiation in some parent cell. The references do not necessarily map to references or cover all references in the layout database.
|
||||
"""
|
||||
@classmethod
|
||||
def new(cls) -> RdbCell:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
"""
|
||||
def _create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def _destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def _destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def _is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def _manage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as managed by the script side.
|
||||
After calling this method on an object, the script side will be responsible for the management of the object. This method may be called if an object is returned from a C++ function and the object is known not to be owned by any C++ instance. If necessary, the script side may delete the object if the script's reference is no longer required.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def _unmanage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as no longer owned by the script side.
|
||||
Calling this method will make this object no longer owned by the script's memory management. Instead, the object must be managed in some other way. Usually this method may be called if it is known that some C++ object holds and manages this object. Technically speaking, this method will turn the script's reference into a weak reference. After the script engine decides to delete the reference, the object itself will still exist. If the object is not managed otherwise, memory leaks will occur.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def add_reference(self, ref: RdbReference) -> None:
|
||||
r"""
|
||||
@brief Adds a reference to the references of this cell
|
||||
@param ref The reference to add.
|
||||
"""
|
||||
def clear_references(self) -> None:
|
||||
r"""
|
||||
@brief Removes all references from this cell
|
||||
"""
|
||||
def create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def database(self) -> ReportDatabase:
|
||||
r"""
|
||||
@brief Gets the database object that category is associated with
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
"""
|
||||
def destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def each_item(self) -> Iterator[RdbItem]:
|
||||
r"""
|
||||
@brief Iterates over all items inside the database which are associated with this cell
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
"""
|
||||
def each_reference(self) -> Iterator[RdbReference]:
|
||||
r"""
|
||||
@brief Iterates over all references
|
||||
"""
|
||||
def is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def name(self) -> str:
|
||||
r"""
|
||||
@brief Gets the cell name
|
||||
The cell name is an string that identifies the category in the database. Additionally, a cell may carry a variant identifier which is a string that uniquely identifies a cell in the context of it's variants. The "qualified name" contains both the cell name and the variant name. Cell names are also used to identify report database cell's with layout cells. @return The cell name
|
||||
"""
|
||||
def num_items(self) -> int:
|
||||
r"""
|
||||
@brief Gets the number of items for this cell
|
||||
"""
|
||||
def num_items_visited(self) -> int:
|
||||
r"""
|
||||
@brief Gets the number of visited items for this cell
|
||||
"""
|
||||
def qname(self) -> str:
|
||||
r"""
|
||||
@brief Gets the cell's qualified name
|
||||
The qualified name is a combination of the cell name and optionally the variant name. It is used to identify the cell by name in a unique way.
|
||||
@return The qualified name
|
||||
"""
|
||||
def rdb_id(self) -> int:
|
||||
r"""
|
||||
@brief Gets the cell ID
|
||||
The cell ID is an integer that uniquely identifies the cell. It is used for referring to a cell in \RdbItem for example.
|
||||
@return The cell ID
|
||||
"""
|
||||
def variant(self) -> str:
|
||||
r"""
|
||||
@brief Gets the cell variant name
|
||||
A variant name additionally identifies the cell when multiple cells with the same name are present. A variant name is either assigned automatically or set when creating a cell. @return The cell variant name
|
||||
"""
|
||||
|
||||
class RdbCategory:
|
||||
r"""
|
||||
@brief A category inside the report database
|
||||
|
|
@ -443,6 +197,373 @@ class RdbCategory:
|
|||
This method has been introduced in version 0.23. The flat mode argument has been added in version 0.26. The 'with_properties' argument has been added in version 0.28.
|
||||
"""
|
||||
|
||||
class RdbCell:
|
||||
r"""
|
||||
@brief A cell inside the report database
|
||||
This class represents a cell in the report database. There is not necessarily a 1:1 correspondence of RDB cells and layout database cells. Cells have an ID, a name, optionally a variant name and a set of references which describe at least one example instantiation in some parent cell. The references do not necessarily map to references or cover all references in the layout database.
|
||||
"""
|
||||
@classmethod
|
||||
def new(cls) -> RdbCell:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
"""
|
||||
def _create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def _destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def _destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def _is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def _manage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as managed by the script side.
|
||||
After calling this method on an object, the script side will be responsible for the management of the object. This method may be called if an object is returned from a C++ function and the object is known not to be owned by any C++ instance. If necessary, the script side may delete the object if the script's reference is no longer required.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def _unmanage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as no longer owned by the script side.
|
||||
Calling this method will make this object no longer owned by the script's memory management. Instead, the object must be managed in some other way. Usually this method may be called if it is known that some C++ object holds and manages this object. Technically speaking, this method will turn the script's reference into a weak reference. After the script engine decides to delete the reference, the object itself will still exist. If the object is not managed otherwise, memory leaks will occur.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def add_reference(self, ref: RdbReference) -> None:
|
||||
r"""
|
||||
@brief Adds a reference to the references of this cell
|
||||
@param ref The reference to add.
|
||||
"""
|
||||
def clear_references(self) -> None:
|
||||
r"""
|
||||
@brief Removes all references from this cell
|
||||
"""
|
||||
def create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def database(self) -> ReportDatabase:
|
||||
r"""
|
||||
@brief Gets the database object that category is associated with
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
"""
|
||||
def destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def each_item(self) -> Iterator[RdbItem]:
|
||||
r"""
|
||||
@brief Iterates over all items inside the database which are associated with this cell
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
"""
|
||||
def each_reference(self) -> Iterator[RdbReference]:
|
||||
r"""
|
||||
@brief Iterates over all references
|
||||
"""
|
||||
def is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def name(self) -> str:
|
||||
r"""
|
||||
@brief Gets the cell name
|
||||
The cell name is an string that identifies the category in the database. Additionally, a cell may carry a variant identifier which is a string that uniquely identifies a cell in the context of it's variants. The "qualified name" contains both the cell name and the variant name. Cell names are also used to identify report database cell's with layout cells. @return The cell name
|
||||
"""
|
||||
def num_items(self) -> int:
|
||||
r"""
|
||||
@brief Gets the number of items for this cell
|
||||
"""
|
||||
def num_items_visited(self) -> int:
|
||||
r"""
|
||||
@brief Gets the number of visited items for this cell
|
||||
"""
|
||||
def qname(self) -> str:
|
||||
r"""
|
||||
@brief Gets the cell's qualified name
|
||||
The qualified name is a combination of the cell name and optionally the variant name. It is used to identify the cell by name in a unique way.
|
||||
@return The qualified name
|
||||
"""
|
||||
def rdb_id(self) -> int:
|
||||
r"""
|
||||
@brief Gets the cell ID
|
||||
The cell ID is an integer that uniquely identifies the cell. It is used for referring to a cell in \RdbItem for example.
|
||||
@return The cell ID
|
||||
"""
|
||||
def variant(self) -> str:
|
||||
r"""
|
||||
@brief Gets the cell variant name
|
||||
A variant name additionally identifies the cell when multiple cells with the same name are present. A variant name is either assigned automatically or set when creating a cell. @return The cell variant name
|
||||
"""
|
||||
|
||||
class RdbItem:
|
||||
r"""
|
||||
@brief An item inside the report database
|
||||
An item is the basic information entity in the RDB. It is associated with a cell and a category. It can be assigned values which encapsulate other objects such as strings and geometrical objects. In addition, items can be assigned an image (i.e. a screenshot image) and tags which are basically boolean flags that can be defined freely.
|
||||
"""
|
||||
@property
|
||||
def image(self) -> None:
|
||||
r"""
|
||||
WARNING: This variable can only be set, not retrieved.
|
||||
@brief Sets the attached image from a PixelBuffer object
|
||||
|
||||
This method has been added in version 0.28.
|
||||
"""
|
||||
image_str: str
|
||||
r"""
|
||||
Getter:
|
||||
@brief Gets the image associated with this item as a string
|
||||
@return A base64-encoded image file (in PNG format)
|
||||
|
||||
Setter:
|
||||
@brief Sets the image from a string
|
||||
@param image A base64-encoded image file (preferably in PNG format)
|
||||
"""
|
||||
tags_str: str
|
||||
r"""
|
||||
Getter:
|
||||
@brief Returns a string listing all tags of this item
|
||||
@return A comma-separated list of tags
|
||||
|
||||
Setter:
|
||||
@brief Sets the tags from a string
|
||||
@param tags A comma-separated list of tags
|
||||
"""
|
||||
@classmethod
|
||||
def new(cls) -> RdbItem:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
"""
|
||||
def __copy__(self) -> RdbItem:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def __deepcopy__(self) -> RdbItem:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
"""
|
||||
def _create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def _destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def _destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def _is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def _manage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as managed by the script side.
|
||||
After calling this method on an object, the script side will be responsible for the management of the object. This method may be called if an object is returned from a C++ function and the object is known not to be owned by any C++ instance. If necessary, the script side may delete the object if the script's reference is no longer required.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def _unmanage(self) -> None:
|
||||
r"""
|
||||
@brief Marks the object as no longer owned by the script side.
|
||||
Calling this method will make this object no longer owned by the script's memory management. Instead, the object must be managed in some other way. Usually this method may be called if it is known that some C++ object holds and manages this object. Technically speaking, this method will turn the script's reference into a weak reference. After the script engine decides to delete the reference, the object itself will still exist. If the object is not managed otherwise, memory leaks will occur.
|
||||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def add_tag(self, tag_id: int) -> None:
|
||||
r"""
|
||||
@brief Adds a tag with the given id to the item
|
||||
Each tag can be added once to the item. The tags of an item thus form a set. If a tag with that ID already exists, this method does nothing.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, shape: db.Shape, trans: db.CplxTrans) -> None:
|
||||
r"""
|
||||
@brief Adds a geometrical value object from a shape
|
||||
@param value The shape object from which to take the geometrical object.
|
||||
@param trans The transformation to apply.
|
||||
|
||||
The transformation can be used to convert database units to micron units.
|
||||
|
||||
This method has been introduced in version 0.25.3.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: RdbItemValue) -> None:
|
||||
r"""
|
||||
@brief Adds a value object to the values of this item
|
||||
@param value The value to add.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DBox) -> None:
|
||||
r"""
|
||||
@brief Adds a box object to the values of this item
|
||||
@param value The box to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DEdge) -> None:
|
||||
r"""
|
||||
@brief Adds an edge object to the values of this item
|
||||
@param value The edge to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DEdgePair) -> None:
|
||||
r"""
|
||||
@brief Adds an edge pair object to the values of this item
|
||||
@param value The edge pair to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DPolygon) -> None:
|
||||
r"""
|
||||
@brief Adds a polygon object to the values of this item
|
||||
@param value The polygon to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: float) -> None:
|
||||
r"""
|
||||
@brief Adds a numeric value to the values of this item
|
||||
@param value The value to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: str) -> None:
|
||||
r"""
|
||||
@brief Adds a string object to the values of this item
|
||||
@param value The string to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
def assign(self, other: RdbItem) -> None:
|
||||
r"""
|
||||
@brief Assigns another object to self
|
||||
"""
|
||||
def category_id(self) -> int:
|
||||
r"""
|
||||
@brief Gets the category ID
|
||||
Returns the ID of the category that this item is associated with.
|
||||
@return The category ID
|
||||
"""
|
||||
def cell_id(self) -> int:
|
||||
r"""
|
||||
@brief Gets the cell ID
|
||||
Returns the ID of the cell that this item is associated with.
|
||||
@return The cell ID
|
||||
"""
|
||||
def clear_values(self) -> None:
|
||||
r"""
|
||||
@brief Removes all values from this item
|
||||
"""
|
||||
def create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
Use this method to ensure the C++ object is created, for example to ensure that resources are allocated. Usually C++ objects are created on demand and not necessarily when the script object is created.
|
||||
"""
|
||||
def database(self) -> ReportDatabase:
|
||||
r"""
|
||||
@brief Gets the database object that item is associated with
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
"""
|
||||
def destroy(self) -> None:
|
||||
r"""
|
||||
@brief Explicitly destroys the object
|
||||
Explicitly destroys the object on C++ side if it was owned by the script interpreter. Subsequent access to this object will throw an exception.
|
||||
If the object is not owned by the script, this method will do nothing.
|
||||
"""
|
||||
def destroyed(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the object was already destroyed
|
||||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def dup(self) -> RdbItem:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def each_value(self) -> Iterator[RdbItemValue]:
|
||||
r"""
|
||||
@brief Iterates over all values
|
||||
"""
|
||||
def has_image(self) -> bool:
|
||||
r"""
|
||||
@brief Gets a value indicating that the item has an image attached
|
||||
See \image_str how to obtain the image.
|
||||
|
||||
This method has been introduced in version 0.28.
|
||||
"""
|
||||
def has_tag(self, tag_id: int) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the item has a tag with the given ID
|
||||
@return True, if the item has a tag with the given ID
|
||||
"""
|
||||
def image_pixels(self) -> lay.PixelBuffer:
|
||||
r"""
|
||||
@brief Gets the attached image as a PixelBuffer object
|
||||
|
||||
This method has been added in version 0.28.
|
||||
"""
|
||||
def is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def is_visited(self) -> bool:
|
||||
r"""
|
||||
@brief Gets a value indicating whether the item was already visited
|
||||
@return True, if the item has been visited already
|
||||
"""
|
||||
def remove_tag(self, tag_id: int) -> None:
|
||||
r"""
|
||||
@brief Remove the tag with the given id from the item
|
||||
If a tag with that ID does not exists on this item, this method does nothing.
|
||||
"""
|
||||
|
||||
class RdbItemValue:
|
||||
r"""
|
||||
@brief A value object inside the report database
|
||||
|
|
@ -741,55 +862,46 @@ class RdbItemValue:
|
|||
@return The string
|
||||
"""
|
||||
|
||||
class RdbItem:
|
||||
class RdbReference:
|
||||
r"""
|
||||
@brief An item inside the report database
|
||||
An item is the basic information entity in the RDB. It is associated with a cell and a category. It can be assigned values which encapsulate other objects such as strings and geometrical objects. In addition, items can be assigned an image (i.e. a screenshot image) and tags which are basically boolean flags that can be defined freely.
|
||||
@brief A cell reference inside the report database
|
||||
This class describes a cell reference. Such reference object can be attached to cells to describe instantiations of them in parent cells. Not necessarily all instantiations of a cell in the layout database are represented by references and in some cases there might even be no references at all. The references are merely a hint how a marker must be displayed in the context of any other, potentially parent, cell in the layout database.
|
||||
"""
|
||||
@property
|
||||
def image(self) -> None:
|
||||
r"""
|
||||
WARNING: This variable can only be set, not retrieved.
|
||||
@brief Sets the attached image from a PixelBuffer object
|
||||
|
||||
This method has been added in version 0.28.
|
||||
"""
|
||||
image_str: str
|
||||
parent_cell_id: int
|
||||
r"""
|
||||
Getter:
|
||||
@brief Gets the image associated with this item as a string
|
||||
@return A base64-encoded image file (in PNG format)
|
||||
@brief Gets parent cell ID for this reference
|
||||
@return The parent cell ID
|
||||
|
||||
Setter:
|
||||
@brief Sets the image from a string
|
||||
@param image A base64-encoded image file (preferably in PNG format)
|
||||
@brief Sets the parent cell ID for this reference
|
||||
"""
|
||||
tags_str: str
|
||||
trans: db.DCplxTrans
|
||||
r"""
|
||||
Getter:
|
||||
@brief Returns a string listing all tags of this item
|
||||
@return A comma-separated list of tags
|
||||
@brief Gets the transformation for this reference
|
||||
The transformation describes the transformation of the child cell into the parent cell. In that sense that is the usual transformation of a cell reference.
|
||||
@return The transformation
|
||||
|
||||
Setter:
|
||||
@brief Sets the tags from a string
|
||||
@param tags A comma-separated list of tags
|
||||
@brief Sets the transformation for this reference
|
||||
"""
|
||||
@classmethod
|
||||
def new(cls) -> RdbItem:
|
||||
def new(cls, trans: db.DCplxTrans, parent_cell_id: int) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
@brief Creates a reference with a given transformation and parent cell ID
|
||||
"""
|
||||
def __copy__(self) -> RdbItem:
|
||||
def __copy__(self) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def __deepcopy__(self) -> RdbItem:
|
||||
def __deepcopy__(self) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, trans: db.DCplxTrans, parent_cell_id: int) -> None:
|
||||
r"""
|
||||
@brief Creates a new object of this class
|
||||
@brief Creates a reference with a given transformation and parent cell ID
|
||||
"""
|
||||
def _create(self) -> None:
|
||||
r"""
|
||||
|
|
@ -828,90 +940,10 @@ class RdbItem:
|
|||
|
||||
Usually it's not required to call this method. It has been introduced in version 0.24.
|
||||
"""
|
||||
def add_tag(self, tag_id: int) -> None:
|
||||
r"""
|
||||
@brief Adds a tag with the given id to the item
|
||||
Each tag can be added once to the item. The tags of an item thus form a set. If a tag with that ID already exists, this method does nothing.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: float) -> None:
|
||||
r"""
|
||||
@brief Adds a numeric value to the values of this item
|
||||
@param value The value to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: RdbItemValue) -> None:
|
||||
r"""
|
||||
@brief Adds a value object to the values of this item
|
||||
@param value The value to add.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DBox) -> None:
|
||||
r"""
|
||||
@brief Adds a box object to the values of this item
|
||||
@param value The box to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DEdge) -> None:
|
||||
r"""
|
||||
@brief Adds an edge object to the values of this item
|
||||
@param value The edge to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DEdgePair) -> None:
|
||||
r"""
|
||||
@brief Adds an edge pair object to the values of this item
|
||||
@param value The edge pair to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: db.DPolygon) -> None:
|
||||
r"""
|
||||
@brief Adds a polygon object to the values of this item
|
||||
@param value The polygon to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, value: str) -> None:
|
||||
r"""
|
||||
@brief Adds a string object to the values of this item
|
||||
@param value The string to add.
|
||||
This method has been introduced in version 0.25 as a convenience method.
|
||||
"""
|
||||
@overload
|
||||
def add_value(self, shape: db.Shape, trans: db.CplxTrans) -> None:
|
||||
r"""
|
||||
@brief Adds a geometrical value object from a shape
|
||||
@param value The shape object from which to take the geometrical object.
|
||||
@param trans The transformation to apply.
|
||||
|
||||
The transformation can be used to convert database units to micron units.
|
||||
|
||||
This method has been introduced in version 0.25.3.
|
||||
"""
|
||||
def assign(self, other: RdbItem) -> None:
|
||||
def assign(self, other: RdbReference) -> None:
|
||||
r"""
|
||||
@brief Assigns another object to self
|
||||
"""
|
||||
def category_id(self) -> int:
|
||||
r"""
|
||||
@brief Gets the category ID
|
||||
Returns the ID of the category that this item is associated with.
|
||||
@return The category ID
|
||||
"""
|
||||
def cell_id(self) -> int:
|
||||
r"""
|
||||
@brief Gets the cell ID
|
||||
Returns the ID of the cell that this item is associated with.
|
||||
@return The cell ID
|
||||
"""
|
||||
def clear_values(self) -> None:
|
||||
r"""
|
||||
@brief Removes all values from this item
|
||||
"""
|
||||
def create(self) -> None:
|
||||
r"""
|
||||
@brief Ensures the C++ object is created
|
||||
|
|
@ -919,7 +951,7 @@ class RdbItem:
|
|||
"""
|
||||
def database(self) -> ReportDatabase:
|
||||
r"""
|
||||
@brief Gets the database object that item is associated with
|
||||
@brief Gets the database object that category is associated with
|
||||
|
||||
This method has been introduced in version 0.23.
|
||||
"""
|
||||
|
|
@ -935,48 +967,16 @@ class RdbItem:
|
|||
This method returns true, if the object was destroyed, either explicitly or by the C++ side.
|
||||
The latter may happen, if the object is owned by a C++ object which got destroyed itself.
|
||||
"""
|
||||
def dup(self) -> RdbItem:
|
||||
def dup(self) -> RdbReference:
|
||||
r"""
|
||||
@brief Creates a copy of self
|
||||
"""
|
||||
def each_value(self) -> Iterator[RdbItemValue]:
|
||||
r"""
|
||||
@brief Iterates over all values
|
||||
"""
|
||||
def has_image(self) -> bool:
|
||||
r"""
|
||||
@brief Gets a value indicating that the item has an image attached
|
||||
See \image_str how to obtain the image.
|
||||
|
||||
This method has been introduced in version 0.28.
|
||||
"""
|
||||
def has_tag(self, tag_id: int) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the item has a tag with the given ID
|
||||
@return True, if the item has a tag with the given ID
|
||||
"""
|
||||
def image_pixels(self) -> lay.PixelBuffer:
|
||||
r"""
|
||||
@brief Gets the attached image as a PixelBuffer object
|
||||
|
||||
This method has been added in version 0.28.
|
||||
"""
|
||||
def is_const_object(self) -> bool:
|
||||
r"""
|
||||
@brief Returns a value indicating whether the reference is a const reference
|
||||
This method returns true, if self is a const reference.
|
||||
In that case, only const methods may be called on self.
|
||||
"""
|
||||
def is_visited(self) -> bool:
|
||||
r"""
|
||||
@brief Gets a value indicating whether the item was already visited
|
||||
@return True, if the item has been visited already
|
||||
"""
|
||||
def remove_tag(self, tag_id: int) -> None:
|
||||
r"""
|
||||
@brief Remove the tag with the given id from the item
|
||||
If a tag with that ID does not exists on this item, this method does nothing.
|
||||
"""
|
||||
|
||||
class ReportDatabase:
|
||||
r"""
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -54,11 +54,26 @@ INSTALLS = lib_target
|
|||
msvc {
|
||||
QMAKE_POST_LINK += && $(COPY) $$shell_path($$PWD/distutils_src/klayout/$$PYI) $$shell_path($$DESTDIR_PYMOD)
|
||||
} else {
|
||||
QMAKE_POST_LINK += && $(MKDIR) $$DESTDIR_PYMOD/$$REALMODULE && $(COPY) $$PWD/distutils_src/klayout/$$PYI $$DESTDIR_PYMOD
|
||||
QMAKE_POST_LINK += && $(MKDIR) $$DESTDIR_PYMOD && $(COPY) $$PWD/distutils_src/klayout/$$PYI $$DESTDIR_PYMOD
|
||||
}
|
||||
|
||||
POST_TARGETDEPS += $$PWD/distutils_src/klayout/$$PYI
|
||||
|
||||
# INSTALLS needs to be inside a lib or app templates.
|
||||
modpyi_target.path = $$PREFIX/pymod/klayout
|
||||
# This would be nice:
|
||||
# init_target.files += $$DESTDIR_PYMOD/$$REALMODULE/*
|
||||
# but some Qt versions need this explicitly:
|
||||
msvc {
|
||||
modpyi_target.extra = $(INSTALL_PROGRAM) $$shell_path($$DESTDIR_PYMOD/$$PYI) $$shell_path($(INSTALLROOT)$$PREFIX/pymod/klayout)
|
||||
} else {
|
||||
modpyi_target.extra = $(INSTALL_PROGRAM) $$DESTDIR_PYMOD/$$PYI $(INSTALLROOT)$$PREFIX/pymod/klayout
|
||||
}
|
||||
|
||||
# Not yet. As long as .pyi files are not generated automatically,
|
||||
# this does not make much sense:
|
||||
# INSTALLS += modpyi_target
|
||||
|
||||
}
|
||||
|
||||
!equals(REALMODULE, "") {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
* Test
|
||||
|
||||
.options scale=1e-6
|
||||
|
||||
.model sky130_fd_pr__pfet_01v8 NMOS level=8 version=3.3.0
|
||||
.model sky130_fd_pr__nfet_01v8 NMOS level=8 version=3.3.0
|
||||
|
||||
XXpmos Q I VDD VDD pmos4_standard w=1.5 l=0.15 nf=4
|
||||
XXnmos Q I VSS VSS nmos4_standard w=1.5 l=0.15 nf=4
|
||||
XXDUMMY0 VSS VSS VSS VSS nmos4_standard w=1.5 l=0.15 nf=2
|
||||
XXDUMMY1 VSS VSS VSS VSS nmos4_standard w=1.5 l=0.15 nf=2
|
||||
XXDUMMY2 VDD VDD VDD VDD pmos4_standard w=1.5 l=0.15 nf=2
|
||||
XXDUMMY3 VDD VDD VDD VDD pmos4_standard w=1.5 l=0.15 nf=2
|
||||
|
||||
.subckt pmos4_standard D G S B w=0.1 l=0.018 nf=4
|
||||
MM1 D G S B sky130_fd_pr__pfet_01v8 L=l W='w * nf ' ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
|
||||
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
|
||||
+ m=1
|
||||
.ends
|
||||
|
||||
.subckt nmos4_standard D G S B w=0.1 l=0.018 nf=4
|
||||
MM1 D G S B sky130_fd_pr__nfet_01v8 L=l W='w * nf ' ad='int((nf+1)/2) * W/nf * 0.29' as='int((nf+2)/2) * W/nf * 0.29'
|
||||
+ pd='2*int((nf+1)/2) * (W/nf + 0.29)' ps='2*int((nf+2)/2) * (W/nf + 0.29)' nrd='0.29 / W' nrs='0.29 / W'
|
||||
+ m=1
|
||||
.ends
|
||||
|
||||
.end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
source $drc_test_source
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
to_fill = input(1, 0)
|
||||
|
||||
# Create a fill pattern with a 0.025x0.025 µm box at 2/0
|
||||
pattern = fill_pattern("FILL_CELL").shape(2, 0, box(0, 0, 0.025, 0.025))
|
||||
|
||||
# place every 25 nm
|
||||
to_fill.fill(pattern, hstep(0.025), vstep(0.025))
|
||||
|
||||
# compute remaining parts
|
||||
l2 = input(2, 0)
|
||||
(to_fill - l2).output(100, 0)
|
||||
|
||||
# we cannot use input(..) on the fill output if we use
|
||||
# a separate target layout, so wo do this:
|
||||
layout.layout.write($drc_test_target)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -625,14 +625,9 @@ class DBNetlist_TestClass < TestBase
|
|||
dc.terminal_definitions.each { |pd| names << pd.name }
|
||||
assert_equal(names, [])
|
||||
|
||||
pd = RBA::DeviceParameterDefinition::new("P1", "Parameter 1", 2.0)
|
||||
assert_equal(pd.default_value, 2.0)
|
||||
pd = RBA::DeviceParameterDefinition::new("P1", "Parameter 1")
|
||||
pd.default_value = 1.0
|
||||
assert_equal(pd.default_value, 1.0)
|
||||
pd.is_primary = false
|
||||
assert_equal(pd.is_primary?, false)
|
||||
pd.is_primary = true
|
||||
assert_equal(pd.is_primary?, true)
|
||||
|
||||
dc.add_parameter(pd)
|
||||
|
||||
|
|
@ -1181,6 +1176,24 @@ END
|
|||
|
||||
end
|
||||
|
||||
def test_16_deviceParameterObject
|
||||
|
||||
pd = RBA::DeviceParameterDefinition::new("P1", "Parameter 1", 2.0, false, 17.5, 2.0)
|
||||
assert_equal(pd.default_value, 2.0)
|
||||
pd.default_value = 1.0
|
||||
assert_equal(pd.default_value, 1.0)
|
||||
assert_equal(pd.is_primary?, false)
|
||||
pd.is_primary = true
|
||||
assert_equal(pd.is_primary?, true)
|
||||
assert_equal(pd.si_scaling, 17.5)
|
||||
pd.si_scaling = 1.0
|
||||
assert_equal(pd.si_scaling, 1.0)
|
||||
assert_equal(pd.geo_scaling_exponent, 2.0)
|
||||
pd.geo_scaling_exponent = 1.0
|
||||
assert_equal(pd.geo_scaling_exponent, 1.0)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue