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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 138 additions and 19 deletions

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

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
*

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"

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

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%

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

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

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.

Binary file not shown.

View File

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

Binary file not shown.

View File

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