From 38ddffc645d9e3b8bc53050e08684cd568dea703 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 4 Jan 2026 22:46:29 +0100 Subject: [PATCH] L2N log entries with net references * Log entries on the L2N object can now have net references (by expanded name) and the nets will be highlighted when the log entry is selected in the netlist browser For an application see drcSimpleTests:147. * New function ("db") in evaluate_nets * BUGFIX: proper computation of transformations for multiple selections of nets in netlist browser --- src/db/db/dbLayoutToNetlistFormatDefs.h | 5 +- src/db/db/dbLayoutToNetlistReader.cc | 17 ++- src/db/db/dbLayoutToNetlistReader.h | 1 + src/db/db/dbLayoutToNetlistWriter.cc | 4 + src/db/db/dbLog.cc | 47 ++++++-- src/db/db/dbLog.h | 16 +++ src/db/db/dbMeasureEval.cc | 31 +++++- src/db/db/dbMeasureEval.h | 6 +- src/db/db/gsiDeclDbLayoutToNetlist.cc | 3 +- src/db/db/gsiDeclDbLog.cc | 57 ++++++++++ src/drc/drc/built-in-macros/_drc_netter.rb | 1 + src/drc/unit_tests/drcSimpleTests.cc | 32 ++++++ src/gsi/gsi/gsiVariantArgs.cc | 18 ++++ src/layui/layui/layNetlistBrowserPage.cc | 118 ++++++++++++++++----- src/layui/layui/layNetlistBrowserPage.h | 1 + testdata/drc/drcSimpleTests_147.drc | 37 +++++++ testdata/drc/drcSimpleTests_147.gds | Bin 0 -> 1932 bytes testdata/drc/drcSimpleTests_au147.l2n | 74 +++++++++++++ testdata/ruby/dbLogTest.rb | 43 ++++++++ 19 files changed, 471 insertions(+), 40 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_147.drc create mode 100644 testdata/drc/drcSimpleTests_147.gds create mode 100644 testdata/drc/drcSimpleTests_au147.l2n diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index bea7dbd60..a9d18e078 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -188,7 +188,7 @@ namespace db * scale() - magnification (default is 1) [short key: S] * * [message-entry]: - * message([severity] [message|message-geometry|message-cell|message-category|any]*) - message entry [short key: H] + * message([severity] [message|message-geometry|message-cell|message-category|message-net|any]*) - message entry [short key: H] * * [message]: * description() - message text [short key: B] @@ -199,6 +199,9 @@ namespace db * [message-cell]: * cell() - message cell [short key: C] * + * [message-net]: + * net() - message net name [short key: N] + * * [message-category]: * cat( ?) - message category with optional description [short key: X] * diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 43b3850bd..3e65a1f38 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -225,6 +225,18 @@ bool LayoutToNetlistStandardReader::read_message_cell (std::string &cell_name) } } +bool LayoutToNetlistStandardReader::read_message_net (std::string &net_name) +{ + if (test (skeys::net_key) || test (lkeys::net_key)) { + Brace br (this); + read_word_or_quoted (net_name); + br.done (); + return true; + } else { + return false; + } +} + bool LayoutToNetlistStandardReader::read_message_geometry (db::DPolygon &polygon) { if (test (skeys::polygon_key) || test (lkeys::polygon_key)) { @@ -258,7 +270,7 @@ bool LayoutToNetlistStandardReader::read_message_cat (std::string &category_name void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data) { Severity severity (db::NoSeverity); - std::string msg, cell_name, category_name, category_description; + std::string msg, cell_name, net_name, category_name, category_description; db::DPolygon geometry; Brace br (this); @@ -269,6 +281,8 @@ void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data) // continue } else if (read_message_cell (cell_name)) { // continue + } else if (read_message_net (net_name)) { + // continue } else if (read_message_cat (category_name, category_description)) { // continue } else if (read_message_geometry (geometry)) { @@ -282,6 +296,7 @@ void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data) data.set_severity (severity); data.set_message (msg); data.set_cell_name (cell_name); + data.set_net_name (net_name); data.set_category_description (category_description); data.set_category_name (category_name); data.set_geometry (geometry); diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index bc1230f66..cbfd57fff 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -164,6 +164,7 @@ private: db::Point read_point (); void read_message_entry (db::LogEntryData &data); bool read_message_cell (std::string &cell_name); + bool read_message_net (std::string &net_name); bool read_message_geometry (db::DPolygon &polygon); bool read_message_cat (std::string &category_name, std::string &category_description); }; diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 0b734b7a0..35a250182 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -211,6 +211,10 @@ void std_writer_impl::write_log_entry (TokenizedOutput &stream, const LogE TokenizedOutput (stream, Keys::cell_key, true) << tl::to_word_or_quoted_string (le.cell_name ()); } + if (! le.net_name ().empty ()) { + TokenizedOutput (stream, Keys::net_key, true) << tl::to_word_or_quoted_string (le.net_name ()); + } + if (! le.category_name ().empty ()) { TokenizedOutput o (stream, Keys::cat_key, true); o << tl::to_word_or_quoted_string (le.category_name ()); diff --git a/src/db/db/dbLog.cc b/src/db/db/dbLog.cc index 0a3c80fb5..58284d535 100644 --- a/src/db/db/dbLog.cc +++ b/src/db/db/dbLog.cc @@ -81,19 +81,25 @@ static LogEntryStringRepository s_strings; // LogEntryData implementation LogEntryData::LogEntryData () - : m_severity (NoSeverity), m_cell_name (0), m_message (0), m_category_name (0), m_category_description (0) + : m_severity (NoSeverity), m_cell_name (0), m_net_name (0), m_message (0), m_category_name (0), m_category_description (0) { // .. nothing yet .. } LogEntryData::LogEntryData (Severity s, const std::string &msg) - : m_severity (s), m_cell_name (0), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0) + : m_severity (s), m_cell_name (0), m_net_name (0), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0) { // .. nothing yet .. } LogEntryData::LogEntryData (Severity s, const std::string &cell_name, const std::string &msg) - : m_severity (s), m_cell_name (s_strings.id_for_string (cell_name)), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0) + : m_severity (s), m_cell_name (s_strings.id_for_string (cell_name)), m_net_name (0), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0) +{ + // .. nothing yet .. +} + +LogEntryData::LogEntryData (Severity s, const std::string &cell_name, const std::string &net_name, const std::string &msg) + : m_severity (s), m_cell_name (s_strings.id_for_string (cell_name)), m_net_name (s_strings.id_for_string (net_name)), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0) { // .. nothing yet .. } @@ -104,6 +110,7 @@ LogEntryData::operator== (const LogEntryData &other) const return m_severity == other.m_severity && m_message == other.m_message && m_cell_name == other.m_cell_name && + m_net_name == other.m_net_name && m_geometry == other.m_geometry && m_category_name == other.m_category_name && m_category_description == other.m_category_description; @@ -157,6 +164,18 @@ LogEntryData::set_cell_name (const std::string &n) m_cell_name = s_strings.id_for_string (n); } +const std::string & +LogEntryData::net_name () const +{ + return s_strings.string_for_id (m_net_name); +} + +void +LogEntryData::set_net_name (const std::string &n) +{ + m_net_name = s_strings.id_for_string (n); +} + std::string LogEntryData::to_string (bool with_geometry) const { @@ -179,10 +198,24 @@ LogEntryData::to_string (bool with_geometry) const } } - if (m_cell_name != 0) { - res += tl::to_string (tr ("In cell ")); - res += cell_name (); - res += ": "; + if (m_net_name != 0) { + if (m_cell_name != 0) { + res += tl::to_string (tr ("In net ")); + res += net_name (); + res += tl::to_string (tr (" in circuit ")); + res += cell_name (); + res += ": "; + } else { + res += tl::to_string (tr ("In net ")); + res += net_name (); + res += ": "; + } + } else { + if (m_cell_name != 0) { + res += tl::to_string (tr ("In cell ")); + res += cell_name (); + res += ": "; + } } res += msg; diff --git a/src/db/db/dbLog.h b/src/db/db/dbLog.h index 85e60a587..d26009d28 100644 --- a/src/db/db/dbLog.h +++ b/src/db/db/dbLog.h @@ -68,6 +68,11 @@ public: */ LogEntryData (Severity s, const std::string &cell_name, const std::string &msg); + /** + * @brief Creates an error with the severity, a cell (circuit) name, a net name and a message + */ + LogEntryData (Severity s, const std::string &cell_name, const std::string &net_name, const std::string &msg); + /** * @brief Equality */ @@ -158,6 +163,16 @@ public: */ void set_cell_name (const std::string &n); + /** + * @brief Gets the net name the error occurred in + */ + const std::string &net_name () const; + + /** + * @brief Sets the net name + */ + void set_net_name (const std::string &n); + /** * @brief Formats this message for printing */ @@ -166,6 +181,7 @@ public: private: Severity m_severity; string_id_type m_cell_name; + string_id_type m_net_name; string_id_type m_message; db::DPolygon m_geometry; string_id_type m_category_name, m_category_description; diff --git a/src/db/db/dbMeasureEval.cc b/src/db/db/dbMeasureEval.cc index 7bb2d45cc..d826868fc 100644 --- a/src/db/db/dbMeasureEval.cc +++ b/src/db/db/dbMeasureEval.cc @@ -492,6 +492,28 @@ private: MeasureNetEval *mp_eval; }; +class NetDbFunction + : public tl::EvalFunction +{ +public: + NetDbFunction (MeasureNetEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 0) { + throw tl::EvalError (tl::to_string (tr ("'db' function does not take any argument")), context); + } + out = mp_eval->db_func (); + } + +private: + MeasureNetEval *mp_eval; +}; + class NetFunction : public tl::EvalFunction { @@ -558,7 +580,7 @@ private: MeasureNetEval *mp_eval; }; -MeasureNetEval::MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu) +MeasureNetEval::MeasureNetEval (LayoutToNetlist *l2n, double dbu) : tl::Eval (), mp_l2n (l2n), m_dbu (dbu) { m_copy_merge = false; @@ -588,6 +610,7 @@ MeasureNetEval::init () define_function ("area", new NetAreaFunction (this)); define_function ("perimeter", new NetPerimeterFunction (this)); define_function ("net", new NetFunction (this)); + define_function ("db", new NetDbFunction (this)); } void @@ -701,4 +724,10 @@ MeasureNetEval::net_func () const } } +tl::Variant +MeasureNetEval::db_func () const +{ + return tl::Variant::make_variant_ref (mp_l2n); +} + } diff --git a/src/db/db/dbMeasureEval.h b/src/db/db/dbMeasureEval.h index 882d422fc..328891e90 100644 --- a/src/db/db/dbMeasureEval.h +++ b/src/db/db/dbMeasureEval.h @@ -122,7 +122,7 @@ class DB_PUBLIC MeasureNetEval : public tl::Eval { public: - MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu); + MeasureNetEval (db::LayoutToNetlist *l2n, double dbu); void set_primary_layer (unsigned int layer_index); void set_secondary_layer (const std::string &name, unsigned int layer_index); @@ -144,6 +144,7 @@ private: friend class NetAreaFunction; friend class NetPerimeterFunction; friend class NetFunction; + friend class NetDbFunction; friend class NetSkipFunction; friend class NetCopyFunction; @@ -153,7 +154,7 @@ private: double area, perimeter; }; - const db::LayoutToNetlist *mp_l2n; + db::LayoutToNetlist *mp_l2n; double m_dbu; std::vector m_layers; mutable std::vector m_copy_layers; @@ -173,6 +174,7 @@ private: tl::Variant perimeter_func (int layer_index) const; void copy_func (const std::vector &layer_indexes, bool merge, size_t max_polygons) const; tl::Variant net_func () const; + tl::Variant db_func () const; }; } diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 506e7dc32..36453908d 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -1251,6 +1251,7 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@li 'skip' or 'skip(flag)': will skip the primary shapes of that net when called with a true value or without one. See also 'copy'. @/li\n" "@li 'copy(...)': see below for details @/li\n" "@li 'net': the \\Net object of the current net @/li\n" + "@li 'db': the \\LayoutToDatabase object the netlist lives in @/li\n" "@/ul\n" "\n" "If given, the 'dbu' argument gives the database unit to use for converting shape dimensions into micrometer units. " @@ -1294,7 +1295,7 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "where the second expression establishes 'skip' as the default and conditionally executes 'copy',\n" "overriding 'skip'.\n" "\n" - "The 'copy' function was added and the 'skip' argument was made optional in version 0.30.6." + "The 'copy' and 'db' functions were added and the 'skip' argument was made optional in version 0.30.6." ) + // test API gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"), "@hide") + diff --git a/src/db/db/gsiDeclDbLog.cc b/src/db/db/gsiDeclDbLog.cc index 8c26282a8..171854868 100644 --- a/src/db/db/gsiDeclDbLog.cc +++ b/src/db/db/gsiDeclDbLog.cc @@ -23,11 +23,53 @@ #include "gsiDecl.h" #include "gsiEnums.h" #include "dbLog.h" +#include "dbNet.h" +#include "dbCircuit.h" namespace gsi { +db::LogEntryData *new_le1 (db::Severity severity, const std::string &msg) +{ + return new db::LogEntryData (severity, msg); +} + +db::LogEntryData *new_le2 (db::Severity severity, const std::string &cell_name, const std::string &msg) +{ + return new db::LogEntryData (severity, cell_name, msg); +} + +db::LogEntryData *new_le3 (db::Severity severity, const std::string &cell_name, const std::string &net_name, const std::string &msg) +{ + return new db::LogEntryData (severity, cell_name, net_name, msg); +} + +db::LogEntryData *new_le4 (db::Severity severity, const db::Net *net, const std::string &msg) +{ + if (! net || ! net->circuit ()) { + return new db::LogEntryData (severity, msg); + } else { + return new db::LogEntryData (severity, net->circuit ()->name (), net->expanded_name (), msg); + } +} + Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData", + gsi::constructor ("new", &new_le1, gsi::arg ("severity"), gsi::arg ("msg"), + "@brief Creates a new LogEntry object with the given severity and message\n" + "This convenience constructor has been added in version 0.30.6\n" + ) + + gsi::constructor ("new", &new_le2, gsi::arg ("severity"), gsi::arg ("cell_name"), gsi::arg ("msg"), + "@brief Creates a new LogEntry object with the given severity, cell or circuit name and message\n" + "This convenience constructor has been added in version 0.30.6\n" + ) + + gsi::constructor ("new", &new_le3, gsi::arg ("severity"), gsi::arg ("cell_name"), gsi::arg ("new_name"), gsi::arg ("msg"), + "@brief Creates a new LogEntry object with the given severity, cell or circuit name, net name and message\n" + "This convenience constructor has been added in version 0.30.6\n" + ) + + gsi::constructor ("new", &new_le4, gsi::arg ("severity"), gsi::arg ("net"), gsi::arg ("msg"), + "@brief Creates a new LogEntry object with the given severity and message and circuit and net name taken from the given \\Net object\n" + "This convenience constructor has been added in version 0.30.6\n" + ) + gsi::method ("severity", &db::LogEntryData::severity, "@brief Gets the severity attribute.\n" ) + @@ -51,6 +93,21 @@ Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData" "warning generated during device extraction, the cell name is " "the circuit the device should have appeared in." ) + + gsi::method ("net_name", &db::LogEntryData::net_name, + "@brief Gets the net name.\n" + "See \\net_name= for details about this attribute." + "\n" + "The net_name attribute has been introduced in version 0.30.6.\n" + ) + + gsi::method ("net_name=", &db::LogEntryData::set_net_name, gsi::arg ("net_name"), + "@brief Sets the net name.\n" + "The net (or circuit) name specifies the net the " + "log entry is related to.\n" + "\n" + "By convention, the net name is the expanded net name (see \\Net#expanded_name).\n" + "\n" + "The net_name attribute has been introduced in version 0.30.6.\n" + ) + gsi::method ("geometry", &db::LogEntryData::geometry, "@brief Gets the geometry.\n" "See \\geometry= for more details." diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index efb9853ee..e5ec8f0a2 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -807,6 +807,7 @@ module DRC # # @ul # @li "net" - the RBA::Net object of the current net @/li + # @li "db" - the RBA::LayoutToNetlist object the netlist lives in @/li # @li "skip" or "skip(flag)" - if called with a 'true' argument (the default), the primary layer's shapes are not copied for this net @/li # @li "copy(...)" - configures polygon output in a more elaborate way than "skip" (see below) @/li # @li "put(name, value)" - places the value as a property with name 'name' (this must be a string) on the output shapes @/li diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 6ccccb378..80199b2fb 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -2076,3 +2076,35 @@ TEST(146d_edges_and_corners) run_test (_this, "146", true); } +TEST(147_MeasureNetsWithL2N) +{ + std::string rs = tl::testdata (); + rs += "/drc/drcSimpleTests_147.drc"; + + std::string input = tl::testdata (); + input += "/drc/drcSimpleTests_147.gds"; + + std::string au_output = tl::testdata (); + au_output += "/drc/drcSimpleTests_au147.l2n"; + + std::string output = this->tmp_file ("tmp.l2n"); + + { + // Set some variables + lym::Macro config; + config.set_text (tl::sprintf ( + "$drc_test_source = '%s'\n" + "$drc_test_target = '%s'\n" + , input, output) + ); + config.set_interpreter (lym::Macro::Ruby); + EXPECT_EQ (config.run (), 0); + } + + lym::Macro drc; + drc.load_from (rs); + EXPECT_EQ (drc.run (), 0); + + compare_text_files (output, au_output); +} + diff --git a/src/gsi/gsi/gsiVariantArgs.cc b/src/gsi/gsi/gsiVariantArgs.cc index 5e1b4ffb7..d8e565f33 100644 --- a/src/gsi/gsi/gsiVariantArgs.cc +++ b/src/gsi/gsi/gsiVariantArgs.cc @@ -75,6 +75,24 @@ struct test_arg_func } }; +template <> +struct test_arg_func +{ + void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType & /*atype*/, bool /*loose*/, bool /*object_substitution*/) + { + *ret = arg.is_a_string (); + } +}; + +template <> +struct test_arg_func +{ + void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType & /*atype*/, bool /*loose*/, bool /*object_substitution*/) + { + *ret = arg.is_a_bytearray (); + } +}; + template <> struct test_arg_func { diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index ce725e086..b16dbf2e3 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -816,15 +816,31 @@ NetlistBrowserPage::log_selection_changed () QModelIndexList selection = log_view->selectionModel ()->selectedIndexes (); for (QModelIndexList::const_iterator i = selection.begin (); i != selection.end (); ++i) { - if (i->column () == 0) { - const db::LogEntryData *le = model->log_entry (*i); - if (le && le->geometry () != db::DPolygon () && ! le->cell_name ().empty ()) { - const db::Circuit *c = mp_database->netlist ()->circuit_by_name (le->cell_name ()); - if (c) { - m_markers.push_back (std::make_pair (c, le->geometry ())); - } + + if (i->column () != 0) { + continue; + } + + const db::LogEntryData *le = model->log_entry (*i); + + const db::Circuit *c = 0; + if (le && ! le->cell_name ().empty ()) { + c = mp_database->netlist ()->circuit_by_name (le->cell_name ()); + } + + // highlight geometries + if (c && le->geometry () != db::DPolygon ()) { + m_markers.push_back (std::make_pair (c, le->geometry ())); + } + + // highlight nets + if (c && ! le->net_name ().empty ()) { + const db::Net *net = c->net_by_name (le->net_name ()); + if (net) { + m_net_markers.push_back (std::make_pair (c, net)); } } + } update_highlights (); @@ -1291,6 +1307,7 @@ NetlistBrowserPage::clear_highlights () m_current_path = lay::NetlistObjectsPath (); m_selected_paths.clear (); m_markers.clear (); + m_net_markers.clear (); update_highlights (); } @@ -1350,6 +1367,31 @@ bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit) return layout->cell (circuit->cell_index ()).bbox (); } +static db::Box +bbox_for_net (const db::LayoutToNetlist *db, const db::Circuit *circuit, const db::Net *net) +{ + db::Box bbox; + + db::cell_index_type cell_index = circuit->cell_index (); + size_t cluster_id = net->cluster_id (); + + const db::Connectivity &conn = db->connectivity (); + for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { + + db::Box layer_bbox; + db::recursive_cluster_shape_iterator shapes (db->net_clusters (), *layer, cell_index, cluster_id); + while (! shapes.at_end ()) { + layer_bbox += shapes->bbox ().transformed (shapes.trans ()); + ++shapes; + } + + bbox += layer_bbox; + + } + + return bbox; +} + void NetlistBrowserPage::adjust_view () { @@ -1425,22 +1467,7 @@ NetlistBrowserPage::adjust_view () } else if (net) { - db::cell_index_type cell_index = net->circuit ()->cell_index (); - size_t cluster_id = net->cluster_id (); - - const db::Connectivity &conn = mp_database->connectivity (); - for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { - - db::Box layer_bbox; - db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); - while (! shapes.at_end ()) { - layer_bbox += shapes->bbox ().transformed (shapes.trans ()); - ++shapes; - } - - ebox += layer_bbox; - - } + ebox += bbox_for_net (mp_database.get (), circuit, net); } else if (circuit) { ebox += bbox_for_circuit (layout, circuit); @@ -1461,6 +1488,17 @@ NetlistBrowserPage::adjust_view () } + // add net markers boxes + + for (auto marker = m_net_markers.begin (); marker != m_net_markers.end (); ++marker) { + + std::pair tr = trans_for (marker->first, *layout, *cell, m_cell_context_cache, cv.context_dtrans ()); + if (tr.first) { + bbox += tr.second * db::CplxTrans (layout->dbu ()) * bbox_for_net (mp_database.get (), marker->first, marker->second); + } + + } + if (! bbox.empty ()) { std::vector tv = mp_view->cv_transform_variants (m_cv_index); @@ -1739,26 +1777,52 @@ NetlistBrowserPage::update_highlights () // a map of display properties vs. layer properties // correct DBU differences between the storage layout and the original layout - for (std::vector::iterator t = tv.begin (); t != tv.end (); ++t) { + std::vector tvt = tv; + for (std::vector::iterator t = tvt.begin (); t != tvt.end (); ++t) { *t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); } if (path->net.first) { - if (produce_highlights_for_net (path->net.first, n_markers, display_by_lp, tv)) { + if (produce_highlights_for_net (path->net.first, n_markers, display_by_lp, tvt)) { not_all_shapes_are_shown = true; } } else if (path->device.first) { - if (produce_highlights_for_device (path->device.first, n_markers, tv)) { + if (produce_highlights_for_device (path->device.first, n_markers, tvt)) { not_all_shapes_are_shown = true; } } else if (circuit) { - if (produce_highlights_for_circuit (circuit, n_markers, tv)) { + if (produce_highlights_for_circuit (circuit, n_markers, tvt)) { not_all_shapes_are_shown = true; } } } + for (auto marker = m_net_markers.begin (); marker != m_net_markers.end (); ++marker) { + + // computes the transformation supplied by the path + + std::pair tr = trans_for (marker->first, *layout, *cell, m_cell_context_cache, cv.context_dtrans ()); + if (! tr.first) { + continue; + } + + db::DCplxTrans trans = tr.second; + + // a map of display properties vs. layer properties + + // correct DBU differences between the storage layout and the original layout + std::vector tvt = tv; + for (std::vector::iterator t = tvt.begin (); t != tvt.end (); ++t) { + *t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); + } + + if (produce_highlights_for_net (marker->second, n_markers, display_by_lp, tvt)) { + not_all_shapes_are_shown = true; + } + + } + for (auto marker = m_markers.begin (); marker != m_markers.end (); ++marker) { // computes the transformation supplied by the path diff --git a/src/layui/layui/layNetlistBrowserPage.h b/src/layui/layui/layNetlistBrowserPage.h index c9012e83f..b0345934b 100644 --- a/src/layui/layui/layNetlistBrowserPage.h +++ b/src/layui/layui/layNetlistBrowserPage.h @@ -246,6 +246,7 @@ private: lay::NetlistObjectsPath m_current_path; std::vector m_selected_paths; std::vector > m_markers; + std::vector > m_net_markers; lay::NetInfoDialog *mp_info_dialog; tl::DeferredMethod dm_update_highlights; tl::DeferredMethod dm_rerun_macro; diff --git a/testdata/drc/drcSimpleTests_147.drc b/testdata/drc/drcSimpleTests_147.drc new file mode 100644 index 000000000..1751e29c0 --- /dev/null +++ b/testdata/drc/drcSimpleTests_147.drc @@ -0,0 +1,37 @@ + +source $drc_test_source +report_netlist $drc_test_target + +deep + +l1 = input(1, 0) +l2 = input(2, 0) +l3 = input(3, 0) +l4 = input(4, 0) +l5 = input(5, 0) + +connect(l1, l2) +connect(l2, l3) +connect(l3, l4) +connect(l4, l5) + +l1.output(1, 0) +l2.output(2, 0) +l3.output(3, 0) +l4.output(4, 0) +l5.output(5, 0) + +netlist + +sec = { "l2" => l2, "l3" => l3, "l4" => l4, "l5" => l5 } + +script = <<"END" + skip; + var ar=area(l5)/area; + db.add_log_entry(LogEntryData.new(Severity.Info, net, 'AR='+to_s(ar))) +END + +evaluate_nets(l1, sec, script, { "n" => "NET1" }) + +netlist + diff --git a/testdata/drc/drcSimpleTests_147.gds b/testdata/drc/drcSimpleTests_147.gds new file mode 100644 index 0000000000000000000000000000000000000000..ea99561480ce59460971559aa264df2ee54e23f6 GIT binary patch literal 1932 zcmb7EJ!@1!6g}_l+u4U%HGYs)vtS^F!AOkT1TDfQs3=O@VgrknDN=f}Y8S?317(%XecpZ9vV?;hOT{qVGndbyZqj9CJb6fmb_Ioq6x0o)ib z$*+v7%?vQt1wRGCV2BzQ^!X*9?=t^BzqjV|6Q9q# zI+@#_8W;5WWuNcm$lm^L!)ZYDM#ir?{e(Y3{Y))FiYirHd<9gFkzO_{_u37Yt%ASR zL@Jq_l5@_pI_63whsbHxc0U0tQ|^>8T~9BtauMoohqXs7?({KuWl-g{eQSSg0c-m} z;}CfHKvClv`YHu{I)iQ?a`L^38Xs{GtB8qQ-Oj1^mXL+sFD*ch=9L z#&i7OE2aKNE$2DD+t<&G9%pL|7)tNwrPGWT0ymnq);`q^k`~sS5 BQ0)K! literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au147.l2n b/testdata/drc/drcSimpleTests_au147.l2n new file mode 100644 index 000000000..6107261a6 --- /dev/null +++ b/testdata/drc/drcSimpleTests_au147.l2n @@ -0,0 +1,74 @@ +#%l2n-klayout +W(TOP) +U(0.001) +L(l1 '1/0') +L(l2 '2/0') +L(l3 '3/0') +L(l4 '4/0') +L(l5 '5/0') +C(l1 l1 l2) +C(l2 l1 l2 l3) +C(l3 l2 l3 l4) +C(l4 l3 l4 l5) +C(l5 l4 l5) +H(I B('AR=5') C(B) N(NET1)) +H(I B('AR=0') C(B) N($4)) +H(I B('AR=9.875') C(TOP) N($1)) +H(I B('AR=9.5') C(TOP) N($I2)) +X(A + R((0 0) (38000 12000)) + N(1 I(NET2) + R(l1 (0 8000) (4000 4000)) + R(l2 (-3000 -3000) (2000 2000)) + R(l3 (-3000 -11000) (4000 12000)) + R(l4 (-3000 -11000) (2000 2000)) + R(l5 (-3000 -3000) (38000 4000)) + R(l5 (-22000 -2000) (0 0)) + ) + P(1 I(NET2)) +) +X(B + R((-8000 -14000) (48000 34000)) + N(1 I(NET1) + R(l1 (12000 8000) (4000 4000)) + R(l1 (-10000 -14000) (4000 4000)) + R(l2 (3000 7000) (2000 2000)) + R(l2 (-8000 -12000) (2000 2000)) + R(l3 (3000 -3000) (4000 14000)) + R(l3 (-10000 -14000) (10000 4000)) + R(l4 (-3000 -3000) (2000 2000)) + R(l5 (-3000 -15000) (4000 16000)) + R(l5 (14000 -16000) (10000 4000)) + R(l5 (-6000 -2000) (0 0)) + ) + N(2 I($2) + R(l3 (25000 -5000) (4000 7000)) + R(l4 (-3000 -3000) (2000 2000)) + R(l5 (-3000 -3000) (15000 4000)) + ) + N(3 I($4) + R(l1 (25000 -5000) (4000 18000)) + ) + N(4 I($5) + R(l3 (25000 6000) (4000 7000)) + ) + N(5 I($6) + R(l5 (25000 6000) (15000 4000)) + ) + N(6 I(NET2) + R(l5 (16000 18000) (0 0)) + ) + P(6 I(NET2)) + X(1 A Y(-8000 -14000) P(0 1)) + X(2 A M Y(-8000 20000) P(0 6)) +) +X(TOP + R((-18000 -51000) (58000 108000)) + N(1 I($1) + R(l5 (0 16000) (4000 11000)) + ) + N(2 I($I2)) + X(1 B Y(0 0) P(0 1)) + X(2 B O(180) Y(22000 43000) P(0 1)) + X(3 B O(180) Y(22000 -31000) P(0 2)) +) diff --git a/testdata/ruby/dbLogTest.rb b/testdata/ruby/dbLogTest.rb index 795e6eb49..7bbfa6ad1 100644 --- a/testdata/ruby/dbLogTest.rb +++ b/testdata/ruby/dbLogTest.rb @@ -35,6 +35,11 @@ class DBLog_TestClass < TestBase le = RBA::LogEntryData::new + le.severity = RBA::LogEntryData::Error + assert_equal(le.severity.to_s, "Error") + le.severity = RBA::LogEntryData::NoSeverity + assert_equal(le.severity.to_s, "NoSeverity") + le.message = "message" assert_equal(le.message, "message") @@ -52,6 +57,44 @@ class DBLog_TestClass < TestBase assert_equal(le.to_s, "[the answer] In cell TOP: message, shape: (1,2;1,4;3,4;3,2)") + le.net_name = "NET" + assert_equal(le.net_name, "NET") + + assert_equal(le.to_s, "[the answer] In net NET in circuit TOP: message, shape: (1,2;1,4;3,4;3,2)") + + end + + def test_2_LogConstructors + + le = RBA::LogEntryData::new(RBA::LogEntryData::Error, "a message") + assert_equal(le.to_s, "a message") + + assert_equal(le.severity.to_s, "Error") + + le = RBA::LogEntryData::new(RBA::LogEntryData::Info, "CELL", "a message") + assert_equal(le.to_s, "In cell CELL: a message") + + assert_equal(le.severity.to_s, "Info") + + le = RBA::LogEntryData::new(RBA::LogEntryData::Warning, "CELL", "NET", "a message") + assert_equal(le.to_s, "In net NET in circuit CELL: a message") + + assert_equal(le.severity.to_s, "Warning") + + # Create a LogEntry from a Net object: + + nl = RBA::Netlist::new + c = RBA::Circuit::new + c.name = "CIRCUIT" + nl.add(c) + # NOTE: no explicit name, but ID 0 + net = c.create_net + + le = RBA::LogEntryData::new(RBA::LogEntryData::Error, net, "a message") + assert_equal(le.to_s, "In net $0 in circuit CIRCUIT: a message") + + assert_equal(le.severity.to_s, "Error") + end end