mirror of https://github.com/KLayout/klayout.git
First version of antenna check.
This commit is contained in:
parent
f83278207c
commit
9f4f2d58d7
|
|
@ -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 ®ion) 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue