diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc
index 3dbcea43e..9e2d164d5 100644
--- a/src/db/db/dbLayoutToNetlist.cc
+++ b/src/db/db/dbLayoutToNetlist.cc
@@ -1180,7 +1180,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
}
}
-db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector > &diodes)
+db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes)
{
// TODO: that's basically too much .. we only need the clusters
if (! m_netlist_extracted) {
@@ -1210,12 +1210,18 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_p
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (gate), db::ICplxTrans (), rgate, 0);
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (metal), db::ICplxTrans (), rmetal, 0);
- double agate = rgate.area () * dbu * dbu;
+ double agate = 0.0;
+ if (fabs (gate_area_factor) > 1e-6) {
+ agate += rgate.area () * dbu * dbu * gate_area_factor;
+ }
if (fabs (gate_perimeter_factor) > 1e-6) {
agate += rgate.perimeter () * dbu * gate_perimeter_factor;
}
- double ametal = rmetal.area () * dbu * dbu;
+ double ametal = 0.0;
+ if (fabs (metal_area_factor) > 1e-6) {
+ ametal += rmetal.area () * dbu * dbu * metal_area_factor;
+ }
if (fabs (metal_perimeter_factor) > 1e-6) {
ametal += rmetal.perimeter () * dbu * metal_perimeter_factor;
}
diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h
index 13ac9fe7f..63bf835aa 100644
--- a/src/db/db/dbLayoutToNetlist.h
+++ b/src/db/db/dbLayoutToNetlist.h
@@ -733,9 +733,9 @@ public:
* The area computation of gate and metal happens by taking the polygon
* area (A) and perimeter (P) into account:
*
- * A(antenna) = A + P * f
+ * A(antenna) = A + P * t
*
- * where f is the perimeter factor. The unit of the area factor is
+ * where t is the perimeter factor. The unit of this area factor is
* micrometers.
*
* The limit ratio can be modified by the presence of connections to
@@ -750,7 +750,10 @@ public:
* regardless of the diode's area.
* In other words: any diode will make the net safe against antenna discharge.
*/
- db::Region antenna_check (const db::Region &gate, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > ());
+ db::Region antenna_check (const db::Region &gate, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > ())
+ {
+ return antenna_check (gate, 1.0, gate_perimeter_factor, metal, 1.0, metal_perimeter_factor, ratio, diodes);
+ }
/**
* @brief Variant of the antennna check not using the perimeter
@@ -758,9 +761,21 @@ public:
*/
db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector > &diodes = std::vector > ())
{
- return antenna_check (gate, 0.0, metal, 0.0, ratio, diodes);
+ return antenna_check (gate, 1.0, 0.0, metal, 1.0, 0.0, ratio, diodes);
}
+ /**
+ * @brief Variant of the antenna check providing an area scale factor
+ *
+ * This version provides an additional area scale factor f, so the effective area becomes
+ *
+ * A(antenna) = A * f + P * t
+ *
+ * where f is the area scale factor and t the perimeter scale factor. This version allows to ignore the
+ * area contribution entirely and switch to a perimeter-based antenna check by setting f to zero.
+ */
+ db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > ());
+
/**
* @brief Saves the database to the given path
*
diff --git a/src/db/db/dbLibrary.cc b/src/db/db/dbLibrary.cc
index fec55c29b..6c0ca490c 100644
--- a/src/db/db/dbLibrary.cc
+++ b/src/db/db/dbLibrary.cc
@@ -46,6 +46,39 @@ Library::~Library ()
// .. nothing yet ..
}
+bool
+Library::is_for_technology (const std::string &name) const
+{
+ return m_technologies.find (name) != m_technologies.end ();
+}
+
+bool
+Library::for_technologies () const
+{
+ return ! m_technologies.empty ();
+}
+
+void
+Library::set_technology (const std::string &t)
+{
+ m_technologies.clear ();
+ if (! t.empty ()) {
+ m_technologies.insert (t);
+ }
+}
+
+void
+Library::clear_technologies ()
+{
+ m_technologies.clear ();
+}
+
+void
+Library::add_technology (const std::string &tech)
+{
+ m_technologies.insert (tech);
+}
+
void
Library::register_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly)
{
diff --git a/src/db/db/dbLibrary.h b/src/db/db/dbLibrary.h
index 422eec281..21cd70061 100644
--- a/src/db/db/dbLibrary.h
+++ b/src/db/db/dbLibrary.h
@@ -31,6 +31,7 @@
#include "tlObject.h"
#include
+#include
namespace db
{
@@ -108,18 +109,38 @@ public:
* If this attribute is non-empty, the library is selected only when the given technology is
* used for the layout.
*/
- const std::string &get_technology () const
+ const std::set &get_technologies () const
{
- return m_technology;
+ return m_technologies;
}
/**
- * @brief Sets the technology name this library is associated with
+ * @brief Gets a value indicating whether this library is associated with the given technology
*/
- void set_technology (const std::string &t)
- {
- m_technology = t;
- }
+ bool is_for_technology (const std::string &name) const;
+
+ /**
+ * @brief Gets a value indicating whether the library is associated with any technology
+ */
+ bool for_technologies () const;
+
+ /**
+ * @brief Sets the technology name this library is associated with
+ *
+ * This will reset the list of technologies to this one.
+ * If the given technology string is empty, the list of technologies will be cleared.
+ */
+ void set_technology (const std::string &t);
+
+ /**
+ * @brief Clears the list of technologies this library is associated with
+ */
+ void clear_technologies ();
+
+ /**
+ * @brief Additionally associate the library with the given technology
+ */
+ void add_technology (const std::string &tech);
/**
* @brief Getter for the description property
@@ -198,7 +219,7 @@ public:
private:
std::string m_name;
std::string m_description;
- std::string m_technology;
+ std::set m_technologies;
lib_id_type m_id;
db::Layout m_layout;
std::map m_referrers;
diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc
index 3c0b85fd0..1e5cce32d 100644
--- a/src/db/db/gsiDeclDbLayoutToNetlist.cc
+++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc
@@ -98,7 +98,7 @@ static std::vector l2n_layer_names (const db::LayoutToNetlist *l2n)
return ln;
}
-static db::Region antenna_check2 (db::LayoutToNetlist *l2n, const db::Region &poly, double poly_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector &diodes)
+static db::Region antenna_check3 (db::LayoutToNetlist *l2n, const db::Region &poly, double poly_area_factor, double poly_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector &diodes)
{
std::vector > diode_pairs;
@@ -127,12 +127,17 @@ static db::Region antenna_check2 (db::LayoutToNetlist *l2n, const db::Region &po
}
- return l2n->antenna_check (poly, poly_perimeter_factor, metal, metal_perimeter_factor, ratio, diode_pairs);
+ return l2n->antenna_check (poly, poly_area_factor, poly_perimeter_factor, metal, metal_area_factor, metal_perimeter_factor, ratio, diode_pairs);
+}
+
+static db::Region antenna_check2 (db::LayoutToNetlist *l2n, const db::Region &poly, double poly_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector &diodes)
+{
+ return antenna_check3 (l2n, poly, 1, poly_perimeter_factor, metal, 1, metal_perimeter_factor, ratio, diodes);
}
static db::Region antenna_check (db::LayoutToNetlist *l2n, const db::Region &poly, const db::Region &metal, double ratio, const std::vector &diodes)
{
- return antenna_check2 (l2n, poly, 0, metal, 0, ratio, diodes);
+ return antenna_check3 (l2n, poly, 1, 0, metal, 1, 0, ratio, diodes);
}
Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
@@ -617,15 +622,32 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"The effective area is computed using:\n"
"\n"
"@code\n"
- "Aeff = A + P * f\n"
+ "Aeff = A + P * t\n"
"@/code\n"
"\n"
- "Here Aeff is the area used in the check, A is the polygon area, P the perimeter and f the perimeter factor. "
- "This formula applies to gate polygon area/perimeter with 'gate_perimeter_factor' for f and metal polygon area/perimeter "
+ "Here Aeff is the area used in the check, A is the polygon area, P the perimeter and t the perimeter factor. "
+ "This formula applies to gate polygon area/perimeter with 'gate_perimeter_factor' for t and metal polygon area/perimeter "
"with 'metal_perimeter_factor'. The perimeter_factor has the dimension of micrometers and can be thought of as the width "
"of the material. Essentially the side walls of the material are taking into account for the surface area as well.\n"
"\n"
"This variant has been introduced in version 0.26.6.\n"
+ ) +
+ gsi::method_ext ("antenna_check", &antenna_check3, gsi::arg ("gate"), gsi::arg ("gate_area_factor"), gsi::arg ("gate_perimeter_factor"), gsi::arg ("metal"), gsi::arg ("metal_area_factor"), gsi::arg ("metal_perimeter_factor"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector (), "[]"),
+ "@brief Runs an antenna check on the extracted clusters taking the perimeter into account and providing an area factor\n"
+ "\n"
+ "This (most generic) version of the \\antenna_check method allows taking the perimeter of gate or metal into account and also "
+ "provides a scaling factor for the area part.\n"
+ "The effective area is computed using:\n"
+ "\n"
+ "@code\n"
+ "Aeff = A * f + P * t\n"
+ "@/code\n"
+ "\n"
+ "Here f is the area factor and t the perimeter factor. A is the polygon area and P the polygon perimeter. "
+ "A use case for this variant is to set the area factor to zero. This way, only perimeter contributions are "
+ "considered.\n"
+ "\n"
+ "This variant has been introduced in version 0.26.6.\n"
),
"@brief A generic framework for extracting netlists from layouts\n"
"\n"
diff --git a/src/db/db/gsiDeclDbLibrary.cc b/src/db/db/gsiDeclDbLibrary.cc
index fff5bea12..98f737d88 100644
--- a/src/db/db/gsiDeclDbLibrary.cc
+++ b/src/db/db/gsiDeclDbLibrary.cc
@@ -68,6 +68,16 @@ static void delete_lib (db::Library *lib)
db::LibraryManager::instance ().delete_lib (lib);
}
+static std::string get_technology (db::Library *lib)
+{
+ const std::set &techs = lib->get_technologies ();
+ if (techs.empty ()) {
+ return std::string ();
+ } else {
+ return *techs.begin ();
+ }
+}
+
Class decl_Library ("db", "Library",
gsi::constructor ("new", &new_lib,
"@brief Creates a new, empty library"
@@ -111,18 +121,47 @@ Class decl_Library ("db", "Library",
gsi::method ("description=", &db::Library::set_description, gsi::arg ("description"),
"@brief Sets the libraries' description text\n"
) +
- gsi::method ("technology", &db::Library::get_technology,
+ gsi::method_ext ("#technology", &get_technology,
"@brief Returns name of the technology the library is associated with\n"
"If this attribute is a non-empty string, this library is only offered for "
"selection if the current layout uses this technology.\n"
"\n"
- "This attribute has been introduced in version 0.25."
+ "This attribute has been introduced in version 0.25. In version 0.27 this attribute is deprecated as "
+ "a library can now be associated with multiple technologies."
) +
gsi::method ("technology=", &db::Library::set_technology, gsi::arg ("technology"),
"@brief sets the name of the technology the library is associated with\n"
"\n"
"See \\technology for details. "
- "This attribute has been introduced in version 0.25."
+ "This attribute has been introduced in version 0.25. In version 0.27, a library can be associated with "
+ "multiple technologies and this method will revert the selection to a single one. Passing an empty string "
+ "is equivalent to \\clear_technologies."
+ ) +
+ gsi::method ("clear_technologies", &db::Library::clear_technologies,
+ "@brief Clears the list of technologies the library is associated with.\n"
+ "See also \\add_technology.\n"
+ "\n"
+ "This method has been introduced in version 0.27"
+ ) +
+ gsi::method ("add_technology", &db::Library::add_technology, gsi::arg ("tech"),
+ "@brief Additionally associates the library with the given technology.\n"
+ "See also \\clear_technologies.\n"
+ "\n"
+ "This method has been introduced in version 0.27"
+ ) +
+ gsi::method ("is_for_technology", &db::Library::is_for_technology, gsi::arg ("tech"),
+ "@brief Returns a value indicating whether the library is associated with the given technology.\n"
+ "This method has been introduced in version 0.27"
+ ) +
+ gsi::method ("for_technologies", &db::Library::for_technologies,
+ "@brief Returns a value indicating whether the library is associated with any technology.\n"
+ "The method is equivalent to checking whether the \\technologies list is empty.\n"
+ "\n"
+ "This method has been introduced in version 0.27"
+ ) +
+ gsi::method ("technologies", &db::Library::get_technologies,
+ "@brief Gets the list of technologies this library is associated with.\n"
+ "This method has been introduced in version 0.27"
) +
gsi::method ("layout_const", (const db::Layout &(db::Library::*)() const) &db::Library::layout,
"@brief The layout object where the cells reside that this library defines (const version)\n"
diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc
index 144edcf1f..3e886b16a 100644
--- a/src/db/unit_tests/dbLayoutToNetlistTests.cc
+++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc
@@ -2639,8 +2639,16 @@ TEST(10_Antenna)
a5_5.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (500, 0)));
a5_15.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (501, 0)));
a5_29.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (502, 0)));
- }
+ // with area factor
+ db::Region b5_5 = l2n.antenna_check (*rpoly, 2.0, 0.0, *rmetal2, 1.0, 1.0, 2.5);
+ db::Region b5_15 = l2n.antenna_check (*rpoly, 2.0, 0.0, *rmetal2, 1.0, 1.0, 7.5);
+ db::Region b5_29 = l2n.antenna_check (*rpoly, 2.0, 0.0, *rmetal2, 1.0, 1.0, 14.5);
+
+ b5_5.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (550, 0)));
+ b5_15.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (551, 0)));
+ b5_29.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (552, 0)));
+ }
{
db::LayoutToNetlist l2n (&dss);
@@ -2672,6 +2680,15 @@ TEST(10_Antenna)
a6_3.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (600, 0)));
a6_5.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (601, 0)));
a6_9.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (602, 0)));
+
+ // with area factor
+ db::Region b6_3 = l2n.antenna_check (*rpoly, 1.0, 0.3, *rmetal2, 2.0, 0.0, 6);
+ db::Region b6_5 = l2n.antenna_check (*rpoly, 1.0, 0.3, *rmetal2, 2.0, 0.0, 10);
+ db::Region b6_9 = l2n.antenna_check (*rpoly, 1.0, 0.3, *rmetal2, 2.0, 0.0, 18);
+
+ b6_3.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (650, 0)));
+ b6_5.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (651, 0)));
+ b6_9.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (652, 0)));
}
std::string au = tl::testsrc ();
diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb
index 0a185d477..6c6b6186a 100644
--- a/src/drc/drc/built-in-macros/_drc_engine.rb
+++ b/src/drc/drc/built-in-macros/_drc_engine.rb
@@ -122,11 +122,15 @@ module DRC
end
def area_only(r)
- DRCAreaAndPerimeter::new(r, 0.0)
+ DRCAreaAndPerimeter::new(r, 1.0, 0.0)
+ end
+
+ def perimeter_only(r, f)
+ DRCAreaAndPerimeter::new(r, 0.0, f)
end
def area_and_perimeter(r, f)
- DRCAreaAndPerimeter::new(r, f)
+ DRCAreaAndPerimeter::new(r, 1.0, f)
end
# %DRC%
diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb
index 4006c2054..2c32640ad 100644
--- a/src/drc/drc/built-in-macros/_drc_netter.rb
+++ b/src/drc/drc/built-in-macros/_drc_netter.rb
@@ -370,6 +370,18 @@ module DRC
# errors = antenna_check(gate, ...)
# @/code
#
+ # Finally there is also "perimeter_only". When using this
+ # specification with a thickness value, the area is computed
+ # from the perimeter alone:
+ #
+ # @code
+ # A(eff) = P * t
+ # @/code
+ #
+ # @code
+ # errors = antenna_check(perimeter_only(gate, 0.5), ...)
+ # @/code
+ #
# The error shapes produced by the antenna check are copies
# of the metal shapes on the metal layers of each network
# violating the antenna rule.
@@ -377,11 +389,13 @@ module DRC
def antenna_check(agate, ametal, ratio, *diodes)
gate_perimeter_factor = 0.0
+ gate_area_factor = 1.0
if agate.is_a?(DRC::DRCLayer)
gate = agate
elsif agate.is_a?(DRC::DRCAreaAndPerimeter)
gate = agate.region
gate_perimeter_factor = agate.perimeter_factor
+ gate_area_factor = agate.area_factor
if ! gate.is_a?(DRC::DRCLayer)
raise("gate with area or area_and_perimeter: input argument must be a layer")
end
@@ -392,11 +406,13 @@ module DRC
gate.requires_region("Netter#antenna_check (gate argument)")
metal_perimeter_factor = 0.0
+ metal_area_factor = 1.0
if ametal.is_a?(DRC::DRCLayer)
metal = ametal
elsif ametal.is_a?(DRC::DRCAreaAndPerimeter)
metal = ametal.region
metal_perimeter_factor = ametal.perimeter_factor
+ metal_area_factor = ametal.area_factor
if ! metal.is_a?(DRC::DRCLayer)
raise("metal with area or area_and_perimeter: input argument must be a layer")
end
@@ -421,7 +437,7 @@ module DRC
end
end
- DRC::DRCLayer::new(@engine, @engine._cmd(l2n_data, :antenna_check, gate.data, gate_perimeter_factor, metal.data, metal_perimeter_factor, ratio, dl))
+ DRC::DRCLayer::new(@engine, @engine._cmd(l2n_data, :antenna_check, gate.data, gate_area_factor, gate_perimeter_factor, metal.data, metal_area_factor, metal_perimeter_factor, ratio, dl))
end
diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb
index 9584adcf4..4cbe21533 100644
--- a/src/drc/drc/built-in-macros/_drc_tags.rb
+++ b/src/drc/drc/built-in-macros/_drc_tags.rb
@@ -117,10 +117,12 @@ module DRC
# optional perimeter factor
class DRCAreaAndPerimeter
attr_accessor :region
+ attr_accessor :area_factor
attr_accessor :perimeter_factor
- def initialize(r, f)
+ def initialize(r, f, t)
self.region = r
- self.perimeter_factor = f
+ self.area_factor = f
+ self.perimeter_factor = t
end
end
diff --git a/src/edt/edt/EditorOptionsInst.ui b/src/edt/edt/EditorOptionsInst.ui
index 74a3eb7be..3cd38120a 100644
--- a/src/edt/edt/EditorOptionsInst.ui
+++ b/src/edt/edt/EditorOptionsInst.ui
@@ -1,7 +1,8 @@
-
+
+
EditorOptionsInst
-
-
+
+
0
0
@@ -9,52 +10,66 @@
574
-
+
Form
-
-
- 9
-
-
+
+
6
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
-
-
-
+
+
QFrame::NoFrame
-
+
QFrame::Raised
-
-
- 0
-
-
+
+
6
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
-
-
-
-
- 0
- 0
+
+
+
0
0
-
+
Cell
-
-
-
-
- 7
- 0
+
+
+
0
0
@@ -62,47 +77,41 @@
-
-
-
+
+
...
-
-
-
+
+
Library
-
-
-
- -
-
-
- Qt::Horizontal
+
+
+
+ 0
+ 0
+
-
-
- 40
- 20
-
-
-
+
-
-
+
Qt::Vertical
-
+
QSizePolicy::Fixed
-
+
522
8
@@ -111,99 +120,111 @@
-
-
-
-
- 7
- 7
+
+
+
0
1
-
+
0
-
-
+
+
Geometry
-
-
- 9
-
-
+
+
6
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
-
-
-
+
+
Rotation / Scaling
-
-
+
+
9
-
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
6
-
-
-
-
-
- 0
- 0
+
-
+
+
+
0
0
- -
-
-
+
-
+
+
Mirror
-
+
mirror_cbx
- -
-
-
+
-
+
+
Scaling factor (magnification)
- -
-
-
-
- 0
- 0
+
-
+
+
+
0
0
- -
-
-
+
-
+
+
degree
- -
-
-
+
-
+
+
Rotation angle
- -
-
-
+
-
+
+
(at X-axis before rotation)
@@ -212,182 +233,177 @@
-
-
-
-
- 5
- 5
+
+
+
0
0
-
+
Array Instance
-
+
true
-
-
+
+
9
-
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
6
-
-
-
-
+
-
+
+
Column vector (x,y)
- -
-
-
-
- 0
- 0
+
-
+
+
+
1
0
- -
-
-
+
-
+
+
x =
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- -
-
-
-
- 0
- 0
+
-
+
+
+
1
0
- -
-
-
+
-
+
+
y =
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- -
-
-
-
- 0
- 0
+
-
+
+
+
1
0
- -
-
-
+
-
+
+
y =
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- -
-
-
-
- 0
- 0
+
-
+
+
+
1
0
- -
-
-
+
-
+
+
x =
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- -
-
-
+
-
+
+
Row vector (x,y)
- -
-
-
+
-
+
+
Rows/Columns
- -
-
-
+
-
+
+
columns =
- -
-
-
-
- 0
- 0
+
-
+
+
+
1
0
- -
-
-
+
-
+
+
rows =
- -
-
-
-
- 0
- 0
+
-
+
+
+
1
0
- -
-
-
+
-
+
+
Warning: although row and column vectors can be arbitrary combination,
some design systems only accept orthogonal (rectangular) arrays.
-
+
true
@@ -397,10 +413,10 @@ some design systems only accept orthogonal (rectangular) arrays.
-
-
+
Qt::Vertical
-
+
20
40
@@ -410,26 +426,26 @@ some design systems only accept orthogonal (rectangular) arrays.
-
-
+
+
PCell
-
-
-
+
+
Place origin of cell
-
-
+
Qt::Vertical
-
+
50
8
@@ -462,8 +478,6 @@ some design systems only accept orthogonal (rectangular) arrays.
column_y_le
place_origin_cb
-
-
-
+
diff --git a/src/edt/edt/InstPropertiesPage.ui b/src/edt/edt/InstPropertiesPage.ui
index 0c6eea4c2..ab2f59622 100644
--- a/src/edt/edt/InstPropertiesPage.ui
+++ b/src/edt/edt/InstPropertiesPage.ui
@@ -17,7 +17,16 @@
6
-
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
9
-
@@ -32,7 +41,16 @@
6
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
@@ -84,7 +102,16 @@
6
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
@@ -119,20 +146,14 @@
-
-
-
- -
-
-
- Qt::Horizontal
+
+
+
+ 0
+ 0
+
-
-
- 40
- 20
-
-
-
+
@@ -178,7 +199,16 @@
6
-
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
9
-
@@ -190,7 +220,16 @@
QFrame::Raised
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
@@ -265,7 +304,16 @@
Position / Rotation / Scaling
-
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
9
@@ -393,7 +441,16 @@
true
-
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
9
@@ -629,7 +686,16 @@ some design systems only accept orthogonal (rectangular) arrays.
6
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
diff --git a/src/lay/lay/doc/about/drc_ref_netter.xml b/src/lay/lay/doc/about/drc_ref_netter.xml
index 39eb2a6a0..6d4a91380 100644
--- a/src/lay/lay/doc/about/drc_ref_netter.xml
+++ b/src/lay/lay/doc/about/drc_ref_netter.xml
@@ -167,6 +167,18 @@ errors = antenna_check(area_and_perimeter(gate, 0.0), ...)
errors = antenna_check(gate, ...)
+Finally there is also "perimeter_only". When using this
+specification with a thickness value, the area is computed
+from the perimeter alone:
+
+
+A(eff) = P * t
+
+
+
+errors = antenna_check(perimeter_only(gate, 0.5), ...)
+
+
The error shapes produced by the antenna check are copies
of the metal shapes on the metal layers of each network
violating the antenna rule.
diff --git a/src/lay/lay/layLibraryController.cc b/src/lay/lay/layLibraryController.cc
index b9b304d37..c76f13667 100644
--- a/src/lay/lay/layLibraryController.cc
+++ b/src/lay/lay/layLibraryController.cc
@@ -205,7 +205,7 @@ LibraryController::sync_files ()
}
}
- tl::log << "Registering as '" << lib->get_name () << "' for tech '" << lib->get_technology () << "'";
+ tl::log << "Registering as '" << lib->get_name () << "' for tech '" << p->second << "'";
new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ())));
db::LibraryManager::instance ().register_lib (lib.release ());
diff --git a/src/lay/lay/layTechSetupDialog.cc b/src/lay/lay/layTechSetupDialog.cc
index e89396411..266c42cf6 100644
--- a/src/lay/lay/layTechSetupDialog.cc
+++ b/src/lay/lay/layTechSetupDialog.cc
@@ -135,7 +135,7 @@ TechBaseEditorPage::setup ()
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
const db::Library *lib = db::LibraryManager::instance ().lib (l->second);
- if (lib->get_technology () == tech ()->name ()) {
+ if (lib->is_for_technology (tech ()->name ())) {
std::string text = lib->get_name ();
if (! lib->get_description ().empty ()) {
text += " - " + lib->get_description ();
diff --git a/src/laybasic/laybasic/layHierarchyControlPanel.cc b/src/laybasic/laybasic/layHierarchyControlPanel.cc
index d983e5b64..5ca8186dc 100644
--- a/src/laybasic/laybasic/layHierarchyControlPanel.cc
+++ b/src/laybasic/laybasic/layHierarchyControlPanel.cc
@@ -213,6 +213,7 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa
mp_selector = new QComboBox (this);
mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
+ mp_selector->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed);
ly->addWidget (mp_selector);
mp_search_frame = new QFrame (this);
diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc
index 099c84e63..44d534acf 100644
--- a/src/laybasic/laybasic/layLayoutView.cc
+++ b/src/laybasic/laybasic/layLayoutView.cc
@@ -4739,6 +4739,8 @@ LayoutView::active_library_changed (int /*index*/)
void
LayoutView::cellview_changed (unsigned int index)
{
+ mp_hierarchy_panel->do_update_content (index);
+
cellview_changed_event (index);
if (m_title.empty ()) {
diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc
index 3ef2bb4b6..5209b6f68 100644
--- a/src/laybasic/laybasic/layLibrariesView.cc
+++ b/src/laybasic/laybasic/layLibrariesView.cc
@@ -210,7 +210,8 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char
ly->setContentsMargins (0, 0, 0, 0);
mp_selector = new QComboBox (this);
- mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
+ mp_selector->setObjectName (QString::fromUtf8 ("library_selection"));
+ mp_selector->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed);
ly->addWidget (mp_selector);
mp_search_frame = new QFrame (this);
@@ -771,9 +772,10 @@ LibrariesView::display_string (int n) const
if (! lib->get_description ().empty ()) {
text += " - " + lib->get_description ();
}
- if (! lib->get_technology ().empty ()) {
+ if (lib->for_technologies ()) {
text += " ";
- text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ())));
+ std::string tn = tl::join (std::vector (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ",");
+ text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn)));
}
return text;
}
diff --git a/src/laybasic/laybasic/layWidgets.cc b/src/laybasic/laybasic/layWidgets.cc
index 7c35f9734..aee5a598f 100644
--- a/src/laybasic/laybasic/layWidgets.cc
+++ b/src/laybasic/laybasic/layWidgets.cc
@@ -600,15 +600,16 @@ LibrarySelectionComboBox::update_list ()
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
db::Library *lib = db::LibraryManager::instance ().lib (l->second);
- if (! m_tech_set || lib->get_technology ().empty () || m_tech == lib->get_technology ()) {
+ if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) {
std::string item_text = lib->get_name ();
if (! lib->get_description ().empty ()) {
item_text += " - " + lib->get_description ();
}
- if (m_tech_set && !lib->get_technology ().empty ()) {
+ if (m_tech_set && lib->for_technologies ()) {
item_text += " ";
- item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ())));
+ std::string tn = tl::join (std::vector (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ",");
+ item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn)));
}
addItem (tl::to_qstring (item_text), QVariant ((unsigned int) lib->get_id ()));
diff --git a/src/plugins/streamers/cif/db_plugin/dbCIFWriter.cc b/src/plugins/streamers/cif/db_plugin/dbCIFWriter.cc
index 955eb8569..1b1a98459 100644
--- a/src/plugins/streamers/cif/db_plugin/dbCIFWriter.cc
+++ b/src/plugins/streamers/cif/db_plugin/dbCIFWriter.cc
@@ -165,23 +165,18 @@ CIFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa
}
double a = t.angle();
- while (a < 0) {
- a += 360.0;
- }
- double ya = 0.0, xa = 0.0;
- if (a < 45 || a > 315) {
- xa = 1.0;
- ya = tan(a / 180.0 * M_PI);
- } else if (a < 135) {
- xa = 1.0 / tan(a / 180.0 * M_PI);
- ya = 1.0;
- } else if (a < 225) {
- xa = -1.0;
- ya = tan(a / 180.0 * M_PI);
+ double xa = cos(a / 180.0 * M_PI);
+ double ya = sin(a / 180.0 * M_PI);
+
+ // normalize xa or ya whichever is better
+ double n;
+ if (fabs (xa) >= M_SQRT1_2) {
+ n = 1.0 / fabs (xa);
} else {
- xa = 1.0 / tan(a / 180.0 * M_PI);
- ya = -1.0;
- }
+ n = 1.0 / fabs (ya);
+ }
+ xa *= n;
+ ya *= n;
// TODO: that can be done smarter ...
for (int n = 0; n < 20 && (fabs (xa - floor (0.5 + xa)) > 1e-3 || fabs (ya - floor (0.5 + ya)) > 1e-3); ++n) {
diff --git a/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc b/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc
index 8f1cc2b3a..7b74f0846 100644
--- a/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc
+++ b/src/plugins/streamers/cif/unit_tests/dbCIFReader.cc
@@ -200,3 +200,9 @@ TEST(rot_instances)
{
run_test (_this, tl::testsrc (), "issue_568.cif", "issue_568_au.gds");
}
+
+// Issue #578
+TEST(rot_instances2)
+{
+ run_test (_this, tl::testsrc (), "issue_578.cif", "issue_578_au.gds");
+}
diff --git a/src/rba/unit_tests/rba.cc b/src/rba/unit_tests/rba.cc
index 924514fc9..af7cb5105 100644
--- a/src/rba/unit_tests/rba.cc
+++ b/src/rba/unit_tests/rba.cc
@@ -104,6 +104,7 @@ RUBYTEST (dbGlyphs, "dbGlyphs.rb")
RUBYTEST (dbInstanceTest, "dbInstanceTest.rb")
RUBYTEST (dbInstElementTest, "dbInstElementTest.rb")
RUBYTEST (dbLayerMapping, "dbLayerMapping.rb")
+RUBYTEST (dbLibrary, "dbLibrary.rb")
RUBYTEST (dbLayout, "dbLayout.rb")
RUBYTEST (dbLayoutTest, "dbLayoutTest.rb")
RUBYTEST (dbLayoutDiff, "dbLayoutDiff.rb")
diff --git a/src/rdb/rdb/rdbRVEReader.cc b/src/rdb/rdb/rdbRVEReader.cc
index 2bcdff3cc..14e3139af 100644
--- a/src/rdb/rdb/rdbRVEReader.cc
+++ b/src/rdb/rdb/rdbRVEReader.cc
@@ -83,7 +83,7 @@ public:
std::vector points;
std::vector edges;
- ex = tl::Extractor (m_input_stream.get_line ().c_str ());
+ ex = tl::Extractor (get_line ().c_str ());
ex.read (s, " ");
ex.read (res);
@@ -99,7 +99,7 @@ public:
std::string cat_name;
id_type waived_tag_id = db.tags ().tag ("waived").id ();
- while (! m_input_stream.at_end ()) {
+ while (! at_end ()) {
// TODO: check if this is correct: when a new category is started the
// cell name is reset. Any shape not having a specific cell will go into the
@@ -108,7 +108,7 @@ public:
// Read the category name unless we have some already (that we got when parsing the shapes).
if (cat_name.empty ()) {
- ex = tl::Extractor (m_input_stream.get_line ().c_str ());
+ ex = tl::Extractor (get_line ().c_str ());
const char *start = ex.skip ();
if (! *start) {
break;
@@ -127,11 +127,11 @@ public:
Category *cath = db.create_category (cat_name);
cat_name.clear ();
- if (m_input_stream.at_end ()) {
+ if (at_end ()) {
error (tl::to_string (tr ("Unexpected end of file")));
}
- ex = tl::Extractor (m_input_stream.get_line ().c_str ());
+ ex = tl::Extractor (get_line ().c_str ());
size_t n1, n2, n3;
ex.read (n1);
ex.read (n2);
@@ -142,11 +142,11 @@ public:
std::string desc;
for (size_t i = 0; i < n3; ++i) {
- if (m_input_stream.at_end ()) {
+ if (at_end ()) {
error (tl::to_string (tr ("Unexpected end of file")));
}
- std::string l = m_input_stream.get_line ();
+ std::string l = get_line ();
if (l.size () > 3 && l[0] == 'W' && l[1] == 'E' && isdigit (l[2])) {
size_t n = 0;
@@ -178,12 +178,12 @@ public:
bool waived = (w != waivers.end ());
// TODO: add waiver string somehow ...
- if (m_input_stream.at_end ()) {
+ if (at_end ()) {
warn (tl::to_string (tr ("Unexpected end of file before the specified number of shapes was read - stopping.")));
break;
}
- s = m_input_stream.get_line ();
+ s = get_line ();
ex = tl::Extractor (s.c_str ());
@@ -221,11 +221,11 @@ public:
while (true) {
- if (m_input_stream.at_end ()) {
+ if (at_end ()) {
error (tl::to_string (tr ("Unexpected end of file")));
}
- ex = tl::Extractor (m_input_stream.get_line ().c_str ());
+ ex = tl::Extractor (get_line ().c_str ());
char c = *ex.skip ();
if (isalpha (c)) {
@@ -340,11 +340,11 @@ public:
if (point > 0) {
- if (m_input_stream.at_end ()) {
+ if (at_end ()) {
error (tl::to_string (tr ("Unexpected end of file")));
}
- ex = tl::Extractor (m_input_stream.get_line ().c_str ());
+ ex = tl::Extractor (get_line ().c_str ());
}
@@ -368,11 +368,11 @@ public:
if (point > 0) {
- if (m_input_stream.at_end ()) {
+ if (at_end ()) {
error (tl::to_string (tr ("Unexpected end of file")));
}
- ex = tl::Extractor (m_input_stream.get_line ().c_str ());
+ ex = tl::Extractor (get_line ().c_str ());
}
@@ -424,6 +424,26 @@ public:
private:
tl::TextInputStream m_input_stream;
tl::AbsoluteProgress m_progress;
+ std::string m_line;
+
+ bool at_end ()
+ {
+ return m_input_stream.at_end ();
+ }
+
+ const std::string &get_line ()
+ {
+ m_line.clear ();
+ while (! m_input_stream.at_end ()) {
+ m_line = m_input_stream.get_line ();
+ // skip lines starting with "//" (#522)
+ if (m_line.size () < 2 || m_line[0] != '/' || m_line[1] != '/') {
+ break;
+ }
+ m_line.clear ();
+ }
+ return m_line;
+ }
void warn (const std::string &msg)
{
diff --git a/src/rdb/unit_tests/rdb.cc b/src/rdb/unit_tests/rdb.cc
index d4ba26c0a..106f74874 100644
--- a/src/rdb/unit_tests/rdb.cc
+++ b/src/rdb/unit_tests/rdb.cc
@@ -20,8 +20,6 @@
*/
-
-
#include "rdb.h"
#include "tlUnitTest.h"
#include "dbBox.h"
diff --git a/src/rdb/unit_tests/rdbRVEReaderTests.cc b/src/rdb/unit_tests/rdbRVEReaderTests.cc
new file mode 100644
index 000000000..110398787
--- /dev/null
+++ b/src/rdb/unit_tests/rdbRVEReaderTests.cc
@@ -0,0 +1,78 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2020 Matthias Koefferlein
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "rdb.h"
+#include "rdbReader.h"
+#include "tlUnitTest.h"
+#include "tlFileUtils.h"
+#include "tlLog.h"
+
+void run_rve_test (tl::TestBase *_this, const std::string &fn_rve, const std::string &fn_au)
+{
+ rdb::Database db;
+
+ {
+ tl::InputFile input (tl::testsrc_private () + "/testdata/rve/" + fn_rve);
+ tl::InputStream is (input);
+ rdb::Reader reader (is);
+ reader.read (db);
+ }
+
+ std::string tmp = _this->tmp_file ();
+ db.save (tmp);
+
+ std::string au_path = tl::absolute_file_path (tl::testsrc_private () + "/testdata/rve/" + fn_au);
+
+ std::string txt, au_txt;
+
+ try {
+ tl::InputFile input (au_path);
+ tl::InputStream is (input);
+ tl::TextInputStream ts (is);
+ au_txt = ts.read_all ();
+ } catch (tl::Exception &ex) {
+ tl::error << ex.msg ();
+ }
+
+ {
+ tl::InputFile input (tmp);
+ tl::InputStream is (input);
+ tl::TextInputStream ts (is);
+ txt = ts.read_all ();
+ }
+
+ if (au_txt != txt) {
+ tl::error << "Golden and actual data differs:";
+ tl::error << " cp " << tmp << " " << au_path;
+ }
+ EXPECT_EQ (au_txt == txt, true);
+}
+
+TEST(1)
+{
+ run_rve_test (_this, "rve1.db", "rve1_au.txt");
+}
+
+TEST(2)
+{
+ run_rve_test (_this, "rve2.db", "rve2_au.txt");
+}
diff --git a/src/rdb/unit_tests/unit_tests.pro b/src/rdb/unit_tests/unit_tests.pro
index 2453bc017..ed51891c5 100644
--- a/src/rdb/unit_tests/unit_tests.pro
+++ b/src/rdb/unit_tests/unit_tests.pro
@@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
rdb.cc \
+ rdbRVEReaderTests.cc
INCLUDEPATH += $$RDB_INC $$TL_INC $$DB_INC $$GSI_INC
DEPENDPATH += $$RDB_INC $$TL_INC $$DB_INC $$GSI_INC
diff --git a/testdata/algo/antenna_au1.gds b/testdata/algo/antenna_au1.gds
index 9c56d0a66..7527f097c 100644
Binary files a/testdata/algo/antenna_au1.gds and b/testdata/algo/antenna_au1.gds differ
diff --git a/testdata/cif/issue_578.cif b/testdata/cif/issue_578.cif
new file mode 100644
index 000000000..54695dcd8
--- /dev/null
+++ b/testdata/cif/issue_578.cif
@@ -0,0 +1,18 @@
+(CIF file written 2020-06-04 16:17:46 by KLayout);
+DS 1 1 10;
+9 F;
+L L1D0;
+P 0,0 0,7000 4000,7000 4000,6000 1000,6000 1000,4000 2000,4000 2000,3000 1000,3000 1000,0;
+DF;
+DS 2 1 10;
+9 ALL;
+C1 R1,0 T0,0;
+C1 R1,1 T0,0;
+C1 R0,1 T0,0;
+C1 R-1,-1 T0,0;
+C1 R-1,0 T0,0;
+C1 R-1,1 T0,0;
+C1 R0,-1 T0,0;
+C1 R1,-1 T0,0;
+DF;
+E
diff --git a/testdata/cif/issue_578_au.gds b/testdata/cif/issue_578_au.gds
new file mode 100644
index 000000000..aacd0f06b
Binary files /dev/null and b/testdata/cif/issue_578_au.gds differ
diff --git a/testdata/drc/drcSimpleTests_7.drc b/testdata/drc/drcSimpleTests_7.drc
index 8ed2a0e36..28797e54b 100644
--- a/testdata/drc/drcSimpleTests_7.drc
+++ b/testdata/drc/drcSimpleTests_7.drc
@@ -52,3 +52,10 @@ antenna_check(area_and_perimeter(gate, 70.nm), area_only(metal2), 5.0, diode).ou
antenna_check(area_and_perimeter(gate, 0.07), area_only(metal2), 10.0, diode).output(410)
antenna_check(area_and_perimeter(gate, 0.07), area_only(metal2), 50.0, diode).output(450)
+antenna_check(perimeter_only(gate, 0.07.um), area_only(metal2), 1.0, diode).output(501)
+antenna_check(perimeter_only(gate, 0.07.um), area_only(metal2), 1.5, diode).output(502)
+antenna_check(perimeter_only(gate, 0.07.um), area_only(metal2), 2.0, diode).output(503)
+antenna_check(perimeter_only(gate, 70.nm), area_only(metal2), 5.0, diode).output(505)
+antenna_check(perimeter_only(gate, 0.07), area_only(metal2), 10.0, diode).output(510)
+antenna_check(perimeter_only(gate, 0.07), area_only(metal2), 50.0, diode).output(550)
+
diff --git a/testdata/drc/drcSimpleTests_au7.gds b/testdata/drc/drcSimpleTests_au7.gds
index 2a6e918c2..cb53332ae 100644
Binary files a/testdata/drc/drcSimpleTests_au7.gds and b/testdata/drc/drcSimpleTests_au7.gds differ
diff --git a/testdata/ruby/dbLayoutToNetlist.rb b/testdata/ruby/dbLayoutToNetlist.rb
index a6e3b6922..094eef598 100644
--- a/testdata/ruby/dbLayoutToNetlist.rb
+++ b/testdata/ruby/dbLayoutToNetlist.rb
@@ -798,6 +798,15 @@ END
assert_equal((a5_15.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(501, 0)))).to_s, "")
assert_equal((a5_29.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(502, 0)))).to_s, "")
+ b5_5 = l2n.antenna_check(rpoly, 2.0, 0.0, rmetal2, 1.0, 1.0, 2.5)
+ b5_15 = l2n.antenna_check(rpoly, 2.0, 0.0, rmetal2, 1.0, 1.0, 7.5)
+ b5_29 = l2n.antenna_check(rpoly, 2.0, 0.0, rmetal2, 1.0, 1.0, 14.5)
+
+ # Note: flatten.merged performs some normalization
+ assert_equal((b5_5.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(500, 0)))).to_s, "")
+ assert_equal((b5_15.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(501, 0)))).to_s, "")
+ assert_equal((b5_29.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(502, 0)))).to_s, "")
+
# --- antenna check gate perimeter included
l2n._destroy
@@ -830,6 +839,15 @@ END
assert_equal((a6_5.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(601, 0)))).to_s, "")
assert_equal((a6_9.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(602, 0)))).to_s, "")
+ b6_3 = l2n.antenna_check(rpoly, 1.0, 0.3, rmetal2, 2.0, 0.0, 6)
+ b6_5 = l2n.antenna_check(rpoly, 1.0, 0.3, rmetal2, 2.0, 0.0, 10)
+ b6_9 = l2n.antenna_check(rpoly, 1.0, 0.3, rmetal2, 2.0, 0.0, 18)
+
+ # Note: flatten.merged performs some normalization
+ assert_equal((b6_3.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(600, 0)))).to_s, "")
+ assert_equal((b6_5.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(601, 0)))).to_s, "")
+ assert_equal((b6_9.flatten ^ RBA::Region::new(ly_au.top_cell.begin_shapes_rec(ly_au.layer(602, 0)))).to_s, "")
+
end
end
diff --git a/testdata/ruby/dbLibrary.rb b/testdata/ruby/dbLibrary.rb
new file mode 100644
index 000000000..cd73007a5
--- /dev/null
+++ b/testdata/ruby/dbLibrary.rb
@@ -0,0 +1,93 @@
+# encoding: UTF-8
+
+# KLayout Layout Viewer
+# Copyright (C) 2006-2020 Matthias Koefferlein
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+if !$:.member?(File::dirname($0))
+ $:.push(File::dirname($0))
+end
+
+load("test_prologue.rb")
+
+class DBLibrary_TestClass < TestBase
+
+ def test_1_registration
+
+ lib = RBA::Library::new
+
+ assert_equal(lib.name, "")
+ assert_equal(lib.id, 0)
+
+ lib.register("RBA-unit-test")
+
+ assert_equal(lib.name, "RBA-unit-test")
+ assert_equal(lib.id != 0, true)
+
+ assert_equal(RBA::Library::library_names.member?("RBA-unit-test"), true)
+ assert_equal(RBA::Library::library_by_name("RBA-unit-test").id, lib.id)
+
+ lib.delete
+ assert_equal(RBA::Library::library_by_name("RBA-unit-test"), nil)
+
+ end
+
+ def test_2_attributes
+
+ lib = RBA::Library::new
+
+ lib.description = "42 is the answer"
+ assert_equal(lib.description, "42 is the answer")
+
+ assert_equal(lib.is_for_technology("X"), false)
+ assert_equal(lib.technologies, [])
+ assert_equal(lib.for_technologies, false)
+
+ lib.technology = "X"
+ assert_equal(lib.is_for_technology("X"), true)
+ assert_equal(lib.technologies, ["X"])
+ assert_equal(lib.for_technologies, true)
+
+ lib.technology = ""
+ assert_equal(lib.is_for_technology("X"), false)
+ assert_equal(lib.technologies, [])
+ assert_equal(lib.for_technologies, false)
+
+ lib.add_technology("Y")
+ assert_equal(lib.is_for_technology("X"), false)
+ assert_equal(lib.is_for_technology("Y"), true)
+ assert_equal(lib.technologies, ["Y"])
+ assert_equal(lib.for_technologies, true)
+
+ lib.clear_technologies
+ assert_equal(lib.is_for_technology("Y"), false)
+ assert_equal(lib.technologies, [])
+ assert_equal(lib.for_technologies, false)
+
+ end
+
+ def test_3_layout
+
+ lib = RBA::Library::new
+ lib.layout.create_cell("X")
+ assert_equal(lib.layout.top_cell.name, "X")
+
+ end
+
+end
+
+load("test_epilogue.rb")
+