mirror of https://github.com/KLayout/klayout.git
Antenna check: tests added, 'catchall' diode protection
This commit is contained in:
parent
9f4f2d58d7
commit
8d3b94201e
|
|
@ -896,25 +896,36 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg
|
||||||
double ametal = rmetal.area () * dbu * dbu;
|
double ametal = rmetal.area () * dbu * dbu;
|
||||||
|
|
||||||
double r = ratio;
|
double r = ratio;
|
||||||
|
bool skip = false;
|
||||||
|
|
||||||
for (std::vector<std::pair<db::Region *, double> >::const_iterator d = diodes.begin (); d != diodes.end (); ++d) {
|
for (std::vector<std::pair<db::Region *, double> >::const_iterator d = diodes.begin (); d != diodes.end () && ! skip; ++d) {
|
||||||
|
|
||||||
db::Region rdiode;
|
db::Region rdiode;
|
||||||
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (*d->first), db::ICplxTrans (), rdiode);
|
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (*d->first), db::ICplxTrans (), rdiode);
|
||||||
|
|
||||||
r += rdiode.area () * dbu * dbu / d->second;
|
if (fabs (d->second) < db::epsilon) {
|
||||||
|
if (rdiode.area () > 0) {
|
||||||
}
|
skip = true;
|
||||||
|
}
|
||||||
if (tl::verbosity () >= 0 /*50*/) {
|
} else {
|
||||||
tl::info << "cell [" << ly.cell_name (*cid) << "]: agate=" << tl::to_string (agate) << ", ametal=" << tl::to_string (ametal) << ", r=" << tl::sprintf ("%.12g", r);
|
r += rdiode.area () * dbu * dbu * d->second;
|
||||||
}
|
|
||||||
|
|
||||||
if (agate > dbu * dbu && ametal / agate > r + db::epsilon) {
|
|
||||||
db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ());
|
|
||||||
for (db::Region::const_iterator r = rmetal.begin_merged (); ! r.at_end (); ++r) {
|
|
||||||
shapes.insert (*r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! skip) {
|
||||||
|
|
||||||
|
if (tl::verbosity () >= 50) {
|
||||||
|
tl::info << "cell [" << ly.cell_name (*cid) << "]: agate=" << tl::to_string (agate) << ", ametal=" << tl::to_string (ametal) << ", r=" << tl::sprintf ("%.12g", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (agate > dbu * dbu && ametal / agate > r + db::epsilon) {
|
||||||
|
db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ());
|
||||||
|
for (db::Region::const_iterator r = rmetal.begin_merged (); ! r.at_end (); ++r) {
|
||||||
|
shapes.insert (*r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -517,6 +517,11 @@ public:
|
||||||
* A(diode) / Ared[um^2] to the ratio. A(diode) is the area of the
|
* A(diode) / Ared[um^2] to the ratio. A(diode) is the area of the
|
||||||
* diode layer per cluster. Both the diode layer and the Ared value
|
* diode layer per cluster. Both the diode layer and the Ared value
|
||||||
* are specified as pairs in "diodes".
|
* are specified as pairs in "diodes".
|
||||||
|
*
|
||||||
|
* A special case is Ared = 0: in this case, the presence of any shapes
|
||||||
|
* on the diode layer will entirely disable the check on a cluster,
|
||||||
|
* 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, const db::Region &metal, double ratio, const std::vector<std::pair<db::Region *, double> > &diodes = std::vector<std::pair<db::Region *, double> > ());
|
db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector<std::pair<db::Region *, double> > &diodes = std::vector<std::pair<db::Region *, double> > ());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2263,6 +2263,7 @@ TEST(10_Antenna)
|
||||||
unsigned int metal1 = define_layer (ly, lmap, 9);
|
unsigned int metal1 = define_layer (ly, lmap, 9);
|
||||||
unsigned int via1 = define_layer (ly, lmap, 11);
|
unsigned int via1 = define_layer (ly, lmap, 11);
|
||||||
unsigned int metal2 = define_layer (ly, lmap, 12);
|
unsigned int metal2 = define_layer (ly, lmap, 12);
|
||||||
|
unsigned int diode = define_layer (ly, lmap, 1);
|
||||||
|
|
||||||
{
|
{
|
||||||
db::LoadLayoutOptions options;
|
db::LoadLayoutOptions options;
|
||||||
|
|
@ -2283,6 +2284,7 @@ TEST(10_Antenna)
|
||||||
|
|
||||||
db::DeepShapeStore dss;
|
db::DeepShapeStore dss;
|
||||||
|
|
||||||
|
std::auto_ptr<db::Region> rdiode (new db::Region (db::RecursiveShapeIterator (ly, tc, diode), dss));
|
||||||
std::auto_ptr<db::Region> rpoly (new db::Region (db::RecursiveShapeIterator (ly, tc, poly), dss));
|
std::auto_ptr<db::Region> rpoly (new db::Region (db::RecursiveShapeIterator (ly, tc, poly), dss));
|
||||||
std::auto_ptr<db::Region> rcont (new db::Region (db::RecursiveShapeIterator (ly, tc, cont), dss));
|
std::auto_ptr<db::Region> rcont (new db::Region (db::RecursiveShapeIterator (ly, tc, cont), dss));
|
||||||
std::auto_ptr<db::Region> rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1), dss));
|
std::auto_ptr<db::Region> rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1), dss));
|
||||||
|
|
@ -2293,6 +2295,7 @@ TEST(10_Antenna)
|
||||||
ly2.dbu (ly.dbu ());
|
ly2.dbu (ly.dbu ());
|
||||||
db::Cell &top2 = ly2.cell (ly2.add_cell ("TOPTOP"));
|
db::Cell &top2 = ly2.cell (ly2.add_cell ("TOPTOP"));
|
||||||
|
|
||||||
|
rdiode->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (1, 0)));
|
||||||
rpoly->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (6, 0)));
|
rpoly->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (6, 0)));
|
||||||
rcont->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (8, 0)));
|
rcont->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (8, 0)));
|
||||||
rmetal1->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (9, 0)));
|
rmetal1->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (9, 0)));
|
||||||
|
|
@ -2367,6 +2370,72 @@ TEST(10_Antenna)
|
||||||
a2_17.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (202, 0)));
|
a2_17.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (202, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
db::LayoutToNetlist l2n (&dss);
|
||||||
|
|
||||||
|
l2n.register_layer (*rdiode, "diode");
|
||||||
|
l2n.register_layer (*rpoly, "poly");
|
||||||
|
l2n.register_layer (*rcont, "cont");
|
||||||
|
l2n.register_layer (*rmetal1, "metal1");
|
||||||
|
|
||||||
|
// Intra-layer
|
||||||
|
l2n.connect (*rdiode);
|
||||||
|
l2n.connect (*rpoly);
|
||||||
|
l2n.connect (*rcont);
|
||||||
|
l2n.connect (*rmetal1);
|
||||||
|
// Inter-layer
|
||||||
|
l2n.connect (*rdiode, *rcont);
|
||||||
|
l2n.connect (*rpoly, *rcont);
|
||||||
|
l2n.connect (*rcont, *rmetal1);
|
||||||
|
|
||||||
|
l2n.extract_netlist ();
|
||||||
|
|
||||||
|
std::vector<std::pair<db::Region *, double> > diodes;
|
||||||
|
// 8.0 means: increase r by 8.0 for each um^2 of diode attached to a net
|
||||||
|
diodes.push_back (std::make_pair (rdiode.get (), 8.0));
|
||||||
|
|
||||||
|
db::Region a3_3 = l2n.antenna_check (*rpoly, *rmetal1, 3, diodes);
|
||||||
|
db::Region a3_10 = l2n.antenna_check (*rpoly, *rmetal1, 10, diodes);
|
||||||
|
db::Region a3_30 = l2n.antenna_check (*rpoly, *rmetal1, 30, diodes);
|
||||||
|
|
||||||
|
a3_3.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (300, 0)));
|
||||||
|
a3_10.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (301, 0)));
|
||||||
|
a3_30.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (302, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
db::LayoutToNetlist l2n (&dss);
|
||||||
|
|
||||||
|
l2n.register_layer (*rdiode, "diode");
|
||||||
|
l2n.register_layer (*rpoly, "poly");
|
||||||
|
l2n.register_layer (*rcont, "cont");
|
||||||
|
l2n.register_layer (*rmetal1, "metal1");
|
||||||
|
|
||||||
|
// Intra-layer
|
||||||
|
l2n.connect (*rdiode);
|
||||||
|
l2n.connect (*rpoly);
|
||||||
|
l2n.connect (*rcont);
|
||||||
|
l2n.connect (*rmetal1);
|
||||||
|
// Inter-layer
|
||||||
|
l2n.connect (*rdiode, *rcont);
|
||||||
|
l2n.connect (*rpoly, *rcont);
|
||||||
|
l2n.connect (*rcont, *rmetal1);
|
||||||
|
|
||||||
|
l2n.extract_netlist ();
|
||||||
|
|
||||||
|
std::vector<std::pair<db::Region *, double> > diodes;
|
||||||
|
// 0.0 means: skip all nets where there is a rdiode attached
|
||||||
|
diodes.push_back (std::make_pair (rdiode.get (), 0.0));
|
||||||
|
|
||||||
|
db::Region a4_3 = l2n.antenna_check (*rpoly, *rmetal1, 3, diodes);
|
||||||
|
db::Region a4_10 = l2n.antenna_check (*rpoly, *rmetal1, 10, diodes);
|
||||||
|
db::Region a4_30 = l2n.antenna_check (*rpoly, *rmetal1, 30, diodes);
|
||||||
|
|
||||||
|
a4_3.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (400, 0)));
|
||||||
|
a4_10.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (401, 0)));
|
||||||
|
a4_30.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (402, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
std::string au = tl::testsrc ();
|
std::string au = tl::testsrc ();
|
||||||
au = tl::combine_path (au, "testdata");
|
au = tl::combine_path (au, "testdata");
|
||||||
au = tl::combine_path (au, "algo");
|
au = tl::combine_path (au, "algo");
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue