diff --git a/README.md b/README.md index 8873c3dce..075eae92f 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ For more details see http://www.klayout.org. Building on Linux: -* Qt 4.7 or later (4.6 with some restrictions) or Qt 5 +* Qt 4.7 or later (4.6 with some restrictions), Qt 5 or Qt 6 * gcc 4.6 or later or clang 3.8 or later Building on Windows with MSYS2: -* MSYS2 with gcc, Qt4 or 5, zlib, ruby and python packages installed +* MSYS2 with gcc, Qt4, 5 or 6, zlib, ruby and python packages installed Building on Windows with MSVC 2017: @@ -34,14 +34,10 @@ For more build instructions see http://www.klayout.de/build.html. ## Building instructions (Linux) -### Plain building for Qt4 +### Plain building for Qt4, Qt5 and Qt6 (one Qt version installed) ./build.sh -### Plain building for Qt5 - - ./build.sh -qt5 - ### Building without Qt binding ./build.sh -without-qtbinding diff --git a/src/db/db/dbCommonReader.cc b/src/db/db/dbCommonReader.cc index 315499971..0400621eb 100644 --- a/src/db/db/dbCommonReader.cc +++ b/src/db/db/dbCommonReader.cc @@ -556,6 +556,7 @@ CommonReader::read (db::Layout &layout) void CommonReader::init (const LoadLayoutOptions &options) { + ReaderBase::init (options); CommonReaderBase::init (); db::CommonReaderOptions common_options = options.get_options (); diff --git a/src/db/db/dbCommonReader.h b/src/db/db/dbCommonReader.h index 9610e1634..b5a5a9a19 100644 --- a/src/db/db/dbCommonReader.h +++ b/src/db/db/dbCommonReader.h @@ -237,7 +237,7 @@ protected: friend class CommonReaderLayerMapping; virtual void common_reader_error (const std::string &msg) = 0; - virtual void common_reader_warn (const std::string &msg) = 0; + virtual void common_reader_warn (const std::string &msg, int warn_level = 1) = 0; /** * @brief Merge (and delete) the src_cell into target_cell diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 6b9bf63cc..d8c9114d5 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -1366,9 +1366,10 @@ compute_area_and_perimeter_of_net_shapes (const db::hier_clusters perimeter = ap_collector.perimeter (); } -static void +static db::Point get_merged_shapes_of_net (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes) { + db::Point ref; db::EdgeProcessor ep; // count vertices and reserve space @@ -1380,16 +1381,76 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c size_t p = 0; for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { - ep.insert (rci.trans () * rci->polygon_ref (), ++p); + if (p == 0) { + db::PolygonRef pr = (rci.trans () * rci->polygon_ref ()); + db::PolygonRef::polygon_edge_iterator e = pr.begin_edge (); + if (! e.at_end ()) { + // pick one reference point for the label + ref = (*e).p1 (); + ep.insert (pr, ++p); + } + } else { + ep.insert (rci.trans () * rci->polygon_ref (), ++p); + } } db::ShapeGenerator sg (shapes); db::PolygonGenerator pg (sg, false); db::SimpleMerge op; ep.process (pg, op); + + return ref; } -db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes) +static std::string +create_antenna_msg (double agate, db::Polygon::area_type agate_int, double gate_area_factor, db::Polygon::perimeter_type pgate_int, double gate_perimeter_factor, + double ametal, db::Polygon::area_type ametal_int, double metal_area_factor, db::Polygon::perimeter_type pmetal_int, double metal_perimeter_factor, + const std::vector > &diodes, + const std::vector &adiodes_int, + double r, double ratio, double dbu) +{ + std::string msg; + msg += tl::sprintf ("agate_eff: %.12g, ", agate); + if (fabs (gate_area_factor) > 1e-6) { + msg += tl::sprintf ("agate: %.12g, agate_factor: %.12g, ", agate_int * dbu * dbu, gate_area_factor); + } + if (fabs (gate_perimeter_factor) > 1e-6) { + msg += tl::sprintf ("pgate: %.12g, pgate_factor: %.12g, ", pgate_int * dbu * dbu, gate_perimeter_factor); + } + msg += tl::sprintf ("ametal_eff: %.12g, ", ametal); + if (fabs (metal_area_factor) > 1e-6) { + msg += tl::sprintf ("ametal: %.12g, ametal_factor: %.12g, ", ametal_int * dbu * dbu, metal_area_factor); + } + if (fabs (metal_perimeter_factor) > 1e-6) { + msg += tl::sprintf ("pmetal: %.12g, pmetal_factor: %.12g, ", pmetal_int * dbu * dbu, metal_perimeter_factor); + } + if (! adiodes_int.empty ()) { + msg += "adiodes: ["; + for (auto d = adiodes_int.begin (); d != adiodes_int.end (); ++d) { + if (d != adiodes_int.begin ()) { + msg += ", "; + } + msg += tl::sprintf ("%.12g", *d * dbu * dbu); + } + msg += "], "; + } + if (! diodes.empty ()) { + msg += "diode_factors: ["; + for (auto d = diodes.begin (); d != diodes.end (); ++d) { + if (d != diodes.begin ()) { + msg += ", "; + } + msg += tl::sprintf ("%.12g", d->second); + } + msg += "], "; + } + msg += tl::sprintf ("ratio: %.12g, ", ametal / agate); + msg += tl::sprintf ("max_ratio_eff: %.12g, ", r); + msg += tl::sprintf ("max_ratio: %.12g", ratio); + return msg; +} + +db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes, db::Texts *values) { // TODO: that's basically too much .. we only need the clusters if (! m_netlist_extracted) { @@ -1401,6 +1462,11 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::DeepLayer dl (&dss (), m_layout_index, ly.insert_layer ()); + db::DeepLayer dlv; + if (values) { + dlv = db::DeepLayer (&dss (), m_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); @@ -1408,6 +1474,8 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a continue; } + std::vector adiodes_int; + for (connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { if (! clusters.is_root (*c)) { @@ -1417,13 +1485,18 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a double r = ratio; bool skip = false; - for (std::vector >::const_iterator d = diodes.begin (); d != diodes.end () && ! skip; ++d) { + adiodes_int.clear (); + adiodes_int.reserve (diodes.size ()); + + for (auto d = diodes.begin (); d != diodes.end () && ! skip; ++d) { db::Polygon::area_type adiode_int = 0; db::Polygon::perimeter_type pdiode_int = 0; compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (*d->first), adiode_int, pdiode_int); + adiodes_int.push_back (adiode_int); + if (fabs (d->second) < db::epsilon) { if (adiode_int > 0) { skip = true; @@ -1465,12 +1538,29 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a } 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); + tl::info << "cell [" << ly.cell_name (*cid) << "]: " << + create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, + ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, + diodes, adiodes_int, r, ratio, dbu); } if (ametal / agate > r + db::epsilon) { + db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ()); - get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), shapes); + db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), shapes); + + if (values) { + + // generate a data string with the details of the antenna computation (intentionally like JSON) + std::string msg = create_antenna_msg (agate, agate_int, gate_area_factor, pgate_int, gate_perimeter_factor, + ametal, ametal_int, metal_area_factor, pmetal_int, metal_perimeter_factor, + diodes, adiodes_int, r, ratio, dbu); + + db::Shapes &shapesv = ly.cell (*cid).shapes (dlv.layer ()); + shapesv.insert (db::Text (msg, db::Trans (ref - db::Point ()))); + + } + } } @@ -1481,6 +1571,10 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a } + if (values) { + *values = db::Texts (new db::DeepTexts (dlv)); + } + return db::Region (new db::DeepRegion (dl)); } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 6b04e5cce..f1b099076 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -856,18 +856,18 @@ public: * 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, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > ()) + db::Region antenna_check (const db::Region &gate, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > (), db::Texts *values = 0) { - return antenna_check (gate, 1.0, gate_perimeter_factor, metal, 1.0, metal_perimeter_factor, ratio, diodes); + return antenna_check (gate, 1.0, gate_perimeter_factor, metal, 1.0, metal_perimeter_factor, ratio, diodes, values); } /** * @brief Variant of the antenna check not using the perimeter * This version uses 0 for the perimeter factor hence not taking into account the perimeter at all. */ - db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector > &diodes = std::vector > ()) + db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector > &diodes = std::vector > (), db::Texts *values = 0) { - return antenna_check (gate, 1.0, 0.0, metal, 1.0, 0.0, ratio, diodes); + return antenna_check (gate, 1.0, 0.0, metal, 1.0, 0.0, ratio, diodes, values); } /** @@ -879,8 +879,10 @@ public: * * where f is the area scale factor and t the perimeter scale factor. This version allows to ignore the * area contribution entirely and switch to a perimeter-based antenna check by setting f to zero. + * + * If values is non-null, texts explaining the violations are placed there. */ - db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > ()); + db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > (), Texts *values = 0); /** * @brief Saves the database to the given path diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index d77386a2d..428eaaeaa 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -46,55 +46,76 @@ namespace db * The file follows the declaration-before-use principle * (circuits before subcircuits, nets before use ...) * - * Global statements: + * Main body: + * [version|description|unit|top|layer|connect|global|circuit|class|device|any]* * + * [version]: * version() - file format version [short key: V] + * + * [description]: * description() - an arbitrary description text [short key: B] + * + * [unit]: * unit() - specifies the database unit [short key: U] + * + * [top]: * top() - specifies the name of the top circuit [short key: W] + * + * [layer]: * layer( ?) - define a layer [short key: L] + * + * [connect]: * connect( ...) - connects layer1 with the following layers [short key: C] + * + * [global]: * global( ...) * - connects the shapes of the layer with the given global * nets [short key: G] + * + * [circuit]: * circuit( [circuit-def]) - circuit (cell) [short key: X] + * + * [class]: * class(