From 9f4f2d58d771b9f2722efa2ad0c1f3391a1a4a38 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 28 Feb 2019 23:56:49 +0100 Subject: [PATCH] First version of antenna check. --- src/db/db/dbLayoutToNetlist.cc | 71 ++++++++++-- src/db/db/dbLayoutToNetlist.h | 19 +++ src/db/unit_tests/dbLayoutToNetlistTests.cc | 122 ++++++++++++++++++++ testdata/algo/antenna_au1.gds | Bin 0 -> 5506 bytes testdata/algo/antenna_l1.gds | Bin 0 -> 2932 bytes 5 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 testdata/algo/antenna_au1.gds create mode 100644 testdata/algo/antenna_l1.gds diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index cc89b9326..ecfeae414 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -30,10 +30,7 @@ namespace db { -static bool is_deep (const db::Region &r) -{ - return dynamic_cast (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 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 > &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 &clusters = m_net_clusters.clusters_per_cell (*cid); + if (clusters.empty ()) { + continue; + } + + for (connected_clusters::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 >::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)); +} + } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 367cf9340..29add2865 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -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 > &diodes = std::vector > ()); + private: // no copying LayoutToNetlist (const db::LayoutToNetlist &other); diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 98a13b305..16594f9c7 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -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 ().layer_map = lmap; + options.get_options ().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 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)); + std::auto_ptr rvia1 (new db::Region (db::RecursiveShapeIterator (ly, tc, via1), dss)); + std::auto_ptr 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); +} + diff --git a/testdata/algo/antenna_au1.gds b/testdata/algo/antenna_au1.gds new file mode 100644 index 0000000000000000000000000000000000000000..c9c5cc89f7f3ab901ca1aab4f556287a7e3e65fc GIT binary patch literal 5506 zcmc(iL1>&s6vzL&*=)Ay8lo&%bWKyDSRr5zk)SLkl^ztMi5f~M9&%7Al9S}nL%<*f zE#x3lO2mjgL=;pER54({97;{AhfspuXsD5z z*AMg}U+dS^r_;Sp?0xJ>Ae8~qHzkoqx*-XmwXuf(IzRQRKut5CbX=*Mtv(ac&+weI2T1n&C{ldpJ%#r*MmAoprJdzU5kP%kCgkk5_z6Ig>#JEsweBP-QRC z;&e6bi7ui)_EpvbUk+CDp6CK@@AGNT71%rF^B&DwZCKN7ZcTP}60P^g#10(Vv`S^DMBd4BTB*sy(1L{x@yBP?m{= zyGA+ggr(Z^%Vu^ejsNTj(aJb*c7#jMYjb5-srG=L_`tCl^SNWJ75&GYgQ421>*w-B zzxM!hc~gV0?^LQipf~=jJny%)0>Y*Rj$gJ^JJYNGWSHnO=PWGo9G;o7R6EnvZ@24* z=wg;=gIBNc*A&rrW0q>)81(6Ru0V9GHf0oy81G&#gJ;(J)bc>(HTE5%K82>X}JCn@EWg0rP`UE_<;05^H`LbWs9_!0f7tofW!^j}R|iazvv^hC2$a`G6K7m0q#5h>Nq zCzDrysSjvqBoela1gFs7RC`0CUtb=Q^~*7tzdgnMd(cwto7Qh+{D(6{=Xw7MuX68u zv)@wfOi%v6*f_Ag*HF%oiC4^7B2+umt8eH1d;SYRDE*^*!cy%_ul{@9uM2~K@Ja!R zWZ6>fOt1bq&c8MX2y-6-?@U{&o$2bI4%c6o+;%pf-!cbs{$6{Y>bb5A&SlkC`hLFi z#X8?Lzu?Xo<9vK(i^r$mA9s9?KGyj^(9}feW&~EU+%w%K1TnD=wtK`)d%Z$ z^ZJ+lEc-xMX+O*UkbN!m?2ps`aef_rtoe=TW6ZDWw`zXQxclq>od17#v&rkSyGNdF z@@mWQt4&^TS?OZ63&CqJ=t5DSc?Iw*gAAi(Yx1@q-E%`Nnd&3=}zUc~Q@oEagS>EzFBX zDE>7*Wersq&>f$4s2eptjlWgndp4~9jT)bJuvS?=7bk!MzaEAAdyzl4w- zjr;LVbMxLm$v4;(>qDxY>D8ayVe~@L75O%!6n*IT>R-$Od-8zrKmmATz*6l@uYP6N z+@OSfgGywImV9&K7j@wG>gB~FH-BNN#5dkKOSLn-`p=h*UMTv-F-y^hey{$>65pVC zPYKIIz*_}NwKHA4cIdeEkLY96KcbIO|A;a zazc5d2qA@K*nqXc?}&w>wL7;1$=t}c>JyuH-Mf_DQq#Th;<_C_B!&o|mt3lufFyhD{d+T$8+k6W+bX^VoLvZ{(G-2|+v z;x20iwpJ)r_ZaN7fS+jesEiAZFU+~hd%|3=(dY96CH+J{ImeQIV09K)H>_0Mqci@C za&F&oBH`*Y9JkX__0+hTow@2CXd{~J00!E)ZFt2@wkTEi=!g%T?laGwX0P~faSn#6 z&+i{h5q+-*22U2*=M_s?K!!Z?_PA;GBgsJckc^ELCR) z{ROsvh+f5sGTgnwFJYqB=PgywG`svfS0MU)(Qu|+b}EkVQ+1{zK2VyLc!uIzJ7)Ys z)tL^zskQisVaXw)Z^yY8eX6cILd@*cf%<_nobRV@!|5HsS?)!p>P$y`K=y^HF~iI- zaI=Hw)2Hf8r+=u@#1o3|Nx7xu;g380SGaF@_keIEubpdyma6OSGFSbZ{Cb5Fe>2ae zQsVpL&iE4*L?6?DaH<7(d)HERrqkbZ)y%&zlK}1?3Cwt1(}Z>nCHaQm}IrGGgl^Xq=zznd*p|D%6r)!!N;dd}-t_>K3z z3r&`)GadN@=R1Ic217YRI!~IjM5sE`>964R`}`3gl>MWw(^7S&)BlFo>qs*o{9K8g zP}Wj)rqh3r^N%C}Ve$rWxz|#4rsx05O-=5Ub@g&tle=1s?`m>y`-huaWW>86dNCH_ jG$(Y^@>$gdZU?|S?%>*K!^6YKId%Y0s?OBv!eRUZQjF_T literal 0 HcmV?d00001