First version of antenna check.

This commit is contained in:
Matthias Koefferlein 2019-02-28 23:56:49 +01:00
parent f83278207c
commit 9f4f2d58d7
5 changed files with 205 additions and 7 deletions

View File

@ -30,10 +30,7 @@
namespace db
{
static bool is_deep (const db::Region &r)
{
return dynamic_cast<const db::DeepRegion *> (r.delegate ()) != 0;
}
static const unsigned int singular_layout_index = 0;
// the iterator provides the hierarchical selection (enabling/disabling cells etc.)
@ -414,8 +411,6 @@ unsigned int LayoutToNetlist::layer_of (const db::Region &region) const
db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell &cell, bool with_device_cells)
{
unsigned int layout_index = 0;
std::set<db::cell_index_type> device_cells;
if (! with_device_cells && mp_netlist.get ()) {
for (db::Netlist::device_abstract_iterator i = mp_netlist->begin_device_abstracts (); i != mp_netlist->end_device_abstracts (); ++i) {
@ -423,7 +418,7 @@ db::CellMapping LayoutToNetlist::cell_mapping_into (db::Layout &layout, db::Cell
}
}
return dss ().cell_mapping_to_original (layout_index, &layout, cell.cell_index (), &device_cells);
return dss ().cell_mapping_to_original (singular_layout_index, &layout, cell.cell_index (), &device_cells);
}
db::CellMapping LayoutToNetlist::const_cell_mapping_into (const db::Layout &layout, const db::Cell &cell)
@ -867,4 +862,66 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
}
}
db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector<std::pair<db::Region *, double> > &diodes)
{
// TODO: that's basically too much .. we only need the clusters
if (! m_netlist_extracted) {
throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet")));
}
db::Layout &ly = dss ().layout ();
double dbu = ly.dbu ();
db::DeepLayer dl (&dss (), singular_layout_index, ly.insert_layer ());
for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) {
const connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (*cid);
if (clusters.empty ()) {
continue;
}
for (connected_clusters<db::PolygonRef>::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
if (! clusters.is_root (*c)) {
continue;
}
db::Region rgate, rmetal;
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (gate), db::ICplxTrans (), rgate);
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (metal), db::ICplxTrans (), rmetal);
double agate = rgate.area () * dbu * dbu;
double ametal = rmetal.area () * dbu * dbu;
double r = ratio;
for (std::vector<std::pair<db::Region *, double> >::const_iterator d = diodes.begin (); d != diodes.end (); ++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);
}
}
}
}
return db::Region (new db::DeepRegion (dl));
}
}

View File

@ -501,6 +501,25 @@ public:
*/
db::Net *probe_net (const db::Region &of_region, const db::Point &point);
/**
* @brief Runs an antenna check on the extracted clusters
*
* The antenna check will traverse all clusters and run an antenna check
* for all root clusters. The antenna ratio is defined by the total
* area of all "metal" shapes divided by the total area of all "gate" shapes
* on the cluster. Of all clusters where the antenna ratio is larger than
* the limit ratio all metal shapes are copied to the output region as
* error markers.
*
* The limit ratio can be modified by the presence of connections to
* other layers (specifically designating diodes for charge removal).
* Each of these layers will modify the ratio by adding a value of
* 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".
*/
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> > ());
private:
// no copying
LayoutToNetlist (const db::LayoutToNetlist &other);

View File

@ -2253,3 +2253,125 @@ TEST(9_FlatExtractionWithExternalDSS)
);
}
TEST(10_Antenna)
{
db::Layout ly;
db::LayerMap lmap;
unsigned int poly = define_layer (ly, lmap, 6);
unsigned int cont = define_layer (ly, lmap, 8);
unsigned int metal1 = define_layer (ly, lmap, 9);
unsigned int via1 = define_layer (ly, lmap, 11);
unsigned int metal2 = define_layer (ly, lmap, 12);
{
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
std::string fn (tl::testsrc ());
fn = tl::combine_path (fn, "testdata");
fn = tl::combine_path (fn, "algo");
fn = tl::combine_path (fn, "antenna_l1.gds");
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly, options);
}
db::Cell &tc = ly.cell (*ly.begin_top_down ());
db::DeepShapeStore 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> rmetal1 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal1), dss));
std::auto_ptr<db::Region> rvia1 (new db::Region (db::RecursiveShapeIterator (ly, tc, via1), dss));
std::auto_ptr<db::Region> rmetal2 (new db::Region (db::RecursiveShapeIterator (ly, tc, metal2), dss));
db::Layout ly2;
ly2.dbu (ly.dbu ());
db::Cell &top2 = ly2.cell (ly2.add_cell ("TOPTOP"));
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)));
rvia1->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (11, 0)));
rmetal2->insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (12, 0)));
{
db::LayoutToNetlist l2n (&dss);
l2n.register_layer (*rpoly, "poly");
l2n.register_layer (*rcont, "cont");
l2n.register_layer (*rmetal1, "metal1");
l2n.register_layer (*rvia1, "via1");
l2n.register_layer (*rmetal2, "metal2");
// Intra-layer
l2n.connect (*rpoly);
l2n.connect (*rcont);
l2n.connect (*rmetal1);
/* not yet:
l2n.connect (*rvia1);
l2n.connect (*rmetal2);
*/
// Inter-layer
l2n.connect (*rpoly, *rcont);
l2n.connect (*rcont, *rmetal1);
/* not yet:
l2n.connect (*rmetal1, *rvia1);
l2n.connect (*rvia1, *rmetal2);
*/
l2n.extract_netlist ();
db::Region a1_3 = l2n.antenna_check (*rpoly, *rmetal1, 3);
db::Region a1_10 = l2n.antenna_check (*rpoly, *rmetal1, 10);
db::Region a1_30 = l2n.antenna_check (*rpoly, *rmetal1, 30);
a1_3.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (100, 0)));
a1_10.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (101, 0)));
a1_30.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (102, 0)));
}
{
db::LayoutToNetlist l2n (&dss);
l2n.register_layer (*rpoly, "poly");
l2n.register_layer (*rcont, "cont");
l2n.register_layer (*rmetal1, "metal1");
l2n.register_layer (*rvia1, "via1");
l2n.register_layer (*rmetal2, "metal2");
// Intra-layer
l2n.connect (*rpoly);
l2n.connect (*rcont);
l2n.connect (*rmetal1);
l2n.connect (*rvia1);
l2n.connect (*rmetal2);
// Inter-layer
l2n.connect (*rpoly, *rcont);
l2n.connect (*rcont, *rmetal1);
l2n.connect (*rmetal1, *rvia1);
l2n.connect (*rvia1, *rmetal2);
l2n.extract_netlist ();
db::Region a2_5 = l2n.antenna_check (*rpoly, *rmetal2, 5);
db::Region a2_10 = l2n.antenna_check (*rpoly, *rmetal2, 10);
db::Region a2_17 = l2n.antenna_check (*rpoly, *rmetal2, 17);
a2_5.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (200, 0)));
a2_10.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (201, 0)));
a2_17.insert_into (&ly2, top2.cell_index (), ly2.insert_layer (db::LayerProperties (202, 0)));
}
std::string au = tl::testsrc ();
au = tl::combine_path (au, "testdata");
au = tl::combine_path (au, "algo");
au = tl::combine_path (au, "antenna_au1.gds");
db::compare_layouts (_this, ly2, au);
}

BIN
testdata/algo/antenna_au1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/antenna_l1.gds vendored Normal file

Binary file not shown.