Implemented #579 (perimeter_only mode for antenna check) (#582)

* WIP: added basic feature and tests.

* WIP: provide tests are GSI binding of new antenna check

* Fixed issue #579 (perimeter_only mode for antenna check)

* Updated DRC doc for 'perimeter_only'
This commit is contained in:
Matthias Köfferlein
2020-06-05 10:55:07 +02:00
committed by GitHub
parent 0c0d247c23
commit 2d0a9418f9
12 changed files with 138 additions and 19 deletions
+9 -3
View File
@@ -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<std::pair<const db::Region *, double> > &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<std::pair<const db::Region *, double> > &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;
}
+19 -4
View File
@@ -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<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ());
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<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ())
{
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<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ())
{
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<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ());
/**
* @brief Saves the database to the given path
*
+28 -6
View File
@@ -98,7 +98,7 @@ static std::vector<std::string> 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<tl::Variant> &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<tl::Variant> &diodes)
{
std::vector<std::pair<const db::Region *, double> > 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<tl::Variant> &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<tl::Variant> &diodes)
{
return antenna_check2 (l2n, poly, 0, metal, 0, ratio, diodes);
return antenna_check3 (l2n, poly, 1, 0, metal, 1, 0, ratio, diodes);
}
Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
@@ -617,15 +622,32 @@ Class<db::LayoutToNetlist> 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<tl::Variant> (), "[]"),
"@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"
+18 -1
View File
@@ -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 ();
+6 -2
View File
@@ -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%
+17 -1
View File
@@ -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
+4 -2
View File
@@ -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
+12
View File
@@ -167,6 +167,18 @@ errors = antenna_check(area_and_perimeter(gate, 0.0), ...)
errors = antenna_check(gate, ...)
</pre>
</p><p>
Finally there is also "perimeter_only". When using this
specification with a thickness value, the area is computed
from the perimeter alone:
</p><p>
<pre>
A(eff) = P * t
</pre>
</p><p>
<pre>
errors = antenna_check(perimeter_only(gate, 0.5), ...)
</pre>
</p><p>
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.