Merge pull request #1313 from KLayout/wip2

Wip2
This commit is contained in:
Matthias Köfferlein 2023-03-16 21:22:56 +01:00 committed by GitHub
commit 40848be14b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 44215 additions and 42984 deletions

View File

@ -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"

View File

@ -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], [])

View File

@ -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

View File

@ -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"
);

View File

@ -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);

View File

@ -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 ()));
}
}

View File

@ -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)

View File

@ -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 &);

View File

@ -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)
{

View File

@ -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));
}

View File

@ -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 ());
}
}

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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);
};
}

View File

@ -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') {

View File

@ -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;

View File

@ -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));

View File

@ -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.

View File

@ -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"

View File

@ -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 "

View File

@ -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");
}

View File

@ -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)");
}

View File

@ -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

View File

@ -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);

View File

@ -27,6 +27,7 @@
* This file has been created automatically
*/
#include <limits>
#include <QByteArrayMatcher>
#include "gsiQt.h"
#include "gsiQtCoreCommon.h"

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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, "") {

27
testdata/algo/nreader19.cir vendored Normal file
View File

@ -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

23
testdata/drc/drcSimpleTests_47b.drc vendored Normal file
View File

@ -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)

BIN
testdata/drc/drcSimpleTests_47b.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au47b.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au47bd.gds vendored Normal file

Binary file not shown.

View File

@ -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")