mirror of https://github.com/KLayout/klayout.git
* 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:
parent
0c0d247c23
commit
2d0a9418f9
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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%
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue