From 7126375646d1c9a985eaa43e51dc13831c12606f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 19:26:18 +0200 Subject: [PATCH 01/41] WIP --- src/db/db/db.pro | 2 + src/db/db/dbLayoutToNetlist.cc | 15 ++++++ src/db/db/dbLayoutToNetlist.h | 32 +++++++++++- src/db/db/dbLayoutToNetlistFormatDefs.cc | 14 +++++- src/db/db/dbLayoutToNetlistFormatDefs.h | 21 +++++++- src/db/db/dbLayoutToNetlistReader.cc | 53 ++++++++++++++++++++ src/db/db/dbLayoutToNetlistReader.h | 21 ++++---- src/db/db/dbLayoutToNetlistWriter.cc | 34 +++++++++++++ src/db/db/dbLayoutToNetlistWriter.h | 4 ++ src/db/db/dbLayoutVsSchematicFormatDefs.cc | 10 +--- src/db/db/dbLayoutVsSchematicFormatDefs.h | 20 +++----- src/db/db/dbLayoutVsSchematicReader.cc | 38 +++------------ src/db/db/dbLayoutVsSchematicReader.h | 5 +- src/db/db/dbLayoutVsSchematicWriter.cc | 54 ++++++++------------ src/db/db/dbLog.cc | 31 ++++++++++++ src/db/db/dbLog.h | 57 ++++++++++++++++++++++ src/db/db/dbNetlistCompare.cc | 10 ++-- src/db/db/dbNetlistCompare.h | 13 +---- src/db/db/dbNetlistCompareCore.cc | 14 +++--- src/db/db/dbNetlistCrossReference.h | 9 ---- src/db/db/dbNetlistDeviceExtractor.h | 8 +++ src/db/db/gsiDeclDbNetlistCompare.cc | 16 +++--- src/layui/layui/layNetlistBrowserPage.cc | 4 +- src/layui/layui/layNetlistLogModel.cc | 15 +++--- 24 files changed, 347 insertions(+), 153 deletions(-) create mode 100644 src/db/db/dbLog.cc create mode 100644 src/db/db/dbLog.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 6914e12fa..ac7f6ec76 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -50,6 +50,7 @@ SOURCES = \ dbLibraryManager.cc \ dbLibraryProxy.cc \ dbLoadLayoutOptions.cc \ + dbLog.cc \ dbManager.cc \ dbMatrix.cc \ dbMemStatistics.cc \ @@ -271,6 +272,7 @@ HEADERS = \ dbLibraryManager.h \ dbLibraryProxy.h \ dbLoadLayoutOptions.h \ + dbLog.h \ dbManager.h \ dbMatrix.h \ dbMemStatistics.h \ diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 83395e612..19d31468b 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -33,6 +33,7 @@ #include "dbLayoutToNetlistFormatDefs.h" #include "dbLayoutVsSchematicFormatDefs.h" #include "dbShapeProcessor.h" +#include "dbLog.h" #include "tlGlobPattern.h" namespace db @@ -238,8 +239,16 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); } + ensure_netlist (); + + extractor.clear_errors (); extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters, m_device_scaling); + + // transfer errors to log entries + for (auto e = extractor.begin_errors (); e != extractor.end_errors (); ++e) { + m_log_entries.push_back (db::LogEntryData (db::Error, e->to_string ())); + } } void LayoutToNetlist::reset_extracted () @@ -249,6 +258,8 @@ void LayoutToNetlist::reset_extracted () m_net_clusters.clear (); mp_netlist.reset (0); + m_log_entries.clear (); + m_netlist_extracted = false; } @@ -362,6 +373,7 @@ void LayoutToNetlist::extract_netlist () db::NetlistExtractor netex; +#if 0 // @@@ remove this plus corresponding code inside NetlistExtractor ... netex.set_joined_net_names (m_joined_net_names); std::map > jp_per_cell; @@ -397,10 +409,13 @@ void LayoutToNetlist::extract_netlist () for (std::map > >::const_iterator i = jn_per_cell.begin (); i != jn_per_cell.end (); ++i) { netex.set_joined_nets (i->first, i->second); } + #endif netex.set_include_floating_subcircuits (m_include_floating_subcircuits); netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); + // @@@ join_nets (); + if (tl::verbosity () >= 41) { MemStatisticsCollector m (false); mem_stat (&m, db::MemStatistics::None, 0); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index e6bb022af..e159e46e4 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -28,6 +28,7 @@ #include "dbNetlistExtractor.h" #include "dbNetlistDeviceExtractor.h" #include "dbLayoutToNetlistEnums.h" +#include "dbLog.h" #include "tlGlobPattern.h" namespace db @@ -78,6 +79,7 @@ class DB_PUBLIC LayoutToNetlist { public: typedef std::map::const_iterator layer_iterator; + typedef std::vector log_entries_type; /** * @brief The constructor @@ -190,6 +192,33 @@ public: m_filename = filename; } + /** + * @brief Gets the log entries + * @@@ TODO: provide GSI interface + */ + const log_entries_type &log_entries () const + { + return m_log_entries; + } + + /** + * @brief Clears the log entries + * @@@ TODO: provide GSI interface + */ + void clear_log_entries () + { + m_log_entries.clear (); + } + + /** + * @brief Adds a log entry + * @@@ TODO: provide GSI interface + */ + void log_entry (const db::LogEntryData &log_entry) + { + m_log_entries.push_back (log_entry); + } + /** * @brief Sets the number of threads to use for operations which support multiple threads */ @@ -388,7 +417,7 @@ public: * @brief Resets the extracted netlist * * This method will invalidate the netlist and extraction. It is called automatically when - * cone of the connect methods is called. + * one of the connect methods is called. */ void reset_extracted (); @@ -930,6 +959,7 @@ private: std::string m_name; std::string m_original_file; std::string m_filename; + log_entries_type m_log_entries; db::RecursiveShapeIterator m_iter; std::unique_ptr mp_internal_dss; tl::weak_ptr mp_dss; diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index 133a4cbd3..c317ac857 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -56,8 +56,13 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::mirror_key ("mirror"); DB_PUBLIC std::string LongKeys::scale_key ("scale"); DB_PUBLIC std::string LongKeys::pin_key ("pin"); + DB_PUBLIC std::string LongKeys::message_key ("message"); - // A, B, C, D, E, F, G, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y + DB_PUBLIC std::string LongKeys::info_severity_key ("info"); + DB_PUBLIC std::string LongKeys::warning_severity_key ("warning"); + DB_PUBLIC std::string LongKeys::error_severity_key ("error"); + + // A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y DB_PUBLIC std::string ShortKeys::version_key ("V"); DB_PUBLIC std::string ShortKeys::description_key ("B"); DB_PUBLIC std::string ShortKeys::top_key ("W"); @@ -82,6 +87,13 @@ namespace l2n_std_format DB_PUBLIC std::string ShortKeys::mirror_key ("M"); DB_PUBLIC std::string ShortKeys::scale_key ("S"); DB_PUBLIC std::string ShortKeys::pin_key ("P"); + DB_PUBLIC std::string ShortKeys::message_key ("H"); + + // I, W, E + + DB_PUBLIC std::string ShortKeys::info_severity_key ("I"); + DB_PUBLIC std::string ShortKeys::warning_severity_key ("W"); + DB_PUBLIC std::string ShortKeys::error_severity_key ("E"); } } diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index b0818ff47..ea09112ff 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -47,7 +47,7 @@ namespace db * (circuits before subcircuits, nets before use ...) * * Main body: - * [version|description|unit|top|layer|connect|global|circuit|class|device|any]* + * [version|description|unit|top|layer|connect|global|circuit|class|device|message-entry|any]* * * [version]: * version() - file format version [short key: V] @@ -181,6 +181,17 @@ namespace db * mirror - if specified, the instance is mirrored before rotation [short key: M] * scale() - magnification (default is 1) [short key: S] * + * [message-entry]: + * message([severity] [message|any]*) - message entry [short key: H] + * + * [message]: + * description() - error description [short key: B] + * + * [severity]: + * info | - [short key: I] + * warning | - [short key: W] + * error - [short key: E] + * * [any]: * * | * | @@ -220,8 +231,12 @@ namespace l2n_std_format static std::string mirror_key; static std::string scale_key; static std::string pin_key; + static std::string message_key; static std::string indent1; static std::string indent2; + static std::string info_severity_key; + static std::string warning_severity_key; + static std::string error_severity_key; }; struct DB_PUBLIC LongKeys @@ -253,8 +268,12 @@ namespace l2n_std_format static std::string mirror_key; static std::string scale_key; static std::string pin_key; + static std::string message_key; static std::string indent1; static std::string indent2; + static std::string info_severity_key; + static std::string warning_severity_key; + static std::string error_severity_key; }; template struct DB_PUBLIC keys; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 033a8fb79..0b980ebbb 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -184,6 +184,52 @@ void LayoutToNetlistStandardReader::skip_element () } } +bool LayoutToNetlistStandardReader::read_message (std::string &msg) +{ + if (test (skeys::description_key) || test (lkeys::description_key)) { + Brace br (this); + read_word_or_quoted (msg); + br.done (); + return true; + } else { + return false; + } +} + +bool LayoutToNetlistStandardReader::read_severity (db::Severity &severity) +{ + if (test (skeys::info_severity_key) || test (lkeys::info_severity_key)) { + severity = db::Info; + return true; + } else if (test (skeys::warning_severity_key) || test (lkeys::warning_severity_key)) { + severity = db::Warning; + return true; + } else if (test (skeys::error_severity_key) || test (lkeys::error_severity_key)) { + severity = db::Error; + return true; + } else { + return false; + } +} + +void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data) +{ + data.severity = db::NoSeverity; + data.msg.clear (); + + Brace br (this); + while (br) { + if (read_severity (data.severity)) { + // continue + } else if (read_message (data.msg)) { + // continue + } else { + skip_element (); + } + } + br.done (); +} + void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) { tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_path); @@ -359,6 +405,13 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo } br.done (); + } else if (l2n && (test (skeys::message_key) || test (lkeys::message_key))) { + + db::LogEntryData data; + read_message_entry (data); + + l2n->log_entry (data); + } else if (l2n && (test (skeys::global_key) || test (lkeys::global_key))) { Brace br (this); diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 46c917d3f..367e5c4e6 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -109,6 +109,8 @@ protected: void read_netlist (Netlist *netlist, db::LayoutToNetlist *l2n, Brace *nested = 0, std::map *map_per_circuit = 0); static size_t terminal_id (const db::DeviceClass *device_class, const std::string &tname); static std::pair device_model_by_name (db::Netlist *netlist, const std::string &dmname); + bool read_message (std::string &msg); + bool read_severity (Severity &severity); const std::string &path () const { @@ -140,6 +142,15 @@ protected: void skip (); void skip_element (); +private: + tl::TextInputStream m_stream; + std::string m_path; + std::string m_line; + double m_dbu; + tl::Extractor m_ex; + db::Point m_ref; + tl::AbsoluteProgress m_progress; + void read_net (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map); void read_pin (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map); void read_device (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map > &connections); @@ -151,15 +162,7 @@ protected: db::Box read_rect (); void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); db::Point read_point (); - -private: - tl::TextInputStream m_stream; - std::string m_path; - std::string m_line; - double m_dbu; - tl::Extractor m_ex; - db::Point m_ref; - tl::AbsoluteProgress m_progress; + void read_message_entry (db::LogEntryData &data); }; } diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 1713ee504..86e254a2f 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -142,6 +142,30 @@ std_writer_impl::std_writer_impl (tl::OutputStream &stream, double dbu, co m_progress.set_unit (1024 * 1024); } +template +std::string std_writer_impl::message_to_s (const std::string &msg) +{ + if (msg.empty ()) { + return std::string (); + } else { + return Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")"; + } +} + +template +std::string std_writer_impl::severity_to_s (const db::Severity severity) +{ + if (severity == db::Info) { + return Keys::info_severity_key; + } else if (severity == db::Warning) { + return Keys::warning_severity_key; + } else if (severity == db::Error) { + return Keys::error_severity_key; + } else { + return std::string (); + } +} + static std::string name_for_layer (const db::LayoutToNetlist *l2n, unsigned int l) { std::string n = l2n->name (l); @@ -318,6 +342,16 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma } + if (! mp_l2n->log_entries ().empty ()) { + if (! Keys::is_short ()) { + stream << endl << "# Log entries" << endl; + } + for (auto l = mp_l2n->log_entries ().begin (); l != mp_l2n->log_entries ().end (); ++l) { + TokenizedOutput (stream, Keys::message_key) << severity_to_s (l->severity) << message_to_s (l->msg); + m_progress.set (mp_stream->pos ()); + } + } + } if (mp_netlist->begin_device_classes () != mp_netlist->end_device_classes () && ! Keys::is_short ()) { diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index 8032e2651..25c175f9f 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -28,6 +28,7 @@ #include "dbTrans.h" #include "dbPolygon.h" #include "dbHierNetworkProcessor.h" +#include "dbLog.h" #include "tlStream.h" #include "tlProgress.h" @@ -92,6 +93,9 @@ protected: return *mp_stream; } + std::string severity_to_s (const db::Severity severity); + std::string message_to_s (const std::string &msg); + private: tl::OutputStream *mp_stream; db::Point m_ref; diff --git a/src/db/db/dbLayoutVsSchematicFormatDefs.cc b/src/db/db/dbLayoutVsSchematicFormatDefs.cc index 62de797d0..12f88601e 100644 --- a/src/db/db/dbLayoutVsSchematicFormatDefs.cc +++ b/src/db/db/dbLayoutVsSchematicFormatDefs.cc @@ -43,11 +43,7 @@ namespace lvs_std_format DB_PUBLIC std::string LongKeys::warning_key ("warning"); DB_PUBLIC std::string LongKeys::skipped_key ("skipped"); - DB_PUBLIC std::string LongKeys::info_severity_key ("info"); - DB_PUBLIC std::string LongKeys::warning_severity_key ("warning"); - DB_PUBLIC std::string LongKeys::error_severity_key ("error"); - - // E, H, I, J, L, M, S, W, X, Z, 0, 1 + // H, J, L, M, S, X, Z, 0, 1 DB_PUBLIC std::string ShortKeys::reference_key ("H"); DB_PUBLIC std::string ShortKeys::layout_key ("J"); @@ -60,10 +56,6 @@ namespace lvs_std_format DB_PUBLIC std::string ShortKeys::nomatch_key ("X"); DB_PUBLIC std::string ShortKeys::warning_key ("W"); DB_PUBLIC std::string ShortKeys::skipped_key ("S"); - - DB_PUBLIC std::string ShortKeys::info_severity_key ("I"); - DB_PUBLIC std::string ShortKeys::warning_severity_key ("W"); - DB_PUBLIC std::string ShortKeys::error_severity_key ("E"); } } diff --git a/src/db/db/dbLayoutVsSchematicFormatDefs.h b/src/db/db/dbLayoutVsSchematicFormatDefs.h index 9703a70b8..80abceaac 100644 --- a/src/db/db/dbLayoutVsSchematicFormatDefs.h +++ b/src/db/db/dbLayoutVsSchematicFormatDefs.h @@ -67,7 +67,7 @@ namespace db * Content is the Netlist dump (reduced version of LayoutToNetlist) * * [xrefs]: - * xref([xref|any]*) - cross-reference part [short key: Z] + * xref([xref|log|any]*) - cross-reference part [short key: Z] * * [xref]: * circuit([non] [non] [status|message|log|circuit-xrefs|any]*) @@ -82,11 +82,6 @@ namespace db * [log-entry]: * entry([severity] [message|any]*) - log entry [short key: M] * - * [severity]: - * info | - [short key: I] - * warning | - [short key: W] - * error - [short key: E] - * * [circuit-xrefs]: * xref([xref-pin|xref-device|xref-circuit|xref-net|any]*) * - circuit cross-reference part [short key: Z] @@ -113,6 +108,11 @@ namespace db * [message]: * description() - error description [short key: B] * + * [severity]: + * info | - [short key: I] + * warning | - [short key: W] + * error - [short key: E] + * * [status]: * mismatch | - [short key: 0] * match | - [short key: 1] @@ -145,10 +145,6 @@ namespace lvs_std_format static std::string nomatch_key; static std::string warning_key; static std::string skipped_key; - - static std::string info_severity_key; - static std::string warning_severity_key; - static std::string error_severity_key; }; struct DB_PUBLIC LongKeys @@ -166,10 +162,6 @@ namespace lvs_std_format static std::string nomatch_key; static std::string warning_key; static std::string skipped_key; - - static std::string info_severity_key; - static std::string warning_severity_key; - static std::string error_severity_key; }; template struct DB_PUBLIC keys; diff --git a/src/db/db/dbLayoutVsSchematicReader.cc b/src/db/db/dbLayoutVsSchematicReader.cc index 42f76e27f..1101d1d56 100644 --- a/src/db/db/dbLayoutVsSchematicReader.cc +++ b/src/db/db/dbLayoutVsSchematicReader.cc @@ -116,18 +116,6 @@ void LayoutVsSchematicStandardReader::read_netlist (db::LayoutVsSchematic *lvs) } } -bool LayoutVsSchematicStandardReader::read_message (std::string &msg) -{ - if (test (skeys::description_key) || test (lkeys::description_key)) { - Brace br (this); - read_word_or_quoted (msg); - br.done (); - return true; - } else { - return false; - } -} - bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::Status &status) { if (test (skeys::match_key) || test (lkeys::match_key)) { @@ -150,25 +138,9 @@ bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::St } } -bool LayoutVsSchematicStandardReader::read_severity (db::NetlistCrossReference::Severity &severity) -{ - if (test (skeys::info_severity_key) || test (lkeys::info_severity_key)) { - severity = db::NetlistCrossReference::Info; - return true; - } else if (test (skeys::warning_severity_key) || test (lkeys::warning_severity_key)) { - severity = db::NetlistCrossReference::Warning; - return true; - } else if (test (skeys::error_severity_key) || test (lkeys::error_severity_key)) { - severity = db::NetlistCrossReference::Error; - return true; - } else { - return false; - } -} - void LayoutVsSchematicStandardReader::read_log_entry (db::NetlistCrossReference *xref) { - db::NetlistCrossReference::Severity severity = db::NetlistCrossReference::NoSeverity; + db::Severity severity = db::NoSeverity; std::string msg; Brace br (this); @@ -186,7 +158,7 @@ void LayoutVsSchematicStandardReader::read_log_entry (db::NetlistCrossReference xref->log_entry (severity, msg); } -void LayoutVsSchematicStandardReader::read_logs_for_circuits (db::NetlistCrossReference *xref) +void LayoutVsSchematicStandardReader::read_logs (db::NetlistCrossReference *xref) { Brace br (this); while (br) { @@ -194,7 +166,7 @@ void LayoutVsSchematicStandardReader::read_logs_for_circuits (db::NetlistCrossRe if (test (skeys::log_entry_key) || test (lkeys::log_entry_key)) { read_log_entry (xref); } else if (at_end ()) { - throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside circuit definition (net, pin, device or circuit expected)"))); + throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside log section (entry expected)"))); } else { skip_element (); } @@ -269,7 +241,7 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref } else if (test (skeys::xref_key) || test (lkeys::xref_key)) { read_xrefs_for_circuits (xref, circuit_a, circuit_b); } else if (test (skeys::log_key) || test (lkeys::log_key)) { - read_logs_for_circuits (xref); + read_logs (xref); } else if (at_end ()) { throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside circuit definition (status keyword of xrefs expected)"))); } else { @@ -282,6 +254,8 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref br.done (); + } else if (test (skeys::log_key) || test (lkeys::log_key)) { + read_logs (xref); } else { skip_element (); } diff --git a/src/db/db/dbLayoutVsSchematicReader.h b/src/db/db/dbLayoutVsSchematicReader.h index 08aa9e5a1..7e0e98c36 100644 --- a/src/db/db/dbLayoutVsSchematicReader.h +++ b/src/db/db/dbLayoutVsSchematicReader.h @@ -28,6 +28,7 @@ #include "dbCell.h" #include "dbLayoutVsSchematic.h" #include "dbLayoutToNetlistReader.h" +#include "dbLog.h" #include "tlStream.h" namespace db { @@ -78,10 +79,8 @@ private: void read_netlist (db::LayoutVsSchematic *lvs); bool read_status (db::NetlistCrossReference::Status &status); - bool read_message (std::string &msg); void read_log_entry (db::NetlistCrossReference *xref); - void read_logs_for_circuits (db::NetlistCrossReference *xref); - bool read_severity (db::NetlistCrossReference::Severity &severity); + void read_logs (db::NetlistCrossReference *xref); void read_xref (db::NetlistCrossReference *xref); void read_xrefs_for_circuits (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b); void read_net_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b); diff --git a/src/db/db/dbLayoutVsSchematicWriter.cc b/src/db/db/dbLayoutVsSchematicWriter.cc index 9b1085102..9060c5a99 100644 --- a/src/db/db/dbLayoutVsSchematicWriter.cc +++ b/src/db/db/dbLayoutVsSchematicWriter.cc @@ -72,8 +72,6 @@ private: } std::string status_to_s (const db::NetlistCrossReference::Status status); - std::string severity_to_s (const db::NetlistCrossReference::Severity severity); - std::string message_to_s (const std::string &msg); void write (TokenizedOutput &stream, const db::NetlistCrossReference *xref); std::map > m_net2id_per_circuit_a, m_net2id_per_circuit_b; @@ -178,16 +176,6 @@ static std::string pin_id_to_s (const db::Pin *pin, const std::map -std::string std_writer_impl::message_to_s (const std::string &msg) -{ - if (msg.empty ()) { - return std::string (); - } else { - return Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")"; - } -} - template std::string std_writer_impl::status_to_s (const db::NetlistCrossReference::Status status) { @@ -206,30 +194,28 @@ std::string std_writer_impl::status_to_s (const db::NetlistCrossReference: } } -template -std::string std_writer_impl::severity_to_s (const db::NetlistCrossReference::Severity severity) -{ - if (severity == db::NetlistCrossReference::Info) { - return Keys::info_severity_key; - } else if (severity == db::NetlistCrossReference::Warning) { - return Keys::warning_severity_key; - } else if (severity == db::NetlistCrossReference::Error) { - return Keys::error_severity_key; - } else { - return std::string (); - } -} - template void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCrossReference *xref) { - for (db::NetlistCrossReference::circuits_iterator c = xref->begin_circuits (); c != xref->end_circuits (); ++c) { + if (! xref->other_log_entries ().empty ()) { + + TokenizedOutput o (stream, Keys::log_key); + o << endl; + + for (auto l = xref->other_log_entries ().begin (); l != xref->other_log_entries ().end (); ++l) { + TokenizedOutput (o, Keys::log_entry_key, true) << this->severity_to_s (l->severity) << this->message_to_s (l->msg); + o << endl; + } + + } + + for (auto c = xref->begin_circuits (); c != xref->end_circuits (); ++c) { const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c); tl_assert (pcd != 0); TokenizedOutput out (stream, Keys::circuit_key); - out << name_to_s (c->first) << name_to_s (c->second) << status_to_s (pcd->status) << message_to_s (pcd->msg); + out << name_to_s (c->first) << name_to_s (c->second) << status_to_s (pcd->status) << this->message_to_s (pcd->msg); out << endl; if (! pcd->log_entries.empty ()) { @@ -237,8 +223,8 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro TokenizedOutput o (out, Keys::log_key); o << endl; - for (db::NetlistCrossReference::PerCircuitData::log_entries_const_iterator l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { - TokenizedOutput (o, Keys::log_entry_key, true) << severity_to_s (l->severity) << message_to_s (l->msg); + for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { + TokenizedOutput (o, Keys::log_entry_key, true) << this->severity_to_s (l->severity) << this->message_to_s (l->msg); o << endl; } @@ -249,7 +235,7 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro o << endl; for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) { - TokenizedOutput (o, Keys::net_key) << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::net_key) << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << this->message_to_s (n->msg); } std::map pin2index_a, pin2index_b; @@ -257,15 +243,15 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro build_pin_index_map (c->second, pin2index_b); for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) { - TokenizedOutput (o, Keys::pin_key) << pin_id_to_s (n->pair.first, pin2index_a) << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::pin_key) << pin_id_to_s (n->pair.first, pin2index_a) << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << this->message_to_s (n->msg); } for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) { - TokenizedOutput (o, Keys::device_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::device_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << this->message_to_s (n->msg); } for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) { - TokenizedOutput (o, Keys::circuit_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg); + TokenizedOutput (o, Keys::circuit_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << this->message_to_s (n->msg); } } diff --git a/src/db/db/dbLog.cc b/src/db/db/dbLog.cc new file mode 100644 index 000000000..b777f6c94 --- /dev/null +++ b/src/db/db/dbLog.cc @@ -0,0 +1,31 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbCommon.h" +#include "dbLog.h" + +namespace db +{ + + // .. nothing yet .. + +} diff --git a/src/db/db/dbLog.h b/src/db/db/dbLog.h new file mode 100644 index 000000000..d9aea2650 --- /dev/null +++ b/src/db/db/dbLog.h @@ -0,0 +1,57 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _HDR_dbLog +#define _HDR_dbLog + +#include "dbCommon.h" + +#include + +namespace db +{ + +/** + * @brief An enum describing the severity for a log entry + */ +enum Severity { + NoSeverity = 0, // unspecific + Info = 1, // information only + Warning = 2, // a warning + Error = 3 // an error +}; + +/** + * @brief A class representing one log entry + */ +struct LogEntryData +{ + LogEntryData (Severity s, const std::string &m) : severity (s), msg (m) { } + LogEntryData () : severity (NoSeverity) { } + + Severity severity; + std::string msg; +}; + +} + +#endif diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 0a1f2e60c..e628dcfb0 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -385,7 +385,7 @@ NetlistComparer::compare_impl (const db::Netlist *a, const db::Netlist *b) const std::string msg = generate_subcircuits_not_verified_warning (ca, verified_circuits_a, cb, verified_circuits_b); if (m_with_log) { - mp_logger->log_entry (db::NetlistCompareLogger::Error, msg); + mp_logger->log_entry (db::Error, msg); } mp_logger->circuit_skipped (ca, cb, msg); @@ -899,7 +899,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, if (mp_logger) { if (p->second && ! exact_match) { if (m_with_log) { - mp_logger->log_entry (db::NetlistCompareLogger::Error, + mp_logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("Nets %s are paired explicitly, but are not identical topologically")), nets2string (p->first))); } mp_logger->net_mismatch (p->first.first, p->first.second); @@ -1145,12 +1145,12 @@ static void analyze_pin_mismatch (const db::Pin *pin1, const db::Circuit *c1, const db::Pin *pin2, const db::Circuit * /*c2*/, db::NetlistCompareLogger *logger) { if (! pin1) { - logger->log_entry (db::NetlistCompareLogger::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from reference netlist found in netlist.\nThis is an indication that a physical connection is not made to the subcircuit.")), pin2->expanded_name ())); + logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from reference netlist found in netlist.\nThis is an indication that a physical connection is not made to the subcircuit.")), pin2->expanded_name ())); } if (! pin2) { - logger->log_entry (db::NetlistCompareLogger::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from netlist found in reference netlist.\nThis is an indication that additional physical connections are made to the subcircuit cell.")), pin1->expanded_name ())); + logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("No equivalent pin %s from netlist found in reference netlist.\nThis is an indication that additional physical connections are made to the subcircuit cell.")), pin1->expanded_name ())); // attempt to identify pins which are creating invalid connections for (auto p = c1->begin_parents (); p != c1->end_parents (); ++p) { @@ -1159,7 +1159,7 @@ analyze_pin_mismatch (const db::Pin *pin1, const db::Circuit *c1, const db::Pin if (sc.circuit_ref () == c1) { const db::Net *net = sc.net_for_pin (pin1->id ()); if (net && (net->subcircuit_pin_count () > 1 || net->terminal_count () > 0 || net->pin_count () > 0)) { - logger->log_entry (db::NetlistCompareLogger::Info, tl::sprintf (tl::to_string (tr ("Potential invalid connection in circuit %s, subcircuit cell reference at %s")), p->name (), sc.trans ().to_string ())); + logger->log_entry (db::Info, tl::sprintf (tl::to_string (tr ("Potential invalid connection in circuit %s, subcircuit cell reference at %s")), p->name (), sc.trans ().to_string ())); } } } diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index e5e2cfa7d..9c775982f 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -25,6 +25,7 @@ #include "dbCommon.h" #include "dbNetlist.h" +#include "dbLog.h" #include #include @@ -50,16 +51,6 @@ public: NetlistCompareLogger () { } virtual ~NetlistCompareLogger () { } - /** - * @brief An enum describing the severity for the log_entry function - */ - enum Severity { - NoSeverity = 0, // unspecific - Info = 1, // information only - Warning = 2, // a warning - Error = 3 // an error - }; - /** * @brief Begin logging for netlist a and b */ @@ -101,7 +92,7 @@ public: /** * @brief Receives log entries for the current circuit pair */ - virtual void log_entry (Severity /*level*/, const std::string & /*msg*/) { } + virtual void log_entry (db::Severity /*level*/, const std::string & /*msg*/) { } /** * @brief Nets a and b match exactly diff --git a/src/db/db/dbNetlistCompareCore.cc b/src/db/db/dbNetlistCompareCore.cc index 3d9e1907f..e4e61deea 100644 --- a/src/db/db/dbNetlistCompareCore.cc +++ b/src/db/db/dbNetlistCompareCore.cc @@ -1052,7 +1052,7 @@ NetlistCompareCore::derive_node_identities_from_ambiguity_group (const NodeRange if (ambiguous) { if (logger) { if (with_log) { - logger->log_entry (db::NetlistCompareLogger::Warning, + logger->log_entry (db::Warning, tl::sprintf (tl::to_string (tr ("Matching nets %s from an ambiguous group of nets")), nets2string (p->first->net (), p->second->net ()))); } logger->match_ambiguous_nets (p->first->net (), p->second->net ()); @@ -1116,7 +1116,7 @@ NetlistCompareCore::derive_node_identities_from_ambiguity_group (const NodeRange } if (logger && with_log && was_ambiguous) { - logger->log_entry (db::NetlistCompareLogger::Info, + logger->log_entry (db::Info, tl::sprintf (tl::to_string (tr ("Matching nets %s following an ambiguous match")), nets2string (n->net (), n_other->net ()))); } @@ -1397,7 +1397,7 @@ analyze_nodes_for_close_matches (const std::multimaplog_entry (db::NetlistCompareLogger::Info, tl::sprintf (msg, + logger->log_entry (db::Info, tl::sprintf (msg, i->second->net ()->expanded_name (), j->second->net ()->expanded_name (), int (fuzz))); @@ -1417,7 +1417,7 @@ analyze_nodes_for_close_matches (const std::multimapsecond, *j->second, *k->second, g2); double fuzz_factor = double (fuzz) / i->first; if (fuzz_factor < max_fuzz_factor) { - logger->log_entry (db::NetlistCompareLogger::Info, tl::sprintf (msg, + logger->log_entry (db::Info, tl::sprintf (msg, (layout2ref ? i : j)->second->net ()->expanded_name (), (layout2ref ? j : k)->second->net ()->expanded_name (), (layout2ref ? k : i)->second->net ()->expanded_name (), @@ -1493,7 +1493,7 @@ NetlistCompareCore::analyze_failed_matches () const } for (auto i = singular1.begin (); i != singular1.end (); ++i) { - logger->log_entry (db::NetlistCompareLogger::Error, tl::sprintf (tl::to_string (tr ("Net %s is not matching any net from reference netlist")), (*i)->net ()->expanded_name ())); + logger->log_entry (db::Error, tl::sprintf (tl::to_string (tr ("Net %s is not matching any net from reference netlist")), (*i)->net ()->expanded_name ())); } // attempt some analysis for close matches (including shorts / opens) @@ -1552,7 +1552,7 @@ NetlistCompareCore::derive_node_identities_from_node_set (std::vector::max() && depth > max_depth) { if (with_log) { - logger->log_entry (db::NetlistCompareLogger::Warning, tl::sprintf (tl::to_string (tr ("Maximum depth exhausted (max depth is %d)")), int (max_depth))); + logger->log_entry (db::Warning, tl::sprintf (tl::to_string (tr ("Maximum depth exhausted (max depth is %d)")), int (max_depth))); } if (db::NetlistCompareGlobalOptions::options ()->debug_netcompare) { tl::info << indent_s << "max. depth exhausted (" << depth << ">" << max_depth << ")"; @@ -1670,7 +1670,7 @@ NetlistCompareCore::derive_node_identities_from_node_set (std::vector::max () && double (std::max (nr->num1, nr->num2)) * double (n_branch) > double (max_n_branch)) { if (with_log) { - logger->log_entry (db::NetlistCompareLogger::Warning, tl::sprintf (tl::to_string (tr ("Maximum complexity exhausted (max complexity is %s, needs at least %s)")), tl::to_string (max_n_branch), tl::to_string (std::max (nr->num1, nr->num2) * n_branch))); + logger->log_entry (db::Warning, tl::sprintf (tl::to_string (tr ("Maximum complexity exhausted (max complexity is %s, needs at least %s)")), tl::to_string (max_n_branch), tl::to_string (std::max (nr->num1, nr->num2) * n_branch))); } if (db::NetlistCompareGlobalOptions::options ()->debug_netcompare) { tl::info << indent_s << "max. complexity exhausted (" << std::max (nr->num1, nr->num2) << "*" << n_branch << ">" << max_n_branch << ") - mismatch."; diff --git a/src/db/db/dbNetlistCrossReference.h b/src/db/db/dbNetlistCrossReference.h index 71d32f7ca..aec52a8ed 100644 --- a/src/db/db/dbNetlistCrossReference.h +++ b/src/db/db/dbNetlistCrossReference.h @@ -105,15 +105,6 @@ public: std::string msg; }; - struct LogEntryData - { - LogEntryData (Severity s, const std::string &m) : severity (s), msg (m) { } - LogEntryData () : severity (NoSeverity) { } - - Severity severity; - std::string msg; - }; - struct PerCircuitData { PerCircuitData () : status (None) { } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index e1710c603..f80ca09ee 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -265,6 +265,14 @@ public: */ void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters, double device_scaling = 1.0); + /** + * @brief Clears the errors + */ + void clear_errors () + { + m_errors.clear (); + } + /** * @brief Gets the error iterator, begin */ diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc index c8f1fe6a4..ed61e975a 100644 --- a/src/db/db/gsiDeclDbNetlistCompare.cc +++ b/src/db/db/gsiDeclDbNetlistCompare.cc @@ -137,16 +137,16 @@ public: db::NetlistCompareLogger::circuit_mismatch (a, b, msg); } - virtual void log_entry (db::NetlistCompareLogger::Severity severity, const std::string &msg) + virtual void log_entry (db::Severity severity, const std::string &msg) { if (cb_log_entry.can_issue ()) { - cb_log_entry.issue (&GenericNetlistCompareLogger::log_entry, severity, msg); + cb_log_entry.issue (&GenericNetlistCompareLogger::log_entry, severity, msg); } else { db::NetlistCompareLogger::log_entry (severity, msg); } } - void log_entry_fb (db::NetlistCompareLogger::Severity severity, const std::string &msg) + void log_entry_fb (db::Severity severity, const std::string &msg) { db::NetlistCompareLogger::log_entry (severity, msg); } @@ -657,17 +657,17 @@ Class decl_dbNetlistComparer ("db", "NetlistComparer", "This class has been introduced in version 0.26." ); -gsi::EnumIn decl_CompareLoggerSeverity ("db", "Severity", - gsi::enum_const ("NoSeverity", db::NetlistCompareLogger::NoSeverity, +gsi::EnumIn decl_CompareLoggerSeverity ("db", "Severity", + gsi::enum_const ("NoSeverity", db::NoSeverity, "@brief Unspecific severity\n" ) + - gsi::enum_const ("Info", db::NetlistCompareLogger::Info, + gsi::enum_const ("Info", db::Info, "@brief Information only\n" ) + - gsi::enum_const ("Warning", db::NetlistCompareLogger::Warning, + gsi::enum_const ("Warning", db::Warning, "@brief A warning\n" ) + - gsi::enum_const ("Error", db::NetlistCompareLogger::Error, + gsi::enum_const ("Error", db::Error, "@brief An error\n" ), "@brief This class represents the log severity level for \\GenericNetlistCompareLogger#log_entry.\n" diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index faf4d4000..a967d9b73 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -1132,9 +1132,9 @@ NetlistBrowserPage::setup_trees () db::LayoutToNetlist *l2ndb = mp_database.get (); db::LayoutVsSchematic *lvsdb = dynamic_cast (l2ndb); - if (lvsdb && lvsdb->cross_ref ()) { + if ((lvsdb && lvsdb->cross_ref ()) || (l2ndb && ! l2ndb->log_entries ().empty ())) { - NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref ()); + NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref () /*@@@, l2ndb*/); delete log_view->model (); log_view->setModel (new_model); diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index aed4ac6f4..021c24b9a 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -137,6 +137,7 @@ NetlistLogModel::rowCount (const QModelIndex &parent) const } else if (parent.parent ().isValid ()) { return 0; } else if (parent.row () >= 0 && parent.row () < int (m_circuits.size ())) { + // @@@ that would crash for "other entries"! return int (m_circuits [parent.row ()].second->size ()); } else { return 0; @@ -152,7 +153,7 @@ NetlistLogModel::columnCount (const QModelIndex & /*parent*/) const QVariant NetlistLogModel::data (const QModelIndex &index, int role) const { - const db::NetlistCrossReference::LogEntryData *le = 0; + const db::LogEntryData *le = 0; if (index.parent ().isValid ()) { const circuit_entry *ce = (const circuit_entry *) index.internalPointer (); if (ce) { @@ -164,11 +165,11 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (! le) { // ignore - } else if (le->severity == db::NetlistCrossReference::Error) { + } else if (le->severity == db::Error) { return QIcon (QString::fromUtf8 (":/error_16px.png")); - } else if (le->severity == db::NetlistCrossReference::Warning) { + } else if (le->severity == db::Warning) { return QIcon (QString::fromUtf8 (":/warn_16px.png")); - } else if (le->severity == db::NetlistCrossReference::Info) { + } else if (le->severity == db::Info) { return QIcon (QString::fromUtf8 (":/info_16px.png")); } @@ -192,7 +193,7 @@ NetlistLogModel::data (const QModelIndex &index, int role) const } else if (role == Qt::FontRole) { if (index.parent ().isValid ()) { - if (le && le->severity == db::NetlistCrossReference::Error) { + if (le && le->severity == db::Error) { QFont f; f.setBold (true); return QVariant (f); @@ -208,9 +209,9 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (index.parent ().isValid ()) { if (!le) { // ignore - } else if (le->severity == db::NetlistCrossReference::Error) { + } else if (le->severity == db::Error) { return QColor (255, 0, 0); - } else if (le->severity == db::NetlistCrossReference::Warning) { + } else if (le->severity == db::Warning) { return QColor (0, 0, 255); } } From 7c1fd487d669f6e1f3f64d9c70bbdfcd71579e3a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 19:58:04 +0200 Subject: [PATCH 02/41] [consider merging] Bugfix for LayoutToNetlistReader --- src/db/db/dbLayoutToNetlistReader.cc | 1 + testdata/algo/l2n_reader_6.l2n | 6 ++++++ testdata/algo/l2n_reader_au_6.l2n | 18 ++++++++++++++++++ testdata/algo/l2n_writer_au_3.txt | 18 ++++++++++++++++++ testdata/algo/l2n_writer_au_3s.txt | 6 ++++++ 5 files changed, 49 insertions(+) create mode 100644 testdata/algo/l2n_reader_6.l2n create mode 100644 testdata/algo/l2n_reader_au_6.l2n create mode 100644 testdata/algo/l2n_writer_au_3.txt create mode 100644 testdata/algo/l2n_writer_au_3s.txt diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 0b980ebbb..5d44b714c 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -132,6 +132,7 @@ LayoutToNetlistStandardReader::skip () { while (m_ex.at_end () || *m_ex.skip () == '#') { if (m_stream.at_end ()) { + m_ex = tl::Extractor (); return; } m_progress.set (m_stream.line_number ()); diff --git a/testdata/algo/l2n_reader_6.l2n b/testdata/algo/l2n_reader_6.l2n new file mode 100644 index 000000000..4a4b7939c --- /dev/null +++ b/testdata/algo/l2n_reader_6.l2n @@ -0,0 +1,6 @@ +#%l2n-klayout +W(TOP) +U(0.001) +H(I B(info)) +H(W B(warning)) +H(E B(error)) diff --git a/testdata/algo/l2n_reader_au_6.l2n b/testdata/algo/l2n_reader_au_6.l2n new file mode 100644 index 000000000..2b0c7fd7c --- /dev/null +++ b/testdata/algo/l2n_reader_au_6.l2n @@ -0,0 +1,18 @@ +#%l2n-klayout +top(TOP) +unit(0.001) + +# Layer section +# This section lists the mask layers (drawing or derived) and their connections. + +# Mask layers + +# Mask layer connectivity + +# Log entries +message(info description(info)) +message(warning description(warning)) +message(error description(error)) + +# Circuit section +# Circuits are the hierarchical building blocks of the netlist. diff --git a/testdata/algo/l2n_writer_au_3.txt b/testdata/algo/l2n_writer_au_3.txt new file mode 100644 index 000000000..2b0c7fd7c --- /dev/null +++ b/testdata/algo/l2n_writer_au_3.txt @@ -0,0 +1,18 @@ +#%l2n-klayout +top(TOP) +unit(0.001) + +# Layer section +# This section lists the mask layers (drawing or derived) and their connections. + +# Mask layers + +# Mask layer connectivity + +# Log entries +message(info description(info)) +message(warning description(warning)) +message(error description(error)) + +# Circuit section +# Circuits are the hierarchical building blocks of the netlist. diff --git a/testdata/algo/l2n_writer_au_3s.txt b/testdata/algo/l2n_writer_au_3s.txt new file mode 100644 index 000000000..4a4b7939c --- /dev/null +++ b/testdata/algo/l2n_writer_au_3s.txt @@ -0,0 +1,6 @@ +#%l2n-klayout +W(TOP) +U(0.001) +H(I B(info)) +H(W B(warning)) +H(E B(error)) From 1333856337b5a208aa5312e96bc9494b0c8f5a5a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 19:58:22 +0200 Subject: [PATCH 03/41] WIP --- .../dbLayoutToNetlistReaderTests.cc | 42 +++++++++++++++++++ .../dbLayoutToNetlistWriterTests.cc | 35 ++++++++++++++++ testdata/algo/l2n_reader_6.l2n | 22 +++++++--- testdata/algo/l2n_reader_6s.l2n | 6 +++ 4 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 testdata/algo/l2n_reader_6s.l2n diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index 0d56d2dae..1fd37692f 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -497,3 +497,45 @@ TEST(5_ReaderFuture) compare_text_files (path, au_path); } +TEST(6_ReaderLog) +{ + db::LayoutToNetlist l2n; + + std::string in_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "l2n_reader_6.l2n"); + tl::InputStream is_in (in_path); + + db::LayoutToNetlistStandardReader reader (is_in); + reader.read (&l2n); + + // verify against the input + + std::string path = tmp_file ("tmp.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, false); + writer.write (&l2n); + } + + std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "l2n_reader_au_6.l2n"); + + compare_text_files (path, au_path); + + std::string in_path_s = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "l2n_reader_6s.l2n"); + tl::InputStream is_in_s (in_path_s); + + l2n.clear_log_entries (); + db::LayoutToNetlistStandardReader reader_s (is_in_s); + reader_s.read (&l2n); + + // verify against the input + + path = tmp_file ("tmp2.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, false); + writer.write (&l2n); + } + + compare_text_files (path, au_path); +} + diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index 68cac78b0..9acaab77d 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -449,3 +449,38 @@ TEST(2_WriterWithGlobalNets) db::compare_layouts (_this, ly2, au); } } + +TEST(3_Messages) +{ + db::Layout ly; + db::Cell &tc = ly.cell (ly.add_cell ("TOP")); + db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); + + l2n.extract_netlist (); + + l2n.log_entry (db::LogEntryData (db::Info, "info")); + l2n.log_entry (db::LogEntryData (db::Warning, "warning")); + l2n.log_entry (db::LogEntryData (db::Error, "error")); + + std::string path = tmp_file ("tmp_l2nwriter_3.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, false); + writer.write (&l2n); + } + + std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "l2n_writer_au_3.txt"); + + compare_text_files (path, au_path); + + path = tmp_file ("tmp_l2nwriter_3s.txt"); + { + tl::OutputStream stream (path); + db::LayoutToNetlistStandardWriter writer (stream, true); + writer.write (&l2n); + } + + au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "l2n_writer_au_3s.txt"); + + compare_text_files (path, au_path); +} diff --git a/testdata/algo/l2n_reader_6.l2n b/testdata/algo/l2n_reader_6.l2n index 4a4b7939c..2b0c7fd7c 100644 --- a/testdata/algo/l2n_reader_6.l2n +++ b/testdata/algo/l2n_reader_6.l2n @@ -1,6 +1,18 @@ #%l2n-klayout -W(TOP) -U(0.001) -H(I B(info)) -H(W B(warning)) -H(E B(error)) +top(TOP) +unit(0.001) + +# Layer section +# This section lists the mask layers (drawing or derived) and their connections. + +# Mask layers + +# Mask layer connectivity + +# Log entries +message(info description(info)) +message(warning description(warning)) +message(error description(error)) + +# Circuit section +# Circuits are the hierarchical building blocks of the netlist. diff --git a/testdata/algo/l2n_reader_6s.l2n b/testdata/algo/l2n_reader_6s.l2n new file mode 100644 index 000000000..4a4b7939c --- /dev/null +++ b/testdata/algo/l2n_reader_6s.l2n @@ -0,0 +1,6 @@ +#%l2n-klayout +W(TOP) +U(0.001) +H(I B(info)) +H(W B(warning)) +H(E B(error)) From b589f015daa892dcd4b995aa94bdce91a84cfb8b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 21:53:02 +0200 Subject: [PATCH 04/41] New tests --- testdata/algo/lvs_test3.lvsdb | 11 +++++++++++ testdata/algo/lvs_test3_au.lvsdb | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/testdata/algo/lvs_test3.lvsdb b/testdata/algo/lvs_test3.lvsdb index d94707f4b..91f3aa00d 100644 --- a/testdata/algo/lvs_test3.lvsdb +++ b/testdata/algo/lvs_test3.lvsdb @@ -613,7 +613,17 @@ reference( # Cross reference xref( + log( + entry(error description("An error (global)")) + entry(warning description("A warning (global)")) + entry(info description("Some info (global)")) + ) circuit(() INV2PAIRX mismatch + log( + entry(error description("An error")) + entry(warning description("A warning")) + entry(info description("Some info")) + ) kk( jj("hello" W) jj("world!" E) ) # invalid xref( ) @@ -684,4 +694,5 @@ xref( circuit(5 5 match) ) ) + kk( xx(1 2 3) ) # invalid ) diff --git a/testdata/algo/lvs_test3_au.lvsdb b/testdata/algo/lvs_test3_au.lvsdb index fd107f1b9..617d84271 100644 --- a/testdata/algo/lvs_test3_au.lvsdb +++ b/testdata/algo/lvs_test3_au.lvsdb @@ -602,7 +602,17 @@ reference( # Cross reference xref( + log( + entry(error description('An error (global)')) + entry(warning description('A warning (global)')) + entry(info description('Some info (global)')) + ) circuit(() INV2PAIRX mismatch + log( + entry(error description('An error')) + entry(warning description('A warning')) + entry(info description('Some info')) + ) xref( ) ) From 93c570a6f9ef19359f94394809dce8cfdfe5f9f9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 22:04:36 +0200 Subject: [PATCH 05/41] [consider merging] Fixed an unitialized pointer --- src/db/db/dbNetlistCrossReference.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/db/db/dbNetlistCrossReference.cc b/src/db/db/dbNetlistCrossReference.cc index 93f46acea..37598df5c 100644 --- a/src/db/db/dbNetlistCrossReference.cc +++ b/src/db/db/dbNetlistCrossReference.cc @@ -27,6 +27,7 @@ namespace db { NetlistCrossReference::NetlistCrossReference () + : mp_per_circuit_data (0) { // .. nothing yet .. } From 2fe611a75c82d74ec3e2a973c4dbeaef5a182868 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 23:21:34 +0200 Subject: [PATCH 06/41] Log model enhanced for extractor messages --- src/layui/layui/layNetlistBrowserPage.cc | 2 +- src/layui/layui/layNetlistLogModel.cc | 79 +++++++++++++----------- src/layui/layui/layNetlistLogModel.h | 6 +- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index a967d9b73..58a4a7b23 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -1134,7 +1134,7 @@ NetlistBrowserPage::setup_trees () if ((lvsdb && lvsdb->cross_ref ()) || (l2ndb && ! l2ndb->log_entries ().empty ())) { - NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref () /*@@@, l2ndb*/); + NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref (), l2ndb); delete log_view->model (); log_view->setModel (new_model); diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index 021c24b9a..7bf06c714 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -78,19 +78,20 @@ namespace { const std::string var_sep (" \u21D4 "); -NetlistLogModel::NetlistLogModel (QWidget *parent, const db::NetlistCrossReference *cross_ref) +NetlistLogModel::NetlistLogModel (QWidget *parent, const db::NetlistCrossReference *cross_ref, const db::LayoutToNetlist *l2n) : QAbstractItemModel (parent) { tl_assert (cross_ref->netlist_a () != 0); tl_assert (cross_ref->netlist_b () != 0); - if (! cross_ref->other_log_entries ().empty ()) { - m_circuits.push_back (std::make_pair (std::make_pair ((const db::Circuit *)0, (const db::Circuit *)0), &cross_ref->other_log_entries ())); - } + mp_lvsdb_messages = cross_ref ? &cross_ref->other_log_entries () : 0; + mp_l2n_messages = l2n ? &l2n->log_entries () : 0; + + m_global_entries = int ((mp_lvsdb_messages ? mp_lvsdb_messages->size () : 0) + (mp_l2n_messages ? mp_l2n_messages->size () : 0)); for (auto i = cross_ref->begin_circuits (); i != cross_ref->end_circuits (); ++i) { const db::NetlistCrossReference::PerCircuitData *pcd = cross_ref->per_circuit_data_for (*i); - if (pcd && i->first && i->second && ! pcd->log_entries.empty ()) { + if (pcd && (i->first || i->second) && ! pcd->log_entries.empty ()) { m_circuits.push_back (std::make_pair (*i, &pcd->log_entries)); } } @@ -102,9 +103,11 @@ bool NetlistLogModel::hasChildren (const QModelIndex &parent) const { if (! parent.isValid ()) { - return ! m_circuits.empty (); + return m_global_entries > 0 || ! m_circuits.empty (); + } else if (! parent.parent ().isValid ()) { + return parent.row () >= m_global_entries; } else { - return ! parent.parent ().isValid (); + return false; } } @@ -114,7 +117,7 @@ NetlistLogModel::index (int row, int column, const QModelIndex &parent) const if (! parent.isValid ()) { return createIndex (row, column, (void *) (0)); } else { - return createIndex (row, column, (void *) (& m_circuits [parent.row ()])); + return createIndex (row, column, (void *) (& m_circuits [parent.row () - m_global_entries])); } } @@ -125,7 +128,7 @@ NetlistLogModel::parent (const QModelIndex &child) const return QModelIndex (); } else { const circuit_entry *ce = (const circuit_entry *) child.internalPointer (); - return createIndex (int (ce - & m_circuits.front ()), child.column (), (void *) (0)); + return createIndex (int (ce - & m_circuits.front ()) + m_global_entries, child.column (), (void *) (0)); } } @@ -133,12 +136,11 @@ int NetlistLogModel::rowCount (const QModelIndex &parent) const { if (! parent.isValid ()) { - return int (m_circuits.size ()); + return int (m_circuits.size ()) + m_global_entries; } else if (parent.parent ().isValid ()) { return 0; - } else if (parent.row () >= 0 && parent.row () < int (m_circuits.size ())) { - // @@@ that would crash for "other entries"! - return int (m_circuits [parent.row ()].second->size ()); + } else if (parent.row () >= m_global_entries && parent.row () < int (m_circuits.size ()) + m_global_entries) { + return int (m_circuits [parent.row () - m_global_entries].second->size ()); } else { return 0; } @@ -157,7 +159,14 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (index.parent ().isValid ()) { const circuit_entry *ce = (const circuit_entry *) index.internalPointer (); if (ce) { - le = &(*ce->second) [index.row ()]; + le = (ce->second->begin () + index.row ()).operator-> (); + } + } else if (index.row () < m_global_entries) { + int n_l2n = int (mp_l2n_messages ? mp_l2n_messages->size () : 0); + if (index.row () < n_l2n) { + le = (mp_l2n_messages->begin () + index.row ()).operator-> (); + } else { + le = (mp_lvsdb_messages->begin () + (index.row () - n_l2n)).operator-> (); } } @@ -175,14 +184,14 @@ NetlistLogModel::data (const QModelIndex &index, int role) const } else if (role == Qt::DisplayRole) { - if (index.parent ().isValid ()) { - if (le) { - return QVariant (tl::to_qstring (le->msg)); - } - } else if (index.row () >= 0 && index.row () < int (m_circuits.size ())) { - const std::pair &cp = m_circuits [index.row ()].first; - if (! cp.first || ! cp.second) { - return QVariant (tr ("General")); + if (le) { + return QVariant (tl::to_qstring (le->msg)); + } else if (! index.parent ().isValid () && index.row () >= m_global_entries && index.row () < int (m_circuits.size ()) + m_global_entries) { + const std::pair &cp = m_circuits [index.row () - m_global_entries].first; + if (! cp.first) { + return QVariant (tr ("Circuit ") + tl::to_qstring (std::string ("-") + var_sep + cp.second->name ())); + } else if (! cp.second) { + return QVariant (tr ("Circuit ") + tl::to_qstring (cp.first->name () + var_sep + std::string ("-"))); } else if (cp.first->name () != cp.second->name ()) { return QVariant (tr ("Circuit ") + tl::to_qstring (cp.first->name () + var_sep + cp.second->name ())); } else { @@ -192,13 +201,11 @@ NetlistLogModel::data (const QModelIndex &index, int role) const } else if (role == Qt::FontRole) { - if (index.parent ().isValid ()) { - if (le && le->severity == db::Error) { - QFont f; - f.setBold (true); - return QVariant (f); - } - } else { + if (le) { + QFont f; + f.setBold (le->severity == db::Error); + return QVariant (f); + } else if (! index.parent ().isValid () && index.row () >= m_global_entries && index.row () < int (m_circuits.size ()) + m_global_entries) { QFont f; f.setBold (true); return QVariant (f); @@ -206,14 +213,12 @@ NetlistLogModel::data (const QModelIndex &index, int role) const } else if (role == Qt::ForegroundRole) { - if (index.parent ().isValid ()) { - if (!le) { - // ignore - } else if (le->severity == db::Error) { - return QColor (255, 0, 0); - } else if (le->severity == db::Warning) { - return QColor (0, 0, 255); - } + if (! le) { + // ignore + } else if (le->severity == db::Error) { + return QColor (255, 0, 0); + } else if (le->severity == db::Warning) { + return QColor (0, 0, 255); } } diff --git a/src/layui/layui/layNetlistLogModel.h b/src/layui/layui/layNetlistLogModel.h index 751a007e0..cd4178936 100644 --- a/src/layui/layui/layNetlistLogModel.h +++ b/src/layui/layui/layNetlistLogModel.h @@ -27,6 +27,7 @@ #include "layuiCommon.h" #include "dbNetlistCrossReference.h" +#include "dbLayoutToNetlist.h" #include @@ -40,7 +41,7 @@ class LAYUI_PUBLIC NetlistLogModel : public QAbstractItemModel { public: - NetlistLogModel (QWidget *parent, const db::NetlistCrossReference *cross_ref); + NetlistLogModel (QWidget *parent, const db::NetlistCrossReference *cross_ref, const db::LayoutToNetlist *l2n); virtual bool hasChildren (const QModelIndex &parent) const; virtual QModelIndex index (int row, int column, const QModelIndex &parent) const; @@ -53,6 +54,9 @@ public: private: typedef std::pair, const db::NetlistCrossReference::PerCircuitData::log_entries_type *> circuit_entry; std::vector m_circuits; + const db::NetlistCrossReference::PerCircuitData::log_entries_type *mp_lvsdb_messages; + const db::LayoutToNetlist::log_entries_type *mp_l2n_messages; + int m_global_entries; }; } From 033d6309921fbf4a967e3e1be1ce3dd7fc99b3d6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 17 Sep 2023 23:33:47 +0200 Subject: [PATCH 07/41] Log tab now shows max severity of logs --- src/layui/layui/layNetlistBrowserPage.cc | 6 ++++ src/layui/layui/layNetlistLogModel.cc | 40 ++++++++++++++++++------ src/layui/layui/layNetlistLogModel.h | 9 ++++++ 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index 58a4a7b23..51e4b367c 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -1132,12 +1132,16 @@ NetlistBrowserPage::setup_trees () db::LayoutToNetlist *l2ndb = mp_database.get (); db::LayoutVsSchematic *lvsdb = dynamic_cast (l2ndb); + QIcon log_tab_icon; + if ((lvsdb && lvsdb->cross_ref ()) || (l2ndb && ! l2ndb->log_entries ().empty ())) { NetlistLogModel *new_model = new NetlistLogModel (log_view, lvsdb->cross_ref (), l2ndb); delete log_view->model (); log_view->setModel (new_model); + log_tab_icon = NetlistLogModel::icon_for_severity (new_model->max_severity ()); + } else { delete log_view->model (); @@ -1145,6 +1149,8 @@ NetlistBrowserPage::setup_trees () } + mode_tab->setTabIcon (3, log_tab_icon); + { // NOTE: with the tree as the parent, the tree will take over ownership of the model NetlistBrowserModel *new_model = new NetlistBrowserModel (nl_directory_tree, l2ndb, &m_colorizer); diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index 7bf06c714..c89ef2c22 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -79,19 +79,33 @@ namespace { const std::string var_sep (" \u21D4 "); NetlistLogModel::NetlistLogModel (QWidget *parent, const db::NetlistCrossReference *cross_ref, const db::LayoutToNetlist *l2n) - : QAbstractItemModel (parent) + : QAbstractItemModel (parent), m_max_severity (db::NoSeverity) { tl_assert (cross_ref->netlist_a () != 0); tl_assert (cross_ref->netlist_b () != 0); mp_lvsdb_messages = cross_ref ? &cross_ref->other_log_entries () : 0; + if (mp_lvsdb_messages) { + for (auto l = mp_lvsdb_messages->begin (); l != mp_lvsdb_messages->end (); ++l) { + m_max_severity = std::max (m_max_severity, l->severity); + } + } + mp_l2n_messages = l2n ? &l2n->log_entries () : 0; + if (mp_l2n_messages) { + for (auto l = mp_l2n_messages->begin (); l != mp_l2n_messages->end (); ++l) { + m_max_severity = std::max (m_max_severity, l->severity); + } + } m_global_entries = int ((mp_lvsdb_messages ? mp_lvsdb_messages->size () : 0) + (mp_l2n_messages ? mp_l2n_messages->size () : 0)); for (auto i = cross_ref->begin_circuits (); i != cross_ref->end_circuits (); ++i) { const db::NetlistCrossReference::PerCircuitData *pcd = cross_ref->per_circuit_data_for (*i); if (pcd && (i->first || i->second) && ! pcd->log_entries.empty ()) { + for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { + m_max_severity = std::max (m_max_severity, l->severity); + } m_circuits.push_back (std::make_pair (*i, &pcd->log_entries)); } } @@ -152,6 +166,20 @@ NetlistLogModel::columnCount (const QModelIndex & /*parent*/) const return 1; } +QIcon +NetlistLogModel::icon_for_severity (db::Severity severity) +{ + if (severity == db::Error) { + return QIcon (QString::fromUtf8 (":/error_16px.png")); + } else if (severity == db::Warning) { + return QIcon (QString::fromUtf8 (":/warn_16px.png")); + } else if (severity == db::Info) { + return QIcon (QString::fromUtf8 (":/info_16px.png")); + } else { + return QIcon (); + } +} + QVariant NetlistLogModel::data (const QModelIndex &index, int role) const { @@ -172,14 +200,8 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (role == Qt::DecorationRole) { - if (! le) { - // ignore - } else if (le->severity == db::Error) { - return QIcon (QString::fromUtf8 (":/error_16px.png")); - } else if (le->severity == db::Warning) { - return QIcon (QString::fromUtf8 (":/warn_16px.png")); - } else if (le->severity == db::Info) { - return QIcon (QString::fromUtf8 (":/info_16px.png")); + if (le) { + return icon_for_severity (le->severity); } } else if (role == Qt::DisplayRole) { diff --git a/src/layui/layui/layNetlistLogModel.h b/src/layui/layui/layNetlistLogModel.h index cd4178936..bbd26f2eb 100644 --- a/src/layui/layui/layNetlistLogModel.h +++ b/src/layui/layui/layNetlistLogModel.h @@ -30,6 +30,7 @@ #include "dbLayoutToNetlist.h" #include +#include namespace lay { @@ -51,12 +52,20 @@ public: virtual QVariant data (const QModelIndex &index, int role) const; virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; + static QIcon icon_for_severity (db::Severity severity); + + db::Severity max_severity () const + { + return m_max_severity; + } + private: typedef std::pair, const db::NetlistCrossReference::PerCircuitData::log_entries_type *> circuit_entry; std::vector m_circuits; const db::NetlistCrossReference::PerCircuitData::log_entries_type *mp_lvsdb_messages; const db::LayoutToNetlist::log_entries_type *mp_l2n_messages; int m_global_entries; + db::Severity m_max_severity; }; } From e7a85690529b45bde1f95d2cafeb6456e6f8771b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 19 Sep 2023 23:10:51 +0200 Subject: [PATCH 08/41] WIP: reimplementing connect_implicit on netlist basis --- src/db/db/dbCircuit.cc | 45 +++++++++++++--- src/db/db/dbCircuit.h | 2 +- src/db/db/dbLayoutToNetlist.cc | 98 +++++++++++++++++++++++++++++++++- src/db/db/dbLayoutToNetlist.h | 5 ++ src/db/db/dbSubCircuit.cc | 5 ++ src/db/db/dbSubCircuit.h | 5 ++ 6 files changed, 151 insertions(+), 9 deletions(-) diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index 2cd32edfd..9941d3d51 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -366,14 +366,11 @@ void Circuit::remove_net (Net *net) void Circuit::join_nets (Net *net, Net *with) { - if (! net) { - return; - } - if (net == with || ! with) { + if (net == with || ! with || ! net) { return; } if (net->circuit () != this || with->circuit () != this) { - throw tl::Exception (tl::to_string (tr ("Nets not withing given circuit"))); + throw tl::Exception (tl::to_string (tr ("Nets not within given circuit"))); } while (with->begin_terminals () != with->end_terminals ()) { @@ -390,7 +387,6 @@ void Circuit::join_nets (Net *net, Net *with) connect_pin (with->begin_pins ()->pin_id (), net); } - // TODO: join clusters too, join net properties(?) if (netlist ()->callbacks ()) { netlist ()->callbacks ()->link_nets (net, with); } @@ -676,7 +672,42 @@ void Circuit::connect_pin (size_t pin_id, Net *net) } if (net) { - net->add_pin (NetPinRef (pin_id)); + if (net->begin_pins () != net->end_pins ()) { + join_pins (net->begin_pins ()->pin_id (), pin_id); + } else { + net->add_pin (NetPinRef (pin_id)); + } + } +} + +void Circuit::join_pins (size_t pin, size_t with) +{ + if (with < m_pin_by_id.size () && ! tl::is_null_iterator (m_pin_by_id [with])) { + + m_pins.erase (m_pin_by_id [with]); + m_pin_by_id.erase (m_pin_by_id.begin () + with); + m_pin_refs.erase (m_pin_refs.begin () + with); + + // join nets in calls + for (auto s = begin_refs (); s != end_refs (); ++s) { + + db::SubCircuit &sc = *s; + + db::Net *with_net = sc.net_for_pin (with); + // remove the subcircuit pin reference from the "with" net + for (auto sc_pin = with_net->begin_subcircuit_pins (); sc_pin != with_net->end_subcircuit_pins (); ++sc_pin) { + if (sc_pin->subcircuit () == &sc && sc_pin->pin_id () == with) { + with_net->erase_subcircuit_pin (sc_pin); + break; + } + } + + sc.circuit ()->join_nets (sc.net_for_pin (pin), with_net); + + sc.erase_pin_ref (with); + + } + } } diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index 4ffad288a..5c90ed4a0 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -819,7 +819,7 @@ private: bool combine_parallel_devices (const db::DeviceClass &cls); bool combine_serial_devices (const db::DeviceClass &cls); void do_purge_nets (bool keep_pins); - + void join_pins (size_t pin_id, size_t with); void devices_changed (); void subcircuits_changed (); void nets_changed (); diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 19d31468b..93cb191ef 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -414,7 +414,7 @@ void LayoutToNetlist::extract_netlist () netex.set_include_floating_subcircuits (m_include_floating_subcircuits); netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); - // @@@ join_nets (); + do_join_nets (); if (tl::verbosity () >= 41) { MemStatisticsCollector m (false); @@ -425,6 +425,102 @@ void LayoutToNetlist::extract_netlist () m_netlist_extracted = true; } +static std::vector nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p) +{ + std::vector result; + for (auto n = c.begin_nets (); n != c.end_nets (); ++n) { + if (p.match (n->name ())) { + result.push_back (n.operator-> ()); + } + } + return result; +} + +static std::vector nets_from_pattern (db::Circuit &c, const std::set &p) +{ + std::vector result; + for (auto n = p.begin (); n != p.end (); ++n) { + db::Net *net = c.net_by_name (*n); + if (net) { + result.push_back (net); + } + } + return result; +} + +void LayoutToNetlist::do_join_nets (db::Circuit &c, const std::vector &nets) +{ + if (nets.size () <= 1) { + return; + } + + std::set names; + for (auto n = nets.begin (); n != nets.end (); ++n) { + if (! (*n)->name ().empty ()) { + names.insert ((*n)->name ()); + } + } + + nets [0]->set_name (tl::join (names.begin (), names.end (), ",")); + + for (auto n = nets.begin () + 1; n != nets.end (); ++n) { + c.join_nets (nets [0], *n); + } +} + +void LayoutToNetlist::do_join_nets () +{ + if (! mp_netlist) { + return; + } + + // prevents updates + NetlistLocker locked_netlist (mp_netlist.get ()); + + for (auto jn = m_joined_net_names.begin (); jn != m_joined_net_names.end (); ++jn) { + for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + do_join_nets (*c, nets_from_pattern (*c, *jn)); + } + } + + for (auto jn = m_joined_nets.begin (); jn != m_joined_nets.end (); ++jn) { + for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + do_join_nets (*c, nets_from_pattern (*c, *jn)); + } + } + + for (auto jn = m_joined_net_names_per_cell.begin (); jn != m_joined_net_names_per_cell.end (); ++jn) { + for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + if (jn->first.match (c->name ())) { + do_join_nets (*c, nets_from_pattern (*c, jn->second)); + } + } + } + + for (auto jn = m_joined_nets_per_cell.begin (); jn != m_joined_nets_per_cell.end (); ++jn) { + for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + if (jn->first.match (c->name ())) { + do_join_nets (*c, nets_from_pattern (*c, jn->second)); + } + } + } +} + +void LayoutToNetlist::error (const std::string &msg) +{ + m_log_entries.push_back (db::LogEntryData (db::Error, msg)); +} + +void LayoutToNetlist::warn (const std::string &msg) +{ + m_log_entries.push_back (db::LogEntryData (db::Warning, msg)); +} + +void LayoutToNetlist::info (const std::string &msg) +{ + m_log_entries.push_back (db::LogEntryData (db::Info, msg)); +} + void LayoutToNetlist::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const { if (! no_self) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index e159e46e4..7be093bb3 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -993,6 +993,11 @@ private: void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b); size_t connect_global_impl (const db::ShapeCollection &l, const std::string &gn); bool is_persisted_impl (const db::ShapeCollection &coll) const; + void do_join_nets (db::Circuit &c, const std::vector &nets); + void do_join_nets (); + void error (const std::string &msg); + void warn (const std::string &msg); + void info (const std::string &msg); // implementation of NetlistManipulationCallbacks virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans); diff --git a/src/db/db/dbSubCircuit.cc b/src/db/db/dbSubCircuit.cc index 58a607cf3..4107a1475 100644 --- a/src/db/db/dbSubCircuit.cc +++ b/src/db/db/dbSubCircuit.cc @@ -90,6 +90,11 @@ void SubCircuit::set_trans (const db::DCplxTrans &t) m_trans = t; } +void SubCircuit::erase_pin_ref (size_t pin_id) +{ + m_pin_refs.erase (m_pin_refs.begin () + pin_id); +} + void SubCircuit::set_pin_ref_for_pin (size_t pin_id, Net::subcircuit_pin_iterator iter) { if (m_pin_refs.size () < pin_id + 1) { diff --git a/src/db/db/dbSubCircuit.h b/src/db/db/dbSubCircuit.h index a83bec881..9e0877adf 100644 --- a/src/db/db/dbSubCircuit.h +++ b/src/db/db/dbSubCircuit.h @@ -230,6 +230,11 @@ private: */ void set_circuit_ref (Circuit *c); + /** + * @brief Erases the given pin reference + */ + void erase_pin_ref (size_t pin_id); + /** * @brief Sets the circuit the subcircuit belongs to */ From 034a2673d0d96901e23a5e2f291131fc200dbc02 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 19 Sep 2023 23:39:02 +0200 Subject: [PATCH 09/41] Implemented must-connect check --- src/db/db/dbLayoutToNetlist.cc | 40 ++++++++++++++++++++++++++++++++++ src/db/db/dbLayoutToNetlist.h | 1 + 2 files changed, 41 insertions(+) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 93cb191ef..c8ce482ba 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -464,10 +464,50 @@ void LayoutToNetlist::do_join_nets (db::Circuit &c, const std::vector nets [0]->set_name (tl::join (names.begin (), names.end (), ",")); for (auto n = nets.begin () + 1; n != nets.end (); ++n) { + check_must_connect (c, *nets [0], **n); c.join_nets (nets [0], *n); } } +static std::string subcircuit_to_string (const db::SubCircuit &sc) +{ + if (! sc.name ().empty ()) { + return tl::to_string (tr ("on subcircuit ")) + sc.name () + tl::to_string (tr (" in ")) + sc.circuit ()->name (); + } else { + return tl::to_string (tr ("in ")) + sc.circuit ()->name (); + } +} + +void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b) +{ + if (&a == &b) { + return; + } + + if (a.begin_pins () == a.end_pins ()) { + error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); + } + if (b.begin_pins () == b.end_pins ()) { + error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); + } + if (a.begin_pins () != a.end_pins () && b.begin_pins () != b.end_pins ()) { + for (auto ref = c.begin_refs (); ref != c.end_refs (); ++ref) { + const db::SubCircuit &sc = *ref; + const db::Net *net_a = sc.net_for_pin (a.begin_pins ()->pin_id ()); + const db::Net *net_b = sc.net_for_pin (b.begin_pins ()->pin_id ()); + if (net_a == 0) { + error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected at all %s")), a.expanded_name (), c.name (), subcircuit_to_string (sc))); + } + if (net_b == 0) { + error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected at all %s")), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + } + if (net_a && net_b && net_a != net_b) { + error (tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s from circuit %s are not connected %s")), a.expanded_name (), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + } + } + } +} + void LayoutToNetlist::do_join_nets () { if (! mp_netlist) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 7be093bb3..443bef184 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -995,6 +995,7 @@ private: bool is_persisted_impl (const db::ShapeCollection &coll) const; void do_join_nets (db::Circuit &c, const std::vector &nets); void do_join_nets (); + void check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b); void error (const std::string &msg); void warn (const std::string &msg); void info (const std::string &msg); From 1639ffdf34e248e614ec53ce873350841e14eb85 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 19 Sep 2023 23:42:19 +0200 Subject: [PATCH 10/41] WIP --- src/db/db/dbLayoutToNetlist.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index c8ce482ba..63ff977c1 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -423,6 +423,8 @@ void LayoutToNetlist::extract_netlist () } m_netlist_extracted = true; + + // @@@ raise error on error } static std::vector nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p) @@ -484,12 +486,15 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a return; } - if (a.begin_pins () == a.end_pins ()) { - error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); - } - if (b.begin_pins () == b.end_pins ()) { - error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); + if (c.begin_refs () != c.end_refs ()) { + if (a.begin_pins () == a.end_pins ()) { + error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); + } + if (b.begin_pins () == b.end_pins ()) { + error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); + } } + if (a.begin_pins () != a.end_pins () && b.begin_pins () != b.end_pins ()) { for (auto ref = c.begin_refs (); ref != c.end_refs (); ++ref) { const db::SubCircuit &sc = *ref; From 2f1cbf2e0111af9b1fdd149555c6ea4d712d77df Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 22 Sep 2023 21:45:34 +0200 Subject: [PATCH 11/41] WIP --- src/db/db/dbLayoutToNetlist.cc | 43 ++++++++++++++++++++-------------- src/db/db/dbLayoutToNetlist.h | 2 ++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 63ff977c1..48eba3c61 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -427,27 +427,36 @@ void LayoutToNetlist::extract_netlist () // @@@ raise error on error } -static std::vector nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p) +void LayoutToNetlist::join_nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p) { - std::vector result; + std::map > nets_by_name; for (auto n = c.begin_nets (); n != c.end_nets (); ++n) { - if (p.match (n->name ())) { - result.push_back (n.operator-> ()); + if (! n->name ().empty () && p.match (n->name ())) { + nets_by_name [n->name ()].push_back (n.operator-> ()); + } + } + + for (auto n2n = nets_by_name.begin (); n2n != nets_by_name.end (); ++n2n) { + if (n2n->second.size () > 1) { + do_join_nets (c, n2n->second); } } - return result; } -static std::vector nets_from_pattern (db::Circuit &c, const std::set &p) +void LayoutToNetlist::join_nets_from_pattern (db::Circuit &c, const std::set &p) { - std::vector result; + std::vector nets; for (auto n = p.begin (); n != p.end (); ++n) { - db::Net *net = c.net_by_name (*n); - if (net) { - result.push_back (net); + if (! n->empty ()) { + db::Net *net = c.net_by_name (*n); + if (net) { + nets.push_back (net); + } } } - return result; + if (nets.size () > 1) { + do_join_nets (c, nets); + } } void LayoutToNetlist::do_join_nets (db::Circuit &c, const std::vector &nets) @@ -458,9 +467,7 @@ void LayoutToNetlist::do_join_nets (db::Circuit &c, const std::vector std::set names; for (auto n = nets.begin (); n != nets.end (); ++n) { - if (! (*n)->name ().empty ()) { - names.insert ((*n)->name ()); - } + names.insert ((*n)->name ()); } nets [0]->set_name (tl::join (names.begin (), names.end (), ",")); @@ -524,20 +531,20 @@ void LayoutToNetlist::do_join_nets () for (auto jn = m_joined_net_names.begin (); jn != m_joined_net_names.end (); ++jn) { for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { - do_join_nets (*c, nets_from_pattern (*c, *jn)); + join_nets_from_pattern (*c, *jn); } } for (auto jn = m_joined_nets.begin (); jn != m_joined_nets.end (); ++jn) { for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { - do_join_nets (*c, nets_from_pattern (*c, *jn)); + join_nets_from_pattern (*c, *jn); } } for (auto jn = m_joined_net_names_per_cell.begin (); jn != m_joined_net_names_per_cell.end (); ++jn) { for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { if (jn->first.match (c->name ())) { - do_join_nets (*c, nets_from_pattern (*c, jn->second)); + join_nets_from_pattern (*c, jn->second); } } } @@ -545,7 +552,7 @@ void LayoutToNetlist::do_join_nets () for (auto jn = m_joined_nets_per_cell.begin (); jn != m_joined_nets_per_cell.end (); ++jn) { for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { if (jn->first.match (c->name ())) { - do_join_nets (*c, nets_from_pattern (*c, jn->second)); + join_nets_from_pattern (*c, jn->second); } } } diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 443bef184..b3ce1d6d9 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -995,6 +995,8 @@ private: bool is_persisted_impl (const db::ShapeCollection &coll) const; void do_join_nets (db::Circuit &c, const std::vector &nets); void do_join_nets (); + void join_nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p); + void join_nets_from_pattern (db::Circuit &c, const std::set &p); void check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b); void error (const std::string &msg); void warn (const std::string &msg); From e56cdaeaab0adde8ac61801f0f5b006364c4d101 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 22 Sep 2023 22:59:43 +0200 Subject: [PATCH 12/41] WIP --- src/db/db/dbCircuit.cc | 28 +++++++++++++++++----------- src/db/db/dbNet.h | 18 ++++++++++++++++++ src/db/db/dbNetlistCompareUtils.cc | 4 ++-- src/db/db/dbSubCircuit.cc | 10 +++++++++- src/db/db/dbSubCircuit.h | 2 +- 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index 9941d3d51..ebf520118 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -682,30 +682,36 @@ void Circuit::connect_pin (size_t pin_id, Net *net) void Circuit::join_pins (size_t pin, size_t with) { - if (with < m_pin_by_id.size () && ! tl::is_null_iterator (m_pin_by_id [with])) { + if (with != pin && with < m_pin_by_id.size () && ! tl::is_null_iterator (m_pin_by_id [with])) { m_pins.erase (m_pin_by_id [with]); m_pin_by_id.erase (m_pin_by_id.begin () + with); m_pin_refs.erase (m_pin_refs.begin () + with); + // correct the pin IDs inside the circuit: all IDS > with will be reduced by 1 + if (pin > with) { + --pin; + } + for (auto p = m_pins.begin (); p != m_pins.end (); ++p) { + if (p->id () > with) { + p->set_id (p->id () - 1); + } + } + for (auto p = m_pin_refs.begin () + with; p != m_pin_refs.end (); ++p) { + (*p)->set_pin_id ((*p)->pin_id () - 1); + } + // join nets in calls for (auto s = begin_refs (); s != end_refs (); ++s) { db::SubCircuit &sc = *s; - db::Net *with_net = sc.net_for_pin (with); - // remove the subcircuit pin reference from the "with" net - for (auto sc_pin = with_net->begin_subcircuit_pins (); sc_pin != with_net->end_subcircuit_pins (); ++sc_pin) { - if (sc_pin->subcircuit () == &sc && sc_pin->pin_id () == with) { - with_net->erase_subcircuit_pin (sc_pin); - break; - } - } + + // NOTE: this will also correct the Pin IDs on the attached nets + sc.erase_pin (with); sc.circuit ()->join_nets (sc.net_for_pin (pin), with_net); - sc.erase_pin_ref (with); - } } diff --git a/src/db/db/dbNet.h b/src/db/db/dbNet.h index 99d3be607..d76e2b676 100644 --- a/src/db/db/dbNet.h +++ b/src/db/db/dbNet.h @@ -235,6 +235,7 @@ public: private: friend class Net; + friend class Circuit; size_t m_pin_id; Net *mp_net; @@ -246,6 +247,14 @@ private: { mp_net = net; } + + /** + * @brief Sets the pin ID + */ + void set_pin_id (size_t id) + { + m_pin_id = id; + } }; /** @@ -343,6 +352,7 @@ public: private: friend class Net; + friend class SubCircuit; size_t m_pin_id; SubCircuit *mp_subcircuit; @@ -355,6 +365,14 @@ private: { mp_net = net; } + + /** + * @brief Sets the pin ID + */ + void set_pin_id (size_t pin) + { + m_pin_id = pin; + } }; /** diff --git a/src/db/db/dbNetlistCompareUtils.cc b/src/db/db/dbNetlistCompareUtils.cc index 7320e6a58..18f4f4fb3 100644 --- a/src/db/db/dbNetlistCompareUtils.cc +++ b/src/db/db/dbNetlistCompareUtils.cc @@ -414,8 +414,8 @@ generic_categorizer::cat_for (const Obj *cls) } // explicit instantiations -template class DB_PUBLIC generic_categorizer; -template class DB_PUBLIC generic_categorizer; +template class generic_categorizer; +template class generic_categorizer; // -------------------------------------------------------------------------------------------------------------------- // DeviceCategorizer implementation diff --git a/src/db/db/dbSubCircuit.cc b/src/db/db/dbSubCircuit.cc index 4107a1475..21edd6806 100644 --- a/src/db/db/dbSubCircuit.cc +++ b/src/db/db/dbSubCircuit.cc @@ -90,9 +90,17 @@ void SubCircuit::set_trans (const db::DCplxTrans &t) m_trans = t; } -void SubCircuit::erase_pin_ref (size_t pin_id) +void SubCircuit::erase_pin (size_t pin_id) { + Net *net = net_for_pin (pin_id); + net->erase_subcircuit_pin (m_pin_refs [pin_id]); + m_pin_refs.erase (m_pin_refs.begin () + pin_id); + + // correct pin IDs for the pins with ID > pin_id + for (auto p = m_pin_refs.begin () + pin_id; p != m_pin_refs.end (); ++p) { + (*p)->set_pin_id ((*p)->pin_id () - 1); + } } void SubCircuit::set_pin_ref_for_pin (size_t pin_id, Net::subcircuit_pin_iterator iter) diff --git a/src/db/db/dbSubCircuit.h b/src/db/db/dbSubCircuit.h index 9e0877adf..618b8f230 100644 --- a/src/db/db/dbSubCircuit.h +++ b/src/db/db/dbSubCircuit.h @@ -233,7 +233,7 @@ private: /** * @brief Erases the given pin reference */ - void erase_pin_ref (size_t pin_id); + void erase_pin (size_t pin_id); /** * @brief Sets the circuit the subcircuit belongs to From 4f3522961eed4e86ff48af2d71555cb4b1c7e3aa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 22 Sep 2023 23:35:09 +0200 Subject: [PATCH 13/41] WIP --- src/db/unit_tests/dbLayoutToNetlistTests.cc | 442 ++++++++++++-------- 1 file changed, 267 insertions(+), 175 deletions(-) diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index f2c1716e6..83161873b 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -3359,30 +3359,272 @@ TEST(13_JoinNetNames) db::compare_layouts (_this, ly, au); } +namespace +{ + +class TestRig +{ +public: + TestRig (db::Layout &ly) + : m_ly (ly) + { + nwell = define_layer (m_ly, m_lmap, 1); + nwell_lbl = define_layer (m_ly, m_lmap, 1, 1); + active = define_layer (m_ly, m_lmap, 2); + pplus = define_layer (m_ly, m_lmap, 10); + nplus = define_layer (m_ly, m_lmap, 11); + poly = define_layer (m_ly, m_lmap, 3); + poly_lbl = define_layer (m_ly, m_lmap, 3, 1); + diff_cont = define_layer (m_ly, m_lmap, 4); + poly_cont = define_layer (m_ly, m_lmap, 5); + metal1 = define_layer (m_ly, m_lmap, 6); + metal1_lbl = define_layer (m_ly, m_lmap, 6, 1); + via1 = define_layer (m_ly, m_lmap, 7); + metal2 = define_layer (m_ly, m_lmap, 8); + metal2_lbl = define_layer (m_ly, m_lmap, 8, 1); + } + + db::LayoutToNetlist * + make_l2n () + { + db::Cell &tc = m_ly.cell (*m_ly.begin_top_down ()); + + std::unique_ptr l2n_p (new db::LayoutToNetlist (db::RecursiveShapeIterator (m_ly, tc, std::set ()))); + db::LayoutToNetlist &l2n = *l2n_p; + + rbulk.reset (l2n.make_layer ("bulk")); + rnwell.reset (l2n.make_layer (nwell, "nwell")); + rnwell_lbl.reset (l2n.make_layer (nwell_lbl, "nwell_lbl")); + ractive.reset (l2n.make_layer (active, "active")); + rpplus.reset (l2n.make_layer (pplus, "pplus")); + rnplus.reset (l2n.make_layer (nplus, "nplus")); + rpoly.reset (l2n.make_polygon_layer (poly, "poly")); + rpoly_lbl.reset (l2n.make_text_layer (poly_lbl, "poly_lbl")); + rdiff_cont.reset (l2n.make_polygon_layer (diff_cont, "diff_cont")); + rpoly_cont.reset (l2n.make_polygon_layer (poly_cont, "poly_cont")); + rmetal1.reset (l2n.make_polygon_layer (metal1, "metal1")); + rmetal1_lbl.reset (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + rvia1.reset (l2n.make_polygon_layer (via1, "via1")); + rmetal2.reset (l2n.make_polygon_layer (metal2, "metal2")); + rmetal2_lbl.reset (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + + // derived regions + + ractive_in_nwell = *ractive & *rnwell; + rpactive = ractive_in_nwell & *rpplus; + rntie = ractive_in_nwell & *rnplus; + rpgate = rpactive & *rpoly; + rpsd = rpactive - rpgate; + + ractive_outside_nwell = *ractive - *rnwell; + rnactive = ractive_outside_nwell & *rnplus; + rptie = ractive_outside_nwell & *rpplus; + rngate = rnactive & *rpoly; + rnsd = rnactive - rngate; + + // return the computed layers into the original layout and write it for debugging purposes + + unsigned int lgate = m_ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate + unsigned int lsd = m_ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain + unsigned int lpdiff = m_ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion + unsigned int lndiff = m_ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion + unsigned int lptie = m_ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie + unsigned int lntie = m_ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie + + rpgate.insert_into (&m_ly, tc.cell_index (), lgate); + rngate.insert_into (&m_ly, tc.cell_index (), lgate); + rpsd.insert_into (&m_ly, tc.cell_index (), lsd); + rnsd.insert_into (&m_ly, tc.cell_index (), lsd); + rpsd.insert_into (&m_ly, tc.cell_index (), lpdiff); + rnsd.insert_into (&m_ly, tc.cell_index (), lndiff); + rpsd.insert_into (&m_ly, tc.cell_index (), lptie); + rnsd.insert_into (&m_ly, tc.cell_index (), lntie); + + db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); + + // device extraction + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes + dl["W"] = rnwell.get (); + l2n.extract_devices (pmos_ex, dl); + + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes + dl["W"] = rbulk.get (); + l2n.extract_devices (nmos_ex, dl); + + // net extraction + + l2n.register_layer (rpsd, "psd"); + l2n.register_layer (rnsd, "nsd"); + l2n.register_layer (rptie, "ptie"); + l2n.register_layer (rntie, "ntie"); + + // Intra-layer + l2n.connect (rpsd); + l2n.connect (rnsd); + l2n.connect (*rnwell); + l2n.connect (*rpoly); + l2n.connect (*rdiff_cont); + l2n.connect (*rpoly_cont); + l2n.connect (*rmetal1); + l2n.connect (*rvia1); + l2n.connect (*rmetal2); + l2n.connect (rptie); + l2n.connect (rntie); + // Inter-layer + l2n.connect (rpsd, *rdiff_cont); + l2n.connect (rnsd, *rdiff_cont); + l2n.connect (rntie, *rnwell); + l2n.connect (*rpoly, *rpoly_cont); + l2n.connect (*rpoly_cont, *rmetal1); + l2n.connect (*rdiff_cont, *rmetal1); + l2n.connect (*rdiff_cont, rptie); + l2n.connect (*rdiff_cont, rntie); + l2n.connect (*rnwell, rntie); + l2n.connect (*rmetal1, *rvia1); + l2n.connect (*rvia1, *rmetal2); + l2n.connect (*rnwell, *rnwell_lbl); // attaches labels + l2n.connect (*rpoly, *rpoly_lbl); // attaches labels + l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels + l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels + // Global + l2n.connect_global (*rbulk, "BULK"); + l2n.connect_global (rptie, "BULK"); + + return l2n_p.release (); + } + + void dump_nets (db::LayoutToNetlist &l2n) + { + // debug layers produced for nets + // 201/0 -> Well + // 203/0 -> Poly + // 204/0 -> Diffusion contacts + // 205/0 -> Poly contacts + // 206/0 -> Metal1 + // 207/0 -> Via1 + // 208/0 -> Metal2 + // 210/0 -> N source/drain + // 211/0 -> P source/drain + // 212/0 -> N tie + // 213/0 -> P tie + std::map dump_map; + dump_map [&rpsd ] = m_ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [&rnsd ] = m_ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [&rptie ] = m_ly.insert_layer (db::LayerProperties (212, 0)); + dump_map [&rntie ] = m_ly.insert_layer (db::LayerProperties (213, 0)); + dump_map [rbulk.get () ] = m_ly.insert_layer (db::LayerProperties (214, 0)); + dump_map [rnwell.get () ] = m_ly.insert_layer (db::LayerProperties (201, 0)); + dump_map [rpoly.get () ] = m_ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [rdiff_cont.get ()] = m_ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [rpoly_cont.get ()] = m_ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [rmetal1.get () ] = m_ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [rvia1.get () ] = m_ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [rmetal2.get () ] = m_ly.insert_layer (db::LayerProperties (208, 0)); + + // write nets to layout + db::Cell &tc = m_ly.cell (*m_ly.begin_top_down ()); + db::CellMapping cm = l2n.cell_mapping_into (m_ly, tc); + dump_nets_to_layout (l2n, m_ly, dump_map, cm); + } + + void dump_nets_recursive (db::LayoutToNetlist &l2n) + { + // debug layers produced for nets + // 301/0 -> Well + // 303/0 -> Poly + // 304/0 -> Diffusion contacts + // 305/0 -> Poly contacts + // 306/0 -> Metal1 + // 307/0 -> Via1 + // 308/0 -> Metal2 + // 310/0 -> N source/drain + // 311/0 -> P source/drain + // 312/0 -> N tie + // 313/0 -> P tie + std::map dump_map; + dump_map [&rpsd ] = m_ly.insert_layer (db::LayerProperties (310, 0)); + dump_map [&rnsd ] = m_ly.insert_layer (db::LayerProperties (311, 0)); + dump_map [&rptie ] = m_ly.insert_layer (db::LayerProperties (312, 0)); + dump_map [&rntie ] = m_ly.insert_layer (db::LayerProperties (313, 0)); + dump_map [rbulk.get () ] = m_ly.insert_layer (db::LayerProperties (314, 0)); + dump_map [rnwell.get () ] = m_ly.insert_layer (db::LayerProperties (301, 0)); + dump_map [rpoly.get () ] = m_ly.insert_layer (db::LayerProperties (303, 0)); + dump_map [rdiff_cont.get ()] = m_ly.insert_layer (db::LayerProperties (304, 0)); + dump_map [rpoly_cont.get ()] = m_ly.insert_layer (db::LayerProperties (305, 0)); + dump_map [rmetal1.get () ] = m_ly.insert_layer (db::LayerProperties (306, 0)); + dump_map [rvia1.get () ] = m_ly.insert_layer (db::LayerProperties (307, 0)); + dump_map [rmetal2.get () ] = m_ly.insert_layer (db::LayerProperties (308, 0)); + + // write nets to layout + db::Cell &tc = m_ly.cell (*m_ly.begin_top_down ()); + db::CellMapping cm = l2n.cell_mapping_into (m_ly, tc); + dump_recursive_nets_to_layout (l2n, m_ly, dump_map, cm); + } + + const db::LayerMap &lmap () const { return m_lmap; } + +private: + db::Layout &m_ly; + db::LayerMap m_lmap; + unsigned int nwell; + unsigned int nwell_lbl; + unsigned int active; + unsigned int pplus; + unsigned int nplus; + unsigned int poly; + unsigned int poly_lbl; + unsigned int diff_cont; + unsigned int poly_cont; + unsigned int metal1; + unsigned int metal1_lbl; + unsigned int via1; + unsigned int metal2; + unsigned int metal2_lbl; + std::unique_ptr rbulk; + std::unique_ptr rnwell; + std::unique_ptr rnwell_lbl; + std::unique_ptr ractive; + std::unique_ptr rpplus; + std::unique_ptr rnplus; + std::unique_ptr rpoly; + std::unique_ptr rpoly_lbl; + std::unique_ptr rdiff_cont; + std::unique_ptr rpoly_cont; + std::unique_ptr rmetal1; + std::unique_ptr rmetal1_lbl; + std::unique_ptr rvia1; + std::unique_ptr rmetal2; + std::unique_ptr rmetal2_lbl; + db::Region ractive_in_nwell; + db::Region rpactive; + db::Region rntie; + db::Region rpgate; + db::Region rpsd; + db::Region ractive_outside_nwell; + db::Region rnactive; + db::Region rptie; + db::Region rngate; + db::Region rnsd; +}; + +} TEST(14_JoinNets) { db::Layout ly; - db::LayerMap lmap; - - unsigned int nwell = define_layer (ly, lmap, 1); - unsigned int nwell_lbl = define_layer (ly, lmap, 1, 1); - unsigned int active = define_layer (ly, lmap, 2); - unsigned int pplus = define_layer (ly, lmap, 10); - unsigned int nplus = define_layer (ly, lmap, 11); - unsigned int poly = define_layer (ly, lmap, 3); - unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); - unsigned int diff_cont = define_layer (ly, lmap, 4); - unsigned int poly_cont = define_layer (ly, lmap, 5); - unsigned int metal1 = define_layer (ly, lmap, 6); - unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); - unsigned int via1 = define_layer (ly, lmap, 7); - unsigned int metal2 = define_layer (ly, lmap, 8); - unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); + TestRig test_rig (ly); { db::LoadLayoutOptions options; - options.get_options ().layer_map = lmap; + options.get_options ().layer_map = test_rig.lmap (); options.get_options ().create_other_layers = false; std::string fn (tl::testdata ()); @@ -3394,181 +3636,31 @@ TEST(14_JoinNets) reader.read (ly, options); } - db::Cell &tc = ly.cell (*ly.begin_top_down ()); - db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); - - std::unique_ptr rbulk (l2n.make_layer ("bulk")); - std::unique_ptr rnwell (l2n.make_layer (nwell, "nwell")); - std::unique_ptr rnwell_lbl (l2n.make_layer (nwell_lbl, "nwell_lbl")); - std::unique_ptr ractive (l2n.make_layer (active, "active")); - std::unique_ptr rpplus (l2n.make_layer (pplus, "pplus")); - std::unique_ptr rnplus (l2n.make_layer (nplus, "nplus")); - std::unique_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::unique_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); - std::unique_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); - std::unique_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); - std::unique_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::unique_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); - std::unique_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); - std::unique_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::unique_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); - - // derived regions - - db::Region ractive_in_nwell = *ractive & *rnwell; - db::Region rpactive = ractive_in_nwell & *rpplus; - db::Region rntie = ractive_in_nwell & *rnplus; - db::Region rpgate = rpactive & *rpoly; - db::Region rpsd = rpactive - rpgate; - - db::Region ractive_outside_nwell = *ractive - *rnwell; - db::Region rnactive = ractive_outside_nwell & *rnplus; - db::Region rptie = ractive_outside_nwell & *rpplus; - db::Region rngate = rnactive & *rpoly; - db::Region rnsd = rnactive - rngate; - - // return the computed layers into the original layout and write it for debugging purposes - - unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate - unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain - unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion - unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion - unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie - unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie - - rpgate.insert_into (&ly, tc.cell_index (), lgate); - rngate.insert_into (&ly, tc.cell_index (), lgate); - rpsd.insert_into (&ly, tc.cell_index (), lsd); - rnsd.insert_into (&ly, tc.cell_index (), lsd); - rpsd.insert_into (&ly, tc.cell_index (), lpdiff); - rnsd.insert_into (&ly, tc.cell_index (), lndiff); - rpsd.insert_into (&ly, tc.cell_index (), lptie); - rnsd.insert_into (&ly, tc.cell_index (), lntie); - - db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); - db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); - - // device extraction - - db::NetlistDeviceExtractor::input_layers dl; - - dl["SD"] = &rpsd; - dl["G"] = &rpgate; - dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes - dl["W"] = rnwell.get (); - l2n.extract_devices (pmos_ex, dl); - - dl["SD"] = &rnsd; - dl["G"] = &rngate; - dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes - dl["W"] = rbulk.get (); - l2n.extract_devices (nmos_ex, dl); - - // net extraction - - l2n.register_layer (rpsd, "psd"); - l2n.register_layer (rnsd, "nsd"); - l2n.register_layer (rptie, "ptie"); - l2n.register_layer (rntie, "ntie"); - - // Intra-layer - l2n.connect (rpsd); - l2n.connect (rnsd); - l2n.connect (*rnwell); - l2n.connect (*rpoly); - l2n.connect (*rdiff_cont); - l2n.connect (*rpoly_cont); - l2n.connect (*rmetal1); - l2n.connect (*rvia1); - l2n.connect (*rmetal2); - l2n.connect (rptie); - l2n.connect (rntie); - // Inter-layer - l2n.connect (rpsd, *rdiff_cont); - l2n.connect (rnsd, *rdiff_cont); - l2n.connect (rntie, *rnwell); - l2n.connect (*rpoly, *rpoly_cont); - l2n.connect (*rpoly_cont, *rmetal1); - l2n.connect (*rdiff_cont, *rmetal1); - l2n.connect (*rdiff_cont, rptie); - l2n.connect (*rdiff_cont, rntie); - l2n.connect (*rnwell, rntie); - l2n.connect (*rmetal1, *rvia1); - l2n.connect (*rvia1, *rmetal2); - l2n.connect (*rnwell, *rnwell_lbl); // attaches labels - l2n.connect (*rpoly, *rpoly_lbl); // attaches labels - l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels - l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels - // Global - l2n.connect_global (*rbulk, "BULK"); - l2n.connect_global (rptie, "BULK"); + std::unique_ptr l2n (test_rig.make_l2n ()); // Extract while joining VSS with BULK and VDD with NWELL std::set jn; jn.insert ("VDD"); jn.insert ("NWELL"); - l2n.join_nets (tl::GlobPattern ("INV2"), jn); + l2n->join_nets (tl::GlobPattern ("INV2"), jn); jn.clear (); jn.insert ("VSS"); jn.insert ("BULK"); - l2n.join_nets (tl::GlobPattern ("INV2"), jn); + l2n->join_nets (tl::GlobPattern ("INV2"), jn); // This will trigger an implicit connection on top level (side effect of explicit connections) jn.clear (); jn.insert ("VDD"); - l2n.join_nets (jn); + l2n->join_nets (jn); - l2n.extract_netlist (); + l2n->extract_netlist (); - // debug layers produced for nets - // 201/0 -> Well - // 203/0 -> Poly - // 204/0 -> Diffusion contacts - // 205/0 -> Poly contacts - // 206/0 -> Metal1 - // 207/0 -> Via1 - // 208/0 -> Metal2 - // 210/0 -> N source/drain - // 211/0 -> P source/drain - // 212/0 -> N tie - // 213/0 -> P tie - std::map dump_map; - dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0)); - dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0)); - dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0)); - dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0)); - dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0)); - dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0)); - dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0)); - dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0)); - dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0)); - dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0)); - dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0)); - dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0)); - - // write nets to layout - db::CellMapping cm = l2n.cell_mapping_into (ly, tc); - dump_nets_to_layout (l2n, ly, dump_map, cm); - - dump_map.clear (); - dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0)); - dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0)); - dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0)); - dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0)); - dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0)); - dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0)); - dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0)); - dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0)); - dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0)); - dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0)); - dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0)); - dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0)); - - dump_recursive_nets_to_layout (l2n, ly, dump_map, cm); + test_rig.dump_nets (*l2n); + test_rig.dump_nets_recursive (*l2n); // compare netlist as string CHECKPOINT (); - db::compare_netlist (_this, *l2n.netlist (), + db::compare_netlist (_this, *l2n->netlist (), "circuit RINGO ();\n" " subcircuit INV2 $1 ('NWELL,VDD'=VDD,IN=$I15,$3=FB,OUT=OSC,VSS=VSS);\n" " subcircuit INV2 $2 ('NWELL,VDD'=VDD,IN=FB,$3=$I26,OUT=$I25,VSS=VSS);\n" From b72dfe34b4ad30370b20ebcc83f33d50cd777cf7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Sep 2023 00:35:11 +0200 Subject: [PATCH 14/41] WIP: aligned new implementation better with original one --- src/db/db/dbCircuit.cc | 30 ++++++++++++++++++++ src/db/db/dbLayoutToNetlist.cc | 18 ++++-------- src/db/unit_tests/dbLayoutToNetlistTests.cc | 2 +- testdata/algo/device_extract_l14.gds | Bin 3158 -> 3158 bytes 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index ebf520118..07d8cb338 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -30,6 +30,30 @@ namespace db { +/** + * @brief Creates a joined name for nets and pins + */ +static std::string +join_names (const std::string &n1, const std::string &n2) +{ + // create a new name for the joined net + if (n2.empty ()) { + return n1; + } else if (n1.empty ()) { + return n2; + } else if (n1 == n2) { + return n1; + } else { + // separate parts (if already joined) and mix + auto p1 = tl::split (n1, ","); + auto p2 = tl::split (n2, ","); + std::set ps; + ps.insert (p1.begin (), p1.end ()); + ps.insert (p2.begin (), p2.end ()); + return tl::join (ps.begin (), ps.end (), ","); + } +} + // -------------------------------------------------------------------------------- // Circuit class implementation @@ -391,6 +415,9 @@ void Circuit::join_nets (Net *net, Net *with) netlist ()->callbacks ()->link_nets (net, with); } + // create a new name for the joined net + net->set_name (join_names (net->name (), with->name ())); + remove_net (with); } @@ -684,6 +711,9 @@ void Circuit::join_pins (size_t pin, size_t with) { if (with != pin && with < m_pin_by_id.size () && ! tl::is_null_iterator (m_pin_by_id [with])) { + // create a new joined name + m_pin_by_id [pin]->set_name (join_names (m_pin_by_id [pin]->name (), m_pin_by_id [with]->name ())); + m_pins.erase (m_pin_by_id [with]); m_pin_by_id.erase (m_pin_by_id.begin () + with); m_pin_refs.erase (m_pin_refs.begin () + with); diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 48eba3c61..53a88e01f 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -445,15 +445,14 @@ void LayoutToNetlist::join_nets_from_pattern (db::Circuit &c, const tl::GlobPatt void LayoutToNetlist::join_nets_from_pattern (db::Circuit &c, const std::set &p) { + // NOTE: this version implies implicit joining of different nets with the same name from the set p std::vector nets; - for (auto n = p.begin (); n != p.end (); ++n) { - if (! n->empty ()) { - db::Net *net = c.net_by_name (*n); - if (net) { - nets.push_back (net); - } + for (auto n = c.begin_nets (); n != c.end_nets (); ++n) { + if (! n->name ().empty () && p.find (n->name ()) != p.end ()) { + nets.push_back (n.operator-> ()); } } + if (nets.size () > 1) { do_join_nets (c, nets); } @@ -465,13 +464,6 @@ void LayoutToNetlist::do_join_nets (db::Circuit &c, const std::vector return; } - std::set names; - for (auto n = nets.begin (); n != nets.end (); ++n) { - names.insert ((*n)->name ()); - } - - nets [0]->set_name (tl::join (names.begin (), names.end (), ",")); - for (auto n = nets.begin () + 1; n != nets.end (); ++n) { check_must_connect (c, *nets [0], **n); c.join_nets (nets [0], *n); diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 83161873b..d7524ad70 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -3648,7 +3648,7 @@ TEST(14_JoinNets) jn.insert ("BULK"); l2n->join_nets (tl::GlobPattern ("INV2"), jn); - // This will trigger an implicit connection on top level (side effect of explicit connections) + // Implicit connection of nets with same name "VDD" jn.clear (); jn.insert ("VDD"); l2n->join_nets (jn); diff --git a/testdata/algo/device_extract_l14.gds b/testdata/algo/device_extract_l14.gds index 740a561b4a75ddda9b93bef45e0b86754f84dfd4..ecb5ef30638c87d91aa19fcffcd8bba62b75bcea 100644 GIT binary patch delta 157 zcmca6aZMtMfsKKQDS|{L4=vr&au{L4=vr&au From 939870c84c598d109ee69d0d4aa8489155da75aa Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Sep 2023 00:39:26 +0200 Subject: [PATCH 15/41] Fixed unit test --- .../algo/device_extract_au14_circuits.gds | Bin 48570 -> 48594 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/testdata/algo/device_extract_au14_circuits.gds b/testdata/algo/device_extract_au14_circuits.gds index 7cf932fc888b37e5cb428c4c8a31894415616f6a..11fecc3064237bac33ca3d1ae5e703f6df18c399 100644 GIT binary patch delta 1623 zcmdn>o9WVTrYHtB1}3Hm1{p>s_U8{WCk6%)W>!1LPIK>L z%RgAU?9g8@J1T@hh83s2iBXZ_IELxC!$-5YD>f+GGAjZb#=Nc04=@(`c?-c6e ztrHd;%&>VE6DK1s<2K)7#v}QQ1O7|%ni(&oofy-Pqvrf-7L`YnR)Vl5Tp4s%Vchln!eABll7&5B0a@S zlP#A68Iyq`AjX6VK#|Jj+>`yLy_;OLTxc`jR6RyHb_RU0viT18X%<|r+q_TUEN;m~ zqIe|Rr0_^)$>WjqQ^6x?q=X#6XVS!=rP$WXmN@J^`>AuWNb;X!wjrPz=;$+=3qT6?xg6k*!<9&6u(%4?RXQg znMDs*yhxzL3oN5f4ipsMJTDTM^y|fVH{S~dCVjzprp*&$8ki>c+w*RgO9Li-e+M8V z5t{Vp@>Sz@~7FwII~2}oNi{El5z`Xv*VJSd|^4x0&ud!irKjIZT_@E5_jRE zv`U>(L`(>?9Gv`chw$dC)$h4*np?2#HKUk>5OSV@$IZhXYD^}UKr?`p1%xt(P-YOy g6hfImC}Rj^wE5yrO~%P}JA@`@?GV}gYu5oL09AQsp#T5? delta 1610 zcmb7^Ur5tY6vywqzwNjD^J{KxnzTlLq}f_iH*gLuGRhc}E!3=jFN1>UC5pt5KpX8L z)8U*4i<*$ogVK8Hkm-D>mmUmzh+YOhNPi$G*kq5Ubhkk3;jZ@fz2|#A_nhDFaL4J{s$@BEx+mld^twX5-QD<_l~K_}xGIUw7uvKCgsd#=4p(&{ zA&9+Y{Y==-$D{8wLUYcwEH)o|ikL%fMa)a>Ma+(lBBtHHtg(y6V3Oso{2aP`fiuBS zozK;b`_C?wkne$bTMatSVF^r2f!U{)!gvdeDO3XEZp5|AC47s!sZitR)lzD>3QYDI zY7YPJKX$`-+iv`Fvj}4RYb^YIfU~6ya5Be6Ia<2efYNuKk-L1B2(1eVDkRvjs}0^n0c zJ(lZv0}W0E%PVsXHjD}`nR%ojj68C^QNfYDypv2`)aE1{tP3*;x%lZoj^ai=KOM6f zaHlOpanRwVaLZwWkt6@Aj#nOjmf%jS7RC}cAdqN<4A+~9KH)PQo*I>erhPi06Pd6w zBV2aSIhzo1xH(%Z-Y3pyHVR6zQsT3mSggfJ@>{v^rn__BDP&Ry!8&iq18^c~hDY;N x%6OUNBJamTK8jo-Ng!SD0SdMd5v!4*V4g9$I|PegU*eat#0g From b09d63e780236b8ef9641e4bd80150195cda9389 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Sep 2023 00:57:57 +0200 Subject: [PATCH 16/41] Doc update, test updates --- src/db/db/gsiDeclDbNetlist.cc | 3 ++- src/db/unit_tests/dbLayoutToNetlistTests.cc | 10 +++++----- .../algo/device_extract_au1_joined_nets.gds | Bin 11098 -> 11114 bytes 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index af209c40e..29f2e7396 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -1659,7 +1659,8 @@ Class decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit", "@brief Joins (connects) two nets into one\n" "This method will connect the 'with' net with 'net' and remove 'with'.\n" "\n" - "This method has been introduced in version 0.26.4." + "This method has been introduced in version 0.26.4. Starting with version 0.28.13, " + "net names will be formed from both input names, combining them with as a comma-separated list." ) + gsi::iterator ("each_net", (db::Circuit::net_iterator (db::Circuit::*) ()) &db::Circuit::begin_nets, (db::Circuit::net_iterator (db::Circuit::*) ()) &db::Circuit::end_nets, "@brief Iterates over the nets of the circuit" diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index d7524ad70..b36e38a07 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -608,12 +608,12 @@ TEST(1_BasicExtraction) // do some probing after purging // top level - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (0.0, 1.8))), "RINGO:FB"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::Point (0, 1800))), "RINGO:FB"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (0.0, 1.8))), "RINGO:FB,OSC"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::Point (0, 1800))), "RINGO:FB,OSC"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal2, db::DPoint (-2.0, 1.8))), "(null)"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:FB"); - EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:VSS"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (-1.5, 1.8))), "RINGO:FB,OSC"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (24.5, 1.8))), "RINGO:FB,OSC"); + EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (5.3, 0.0))), "RINGO:VDD,VSS"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (2.6, 1.0))), "RINGO:$I39"); EXPECT_EQ (qnet_name (l2n.probe_net (*rmetal1, db::DPoint (6.4, 1.0))), "RINGO:$I2"); diff --git a/testdata/algo/device_extract_au1_joined_nets.gds b/testdata/algo/device_extract_au1_joined_nets.gds index ceda8361f0d0f8d30c9c51e1b66eab86503269a6..919bc22a386387a2fb17bf0edbf8b1c537131af6 100644 GIT binary patch delta 1537 zcmcZ=_9`rjfsKKQDS|{L4=vr&aukKIiPP`r@W{!@TZc#PpMs?tt|ThJ#^&c55+CN` zq7xPzJo%%d?B+7Xr%bB2)bl~qyE*Cj2Rm=BQTfS;E9f@&s0reh+@h|^sLLk=wj5#@ e1CIbRuqcNB7C~T={L4=vr&aukKIiPP`r@W{!@TZc#PpMs?lt|SUfcz&)S@nONi zlO2_0H&-b>Wm3eY7MPkqYTcYBcgaa@o~Lr35m&Hno}wm*TXK)ODkCSC5X`U(>Z0sC L5Z-1!%@`&CK-}pl From c81388d830cf3994196398abeea26c168ba9e128 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Sep 2023 17:33:44 +0200 Subject: [PATCH 17/41] Updated tests --- src/db/db/dbLayoutToNetlist.cc | 7 +- src/drc/drc/built-in-macros/_drc_netter.rb | 79 +- src/lvs/unit_tests/lvsTests.cc | 2 +- testdata/lvs/bbdevices3b.lvsdb | 3 + testdata/lvs/bbdevices4b.lvsdb | 3 + testdata/lvs/double_height2.lvsdb | 1 + testdata/lvs/double_height2_texts.lvsdb | 1 + testdata/lvs/ringo_simple_dmos.lvsdb.1 | 3 + testdata/lvs/ringo_simple_dmos.lvsdb.2 | 886 ----------------- .../ringo_simple_implicit_connections.lvsdb.1 | 64 +- .../ringo_simple_implicit_connections.lvsdb.2 | 927 ------------------ 11 files changed, 93 insertions(+), 1883 deletions(-) delete mode 100644 testdata/lvs/ringo_simple_dmos.lvsdb.2 delete mode 100644 testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 53a88e01f..d9b4aa299 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -485,6 +485,7 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a return; } + // @@@ raise a warning for top level cells? if (c.begin_refs () != c.end_refs ()) { if (a.begin_pins () == a.end_pins ()) { error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); @@ -506,7 +507,11 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected at all %s")), b.expanded_name (), c.name (), subcircuit_to_string (sc))); } if (net_a && net_b && net_a != net_b) { - error (tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s from circuit %s are not connected %s")), a.expanded_name (), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + if (net_a->expanded_name () == net_b->expanded_name ()) { + error (tl::sprintf (tl::to_string (tr ("Must-connect nets %s from circuit %s are not connected %s")), a.expanded_name (), c.name (), subcircuit_to_string (sc))); + } else { + error (tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s from circuit %s are not connected %s")), a.expanded_name (), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + } } } } diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index d56466183..f7ea6f2ec 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -249,26 +249,31 @@ module DRC # %DRC% # @name connect_implicit - # @brief Specifies a search pattern for labels which create implicit net connections + # @brief Specifies a search pattern for implicit net connections ("must connect" nets) # @synopsis connect_implicit(label_pattern) # @synopsis connect_implicit(cell_pattern, label_pattern) - # Use this method to supply label strings which create implicit net connections - # on the top level circuit in the first version. This feature is useful to connect identically labelled nets - # while a component isn't integrated yet. If the component is integrated, nets may be connected - # on a higher hierarchy level - e.g. by a power mesh. Inside the component this net consists - # of individual islands. To properly perform netlist extraction and comparison, these islands - # need to be connected even though there isn't a physical connection. "connect_implicit" can - # achive this if these islands are labelled with the same text on the top level of the - # component. + # This method specifies a net name search pattern, either for all cells or for + # certain cells, given by a name search pattern. Search pattern follow the usual glob + # form (e.g. "A*" for all cells or nets with names starting with "A"). + # + # Then, for nets matching the net name pattern and for which there is more than + # one subnet, the subnets are connected. "Subnets" are physically disconnected parts + # of a net which carry the same name. # - # In the second version, the pattern can be specified for a cell range (given by a cell name pattern or a - # single cell name). These pattern are applied to non-top cells. The unspecific pattern - # has priority over the cell-specific ones. As the cell selector is a pattern itself, a - # single cell may fall into more than one category. In this case, the label filters are - # combined. + # This feature is useful for example for power nets which are complete in a cell, + # but are supposed to be connected upwards in the hierarchy ("must connect" nets). + # Physically there are multiple nets, logically - and specifically in the schematic for + # the purpose of LVS - there is only one net. + # "connect_implicit" now creates a virtual, combined physical net that matches the logical net. + # + # This is general bears the risk of missing a physical connection. The "connect_implicit" + # feature therefore checks whether the connection is made physically on the next hierarchy + # level, except for top-level cells for which it is assumed that this connection is made + # later. A warning is raised instead for top level cells. # # The implicit connections are applied on the next net extraction and cleared - # on "clear_connections". + # on "clear_connections". Another feature is \connect_explicit which allows connecting + # differently named subnets in a similar fashion. def connect_implicit(arg1, arg2 = nil) @@ -290,27 +295,24 @@ module DRC # %DRC% # @name connect_explicit - # @brief Specifies a list of net names for nets to connect explicitly + # @brief Specifies a list of net names for nets to connect ("must connect" nets) # @synopsis connect_explicit(net_names) # @synopsis connect_explicit(cell_pattern, net_names) # Use this method to explicitly connect nets even if there is no physical connection. - # As this breaks with the concept of physical verification, this feature should be used - # with care. + # The concept is similar to implicit connection (see \connect_implicit). The method gets + # a list of nets which are connected virtually, even if there is no physical connection. + # The first version applies this scheme to all cells, the second version to cells matching + # the cell name pattern. The cell name pattern follows the usual glob style form (e.g. "A*" + # applies the connection in all cells whose name starts with "A"). # - # The first version of this function will connect all nets listed in the "net_names" array - # in the top level cell. The second version takes a cell name pattern and connects all nets listed - # in "net_names" for cells matching this pattern. - # - # A use case for this method is the following: consider a set of standard cells. These do not have a bulk - # or n-well pin in the schematics. They also do not have build in tie-down diodes for the - # substrate connections. In this case there is a build-in discrepancy between the - # schematics and the layout: bulk and VSS are separate nets within the layout, but the - # schematic does not list them as separate. The solution is to make an explicit connection - # between VDD and n-well and VSS and bulk, provided VDD and VSS are properly labelled as "VDD" and "VSS" - # and n-well and bulk are accessible as named nets (for bulk you can use "connect_global"). - # - # The following code will establish an explicit connection for all cells called "INV.." between - # BULK and VSS nets: + # This method is useful to establish a logical connection which is made later up on the + # next level of hierarchy. For example, a standard cell my not contain substrate or well + # taps as these may be made by tap or spare cells. Logically however, the cell only has + # one power or ground pin for the devices and substrate or well. In order to match both + # representations - for example for the purpose of LVS - the dual power or ground pins have + # to be connected. Assuming that there is a global net "BULK" for the substrate and a + # net "VSS" for the sources of the NMOS devices, the following statement will create this + # connection for all cell names beginning with "INV": # # @code # connect_global(bulk, "BULK") @@ -318,14 +320,19 @@ module DRC # connect_explicit("INV*", [ "BULK", "VSS" ]) # @/code # + # The resulting net and pin will carry a name made from the combination of the connected + # nets. In this case it will be "BULK,VSS". + # + # The virtual connection in general bears the risk of missing a physical connection. + # The "connect_explicit" feature therefore checks whether the connection is made physically + # on the next hierarchy level ("must connect" nets), except for top-level cells for which + # it is assumed that this connection is made later. + # A warning is raised instead for top level cells. + # # Explicit connections also imply implicit connections between different parts of # one of the nets. In the example before, "VSS" pieces without a physical connection # will also be connected. # - # When you use explicit connections you should make sure by other ways that the connection - # is made physically. For example, for the bulk/n-well pin example above, by enforcing at least one - # tie-down diode per n-well island and in the substrate by means of a DRC rule. - # # The explicit connections are applied on the next net extraction and cleared # on "clear_connections". diff --git a/src/lvs/unit_tests/lvsTests.cc b/src/lvs/unit_tests/lvsTests.cc index 18c0810bf..53584222b 100644 --- a/src/lvs/unit_tests/lvsTests.cc +++ b/src/lvs/unit_tests/lvsTests.cc @@ -165,7 +165,7 @@ TEST(20_private) TEST(21_private) { - run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_2.lvsdb"); + run_test (_this, "test_21.lylvs", "test_21.cir.gz", "test_21.gds.gz", true, "test_21_3.lvsdb"); } // issue #1021 diff --git a/testdata/lvs/bbdevices3b.lvsdb b/testdata/lvs/bbdevices3b.lvsdb index 95ff6ee8b..d4573f7a4 100644 --- a/testdata/lvs/bbdevices3b.lvsdb +++ b/testdata/lvs/bbdevices3b.lvsdb @@ -280,6 +280,9 @@ reference( # Cross reference xref( + log( + entry(error description('Circuits testall and TESTALL could not be compared because the following subcircuits failed to compare:\n B: BWBTEST')) + ) circuit(BBGATEST BBGATEST match xref( pin(() 1 match) diff --git a/testdata/lvs/bbdevices4b.lvsdb b/testdata/lvs/bbdevices4b.lvsdb index b91a05e0c..90993b7b2 100644 --- a/testdata/lvs/bbdevices4b.lvsdb +++ b/testdata/lvs/bbdevices4b.lvsdb @@ -275,6 +275,9 @@ reference( # Cross reference xref( + log( + entry(error description('Circuits testall and TESTALL could not be compared because the following subcircuits failed to compare:\n B: BWBTEST')) + ) circuit(BBGATEST BBGATEST match xref( pin(() 1 match) diff --git a/testdata/lvs/double_height2.lvsdb b/testdata/lvs/double_height2.lvsdb index e794e299c..8bad8efaa 100644 --- a/testdata/lvs/double_height2.lvsdb +++ b/testdata/lvs/double_height2.lvsdb @@ -27,6 +27,7 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) + H(E B('Must-connect nets R from circuit INV2 are not connected in INVCHAIN')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/double_height2_texts.lvsdb b/testdata/lvs/double_height2_texts.lvsdb index 2c986d071..ec8dc1494 100644 --- a/testdata/lvs/double_height2_texts.lvsdb +++ b/testdata/lvs/double_height2_texts.lvsdb @@ -27,6 +27,7 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) + H(E B('Must-connect nets R from circuit INV2 are not connected in INVCHAIN')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.1 b/testdata/lvs/ringo_simple_dmos.lvsdb.1 index 59c0c5194..155a4128c 100644 --- a/testdata/lvs/ringo_simple_dmos.lvsdb.1 +++ b/testdata/lvs/ringo_simple_dmos.lvsdb.1 @@ -832,6 +832,9 @@ reference( # Cross reference xref( + log( + entry(error description('Circuits RINGO and RINGO could not be compared because the following subcircuits failed to compare:\n A: ND2X1\n B: ND2X1')) + ) circuit(INVX1 INVX1 match xref( net(4 4 match) diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.2 b/testdata/lvs/ringo_simple_dmos.lvsdb.2 deleted file mode 100644 index 94072e582..000000000 --- a/testdata/lvs/ringo_simple_dmos.lvsdb.2 +++ /dev/null @@ -1,886 +0,0 @@ -#%lvsdb-klayout - -# Layout -layout( - top(RINGO) - unit(0.001) - - # Layer section - # This section lists the mask layers (drawing or derived) and their connections. - - # Mask layers - layer(l4 '1/0') - layer(l5 '5/0') - layer(l10 '8/0') - layer(l13 '9/0') - layer(l14 '10/0') - layer(l15 '11/0') - layer(l9) - layer(l3) - layer(l1) - layer(l11) - layer(l8) - layer(l6) - layer(l12) - - # Mask layer connectivity - connect(l4 l4 l11) - connect(l5 l5 l10) - connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12) - connect(l13 l10 l13 l14) - connect(l14 l13 l14 l15) - connect(l15 l14 l15) - connect(l9 l9) - connect(l3 l10 l3) - connect(l1 l10 l1) - connect(l11 l4 l10 l11) - connect(l8 l10 l8) - connect(l6 l10 l6) - connect(l12 l10 l12) - - # Global nets and connectivity - global(l9 SUBSTRATE) - global(l12 SUBSTRATE) - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Device abstracts section - # Device abstracts list the pin shapes of the devices. - device(D$PMOS PMOS - terminal(S - rect(l3 (125 -750) (450 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (-550 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$1 PMOS - terminal(S - rect(l3 (-575 -750) (450 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (125 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$2 PMOS - terminal(S - rect(l3 (-550 -750) (425 1500)) - ) - terminal(G - rect(l5 (-125 -750) (250 1500)) - ) - terminal(D - rect(l1 (125 -750) (425 1500)) - ) - terminal(B - rect(l4 (-125 -750) (250 1500)) - ) - ) - device(D$NMOS NMOS - terminal(S - rect(l8 (125 -475) (450 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (-550 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$1 NMOS - terminal(S - rect(l8 (-575 -475) (450 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$2 NMOS - terminal(S - rect(l8 (-550 -475) (425 950)) - ) - terminal(G - rect(l5 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l9 (-125 -475) (250 950)) - ) - ) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Circuit boundary - rect((-100 400) (2600 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l10 (1110 5160) (180 180)) - rect(l10 (-180 920) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l13 (-240 -790) (300 1700)) - rect(l13 (-1350 0) (2400 800)) - rect(l13 (-1150 -400) (0 0)) - rect(l3 (-250 -2150) (425 1500)) - rect(l3 (-450 -1500) (425 1500)) - ) - net(2 name(OUT) - rect(l10 (1810 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-1580 3760) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (1220 920) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) - rect(l13 (-110 1390) (300 1400)) - polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) - rect(l13 (-140 -500) (0 0)) - rect(l13 (-1750 1100) (300 1400)) - rect(l13 (1100 -1700) (300 300)) - rect(l13 (-300 0) (300 1400)) - rect(l1 (-1750 -1450) (425 1500)) - rect(l1 (950 -1500) (425 1500)) - rect(l6 (-425 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l10 (410 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -1300) (300 1360)) - rect(l13 (-650 -2160) (2400 800)) - rect(l13 (-1150 -400) (0 0)) - rect(l6 (-950 860) (425 950)) - ) - net(4 - rect(l8 (1000 1660) (425 950)) - rect(l8 (-450 -950) (425 950)) - ) - net(5 - rect(l4 (-100 4500) (2600 3500)) - ) - net(6 name(B) - rect(l5 (1425 2860) (250 1940)) - rect(l5 (-345 -950) (300 300)) - rect(l5 (-205 650) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-285 1050) (180 180)) - rect(l13 (-70 -90) (0 0)) - rect(l13 (-170 -150) (300 300)) - ) - net(7 name(A) - rect(l5 (725 2860) (250 1940)) - rect(l5 (-325 -1850) (300 300)) - rect(l5 (-225 1550) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-265 150) (180 180)) - rect(l13 (-90 -90) (0 0)) - rect(l13 (-150 -150) (300 300)) - ) - net(8 name(SUBSTRATE)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(5) - pin(6 name(B)) - pin(7 name(A)) - pin(8 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.3375) - param(AD 0.6375) - param(PS 1.95) - param(PD 3.85) - terminal(S 1) - terminal(G 7) - terminal(D 2) - terminal(B 5) - ) - device(2 D$PMOS$1 - location(1550 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.3375) - param(AD 0.6375) - param(PS 1.95) - param(PD 3.85) - terminal(S 1) - terminal(G 6) - terminal(D 2) - terminal(B 5) - ) - device(3 D$NMOS - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.21375) - param(AD 0.40375) - param(PS 1.4) - param(PD 2.75) - terminal(S 4) - terminal(G 7) - terminal(D 3) - terminal(B 8) - ) - device(4 D$NMOS$1 - location(1550 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.21375) - param(AD 0.40375) - param(PS 1.4) - param(PD 2.75) - terminal(S 4) - terminal(G 6) - terminal(D 2) - terminal(B 8) - ) - - ) - circuit(INVX1 - - # Circuit boundary - rect((-100 400) (2000 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l10 (410 6260) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l13 (-240 -240) (300 1400)) - rect(l13 (-650 300) (1800 800)) - rect(l13 (-1450 -1100) (300 300)) - rect(l13 (300 400) (0 0)) - rect(l3 (-650 -2150) (425 1500)) - ) - net(2 name(OUT) - rect(l10 (1110 5160) (180 180)) - rect(l10 (-180 920) (180 180)) - rect(l10 (-180 -730) (180 180)) - rect(l10 (-180 -4120) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -790) (300 4790)) - rect(l13 (-150 -2500) (0 0)) - rect(l1 (-225 1050) (425 1500)) - rect(l6 (-425 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l10 (410 1770) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-240 -1300) (300 1360)) - rect(l13 (-650 -2160) (1800 800)) - rect(l13 (-850 -400) (0 0)) - rect(l8 (-650 860) (425 950)) - ) - net(4 - rect(l4 (-100 4500) (2000 3500)) - ) - net(5 name(IN) - rect(l5 (725 2860) (250 1940)) - rect(l5 (-525 -1850) (300 300)) - rect(l5 (-25 1550) (250 2000)) - rect(l5 (-250 -2000) (250 2000)) - rect(l5 (-250 -5390) (250 1450)) - rect(l10 (-465 150) (180 180)) - rect(l13 (-90 -90) (0 0)) - rect(l13 (-150 -150) (300 300)) - ) - net(6 name(SUBSTRATE)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4) - pin(5 name(IN)) - pin(6 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS$2 - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.6375) - param(AD 0.6375) - param(PS 3.85) - param(PD 3.85) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 D$NMOS$2 - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.40375) - param(AD 0.40375) - param(PS 2.75) - param(PD 2.75) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Circuit boundary - rect((0 350) (25800 7650)) - - # Nets with their geometries - net(1 - rect(l13 (4040 2950) (610 300)) - ) - net(2 - rect(l13 (5550 2950) (900 300)) - ) - net(3 - rect(l13 (7350 2950) (900 300)) - ) - net(4 - rect(l13 (9150 2950) (900 300)) - ) - net(5 - rect(l13 (10950 2950) (900 300)) - ) - net(6 - rect(l13 (12750 2950) (900 300)) - ) - net(7 - rect(l13 (14550 2950) (900 300)) - ) - net(8 - rect(l13 (16350 2950) (900 300)) - ) - net(9 - rect(l13 (18150 2950) (900 300)) - ) - net(10 - rect(l13 (19950 2950) (900 300)) - ) - net(11 name(FB) - rect(l13 (21750 2950) (900 300)) - rect(l13 (-19530 590) (320 320)) - rect(l13 (17820 -320) (320 320)) - rect(l14 (-18400 -260) (200 200)) - rect(l14 (17940 -200) (200 200)) - rect(l15 (-18040 -300) (17740 400)) - rect(l15 (-17920 -200) (0 0)) - rect(l15 (-220 -200) (400 400)) - rect(l15 (17740 -400) (400 400)) - ) - net(12 name(VDD) - rect(l4 (500 4500) (1400 3500)) - rect(l4 (-1900 -3500) (600 3500)) - rect(l4 (23300 -3500) (1400 3500)) - rect(l4 (-100 -3500) (600 3500)) - rect(l10 (-24690 -1240) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (23220 370) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l13 (-21740 860) (0 0)) - rect(l13 (-2350 -450) (1200 800)) - rect(l13 (-750 -1450) (300 1400)) - rect(l13 (-100 -350) (0 0)) - rect(l13 (-1250 -400) (600 800)) - rect(l13 (23400 -800) (1200 800)) - rect(l13 (-750 -1450) (300 1400)) - rect(l13 (-100 -350) (0 0)) - rect(l13 (550 -400) (600 800)) - rect(l11 (-24850 -1500) (500 1500)) - rect(l11 (22900 -1500) (500 1500)) - ) - net(13 name(OUT) - rect(l13 (23440 3840) (320 320)) - rect(l14 (-260 -260) (200 200)) - rect(l15 (-100 -100) (0 0)) - rect(l15 (-200 -200) (400 400)) - ) - net(14 name(ENABLE) - rect(l13 (2440 2940) (320 320)) - rect(l14 (-260 -260) (200 200)) - rect(l15 (-100 -100) (0 0)) - rect(l15 (-200 -200) (400 400)) - ) - net(15 name(VSS) - rect(l10 (1110 1610) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l10 (23220 370) (180 180)) - rect(l10 (-180 -1280) (180 180)) - rect(l10 (-180 370) (180 180)) - rect(l13 (-21740 -390) (0 0)) - rect(l13 (-1900 -400) (300 1400)) - rect(l13 (-750 -1450) (1200 800)) - rect(l13 (-550 -400) (0 0)) - rect(l13 (-1250 -400) (600 800)) - rect(l13 (23850 -750) (300 1400)) - rect(l13 (-750 -1450) (1200 800)) - rect(l13 (-550 -400) (0 0)) - rect(l13 (550 -400) (600 800)) - rect(l12 (-24850 -800) (500 1500)) - rect(l12 (22900 -1500) (500 1500)) - ) - - # Outgoing pins and their connections to nets - pin(11 name(FB)) - pin(12 name(VDD)) - pin(13 name(OUT)) - pin(14 name(ENABLE)) - pin(15 name(VSS)) - - # Subcircuits and their connections - circuit(1 ND2X1 location(1800 0) - pin(0 12) - pin(1 1) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 14) - pin(6 15) - ) - circuit(2 INVX1 location(4200 0) - pin(0 12) - pin(1 2) - pin(2 15) - pin(3 12) - pin(4 1) - pin(5 15) - ) - circuit(3 INVX1 location(6000 0) - pin(0 12) - pin(1 3) - pin(2 15) - pin(3 12) - pin(4 2) - pin(5 15) - ) - circuit(4 INVX1 location(7800 0) - pin(0 12) - pin(1 4) - pin(2 15) - pin(3 12) - pin(4 3) - pin(5 15) - ) - circuit(5 INVX1 location(9600 0) - pin(0 12) - pin(1 5) - pin(2 15) - pin(3 12) - pin(4 4) - pin(5 15) - ) - circuit(6 INVX1 location(11400 0) - pin(0 12) - pin(1 6) - pin(2 15) - pin(3 12) - pin(4 5) - pin(5 15) - ) - circuit(7 INVX1 location(13200 0) - pin(0 12) - pin(1 7) - pin(2 15) - pin(3 12) - pin(4 6) - pin(5 15) - ) - circuit(8 INVX1 location(15000 0) - pin(0 12) - pin(1 8) - pin(2 15) - pin(3 12) - pin(4 7) - pin(5 15) - ) - circuit(9 INVX1 location(16800 0) - pin(0 12) - pin(1 9) - pin(2 15) - pin(3 12) - pin(4 8) - pin(5 15) - ) - circuit(10 INVX1 location(18600 0) - pin(0 12) - pin(1 10) - pin(2 15) - pin(3 12) - pin(4 9) - pin(5 15) - ) - circuit(11 INVX1 location(20400 0) - pin(0 12) - pin(1 11) - pin(2 15) - pin(3 12) - pin(4 10) - pin(5 15) - ) - circuit(12 INVX1 location(22200 0) - pin(0 12) - pin(1 13) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 15) - ) - - ) -) - -# Reference netlist -reference( - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(B)) - net(6 name(A)) - net(7 name(BULK)) - net(8 name('1')) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(B)) - pin(6 name(A)) - pin(7 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 6) - terminal(D 2) - terminal(B 4) - ) - device(2 PMOS - name($2) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(3 NMOS - name($3) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 6) - terminal(D 8) - terminal(B 7) - ) - device(4 NMOS - name($4) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 8) - terminal(G 5) - terminal(D 2) - terminal(B 7) - ) - - ) - circuit(INVX1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(IN)) - net(6 name(BULK)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(IN)) - pin(6 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 NMOS - name($2) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Nets - net(1 name(VSS)) - net(2 name(VDD)) - net(3 name(FB)) - net(4 name(ENABLE)) - net(5 name(OUT)) - net(6 name('1')) - net(7 name('2')) - net(8 name('3')) - net(9 name('4')) - net(10 name('5')) - net(11 name('6')) - net(12 name('7')) - net(13 name('8')) - net(14 name('9')) - net(15 name('10')) - - # Outgoing pins and their connections to nets - pin(1 name(VSS)) - pin(2 name(VDD)) - pin(3 name(FB)) - pin(4 name(ENABLE)) - pin(5 name(OUT)) - - # Subcircuits and their connections - circuit(1 ND2X1 name($1) - pin(0 2) - pin(1 6) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 4) - pin(6 1) - ) - circuit(2 INVX1 name($2) - pin(0 2) - pin(1 7) - pin(2 1) - pin(3 2) - pin(4 6) - pin(5 1) - ) - circuit(3 INVX1 name($3) - pin(0 2) - pin(1 8) - pin(2 1) - pin(3 2) - pin(4 7) - pin(5 1) - ) - circuit(4 INVX1 name($4) - pin(0 2) - pin(1 9) - pin(2 1) - pin(3 2) - pin(4 8) - pin(5 1) - ) - circuit(5 INVX1 name($5) - pin(0 2) - pin(1 10) - pin(2 1) - pin(3 2) - pin(4 9) - pin(5 1) - ) - circuit(6 INVX1 name($6) - pin(0 2) - pin(1 11) - pin(2 1) - pin(3 2) - pin(4 10) - pin(5 1) - ) - circuit(7 INVX1 name($7) - pin(0 2) - pin(1 12) - pin(2 1) - pin(3 2) - pin(4 11) - pin(5 1) - ) - circuit(8 INVX1 name($8) - pin(0 2) - pin(1 13) - pin(2 1) - pin(3 2) - pin(4 12) - pin(5 1) - ) - circuit(9 INVX1 name($9) - pin(0 2) - pin(1 14) - pin(2 1) - pin(3 2) - pin(4 13) - pin(5 1) - ) - circuit(10 INVX1 name($10) - pin(0 2) - pin(1 15) - pin(2 1) - pin(3 2) - pin(4 14) - pin(5 1) - ) - circuit(11 INVX1 name($11) - pin(0 2) - pin(1 3) - pin(2 1) - pin(3 2) - pin(4 15) - pin(5 1) - ) - circuit(12 INVX1 name($12) - pin(0 2) - pin(1 5) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 1) - ) - - ) -) - -# Cross reference -xref( - circuit(INVX1 INVX1 match - xref( - net(4 4 match) - net(5 5 match) - net(2 2 match) - net(6 6 match) - net(1 1 match) - net(3 3 match) - pin(3 3 match) - pin(4 4 match) - pin(1 1 match) - pin(5 5 match) - pin(0 0 match) - pin(2 2 match) - device(2 2 match) - device(1 1 match) - ) - ) - circuit(ND2X1 ND2X1 nomatch - log( - entry(error description('No equivalent pin VSS from netlist found in reference netlist.\nThis is an indication that additional physical connections are made to the subcircuit cell.')) - entry(info description('Potential invalid connection in circuit RINGO, subcircuit cell reference at r0 *1 1.8,0')) - entry(error description('No equivalent pin VSS from reference netlist found in netlist.\nThis is an indication that a physical connection is not made to the subcircuit.')) - ) - xref( - net(5 4 match) - net(4 3 mismatch) - net(7 6 match) - net(6 5 match) - net(2 2 match) - net(8 7 mismatch) - net(1 1 match) - net(3 8 mismatch) - pin(() 2 mismatch) - pin(3 3 match) - pin(5 5 match) - pin(4 4 match) - pin(1 1 match) - pin(6 6 match) - pin(0 0 match) - pin(2 () mismatch) - device(3 3 match) - device(4 4 mismatch) - device(1 1 match) - device(2 2 match) - ) - ) - circuit(RINGO RINGO skipped description('Circuits RINGO and RINGO could not be compared because the following subcircuits failed to compare:\n A: ND2X1\n B: ND2X1') - xref( - ) - ) -) diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 index 179fe4455..24fa78ec9 100644 --- a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 +++ b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 @@ -404,36 +404,36 @@ layout( ) net(12 name(VDD) rect(l3 (22600 4500) (1400 3500)) - rect(l3 (-23500 -3500) (1400 3500)) - rect(l3 (-1900 -3500) (600 3500)) - rect(l3 (25800 -3500) (1400 3500)) + rect(l3 (2400 -3500) (1400 3500)) rect(l3 (-100 -3500) (600 3500)) - rect(l8 (-5090 -1240) (180 180)) + rect(l3 (-27800 -3500) (1400 3500)) + rect(l3 (-1900 -3500) (600 3500)) + rect(l8 (22610 -1240) (180 180)) rect(l8 (-180 370) (180 180)) rect(l8 (-180 -1280) (180 180)) - rect(l8 (-22280 370) (180 180)) + rect(l8 (3620 370) (180 180)) rect(l8 (-180 370) (180 180)) rect(l8 (-180 -1280) (180 180)) - rect(l8 (25720 370) (180 180)) + rect(l8 (-26080 370) (180 180)) rect(l8 (-180 370) (180 180)) rect(l8 (-180 -1280) (180 180)) - rect(l11 (-4890 1010) (0 0)) + rect(l11 (21010 1010) (0 0)) rect(l11 (2800 -50) (0 0)) rect(l11 (-22150 -100) (0 0)) rect(l11 (19750 -450) (1200 800)) rect(l11 (-750 -1450) (300 1400)) rect(l11 (-100 -350) (0 0)) - rect(l11 (-22750 -400) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-100 -350) (0 0)) - rect(l11 (-1250 -400) (600 800)) - rect(l11 (25900 -800) (1200 800)) + rect(l11 (3150 -400) (1200 800)) rect(l11 (-750 -1450) (300 1400)) rect(l11 (-100 -350) (0 0)) rect(l11 (550 -400) (600 800)) - rect(l9 (-5250 -1500) (500 1500)) - rect(l9 (-22600 -1500) (500 1500)) - rect(l9 (25400 -1500) (500 1500)) + rect(l11 (-27700 -800) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-100 -350) (0 0)) + rect(l11 (-1250 -400) (600 800)) + rect(l9 (22450 -1500) (500 1500)) + rect(l9 (3300 -1500) (500 1500)) + rect(l9 (-26400 -1500) (500 1500)) ) net(13 name(OUT) rect(l11 (25990 3840) (320 320)) @@ -448,32 +448,32 @@ layout( rect(l13 (-150 -200) (400 400)) ) net(15 name(VSS) - rect(l8 (27010 1610) (180 180)) + rect(l8 (1110 1610) (180 180)) rect(l8 (-180 -1280) (180 180)) rect(l8 (-180 370) (180 180)) - rect(l8 (-3980 370) (180 180)) + rect(l8 (21920 370) (180 180)) rect(l8 (-180 -1280) (180 180)) rect(l8 (-180 370) (180 180)) - rect(l8 (-22280 370) (180 180)) + rect(l8 (3620 370) (180 180)) rect(l8 (-180 -1280) (180 180)) rect(l8 (-180 370) (180 180)) - rect(l11 (24710 -290) (0 0)) - rect(l11 (-3850 0) (0 0)) - rect(l11 (-19200 -100) (0 0)) - rect(l11 (24000 -400) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-550 -400) (0 0)) - rect(l11 (550 -400) (600 800)) - rect(l11 (-5150 -750) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-550 -400) (0 0)) - rect(l11 (-22300 -350) (300 1400)) + rect(l11 (-24240 -390) (0 0)) + rect(l11 (19200 100) (0 0)) + rect(l11 (3850 0) (0 0)) + rect(l11 (-24950 -500) (300 1400)) rect(l11 (-750 -1450) (1200 800)) rect(l11 (-550 -400) (0 0)) rect(l11 (-1250 -400) (600 800)) - rect(l10 (26250 -800) (500 1500)) - rect(l10 (-4300 -1500) (500 1500)) - rect(l10 (-22600 -1500) (500 1500)) + rect(l11 (22550 -750) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-550 -400) (0 0)) + rect(l11 (3600 -350) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-550 -400) (0 0)) + rect(l11 (550 -400) (600 800)) + rect(l10 (-27350 -800) (500 1500)) + rect(l10 (21600 -1500) (500 1500)) + rect(l10 (3300 -1500) (500 1500)) ) # Outgoing pins and their connections to nets diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 deleted file mode 100644 index 6ae8d34f4..000000000 --- a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 +++ /dev/null @@ -1,927 +0,0 @@ -#%lvsdb-klayout - -# Layout -layout( - top(RINGO) - unit(0.001) - - # Layer section - # This section lists the mask layers (drawing or derived) and their connections. - - # Mask layers - layer(l3 '1/0') - layer(l4 '5/0') - layer(l8 '8/0') - layer(l11 '9/0') - layer(l12 '10/0') - layer(l13 '11/0') - layer(l7) - layer(l2) - layer(l9) - layer(l6) - layer(l10) - - # Mask layer connectivity - connect(l3 l3 l9) - connect(l4 l4 l8) - connect(l8 l4 l8 l11 l2 l9 l6 l10) - connect(l11 l8 l11 l12) - connect(l12 l11 l12 l13) - connect(l13 l12 l13) - connect(l7 l7) - connect(l2 l8 l2) - connect(l9 l3 l8 l9) - connect(l6 l8 l6) - connect(l10 l8 l10) - - # Global nets and connectivity - global(l7 SUBSTRATE) - global(l10 SUBSTRATE) - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Device abstracts section - # Device abstracts list the pin shapes of the devices. - device(D$PMOS PMOS - terminal(S - rect(l2 (-550 -750) (425 1500)) - ) - terminal(G - rect(l4 (-125 -750) (250 1500)) - ) - terminal(D - rect(l2 (125 -750) (450 1500)) - ) - terminal(B - rect(l3 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$1 PMOS - terminal(S - rect(l2 (-575 -750) (450 1500)) - ) - terminal(G - rect(l4 (-125 -750) (250 1500)) - ) - terminal(D - rect(l2 (125 -750) (425 1500)) - ) - terminal(B - rect(l3 (-125 -750) (250 1500)) - ) - ) - device(D$PMOS$2 PMOS - terminal(S - rect(l2 (-550 -750) (425 1500)) - ) - terminal(G - rect(l4 (-125 -750) (250 1500)) - ) - terminal(D - rect(l2 (125 -750) (425 1500)) - ) - terminal(B - rect(l3 (-125 -750) (250 1500)) - ) - ) - device(D$NMOS NMOS - terminal(S - rect(l6 (-550 -475) (425 950)) - ) - terminal(G - rect(l4 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (450 950)) - ) - terminal(B - rect(l7 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$1 NMOS - terminal(S - rect(l6 (-575 -475) (450 950)) - ) - terminal(G - rect(l4 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l7 (-125 -475) (250 950)) - ) - ) - device(D$NMOS$2 NMOS - terminal(S - rect(l6 (-550 -475) (425 950)) - ) - terminal(G - rect(l4 (-125 -475) (250 950)) - ) - terminal(D - rect(l6 (125 -475) (425 950)) - ) - terminal(B - rect(l7 (-125 -475) (250 950)) - ) - ) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Circuit boundary - rect((-100 400) (2600 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l8 (1110 5160) (180 180)) - rect(l8 (-180 920) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l11 (-240 -790) (300 1700)) - rect(l11 (-1350 0) (2400 800)) - rect(l11 (-1150 -400) (0 0)) - rect(l2 (-275 -2150) (425 1500)) - rect(l2 (-400 -1500) (425 1500)) - ) - net(2 name(OUT) - rect(l8 (1810 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-1580 3760) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (1220 920) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) - rect(l11 (-110 1390) (300 1400)) - polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) - rect(l11 (-140 -500) (0 0)) - rect(l11 (-1750 1100) (300 1400)) - rect(l11 (1100 -1700) (300 300)) - rect(l11 (-300 0) (300 1400)) - rect(l2 (-375 -1450) (425 1500)) - rect(l2 (-1800 -1500) (425 1500)) - rect(l6 (950 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l8 (410 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -1300) (300 1360)) - rect(l11 (-650 -2160) (2400 800)) - rect(l11 (-1150 -400) (0 0)) - rect(l6 (-950 860) (425 950)) - ) - net(4 - rect(l3 (-100 4500) (2600 3500)) - ) - net(5 name(B) - rect(l4 (1425 2860) (250 1940)) - rect(l4 (-345 -950) (300 300)) - rect(l4 (-205 650) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-285 1050) (180 180)) - rect(l11 (-70 -90) (0 0)) - rect(l11 (-170 -150) (300 300)) - ) - net(6 name(A) - rect(l4 (725 2860) (250 1940)) - rect(l4 (-325 -1850) (300 300)) - rect(l4 (-225 1550) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-265 150) (180 180)) - rect(l11 (-90 -90) (0 0)) - rect(l11 (-150 -150) (300 300)) - ) - net(7 name(SUBSTRATE)) - net(8 - rect(l6 (975 1660) (425 950)) - rect(l6 (-400 -950) (425 950)) - ) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4) - pin(5 name(B)) - pin(6 name(A)) - pin(7 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.6375) - param(AD 0.3375) - param(PS 3.85) - param(PD 1.95) - terminal(S 2) - terminal(G 6) - terminal(D 1) - terminal(B 4) - ) - device(2 D$PMOS$1 - location(1550 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.3375) - param(AD 0.6375) - param(PS 1.95) - param(PD 3.85) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(3 D$NMOS - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.40375) - param(AD 0.21375) - param(PS 2.75) - param(PD 1.4) - terminal(S 3) - terminal(G 6) - terminal(D 8) - terminal(B 7) - ) - device(4 D$NMOS$1 - location(1550 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.21375) - param(AD 0.40375) - param(PS 1.4) - param(PD 2.75) - terminal(S 8) - terminal(G 5) - terminal(D 2) - terminal(B 7) - ) - - ) - circuit(INVX1 - - # Circuit boundary - rect((-100 400) (2000 7600)) - - # Nets with their geometries - net(1 name(VDD) - rect(l8 (410 6260) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l11 (-240 -240) (300 1400)) - rect(l11 (-650 300) (1800 800)) - rect(l11 (-1450 -1100) (300 300)) - rect(l11 (300 400) (0 0)) - rect(l2 (-650 -2150) (425 1500)) - ) - net(2 name(OUT) - rect(l8 (1110 5160) (180 180)) - rect(l8 (-180 920) (180 180)) - rect(l8 (-180 -730) (180 180)) - rect(l8 (-180 -4120) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -790) (300 4790)) - rect(l11 (-150 -2500) (0 0)) - rect(l2 (-225 1050) (425 1500)) - rect(l6 (-425 -4890) (425 950)) - ) - net(3 name(VSS) - rect(l8 (410 1770) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (-240 -1300) (300 1360)) - rect(l11 (-650 -2160) (1800 800)) - rect(l11 (-850 -400) (0 0)) - rect(l6 (-650 860) (425 950)) - ) - net(4 - rect(l3 (-100 4500) (2000 3500)) - ) - net(5 name(IN) - rect(l4 (725 2860) (250 1940)) - rect(l4 (-525 -1850) (300 300)) - rect(l4 (-25 1550) (250 2000)) - rect(l4 (-250 -2000) (250 2000)) - rect(l4 (-250 -5390) (250 1450)) - rect(l8 (-465 150) (180 180)) - rect(l11 (-90 -90) (0 0)) - rect(l11 (-150 -150) (300 300)) - ) - net(6 name(SUBSTRATE)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4) - pin(5 name(IN)) - pin(6 name(SUBSTRATE)) - - # Devices and their connections - device(1 D$PMOS$2 - location(850 5800) - param(L 0.25) - param(W 1.5) - param(AS 0.6375) - param(AD 0.6375) - param(PS 3.85) - param(PD 3.85) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 D$NMOS$2 - location(850 2135) - param(L 0.25) - param(W 0.95) - param(AS 0.40375) - param(AD 0.40375) - param(PS 2.75) - param(PD 2.75) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Circuit boundary - rect((0 350) (28300 7650)) - - # Nets with their geometries - net(1 - rect(l11 (4040 2950) (1160 300)) - ) - net(2 - rect(l11 (6050 2950) (900 300)) - ) - net(3 - rect(l11 (7850 2950) (900 300)) - ) - net(4 - rect(l11 (9650 2950) (900 300)) - ) - net(5 - rect(l11 (11450 2950) (900 300)) - ) - net(6 - rect(l11 (13250 2950) (900 300)) - ) - net(7 - rect(l11 (15050 2950) (900 300)) - ) - net(8 - rect(l11 (16850 2950) (900 300)) - ) - net(9 - rect(l11 (18650 2950) (900 300)) - ) - net(10 - rect(l11 (20450 2950) (900 300)) - ) - net(11 name(FB) - rect(l11 (22250 2950) (2900 300)) - rect(l11 (-21980 590) (320 320)) - rect(l11 (18570 -320) (320 320)) - rect(l12 (-19150 -260) (200 200)) - rect(l12 (18690 -200) (200 200)) - rect(l13 (-18840 -300) (18890 400)) - rect(l13 (-19070 -200) (0 0)) - rect(l13 (-170 -200) (400 400)) - rect(l13 (18490 -400) (400 400)) - ) - net(12 name(VDD) - rect(l3 (22600 4500) (1400 3500)) - rect(l3 (-23500 -3500) (1400 3500)) - rect(l3 (-1900 -3500) (600 3500)) - rect(l3 (25800 -3500) (1400 3500)) - rect(l3 (-100 -3500) (600 3500)) - rect(l8 (-5090 -1240) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-22280 370) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (25720 370) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l11 (-4890 1010) (0 0)) - rect(l11 (2800 -50) (0 0)) - rect(l11 (-22150 -100) (0 0)) - rect(l11 (19750 -450) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-100 -350) (0 0)) - rect(l11 (-22750 -400) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-100 -350) (0 0)) - rect(l11 (-1250 -400) (600 800)) - rect(l11 (25900 -800) (1200 800)) - rect(l11 (-750 -1450) (300 1400)) - rect(l11 (-100 -350) (0 0)) - rect(l11 (550 -400) (600 800)) - rect(l9 (-5250 -1500) (500 1500)) - rect(l9 (-22600 -1500) (500 1500)) - rect(l9 (25400 -1500) (500 1500)) - ) - net(13 name(OUT) - rect(l11 (25990 3840) (320 320)) - rect(l12 (-260 -260) (200 200)) - rect(l13 (-150 -100) (0 0)) - rect(l13 (-150 -200) (400 400)) - ) - net(14 name(ENABLE) - rect(l11 (2490 2940) (320 320)) - rect(l12 (-260 -260) (200 200)) - rect(l13 (-150 -100) (0 0)) - rect(l13 (-150 -200) (400 400)) - ) - net(15 name(VSS) - rect(l8 (27010 1610) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-3980 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l8 (-22280 370) (180 180)) - rect(l8 (-180 -1280) (180 180)) - rect(l8 (-180 370) (180 180)) - rect(l11 (24710 -290) (0 0)) - rect(l11 (-3850 0) (0 0)) - rect(l11 (-19200 -100) (0 0)) - rect(l11 (24000 -400) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-550 -400) (0 0)) - rect(l11 (550 -400) (600 800)) - rect(l11 (-5150 -750) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-550 -400) (0 0)) - rect(l11 (-22300 -350) (300 1400)) - rect(l11 (-750 -1450) (1200 800)) - rect(l11 (-550 -400) (0 0)) - rect(l11 (-1250 -400) (600 800)) - rect(l10 (26250 -800) (500 1500)) - rect(l10 (-4300 -1500) (500 1500)) - rect(l10 (-22600 -1500) (500 1500)) - ) - - # Outgoing pins and their connections to nets - pin(11 name(FB)) - pin(12 name(VDD)) - pin(13 name(OUT)) - pin(14 name(ENABLE)) - pin(15 name(VSS)) - - # Subcircuits and their connections - circuit(1 ND2X1 location(1800 0) - pin(0 12) - pin(1 1) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 14) - pin(6 15) - ) - circuit(2 INVX1 location(4700 0) - pin(0 12) - pin(1 2) - pin(2 15) - pin(3 12) - pin(4 1) - pin(5 15) - ) - circuit(3 INVX1 location(6500 0) - pin(0 12) - pin(1 3) - pin(2 15) - pin(3 12) - pin(4 2) - pin(5 15) - ) - circuit(4 INVX1 location(8300 0) - pin(0 12) - pin(1 4) - pin(2 15) - pin(3 12) - pin(4 3) - pin(5 15) - ) - circuit(5 INVX1 location(10100 0) - pin(0 12) - pin(1 5) - pin(2 15) - pin(3 12) - pin(4 4) - pin(5 15) - ) - circuit(6 INVX1 location(11900 0) - pin(0 12) - pin(1 6) - pin(2 15) - pin(3 12) - pin(4 5) - pin(5 15) - ) - circuit(7 INVX1 location(13700 0) - pin(0 12) - pin(1 7) - pin(2 15) - pin(3 12) - pin(4 6) - pin(5 15) - ) - circuit(8 INVX1 location(15500 0) - pin(0 12) - pin(1 8) - pin(2 15) - pin(3 12) - pin(4 7) - pin(5 15) - ) - circuit(9 INVX1 location(17300 0) - pin(0 12) - pin(1 9) - pin(2 15) - pin(3 12) - pin(4 8) - pin(5 15) - ) - circuit(10 INVX1 location(19100 0) - pin(0 12) - pin(1 10) - pin(2 15) - pin(3 12) - pin(4 9) - pin(5 15) - ) - circuit(11 INVX1 location(20900 0) - pin(0 12) - pin(1 11) - pin(2 15) - pin(3 12) - pin(4 10) - pin(5 15) - ) - circuit(12 INVX1 location(24700 0) - pin(0 12) - pin(1 13) - pin(2 15) - pin(3 12) - pin(4 11) - pin(5 15) - ) - - ) -) - -# Reference netlist -reference( - - # Device class section - class(PMOS MOS4) - class(NMOS MOS4) - - # Circuit section - # Circuits are the hierarchical building blocks of the netlist. - circuit(ND2X1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(B)) - net(6 name(A)) - net(7 name(BULK)) - net(8 name('1')) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(B)) - pin(6 name(A)) - pin(7 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 6) - terminal(D 2) - terminal(B 4) - ) - device(2 PMOS - name($2) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(3 NMOS - name($3) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 6) - terminal(D 8) - terminal(B 7) - ) - device(4 NMOS - name($4) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 8) - terminal(G 5) - terminal(D 2) - terminal(B 7) - ) - - ) - circuit(INVX1 - - # Nets - net(1 name(VDD)) - net(2 name(OUT)) - net(3 name(VSS)) - net(4 name(NWELL)) - net(5 name(IN)) - net(6 name(BULK)) - - # Outgoing pins and their connections to nets - pin(1 name(VDD)) - pin(2 name(OUT)) - pin(3 name(VSS)) - pin(4 name(NWELL)) - pin(5 name(IN)) - pin(6 name(BULK)) - - # Devices and their connections - device(1 PMOS - name($1) - param(L 0.25) - param(W 1.5) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 1) - terminal(G 5) - terminal(D 2) - terminal(B 4) - ) - device(2 NMOS - name($2) - param(L 0.25) - param(W 0.95) - param(AS 0) - param(AD 0) - param(PS 0) - param(PD 0) - terminal(S 3) - terminal(G 5) - terminal(D 2) - terminal(B 6) - ) - - ) - circuit(RINGO - - # Nets - net(1 name(VSS)) - net(2 name(VDD)) - net(3 name(FB)) - net(4 name(ENABLE)) - net(5 name(OUT)) - net(6 name('1')) - net(7 name('2')) - net(8 name('3')) - net(9 name('4')) - net(10 name('5')) - net(11 name('6')) - net(12 name('7')) - net(13 name('8')) - net(14 name('9')) - net(15 name('10')) - - # Outgoing pins and their connections to nets - pin(1 name(VSS)) - pin(2 name(VDD)) - pin(3 name(FB)) - pin(4 name(ENABLE)) - pin(5 name(OUT)) - - # Subcircuits and their connections - circuit(1 ND2X1 name($1) - pin(0 2) - pin(1 6) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 4) - pin(6 1) - ) - circuit(2 INVX1 name($2) - pin(0 2) - pin(1 7) - pin(2 1) - pin(3 2) - pin(4 6) - pin(5 1) - ) - circuit(3 INVX1 name($3) - pin(0 2) - pin(1 8) - pin(2 1) - pin(3 2) - pin(4 7) - pin(5 1) - ) - circuit(4 INVX1 name($4) - pin(0 2) - pin(1 9) - pin(2 1) - pin(3 2) - pin(4 8) - pin(5 1) - ) - circuit(5 INVX1 name($5) - pin(0 2) - pin(1 10) - pin(2 1) - pin(3 2) - pin(4 9) - pin(5 1) - ) - circuit(6 INVX1 name($6) - pin(0 2) - pin(1 11) - pin(2 1) - pin(3 2) - pin(4 10) - pin(5 1) - ) - circuit(7 INVX1 name($7) - pin(0 2) - pin(1 12) - pin(2 1) - pin(3 2) - pin(4 11) - pin(5 1) - ) - circuit(8 INVX1 name($8) - pin(0 2) - pin(1 13) - pin(2 1) - pin(3 2) - pin(4 12) - pin(5 1) - ) - circuit(9 INVX1 name($9) - pin(0 2) - pin(1 14) - pin(2 1) - pin(3 2) - pin(4 13) - pin(5 1) - ) - circuit(10 INVX1 name($10) - pin(0 2) - pin(1 15) - pin(2 1) - pin(3 2) - pin(4 14) - pin(5 1) - ) - circuit(11 INVX1 name($11) - pin(0 2) - pin(1 3) - pin(2 1) - pin(3 2) - pin(4 15) - pin(5 1) - ) - circuit(12 INVX1 name($12) - pin(0 2) - pin(1 5) - pin(2 1) - pin(3 2) - pin(4 3) - pin(5 1) - ) - - ) -) - -# Cross reference -xref( - circuit(INVX1 INVX1 match - xref( - net(4 4 match) - net(5 5 match) - net(2 2 match) - net(6 6 match) - net(1 1 match) - net(3 3 match) - pin(3 3 match) - pin(4 4 match) - pin(1 1 match) - pin(5 5 match) - pin(0 0 match) - pin(2 2 match) - device(2 2 match) - device(1 1 match) - ) - ) - circuit(ND2X1 ND2X1 match - xref( - net(8 8 match) - net(4 4 match) - net(6 6 match) - net(5 5 match) - net(2 2 match) - net(7 7 match) - net(1 1 match) - net(3 3 match) - pin(3 3 match) - pin(5 5 match) - pin(4 4 match) - pin(1 1 match) - pin(6 6 match) - pin(0 0 match) - pin(2 2 match) - device(3 3 match) - device(4 4 match) - device(1 1 match) - device(2 2 match) - ) - ) - circuit(RINGO RINGO match - xref( - net(1 6 match) - net(10 15 match) - net(2 7 match) - net(3 8 match) - net(4 9 match) - net(5 10 match) - net(6 11 match) - net(7 12 match) - net(8 13 match) - net(9 14 match) - net(14 4 match) - net(11 3 match) - net(13 5 match) - net(12 2 match) - net(15 1 match) - pin(3 3 match) - pin(0 2 match) - pin(2 4 match) - pin(1 1 match) - pin(4 0 match) - circuit(2 2 match) - circuit(3 3 match) - circuit(4 4 match) - circuit(5 5 match) - circuit(6 6 match) - circuit(7 7 match) - circuit(8 8 match) - circuit(9 9 match) - circuit(10 10 match) - circuit(11 11 match) - circuit(12 12 match) - circuit(1 1 match) - ) - ) -) From 4d41ca6f5c6edcc4631f487a61fb6ebaa5b91b0e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Sep 2023 21:44:35 +0200 Subject: [PATCH 18/41] Fixed tests. Note that now a net with two labels carries a combined net name and does not qualify for connect_implicit if one label matches --- src/db/db/dbLayoutToNetlist.cc | 91 +++++++++--------- src/db/db/dbLayoutToNetlist.h | 5 +- src/db/db/dbNetlistDeviceExtractor.cc | 49 +++++++++- src/db/db/dbNetlistDeviceExtractor.h | 53 ++++++++++ src/db/db/dbNetlistDeviceExtractorClasses.cc | 24 ++--- src/db/db/dbNetlistExtractor.cc | 2 + src/db/db/dbNetlistExtractor.h | 8 ++ src/db/db/gsiDeclDbLayoutToNetlist.cc | 5 + src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 46 ++++++++- src/drc/drc/built-in-macros/_drc_engine.rb | 7 ++ src/drc/drc/built-in-macros/_drc_netter.rb | 18 ++++ testdata/drc/drcSimpleTests_12.drc | 4 +- testdata/drc/drcSimpleTests_au12a.cir | 32 +++--- testdata/drc/implicit_nets.gds | Bin 3276 -> 3196 bytes testdata/lvs/double_height2.lvs | 2 + testdata/lvs/double_height2.lvsdb | 2 + testdata/lvs/double_height2_texts.lvs | 2 + testdata/lvs/double_height2_texts.lvsdb | 2 + .../ringo_simple_implicit_connections.lvsdb.1 | 3 + testdata/lvs/test_22a.lvsdb.1 | 3 + testdata/lvs/test_22a.lvsdb.2 | 3 + testdata/lvs/test_22b.lvsdb.1 | 3 + testdata/lvs/test_22b.lvsdb.2 | 3 + testdata/lvs/test_22c.lvsdb.1 | 3 + testdata/lvs/test_22c.lvsdb.2 | 3 + testdata/lvs/test_22c.lvsdb.3 | 3 + testdata/lvs/test_22d.lvsdb.1 | 3 + testdata/lvs/test_22d.lvsdb.2 | 3 + testdata/lvs/test_22d.lvsdb.3 | 3 + 29 files changed, 300 insertions(+), 85 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index d9b4aa299..c0b3d965b 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -247,7 +247,7 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co // transfer errors to log entries for (auto e = extractor.begin_errors (); e != extractor.end_errors (); ++e) { - m_log_entries.push_back (db::LogEntryData (db::Error, e->to_string ())); + m_log_entries.push_back (db::LogEntryData (e->is_warning () ? db::Warning : db::Error, e->to_string ())); } } @@ -369,48 +369,7 @@ void LayoutToNetlist::extract_netlist () } ensure_netlist (); - const db::Layout &layout = dss ().layout (m_layout_index); - db::NetlistExtractor netex; - -#if 0 // @@@ remove this plus corresponding code inside NetlistExtractor ... - netex.set_joined_net_names (m_joined_net_names); - - std::map > jp_per_cell; - for (std::list >::const_iterator j = m_joined_net_names_per_cell.begin (); j != m_joined_net_names_per_cell.end (); ++j) { - if (j->first.is_const ()) { - jp_per_cell [j->first.pattern ()].push_back (j->second); - } else { - for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) { - if (j->first.match (layout.cell_name (c->cell_index ()))) { - jp_per_cell [layout.cell_name (c->cell_index ())].push_back (j->second); - } - } - } - } - for (std::map >::const_iterator i = jp_per_cell.begin (); i != jp_per_cell.end (); ++i) { - netex.set_joined_net_names (i->first, i->second); - } - - netex.set_joined_nets (m_joined_nets); - - std::map > > jn_per_cell; - for (std::list > >::const_iterator j = m_joined_nets_per_cell.begin (); j != m_joined_nets_per_cell.end (); ++j) { - if (j->first.is_const ()) { - jn_per_cell [j->first.pattern ()].push_back (j->second); - } else { - for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) { - if (j->first.match (layout.cell_name (c->cell_index ()))) { - jn_per_cell [layout.cell_name (c->cell_index ())].push_back (j->second); - } - } - } - } - for (std::map > >::const_iterator i = jn_per_cell.begin (); i != jn_per_cell.end (); ++i) { - netex.set_joined_nets (i->first, i->second); - } - #endif - netex.set_include_floating_subcircuits (m_include_floating_subcircuits); netex.extract_nets (dss (), m_layout_index, m_conn, *mp_netlist, m_net_clusters); @@ -423,8 +382,29 @@ void LayoutToNetlist::extract_netlist () } m_netlist_extracted = true; +} - // @@@ raise error on error +void LayoutToNetlist::check_extraction_errors () +{ + int num_errors = 0; + int max_errors = 10; + std::string errors; + for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) { + if (l->severity >= db::Error) { + errors += "\n"; + if (++num_errors >= max_errors) { + errors += "...\n"; + errors += tl::sprintf (tl::to_string (tr ("(list shortened after %d errrors, see log for all errors)")), max_errors); + break; + } else { + errors += l->msg; + } + } + } + + if (num_errors > 0) { + throw tl::Exception (tl::to_string (tr ("Errors encountered during netlist extraction:")) + errors); + } } void LayoutToNetlist::join_nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p) @@ -485,7 +465,6 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a return; } - // @@@ raise a warning for top level cells? if (c.begin_refs () != c.end_refs ()) { if (a.begin_pins () == a.end_pins ()) { error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); @@ -493,11 +472,18 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a if (b.begin_pins () == b.end_pins ()) { error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); } + } else { + if (a.expanded_name () == b.expanded_name ()) { + warn (tl::sprintf (tl::to_string (tr ("Must-connect nets %s from circuit %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name (), c.name ())); + } else { + warn (tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s from circuit %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name (), b.expanded_name (), c.name ())); + } } if (a.begin_pins () != a.end_pins () && b.begin_pins () != b.end_pins ()) { for (auto ref = c.begin_refs (); ref != c.end_refs (); ++ref) { const db::SubCircuit &sc = *ref; + // TODO: consider the case of multiple pins on a net (rare) const db::Net *net_a = sc.net_for_pin (a.begin_pins ()->pin_id ()); const db::Net *net_b = sc.net_for_pin (b.begin_pins ()->pin_id ()); if (net_a == 0) { @@ -557,17 +543,28 @@ void LayoutToNetlist::do_join_nets () void LayoutToNetlist::error (const std::string &msg) { - m_log_entries.push_back (db::LogEntryData (db::Error, msg)); + if (m_log_entries.empty () || m_log_entries.back ().severity != db::Error || m_log_entries.back ().msg != msg) { + tl::error << msg; + m_log_entries.push_back (db::LogEntryData (db::Error, msg)); + } } void LayoutToNetlist::warn (const std::string &msg) { - m_log_entries.push_back (db::LogEntryData (db::Warning, msg)); + if (m_log_entries.empty () || m_log_entries.back ().severity != db::Warning || m_log_entries.back ().msg != msg) { + tl::warn << msg; + m_log_entries.push_back (db::LogEntryData (db::Warning, msg)); + } } void LayoutToNetlist::info (const std::string &msg) { - m_log_entries.push_back (db::LogEntryData (db::Info, msg)); + if (m_log_entries.empty () || m_log_entries.back ().severity != db::Info || m_log_entries.back ().msg != msg) { + if (tl::verbosity () >= 10) { + tl::info << msg; + } + m_log_entries.push_back (db::LogEntryData (db::Info, msg)); + } } void LayoutToNetlist::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index b3ce1d6d9..eaa149907 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -194,7 +194,6 @@ public: /** * @brief Gets the log entries - * @@@ TODO: provide GSI interface */ const log_entries_type &log_entries () const { @@ -203,7 +202,6 @@ public: /** * @brief Clears the log entries - * @@@ TODO: provide GSI interface */ void clear_log_entries () { @@ -212,7 +210,6 @@ public: /** * @brief Adds a log entry - * @@@ TODO: provide GSI interface */ void log_entry (const db::LogEntryData &log_entry) { @@ -587,6 +584,8 @@ public: */ void extract_netlist (); + void check_extraction_errors (); + /** * @brief Marks the netlist as extracted * NOTE: this method is provided for special cases such as netlist readers. Don't diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index a7c7d7b98..04b39e4ff 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -36,12 +36,13 @@ namespace db // NetlistDeviceExtractorError implementation NetlistDeviceExtractorError::NetlistDeviceExtractorError () + : m_warning (false) { // .. nothing yet .. } NetlistDeviceExtractorError::NetlistDeviceExtractorError (const std::string &cell_name, const std::string &msg) - : m_cell_name (cell_name), m_message (msg) + : m_warning (false), m_cell_name (cell_name), m_message (msg) { // .. nothing yet .. } @@ -626,4 +627,50 @@ void NetlistDeviceExtractor::error (const std::string &category_name, const std: } } +void NetlistDeviceExtractor::warn (const std::string &msg) +{ + m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); + m_errors.back ().set_warning (true); + + if (tl::verbosity () >= 20) { + tl::warn << m_errors.back ().to_string (); + } +} + +void NetlistDeviceExtractor::warn (const std::string &msg, const db::DPolygon &poly) +{ + m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); + m_errors.back ().set_geometry (poly); + m_errors.back ().set_warning (true); + + if (tl::verbosity () >= 20) { + tl::warn << m_errors.back ().to_string (); + } +} + +void NetlistDeviceExtractor::warn (const std::string &category_name, const std::string &category_description, const std::string &msg) +{ + m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); + m_errors.back ().set_category_name (category_name); + m_errors.back ().set_category_description (category_description); + m_errors.back ().set_warning (true); + + if (tl::verbosity () >= 20) { + tl::warn << m_errors.back ().to_string (); + } +} + +void NetlistDeviceExtractor::warn (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::DPolygon &poly) +{ + m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); + m_errors.back ().set_category_name (category_name); + m_errors.back ().set_category_description (category_description); + m_errors.back ().set_geometry (poly); + m_errors.back ().set_warning (true); + + if (tl::verbosity () >= 20) { + tl::warn << m_errors.back ().to_string (); + } +} + } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index f80ca09ee..b3b6bbed8 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -54,6 +54,22 @@ public: */ NetlistDeviceExtractorError (const std::string &cell_name, const std::string &msg); + /** + * @brief Sets a value indicating whether the error is only a warning + */ + void set_warning (bool f) + { + m_warning = f; + } + + /** + * @brief Gets a value indicating whether the error is only a warning + */ + bool is_warning () const + { + return m_warning; + } + /** * @brief The category name of the error * Specifying the category name is optional. If a category is given, it will be used for @@ -145,6 +161,7 @@ public: std::string to_string () const; private: + bool m_warning; std::string m_cell_name; std::string m_message; db::DPolygon m_geometry; @@ -506,6 +523,42 @@ public: error (category_name, category_description, msg, poly.transformed (db::CplxTrans (dbu ()))); } + /** + * @brief Issues a warning with the given message + */ + void warn (const std::string &msg); + + /** + * @brief Issues a warning with the given message and warn shape + */ + void warn (const std::string &msg, const db::DPolygon &poly); + + /** + * @brief Issues a warning with the given message and warn shape + */ + void warn (const std::string &msg, const db::Polygon &poly) + { + warn (msg, poly.transformed (db::CplxTrans (dbu ()))); + } + + /** + * @brief Issues a warning with the given category name, description and message + */ + void warn (const std::string &category_name, const std::string &category_description, const std::string &msg); + + /** + * @brief Issues a warning with the given category name, description and message and warn shape + */ + void warn (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::DPolygon &poly); + + /** + * @brief Issues a warning with the given category name, description and message and warn shape + */ + void warn (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::Polygon &poly) + { + warn (category_name, category_description, msg, poly.transformed (db::CplxTrans (dbu ()))); + } + /** * @brief Gets the name of the current cell */ diff --git a/src/db/db/dbNetlistDeviceExtractorClasses.cc b/src/db/db/dbNetlistDeviceExtractorClasses.cc index c6adfe34f..ba723fa19 100644 --- a/src/db/db/dbNetlistDeviceExtractorClasses.cc +++ b/src/db/db/dbNetlistDeviceExtractorClasses.cc @@ -136,11 +136,11 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vectorproperties_repository ().get_id_of_name (db::NetlistDeviceExtractor::device_id_property_name ()); // build an attribute equivalence map which lists the "attribute IDs" which are identical in terms of net names + // TODO: this feature is not really used as must-connect nets now are handled in the LayoutToNetlist class on netlist level. + // Remove this later. std::map > net_name_equivalence; if (m_text_annot_name_id.first) { diff --git a/src/db/db/dbNetlistExtractor.h b/src/db/db/dbNetlistExtractor.h index f85154378..3f8d8915b 100644 --- a/src/db/db/dbNetlistExtractor.h +++ b/src/db/db/dbNetlistExtractor.h @@ -106,6 +106,8 @@ public: * This is a glob expression rendering net names where partial nets with the * same name are joined even without explicit connection. * The cell-less version applies to top level cells only. + * NOTE: this feature is not really used as must-connect nets are handled now in the LayoutToNetlist extractor. + * Remove this function later. */ void set_joined_net_names (const std::list &jnn); @@ -113,6 +115,8 @@ public: * @brief Sets the joined net names attribute for a given cell name * While the single-parameter set_joined_net_names only acts on the top cell, this * version will act on the cell with the given name. + * NOTE: this feature is not really used as must-connect nets are handled now in the LayoutToNetlist extractor. + * Remove this function later. */ void set_joined_net_names (const std::string &cell_name, const std::list &jnn); @@ -122,11 +126,15 @@ public: * names that are to be connected. Multiple such groups can be specified. Each net name listed in a * group implies implicit joining of the corresponding labels into one net. * The cell-less version applies to top level cells only. + * NOTE: this feature is not really used as must-connect nets are handled now in the LayoutToNetlist extractor. + * Remove this function later. */ void set_joined_nets (const std::list > &jnn); /** * @brief Sets the joined nets attribute per cell + * NOTE: this feature is not really used as must-connect nets are handled now in the LayoutToNetlist extractor. + * Remove this function later. */ void set_joined_nets (const std::string &cell_name, const std::list > &jnn); diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 417abd105..d60455c71 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -530,6 +530,11 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "\n" "This method has been made parameter-less in version 0.27. Use \\include_floating_subcircuits= and \\join_net_names as substitutes for the arguments of previous versions." ) + + gsi::method ("check_extraction_errors", &db::LayoutToNetlist::check_extraction_errors, + "@brief Raises an exception if extraction errors are present\n" + "\n" + "This method has been introduced in version 0.28.13." + ) + gsi::method_ext ("internal_layout", &l2n_internal_layout, "@brief Gets the internal layout\n" "Usually it should not be required to obtain the internal layout. If you need to do so, make sure not to modify the layout as\n" diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 9219c823e..05b67a8e3 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -157,6 +157,14 @@ Class decl_dbDeviceClassFactoryBase ("db", "DeviceClassF ); Class decl_dbNetlistDeviceExtractorError ("db", "NetlistDeviceExtractorError", + gsi::method ("is_warning?|is_warning", &db::NetlistDeviceExtractorError::is_warning, + "@brief Gets a value indicating whether the error is a warning.\n" + "This predicate has been introduced in version 0.28.13." + ) + + gsi::method ("warning=", &db::NetlistDeviceExtractorError::set_warning, gsi::arg ("flag"), + "@brief Sets a value indicating whether the error is a warning.\n" + "This predicate has been introduced in version 0.28.13." + ) + gsi::method ("message", &db::NetlistDeviceExtractorError::message, "@brief Gets the message text.\n" ) + @@ -199,8 +207,12 @@ Class decl_dbNetlistDeviceExtractorError ("db", gsi::method ("category_description=", &db::NetlistDeviceExtractorError::set_category_description, gsi::arg ("description"), "@brief Sets the category description.\n" "See \\category_name= for details about categories." + ) + + gsi::method ("to_s", &db::NetlistDeviceExtractorError::to_string, + "@brief Gets the string representation of this error or warning.\n" + "This method has been introduced in version 0.28.13." ), - "@brief An error that occurred during device extraction\n" + "@brief An error or a warning that occurred during device extraction\n" "The device extractor will keep errors that occurred during extraction of the devices. " "It does not by using this error class.\n" "\n" @@ -211,7 +223,7 @@ Class decl_dbNetlistDeviceExtractorError ("db", "For categorization of the errors, a category name and description may be specified. If given, the " "errors will be shown in the specified category. The category description is optional.\n" "\n" - "This class has been introduced in version 0.26." + "This class has been introduced in version 0.26. Warning mode has been added in version 0.28.13." ); static const std::string &ld_name (const db::NetlistDeviceExtractorLayerDefinition *ld) @@ -468,6 +480,36 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE gsi::method ("error", (void (GenericDeviceExtractor::*) (const std::string &, const std::string &, const std::string &, const db::Polygon &)) &GenericDeviceExtractor::error, gsi::arg ("category_name"), gsi::arg ("category_description"), gsi::arg ("message"), gsi::arg ("geometry"), "@brief Issues an error with the given category name and description, message and database-unit polygon geometry\n" + ) + + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &)) &GenericDeviceExtractor::warn, + gsi::arg ("message"), + "@brief Issues a warning with the given message\n" + "Warnings have been introduced in version 0.28.13." + ) + + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &, const db::DPolygon &)) &GenericDeviceExtractor::warn, + gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues a warning with the given message and micrometer-units polygon geometry\n" + "Warnings have been introduced in version 0.28.13." + ) + + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &, const db::Polygon &)) &GenericDeviceExtractor::warn, + gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues a warning with the given message and database-unit polygon geometry\n" + "Warnings have been introduced in version 0.28.13." + ) + + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &, const std::string &, const std::string &)) &GenericDeviceExtractor::warn, + gsi::arg ("category_name"), gsi::arg ("category_description"), gsi::arg ("message"), + "@brief Issues a warning with the given category name and description, message\n" + "Warnings have been introduced in version 0.28.13." + ) + + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &, const std::string &, const std::string &, const db::DPolygon &)) &GenericDeviceExtractor::warn, + gsi::arg ("category_name"), gsi::arg ("category_description"), gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues a warning with the given category name and description, message and micrometer-units polygon geometry\n" + "Warnings have been introduced in version 0.28.13." + ) + + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &, const std::string &, const std::string &, const db::Polygon &)) &GenericDeviceExtractor::warn, + gsi::arg ("category_name"), gsi::arg ("category_description"), gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues a warning with the given category name and description, message and database-unit polygon geometry\n" + "Warnings have been introduced in version 0.28.13." ), "@brief The basic class for implementing custom device extractors.\n" "\n" diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 53ac76a5a..70cd8bfa8 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -2277,6 +2277,12 @@ CODE # @synopsis device_scaling(factor) # See \Netter#device_scaling for a description of that function. + # %DRC% + # @name ignore_extraction_errors + # @brief Specifies whether to ignore extraction errors + # @synopsis ignore_extraction_errors(value) + # See \Netter#ignore_extraction_errors for a description of that function. + # %DRC% # @name extract_devices # @brief Extracts devices for a given device extractor and device layer selection @@ -2299,6 +2305,7 @@ CODE connect_implicit connect_explicit device_scaling + ignore_extraction_errors extract_devices l2n_data netlist diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index f7ea6f2ec..7dbdf6c20 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -69,6 +69,7 @@ module DRC @l2n = nil @lnum = 0 @device_scaling = 1.0 + @ignore_extraction_errors = false end # %DRC% @@ -234,6 +235,18 @@ module DRC @l2n && @l2n.device_scaling = factor end end + + # %DRC% + # @name ignore_extraction_errors + # @brief Specifies whether to ignore extraction errors + # @synopsis ignore_extraction_errors(value) + # With this value set to false (the default), "extract_netlist" will raise + # an exception upon extraction errors. Otherwise, extraction errors will be logged + # but no error is raised. + + def ignore_extraction_errors(value) + @ignore_extraction_errors = value + end # %DRC% # @name clear_connections @@ -602,6 +615,11 @@ module DRC cfg.call(@l2n) end + # checks for errors if needed + if !@ignore_extraction_errors + @l2n.check_extraction_errors + end + end @l2n diff --git a/testdata/drc/drcSimpleTests_12.drc b/testdata/drc/drcSimpleTests_12.drc index ed7b9c996..0c21bad68 100644 --- a/testdata/drc/drcSimpleTests_12.drc +++ b/testdata/drc/drcSimpleTests_12.drc @@ -21,8 +21,8 @@ metal2_lbl = input(8, 1) # Computed layers pactive = active & nwell -pgate = active & poly -psd = active - pgate +pgate = pactive & poly +psd = pactive - pgate nactive = active - nwell ngate = nactive & poly diff --git a/testdata/drc/drcSimpleTests_au12a.cir b/testdata/drc/drcSimpleTests_au12a.cir index b459b2a77..8b0577698 100644 --- a/testdata/drc/drcSimpleTests_au12a.cir +++ b/testdata/drc/drcSimpleTests_au12a.cir @@ -5,12 +5,12 @@ * net 1 FB * net 2 OSC * net 3 NEXT -* net 4 VSSZ,VSS -* net 5 VDDZ,VDD -* cell instance $1 r180 *1 -0.24,9.18 -X$1 16 1 2 4 5 INV2 -* cell instance $2 r0 *1 0,0 -X$2 1 14 15 4 5 INV2 +* net 4 VSSZ +* net 5 VDDZ +* cell instance $1 r0 *1 0,0 +X$1 1 14 15 4 5 INV2 +* cell instance $2 r180 *1 -0.24,9.18 +X$2 16 1 2 4 5 INV2 * cell instance $3 r180 *1 10.32,9.18 X$3 3 9 19 4 5 INV2 * cell instance $4 r0 *1 10.56,0 @@ -46,18 +46,14 @@ X$2 2 5 1 TRANS X$3 5 3 2 TRANS * cell instance $4 m0 *1 0.4,0 X$4 4 3 2 TRANS -* device instance $1 -0.4,0 PMOS -M$1 2 1 4 2 PMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U -* device instance $2 0.4,0 PMOS -M$2 4 2 3 4 PMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U -* device instance $3 -0.4,2.8 PMOS -M$3 2 1 5 2 PMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U -* device instance $4 0.4,2.8 PMOS -M$4 5 2 3 5 PMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U -* device instance $5 -0.4,0 NMOS -M$5 2 1 4 2 NMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U -* device instance $6 0.4,0 NMOS -M$6 4 2 3 4 NMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U +* device instance $1 r0 *1 -0.4,2.8 PMOS +M$1 5 1 2 2 PMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U +* device instance $2 r0 *1 0.4,2.8 PMOS +M$2 3 2 5 5 PMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U +* device instance $3 r0 *1 -0.4,0 NMOS +M$3 4 1 2 2 NMOS L=0.25U W=0.95U AS=0.49875P AD=0.26125P PS=2.95U PD=1.5U +* device instance $4 r0 *1 0.4,0 NMOS +M$4 3 2 4 4 NMOS L=0.25U W=0.95U AS=0.26125P AD=0.49875P PS=1.5U PD=2.95U .ENDS INV2 * cell TRANS diff --git a/testdata/drc/implicit_nets.gds b/testdata/drc/implicit_nets.gds index 0b8e3faf949ab06c07f009651db362b27729fa00..1ea4c7aaf5b80e7c4c0df1c0926ed22275e2b38a 100644 GIT binary patch delta 164 zcmX>j`9~s(fsKKQDS|{L4=vr&auZg^itofrW(u08``}@&Et; delta 244 zcmew(aYizVfsKKQDS|{L4=vr&auZC5(rGfsL1mfrEifjERAffk%Lu i0R}iE*}{T@85mduff$!Mt`7_#buKPYb?iWzg#iH82_EDC diff --git a/testdata/lvs/double_height2.lvs b/testdata/lvs/double_height2.lvs index cac92ec75..71e32a05c 100644 --- a/testdata/lvs/double_height2.lvs +++ b/testdata/lvs/double_height2.lvs @@ -3,6 +3,8 @@ source($lvs_test_source) report_lvs($lvs_test_target_lvsdb) +ignore_extraction_errors(true) + writer = write_spice(true, false) target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout") diff --git a/testdata/lvs/double_height2.lvsdb b/testdata/lvs/double_height2.lvsdb index 8bad8efaa..41231a058 100644 --- a/testdata/lvs/double_height2.lvsdb +++ b/testdata/lvs/double_height2.lvsdb @@ -27,6 +27,8 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) + H(W B('Must-connect nets GND from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) + H(W B('Must-connect nets R from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) H(E B('Must-connect nets R from circuit INV2 are not connected in INVCHAIN')) K(PMOS MOS3) K(NMOS MOS3) diff --git a/testdata/lvs/double_height2_texts.lvs b/testdata/lvs/double_height2_texts.lvs index 33ae20e7f..c3d169a9d 100644 --- a/testdata/lvs/double_height2_texts.lvs +++ b/testdata/lvs/double_height2_texts.lvs @@ -3,6 +3,8 @@ source($lvs_test_source) report_lvs($lvs_test_target_lvsdb) +ignore_extraction_errors(true) + writer = write_spice(true, false) target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout") diff --git a/testdata/lvs/double_height2_texts.lvsdb b/testdata/lvs/double_height2_texts.lvsdb index ec8dc1494..d99bb36e5 100644 --- a/testdata/lvs/double_height2_texts.lvsdb +++ b/testdata/lvs/double_height2_texts.lvsdb @@ -27,6 +27,8 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) + H(W B('Must-connect nets GND from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) + H(W B('Must-connect nets R from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) H(E B('Must-connect nets R from circuit INV2 are not connected in INVCHAIN')) K(PMOS MOS3) K(NMOS MOS3) diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 index 24fa78ec9..b8db0187d 100644 --- a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 +++ b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 @@ -38,6 +38,9 @@ layout( global(l7 SUBSTRATE) global(l10 SUBSTRATE) + # Log entries + message(warning description('Must-connect nets VDD from circuit RINGO must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(PMOS MOS4) class(NMOS MOS4) diff --git a/testdata/lvs/test_22a.lvsdb.1 b/testdata/lvs/test_22a.lvsdb.1 index a09d71fe2..0c615c0a6 100644 --- a/testdata/lvs/test_22a.lvsdb.1 +++ b/testdata/lvs/test_22a.lvsdb.1 @@ -70,6 +70,9 @@ layout( global(l1 vss) global(l6 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22a.lvsdb.2 b/testdata/lvs/test_22a.lvsdb.2 index b2354cc21..db581b3ce 100644 --- a/testdata/lvs/test_22a.lvsdb.2 +++ b/testdata/lvs/test_22a.lvsdb.2 @@ -70,6 +70,9 @@ layout( global(l1 vss) global(l6 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.1 b/testdata/lvs/test_22b.lvsdb.1 index 5b71fbe2d..adae1c5b2 100644 --- a/testdata/lvs/test_22b.lvsdb.1 +++ b/testdata/lvs/test_22b.lvsdb.1 @@ -70,6 +70,9 @@ layout( global(l1 vss) global(l6 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.2 b/testdata/lvs/test_22b.lvsdb.2 index 03b56d2fd..780f9903e 100644 --- a/testdata/lvs/test_22b.lvsdb.2 +++ b/testdata/lvs/test_22b.lvsdb.2 @@ -70,6 +70,9 @@ layout( global(l1 vss) global(l6 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.1 b/testdata/lvs/test_22c.lvsdb.1 index 3daddbd99..1dde5fe1e 100644 --- a/testdata/lvs/test_22c.lvsdb.1 +++ b/testdata/lvs/test_22c.lvsdb.1 @@ -70,6 +70,9 @@ layout( global(l6 vss) global(l1 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.2 b/testdata/lvs/test_22c.lvsdb.2 index 4e459b3fe..4b291a048 100644 --- a/testdata/lvs/test_22c.lvsdb.2 +++ b/testdata/lvs/test_22c.lvsdb.2 @@ -70,6 +70,9 @@ layout( global(l6 vss) global(l1 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.3 b/testdata/lvs/test_22c.lvsdb.3 index 66213ecfc..dfcc716bf 100644 --- a/testdata/lvs/test_22c.lvsdb.3 +++ b/testdata/lvs/test_22c.lvsdb.3 @@ -70,6 +70,9 @@ layout( global(l6 vss) global(l1 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.1 b/testdata/lvs/test_22d.lvsdb.1 index 453674e0e..6c4dda0ef 100644 --- a/testdata/lvs/test_22d.lvsdb.1 +++ b/testdata/lvs/test_22d.lvsdb.1 @@ -70,6 +70,9 @@ layout( global(l6 vss) global(l1 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.2 b/testdata/lvs/test_22d.lvsdb.2 index 253f1dbb1..bf0e96e24 100644 --- a/testdata/lvs/test_22d.lvsdb.2 +++ b/testdata/lvs/test_22d.lvsdb.2 @@ -70,6 +70,9 @@ layout( global(l6 vss) global(l1 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.3 b/testdata/lvs/test_22d.lvsdb.3 index a0c293345..2a177b469 100644 --- a/testdata/lvs/test_22d.lvsdb.3 +++ b/testdata/lvs/test_22d.lvsdb.3 @@ -70,6 +70,9 @@ layout( global(l6 vss) global(l1 vss) + # Log entries + message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + # Device class section class(active_res RES) class(poly_res RES) From 1fbb907c5b51a098861c6aa03d703e1938a249e5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Sep 2023 23:46:53 +0200 Subject: [PATCH 19/41] Fixed some unit tests The flatten test now reduces pins of subcircuits if they would connect to the same net internally --- src/db/db/dbSubCircuit.cc | 9 +++-- src/db/unit_tests/dbNetlistTests.cc | 51 ++++++++++++++--------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/db/db/dbSubCircuit.cc b/src/db/db/dbSubCircuit.cc index 21edd6806..bd1047727 100644 --- a/src/db/db/dbSubCircuit.cc +++ b/src/db/db/dbSubCircuit.cc @@ -93,13 +93,18 @@ void SubCircuit::set_trans (const db::DCplxTrans &t) void SubCircuit::erase_pin (size_t pin_id) { Net *net = net_for_pin (pin_id); - net->erase_subcircuit_pin (m_pin_refs [pin_id]); + + if (! tl::is_null_iterator (m_pin_refs [pin_id])) { + net->erase_subcircuit_pin (m_pin_refs [pin_id]); + } m_pin_refs.erase (m_pin_refs.begin () + pin_id); // correct pin IDs for the pins with ID > pin_id for (auto p = m_pin_refs.begin () + pin_id; p != m_pin_refs.end (); ++p) { - (*p)->set_pin_id ((*p)->pin_id () - 1); + if (! tl::is_null_iterator (*p)) { + (*p)->set_pin_id ((*p)->pin_id () - 1); + } } } diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index 3e13ac8df..bc55997be 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -1380,15 +1380,15 @@ TEST(22_FlattenSubCircuitPinsJoinNets) nl2.flatten_circuit (nl2.circuit_by_name ("PTRANS")); EXPECT_EQ (nl2.to_string (), - "circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n" - " subcircuit INV2 INV2_SC1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" - " subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n" + "circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD='FB,VDD');\n" + " subcircuit INV2 INV2_SC1 (OUT=OSC,$2=VSS,IN='FB,VDD');\n" + " subcircuit INV2 INV2_SC2 (OUT='FB,VDD',$2=VSS,IN='FB,VDD');\n" "end;\n" - "circuit INV2 (IN=$5,$2=$5,OUT=OUT,$4=$4,$5=$5);\n" - " device PMOS $1 (S=$5,G=$5,D=$5) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $2 (S=$5,G=$5,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " subcircuit NTRANS SC2 ($1=$4,$2=$5,$3=$5);\n" - " subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=$5);\n" + "circuit INV2 (OUT=OUT,$2=$4,IN=IN);\n" + " device PMOS $1 (S=IN,G=IN,D=IN) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S=IN,G=IN,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " subcircuit NTRANS SC2 ($1=$4,$2=IN,$3=IN);\n" + " subcircuit NTRANS SC4 ($1=$4,$2=OUT,$3=IN);\n" "end;\n" "circuit NTRANS ($1=$1,$2=$2,$3=$2);\n" " device NMOS $1 (S=$1,G=$2,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" @@ -1398,33 +1398,32 @@ TEST(22_FlattenSubCircuitPinsJoinNets) nl2.flatten_circuit (nl2.circuit_by_name ("NTRANS")); EXPECT_EQ (nl2.to_string (), - "circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=VDD);\n" - " subcircuit INV2 INV2_SC1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" - " subcircuit INV2 INV2_SC2 (IN=FB,$2=(null),OUT=$I8,$4=VSS,$5=VDD);\n" + "circuit RINGO (IN=IN,'OSC,VDD'='FB,OSC,VDD',VSS=VSS);\n" + " subcircuit INV2 INV2_SC1 ('IN,OUT'='FB,OSC,VDD',$2=VSS);\n" + " subcircuit INV2 INV2_SC2 ('IN,OUT'='FB,OSC,VDD',$2=VSS);\n" "end;\n" - "circuit INV2 (IN=OUT,$2=OUT,OUT=OUT,$4=$4,$5=OUT);\n" - " device PMOS $1 (S=OUT,G=OUT,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $2 (S=OUT,G=OUT,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $3 (S=$4,G=OUT,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $4 (S=$4,G=OUT,D=OUT) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + "circuit INV2 ('IN,OUT'='IN,OUT',$2=$4);\n" + " device PMOS $1 (S='IN,OUT',G='IN,OUT',D='IN,OUT') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S='IN,OUT',G='IN,OUT',D='IN,OUT') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $3 (S=$4,G='IN,OUT',D='IN,OUT') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $4 (S=$4,G='IN,OUT',D='IN,OUT') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); nl2.flatten_circuit (nl2.circuit_by_name ("INV2")); EXPECT_EQ (nl2.to_string (), - "circuit RINGO (IN=IN,OSC=OSC,VSS=VSS,VDD=OSC);\n" - " device PMOS $1 (S=OSC,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $2 (S=OSC,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $3 (S=VSS,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $4 (S=VSS,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $5 (S=OSC,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $6 (S=OSC,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $7 (S=VSS,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $8 (S=VSS,G=OSC,D=OSC) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + "circuit RINGO (IN=IN,'OSC,VDD'='FB,OSC,VDD',VSS=VSS);\n" + " device PMOS $1 (S='FB,OSC,VDD',G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S='FB,OSC,VDD',G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $3 (S=VSS,G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $4 (S=VSS,G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $5 (S='FB,OSC,VDD',G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $6 (S='FB,OSC,VDD',G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $7 (S=VSS,G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $8 (S=VSS,G='FB,OSC,VDD',D='FB,OSC,VDD') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); - } TEST(23_BlankCircuit) From 439e10c98240bb79cd9c70c68100be1121cdcecc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Sep 2023 23:58:43 +0200 Subject: [PATCH 20/41] Bug fixes --- src/db/db/dbCircuit.cc | 21 ++++++++++++++++++++- src/db/db/dbCircuit.h | 9 +++++++++ src/db/db/gsiDeclDbLayoutToNetlist.cc | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/db/db/dbCircuit.cc b/src/db/db/dbCircuit.cc index 07d8cb338..10022a34e 100644 --- a/src/db/db/dbCircuit.cc +++ b/src/db/db/dbCircuit.cc @@ -408,7 +408,7 @@ void Circuit::join_nets (Net *net, Net *with) } while (with->begin_pins () != with->end_pins ()) { - connect_pin (with->begin_pins ()->pin_id (), net); + join_pin_with_net (with->begin_pins ()->pin_id (), net); } if (netlist ()->callbacks ()) { @@ -698,6 +698,25 @@ void Circuit::connect_pin (size_t pin_id, Net *net) m_pin_refs [pin_id] = Net::pin_iterator (); } + if (net) { + net->add_pin (NetPinRef (pin_id)); + } +} + +void Circuit::join_pin_with_net (size_t pin_id, Net *net) +{ + if (net_for_pin (pin_id) == net) { + return; + } + + if (pin_id < m_pin_refs.size ()) { + Net::pin_iterator p = m_pin_refs [pin_id]; + if (! tl::is_null_iterator (p) && p->net ()) { + p->net ()->erase_pin (p); + } + m_pin_refs [pin_id] = Net::pin_iterator (); + } + if (net) { if (net->begin_pins () != net->end_pins ()) { join_pins (net->begin_pins ()->pin_id (), pin_id); diff --git a/src/db/db/dbCircuit.h b/src/db/db/dbCircuit.h index 5c90ed4a0..22253a78c 100644 --- a/src/db/db/dbCircuit.h +++ b/src/db/db/dbCircuit.h @@ -702,6 +702,15 @@ public: */ void connect_pin (size_t pin_id, Net *net); + /** + * @brief Adds a pin to the given net + * The pin will be added to the net. If there is already a pin + * on the net, the existing and new pin will be joined. + * This usually implies that nets further up in the hierarchy + * are joined too. + */ + void join_pin_with_net (size_t pin_id, Net *net); + /** * @brief Renames the pin with the given ID */ diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index d60455c71..dfaa7046a 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -712,6 +712,7 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@brief Reads the extracted netlist from the file.\n" "This method employs the native format of KLayout.\n" ) + + // @@@ Add API for logs gsi::method_ext ("antenna_check", &antenna_check, gsi::arg ("gate"), gsi::arg ("metal"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"), "@brief Runs an antenna check on the extracted clusters\n" "\n" From a5bee51046c87b117cd30d516ea2a694212eda6f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Sep 2023 00:07:50 +0200 Subject: [PATCH 21/41] Updated tests --- src/db/unit_tests/dbNetlistCompareTests.cc | 16 +++--- .../unit_tests/dbNetlistDeviceClassesTests.cc | 56 +++++++++---------- src/db/unit_tests/dbNetlistTests.cc | 20 +++---- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 0f1cc9a06..0eb1e4b6a 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -4698,14 +4698,14 @@ TEST(28_JoinSymmetricNets) " device PMOS $2 (S=VDD,G=A,D=OUT1) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $3 (S=VSS,G=A,D=OUT1) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" " device NMOS $4 (S=VSS,G=A,D=OUT1) (L=0.25,W=1.5,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $5 (S=OUT2,G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $6 (S=VDD,G=A,D=OUT2) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $7 (S=OUT2,G=A,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $8 (S=OUT2,G=A,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $9 (S=OUT2,G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $10 (S=VDD,G=A,D=OUT2) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $11 (S=VSS,G=A,D=OUT2) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $12 (S=OUT2,G=A,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $5 (S='OUT2,OUT3',G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $6 (S=VDD,G=A,D='OUT2,OUT3') (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $7 (S='OUT2,OUT3',G=A,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $8 (S='OUT2,OUT3',G=A,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $9 (S='OUT2,OUT3',G=A,D=VDD) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $10 (S=VDD,G=A,D='OUT2,OUT3') (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $11 (S=VSS,G=A,D='OUT2,OUT3') (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $12 (S='OUT2,OUT3',G=A,D=VSS) (L=0.25,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ) } diff --git a/src/db/unit_tests/dbNetlistDeviceClassesTests.cc b/src/db/unit_tests/dbNetlistDeviceClassesTests.cc index 5f370c062..cee4aa3de 100644 --- a/src/db/unit_tests/dbNetlistDeviceClassesTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceClassesTests.cc @@ -2285,11 +2285,11 @@ TEST(50_SplitGatesSimple) EXPECT_EQ (nl2->to_string (), "circuit '' (A=n1,B=n2,G1=g1,G2=g2);\n" - " device '' m11 (S=n1,G=g1,D=sd1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m21 (S=sd1,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m11 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m21 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" // sd2 -> sd1 - " device '' m12 (S=n1,G=g1,D=sd1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m22 (S=sd1,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m12 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m22 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); @@ -2314,10 +2314,10 @@ TEST(50_SplitGatesSimple) EXPECT_EQ (nl2->to_string (), "circuit '' (A=n1,B=n2,G1=g1,G2=g2);\n" // sd1 -> sd2 - " device '' m11 (S=sd2,G=g1,D=n1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m21 (S=sd2,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m12 (S=n1,G=g1,D=sd2) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m22 (S=sd2,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m11 (S='sd1,sd2',G=g1,D=n1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m21 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m12 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m22 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); @@ -2389,10 +2389,10 @@ TEST(50_SplitGatesSimple) EXPECT_EQ (nl2->to_string (), "circuit '' (A=n1,B=n2,G1=g1,G2=g2);\n" // sd1 -> sd2 - " device '' m11 (S=sd2,G=g1,D=n1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m21 (S=sd2,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m12 (S=n1,G=g1,D=sd2) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m22 (S=sd2,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m11 (S='sd1,sd2',G=g1,D=n1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m21 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m12 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m22 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" " device '' mp1 (S=n1,G=g1,D=sd3) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" " device '' mp2 (S=sd3,G=g1,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" @@ -2516,11 +2516,11 @@ TEST(51_SplitGatesStrict) EXPECT_EQ (nl2->to_string (), "circuit '' (A=n1,B=n2,G1=g1,G2=g2);\n" - " device '' m11 (S=n1,G=g1,D=sd1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m21 (S=sd1,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m11 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m21 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" // sd2 -> sd1 - " device '' m12 (S=n1,G=g1,D=sd1) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m22 (S=sd1,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m12 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m22 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); @@ -2623,10 +2623,10 @@ TEST(51_SplitGatesStrict) EXPECT_EQ (nl2->to_string (), "circuit '' (A=n1,B=n2,G1=g1,G2=g2);\n" // sd1 -> sd2 - " device '' m11 (S=n1,G=g1,D=sd2) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m21 (S=sd2,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m12 (S=n1,G=g1,D=sd2) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m22 (S=sd2,G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m11 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m21 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m12 (S=n1,G=g1,D='sd1,sd2') (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m22 (S='sd1,sd2',G=g2,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" " device '' mp1 (S=n1,G=g1,D=sd3) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" " device '' mp2 (S=sd3,G=g1,D=n2) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" @@ -2725,11 +2725,11 @@ TEST(52_SplitGatesMOS4) EXPECT_EQ (nl2->to_string (), "circuit '' (A=n1,B=n2,G1=g1,G2=g2,VSS=vss);\n" - " device '' m11 (S=n1,G=g1,D=sd1,B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m21 (S=sd1,G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m11 (S=n1,G=g1,D='sd1,sd2',B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m21 (S='sd1,sd2',G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" // sd2 -> sd1 - " device '' m12 (S=n1,G=g1,D=sd1,B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m22 (S=sd1,G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m12 (S=n1,G=g1,D='sd1,sd2',B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m22 (S='sd1,sd2',G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); @@ -2754,10 +2754,10 @@ TEST(52_SplitGatesMOS4) EXPECT_EQ (nl2->to_string (), "circuit '' (A=n1,B=n2,G1=g1,G2=g2,VSS=vss);\n" // sd1 -> sd2 - " device '' m11 (S=sd2,G=g1,D=n1,B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m21 (S=sd2,G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m12 (S=n1,G=g1,D=sd2,B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" - " device '' m22 (S=sd2,G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m11 (S='sd1,sd2',G=g1,D=n1,B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m21 (S='sd1,sd2',G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m12 (S=n1,G=g1,D='sd1,sd2',B=vss) (L=6,W=1,AS=0,AD=0,PS=0,PD=0);\n" + " device '' m22 (S='sd1,sd2',G=g2,D=n2,B=vss) (L=10,W=1,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); diff --git a/src/db/unit_tests/dbNetlistTests.cc b/src/db/unit_tests/dbNetlistTests.cc index bc55997be..093f428b9 100644 --- a/src/db/unit_tests/dbNetlistTests.cc +++ b/src/db/unit_tests/dbNetlistTests.cc @@ -1647,11 +1647,11 @@ TEST(25_JoinNets) c->join_nets (c->net_by_name ("IN"), c->net_by_name ("OUT")); EXPECT_EQ (nl.to_string (), - "circuit INV2 (IN=IN,$2=$2,OUT=IN,$4=$4,$5=$5);\n" - " subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN);\n" - " subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN);\n" - " subcircuit PTRANS SC3 ($1=$5,$2=IN,$3=$2);\n" - " subcircuit NTRANS SC4 ($1=$4,$2=IN,$3=$2);\n" + "circuit INV2 ('IN,OUT'='IN,OUT',$2=$2,$3=$4,$4=$5);\n" + " subcircuit PTRANS SC1 ($1=$5,$2=$2,$3='IN,OUT');\n" + " subcircuit NTRANS SC2 ($1=$4,$2=$2,$3='IN,OUT');\n" + " subcircuit PTRANS SC3 ($1=$5,$2='IN,OUT',$3=$2);\n" + " subcircuit NTRANS SC4 ($1=$4,$2='IN,OUT',$3=$2);\n" "end;\n" "circuit PTRANS ($1=$1,$2=$2,$3=$3);\n" " device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" @@ -1690,11 +1690,11 @@ TEST(26_JoinNets) c->join_nets (c->net_by_name ("IN"), c->net_by_name ("OUT")); EXPECT_EQ (nl.to_string (), - "circuit INV2 (IN=IN,$2=$2,OUT=IN,$4=$4,$5=$5);\n" - " device PMOS $1 (S=$5,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device PMOS $2 (S=$5,G=$2,D=IN) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $3 (S=$4,G=IN,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" - " device NMOS $4 (S=$4,G=$2,D=IN) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + "circuit INV2 ('IN,OUT'='IN,OUT',$2=$2,$3=$4,$4=$5);\n" + " device PMOS $1 (S=$5,G='IN,OUT',D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device PMOS $2 (S=$5,G=$2,D='IN,OUT') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $3 (S=$4,G='IN,OUT',D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" + " device NMOS $4 (S=$4,G=$2,D='IN,OUT') (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0);\n" "end;\n" ); } From 1b4c81ac7b5154114cee2210500e050796b7bd24 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Sep 2023 18:16:19 +0200 Subject: [PATCH 22/41] Rework: unifying device extractor logger entries and LayoutToNetlist ones --- src/db/db/db.pro | 1 + src/db/db/dbLayoutToNetlist.cc | 68 +++----- src/db/db/dbLayoutToNetlist.h | 29 ++- src/db/db/dbLayoutToNetlistFormatDefs.cc | 6 +- src/db/db/dbLayoutToNetlistFormatDefs.h | 25 ++- src/db/db/dbLayoutToNetlistReader.cc | 64 ++++++- src/db/db/dbLayoutToNetlistReader.h | 3 + src/db/db/dbLayoutToNetlistWriter.cc | 97 ++++++---- src/db/db/dbLayoutToNetlistWriter.h | 2 + src/db/db/dbLayoutVsSchematicReader.cc | 2 + src/db/db/dbLayoutVsSchematicWriter.cc | 6 +- src/db/db/dbLog.cc | 155 ++++++++++++++++ src/db/db/dbLog.h | 133 +++++++++++++- src/db/db/dbNetlistDeviceExtractor.cc | 100 +++-------- src/db/db/dbNetlistDeviceExtractor.h | 165 ++---------------- src/db/db/gsiDeclDbEdges.cc | 2 +- src/db/db/gsiDeclDbLayoutToNetlist.cc | 5 +- src/db/db/gsiDeclDbLog.cc | 117 +++++++++++++ src/db/db/gsiDeclDbNetlistCompare.cc | 18 +- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 76 +------- .../dbNetlistDeviceExtractorTests.cc | 14 +- src/layui/layui/layNetlistLogModel.cc | 16 +- 22 files changed, 678 insertions(+), 426 deletions(-) create mode 100644 src/db/db/gsiDeclDbLog.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index ac7f6ec76..3b5aa2b4e 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -123,6 +123,7 @@ SOURCES = \ gsiDeclDbLayoutUtils.cc \ gsiDeclDbLayoutQuery.cc \ gsiDeclDbLibrary.cc \ + gsiDeclDbLog.cc \ gsiDeclDbManager.cc \ gsiDeclDbMatrix.cc \ gsiDeclDbMetaInfo.cc \ diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index c0b3d965b..d70d3c04b 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -242,13 +242,11 @@ void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, co ensure_netlist (); - extractor.clear_errors (); + extractor.clear_log_entries (); extractor.extract (dss (), m_layout_index, layers, *mp_netlist, m_net_clusters, m_device_scaling); // transfer errors to log entries - for (auto e = extractor.begin_errors (); e != extractor.end_errors (); ++e) { - m_log_entries.push_back (db::LogEntryData (e->is_warning () ? db::Warning : db::Error, e->to_string ())); - } + m_log_entries.insert (m_log_entries.end (), extractor.begin_log_entries (), extractor.end_log_entries ()); } void LayoutToNetlist::reset_extracted () @@ -390,14 +388,14 @@ void LayoutToNetlist::check_extraction_errors () int max_errors = 10; std::string errors; for (auto l = m_log_entries.begin (); l != m_log_entries.end (); ++l) { - if (l->severity >= db::Error) { + if (l->severity () >= db::Error) { errors += "\n"; if (++num_errors >= max_errors) { errors += "...\n"; errors += tl::sprintf (tl::to_string (tr ("(list shortened after %d errrors, see log for all errors)")), max_errors); break; } else { - errors += l->msg; + errors += l->to_string (); } } } @@ -467,16 +465,24 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a if (c.begin_refs () != c.end_refs ()) { if (a.begin_pins () == a.end_pins ()) { - error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected to outside")), a.expanded_name ())); + error.set_cell_name (c.name ()); + log_entry (error); } if (b.begin_pins () == b.end_pins ()) { - error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected to outside")), a.expanded_name (), c.name ())); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected to outside")), a.expanded_name ())); + error.set_cell_name (c.name ()); + log_entry (error); } } else { if (a.expanded_name () == b.expanded_name ()) { - warn (tl::sprintf (tl::to_string (tr ("Must-connect nets %s from circuit %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name (), c.name ())); + db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name ())); + warn.set_cell_name (c.name ()); + log_entry (warn); } else { - warn (tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s from circuit %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name (), b.expanded_name (), c.name ())); + db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name (), b.expanded_name ())); + warn.set_cell_name (c.name ()); + log_entry (warn); } } @@ -487,16 +493,24 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a const db::Net *net_a = sc.net_for_pin (a.begin_pins ()->pin_id ()); const db::Net *net_b = sc.net_for_pin (b.begin_pins ()->pin_id ()); if (net_a == 0) { - error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected at all %s")), a.expanded_name (), c.name (), subcircuit_to_string (sc))); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected at all %s")), a.expanded_name (), subcircuit_to_string (sc))); + error.set_cell_name (c.name ()); + log_entry (error); } if (net_b == 0) { - error (tl::sprintf (tl::to_string (tr ("Must-connect net %s from circuit %s is not connected at all %s")), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected at all %s")), b.expanded_name (), subcircuit_to_string (sc))); + error.set_cell_name (c.name ()); + log_entry (error); } if (net_a && net_b && net_a != net_b) { if (net_a->expanded_name () == net_b->expanded_name ()) { - error (tl::sprintf (tl::to_string (tr ("Must-connect nets %s from circuit %s are not connected %s")), a.expanded_name (), c.name (), subcircuit_to_string (sc))); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect nets %s are not connected %s")), a.expanded_name (), subcircuit_to_string (sc))); + error.set_cell_name (c.name ()); + log_entry (error); } else { - error (tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s from circuit %s are not connected %s")), a.expanded_name (), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s are not connected %s")), a.expanded_name (), b.expanded_name (), subcircuit_to_string (sc))); + error.set_cell_name (c.name ()); + log_entry (error); } } } @@ -541,32 +555,6 @@ void LayoutToNetlist::do_join_nets () } } -void LayoutToNetlist::error (const std::string &msg) -{ - if (m_log_entries.empty () || m_log_entries.back ().severity != db::Error || m_log_entries.back ().msg != msg) { - tl::error << msg; - m_log_entries.push_back (db::LogEntryData (db::Error, msg)); - } -} - -void LayoutToNetlist::warn (const std::string &msg) -{ - if (m_log_entries.empty () || m_log_entries.back ().severity != db::Warning || m_log_entries.back ().msg != msg) { - tl::warn << msg; - m_log_entries.push_back (db::LogEntryData (db::Warning, msg)); - } -} - -void LayoutToNetlist::info (const std::string &msg) -{ - if (m_log_entries.empty () || m_log_entries.back ().severity != db::Info || m_log_entries.back ().msg != msg) { - if (tl::verbosity () >= 10) { - tl::info << msg; - } - m_log_entries.push_back (db::LogEntryData (db::Info, msg)); - } -} - void LayoutToNetlist::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const { if (! no_self) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index eaa149907..be1bb68c0 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -200,6 +200,22 @@ public: return m_log_entries; } + /** + * @brief Iterator for the log entries (begin) + */ + log_entries_type::const_iterator begin_log_entries () const + { + return m_log_entries.begin (); + } + + /** + * @brief Iterator for the log entries (end) + */ + log_entries_type::const_iterator end_log_entries () const + { + return m_log_entries.end (); + } + /** * @brief Clears the log entries */ @@ -213,7 +229,9 @@ public: */ void log_entry (const db::LogEntryData &log_entry) { - m_log_entries.push_back (log_entry); + if (m_log_entries.empty () || m_log_entries.back () != log_entry) { + m_log_entries.push_back (log_entry); + } } /** @@ -406,7 +424,8 @@ public: * boolean operations for deriving layers. Other operations are applicable as long as they are * capable of delivering hierarchical layers. * - * If errors occur, the device extractor will contain theses errors. + * If errors occur, the device extractor will contain theses errors. They are also transferred + * to the LayoutToNetlist object. */ void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers); @@ -584,6 +603,9 @@ public: */ void extract_netlist (); + /** + * @brief Throws an exception if the extractor contains errors + */ void check_extraction_errors (); /** @@ -997,9 +1019,6 @@ private: void join_nets_from_pattern (db::Circuit &c, const tl::GlobPattern &p); void join_nets_from_pattern (db::Circuit &c, const std::set &p); void check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b); - void error (const std::string &msg); - void warn (const std::string &msg); - void info (const std::string &msg); // implementation of NetlistManipulationCallbacks virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index c317ac857..3c54a06d8 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -61,6 +61,8 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::info_severity_key ("info"); DB_PUBLIC std::string LongKeys::warning_severity_key ("warning"); DB_PUBLIC std::string LongKeys::error_severity_key ("error"); + DB_PUBLIC std::string LongKeys::cell_key ("cell"); + DB_PUBLIC std::string LongKeys::cat_key ("cat"); // A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y DB_PUBLIC std::string ShortKeys::version_key ("V"); @@ -89,11 +91,13 @@ namespace l2n_std_format DB_PUBLIC std::string ShortKeys::pin_key ("P"); DB_PUBLIC std::string ShortKeys::message_key ("H"); - // I, W, E + // I, W, E, C, X DB_PUBLIC std::string ShortKeys::info_severity_key ("I"); DB_PUBLIC std::string ShortKeys::warning_severity_key ("W"); DB_PUBLIC std::string ShortKeys::error_severity_key ("E"); + DB_PUBLIC std::string ShortKeys::cell_key ("C"); + DB_PUBLIC std::string ShortKeys::cat_key ("X"); } } diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index ea09112ff..8f5ec1d7c 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -144,7 +144,7 @@ namespace db * coordinates are bottom/left and top/right * * [text]: - * text( [text] [coord]) - defines a rectangle [short key: J] + * text( [coord]) - defines a label [short key: J] * * [coord]: * - absolute coordinates @@ -182,15 +182,24 @@ namespace db * scale() - magnification (default is 1) [short key: S] * * [message-entry]: - * message([severity] [message|any]*) - message entry [short key: H] + * message([severity] [message|message-geometry|message-cell|message-category|any]*) - message entry [short key: H] * * [message]: - * description() - error description [short key: B] + * description() - message text [short key: B] + * + * [message-geometry]: + * polygon() - message geometry polygon in string-serialized form [short key: Q] + * + * [message-cell]: + * cell() - message cell [short key: C] + * + * [message-category]: + * cat( ?) - message category with optional description [short key: X] * * [severity]: - * info | - [short key: I] - * warning | - [short key: W] - * error - [short key: E] + * info | - [short key: I] + * warning | - [short key: W] + * error - [short key: E] * * [any]: * * | @@ -237,6 +246,8 @@ namespace l2n_std_format static std::string info_severity_key; static std::string warning_severity_key; static std::string error_severity_key; + static std::string cell_key; + static std::string cat_key; }; struct DB_PUBLIC LongKeys @@ -274,6 +285,8 @@ namespace l2n_std_format static std::string info_severity_key; static std::string warning_severity_key; static std::string error_severity_key; + static std::string cell_key; + static std::string cat_key; }; template struct DB_PUBLIC keys; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 5d44b714c..365e9d828 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -213,22 +213,78 @@ bool LayoutToNetlistStandardReader::read_severity (db::Severity &severity) } } +bool LayoutToNetlistStandardReader::read_message_cell (std::string &cell_name) +{ + if (test (skeys::cell_key) || test (lkeys::cell_key)) { + Brace br (this); + read_word_or_quoted (cell_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)) { + Brace br (this); + std::string s; + read_word_or_quoted (s); + tl::Extractor ex (s.c_str ()); + ex.read (polygon); + br.done (); + return true; + } else { + return false; + } +} + +bool LayoutToNetlistStandardReader::read_message_cat (std::string &category_name, std::string &category_description) +{ + if (test (skeys::cat_key) || test (lkeys::cat_key)) { + Brace br (this); + read_word_or_quoted (category_name); + if (br) { + read_word_or_quoted (category_description); + } + br.done (); + return true; + } else { + return false; + } +} + void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data) { - data.severity = db::NoSeverity; - data.msg.clear (); + Severity severity (db::NoSeverity); + std::string msg, cell_name, category_name, category_description; + db::DPolygon geometry; Brace br (this); while (br) { - if (read_severity (data.severity)) { + if (read_severity (severity)) { // continue - } else if (read_message (data.msg)) { + } else if (read_message (msg)) { + // continue + } else if (read_message_cell (cell_name)) { + // continue + } else if (read_message_cat (category_name, category_description)) { + // continue + } else if (read_message_geometry (geometry)) { // continue } else { skip_element (); } } br.done (); + + data.set_severity (severity); + data.set_message (msg); + data.set_cell_name (cell_name); + data.set_category_description (category_description); + data.set_category_name (category_name); + data.set_geometry (geometry); } void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 367e5c4e6..fcb8eb245 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -163,6 +163,9 @@ private: void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); db::Point read_point (); void read_message_entry (db::LogEntryData &data); + bool read_message_cell (std::string &cell_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 86e254a2f..3b2c2754c 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -130,6 +130,41 @@ TokenizedOutput &TokenizedOutput::operator<< (const std::string &s) // ------------------------------------------------------------------------------------------- +static void write_point (TokenizedOutput &out, const db::Point &pt, db::Point &ref, bool relative) +{ + if (relative) { + + TokenizedOutput (out, std::string (), true) << tl::to_string (pt.x () - ref.x ()) << tl::to_string (pt.y () - ref.y ()); + + } else { + + if (pt.x () == 0 || pt.x () != ref.x ()) { + out << tl::to_string (pt.x ()); + } else { + out << "*"; + } + + if (pt.y () == 0 || pt.y () != ref.y ()) { + out << tl::to_string (pt.y ()); + } else { + out << "*"; + } + + } + + ref = pt; +} + +template +static void write_points (TokenizedOutput &out, const T &poly, const Tr &tr, db::Point &ref, bool relative) +{ + for (typename T::polygon_contour_iterator c = poly.begin_hull (); c != poly.end_hull (); ++c) { + write_point (out, tr * *c, ref, relative); + } +} + +// ------------------------------------------------------------------------------------------- + namespace l2n_std_format { @@ -166,6 +201,30 @@ std::string std_writer_impl::severity_to_s (const db::Severity severity) } } +template +void std_writer_impl::write_log_entry (TokenizedOutput &stream, const LogEntryData &le) +{ + stream << severity_to_s (le.severity ()); + stream << message_to_s (le.to_string ()); + + if (! le.cell_name ().empty ()) { + TokenizedOutput (stream, Keys::cell_key, true) << tl::to_word_or_quoted_string (le.cell_name ()); + } + + if (! le.category_name ().empty ()) { + TokenizedOutput o (stream, Keys::cat_key, true); + o << tl::to_word_or_quoted_string (le.category_name ()); + if (! le.category_description ().empty ()) { + o << tl::to_word_or_quoted_string (le.category_description ()); + } + } + + if (le.geometry () != db::DPolygon ()) { + TokenizedOutput o (stream, Keys::polygon_key); + o << tl::to_word_or_quoted_string (le.geometry ().to_string ()); + } +} + static std::string name_for_layer (const db::LayoutToNetlist *l2n, unsigned int l) { std::string n = l2n->name (l); @@ -346,8 +405,9 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma if (! Keys::is_short ()) { stream << endl << "# Log entries" << endl; } - for (auto l = mp_l2n->log_entries ().begin (); l != mp_l2n->log_entries ().end (); ++l) { - TokenizedOutput (stream, Keys::message_key) << severity_to_s (l->severity) << message_to_s (l->msg); + for (auto l = mp_l2n->begin_log_entries (); l != mp_l2n->end_log_entries (); ++l) { + TokenizedOutput out (stream, Keys::message_key); + this->write_log_entry (out, *l); m_progress.set (mp_stream->pos ()); } } @@ -395,39 +455,6 @@ void std_writer_impl::write (bool nested, TokenizedOutput &stream, std::ma } } -static void write_point (TokenizedOutput &out, const db::Point &pt, db::Point &ref, bool relative) -{ - if (relative) { - - TokenizedOutput (out, std::string (), true) << tl::to_string (pt.x () - ref.x ()) << tl::to_string (pt.y () - ref.y ()); - - } else { - - if (pt.x () == 0 || pt.x () != ref.x ()) { - out << tl::to_string (pt.x ()); - } else { - out << "*"; - } - - if (pt.y () == 0 || pt.y () != ref.y ()) { - out << tl::to_string (pt.y ()); - } else { - out << "*"; - } - - } - - ref = pt; -} - -template -static void write_points (TokenizedOutput &out, const T &poly, const Tr &tr, db::Point &ref, bool relative) -{ - for (typename T::polygon_contour_iterator c = poly.begin_hull (); c != poly.end_hull (); ++c) { - write_point (out, tr * *c, ref, relative); - } -} - template void std_writer_impl::write (TokenizedOutput &stream, const db::Circuit &circuit, std::map > *net2id_per_circuit) { diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index 25c175f9f..26434e06b 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -44,6 +44,7 @@ class Net; class Netlist; class LayoutToNetlist; class NetShape; +class LogEntryData; /** * @brief A helper class to produce token/list lines @@ -95,6 +96,7 @@ protected: std::string severity_to_s (const db::Severity severity); std::string message_to_s (const std::string &msg); + void write_log_entry (TokenizedOutput &stream, const LogEntryData &log_entry); private: tl::OutputStream *mp_stream; diff --git a/src/db/db/dbLayoutVsSchematicReader.cc b/src/db/db/dbLayoutVsSchematicReader.cc index 1101d1d56..f486a19eb 100644 --- a/src/db/db/dbLayoutVsSchematicReader.cc +++ b/src/db/db/dbLayoutVsSchematicReader.cc @@ -155,6 +155,8 @@ void LayoutVsSchematicStandardReader::read_log_entry (db::NetlistCrossReference } br.done (); + // NOTE: this API does not use the full feature set of db::LogEntryData, so + // we do not use this object here. xref->log_entry (severity, msg); } diff --git a/src/db/db/dbLayoutVsSchematicWriter.cc b/src/db/db/dbLayoutVsSchematicWriter.cc index 9060c5a99..f51bd291f 100644 --- a/src/db/db/dbLayoutVsSchematicWriter.cc +++ b/src/db/db/dbLayoutVsSchematicWriter.cc @@ -203,7 +203,8 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro o << endl; for (auto l = xref->other_log_entries ().begin (); l != xref->other_log_entries ().end (); ++l) { - TokenizedOutput (o, Keys::log_entry_key, true) << this->severity_to_s (l->severity) << this->message_to_s (l->msg); + TokenizedOutput to (o, Keys::log_entry_key, true); + this->write_log_entry (to, *l); o << endl; } @@ -224,7 +225,8 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro o << endl; for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { - TokenizedOutput (o, Keys::log_entry_key, true) << this->severity_to_s (l->severity) << this->message_to_s (l->msg); + TokenizedOutput to (o, Keys::log_entry_key, true); + this->write_log_entry (to, *l); o << endl; } diff --git a/src/db/db/dbLog.cc b/src/db/db/dbLog.cc index b777f6c94..3d423a50b 100644 --- a/src/db/db/dbLog.cc +++ b/src/db/db/dbLog.cc @@ -22,10 +22,165 @@ #include "dbCommon.h" #include "dbLog.h" +#include "tlThreads.h" namespace db { +// ------------------------------------------------------------------ +// A string repository for keeping the memory footprint low for +// the log entries + +class LogEntryStringRepository +{ +public: + LogEntryStringRepository () + { + // .. nothing yet .. + } + + size_t id_for_string (const std::string &s) + { + if (s.empty ()) { + return 0; + } + + tl::MutexLocker locker (&m_lock); + + auto m = m_id_to_string.find (s); + if (m == m_id_to_string.end ()) { + m_strings.push_back (s); + size_t id = m_strings.size (); + m_id_to_string.insert (std::make_pair (s, id)); + return id; + } else { + return m->second; + } + } + + const std::string &string_for_id (size_t id) const + { + if (id == 0) { + static const std::string empty; + return empty; + } + + tl::MutexLocker locker (&m_lock); + return m_strings [id - 1]; + } + +private: + mutable tl::Mutex m_lock; + std::vector m_strings; + std::map m_id_to_string; +}; + +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) +{ // .. 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) +{ + // .. 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) +{ + // .. nothing yet .. +} + +bool +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_geometry == other.m_geometry && + m_category_name == other.m_category_name && + m_category_description == other.m_category_description; +} + +const std::string & +LogEntryData::category_name () const +{ + return s_strings.string_for_id (m_category_name); +} + +void +LogEntryData::set_category_name (const std::string &s) +{ + m_category_name = s_strings.id_for_string (s); +} + +const std::string & +LogEntryData::category_description () const +{ + return s_strings.string_for_id (m_category_description); +} + +void +LogEntryData::set_category_description (const std::string &s) +{ + m_category_description = s_strings.id_for_string (s); +} + +const std::string & +LogEntryData::message () const +{ + return s_strings.string_for_id (m_message); +} + +void +LogEntryData::set_message (const std::string &n) +{ + m_message = s_strings.id_for_string (n); +} + +const std::string & +LogEntryData::cell_name () const +{ + return s_strings.string_for_id (m_cell_name); +} + +void +LogEntryData::set_cell_name (const std::string &n) +{ + m_cell_name = s_strings.id_for_string (n); +} + +std::string +LogEntryData::to_string () const +{ + std::string res; + + if (m_category_name != 0) { + if (m_category_description != 0) { + res += "[" + category_name () + "] "; + } else { + res += "[" + category_description () + "] "; + } + } + + res += message (); + + if (m_cell_name != 0) { + res += tl::to_string (tr (", in cell: ")) + cell_name (); + } + + if (! m_geometry.box ().empty ()) { + res += tl::to_string (tr (", shape: ")) + m_geometry.to_string (); + } + + return res; +} } diff --git a/src/db/db/dbLog.h b/src/db/db/dbLog.h index d9aea2650..985558b6d 100644 --- a/src/db/db/dbLog.h +++ b/src/db/db/dbLog.h @@ -24,6 +24,7 @@ #define _HDR_dbLog #include "dbCommon.h" +#include "dbPolygon.h" #include @@ -41,17 +42,137 @@ enum Severity { }; /** - * @brief A class representing one log entry + * @brief A generic log entry + * + * This object can be used for collecting errors or warnings. + * It features a message and a severity level and optionally + * a polygon (for geometry marker), a category name and a category description. */ -struct LogEntryData +class DB_PUBLIC LogEntryData { - LogEntryData (Severity s, const std::string &m) : severity (s), msg (m) { } - LogEntryData () : severity (NoSeverity) { } +public: + typedef size_t string_id_type; - Severity severity; - std::string msg; + /** + * @brief Creates a log entry + */ + LogEntryData (); + + /** + * @brief Creates a log entry with the severity and a message + */ + LogEntryData (Severity s, const std::string &msg); + + /** + * @brief Creates an error with the severity, a cell name and a message + */ + LogEntryData (Severity s, const std::string &cell_name, const std::string &msg); + + /** + * @brief Equality + */ + bool operator== (const LogEntryData &other) const; + + /** + * @brief Inequality + */ + bool operator!= (const LogEntryData &other) const + { + return ! operator== (other); + } + + /** + * @brief Sets the severity + */ + void set_severity (Severity severity) + { + m_severity = severity; + } + + /** + * @brief Gets the severity + */ + Severity severity () const + { + return m_severity; + } + + /** + * @brief The category name of the error + * Specifying the category name is optional. If a category is given, it will be used for + * the report. + */ + const std::string &category_name () const; + + /** + * @brief Sets the category name + */ + void set_category_name (const std::string &s); + + /** + * @brief The category description of the error + * Specifying the category description is optional. If a category is given, this attribute will + * be used for the category description. + */ + const std::string &category_description () const; + + /** + * @brief Sets the category description + */ + void set_category_description (const std::string &s); + + /** + * @brief Gets the geometry for this error + * Not all errors may specify a geometry. In this case, the polygon is empty. + */ + const db::DPolygon &geometry () const + { + return m_geometry; + } + + /** + * @brief Sets the geometry + */ + void set_geometry (const db::DPolygon &g) + { + m_geometry = g; + } + + /** + * @brief Gets the message for this error + */ + const std::string &message () const; + + /** + * @brief Sets the message + */ + void set_message (const std::string &n); + + /** + * @brief Gets the cell name the error occurred in + */ + const std::string &cell_name () const; + + /** + * @brief Sets the cell name + */ + void set_cell_name (const std::string &n); + + /** + * @brief Formats this message for printing + */ + std::string to_string () const; + +private: + Severity m_severity; + string_id_type m_cell_name; + string_id_type m_message; + db::DPolygon m_geometry; + string_id_type m_category_name, m_category_description; }; + + } #endif diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 04b39e4ff..581861ac7 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -32,46 +32,6 @@ namespace db { -// ---------------------------------------------------------------------------------------- -// NetlistDeviceExtractorError implementation - -NetlistDeviceExtractorError::NetlistDeviceExtractorError () - : m_warning (false) -{ - // .. nothing yet .. -} - -NetlistDeviceExtractorError::NetlistDeviceExtractorError (const std::string &cell_name, const std::string &msg) - : m_warning (false), m_cell_name (cell_name), m_message (msg) -{ - // .. nothing yet .. -} - -std::string NetlistDeviceExtractorError::to_string () const -{ - std::string res; - - if (! m_category_name.empty ()) { - if (m_category_description.empty ()) { - res += "[" + m_category_name + "] "; - } else { - res += "[" + m_category_description + "] "; - } - } - - res += m_message; - - if (! m_cell_name.empty ()) { - res += tl::to_string (tr (", in cell: ")) + m_cell_name; - } - - if (! m_geometry.box ().empty ()) { - res += tl::to_string (tr (", shape: ")) + m_geometry.to_string (); - } - - return res; -} - // ---------------------------------------------------------------------------------------- // NetlistDeviceExtractor implementation @@ -587,89 +547,85 @@ std::string NetlistDeviceExtractor::cell_name () const void NetlistDeviceExtractor::error (const std::string &msg) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); + m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); if (tl::verbosity () >= 20) { - tl::error << m_errors.back ().to_string (); + tl::error << m_log_entries.back ().to_string (); } } void NetlistDeviceExtractor::error (const std::string &msg, const db::DPolygon &poly) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); - m_errors.back ().set_geometry (poly); + m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); + m_log_entries.back ().set_geometry (poly); if (tl::verbosity () >= 20) { - tl::error << m_errors.back ().to_string (); + tl::error << m_log_entries.back ().to_string (); } } void NetlistDeviceExtractor::error (const std::string &category_name, const std::string &category_description, const std::string &msg) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); - m_errors.back ().set_category_name (category_name); - m_errors.back ().set_category_description (category_description); + m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); + m_log_entries.back ().set_category_name (category_name); + m_log_entries.back ().set_category_description (category_description); if (tl::verbosity () >= 20) { - tl::error << m_errors.back ().to_string (); + tl::error << m_log_entries.back ().to_string (); } } void NetlistDeviceExtractor::error (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::DPolygon &poly) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); - m_errors.back ().set_category_name (category_name); - m_errors.back ().set_category_description (category_description); - m_errors.back ().set_geometry (poly); + m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); + m_log_entries.back ().set_category_name (category_name); + m_log_entries.back ().set_category_description (category_description); + m_log_entries.back ().set_geometry (poly); if (tl::verbosity () >= 20) { - tl::error << m_errors.back ().to_string (); + tl::error << m_log_entries.back ().to_string (); } } void NetlistDeviceExtractor::warn (const std::string &msg) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); - m_errors.back ().set_warning (true); + m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); if (tl::verbosity () >= 20) { - tl::warn << m_errors.back ().to_string (); + tl::warn << m_log_entries.back ().to_string (); } } void NetlistDeviceExtractor::warn (const std::string &msg, const db::DPolygon &poly) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); - m_errors.back ().set_geometry (poly); - m_errors.back ().set_warning (true); + m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); + m_log_entries.back ().set_geometry (poly); if (tl::verbosity () >= 20) { - tl::warn << m_errors.back ().to_string (); + tl::warn << m_log_entries.back ().to_string (); } } void NetlistDeviceExtractor::warn (const std::string &category_name, const std::string &category_description, const std::string &msg) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); - m_errors.back ().set_category_name (category_name); - m_errors.back ().set_category_description (category_description); - m_errors.back ().set_warning (true); + m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); + m_log_entries.back ().set_category_name (category_name); + m_log_entries.back ().set_category_description (category_description); if (tl::verbosity () >= 20) { - tl::warn << m_errors.back ().to_string (); + tl::warn << m_log_entries.back ().to_string (); } } void NetlistDeviceExtractor::warn (const std::string &category_name, const std::string &category_description, const std::string &msg, const db::DPolygon &poly) { - m_errors.push_back (db::NetlistDeviceExtractorError (cell_name (), msg)); - m_errors.back ().set_category_name (category_name); - m_errors.back ().set_category_description (category_description); - m_errors.back ().set_geometry (poly); - m_errors.back ().set_warning (true); + m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); + m_log_entries.back ().set_category_name (category_name); + m_log_entries.back ().set_category_description (category_description); + m_log_entries.back ().set_geometry (poly); if (tl::verbosity () >= 20) { - tl::warn << m_errors.back ().to_string (); + tl::warn << m_log_entries.back ().to_string (); } } diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index b3b6bbed8..d12369f7d 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -30,144 +30,13 @@ #include "dbDeepShapeStore.h" #include "dbRegion.h" #include "dbNetShape.h" +#include "dbLog.h" #include "gsiObject.h" namespace db { -/** - * @brief An error object for the netlist device extractor - * - * The device extractor will keep errors using objects of this kind. - */ -class DB_PUBLIC NetlistDeviceExtractorError -{ -public: - /** - * @brief Creates an error - */ - NetlistDeviceExtractorError (); - - /** - * @brief Creates an error with a cell name and a message (the minimum information) - */ - NetlistDeviceExtractorError (const std::string &cell_name, const std::string &msg); - - /** - * @brief Sets a value indicating whether the error is only a warning - */ - void set_warning (bool f) - { - m_warning = f; - } - - /** - * @brief Gets a value indicating whether the error is only a warning - */ - bool is_warning () const - { - return m_warning; - } - - /** - * @brief The category name of the error - * Specifying the category name is optional. If a category is given, it will be used for - * the report. - */ - const std::string &category_name () const - { - return m_category_name; - } - - /** - * @brief Sets the category name - */ - void set_category_name (const std::string &s) - { - m_category_name = s; - } - - /** - * @brief The category description of the error - * Specifying the category description is optional. If a category is given, this attribute will - * be used for the category description. - */ - const std::string &category_description () const - { - return m_category_description; - } - - /** - * @brief Sets the category description - */ - void set_category_description (const std::string &s) - { - m_category_description = s; - } - - /** - * @brief Gets the geometry for this error - * Not all errors may specify a geometry. In this case, the polygon is empty. - */ - const db::DPolygon &geometry () const - { - return m_geometry; - } - - /** - * @brief Sets the geometry - */ - void set_geometry (const db::DPolygon &g) - { - m_geometry = g; - } - - /** - * @brief Gets the message for this error - */ - const std::string &message () const - { - return m_message; - } - - /** - * @brief Sets the message - */ - void set_message (const std::string &n) - { - m_message = n; - } - - /** - * @brief Gets the cell name the error occurred in - */ - const std::string &cell_name () const - { - return m_cell_name; - } - - /** - * @brief Sets the cell name - */ - void set_cell_name (const std::string &n) - { - m_cell_name = n; - } - - /** - * @brief Formats this message for printing - */ - std::string to_string () const; - -private: - bool m_warning; - std::string m_cell_name; - std::string m_message; - db::DPolygon m_geometry; - std::string m_category_name, m_category_description; -}; - /** * @brief Specifies a single layer from the device extractor */ @@ -218,8 +87,8 @@ class DB_PUBLIC NetlistDeviceExtractor : public gsi::ObjectBase, public tl::Object { public: - typedef std::list error_list; - typedef error_list::const_iterator error_iterator; + typedef std::list log_entry_list; + typedef log_entry_list::const_iterator log_entry_iterator; typedef std::vector layer_definitions; typedef layer_definitions::const_iterator layer_definitions_iterator; typedef std::map input_layers; @@ -283,35 +152,27 @@ public: void extract (DeepShapeStore &dss, unsigned int layout_index, const input_layers &layers, Netlist &netlist, hier_clusters_type &clusters, double device_scaling = 1.0); /** - * @brief Clears the errors + * @brief Clears the log entries */ - void clear_errors () + void clear_log_entries () { - m_errors.clear (); + m_log_entries.clear (); } /** - * @brief Gets the error iterator, begin + * @brief Gets the log entry iterator, begin */ - error_iterator begin_errors () + log_entry_iterator begin_log_entries () { - return m_errors.begin (); + return m_log_entries.begin (); } /** - * @brief Gets the error iterator, end + * @brief Gets the log entry iterator, end */ - error_iterator end_errors () + log_entry_iterator end_log_entries () { - return m_errors.end (); - } - - /** - * @brief Returns true, if there are errors - */ - bool has_errors () const - { - return ! m_errors.empty (); + return m_log_entries.end (); } /** @@ -617,7 +478,7 @@ private: std::string m_name; layer_definitions m_layer_definitions; std::vector m_layers; - error_list m_errors; + log_entry_list m_log_entries; std::map > m_new_devices; std::map > m_device_cells; diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index 2994880b9..f1abfe620 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -1839,7 +1839,7 @@ gsi::EnumIn decl_EdgesE gsi::enum_const ("OrthoDiagonalEdges", db::SpecialEdgeOrientationFilter::OrthoDiagonal, "@brief Diagonal or orthogonal edges are selected (0, 90, -45 and 45 degree)\n" ), - "@brief This enum specifies the the edge type for edge angle filters.\n" + "@brief This enum specifies the edge type for edge angle filters.\n" "\n" "This enum was introduced in version 0.28.\n" ); diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index dfaa7046a..59915bdfe 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -712,7 +712,10 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@brief Reads the extracted netlist from the file.\n" "This method employs the native format of KLayout.\n" ) + - // @@@ Add API for logs + gsi::iterator ("each_log_entry|#each_error", &db::LayoutToNetlist::begin_log_entries, &db::LayoutToNetlist::end_log_entries, + "@brief Iterates over all log entries collected during device and netlist extraction.\n" + "This method has been introduced in version 0.28.13." + ) + gsi::method_ext ("antenna_check", &antenna_check, gsi::arg ("gate"), gsi::arg ("metal"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"), "@brief Runs an antenna check on the extracted clusters\n" "\n" diff --git a/src/db/db/gsiDeclDbLog.cc b/src/db/db/gsiDeclDbLog.cc new file mode 100644 index 000000000..621c8e848 --- /dev/null +++ b/src/db/db/gsiDeclDbLog.cc @@ -0,0 +1,117 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "gsiDecl.h" +#include "gsiEnums.h" +#include "dbLog.h" + +namespace gsi +{ + +Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData", + gsi::method ("severity", &db::LogEntryData::severity, + "@brief Gets the severity attribute.\n" + ) + + gsi::method ("severity=", &db::LogEntryData::set_severity, gsi::arg ("severity"), + "@brief Sets the severity attribute.\n" + ) + + gsi::method ("message", &db::LogEntryData::message, + "@brief Gets the message text.\n" + ) + + gsi::method ("message=", &db::LogEntryData::set_message, gsi::arg ("message"), + "@brief Sets the message text.\n" + ) + + gsi::method ("cell_name", &db::LogEntryData::cell_name, + "@brief Gets the cell name.\n" + "See \\cell_name= for details about this attribute." + ) + + gsi::method ("cell_name=", &db::LogEntryData::set_cell_name, gsi::arg ("cell_name"), + "@brief Sets the cell name.\n" + "The cell name is the name of the layout cell which was treated. This is " + "also the name of the circuit the device should have appeared in (it may be dropped because of this error). " + "If netlist hierarchy manipulation happens however, the circuit may not exist " + "any longer or may be renamed." + ) + + gsi::method ("geometry", &db::LogEntryData::geometry, + "@brief Gets the geometry.\n" + "See \\geometry= for more details." + ) + + gsi::method ("geometry=", &db::LogEntryData::set_geometry, gsi::arg ("polygon"), + "@brief Sets the geometry.\n" + "The geometry is optional. If given, a marker will be shown when selecting this error." + ) + + gsi::method ("category_name", &db::LogEntryData::category_name, + "@brief Gets the category name.\n" + "See \\category_name= for more details." + ) + + gsi::method ("category_name=", &db::LogEntryData::set_category_name, gsi::arg ("name"), + "@brief Sets the category name.\n" + "The category name is optional. If given, it specifies a formal category name. Errors with the same " + "category name are shown in that category. If in addition a category description is specified " + "(see \\category_description), this description will be displayed as the title of." + ) + + gsi::method ("category_description", &db::LogEntryData::category_description, + "@brief Gets the category description.\n" + "See \\category_name= for details about categories." + ) + + gsi::method ("category_description=", &db::LogEntryData::set_category_description, gsi::arg ("description"), + "@brief Sets the category description.\n" + "See \\category_name= for details about categories." + ) + + gsi::method ("to_s", &db::LogEntryData::to_string, + "@brief Gets the string representation of this error or warning.\n" + "This method has been introduced in version 0.28.13." + ), + "@brief A generic log entry\n" + "This class is used for example by the device extractor (see \\NetlistDeviceExtractor) to keep errors or warnings " + "that occurred during extraction of the devices.\n" + "\n" + "Other classes also make use of this object to store errors, warnings or information. " + "The log entry object features a severity (warning, error, info), a message, an optional " + "category name and description (good for filtering if needed) and an optional \\DPolygon object " + "for indicating some location or error marker." + "\n" + "The original class used to be \"NetlistDeviceExtractorError\" which had been introduced in version 0.26. " + "It was generalized and renamed in version 0.28.13 as it was basically not useful as a seperate class." +); + +gsi::Enum decl_Severity ("db", "Severity", + gsi::enum_const ("NoSeverity", db::NoSeverity, + "@brief Specifies no particular severity (default)\n" + ) + + gsi::enum_const ("Warning", db::Warning, + "@brief Specifies warning severity (log with high priority, but do not stop)\n" + ) + + gsi::enum_const ("Error", db::Error, + "@brief Specifies error severity (preferred action is stop)\n" + ) + + gsi::enum_const ("Info", db::Info, + "@brief Specifies info severity (print if requested, otherwise silent)\n" + ), + "@brief This enum specifies the severity level for log entries.\n" + "\n" + "This enum was introduced in version 0.28.13.\n" +); + +gsi::ClassExt inject_SeverityEnum_into_LogEntryData (decl_Severity.defs ()); + +} diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc index ed61e975a..f138cdfb8 100644 --- a/src/db/db/gsiDeclDbNetlistCompare.cc +++ b/src/db/db/gsiDeclDbNetlistCompare.cc @@ -657,21 +657,7 @@ Class decl_dbNetlistComparer ("db", "NetlistComparer", "This class has been introduced in version 0.26." ); -gsi::EnumIn decl_CompareLoggerSeverity ("db", "Severity", - gsi::enum_const ("NoSeverity", db::NoSeverity, - "@brief Unspecific severity\n" - ) + - gsi::enum_const ("Info", db::Info, - "@brief Information only\n" - ) + - gsi::enum_const ("Warning", db::Warning, - "@brief A warning\n" - ) + - gsi::enum_const ("Error", db::Error, - "@brief An error\n" - ), - "@brief This class represents the log severity level for \\GenericNetlistCompareLogger#log_entry.\n" - "This enum has been introduced in version 0.28." -); +extern gsi::Enum decl_Severity; +gsi::ClassExt inject_SeverityEnum_into_GenericNetlistCompareLogger (decl_Severity.defs ()); } diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 05b67a8e3..c7a214dca 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -156,76 +156,6 @@ Class decl_dbDeviceClassFactoryBase ("db", "DeviceClassF "This class has been introduced in version 0.27.3.\n" ); -Class decl_dbNetlistDeviceExtractorError ("db", "NetlistDeviceExtractorError", - gsi::method ("is_warning?|is_warning", &db::NetlistDeviceExtractorError::is_warning, - "@brief Gets a value indicating whether the error is a warning.\n" - "This predicate has been introduced in version 0.28.13." - ) + - gsi::method ("warning=", &db::NetlistDeviceExtractorError::set_warning, gsi::arg ("flag"), - "@brief Sets a value indicating whether the error is a warning.\n" - "This predicate has been introduced in version 0.28.13." - ) + - gsi::method ("message", &db::NetlistDeviceExtractorError::message, - "@brief Gets the message text.\n" - ) + - gsi::method ("message=", &db::NetlistDeviceExtractorError::set_message, gsi::arg ("message"), - "@brief Sets the message text.\n" - ) + - gsi::method ("cell_name", &db::NetlistDeviceExtractorError::cell_name, - "@brief Gets the cell name.\n" - "See \\cell_name= for details about this attribute." - ) + - gsi::method ("cell_name=", &db::NetlistDeviceExtractorError::set_cell_name, gsi::arg ("cell_name"), - "@brief Sets the cell name.\n" - "The cell name is the name of the layout cell which was treated. This is " - "also the name of the circuit the device should have appeared in (it may be dropped because of this error). " - "If netlist hierarchy manipulation happens however, the circuit may not exist " - "any longer or may be renamed." - ) + - gsi::method ("geometry", &db::NetlistDeviceExtractorError::geometry, - "@brief Gets the geometry.\n" - "See \\geometry= for more details." - ) + - gsi::method ("geometry=", &db::NetlistDeviceExtractorError::set_geometry, gsi::arg ("polygon"), - "@brief Sets the geometry.\n" - "The geometry is optional. If given, a marker will be shown when selecting this error." - ) + - gsi::method ("category_name", &db::NetlistDeviceExtractorError::category_name, - "@brief Gets the category name.\n" - "See \\category_name= for more details." - ) + - gsi::method ("category_name=", &db::NetlistDeviceExtractorError::set_category_name, gsi::arg ("name"), - "@brief Sets the category name.\n" - "The category name is optional. If given, it specifies a formal category name. Errors with the same " - "category name are shown in that category. If in addition a category description is specified " - "(see \\category_description), this description will be displayed as the title of." - ) + - gsi::method ("category_description", &db::NetlistDeviceExtractorError::category_description, - "@brief Gets the category description.\n" - "See \\category_name= for details about categories." - ) + - gsi::method ("category_description=", &db::NetlistDeviceExtractorError::set_category_description, gsi::arg ("description"), - "@brief Sets the category description.\n" - "See \\category_name= for details about categories." - ) + - gsi::method ("to_s", &db::NetlistDeviceExtractorError::to_string, - "@brief Gets the string representation of this error or warning.\n" - "This method has been introduced in version 0.28.13." - ), - "@brief An error or a warning that occurred during device extraction\n" - "The device extractor will keep errors that occurred during extraction of the devices. " - "It does not by using this error class.\n" - "\n" - "An error is basically described by the cell/circuit it occurs in and the message. " - "In addition, a geometry may be attached forming a marker that can be shown when the error is selected. " - "The geometry is given as a \\DPolygon object. If no geometry is specified, this polygon is empty.\n" - "\n" - "For categorization of the errors, a category name and description may be specified. If given, the " - "errors will be shown in the specified category. The category description is optional.\n" - "\n" - "This class has been introduced in version 0.26. Warning mode has been added in version 0.28.13." -); - static const std::string &ld_name (const db::NetlistDeviceExtractorLayerDefinition *ld) { return ld->name; @@ -292,8 +222,10 @@ Class decl_dbNetlistDeviceExtractor ("db", "DeviceEx gsi::iterator ("each_layer_definition", &db::NetlistDeviceExtractor::begin_layer_definitions, &db::NetlistDeviceExtractor::end_layer_definitions, "@brief Iterates over all layer definitions." ) + - gsi::iterator ("each_error", &db::NetlistDeviceExtractor::begin_errors, &db::NetlistDeviceExtractor::end_errors, - "@brief Iterates over all errors collected in the device extractor." + gsi::iterator ("each_log_entry|#each_error", &db::NetlistDeviceExtractor::begin_log_entries, &db::NetlistDeviceExtractor::end_log_entries, + "@brief Iterates over all log entries collected in the device extractor." + "Starting with version 0.28.13, the preferred name of the method is 'each_log_entry' as " + "log entries have been generalized to become warnings too." ), "@brief The base class for all device extractors.\n" "This is an abstract base class for device extractors. See \\GenericDeviceExtractor for a generic " diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index a3d4ac867..e810c286b 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -33,7 +33,7 @@ TEST(1_NetlistDeviceExtractorErrorBasic) { - db::NetlistDeviceExtractorError error; + db::LogEntryData error; EXPECT_EQ (error.message (), ""); error.set_message ("x"); @@ -47,12 +47,16 @@ TEST(1_NetlistDeviceExtractorErrorBasic) error.set_geometry (db::DPolygon (db::DBox (0, 1, 2, 3))); EXPECT_EQ (error.geometry ().to_string (), "(0,1;0,3;2,3;2,1)"); - error = db::NetlistDeviceExtractorError ("cell2", "msg2"); + error = db::LogEntryData (db::Error, "cell2", "msg2"); + EXPECT_EQ (error.severity () == db::Error, true); EXPECT_EQ (error.cell_name (), "cell2"); EXPECT_EQ (error.message (), "msg2"); EXPECT_EQ (error.category_name (), ""); EXPECT_EQ (error.category_description (), ""); EXPECT_EQ (error.geometry ().to_string (), "()"); + + error.set_severity (db::Warning); + EXPECT_EQ (error.severity () == db::Warning, true); } namespace { @@ -71,7 +75,7 @@ namespace { }; } -static std::string error2string (const db::NetlistDeviceExtractorError &e) +static std::string error2string (const db::LogEntryData &e) { return e.cell_name() + ":" + e.category_name () + ":" + e.category_description () + ":" + e.geometry ().to_string () + ":" + e.message (); @@ -81,9 +85,9 @@ TEST(2_NetlistDeviceExtractorErrors) { DummyDeviceExtractor dummy_ex; - EXPECT_EQ (dummy_ex.has_errors (), true); + EXPECT_EQ (dummy_ex.begin_log_entries () != dummy_ex.end_log_entries (), true); - std::vector errors (dummy_ex.begin_errors (), dummy_ex.end_errors ()); + std::vector errors (dummy_ex.begin_log_entries (), dummy_ex.end_log_entries ()); EXPECT_EQ (int (errors.size ()), 4); EXPECT_EQ (error2string (errors [0]), ":::():msg1"); EXPECT_EQ (error2string (errors [1]), ":::(0,1;0,3;2,3;2,1):msg2"); diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index c89ef2c22..387ccbc6c 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -87,14 +87,14 @@ NetlistLogModel::NetlistLogModel (QWidget *parent, const db::NetlistCrossReferen mp_lvsdb_messages = cross_ref ? &cross_ref->other_log_entries () : 0; if (mp_lvsdb_messages) { for (auto l = mp_lvsdb_messages->begin (); l != mp_lvsdb_messages->end (); ++l) { - m_max_severity = std::max (m_max_severity, l->severity); + m_max_severity = std::max (m_max_severity, l->severity ()); } } mp_l2n_messages = l2n ? &l2n->log_entries () : 0; if (mp_l2n_messages) { for (auto l = mp_l2n_messages->begin (); l != mp_l2n_messages->end (); ++l) { - m_max_severity = std::max (m_max_severity, l->severity); + m_max_severity = std::max (m_max_severity, l->severity ()); } } @@ -104,7 +104,7 @@ NetlistLogModel::NetlistLogModel (QWidget *parent, const db::NetlistCrossReferen const db::NetlistCrossReference::PerCircuitData *pcd = cross_ref->per_circuit_data_for (*i); if (pcd && (i->first || i->second) && ! pcd->log_entries.empty ()) { for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { - m_max_severity = std::max (m_max_severity, l->severity); + m_max_severity = std::max (m_max_severity, l->severity ()); } m_circuits.push_back (std::make_pair (*i, &pcd->log_entries)); } @@ -201,13 +201,13 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (role == Qt::DecorationRole) { if (le) { - return icon_for_severity (le->severity); + return icon_for_severity (le->severity ()); } } else if (role == Qt::DisplayRole) { if (le) { - return QVariant (tl::to_qstring (le->msg)); + return QVariant (tl::to_qstring (le->to_string ())); } else if (! index.parent ().isValid () && index.row () >= m_global_entries && index.row () < int (m_circuits.size ()) + m_global_entries) { const std::pair &cp = m_circuits [index.row () - m_global_entries].first; if (! cp.first) { @@ -225,7 +225,7 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (le) { QFont f; - f.setBold (le->severity == db::Error); + f.setBold (le->severity () == db::Error); return QVariant (f); } else if (! index.parent ().isValid () && index.row () >= m_global_entries && index.row () < int (m_circuits.size ()) + m_global_entries) { QFont f; @@ -237,9 +237,9 @@ NetlistLogModel::data (const QModelIndex &index, int role) const if (! le) { // ignore - } else if (le->severity == db::Error) { + } else if (le->severity () == db::Error) { return QColor (255, 0, 0); - } else if (le->severity == db::Warning) { + } else if (le->severity () == db::Warning) { return QColor (0, 0, 255); } From 6412c534b8272bab09c488f4cd31dd270bd5e7bd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Sep 2023 19:01:30 +0200 Subject: [PATCH 23/41] Updated tests --- src/db/db/dbLayoutToNetlist.cc | 4 ++-- src/db/db/dbLayoutToNetlistWriter.cc | 4 ++-- src/db/db/dbLayoutVsSchematicWriter.cc | 12 ++++++++---- src/db/db/dbLog.cc | 8 +++++--- testdata/lvs/double_height2.lvsdb | 6 +++--- testdata/lvs/double_height2_texts.lvsdb | 6 +++--- .../lvs/ringo_simple_implicit_connections.lvsdb.1 | 2 +- testdata/lvs/test_22a.lvsdb.1 | 2 +- testdata/lvs/test_22a.lvsdb.2 | 2 +- testdata/lvs/test_22b.lvsdb.1 | 2 +- testdata/lvs/test_22b.lvsdb.2 | 2 +- testdata/lvs/test_22c.lvsdb.1 | 2 +- testdata/lvs/test_22c.lvsdb.2 | 2 +- testdata/lvs/test_22d.lvsdb.1 | 2 +- testdata/ruby/dbNetlist.rb | 10 +++++----- testdata/ruby/dbNetlistDeviceExtractors.rb | 2 +- 16 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index d70d3c04b..0ba3b4cab 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -476,11 +476,11 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a } } else { if (a.expanded_name () == b.expanded_name ()) { - db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name ())); + db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at the chip top level")), a.expanded_name ())); warn.set_cell_name (c.name ()); log_entry (warn); } else { - db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy. This is an error at the chip top level.")), a.expanded_name (), b.expanded_name ())); + db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at the chip top level")), a.expanded_name (), b.expanded_name ())); warn.set_cell_name (c.name ()); log_entry (warn); } diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 3b2c2754c..b188d7876 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -205,7 +205,7 @@ template void std_writer_impl::write_log_entry (TokenizedOutput &stream, const LogEntryData &le) { stream << severity_to_s (le.severity ()); - stream << message_to_s (le.to_string ()); + stream << message_to_s (le.message ()); if (! le.cell_name ().empty ()) { TokenizedOutput (stream, Keys::cell_key, true) << tl::to_word_or_quoted_string (le.cell_name ()); @@ -220,7 +220,7 @@ void std_writer_impl::write_log_entry (TokenizedOutput &stream, const LogE } if (le.geometry () != db::DPolygon ()) { - TokenizedOutput o (stream, Keys::polygon_key); + TokenizedOutput o (stream, Keys::polygon_key, true); o << tl::to_word_or_quoted_string (le.geometry ().to_string ()); } } diff --git a/src/db/db/dbLayoutVsSchematicWriter.cc b/src/db/db/dbLayoutVsSchematicWriter.cc index f51bd291f..9c100da4f 100644 --- a/src/db/db/dbLayoutVsSchematicWriter.cc +++ b/src/db/db/dbLayoutVsSchematicWriter.cc @@ -203,8 +203,10 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro o << endl; for (auto l = xref->other_log_entries ().begin (); l != xref->other_log_entries ().end (); ++l) { - TokenizedOutput to (o, Keys::log_entry_key, true); - this->write_log_entry (to, *l); + { + TokenizedOutput to (o, Keys::log_entry_key, true); + this->write_log_entry (to, *l); + } o << endl; } @@ -225,8 +227,10 @@ void std_writer_impl::write (TokenizedOutput &stream, const db::NetlistCro o << endl; for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { - TokenizedOutput to (o, Keys::log_entry_key, true); - this->write_log_entry (to, *l); + { + TokenizedOutput to (o, Keys::log_entry_key, true); + this->write_log_entry (to, *l); + } o << endl; } diff --git a/src/db/db/dbLog.cc b/src/db/db/dbLog.cc index 3d423a50b..2f504cd7f 100644 --- a/src/db/db/dbLog.cc +++ b/src/db/db/dbLog.cc @@ -170,12 +170,14 @@ LogEntryData::to_string () const } } - res += message (); - if (m_cell_name != 0) { - res += tl::to_string (tr (", in cell: ")) + cell_name (); + res += tl::to_string (tr ("In cell ")); + res += cell_name (); + res += ": "; } + res += message (); + if (! m_geometry.box ().empty ()) { res += tl::to_string (tr (", shape: ")) + m_geometry.to_string (); } diff --git a/testdata/lvs/double_height2.lvsdb b/testdata/lvs/double_height2.lvsdb index 41231a058..784d0a7bd 100644 --- a/testdata/lvs/double_height2.lvsdb +++ b/testdata/lvs/double_height2.lvsdb @@ -27,9 +27,9 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets GND from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) - H(W B('Must-connect nets R from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) - H(E B('Must-connect nets R from circuit INV2 are not connected in INVCHAIN')) + H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) + H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) + H(E B('Must-connect nets R are not connected in INVCHAIN') C(INV2)) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/double_height2_texts.lvsdb b/testdata/lvs/double_height2_texts.lvsdb index d99bb36e5..9314d3a8f 100644 --- a/testdata/lvs/double_height2_texts.lvsdb +++ b/testdata/lvs/double_height2_texts.lvsdb @@ -27,9 +27,9 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets GND from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) - H(W B('Must-connect nets R from circuit INVCHAIN must be connected further up in the hierarchy. This is an error at the chip top level.')) - H(E B('Must-connect nets R from circuit INV2 are not connected in INVCHAIN')) + H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) + H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) + H(E B('Must-connect nets R are not connected in INVCHAIN') C(INV2)) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 index b8db0187d..dfe2f524b 100644 --- a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 +++ b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 @@ -39,7 +39,7 @@ layout( global(l10 SUBSTRATE) # Log entries - message(warning description('Must-connect nets VDD from circuit RINGO must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at the chip top level') cell(RINGO)) # Device class section class(PMOS MOS4) diff --git a/testdata/lvs/test_22a.lvsdb.1 b/testdata/lvs/test_22a.lvsdb.1 index 0c615c0a6..3b03a7008 100644 --- a/testdata/lvs/test_22a.lvsdb.1 +++ b/testdata/lvs/test_22a.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22a.lvsdb.2 b/testdata/lvs/test_22a.lvsdb.2 index db581b3ce..7b3f46cb7 100644 --- a/testdata/lvs/test_22a.lvsdb.2 +++ b/testdata/lvs/test_22a.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.1 b/testdata/lvs/test_22b.lvsdb.1 index adae1c5b2..0ba4a5715 100644 --- a/testdata/lvs/test_22b.lvsdb.1 +++ b/testdata/lvs/test_22b.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.2 b/testdata/lvs/test_22b.lvsdb.2 index 780f9903e..8143cde2e 100644 --- a/testdata/lvs/test_22b.lvsdb.2 +++ b/testdata/lvs/test_22b.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.1 b/testdata/lvs/test_22c.lvsdb.1 index 1dde5fe1e..dc8c9a02b 100644 --- a/testdata/lvs/test_22c.lvsdb.1 +++ b/testdata/lvs/test_22c.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.2 b/testdata/lvs/test_22c.lvsdb.2 index 4b291a048..041d90937 100644 --- a/testdata/lvs/test_22c.lvsdb.2 +++ b/testdata/lvs/test_22c.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.1 b/testdata/lvs/test_22d.lvsdb.1 index 6c4dda0ef..a7d57594a 100644 --- a/testdata/lvs/test_22d.lvsdb.1 +++ b/testdata/lvs/test_22d.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) # Device class section class(active_res RES) diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index 4c5b9fd83..738b57433 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -1120,11 +1120,11 @@ END c.join_nets(c.net_by_name("IN"), c.net_by_name("OUT")) assert_equal(nl.to_s, <<"END") -circuit INV2 (IN=IN,$2=$2,OUT=IN,$4=$4,$5=$5); - subcircuit PTRANS SC1 ($1=$5,$2=$2,$3=IN); - subcircuit NTRANS SC2 ($1=$4,$2=$2,$3=IN); - subcircuit PTRANS SC3 ($1=$5,$2=IN,$3=$2); - subcircuit NTRANS SC4 ($1=$4,$2=IN,$3=$2); +circuit INV2 ('IN,OUT'='IN,OUT',$2=$2,$3=$4,$4=$5); + subcircuit PTRANS SC1 ($1=$5,$2=$2,$3='IN,OUT'); + subcircuit NTRANS SC2 ($1=$4,$2=$2,$3='IN,OUT'); + subcircuit PTRANS SC3 ($1=$5,$2='IN,OUT',$3=$2); + subcircuit NTRANS SC4 ($1=$4,$2='IN,OUT',$3=$2); end; circuit PTRANS ($1=$1,$2=$2,$3=$3); device PMOS $1 (S=$1,G=$3,D=$2) (L=0.25,W=0.95,AS=0,AD=0,PS=0,PD=0); diff --git a/testdata/ruby/dbNetlistDeviceExtractors.rb b/testdata/ruby/dbNetlistDeviceExtractors.rb index 5caa5ff90..d4d7023a3 100644 --- a/testdata/ruby/dbNetlistDeviceExtractors.rb +++ b/testdata/ruby/dbNetlistDeviceExtractors.rb @@ -27,7 +27,7 @@ class DBNetlistExtractorTests_TestClass < TestBase def test_1_Error - err = RBA::NetlistDeviceExtractorError::new + err = RBA::LogEntryData::new err.message = "MSG" err.cell_name = "Cell" From 2a85ae8e5c03a938b49a2af55b038c4a909b280c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Sep 2023 21:33:28 +0200 Subject: [PATCH 24/41] Added tests --- src/db/db/dbLog.cc | 2 +- src/db/unit_tests/dbLogTests.cc | 93 +++++++++++++++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 1 + testdata/ruby/dbNetlistCompare.rb | 6 ++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 src/db/unit_tests/dbLogTests.cc diff --git a/src/db/db/dbLog.cc b/src/db/db/dbLog.cc index 2f504cd7f..6e9428c5c 100644 --- a/src/db/db/dbLog.cc +++ b/src/db/db/dbLog.cc @@ -163,7 +163,7 @@ LogEntryData::to_string () const std::string res; if (m_category_name != 0) { - if (m_category_description != 0) { + if (m_category_description == 0) { res += "[" + category_name () + "] "; } else { res += "[" + category_description () + "] "; diff --git a/src/db/unit_tests/dbLogTests.cc b/src/db/unit_tests/dbLogTests.cc new file mode 100644 index 000000000..03b2941f6 --- /dev/null +++ b/src/db/unit_tests/dbLogTests.cc @@ -0,0 +1,93 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbLog.h" + +#include "tlUnitTest.h" + +TEST(1_Basic) +{ + db::LogEntryData data; + EXPECT_EQ (data.severity (), db::NoSeverity); + EXPECT_EQ (data.message (), std::string ()); + EXPECT_EQ (data.category_description (), std::string ()); + EXPECT_EQ (data.category_name (), std::string ()); + EXPECT_EQ (data.cell_name (), std::string ()); + EXPECT_EQ (data.geometry ().to_string (), "()"); + + EXPECT_EQ (data == db::LogEntryData (), true); + EXPECT_EQ (data != db::LogEntryData (), false); +} + +TEST(2_Attributes) +{ + db::LogEntryData data; + data.set_severity (db::Error); + data.set_message ("Message"); + data.set_category_name ("42"); + data.set_cell_name ("cell"); + data.set_category_description ("the answer"); + data.set_geometry (db::DPolygon (db::DBox (db::DPoint (1, 2), db::DPoint (3, 4)))); + + db::LogEntryData data2 = data; + + EXPECT_EQ (data == db::LogEntryData (), false); + EXPECT_EQ (data != db::LogEntryData (), true); + EXPECT_EQ (data == data2, true); + EXPECT_EQ (data != data2, false); + + EXPECT_EQ (data.severity (), db::Error); + EXPECT_EQ (data.message (), std::string ("Message")); + EXPECT_EQ (data.category_description (), std::string ("the answer")); + EXPECT_EQ (data.category_name (), std::string ("42")); + EXPECT_EQ (data.cell_name (), std::string ("cell")); + EXPECT_EQ (data.geometry ().to_string (), "(1,2;1,4;3,4;3,2)"); +} + +TEST(3_toString) +{ + db::LogEntryData data; + data.set_severity (db::Error); + data.set_message ("Message"); + data.set_category_name ("42"); + data.set_cell_name ("cell"); + data.set_category_description ("the answer"); + data.set_geometry (db::DPolygon (db::DBox (db::DPoint (1, 2), db::DPoint (3, 4)))); + + EXPECT_EQ (data.to_string (), std::string ("[the answer] In cell cell: Message, shape: (1,2;1,4;3,4;3,2)")); + + data.set_category_description (std::string ()); + + EXPECT_EQ (data.to_string (), std::string ("[42] In cell cell: Message, shape: (1,2;1,4;3,4;3,2)")); + + data.set_category_name (std::string ()); + + EXPECT_EQ (data.to_string (), std::string ("In cell cell: Message, shape: (1,2;1,4;3,4;3,2)")); + + data.set_geometry (db::DPolygon ()); + + EXPECT_EQ (data.to_string (), std::string ("In cell cell: Message")); + + data.set_cell_name (std::string ()); + + EXPECT_EQ (data.to_string (), std::string ("Message")); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 351bf8860..14a462810 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -9,6 +9,7 @@ include($$PWD/../../lib_ut.pri) SOURCES = \ dbCompoundOperationTests.cc \ dbFillToolTests.cc \ + dbLogTests.cc \ dbRecursiveInstanceIteratorTests.cc \ dbRegionCheckUtilsTests.cc \ dbUtilsTests.cc \ diff --git a/testdata/ruby/dbNetlistCompare.rb b/testdata/ruby/dbNetlistCompare.rb index c3b58c824..6a447e9f0 100644 --- a/testdata/ruby/dbNetlistCompare.rb +++ b/testdata/ruby/dbNetlistCompare.rb @@ -181,6 +181,12 @@ class NetlistCompare_TestClass < TestBase def test_1 + # severity enums + assert_equal(NetlistCompareTestLogger::Info.to_s, "Info") + assert_equal(NetlistCompareTestLogger::Error.to_s, "Error") + assert_equal(NetlistCompareTestLogger::Warning.to_s, "Warning") + assert_equal(NetlistCompareTestLogger::NoSeverity.to_s, "NoSeverity") + nl1 = RBA::Netlist::new nl2 = RBA::Netlist::new dc = RBA::DeviceClass::new From 27f67cf9c20f8fe3f4fb7c8b3c54373eaee4b6c2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Sep 2023 22:27:23 +0200 Subject: [PATCH 25/41] Added tests --- src/rba/unit_tests/rbaTests.cc | 1 + testdata/ruby/dbLogTest.rb | 59 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 testdata/ruby/dbLogTest.rb diff --git a/src/rba/unit_tests/rbaTests.cc b/src/rba/unit_tests/rbaTests.cc index 7bea46066..ec0fcb24a 100644 --- a/src/rba/unit_tests/rbaTests.cc +++ b/src/rba/unit_tests/rbaTests.cc @@ -107,6 +107,7 @@ RUBYTEST (dbLayerMapping, "dbLayerMapping.rb") RUBYTEST (dbLibrary, "dbLibrary.rb") RUBYTEST (dbLayoutTests1, "dbLayoutTests1.rb") RUBYTEST (dbLayoutTests2, "dbLayoutTests2.rb") +RUBYTEST (dbLog, "dbLogTest.rb") RUBYTEST (dbCellTests, "dbCellTests.rb") RUBYTEST (dbRecursiveShapeIterator, "dbRecursiveShapeIterator.rb") RUBYTEST (dbRecursiveInstanceIterator, "dbRecursiveInstanceIterator.rb") diff --git a/testdata/ruby/dbLogTest.rb b/testdata/ruby/dbLogTest.rb new file mode 100644 index 000000000..f53e00f73 --- /dev/null +++ b/testdata/ruby/dbLogTest.rb @@ -0,0 +1,59 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2023 Matthias Koefferlein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + + +class DBLog_TestClass < TestBase + + def test_1_Log + + assert_equal(RBA::LogEntryData::NoSeverity.to_s, "NoSeverity") + assert_equal(RBA::LogEntryData::Info.to_s, "Info") + assert_equal(RBA::LogEntryData::Error.to_s, "Error") + assert_equal(RBA::LogEntryData::Warning.to_s, "Warning") + + le = RBA::LogEntryData::new + + le.message = "message" + assert_equal(le.message, "message") + + le.geometry = RBA::DPolygon::new(RBA::DBox::new(1, 2, 3, 4)) + assert_equal(le.geometry.to_s, "(1,2;1,4;3,4;3,2)") + + le.category_name = "42" + assert_equal(le.category_name, "42") + + le.category_description = "the answer" + assert_equal(le.category_description, "the answer") + + le.cell_name = "TOP" + assert_equal(le.cell_name, "TOP") + + assert_equal(le.to_s, "[the answer] In cell TOP: message, shape: (1,2;1,4;3,4;3,2)") + + end + +end + +load("test_epilogue.rb") From 44d9ae91cc3f3022569fc20294dcef32704ed8a4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 24 Sep 2023 22:43:36 +0200 Subject: [PATCH 26/41] Some bug fixes --- src/layui/layui/layNetlistLogModel.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index 387ccbc6c..c9a85cc53 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -81,8 +81,8 @@ const std::string var_sep (" \u21D4 "); NetlistLogModel::NetlistLogModel (QWidget *parent, const db::NetlistCrossReference *cross_ref, const db::LayoutToNetlist *l2n) : QAbstractItemModel (parent), m_max_severity (db::NoSeverity) { - tl_assert (cross_ref->netlist_a () != 0); - tl_assert (cross_ref->netlist_b () != 0); + tl_assert (! cross_ref || cross_ref->netlist_a () != 0); + tl_assert (! cross_ref || cross_ref->netlist_b () != 0); mp_lvsdb_messages = cross_ref ? &cross_ref->other_log_entries () : 0; if (mp_lvsdb_messages) { @@ -100,13 +100,15 @@ NetlistLogModel::NetlistLogModel (QWidget *parent, const db::NetlistCrossReferen m_global_entries = int ((mp_lvsdb_messages ? mp_lvsdb_messages->size () : 0) + (mp_l2n_messages ? mp_l2n_messages->size () : 0)); - for (auto i = cross_ref->begin_circuits (); i != cross_ref->end_circuits (); ++i) { - const db::NetlistCrossReference::PerCircuitData *pcd = cross_ref->per_circuit_data_for (*i); - if (pcd && (i->first || i->second) && ! pcd->log_entries.empty ()) { - for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { - m_max_severity = std::max (m_max_severity, l->severity ()); + if (cross_ref) { + for (auto i = cross_ref->begin_circuits (); i != cross_ref->end_circuits (); ++i) { + const db::NetlistCrossReference::PerCircuitData *pcd = cross_ref->per_circuit_data_for (*i); + if (pcd && (i->first || i->second) && ! pcd->log_entries.empty ()) { + for (auto l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) { + m_max_severity = std::max (m_max_severity, l->severity ()); + } + m_circuits.push_back (std::make_pair (*i, &pcd->log_entries)); } - m_circuits.push_back (std::make_pair (*i, &pcd->log_entries)); } } From 11aebdb040ad2c139459c371c8694c42cd205978 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 25 Sep 2023 22:53:00 +0200 Subject: [PATCH 27/41] More tests --- testdata/algo/l2n_reader_6.l2n | 1 + testdata/algo/l2n_reader_6s.l2n | 1 + testdata/algo/l2n_reader_au_6.l2n | 1 + 3 files changed, 3 insertions(+) diff --git a/testdata/algo/l2n_reader_6.l2n b/testdata/algo/l2n_reader_6.l2n index 2b0c7fd7c..fa5e68b37 100644 --- a/testdata/algo/l2n_reader_6.l2n +++ b/testdata/algo/l2n_reader_6.l2n @@ -11,6 +11,7 @@ unit(0.001) # Log entries message(info description(info)) +message(info description(info) cell(cell_name) cat("cat name" "cat description") polygon("(1,1;2,2;3,1)")) message(warning description(warning)) message(error description(error)) diff --git a/testdata/algo/l2n_reader_6s.l2n b/testdata/algo/l2n_reader_6s.l2n index 4a4b7939c..2c9d2ed65 100644 --- a/testdata/algo/l2n_reader_6s.l2n +++ b/testdata/algo/l2n_reader_6s.l2n @@ -2,5 +2,6 @@ W(TOP) U(0.001) H(I B(info)) +H(I B(info) C(cell_name) X("cat name" "cat description") Q("(1,1;2,2;3,1)")) H(W B(warning)) H(E B(error)) diff --git a/testdata/algo/l2n_reader_au_6.l2n b/testdata/algo/l2n_reader_au_6.l2n index 2b0c7fd7c..aac060d33 100644 --- a/testdata/algo/l2n_reader_au_6.l2n +++ b/testdata/algo/l2n_reader_au_6.l2n @@ -11,6 +11,7 @@ unit(0.001) # Log entries message(info description(info)) +message(info description(info) cell(cell_name) cat('cat name' 'cat description') polygon('(1,1;2,2;3,1)')) message(warning description(warning)) message(error description(error)) From 579f5ffca424718f3d96e86cd70ecfa0b5ec69a1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 25 Sep 2023 23:33:15 +0200 Subject: [PATCH 28/41] Doc updates --- src/db/db/gsiDeclDbLog.cc | 14 ++--- src/doc/doc/manual/lvs_connect.xml | 91 ++++++++++++++++++------------ src/edt/edt/edtPartialService.cc | 2 +- testdata/ruby/dbLayoutToNetlist.rb | 14 +++++ 4 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/db/db/gsiDeclDbLog.cc b/src/db/db/gsiDeclDbLog.cc index 621c8e848..a88c67691 100644 --- a/src/db/db/gsiDeclDbLog.cc +++ b/src/db/db/gsiDeclDbLog.cc @@ -46,10 +46,10 @@ Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData" ) + gsi::method ("cell_name=", &db::LogEntryData::set_cell_name, gsi::arg ("cell_name"), "@brief Sets the cell name.\n" - "The cell name is the name of the layout cell which was treated. This is " - "also the name of the circuit the device should have appeared in (it may be dropped because of this error). " - "If netlist hierarchy manipulation happens however, the circuit may not exist " - "any longer or may be renamed." + "The cell (or circuit) name specifies the cell or circuit the " + "log entry is related to. If the log entry is an error or " + "warning generated during device extraction, the cell name is " + "the circuit the device should have appeared in." ) + gsi::method ("geometry", &db::LogEntryData::geometry, "@brief Gets the geometry.\n" @@ -57,7 +57,7 @@ Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData" ) + gsi::method ("geometry=", &db::LogEntryData::set_geometry, gsi::arg ("polygon"), "@brief Sets the geometry.\n" - "The geometry is optional. If given, a marker will be shown when selecting this error." + "The geometry is optional. If given, a marker may be shown when selecting this error." ) + gsi::method ("category_name", &db::LogEntryData::category_name, "@brief Gets the category name.\n" @@ -67,7 +67,7 @@ Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData" "@brief Sets the category name.\n" "The category name is optional. If given, it specifies a formal category name. Errors with the same " "category name are shown in that category. If in addition a category description is specified " - "(see \\category_description), this description will be displayed as the title of." + "(see \\category_description), this description will be displayed as the title." ) + gsi::method ("category_description", &db::LogEntryData::category_description, "@brief Gets the category description.\n" @@ -91,7 +91,7 @@ Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData" "for indicating some location or error marker." "\n" "The original class used to be \"NetlistDeviceExtractorError\" which had been introduced in version 0.26. " - "It was generalized and renamed in version 0.28.13 as it was basically not useful as a seperate class." + "It was generalized and renamed in version 0.28.13 as it was basically not useful as a separate class." ); gsi::Enum decl_Severity ("db", "Severity", diff --git a/src/doc/doc/manual/lvs_connect.xml b/src/doc/doc/manual/lvs_connect.xml index 5757e5336..44bdb0108 100644 --- a/src/doc/doc/manual/lvs_connect.xml +++ b/src/doc/doc/manual/lvs_connect.xml @@ -102,19 +102,21 @@ connect(metal2, metal2_labels)

Implicit connections can be useful to supply preliminary connections which are supposed to be created higher up in the hierarchy: - Imagine a circuit which a big power net for example. When the layout - is made, the power net may not be completely connected yet because the + Imagine a circuit with a big power net for example. When the layout + is made, the power net may not be completely connected yet, because the plan is to connect all parts of this power net later when the cell is integrated. In this situation, the - subcircuit cell itself won't be LVS clean because the power net is a single + subcircuit cell itself won't be LVS clean, because the power net is a single net schematic-wise, but exist as multiple nets layout-wise. This prevents bottom-up verification - a very useful technique to achieve LVS clean - layouts. + layouts. It also prevents matching in general, as the layout cell will + have two pins while the schematic subcircuit has only one. In this case, + the cell and subcircuit will never match.

To allow verification of such a cell, "implicit connections" can be - made by giving the net parts the same name through labels and assume + made by giving the net parts the same name through labels and assuming these parts are connected: for example to specify implicit connections between all parts of a "VDD" net, place a label "VDD" on each part and include the following statement @@ -126,9 +128,16 @@ connect(metal2, metal2_labels)

"connect_implicit" (see connect_implicit) can be present multiple times to make many of such connections. - Implicit connections will only be made on the topmost circuit to prevent false verification results. - Be careful not to use this option in a final verification of a full design as power net - opens may pass unnoticed. + Implicit connections are accepted on top level, but a warning is issued, indicating + that the connection needs to be made further up in the hierarchy. + In a subcircuit, implicit connections are required to be connected on the + next level of hierarchy - either physically or by another implicit connection. + This way, a missing physical connection does not escape and at least a warning + is issued if the connection is still not made on top level. +

+ +

+ This feature is also called "must connect" nets in other systems.

@@ -142,7 +151,8 @@ connect(metal2, metal2_labels) This will connect all nets labelled with "VDD1" for example or those labelled with "VDD_5V". However, this statement will only connect "VDD1" with "VDD1", not nets with different labels. I.e. it will not connect "VDD1" with "VDD2" - labels. + labels. To make connections between differently named nets, use "explicit connections" + (see below).

@@ -151,30 +161,22 @@ connect(metal2, metal2_labels)

- The standard method "connect_implicit" will only act on top-level cells. - However, sometimes the construction of certain library cells requires - connecting nets inside subcells. For example, memory cells are often made - in a way that their common rails are exposed on different sides but - not connected internally. Formally, those cells need to be described by - circuits with multiple pins in the schematic. As the cells are only used - in certain contexts where these rails are connected, it's sufficient to - specify a single pin and connect the rails inside the subcells if labelled - properly. The following statement will connect all nets labelled with "VDD" + The above examples of "connect_implicit" apply to all cells. The statement + can be made cell specific, by giving a cell name glob pattern for the + first argument, followed by the net name pattern. +

+ +

+ The following statement will connect all nets labelled with "VDD" from the "MEMCELL" subcell:

connect_implicit("MEMCELL", "VDD")

- If MEMCELL is the top cell, the single-argument, unspecific "connect_implicit" - rule is applied, unless no such rule is given. In other words: the unspecific - rule has priority for the top cell. -

- -

- The cell argument can be a glob-style pattern. In this case, the rule is - applied to all matching cells. Again, the "connect_implicit" rule may be - given multiple times. In this case, all matching occurances act together. + The rule is applied to all cells matching the glob pattern in the first argument. + Again, the "connect_implicit" rule may be given multiple times. + In this case, all matching occurrences act together.

@@ -217,12 +219,10 @@ connect(metal2, metal2_labels)

- To align layout and schematics, bulk and VSS pins can be connected + To align layout and schematic, bulk and VSS pins can be connected explicitly. Same for n-well and VDD. - There is a certain risk to forget making these connections later. - But this risk can be mitigated by implementing DRC rules which - demand at least one tie-down diode for each isolated n-well island - or the bulk. + This scheme is similar to the "connect_implicit" scheme explained + above, but acts on differently named nets.

@@ -230,7 +230,7 @@ connect(metal2, metal2_labels) bulk have proper names. For the n-well this can be done by creating labels on the n-well islands giving them a proper name - e.g. "NWELL". The bulk isn't a real layout layer with polygons on it. Using "connect_global" - will both connect everthing on this layer and give it a name. + will both connect everything on this layer and give it a name.

@@ -242,17 +242,36 @@ connect(metal2, metal2_labels) connect_explicit("INV", [ "BULK", "VSS" ]) +

+ Note that this rule will form a new net called "BULK,VSS" combining both + subnets. +

+

The cell name can be a pattern. For example "INV*" will apply this rule on all cells starting with "INV". - The cell is not mandatory: if it is omitted, the rule is applied to top level only - to avoid introducing rules in subcells where they would mask layout errors. + The cell pattern is not mandatory: if it is omitted, the rule is applied to all + cells. +

+ +

+ Like implicit connections, explicit connections are checked for being made + on the next level of hierarchy, either physically or by another explicit or + implicit connection. + This feature is also called "must connect" nets in other systems.

An explicit connection will also imply implicit connections on the nets listed in the net names. So in the example above, different pieces of "VSS" - are connected even if they are not physically connected. + are connected even if they are not physically connected. Again, it is checked + that these connections are made later up in the hierarchy. +

+ +

+ Again, the "connect_explicit" statements must be given before the netlist is + extracted. Typically this happens before or shortly after "connect" + statements.

diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc index 368ddaa39..40d19bb05 100644 --- a/src/edt/edt/edtPartialService.cc +++ b/src/edt/edt/edtPartialService.cc @@ -2989,7 +2989,7 @@ PartialService::partial_select (const db::DBox &box, lay::Editable::SelectionMod shape_flags |= db::ShapeIterator::Polygons; } if (edt::paths_enabled ()) { - // Note: points, edges and edge pairs don't have seperate entires, so + // Note: points, edges and edge pairs don't have separate entires, so // we count them as paths here shape_flags |= db::ShapeIterator::Paths; shape_flags |= db::ShapeIterator::Edges; diff --git a/testdata/ruby/dbLayoutToNetlist.rb b/testdata/ruby/dbLayoutToNetlist.rb index c40e91b9b..e5404b547 100644 --- a/testdata/ruby/dbLayoutToNetlist.rb +++ b/testdata/ruby/dbLayoutToNetlist.rb @@ -1011,6 +1011,20 @@ END end + def test_21_LogAPI + + l2n = RBA::LayoutToNetlist::new + l2n.read(File.join($ut_testsrc, "testdata", "algo", "l2n_reader_au_6.l2n")) + + le = l2n.each_log_entry.collect { |s| s.to_s } + assert_equal(le.size, 4) + assert_equal(le[0].to_s, "info") + assert_equal(le[1].to_s, "[cat description] In cell cell_name: info, shape: (1,1;2,2;3,1)") + assert_equal(le[2].to_s, "warning") + assert_equal(le[3].to_s, "error") + + end + end load("test_epilogue.rb") From 1115e44886af8d2f226b37e35f6a7e3746a69a73 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 21:40:21 +0200 Subject: [PATCH 29/41] Added tests for must-connect feature --- testdata/lvs/must_connect1.cir | 23 ++ testdata/lvs/must_connect1.gds | Bin 0 -> 4394 bytes testdata/lvs/must_connect1.lvs | 139 +++++++++ testdata/lvs/must_connect1.lvsdb | 484 ++++++++++++++++++++++++++++++ testdata/lvs/must_connect1.sch | 24 ++ testdata/lvs/must_connect2.cir | 23 ++ testdata/lvs/must_connect2.gds | Bin 0 -> 4568 bytes testdata/lvs/must_connect2.lvs | 142 +++++++++ testdata/lvs/must_connect2.lvsdb | 490 +++++++++++++++++++++++++++++++ testdata/lvs/must_connect2.sch | 24 ++ 10 files changed, 1349 insertions(+) create mode 100644 testdata/lvs/must_connect1.cir create mode 100644 testdata/lvs/must_connect1.gds create mode 100644 testdata/lvs/must_connect1.lvs create mode 100644 testdata/lvs/must_connect1.lvsdb create mode 100644 testdata/lvs/must_connect1.sch create mode 100644 testdata/lvs/must_connect2.cir create mode 100644 testdata/lvs/must_connect2.gds create mode 100644 testdata/lvs/must_connect2.lvs create mode 100644 testdata/lvs/must_connect2.lvsdb create mode 100644 testdata/lvs/must_connect2.sch diff --git a/testdata/lvs/must_connect1.cir b/testdata/lvs/must_connect1.cir new file mode 100644 index 000000000..9b6488f75 --- /dev/null +++ b/testdata/lvs/must_connect1.cir @@ -0,0 +1,23 @@ +* Extracted by KLayout + +.SUBCKT TOP VSSTOP A Q +X$1 \$8 \$2 \$1 \$1 Q VSSTOP INV2 +X$2 A \$3 VSSTOP \$3 \$2 \$8 INVCHAIN +.ENDS TOP + +.SUBCKT INVCHAIN IN IN2 VSS|VSS2|VSS2B OUT OUT2 VDD +X$1 VDD IN2 \$1 \$1 OUT2 VSS|VSS2|VSS2B INV2 +X$2 VDD IN \$2 \$2 OUT VSS|VSS2|VSS2B INV2 +.ENDS INVCHAIN + +.SUBCKT INV2 VDD A1 A2 Q1 Q2 VSS +X$1 VSS VDD A2 Q2 INV +X$2 VSS VDD A1 Q1 INV +.ENDS INV2 + +.SUBCKT INV \$1 \$2 \$3 \$4 +M$1 \$2 \$3 \$4 \$4 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +M$2 \$1 \$3 \$4 \$4 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +.ENDS INV diff --git a/testdata/lvs/must_connect1.gds b/testdata/lvs/must_connect1.gds new file mode 100644 index 0000000000000000000000000000000000000000..cf15929c54e2efc8fef22002a23260b10a20c7d5 GIT binary patch literal 4394 zcmbW4U1%It6vxlb?#|9`HZlE3%6?3;8&;808k?k%C=@qFYDi6uiB&_N6e(K8mx3Y+ zg+`$dz7=1JA1Ky>B2xSaHi8BT5(O0>6czD75QNtBNr_3u|GD=bXKvWtOd8ny!rA%X zb3e}c-wC@!oGCoSQJDEOIKYQ!M(%UN|WApv5pP!wf za=N)L=ejfZ)hDNkQXY}p?vO)nheJgBI+H=L_FNEb+{h$K{7jUb6H1&(sU4v{71eJz z_%UcbN4dB~G)=^mw)pnq|%40=U8XH6`9WKkGQZW@4Ci z_!vrjQ+_wP{`Cdqp9_NZ1?aGsK}{%erZxYF9=U%}--E0pa>j%b5A|7neo2$xt@0^) zHze_Um3DVB2`Bj*6DL{GSu@nKK0MbQpFD=s%@O5xO0DGeXlfvJ_Km;Itu$L1?+9jo zT<=Wwl-?Oli8C#|tV~sAa0VI|pEFn_PMDq-N}Orwz39oT)-e8|AXw!SStLsH4l7EW z*-B58-LLieOIk0Kcy_;~PuTg1GM?6V{HXOpiDx`Zp9%Gt>n_aivS#ohDx)3iHIz6Q z?aWPj?AZkC@wtojAtesB)Mww(`rKPuFO)dgQr~vF*5?muy-?zy(#NXN0ac^kPF=5V zF>#tGUrvvHpsEyqbItN8OXZ_xBTwV0hEG?%wbl@+Aw6z>QghE6L~Zj#LWzTF4SC(2 z(04n8O4yU2G+~yUx0J3|^eB3kDKy-Uf5+#`Hxq*-+69?7U zjr9KaM8zke0m~;*4=;q2IH>e3Z;l%GP5E7v?_Wf<*Fu&~5cT|k-98a_6!#&l=OR(Z zk&xvI+HejTD%M(Tug8sDT*Q8XKD6A$LWvg_o9T(VtI)rw>31U61JD~v9E|RT^tpYD zs=eS-t$d7|^v{s+6!jzC62IHv;tr3~u-js}MeieUi-qfViz?>cJ8$ya9TzKqbp)Pz zg>rDK>FI&d>+l9=q_ycNzIy%%eRtL4>=s~u3?u@3elVVq^N>+O3K-#x8!7}pWkvpa2w zU8nLDR(qUiFWyZQ;m$(;6j47eN9HXbDXN*b998vi(Z|zmL|xy7%yz+H3)s^xYyV_! zc;h4*{1p3rk7myV(eP97KSPOw(OHO#*=tj?7zvWo{7oq&zOrIJ`9Bir|T8DlaJpuZt^MhAHN*q*r JI94h}{{baUO!NQ% literal 0 HcmV?d00001 diff --git a/testdata/lvs/must_connect1.lvs b/testdata/lvs/must_connect1.lvs new file mode 100644 index 000000000..799fa0364 --- /dev/null +++ b/testdata/lvs/must_connect1.lvs @@ -0,0 +1,139 @@ + +$lvs_test_source && source($lvs_test_source) + +if $lvs_test_target_lvsdb + report_lvs($lvs_test_target_lvsdb) +else + report_lvs +end + + +writer = write_spice(true, false) +$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout") + +# needs this delegate because we use MOS3 which is not available in Spice +class SpiceReaderDelegate < RBA::NetlistSpiceReaderDelegate + + # says we want to catch these subcircuits as devices + def wants_subcircuit(name) + name == "HVNMOS" || name == "HVPMOS" + end + + # translate the element + def element(circuit, el, name, model, value, nets, params) + + if el != "M" + # all other elements are left to the standard implementation + return super + end + + if nets.size != 4 + error("Device #{model} needs four nodes") + end + + # provide a device class + cls = circuit.netlist.device_class_by_name(model) + if ! cls + cls = RBA::DeviceClassMOS3Transistor::new + cls.name = model + circuit.netlist.add(cls) + end + + # create a device + device = circuit.create_device(cls, name) + + # and configure the device + [ "S", "G", "D" ].each_with_index do |t,index| + device.connect_terminal(t, nets[index]) + end + device.set_parameter("W", params["W"] * 1e6) + device.set_parameter("L", params["L"] * 1e6) + + device + + end + +end + +reader = RBA::NetlistSpiceReader::new(SpiceReaderDelegate::new) +schematic(File.basename(source.path, ".*") + ".sch", reader) + +deep + +# Drawing layers + +nwell = input(1, 0) +active = input(2, 0) +poly = input(3, 0) +poly_lbl = input(3, 1) +diff_cont = input(4, 0) +poly_cont = input(5, 0) +metal1 = input(6, 0) +metal1_lbl = input(6, 1) +via1 = input(7, 0) +metal2 = input(8, 0) +metal2_lbl = input(8, 1) + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +psd = nil +nsd = nil + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell +pgate = pactive & poly +psd = pactive - pgate + +active_outside_nwell = active - nwell +nactive = active_outside_nwell +ngate = nactive & poly +nsd = nactive - ngate + +# Device extraction + +# PMOS transistor device extraction +extract_devices(mos3("PMOS"), { "SD" => psd, "G" => pgate, + "tS" => psd, "tD" => psd, "tG" => poly }) + +# NMOS transistor device extraction +extract_devices(mos3("NMOS"), { "SD" => nsd, "G" => ngate, + "tS" => nsd, "tD" => nsd, "tG" => poly }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, diff_cont) +connect(nsd, diff_cont) +connect(poly, poly_cont) +connect(diff_cont, metal1) +connect(poly_cont, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# attach labels +connect(poly, poly_lbl) +connect(metal1, metal1_lbl) +connect(metal2, metal2_lbl) + +# Global +connect_global(bulk, "SUBSTRATE") + +# Implicit connection of the INV2 +# VSS nets +connect_implicit("INV2", "VSS") +connect_implicit("TOP", "VSS*") +# Fix 1 +connect_explicit("INVCHAIN", ["VSS2", "VSS2B", "VSS"]) +connect_implicit("INVCHAIN", "VDD") + +# Compare section + +netlist.simplify +align + +compare + diff --git a/testdata/lvs/must_connect1.lvsdb b/testdata/lvs/must_connect1.lvsdb new file mode 100644 index 000000000..6d86052d3 --- /dev/null +++ b/testdata/lvs/must_connect1.lvsdb @@ -0,0 +1,484 @@ +#%lvsdb-klayout +J( + W(TOP) + U(0.001) + L(l3 '3/0') + L(l11 '3/1') + L(l6 '4/0') + L(l7 '5/0') + L(l8 '6/0') + L(l12 '6/1') + L(l9 '7/0') + L(l10 '8/0') + L(l13 '8/1') + L(l14) + L(l2) + L(l5) + C(l3 l3 l11 l7) + C(l11 l3 l11) + C(l6 l6 l8 l2 l5) + C(l7 l3 l7 l8) + C(l8 l6 l7 l8 l12 l9) + C(l12 l8 l12) + C(l9 l8 l9 l10) + C(l10 l9 l10 l13) + C(l13 l10 l13) + C(l14 l14) + C(l2 l6 l2) + C(l5 l6 l5) + G(l14 SUBSTRATE) + H(W B('Must-connect nets VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) + K(PMOS MOS3) + K(NMOS MOS3) + D(D$PMOS PMOS + T(S + R(l2 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l2 (125 -475) (775 950)) + ) + ) + D(D$NMOS NMOS + T(S + R(l5 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l5 (125 -475) (775 950)) + ) + ) + X(INV + R((-1500 -800) (3000 4600)) + N(1 + R(l6 (290 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l5 (-1375 -925) (775 950)) + ) + N(2 + R(l6 (290 2490) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l2 (-1375 -925) (775 950)) + ) + N(3 + R(l3 (-125 -250) (250 2500)) + R(l3 (-250 -3050) (250 1600)) + R(l3 (-250 1200) (250 1600)) + ) + N(4 + R(l6 (-510 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l6 (-220 2180) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -3530) (360 2840)) + R(l8 (-360 -2800) (360 760)) + R(l8 (-360 2040) (360 760)) + R(l2 (-680 -855) (775 950)) + R(l5 (-775 -3750) (775 950)) + ) + P(1) + P(2) + P(3) + P(4) + D(1 D$PMOS + Y(0 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 2) + ) + D(2 D$NMOS + Y(0 0) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 1) + ) + ) + X(INV2 + R((0 0) (3000 9200)) + N(1 I(VDD) + R(l10 (0 3150) (3000 2900)) + R(l13 (-1890 -1450) (0 0)) + ) + N(2 I(A1) + R(l11 (1480 7110) (0 0)) + ) + N(3 I(A2) + R(l11 (1520 1950) (0 0)) + ) + N(4 I(Q1) + R(l12 (1920 7070) (0 0)) + ) + N(5 I(Q2) + R(l12 (1940 1950) (0 0)) + ) + N(6 I(VSS) + R(l13 (2680 8390) (0 0)) + R(l13 (-30 -7640) (0 0)) + ) + P(1 I(VDD)) + P(2 I(A1)) + P(3 I(A2)) + P(4 I(Q1)) + P(5 I(Q2)) + P(6 I(VSS)) + X(1 INV M O(180) Y(1500 800) + P(0 6) + P(1 1) + P(2 3) + P(3 5) + ) + X(2 INV O(180) Y(1500 8400) + P(0 6) + P(1 1) + P(2 2) + P(3 4) + ) + ) + X(INVCHAIN + R((-915 -15) (10415 9215)) + N(1 + R(l3 (7340 1650) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(2 + R(l3 (1625 1835) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(3 I(IN) + R(l3 (-90 6850) (1590 650)) + R(l11 (-700 -350) (0 0)) + ) + N(4 I(IN2) + R(l3 (5665 6790) (1590 650)) + R(l11 (-700 -350) (0 0)) + ) + N(5 I('VSS,VSS2,VSS2B') + R(l10 (-915 675) (915 250)) + R(l10 (-915 0) (250 7325)) + R(l10 (-250 0) (915 250)) + R(l13 (-510 -125) (0 0)) + R(l13 (8990 -255) (0 0)) + R(l13 (25 -7115) (0 0)) + ) + N(6 I(OUT) + R(l12 (1890 2105) (0 0)) + ) + N(7 I(OUT2) + R(l12 (7730 2155) (0 0)) + ) + N(8 I(VDD) + R(l13 (8035 4540) (0 0)) + R(l13 (-5735 60) (0 0)) + ) + P(3 I(IN)) + P(4 I(IN2)) + P(5 I('VSS,VSS2,VSS2B')) + P(6 I(OUT)) + P(7 I(OUT2)) + P(8 I(VDD)) + X(1 INV2 Y(5780 -15) + P(0 8) + P(1 4) + P(2 1) + P(3 1) + P(4 7) + P(5 5) + ) + X(2 INV2 Y(0 0) + P(0 8) + P(1 3) + P(2 2) + P(3 2) + P(4 6) + P(5 5) + ) + ) + X(TOP + R((-305 350) (15415 9225)) + N(1 + R(l3 (12950 2130) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(2 + R(l3 (12100 7300) (640 530)) + R(l7 (-540 -415) (270 250)) + R(l8 (-1695 -250) (1695 250)) + R(l8 (-4075 -5650) (2630 250)) + R(l8 (-250 0) (250 5150)) + ) + N(3 + R(l7 (6465 7325) (220 240)) + R(l8 (-4100 -5365) (3125 250)) + R(l8 (-250 0) (250 4860)) + R(l8 (-250 0) (1225 250)) + ) + N(4 I(VSSTOP) + R(l10 (3610 8300) (2815 440)) + R(l10 (-710 -250) (0 0)) + R(l10 (3675 -165) (1975 565)) + R(l10 (-1975 -8190) (1975 575)) + R(l10 (-1005 -255) (0 0)) + ) + N(5 I(A) + R(l11 (975 7530) (0 0)) + ) + N(6 I(Q) + R(l12 (13260 2010) (0 0)) + ) + N(7 + R(l10 (3450 4840) (3055 250)) + R(l10 (2885 -250) (1975 250)) + ) + P(4 I(VSSTOP)) + P(5 I(A)) + P(6 I(Q)) + X(1 INV2 Y(11365 375) + P(0 7) + P(1 2) + P(2 1) + P(3 1) + P(4 6) + P(5 4) + ) + X(2 INVCHAIN Y(610 365) + P(0 5) + P(1 3) + P(2 4) + P(3 3) + P(4 2) + P(5 7) + ) + ) +) +H( + K(PMOS MOS3) + K(NMOS MOS3) + X(INV + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A)) + N(4 I(Q)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A)) + P(4 I(Q)) + D(1 PMOS + I($1) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 1) + T(G 3) + T(D 4) + ) + D(2 NMOS + I($3) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 2) + T(G 3) + T(D 4) + ) + ) + X(INV2 + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A1)) + N(4 I(Q1)) + N(5 I(A2)) + N(6 I(Q2)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A1)) + P(4 I(Q1)) + P(5 I(A2)) + P(6 I(Q2)) + X(1 INV I($1) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + ) + X(2 INV I($2) + P(0 1) + P(1 2) + P(2 5) + P(3 6) + ) + ) + X(INVCHAIN + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A1)) + N(4 I(Q1)) + N(5 I(A2)) + N(6 I(Q2)) + N(7 I('1')) + N(8 I('2')) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A1)) + P(4 I(Q1)) + P(5 I(A2)) + P(6 I(Q2)) + X(1 INV2 I($2) + P(0 1) + P(1 2) + P(2 3) + P(3 7) + P(4 7) + P(5 4) + ) + X(2 INV2 I($3) + P(0 1) + P(1 2) + P(2 5) + P(3 8) + P(4 8) + P(5 6) + ) + ) + X(TOP + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A)) + N(4 I('1')) + N(5 I('3')) + N(6 I('2')) + N(7 I(Q)) + X(1 INVCHAIN I($1) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + P(4 4) + P(5 5) + ) + X(2 INV2 I($2) + P(0 1) + P(1 2) + P(2 5) + P(3 6) + P(4 6) + P(5 7) + ) + ) +) +Z( + X(INV INV 1 + Z( + N(3 3 1) + N(4 4 1) + N(2 1 1) + N(1 2 1) + P(2 2 1) + P(3 3 1) + P(1 0 1) + P(0 1 1) + D(2 2 1) + D(1 1 1) + ) + ) + X(INV2 INV2 1 + Z( + N(2 3 1) + N(3 5 1) + N(4 4 1) + N(5 6 1) + N(1 1 1) + N(6 2 1) + P(1 2 1) + P(2 4 1) + P(3 3 1) + P(4 5 1) + P(0 0 1) + P(5 1 1) + X(2 1 1) + X(1 2 1) + ) + ) + X(INVCHAIN INVCHAIN 1 + L( + M(W B('Matching nets OUT vs. Q1 from an ambiguous group of nets')) + M(W B('Matching nets OUT2 vs. Q2 from an ambiguous group of nets')) + M(I B('Matching nets $2 vs. 1 following an ambiguous match')) + M(I B('Matching nets IN vs. A1 following an ambiguous match')) + M(I B('Matching nets $1 vs. 2 following an ambiguous match')) + M(I B('Matching nets IN2 vs. A2 following an ambiguous match')) + ) + Z( + N(2 7 1) + N(1 8 1) + N(3 3 1) + N(4 5 1) + N(6 4 W) + N(7 6 W) + N(8 1 1) + N(5 2 1) + P(0 2 1) + P(1 4 1) + P(3 3 1) + P(4 5 1) + P(5 0 1) + P(2 1 1) + X(2 1 1) + X(1 2 1) + ) + ) + X(TOP TOP 1 + Z( + N(3 4 1) + N(1 6 1) + N(2 5 1) + N(7 1 1) + N(5 3 1) + N(6 7 1) + N(4 2 1) + P(1 () 1) + P(2 () 1) + P(0 () 1) + X(1 2 1) + X(2 1 1) + ) + ) +) diff --git a/testdata/lvs/must_connect1.sch b/testdata/lvs/must_connect1.sch new file mode 100644 index 000000000..9114c6de9 --- /dev/null +++ b/testdata/lvs/must_connect1.sch @@ -0,0 +1,24 @@ + +.SUBCKT TOP +X$1 VDD VSS A 1 1 3 INVCHAIN +X$2 VDD VSS 3 2 2 Q INV2 +.ENDS TOP + +* cell INVCHAIN +.SUBCKT INVCHAIN VDD VSS A1 Q1 A2 Q2 +X$2 VDD VSS A1 1 1 Q1 INV2 +X$3 VDD VSS A2 2 2 Q2 INV2 +.ENDS INVCHAIN + +* cell INV2 +.SUBCKT INV2 VDD VSS A1 Q1 A2 Q2 +X$1 VDD VSS A1 Q1 INV +X$2 VDD VSS A2 Q2 INV +.ENDS INV2 + +* cell INV +.SUBCKT INV VDD VSS A Q +M$1 VDD A Q VDD PMOS L=0.25U W=0.95U +M$3 VSS A Q VSS NMOS L=0.25U W=0.95U +.ENDS INV + diff --git a/testdata/lvs/must_connect2.cir b/testdata/lvs/must_connect2.cir new file mode 100644 index 000000000..fc641f467 --- /dev/null +++ b/testdata/lvs/must_connect2.cir @@ -0,0 +1,23 @@ +* Extracted by KLayout + +.SUBCKT TOP VSSTOP A Q VDD +X$1 VDD \$2 \$1 \$1 Q VSSTOP INV2 +X$2 A \$3 VSSTOP \$3 \$2 VDD INVCHAIN +.ENDS TOP + +.SUBCKT INVCHAIN IN IN2 VSS|VSS2|VSS2B OUT OUT2 VDD +X$1 VDD IN2 \$1 \$1 OUT2 VSS|VSS2|VSS2B INV2 +X$2 VDD IN \$2 \$2 OUT VSS|VSS2|VSS2B INV2 +.ENDS INVCHAIN + +.SUBCKT INV2 VDD A1 A2 Q1 Q2 VSS +X$1 VSS VDD A2 Q2 INV +X$2 VSS VDD A1 Q1 INV +.ENDS INV2 + +.SUBCKT INV \$1 \$2 \$3 \$4 +M$1 \$2 \$3 \$4 \$4 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +M$2 \$1 \$3 \$4 \$4 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +.ENDS INV diff --git a/testdata/lvs/must_connect2.gds b/testdata/lvs/must_connect2.gds new file mode 100644 index 0000000000000000000000000000000000000000..885df5c13e257f70e47712c147694f9467e8b786 GIT binary patch literal 4568 zcmbW4TWDNW6o%KFnK^UGG)-fYGMAIgq@zeFiOo$?r8qHCLuzVFtQz{HNWm(;RP;fi z&?xl5x8h6jg27g*h!iiSM$n)^qM+h~q9Q(sg3y{iDKW|MUwiN6IXlcuCMit6vd;PU z+LyKdeM&Al&Vy8lIEgBqnCSMJ2x{; zg?MdU+I6Szt4vH0#gats4u>3an;jzB*An&p)n|Qw{YEBHs}WOF)UQFV)jyCNr!@-XYcplsL`Q(&OE3XqGhn^WZw?*OYke{H){rnvo&a z;b$oE4f);h`q$=>f7bWc=Apx0`emWSnb!P6dgT6DJqKAw9_Um0{GukmTjEnp z?u_E^6>4i?5>E10CQh=bvnHr+eI#9XY~m2R-A5h|8U47~;txvz9^+Jh*b@ffRX?xB{rmA;`G?Nc?HY}NJZ z<|3zvGKKiad#XzDZ?0KBWvP7BZ0K#gRrT%SH`W?LHKfPQOlamN#H-J_#u_$}+x&kz+Cm41qyo!xmW`O|Pb z=UP=gdT{gk$G;%TFOr*eEBmeNjj5N>8Lucc&NMW4IOFEI6Q__{sVD8+jj7K{?n#q- zliJHDf4uYV${5c1|BC9<=V;DUtzqM{jw10W=Czz(t>Y%l2J7+QQR%*bc@qcK z*wysjcSN}-paBafP!G=slsKsLb#IO`_f6q#lL@|~f~MDkTn|8RC~+{nm(u6A ztFIvJqcexQ6WsYb?kuca7=2lvvQXZ0=IW2vc2SR48qj)S@qiv*DDSmh)Z;bY$G9IH zoco7W`?w(=>Usn|G{1cxD&cIqE}Q&zFE^CGGz_=CN@@7u)KuTdHk>TETGL4z@}lfH z)b}M`!Po>EP*sRIfrj+BYbbw>y^Q@~%U<>{dSjTgAGv?p&fbulbz;iN6Gm_L-*^S? z9{I}0JD*^dbD9OzbLw66h@r&6aDQ0(E__4e{=`{>`QK1;a15cuL8afsPw~AuedJ!O z6@Hmfce(afb$dJ5kBITCjeffCQ9OHE=P-UIerkUS53rvVzr<>f5$(lSk0N|u=$$0$ z#kI@46>%d*T>=RV0W1)i&YCH4%XC{-+>;t6tnvZ{sW2=6-peet9RzLKK8HH3ndOJz2%~~ z((JFXJNnh10ey?7_Yk#yu3W78*Vra{?ts<{+t>Ht)@*%h`}&*lH5gqrF3Qcd!Gta~I tW4Tx_zDx>#qy9nfy6JsGiGwxu18dMPq0c}My)$? psd, "G" => pgate, + "tS" => psd, "tD" => psd, "tG" => poly }) + +# NMOS transistor device extraction +extract_devices(mos3("NMOS"), { "SD" => nsd, "G" => ngate, + "tS" => nsd, "tD" => nsd, "tG" => poly }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, diff_cont) +connect(nsd, diff_cont) +connect(poly, poly_cont) +connect(diff_cont, metal1) +connect(poly_cont, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# attach labels +connect(poly, poly_lbl) +connect(metal1, metal1_lbl) +connect(metal2, metal2_lbl) + +# Global +connect_global(bulk, "SUBSTRATE") + +# Compare section + +netlist.simplify +align + +# Skip as we have errors .. +compare + diff --git a/testdata/lvs/must_connect2.lvsdb b/testdata/lvs/must_connect2.lvsdb new file mode 100644 index 000000000..b3fd8d3a3 --- /dev/null +++ b/testdata/lvs/must_connect2.lvsdb @@ -0,0 +1,490 @@ +#%lvsdb-klayout +J( + W(TOP) + U(0.001) + L(l3 '3/0') + L(l11 '3/1') + L(l6 '4/0') + L(l7 '5/0') + L(l8 '6/0') + L(l12 '6/1') + L(l9 '7/0') + L(l10 '8/0') + L(l13 '8/1') + L(l14) + L(l2) + L(l5) + C(l3 l3 l11 l7) + C(l11 l3 l11) + C(l6 l6 l8 l2 l5) + C(l7 l3 l7 l8) + C(l8 l6 l7 l8 l12 l9) + C(l12 l8 l12) + C(l9 l8 l9 l10) + C(l10 l9 l10 l13) + C(l13 l10 l13) + C(l14 l14) + C(l2 l6 l2) + C(l5 l6 l5) + G(l14 SUBSTRATE) + H(W B('Must-connect nets VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) + H(W B('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) + H(E B('Must-connect nets VSS of circuit INV2 are not connected') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) + K(PMOS MOS3) + K(NMOS MOS3) + D(D$PMOS PMOS + T(S + R(l2 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l2 (125 -475) (775 950)) + ) + ) + D(D$NMOS NMOS + T(S + R(l5 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l5 (125 -475) (775 950)) + ) + ) + X(INV + R((-1500 -800) (3000 4600)) + N(1 + R(l6 (290 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l5 (-1375 -925) (775 950)) + ) + N(2 + R(l6 (290 2490) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l2 (-1375 -925) (775 950)) + ) + N(3 + R(l3 (-125 -250) (250 2500)) + R(l3 (-250 -3050) (250 1600)) + R(l3 (-250 1200) (250 1600)) + ) + N(4 + R(l6 (-510 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l6 (-220 2180) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -3530) (360 2840)) + R(l8 (-360 -2800) (360 760)) + R(l8 (-360 2040) (360 760)) + R(l2 (-680 -855) (775 950)) + R(l5 (-775 -3750) (775 950)) + ) + P(1) + P(2) + P(3) + P(4) + D(1 D$PMOS + Y(0 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 2) + ) + D(2 D$NMOS + Y(0 0) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 1) + ) + ) + X(INV2 + R((0 0) (3000 9200)) + N(1 I(VDD) + R(l10 (0 3150) (3000 2900)) + R(l13 (-1890 -1450) (0 0)) + ) + N(2 I(A1) + R(l11 (1480 7110) (0 0)) + ) + N(3 I(A2) + R(l11 (1520 1950) (0 0)) + ) + N(4 I(Q1) + R(l12 (1920 7070) (0 0)) + ) + N(5 I(Q2) + R(l12 (1940 1950) (0 0)) + ) + N(6 I(VSS) + R(l13 (2680 8390) (0 0)) + R(l13 (-30 -7640) (0 0)) + ) + P(1 I(VDD)) + P(2 I(A1)) + P(3 I(A2)) + P(4 I(Q1)) + P(5 I(Q2)) + P(6 I(VSS)) + X(1 INV M O(180) Y(1500 800) + P(0 6) + P(1 1) + P(2 3) + P(3 5) + ) + X(2 INV O(180) Y(1500 8400) + P(0 6) + P(1 1) + P(2 2) + P(3 4) + ) + ) + X(INVCHAIN + R((-915 -15) (10415 9215)) + N(1 + R(l3 (7340 1650) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(2 + R(l3 (1625 1835) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(3 I(IN) + R(l3 (-90 6850) (1590 650)) + R(l11 (-700 -350) (0 0)) + ) + N(4 I(IN2) + R(l3 (5665 6790) (1590 650)) + R(l11 (-700 -350) (0 0)) + ) + N(5 I('VSS,VSS2,VSS2B') + R(l10 (-915 5290) (250 2960)) + R(l10 (-250 0) (915 250)) + R(l10 (-915 -7825) (915 250)) + R(l10 (-915 0) (250 3145)) + R(l13 (155 4305) (0 0)) + R(l13 (8990 -255) (0 0)) + R(l13 (25 -7115) (0 0)) + ) + N(6 I(OUT) + R(l12 (1890 2105) (0 0)) + ) + N(7 I(OUT2) + R(l12 (7730 2155) (0 0)) + ) + N(8 I(VDD) + R(l13 (8035 4540) (0 0)) + R(l13 (-5735 60) (0 0)) + ) + P(3 I(IN)) + P(4 I(IN2)) + P(5 I('VSS,VSS2,VSS2B')) + P(6 I(OUT)) + P(7 I(OUT2)) + P(8 I(VDD)) + X(1 INV2 Y(5780 -15) + P(0 8) + P(1 4) + P(2 1) + P(3 1) + P(4 7) + P(5 5) + ) + X(2 INV2 Y(0 0) + P(0 8) + P(1 3) + P(2 2) + P(3 2) + P(4 6) + P(5 5) + ) + ) + X(TOP + R((-305 350) (15415 9225)) + N(1 + R(l3 (12950 2130) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(2 + R(l3 (12100 7300) (640 530)) + R(l7 (-540 -415) (270 250)) + R(l8 (-1695 -250) (1695 250)) + R(l8 (-4075 -5650) (2630 250)) + R(l8 (-250 0) (250 5150)) + ) + N(3 + R(l7 (6465 7325) (220 240)) + R(l8 (-4100 -5365) (3125 250)) + R(l8 (-250 0) (250 4860)) + R(l8 (-250 0) (1225 250)) + ) + N(4 I(VSSTOP) + R(l10 (3610 8300) (2815 440)) + R(l10 (-710 -250) (0 0)) + R(l10 (3675 -165) (1975 565)) + R(l10 (-1975 -8190) (1975 575)) + R(l10 (-1005 -255) (0 0)) + ) + N(5 I(A) + R(l11 (975 7530) (0 0)) + ) + N(6 I(Q) + R(l12 (13260 2010) (0 0)) + ) + N(7 I(VDD) + R(l10 (2595 4805) (0 0)) + R(l10 (4295 -30) (0 0)) + R(l10 (4975 -50) (0 0)) + ) + P(4 I(VSSTOP)) + P(5 I(A)) + P(6 I(Q)) + P(7 I(VDD)) + X(1 INV2 Y(11365 375) + P(0 7) + P(1 2) + P(2 1) + P(3 1) + P(4 6) + P(5 4) + ) + X(2 INVCHAIN Y(610 365) + P(0 5) + P(1 3) + P(2 4) + P(3 3) + P(4 2) + P(5 7) + ) + ) +) +H( + K(PMOS MOS3) + K(NMOS MOS3) + X(INV + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A)) + N(4 I(Q)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A)) + P(4 I(Q)) + D(1 PMOS + I($1) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 1) + T(G 3) + T(D 4) + ) + D(2 NMOS + I($3) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 2) + T(G 3) + T(D 4) + ) + ) + X(INV2 + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A1)) + N(4 I(Q1)) + N(5 I(A2)) + N(6 I(Q2)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A1)) + P(4 I(Q1)) + P(5 I(A2)) + P(6 I(Q2)) + X(1 INV I($1) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + ) + X(2 INV I($2) + P(0 1) + P(1 2) + P(2 5) + P(3 6) + ) + ) + X(INVCHAIN + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A1)) + N(4 I(Q1)) + N(5 I(A2)) + N(6 I(Q2)) + N(7 I('1')) + N(8 I('2')) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A1)) + P(4 I(Q1)) + P(5 I(A2)) + P(6 I(Q2)) + X(1 INV2 I($2) + P(0 1) + P(1 2) + P(2 3) + P(3 7) + P(4 7) + P(5 4) + ) + X(2 INV2 I($3) + P(0 1) + P(1 2) + P(2 5) + P(3 8) + P(4 8) + P(5 6) + ) + ) + X(TOP + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A)) + N(4 I('1')) + N(5 I('3')) + N(6 I('2')) + N(7 I(Q)) + X(1 INVCHAIN I($1) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + P(4 4) + P(5 5) + ) + X(2 INV2 I($2) + P(0 1) + P(1 2) + P(2 5) + P(3 6) + P(4 6) + P(5 7) + ) + ) +) +Z( + X(INV INV 1 + Z( + N(3 3 1) + N(4 4 1) + N(2 1 1) + N(1 2 1) + P(2 2 1) + P(3 3 1) + P(1 0 1) + P(0 1 1) + D(2 2 1) + D(1 1 1) + ) + ) + X(INV2 INV2 1 + Z( + N(2 3 1) + N(3 5 1) + N(4 4 1) + N(5 6 1) + N(1 1 1) + N(6 2 1) + P(1 2 1) + P(2 4 1) + P(3 3 1) + P(4 5 1) + P(0 0 1) + P(5 1 1) + X(2 1 1) + X(1 2 1) + ) + ) + X(INVCHAIN INVCHAIN 1 + L( + M(W B('Matching nets OUT vs. Q1 from an ambiguous group of nets')) + M(W B('Matching nets OUT2 vs. Q2 from an ambiguous group of nets')) + M(I B('Matching nets $2 vs. 1 following an ambiguous match')) + M(I B('Matching nets IN vs. A1 following an ambiguous match')) + M(I B('Matching nets $1 vs. 2 following an ambiguous match')) + M(I B('Matching nets IN2 vs. A2 following an ambiguous match')) + ) + Z( + N(2 7 1) + N(1 8 1) + N(3 3 1) + N(4 5 1) + N(6 4 W) + N(7 6 W) + N(8 1 1) + N(5 2 1) + P(0 2 1) + P(1 4 1) + P(3 3 1) + P(4 5 1) + P(5 0 1) + P(2 1 1) + X(2 1 1) + X(1 2 1) + ) + ) + X(TOP TOP 1 + Z( + N(3 4 1) + N(1 6 1) + N(2 5 1) + N(5 3 1) + N(6 7 1) + N(7 1 1) + N(4 2 1) + P(1 () 1) + P(2 () 1) + P(3 () 1) + P(0 () 1) + X(1 2 1) + X(2 1 1) + ) + ) +) diff --git a/testdata/lvs/must_connect2.sch b/testdata/lvs/must_connect2.sch new file mode 100644 index 000000000..9114c6de9 --- /dev/null +++ b/testdata/lvs/must_connect2.sch @@ -0,0 +1,24 @@ + +.SUBCKT TOP +X$1 VDD VSS A 1 1 3 INVCHAIN +X$2 VDD VSS 3 2 2 Q INV2 +.ENDS TOP + +* cell INVCHAIN +.SUBCKT INVCHAIN VDD VSS A1 Q1 A2 Q2 +X$2 VDD VSS A1 1 1 Q1 INV2 +X$3 VDD VSS A2 2 2 Q2 INV2 +.ENDS INVCHAIN + +* cell INV2 +.SUBCKT INV2 VDD VSS A1 Q1 A2 Q2 +X$1 VDD VSS A1 Q1 INV +X$2 VDD VSS A2 Q2 INV +.ENDS INV2 + +* cell INV +.SUBCKT INV VDD VSS A Q +M$1 VDD A Q VDD PMOS L=0.25U W=0.95U +M$3 VSS A Q VSS NMOS L=0.25U W=0.95U +.ENDS INV + From 2c88f7753d964dd3eb0bcbd0459a2715d495d399 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 21:57:16 +0200 Subject: [PATCH 30/41] Bug fix --- src/db/db/dbLayoutToNetlist.cc | 66 +++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 0ba3b4cab..2da483769 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -451,12 +451,22 @@ void LayoutToNetlist::do_join_nets (db::Circuit &c, const std::vector static std::string subcircuit_to_string (const db::SubCircuit &sc) { if (! sc.name ().empty ()) { - return tl::to_string (tr ("on subcircuit ")) + sc.name () + tl::to_string (tr (" in ")) + sc.circuit ()->name (); + return tl::to_string (tr (" on subcircuit ")) + sc.name (); } else { - return tl::to_string (tr ("in ")) + sc.circuit ()->name (); + return std::string (); } } +static db::DPolygon subcircuit_geometry (const db::SubCircuit &sc, const db::Layout *layout) +{ + if (! layout || ! sc.circuit_ref () || ! layout->is_valid_cell_index (sc.circuit_ref ()->cell_index ())) { + return db::DPolygon (); + } + + db::DBox dbox = db::CplxTrans (layout->dbu ()) * layout->cell (sc.circuit_ref ()->cell_index ()).bbox (); + return db::DPolygon (sc.trans () * dbox); +} + void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a, const db::Net &b) { if (&a == &b) { @@ -467,21 +477,25 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a if (a.begin_pins () == a.end_pins ()) { db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected to outside")), a.expanded_name ())); error.set_cell_name (c.name ()); + error.set_category_name ("must-connect"); log_entry (error); } if (b.begin_pins () == b.end_pins ()) { db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected to outside")), a.expanded_name ())); error.set_cell_name (c.name ()); + error.set_category_name ("must-connect"); log_entry (error); } } else { if (a.expanded_name () == b.expanded_name ()) { - db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at the chip top level")), a.expanded_name ())); + db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at chip top level")), a.expanded_name ())); warn.set_cell_name (c.name ()); + warn.set_category_name ("must-connect"); log_entry (warn); } else { - db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at the chip top level")), a.expanded_name (), b.expanded_name ())); + db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at chip top level")), a.expanded_name (), b.expanded_name ())); warn.set_cell_name (c.name ()); + warn.set_category_name ("must-connect"); log_entry (warn); } } @@ -493,23 +507,31 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a const db::Net *net_a = sc.net_for_pin (a.begin_pins ()->pin_id ()); const db::Net *net_b = sc.net_for_pin (b.begin_pins ()->pin_id ()); if (net_a == 0) { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected at all %s")), a.expanded_name (), subcircuit_to_string (sc))); - error.set_cell_name (c.name ()); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), a.expanded_name (), c.name (), subcircuit_to_string (sc))); + error.set_cell_name (sc.circuit ()->name ()); + error.set_geometry (subcircuit_geometry (sc, internal_layout ())); + error.set_category_name ("must-connect"); log_entry (error); } if (net_b == 0) { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s is not connected at all %s")), b.expanded_name (), subcircuit_to_string (sc))); - error.set_cell_name (c.name ()); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect net %s of circuit %s is not connected at all%s")), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + error.set_cell_name (sc.circuit ()->name ()); + error.set_geometry (subcircuit_geometry (sc, internal_layout ())); + error.set_category_name ("must-connect"); log_entry (error); } if (net_a && net_b && net_a != net_b) { - if (net_a->expanded_name () == net_b->expanded_name ()) { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect nets %s are not connected %s")), a.expanded_name (), subcircuit_to_string (sc))); - error.set_cell_name (c.name ()); + if (a.expanded_name () == b.expanded_name ()) { + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect nets %s of circuit %s are not connected%s")), a.expanded_name (), c.name (), subcircuit_to_string (sc))); + error.set_cell_name (sc.circuit ()->name ()); + error.set_geometry (subcircuit_geometry (sc, internal_layout ())); + error.set_category_name ("must-connect"); log_entry (error); } else { - db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s are not connected %s")), a.expanded_name (), b.expanded_name (), subcircuit_to_string (sc))); - error.set_cell_name (c.name ()); + db::LogEntryData error (db::Error, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s of circuit %s are not connected%s")), a.expanded_name (), b.expanded_name (), c.name (), subcircuit_to_string (sc))); + error.set_cell_name (sc.circuit ()->name ()); + error.set_geometry (subcircuit_geometry (sc, internal_layout ())); + error.set_category_name ("must-connect"); log_entry (error); } } @@ -526,32 +548,28 @@ void LayoutToNetlist::do_join_nets () // prevents updates NetlistLocker locked_netlist (mp_netlist.get ()); - for (auto jn = m_joined_net_names.begin (); jn != m_joined_net_names.end (); ++jn) { - for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + + for (auto jn = m_joined_net_names.begin (); jn != m_joined_net_names.end (); ++jn) { join_nets_from_pattern (*c, *jn); } - } - for (auto jn = m_joined_nets.begin (); jn != m_joined_nets.end (); ++jn) { - for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + for (auto jn = m_joined_nets.begin (); jn != m_joined_nets.end (); ++jn) { join_nets_from_pattern (*c, *jn); } - } - for (auto jn = m_joined_net_names_per_cell.begin (); jn != m_joined_net_names_per_cell.end (); ++jn) { - for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + for (auto jn = m_joined_net_names_per_cell.begin (); jn != m_joined_net_names_per_cell.end (); ++jn) { if (jn->first.match (c->name ())) { join_nets_from_pattern (*c, jn->second); } } - } - for (auto jn = m_joined_nets_per_cell.begin (); jn != m_joined_nets_per_cell.end (); ++jn) { - for (auto c = mp_netlist->begin_top_down (); c != mp_netlist->end_top_down (); ++c) { + for (auto jn = m_joined_nets_per_cell.begin (); jn != m_joined_nets_per_cell.end (); ++jn) { if (jn->first.match (c->name ())) { join_nets_from_pattern (*c, jn->second); } } + } } From e9eb8e7ebca22e0e041876e68a5989d37a724223 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 21:57:50 +0200 Subject: [PATCH 31/41] Using categories for device extractor errors --- src/db/db/dbNetlistDeviceExtractor.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 581861ac7..e5541ee98 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -548,6 +548,7 @@ std::string NetlistDeviceExtractor::cell_name () const void NetlistDeviceExtractor::error (const std::string &msg) { m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::error << m_log_entries.back ().to_string (); @@ -558,6 +559,7 @@ void NetlistDeviceExtractor::error (const std::string &msg, const db::DPolygon & { m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); m_log_entries.back ().set_geometry (poly); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::error << m_log_entries.back ().to_string (); @@ -569,6 +571,7 @@ void NetlistDeviceExtractor::error (const std::string &category_name, const std: m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::error << m_log_entries.back ().to_string (); @@ -581,6 +584,7 @@ void NetlistDeviceExtractor::error (const std::string &category_name, const std: m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); m_log_entries.back ().set_geometry (poly); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::error << m_log_entries.back ().to_string (); @@ -590,6 +594,7 @@ void NetlistDeviceExtractor::error (const std::string &category_name, const std: void NetlistDeviceExtractor::warn (const std::string &msg) { m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::warn << m_log_entries.back ().to_string (); @@ -600,6 +605,7 @@ void NetlistDeviceExtractor::warn (const std::string &msg, const db::DPolygon &p { m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); m_log_entries.back ().set_geometry (poly); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::warn << m_log_entries.back ().to_string (); @@ -611,6 +617,7 @@ void NetlistDeviceExtractor::warn (const std::string &category_name, const std:: m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::warn << m_log_entries.back ().to_string (); @@ -623,6 +630,7 @@ void NetlistDeviceExtractor::warn (const std::string &category_name, const std:: m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); m_log_entries.back ().set_geometry (poly); + m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::warn << m_log_entries.back ().to_string (); From 5b9087c8648cda5b9c3b99b92bdba960ae10b7b6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 21:58:04 +0200 Subject: [PATCH 32/41] Added LVS tests --- src/lvs/unit_tests/lvsSimpleTests.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 7fb2b8ae4..5a8c838e3 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -275,3 +275,13 @@ TEST(29_DeviceCombineAndTolerances) run_test (_this, "res_combine2", "res_combine.gds"); run_test (_this, "res_combine3", "res_combine.gds"); } + +TEST(30_MustConnect1) +{ + run_test (_this, "must_connect1", "must_connect1.gds"); +} + +TEST(31_MustConnect2) +{ + run_test (_this, "must_connect2", "must_connect2.gds"); +} From e71a4dfb92ceffa86c3062f26fe276e2f9554631 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 22:13:19 +0200 Subject: [PATCH 33/41] Simplified test code --- src/db/unit_tests/dbLayoutToNetlistTests.cc | 309 +++++--------------- 1 file changed, 78 insertions(+), 231 deletions(-) diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index b36e38a07..753302d07 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -3131,234 +3131,6 @@ TEST(12_FlattenCircuitDoesFlattenLayout) db::compare_layouts (_this, ly, au); } -TEST(13_JoinNetNames) -{ - db::Layout ly; - db::LayerMap lmap; - - unsigned int nwell = define_layer (ly, lmap, 1); - unsigned int active = define_layer (ly, lmap, 2); - unsigned int pplus = define_layer (ly, lmap, 10); - unsigned int nplus = define_layer (ly, lmap, 11); - unsigned int poly = define_layer (ly, lmap, 3); - unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); - unsigned int diff_cont = define_layer (ly, lmap, 4); - unsigned int poly_cont = define_layer (ly, lmap, 5); - unsigned int metal1 = define_layer (ly, lmap, 6); - unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); - unsigned int via1 = define_layer (ly, lmap, 7); - unsigned int metal2 = define_layer (ly, lmap, 8); - unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); - - { - db::LoadLayoutOptions options; - options.get_options ().layer_map = lmap; - options.get_options ().create_other_layers = false; - - std::string fn (tl::testdata ()); - fn = tl::combine_path (fn, "algo"); - fn = tl::combine_path (fn, "device_extract_l13.gds"); - - tl::InputStream stream (fn); - db::Reader reader (stream); - reader.read (ly, options); - } - - db::Cell &tc = ly.cell (*ly.begin_top_down ()); - db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); - - std::unique_ptr rbulk (l2n.make_layer ("bulk")); - std::unique_ptr rnwell (l2n.make_layer (nwell, "nwell")); - std::unique_ptr ractive (l2n.make_layer (active, "active")); - std::unique_ptr rpplus (l2n.make_layer (pplus, "pplus")); - std::unique_ptr rnplus (l2n.make_layer (nplus, "nplus")); - std::unique_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::unique_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); - std::unique_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); - std::unique_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); - std::unique_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::unique_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); - std::unique_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); - std::unique_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::unique_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); - - // derived regions - - db::Region ractive_in_nwell = *ractive & *rnwell; - db::Region rpactive = ractive_in_nwell & *rpplus; - db::Region rntie = ractive_in_nwell & *rnplus; - db::Region rpgate = rpactive & *rpoly; - db::Region rpsd = rpactive - rpgate; - - db::Region ractive_outside_nwell = *ractive - *rnwell; - db::Region rnactive = ractive_outside_nwell & *rnplus; - db::Region rptie = ractive_outside_nwell & *rpplus; - db::Region rngate = rnactive & *rpoly; - db::Region rnsd = rnactive - rngate; - - // return the computed layers into the original layout and write it for debugging purposes - - unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate - unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain - unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion - unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion - unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie - unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie - - rpgate.insert_into (&ly, tc.cell_index (), lgate); - rngate.insert_into (&ly, tc.cell_index (), lgate); - rpsd.insert_into (&ly, tc.cell_index (), lsd); - rnsd.insert_into (&ly, tc.cell_index (), lsd); - rpsd.insert_into (&ly, tc.cell_index (), lpdiff); - rnsd.insert_into (&ly, tc.cell_index (), lndiff); - rpsd.insert_into (&ly, tc.cell_index (), lptie); - rnsd.insert_into (&ly, tc.cell_index (), lntie); - - db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); - db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); - - // device extraction - - db::NetlistDeviceExtractor::input_layers dl; - - dl["SD"] = &rpsd; - dl["G"] = &rpgate; - dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes - dl["W"] = rnwell.get (); - l2n.extract_devices (pmos_ex, dl); - - dl["SD"] = &rnsd; - dl["G"] = &rngate; - dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes - dl["W"] = rbulk.get (); - l2n.extract_devices (nmos_ex, dl); - - // net extraction - - l2n.register_layer (rpsd, "psd"); - l2n.register_layer (rnsd, "nsd"); - l2n.register_layer (rptie, "ptie"); - l2n.register_layer (rntie, "ntie"); - - // Intra-layer - l2n.connect (rpsd); - l2n.connect (rnsd); - l2n.connect (*rnwell); - l2n.connect (*rpoly); - l2n.connect (*rdiff_cont); - l2n.connect (*rpoly_cont); - l2n.connect (*rmetal1); - l2n.connect (*rvia1); - l2n.connect (*rmetal2); - l2n.connect (rptie); - l2n.connect (rntie); - // Inter-layer - l2n.connect (rpsd, *rdiff_cont); - l2n.connect (rnsd, *rdiff_cont); - l2n.connect (*rpoly, *rpoly_cont); - l2n.connect (*rpoly_cont, *rmetal1); - l2n.connect (*rdiff_cont, *rmetal1); - l2n.connect (*rdiff_cont, rptie); - l2n.connect (*rdiff_cont, rntie); - l2n.connect (*rnwell, rntie); - l2n.connect (*rmetal1, *rvia1); - l2n.connect (*rvia1, *rmetal2); - l2n.connect (*rpoly, *rpoly_lbl); // attaches labels - l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels - l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels - // Global - l2n.connect_global (rntie, "VDD"); - l2n.connect_global (*rnwell, "VDD"); - l2n.connect_global (rptie, "VSS"); - l2n.connect_global (*rbulk, "VSS"); - - // Extract with joining VSS and VDD - l2n.join_net_names (tl::GlobPattern ("{VSS,VDD}")); - l2n.extract_netlist (); - - // debug layers produced for nets - // 201/0 -> Well - // 203/0 -> Poly - // 204/0 -> Diffusion contacts - // 205/0 -> Poly contacts - // 206/0 -> Metal1 - // 207/0 -> Via1 - // 208/0 -> Metal2 - // 210/0 -> N source/drain - // 211/0 -> P source/drain - // 212/0 -> N tie - // 213/0 -> P tie - std::map dump_map; - dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0)); - dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0)); - dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0)); - dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0)); - dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0)); - dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0)); - dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0)); - dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0)); - dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0)); - dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0)); - dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0)); - dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0)); - - // write nets to layout - db::CellMapping cm = l2n.cell_mapping_into (ly, tc); - dump_nets_to_layout (l2n, ly, dump_map, cm); - - dump_map.clear (); - dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0)); - dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0)); - dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0)); - dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0)); - dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0)); - dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0)); - dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0)); - dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0)); - dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0)); - dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0)); - dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0)); - dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0)); - - dump_recursive_nets_to_layout (l2n, ly, dump_map, cm); - - // compare netlist as string - CHECKPOINT (); - db::compare_netlist (_this, *l2n.netlist (), - "circuit RINGO ();\n" - " subcircuit INV2 $1 (IN=$I7,$2=FB,OUT=OSC,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $2 (IN=FB,$2=$I34,OUT=$I17,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $3 (IN=$3,$2=$I38,OUT=$I4,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $4 (IN=$I2,$2=$I37,OUT=$3,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $5 (IN=$I4,$2=$I39,OUT=$I5,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $6 (IN=$I5,$2=$I40,OUT=$I6,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $7 (IN=$I6,$2=$I41,OUT=$I7,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $8 (IN=$I17,$2=$I35,OUT=$I1,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - " subcircuit INV2 $9 (IN=$I1,$2=$I36,OUT=$I2,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" - "end;\n" - "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5,VDD=VDD,VSS=VSS);\n" - " device PMOS $1 (S=$2,G=IN,D=$5,B=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" - " device PMOS $2 (S=$5,G=$2,D=OUT,B=VDD) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" - " device NMOS $3 (S=$2,G=IN,D=$4,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" - " device NMOS $4 (S=$4,G=$2,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" - " subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n" - " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" - " subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n" - " subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n" - "end;\n" - "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" - "end;\n" - ); - - // compare the collected test data - - std::string au = tl::testdata (); - au = tl::combine_path (au, "algo"); - au = tl::combine_path (au, "device_extract_au13_circuits.gds"); - - db::compare_layouts (_this, ly, au); -} - namespace { @@ -3494,9 +3266,6 @@ public: l2n.connect (*rpoly, *rpoly_lbl); // attaches labels l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels - // Global - l2n.connect_global (*rbulk, "BULK"); - l2n.connect_global (rptie, "BULK"); return l2n_p.release (); } @@ -3574,6 +3343,8 @@ public: private: db::Layout &m_ly; db::LayerMap m_lmap; + +public: unsigned int nwell; unsigned int nwell_lbl; unsigned int active; @@ -3617,6 +3388,78 @@ private: } +TEST(13_JoinNetNames) +{ + db::Layout ly; + TestRig test_rig (ly); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = test_rig.lmap (); + options.get_options ().create_other_layers = false; + + std::string fn (tl::testdata ()); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l13.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + std::unique_ptr l2n (test_rig.make_l2n ()); + + // Global + l2n->connect_global (test_rig.rntie, "VDD"); + l2n->connect_global (*test_rig.rnwell, "VDD"); + l2n->connect_global (test_rig.rptie, "VSS"); + l2n->connect_global (*test_rig.rbulk, "VSS"); + + // Extract with joining VSS and VDD + l2n->join_net_names (tl::GlobPattern ("{VSS,VDD}")); + + l2n->extract_netlist (); + + test_rig.dump_nets (*l2n); + test_rig.dump_nets_recursive (*l2n); + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, *l2n->netlist (), + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=$I7,$2=FB,OUT=OSC,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I34,OUT=$I17,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $3 (IN=$3,$2=$I38,OUT=$I4,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $4 (IN=$I2,$2=$I37,OUT=$3,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $5 (IN=$I4,$2=$I39,OUT=$I5,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $6 (IN=$I5,$2=$I40,OUT=$I6,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $7 (IN=$I6,$2=$I41,OUT=$I7,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $8 (IN=$I17,$2=$I35,OUT=$I1,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + " subcircuit INV2 $9 (IN=$I1,$2=$I36,OUT=$I2,$4=VSS,$5=VDD,VDD=VDD,VSS=VSS);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5,VDD=VDD,VSS=VSS);\n" + " device PMOS $1 (S=$2,G=IN,D=$5,B=VDD) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT,B=VDD) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$2,G=IN,D=$4,B=VSS) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT,B=VSS) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n" + " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" + " subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n" + " subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n" + "end;\n" + "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" + "end;\n" + ); + + // compare the collected test data + + std::string au = tl::testdata (); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au13_circuits.gds"); + + db::compare_layouts (_this, ly, au); +} + TEST(14_JoinNets) { db::Layout ly; @@ -3638,6 +3481,10 @@ TEST(14_JoinNets) std::unique_ptr l2n (test_rig.make_l2n ()); + // Global + l2n->connect_global (*test_rig.rbulk, "BULK"); + l2n->connect_global (test_rig.rptie, "BULK"); + // Extract while joining VSS with BULK and VDD with NWELL std::set jn; jn.insert ("VDD"); From b3992ab25cefbed8b10f502e55d4ae0b01de879a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 22:18:33 +0200 Subject: [PATCH 34/41] Simplified test code --- src/db/unit_tests/dbLayoutToNetlistTests.cc | 350 ++++++-------------- 1 file changed, 98 insertions(+), 252 deletions(-) diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 753302d07..940173167 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -2879,258 +2879,6 @@ TEST(11_DuplicateInstances) ); } -TEST(12_FlattenCircuitDoesFlattenLayout) -{ - db::Layout ly; - db::LayerMap lmap; - - unsigned int nwell = define_layer (ly, lmap, 1); - unsigned int active = define_layer (ly, lmap, 2); - unsigned int pplus = define_layer (ly, lmap, 10); - unsigned int nplus = define_layer (ly, lmap, 11); - unsigned int poly = define_layer (ly, lmap, 3); - unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); - unsigned int diff_cont = define_layer (ly, lmap, 4); - unsigned int poly_cont = define_layer (ly, lmap, 5); - unsigned int metal1 = define_layer (ly, lmap, 6); - unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); - unsigned int via1 = define_layer (ly, lmap, 7); - unsigned int metal2 = define_layer (ly, lmap, 8); - unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); - - { - db::LoadLayoutOptions options; - options.get_options ().layer_map = lmap; - options.get_options ().create_other_layers = false; - - std::string fn (tl::testdata ()); - fn = tl::combine_path (fn, "algo"); - fn = tl::combine_path (fn, "device_extract_l5.gds"); - - tl::InputStream stream (fn); - db::Reader reader (stream); - reader.read (ly, options); - } - - db::Cell &tc = ly.cell (*ly.begin_top_down ()); - db::LayoutToNetlist l2n (db::RecursiveShapeIterator (ly, tc, std::set ())); - - std::unique_ptr rbulk (l2n.make_layer ("bulk")); - std::unique_ptr rnwell (l2n.make_layer (nwell, "nwell")); - std::unique_ptr ractive (l2n.make_layer (active, "active")); - std::unique_ptr rpplus (l2n.make_layer (pplus, "pplus")); - std::unique_ptr rnplus (l2n.make_layer (nplus, "nplus")); - std::unique_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::unique_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); - std::unique_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); - std::unique_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); - std::unique_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::unique_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); - std::unique_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); - std::unique_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::unique_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); - - // derived regions - - db::Region ractive_in_nwell = *ractive & *rnwell; - db::Region rpactive = ractive_in_nwell & *rpplus; - db::Region rntie = ractive_in_nwell & *rnplus; - db::Region rpgate = rpactive & *rpoly; - db::Region rpsd = rpactive - rpgate; - - db::Region ractive_outside_nwell = *ractive - *rnwell; - db::Region rnactive = ractive_outside_nwell & *rnplus; - db::Region rptie = ractive_outside_nwell & *rpplus; - db::Region rngate = rnactive & *rpoly; - db::Region rnsd = rnactive - rngate; - - // return the computed layers into the original layout and write it for debugging purposes - - unsigned int lgate = ly.insert_layer (db::LayerProperties (20, 0)); // 20/0 -> Gate - unsigned int lsd = ly.insert_layer (db::LayerProperties (21, 0)); // 21/0 -> Source/Drain - unsigned int lpdiff = ly.insert_layer (db::LayerProperties (22, 0)); // 22/0 -> P Diffusion - unsigned int lndiff = ly.insert_layer (db::LayerProperties (23, 0)); // 23/0 -> N Diffusion - unsigned int lptie = ly.insert_layer (db::LayerProperties (24, 0)); // 24/0 -> P Tie - unsigned int lntie = ly.insert_layer (db::LayerProperties (25, 0)); // 25/0 -> N Tie - - rpgate.insert_into (&ly, tc.cell_index (), lgate); - rngate.insert_into (&ly, tc.cell_index (), lgate); - rpsd.insert_into (&ly, tc.cell_index (), lsd); - rnsd.insert_into (&ly, tc.cell_index (), lsd); - rpsd.insert_into (&ly, tc.cell_index (), lpdiff); - rnsd.insert_into (&ly, tc.cell_index (), lndiff); - rpsd.insert_into (&ly, tc.cell_index (), lptie); - rnsd.insert_into (&ly, tc.cell_index (), lntie); - - db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); - db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); - - // device extraction - - db::NetlistDeviceExtractor::input_layers dl; - - dl["SD"] = &rpsd; - dl["G"] = &rpgate; - dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes - dl["W"] = rnwell.get (); - l2n.extract_devices (pmos_ex, dl); - - dl["SD"] = &rnsd; - dl["G"] = &rngate; - dl["P"] = rpoly.get (); // not needed for extraction but to return terminal shapes - dl["W"] = rbulk.get (); - l2n.extract_devices (nmos_ex, dl); - - // net extraction - - l2n.register_layer (rpsd, "psd"); - l2n.register_layer (rnsd, "nsd"); - l2n.register_layer (rptie, "ptie"); - l2n.register_layer (rntie, "ntie"); - - // Intra-layer - l2n.connect (rpsd); - l2n.connect (rnsd); - l2n.connect (*rnwell); - l2n.connect (*rpoly); - l2n.connect (*rdiff_cont); - l2n.connect (*rpoly_cont); - l2n.connect (*rmetal1); - l2n.connect (*rvia1); - l2n.connect (*rmetal2); - l2n.connect (rptie); - l2n.connect (rntie); - // Inter-layer - l2n.connect (rpsd, *rdiff_cont); - l2n.connect (rnsd, *rdiff_cont); - l2n.connect (*rpoly, *rpoly_cont); - l2n.connect (*rpoly_cont, *rmetal1); - l2n.connect (*rdiff_cont, *rmetal1); - l2n.connect (*rdiff_cont, rptie); - l2n.connect (*rdiff_cont, rntie); - l2n.connect (*rnwell, rntie); - l2n.connect (*rmetal1, *rvia1); - l2n.connect (*rvia1, *rmetal2); - l2n.connect (*rpoly, *rpoly_lbl); // attaches labels - l2n.connect (*rmetal1, *rmetal1_lbl); // attaches labels - l2n.connect (*rmetal2, *rmetal2_lbl); // attaches labels - // Global - l2n.connect_global (rptie, "BULK"); - l2n.connect_global (*rbulk, "BULK"); - - // create some mess - we have to keep references to the layers to make them not disappear - rmetal1_lbl.reset (0); - rmetal2_lbl.reset (0); - rpoly_lbl.reset (0); - - l2n.extract_netlist (); - - l2n.netlist ()->flatten_circuit (l2n.netlist ()->circuit_by_name ("INV2")); - l2n.netlist ()->flatten_circuit (l2n.netlist ()->circuit_by_name ("INV2PAIR")); - l2n.netlist ()->flatten_circuit (l2n.netlist ()->circuit_by_name ("TRANS")); - - // debug layers produced for nets - // 201/0 -> Well - // 203/0 -> Poly - // 204/0 -> Diffusion contacts - // 205/0 -> Poly contacts - // 206/0 -> Metal1 - // 207/0 -> Via1 - // 208/0 -> Metal2 - // 210/0 -> N source/drain - // 211/0 -> P source/drain - // 212/0 -> N tie - // 213/0 -> P tie - std::map dump_map; - dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (210, 0)); - dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (211, 0)); - dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (212, 0)); - dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (213, 0)); - dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (214, 0)); - dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (201, 0)); - dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (203, 0)); - dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (204, 0)); - dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (205, 0)); - dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (206, 0)); - dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (207, 0)); - dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (208, 0)); - - // write nets to layout - db::CellMapping cm = l2n.cell_mapping_into (ly, tc); - dump_nets_to_layout (l2n, ly, dump_map, cm); - - dump_map.clear (); - dump_map [&rpsd ] = ly.insert_layer (db::LayerProperties (310, 0)); - dump_map [&rnsd ] = ly.insert_layer (db::LayerProperties (311, 0)); - dump_map [&rptie ] = ly.insert_layer (db::LayerProperties (312, 0)); - dump_map [&rntie ] = ly.insert_layer (db::LayerProperties (313, 0)); - dump_map [rbulk.get () ] = ly.insert_layer (db::LayerProperties (314, 0)); - dump_map [rnwell.get () ] = ly.insert_layer (db::LayerProperties (301, 0)); - dump_map [rpoly.get () ] = ly.insert_layer (db::LayerProperties (303, 0)); - dump_map [rdiff_cont.get ()] = ly.insert_layer (db::LayerProperties (304, 0)); - dump_map [rpoly_cont.get ()] = ly.insert_layer (db::LayerProperties (305, 0)); - dump_map [rmetal1.get () ] = ly.insert_layer (db::LayerProperties (306, 0)); - dump_map [rvia1.get () ] = ly.insert_layer (db::LayerProperties (307, 0)); - dump_map [rmetal2.get () ] = ly.insert_layer (db::LayerProperties (308, 0)); - - dump_recursive_nets_to_layout (l2n, ly, dump_map, cm); - - // compare netlist as string - CHECKPOINT (); - db::compare_netlist (_this, *l2n.netlist (), - "circuit RINGO ();\n" - " device PMOS $1 (S=FB,G=$I7,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $2 (S=VDD,G=$I7,D=FB,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $3 (S=FB,G=$I7,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $4 (S=VSS,G=$I7,D=FB,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $5 (S=OSC,G=FB,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $6 (S=VDD,G=FB,D=OSC,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $7 (S=OSC,G=FB,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $8 (S=VSS,G=FB,D=OSC,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $9 (S=$I22,G=FB,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $10 (S=VDD,G=FB,D=$I22,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $11 (S=$I22,G=FB,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $12 (S=VSS,G=FB,D=$I22,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $13 (S=$I13,G=$I22,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $14 (S=VDD,G=$I22,D=$I13,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $15 (S=$I13,G=$I22,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $16 (S=VSS,G=$I22,D=$I13,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $17 (S=$I23,G=$I13,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $18 (S=VDD,G=$I13,D=$I23,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $19 (S=$I23,G=$I13,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $20 (S=VSS,G=$I13,D=$I23,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $21 (S=$I5,G=$I23,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $22 (S=VDD,G=$I23,D=$I5,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $23 (S=$I5,G=$I23,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $24 (S=VSS,G=$I23,D=$I5,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $25 (S=$I24,G=$I5,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $26 (S=VDD,G=$I5,D=$I24,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $27 (S=$I24,G=$I5,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $28 (S=VSS,G=$I5,D=$I24,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $29 (S=$I6,G=$I24,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $30 (S=VDD,G=$I24,D=$I6,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $31 (S=$I6,G=$I24,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $32 (S=VSS,G=$I24,D=$I6,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $33 (S=$I25,G=$I6,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $34 (S=VDD,G=$I6,D=$I25,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $35 (S=$I25,G=$I6,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $36 (S=VSS,G=$I6,D=$I25,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device PMOS $37 (S=$I7,G=$I25,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device PMOS $38 (S=VDD,G=$I25,D=$I7,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - " device NMOS $39 (S=$I7,G=$I25,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" - " device NMOS $40 (S=VSS,G=$I25,D=$I7,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" - "end;\n" - ); - - // compare the collected test data - - std::string au = tl::testdata (); - au = tl::combine_path (au, "algo"); - au = tl::combine_path (au, "device_extract_au5_flattened_circuits.gds"); - - db::compare_layouts (_this, ly, au); -} - namespace { @@ -3388,6 +3136,104 @@ public: } +TEST(12_FlattenCircuitDoesFlattenLayout) +{ + db::Layout ly; + TestRig test_rig (ly); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = test_rig.lmap (); + options.get_options ().create_other_layers = false; + + std::string fn (tl::testdata ()); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l5.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + std::unique_ptr l2n (test_rig.make_l2n ()); + + // Global + l2n->connect_global (test_rig.rptie, "BULK"); + l2n->connect_global (*test_rig.rbulk, "BULK"); + + // Extract with joining VSS and VDD + l2n->join_net_names (tl::GlobPattern ("{VSS,VDD}")); + + // create some mess - we have to keep references to the layers to make them not disappear + test_rig.rmetal1_lbl.reset (0); + test_rig.rmetal2_lbl.reset (0); + test_rig.rpoly_lbl.reset (0); + + l2n->extract_netlist (); + + l2n->netlist ()->flatten_circuit (l2n->netlist ()->circuit_by_name ("INV2")); + l2n->netlist ()->flatten_circuit (l2n->netlist ()->circuit_by_name ("INV2PAIR")); + l2n->netlist ()->flatten_circuit (l2n->netlist ()->circuit_by_name ("TRANS")); + + test_rig.dump_nets (*l2n); + test_rig.dump_nets_recursive (*l2n); + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, *l2n->netlist (), + "circuit RINGO ();\n" + " device PMOS $1 (S=FB,G=$I7,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $2 (S=VDD,G=$I7,D=FB,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $3 (S=FB,G=$I7,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $4 (S=VSS,G=$I7,D=FB,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $5 (S=OSC,G=FB,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $6 (S=VDD,G=FB,D=OSC,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $7 (S=OSC,G=FB,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $8 (S=VSS,G=FB,D=OSC,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $9 (S=$I22,G=FB,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $10 (S=VDD,G=FB,D=$I22,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $11 (S=$I22,G=FB,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $12 (S=VSS,G=FB,D=$I22,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $13 (S=$I13,G=$I22,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $14 (S=VDD,G=$I22,D=$I13,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $15 (S=$I13,G=$I22,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $16 (S=VSS,G=$I22,D=$I13,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $17 (S=$I23,G=$I13,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $18 (S=VDD,G=$I13,D=$I23,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $19 (S=$I23,G=$I13,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $20 (S=VSS,G=$I13,D=$I23,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $21 (S=$I5,G=$I23,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $22 (S=VDD,G=$I23,D=$I5,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $23 (S=$I5,G=$I23,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $24 (S=VSS,G=$I23,D=$I5,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $25 (S=$I24,G=$I5,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $26 (S=VDD,G=$I5,D=$I24,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $27 (S=$I24,G=$I5,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $28 (S=VSS,G=$I5,D=$I24,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $29 (S=$I6,G=$I24,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $30 (S=VDD,G=$I24,D=$I6,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $31 (S=$I6,G=$I24,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $32 (S=VSS,G=$I24,D=$I6,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $33 (S=$I25,G=$I6,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $34 (S=VDD,G=$I6,D=$I25,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $35 (S=$I25,G=$I6,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $36 (S=VSS,G=$I6,D=$I25,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device PMOS $37 (S=$I7,G=$I25,D=VDD,B=VDD) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device PMOS $38 (S=VDD,G=$I25,D=$I7,B=VDD) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + " device NMOS $39 (S=$I7,G=$I25,D=VSS,B=VSS) (L=0.25,W=1.75,AS=0.91875,AD=0.48125,PS=4.55,PD=2.3);\n" + " device NMOS $40 (S=VSS,G=$I25,D=$I7,B=VSS) (L=0.25,W=1.75,AS=0.48125,AD=0.91875,PS=2.3,PD=4.55);\n" + "end;\n" + ); + + // compare the collected test data + + std::string au = tl::testdata (); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au5_flattened_circuits.gds"); + + db::compare_layouts (_this, ly, au); +} + TEST(13_JoinNetNames) { db::Layout ly; From 30a5954f7786121ca7aa15d42fcb38ec347acf96 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 22:42:15 +0200 Subject: [PATCH 35/41] Fixed tests --- src/layui/layui/layNetlistBrowserPage.cc | 26 ++++++++++++++++++++++++ src/layui/layui/layNetlistBrowserPage.h | 1 + src/layui/layui/layNetlistLogModel.cc | 13 ++++++++++-- src/layui/layui/layNetlistLogModel.h | 2 ++ testdata/lvs/double_height2.lvsdb | 6 +++--- testdata/lvs/double_height2_texts.lvsdb | 6 +++--- testdata/lvs/test_22a.lvsdb.1 | 2 +- testdata/lvs/test_22a.lvsdb.2 | 2 +- testdata/lvs/test_22b.lvsdb.1 | 2 +- testdata/lvs/test_22b.lvsdb.2 | 2 +- testdata/lvs/test_22c.lvsdb.1 | 2 +- testdata/lvs/test_22c.lvsdb.2 | 2 +- testdata/lvs/test_22c.lvsdb.3 | 2 +- testdata/lvs/test_22d.lvsdb.1 | 2 +- testdata/lvs/test_22d.lvsdb.2 | 2 +- testdata/lvs/test_22d.lvsdb.3 | 2 +- 16 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index 51e4b367c..f879e9e24 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -40,6 +40,7 @@ #include "dbCellMapping.h" #include "dbLayerMapping.h" #include "dbCell.h" +#include "dbLog.h" #include #include @@ -792,6 +793,29 @@ NetlistBrowserPage::navigate_to (const QModelIndex &index, bool fwd) selection_changed (hierarchy_tree, directory_tree); } +void +NetlistBrowserPage::log_selection_changed () +{ + clear_highlights (); + + NetlistLogModel *model = dynamic_cast (log_view->model ()); + tl_assert (model != 0); + + 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 ()) { + + // @@@ TODO: add highlight for error here. + + } + } + } + + update_highlights (); +} + void NetlistBrowserPage::add_to_history (const QModelIndex &index, bool fwd) { @@ -1140,6 +1164,8 @@ NetlistBrowserPage::setup_trees () delete log_view->model (); log_view->setModel (new_model); + connect (log_view->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (log_selection_changed ())); + log_tab_icon = NetlistLogModel::icon_for_severity (new_model->max_severity ()); } else { diff --git a/src/layui/layui/layNetlistBrowserPage.h b/src/layui/layui/layNetlistBrowserPage.h index 258385dd2..aec13cbf5 100644 --- a/src/layui/layui/layNetlistBrowserPage.h +++ b/src/layui/layui/layNetlistBrowserPage.h @@ -211,6 +211,7 @@ private slots: void nl_selection_changed (); void sch_selection_changed (); void xref_selection_changed (); + void log_selection_changed (); void browse_color_for_net (); void select_color_for_net (); diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index c9a85cc53..4b6aa865a 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -182,10 +182,11 @@ NetlistLogModel::icon_for_severity (db::Severity severity) } } -QVariant -NetlistLogModel::data (const QModelIndex &index, int role) const +const db::LogEntryData * +NetlistLogModel::log_entry (const QModelIndex &index) const { const db::LogEntryData *le = 0; + if (index.parent ().isValid ()) { const circuit_entry *ce = (const circuit_entry *) index.internalPointer (); if (ce) { @@ -200,6 +201,14 @@ NetlistLogModel::data (const QModelIndex &index, int role) const } } + return le; +} + +QVariant +NetlistLogModel::data (const QModelIndex &index, int role) const +{ + const db::LogEntryData *le = log_entry (index); + if (role == Qt::DecorationRole) { if (le) { diff --git a/src/layui/layui/layNetlistLogModel.h b/src/layui/layui/layNetlistLogModel.h index bbd26f2eb..670cf389a 100644 --- a/src/layui/layui/layNetlistLogModel.h +++ b/src/layui/layui/layNetlistLogModel.h @@ -52,6 +52,8 @@ public: virtual QVariant data (const QModelIndex &index, int role) const; virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const; + const db::LogEntryData *log_entry (const QModelIndex &index) const; + static QIcon icon_for_severity (db::Severity severity); db::Severity max_severity () const diff --git a/testdata/lvs/double_height2.lvsdb b/testdata/lvs/double_height2.lvsdb index 784d0a7bd..cb79afe2b 100644 --- a/testdata/lvs/double_height2.lvsdb +++ b/testdata/lvs/double_height2.lvsdb @@ -27,9 +27,9 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) - H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) - H(E B('Must-connect nets R are not connected in INVCHAIN') C(INV2)) + H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) + H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) + H(E B('Must-connect nets R of circuit INV2 are not connected') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/double_height2_texts.lvsdb b/testdata/lvs/double_height2_texts.lvsdb index 9314d3a8f..509b5b815 100644 --- a/testdata/lvs/double_height2_texts.lvsdb +++ b/testdata/lvs/double_height2_texts.lvsdb @@ -27,9 +27,9 @@ J( C(l2 l6 l2) C(l5 l6 l5) G(l14 SUBSTRATE) - H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) - H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at the chip top level') C(INVCHAIN)) - H(E B('Must-connect nets R are not connected in INVCHAIN') C(INV2)) + H(W B('Must-connect nets GND must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) + H(W B('Must-connect nets R must be connected further up in the hierarchy - this is an error at chip top level') C(INVCHAIN) X('must-connect')) + H(E B('Must-connect nets R of circuit INV2 are not connected') C(INVCHAIN) X('must-connect') Q('(0,0;0,9.2;3,9.2;3,0)')) K(PMOS MOS3) K(NMOS MOS3) D(D$PMOS PMOS diff --git a/testdata/lvs/test_22a.lvsdb.1 b/testdata/lvs/test_22a.lvsdb.1 index 3b03a7008..ed14452f3 100644 --- a/testdata/lvs/test_22a.lvsdb.1 +++ b/testdata/lvs/test_22a.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22a.lvsdb.2 b/testdata/lvs/test_22a.lvsdb.2 index 7b3f46cb7..653bea80f 100644 --- a/testdata/lvs/test_22a.lvsdb.2 +++ b/testdata/lvs/test_22a.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.1 b/testdata/lvs/test_22b.lvsdb.1 index 0ba4a5715..37f240e44 100644 --- a/testdata/lvs/test_22b.lvsdb.1 +++ b/testdata/lvs/test_22b.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22b.lvsdb.2 b/testdata/lvs/test_22b.lvsdb.2 index 8143cde2e..806634244 100644 --- a/testdata/lvs/test_22b.lvsdb.2 +++ b/testdata/lvs/test_22b.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l6 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.1 b/testdata/lvs/test_22c.lvsdb.1 index dc8c9a02b..f61eaa9e9 100644 --- a/testdata/lvs/test_22c.lvsdb.1 +++ b/testdata/lvs/test_22c.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.2 b/testdata/lvs/test_22c.lvsdb.2 index 041d90937..c85f87ba1 100644 --- a/testdata/lvs/test_22c.lvsdb.2 +++ b/testdata/lvs/test_22c.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22c.lvsdb.3 b/testdata/lvs/test_22c.lvsdb.3 index dfcc716bf..2fbe22102 100644 --- a/testdata/lvs/test_22c.lvsdb.3 +++ b/testdata/lvs/test_22c.lvsdb.3 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.1 b/testdata/lvs/test_22d.lvsdb.1 index a7d57594a..45e3e88fc 100644 --- a/testdata/lvs/test_22d.lvsdb.1 +++ b/testdata/lvs/test_22d.lvsdb.1 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at the chip top level') cell(SP6TArray_2X4)) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.2 b/testdata/lvs/test_22d.lvsdb.2 index bf0e96e24..22c7b9fa6 100644 --- a/testdata/lvs/test_22d.lvsdb.2 +++ b/testdata/lvs/test_22d.lvsdb.2 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) diff --git a/testdata/lvs/test_22d.lvsdb.3 b/testdata/lvs/test_22d.lvsdb.3 index 2a177b469..5c772a9c5 100644 --- a/testdata/lvs/test_22d.lvsdb.3 +++ b/testdata/lvs/test_22d.lvsdb.3 @@ -71,7 +71,7 @@ layout( global(l1 vss) # Log entries - message(warning description('Must-connect nets vdd from circuit SP6TArray_2X4 must be connected further up in the hierarchy. This is an error at the chip top level.')) + message(warning description('Must-connect nets vdd must be connected further up in the hierarchy - this is an error at chip top level') cell(SP6TArray_2X4) cat('must-connect')) # Device class section class(active_res RES) From 883b7e7db8295ebe4c0fce7eb778d289c02a4d46 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 22:45:13 +0200 Subject: [PATCH 36/41] Fixed category assignement in device extractor --- src/db/db/dbNetlistDeviceExtractor.cc | 4 ---- src/db/unit_tests/dbNetlistDeviceExtractorTests.cc | 4 ++-- testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index e5541ee98..7d627695e 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -571,7 +571,6 @@ void NetlistDeviceExtractor::error (const std::string &category_name, const std: m_log_entries.push_back (db::LogEntryData (db::Error, cell_name (), msg)); m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); - m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::error << m_log_entries.back ().to_string (); @@ -584,7 +583,6 @@ void NetlistDeviceExtractor::error (const std::string &category_name, const std: m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); m_log_entries.back ().set_geometry (poly); - m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::error << m_log_entries.back ().to_string (); @@ -617,7 +615,6 @@ void NetlistDeviceExtractor::warn (const std::string &category_name, const std:: m_log_entries.push_back (db::LogEntryData (db::Warning, cell_name (), msg)); m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); - m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::warn << m_log_entries.back ().to_string (); @@ -630,7 +627,6 @@ void NetlistDeviceExtractor::warn (const std::string &category_name, const std:: m_log_entries.back ().set_category_name (category_name); m_log_entries.back ().set_category_description (category_description); m_log_entries.back ().set_geometry (poly); - m_log_entries.back ().set_category_name ("device-extract"); if (tl::verbosity () >= 20) { tl::warn << m_log_entries.back ().to_string (); diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index e810c286b..751d892c8 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -89,8 +89,8 @@ TEST(2_NetlistDeviceExtractorErrors) std::vector errors (dummy_ex.begin_log_entries (), dummy_ex.end_log_entries ()); EXPECT_EQ (int (errors.size ()), 4); - EXPECT_EQ (error2string (errors [0]), ":::():msg1"); - EXPECT_EQ (error2string (errors [1]), ":::(0,1;0,3;2,3;2,1):msg2"); + EXPECT_EQ (error2string (errors [0]), ":device-extract::():msg1"); + EXPECT_EQ (error2string (errors [1]), ":device-extract::(0,1;0,3;2,3;2,1):msg2"); EXPECT_EQ (error2string (errors [2]), ":cat1:desc1:():msg1"); EXPECT_EQ (error2string (errors [3]), ":cat1:desc1:(10,11;10,13;12,13;12,11):msg3"); } diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 index dfe2f524b..576801b98 100644 --- a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 +++ b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.1 @@ -39,7 +39,7 @@ layout( global(l10 SUBSTRATE) # Log entries - message(warning description('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at the chip top level') cell(RINGO)) + message(warning description('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at chip top level') cell(RINGO) cat('must-connect')) # Device class section class(PMOS MOS4) From 001c2240e2fc365485551053e9805355c77e28fc Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 26 Sep 2023 23:39:46 +0200 Subject: [PATCH 37/41] Highlight error marker from netlist browser --- src/db/db/dbLog.cc | 4 +- src/db/db/dbLog.h | 2 +- src/layui/layui/layNetlistBrowserPage.cc | 53 +++++++++++++++++++++--- src/layui/layui/layNetlistBrowserPage.h | 1 + src/layui/layui/layNetlistLogModel.cc | 2 +- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/db/db/dbLog.cc b/src/db/db/dbLog.cc index 6e9428c5c..acc295813 100644 --- a/src/db/db/dbLog.cc +++ b/src/db/db/dbLog.cc @@ -158,7 +158,7 @@ LogEntryData::set_cell_name (const std::string &n) } std::string -LogEntryData::to_string () const +LogEntryData::to_string (bool with_geometry) const { std::string res; @@ -178,7 +178,7 @@ LogEntryData::to_string () const res += message (); - if (! m_geometry.box ().empty ()) { + if (with_geometry && ! m_geometry.box ().empty ()) { res += tl::to_string (tr (", shape: ")) + m_geometry.to_string (); } diff --git a/src/db/db/dbLog.h b/src/db/db/dbLog.h index 985558b6d..ff11f528e 100644 --- a/src/db/db/dbLog.h +++ b/src/db/db/dbLog.h @@ -161,7 +161,7 @@ public: /** * @brief Formats this message for printing */ - std::string to_string () const; + std::string to_string (bool with_geometry = true) const; private: Severity m_severity; diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index f879e9e24..e8c3947ed 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -798,6 +798,10 @@ NetlistBrowserPage::log_selection_changed () { clear_highlights (); + if (! mp_database.get () || ! mp_database->netlist ()) { + return; + } + NetlistLogModel *model = dynamic_cast (log_view->model ()); tl_assert (model != 0); @@ -805,15 +809,17 @@ NetlistBrowserPage::log_selection_changed () 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 ()) { - - // @@@ TODO: add highlight for error here. - + 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 ())); + } } } } update_highlights (); + adjust_view (); } void @@ -1276,6 +1282,7 @@ NetlistBrowserPage::clear_highlights () { m_current_path = lay::NetlistObjectsPath (); m_selected_paths.clear (); + m_markers.clear (); update_highlights (); } @@ -1435,6 +1442,17 @@ NetlistBrowserPage::adjust_view () } + // add markers boxes + + for (auto marker = m_markers.begin (); marker != m_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 * marker->second).box (); + } + + } + if (! bbox.empty ()) { std::vector tv = mp_view->cv_transform_variants (m_cv_index); @@ -1676,10 +1694,12 @@ NetlistBrowserPage::update_highlights () } } + std::vector tv = mp_view->cv_transform_variants (m_cv_index); + size_t n_markers = 0; bool not_all_shapes_are_shown = false; - for (std::vector::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { + for (auto path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) { const db::Circuit *circuit = path->root.first; if (! circuit) { @@ -1711,7 +1731,6 @@ NetlistBrowserPage::update_highlights () // a map of display properties vs. layer properties // correct DBU differences between the storage layout and the original layout - std::vector tv = mp_view->cv_transform_variants (m_cv_index); for (std::vector::iterator t = tv.begin (); t != tv.end (); ++t) { *t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ()); } @@ -1732,6 +1751,28 @@ NetlistBrowserPage::update_highlights () } + for (auto marker = m_markers.begin (); marker != m_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; + } + + // creates a highlight from the marker + + tl::Color color = make_valid_color (m_colorizer.marker_color ()); + + mp_markers.push_back (new lay::Marker (mp_view, m_cv_index)); + mp_markers.back ()->set (marker->second, db::DCplxTrans (1.0 / original_layout.dbu ()) * tr.second, tv); + mp_markers.back ()->set_color (color); + mp_markers.back ()->set_frame_color (color); + + configure_marker (mp_markers.back (), true); + + } + if (not_all_shapes_are_shown) { info_label->setText (tl::to_qstring ("

" + tl::to_string (QObject::tr ("Not all shapes are highlighted")) + diff --git a/src/layui/layui/layNetlistBrowserPage.h b/src/layui/layui/layNetlistBrowserPage.h index aec13cbf5..ad29cdba9 100644 --- a/src/layui/layui/layNetlistBrowserPage.h +++ b/src/layui/layui/layNetlistBrowserPage.h @@ -244,6 +244,7 @@ private: bool m_update_needed; lay::NetlistObjectsPath m_current_path; std::vector m_selected_paths; + std::vector > m_markers; lay::NetInfoDialog *mp_info_dialog; tl::DeferredMethod dm_update_highlights; tl::DeferredMethod dm_rerun_macro; diff --git a/src/layui/layui/layNetlistLogModel.cc b/src/layui/layui/layNetlistLogModel.cc index 4b6aa865a..82784d628 100644 --- a/src/layui/layui/layNetlistLogModel.cc +++ b/src/layui/layui/layNetlistLogModel.cc @@ -218,7 +218,7 @@ NetlistLogModel::data (const QModelIndex &index, int role) const } else if (role == Qt::DisplayRole) { if (le) { - return QVariant (tl::to_qstring (le->to_string ())); + return QVariant (tl::to_qstring (le->to_string (false))); } else if (! index.parent ().isValid () && index.row () >= m_global_entries && index.row () < int (m_circuits.size ()) + m_global_entries) { const std::pair &cp = m_circuits [index.row () - m_global_entries].first; if (! cp.first) { From cd5204fdf1f391240a623fc86427b0ca4e4c6118 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 27 Sep 2023 21:14:11 +0200 Subject: [PATCH 38/41] Backwards compatible definition of LogDataEntry#to_s --- src/db/db/gsiDeclDbLog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/db/gsiDeclDbLog.cc b/src/db/db/gsiDeclDbLog.cc index a88c67691..814178e7a 100644 --- a/src/db/db/gsiDeclDbLog.cc +++ b/src/db/db/gsiDeclDbLog.cc @@ -77,7 +77,7 @@ Class decl_dbNetlistDeviceExtractorError ("db", "LogEntryData" "@brief Sets the category description.\n" "See \\category_name= for details about categories." ) + - gsi::method ("to_s", &db::LogEntryData::to_string, + gsi::method ("to_s", &db::LogEntryData::to_string, gsi::arg ("with_geometry", true), "@brief Gets the string representation of this error or warning.\n" "This method has been introduced in version 0.28.13." ), From 4a1e55be5c5c86ffe2e07aa16a64f04761267944 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 27 Sep 2023 21:16:11 +0200 Subject: [PATCH 39/41] Added new testdata variant --- .../ringo_simple_implicit_connections.lvsdb.2 | 930 ++++++++++++++++++ 1 file changed, 930 insertions(+) create mode 100644 testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 diff --git a/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 new file mode 100644 index 000000000..86c5148b8 --- /dev/null +++ b/testdata/lvs/ringo_simple_implicit_connections.lvsdb.2 @@ -0,0 +1,930 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l3 '1/0') + layer(l4 '5/0') + layer(l8 '8/0') + layer(l11 '9/0') + layer(l12 '10/0') + layer(l13 '11/0') + layer(l7) + layer(l2) + layer(l9) + layer(l6) + layer(l10) + + # Mask layer connectivity + connect(l3 l3 l9) + connect(l4 l4 l8) + connect(l8 l4 l8 l11 l2 l9 l6 l10) + connect(l11 l8 l11 l12) + connect(l12 l11 l12 l13) + connect(l13 l12 l13) + connect(l7 l7) + connect(l2 l8 l2) + connect(l9 l3 l8 l9) + connect(l6 l8 l6) + connect(l10 l8 l10) + + # Global nets and connectivity + global(l7 SUBSTRATE) + global(l10 SUBSTRATE) + + # Log entries + message(warning description('Must-connect nets VDD must be connected further up in the hierarchy - this is an error at chip top level') cell(RINGO) cat('must-connect')) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (450 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l2 (-575 -750) (450 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l2 (-550 -750) (425 1500)) + ) + terminal(G + rect(l4 (-125 -750) (250 1500)) + ) + terminal(D + rect(l2 (125 -750) (425 1500)) + ) + terminal(B + rect(l3 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (450 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l6 (-575 -475) (450 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l6 (-550 -475) (425 950)) + ) + terminal(G + rect(l4 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l7 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -790) (300 1700)) + rect(l11 (-1350 0) (2400 800)) + rect(l11 (-1150 -400) (0 0)) + rect(l2 (-275 -2150) (425 1500)) + rect(l2 (-400 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1810 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-1580 3760) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (1220 920) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + polygon(l11 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l11 (-110 1390) (300 1400)) + polygon(l11 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l11 (-140 -500) (0 0)) + rect(l11 (-1750 1100) (300 1400)) + rect(l11 (1100 -1700) (300 300)) + rect(l11 (-300 0) (300 1400)) + rect(l2 (-375 -1450) (425 1500)) + rect(l2 (-1800 -1500) (425 1500)) + rect(l6 (950 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (2400 800)) + rect(l11 (-1150 -400) (0 0)) + rect(l6 (-950 860) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2600 3500)) + ) + net(5 name(B) + rect(l4 (1425 2860) (250 1940)) + rect(l4 (-345 -950) (300 300)) + rect(l4 (-205 650) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-285 1050) (180 180)) + rect(l11 (-70 -90) (0 0)) + rect(l11 (-170 -150) (300 300)) + ) + net(6 name(A) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-325 -1850) (300 300)) + rect(l4 (-225 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-265 150) (180 180)) + rect(l11 (-90 -90) (0 0)) + rect(l11 (-150 -150) (300 300)) + ) + net(7 name(SUBSTRATE)) + net(8 + rect(l6 (975 1660) (425 950)) + rect(l6 (-400 -950) (425 950)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.3375) + param(PS 3.85) + param(PD 1.95) + terminal(S 2) + terminal(G 6) + terminal(D 1) + terminal(B 4) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.21375) + param(PS 2.75) + param(PD 1.4) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 D$NMOS$1 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l8 (410 6260) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l11 (-240 -240) (300 1400)) + rect(l11 (-650 300) (1800 800)) + rect(l11 (-1450 -1100) (300 300)) + rect(l11 (300 400) (0 0)) + rect(l2 (-650 -2150) (425 1500)) + ) + net(2 name(OUT) + rect(l8 (1110 5160) (180 180)) + rect(l8 (-180 920) (180 180)) + rect(l8 (-180 -730) (180 180)) + rect(l8 (-180 -4120) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -790) (300 4790)) + rect(l11 (-150 -2500) (0 0)) + rect(l2 (-225 1050) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l8 (410 1770) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-240 -1300) (300 1360)) + rect(l11 (-650 -2160) (1800 800)) + rect(l11 (-850 -400) (0 0)) + rect(l6 (-650 860) (425 950)) + ) + net(4 + rect(l3 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l4 (725 2860) (250 1940)) + rect(l4 (-525 -1850) (300 300)) + rect(l4 (-25 1550) (250 2000)) + rect(l4 (-250 -2000) (250 2000)) + rect(l4 (-250 -5390) (250 1450)) + rect(l8 (-465 150) (180 180)) + rect(l11 (-90 -90) (0 0)) + rect(l11 (-150 -150) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (28300 7650)) + + # Nets with their geometries + net(1 + rect(l11 (4040 2950) (1160 300)) + ) + net(2 + rect(l11 (6050 2950) (900 300)) + ) + net(3 + rect(l11 (7850 2950) (900 300)) + ) + net(4 + rect(l11 (9650 2950) (900 300)) + ) + net(5 + rect(l11 (11450 2950) (900 300)) + ) + net(6 + rect(l11 (13250 2950) (900 300)) + ) + net(7 + rect(l11 (15050 2950) (900 300)) + ) + net(8 + rect(l11 (16850 2950) (900 300)) + ) + net(9 + rect(l11 (18650 2950) (900 300)) + ) + net(10 + rect(l11 (20450 2950) (900 300)) + ) + net(11 name(FB) + rect(l11 (22250 2950) (2900 300)) + rect(l11 (-21980 590) (320 320)) + rect(l11 (18570 -320) (320 320)) + rect(l12 (-19150 -260) (200 200)) + rect(l12 (18690 -200) (200 200)) + rect(l13 (-18840 -300) (18890 400)) + rect(l13 (-19070 -200) (0 0)) + rect(l13 (-170 -200) (400 400)) + rect(l13 (18490 -400) (400 400)) + ) + net(12 name(VDD) + rect(l3 (22600 4500) (1400 3500)) + rect(l3 (2400 -3500) (1400 3500)) + rect(l3 (-100 -3500) (600 3500)) + rect(l3 (-27800 -3500) (1400 3500)) + rect(l3 (-1900 -3500) (600 3500)) + rect(l8 (22610 -1240) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (3620 370) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-26080 370) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l11 (21010 1010) (0 0)) + rect(l11 (2800 -50) (0 0)) + rect(l11 (-22150 -100) (0 0)) + rect(l11 (19750 -450) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-100 -350) (0 0)) + rect(l11 (3150 -400) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-100 -350) (0 0)) + rect(l11 (550 -400) (600 800)) + rect(l11 (-27700 -800) (1200 800)) + rect(l11 (-750 -1450) (300 1400)) + rect(l11 (-100 -350) (0 0)) + rect(l11 (-1250 -400) (600 800)) + rect(l9 (22450 -1500) (500 1500)) + rect(l9 (3300 -1500) (500 1500)) + rect(l9 (-26400 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l11 (25990 3840) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-150 -100) (0 0)) + rect(l13 (-150 -200) (400 400)) + ) + net(14 name(ENABLE) + rect(l11 (2490 2940) (320 320)) + rect(l12 (-260 -260) (200 200)) + rect(l13 (-150 -100) (0 0)) + rect(l13 (-150 -200) (400 400)) + ) + net(15 name(VSS) + rect(l8 (1110 1610) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (21920 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l8 (3620 370) (180 180)) + rect(l8 (-180 -1280) (180 180)) + rect(l8 (-180 370) (180 180)) + rect(l11 (-24240 -390) (0 0)) + rect(l11 (19200 100) (0 0)) + rect(l11 (3850 0) (0 0)) + rect(l11 (-24950 -500) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-550 -400) (0 0)) + rect(l11 (-1250 -400) (600 800)) + rect(l11 (22550 -750) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-550 -400) (0 0)) + rect(l11 (3600 -350) (300 1400)) + rect(l11 (-750 -1450) (1200 800)) + rect(l11 (-550 -400) (0 0)) + rect(l11 (550 -400) (600 800)) + rect(l10 (-27350 -800) (500 1500)) + rect(l10 (21600 -1500) (500 1500)) + rect(l10 (3300 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Subcircuits and their connections + circuit(1 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(2 INVX1 location(4700 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(3 INVX1 location(6500 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(4 INVX1 location(8300 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(5 INVX1 location(10100 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(6 INVX1 location(11900 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(7 INVX1 location(13700 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(8 INVX1 location(15500 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(9 INVX1 location(17300 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(10 INVX1 location(19100 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(11 INVX1 location(20900 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(12 INVX1 location(24700 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 6) + terminal(D 2) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 match + xref( + net(8 8 match) + net(4 4 match) + net(6 6 match) + net(5 5 match) + net(2 2 match) + net(7 7 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 2 match) + device(3 3 match) + device(4 4 match) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(RINGO RINGO match + xref( + net(1 6 match) + net(10 15 match) + net(2 7 match) + net(3 8 match) + net(4 9 match) + net(5 10 match) + net(6 11 match) + net(7 12 match) + net(8 13 match) + net(9 14 match) + net(14 4 match) + net(11 3 match) + net(13 5 match) + net(12 2 match) + net(15 1 match) + pin(3 3 match) + pin(0 2 match) + pin(2 4 match) + pin(1 1 match) + pin(4 0 match) + circuit(2 2 match) + circuit(3 3 match) + circuit(4 4 match) + circuit(5 5 match) + circuit(6 6 match) + circuit(7 7 match) + circuit(8 8 match) + circuit(9 9 match) + circuit(10 10 match) + circuit(11 11 match) + circuit(12 12 match) + circuit(1 1 match) + ) + ) +) From 583232c7f4288becea8db7b60a5fbf2acd91bbfd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 27 Sep 2023 21:19:55 +0200 Subject: [PATCH 40/41] New testdata variants --- testdata/lvs/ringo_simple_dmos.lvsdb.2 | 889 +++++++++++++++++++++++++ 1 file changed, 889 insertions(+) create mode 100644 testdata/lvs/ringo_simple_dmos.lvsdb.2 diff --git a/testdata/lvs/ringo_simple_dmos.lvsdb.2 b/testdata/lvs/ringo_simple_dmos.lvsdb.2 new file mode 100644 index 000000000..64a000533 --- /dev/null +++ b/testdata/lvs/ringo_simple_dmos.lvsdb.2 @@ -0,0 +1,889 @@ +#%lvsdb-klayout + +# Layout +layout( + top(RINGO) + unit(0.001) + + # Layer section + # This section lists the mask layers (drawing or derived) and their connections. + + # Mask layers + layer(l4 '1/0') + layer(l5 '5/0') + layer(l10 '8/0') + layer(l13 '9/0') + layer(l14 '10/0') + layer(l15 '11/0') + layer(l9) + layer(l3) + layer(l1) + layer(l11) + layer(l8) + layer(l6) + layer(l12) + + # Mask layer connectivity + connect(l4 l4 l11) + connect(l5 l5 l10) + connect(l10 l5 l10 l13 l3 l1 l11 l8 l6 l12) + connect(l13 l10 l13 l14) + connect(l14 l13 l14 l15) + connect(l15 l14 l15) + connect(l9 l9) + connect(l3 l10 l3) + connect(l1 l10 l1) + connect(l11 l4 l10 l11) + connect(l8 l10 l8) + connect(l6 l10 l6) + connect(l12 l10 l12) + + # Global nets and connectivity + global(l9 SUBSTRATE) + global(l12 SUBSTRATE) + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Device abstracts section + # Device abstracts list the pin shapes of the devices. + device(D$PMOS PMOS + terminal(S + rect(l3 (125 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (-550 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$1 PMOS + terminal(S + rect(l3 (-575 -750) (450 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$PMOS$2 PMOS + terminal(S + rect(l3 (-550 -750) (425 1500)) + ) + terminal(G + rect(l5 (-125 -750) (250 1500)) + ) + terminal(D + rect(l1 (125 -750) (425 1500)) + ) + terminal(B + rect(l4 (-125 -750) (250 1500)) + ) + ) + device(D$NMOS NMOS + terminal(S + rect(l8 (125 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (-550 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$1 NMOS + terminal(S + rect(l8 (-575 -475) (450 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + device(D$NMOS$2 NMOS + terminal(S + rect(l8 (-550 -475) (425 950)) + ) + terminal(G + rect(l5 (-125 -475) (250 950)) + ) + terminal(D + rect(l6 (125 -475) (425 950)) + ) + terminal(B + rect(l9 (-125 -475) (250 950)) + ) + ) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Circuit boundary + rect((-100 400) (2600 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -790) (300 1700)) + rect(l13 (-1350 0) (2400 800)) + rect(l13 (-1150 -400) (0 0)) + rect(l3 (-250 -2150) (425 1500)) + rect(l3 (-450 -1500) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1810 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-1580 3760) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (1220 920) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + polygon(l13 (-240 -4180) (0 1390) (490 0) (0 -300) (-190 0) (0 -1090)) + rect(l13 (-110 1390) (300 1400)) + polygon(l13 (-1890 0) (0 600) (300 0) (0 -300) (1590 0) (0 -300)) + rect(l13 (-140 -500) (0 0)) + rect(l13 (-1750 1100) (300 1400)) + rect(l13 (1100 -1700) (300 300)) + rect(l13 (-300 0) (300 1400)) + rect(l1 (-1750 -1450) (425 1500)) + rect(l1 (950 -1500) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (2400 800)) + rect(l13 (-1150 -400) (0 0)) + rect(l6 (-950 860) (425 950)) + ) + net(4 + rect(l8 (1000 1660) (425 950)) + rect(l8 (-450 -950) (425 950)) + ) + net(5 + rect(l4 (-100 4500) (2600 3500)) + ) + net(6 name(B) + rect(l5 (1425 2860) (250 1940)) + rect(l5 (-345 -950) (300 300)) + rect(l5 (-205 650) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-285 1050) (180 180)) + rect(l13 (-70 -90) (0 0)) + rect(l13 (-170 -150) (300 300)) + ) + net(7 name(A) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-325 -1850) (300 300)) + rect(l5 (-225 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-265 150) (180 180)) + rect(l13 (-90 -90) (0 0)) + rect(l13 (-150 -150) (300 300)) + ) + net(8 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(5) + pin(6 name(B)) + pin(7 name(A)) + pin(8 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 7) + terminal(D 2) + terminal(B 5) + ) + device(2 D$PMOS$1 + location(1550 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.3375) + param(AD 0.6375) + param(PS 1.95) + param(PD 3.85) + terminal(S 1) + terminal(G 6) + terminal(D 2) + terminal(B 5) + ) + device(3 D$NMOS + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 7) + terminal(D 3) + terminal(B 8) + ) + device(4 D$NMOS$1 + location(1550 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.21375) + param(AD 0.40375) + param(PS 1.4) + param(PD 2.75) + terminal(S 4) + terminal(G 6) + terminal(D 2) + terminal(B 8) + ) + + ) + circuit(INVX1 + + # Circuit boundary + rect((-100 400) (2000 7600)) + + # Nets with their geometries + net(1 name(VDD) + rect(l10 (410 6260) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l13 (-240 -240) (300 1400)) + rect(l13 (-650 300) (1800 800)) + rect(l13 (-1450 -1100) (300 300)) + rect(l13 (300 400) (0 0)) + rect(l3 (-650 -2150) (425 1500)) + ) + net(2 name(OUT) + rect(l10 (1110 5160) (180 180)) + rect(l10 (-180 920) (180 180)) + rect(l10 (-180 -730) (180 180)) + rect(l10 (-180 -4120) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -790) (300 4790)) + rect(l13 (-150 -2500) (0 0)) + rect(l1 (-225 1050) (425 1500)) + rect(l6 (-425 -4890) (425 950)) + ) + net(3 name(VSS) + rect(l10 (410 1770) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-240 -1300) (300 1360)) + rect(l13 (-650 -2160) (1800 800)) + rect(l13 (-850 -400) (0 0)) + rect(l8 (-650 860) (425 950)) + ) + net(4 + rect(l4 (-100 4500) (2000 3500)) + ) + net(5 name(IN) + rect(l5 (725 2860) (250 1940)) + rect(l5 (-525 -1850) (300 300)) + rect(l5 (-25 1550) (250 2000)) + rect(l5 (-250 -2000) (250 2000)) + rect(l5 (-250 -5390) (250 1450)) + rect(l10 (-465 150) (180 180)) + rect(l13 (-90 -90) (0 0)) + rect(l13 (-150 -150) (300 300)) + ) + net(6 name(SUBSTRATE)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4) + pin(5 name(IN)) + pin(6 name(SUBSTRATE)) + + # Devices and their connections + device(1 D$PMOS$2 + location(850 5800) + param(L 0.25) + param(W 1.5) + param(AS 0.6375) + param(AD 0.6375) + param(PS 3.85) + param(PD 3.85) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 D$NMOS$2 + location(850 2135) + param(L 0.25) + param(W 0.95) + param(AS 0.40375) + param(AD 0.40375) + param(PS 2.75) + param(PD 2.75) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Circuit boundary + rect((0 350) (25800 7650)) + + # Nets with their geometries + net(1 + rect(l13 (4040 2950) (610 300)) + ) + net(2 + rect(l13 (5550 2950) (900 300)) + ) + net(3 + rect(l13 (7350 2950) (900 300)) + ) + net(4 + rect(l13 (9150 2950) (900 300)) + ) + net(5 + rect(l13 (10950 2950) (900 300)) + ) + net(6 + rect(l13 (12750 2950) (900 300)) + ) + net(7 + rect(l13 (14550 2950) (900 300)) + ) + net(8 + rect(l13 (16350 2950) (900 300)) + ) + net(9 + rect(l13 (18150 2950) (900 300)) + ) + net(10 + rect(l13 (19950 2950) (900 300)) + ) + net(11 name(FB) + rect(l13 (21750 2950) (900 300)) + rect(l13 (-19530 590) (320 320)) + rect(l13 (17820 -320) (320 320)) + rect(l14 (-18400 -260) (200 200)) + rect(l14 (17940 -200) (200 200)) + rect(l15 (-18040 -300) (17740 400)) + rect(l15 (-17920 -200) (0 0)) + rect(l15 (-220 -200) (400 400)) + rect(l15 (17740 -400) (400 400)) + ) + net(12 name(VDD) + rect(l4 (500 4500) (1400 3500)) + rect(l4 (-1900 -3500) (600 3500)) + rect(l4 (23300 -3500) (1400 3500)) + rect(l4 (-100 -3500) (600 3500)) + rect(l10 (-24690 -1240) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l13 (-21740 860) (0 0)) + rect(l13 (-2350 -450) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-100 -350) (0 0)) + rect(l13 (-1250 -400) (600 800)) + rect(l13 (23400 -800) (1200 800)) + rect(l13 (-750 -1450) (300 1400)) + rect(l13 (-100 -350) (0 0)) + rect(l13 (550 -400) (600 800)) + rect(l11 (-24850 -1500) (500 1500)) + rect(l11 (22900 -1500) (500 1500)) + ) + net(13 name(OUT) + rect(l13 (23440 3840) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-100 -100) (0 0)) + rect(l15 (-200 -200) (400 400)) + ) + net(14 name(ENABLE) + rect(l13 (2440 2940) (320 320)) + rect(l14 (-260 -260) (200 200)) + rect(l15 (-100 -100) (0 0)) + rect(l15 (-200 -200) (400 400)) + ) + net(15 name(VSS) + rect(l10 (1110 1610) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l10 (23220 370) (180 180)) + rect(l10 (-180 -1280) (180 180)) + rect(l10 (-180 370) (180 180)) + rect(l13 (-21740 -390) (0 0)) + rect(l13 (-1900 -400) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-550 -400) (0 0)) + rect(l13 (-1250 -400) (600 800)) + rect(l13 (23850 -750) (300 1400)) + rect(l13 (-750 -1450) (1200 800)) + rect(l13 (-550 -400) (0 0)) + rect(l13 (550 -400) (600 800)) + rect(l12 (-24850 -800) (500 1500)) + rect(l12 (22900 -1500) (500 1500)) + ) + + # Outgoing pins and their connections to nets + pin(11 name(FB)) + pin(12 name(VDD)) + pin(13 name(OUT)) + pin(14 name(ENABLE)) + pin(15 name(VSS)) + + # Subcircuits and their connections + circuit(1 ND2X1 location(1800 0) + pin(0 12) + pin(1 1) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 14) + pin(6 15) + ) + circuit(2 INVX1 location(4200 0) + pin(0 12) + pin(1 2) + pin(2 15) + pin(3 12) + pin(4 1) + pin(5 15) + ) + circuit(3 INVX1 location(6000 0) + pin(0 12) + pin(1 3) + pin(2 15) + pin(3 12) + pin(4 2) + pin(5 15) + ) + circuit(4 INVX1 location(7800 0) + pin(0 12) + pin(1 4) + pin(2 15) + pin(3 12) + pin(4 3) + pin(5 15) + ) + circuit(5 INVX1 location(9600 0) + pin(0 12) + pin(1 5) + pin(2 15) + pin(3 12) + pin(4 4) + pin(5 15) + ) + circuit(6 INVX1 location(11400 0) + pin(0 12) + pin(1 6) + pin(2 15) + pin(3 12) + pin(4 5) + pin(5 15) + ) + circuit(7 INVX1 location(13200 0) + pin(0 12) + pin(1 7) + pin(2 15) + pin(3 12) + pin(4 6) + pin(5 15) + ) + circuit(8 INVX1 location(15000 0) + pin(0 12) + pin(1 8) + pin(2 15) + pin(3 12) + pin(4 7) + pin(5 15) + ) + circuit(9 INVX1 location(16800 0) + pin(0 12) + pin(1 9) + pin(2 15) + pin(3 12) + pin(4 8) + pin(5 15) + ) + circuit(10 INVX1 location(18600 0) + pin(0 12) + pin(1 10) + pin(2 15) + pin(3 12) + pin(4 9) + pin(5 15) + ) + circuit(11 INVX1 location(20400 0) + pin(0 12) + pin(1 11) + pin(2 15) + pin(3 12) + pin(4 10) + pin(5 15) + ) + circuit(12 INVX1 location(22200 0) + pin(0 12) + pin(1 13) + pin(2 15) + pin(3 12) + pin(4 11) + pin(5 15) + ) + + ) +) + +# Reference netlist +reference( + + # Device class section + class(PMOS MOS4) + class(NMOS MOS4) + + # Circuit section + # Circuits are the hierarchical building blocks of the netlist. + circuit(ND2X1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(B)) + net(6 name(A)) + net(7 name(BULK)) + net(8 name('1')) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(B)) + pin(6 name(A)) + pin(7 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 6) + terminal(D 2) + terminal(B 4) + ) + device(2 PMOS + name($2) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(3 NMOS + name($3) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 6) + terminal(D 8) + terminal(B 7) + ) + device(4 NMOS + name($4) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 8) + terminal(G 5) + terminal(D 2) + terminal(B 7) + ) + + ) + circuit(INVX1 + + # Nets + net(1 name(VDD)) + net(2 name(OUT)) + net(3 name(VSS)) + net(4 name(NWELL)) + net(5 name(IN)) + net(6 name(BULK)) + + # Outgoing pins and their connections to nets + pin(1 name(VDD)) + pin(2 name(OUT)) + pin(3 name(VSS)) + pin(4 name(NWELL)) + pin(5 name(IN)) + pin(6 name(BULK)) + + # Devices and their connections + device(1 PMOS + name($1) + param(L 0.25) + param(W 1.5) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 1) + terminal(G 5) + terminal(D 2) + terminal(B 4) + ) + device(2 NMOS + name($2) + param(L 0.25) + param(W 0.95) + param(AS 0) + param(AD 0) + param(PS 0) + param(PD 0) + terminal(S 3) + terminal(G 5) + terminal(D 2) + terminal(B 6) + ) + + ) + circuit(RINGO + + # Nets + net(1 name(VSS)) + net(2 name(VDD)) + net(3 name(FB)) + net(4 name(ENABLE)) + net(5 name(OUT)) + net(6 name('1')) + net(7 name('2')) + net(8 name('3')) + net(9 name('4')) + net(10 name('5')) + net(11 name('6')) + net(12 name('7')) + net(13 name('8')) + net(14 name('9')) + net(15 name('10')) + + # Outgoing pins and their connections to nets + pin(1 name(VSS)) + pin(2 name(VDD)) + pin(3 name(FB)) + pin(4 name(ENABLE)) + pin(5 name(OUT)) + + # Subcircuits and their connections + circuit(1 ND2X1 name($1) + pin(0 2) + pin(1 6) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 4) + pin(6 1) + ) + circuit(2 INVX1 name($2) + pin(0 2) + pin(1 7) + pin(2 1) + pin(3 2) + pin(4 6) + pin(5 1) + ) + circuit(3 INVX1 name($3) + pin(0 2) + pin(1 8) + pin(2 1) + pin(3 2) + pin(4 7) + pin(5 1) + ) + circuit(4 INVX1 name($4) + pin(0 2) + pin(1 9) + pin(2 1) + pin(3 2) + pin(4 8) + pin(5 1) + ) + circuit(5 INVX1 name($5) + pin(0 2) + pin(1 10) + pin(2 1) + pin(3 2) + pin(4 9) + pin(5 1) + ) + circuit(6 INVX1 name($6) + pin(0 2) + pin(1 11) + pin(2 1) + pin(3 2) + pin(4 10) + pin(5 1) + ) + circuit(7 INVX1 name($7) + pin(0 2) + pin(1 12) + pin(2 1) + pin(3 2) + pin(4 11) + pin(5 1) + ) + circuit(8 INVX1 name($8) + pin(0 2) + pin(1 13) + pin(2 1) + pin(3 2) + pin(4 12) + pin(5 1) + ) + circuit(9 INVX1 name($9) + pin(0 2) + pin(1 14) + pin(2 1) + pin(3 2) + pin(4 13) + pin(5 1) + ) + circuit(10 INVX1 name($10) + pin(0 2) + pin(1 15) + pin(2 1) + pin(3 2) + pin(4 14) + pin(5 1) + ) + circuit(11 INVX1 name($11) + pin(0 2) + pin(1 3) + pin(2 1) + pin(3 2) + pin(4 15) + pin(5 1) + ) + circuit(12 INVX1 name($12) + pin(0 2) + pin(1 5) + pin(2 1) + pin(3 2) + pin(4 3) + pin(5 1) + ) + + ) +) + +# Cross reference +xref( + log( + entry(error description('Circuits RINGO and RINGO could not be compared because the following subcircuits failed to compare:\n A: ND2X1\n B: ND2X1')) + ) + circuit(INVX1 INVX1 match + xref( + net(4 4 match) + net(5 5 match) + net(2 2 match) + net(6 6 match) + net(1 1 match) + net(3 3 match) + pin(3 3 match) + pin(4 4 match) + pin(1 1 match) + pin(5 5 match) + pin(0 0 match) + pin(2 2 match) + device(2 2 match) + device(1 1 match) + ) + ) + circuit(ND2X1 ND2X1 nomatch + log( + entry(error description('No equivalent pin VSS from netlist found in reference netlist.\nThis is an indication that additional physical connections are made to the subcircuit cell.')) + entry(info description('Potential invalid connection in circuit RINGO, subcircuit cell reference at r0 *1 1.8,0')) + entry(error description('No equivalent pin VSS from reference netlist found in netlist.\nThis is an indication that a physical connection is not made to the subcircuit.')) + ) + xref( + net(5 4 match) + net(4 3 mismatch) + net(7 6 match) + net(6 5 match) + net(2 2 match) + net(8 7 mismatch) + net(1 1 match) + net(3 8 mismatch) + pin(() 2 mismatch) + pin(3 3 match) + pin(5 5 match) + pin(4 4 match) + pin(1 1 match) + pin(6 6 match) + pin(0 0 match) + pin(2 () mismatch) + device(3 3 match) + device(4 4 mismatch) + device(1 1 match) + device(2 2 match) + ) + ) + circuit(RINGO RINGO skipped description('Circuits RINGO and RINGO could not be compared because the following subcircuits failed to compare:\n A: ND2X1\n B: ND2X1') + xref( + ) + ) +) From 72278b90ecb0c2caae1bfc7ee58db0b8a5bd71ca Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 27 Sep 2023 21:45:06 +0200 Subject: [PATCH 41/41] Added 'top_level' feature to tell LVS to perform in top level mode --- src/db/db/dbLayoutToNetlist.cc | 12 +- src/db/db/dbLayoutToNetlist.h | 22 + src/db/db/gsiDeclDbLayoutToNetlist.cc | 14 + src/doc/doc/manual/lvs_connect.xml | 16 +- src/drc/drc/built-in-macros/_drc_engine.rb | 7 + src/drc/drc/built-in-macros/_drc_netter.rb | 20 + src/lvs/unit_tests/lvsSimpleTests.cc | 2 + testdata/lvs/must_connect1_tl.cir | 23 + testdata/lvs/must_connect1_tl.lvs | 143 ++++++ testdata/lvs/must_connect1_tl.lvsdb | 484 +++++++++++++++++++++ 10 files changed, 732 insertions(+), 11 deletions(-) create mode 100644 testdata/lvs/must_connect1_tl.cir create mode 100644 testdata/lvs/must_connect1_tl.lvs create mode 100644 testdata/lvs/must_connect1_tl.lvsdb diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 2da483769..ae2972a1b 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -45,7 +45,7 @@ namespace db // Note: the iterator provides the hierarchical selection (enabling/disabling cells etc.) LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter) - : m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false) + : m_iter (iter), m_layout_index (0), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) { // check the iterator if (iter.has_complex_region () || iter.region () != db::Box::world ()) { @@ -65,7 +65,7 @@ LayoutToNetlist::LayoutToNetlist (const db::RecursiveShapeIterator &iter) } LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_index) - : mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false) + : mp_dss (dss), m_layout_index (layout_index), m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) { if (dss->is_valid_layout_index (m_layout_index)) { m_iter = db::RecursiveShapeIterator (dss->layout (m_layout_index), dss->initial_cell (m_layout_index), std::set ()); @@ -73,7 +73,7 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i } LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu) - : m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false) + : m_iter (), m_netlist_extracted (false), m_is_flat (true), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) { mp_internal_dss.reset (new db::DeepShapeStore (topcell_name, dbu)); mp_dss.reset (mp_internal_dss.get ()); @@ -84,7 +84,7 @@ LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu) LayoutToNetlist::LayoutToNetlist () : m_iter (), mp_internal_dss (new db::DeepShapeStore ()), mp_dss (mp_internal_dss.get ()), m_layout_index (0), - m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false) + m_netlist_extracted (false), m_is_flat (false), m_device_scaling (1.0), m_include_floating_subcircuits (false), m_top_level_mode (false) { init (); } @@ -488,12 +488,12 @@ void LayoutToNetlist::check_must_connect (const db::Circuit &c, const db::Net &a } } else { if (a.expanded_name () == b.expanded_name ()) { - db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at chip top level")), a.expanded_name ())); + db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s must be connected further up in the hierarchy - this is an error at chip top level")), a.expanded_name ())); warn.set_cell_name (c.name ()); warn.set_category_name ("must-connect"); log_entry (warn); } else { - db::LogEntryData warn (db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at chip top level")), a.expanded_name (), b.expanded_name ())); + db::LogEntryData warn (m_top_level_mode ? db::Error : db::Warning, tl::sprintf (tl::to_string (tr ("Must-connect nets %s and %s must be connected further up in the hierarchy - this is an error at chip top level")), a.expanded_name (), b.expanded_name ())); warn.set_cell_name (c.name ()); warn.set_category_name ("must-connect"); log_entry (warn); diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index be1bb68c0..bfa07f98e 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -192,6 +192,27 @@ public: m_filename = filename; } + /** + * @brief Gets the top level mode flag + */ + bool top_level_mode () const + { + return m_top_level_mode; + } + + /** + * @brief Sets top level mode + * + * In top level mode, must-connect warnings are turned into + * errors for example. + * + * By default, top-level mode is off. + */ + void set_top_level_mode (bool f) + { + m_top_level_mode = f; + } + /** * @brief Gets the log entries */ @@ -999,6 +1020,7 @@ private: db::DeepLayer m_dummy_layer; std::string m_generator; bool m_include_floating_subcircuits; + bool m_top_level_mode; std::list m_joined_net_names; std::list > m_joined_net_names_per_cell; std::list > m_joined_nets; diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 59915bdfe..3d29e8e68 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -464,6 +464,20 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "\n" "This attribute has been introduced in version 0.27.\n" ) + + gsi::method ("top_level_mode=", &db::LayoutToNetlist::set_top_level_mode, gsi::arg ("flag"), + "@brief Sets a flag indicating whether top level mode is enabled.\n" + "\n" + "In top level mode, must-connect warnings are turned into errors for example.\n" + "To enable top level mode, set this attribute to true. By default, top-level mode is turned off.\n" + "\n" + "This attribute has been introduced in version 0.28.13." + ) + + gsi::method ("top_level_mode", &db::LayoutToNetlist::top_level_mode, + "@brief Gets a flag indicating whether top level mode is enabled.\n" + "See \\top_level_mode= for details.\n" + "\n" + "This attribute has been introduced in version 0.28.13.\n" + ) + gsi::method ("clear_join_net_names", &db::LayoutToNetlist::clear_join_net_names, "@brief Clears all implicit net joining expressions.\n" "See \\extract_netlist for more details about this feature.\n" diff --git a/src/doc/doc/manual/lvs_connect.xml b/src/doc/doc/manual/lvs_connect.xml index 44bdb0108..501695d35 100644 --- a/src/doc/doc/manual/lvs_connect.xml +++ b/src/doc/doc/manual/lvs_connect.xml @@ -137,7 +137,14 @@ connect(metal2, metal2_labels)

- This feature is also called "must connect" nets in other systems. + You can declare the layout as being a top level one. This turns the + warning about missing physical connections into an error: +

+ +
top_level(true)
+ +

+ The "connect_implicit" feature is also called "must connect" nets in other systems.

@@ -222,11 +229,11 @@ connect(metal2, metal2_labels) To align layout and schematic, bulk and VSS pins can be connected explicitly. Same for n-well and VDD. This scheme is similar to the "connect_implicit" scheme explained - above, but acts on differently named nets. + above, but can connect differently named nets.

- To establish an explicit connection, make sure that n-well and + To establish an explicit connection in the above example, make sure that n-well and bulk have proper names. For the n-well this can be done by creating labels on the n-well islands giving them a proper name - e.g. "NWELL". The bulk isn't a real layout layer with polygons on it. Using "connect_global" @@ -257,8 +264,7 @@ connect_explicit("INV", [ "BULK", "VSS" ])

Like implicit connections, explicit connections are checked for being made on the next level of hierarchy, either physically or by another explicit or - implicit connection. - This feature is also called "must connect" nets in other systems. + implicit connection.

diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 70cd8bfa8..79de6a0c7 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -2277,6 +2277,12 @@ CODE # @synopsis device_scaling(factor) # See \Netter#device_scaling for a description of that function. + # %DRC% + # @name top_level + # @brief Specifies that the circuit is a chip top level circuit + # @synopsis top_level(flag) + # See \Netter#top_level for a description of that function. + # %DRC% # @name ignore_extraction_errors # @brief Specifies whether to ignore extraction errors @@ -2305,6 +2311,7 @@ CODE connect_implicit connect_explicit device_scaling + top_level ignore_extraction_errors extract_devices l2n_data diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 7dbdf6c20..99823336b 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -70,6 +70,7 @@ module DRC @lnum = 0 @device_scaling = 1.0 @ignore_extraction_errors = false + @top_level = false end # %DRC% @@ -236,6 +237,24 @@ module DRC end end + # %DRC% + # @name top_level + # @brief Specifies top level mode + # @synopsis top_level(value) + # With this value set to false (the default), it is assumed that the + # circuit is not used as a top level chip circuit. In that case, for + # example must-connect nets which are not connected are reported as + # as warnings. If top level mode is set to true, such disconnected + # nets are reported as errors as this indicates a missing physical + # connection. + + def top_level(value) + @engine._context("top_level") do + @top_level = value + @l2n && @l2n.top_level_mode = value + end + end + # %DRC% # @name ignore_extraction_errors # @brief Specifies whether to ignore extraction errors @@ -672,6 +691,7 @@ module DRC @layers = {} _make_data @l2n.device_scaling = @device_scaling + @l2n.top_level_mode = @top_level end end diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 5a8c838e3..7f000a3b6 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -279,9 +279,11 @@ TEST(29_DeviceCombineAndTolerances) TEST(30_MustConnect1) { run_test (_this, "must_connect1", "must_connect1.gds"); + run_test (_this, "must_connect1_tl", "must_connect1.gds"); } TEST(31_MustConnect2) { run_test (_this, "must_connect2", "must_connect2.gds"); } + diff --git a/testdata/lvs/must_connect1_tl.cir b/testdata/lvs/must_connect1_tl.cir new file mode 100644 index 000000000..9b6488f75 --- /dev/null +++ b/testdata/lvs/must_connect1_tl.cir @@ -0,0 +1,23 @@ +* Extracted by KLayout + +.SUBCKT TOP VSSTOP A Q +X$1 \$8 \$2 \$1 \$1 Q VSSTOP INV2 +X$2 A \$3 VSSTOP \$3 \$2 \$8 INVCHAIN +.ENDS TOP + +.SUBCKT INVCHAIN IN IN2 VSS|VSS2|VSS2B OUT OUT2 VDD +X$1 VDD IN2 \$1 \$1 OUT2 VSS|VSS2|VSS2B INV2 +X$2 VDD IN \$2 \$2 OUT VSS|VSS2|VSS2B INV2 +.ENDS INVCHAIN + +.SUBCKT INV2 VDD A1 A2 Q1 Q2 VSS +X$1 VSS VDD A2 Q2 INV +X$2 VSS VDD A1 Q1 INV +.ENDS INV2 + +.SUBCKT INV \$1 \$2 \$3 \$4 +M$1 \$2 \$3 \$4 \$4 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +M$2 \$1 \$3 \$4 \$4 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +.ENDS INV diff --git a/testdata/lvs/must_connect1_tl.lvs b/testdata/lvs/must_connect1_tl.lvs new file mode 100644 index 000000000..4e9cc35ed --- /dev/null +++ b/testdata/lvs/must_connect1_tl.lvs @@ -0,0 +1,143 @@ + +$lvs_test_source && source($lvs_test_source) + +if $lvs_test_target_lvsdb + report_lvs($lvs_test_target_lvsdb) +else + report_lvs +end + + +writer = write_spice(true, false) +$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout") + +# Turns the warning about VSSTOP into an error +top_level(true) +ignore_extraction_errors(true) + +# needs this delegate because we use MOS3 which is not available in Spice +class SpiceReaderDelegate < RBA::NetlistSpiceReaderDelegate + + # says we want to catch these subcircuits as devices + def wants_subcircuit(name) + name == "HVNMOS" || name == "HVPMOS" + end + + # translate the element + def element(circuit, el, name, model, value, nets, params) + + if el != "M" + # all other elements are left to the standard implementation + return super + end + + if nets.size != 4 + error("Device #{model} needs four nodes") + end + + # provide a device class + cls = circuit.netlist.device_class_by_name(model) + if ! cls + cls = RBA::DeviceClassMOS3Transistor::new + cls.name = model + circuit.netlist.add(cls) + end + + # create a device + device = circuit.create_device(cls, name) + + # and configure the device + [ "S", "G", "D" ].each_with_index do |t,index| + device.connect_terminal(t, nets[index]) + end + device.set_parameter("W", params["W"] * 1e6) + device.set_parameter("L", params["L"] * 1e6) + + device + + end + +end + +reader = RBA::NetlistSpiceReader::new(SpiceReaderDelegate::new) +schematic(File.basename(source.path, ".*") + ".sch", reader) + +deep + +# Drawing layers + +nwell = input(1, 0) +active = input(2, 0) +poly = input(3, 0) +poly_lbl = input(3, 1) +diff_cont = input(4, 0) +poly_cont = input(5, 0) +metal1 = input(6, 0) +metal1_lbl = input(6, 1) +via1 = input(7, 0) +metal2 = input(8, 0) +metal2_lbl = input(8, 1) + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +psd = nil +nsd = nil + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell +pgate = pactive & poly +psd = pactive - pgate + +active_outside_nwell = active - nwell +nactive = active_outside_nwell +ngate = nactive & poly +nsd = nactive - ngate + +# Device extraction + +# PMOS transistor device extraction +extract_devices(mos3("PMOS"), { "SD" => psd, "G" => pgate, + "tS" => psd, "tD" => psd, "tG" => poly }) + +# NMOS transistor device extraction +extract_devices(mos3("NMOS"), { "SD" => nsd, "G" => ngate, + "tS" => nsd, "tD" => nsd, "tG" => poly }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, diff_cont) +connect(nsd, diff_cont) +connect(poly, poly_cont) +connect(diff_cont, metal1) +connect(poly_cont, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# attach labels +connect(poly, poly_lbl) +connect(metal1, metal1_lbl) +connect(metal2, metal2_lbl) + +# Global +connect_global(bulk, "SUBSTRATE") + +# Implicit connection of the INV2 +# VSS nets +connect_implicit("INV2", "VSS") +connect_implicit("TOP", "VSS*") +# Fix 1 +connect_explicit("INVCHAIN", ["VSS2", "VSS2B", "VSS"]) +connect_implicit("INVCHAIN", "VDD") + +# Compare section + +netlist.simplify +align + +compare + diff --git a/testdata/lvs/must_connect1_tl.lvsdb b/testdata/lvs/must_connect1_tl.lvsdb new file mode 100644 index 000000000..0bd8468c4 --- /dev/null +++ b/testdata/lvs/must_connect1_tl.lvsdb @@ -0,0 +1,484 @@ +#%lvsdb-klayout +J( + W(TOP) + U(0.001) + L(l3 '3/0') + L(l11 '3/1') + L(l6 '4/0') + L(l7 '5/0') + L(l8 '6/0') + L(l12 '6/1') + L(l9 '7/0') + L(l10 '8/0') + L(l13 '8/1') + L(l14) + L(l2) + L(l5) + C(l3 l3 l11 l7) + C(l11 l3 l11) + C(l6 l6 l8 l2 l5) + C(l7 l3 l7 l8) + C(l8 l6 l7 l8 l12 l9) + C(l12 l8 l12) + C(l9 l8 l9 l10) + C(l10 l9 l10 l13) + C(l13 l10 l13) + C(l14 l14) + C(l2 l6 l2) + C(l5 l6 l5) + G(l14 SUBSTRATE) + H(E B('Must-connect nets VSSTOP must be connected further up in the hierarchy - this is an error at chip top level') C(TOP) X('must-connect')) + K(PMOS MOS3) + K(NMOS MOS3) + D(D$PMOS PMOS + T(S + R(l2 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l2 (125 -475) (775 950)) + ) + ) + D(D$NMOS NMOS + T(S + R(l5 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l5 (125 -475) (775 950)) + ) + ) + X(INV + R((-1500 -800) (3000 4600)) + N(1 + R(l6 (290 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l5 (-1375 -925) (775 950)) + ) + N(2 + R(l6 (290 2490) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l2 (-1375 -925) (775 950)) + ) + N(3 + R(l3 (-125 -250) (250 2500)) + R(l3 (-250 -3050) (250 1600)) + R(l3 (-250 1200) (250 1600)) + ) + N(4 + R(l6 (-510 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l6 (-220 2180) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -3530) (360 2840)) + R(l8 (-360 -2800) (360 760)) + R(l8 (-360 2040) (360 760)) + R(l2 (-680 -855) (775 950)) + R(l5 (-775 -3750) (775 950)) + ) + P(1) + P(2) + P(3) + P(4) + D(1 D$PMOS + Y(0 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 2) + ) + D(2 D$NMOS + Y(0 0) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 1) + ) + ) + X(INV2 + R((0 0) (3000 9200)) + N(1 I(VDD) + R(l10 (0 3150) (3000 2900)) + R(l13 (-1890 -1450) (0 0)) + ) + N(2 I(A1) + R(l11 (1480 7110) (0 0)) + ) + N(3 I(A2) + R(l11 (1520 1950) (0 0)) + ) + N(4 I(Q1) + R(l12 (1920 7070) (0 0)) + ) + N(5 I(Q2) + R(l12 (1940 1950) (0 0)) + ) + N(6 I(VSS) + R(l13 (2680 8390) (0 0)) + R(l13 (-30 -7640) (0 0)) + ) + P(1 I(VDD)) + P(2 I(A1)) + P(3 I(A2)) + P(4 I(Q1)) + P(5 I(Q2)) + P(6 I(VSS)) + X(1 INV M O(180) Y(1500 800) + P(0 6) + P(1 1) + P(2 3) + P(3 5) + ) + X(2 INV O(180) Y(1500 8400) + P(0 6) + P(1 1) + P(2 2) + P(3 4) + ) + ) + X(INVCHAIN + R((-915 -15) (10415 9215)) + N(1 + R(l3 (7340 1650) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(2 + R(l3 (1625 1835) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(3 I(IN) + R(l3 (-90 6850) (1590 650)) + R(l11 (-700 -350) (0 0)) + ) + N(4 I(IN2) + R(l3 (5665 6790) (1590 650)) + R(l11 (-700 -350) (0 0)) + ) + N(5 I('VSS,VSS2,VSS2B') + R(l10 (-915 675) (915 250)) + R(l10 (-915 0) (250 7325)) + R(l10 (-250 0) (915 250)) + R(l13 (-510 -125) (0 0)) + R(l13 (8990 -255) (0 0)) + R(l13 (25 -7115) (0 0)) + ) + N(6 I(OUT) + R(l12 (1890 2105) (0 0)) + ) + N(7 I(OUT2) + R(l12 (7730 2155) (0 0)) + ) + N(8 I(VDD) + R(l13 (8035 4540) (0 0)) + R(l13 (-5735 60) (0 0)) + ) + P(3 I(IN)) + P(4 I(IN2)) + P(5 I('VSS,VSS2,VSS2B')) + P(6 I(OUT)) + P(7 I(OUT2)) + P(8 I(VDD)) + X(1 INV2 Y(5780 -15) + P(0 8) + P(1 4) + P(2 1) + P(3 1) + P(4 7) + P(5 5) + ) + X(2 INV2 Y(0 0) + P(0 8) + P(1 3) + P(2 2) + P(3 2) + P(4 6) + P(5 5) + ) + ) + X(TOP + R((-305 350) (15415 9225)) + N(1 + R(l3 (12950 2130) (2160 250)) + R(l3 (-250 0) (250 4990)) + R(l3 (-1605 0) (1605 250)) + R(l7 (-1545 -250) (240 250)) + R(l8 (-560 -375) (690 510)) + ) + N(2 + R(l3 (12100 7300) (640 530)) + R(l7 (-540 -415) (270 250)) + R(l8 (-1695 -250) (1695 250)) + R(l8 (-4075 -5650) (2630 250)) + R(l8 (-250 0) (250 5150)) + ) + N(3 + R(l7 (6465 7325) (220 240)) + R(l8 (-4100 -5365) (3125 250)) + R(l8 (-250 0) (250 4860)) + R(l8 (-250 0) (1225 250)) + ) + N(4 I(VSSTOP) + R(l10 (3610 8300) (2815 440)) + R(l10 (-710 -250) (0 0)) + R(l10 (3675 -165) (1975 565)) + R(l10 (-1975 -8190) (1975 575)) + R(l10 (-1005 -255) (0 0)) + ) + N(5 I(A) + R(l11 (975 7530) (0 0)) + ) + N(6 I(Q) + R(l12 (13260 2010) (0 0)) + ) + N(7 + R(l10 (3450 4840) (3055 250)) + R(l10 (2885 -250) (1975 250)) + ) + P(4 I(VSSTOP)) + P(5 I(A)) + P(6 I(Q)) + X(1 INV2 Y(11365 375) + P(0 7) + P(1 2) + P(2 1) + P(3 1) + P(4 6) + P(5 4) + ) + X(2 INVCHAIN Y(610 365) + P(0 5) + P(1 3) + P(2 4) + P(3 3) + P(4 2) + P(5 7) + ) + ) +) +H( + K(PMOS MOS3) + K(NMOS MOS3) + X(INV + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A)) + N(4 I(Q)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A)) + P(4 I(Q)) + D(1 PMOS + I($1) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 1) + T(G 3) + T(D 4) + ) + D(2 NMOS + I($3) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 2) + T(G 3) + T(D 4) + ) + ) + X(INV2 + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A1)) + N(4 I(Q1)) + N(5 I(A2)) + N(6 I(Q2)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A1)) + P(4 I(Q1)) + P(5 I(A2)) + P(6 I(Q2)) + X(1 INV I($1) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + ) + X(2 INV I($2) + P(0 1) + P(1 2) + P(2 5) + P(3 6) + ) + ) + X(INVCHAIN + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A1)) + N(4 I(Q1)) + N(5 I(A2)) + N(6 I(Q2)) + N(7 I('1')) + N(8 I('2')) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A1)) + P(4 I(Q1)) + P(5 I(A2)) + P(6 I(Q2)) + X(1 INV2 I($2) + P(0 1) + P(1 2) + P(2 3) + P(3 7) + P(4 7) + P(5 4) + ) + X(2 INV2 I($3) + P(0 1) + P(1 2) + P(2 5) + P(3 8) + P(4 8) + P(5 6) + ) + ) + X(TOP + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A)) + N(4 I('1')) + N(5 I('3')) + N(6 I('2')) + N(7 I(Q)) + X(1 INVCHAIN I($1) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + P(4 4) + P(5 5) + ) + X(2 INV2 I($2) + P(0 1) + P(1 2) + P(2 5) + P(3 6) + P(4 6) + P(5 7) + ) + ) +) +Z( + X(INV INV 1 + Z( + N(3 3 1) + N(4 4 1) + N(2 1 1) + N(1 2 1) + P(2 2 1) + P(3 3 1) + P(1 0 1) + P(0 1 1) + D(2 2 1) + D(1 1 1) + ) + ) + X(INV2 INV2 1 + Z( + N(2 3 1) + N(3 5 1) + N(4 4 1) + N(5 6 1) + N(1 1 1) + N(6 2 1) + P(1 2 1) + P(2 4 1) + P(3 3 1) + P(4 5 1) + P(0 0 1) + P(5 1 1) + X(2 1 1) + X(1 2 1) + ) + ) + X(INVCHAIN INVCHAIN 1 + L( + M(W B('Matching nets OUT vs. Q1 from an ambiguous group of nets')) + M(W B('Matching nets OUT2 vs. Q2 from an ambiguous group of nets')) + M(I B('Matching nets $2 vs. 1 following an ambiguous match')) + M(I B('Matching nets IN vs. A1 following an ambiguous match')) + M(I B('Matching nets $1 vs. 2 following an ambiguous match')) + M(I B('Matching nets IN2 vs. A2 following an ambiguous match')) + ) + Z( + N(2 7 1) + N(1 8 1) + N(3 3 1) + N(4 5 1) + N(6 4 W) + N(7 6 W) + N(8 1 1) + N(5 2 1) + P(0 2 1) + P(1 4 1) + P(3 3 1) + P(4 5 1) + P(5 0 1) + P(2 1 1) + X(2 1 1) + X(1 2 1) + ) + ) + X(TOP TOP 1 + Z( + N(3 4 1) + N(1 6 1) + N(2 5 1) + N(7 1 1) + N(5 3 1) + N(6 7 1) + N(4 2 1) + P(1 () 1) + P(2 () 1) + P(0 () 1) + X(1 2 1) + X(2 1 1) + ) + ) +)