diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index ecfeae414..125e96e77 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -896,25 +896,36 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg double ametal = rmetal.area () * dbu * dbu; double r = ratio; + bool skip = false; - for (std::vector >::const_iterator d = diodes.begin (); d != diodes.end (); ++d) { + for (std::vector >::const_iterator d = diodes.begin (); d != diodes.end () && ! skip; ++d) { db::Region 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 (tl::verbosity () >= 0 /*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); + if (fabs (d->second) < db::epsilon) { + if (rdiode.area () > 0) { + skip = true; + } + } else { + r += rdiode.area () * dbu * dbu * d->second; } + + } + + 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); + } + } + } } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 29add2865..497cddef8 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -517,6 +517,11 @@ public: * 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 * 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 > &diodes = std::vector > ()); diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 16594f9c7..7e04e113d 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -2263,6 +2263,7 @@ TEST(10_Antenna) unsigned int metal1 = define_layer (ly, lmap, 9); unsigned int via1 = define_layer (ly, lmap, 11); unsigned int metal2 = define_layer (ly, lmap, 12); + unsigned int diode = define_layer (ly, lmap, 1); { db::LoadLayoutOptions options; @@ -2283,6 +2284,7 @@ TEST(10_Antenna) db::DeepShapeStore dss; + std::auto_ptr rdiode (new db::Region (db::RecursiveShapeIterator (ly, tc, diode), dss)); std::auto_ptr rpoly (new db::Region (db::RecursiveShapeIterator (ly, tc, poly), dss)); std::auto_ptr rcont (new db::Region (db::RecursiveShapeIterator (ly, tc, cont), dss)); std::auto_ptr rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1), dss)); @@ -2293,6 +2295,7 @@ TEST(10_Antenna) ly2.dbu (ly.dbu ()); 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))); 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))); @@ -2367,6 +2370,72 @@ TEST(10_Antenna) 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 > 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 > 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 (); au = tl::combine_path (au, "testdata"); au = tl::combine_path (au, "algo"); diff --git a/testdata/algo/antenna_au1.gds b/testdata/algo/antenna_au1.gds index c9c5cc89f..0367b454c 100644 Binary files a/testdata/algo/antenna_au1.gds and b/testdata/algo/antenna_au1.gds differ diff --git a/testdata/algo/antenna_l1.gds b/testdata/algo/antenna_l1.gds index ae0d8979e..97fcd2569 100644 Binary files a/testdata/algo/antenna_l1.gds and b/testdata/algo/antenna_l1.gds differ